Merge "Clean up Fence a little."
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/BufferingSettings.h b/include/media/BufferingSettings.h
index 7dd9d40..281a5c1 100644
--- a/include/media/BufferingSettings.h
+++ b/include/media/BufferingSettings.h
@@ -40,6 +40,8 @@
static const int kNoWatermark = -1;
static bool IsValidBufferingMode(int mode);
+ static bool IsTimeBasedBufferingMode(int mode);
+ static bool IsSizeBasedBufferingMode(int mode);
BufferingMode mInitialBufferingMode; // for prepare
BufferingMode mRebufferingMode; // for playback
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/PluginLoader.h b/include/media/PluginLoader.h
index 7d54ce4..360af2d 100644
--- a/include/media/PluginLoader.h
+++ b/include/media/PluginLoader.h
@@ -43,7 +43,7 @@
while ((pEntry = readdir(pDir))) {
String8 file(pEntry->d_name);
if (file.getPathExtension() == ".so") {
- String8 path = pluginDir + pEntry->d_name;
+ String8 path = pluginDir + "/" + pEntry->d_name;
T *plugin = loadOne(path, entry);
if (plugin) {
factories.push(plugin);
@@ -77,7 +77,8 @@
libraries.push(library);
return createFactoryFunc();
} else {
- ALOGE("Failed to create plugin factory from %s", path);
+ ALOGE("Failed to create plugin factory from %s at entry %s: %s",
+ path, entry, library->lastError());
}
}
return NULL;
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/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index fbb4a67..b460ef7 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -72,7 +72,6 @@
virtual ~MediaExtractor() {}
private:
- bool mIsDrm;
typedef bool (*SnifferFunc)(
const sp<DataSource> &source, String8 *mimeType,
diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h
index 8eff914..88a416a 100644
--- a/include/media/stagefright/Utils.h
+++ b/include/media/stagefright/Utils.h
@@ -23,6 +23,7 @@
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <system/audio.h>
+#include <media/BufferingSettings.h>
#include <media/MediaPlayerInterface.h>
namespace android {
@@ -90,6 +91,9 @@
void readFromAMessage(
const sp<AMessage> &msg, AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
+void writeToAMessage(const sp<AMessage> &msg, const BufferingSettings &buffering);
+void readFromAMessage(const sp<AMessage> &msg, BufferingSettings *buffering /* nonnull */);
+
AString nameForFd(int fd);
} // namespace android
diff --git a/media/libaudiohal/Android.mk b/media/libaudiohal/Android.mk
index deb26b5..58b38a6 100644
--- a/media/libaudiohal/Android.mk
+++ b/media/libaudiohal/Android.mk
@@ -9,9 +9,20 @@
liblog \
libutils
-ifeq ($(ENABLE_TREBLE), true)
+ifeq ($(USE_LEGACY_LOCAL_AUDIO_HAL), true)
-LOCAL_CFLAGS += -DENABLE_TREBLE
+# Use audiohal directly w/o hwbinder middleware.
+# This is for performance comparison and debugging only.
+
+LOCAL_SRC_FILES := \
+ DeviceHalLocal.cpp \
+ DevicesFactoryHalLocal.cpp \
+ EffectBufferHalLocal.cpp \
+ EffectHalLocal.cpp \
+ EffectsFactoryHalLocal.cpp \
+ StreamHalLocal.cpp
+
+else # if !USE_LEGACY_LOCAL_AUDIO_HAL
LOCAL_SRC_FILES := \
ConversionHelperHidl.cpp \
@@ -36,16 +47,7 @@
android.hidl.memory@1.0 \
libmedia_helper
-else # if !ENABLE_TREBLE
-
-LOCAL_SRC_FILES := \
- DeviceHalLocal.cpp \
- DevicesFactoryHalLocal.cpp \
- EffectBufferHalLocal.cpp \
- EffectHalLocal.cpp \
- EffectsFactoryHalLocal.cpp \
- StreamHalLocal.cpp
-endif # ENABLE_TREBLE
+endif # USE_LEGACY_LOCAL_AUDIO_HAL
LOCAL_MODULE := libaudiohal
diff --git a/media/libaudiohal/EffectHalHidl.cpp b/media/libaudiohal/EffectHalHidl.cpp
index f1f3f2a..3fb2f43 100644
--- a/media/libaudiohal/EffectHalHidl.cpp
+++ b/media/libaudiohal/EffectHalHidl.cpp
@@ -167,14 +167,16 @@
uint32_t *replySize, void *pReplyData) {
if (mEffect == 0) return NO_INIT;
hidl_vec<uint8_t> hidlData;
- hidlData.setToExternal(reinterpret_cast<uint8_t*>(pCmdData), cmdSize);
+ if (pCmdData != nullptr && cmdSize > 0) {
+ hidlData.setToExternal(reinterpret_cast<uint8_t*>(pCmdData), cmdSize);
+ }
status_t status;
Return<void> ret = mEffect->command(cmdCode, hidlData, *replySize,
[&](int32_t s, const hidl_vec<uint8_t>& result) {
status = s;
if (status == 0) {
if (*replySize > result.size()) *replySize = result.size();
- if (pReplyData && *replySize > 0) {
+ if (pReplyData != nullptr && *replySize > 0) {
memcpy(pReplyData, &result[0], *replySize);
}
}
diff --git a/media/libaudiohal/EffectHalLocal.cpp b/media/libaudiohal/EffectHalLocal.cpp
index b4f1934..dd465c3 100644
--- a/media/libaudiohal/EffectHalLocal.cpp
+++ b/media/libaudiohal/EffectHalLocal.cpp
@@ -45,11 +45,21 @@
}
status_t EffectHalLocal::process() {
+ if (mInBuffer == nullptr || mOutBuffer == nullptr) {
+ ALOGE_IF(mInBuffer == nullptr, "Input buffer not set");
+ ALOGE_IF(mOutBuffer == nullptr, "Output buffer not set");
+ return NO_INIT;
+ }
return (*mHandle)->process(mHandle, mInBuffer->audioBuffer(), mOutBuffer->audioBuffer());
}
status_t EffectHalLocal::processReverse() {
if ((*mHandle)->process_reverse != NULL) {
+ if (mInBuffer == nullptr || mOutBuffer == nullptr) {
+ ALOGE_IF(mInBuffer == nullptr, "Input buffer not set");
+ ALOGE_IF(mOutBuffer == nullptr, "Output buffer not set");
+ return NO_INIT;
+ }
return (*mHandle)->process_reverse(
mHandle, mInBuffer->audioBuffer(), mOutBuffer->audioBuffer());
} else {
diff --git a/media/libaudiohal/StreamHalHidl.cpp b/media/libaudiohal/StreamHalHidl.cpp
index 5943e22..cbc8a08 100644
--- a/media/libaudiohal/StreamHalHidl.cpp
+++ b/media/libaudiohal/StreamHalHidl.cpp
@@ -242,7 +242,7 @@
StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
: StreamHalHidl(stream.get()), mStream(stream), mEfGroup(nullptr),
- mGetPresentationPositionNotSupported(false), mPPosFromWriteObtained(0) {
+ mGetPresentationPositionNotSupported(false), mPPosFromWrite{ 0, OK, 0, { 0, 0 } } {
}
StreamOutHalHidl::~StreamOutHalHidl() {
@@ -301,19 +301,22 @@
status_t ret = mEfGroup->wait(
static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState, NS_PER_SEC);
if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
- WriteStatus writeStatus = { Result::NOT_INITIALIZED, 0, 0, { 0, 0 } };
+ WriteStatus writeStatus =
+ { Result::NOT_INITIALIZED, 0, Result::NOT_INITIALIZED, 0, { 0, 0 } };
mStatusMQ->read(&writeStatus);
- if (writeStatus.retval == Result::OK) {
+ if (writeStatus.writeRetval == Result::OK) {
status = OK;
*written = writeStatus.written;
- mPPosFromWriteFrames = writeStatus.frames;
- mPPosFromWriteTS.tv_sec = writeStatus.timeStamp.tvSec;
- mPPosFromWriteTS.tv_nsec = writeStatus.timeStamp.tvNSec;
- struct timespec timeNow;
- clock_gettime(CLOCK_MONOTONIC, &timeNow);
- mPPosFromWriteObtained = timeNow.tv_sec * 1000000 + timeNow.tv_nsec / 1000;
+ mPPosFromWrite.status = processReturn(
+ "get_presentation_position", writeStatus.presentationPositionRetval);
+ if (mPPosFromWrite.status == OK) {
+ mPPosFromWrite.frames = writeStatus.frames;
+ mPPosFromWrite.ts.tv_sec = writeStatus.timeStamp.tvSec;
+ mPPosFromWrite.ts.tv_nsec = writeStatus.timeStamp.tvNSec;
+ }
+ mPPosFromWrite.obtained = getCurrentTimeMs();
} else {
- status = processReturn("write", writeStatus.retval);
+ status = processReturn("write", writeStatus.writeRetval);
}
return status;
}
@@ -324,6 +327,12 @@
return ret;
}
+uint64_t StreamOutHalHidl::getCurrentTimeMs() {
+ struct timespec timeNow;
+ clock_gettime(CLOCK_MONOTONIC, &timeNow);
+ return timeNow.tv_sec * 1000000 + timeNow.tv_nsec / 1000;
+}
+
status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
std::unique_ptr<DataMQ> tempDataMQ;
std::unique_ptr<StatusMQ> tempStatusMQ;
@@ -435,15 +444,14 @@
status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
if (mStream == 0) return NO_INIT;
if (mGetPresentationPositionNotSupported) return INVALID_OPERATION;
- struct timespec timeNow;
- clock_gettime(CLOCK_MONOTONIC, &timeNow);
- uint64_t timeStampNow = timeNow.tv_sec * 1000000 + timeNow.tv_nsec / 1000;
- if (timeStampNow - mPPosFromWriteObtained <= 1000) {
+ if (getCurrentTimeMs() - mPPosFromWrite.obtained <= 1000) {
// No more than 1 ms passed since the last write, use cached result to avoid binder calls.
- *frames = mPPosFromWriteFrames;
- timestamp->tv_sec = mPPosFromWriteTS.tv_sec;
- timestamp->tv_nsec = mPPosFromWriteTS.tv_nsec;
- return OK;
+ if (mPPosFromWrite.status == OK) {
+ *frames = mPPosFromWrite.frames;
+ timestamp->tv_sec = mPPosFromWrite.ts.tv_sec;
+ timestamp->tv_nsec = mPPosFromWrite.ts.tv_nsec;
+ }
+ return mPPosFromWrite.status;
}
Result retval;
diff --git a/media/libaudiohal/StreamHalHidl.h b/media/libaudiohal/StreamHalHidl.h
index 0093957..8b5867e 100644
--- a/media/libaudiohal/StreamHalHidl.h
+++ b/media/libaudiohal/StreamHalHidl.h
@@ -164,15 +164,19 @@
std::unique_ptr<StatusMQ> mStatusMQ;
EventFlag* mEfGroup;
bool mGetPresentationPositionNotSupported;
- uint64_t mPPosFromWriteObtained;
- uint64_t mPPosFromWriteFrames;
- struct timespec mPPosFromWriteTS;
+ struct {
+ uint64_t obtained;
+ status_t status;
+ uint64_t frames;
+ struct timespec ts;
+ } mPPosFromWrite;
// Can not be constructed directly by clients.
StreamOutHalHidl(const sp<IStreamOut>& stream);
virtual ~StreamOutHalHidl();
+ uint64_t getCurrentTimeMs();
status_t prepareForWriting(size_t bufferSize);
};
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/BufferProviders.cpp b/media/libaudioprocessing/BufferProviders.cpp
index 11ec367..8341a1e 100644
--- a/media/libaudioprocessing/BufferProviders.cpp
+++ b/media/libaudioprocessing/BufferProviders.cpp
@@ -200,6 +200,8 @@
mEffectsFactory.clear();
return;
}
+ mDownmixInterface->setInBuffer(mInBuffer);
+ mDownmixInterface->setOutBuffer(mOutBuffer);
int cmdStatus;
uint32_t replySize = sizeof(int);
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/BufferingSettings.cpp b/media/libmedia/BufferingSettings.cpp
index 6dc4a53..5d6e03d 100644
--- a/media/libmedia/BufferingSettings.cpp
+++ b/media/libmedia/BufferingSettings.cpp
@@ -28,6 +28,16 @@
return (mode >= BUFFERING_MODE_NONE && mode < BUFFERING_MODE_COUNT);
}
+// static
+bool BufferingSettings::IsTimeBasedBufferingMode(int mode) {
+ return (mode == BUFFERING_MODE_TIME_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE);
+}
+
+// static
+bool BufferingSettings::IsSizeBasedBufferingMode(int mode) {
+ return (mode == BUFFERING_MODE_SIZE_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE);
+}
+
BufferingSettings::BufferingSettings()
: mInitialBufferingMode(BUFFERING_MODE_NONE),
mRebufferingMode(BUFFERING_MODE_NONE),
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..407a5bf 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -38,11 +38,12 @@
namespace android {
-static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
-static int64_t kHighWaterMarkUs = 5000000ll; // 5secs
-static int64_t kHighWaterMarkRebufferUs = 15000000ll; // 15secs
-static const ssize_t kLowWaterMarkBytes = 40000;
-static const ssize_t kHighWaterMarkBytes = 200000;
+static const int kLowWaterMarkMs = 2000; // 2secs
+static const int kHighWaterMarkMs = 5000; // 5secs
+static const int kHighWaterMarkRebufferMs = 15000; // 15secs
+
+static const int kLowWaterMarkKB = 40;
+static const int kHighWaterMarkKB = 200;
NuPlayer::GenericSource::GenericSource(
const sp<AMessage> ¬ify,
@@ -237,6 +238,16 @@
return OK;
}
+status_t NuPlayer::GenericSource::getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) {
+ mBufferingMonitor->getDefaultBufferingSettings(buffering);
+ return OK;
+}
+
+status_t NuPlayer::GenericSource::setBufferingSettings(const BufferingSettings& buffering) {
+ return mBufferingMonitor->setBufferingSettings(buffering);
+}
+
status_t NuPlayer::GenericSource::startSources() {
// Start the selected A/V tracks now before we start buffering.
// Widevine sources might re-initialize crypto when starting, if we delay
@@ -618,6 +629,12 @@
break;
}
+ case kWhatGetTrackInfo:
+ {
+ onGetTrackInfo(msg);
+ break;
+ }
+
case kWhatSelectTrack:
{
onSelectTrack(msg);
@@ -868,6 +885,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;
@@ -1435,11 +1480,48 @@
mFirstDequeuedBufferRealUs(-1ll),
mFirstDequeuedBufferMediaUs(-1ll),
mlastDequeuedBufferMediaUs(-1ll) {
+ getDefaultBufferingSettings(&mSettings);
}
NuPlayer::GenericSource::BufferingMonitor::~BufferingMonitor() {
}
+void NuPlayer::GenericSource::BufferingMonitor::getDefaultBufferingSettings(
+ BufferingSettings *buffering /* nonnull */) {
+ buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
+ buffering->mRebufferingMode = BUFFERING_MODE_TIME_THEN_SIZE;
+ buffering->mInitialWatermarkMs = kHighWaterMarkMs;
+ buffering->mRebufferingWatermarkLowMs = kLowWaterMarkMs;
+ buffering->mRebufferingWatermarkHighMs = kHighWaterMarkRebufferMs;
+ buffering->mRebufferingWatermarkLowKB = kLowWaterMarkKB;
+ buffering->mRebufferingWatermarkHighKB = kHighWaterMarkKB;
+}
+
+status_t NuPlayer::GenericSource::BufferingMonitor::setBufferingSettings(
+ const BufferingSettings &buffering) {
+ Mutex::Autolock _l(mLock);
+ if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
+ || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
+ && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)
+ || (buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
+ && buffering.mRebufferingWatermarkLowKB > buffering.mRebufferingWatermarkHighKB)) {
+ return BAD_VALUE;
+ }
+ mSettings = buffering;
+ if (mSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
+ mSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
+ }
+ if (!mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) {
+ mSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
+ mSettings.mRebufferingWatermarkHighMs = INT32_MAX;
+ }
+ if (!mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) {
+ mSettings.mRebufferingWatermarkLowKB = BufferingSettings::kNoWatermark;
+ mSettings.mRebufferingWatermarkHighKB = INT32_MAX;
+ }
+ return OK;
+}
+
void NuPlayer::GenericSource::BufferingMonitor::prepare(
const sp<NuCachedSource2> &cachedSource,
int64_t durationUs,
@@ -1668,7 +1750,9 @@
stopBufferingIfNecessary_l();
return;
- } else if (cachedDurationUs >= 0ll) {
+ }
+
+ if (cachedDurationUs >= 0ll) {
if (mDurationUs > 0ll) {
int64_t cachedPosUs = getLastReadPosition_l() + cachedDurationUs;
int percentage = 100.0 * cachedPosUs / mDurationUs;
@@ -1679,36 +1763,40 @@
notifyBufferingUpdate_l(percentage);
}
- ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec",
- cachedDurationUs / 1000000.0f);
+ ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
- if (cachedDurationUs < kLowWaterMarkUs) {
- // Take into account the data cached in downstream components to try to avoid
- // unnecessary pause.
- if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) {
- int64_t downStreamCacheUs = mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs
- - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs);
- if (downStreamCacheUs > 0) {
- cachedDurationUs += downStreamCacheUs;
+ if (mPrepareBuffering) {
+ if (cachedDurationUs > mSettings.mInitialWatermarkMs * 1000) {
+ stopBufferingIfNecessary_l();
+ }
+ } else if (mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) {
+ if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) {
+ // Take into account the data cached in downstream components to try to avoid
+ // unnecessary pause.
+ if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) {
+ int64_t downStreamCacheUs =
+ mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs
+ - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs);
+ if (downStreamCacheUs > 0) {
+ cachedDurationUs += downStreamCacheUs;
+ }
}
- }
- if (cachedDurationUs < kLowWaterMarkUs) {
- startBufferingIfNecessary_l();
- }
- } else {
- int64_t highWaterMark = mPrepareBuffering ? kHighWaterMarkUs : kHighWaterMarkRebufferUs;
- if (cachedDurationUs > highWaterMark) {
+ if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) {
+ startBufferingIfNecessary_l();
+ }
+ } else if (cachedDurationUs > mSettings.mRebufferingWatermarkHighMs * 1000) {
stopBufferingIfNecessary_l();
}
}
- } else if (cachedDataRemaining >= 0) {
+ } else if (cachedDataRemaining >= 0
+ && mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) {
ALOGV("onPollBuffering_l: cachedDataRemaining %zd bytes",
cachedDataRemaining);
- if (cachedDataRemaining < kLowWaterMarkBytes) {
+ if (cachedDataRemaining < (mSettings.mRebufferingWatermarkLowKB << 10)) {
startBufferingIfNecessary_l();
- } else if (cachedDataRemaining > kHighWaterMarkBytes) {
+ } else if (cachedDataRemaining > (mSettings.mRebufferingWatermarkHighKB << 10)) {
stopBufferingIfNecessary_l();
}
}
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index a14056f..e1949f3 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -50,6 +50,10 @@
status_t setDataSource(const sp<DataSource>& dataSource);
+ virtual status_t getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) override;
+ virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
+
virtual void prepareAsync();
virtual void start();
@@ -119,6 +123,9 @@
public:
explicit BufferingMonitor(const sp<AMessage> ¬ify);
+ void getDefaultBufferingSettings(BufferingSettings *buffering /* nonnull */);
+ status_t setBufferingSettings(const BufferingSettings &buffering);
+
// Set up state.
void prepare(const sp<NuCachedSource2> &cachedSource,
int64_t durationUs,
@@ -167,6 +174,7 @@
mutable Mutex mLock;
+ BufferingSettings mSettings;
bool mOffloadAudio;
int64_t mFirstDequeuedBufferRealUs;
int64_t mFirstDequeuedBufferMediaUs;
@@ -245,6 +253,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/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 51bfad4..05e6201 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -32,6 +32,11 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/Utils.h>
+// default buffer prepare/ready/underflow marks
+static const int kReadyMarkMs = 5000; // 5 seconds
+static const int kPrepareMarkMs = 1500; // 1.5 seconds
+static const int kUnderflowMarkMs = 1000; // 1 second
+
namespace android {
NuPlayer::HTTPLiveSource::HTTPLiveSource(
@@ -49,6 +54,7 @@
mFetchMetaDataGeneration(0),
mHasMetadata(false),
mMetadataSelected(false) {
+ getDefaultBufferingSettings(&mBufferingSettings);
if (headers) {
mExtraHeaders = *headers;
@@ -76,6 +82,42 @@
}
}
+status_t NuPlayer::HTTPLiveSource::getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) {
+ buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
+ buffering->mRebufferingMode = BUFFERING_MODE_TIME_ONLY;
+ buffering->mInitialWatermarkMs = kPrepareMarkMs;
+ buffering->mRebufferingWatermarkLowMs = kUnderflowMarkMs;
+ buffering->mRebufferingWatermarkHighMs = kReadyMarkMs;
+
+ return OK;
+}
+
+status_t NuPlayer::HTTPLiveSource::setBufferingSettings(const BufferingSettings& buffering) {
+ if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
+ || buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
+ || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
+ && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)) {
+ return BAD_VALUE;
+ }
+
+ mBufferingSettings = buffering;
+
+ if (mBufferingSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
+ mBufferingSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
+ }
+ if (mBufferingSettings.mRebufferingMode == BUFFERING_MODE_NONE) {
+ mBufferingSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
+ mBufferingSettings.mRebufferingWatermarkHighMs = INT32_MAX;
+ }
+
+ if (mLiveSession != NULL) {
+ mLiveSession->setBufferingSettings(mBufferingSettings);
+ }
+
+ return OK;
+}
+
void NuPlayer::HTTPLiveSource::prepareAsync() {
if (mLiveLooper == NULL) {
mLiveLooper = new ALooper;
@@ -94,6 +136,7 @@
mLiveLooper->registerHandler(mLiveSession);
+ mLiveSession->setBufferingSettings(mBufferingSettings);
mLiveSession->connectAsync(
mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
}
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 45fc8c1..2866a6a 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -34,6 +34,10 @@
const char *url,
const KeyedVector<String8, String8> *headers);
+ virtual status_t getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) override;
+ virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
+
virtual void prepareAsync();
virtual void start();
@@ -80,6 +84,7 @@
int32_t mFetchMetaDataGeneration;
bool mHasMetadata;
bool mMetadataSelected;
+ BufferingSettings mBufferingSettings;
void onSessionNotify(const sp<AMessage> &msg);
void pollForRawData(
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index d1ade1d..4c576a5 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -314,6 +314,31 @@
msg->post();
}
+status_t NuPlayer::getDefaultBufferingSettings(
+ BufferingSettings *buffering /* nonnull */) {
+ sp<AMessage> msg = new AMessage(kWhatGetDefaultBufferingSettings, this);
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ if (err == OK) {
+ readFromAMessage(response, buffering);
+ }
+ }
+ return err;
+}
+
+status_t NuPlayer::setBufferingSettings(const BufferingSettings& buffering) {
+ sp<AMessage> msg = new AMessage(kWhatSetBufferingSettings, this);
+ writeToAMessage(msg, buffering);
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ }
+ return err;
+}
+
void NuPlayer::prepareAsync() {
(new AMessage(kWhatPrepare, this))->post();
}
@@ -508,6 +533,48 @@
break;
}
+ case kWhatGetDefaultBufferingSettings:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ ALOGV("kWhatGetDefaultBufferingSettings");
+ BufferingSettings buffering;
+ status_t err = OK;
+ if (mSource != NULL) {
+ err = mSource->getDefaultBufferingSettings(&buffering);
+ } else {
+ err = INVALID_OPERATION;
+ }
+ sp<AMessage> response = new AMessage;
+ if (err == OK) {
+ writeToAMessage(response, buffering);
+ }
+ response->setInt32("err", err);
+ response->postReply(replyID);
+ break;
+ }
+
+ case kWhatSetBufferingSettings:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ ALOGV("kWhatSetBufferingSettings");
+ BufferingSettings buffering;
+ readFromAMessage(msg, &buffering);
+ status_t err = OK;
+ if (mSource != NULL) {
+ err = mSource->setBufferingSettings(buffering);
+ } else {
+ err = INVALID_OPERATION;
+ }
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+ response->postReply(replyID);
+ break;
+ }
+
case kWhatPrepare:
{
mSource->prepareAsync();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 6f737bb..cc8c97a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -50,6 +50,9 @@
void setDataSourceAsync(const sp<DataSource> &source);
+ status_t getDefaultBufferingSettings(BufferingSettings* buffering /* nonnull */);
+ status_t setBufferingSettings(const BufferingSettings& buffering);
+
void prepareAsync();
void setVideoSurfaceTextureAsync(
@@ -137,6 +140,8 @@
kWhatGetTrackInfo = 'gTrI',
kWhatGetSelectedTrack = 'gSel',
kWhatSelectTrack = 'selT',
+ kWhatGetDefaultBufferingSettings = 'gDBS',
+ kWhatSetBufferingSettings = 'sBuS',
};
wp<NuPlayerDriver> mDriver;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index f7e56e4..b8bb8fe 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -204,6 +204,26 @@
return OK;
}
+status_t NuPlayerDriver::getDefaultBufferingSettings(BufferingSettings* buffering) {
+ ALOGV("getDefaultBufferingSettings(%p)", this);
+ Mutex::Autolock autoLock(mLock);
+ if (mState == STATE_IDLE) {
+ return INVALID_OPERATION;
+ }
+
+ return mPlayer->getDefaultBufferingSettings(buffering);
+}
+
+status_t NuPlayerDriver::setBufferingSettings(const BufferingSettings& buffering) {
+ ALOGV("setBufferingSettings(%p)", this);
+ Mutex::Autolock autoLock(mLock);
+ if (mState == STATE_IDLE) {
+ return INVALID_OPERATION;
+ }
+
+ return mPlayer->setBufferingSettings(buffering);
+}
+
status_t NuPlayerDriver::prepare() {
ALOGV("prepare(%p)", this);
Mutex::Autolock autoLock(mLock);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 9b784ae..5bfc539 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -44,6 +44,11 @@
virtual status_t setVideoSurfaceTexture(
const sp<IGraphicBufferProducer> &bufferProducer);
+
+ virtual status_t getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) override;
+ virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
+
virtual status_t prepare();
virtual status_t prepareAsync();
virtual status_t start();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 6006730..0429ef1 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -63,6 +63,10 @@
: mNotify(notify) {
}
+ virtual status_t getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) = 0;
+ virtual status_t setBufferingSettings(const BufferingSettings& buffering) = 0;
+
virtual void prepareAsync() = 0;
virtual void start() = 0;
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index fb1f31a..9264e49 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -32,11 +32,11 @@
const int64_t kNearEOSTimeoutUs = 2000000ll; // 2 secs
-// Buffer Underflow/Prepare/StartServer/Overflow Marks
-const int64_t NuPlayer::RTSPSource::kUnderflowMarkUs = 1000000ll;
-const int64_t NuPlayer::RTSPSource::kPrepareMarkUs = 3000000ll;
-const int64_t NuPlayer::RTSPSource::kStartServerMarkUs = 5000000ll;
-const int64_t NuPlayer::RTSPSource::kOverflowMarkUs = 10000000ll;
+// Default Buffer Underflow/Prepare/StartServer/Overflow Marks
+static const int kUnderflowMarkMs = 1000; // 1 second
+static const int kPrepareMarkMs = 3000; // 3 seconds
+//static const int kStartServerMarkMs = 5000;
+static const int kOverflowMarkMs = 10000; // 10 seconds
NuPlayer::RTSPSource::RTSPSource(
const sp<AMessage> ¬ify,
@@ -62,6 +62,7 @@
mSeekGeneration(0),
mEOSTimeoutAudio(0),
mEOSTimeoutVideo(0) {
+ getDefaultBufferingSettings(&mBufferingSettings);
if (headers) {
mExtraHeaders = *headers;
@@ -83,6 +84,34 @@
}
}
+status_t NuPlayer::RTSPSource::getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) {
+ buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
+ buffering->mRebufferingMode = BUFFERING_MODE_TIME_ONLY;
+ buffering->mInitialWatermarkMs = kPrepareMarkMs;
+ buffering->mRebufferingWatermarkLowMs = kUnderflowMarkMs;
+ buffering->mRebufferingWatermarkHighMs = kOverflowMarkMs;
+
+ return OK;
+}
+
+status_t NuPlayer::RTSPSource::setBufferingSettings(const BufferingSettings& buffering) {
+ if (mLooper == NULL) {
+ mBufferingSettings = buffering;
+ return OK;
+ }
+
+ sp<AMessage> msg = new AMessage(kWhatSetBufferingSettings, this);
+ writeToAMessage(msg, buffering);
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ }
+
+ return err;
+}
+
void NuPlayer::RTSPSource::prepareAsync() {
if (mIsSDP && mHTTPService == NULL) {
notifyPrepared(BAD_VALUE);
@@ -328,7 +357,8 @@
int64_t bufferedDurationUs = src->getBufferedDurationUs(&finalResult);
// isFinished when duration is 0 checks for EOS result only
- if (bufferedDurationUs > kPrepareMarkUs || src->isFinished(/* duration */ 0)) {
+ if (bufferedDurationUs > mBufferingSettings.mInitialWatermarkMs * 1000
+ || src->isFinished(/* duration */ 0)) {
++preparedCount;
}
@@ -336,13 +366,16 @@
++overflowCount;
++finishedCount;
} else {
- if (bufferedDurationUs < kUnderflowMarkUs) {
+ if (bufferedDurationUs < mBufferingSettings.mRebufferingWatermarkLowMs * 1000) {
++underflowCount;
}
- if (bufferedDurationUs > kOverflowMarkUs) {
+ if (bufferedDurationUs > mBufferingSettings.mRebufferingWatermarkHighMs * 1000) {
++overflowCount;
}
- if (bufferedDurationUs < kStartServerMarkUs) {
+ int64_t startServerMarkUs =
+ (mBufferingSettings.mRebufferingWatermarkLowMs
+ + mBufferingSettings.mRebufferingWatermarkHighMs) / 2 * 1000ll;
+ if (bufferedDurationUs < startServerMarkUs) {
++startCount;
}
}
@@ -479,6 +512,36 @@
} else if (msg->what() == kWhatSignalEOS) {
onSignalEOS(msg);
return;
+ } else if (msg->what() == kWhatSetBufferingSettings) {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ BufferingSettings buffering;
+ readFromAMessage(msg, &buffering);
+
+ status_t err = OK;
+ if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
+ || buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
+ || (buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs
+ && buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode))) {
+ err = BAD_VALUE;
+ } else {
+ if (buffering.mInitialBufferingMode == BUFFERING_MODE_NONE) {
+ buffering.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
+ }
+ if (buffering.mRebufferingMode == BUFFERING_MODE_NONE) {
+ buffering.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
+ buffering.mRebufferingWatermarkHighMs = INT32_MAX;
+ }
+
+ mBufferingSettings = buffering;
+ }
+
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+ response->postReply(replyID);
+
+ return;
}
CHECK_EQ(msg->what(), (int)kWhatNotify);
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index 363f8bb..0812991 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -40,6 +40,10 @@
uid_t uid = 0,
bool isSDP = false);
+ virtual status_t getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) override;
+ virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
+
virtual void prepareAsync();
virtual void start();
virtual void stop();
@@ -67,6 +71,7 @@
kWhatPerformSeek = 'seek',
kWhatPollBuffering = 'poll',
kWhatSignalEOS = 'eos ',
+ kWhatSetBufferingSettings = 'sBuS',
};
enum State {
@@ -81,12 +86,6 @@
kFlagIncognito = 1,
};
- // Buffer Prepare/Underflow/Overflow/Resume Marks
- static const int64_t kPrepareMarkUs;
- static const int64_t kUnderflowMarkUs;
- static const int64_t kOverflowMarkUs;
- static const int64_t kStartServerMarkUs;
-
struct TrackInfo {
sp<AnotherPacketSource> mSource;
@@ -110,6 +109,7 @@
bool mBuffering;
bool mInPreparationPhase;
bool mEOSPending;
+ BufferingSettings mBufferingSettings;
sp<ALooper> mLooper;
sp<MyHandler> mHandler;
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index d6b1e8c..fc0803b 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -51,6 +51,22 @@
}
}
+status_t NuPlayer::StreamingSource::getDefaultBufferingSettings(
+ BufferingSettings *buffering /* nonnull */) {
+ *buffering = BufferingSettings();
+ return OK;
+}
+
+status_t NuPlayer::StreamingSource::setBufferingSettings(
+ const BufferingSettings &buffering) {
+ if (buffering.mInitialBufferingMode != BUFFERING_MODE_NONE
+ || buffering.mRebufferingMode != BUFFERING_MODE_NONE) {
+ return BAD_VALUE;
+ }
+
+ return OK;
+}
+
void NuPlayer::StreamingSource::prepareAsync() {
if (mLooper == NULL) {
mLooper = new ALooper;
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.h b/media/libmediaplayerservice/nuplayer/StreamingSource.h
index db88c7f..2e1d2b3 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.h
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.h
@@ -32,6 +32,10 @@
const sp<AMessage> ¬ify,
const sp<IStreamSource> &source);
+ virtual status_t getDefaultBufferingSettings(
+ BufferingSettings* buffering /* nonnull */) override;
+ virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
+
virtual void prepareAsync();
virtual void start();
diff --git a/media/liboboe/src/binding/AudioEndpointParcelable.h b/media/liboboe/src/binding/AudioEndpointParcelable.h
new file mode 100644
index 0000000..6bdd8a4
--- /dev/null
+++ b/media/liboboe/src/binding/AudioEndpointParcelable.h
@@ -0,0 +1,76 @@
+/*
+ * 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 BINDING_AUDIOENDPOINTPARCELABLE_H
+#define BINDING_AUDIOENDPOINTPARCELABLE_H
+
+#include <stdint.h>
+
+//#include <sys/mman.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include "binding/OboeServiceDefinitions.h"
+#include "binding/RingBufferParcelable.h"
+
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+namespace oboe {
+
+/**
+ * Container for information about the message queues plus
+ * general stream information needed by Oboe clients.
+ * It contains no addresses, just sizes, offsets and file descriptors for
+ * shared memory that can be passed through Binder.
+ */
+class AudioEndpointParcelable : public Parcelable {
+public:
+ AudioEndpointParcelable();
+ virtual ~AudioEndpointParcelable();
+
+ /**
+ * Add the file descriptor to the table.
+ * @return index in table or negative error
+ */
+ int32_t addFileDescriptor(int fd, int32_t sizeInBytes);
+
+ virtual status_t writeToParcel(Parcel* parcel) const override;
+
+ virtual status_t readFromParcel(const Parcel* parcel) override;
+
+ oboe_result_t resolve(EndpointDescriptor *descriptor);
+
+ oboe_result_t validate();
+
+ void dump();
+
+public: // TODO add getters
+ // Set capacityInFrames to zero if Queue is unused.
+ RingBufferParcelable mUpMessageQueueParcelable; // server to client
+ RingBufferParcelable mDownMessageQueueParcelable; // to server
+ RingBufferParcelable mUpDataQueueParcelable; // eg. record, could share same queue
+ RingBufferParcelable mDownDataQueueParcelable; // eg. playback
+
+private:
+ int32_t mNumSharedMemories = 0;
+ SharedMemoryParcelable mSharedMemories[MAX_SHARED_MEMORIES];
+};
+
+} /* namespace oboe */
+
+#endif //BINDING_AUDIOENDPOINTPARCELABLE_H
diff --git a/media/liboboe/src/binding/IOboeAudioService.h b/media/liboboe/src/binding/IOboeAudioService.h
new file mode 100644
index 0000000..4b4c99c
--- /dev/null
+++ b/media/liboboe/src/binding/IOboeAudioService.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 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 BINDING_IOBOEAUDIOSERVICE_H
+#define BINDING_IOBOEAUDIOSERVICE_H
+
+#include <stdint.h>
+#include <utils/RefBase.h>
+#include <binder/TextOutput.h>
+#include <binder/IInterface.h>
+
+#include <oboe/OboeAudio.h>
+
+#include "binding/OboeServiceDefinitions.h"
+#include "binding/AudioEndpointParcelable.h"
+#include "binding/OboeStreamRequest.h"
+#include "binding/OboeStreamConfiguration.h"
+
+//using android::status_t;
+//using android::IInterface;
+//using android::BnInterface;
+
+using oboe::AudioEndpointParcelable;
+using oboe::OboeStreamRequest;
+using oboe::OboeStreamConfiguration;
+
+namespace android {
+
+// Interface (our AIDL) - Shared by server and client
+class IOboeAudioService : public IInterface {
+public:
+
+ DECLARE_META_INTERFACE(OboeAudioService);
+
+ virtual oboe_handle_t openStream(OboeStreamRequest &request,
+ OboeStreamConfiguration &configuration) = 0;
+
+ virtual oboe_result_t closeStream(int32_t streamHandle) = 0;
+
+ /* Get an immutable description of the in-memory queues
+ * used to communicate with the underlying HAL or Service.
+ */
+ virtual oboe_result_t getStreamDescription(oboe_handle_t streamHandle,
+ AudioEndpointParcelable &parcelable) = 0;
+
+ /**
+ * Start the flow of data.
+ */
+ virtual oboe_result_t startStream(oboe_handle_t streamHandle) = 0;
+
+ /**
+ * Stop the flow of data such that start() can resume without loss of data.
+ */
+ virtual oboe_result_t pauseStream(oboe_handle_t streamHandle) = 0;
+
+ /**
+ * Discard any data held by the underlying HAL or Service.
+ */
+ virtual oboe_result_t flushStream(oboe_handle_t streamHandle) = 0;
+
+ /**
+ * Manage the specified thread as a low latency audio thread.
+ */
+ virtual oboe_result_t registerAudioThread(oboe_handle_t streamHandle, pid_t clientThreadId,
+ oboe_nanoseconds_t periodNanoseconds) = 0;
+
+ virtual oboe_result_t unregisterAudioThread(oboe_handle_t streamHandle,
+ pid_t clientThreadId) = 0;
+
+ /**
+ * Poke server instead of running a background thread.
+ * Cooperative multi-tasking for early development only.
+ * TODO remove tickle() when service has its own thread.
+ */
+ virtual void tickle() { };
+
+};
+
+class BnOboeAudioService : public BnInterface<IOboeAudioService> {
+public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags = 0);
+
+};
+
+} /* namespace android */
+
+#endif //BINDING_IOBOEAUDIOSERVICE_H
diff --git a/media/liboboe/src/binding/OboeServiceDefinitions.h b/media/liboboe/src/binding/OboeServiceDefinitions.h
new file mode 100644
index 0000000..958f7a7
--- /dev/null
+++ b/media/liboboe/src/binding/OboeServiceDefinitions.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 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 BINDING_OBOESERVICEDEFINITIONS_H
+#define BINDING_OBOESERVICEDEFINITIONS_H
+
+#include <stdint.h>
+#include <utils/RefBase.h>
+#include <binder/TextOutput.h>
+#include <binder/IInterface.h>
+
+#include <oboe/OboeAudio.h>
+
+using android::NO_ERROR;
+using android::IBinder;
+
+namespace oboe {
+
+enum oboe_commands_t {
+ OPEN_STREAM = IBinder::FIRST_CALL_TRANSACTION,
+ CLOSE_STREAM,
+ GET_STREAM_DESCRIPTION,
+ START_STREAM,
+ PAUSE_STREAM,
+ FLUSH_STREAM,
+ REGISTER_AUDIO_THREAD,
+ UNREGISTER_AUDIO_THREAD,
+ TICKLE
+};
+
+// TODO Expand this to include all the open parameters.
+typedef struct OboeServiceStreamInfo_s {
+ int32_t deviceId;
+ int32_t samplesPerFrame; // number of channels
+ oboe_sample_rate_t sampleRate;
+ oboe_audio_format_t audioFormat;
+} OboeServiceStreamInfo;
+
+// This must be a fixed width so it can be in shared memory.
+enum RingbufferFlags : uint32_t {
+ NONE = 0,
+ RATE_ISOCHRONOUS = 0x0001,
+ RATE_ASYNCHRONOUS = 0x0002,
+ COHERENCY_DMA = 0x0004,
+ COHERENCY_ACQUIRE_RELEASE = 0x0008,
+ COHERENCY_AUTO = 0x0010,
+};
+
+// This is not passed through Binder.
+// Client side code will convert Binder data and fill this descriptor.
+typedef struct RingBufferDescriptor_s {
+ uint8_t* dataAddress; // offset from read or write block
+ int64_t* writeCounterAddress;
+ int64_t* readCounterAddress;
+ int32_t bytesPerFrame; // index is in frames
+ int32_t framesPerBurst; // for ISOCHRONOUS queues
+ int32_t capacityInFrames; // zero if unused
+ RingbufferFlags flags;
+} RingBufferDescriptor;
+
+// This is not passed through Binder.
+// Client side code will convert Binder data and fill this descriptor.
+typedef struct EndpointDescriptor_s {
+ // Set capacityInFrames to zero if Queue is unused.
+ RingBufferDescriptor upMessageQueueDescriptor; // server to client
+ RingBufferDescriptor downMessageQueueDescriptor; // client to server
+ RingBufferDescriptor upDataQueueDescriptor; // eg. record
+ RingBufferDescriptor downDataQueueDescriptor; // eg. playback
+} EndpointDescriptor;
+
+} // namespace oboe
+
+#endif //BINDING_OBOESERVICEDEFINITIONS_H
diff --git a/media/liboboe/src/binding/OboeStreamConfiguration.h b/media/liboboe/src/binding/OboeStreamConfiguration.h
new file mode 100644
index 0000000..6bc1924
--- /dev/null
+++ b/media/liboboe/src/binding/OboeStreamConfiguration.h
@@ -0,0 +1,86 @@
+/*
+ * 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 BINDING_OBOE_STREAM_CONFIGURATION_H
+#define BINDING_OBOE_STREAM_CONFIGURATION_H
+
+#include <stdint.h>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <oboe/OboeDefinitions.h>
+
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+namespace oboe {
+
+class OboeStreamConfiguration : public Parcelable {
+public:
+ OboeStreamConfiguration();
+ virtual ~OboeStreamConfiguration();
+
+ oboe_device_id_t getDeviceId() const {
+ return mDeviceId;
+ }
+
+ void setDeviceId(oboe_device_id_t deviceId) {
+ mDeviceId = deviceId;
+ }
+
+ oboe_sample_rate_t getSampleRate() const {
+ return mSampleRate;
+ }
+
+ void setSampleRate(oboe_sample_rate_t sampleRate) {
+ mSampleRate = sampleRate;
+ }
+
+ int32_t getSamplesPerFrame() const {
+ return mSamplesPerFrame;
+ }
+
+ void setSamplesPerFrame(int32_t samplesPerFrame) {
+ mSamplesPerFrame = samplesPerFrame;
+ }
+
+ oboe_audio_format_t getAudioFormat() const {
+ return mAudioFormat;
+ }
+
+ void setAudioFormat(oboe_audio_format_t audioFormat) {
+ mAudioFormat = audioFormat;
+ }
+
+ virtual status_t writeToParcel(Parcel* parcel) const override;
+
+ virtual status_t readFromParcel(const Parcel* parcel) override;
+
+ oboe_result_t validate();
+
+ void dump();
+
+protected:
+ oboe_device_id_t mDeviceId = OBOE_DEVICE_UNSPECIFIED;
+ oboe_sample_rate_t mSampleRate = OBOE_UNSPECIFIED;
+ int32_t mSamplesPerFrame = OBOE_UNSPECIFIED;
+ oboe_audio_format_t mAudioFormat = OBOE_AUDIO_FORMAT_UNSPECIFIED;
+};
+
+} /* namespace oboe */
+
+#endif //BINDING_OBOE_STREAM_CONFIGURATION_H
diff --git a/media/liboboe/src/binding/OboeStreamRequest.h b/media/liboboe/src/binding/OboeStreamRequest.h
new file mode 100644
index 0000000..aab3c97
--- /dev/null
+++ b/media/liboboe/src/binding/OboeStreamRequest.h
@@ -0,0 +1,75 @@
+/*
+ * 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 BINDING_OBOE_STREAM_REQUEST_H
+#define BINDING_OBOE_STREAM_REQUEST_H
+
+#include <stdint.h>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <oboe/OboeDefinitions.h>
+
+#include "binding/OboeStreamConfiguration.h"
+
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+namespace oboe {
+
+class OboeStreamRequest : public Parcelable {
+public:
+ OboeStreamRequest();
+ virtual ~OboeStreamRequest();
+
+ uid_t getUserId() const {
+ return mUserId;
+ }
+
+ void setUserId(uid_t userId) {
+ mUserId = userId;
+ }
+
+ pid_t getProcessId() const {
+ return mProcessId;
+ }
+
+ void setProcessId(pid_t processId) {
+ mProcessId = processId;
+ }
+
+ OboeStreamConfiguration &getConfiguration() {
+ return mConfiguration;
+ }
+
+ virtual status_t writeToParcel(Parcel* parcel) const override;
+
+ virtual status_t readFromParcel(const Parcel* parcel) override;
+
+ oboe_result_t validate();
+
+ void dump();
+
+protected:
+ OboeStreamConfiguration mConfiguration;
+ uid_t mUserId;
+ pid_t mProcessId;
+};
+
+} /* namespace oboe */
+
+#endif //BINDING_OBOE_STREAM_REQUEST_H
diff --git a/media/liboboe/src/binding/RingBufferParcelable.h b/media/liboboe/src/binding/RingBufferParcelable.h
new file mode 100644
index 0000000..9bb695a
--- /dev/null
+++ b/media/liboboe/src/binding/RingBufferParcelable.h
@@ -0,0 +1,83 @@
+/*
+ * 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 BINDING_RINGBUFFER_PARCELABLE_H
+#define BINDING_RINGBUFFER_PARCELABLE_H
+
+#include <stdint.h>
+
+#include <binder/Parcelable.h>
+
+#include "binding/OboeServiceDefinitions.h"
+#include "binding/SharedRegionParcelable.h"
+
+namespace oboe {
+
+class RingBufferParcelable : public Parcelable {
+public:
+ RingBufferParcelable();
+ virtual ~RingBufferParcelable();
+
+ // TODO This assumes that all three use the same SharedMemoryParcelable
+ void setupMemory(int32_t sharedMemoryIndex,
+ int32_t dataMemoryOffset,
+ int32_t dataSizeInBytes,
+ int32_t readCounterOffset,
+ int32_t writeCounterOffset,
+ int32_t counterSizeBytes);
+
+ void setupMemory(int32_t sharedMemoryIndex,
+ int32_t dataMemoryOffset,
+ int32_t dataSizeInBytes);
+
+ int32_t getBytesPerFrame();
+
+ void setBytesPerFrame(int32_t bytesPerFrame);
+
+ int32_t getFramesPerBurst();
+
+ void setFramesPerBurst(int32_t framesPerBurst);
+
+ int32_t getCapacityInFrames();
+
+ void setCapacityInFrames(int32_t capacityInFrames);
+
+ /**
+ * The read and write must be symmetric.
+ */
+ virtual status_t writeToParcel(Parcel* parcel) const override;
+
+ virtual status_t readFromParcel(const Parcel* parcel) override;
+
+ oboe_result_t resolve(SharedMemoryParcelable *memoryParcels, RingBufferDescriptor *descriptor);
+
+ oboe_result_t validate();
+
+ void dump();
+
+private:
+ SharedRegionParcelable mReadCounterParcelable;
+ SharedRegionParcelable mWriteCounterParcelable;
+ SharedRegionParcelable mDataParcelable;
+ int32_t mBytesPerFrame = 0; // index is in frames
+ int32_t mFramesPerBurst = 0; // for ISOCHRONOUS queues
+ int32_t mCapacityInFrames = 0; // zero if unused
+ RingbufferFlags mFlags = RingbufferFlags::NONE;
+};
+
+} /* namespace oboe */
+
+#endif //BINDING_RINGBUFFER_PARCELABLE_H
diff --git a/media/liboboe/src/binding/SharedMemoryParcelable.h b/media/liboboe/src/binding/SharedMemoryParcelable.h
new file mode 100644
index 0000000..9585779
--- /dev/null
+++ b/media/liboboe/src/binding/SharedMemoryParcelable.h
@@ -0,0 +1,68 @@
+/*
+ * 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 BINDING_SHAREDMEMORYPARCELABLE_H
+#define BINDING_SHAREDMEMORYPARCELABLE_H
+
+#include <stdint.h>
+
+#include <sys/mman.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+namespace oboe {
+
+// Arbitrary limits for sanity checks. TODO remove after debugging.
+#define MAX_SHARED_MEMORIES (32)
+#define MAX_MMAP_OFFSET (32 * 1024)
+#define MAX_MMAP_SIZE (32 * 1024)
+
+/**
+ * This is a parcelable description of a shared memory referenced by a file descriptor.
+ * It may be divided into several regions.
+ */
+class SharedMemoryParcelable : public Parcelable {
+public:
+ SharedMemoryParcelable();
+ virtual ~SharedMemoryParcelable();
+
+ void setup(int fd, int32_t sizeInBytes);
+
+ virtual status_t writeToParcel(Parcel* parcel) const override;
+
+ virtual status_t readFromParcel(const Parcel* parcel) override;
+
+ oboe_result_t resolve(int32_t offsetInBytes, int32_t sizeInBytes, void **regionAddressPtr);
+
+ int32_t getSizeInBytes();
+
+ oboe_result_t validate();
+
+ void dump();
+
+protected:
+ int mFd = -1;
+ int32_t mSizeInBytes = 0;
+ uint8_t *mResolvedAddress = nullptr;
+};
+
+} /* namespace oboe */
+
+#endif //BINDING_SHAREDMEMORYPARCELABLE_H
diff --git a/media/liboboe/src/binding/SharedRegionParcelable.h b/media/liboboe/src/binding/SharedRegionParcelable.h
new file mode 100644
index 0000000..bccdaa8
--- /dev/null
+++ b/media/liboboe/src/binding/SharedRegionParcelable.h
@@ -0,0 +1,60 @@
+/*
+ * 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 BINDING_SHAREDREGIONPARCELABLE_H
+#define BINDING_SHAREDREGIONPARCELABLE_H
+
+#include <stdint.h>
+
+#include <sys/mman.h>
+#include <binder/Parcelable.h>
+
+#include <oboe/OboeDefinitions.h>
+
+#include "binding/SharedMemoryParcelable.h"
+
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+namespace oboe {
+
+class SharedRegionParcelable : public Parcelable {
+public:
+ SharedRegionParcelable();
+ virtual ~SharedRegionParcelable();
+
+ void setup(int32_t sharedMemoryIndex, int32_t offsetInBytes, int32_t sizeInBytes);
+
+ virtual status_t writeToParcel(Parcel* parcel) const override;
+
+ virtual status_t readFromParcel(const Parcel* parcel) override;
+
+ oboe_result_t resolve(SharedMemoryParcelable *memoryParcels, void **regionAddressPtr);
+
+ oboe_result_t validate();
+
+ void dump();
+
+protected:
+ int32_t mSharedMemoryIndex = -1;
+ int32_t mOffsetInBytes = 0;
+ int32_t mSizeInBytes = 0;
+};
+
+} /* namespace oboe */
+
+#endif //BINDING_SHAREDREGIONPARCELABLE_H
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/Android.mk b/media/libstagefright/Android.mk
index f3d622b..25dd6b1 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -18,7 +18,6 @@
DataConverter.cpp \
DataSource.cpp \
DataURISource.cpp \
- DRMExtractor.cpp \
ESDS.cpp \
FileSource.cpp \
FLACExtractor.cpp \
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
deleted file mode 100644
index 8ba36d5..0000000
--- a/media/libstagefright/DRMExtractor.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2010 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 "include/DRMExtractor.h"
-
-#include <arpa/inet.h>
-#include <utils/String8.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaBuffer.h>
-
-#include <drm/drm_framework_common.h>
-#include <utils/Errors.h>
-
-
-namespace android {
-
-class DRMSource : public MediaSource {
-public:
- DRMSource(const sp<IMediaSource> &mediaSource,
- const sp<DecryptHandle> &decryptHandle,
- DrmManagerClient *managerClient,
- int32_t trackId, DrmBuffer *ipmpBox);
-
- virtual status_t start(MetaData *params = NULL);
- virtual status_t stop();
- virtual sp<MetaData> getFormat();
- virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
-
-protected:
- virtual ~DRMSource();
-
-private:
- sp<IMediaSource> mOriginalMediaSource;
- sp<DecryptHandle> mDecryptHandle;
- DrmManagerClient* mDrmManagerClient;
- size_t mTrackId;
- mutable Mutex mDRMLock;
- size_t mNALLengthSize;
- bool mWantsNALFragments;
-
- DRMSource(const DRMSource &);
- DRMSource &operator=(const DRMSource &);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-DRMSource::DRMSource(const sp<IMediaSource> &mediaSource,
- const sp<DecryptHandle> &decryptHandle,
- DrmManagerClient *managerClient,
- int32_t trackId, DrmBuffer *ipmpBox)
- : mOriginalMediaSource(mediaSource),
- mDecryptHandle(decryptHandle),
- mDrmManagerClient(managerClient),
- mTrackId(trackId),
- mNALLengthSize(0),
- mWantsNALFragments(false) {
- CHECK(mDrmManagerClient);
- mDrmManagerClient->initializeDecryptUnit(
- mDecryptHandle, trackId, ipmpBox);
-
- const char *mime;
- bool success = getFormat()->findCString(kKeyMIMEType, &mime);
- CHECK(success);
-
- if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
- uint32_t type;
- const void *data;
- size_t size;
- CHECK(getFormat()->findData(kKeyAVCC, &type, &data, &size));
-
- const uint8_t *ptr = (const uint8_t *)data;
-
- CHECK(size >= 7);
- CHECK_EQ(ptr[0], 1); // configurationVersion == 1
-
- // The number of bytes used to encode the length of a NAL unit.
- mNALLengthSize = 1 + (ptr[4] & 3);
- }
-}
-
-DRMSource::~DRMSource() {
- Mutex::Autolock autoLock(mDRMLock);
- mDrmManagerClient->finalizeDecryptUnit(mDecryptHandle, mTrackId);
-}
-
-status_t DRMSource::start(MetaData *params) {
- int32_t val;
- if (params && params->findInt32(kKeyWantsNALFragments, &val)
- && val != 0) {
- mWantsNALFragments = true;
- } else {
- mWantsNALFragments = false;
- }
-
- return mOriginalMediaSource->start(params);
-}
-
-status_t DRMSource::stop() {
- return mOriginalMediaSource->stop();
-}
-
-sp<MetaData> DRMSource::getFormat() {
- return mOriginalMediaSource->getFormat();
-}
-
-status_t DRMSource::read(MediaBuffer **buffer, const ReadOptions *options) {
- Mutex::Autolock autoLock(mDRMLock);
- status_t err;
- if ((err = mOriginalMediaSource->read(buffer, options)) != OK) {
- return err;
- }
-
- size_t len = (*buffer)->range_length();
-
- char *src = (char *)(*buffer)->data() + (*buffer)->range_offset();
-
- DrmBuffer encryptedDrmBuffer(src, len);
- DrmBuffer decryptedDrmBuffer;
- decryptedDrmBuffer.length = len;
- decryptedDrmBuffer.data = new char[len];
- DrmBuffer *pDecryptedDrmBuffer = &decryptedDrmBuffer;
-
- if ((err = mDrmManagerClient->decrypt(mDecryptHandle, mTrackId,
- &encryptedDrmBuffer, &pDecryptedDrmBuffer)) != NO_ERROR) {
-
- if (decryptedDrmBuffer.data) {
- delete [] decryptedDrmBuffer.data;
- decryptedDrmBuffer.data = NULL;
- }
-
- return err;
- }
- CHECK(pDecryptedDrmBuffer == &decryptedDrmBuffer);
-
- const char *mime;
- CHECK(getFormat()->findCString(kKeyMIMEType, &mime));
-
- if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) && !mWantsNALFragments) {
- uint8_t *dstData = (uint8_t*)src;
- size_t srcOffset = 0;
- size_t dstOffset = 0;
-
- len = decryptedDrmBuffer.length;
- while (srcOffset < len) {
- CHECK(srcOffset + mNALLengthSize <= len);
- size_t nalLength = 0;
- const uint8_t* data = (const uint8_t*)(&decryptedDrmBuffer.data[srcOffset]);
-
- switch (mNALLengthSize) {
- case 1:
- nalLength = *data;
- break;
- case 2:
- nalLength = U16_AT(data);
- break;
- case 3:
- nalLength = ((size_t)data[0] << 16) | U16_AT(&data[1]);
- break;
- case 4:
- nalLength = U32_AT(data);
- break;
- default:
- CHECK(!"Should not be here.");
- break;
- }
-
- srcOffset += mNALLengthSize;
-
- size_t end = srcOffset + nalLength;
- if (end > len || end < srcOffset) {
- if (decryptedDrmBuffer.data) {
- delete [] decryptedDrmBuffer.data;
- decryptedDrmBuffer.data = NULL;
- }
-
- return ERROR_MALFORMED;
- }
-
- if (nalLength == 0) {
- continue;
- }
-
- if (dstOffset > SIZE_MAX - 4 ||
- dstOffset + 4 > SIZE_MAX - nalLength ||
- dstOffset + 4 + nalLength > (*buffer)->size()) {
- (*buffer)->release();
- (*buffer) = NULL;
- if (decryptedDrmBuffer.data) {
- delete [] decryptedDrmBuffer.data;
- decryptedDrmBuffer.data = NULL;
- }
- return ERROR_MALFORMED;
- }
-
- dstData[dstOffset++] = 0;
- dstData[dstOffset++] = 0;
- dstData[dstOffset++] = 0;
- dstData[dstOffset++] = 1;
- memcpy(&dstData[dstOffset], &decryptedDrmBuffer.data[srcOffset], nalLength);
- srcOffset += nalLength;
- dstOffset += nalLength;
- }
-
- CHECK_EQ(srcOffset, len);
- (*buffer)->set_range((*buffer)->range_offset(), dstOffset);
-
- } else {
- memcpy(src, decryptedDrmBuffer.data, decryptedDrmBuffer.length);
- (*buffer)->set_range((*buffer)->range_offset(), decryptedDrmBuffer.length);
- }
-
- if (decryptedDrmBuffer.data) {
- delete [] decryptedDrmBuffer.data;
- decryptedDrmBuffer.data = NULL;
- }
-
- return OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-DRMExtractor::DRMExtractor(const sp<DataSource> &source, const char* mime)
- : mDataSource(source),
- mDecryptHandle(NULL),
- mDrmManagerClient(NULL) {
- mOriginalExtractor = MediaExtractor::Create(source, mime);
- mOriginalExtractor->getMetaData()->setInt32(kKeyIsDRM, 1);
-
- source->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
-}
-
-DRMExtractor::~DRMExtractor() {
-}
-
-size_t DRMExtractor::countTracks() {
- return mOriginalExtractor->countTracks();
-}
-
-sp<IMediaSource> DRMExtractor::getTrack(size_t index) {
- sp<IMediaSource> originalMediaSource = mOriginalExtractor->getTrack(index);
- originalMediaSource->getFormat()->setInt32(kKeyIsDRM, 1);
-
- int32_t trackID;
- CHECK(getTrackMetaData(index, 0)->findInt32(kKeyTrackID, &trackID));
-
- DrmBuffer ipmpBox;
- ipmpBox.data = mOriginalExtractor->getDrmTrackInfo(trackID, &(ipmpBox.length));
- CHECK(ipmpBox.length > 0);
-
- return interface_cast<IMediaSource>(
- new DRMSource(originalMediaSource, mDecryptHandle, mDrmManagerClient,
- trackID, &ipmpBox));
-}
-
-sp<MetaData> DRMExtractor::getTrackMetaData(size_t index, uint32_t flags) {
- return mOriginalExtractor->getTrackMetaData(index, flags);
-}
-
-sp<MetaData> DRMExtractor::getMetaData() {
- return mOriginalExtractor->getMetaData();
-}
-
-bool SniffDRM(
- const sp<DataSource> &source, String8 *mimeType, float *confidence,
- sp<AMessage> *) {
- sp<DecryptHandle> decryptHandle = source->DrmInitialization();
-
- if (decryptHandle != NULL) {
- if (decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED) {
- *mimeType = String8("drm+container_based+") + decryptHandle->mimeType;
- *confidence = 10.0f;
- } else if (decryptHandle->decryptApiType == DecryptApiType::ELEMENTARY_STREAM_BASED) {
- *mimeType = String8("drm+es_based+") + decryptHandle->mimeType;
- *confidence = 10.0f;
- } else {
- return false;
- }
-
- return true;
- }
-
- return false;
-}
-} //namespace android
-
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 49f480d..df4d9bf 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -27,7 +27,6 @@
#include "include/OggExtractor.h"
#include "include/MPEG2PSExtractor.h"
#include "include/MPEG2TSExtractor.h"
-#include "include/DRMExtractor.h"
#include "include/FLACExtractor.h"
#include "include/AACExtractor.h"
#include "include/MidiExtractor.h"
@@ -51,8 +50,7 @@
namespace android {
-MediaExtractor::MediaExtractor():
- mIsDrm(false) {
+MediaExtractor::MediaExtractor() {
if (!LOG_NDEBUG) {
uid_t uid = getuid();
struct passwd *pw = getpwuid(uid);
@@ -148,23 +146,6 @@
ALOGW("creating media extractor in calling process");
return CreateFromService(source, mime);
} else {
- String8 mime8;
- float confidence;
- sp<AMessage> meta;
-
- // Check if it's es-based DRM, since DRMExtractor needs to be created in the media server
- // process, not the extractor process.
- if (SniffDRM(source, &mime8, &confidence, &meta)) {
- const char *drmMime = mime8.string();
- ALOGV("Detected media content as '%s' with confidence %.2f", drmMime, confidence);
- if (!strncmp(drmMime, "drm+es_based+", 13)) {
- // DRMExtractor sets container metadata kKeyIsDRM to 1
- return new DRMExtractor(source, drmMime + 14);
- } else {
- mime = drmMime + 20; // get real mimetype after "drm+container_based+" prefix
- }
- }
-
// remote extractor
ALOGV("get service manager");
sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
@@ -187,6 +168,9 @@
ALOGV("MediaExtractor::CreateFromService %s", mime);
RegisterDefaultSniffers();
+ // initialize source decryption if needed
+ source->DrmInitialization();
+
sp<AMessage> meta;
String8 tmp;
@@ -299,9 +283,6 @@
RegisterSniffer_l(SniffMPEG2PS);
RegisterSniffer_l(SniffMidi);
- if (property_get_bool("drm.service.enabled", false)) {
- RegisterSniffer_l(SniffDRM);
- }
gSniffersRegistered = true;
}
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 8061bc6..5ce2b76 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -522,8 +522,6 @@
return ERROR_MALFORMED;
}
- mSyncSampleOffset = data_offset;
-
uint8_t header[8];
if (mDataSource->readAt(
data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
@@ -535,13 +533,13 @@
return ERROR_MALFORMED;
}
- mNumSyncSamples = U32_AT(&header[4]);
+ uint32_t numSyncSamples = U32_AT(&header[4]);
- if (mNumSyncSamples < 2) {
+ if (numSyncSamples < 2) {
ALOGV("Table of sync samples is empty or has only a single entry!");
}
- uint64_t allocSize = (uint64_t)mNumSyncSamples * sizeof(uint32_t);
+ uint64_t allocSize = (uint64_t)numSyncSamples * sizeof(uint32_t);
if (allocSize > kMaxTotalSize) {
ALOGE("Sync sample table size too large.");
return ERROR_OUT_OF_RANGE;
@@ -559,19 +557,21 @@
return ERROR_OUT_OF_RANGE;
}
- mSyncSamples = new (std::nothrow) uint32_t[mNumSyncSamples];
+ mSyncSamples = new (std::nothrow) uint32_t[numSyncSamples];
if (!mSyncSamples) {
ALOGE("Cannot allocate sync sample table with %llu entries.",
- (unsigned long long)mNumSyncSamples);
+ (unsigned long long)numSyncSamples);
return ERROR_OUT_OF_RANGE;
}
- if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples,
+ if (mDataSource->readAt(data_offset + 8, mSyncSamples,
(size_t)allocSize) != (ssize_t)allocSize) {
+ delete mSyncSamples;
+ mSyncSamples = NULL;
return ERROR_IO;
}
- for (size_t i = 0; i < mNumSyncSamples; ++i) {
+ for (size_t i = 0; i < numSyncSamples; ++i) {
if (mSyncSamples[i] == 0) {
ALOGE("b/32423862, unexpected zero value in stss");
continue;
@@ -579,6 +579,9 @@
mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
}
+ mSyncSampleOffset = data_offset;
+ mNumSyncSamples = numSyncSamples;
+
return OK;
}
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index f2638ed..68a5b86 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1770,6 +1770,45 @@
*sync = settings;
}
+void writeToAMessage(const sp<AMessage> &msg, const BufferingSettings &buffering) {
+ msg->setInt32("init-mode", buffering.mInitialBufferingMode);
+ msg->setInt32("rebuffer-mode", buffering.mRebufferingMode);
+ msg->setInt32("init-ms", buffering.mInitialWatermarkMs);
+ msg->setInt32("init-kb", buffering.mInitialWatermarkKB);
+ msg->setInt32("rebuffer-low-ms", buffering.mRebufferingWatermarkLowMs);
+ msg->setInt32("rebuffer-high-ms", buffering.mRebufferingWatermarkHighMs);
+ msg->setInt32("rebuffer-low-kb", buffering.mRebufferingWatermarkLowKB);
+ msg->setInt32("rebuffer-high-kb", buffering.mRebufferingWatermarkHighKB);
+}
+
+void readFromAMessage(const sp<AMessage> &msg, BufferingSettings *buffering /* nonnull */) {
+ int32_t value;
+ if (msg->findInt32("init-mode", &value) == OK) {
+ buffering->mInitialBufferingMode = (BufferingMode)value;
+ }
+ if (msg->findInt32("rebuffer-mode", &value) == OK) {
+ buffering->mRebufferingMode = (BufferingMode)value;
+ }
+ if (msg->findInt32("init-ms", &value) == OK) {
+ buffering->mInitialWatermarkMs = value;
+ }
+ if (msg->findInt32("init-kb", &value) == OK) {
+ buffering->mInitialWatermarkKB = value;
+ }
+ if (msg->findInt32("rebuffer-low-ms", &value) == OK) {
+ buffering->mRebufferingWatermarkLowMs = value;
+ }
+ if (msg->findInt32("rebuffer-high-ms", &value) == OK) {
+ buffering->mRebufferingWatermarkHighMs = value;
+ }
+ if (msg->findInt32("rebuffer-low-kb", &value) == OK) {
+ buffering->mRebufferingWatermarkLowKB = value;
+ }
+ if (msg->findInt32("rebuffer-high-kb", &value) == OK) {
+ buffering->mRebufferingWatermarkHighKB = value;
+ }
+}
+
AString nameForFd(int fd) {
const size_t SIZE = 256;
char buffer[SIZE];
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/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 477280a..e144942 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -49,11 +49,6 @@
const int64_t LiveSession::kUpSwitchMarginUs = 5000000ll;
const int64_t LiveSession::kResumeThresholdUs = 100000ll;
-// Buffer Prepare/Ready/Underflow Marks
-const int64_t LiveSession::kReadyMarkUs = 5000000ll;
-const int64_t LiveSession::kPrepareMarkUs = 1500000ll;
-const int64_t LiveSession::kUnderflowMarkUs = 1000000ll;
-
struct LiveSession::BandwidthEstimator : public RefBase {
BandwidthEstimator();
@@ -495,6 +490,13 @@
return new HTTPDownloader(mHTTPService, mExtraHeaders);
}
+void LiveSession::setBufferingSettings(
+ const BufferingSettings &buffering) {
+ sp<AMessage> msg = new AMessage(kWhatSetBufferingSettings, this);
+ writeToAMessage(msg, buffering);
+ msg->post();
+}
+
void LiveSession::connectAsync(
const char *url, const KeyedVector<String8, String8> *headers) {
sp<AMessage> msg = new AMessage(kWhatConnect, this);
@@ -620,6 +622,12 @@
void LiveSession::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
+ case kWhatSetBufferingSettings:
+ {
+ readFromAMessage(msg, &mBufferingSettings);
+ break;
+ }
+
case kWhatConnect:
{
onConnect(msg);
@@ -830,7 +838,10 @@
// If switching up, require a cushion bigger than kUnderflowMark
// to avoid buffering immediately after the switch.
// (If we don't have that cushion we'd rather cancel and try again.)
- int64_t delayUs = switchUp ? (kUnderflowMarkUs + 1000000ll) : 0;
+ int64_t delayUs =
+ switchUp ?
+ (mBufferingSettings.mRebufferingWatermarkLowMs * 1000ll + 1000000ll)
+ : 0;
bool needResumeUntil = false;
sp<AMessage> stopParams = msg;
if (checkSwitchProgress(stopParams, delayUs, &needResumeUntil)) {
@@ -2189,13 +2200,16 @@
}
++activeCount;
- int64_t readyMark = mInPreparationPhase ? kPrepareMarkUs : kReadyMarkUs;
- if (bufferedDurationUs > readyMark
+ int64_t readyMarkUs =
+ (mInPreparationPhase ?
+ mBufferingSettings.mInitialWatermarkMs :
+ mBufferingSettings.mRebufferingWatermarkHighMs) * 1000ll;
+ if (bufferedDurationUs > readyMarkUs
|| mPacketSources[i]->isFinished(0)) {
++readyCount;
}
if (!mPacketSources[i]->isFinished(0)) {
- if (bufferedDurationUs < kUnderflowMarkUs) {
+ if (bufferedDurationUs < mBufferingSettings.mRebufferingWatermarkLowMs * 1000ll) {
++underflowCount;
}
if (bufferedDurationUs > mUpSwitchMark) {
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index a0138be..abf8cf0 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -18,6 +18,7 @@
#define LIVE_SESSION_H_
+#include <media/BufferingSettings.h>
#include <media/stagefright/foundation/AHandler.h>
#include <media/mediaplayer.h>
@@ -72,6 +73,8 @@
uint32_t flags,
const sp<IMediaHTTPService> &httpService);
+ void setBufferingSettings(const BufferingSettings &buffering);
+
int64_t calculateMediaTimeUs(int64_t firstTimeUs, int64_t timeUs, int32_t discontinuitySeq);
status_t dequeueAccessUnit(StreamType stream, sp<ABuffer> *accessUnit);
@@ -129,6 +132,7 @@
kWhatChangeConfiguration2 = 'chC2',
kWhatChangeConfiguration3 = 'chC3',
kWhatPollBuffering = 'poll',
+ kWhatSetBufferingSettings = 'sBuS',
};
// Bandwidth Switch Mark Defaults
@@ -138,9 +142,7 @@
static const int64_t kResumeThresholdUs;
// Buffer Prepare/Ready/Underflow Marks
- static const int64_t kReadyMarkUs;
- static const int64_t kPrepareMarkUs;
- static const int64_t kUnderflowMarkUs;
+ BufferingSettings mBufferingSettings;
struct BandwidthEstimator;
struct BandwidthItem {
diff --git a/media/libstagefright/include/DRMExtractor.h b/media/libstagefright/include/DRMExtractor.h
deleted file mode 100644
index 3dc7df8..0000000
--- a/media/libstagefright/include/DRMExtractor.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2010 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 DRM_EXTRACTOR_H_
-
-#define DRM_EXTRACTOR_H_
-
-#include <media/IMediaSource.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <drm/DrmManagerClient.h>
-
-namespace android {
-
-struct AMessage;
-class DataSource;
-class SampleTable;
-class String8;
-class DecryptHandle;
-
-class DRMExtractor : public MediaExtractor {
-public:
- DRMExtractor(const sp<DataSource> &source, const char *mime);
-
- virtual size_t countTracks();
- virtual sp<IMediaSource> getTrack(size_t index);
- virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
- virtual sp<MetaData> getMetaData();
- virtual const char * name() { return "DRMExtractor"; }
-
-protected:
- virtual ~DRMExtractor();
-
-private:
- sp<DataSource> mDataSource;
-
- sp<IMediaExtractor> mOriginalExtractor;
- sp<DecryptHandle> mDecryptHandle;
- DrmManagerClient* mDrmManagerClient;
-
- DRMExtractor(const DRMExtractor &);
- DRMExtractor &operator=(const DRMExtractor &);
-};
-
-bool SniffDRM(
- const sp<DataSource> &source, String8 *mimeType, float *confidence,
- sp<AMessage> *);
-
-} // namespace android
-
-#endif // DRM_EXTRACTOR_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..b1ede30 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>
@@ -1263,6 +1264,7 @@
bool chainCreated = false;
bool effectCreated = false;
bool effectRegistered = false;
+ audio_unique_id_t effectId = AUDIO_UNIQUE_ID_USE_UNSPECIFIED;
lStatus = initCheck();
if (lStatus != NO_ERROR) {
@@ -1296,15 +1298,16 @@
ALOGV("createEffect_l() got effect %p on chain %p", effect.get(), chain.get());
if (effect == 0) {
- audio_unique_id_t id = mAudioFlinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
+ effectId = mAudioFlinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
// Check CPU and memory usage
- lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id);
+ lStatus = AudioSystem::registerEffect(
+ desc, mId, chain->strategy(), sessionId, effectId);
if (lStatus != NO_ERROR) {
goto Exit;
}
effectRegistered = true;
// create a new effect module if none present in the chain
- lStatus = chain->createEffect_l(effect, this, desc, id, sessionId, pinned);
+ lStatus = chain->createEffect_l(effect, this, desc, effectId, sessionId, pinned);
if (lStatus != NO_ERROR) {
goto Exit;
}
@@ -1333,7 +1336,7 @@
chain->removeEffect_l(effect);
}
if (effectRegistered) {
- AudioSystem::unregisterEffect(effect->id());
+ AudioSystem::unregisterEffect(effectId);
}
if (chainCreated) {
removeEffectChain_l(chain);
@@ -6936,252 +6939,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"
diff --git a/services/radio/Android.mk b/services/radio/Android.mk
index 4344506..74f1fe0 100644
--- a/services/radio/Android.mk
+++ b/services/radio/Android.mk
@@ -30,9 +30,13 @@
libradio \
libradio_metadata
-ifeq ($(ENABLE_TREBLE),true)
+ifeq ($(USE_LEGACY_LOCAL_AUDIO_HAL),true)
+# libhardware configuration
+LOCAL_SRC_FILES += \
+ RadioHalLegacy.cpp
+else
# Treble configuration
-LOCAL_CFLAGS += -DENABLE_TREBLE
+
LOCAL_SRC_FILES += \
HidlUtils.cpp \
RadioHalHidl.cpp
@@ -43,13 +47,8 @@
libhidltransport \
libbase \
android.hardware.broadcastradio@1.0
-else
-# libhardware configuration
-LOCAL_SRC_FILES += \
- RadioHalLegacy.cpp
endif
-
LOCAL_CFLAGS += -Wall -Wextra -Werror
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk
index e1e1fb1..63a05a6 100644
--- a/services/soundtrigger/Android.mk
+++ b/services/soundtrigger/Android.mk
@@ -34,23 +34,22 @@
libserviceutility
-ifeq ($(ENABLE_TREBLE),true)
+ifeq ($(USE_LEGACY_LOCAL_AUDIO_HAL),true)
+# libhardware configuration
+LOCAL_SRC_FILES += \
+ SoundTriggerHalLegacy.cpp
+else
# Treble configuration
-LOCAL_CFLAGS += -DENABLE_TREBLE
LOCAL_SRC_FILES += \
SoundTriggerHalHidl.cpp
LOCAL_SHARED_LIBRARIES += \
- libhwbinder \
- libhidlbase \
- libhidltransport \
- libbase \
- android.hardware.soundtrigger@2.0 \
- android.hardware.audio.common@2.0
-else
-# libhardware configuration
-LOCAL_SRC_FILES += \
- SoundTriggerHalLegacy.cpp
+ libhwbinder \
+ libhidlbase \
+ libhidltransport \
+ libbase \
+ android.hardware.soundtrigger@2.0 \
+ android.hardware.audio.common@2.0
endif