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> &notify,
@@ -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> &notify);
 
+        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> &notify,
@@ -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> &notify,
             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