Merge "oboeservice: headers for service interface"
diff --git a/include/media/BufferProviders.h b/include/media/BufferProviders.h
index 68b3f23..d5899ea 100644
--- a/include/media/BufferProviders.h
+++ b/include/media/BufferProviders.h
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <media/AudioBufferProvider.h>
+#include <media/AudioResamplerPublic.h>
#include <system/audio.h>
#include <system/audio_effect.h>
#include <utils/StrongPointer.h>
diff --git a/include/media/OMXBuffer.h b/include/media/OMXBuffer.h
index aeb1765..697823f 100644
--- a/include/media/OMXBuffer.h
+++ b/include/media/OMXBuffer.h
@@ -58,10 +58,6 @@
// |codecBuffer|'s size (or 0 if |codecBuffer| is NULL).
OMXBuffer(const sp<MediaCodecBuffer> &codecBuffer);
- // Constructs a buffer of type kBufferTypePreset with a specified
- // mRangeLength.
- explicit OMXBuffer(OMX_U32 rangeLength);
-
// Constructs a buffer of type kBufferTypeSharedMem.
OMXBuffer(const sp<IMemory> &mem);
@@ -101,6 +97,7 @@
// kBufferTypePreset
// If the port is operating in byte buffer mode, mRangeLength is the valid
// range length. Otherwise the range info should also be ignored.
+ OMX_U32 mRangeOffset;
OMX_U32 mRangeLength;
// kBufferTypeSharedMem
diff --git a/include/media/RecordBufferConverter.h b/include/media/RecordBufferConverter.h
new file mode 100644
index 0000000..2abc45e
--- /dev/null
+++ b/include/media/RecordBufferConverter.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RECORD_BUFFER_CONVERTER_H
+#define ANDROID_RECORD_BUFFER_CONVERTER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <media/AudioBufferProvider.h>
+#include <system/audio.h>
+
+class AudioResampler;
+class PassthruBufferProvider;
+
+namespace android {
+
+/* The RecordBufferConverter is used for format, channel, and sample rate
+ * conversion for a RecordTrack.
+ *
+ * RecordBufferConverter uses the convert() method rather than exposing a
+ * buffer provider interface; this is to save a memory copy.
+ *
+ * There are legacy conversion requirements for this converter, specifically
+ * due to mono handling, so be careful about modifying.
+ *
+ * Original source audioflinger/Threads.{h,cpp}
+ */
+class RecordBufferConverter
+{
+public:
+ RecordBufferConverter(
+ audio_channel_mask_t srcChannelMask, audio_format_t srcFormat,
+ uint32_t srcSampleRate,
+ audio_channel_mask_t dstChannelMask, audio_format_t dstFormat,
+ uint32_t dstSampleRate);
+
+ ~RecordBufferConverter();
+
+ /* Converts input data from an AudioBufferProvider by format, channelMask,
+ * and sampleRate to a destination buffer.
+ *
+ * Parameters
+ * dst: buffer to place the converted data.
+ * provider: buffer provider to obtain source data.
+ * frames: number of frames to convert
+ *
+ * Returns the number of frames converted.
+ */
+ size_t convert(void *dst, AudioBufferProvider *provider, size_t frames);
+
+ // returns NO_ERROR if constructor was successful
+ status_t initCheck() const {
+ // mSrcChannelMask set on successful updateParameters
+ return mSrcChannelMask != AUDIO_CHANNEL_INVALID ? NO_ERROR : NO_INIT;
+ }
+
+ // allows dynamic reconfigure of all parameters
+ status_t updateParameters(
+ audio_channel_mask_t srcChannelMask, audio_format_t srcFormat,
+ uint32_t srcSampleRate,
+ audio_channel_mask_t dstChannelMask, audio_format_t dstFormat,
+ uint32_t dstSampleRate);
+
+ // called to reset resampler buffers on record track discontinuity
+ void reset();
+
+private:
+ // format conversion when not using resampler
+ void convertNoResampler(void *dst, const void *src, size_t frames);
+
+ // format conversion when using resampler; modifies src in-place
+ void convertResampler(void *dst, /*not-a-const*/ void *src, size_t frames);
+
+ // user provided information
+ audio_channel_mask_t mSrcChannelMask;
+ audio_format_t mSrcFormat;
+ uint32_t mSrcSampleRate;
+ audio_channel_mask_t mDstChannelMask;
+ audio_format_t mDstFormat;
+ uint32_t mDstSampleRate;
+
+ // derived information
+ uint32_t mSrcChannelCount;
+ uint32_t mDstChannelCount;
+ size_t mDstFrameSize;
+
+ // format conversion buffer
+ void *mBuf;
+ size_t mBufFrames;
+ size_t mBufFrameSize;
+
+ // resampler info
+ AudioResampler *mResampler;
+
+ bool mIsLegacyDownmix; // legacy stereo to mono conversion needed
+ bool mIsLegacyUpmix; // legacy mono to stereo conversion needed
+ bool mRequiresFloat; // data processing requires float (e.g. resampler)
+ PassthruBufferProvider *mInputConverterProvider; // converts input to float
+ int8_t mIdxAry[sizeof(uint32_t) * 8]; // used for channel mask conversion
+};
+
+// ----------------------------------------------------------------------------
+} // namespace android
+
+#endif // ANDROID_RECORD_BUFFER_CONVERTER_H
diff --git a/media/libaudioprocessing/Android.mk b/media/libaudioprocessing/Android.mk
index d47d158..b7ea99e 100644
--- a/media/libaudioprocessing/Android.mk
+++ b/media/libaudioprocessing/Android.mk
@@ -9,6 +9,7 @@
AudioResamplerSinc.cpp.arm \
AudioResamplerDyn.cpp.arm \
BufferProviders.cpp \
+ RecordBufferConverter.cpp \
LOCAL_C_INCLUDES := \
$(TOP) \
diff --git a/media/libaudioprocessing/RecordBufferConverter.cpp b/media/libaudioprocessing/RecordBufferConverter.cpp
new file mode 100644
index 0000000..54151f5
--- /dev/null
+++ b/media/libaudioprocessing/RecordBufferConverter.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "RecordBufferConverter"
+//#define LOG_NDEBUG 0
+
+#include <audio_utils/primitives.h>
+#include <audio_utils/format.h>
+#include <media/AudioMixer.h> // for UNITY_GAIN_FLOAT
+#include <media/AudioResampler.h>
+#include <media/BufferProviders.h>
+#include <media/RecordBufferConverter.h>
+#include <utils/Log.h>
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+#endif
+
+template <typename T>
+static inline T max(const T& a, const T& b)
+{
+ return a > b ? a : b;
+}
+
+namespace android {
+
+RecordBufferConverter::RecordBufferConverter(
+ audio_channel_mask_t srcChannelMask, audio_format_t srcFormat,
+ uint32_t srcSampleRate,
+ audio_channel_mask_t dstChannelMask, audio_format_t dstFormat,
+ uint32_t dstSampleRate) :
+ mSrcChannelMask(AUDIO_CHANNEL_INVALID), // updateParameters will set following vars
+ // mSrcFormat
+ // mSrcSampleRate
+ // mDstChannelMask
+ // mDstFormat
+ // mDstSampleRate
+ // mSrcChannelCount
+ // mDstChannelCount
+ // mDstFrameSize
+ mBuf(NULL), mBufFrames(0), mBufFrameSize(0),
+ mResampler(NULL),
+ mIsLegacyDownmix(false),
+ mIsLegacyUpmix(false),
+ mRequiresFloat(false),
+ mInputConverterProvider(NULL)
+{
+ (void)updateParameters(srcChannelMask, srcFormat, srcSampleRate,
+ dstChannelMask, dstFormat, dstSampleRate);
+}
+
+RecordBufferConverter::~RecordBufferConverter() {
+ free(mBuf);
+ delete mResampler;
+ delete mInputConverterProvider;
+}
+
+void RecordBufferConverter::reset() {
+ if (mResampler != NULL) {
+ mResampler->reset();
+ }
+}
+
+size_t RecordBufferConverter::convert(void *dst,
+ AudioBufferProvider *provider, size_t frames)
+{
+ if (mInputConverterProvider != NULL) {
+ mInputConverterProvider->setBufferProvider(provider);
+ provider = mInputConverterProvider;
+ }
+
+ if (mResampler == NULL) {
+ ALOGV("NO RESAMPLING sampleRate:%u mSrcFormat:%#x mDstFormat:%#x",
+ mSrcSampleRate, mSrcFormat, mDstFormat);
+
+ AudioBufferProvider::Buffer buffer;
+ for (size_t i = frames; i > 0; ) {
+ buffer.frameCount = i;
+ status_t status = provider->getNextBuffer(&buffer);
+ if (status != OK || buffer.frameCount == 0) {
+ frames -= i; // cannot fill request.
+ break;
+ }
+ // format convert to destination buffer
+ convertNoResampler(dst, buffer.raw, buffer.frameCount);
+
+ dst = (int8_t*)dst + buffer.frameCount * mDstFrameSize;
+ i -= buffer.frameCount;
+ provider->releaseBuffer(&buffer);
+ }
+ } else {
+ ALOGV("RESAMPLING mSrcSampleRate:%u mDstSampleRate:%u mSrcFormat:%#x mDstFormat:%#x",
+ mSrcSampleRate, mDstSampleRate, mSrcFormat, mDstFormat);
+
+ // reallocate buffer if needed
+ if (mBufFrameSize != 0 && mBufFrames < frames) {
+ free(mBuf);
+ mBufFrames = frames;
+ (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize);
+ }
+ // resampler accumulates, but we only have one source track
+ memset(mBuf, 0, frames * mBufFrameSize);
+ frames = mResampler->resample((int32_t*)mBuf, frames, provider);
+ // format convert to destination buffer
+ convertResampler(dst, mBuf, frames);
+ }
+ return frames;
+}
+
+status_t RecordBufferConverter::updateParameters(
+ audio_channel_mask_t srcChannelMask, audio_format_t srcFormat,
+ uint32_t srcSampleRate,
+ audio_channel_mask_t dstChannelMask, audio_format_t dstFormat,
+ uint32_t dstSampleRate)
+{
+ // quick evaluation if there is any change.
+ if (mSrcFormat == srcFormat
+ && mSrcChannelMask == srcChannelMask
+ && mSrcSampleRate == srcSampleRate
+ && mDstFormat == dstFormat
+ && mDstChannelMask == dstChannelMask
+ && mDstSampleRate == dstSampleRate) {
+ return NO_ERROR;
+ }
+
+ ALOGV("RecordBufferConverter updateParameters srcMask:%#x dstMask:%#x"
+ " srcFormat:%#x dstFormat:%#x srcRate:%u dstRate:%u",
+ srcChannelMask, dstChannelMask, srcFormat, dstFormat, srcSampleRate, dstSampleRate);
+ const bool valid =
+ audio_is_input_channel(srcChannelMask)
+ && audio_is_input_channel(dstChannelMask)
+ && audio_is_valid_format(srcFormat) && audio_is_linear_pcm(srcFormat)
+ && audio_is_valid_format(dstFormat) && audio_is_linear_pcm(dstFormat)
+ && (srcSampleRate <= dstSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX)
+ ; // no upsampling checks for now
+ if (!valid) {
+ return BAD_VALUE;
+ }
+
+ mSrcFormat = srcFormat;
+ mSrcChannelMask = srcChannelMask;
+ mSrcSampleRate = srcSampleRate;
+ mDstFormat = dstFormat;
+ mDstChannelMask = dstChannelMask;
+ mDstSampleRate = dstSampleRate;
+
+ // compute derived parameters
+ mSrcChannelCount = audio_channel_count_from_in_mask(srcChannelMask);
+ mDstChannelCount = audio_channel_count_from_in_mask(dstChannelMask);
+ mDstFrameSize = mDstChannelCount * audio_bytes_per_sample(mDstFormat);
+
+ // do we need to resample?
+ delete mResampler;
+ mResampler = NULL;
+ if (mSrcSampleRate != mDstSampleRate) {
+ mResampler = AudioResampler::create(AUDIO_FORMAT_PCM_FLOAT,
+ mSrcChannelCount, mDstSampleRate);
+ mResampler->setSampleRate(mSrcSampleRate);
+ mResampler->setVolume(AudioMixer::UNITY_GAIN_FLOAT, AudioMixer::UNITY_GAIN_FLOAT);
+ }
+
+ // are we running legacy channel conversion modes?
+ mIsLegacyDownmix = (mSrcChannelMask == AUDIO_CHANNEL_IN_STEREO
+ || mSrcChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK)
+ && mDstChannelMask == AUDIO_CHANNEL_IN_MONO;
+ mIsLegacyUpmix = mSrcChannelMask == AUDIO_CHANNEL_IN_MONO
+ && (mDstChannelMask == AUDIO_CHANNEL_IN_STEREO
+ || mDstChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK);
+
+ // do we need to process in float?
+ mRequiresFloat = mResampler != NULL || mIsLegacyDownmix || mIsLegacyUpmix;
+
+ // do we need a staging buffer to convert for destination (we can still optimize this)?
+ // we use mBufFrameSize > 0 to indicate both frame size as well as buffer necessity
+ if (mResampler != NULL) {
+ mBufFrameSize = max(mSrcChannelCount, (uint32_t)FCC_2)
+ * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT);
+ } else if (mIsLegacyUpmix || mIsLegacyDownmix) { // legacy modes always float
+ mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT);
+ } else if (mSrcChannelMask != mDstChannelMask && mDstFormat != mSrcFormat) {
+ mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(mSrcFormat);
+ } else {
+ mBufFrameSize = 0;
+ }
+ mBufFrames = 0; // force the buffer to be resized.
+
+ // do we need an input converter buffer provider to give us float?
+ delete mInputConverterProvider;
+ mInputConverterProvider = NULL;
+ if (mRequiresFloat && mSrcFormat != AUDIO_FORMAT_PCM_FLOAT) {
+ mInputConverterProvider = new ReformatBufferProvider(
+ audio_channel_count_from_in_mask(mSrcChannelMask),
+ mSrcFormat,
+ AUDIO_FORMAT_PCM_FLOAT,
+ 256 /* provider buffer frame count */);
+ }
+
+ // do we need a remixer to do channel mask conversion
+ if (!mIsLegacyDownmix && !mIsLegacyUpmix && mSrcChannelMask != mDstChannelMask) {
+ (void) memcpy_by_index_array_initialization_from_channel_mask(
+ mIdxAry, ARRAY_SIZE(mIdxAry), mDstChannelMask, mSrcChannelMask);
+ }
+ return NO_ERROR;
+}
+
+void RecordBufferConverter::convertNoResampler(
+ void *dst, const void *src, size_t frames)
+{
+ // src is native type unless there is legacy upmix or downmix, whereupon it is float.
+ if (mBufFrameSize != 0 && mBufFrames < frames) {
+ free(mBuf);
+ mBufFrames = frames;
+ (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize);
+ }
+ // do we need to do legacy upmix and downmix?
+ if (mIsLegacyUpmix || mIsLegacyDownmix) {
+ void *dstBuf = mBuf != NULL ? mBuf : dst;
+ if (mIsLegacyUpmix) {
+ upmix_to_stereo_float_from_mono_float((float *)dstBuf,
+ (const float *)src, frames);
+ } else /*mIsLegacyDownmix */ {
+ downmix_to_mono_float_from_stereo_float((float *)dstBuf,
+ (const float *)src, frames);
+ }
+ if (mBuf != NULL) {
+ memcpy_by_audio_format(dst, mDstFormat, mBuf, AUDIO_FORMAT_PCM_FLOAT,
+ frames * mDstChannelCount);
+ }
+ return;
+ }
+ // do we need to do channel mask conversion?
+ if (mSrcChannelMask != mDstChannelMask) {
+ void *dstBuf = mBuf != NULL ? mBuf : dst;
+ memcpy_by_index_array(dstBuf, mDstChannelCount,
+ src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mSrcFormat), frames);
+ if (dstBuf == dst) {
+ return; // format is the same
+ }
+ }
+ // convert to destination buffer
+ const void *convertBuf = mBuf != NULL ? mBuf : src;
+ memcpy_by_audio_format(dst, mDstFormat, convertBuf, mSrcFormat,
+ frames * mDstChannelCount);
+}
+
+void RecordBufferConverter::convertResampler(
+ void *dst, /*not-a-const*/ void *src, size_t frames)
+{
+ // src buffer format is ALWAYS float when entering this routine
+ if (mIsLegacyUpmix) {
+ ; // mono to stereo already handled by resampler
+ } else if (mIsLegacyDownmix
+ || (mSrcChannelMask == mDstChannelMask && mSrcChannelCount == 1)) {
+ // the resampler outputs stereo for mono input channel (a feature?)
+ // must convert to mono
+ downmix_to_mono_float_from_stereo_float((float *)src,
+ (const float *)src, frames);
+ } else if (mSrcChannelMask != mDstChannelMask) {
+ // convert to mono channel again for channel mask conversion (could be skipped
+ // with further optimization).
+ if (mSrcChannelCount == 1) {
+ downmix_to_mono_float_from_stereo_float((float *)src,
+ (const float *)src, frames);
+ }
+ // convert to destination format (in place, OK as float is larger than other types)
+ if (mDstFormat != AUDIO_FORMAT_PCM_FLOAT) {
+ memcpy_by_audio_format(src, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT,
+ frames * mSrcChannelCount);
+ }
+ // channel convert and save to dst
+ memcpy_by_index_array(dst, mDstChannelCount,
+ src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mDstFormat), frames);
+ return;
+ }
+ // convert to destination format and save to dst
+ memcpy_by_audio_format(dst, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT,
+ frames * mDstChannelCount);
+}
+
+// ----------------------------------------------------------------------------
+} // namespace android
diff --git a/media/libaudioprocessing/tests/resampler_tests.cpp b/media/libaudioprocessing/tests/resampler_tests.cpp
index 8d5e016..a23c000 100644
--- a/media/libaudioprocessing/tests/resampler_tests.cpp
+++ b/media/libaudioprocessing/tests/resampler_tests.cpp
@@ -32,8 +32,8 @@
#include <utility>
#include <vector>
-#include <android/log.h>
#include <gtest/gtest.h>
+#include <log/log.h>
#include <media/AudioBufferProvider.h>
#include <media/AudioResampler.h>
diff --git a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
index 19d408d..9d29cf1 100644
--- a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
+++ b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
@@ -19,12 +19,13 @@
#include <assert.h>
#include <math.h>
-#include <new>
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include <android/log.h>
+#include <new>
+
+#include <log/log.h>
#include <audio_effects/effect_loudnessenhancer.h>
#include "dsp/core/dynamic_range_compression.h"
diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp
index f5e11a6..db4d009 100644
--- a/media/libeffects/testlibs/EffectEqualizer.cpp
+++ b/media/libeffects/testlibs/EffectEqualizer.cpp
@@ -22,9 +22,10 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
+
#include <new>
-#include <android/log.h>
+#include <log/log.h>
#include "AudioEqualizer.h"
#include "AudioBiquadFilter.h"
diff --git a/media/libeffects/testlibs/EffectReverb.c b/media/libeffects/testlibs/EffectReverb.c
index 08bf9ae..fce9bed 100644
--- a/media/libeffects/testlibs/EffectReverb.c
+++ b/media/libeffects/testlibs/EffectReverb.c
@@ -21,7 +21,7 @@
#include <stdlib.h>
#include <string.h>
-#include <android/log.h>
+#include <log/log.h>
#include "EffectReverb.h"
#include "EffectsMath.h"
diff --git a/media/libmedia/OMXBuffer.cpp b/media/libmedia/OMXBuffer.cpp
index 914cd5b..8ea70e4 100644
--- a/media/libmedia/OMXBuffer.cpp
+++ b/media/libmedia/OMXBuffer.cpp
@@ -35,14 +35,10 @@
OMXBuffer::OMXBuffer(const sp<MediaCodecBuffer>& codecBuffer)
: mBufferType(kBufferTypePreset),
+ mRangeOffset(codecBuffer != NULL ? codecBuffer->offset() : 0),
mRangeLength(codecBuffer != NULL ? codecBuffer->size() : 0) {
}
-OMXBuffer::OMXBuffer(OMX_U32 rangeLength)
- : mBufferType(kBufferTypePreset),
- mRangeLength(rangeLength) {
-}
-
OMXBuffer::OMXBuffer(const sp<IMemory> &mem)
: mBufferType(kBufferTypeSharedMem),
mMem(mem) {
@@ -67,6 +63,10 @@
switch(mBufferType) {
case kBufferTypePreset:
{
+ status_t err = parcel->writeUint32(mRangeOffset);
+ if (err != OK) {
+ return err;
+ }
return parcel->writeUint32(mRangeLength);
}
@@ -97,7 +97,14 @@
switch(bufferType) {
case kBufferTypePreset:
{
- mRangeLength = parcel->readUint32();
+ status_t err = parcel->readUint32(&mRangeOffset);
+ if (err != OK) {
+ return err;
+ }
+ err = parcel->readUint32(&mRangeLength);
+ if (err != OK) {
+ return err;
+ }
break;
}
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index d1d1077..031b473 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -618,6 +618,12 @@
break;
}
+ case kWhatGetTrackInfo:
+ {
+ onGetTrackInfo(msg);
+ break;
+ }
+
case kWhatSelectTrack:
{
onSelectTrack(msg);
@@ -868,6 +874,34 @@
}
sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
+ sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, this);
+ msg->setSize("trackIndex", trackIndex);
+
+ sp<AMessage> response;
+ sp<RefBase> format;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findObject("format", &format));
+ return static_cast<AMessage*>(format.get());
+ } else {
+ return NULL;
+ }
+}
+
+void NuPlayer::GenericSource::onGetTrackInfo(const sp<AMessage>& msg) const {
+ size_t trackIndex;
+ CHECK(msg->findSize("trackIndex", &trackIndex));
+
+ sp<AMessage> response = new AMessage;
+ sp<AMessage> format = doGetTrackInfo(trackIndex);
+ response->setObject("format", format);
+
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+ response->postReply(replyID);
+}
+
+sp<AMessage> NuPlayer::GenericSource::doGetTrackInfo(size_t trackIndex) const {
size_t trackCount = mSources.size();
if (trackIndex >= trackCount) {
return NULL;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index a14056f..81e19bc 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -245,6 +245,9 @@
void onGetFormatMeta(const sp<AMessage>& msg) const;
sp<MetaData> doGetFormatMeta(bool audio) const;
+ void onGetTrackInfo(const sp<AMessage>& msg) const;
+ sp<AMessage> doGetTrackInfo(size_t trackIndex) const;
+
void onGetSelectedTrack(const sp<AMessage>& msg) const;
ssize_t doGetSelectedTrack(media_track_type type) const;
diff --git a/media/liboboe/src/fifo/FifoBuffer.cpp b/media/liboboe/src/fifo/FifoBuffer.cpp
new file mode 100644
index 0000000..c5489f1
--- /dev/null
+++ b/media/liboboe/src/fifo/FifoBuffer.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstring>
+#include <unistd.h>
+
+#define LOG_TAG "FifoBuffer"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "FifoControllerBase.h"
+#include "FifoController.h"
+#include "FifoControllerIndirect.h"
+#include "FifoBuffer.h"
+
+FifoBuffer::FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames)
+ : mFrameCapacity(capacityInFrames)
+ , mBytesPerFrame(bytesPerFrame)
+ , mStorage(nullptr)
+ , mFramesReadCount(0)
+ , mFramesUnderrunCount(0)
+ , mUnderrunCount(0)
+{
+ // TODO Handle possible failures to allocate. Move out of constructor?
+ mFifo = new FifoController(capacityInFrames, capacityInFrames);
+ // allocate buffer
+ int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
+ mStorage = new uint8_t[bytesPerBuffer];
+ mStorageOwned = true;
+ ALOGD("FifoBuffer: capacityInFrames = %d, bytesPerFrame = %d",
+ capacityInFrames, bytesPerFrame);
+}
+
+FifoBuffer::FifoBuffer( int32_t bytesPerFrame,
+ fifo_frames_t capacityInFrames,
+ fifo_counter_t * readIndexAddress,
+ fifo_counter_t * writeIndexAddress,
+ void * dataStorageAddress
+ )
+ : mFrameCapacity(capacityInFrames)
+ , mBytesPerFrame(bytesPerFrame)
+ , mStorage(static_cast<uint8_t *>(dataStorageAddress))
+ , mFramesReadCount(0)
+ , mFramesUnderrunCount(0)
+ , mUnderrunCount(0)
+{
+ // TODO Handle possible failures to allocate. Move out of constructor?
+ mFifo = new FifoControllerIndirect(capacityInFrames,
+ capacityInFrames,
+ readIndexAddress,
+ writeIndexAddress);
+ mStorageOwned = false;
+ ALOGD("FifoProcessor: capacityInFrames = %d, bytesPerFrame = %d",
+ capacityInFrames, bytesPerFrame);
+}
+
+FifoBuffer::~FifoBuffer() {
+ if (mStorageOwned) {
+ delete[] mStorage;
+ }
+ delete mFifo;
+}
+
+
+int32_t FifoBuffer::convertFramesToBytes(fifo_frames_t frames) {
+ return frames * mBytesPerFrame;
+}
+
+fifo_frames_t FifoBuffer::read(void *buffer, fifo_frames_t numFrames) {
+ size_t numBytes;
+ fifo_frames_t framesAvailable = mFifo->getFullFramesAvailable();
+ fifo_frames_t framesToRead = numFrames;
+ // Is there enough data in the FIFO
+ if (framesToRead > framesAvailable) {
+ framesToRead = framesAvailable;
+ }
+ if (framesToRead == 0) {
+ return 0;
+ }
+
+ fifo_frames_t readIndex = mFifo->getReadIndex();
+ uint8_t *destination = (uint8_t *) buffer;
+ uint8_t *source = &mStorage[convertFramesToBytes(readIndex)];
+ if ((readIndex + framesToRead) > mFrameCapacity) {
+ // read in two parts, first part here
+ fifo_frames_t frames1 = mFrameCapacity - readIndex;
+ int32_t numBytes = convertFramesToBytes(frames1);
+ memcpy(destination, source, numBytes);
+ destination += numBytes;
+ // read second part
+ source = &mStorage[0];
+ fifo_frames_t frames2 = framesToRead - frames1;
+ numBytes = convertFramesToBytes(frames2);
+ memcpy(destination, source, numBytes);
+ } else {
+ // just read in one shot
+ numBytes = convertFramesToBytes(framesToRead);
+ memcpy(destination, source, numBytes);
+ }
+ mFifo->advanceReadIndex(framesToRead);
+
+ return framesToRead;
+}
+
+fifo_frames_t FifoBuffer::write(const void *buffer, fifo_frames_t framesToWrite) {
+ fifo_frames_t framesAvailable = mFifo->getEmptyFramesAvailable();
+// ALOGD("FifoBuffer::write() framesToWrite = %d, framesAvailable = %d",
+// framesToWrite, framesAvailable);
+ if (framesToWrite > framesAvailable) {
+ framesToWrite = framesAvailable;
+ }
+ if (framesToWrite <= 0) {
+ return 0;
+ }
+
+ size_t numBytes;
+ fifo_frames_t writeIndex = mFifo->getWriteIndex();
+ int byteIndex = convertFramesToBytes(writeIndex);
+ const uint8_t *source = (const uint8_t *) buffer;
+ uint8_t *destination = &mStorage[byteIndex];
+ if ((writeIndex + framesToWrite) > mFrameCapacity) {
+ // write in two parts, first part here
+ fifo_frames_t frames1 = mFrameCapacity - writeIndex;
+ numBytes = convertFramesToBytes(frames1);
+ memcpy(destination, source, numBytes);
+// ALOGD("FifoBuffer::write(%p to %p, numBytes = %d", source, destination, numBytes);
+ // read second part
+ source += convertFramesToBytes(frames1);
+ destination = &mStorage[0];
+ fifo_frames_t framesLeft = framesToWrite - frames1;
+ numBytes = convertFramesToBytes(framesLeft);
+// ALOGD("FifoBuffer::write(%p to %p, numBytes = %d", source, destination, numBytes);
+ memcpy(destination, source, numBytes);
+ } else {
+ // just write in one shot
+ numBytes = convertFramesToBytes(framesToWrite);
+// ALOGD("FifoBuffer::write(%p to %p, numBytes = %d", source, destination, numBytes);
+ memcpy(destination, source, numBytes);
+ }
+ mFifo->advanceWriteIndex(framesToWrite);
+
+ return framesToWrite;
+}
+
+fifo_frames_t FifoBuffer::readNow(void *buffer, fifo_frames_t numFrames) {
+ mLastReadSize = numFrames;
+ fifo_frames_t framesLeft = numFrames;
+ fifo_frames_t framesRead = read(buffer, numFrames);
+ framesLeft -= framesRead;
+ mFramesReadCount += framesRead;
+ mFramesUnderrunCount += framesLeft;
+ // Zero out any samples we could not set.
+ if (framesLeft > 0) {
+ mUnderrunCount++;
+ int32_t bytesToZero = convertFramesToBytes(framesLeft);
+ memset(buffer, 0, bytesToZero);
+ }
+
+ return framesRead;
+}
+
+fifo_frames_t FifoBuffer::getThreshold() {
+ return mFifo->getThreshold();
+}
+
+void FifoBuffer::setThreshold(fifo_frames_t threshold) {
+ mFifo->setThreshold(threshold);
+}
+
+fifo_frames_t FifoBuffer::getBufferCapacityInFrames() {
+ return mFifo->getCapacity();
+}
+
diff --git a/media/liboboe/src/fifo/FifoBuffer.h b/media/liboboe/src/fifo/FifoBuffer.h
new file mode 100644
index 0000000..faa9ae2
--- /dev/null
+++ b/media/liboboe/src/fifo/FifoBuffer.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIFO_FIFO_BUFFER_H
+#define FIFO_FIFO_BUFFER_H
+
+#include <stdint.h>
+
+#include "FifoControllerBase.h"
+
+class FifoBuffer {
+public:
+ FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames);
+
+ FifoBuffer(int32_t bytesPerFrame,
+ fifo_frames_t capacityInFrames,
+ fifo_counter_t * readCounterAddress,
+ fifo_counter_t * writeCounterAddress,
+ void * dataStorageAddress);
+
+ ~FifoBuffer();
+
+ int32_t convertFramesToBytes(fifo_frames_t frames);
+
+ fifo_frames_t read(void *destination, fifo_frames_t framesToRead);
+
+ fifo_frames_t write(const void *source, fifo_frames_t framesToWrite);
+
+ fifo_frames_t getThreshold();
+ void setThreshold(fifo_frames_t threshold);
+
+ fifo_frames_t getBufferCapacityInFrames();
+
+ fifo_frames_t readNow(void *buffer, fifo_frames_t numFrames);
+
+ int64_t getNextReadTime(int32_t frameRate);
+
+ int32_t getUnderrunCount() const { return mUnderrunCount; }
+
+ FifoControllerBase *getFifoControllerBase() { return mFifo; }
+
+ int32_t getBytesPerFrame() {
+ return mBytesPerFrame;
+ }
+
+ fifo_counter_t getReadCounter() {
+ return mFifo->getReadCounter();
+ }
+
+ void setReadCounter(fifo_counter_t n) {
+ mFifo->setReadCounter(n);
+ }
+
+ fifo_counter_t getWriteCounter() {
+ return mFifo->getWriteCounter();
+ }
+
+ void setWriteCounter(fifo_counter_t n) {
+ mFifo->setWriteCounter(n);
+ }
+
+private:
+ const fifo_frames_t mFrameCapacity;
+ const int32_t mBytesPerFrame;
+ uint8_t * mStorage;
+ bool mStorageOwned; // did this object allocate the storage?
+ FifoControllerBase *mFifo;
+ fifo_counter_t mFramesReadCount;
+ fifo_counter_t mFramesUnderrunCount;
+ int32_t mUnderrunCount; // need? just use frames
+ int32_t mLastReadSize;
+};
+
+#endif //FIFO_FIFO_BUFFER_H
diff --git a/media/liboboe/src/fifo/FifoController.h b/media/liboboe/src/fifo/FifoController.h
new file mode 100644
index 0000000..7434634
--- /dev/null
+++ b/media/liboboe/src/fifo/FifoController.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIFO_FIFO_CONTROLLER_H
+#define FIFO_FIFO_CONTROLLER_H
+
+#include <stdint.h>
+#include <atomic>
+
+#include "FifoControllerBase.h"
+
+/**
+ * A FIFO with counters contained in the class.
+ */
+class FifoController : public FifoControllerBase
+{
+public:
+ FifoController(fifo_counter_t bufferSize, fifo_counter_t threshold)
+ : FifoControllerBase(bufferSize, threshold)
+ , mReadCounter(0)
+ , mWriteCounter(0)
+ {}
+
+ virtual ~FifoController() {}
+
+ // TODO review use of memory barriers, probably incorrect
+ virtual fifo_counter_t getReadCounter() override {
+ return mReadCounter.load(std::memory_order_acquire);
+ }
+ virtual void setReadCounter(fifo_counter_t n) override {
+ mReadCounter.store(n, std::memory_order_release);
+ }
+ virtual fifo_counter_t getWriteCounter() override {
+ return mWriteCounter.load(std::memory_order_acquire);
+ }
+ virtual void setWriteCounter(fifo_counter_t n) override {
+ mWriteCounter.store(n, std::memory_order_release);
+ }
+
+private:
+ std::atomic<fifo_counter_t> mReadCounter;
+ std::atomic<fifo_counter_t> mWriteCounter;
+};
+
+
+#endif //FIFO_FIFO_CONTROLLER_H
diff --git a/media/liboboe/src/fifo/FifoControllerBase.cpp b/media/liboboe/src/fifo/FifoControllerBase.cpp
new file mode 100644
index 0000000..33a253e
--- /dev/null
+++ b/media/liboboe/src/fifo/FifoControllerBase.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "FifoControllerBase"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include "FifoControllerBase.h"
+
+FifoControllerBase::FifoControllerBase(fifo_frames_t capacity, fifo_frames_t threshold)
+ : mCapacity(capacity)
+ , mThreshold(threshold)
+{
+}
+
+FifoControllerBase::~FifoControllerBase() {
+}
+
+fifo_frames_t FifoControllerBase::getFullFramesAvailable() {
+ return (fifo_frames_t) (getWriteCounter() - getReadCounter());
+}
+
+fifo_frames_t FifoControllerBase::getReadIndex() {
+ // % works with non-power of two sizes
+ return (fifo_frames_t) (getReadCounter() % mCapacity);
+}
+
+void FifoControllerBase::advanceReadIndex(fifo_frames_t numFrames) {
+ setReadCounter(getReadCounter() + numFrames);
+}
+
+fifo_frames_t FifoControllerBase::getEmptyFramesAvailable() {
+ return (int32_t)(mThreshold - getFullFramesAvailable());
+}
+
+fifo_frames_t FifoControllerBase::getWriteIndex() {
+ // % works with non-power of two sizes
+ return (fifo_frames_t) (getWriteCounter() % mCapacity);
+}
+
+void FifoControllerBase::advanceWriteIndex(fifo_frames_t numFrames) {
+ setWriteCounter(getWriteCounter() + numFrames);
+}
+
+void FifoControllerBase::setThreshold(fifo_frames_t threshold) {
+ mThreshold = threshold;
+}
diff --git a/media/liboboe/src/fifo/FifoControllerBase.h b/media/liboboe/src/fifo/FifoControllerBase.h
new file mode 100644
index 0000000..c543519
--- /dev/null
+++ b/media/liboboe/src/fifo/FifoControllerBase.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIFO_FIFO_CONTROLLER_BASE_H
+#define FIFO_FIFO_CONTROLLER_BASE_H
+
+#include <stdint.h>
+
+typedef int64_t fifo_counter_t;
+typedef int32_t fifo_frames_t;
+
+/**
+ * Manage the read/write indices of a circular buffer.
+ *
+ * The caller is responsible for reading and writing the actual data.
+ * Note that the span of available frames may not be contiguous. They
+ * may wrap around from the end to the beginning of the buffer. In that
+ * case the data must be read or written in at least two blocks of frames.
+ *
+ */
+class FifoControllerBase {
+
+public:
+ /**
+ * Constructor for FifoControllerBase
+ * @param capacity Total size of the circular buffer in frames.
+ * @param threshold Number of frames to fill. Must be less than capacity.
+ */
+ FifoControllerBase(fifo_frames_t capacity, fifo_frames_t threshold);
+
+ virtual ~FifoControllerBase();
+
+ // Abstract methods to be implemented in subclasses.
+ /**
+ * @return Counter used by the reader of the FIFO.
+ */
+ virtual fifo_counter_t getReadCounter() = 0;
+
+ /**
+ * This is normally only used internally.
+ * @param count Number of frames that have been read.
+ */
+ virtual void setReadCounter(fifo_counter_t count) = 0;
+
+ /**
+ * @return Counter used by the reader of the FIFO.
+ */
+ virtual fifo_counter_t getWriteCounter() = 0;
+
+ /**
+ * This is normally only used internally.
+ * @param count Number of frames that have been read.
+ */
+ virtual void setWriteCounter(fifo_counter_t count) = 0;
+
+ /**
+ * This may be negative if an unthrottled reader has read beyond the available data.
+ * @return number of valid frames available to read. Never read more than this.
+ */
+ fifo_frames_t getFullFramesAvailable();
+
+ /**
+ * The index in a circular buffer of the next frame to read.
+ */
+ fifo_frames_t getReadIndex();
+
+ /**
+ * @param numFrames number of frames to advance the read index
+ */
+ void advanceReadIndex(fifo_frames_t numFrames);
+
+ /**
+ * @return number of frames that can be written. Never write more than this.
+ */
+ fifo_frames_t getEmptyFramesAvailable();
+
+ /**
+ * The index in a circular buffer of the next frame to write.
+ */
+ fifo_frames_t getWriteIndex();
+
+ /**
+ * @param numFrames number of frames to advance the write index
+ */
+ void advanceWriteIndex(fifo_frames_t numFrames);
+
+ /**
+ * You can request that the buffer not be filled above a maximum
+ * number of frames.
+ * @param threshold effective size of the buffer
+ */
+ void setThreshold(fifo_frames_t threshold);
+
+ fifo_frames_t getThreshold() const {
+ return mThreshold;
+ }
+
+ fifo_frames_t getCapacity() const {
+ return mCapacity;
+ }
+
+
+private:
+ fifo_frames_t mCapacity;
+ fifo_frames_t mThreshold;
+};
+
+#endif // FIFO_FIFO_CONTROLLER_BASE_H
diff --git a/media/liboboe/src/fifo/FifoControllerIndirect.h b/media/liboboe/src/fifo/FifoControllerIndirect.h
new file mode 100644
index 0000000..1aaf9ea
--- /dev/null
+++ b/media/liboboe/src/fifo/FifoControllerIndirect.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIFO_FIFO_CONTROLLER_INDIRECT_H
+#define FIFO_FIFO_CONTROLLER_INDIRECT_H
+
+#include <stdint.h>
+#include <atomic>
+
+#include "FifoControllerBase.h"
+
+/**
+ * A FifoControllerBase with counters external to the class.
+ *
+ * The actual copunters may be stored in separate regions of shared memory
+ * with different access rights.
+ */
+class FifoControllerIndirect : public FifoControllerBase {
+
+public:
+ FifoControllerIndirect(fifo_frames_t capacity,
+ fifo_frames_t threshold,
+ fifo_counter_t * readCounterAddress,
+ fifo_counter_t * writeCounterAddress)
+ : FifoControllerBase(capacity, threshold)
+ , mReadCounterAddress((std::atomic<fifo_counter_t> *) readCounterAddress)
+ , mWriteCounterAddress((std::atomic<fifo_counter_t> *) writeCounterAddress)
+ {
+ setReadCounter(0);
+ setWriteCounter(0);
+ }
+ virtual ~FifoControllerIndirect() {};
+
+ // TODO review use of memory barriers, probably incorrect
+ virtual fifo_counter_t getReadCounter() override {
+ return mReadCounterAddress->load(std::memory_order_acquire);
+ }
+
+ virtual void setReadCounter(fifo_counter_t count) override {
+ mReadCounterAddress->store(count, std::memory_order_release);
+ }
+
+ virtual fifo_counter_t getWriteCounter() override {
+ return mWriteCounterAddress->load(std::memory_order_acquire);
+ }
+
+ virtual void setWriteCounter(fifo_counter_t count) override {
+ mWriteCounterAddress->store(count, std::memory_order_release);
+ }
+
+private:
+ std::atomic<fifo_counter_t> * mReadCounterAddress;
+ std::atomic<fifo_counter_t> * mWriteCounterAddress;
+};
+
+#endif //FIFO_FIFO_CONTROLLER_INDIRECT_H
diff --git a/media/liboboe/src/fifo/README.md b/media/liboboe/src/fifo/README.md
new file mode 100644
index 0000000..61ffbae
--- /dev/null
+++ b/media/liboboe/src/fifo/README.md
@@ -0,0 +1,9 @@
+Simple atomic FIFO for passing data between threads or processes.
+This does not require mutexes.
+
+One thread modifies the readCounter and the other thread modifies the writeCounter.
+
+TODO The internal low-level implementation might be merged in some form with audio_utils fifo
+and/or FMQ [after confirming that requirements are met].
+The higher-levels parts related to Oboe use of the FIFO such as API, fds, relative
+location of indices and data buffer, mapping, allocation of memmory will probably be kept as-is.
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index f247475..c63ab47 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -5543,6 +5543,7 @@
}
size_t size = buffer->size();
+ size_t offset = buffer->offset();
if (buffer->base() != info->mCodecData->base()) {
ALOGV("[%s] Needs to copy input data for buffer %u. (%p != %p)",
mCodec->mComponentName.c_str(),
@@ -5560,7 +5561,7 @@
}
size = info->mCodecData->size();
} else {
- info->mCodecData->setRange(0, size);
+ info->mCodecData->setRange(offset, size);
}
if (flags & OMX_BUFFERFLAG_CODECCONFIG) {
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index 045e044..1b0db33 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -22,8 +22,8 @@
#include "AMessage.h"
-#include <android/log.h>
#include <binder/Parcel.h>
+#include <log/log.h>
#include "AAtomizer.h"
#include "ABuffer.h"
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index c20e9fc..ea86a37 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -1559,7 +1559,8 @@
switch (omxBuffer.mBufferType) {
case OMXBuffer::kBufferTypePreset:
return emptyBuffer_l(
- buffer, 0, omxBuffer.mRangeLength, flags, timestamp, fenceFd);
+ buffer, omxBuffer.mRangeOffset, omxBuffer.mRangeLength,
+ flags, timestamp, fenceFd);
case OMXBuffer::kBufferTypeANWBuffer:
return emptyGraphicBuffer_l(
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 35eceb2..e97d1ed 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -80,6 +80,7 @@
class EffectsFactoryHalInterface;
class FastMixer;
class PassthruBufferProvider;
+class RecordBufferConverter;
class ServerProxy;
// ----------------------------------------------------------------------------
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index e025316..a8c761f 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -29,6 +29,7 @@
#include <cutils/properties.h>
#include <media/AudioParameter.h>
#include <media/AudioResamplerPublic.h>
+#include <media/RecordBufferConverter.h>
#include <media/TypeConverter.h>
#include <utils/Log.h>
#include <utils/Trace.h>
@@ -6936,252 +6937,6 @@
buffer->frameCount = 0;
}
-AudioFlinger::RecordThread::RecordBufferConverter::RecordBufferConverter(
- audio_channel_mask_t srcChannelMask, audio_format_t srcFormat,
- uint32_t srcSampleRate,
- audio_channel_mask_t dstChannelMask, audio_format_t dstFormat,
- uint32_t dstSampleRate) :
- mSrcChannelMask(AUDIO_CHANNEL_INVALID), // updateParameters will set following vars
- // mSrcFormat
- // mSrcSampleRate
- // mDstChannelMask
- // mDstFormat
- // mDstSampleRate
- // mSrcChannelCount
- // mDstChannelCount
- // mDstFrameSize
- mBuf(NULL), mBufFrames(0), mBufFrameSize(0),
- mResampler(NULL),
- mIsLegacyDownmix(false),
- mIsLegacyUpmix(false),
- mRequiresFloat(false),
- mInputConverterProvider(NULL)
-{
- (void)updateParameters(srcChannelMask, srcFormat, srcSampleRate,
- dstChannelMask, dstFormat, dstSampleRate);
-}
-
-AudioFlinger::RecordThread::RecordBufferConverter::~RecordBufferConverter() {
- free(mBuf);
- delete mResampler;
- delete mInputConverterProvider;
-}
-
-size_t AudioFlinger::RecordThread::RecordBufferConverter::convert(void *dst,
- AudioBufferProvider *provider, size_t frames)
-{
- if (mInputConverterProvider != NULL) {
- mInputConverterProvider->setBufferProvider(provider);
- provider = mInputConverterProvider;
- }
-
- if (mResampler == NULL) {
- ALOGVV("NO RESAMPLING sampleRate:%u mSrcFormat:%#x mDstFormat:%#x",
- mSrcSampleRate, mSrcFormat, mDstFormat);
-
- AudioBufferProvider::Buffer buffer;
- for (size_t i = frames; i > 0; ) {
- buffer.frameCount = i;
- status_t status = provider->getNextBuffer(&buffer);
- if (status != OK || buffer.frameCount == 0) {
- frames -= i; // cannot fill request.
- break;
- }
- // format convert to destination buffer
- convertNoResampler(dst, buffer.raw, buffer.frameCount);
-
- dst = (int8_t*)dst + buffer.frameCount * mDstFrameSize;
- i -= buffer.frameCount;
- provider->releaseBuffer(&buffer);
- }
- } else {
- ALOGVV("RESAMPLING mSrcSampleRate:%u mDstSampleRate:%u mSrcFormat:%#x mDstFormat:%#x",
- mSrcSampleRate, mDstSampleRate, mSrcFormat, mDstFormat);
-
- // reallocate buffer if needed
- if (mBufFrameSize != 0 && mBufFrames < frames) {
- free(mBuf);
- mBufFrames = frames;
- (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize);
- }
- // resampler accumulates, but we only have one source track
- memset(mBuf, 0, frames * mBufFrameSize);
- frames = mResampler->resample((int32_t*)mBuf, frames, provider);
- // format convert to destination buffer
- convertResampler(dst, mBuf, frames);
- }
- return frames;
-}
-
-status_t AudioFlinger::RecordThread::RecordBufferConverter::updateParameters(
- audio_channel_mask_t srcChannelMask, audio_format_t srcFormat,
- uint32_t srcSampleRate,
- audio_channel_mask_t dstChannelMask, audio_format_t dstFormat,
- uint32_t dstSampleRate)
-{
- // quick evaluation if there is any change.
- if (mSrcFormat == srcFormat
- && mSrcChannelMask == srcChannelMask
- && mSrcSampleRate == srcSampleRate
- && mDstFormat == dstFormat
- && mDstChannelMask == dstChannelMask
- && mDstSampleRate == dstSampleRate) {
- return NO_ERROR;
- }
-
- ALOGV("RecordBufferConverter updateParameters srcMask:%#x dstMask:%#x"
- " srcFormat:%#x dstFormat:%#x srcRate:%u dstRate:%u",
- srcChannelMask, dstChannelMask, srcFormat, dstFormat, srcSampleRate, dstSampleRate);
- const bool valid =
- audio_is_input_channel(srcChannelMask)
- && audio_is_input_channel(dstChannelMask)
- && audio_is_valid_format(srcFormat) && audio_is_linear_pcm(srcFormat)
- && audio_is_valid_format(dstFormat) && audio_is_linear_pcm(dstFormat)
- && (srcSampleRate <= dstSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX)
- ; // no upsampling checks for now
- if (!valid) {
- return BAD_VALUE;
- }
-
- mSrcFormat = srcFormat;
- mSrcChannelMask = srcChannelMask;
- mSrcSampleRate = srcSampleRate;
- mDstFormat = dstFormat;
- mDstChannelMask = dstChannelMask;
- mDstSampleRate = dstSampleRate;
-
- // compute derived parameters
- mSrcChannelCount = audio_channel_count_from_in_mask(srcChannelMask);
- mDstChannelCount = audio_channel_count_from_in_mask(dstChannelMask);
- mDstFrameSize = mDstChannelCount * audio_bytes_per_sample(mDstFormat);
-
- // do we need to resample?
- delete mResampler;
- mResampler = NULL;
- if (mSrcSampleRate != mDstSampleRate) {
- mResampler = AudioResampler::create(AUDIO_FORMAT_PCM_FLOAT,
- mSrcChannelCount, mDstSampleRate);
- mResampler->setSampleRate(mSrcSampleRate);
- mResampler->setVolume(AudioMixer::UNITY_GAIN_FLOAT, AudioMixer::UNITY_GAIN_FLOAT);
- }
-
- // are we running legacy channel conversion modes?
- mIsLegacyDownmix = (mSrcChannelMask == AUDIO_CHANNEL_IN_STEREO
- || mSrcChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK)
- && mDstChannelMask == AUDIO_CHANNEL_IN_MONO;
- mIsLegacyUpmix = mSrcChannelMask == AUDIO_CHANNEL_IN_MONO
- && (mDstChannelMask == AUDIO_CHANNEL_IN_STEREO
- || mDstChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK);
-
- // do we need to process in float?
- mRequiresFloat = mResampler != NULL || mIsLegacyDownmix || mIsLegacyUpmix;
-
- // do we need a staging buffer to convert for destination (we can still optimize this)?
- // we use mBufFrameSize > 0 to indicate both frame size as well as buffer necessity
- if (mResampler != NULL) {
- mBufFrameSize = max(mSrcChannelCount, FCC_2)
- * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT);
- } else if (mIsLegacyUpmix || mIsLegacyDownmix) { // legacy modes always float
- mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT);
- } else if (mSrcChannelMask != mDstChannelMask && mDstFormat != mSrcFormat) {
- mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(mSrcFormat);
- } else {
- mBufFrameSize = 0;
- }
- mBufFrames = 0; // force the buffer to be resized.
-
- // do we need an input converter buffer provider to give us float?
- delete mInputConverterProvider;
- mInputConverterProvider = NULL;
- if (mRequiresFloat && mSrcFormat != AUDIO_FORMAT_PCM_FLOAT) {
- mInputConverterProvider = new ReformatBufferProvider(
- audio_channel_count_from_in_mask(mSrcChannelMask),
- mSrcFormat,
- AUDIO_FORMAT_PCM_FLOAT,
- 256 /* provider buffer frame count */);
- }
-
- // do we need a remixer to do channel mask conversion
- if (!mIsLegacyDownmix && !mIsLegacyUpmix && mSrcChannelMask != mDstChannelMask) {
- (void) memcpy_by_index_array_initialization_from_channel_mask(
- mIdxAry, ARRAY_SIZE(mIdxAry), mDstChannelMask, mSrcChannelMask);
- }
- return NO_ERROR;
-}
-
-void AudioFlinger::RecordThread::RecordBufferConverter::convertNoResampler(
- void *dst, const void *src, size_t frames)
-{
- // src is native type unless there is legacy upmix or downmix, whereupon it is float.
- if (mBufFrameSize != 0 && mBufFrames < frames) {
- free(mBuf);
- mBufFrames = frames;
- (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize);
- }
- // do we need to do legacy upmix and downmix?
- if (mIsLegacyUpmix || mIsLegacyDownmix) {
- void *dstBuf = mBuf != NULL ? mBuf : dst;
- if (mIsLegacyUpmix) {
- upmix_to_stereo_float_from_mono_float((float *)dstBuf,
- (const float *)src, frames);
- } else /*mIsLegacyDownmix */ {
- downmix_to_mono_float_from_stereo_float((float *)dstBuf,
- (const float *)src, frames);
- }
- if (mBuf != NULL) {
- memcpy_by_audio_format(dst, mDstFormat, mBuf, AUDIO_FORMAT_PCM_FLOAT,
- frames * mDstChannelCount);
- }
- return;
- }
- // do we need to do channel mask conversion?
- if (mSrcChannelMask != mDstChannelMask) {
- void *dstBuf = mBuf != NULL ? mBuf : dst;
- memcpy_by_index_array(dstBuf, mDstChannelCount,
- src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mSrcFormat), frames);
- if (dstBuf == dst) {
- return; // format is the same
- }
- }
- // convert to destination buffer
- const void *convertBuf = mBuf != NULL ? mBuf : src;
- memcpy_by_audio_format(dst, mDstFormat, convertBuf, mSrcFormat,
- frames * mDstChannelCount);
-}
-
-void AudioFlinger::RecordThread::RecordBufferConverter::convertResampler(
- void *dst, /*not-a-const*/ void *src, size_t frames)
-{
- // src buffer format is ALWAYS float when entering this routine
- if (mIsLegacyUpmix) {
- ; // mono to stereo already handled by resampler
- } else if (mIsLegacyDownmix
- || (mSrcChannelMask == mDstChannelMask && mSrcChannelCount == 1)) {
- // the resampler outputs stereo for mono input channel (a feature?)
- // must convert to mono
- downmix_to_mono_float_from_stereo_float((float *)src,
- (const float *)src, frames);
- } else if (mSrcChannelMask != mDstChannelMask) {
- // convert to mono channel again for channel mask conversion (could be skipped
- // with further optimization).
- if (mSrcChannelCount == 1) {
- downmix_to_mono_float_from_stereo_float((float *)src,
- (const float *)src, frames);
- }
- // convert to destination format (in place, OK as float is larger than other types)
- if (mDstFormat != AUDIO_FORMAT_PCM_FLOAT) {
- memcpy_by_audio_format(src, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT,
- frames * mSrcChannelCount);
- }
- // channel convert and save to dst
- memcpy_by_index_array(dst, mDstChannelCount,
- src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mDstFormat), frames);
- return;
- }
- // convert to destination format and save to dst
- memcpy_by_audio_format(dst, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT,
- frames * mDstChannelCount);
-}
bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValuePair,
status_t& status)
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index e43f001..3fb0b07 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1323,92 +1323,6 @@
// rolling counter that is never cleared
};
- /* The RecordBufferConverter is used for format, channel, and sample rate
- * conversion for a RecordTrack.
- *
- * TODO: Self contained, so move to a separate file later.
- *
- * RecordBufferConverter uses the convert() method rather than exposing a
- * buffer provider interface; this is to save a memory copy.
- */
- class RecordBufferConverter
- {
- public:
- RecordBufferConverter(
- audio_channel_mask_t srcChannelMask, audio_format_t srcFormat,
- uint32_t srcSampleRate,
- audio_channel_mask_t dstChannelMask, audio_format_t dstFormat,
- uint32_t dstSampleRate);
-
- ~RecordBufferConverter();
-
- /* Converts input data from an AudioBufferProvider by format, channelMask,
- * and sampleRate to a destination buffer.
- *
- * Parameters
- * dst: buffer to place the converted data.
- * provider: buffer provider to obtain source data.
- * frames: number of frames to convert
- *
- * Returns the number of frames converted.
- */
- size_t convert(void *dst, AudioBufferProvider *provider, size_t frames);
-
- // returns NO_ERROR if constructor was successful
- status_t initCheck() const {
- // mSrcChannelMask set on successful updateParameters
- return mSrcChannelMask != AUDIO_CHANNEL_INVALID ? NO_ERROR : NO_INIT;
- }
-
- // allows dynamic reconfigure of all parameters
- status_t updateParameters(
- audio_channel_mask_t srcChannelMask, audio_format_t srcFormat,
- uint32_t srcSampleRate,
- audio_channel_mask_t dstChannelMask, audio_format_t dstFormat,
- uint32_t dstSampleRate);
-
- // called to reset resampler buffers on record track discontinuity
- void reset() {
- if (mResampler != NULL) {
- mResampler->reset();
- }
- }
-
- private:
- // format conversion when not using resampler
- void convertNoResampler(void *dst, const void *src, size_t frames);
-
- // format conversion when using resampler; modifies src in-place
- void convertResampler(void *dst, /*not-a-const*/ void *src, size_t frames);
-
- // user provided information
- audio_channel_mask_t mSrcChannelMask;
- audio_format_t mSrcFormat;
- uint32_t mSrcSampleRate;
- audio_channel_mask_t mDstChannelMask;
- audio_format_t mDstFormat;
- uint32_t mDstSampleRate;
-
- // derived information
- uint32_t mSrcChannelCount;
- uint32_t mDstChannelCount;
- size_t mDstFrameSize;
-
- // format conversion buffer
- void *mBuf;
- size_t mBufFrames;
- size_t mBufFrameSize;
-
- // resampler info
- AudioResampler *mResampler;
-
- bool mIsLegacyDownmix; // legacy stereo to mono conversion needed
- bool mIsLegacyUpmix; // legacy mono to stereo conversion needed
- bool mRequiresFloat; // data processing requires float (e.g. resampler)
- PassthruBufferProvider *mInputConverterProvider; // converts input to float
- int8_t mIdxAry[sizeof(uint32_t) * 8]; // used for channel mask conversion
- };
-
#include "RecordTracks.h"
RecordThread(const sp<AudioFlinger>& audioFlinger,
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 48e09c7..f2dd884 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -32,6 +32,7 @@
#include <media/nbaio/Pipe.h>
#include <media/nbaio/PipeReader.h>
+#include <media/RecordBufferConverter.h>
#include <audio_utils/minifloat.h>
// ----------------------------------------------------------------------------
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
index 1d6787a..c2981a1 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -21,7 +21,7 @@
#include "AudioGain.h"
#include "TypeConverter.h"
-#include <android/log.h>
+#include <log/log.h>
#include <utils/String8.h>
namespace android {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
index f19b43c..dbdcca7 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
@@ -23,7 +23,7 @@
#include "AudioGain.h"
#include "TypeConverter.h"
-#include <android/log.h>
+#include <log/log.h>
#include <utils/String8.h>
namespace android {
diff --git a/services/mediacodec/minijail/minijail.cpp b/services/mediacodec/minijail/minijail.cpp
index 7926380..463f161 100644
--- a/services/mediacodec/minijail/minijail.cpp
+++ b/services/mediacodec/minijail/minijail.cpp
@@ -19,7 +19,8 @@
#include <unistd.h>
-#include <android/log.h>
+#include <log/log.h>
+
#include <libminijail.h>
#include "minijail.h"
diff --git a/services/mediaextractor/minijail/minijail.cpp b/services/mediaextractor/minijail/minijail.cpp
index 8291633..c44d00d 100644
--- a/services/mediaextractor/minijail/minijail.cpp
+++ b/services/mediaextractor/minijail/minijail.cpp
@@ -19,7 +19,8 @@
#include <unistd.h>
-#include <android/log.h>
+#include <log/log.h>
+
#include <libminijail.h>
#include "minijail.h"