Merge "Fix Ogg extractor and Vorbis decoder"
diff --git a/apex/TEST_MAPPING b/apex/TEST_MAPPING
index f036516..09c46d6 100644
--- a/apex/TEST_MAPPING
+++ b/apex/TEST_MAPPING
@@ -14,17 +14,9 @@
         },
         {
           "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
-        }
-      ]
-    },
-    {
-      "name": "GtsExoPlayerTestCases",
-      "options" : [
-        {
-          "include-annotation": "android.platform.test.annotations.SocPresubmit"
         },
         {
-          "include-filter": "com.google.android.exoplayer.gts.DashTest#testWidevine23FpsH264Fixed"
+          "include-filter": "com.google.android.media.gts.WidevineYouTubePerformanceTests"
         }
       ]
     }
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 96dc541..a2c2ca7 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -1890,10 +1890,8 @@
      *   <li>ACaptureRequest</li>
      * </ul></p>
      *
-     * <p>Instead of using ACAMERA_SCALER_CROP_REGION with dual purposes of crop and zoom, the
-     * application can now choose to use this tag to specify the desired zoom level. The
-     * ACAMERA_SCALER_CROP_REGION can still be used to specify the horizontal or vertical
-     * crop to achieve aspect ratios different than the native camera sensor.</p>
+     * <p>Instead of using ACAMERA_SCALER_CROP_REGION for zoom, the application can now choose to
+     * use this tag to specify the desired zoom level.</p>
      * <p>By using this control, the application gains a simpler way to control zoom, which can
      * be a combination of optical and digital zoom. For example, a multi-camera system may
      * contain more than one lens with different focal lengths, and the user can use optical
@@ -3413,16 +3411,24 @@
      * respectively.</p>
      * <p>The camera device may adjust the crop region to account for rounding and other hardware
      * requirements; the final crop region used will be included in the output capture result.</p>
+     * <p>The camera sensor output aspect ratio depends on factors such as output stream
+     * combination and ACAMERA_CONTROL_AE_TARGET_FPS_RANGE, and shouldn't be adjusted by using
+     * this control. And the camera device will treat different camera sensor output sizes
+     * (potentially with in-sensor crop) as the same crop of
+     * ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE. As a result, the application shouldn't assume the
+     * maximum crop region always maps to the same aspect ratio or field of view for the
+     * sensor output.</p>
      * <p>Starting from API level 30, it's strongly recommended to use ACAMERA_CONTROL_ZOOM_RATIO
      * to take advantage of better support for zoom with logical multi-camera. The benefits
      * include better precision with optical-digital zoom combination, and ability to do
      * zoom-out from 1.0x. When using ACAMERA_CONTROL_ZOOM_RATIO for zoom, the crop region in
-     * the capture request must be either letterboxing or pillarboxing (but not both). The
+     * the capture request should be left as the default activeArray size. The
      * coordinate system is post-zoom, meaning that the activeArraySize or
      * preCorrectionActiveArraySize covers the camera device's field of view "after" zoom.  See
      * ACAMERA_CONTROL_ZOOM_RATIO for details.</p>
      * <p>The data representation is int[4], which maps to (left, top, width, height).</p>
      *
+     * @see ACAMERA_CONTROL_AE_TARGET_FPS_RANGE
      * @see ACAMERA_CONTROL_ZOOM_RATIO
      * @see ACAMERA_DISTORTION_CORRECTION_MODE
      * @see ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
diff --git a/drm/TEST_MAPPING b/drm/TEST_MAPPING
index 2595e3e..9f6a532 100644
--- a/drm/TEST_MAPPING
+++ b/drm/TEST_MAPPING
@@ -9,17 +9,9 @@
         },
         {
           "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
-        }
-      ]
-    },
-    {
-      "name": "GtsExoPlayerTestCases",
-      "options" : [
-        {
-          "include-annotation": "android.platform.test.annotations.SocPresubmit"
         },
         {
-          "include-filter": "com.google.android.exoplayer.gts.DashTest#testWidevine23FpsH264Fixed"
+          "include-filter": "com.google.android.media.gts.WidevineYouTubePerformanceTests"
         }
       ]
     }
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index 9a32cc5..74e3223 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -99,13 +99,13 @@
         }
         default:
         {
-            ALOGW("Unrecognized message type: %zd", msg->what());
+            ALOGW("Unrecognized message type: %u", msg->what());
         }
     }
 }
 
 int64_t DrmManager::getMetricsFlushPeriodUs() {
-    return 1000 * 1000 * std::max(1ll, property_get_int64("drmmanager.metrics.period", 86400));
+    return 1000 * 1000 * std::max(1ll, (long long)property_get_int64("drmmanager.metrics.period", 86400));
 }
 
 void DrmManager::recordEngineMetrics(
diff --git a/drm/libmediadrm/DrmMetricsConsumer.cpp b/drm/libmediadrm/DrmMetricsConsumer.cpp
index b47b4ff..5f0b26e 100644
--- a/drm/libmediadrm/DrmMetricsConsumer.cpp
+++ b/drm/libmediadrm/DrmMetricsConsumer.cpp
@@ -37,8 +37,8 @@
 template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
     static const char *type_names[] = {"USABLE", "EXPIRED",
                                        "OUTPUT_NOT_ALLOWED", "STATUS_PENDING",
-                                       "INTERNAL_ERROR"};
-    if (((size_t)type) > arraysize(type_names)) {
+                                       "INTERNAL_ERROR", "USABLE_IN_FUTURE"};
+    if (((size_t)type) >= arraysize(type_names)) {
         return "UNKNOWN_TYPE";
     }
     return type_names[(size_t)type];
@@ -48,7 +48,7 @@
     static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED",
                                        "KEY_EXPIRED", "VENDOR_DEFINED",
                                        "SESSION_RECLAIMED"};
-    if (((size_t)type) > arraysize(type_names)) {
+    if (((size_t)type) >= arraysize(type_names)) {
         return "UNKNOWN_TYPE";
     }
     return type_names[(size_t)type];
diff --git a/include/drm/TEST_MAPPING b/include/drm/TEST_MAPPING
index 28e432e..512e844 100644
--- a/include/drm/TEST_MAPPING
+++ b/include/drm/TEST_MAPPING
@@ -8,17 +8,9 @@
         },
         {
           "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
-        }
-      ]
-    },
-    {
-      "name": "GtsExoPlayerTestCases",
-      "options" : [
-        {
-          "include-annotation": "android.platform.test.annotations.SocPresubmit"
         },
         {
-          "include-filter": "com.google.android.exoplayer.gts.DashTest#testWidevine23FpsH264Fixed"
+          "include-filter": "com.google.android.media.gts.WidevineYouTubePerformanceTests"
         }
       ]
     }
diff --git a/include/media/MmapStreamInterface.h b/include/media/MmapStreamInterface.h
index b3bf16d..61de987 100644
--- a/include/media/MmapStreamInterface.h
+++ b/include/media/MmapStreamInterface.h
@@ -22,6 +22,8 @@
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
+#include <time.h>
+
 namespace android {
 
 class MmapStreamCallback;
@@ -103,6 +105,19 @@
     virtual status_t getMmapPosition(struct audio_mmap_position *position) = 0;
 
     /**
+     * Get a recent count of the number of audio frames presented/received to/from an
+     * external observer.
+     *
+     * \param[out] position count of presented audio frames
+     * \param[out] timeNanos associated clock time
+     *
+     * \return OK if the external position is set correctly.
+     *         NO_INIT in case of initialization error
+     *         INVALID_OPERATION if the interface is not implemented
+     */
+    virtual status_t getExternalPosition(uint64_t* position, int64_t* timeNanos) = 0;
+
+    /**
      * Start a stream operating in mmap mode.
      * createMmapBuffer() must be called before calling start()
      *
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index b006f38..50facfb 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -26,17 +26,9 @@
                 },
                 {
                     "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
-                }
-            ]
-        },
-        {
-            "name": "GtsExoPlayerTestCases",
-            "options" : [
-                {
-                    "include-annotation": "android.platform.test.annotations.SocPresubmit"
                 },
                 {
-                    "include-filter": "com.google.android.exoplayer.gts.DashTest#testWidevine23FpsH264Fixed"
+                    "include-filter": "com.google.android.media.gts.WidevineYouTubePerformanceTests"
                 }
             ]
         }
diff --git a/media/codec2/core/include/C2Enum.h b/media/codec2/core/include/C2Enum.h
index b0fad8f..da1f43b 100644
--- a/media/codec2/core/include/C2Enum.h
+++ b/media/codec2/core/include/C2Enum.h
@@ -54,7 +54,7 @@
 /// \note this will contain any initialization, which we will remove when converting to lower-case
 #define _C2_GET_ENUM_NAME(x, y) #x
 /// mapper to get value of enum
-#define _C2_GET_ENUM_VALUE(x, type) (_C2EnumConst<type>)x
+#define _C2_GET_ENUM_VALUE(x, type_) (_C2EnumConst<typename std::underlying_type<type_>::type>)type_::x
 
 /// \endcond
 
@@ -106,7 +106,7 @@
 template<> \
 C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const name &r __unused) { \
     return _C2EnumUtils::sanitizeEnumValues( \
-            std::vector<C2Value::Primitive> { _C2_MAP(_C2_GET_ENUM_VALUE, type, __VA_ARGS__) }, \
+            std::vector<C2Value::Primitive> { _C2_MAP(_C2_GET_ENUM_VALUE, name, __VA_ARGS__) }, \
             { _C2_MAP(_C2_GET_ENUM_NAME, type, __VA_ARGS__) }, \
             prefix); \
 }
diff --git a/media/codec2/core/include/C2Param.h b/media/codec2/core/include/C2Param.h
index 51d417a..436269a 100644
--- a/media/codec2/core/include/C2Param.h
+++ b/media/codec2/core/include/C2Param.h
@@ -508,6 +508,14 @@
         return _mIndex.setPort(output);
     }
 
+    /// sets the size of this parameter.
+    inline void setSize(size_t size) {
+        if (size < sizeof(C2Param)) {
+            size = 0;
+        }
+        _mSize = c2_min(size, _mSize);
+    }
+
 public:
     /// invalidate this parameter. There is no recovery from this call; e.g. parameter
     /// cannot be 'corrected' to be valid.
diff --git a/media/codec2/core/include/C2ParamDef.h b/media/codec2/core/include/C2ParamDef.h
index 0a33283..d578820 100644
--- a/media/codec2/core/include/C2ParamDef.h
+++ b/media/codec2/core/include/C2ParamDef.h
@@ -97,6 +97,9 @@
         PARAM_TYPE = CoreIndex | TypeFlags
     };
 
+    // the underlying param struct type
+    typedef S Struct;
+
 protected:
     enum : uint32_t {
         FLEX_SIZE = 0,
@@ -270,6 +273,11 @@
         } \
         return 0; \
     } \
+    inline void setFlexCount(size_t count) { \
+        if (count < flexCount()) { \
+            this->setSize(sizeof(_Type) + _Type::FLEX_SIZE * count); \
+        } \
+    } \
 
 /// Mark flexible member variable and make structure flexible.
 #define FLEX(cls, m) \
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 369087d..97145c3 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -618,7 +618,7 @@
 }
 
 void CCodecBufferChannel::feedInputBufferIfAvailableInternal() {
-    if (mInputMetEos || mPipelineWatcher.lock()->pipelineFull()) {
+    if (mInputMetEos) {
         return;
     }
     {
@@ -631,6 +631,9 @@
     }
     size_t numInputSlots = mInput.lock()->numSlots;
     for (size_t i = 0; i < numInputSlots; ++i) {
+        if (mPipelineWatcher.lock()->pipelineFull()) {
+            return;
+        }
         sp<MediaCodecBuffer> inBuffer;
         size_t index;
         {
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index c49a16c..3c99bf6 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -91,7 +91,9 @@
             newFormat->setInt32(KEY_STRIDE, stride);
             ALOGD("[%s] updating stride = %d", mName, stride);
             if (img->mNumPlanes > 1 && stride > 0) {
-                int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
+                int64_t offsetDelta =
+                    (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
+                int32_t vstride = int32_t(offsetDelta / stride);
                 newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
                 ALOGD("[%s] updating vstride = %d", mName, vstride);
             }
diff --git a/media/codec2/tests/C2Param_test.cpp b/media/codec2/tests/C2Param_test.cpp
index 564d4d2..c39605a 100644
--- a/media/codec2/tests/C2Param_test.cpp
+++ b/media/codec2/tests/C2Param_test.cpp
@@ -2328,6 +2328,17 @@
         static_assert(std::is_same<decltype(blobValue->m.value), uint8_t[]>::value, "should be uint8_t[]");
         EXPECT_EQ(0, memcmp(blobValue->m.value, "ABCD\0", 6));
         EXPECT_EQ(6u, blobValue->flexCount());
+        blobValue->setFlexCount(7u); // increasing the count does not change it
+        EXPECT_EQ(6u, blobValue->flexCount());
+        blobValue->setFlexCount(2u); // decreasing the count changes it to it
+        EXPECT_EQ(2u, blobValue->flexCount());
+        blobValue->setFlexCount(0u); // can decrease to 0 and blob remains valid
+        EXPECT_EQ(0u, blobValue->flexCount());
+        EXPECT_TRUE(*blobValue);
+        blobValue->invalidate(); // flex params can be invalidated => results in 0 size
+        EXPECT_FALSE(*blobValue);
+        EXPECT_EQ(0u, blobValue->size());
+
         std::vector<C2FieldDescriptor> fields = blobValue->FieldList();
         EXPECT_EQ(1u, fields.size());
         EXPECT_EQ(FD::BLOB, fields.cbegin()->type());
diff --git a/media/libaaudio/Android.bp b/media/libaaudio/Android.bp
index 140052f..e81ab06 100644
--- a/media/libaaudio/Android.bp
+++ b/media/libaaudio/Android.bp
@@ -32,5 +32,6 @@
 cc_library_headers {
     name: "libaaudio_headers",
     export_include_dirs: ["include"],
+    export_header_lib_headers: ["aaudio-aidl-cpp"],
+    header_libs: ["aaudio-aidl-cpp"],
 }
-
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 717f31a..328ceda 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -85,6 +85,7 @@
         "libcutils",
         "libutils",
         "libbinder",
+        "aaudio-aidl-cpp",
     ],
 
     cflags: [
@@ -114,11 +115,10 @@
         "client/AudioStreamInternalPlay.cpp",
         "client/IsochronousClockModel.cpp",
         "binding/AudioEndpointParcelable.cpp",
+        "binding/AAudioBinderAdapter.cpp",
         "binding/AAudioBinderClient.cpp",
         "binding/AAudioStreamRequest.cpp",
         "binding/AAudioStreamConfiguration.cpp",
-        "binding/IAAudioClient.cpp",
-        "binding/IAAudioService.cpp",
         "binding/RingBufferParcelable.cpp",
         "binding/SharedMemoryParcelable.cpp",
         "binding/SharedRegionParcelable.cpp",
@@ -138,3 +138,33 @@
         misc_undefined: ["bounds"],
     },
 }
+
+aidl_interface {
+    name: "aaudio-aidl",
+    unstable: true,
+    local_include_dir: "binding/aidl",
+    srcs: [
+        "binding/aidl/aaudio/Endpoint.aidl",
+        "binding/aidl/aaudio/RingBuffer.aidl",
+        "binding/aidl/aaudio/SharedRegion.aidl",
+        "binding/aidl/aaudio/StreamParameters.aidl",
+        "binding/aidl/aaudio/StreamRequest.aidl",
+        "binding/aidl/aaudio/IAAudioClient.aidl",
+        "binding/aidl/aaudio/IAAudioService.aidl",
+    ],
+    imports: [
+        "audio_common-aidl",
+        "shared-file-region-aidl",
+    ],
+    backend:
+    {
+        cpp: {
+            enabled: true,
+        },
+        java: {
+            // TODO: need to have audio_common-aidl available in Java to enable
+            //       this.
+            enabled: false,
+        },
+    },
+}
diff --git a/media/libaaudio/src/binding/AAudioBinderAdapter.cpp b/media/libaaudio/src/binding/AAudioBinderAdapter.cpp
new file mode 100644
index 0000000..2b2fe6d
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioBinderAdapter.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2020 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 <binding/AAudioBinderAdapter.h>
+#include <utility/AAudioUtilities.h>
+
+namespace aaudio {
+
+using android::binder::Status;
+
+AAudioBinderAdapter::AAudioBinderAdapter(IAAudioService* delegate)
+        : mDelegate(delegate) {}
+
+void AAudioBinderAdapter::registerClient(const android::sp<IAAudioClient>& client) {
+    mDelegate->registerClient(client);
+}
+
+aaudio_handle_t AAudioBinderAdapter::openStream(const AAudioStreamRequest& request,
+                                                AAudioStreamConfiguration& config) {
+    aaudio_handle_t result;
+    StreamParameters params;
+    Status status = mDelegate->openStream(request.parcelable(),
+                                          &params,
+                                          &result);
+    if (!status.isOk()) {
+        result = AAudioConvert_androidToAAudioResult(status.transactionError());
+    }
+    config = params;
+    return result;
+}
+
+aaudio_result_t AAudioBinderAdapter::closeStream(aaudio_handle_t streamHandle) {
+    aaudio_result_t result;
+    Status status = mDelegate->closeStream(streamHandle, &result);
+    if (!status.isOk()) {
+        result = AAudioConvert_androidToAAudioResult(status.transactionError());
+    }
+    return result;
+}
+
+aaudio_result_t AAudioBinderAdapter::getStreamDescription(aaudio_handle_t streamHandle,
+                                                          AudioEndpointParcelable& endpointOut) {
+    aaudio_result_t result;
+    Endpoint endpoint;
+    Status status = mDelegate->getStreamDescription(streamHandle,
+                                                    &endpoint,
+                                                    &result);
+    if (!status.isOk()) {
+        result = AAudioConvert_androidToAAudioResult(status.transactionError());
+    }
+    endpointOut = std::move(endpoint);
+    return result;
+}
+
+aaudio_result_t AAudioBinderAdapter::startStream(aaudio_handle_t streamHandle) {
+    aaudio_result_t result;
+    Status status = mDelegate->startStream(streamHandle, &result);
+    if (!status.isOk()) {
+        result = AAudioConvert_androidToAAudioResult(status.transactionError());
+    }
+    return result;
+}
+
+aaudio_result_t AAudioBinderAdapter::pauseStream(aaudio_handle_t streamHandle) {
+    aaudio_result_t result;
+    Status status = mDelegate->pauseStream(streamHandle, &result);
+    if (!status.isOk()) {
+        result = AAudioConvert_androidToAAudioResult(status.transactionError());
+    }
+    return result;
+}
+
+aaudio_result_t AAudioBinderAdapter::stopStream(aaudio_handle_t streamHandle) {
+    aaudio_result_t result;
+    Status status = mDelegate->stopStream(streamHandle, &result);
+    if (!status.isOk()) {
+        result = AAudioConvert_androidToAAudioResult(status.transactionError());
+    }
+    return result;
+}
+
+aaudio_result_t AAudioBinderAdapter::flushStream(aaudio_handle_t streamHandle) {
+    aaudio_result_t result;
+    Status status = mDelegate->flushStream(streamHandle, &result);
+    if (!status.isOk()) {
+        result = AAudioConvert_androidToAAudioResult(status.transactionError());
+    }
+    return result;
+}
+
+aaudio_result_t AAudioBinderAdapter::registerAudioThread(aaudio_handle_t streamHandle,
+                                                         pid_t clientThreadId,
+                                                         int64_t periodNanoseconds) {
+    aaudio_result_t result;
+    Status status = mDelegate->registerAudioThread(streamHandle, clientThreadId, periodNanoseconds, &result);
+    if (!status.isOk()) {
+        result = AAudioConvert_androidToAAudioResult(status.transactionError());
+    }
+    return result;
+}
+
+aaudio_result_t AAudioBinderAdapter::unregisterAudioThread(aaudio_handle_t streamHandle,
+                                                           pid_t clientThreadId) {
+    aaudio_result_t result;
+    Status status = mDelegate->unregisterAudioThread(streamHandle, clientThreadId, &result);
+    if (!status.isOk()) {
+        result = AAudioConvert_androidToAAudioResult(status.transactionError());
+    }
+    return result;
+}
+
+}  // namespace aaudio
diff --git a/media/libaaudio/src/binding/AAudioBinderAdapter.h b/media/libaaudio/src/binding/AAudioBinderAdapter.h
new file mode 100644
index 0000000..5e9ab57
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioBinderAdapter.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <aaudio/IAAudioService.h>
+#include <binding/AAudioServiceInterface.h>
+
+namespace aaudio {
+
+/**
+ * An adapter that takes in an underlying IAAudioService and exposes an
+ * AAudioServiceInterface.
+ *
+ * This class is abstract: the client is expected to inherit from this class and implement those
+ * methods from AAudioServiceInterface that don't have counterparts in IAAudioService.
+ */
+class AAudioBinderAdapter : public AAudioServiceInterface {
+public:
+    explicit AAudioBinderAdapter(IAAudioService* delegate);
+
+    void registerClient(const android::sp<IAAudioClient>& client) override;
+
+    aaudio_handle_t openStream(const AAudioStreamRequest& request,
+                               AAudioStreamConfiguration& configuration) override;
+
+    aaudio_result_t closeStream(aaudio_handle_t streamHandle) override;
+
+    aaudio_result_t getStreamDescription(aaudio_handle_t streamHandle,
+                                         AudioEndpointParcelable& endpoint) override;
+
+    aaudio_result_t startStream(aaudio_handle_t streamHandle) override;
+
+    aaudio_result_t pauseStream(aaudio_handle_t streamHandle) override;
+
+    aaudio_result_t stopStream(aaudio_handle_t streamHandle) override;
+
+    aaudio_result_t flushStream(aaudio_handle_t streamHandle) override;
+
+    aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+                                        pid_t clientThreadId,
+                                        int64_t periodNanoseconds) override;
+
+    aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+                                          pid_t clientThreadId) override;
+
+private:
+    IAAudioService* const mDelegate;
+};
+
+}  // namespace aaudio
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
index 7b0d31f..fa5a2da 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.cpp
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -19,35 +19,30 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
-#include <binder/IInterface.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
 #include <utils/Singleton.h>
-#include <media/AudioSystem.h>
-
 #include <aaudio/AAudio.h>
 
 #include "AudioEndpointParcelable.h"
-#include "binding/AAudioBinderClient.h"
-//#include "binding/AAudioStreamRequest.h"
-//#include "binding/AAudioStreamConfiguration.h"
-//#include "binding/IAAudioService.h"
-//#include "binding/AAudioServiceMessage.h"
 
-//#include "AAudioServiceInterface.h"
+#include "binding/AAudioBinderClient.h"
+
+#define AAUDIO_SERVICE_NAME  "media.aaudio"
 
 using android::String16;
 using android::IServiceManager;
 using android::defaultServiceManager;
 using android::interface_cast;
 using android::IInterface;
-using android::IAAudioService;
 using android::Mutex;
 using android::ProcessState;
 using android::sp;
+using android::status_t;
 using android::wp;
+using android::binder::Status;
 
 using namespace aaudio;
 
@@ -67,20 +62,18 @@
 AAudioBinderClient::~AAudioBinderClient() {
     ALOGV("%s - destroying %p", __func__, this);
     Mutex::Autolock _l(mServiceLock);
-    if (mAAudioService != 0) {
-        IInterface::asBinder(mAAudioService)->unlinkToDeath(mAAudioClient);
-    }
 }
 
 // TODO Share code with other service clients.
 // Helper function to get access to the "AAudioService" service.
 // This code was modeled after frameworks/av/media/libaudioclient/AudioSystem.cpp
-const sp<IAAudioService> AAudioBinderClient::getAAudioService() {
+std::shared_ptr<AAudioServiceInterface> AAudioBinderClient::getAAudioService() {
+    std::shared_ptr<AAudioServiceInterface> result;
     sp<IAAudioService> aaudioService;
     bool needToRegister = false;
     {
         Mutex::Autolock _l(mServiceLock);
-        if (mAAudioService.get() == nullptr) {
+        if (mAdapter == nullptr) {
             sp<IBinder> binder;
             sp<IServiceManager> sm = defaultServiceManager();
             // Try several times to get the service.
@@ -99,7 +92,8 @@
                 if (status != NO_ERROR) {
                     ALOGE("%s() - linkToDeath() returned %d", __func__, status);
                 }
-                mAAudioService = interface_cast<IAAudioService>(binder);
+                aaudioService = interface_cast<IAAudioService>(binder);
+                mAdapter.reset(new Adapter(aaudioService, mAAudioClient));
                 needToRegister = true;
                 // Make sure callbacks can be received by mAAudioClient
                 ProcessState::self()->startThreadPool();
@@ -107,18 +101,18 @@
                 ALOGE("AAudioBinderClient could not connect to %s", AAUDIO_SERVICE_NAME);
             }
         }
-        aaudioService = mAAudioService;
+        result = mAdapter;
     }
     // Do this outside the mutex lock.
     if (needToRegister && aaudioService.get() != nullptr) { // new client?
         aaudioService->registerClient(mAAudioClient);
     }
-    return aaudioService;
+    return result;
 }
 
 void AAudioBinderClient::dropAAudioService() {
     Mutex::Autolock _l(mServiceLock);
-    mAAudioService.clear(); // force a reconnect
+    mAdapter.reset();
 }
 
 /**
@@ -127,13 +121,13 @@
 * @return handle to the stream or a negative error
 */
 aaudio_handle_t AAudioBinderClient::openStream(const AAudioStreamRequest &request,
-                                               AAudioStreamConfiguration &configurationOutput) {
+                                               AAudioStreamConfiguration &configuration) {
     aaudio_handle_t stream;
     for (int i = 0; i < 2; i++) {
-        const sp<IAAudioService> &service = getAAudioService();
+        std::shared_ptr<AAudioServiceInterface> service = getAAudioService();
         if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
 
-        stream = service->openStream(request, configurationOutput);
+        stream = service->openStream(request, configuration);
 
         if (stream == AAUDIO_ERROR_NO_SERVICE) {
             ALOGE("openStream lost connection to AAudioService.");
@@ -146,8 +140,9 @@
 }
 
 aaudio_result_t AAudioBinderClient::closeStream(aaudio_handle_t streamHandle) {
-    const sp<IAAudioService> service = getAAudioService();
+    std::shared_ptr<AAudioServiceInterface> service = getAAudioService();
     if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
+
     return service->closeStream(streamHandle);
 }
 
@@ -155,33 +150,38 @@
 * used to communicate with the underlying HAL or Service.
 */
 aaudio_result_t AAudioBinderClient::getStreamDescription(aaudio_handle_t streamHandle,
-                                                         AudioEndpointParcelable &parcelable) {
-    const sp<IAAudioService> service = getAAudioService();
+                                                         AudioEndpointParcelable& endpointOut) {
+    std::shared_ptr<AAudioServiceInterface> service = getAAudioService();
     if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
-    return service->getStreamDescription(streamHandle, parcelable);
+
+    return service->getStreamDescription(streamHandle, endpointOut);
 }
 
 aaudio_result_t AAudioBinderClient::startStream(aaudio_handle_t streamHandle) {
-    const sp<IAAudioService> service = getAAudioService();
+    std::shared_ptr<AAudioServiceInterface> service = getAAudioService();
     if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
+
     return service->startStream(streamHandle);
 }
 
 aaudio_result_t AAudioBinderClient::pauseStream(aaudio_handle_t streamHandle) {
-    const sp<IAAudioService> service = getAAudioService();
+    std::shared_ptr<AAudioServiceInterface> service = getAAudioService();
     if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
+
     return service->pauseStream(streamHandle);
 }
 
 aaudio_result_t AAudioBinderClient::stopStream(aaudio_handle_t streamHandle) {
-    const sp<IAAudioService> service = getAAudioService();
+    std::shared_ptr<AAudioServiceInterface> service = getAAudioService();
     if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
+
     return service->stopStream(streamHandle);
 }
 
 aaudio_result_t AAudioBinderClient::flushStream(aaudio_handle_t streamHandle) {
-    const sp<IAAudioService> service = getAAudioService();
+    std::shared_ptr<AAudioServiceInterface> service = getAAudioService();
     if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
+
     return service->flushStream(streamHandle);
 }
 
@@ -191,17 +191,16 @@
 aaudio_result_t AAudioBinderClient::registerAudioThread(aaudio_handle_t streamHandle,
                                                         pid_t clientThreadId,
                                                         int64_t periodNanoseconds) {
-    const sp<IAAudioService> service = getAAudioService();
+    std::shared_ptr<AAudioServiceInterface> service = getAAudioService();
     if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
-    return service->registerAudioThread(streamHandle,
-                                        clientThreadId,
-                                        periodNanoseconds);
+
+    return service->registerAudioThread(streamHandle, clientThreadId, periodNanoseconds);
 }
 
 aaudio_result_t AAudioBinderClient::unregisterAudioThread(aaudio_handle_t streamHandle,
                                                           pid_t clientThreadId) {
-    const sp<IAAudioService> service = getAAudioService();
+    std::shared_ptr<AAudioServiceInterface> service = getAAudioService();
     if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
-    return service->unregisterAudioThread(streamHandle,
-                                          clientThreadId);
+
+    return service->unregisterAudioThread(streamHandle, clientThreadId);
 }
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
index e8c91fc..6a7b639 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.h
+++ b/media/libaaudio/src/binding/AAudioBinderClient.h
@@ -21,12 +21,15 @@
 #include <utils/Singleton.h>
 
 #include <aaudio/AAudio.h>
-#include "AAudioServiceDefinitions.h"
+#include <binder/IInterface.h>
+
+#include "aaudio/BnAAudioClient.h"
+#include "aaudio/IAAudioService.h"
 #include "AAudioServiceInterface.h"
+#include "binding/AAudioBinderAdapter.h"
 #include "binding/AAudioStreamRequest.h"
-#include "binding/AAudioStreamConfiguration.h"
 #include "binding/AudioEndpointParcelable.h"
-#include "binding/IAAudioService.h"
+#include "core/AAudioStreamParameters.h"
 
 /**
  * Implements the AAudioServiceInterface by talking to the service through Binder.
@@ -44,11 +47,7 @@
 
     virtual ~AAudioBinderClient();
 
-    const android::sp<android::IAAudioService> getAAudioService();
-
-    void dropAAudioService();
-
-    void registerClient(const android::sp<android::IAAudioClient>& client __unused) override {}
+    void registerClient(const android::sp<IAAudioClient>& client __unused) override {}
 
     /**
      * @param request info needed to create the stream
@@ -64,7 +63,7 @@
     * used to communicate with the underlying HAL or Service.
     */
     aaudio_result_t getStreamDescription(aaudio_handle_t streamHandle,
-                                                 AudioEndpointParcelable &parcelable) override;
+                                         AudioEndpointParcelable &endpointOut) override;
 
     /**
      * Start the flow of data.
@@ -115,8 +114,7 @@
         ALOGW("onStreamChange called!");
     }
 
-    class AAudioClient : public android::IBinder::DeathRecipient , public android::BnAAudioClient
-    {
+    class AAudioClient : public android::IBinder::DeathRecipient, public BnAAudioClient {
     public:
         AAudioClient(android::wp<AAudioBinderClient> aaudioBinderClient)
                 : mBinderClient(aaudioBinderClient) {
@@ -132,21 +130,66 @@
         }
 
         // implement BnAAudioClient
-        void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) {
+        android::binder::Status onStreamChange(int32_t handle, int32_t opcode, int32_t value) {
+            static_assert(std::is_same_v<aaudio_handle_t, int32_t>);
             android::sp<AAudioBinderClient> client = mBinderClient.promote();
             if (client.get() != nullptr) {
                 client->onStreamChange(handle, opcode, value);
             }
+            return android::binder::Status::ok();
         }
     private:
         android::wp<AAudioBinderClient> mBinderClient;
     };
 
-private:
+    // This adapter is used to convert the binder interface (delegate) to the AudioServiceInterface
+    // conventions (translating between data types and respective parcelables, translating error
+    // codes and calling conventions).
+    // The adapter also owns the underlying service object and is responsible to unlink its death
+    // listener when destroyed.
+    class Adapter : public AAudioBinderAdapter {
+    public:
+        Adapter(const android::sp<IAAudioService>& delegate,
+                const android::sp<AAudioClient>& aaudioClient)
+                : AAudioBinderAdapter(delegate.get()),
+                  mDelegate(delegate),
+                  mAAudioClient(aaudioClient) {}
 
-    android::Mutex                  mServiceLock;
-    android::sp<android::IAAudioService>  mAAudioService;
-    android::sp<AAudioClient>       mAAudioClient;
+        virtual ~Adapter() {
+            if (mDelegate != nullptr) {
+                android::IInterface::asBinder(mDelegate)->unlinkToDeath(mAAudioClient);
+            }
+        }
+
+        // This should never be called (call is rejected at the AudioBinderClient level).
+        aaudio_result_t startClient(aaudio_handle_t streamHandle __unused,
+                                    const android::AudioClient& client __unused,
+                                    const audio_attributes_t* attr __unused,
+                                    audio_port_handle_t* clientHandle __unused) override {
+            LOG_ALWAYS_FATAL("Shouldn't get here");
+            return AAUDIO_ERROR_UNAVAILABLE;
+        }
+
+        // This should never be called (call is rejected at the AudioBinderClient level).
+        aaudio_result_t stopClient(aaudio_handle_t streamHandle __unused,
+                                   audio_port_handle_t clientHandle __unused) override {
+            LOG_ALWAYS_FATAL("Shouldn't get here");
+            return AAUDIO_ERROR_UNAVAILABLE;
+        }
+
+    private:
+        android::sp<IAAudioService> mDelegate;
+        android::sp<AAudioClient> mAAudioClient;
+    };
+
+private:
+    android::Mutex                          mServiceLock;
+    std::shared_ptr<AAudioServiceInterface> mAdapter;
+    android::sp<AAudioClient>               mAAudioClient;
+
+    std::shared_ptr<AAudioServiceInterface> getAAudioService();
+
+    void dropAAudioService();
 
 };
 
diff --git a/media/libaaudio/src/binding/AAudioServiceInterface.h b/media/libaaudio/src/binding/AAudioServiceInterface.h
index 9c28cc7..5d11512 100644
--- a/media/libaaudio/src/binding/AAudioServiceInterface.h
+++ b/media/libaaudio/src/binding/AAudioServiceInterface.h
@@ -20,11 +20,11 @@
 #include <utils/StrongPointer.h>
 #include <media/AudioClient.h>
 
+#include "aaudio/IAAudioClient.h"
 #include "binding/AAudioServiceDefinitions.h"
 #include "binding/AAudioStreamRequest.h"
 #include "binding/AAudioStreamConfiguration.h"
 #include "binding/AudioEndpointParcelable.h"
-#include "binding/IAAudioClient.h"
 
 /**
  * This has the same methods as IAAudioService but without the Binder features.
@@ -40,7 +40,7 @@
     AAudioServiceInterface() {};
     virtual ~AAudioServiceInterface() = default;
 
-    virtual void registerClient(const android::sp<android::IAAudioClient>& client) = 0;
+    virtual void registerClient(const android::sp<IAAudioClient>& client) = 0;
 
     /**
      * @param request info needed to create the stream
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index b785f88..2d501ef 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -23,101 +23,66 @@
 #include <sys/mman.h>
 #include <aaudio/AAudio.h>
 
-#include <binder/Parcel.h>
-#include <binder/Parcelable.h>
-
 #include "binding/AAudioStreamConfiguration.h"
 
-using android::NO_ERROR;
-using android::status_t;
-using android::Parcel;
-using android::Parcelable;
-
 using namespace aaudio;
 
-AAudioStreamConfiguration::AAudioStreamConfiguration() {}
-AAudioStreamConfiguration::~AAudioStreamConfiguration() {}
+using android::media::audio::common::AudioFormat;
 
-status_t AAudioStreamConfiguration::writeToParcel(Parcel* parcel) const {
-    status_t status;
-
-    status = parcel->writeInt32(getDeviceId());
-    if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32(getSampleRate());
-    if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32(getSamplesPerFrame());
-    if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32((int32_t) getSharingMode());
-    if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32((int32_t) getFormat());
-    if (status != NO_ERROR) goto error;
-
-    status = parcel->writeInt32((int32_t) getDirection());
-    if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32(getBufferCapacity());
-    if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32((int32_t) getUsage());
-    if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32((int32_t) getContentType());
-    if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32((int32_t) getInputPreset());
-    if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32((int32_t) getAllowedCapturePolicy());
-    if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32(getSessionId());
-    if (status != NO_ERROR) goto error;
-    status = parcel->writeInt32(isPrivacySensitive() ? 1 : 0);
-    if (status != NO_ERROR) goto error;
-    return NO_ERROR;
-error:
-    ALOGE("%s(): write failed = %d", __func__, status);
-    return status;
+AAudioStreamConfiguration::AAudioStreamConfiguration(const StreamParameters& parcelable) {
+    setSamplesPerFrame(parcelable.samplesPerFrame);
+    setSampleRate(parcelable.sampleRate);
+    setDeviceId(parcelable.deviceId);
+    static_assert(sizeof(aaudio_sharing_mode_t) == sizeof(parcelable.sharingMode));
+    setSharingMode(parcelable.sharingMode);
+    static_assert(sizeof(audio_format_t) == sizeof(parcelable.audioFormat));
+    setFormat(static_cast<audio_format_t>(parcelable.audioFormat));
+    static_assert(sizeof(aaudio_direction_t) == sizeof(parcelable.direction));
+    setDirection(parcelable.direction);
+    static_assert(sizeof(audio_usage_t) == sizeof(parcelable.usage));
+    setUsage(parcelable.usage);
+    static_assert(sizeof(aaudio_content_type_t) == sizeof(parcelable.contentType));
+    setContentType(parcelable.contentType);
+    static_assert(sizeof(aaudio_input_preset_t) == sizeof(parcelable.inputPreset));
+    setInputPreset(parcelable.inputPreset);
+    setBufferCapacity(parcelable.bufferCapacity);
+    static_assert(
+            sizeof(aaudio_allowed_capture_policy_t) == sizeof(parcelable.allowedCapturePolicy));
+    setAllowedCapturePolicy(parcelable.allowedCapturePolicy);
+    static_assert(sizeof(aaudio_session_id_t) == sizeof(parcelable.sessionId));
+    setSessionId(parcelable.sessionId);
+    setPrivacySensitive(parcelable.isPrivacySensitive);
 }
 
-status_t AAudioStreamConfiguration::readFromParcel(const Parcel* parcel) {
-    int32_t value;
-    status_t status = parcel->readInt32(&value);
-    if (status != NO_ERROR) goto error;
-    setDeviceId(value);
-    status = parcel->readInt32(&value);
-    if (status != NO_ERROR) goto error;
-    setSampleRate(value);
-    status = parcel->readInt32(&value);
-    if (status != NO_ERROR) goto error;
-    setSamplesPerFrame(value);
-    status = parcel->readInt32(&value);
-    if (status != NO_ERROR) goto error;
-    setSharingMode((aaudio_sharing_mode_t) value);
-    status = parcel->readInt32(&value);
-    if (status != NO_ERROR) goto error;
-    setFormat((audio_format_t) value);
+AAudioStreamConfiguration&
+AAudioStreamConfiguration::operator=(const StreamParameters& parcelable) {
+    this->~AAudioStreamConfiguration();
+    new (this) AAudioStreamConfiguration(parcelable);
+    return *this;
+}
 
-    status = parcel->readInt32(&value);
-    if (status != NO_ERROR) goto error;
-    setDirection((aaudio_direction_t) value);
-    status = parcel->readInt32(&value);
-    if (status != NO_ERROR) goto error;
-    setBufferCapacity(value);
-    status = parcel->readInt32(&value);
-    if (status != NO_ERROR) goto error;
-    setUsage((aaudio_usage_t) value);
-    status = parcel->readInt32(&value);
-    if (status != NO_ERROR) goto error;
-    setContentType((aaudio_content_type_t) value);
-    status = parcel->readInt32(&value);
-    if (status != NO_ERROR) goto error;
-    setInputPreset((aaudio_input_preset_t) value);
-    status = parcel->readInt32(&value);
-    if (status != NO_ERROR) goto error;
-    setAllowedCapturePolicy((aaudio_allowed_capture_policy_t) value);
-    status = parcel->readInt32(&value);
-    if (status != NO_ERROR) goto error;
-    setSessionId(value);
-    status = parcel->readInt32(&value);
-    if (status != NO_ERROR) goto error;
-    setPrivacySensitive(value == 1);
-    return NO_ERROR;
-error:
-    ALOGE("%s(): read failed = %d", __func__, status);
-    return status;
+StreamParameters AAudioStreamConfiguration::parcelable() const {
+    StreamParameters result;
+    result.samplesPerFrame = getSamplesPerFrame();
+    result.sampleRate = getSampleRate();
+    result.deviceId = getDeviceId();
+    static_assert(sizeof(aaudio_sharing_mode_t) == sizeof(result.sharingMode));
+    result.sharingMode = getSharingMode();
+    static_assert(sizeof(audio_format_t) == sizeof(result.audioFormat));
+    result.audioFormat = static_cast<AudioFormat>(getFormat());
+    static_assert(sizeof(aaudio_direction_t) == sizeof(result.direction));
+    result.direction = getDirection();
+    static_assert(sizeof(audio_usage_t) == sizeof(result.usage));
+    result.usage = getUsage();
+    static_assert(sizeof(aaudio_content_type_t) == sizeof(result.contentType));
+    result.contentType = getContentType();
+    static_assert(sizeof(aaudio_input_preset_t) == sizeof(result.inputPreset));
+    result.inputPreset = getInputPreset();
+    result.bufferCapacity = getBufferCapacity();
+    static_assert(sizeof(aaudio_allowed_capture_policy_t) == sizeof(result.allowedCapturePolicy));
+    result.allowedCapturePolicy = getAllowedCapturePolicy();
+    static_assert(sizeof(aaudio_session_id_t) == sizeof(result.sessionId));
+    result.sessionId = getSessionId();
+    result.isPrivacySensitive = isPrivacySensitive();
+    return result;
 }
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.h b/media/libaaudio/src/binding/AAudioStreamConfiguration.h
index b324896..f428eb0 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.h
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.h
@@ -20,24 +20,24 @@
 #include <stdint.h>
 
 #include <aaudio/AAudio.h>
+#include <aaudio/StreamParameters.h>
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
 #include "core/AAudioStreamParameters.h"
 
-using android::status_t;
-using android::Parcel;
-using android::Parcelable;
-
 namespace aaudio {
 
-class AAudioStreamConfiguration : public AAudioStreamParameters, public Parcelable {
+// This is a holder for AAudioStreamParameters, which allows conversion to/from it parcelable
+// representation, StreamParameters.
+class AAudioStreamConfiguration : public AAudioStreamParameters {
 public:
-    AAudioStreamConfiguration();
-    virtual ~AAudioStreamConfiguration();
+    AAudioStreamConfiguration() = default;
 
-    virtual status_t writeToParcel(Parcel* parcel) const override;
+    explicit AAudioStreamConfiguration(const StreamParameters& parcelable);
 
-    virtual status_t readFromParcel(const Parcel* parcel) override;
+    AAudioStreamConfiguration& operator=(const StreamParameters& parcelable);
+
+    StreamParameters parcelable() const;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
index c30c5b9..536395a 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -21,67 +21,32 @@
 #include <stdint.h>
 
 #include <sys/mman.h>
-#include <binder/Parcel.h>
-#include <binder/Parcelable.h>
 
 #include <aaudio/AAudio.h>
 
 #include "binding/AAudioStreamConfiguration.h"
 #include "binding/AAudioStreamRequest.h"
 
-using android::NO_ERROR;
-using android::status_t;
-using android::Parcel;
-using android::Parcelable;
-
 using namespace aaudio;
 
-AAudioStreamRequest::AAudioStreamRequest()
-    : mConfiguration()
-    {}
-
-AAudioStreamRequest::~AAudioStreamRequest() {}
-
-status_t AAudioStreamRequest::writeToParcel(Parcel* parcel) const {
-    status_t status = parcel->writeInt32((int32_t) mUserId);
-    if (status != NO_ERROR) goto error;
-
-    status = parcel->writeBool(mSharingModeMatchRequired);
-    if (status != NO_ERROR) goto error;
-
-    status = parcel->writeBool(mInService);
-    if (status != NO_ERROR) goto error;
-
-    status = mConfiguration.writeToParcel(parcel);
-    if (status != NO_ERROR) goto error;
-
-    return NO_ERROR;
-
-error:
-    ALOGE("writeToParcel(): write failed = %d", status);
-    return status;
+AAudioStreamRequest::AAudioStreamRequest(const StreamRequest& parcelable) :
+        mConfiguration(std::move(parcelable.params)),
+        mUserId(parcelable.userId),
+        mProcessId(parcelable.processId),
+        mSharingModeMatchRequired(parcelable.sharingModeMatchRequired),
+        mInService(parcelable.inService) {
+    static_assert(sizeof(mUserId) == sizeof(parcelable.userId));
+    static_assert(sizeof(mProcessId) == sizeof(parcelable.processId));
 }
 
-status_t AAudioStreamRequest::readFromParcel(const Parcel* parcel) {
-    int32_t temp;
-    status_t status = parcel->readInt32(&temp);
-    if (status != NO_ERROR) goto error;
-    mUserId = (uid_t) temp;
-
-    status = parcel->readBool(&mSharingModeMatchRequired);
-    if (status != NO_ERROR) goto error;
-
-    status = parcel->readBool(&mInService);
-    if (status != NO_ERROR) goto error;
-
-    status = mConfiguration.readFromParcel(parcel);
-    if (status != NO_ERROR) goto error;
-
-    return NO_ERROR;
-
-error:
-    ALOGE("readFromParcel(): read failed = %d", status);
-    return status;
+StreamRequest AAudioStreamRequest::parcelable() const {
+    StreamRequest result;
+    result.params = std::move(mConfiguration).parcelable();
+    result.userId = mUserId;
+    result.processId = mProcessId;
+    result.sharingModeMatchRequired = mSharingModeMatchRequired;
+    result.inService = mInService;
+    return result;
 }
 
 aaudio_result_t AAudioStreamRequest::validate() const {
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
index 492f69d..31d3ea1 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.h
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.h
@@ -20,21 +20,18 @@
 #include <stdint.h>
 
 #include <aaudio/AAudio.h>
-#include <binder/Parcel.h>
-#include <binder/Parcelable.h>
+#include <aaudio/StreamRequest.h>
 
 #include "binding/AAudioStreamConfiguration.h"
 
-using android::status_t;
-using android::Parcel;
-using android::Parcelable;
-
 namespace aaudio {
 
-class AAudioStreamRequest : public Parcelable {
+class AAudioStreamRequest {
 public:
-    AAudioStreamRequest();
-    virtual ~AAudioStreamRequest();
+    AAudioStreamRequest() = default;
+
+    // Construct based on a parcelable representation.
+    explicit AAudioStreamRequest(const StreamRequest& parcelable);
 
     uid_t getUserId() const {
         return mUserId;
@@ -76,15 +73,14 @@
         mInService = inService;
     }
 
-    virtual status_t writeToParcel(Parcel* parcel) const override;
-
-    virtual status_t readFromParcel(const Parcel* parcel) override;
-
     aaudio_result_t validate() const;
 
     void dump() const;
 
-protected:
+    // Extract a parcelable representation of this object.
+    StreamRequest parcelable() const;
+
+private:
     AAudioStreamConfiguration  mConfiguration;
     uid_t                      mUserId = (uid_t) -1;
     pid_t                      mProcessId = (pid_t) -1;
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
index 61d7d27..aa4ac27 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
@@ -29,22 +29,43 @@
 #include "binding/AudioEndpointParcelable.h"
 
 using android::base::unique_fd;
+using android::media::SharedFileRegion;
 using android::NO_ERROR;
 using android::status_t;
-using android::Parcel;
-using android::Parcelable;
 
 using namespace aaudio;
 
-/**
- * Container for information about the message queues plus
- * general stream information needed by AAudio clients.
- * It contains no addresses, just sizes, offsets and file descriptors for
- * shared memory that can be passed through Binder.
- */
-AudioEndpointParcelable::AudioEndpointParcelable() {}
+AudioEndpointParcelable::AudioEndpointParcelable(Endpoint&& parcelable)
+        : mUpMessageQueueParcelable(std::move(parcelable.upMessageQueueParcelable)),
+          mDownMessageQueueParcelable(std::move(parcelable.downMessageQueueParcelable)),
+          mUpDataQueueParcelable(std::move(parcelable.upDataQueueParcelable)),
+          mDownDataQueueParcelable(std::move(parcelable.downDataQueueParcelable)),
+          mNumSharedMemories(parcelable.sharedMemories.size()) {
+    for (size_t i = 0; i < parcelable.sharedMemories.size() && i < MAX_SHARED_MEMORIES; ++i) {
+        // Re-construct.
+        mSharedMemories[i].~SharedMemoryParcelable();
+        new(&mSharedMemories[i]) SharedMemoryParcelable(std::move(parcelable.sharedMemories[i]));
+    }
+}
 
-AudioEndpointParcelable::~AudioEndpointParcelable() {}
+AudioEndpointParcelable& AudioEndpointParcelable::operator=(Endpoint&& parcelable) {
+    this->~AudioEndpointParcelable();
+    new(this) AudioEndpointParcelable(std::move(parcelable));
+    return *this;
+}
+
+Endpoint AudioEndpointParcelable::parcelable()&& {
+    Endpoint result;
+    result.upMessageQueueParcelable = std::move(mUpMessageQueueParcelable).parcelable();
+    result.downMessageQueueParcelable = std::move(mDownMessageQueueParcelable).parcelable();
+    result.upDataQueueParcelable = std::move(mUpDataQueueParcelable).parcelable();
+    result.downDataQueueParcelable = std::move(mDownDataQueueParcelable).parcelable();
+    result.sharedMemories.reserve(std::min(mNumSharedMemories, MAX_SHARED_MEMORIES));
+    for (size_t i = 0; i < mNumSharedMemories && i < MAX_SHARED_MEMORIES; ++i) {
+        result.sharedMemories.emplace_back(std::move(mSharedMemories[i]).parcelable());
+    }
+    return result;
+}
 
 /**
  * Add the file descriptor to the table.
@@ -60,60 +81,6 @@
     return index;
 }
 
-/**
- * The read and write must be symmetric.
- */
-status_t AudioEndpointParcelable::writeToParcel(Parcel* parcel) const {
-    status_t status = AAudioConvert_aaudioToAndroidStatus(validate());
-    if (status != NO_ERROR) goto error;
-
-    status = parcel->writeInt32(mNumSharedMemories);
-    if (status != NO_ERROR) goto error;
-
-    for (int i = 0; i < mNumSharedMemories; i++) {
-        status = mSharedMemories[i].writeToParcel(parcel);
-        if (status != NO_ERROR) goto error;
-    }
-    status = mUpMessageQueueParcelable.writeToParcel(parcel);
-    if (status != NO_ERROR) goto error;
-    status = mDownMessageQueueParcelable.writeToParcel(parcel);
-    if (status != NO_ERROR) goto error;
-    status = mUpDataQueueParcelable.writeToParcel(parcel);
-    if (status != NO_ERROR) goto error;
-    status = mDownDataQueueParcelable.writeToParcel(parcel);
-    if (status != NO_ERROR) goto error;
-
-    return NO_ERROR;
-
-error:
-    ALOGE("%s returning %d", __func__, status);
-    return status;
-}
-
-status_t AudioEndpointParcelable::readFromParcel(const Parcel* parcel) {
-    status_t status = parcel->readInt32(&mNumSharedMemories);
-    if (status != NO_ERROR) goto error;
-
-    for (int i = 0; i < mNumSharedMemories; i++) {
-        mSharedMemories[i].readFromParcel(parcel);
-        if (status != NO_ERROR) goto error;
-    }
-    status = mUpMessageQueueParcelable.readFromParcel(parcel);
-    if (status != NO_ERROR) goto error;
-    status = mDownMessageQueueParcelable.readFromParcel(parcel);
-    if (status != NO_ERROR) goto error;
-    status = mUpDataQueueParcelable.readFromParcel(parcel);
-    if (status != NO_ERROR) goto error;
-    status = mDownDataQueueParcelable.readFromParcel(parcel);
-    if (status != NO_ERROR) goto error;
-
-    return AAudioConvert_aaudioToAndroidStatus(validate());
-
-error:
-    ALOGE("%s returning %d", __func__, status);
-    return status;
-}
-
 aaudio_result_t AudioEndpointParcelable::resolve(EndpointDescriptor *descriptor) {
     aaudio_result_t result = mUpMessageQueueParcelable.resolve(mSharedMemories,
                                                            &descriptor->upMessageQueueDescriptor);
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.h b/media/libaaudio/src/binding/AudioEndpointParcelable.h
index e4f8b9e..5237a1a 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.h
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.h
@@ -20,16 +20,13 @@
 #include <stdint.h>
 
 //#include <sys/mman.h>
+#include <aaudio/Endpoint.h>
 #include <android-base/unique_fd.h>
-#include <binder/Parcel.h>
-#include <binder/Parcelable.h>
 
 #include "binding/AAudioServiceDefinitions.h"
 #include "binding/RingBufferParcelable.h"
 
 using android::status_t;
-using android::Parcel;
-using android::Parcelable;
 
 namespace aaudio {
 
@@ -39,10 +36,15 @@
  * It contains no addresses, just sizes, offsets and file descriptors for
  * shared memory that can be passed through Binder.
  */
-class AudioEndpointParcelable : public Parcelable {
+class AudioEndpointParcelable {
 public:
-    AudioEndpointParcelable();
-    virtual ~AudioEndpointParcelable();
+    AudioEndpointParcelable() = default;
+
+    // Ctor/assignment from a parcelable representation.
+    // Since the parcelable object owns unique FDs (for shared memory blocks), move semantics are
+    // provided to avoid the need to dupe.
+    AudioEndpointParcelable(Endpoint&& parcelable);
+    AudioEndpointParcelable& operator=(Endpoint&& parcelable);
 
     /**
      * Add the file descriptor to the table.
@@ -50,16 +52,17 @@
      */
     int32_t addFileDescriptor(const android::base::unique_fd& fd, int32_t sizeInBytes);
 
-    virtual status_t writeToParcel(Parcel* parcel) const override;
-
-    virtual status_t readFromParcel(const Parcel* parcel) override;
-
     aaudio_result_t resolve(EndpointDescriptor *descriptor);
 
     aaudio_result_t close();
 
     void dump();
 
+    // Extract a parcelable representation of this object.
+    // Since our shared memory objects own a unique FD, move semantics are provided to avoid the
+    // need to dupe.
+    Endpoint parcelable()&&;
+
 public: // TODO add getters
     // Set capacityInFrames to zero if Queue is unused.
     RingBufferParcelable    mUpMessageQueueParcelable;   // server to client
diff --git a/media/libaaudio/src/binding/IAAudioClient.cpp b/media/libaaudio/src/binding/IAAudioClient.cpp
deleted file mode 100644
index c69c4e8..0000000
--- a/media/libaaudio/src/binding/IAAudioClient.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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 "AAudio"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <aaudio/AAudio.h>
-
-#include "binding/AAudioBinderClient.h"
-#include "binding/AAudioServiceDefinitions.h"
-#include "binding/IAAudioClient.h"
-#include "utility/AAudioUtilities.h"
-
-namespace android {
-
-using aaudio::aaudio_handle_t;
-
-/**
- * This is used by the AAudio Service to talk to an AAudio Client.
- *
- * The order of parameters in the Parcels must match with code in AAudioClient.cpp.
- */
-class BpAAudioClient : public BpInterface<IAAudioClient>
-{
-public:
-    explicit BpAAudioClient(const sp<IBinder>& impl)
-        : BpInterface<IAAudioClient>(impl)
-    {
-    }
-
-    void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(IAAudioClient::getInterfaceDescriptor());
-        data.writeInt32(handle);
-        data.writeInt32(opcode);
-        data.writeInt32(value);
-        remote()->transact(ON_STREAM_CHANGE, data,  &reply, IBinder::FLAG_ONEWAY);
-    }
-
-};
-
-// Implement an interface to the service.
-IMPLEMENT_META_INTERFACE(AAudioClient, "IAAudioClient");
-
-// The order of parameters in the Parcels must match with code in BpAAudioClient
-
-status_t BnAAudioClient::onTransact(uint32_t code, const Parcel& data,
-                                        Parcel* reply, uint32_t flags) {
-    aaudio_handle_t streamHandle;
-    int32_t opcode = 0;
-    int32_t value = 0;
-    ALOGV("BnAAudioClient::onTransact(%u) %u", code, flags);
-
-    switch(code) {
-        case ON_STREAM_CHANGE: {
-            CHECK_INTERFACE(IAAudioClient, data, reply);
-            data.readInt32(&streamHandle);
-            data.readInt32(&opcode);
-            data.readInt32(&value);
-            onStreamChange(streamHandle, opcode, value);
-            ALOGD("BnAAudioClient onStreamChange(%x, %d, %d)", streamHandle, opcode, value);
-            return NO_ERROR;
-        } break;
-
-        default:
-            // ALOGW("BnAAudioClient::onTransact not handled %u", code);
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-} /* namespace android */
diff --git a/media/libaaudio/src/binding/IAAudioClient.h b/media/libaaudio/src/binding/IAAudioClient.h
deleted file mode 100644
index f21fd93..0000000
--- a/media/libaaudio/src/binding/IAAudioClient.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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_AAUDIO_IAAUDIO_CLIENT_H
-#define ANDROID_AAUDIO_IAAUDIO_CLIENT_H
-
-#include <stdint.h>
-#include <binder/IInterface.h>
-
-#include <aaudio/AAudio.h>
-
-#include "binding/AAudioCommon.h"
-
-namespace android {
-
-
-// Interface (our AIDL) - client methods called by service
-class IAAudioClient : public IInterface {
-public:
-
-    DECLARE_META_INTERFACE(AAudioClient);
-
-    virtual void onStreamChange(aaudio::aaudio_handle_t handle, int32_t opcode, int32_t value) = 0;
-
-};
-
-class BnAAudioClient : public BnInterface<IAAudioClient> {
-public:
-    virtual status_t onTransact(uint32_t code, const Parcel& data,
-                                Parcel* reply, uint32_t flags = 0);
-};
-
-} /* namespace android */
-
-#endif //ANDROID_AAUDIO_IAAUDIO_SERVICE_H
diff --git a/media/libaaudio/src/binding/IAAudioService.cpp b/media/libaaudio/src/binding/IAAudioService.cpp
deleted file mode 100644
index e017b3a..0000000
--- a/media/libaaudio/src/binding/IAAudioService.cpp
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "AAudio"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <aaudio/AAudio.h>
-#include <binder/IPCThreadState.h>
-
-#include "binding/AudioEndpointParcelable.h"
-#include "binding/AAudioStreamRequest.h"
-#include "binding/AAudioServiceDefinitions.h"
-#include "binding/AAudioStreamConfiguration.h"
-#include "binding/IAAudioService.h"
-#include "utility/AAudioUtilities.h"
-
-namespace android {
-
-using aaudio::aaudio_handle_t;
-
-/**
- * This is used by the AAudio Client to talk to the AAudio Service.
- *
- * The order of parameters in the Parcels must match with code in AAudioService.cpp.
- */
-class BpAAudioService : public BpInterface<IAAudioService>
-{
-public:
-    explicit BpAAudioService(const sp<IBinder>& impl)
-        : BpInterface<IAAudioService>(impl)
-    {
-    }
-
-    void registerClient(const sp<IAAudioClient>& client) override
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
-        data.writeStrongBinder(IInterface::asBinder(client));
-        remote()->transact(REGISTER_CLIENT, data, &reply);
-    }
-
-    aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
-                               aaudio::AAudioStreamConfiguration &configurationOutput) override {
-        Parcel data, reply;
-        // send command
-        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
-        // request.dump();
-        request.writeToParcel(&data);
-        status_t err = remote()->transact(OPEN_STREAM, data, &reply);
-        if (err != NO_ERROR) {
-            ALOGE("BpAAudioService::client openStream transact failed %d", err);
-            return AAudioConvert_androidToAAudioResult(err);
-        }
-        // parse reply
-        aaudio_handle_t stream;
-        err = reply.readInt32(&stream);
-        if (err != NO_ERROR) {
-            ALOGE("BpAAudioService::client transact(OPEN_STREAM) readInt %d", err);
-            return AAudioConvert_androidToAAudioResult(err);
-        } else if (stream < 0) {
-            return stream;
-        }
-        err = configurationOutput.readFromParcel(&reply);
-        if (err != NO_ERROR) {
-            ALOGE("BpAAudioService::client openStream readFromParcel failed %d", err);
-            closeStream(stream);
-            return AAudioConvert_androidToAAudioResult(err);
-        }
-        return stream;
-    }
-
-    virtual aaudio_result_t closeStream(aaudio_handle_t streamHandle) override {
-        Parcel data, reply;
-        // send command
-        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
-        data.writeInt32(streamHandle);
-        status_t err = remote()->transact(CLOSE_STREAM, data, &reply);
-        if (err != NO_ERROR) {
-            ALOGE("BpAAudioService::client closeStream transact failed %d", err);
-            return AAudioConvert_androidToAAudioResult(err);
-        }
-        // parse reply
-        aaudio_result_t res;
-        reply.readInt32(&res);
-        return res;
-    }
-
-    virtual aaudio_result_t getStreamDescription(aaudio_handle_t streamHandle,
-                                               aaudio::AudioEndpointParcelable &parcelable)   {
-        Parcel data, reply;
-        // send command
-        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
-        data.writeInt32(streamHandle);
-        status_t err = remote()->transact(GET_STREAM_DESCRIPTION, data, &reply);
-        if (err != NO_ERROR) {
-            ALOGE("BpAAudioService::client transact(GET_STREAM_DESCRIPTION) returns %d", err);
-            return AAudioConvert_androidToAAudioResult(err);
-        }
-        // parse reply
-        aaudio_result_t result;
-        err = reply.readInt32(&result);
-        if (err != NO_ERROR) {
-            ALOGE("BpAAudioService::client transact(GET_STREAM_DESCRIPTION) readInt %d", err);
-            return AAudioConvert_androidToAAudioResult(err);
-        } else if (result != AAUDIO_OK) {
-            ALOGE("BpAAudioService::client GET_STREAM_DESCRIPTION passed result %d", result);
-            return result;
-        }
-        err = parcelable.readFromParcel(&reply);
-        if (err != NO_ERROR) {
-            ALOGE("BpAAudioService::client transact(GET_STREAM_DESCRIPTION) read endpoint %d", err);
-            return AAudioConvert_androidToAAudioResult(err);
-        }
-        return result;
-    }
-
-    // TODO should we wait for a reply?
-    virtual aaudio_result_t startStream(aaudio_handle_t streamHandle) override {
-        Parcel data, reply;
-        // send command
-        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
-        data.writeInt32(streamHandle);
-        status_t err = remote()->transact(START_STREAM, data, &reply);
-        if (err != NO_ERROR) {
-            return AAudioConvert_androidToAAudioResult(err);
-        }
-        // parse reply
-        aaudio_result_t res;
-        reply.readInt32(&res);
-        return res;
-    }
-
-    virtual aaudio_result_t pauseStream(aaudio_handle_t streamHandle) override {
-        Parcel data, reply;
-        // send command
-        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
-        data.writeInt32(streamHandle);
-        status_t err = remote()->transact(PAUSE_STREAM, data, &reply);
-        if (err != NO_ERROR) {
-            return AAudioConvert_androidToAAudioResult(err);
-        }
-        // parse reply
-        aaudio_result_t res;
-        reply.readInt32(&res);
-        return res;
-    }
-
-    virtual aaudio_result_t stopStream(aaudio_handle_t streamHandle) override {
-        Parcel data, reply;
-        // send command
-        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
-        data.writeInt32(streamHandle);
-        status_t err = remote()->transact(STOP_STREAM, data, &reply);
-        if (err != NO_ERROR) {
-            return AAudioConvert_androidToAAudioResult(err);
-        }
-        // parse reply
-        aaudio_result_t res;
-        reply.readInt32(&res);
-        return res;
-    }
-
-    virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle) override {
-        Parcel data, reply;
-        // send command
-        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
-        data.writeInt32(streamHandle);
-        status_t err = remote()->transact(FLUSH_STREAM, data, &reply);
-        if (err != NO_ERROR) {
-            return AAudioConvert_androidToAAudioResult(err);
-        }
-        // parse reply
-        aaudio_result_t res;
-        reply.readInt32(&res);
-        return res;
-    }
-
-    virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
-                                                pid_t clientThreadId,
-                                                int64_t periodNanoseconds)
-    override {
-        Parcel data, reply;
-        // send command
-        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
-        data.writeInt32(streamHandle);
-        data.writeInt32((int32_t) clientThreadId);
-        data.writeInt64(periodNanoseconds);
-        status_t err = remote()->transact(REGISTER_AUDIO_THREAD, data, &reply);
-        if (err != NO_ERROR) {
-            return AAudioConvert_androidToAAudioResult(err);
-        }
-        // parse reply
-        aaudio_result_t res;
-        reply.readInt32(&res);
-        return res;
-    }
-
-    virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                  pid_t clientThreadId)
-    override {
-        Parcel data, reply;
-        // send command
-        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
-        data.writeInt32(streamHandle);
-        data.writeInt32((int32_t) clientThreadId);
-        status_t err = remote()->transact(UNREGISTER_AUDIO_THREAD, data, &reply);
-        if (err != NO_ERROR) {
-            return AAudioConvert_androidToAAudioResult(err);
-        }
-        // parse reply
-        aaudio_result_t res;
-        reply.readInt32(&res);
-        return res;
-    }
-
-};
-
-// Implement an interface to the service.
-// This is here so that you don't have to link with libaaudio static library.
-IMPLEMENT_META_INTERFACE(AAudioService, "IAAudioService");
-
-// The order of parameters in the Parcels must match with code in BpAAudioService
-
-status_t BnAAudioService::onTransact(uint32_t code, const Parcel& data,
-                                        Parcel* reply, uint32_t flags) {
-    aaudio_handle_t streamHandle = 0;
-    aaudio::AAudioStreamRequest request;
-    aaudio::AAudioStreamConfiguration configuration;
-    pid_t tid = 0;
-    int64_t nanoseconds = 0;
-    aaudio_result_t result = AAUDIO_OK;
-    status_t status = NO_ERROR;
-    ALOGV("BnAAudioService::onTransact(%i) %i", code, flags);
-
-    switch(code) {
-        case REGISTER_CLIENT: {
-            CHECK_INTERFACE(IAAudioService, data, reply);
-            sp<IAAudioClient> client = interface_cast<IAAudioClient>(
-                    data.readStrongBinder());
-            // readStrongBinder() can return null
-            if (client.get() == nullptr) {
-                ALOGE("BnAAudioService::%s(REGISTER_CLIENT) client is NULL!", __func__);
-                android_errorWriteLog(0x534e4554, "116230453");
-                return DEAD_OBJECT;
-            } else {
-                registerClient(client);
-                return NO_ERROR;
-            }
-        } break;
-
-        case OPEN_STREAM: {
-            CHECK_INTERFACE(IAAudioService, data, reply);
-            request.readFromParcel(&data);
-            result = request.validate();
-            if (result != AAUDIO_OK) {
-                streamHandle = result;
-            } else {
-                //ALOGD("BnAAudioService::client openStream request dump --------------------");
-                //request.dump();
-                // Override the uid and pid from the client in case they are incorrect.
-                request.setUserId(IPCThreadState::self()->getCallingUid());
-                request.setProcessId(IPCThreadState::self()->getCallingPid());
-                streamHandle = openStream(request, configuration);
-                //ALOGD("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X",
-                //        streamHandle);
-            }
-            reply->writeInt32(streamHandle);
-            configuration.writeToParcel(reply);
-            return NO_ERROR;
-        } break;
-
-        case CLOSE_STREAM: {
-            CHECK_INTERFACE(IAAudioService, data, reply);
-            status = data.readInt32(&streamHandle);
-            if (status != NO_ERROR) {
-                ALOGE("BnAAudioService::%s(CLOSE_STREAM) streamHandle failed!", __func__);
-                return status;
-            }
-            result = closeStream(streamHandle);
-            //ALOGD("BnAAudioService::onTransact CLOSE_STREAM 0x%08X, result = %d",
-            //      streamHandle, result);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        } break;
-
-        case GET_STREAM_DESCRIPTION: {
-            CHECK_INTERFACE(IAAudioService, data, reply);
-            status = data.readInt32(&streamHandle);
-            if (status != NO_ERROR) {
-                ALOGE("BnAAudioService::%s(GET_STREAM_DESCRIPTION) streamHandle failed!", __func__);
-                return status;
-            }
-            aaudio::AudioEndpointParcelable parcelable;
-            result = getStreamDescription(streamHandle, parcelable);
-            if (result != AAUDIO_OK) {
-                return AAudioConvert_aaudioToAndroidStatus(result);
-            }
-            status = reply->writeInt32(result);
-            if (status != NO_ERROR) {
-                return status;
-            }
-            return parcelable.writeToParcel(reply);
-        } break;
-
-        case START_STREAM: {
-            CHECK_INTERFACE(IAAudioService, data, reply);
-            status = data.readInt32(&streamHandle);
-            if (status != NO_ERROR) {
-                ALOGE("BnAAudioService::%s(START_STREAM) streamHandle failed!", __func__);
-                return status;
-            }
-            result = startStream(streamHandle);
-            ALOGV("BnAAudioService::onTransact START_STREAM 0x%08X, result = %d",
-                    streamHandle, result);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        } break;
-
-        case PAUSE_STREAM: {
-            CHECK_INTERFACE(IAAudioService, data, reply);
-            status = data.readInt32(&streamHandle);
-            if (status != NO_ERROR) {
-                ALOGE("BnAAudioService::%s(PAUSE_STREAM) streamHandle failed!", __func__);
-                return status;
-            }
-            result = pauseStream(streamHandle);
-            ALOGV("BnAAudioService::onTransact PAUSE_STREAM 0x%08X, result = %d",
-                  streamHandle, result);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        } break;
-
-        case STOP_STREAM: {
-            CHECK_INTERFACE(IAAudioService, data, reply);
-            status = data.readInt32(&streamHandle);
-            if (status != NO_ERROR) {
-                ALOGE("BnAAudioService::%s(STOP_STREAM) streamHandle failed!", __func__);
-                return status;
-            }
-            result = stopStream(streamHandle);
-            ALOGV("BnAAudioService::onTransact STOP_STREAM 0x%08X, result = %d",
-                  streamHandle, result);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        } break;
-
-        case FLUSH_STREAM: {
-            CHECK_INTERFACE(IAAudioService, data, reply);
-            status = data.readInt32(&streamHandle);
-            if (status != NO_ERROR) {
-                ALOGE("BnAAudioService::%s(FLUSH_STREAM) streamHandle failed!", __func__);
-                return status;
-            }
-            result = flushStream(streamHandle);
-            ALOGV("BnAAudioService::onTransact FLUSH_STREAM 0x%08X, result = %d",
-                    streamHandle, result);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        } break;
-
-        case REGISTER_AUDIO_THREAD: {
-            CHECK_INTERFACE(IAAudioService, data, reply);
-            status = data.readInt32(&streamHandle);
-            if (status != NO_ERROR) {
-                ALOGE("BnAAudioService::%s(REGISTER_AUDIO_THREAD) streamHandle failed!", __func__);
-                return status;
-            }
-            status = data.readInt32(&tid);
-            if (status != NO_ERROR) {
-                ALOGE("BnAAudioService::%s(REGISTER_AUDIO_THREAD) tid failed!", __func__);
-                return status;
-            }
-            status = data.readInt64(&nanoseconds);
-            if (status != NO_ERROR) {
-                ALOGE("BnAAudioService::%s(REGISTER_AUDIO_THREAD) nanoseconds failed!", __func__);
-                return status;
-            }
-            result = registerAudioThread(streamHandle, tid, nanoseconds);
-            ALOGV("BnAAudioService::%s(REGISTER_AUDIO_THREAD) 0x%08X, result = %d",
-                    __func__, streamHandle, result);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        } break;
-
-        case UNREGISTER_AUDIO_THREAD: {
-            CHECK_INTERFACE(IAAudioService, data, reply);
-            status = data.readInt32(&streamHandle);
-            if (status != NO_ERROR) {
-                ALOGE("BnAAudioService::%s(UNREGISTER_AUDIO_THREAD) streamHandle failed!", __func__);
-                return status;
-            }
-            status = data.readInt32(&tid);
-            if (status != NO_ERROR) {
-                ALOGE("BnAAudioService::%s(UNREGISTER_AUDIO_THREAD) tid failed!", __func__);
-                return status;
-            }
-            result = unregisterAudioThread(streamHandle, tid);
-            ALOGV("BnAAudioService::onTransact UNREGISTER_AUDIO_THREAD 0x%08X, result = %d",
-                    streamHandle, result);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        } break;
-
-        default:
-            // ALOGW("BnAAudioService::onTransact not handled %u", code);
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-} /* namespace android */
diff --git a/media/libaaudio/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h
deleted file mode 100644
index 6bdb826..0000000
--- a/media/libaaudio/src/binding/IAAudioService.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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 ANDROID_AAUDIO_IAAUDIO_SERVICE_H
-#define ANDROID_AAUDIO_IAAUDIO_SERVICE_H
-
-#include <stdint.h>
-#include <utils/RefBase.h>
-#include <binder/TextOutput.h>
-#include <binder/IInterface.h>
-
-#include <aaudio/AAudio.h>
-
-#include "binding/AAudioCommon.h"
-#include "binding/AAudioServiceDefinitions.h"
-#include "binding/AAudioStreamConfiguration.h"
-#include "binding/AAudioStreamRequest.h"
-#include "binding/AudioEndpointParcelable.h"
-#include "binding/IAAudioClient.h"
-
-namespace android {
-
-#define AAUDIO_SERVICE_NAME  "media.aaudio"
-
-// Interface (our AIDL) - service methods called by client
-class IAAudioService : public IInterface {
-public:
-
-    DECLARE_META_INTERFACE(AAudioService);
-
-    // Register an object to receive audio input/output change and track notifications.
-    // For a given calling pid, AAudio service disregards any registrations after the first.
-    // Thus the IAAudioClient must be a singleton per process.
-    virtual void registerClient(const sp<IAAudioClient>& client) = 0;
-
-    /**
-     * @param request info needed to create the stream
-     * @param configuration contains information about the created stream
-     * @return handle to the stream or a negative error
-     */
-    virtual aaudio::aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
-                                     aaudio::AAudioStreamConfiguration &configurationOutput) = 0;
-
-    virtual aaudio_result_t closeStream(aaudio::aaudio_handle_t streamHandle) = 0;
-
-    /* Get an immutable description of the in-memory queues
-    * used to communicate with the underlying HAL or Service.
-    */
-    virtual aaudio_result_t getStreamDescription(aaudio::aaudio_handle_t streamHandle,
-                                               aaudio::AudioEndpointParcelable &parcelable) = 0;
-
-    /**
-     * Start the flow of data.
-     * This is asynchronous. When complete, the service will send a STARTED event.
-     */
-    virtual aaudio_result_t startStream(aaudio::aaudio_handle_t streamHandle) = 0;
-
-    /**
-     * Stop the flow of data such that start() can resume without loss of data.
-     * This is asynchronous. When complete, the service will send a PAUSED event.
-     */
-    virtual aaudio_result_t pauseStream(aaudio::aaudio_handle_t streamHandle) = 0;
-
-    /**
-     * Stop the flow of data such that the data currently in the buffer is played.
-     * This is asynchronous. When complete, the service will send a STOPPED event.
-     */
-    virtual aaudio_result_t stopStream(aaudio::aaudio_handle_t streamHandle) = 0;
-
-    /**
-     *  Discard any data held by the underlying HAL or Service.
-     * This is asynchronous. When complete, the service will send a FLUSHED event.
-     */
-    virtual aaudio_result_t flushStream(aaudio::aaudio_handle_t streamHandle) = 0;
-
-    /**
-     * Manage the specified thread as a low latency audio thread.
-     */
-    virtual aaudio_result_t registerAudioThread(aaudio::aaudio_handle_t streamHandle,
-                                              pid_t clientThreadId,
-                                              int64_t periodNanoseconds) = 0;
-
-    virtual aaudio_result_t unregisterAudioThread(aaudio::aaudio_handle_t streamHandle,
-                                                pid_t clientThreadId) = 0;
-};
-
-class BnAAudioService : public BnInterface<IAAudioService> {
-public:
-    virtual status_t onTransact(uint32_t code, const Parcel& data,
-                                Parcel* reply, uint32_t flags = 0);
-
-};
-
-} /* namespace android */
-
-#endif //ANDROID_AAUDIO_IAAUDIO_SERVICE_H
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.cpp b/media/libaaudio/src/binding/RingBufferParcelable.cpp
index 4996b3f..a4b3cec 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.cpp
+++ b/media/libaaudio/src/binding/RingBufferParcelable.cpp
@@ -29,8 +29,29 @@
 
 using namespace aaudio;
 
-RingBufferParcelable::RingBufferParcelable() {}
-RingBufferParcelable::~RingBufferParcelable() {}
+RingBufferParcelable::RingBufferParcelable(const RingBuffer& parcelable)
+        : mReadCounterParcelable(std::move(parcelable.readCounterParcelable)),
+          mWriteCounterParcelable(std::move(parcelable.writeCounterParcelable)),
+          mDataParcelable(std::move(parcelable.dataParcelable)),
+          mBytesPerFrame(parcelable.bytesPerFrame),
+          mFramesPerBurst(parcelable.framesPerBurst),
+          mCapacityInFrames(parcelable.capacityInFrames),
+          mFlags(static_cast<RingbufferFlags>(parcelable.flags)) {
+    static_assert(sizeof(mFlags) == sizeof(parcelable.flags));
+}
+
+RingBuffer RingBufferParcelable::parcelable() const {
+    RingBuffer result;
+    result.readCounterParcelable = std::move(mReadCounterParcelable).parcelable();
+    result.writeCounterParcelable = std::move(mWriteCounterParcelable).parcelable();
+    result.dataParcelable = std::move(mDataParcelable).parcelable();
+    result.bytesPerFrame = mBytesPerFrame;
+    result.framesPerBurst = mFramesPerBurst;
+    result.capacityInFrames = mCapacityInFrames;
+    static_assert(sizeof(mFlags) == sizeof(result.flags));
+    result.flags = static_cast<int32_t>(mFlags);
+    return result;
+}
 
 // TODO This assumes that all three use the same SharedMemoryParcelable
 void RingBufferParcelable::setupMemory(int32_t sharedMemoryIndex,
@@ -76,58 +97,6 @@
     mCapacityInFrames = capacityInFrames;
 }
 
-/**
- * The read and write must be symmetric.
- */
-status_t RingBufferParcelable::writeToParcel(Parcel* parcel) const {
-    status_t status = AAudioConvert_aaudioToAndroidStatus(validate());
-    if (status != NO_ERROR) goto error;
-
-    status = parcel->writeInt32(mCapacityInFrames);
-    if (status != NO_ERROR) goto error;
-    if (mCapacityInFrames > 0) {
-        status = parcel->writeInt32(mBytesPerFrame);
-        if (status != NO_ERROR) goto error;
-        status = parcel->writeInt32(mFramesPerBurst);
-        if (status != NO_ERROR) goto error;
-        status = parcel->writeInt32(mFlags);
-        if (status != NO_ERROR) goto error;
-        status = mReadCounterParcelable.writeToParcel(parcel);
-        if (status != NO_ERROR) goto error;
-        status = mWriteCounterParcelable.writeToParcel(parcel);
-        if (status != NO_ERROR) goto error;
-        status = mDataParcelable.writeToParcel(parcel);
-        if (status != NO_ERROR) goto error;
-    }
-    return NO_ERROR;
-error:
-    ALOGE("%s returning %d", __func__, status);
-    return status;
-}
-
-status_t RingBufferParcelable::readFromParcel(const Parcel* parcel) {
-    status_t status = parcel->readInt32(&mCapacityInFrames);
-    if (status != NO_ERROR) goto error;
-    if (mCapacityInFrames > 0) {
-        status = parcel->readInt32(&mBytesPerFrame);
-        if (status != NO_ERROR) goto error;
-        status = parcel->readInt32(&mFramesPerBurst);
-        if (status != NO_ERROR) goto error;
-        status = parcel->readInt32((int32_t *)&mFlags);
-        if (status != NO_ERROR) goto error;
-        status = mReadCounterParcelable.readFromParcel(parcel);
-        if (status != NO_ERROR) goto error;
-        status = mWriteCounterParcelable.readFromParcel(parcel);
-        if (status != NO_ERROR) goto error;
-        status = mDataParcelable.readFromParcel(parcel);
-        if (status != NO_ERROR) goto error;
-    }
-    return AAudioConvert_aaudioToAndroidStatus(validate());
-error:
-    ALOGE("%s returning %d", __func__, status);
-    return status;
-}
-
 aaudio_result_t RingBufferParcelable::resolve(SharedMemoryParcelable *memoryParcels, RingBufferDescriptor *descriptor) {
     aaudio_result_t result;
 
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.h b/media/libaaudio/src/binding/RingBufferParcelable.h
index 1dbcf07..2508cea 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.h
+++ b/media/libaaudio/src/binding/RingBufferParcelable.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 
+#include <aaudio/RingBuffer.h>
 #include <binder/Parcelable.h>
 
 #include "binding/AAudioServiceDefinitions.h"
@@ -26,10 +27,12 @@
 
 namespace aaudio {
 
-class RingBufferParcelable : public Parcelable {
+class RingBufferParcelable  {
 public:
-    RingBufferParcelable();
-    virtual ~RingBufferParcelable();
+    RingBufferParcelable() = default;
+
+    // Construct based on a parcelable representation.
+    explicit RingBufferParcelable(const RingBuffer& parcelable);
 
     // TODO This assumes that all three use the same SharedMemoryParcelable
     void setupMemory(int32_t sharedMemoryIndex,
@@ -57,21 +60,14 @@
 
     bool isFileDescriptorSafe(SharedMemoryParcelable *memoryParcels);
 
-    /**
-     * The read and write must be symmetric.
-     */
-    virtual status_t writeToParcel(Parcel* parcel) const override;
-
-    virtual status_t readFromParcel(const Parcel* parcel) override;
-
     aaudio_result_t resolve(SharedMemoryParcelable *memoryParcels, RingBufferDescriptor *descriptor);
 
     void dump();
 
+    // Extract a parcelable representation of this object.
+    RingBuffer parcelable() const;
+
 private:
-
-    aaudio_result_t validate() const;
-
     SharedRegionParcelable  mReadCounterParcelable;
     SharedRegionParcelable  mWriteCounterParcelable;
     SharedRegionParcelable  mDataParcelable;
@@ -79,6 +75,8 @@
     int32_t                 mFramesPerBurst = 0;    // for ISOCHRONOUS queues
     int32_t                 mCapacityInFrames = 0;  // zero if unused
     RingbufferFlags         mFlags = RingbufferFlags::NONE;
+
+    aaudio_result_t validate() const;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index b6e8472..685b779 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -18,6 +18,7 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <inttypes.h>
 #include <stdint.h>
 #include <stdio.h>
 
@@ -33,61 +34,36 @@
 using android::base::unique_fd;
 using android::NO_ERROR;
 using android::status_t;
-using android::Parcel;
-using android::Parcelable;
+using android::media::SharedFileRegion;
 
 using namespace aaudio;
 
-SharedMemoryParcelable::SharedMemoryParcelable() {}
-SharedMemoryParcelable::~SharedMemoryParcelable() {};
+SharedMemoryParcelable::SharedMemoryParcelable(SharedFileRegion&& parcelable) {
+    mFd = parcelable.fd.release();
+    mSizeInBytes = parcelable.size;
+    mOffsetInBytes = parcelable.offset;
+}
+
+SharedFileRegion SharedMemoryParcelable::parcelable() && {
+    SharedFileRegion result;
+    result.fd.reset(std::move(mFd));
+    result.size = mSizeInBytes;
+    result.offset = mOffsetInBytes;
+    return result;
+}
+
+SharedMemoryParcelable SharedMemoryParcelable::dup() const {
+    SharedMemoryParcelable result;
+    result.setup(mFd, static_cast<int32_t>(mSizeInBytes));
+    return result;
+}
 
 void SharedMemoryParcelable::setup(const unique_fd& fd, int32_t sizeInBytes) {
-    mFd.reset(dup(fd.get())); // store a duplicate fd
+    mFd.reset(::dup(fd.get())); // store a duplicate fd
     ALOGV("setup(fd = %d -> %d, size = %d) this = %p\n", fd.get(), mFd.get(), sizeInBytes, this);
     mSizeInBytes = sizeInBytes;
 }
 
-status_t SharedMemoryParcelable::writeToParcel(Parcel* parcel) const {
-    status_t status = AAudioConvert_aaudioToAndroidStatus(validate());
-    if (status != NO_ERROR) return status;
-
-    status = parcel->writeInt32(mSizeInBytes);
-    if (status != NO_ERROR) return status;
-    if (mSizeInBytes > 0) {
-        ALOGV("writeToParcel() mFd = %d, this = %p\n", mFd.get(), this);
-        status = parcel->writeUniqueFileDescriptor(mFd);
-        ALOGE_IF(status != NO_ERROR, "SharedMemoryParcelable writeDupFileDescriptor failed : %d",
-                 status);
-    }
-    return status;
-}
-
-status_t SharedMemoryParcelable::readFromParcel(const Parcel* parcel) {
-    status_t status = parcel->readInt32(&mSizeInBytes);
-    if (status != NO_ERROR) goto error;
-
-    if (mSizeInBytes > 0) {
-        // The Parcel owns the file descriptor and will close it later.
-        unique_fd mmapFd;
-        status = parcel->readUniqueFileDescriptor(&mmapFd);
-        if (status != NO_ERROR) {
-            ALOGE("readFromParcel() readUniqueFileDescriptor() failed : %d", status);
-            goto error;
-        }
-
-        // Resolve the memory now while we still have the FD from the Parcel.
-        // Closing the FD will not affect the shared memory once mmap() has been called.
-        aaudio_result_t result = resolveSharedMemory(mmapFd);
-        status = AAudioConvert_aaudioToAndroidStatus(result);
-        if (status != NO_ERROR) goto error;
-    }
-
-    return AAudioConvert_aaudioToAndroidStatus(validate());
-
-error:
-    return status;
-}
-
 aaudio_result_t SharedMemoryParcelable::close() {
     if (mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) {
         int err = munmap(mResolvedAddress, mSizeInBytes);
@@ -104,7 +80,7 @@
     mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ | PROT_WRITE,
                                         MAP_SHARED, fd.get(), 0);
     if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
-        ALOGE("mmap() failed for fd = %d, nBytes = %d, errno = %s",
+        ALOGE("mmap() failed for fd = %d, nBytes = %" PRId64 ", errno = %s",
               fd.get(), mSizeInBytes, strerror(errno));
         return AAUDIO_ERROR_INTERNAL;
     }
@@ -118,7 +94,7 @@
         return AAUDIO_ERROR_OUT_OF_RANGE;
     } else if ((offsetInBytes + sizeInBytes) > mSizeInBytes) {
         ALOGE("out of range, offsetInBytes = %d, "
-                      "sizeInBytes = %d, mSizeInBytes = %d",
+                      "sizeInBytes = %d, mSizeInBytes = %" PRId64,
               offsetInBytes, sizeInBytes, mSizeInBytes);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
@@ -148,7 +124,11 @@
 
 aaudio_result_t SharedMemoryParcelable::validate() const {
     if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
-        ALOGE("invalid mSizeInBytes = %d", mSizeInBytes);
+        ALOGE("invalid mSizeInBytes = %" PRId64, mSizeInBytes);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+    if (mOffsetInBytes != 0) {
+        ALOGE("invalid mOffsetInBytes = %" PRId64, mOffsetInBytes);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
     return AAUDIO_OK;
@@ -156,5 +136,5 @@
 
 void SharedMemoryParcelable::dump() {
     ALOGD("mFd = %d", mFd.get());
-    ALOGD("mSizeInBytes = %d", mSizeInBytes);
+    ALOGD("mSizeInBytes = %" PRId64, mSizeInBytes);
 }
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.h b/media/libaaudio/src/binding/SharedMemoryParcelable.h
index 3927f58..1f2c335 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.h
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.h
@@ -21,8 +21,7 @@
 #include <sys/mman.h>
 
 #include <android-base/unique_fd.h>
-#include <binder/Parcel.h>
-#include <binder/Parcelable.h>
+#include <android/media/SharedFileRegion.h>
 
 namespace aaudio {
 
@@ -36,10 +35,14 @@
  * It may be divided into several regions.
  * The memory can be shared using Binder or simply shared between threads.
  */
-class SharedMemoryParcelable : public android::Parcelable {
+class SharedMemoryParcelable {
 public:
-    SharedMemoryParcelable();
-    virtual ~SharedMemoryParcelable();
+    SharedMemoryParcelable() = default;
+
+    // Ctor from a parcelable representation.
+    // Since the parcelable object owns a unique FD, move semantics are provided to avoid the need
+    // to dupe.
+    explicit SharedMemoryParcelable(android::media::SharedFileRegion&& parcelable);
 
     /**
      * Make a dup() of the fd and store it for later use.
@@ -49,10 +52,6 @@
      */
     void setup(const android::base::unique_fd& fd, int32_t sizeInBytes);
 
-    virtual android::status_t writeToParcel(android::Parcel* parcel) const override;
-
-    virtual android::status_t readFromParcel(const android::Parcel* parcel) override;
-
     // mmap() shared memory
     aaudio_result_t resolve(int32_t offsetInBytes, int32_t sizeInBytes, void **regionAddressPtr);
 
@@ -63,20 +62,23 @@
 
     void dump();
 
-protected:
+    // Extract a parcelable representation of this object.
+    // Since we own a unique FD, move semantics are provided to avoid the need to dupe.
+    android::media::SharedFileRegion parcelable() &&;
 
-#define MMAP_UNRESOLVED_ADDRESS    reinterpret_cast<uint8_t*>(MAP_FAILED)
-
-    aaudio_result_t resolveSharedMemory(const android::base::unique_fd& fd);
-
-    android::base::unique_fd   mFd;
-    int32_t                    mSizeInBytes = 0;
-    uint8_t                   *mResolvedAddress = MMAP_UNRESOLVED_ADDRESS;
+    // Copy this instance. Duplicates the underlying FD.
+    SharedMemoryParcelable dup() const;
 
 private:
+#define MMAP_UNRESOLVED_ADDRESS    reinterpret_cast<uint8_t*>(MAP_FAILED)
 
+    android::base::unique_fd   mFd;
+    int64_t                    mSizeInBytes = 0;
+    int64_t                    mOffsetInBytes = 0;
+    uint8_t                   *mResolvedAddress = MMAP_UNRESOLVED_ADDRESS;
+
+    aaudio_result_t resolveSharedMemory(const android::base::unique_fd& fd);
     aaudio_result_t validate() const;
-
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.cpp b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
index c776116..56b99c0 100644
--- a/media/libaaudio/src/binding/SharedRegionParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
@@ -36,8 +36,18 @@
 
 using namespace aaudio;
 
-SharedRegionParcelable::SharedRegionParcelable() {}
-SharedRegionParcelable::~SharedRegionParcelable() {}
+SharedRegionParcelable::SharedRegionParcelable(const SharedRegion& parcelable)
+        : mSharedMemoryIndex(parcelable.sharedMemoryIndex),
+          mOffsetInBytes(parcelable.offsetInBytes),
+          mSizeInBytes(parcelable.sizeInBytes) {}
+
+SharedRegion SharedRegionParcelable::parcelable() const {
+    SharedRegion result;
+    result.sharedMemoryIndex = mSharedMemoryIndex;
+    result.offsetInBytes = mOffsetInBytes;
+    result.sizeInBytes = mSizeInBytes;
+    return result;
+}
 
 void SharedRegionParcelable::setup(int32_t sharedMemoryIndex,
                                    int32_t offsetInBytes,
@@ -47,41 +57,6 @@
     mSizeInBytes = sizeInBytes;
 }
 
-status_t SharedRegionParcelable::writeToParcel(Parcel* parcel) const {
-    status_t status = AAudioConvert_aaudioToAndroidStatus(validate());
-    if (status != NO_ERROR) goto error;
-
-    status = parcel->writeInt32(mSizeInBytes);
-    if (status != NO_ERROR) goto error;
-    if (mSizeInBytes > 0) {
-        status = parcel->writeInt32(mSharedMemoryIndex);
-        if (status != NO_ERROR) goto error;
-        status = parcel->writeInt32(mOffsetInBytes);
-        if (status != NO_ERROR) goto error;
-    }
-    return NO_ERROR;
-
-error:
-    ALOGE("%s returning %d", __func__, status);
-    return status;
-}
-
-status_t SharedRegionParcelable::readFromParcel(const Parcel* parcel) {
-    status_t status = parcel->readInt32(&mSizeInBytes);
-    if (status != NO_ERROR) goto error;
-    if (mSizeInBytes > 0) {
-        status = parcel->readInt32(&mSharedMemoryIndex);
-        if (status != NO_ERROR) goto error;
-        status = parcel->readInt32(&mOffsetInBytes);
-        if (status != NO_ERROR) goto error;
-    }
-    return AAudioConvert_aaudioToAndroidStatus(validate());
-
-error:
-    ALOGE("%s returning %d", __func__, status);
-    return status;
-}
-
 aaudio_result_t SharedRegionParcelable::resolve(SharedMemoryParcelable *memoryParcels,
                                               void **regionAddressPtr) {
     if (mSizeInBytes == 0) {
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.h b/media/libaaudio/src/binding/SharedRegionParcelable.h
index 0cd8c04..c15fc30 100644
--- a/media/libaaudio/src/binding/SharedRegionParcelable.h
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.h
@@ -20,41 +20,39 @@
 #include <stdint.h>
 
 #include <sys/mman.h>
-#include <binder/Parcelable.h>
 
 #include <aaudio/AAudio.h>
+#include <aaudio/SharedRegion.h>
 
 #include "binding/SharedMemoryParcelable.h"
 
 using android::status_t;
-using android::Parcel;
-using android::Parcelable;
 
 namespace aaudio {
 
-class SharedRegionParcelable : public Parcelable {
+class SharedRegionParcelable {
 public:
-    SharedRegionParcelable();
-    virtual ~SharedRegionParcelable();
+    SharedRegionParcelable() = default;
+
+    // Construct based on a parcelable representation.
+    explicit SharedRegionParcelable(const SharedRegion& parcelable);
 
     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;
-
     aaudio_result_t resolve(SharedMemoryParcelable *memoryParcels, void **regionAddressPtr);
 
     bool isFileDescriptorSafe(SharedMemoryParcelable *memoryParcels);
 
     void dump();
 
-protected:
+    // Extract a parcelable representation of this object.
+    SharedRegion parcelable() const;
+
+private:
     int32_t mSharedMemoryIndex = -1;
     int32_t mOffsetInBytes     = 0;
     int32_t mSizeInBytes       = 0;
 
-private:
     aaudio_result_t validate() const;
 };
 
diff --git a/media/libaaudio/src/binding/aidl/aaudio/Endpoint.aidl b/media/libaaudio/src/binding/aidl/aaudio/Endpoint.aidl
new file mode 100644
index 0000000..3600b6a
--- /dev/null
+++ b/media/libaaudio/src/binding/aidl/aaudio/Endpoint.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package aaudio;
+
+import aaudio.RingBuffer;
+import android.media.SharedFileRegion;
+
+parcelable Endpoint {
+    // Set capacityInFrames to zero if Queue is unused.
+    RingBuffer upMessageQueueParcelable;   // server to client
+    RingBuffer downMessageQueueParcelable; // to server
+    RingBuffer upDataQueueParcelable;      // eg. record, could share same queue
+    RingBuffer downDataQueueParcelable;    // eg. playback
+    SharedFileRegion[] sharedMemories;
+}
diff --git a/media/libaaudio/src/binding/aidl/aaudio/IAAudioClient.aidl b/media/libaaudio/src/binding/aidl/aaudio/IAAudioClient.aidl
new file mode 100644
index 0000000..a010dbc
--- /dev/null
+++ b/media/libaaudio/src/binding/aidl/aaudio/IAAudioClient.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package aaudio;
+
+interface IAAudioClient {
+    oneway void onStreamChange(int handle, int opcode, int value);
+}
diff --git a/media/libaaudio/src/binding/aidl/aaudio/IAAudioService.aidl b/media/libaaudio/src/binding/aidl/aaudio/IAAudioService.aidl
new file mode 100644
index 0000000..44d2211
--- /dev/null
+++ b/media/libaaudio/src/binding/aidl/aaudio/IAAudioService.aidl
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package aaudio;
+
+import aaudio.Endpoint;
+import aaudio.IAAudioClient;
+import aaudio.StreamParameters;
+import aaudio.StreamRequest;
+
+interface IAAudioService {
+    /**
+     * Register an object to receive audio input/output change and track notifications.
+     * For a given calling pid, AAudio service disregards any registrations after the first.
+     * Thus the IAAudioClient must be a singleton per process.
+     */
+    void registerClient(IAAudioClient client);
+
+    /**
+     * @param request info needed to create the stream
+     * @param paramsOut contains information about the created stream
+     * @return handle to the stream or a negative error
+     */
+    int openStream(in StreamRequest request,
+                   out StreamParameters paramsOut);
+
+    int closeStream(int streamHandle);
+
+    /*
+     * Get an immutable description of the in-memory queues
+     * used to communicate with the underlying HAL or Service.
+     */
+    int getStreamDescription(int streamHandle, out Endpoint endpoint);
+
+    /**
+     * Start the flow of data.
+     * This is asynchronous. When complete, the service will send a STARTED event.
+     */
+    int startStream(int streamHandle);
+
+    /**
+     * Stop the flow of data such that start() can resume without loss of data.
+     * This is asynchronous. When complete, the service will send a PAUSED event.
+     */
+    int pauseStream(int streamHandle);
+
+    /**
+     * Stop the flow of data such that the data currently in the buffer is played.
+     * This is asynchronous. When complete, the service will send a STOPPED event.
+     */
+    int stopStream(int streamHandle);
+
+    /**
+     *  Discard any data held by the underlying HAL or Service.
+     * This is asynchronous. When complete, the service will send a FLUSHED event.
+     */
+    int flushStream(int streamHandle);
+
+    /**
+     * Manage the specified thread as a low latency audio thread.
+     */
+    int registerAudioThread(int streamHandle,
+                            int clientThreadId,
+                            long periodNanoseconds);
+
+    int unregisterAudioThread(int streamHandle,
+                              int clientThreadId);
+}
diff --git a/media/libaaudio/src/binding/aidl/aaudio/RingBuffer.aidl b/media/libaaudio/src/binding/aidl/aaudio/RingBuffer.aidl
new file mode 100644
index 0000000..a58b33a
--- /dev/null
+++ b/media/libaaudio/src/binding/aidl/aaudio/RingBuffer.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package aaudio;
+
+import aaudio.SharedRegion;
+
+parcelable RingBuffer {
+    SharedRegion        readCounterParcelable;
+    SharedRegion        writeCounterParcelable;
+    SharedRegion        dataParcelable;
+    int                 bytesPerFrame;     // index is in frames
+    int                 framesPerBurst;    // for ISOCHRONOUS queues
+    int                 capacityInFrames;  // zero if unused
+    int /* RingbufferFlags */ flags;  // = RingbufferFlags::NONE;
+}
\ No newline at end of file
diff --git a/media/libaaudio/src/binding/aidl/aaudio/SharedRegion.aidl b/media/libaaudio/src/binding/aidl/aaudio/SharedRegion.aidl
new file mode 100644
index 0000000..26153e8
--- /dev/null
+++ b/media/libaaudio/src/binding/aidl/aaudio/SharedRegion.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package aaudio;
+
+parcelable SharedRegion {
+    int sharedMemoryIndex;
+    int offsetInBytes;
+    int sizeInBytes;
+}
diff --git a/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl b/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl
new file mode 100644
index 0000000..b7c4f70
--- /dev/null
+++ b/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package aaudio;
+
+import android.media.audio.common.AudioFormat;
+
+parcelable StreamParameters {
+    int                                       samplesPerFrame;  //      = AAUDIO_UNSPECIFIED;
+    int                                       sampleRate;  //           = AAUDIO_UNSPECIFIED;
+    int                                       deviceId;  //             = AAUDIO_UNSPECIFIED;
+    int /* aaudio_sharing_mode_t */           sharingMode;  //          = AAUDIO_SHARING_MODE_SHARED;
+    AudioFormat                               audioFormat;  //          = AUDIO_FORMAT_DEFAULT;
+    int /* aaudio_direction_t */              direction;  //            = AAUDIO_DIRECTION_OUTPUT;
+    int /* aaudio_usage_t */                  usage;  //                = AAUDIO_UNSPECIFIED;
+    int /* aaudio_content_type_t */           contentType;  //          = AAUDIO_UNSPECIFIED;
+    int /* aaudio_input_preset_t */           inputPreset;  //          = AAUDIO_UNSPECIFIED;
+    int                                       bufferCapacity;  //       = AAUDIO_UNSPECIFIED;
+    int /* aaudio_allowed_capture_policy_t */ allowedCapturePolicy;  // = AAUDIO_UNSPECIFIED;
+    int /* aaudio_session_id_t */             sessionId;  //            = AAUDIO_SESSION_ID_NONE;
+    boolean                                   isPrivacySensitive;  //   = false;
+}
diff --git a/media/libaaudio/src/binding/aidl/aaudio/StreamRequest.aidl b/media/libaaudio/src/binding/aidl/aaudio/StreamRequest.aidl
new file mode 100644
index 0000000..9bf4077
--- /dev/null
+++ b/media/libaaudio/src/binding/aidl/aaudio/StreamRequest.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package aaudio;
+
+import aaudio.StreamParameters;
+
+parcelable StreamRequest {
+    StreamParameters    params;
+    int                 userId; // = (uid_t) -1;
+    int                 processId; // = (pid_t) -1;
+    boolean             sharingModeMatchRequired; // = false;
+    boolean             inService; // = false; // Stream opened by AAudioservice
+}
\ No newline at end of file
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index ac7ad9a..2688597 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -34,7 +34,6 @@
 #include "AudioEndpointParcelable.h"
 #include "binding/AAudioStreamRequest.h"
 #include "binding/AAudioStreamConfiguration.h"
-#include "binding/IAAudioService.h"
 #include "binding/AAudioServiceMessage.h"
 #include "core/AudioGlobal.h"
 #include "core/AudioStreamBuilder.h"
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 63be978..162f098 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -20,7 +20,6 @@
 #include <stdint.h>
 #include <aaudio/AAudio.h>
 
-#include "binding/IAAudioService.h"
 #include "binding/AudioEndpointParcelable.h"
 #include "binding/AAudioServiceInterface.h"
 #include "client/IsochronousClockModel.h"
@@ -29,7 +28,6 @@
 #include "utility/AudioClock.h"
 
 using android::sp;
-using android::IAAudioService;
 
 namespace aaudio {
 
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.h b/media/libaaudio/src/client/AudioStreamInternalCapture.h
index 1d65d87..251a7f2 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.h
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.h
@@ -23,7 +23,6 @@
 #include "client/AudioStreamInternal.h"
 
 using android::sp;
-using android::IAAudioService;
 
 namespace aaudio {
 
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index b47b472..980592c 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -32,6 +32,7 @@
 #define LOG_TAG (mInService ? "AudioStreamInternalPlay_Service" \
                             : "AudioStreamInternalPlay_Client")
 
+using android::status_t;
 using android::WrappingBuffer;
 
 using namespace aaudio;
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.h b/media/libaaudio/src/client/AudioStreamInternalPlay.h
index be95da6..7b1cddc 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.h
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.h
@@ -25,7 +25,6 @@
 #include "client/AudioStreamInternal.h"
 
 using android::sp;
-using android::IAAudioService;
 
 namespace aaudio {
 
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 8935d57..95d6543 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -11,10 +11,12 @@
     defaults: ["libaaudio_tests_defaults"],
     srcs: ["test_marshalling.cpp"],
     shared_libs: [
+        "aaudio-aidl-cpp",
         "libaaudio_internal",
         "libbinder",
         "libcutils",
         "libutils",
+        "shared-file-region-aidl-unstable-cpp",
     ],
 }
 
diff --git a/media/libaaudio/tests/test_marshalling.cpp b/media/libaaudio/tests/test_marshalling.cpp
index c51fbce..49213dc 100644
--- a/media/libaaudio/tests/test_marshalling.cpp
+++ b/media/libaaudio/tests/test_marshalling.cpp
@@ -33,6 +33,29 @@
 using namespace android;
 using namespace aaudio;
 
+template<typename T>
+T copy(const T& object) {
+    return T(object);
+}
+
+template<>
+SharedMemoryParcelable copy<SharedMemoryParcelable>(const SharedMemoryParcelable& object) {
+    return object.dup();
+}
+
+template<typename T>
+void writeToParcel(const T& object, Parcel* parcel) {
+    copy(object).parcelable().writeToParcel(parcel);
+}
+
+template<typename T>
+T readFromParcel(const Parcel& parcel) {
+    using ParcelType = std::decay_t<decltype(std::declval<T>().parcelable())>;
+    ParcelType parcelable;
+    parcelable.readFromParcel(&parcel);
+    return T(std::move(parcelable));
+}
+
 // Test adding one value.
 TEST(test_marshalling, aaudio_one_read_write) {
     Parcel parcel;
@@ -48,7 +71,6 @@
 // Test SharedMemoryParcel.
 TEST(test_marshalling, aaudio_shared_memory) {
     SharedMemoryParcelable sharedMemoryA;
-    SharedMemoryParcelable sharedMemoryB;
     const size_t memSizeBytes = 840;
     unique_fd fd(ashmem_create_region("TestMarshalling", memSizeBytes));
     ASSERT_LE(0, fd);
@@ -63,10 +85,10 @@
 
     Parcel parcel;
     size_t pos = parcel.dataPosition();
-    sharedMemoryA.writeToParcel(&parcel);
+    writeToParcel(sharedMemoryA, &parcel);
 
     parcel.setDataPosition(pos);
-    sharedMemoryB.readFromParcel(&parcel);
+    SharedMemoryParcelable sharedMemoryB = readFromParcel<SharedMemoryParcelable>(parcel);
     EXPECT_EQ(sharedMemoryA.getSizeInBytes(), sharedMemoryB.getSizeInBytes());
 
     // should see same value at two different addresses
@@ -81,7 +103,6 @@
 TEST(test_marshalling, aaudio_shared_region) {
     SharedMemoryParcelable sharedMemories[2];
     SharedRegionParcelable sharedRegionA;
-    SharedRegionParcelable sharedRegionB;
     const size_t memSizeBytes = 840;
     unique_fd fd(ashmem_create_region("TestMarshalling", memSizeBytes));
     ASSERT_LE(0, fd);
@@ -97,10 +118,10 @@
 
     Parcel parcel;
     size_t pos = parcel.dataPosition();
-    sharedRegionA.writeToParcel(&parcel);
+    writeToParcel(sharedRegionA, &parcel);
 
     parcel.setDataPosition(pos);
-    sharedRegionB.readFromParcel(&parcel);
+    SharedRegionParcelable sharedRegionB = readFromParcel<SharedRegionParcelable>(parcel);
 
     // should see same value
     void *region2;
@@ -113,7 +134,6 @@
 TEST(test_marshalling, aaudio_ring_buffer_parcelable) {
     SharedMemoryParcelable sharedMemories[2];
     RingBufferParcelable ringBufferA;
-    RingBufferParcelable ringBufferB;
 
     const size_t bytesPerFrame = 8;
     const size_t framesPerBurst = 32;
@@ -147,11 +167,11 @@
     // write A to parcel
     Parcel parcel;
     size_t pos = parcel.dataPosition();
-    ringBufferA.writeToParcel(&parcel);
+    writeToParcel(ringBufferA, &parcel);
 
     // read B from parcel
     parcel.setDataPosition(pos);
-    ringBufferB.readFromParcel(&parcel);
+    RingBufferParcelable ringBufferB = readFromParcel<RingBufferParcelable>(parcel);
 
     RingBufferDescriptor descriptorB;
     EXPECT_EQ(AAUDIO_OK, ringBufferB.resolve(sharedMemories, &descriptorB));
diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp
index f1f8f9c..e2c9698 100644
--- a/media/libaudioclient/AudioTrackShared.cpp
+++ b/media/libaudioclient/AudioTrackShared.cpp
@@ -900,11 +900,8 @@
     }
     audio_track_cblk_t* cblk = mCblk;
 
-    int32_t flush = cblk->u.mStreaming.mFlush;
-    if (flush != mFlush) {
-        // FIXME should return an accurate value, but over-estimate is better than under-estimate
-        return mFrameCount;
-    }
+    flushBufferIfNeeded();
+
     const int32_t rear = getRear();
     ssize_t filled = audio_utils::safe_sub_overflow(rear, cblk->u.mStreaming.mFront);
     // pipe should not already be overfull
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 225713a..b4e07e0 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -24,6 +24,7 @@
 
 #include <binder/IPCThreadState.h>
 #include <binder/Parcel.h>
+#include <media/IAudioPolicyService.h>
 #include <mediautils/ServiceUtilities.h>
 #include <mediautils/TimeCheck.h>
 #include "IAudioFlinger.h"
@@ -1024,6 +1025,16 @@
     std::string tag("IAudioFlinger command " + std::to_string(code));
     TimeCheck check(tag.c_str());
 
+    // Make sure we connect to Audio Policy Service before calling into AudioFlinger:
+    //  - AudioFlinger can call into Audio Policy Service with its global mutex held
+    //  - If this is the first time Audio Policy Service is queried from inside audioserver process
+    //  this will trigger Audio Policy Manager initialization.
+    //  - Audio Policy Manager initialization calls into AudioFlinger which will try to lock
+    //  its global mutex and a deadlock will occur.
+    if (IPCThreadState::self()->getCallingPid() != getpid()) {
+        AudioSystem::get_audio_policy_service();
+    }
+
     switch (code) {
         case CREATE_TRACK: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
diff --git a/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp b/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
index 311e5ba..9b93659 100644
--- a/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
+++ b/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
@@ -108,7 +108,7 @@
 void addBiquadFilter(
         std::vector<std::function<void(float *, const float *, size_t)>> &processingChain,
         struct HapticGeneratorProcessorsRecord &processorsRecord,
-        std::shared_ptr<BiquadFilter> filter) {
+        std::shared_ptr<HapticBiquadFilter> filter) {
     // The process chain captures the shared pointer of the filter in lambda.
     // The process record will keep a shared pointer to the filter so that it is possible to access
     // the filter outside of the process chain.
diff --git a/media/libeffects/hapticgenerator/EffectHapticGenerator.h b/media/libeffects/hapticgenerator/EffectHapticGenerator.h
index a5688de..57b4338 100644
--- a/media/libeffects/hapticgenerator/EffectHapticGenerator.h
+++ b/media/libeffects/hapticgenerator/EffectHapticGenerator.h
@@ -55,7 +55,7 @@
 
 // A structure to keep all shared pointers for all processors in HapticGenerator.
 struct HapticGeneratorProcessorsRecord {
-    std::vector<std::shared_ptr<BiquadFilter>> filters;
+    std::vector<std::shared_ptr<HapticBiquadFilter>> filters;
     std::vector<std::shared_ptr<Ramp>> ramps;
     std::vector<std::shared_ptr<SlowEnvelope>> slowEnvs;
 };
diff --git a/media/libeffects/hapticgenerator/Processors.cpp b/media/libeffects/hapticgenerator/Processors.cpp
index 179b5dc..3157b35 100644
--- a/media/libeffects/hapticgenerator/Processors.cpp
+++ b/media/libeffects/hapticgenerator/Processors.cpp
@@ -134,22 +134,22 @@
     return coefficient;
 }
 
-std::shared_ptr<BiquadFilter> createLPF(const float cornerFrequency,
+std::shared_ptr<HapticBiquadFilter> createLPF(const float cornerFrequency,
                                         const float sampleRate,
                                         const size_t channelCount) {
     BiquadFilterCoefficients coefficient = lpfCoefs(cornerFrequency, sampleRate);
-    return std::make_shared<BiquadFilter>(channelCount, coefficient);
+    return std::make_shared<HapticBiquadFilter>(channelCount, coefficient);
 }
 
-std::shared_ptr<BiquadFilter> createLPF2(const float cornerFrequency,
+std::shared_ptr<HapticBiquadFilter> createLPF2(const float cornerFrequency,
                                          const float sampleRate,
                                          const size_t channelCount) {
     BiquadFilterCoefficients coefficient = lpfCoefs(cornerFrequency, sampleRate);
-    return std::make_shared<BiquadFilter>(
+    return std::make_shared<HapticBiquadFilter>(
             channelCount, cascadeFirstOrderFilters(coefficient, coefficient));
 }
 
-std::shared_ptr<BiquadFilter> createHPF2(const float cornerFrequency,
+std::shared_ptr<HapticBiquadFilter> createHPF2(const float cornerFrequency,
                                          const float sampleRate,
                                          const size_t channelCount) {
     BiquadFilterCoefficients coefficient;
@@ -162,7 +162,7 @@
     coefficient[2] = 0.0f;
     coefficient[3] = -realPoleZ;
     coefficient[4] = 0.0f;
-    return std::make_shared<BiquadFilter>(
+    return std::make_shared<HapticBiquadFilter>(
             channelCount, cascadeFirstOrderFilters(coefficient, coefficient));
 }
 
@@ -178,24 +178,24 @@
     return coefficient;
 }
 
-std::shared_ptr<BiquadFilter> createAPF(const float cornerFrequency,
+std::shared_ptr<HapticBiquadFilter> createAPF(const float cornerFrequency,
                                         const float sampleRate,
                                         const size_t channelCount) {
     BiquadFilterCoefficients coefficient = apfCoefs(cornerFrequency, sampleRate);
-    return std::make_shared<BiquadFilter>(channelCount, coefficient);
+    return std::make_shared<HapticBiquadFilter>(channelCount, coefficient);
 }
 
-std::shared_ptr<BiquadFilter> createAPF2(const float cornerFrequency1,
+std::shared_ptr<HapticBiquadFilter> createAPF2(const float cornerFrequency1,
                                          const float cornerFrequency2,
                                          const float sampleRate,
                                          const size_t channelCount) {
     BiquadFilterCoefficients coefs1 = apfCoefs(cornerFrequency1, sampleRate);
     BiquadFilterCoefficients coefs2 = apfCoefs(cornerFrequency2, sampleRate);
-    return std::make_shared<BiquadFilter>(
+    return std::make_shared<HapticBiquadFilter>(
             channelCount, cascadeFirstOrderFilters(coefs1, coefs2));
 }
 
-std::shared_ptr<BiquadFilter> createBPF(const float ringingFrequency,
+std::shared_ptr<HapticBiquadFilter> createBPF(const float ringingFrequency,
                                         const float q,
                                         const float sampleRate,
                                         const size_t channelCount) {
@@ -207,10 +207,10 @@
     coefficient[2] = 0.0f;
     coefficient[3] = -2 * real;
     coefficient[4] = real * real + img * img;
-    return std::make_shared<BiquadFilter>(channelCount, coefficient);
+    return std::make_shared<HapticBiquadFilter>(channelCount, coefficient);
 }
 
-std::shared_ptr<BiquadFilter> createBSF(const float ringingFrequency,
+std::shared_ptr<HapticBiquadFilter> createBSF(const float ringingFrequency,
                                         const float zq,
                                         const float pq,
                                         const float sampleRate,
@@ -228,7 +228,7 @@
     coefficient[2] = zeroCoeff2 * norm;
     coefficient[3] = poleCoeff1;
     coefficient[4] = poleCoeff2;
-    return std::make_shared<BiquadFilter>(channelCount, coefficient);
+    return std::make_shared<HapticBiquadFilter>(channelCount, coefficient);
 }
 
 } // namespace android::audio_effect::haptic_generator
diff --git a/media/libeffects/hapticgenerator/Processors.h b/media/libeffects/hapticgenerator/Processors.h
index e14458b..5cf0557 100644
--- a/media/libeffects/hapticgenerator/Processors.h
+++ b/media/libeffects/hapticgenerator/Processors.h
@@ -24,7 +24,7 @@
 
 #include <audio_utils/BiquadFilter.h>
 
-using android::audio_utils::BiquadFilter;
+using HapticBiquadFilter = android::audio_utils::BiquadFilter<float>;
 using BiquadFilterCoefficients = std::array<float, android::audio_utils::kBiquadNumCoefs>;
 
 namespace android::audio_effect::haptic_generator {
@@ -51,7 +51,7 @@
     void clear();
 
 private:
-    const std::shared_ptr<BiquadFilter> mLpf;
+    const std::shared_ptr<HapticBiquadFilter> mLpf;
     std::vector<float> mLpfInBuffer;
     std::vector<float> mLpfOutBuffer;
     const float mNormalizationPower;
@@ -64,36 +64,36 @@
 BiquadFilterCoefficients cascadeFirstOrderFilters(const BiquadFilterCoefficients &coefs1,
                                                   const BiquadFilterCoefficients &coefs2);
 
-std::shared_ptr<BiquadFilter> createLPF(const float cornerFrequency,
+std::shared_ptr<HapticBiquadFilter> createLPF(const float cornerFrequency,
                                         const float sampleRate,
                                         const size_t channelCount);
 
 // Create two cascaded LPF with same corner frequency.
-std::shared_ptr<BiquadFilter> createLPF2(const float cornerFrequency,
+std::shared_ptr<HapticBiquadFilter> createLPF2(const float cornerFrequency,
                                          const float sampleRate,
                                          const size_t channelCount);
 
 // Create two cascaded HPF with same corner frequency.
-std::shared_ptr<BiquadFilter> createHPF2(const float cornerFrequency,
+std::shared_ptr<HapticBiquadFilter> createHPF2(const float cornerFrequency,
                                          const float sampleRate,
                                          const size_t channelCount);
 
-std::shared_ptr<BiquadFilter> createAPF(const float cornerFrequency,
+std::shared_ptr<HapticBiquadFilter> createAPF(const float cornerFrequency,
                                         const float sampleRate,
                                         const size_t channelCount);
 
 // Create two cascaded APF with two different corner frequency.
-std::shared_ptr<BiquadFilter> createAPF2(const float cornerFrequency1,
+std::shared_ptr<HapticBiquadFilter> createAPF2(const float cornerFrequency1,
                                          const float cornerFrequency2,
                                          const float sampleRate,
                                          const size_t channelCount);
 
-std::shared_ptr<BiquadFilter> createBPF(const float ringingFrequency,
+std::shared_ptr<HapticBiquadFilter> createBPF(const float ringingFrequency,
                                         const float q,
                                         const float sampleRate,
                                         const size_t channelCount);
 
-std::shared_ptr<BiquadFilter> createBSF(const float ringingFrequency,
+std::shared_ptr<HapticBiquadFilter> createBSF(const float ringingFrequency,
                                         const float zq,
                                         const float pq,
                                         const float sampleRate,
diff --git a/media/libeffects/lvm/lib/Android.bp b/media/libeffects/lvm/lib/Android.bp
index 742ce38..ee69cfb 100644
--- a/media/libeffects/lvm/lib/Android.bp
+++ b/media/libeffects/lvm/lib/Android.bp
@@ -30,7 +30,6 @@
         "Bundle/src/LVM_Control.cpp",
         "SpectrumAnalyzer/src/LVPSA_Control.cpp",
         "SpectrumAnalyzer/src/LVPSA_Init.cpp",
-        "SpectrumAnalyzer/src/LVPSA_Memory.cpp",
         "SpectrumAnalyzer/src/LVPSA_Process.cpp",
         "SpectrumAnalyzer/src/LVPSA_QPD_Init.cpp",
         "SpectrumAnalyzer/src/LVPSA_QPD_Process.cpp",
diff --git a/media/libeffects/lvm/lib/Bass/lib/LVDBE.h b/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
index 23b7636..cb69c88 100644
--- a/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
+++ b/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
@@ -69,9 +69,6 @@
 /*                                                                                      */
 /****************************************************************************************/
 
-/* Memory table*/
-#define LVDBE_NR_MEMORY_REGIONS        4                            /* Number of memory regions */
-
 /* Bass Enhancement effect level */
 #define LVDBE_EFFECT_03DB            3                              /* Effect defines for backwards compatibility */
 #define LVDBE_EFFECT_06DB            6
@@ -112,25 +109,12 @@
     LVDBE_VOLUME_MAX = LVM_MAXINT_32
 } LVDBE_Volume_en;
 
-/* Memory Types */
-typedef enum
-{
-    LVDBE_PERSISTENT      = 0,
-    LVDBE_PERSISTENT_DATA = 1,
-    LVDBE_PERSISTENT_COEF = 2,
-    LVDBE_SCRATCH         = 3,
-    LVDBE_MEMORY_MAX      = LVM_MAXINT_32
-
-} LVDBE_MemoryTypes_en;
-
 /* Function return status */
 typedef enum
 {
     LVDBE_SUCCESS        = 0,                        /* Successful return from a routine */
-    LVDBE_ALIGNMENTERROR = 1,                        /* Memory alignment error */
-    LVDBE_NULLADDRESS    = 2,                        /* NULL allocation address */
-    LVDBE_TOOMANYSAMPLES = 3,                        /* Maximum block size exceeded */
-    LVDBE_SIZEERROR      = 4,                        /* Incorrect structure size */
+    LVDBE_NULLADDRESS    = 1,                        /* NULL allocation address */
+    LVDBE_TOOMANYSAMPLES = 2,                        /* Maximum block size exceeded */
     LVDBE_STATUS_MAX     = LVM_MAXINT_32
 } LVDBE_ReturnStatus_en;
 
@@ -213,21 +197,6 @@
 /*                                                                                      */
 /****************************************************************************************/
 
-/* Memory region definition */
-typedef struct
-{
-    LVM_UINT32                Size;                        /* Region size in bytes */
-    LVM_UINT16                Alignment;                  /* Region alignment in bytes */
-    LVDBE_MemoryTypes_en      Type;                       /* Region type */
-    void                      *pBaseAddress;              /* Pointer to the region base address */
-} LVDBE_MemoryRegion_t;
-
-/* Memory table containing the region definitions */
-typedef struct
-{
-    LVDBE_MemoryRegion_t    Region[LVDBE_NR_MEMORY_REGIONS];  /* One definition for each region */
-} LVDBE_MemTab_t;
-
 /* Parameter structure */
 typedef struct
 {
@@ -259,75 +228,40 @@
 
 /****************************************************************************************/
 /*                                                                                      */
-/* FUNCTION:                 LVDBE_Memory                                               */
-/*                                                                                      */
-/* DESCRIPTION:                                                                         */
-/*    This function is used for memory allocation and free. It can be called in         */
-/*    two ways:                                                                         */
-/*                                                                                      */
-/*        hInstance = NULL                Returns the memory requirements               */
-/*        hInstance = Instance handle        Returns the memory requirements and        */
-/*                                        allocated base addresses for the instance     */
-/*                                                                                      */
-/*    When this function is called for memory allocation (hInstance=NULL) the memory    */
-/*  base address pointers are NULL on return.                                           */
-/*                                                                                      */
-/*    When the function is called for free (hInstance = Instance Handle) the memory     */
-/*  table returns the allocated memory and base addresses used during initialisation.   */
-/*                                                                                      */
-/* PARAMETERS:                                                                          */
-/*  hInstance                Instance Handle                                            */
-/*  pMemoryTable             Pointer to an empty memory definition table                */
-/*    pCapabilities            Pointer to the default capabilites                       */
-/*                                                                                      */
-/* RETURNS:                                                                             */
-/*  LVDBE_SUCCESS            Succeeded                                                  */
-/*                                                                                      */
-/* NOTES:                                                                               */
-/*    1.    This function may be interrupted by the LVDBE_Process function              */
-/*                                                                                      */
-/****************************************************************************************/
-
-LVDBE_ReturnStatus_en LVDBE_Memory(LVDBE_Handle_t           hInstance,
-                                   LVDBE_MemTab_t           *pMemoryTable,
-                                   LVDBE_Capabilities_t     *pCapabilities);
-
-/****************************************************************************************/
-/*                                                                                      */
 /* FUNCTION:                 LVDBE_Init                                                 */
 /*                                                                                      */
 /* DESCRIPTION:                                                                         */
 /*    Create and initialisation function for the Bass Enhancement module                */
 /*                                                                                      */
-/*    This function can be used to create an algorithm instance by calling with         */
-/*    hInstance set to NULL. In this case the algorithm returns the new instance        */
-/*    handle.                                                                           */
-/*                                                                                      */
-/*    This function can be used to force a full re-initialisation of the algorithm      */
-/*    by calling with hInstance = Instance Handle. In this case the memory table        */
-/*    should be correct for the instance, this can be ensured by calling the function   */
-/*    LVDBE_Memory before calling this function.                                        */
-/*                                                                                      */
 /* PARAMETERS:                                                                          */
-/*  hInstance                  Instance handle                                          */
-/*  pMemoryTable             Pointer to the memory definition table                     */
+/*  phInstance               Pointer to instance handle                                 */
 /*  pCapabilities            Pointer to the initialisation capabilities                 */
+/*  pScratch                 Pointer to the bundle scratch buffer                       */
 /*                                                                                      */
 /* RETURNS:                                                                             */
-/*  LVDBE_SUCCESS                Initialisation succeeded                               */
-/*  LVDBE_ALIGNMENTERROR        Instance or scratch memory on incorrect alignment       */
-/*    LVDBE_NULLADDRESS            One or more memory has a NULL pointer                */
+/*  LVDBE_SUCCESS            Initialisation succeeded                                   */
+/*  LVDBE_NULLADDRESS        One or more memory has a NULL pointer - malloc failure     */
 /*                                                                                      */
 /* NOTES:                                                                               */
-/*  1.     The instance handle is the pointer to the base address of the first memory   */
-/*        region.                                                                       */
-/*    2.    This function must not be interrupted by the LVDBE_Process function         */
+/*  1.    This function must not be interrupted by the LVDBE_Process function           */
 /*                                                                                      */
 /****************************************************************************************/
+LVDBE_ReturnStatus_en LVDBE_Init(LVDBE_Handle_t           *phInstance,
+                                 LVDBE_Capabilities_t     *pCapabilities,
+                                 void                     *pScratch);
 
-LVDBE_ReturnStatus_en LVDBE_Init(LVDBE_Handle_t             *phInstance,
-                                   LVDBE_MemTab_t           *pMemoryTable,
-                                   LVDBE_Capabilities_t     *pCapabilities);
+/****************************************************************************************/
+/*                                                                                      */
+/* FUNCTION:                 LVDBE_DeInit                                               */
+/*                                                                                      */
+/* DESCRIPTION:                                                                         */
+/*    Free the memories created during LVDBE_Init including instance handle             */
+/*                                                                                      */
+/* PARAMETERS:                                                                          */
+/*  phInstance               Pointer to instance handle                                 */
+/*                                                                                      */
+/****************************************************************************************/
+void LVDBE_DeInit(LVDBE_Handle_t         *phInstance);
 
 /****************************************************************************************/
 /*                                                                                      */
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp
index ad77696..bd03dd3 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp
@@ -20,176 +20,60 @@
 /*    Includes                                                                          */
 /*                                                                                      */
 /****************************************************************************************/
+#include <stdlib.h>
 
 #include "LVDBE.h"
 #include "LVDBE_Private.h"
 
 /****************************************************************************************/
 /*                                                                                      */
-/* FUNCTION:                 LVDBE_Memory                                               */
-/*                                                                                      */
-/* DESCRIPTION:                                                                         */
-/*    This function is used for memory allocation and free. It can be called in         */
-/*    two ways:                                                                         */
-/*                                                                                      */
-/*        hInstance = NULL                Returns the memory requirements               */
-/*        hInstance = Instance handle        Returns the memory requirements and        */
-/*                                        allocated base addresses for the instance     */
-/*                                                                                      */
-/*    When this function is called for memory allocation (hInstance=NULL) the memory    */
-/*  base address pointers are NULL on return.                                           */
-/*                                                                                      */
-/*    When the function is called for free (hInstance = Instance Handle) the memory     */
-/*  table returns the allocated memory and base addresses used during initialisation.   */
-/*                                                                                      */
-/* PARAMETERS:                                                                          */
-/*  hInstance                Instance Handle                                            */
-/*  pMemoryTable             Pointer to an empty memory definition table                */
-/*    pCapabilities           Pointer to the instance capabilities                      */
-/*                                                                                      */
-/* RETURNS:                                                                             */
-/*  LVDBE_SUCCESS            Succeeded                                                  */
-/*                                                                                      */
-/* NOTES:                                                                               */
-/*    1.    This function may be interrupted by the LVDBE_Process function              */
-/*                                                                                      */
-/****************************************************************************************/
-
-LVDBE_ReturnStatus_en LVDBE_Memory(LVDBE_Handle_t            hInstance,
-                                   LVDBE_MemTab_t            *pMemoryTable,
-                                   LVDBE_Capabilities_t      *pCapabilities)
-{
-
-    LVM_UINT32          ScratchSize;
-    LVDBE_Instance_t    *pInstance = (LVDBE_Instance_t *)hInstance;
-
-    /*
-     * Fill in the memory table
-     */
-    if (hInstance == LVM_NULL)
-    {
-        /*
-         * Instance memory
-         */
-        pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].Size         = sizeof(LVDBE_Instance_t);
-        pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].Alignment    = LVDBE_INSTANCE_ALIGN;
-        pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].Type         = LVDBE_PERSISTENT;
-        pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].pBaseAddress = LVM_NULL;
-
-        /*
-         * Data memory
-         */
-        pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Size   = sizeof(LVDBE_Data_FLOAT_t);
-        pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Alignment    = LVDBE_PERSISTENT_DATA_ALIGN;
-        pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Type         = LVDBE_PERSISTENT_DATA;
-        pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].pBaseAddress = LVM_NULL;
-
-        /*
-         * Coef memory
-         */
-        pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size   = sizeof(LVDBE_Coef_FLOAT_t);
-        pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Alignment    = LVDBE_PERSISTENT_COEF_ALIGN;
-        pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Type         = LVDBE_PERSISTENT_COEF;
-        pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].pBaseAddress = LVM_NULL;
-
-        /*
-         * Scratch memory
-         */
-        ScratchSize = (LVM_UINT32)(LVDBE_SCRATCHBUFFERS_INPLACE*sizeof(LVM_FLOAT) * \
-                                        pCapabilities->MaxBlockSize);
-        pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Size         = ScratchSize;
-        pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Alignment    = LVDBE_SCRATCH_ALIGN;
-        pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Type         = LVDBE_SCRATCH;
-        pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress = LVM_NULL;
-    }
-    else
-    {
-        /* Read back memory allocation table */
-        *pMemoryTable = pInstance->MemoryTable;
-    }
-
-    return(LVDBE_SUCCESS);
-}
-
-/****************************************************************************************/
-/*                                                                                      */
 /* FUNCTION:                 LVDBE_Init                                                 */
 /*                                                                                      */
 /* DESCRIPTION:                                                                         */
-/*    Create and initialisation function for the Dynamic Bass Enhancement module        */
-/*                                                                                      */
-/*    This function can be used to create an algorithm instance by calling with         */
-/*    hInstance set to NULL. In this case the algorithm returns the new instance        */
-/*    handle.                                                                           */
-/*                                                                                      */
-/*    This function can be used to force a full re-initialisation of the algorithm      */
-/*    by calling with hInstance = Instance Handle. In this case the memory table        */
-/*    should be correct for the instance, this can be ensured by calling the function   */
-/*    DBE_Memory before calling this function.                                          */
+/*    Create and initialisation function for the Bass Enhancement module                */
 /*                                                                                      */
 /* PARAMETERS:                                                                          */
-/*  hInstance                  Instance handle                                          */
-/*  pMemoryTable             Pointer to the memory definition table                     */
-/*  pCapabilities              Pointer to the instance capabilities                     */
+/*  phInstance               Pointer to instance handle                                 */
+/*  pCapabilities            Pointer to the initialisation capabilities                 */
+/*  pScratch                 Pointer to the bundle scratch buffer                       */
 /*                                                                                      */
 /* RETURNS:                                                                             */
 /*  LVDBE_SUCCESS            Initialisation succeeded                                   */
-/*  LVDBE_ALIGNMENTERROR    Instance or scratch memory on incorrect alignment           */
-/*    LVDBE_NULLADDRESS        Instance or scratch memory has a NULL pointer            */
+/*  LVDBE_NULLADDRESS        One or more memory has a NULL pointer - malloc failure     */
 /*                                                                                      */
 /* NOTES:                                                                               */
-/*  1.     The instance handle is the pointer to the base address of the first memory   */
-/*        region.                                                                       */
-/*    2.    This function must not be interrupted by the LVDBE_Process function         */
+/*  1.    This function must not be interrupted by the LVDBE_Process function           */
 /*                                                                                      */
 /****************************************************************************************/
-
-LVDBE_ReturnStatus_en LVDBE_Init(LVDBE_Handle_t         *phInstance,
-                                   LVDBE_MemTab_t       *pMemoryTable,
-                                   LVDBE_Capabilities_t *pCapabilities)
+LVDBE_ReturnStatus_en LVDBE_Init(LVDBE_Handle_t       *phInstance,
+                                 LVDBE_Capabilities_t *pCapabilities,
+                                 void                 *pScratch)
 {
 
     LVDBE_Instance_t      *pInstance;
-    LVMixer3_1St_FLOAT_st       *pMixer_Instance;
-    LVMixer3_2St_FLOAT_st       *pBypassMixer_Instance;
+    LVMixer3_1St_FLOAT_st *pMixer_Instance;
+    LVMixer3_2St_FLOAT_st *pBypassMixer_Instance;
     LVM_FLOAT             MixGain;
-    LVM_INT16             i;
 
     /*
-     * Set the instance handle if not already initialised
+     * Create the instance handle if not already initialised
      */
     if (*phInstance == LVM_NULL)
     {
-        *phInstance = (LVDBE_Handle_t)pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].pBaseAddress;
+        *phInstance = calloc(1, sizeof(*pInstance));
+    }
+    if (*phInstance == LVM_NULL)
+    {
+        return LVDBE_NULLADDRESS;
     }
     pInstance =(LVDBE_Instance_t  *)*phInstance;
 
     /*
-     * Check the memory table for NULL pointers and incorrectly aligned data
-     */
-    for (i=0; i<LVDBE_NR_MEMORY_REGIONS; i++)
-    {
-        if (pMemoryTable->Region[i].Size!=0)
-        {
-            if (pMemoryTable->Region[i].pBaseAddress==LVM_NULL)
-            {
-                return(LVDBE_NULLADDRESS);
-            }
-            if (((uintptr_t)pMemoryTable->Region[i].pBaseAddress % pMemoryTable->Region[i].Alignment)!=0){
-                return(LVDBE_ALIGNMENTERROR);
-            }
-        }
-    }
-
-    /*
      * Save the memory table in the instance structure
      */
     pInstance->Capabilities = *pCapabilities;
 
-    /*
-     * Save the memory table in the instance structure
-     */
-    pInstance->MemoryTable = *pMemoryTable;
+    pInstance->pScratch = pScratch;
 
     /*
      * Set the default instance parameters
@@ -204,12 +88,18 @@
     pInstance->Params.VolumedB          =    0;
 
     /*
-     * Set pointer to data and coef memory
+     * Create pointer to data and coef memory
      */
-    pInstance->pData =
-         (LVDBE_Data_FLOAT_t *)pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].pBaseAddress;
-    pInstance->pCoef =
-         (LVDBE_Coef_FLOAT_t *)pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].pBaseAddress;
+    pInstance->pData = (LVDBE_Data_FLOAT_t *)calloc(1, sizeof(*(pInstance->pData)));
+    if (pInstance->pData == NULL)
+    {
+        return LVDBE_NULLADDRESS;
+    }
+    pInstance->pCoef = (LVDBE_Coef_FLOAT_t *)calloc(1, sizeof(*(pInstance->pCoef)));
+    if (pInstance->pCoef == NULL)
+    {
+        return LVDBE_NULLADDRESS;
+    }
 
     /*
      * Initialise the filters
@@ -278,3 +168,32 @@
 
     return(LVDBE_SUCCESS);
 }
+
+/****************************************************************************************/
+/*                                                                                      */
+/* FUNCTION:                 LVDBE_DeInit                                               */
+/*                                                                                      */
+/* DESCRIPTION:                                                                         */
+/*    Free the memories created during LVDBE_Init including instance handle             */
+/*                                                                                      */
+/* PARAMETERS:                                                                          */
+/*  phInstance               Pointer to instance handle                                 */
+/*                                                                                      */
+/****************************************************************************************/
+void LVDBE_DeInit(LVDBE_Handle_t *phInstance)
+{
+    LVDBE_Instance_t *pInstance = (LVDBE_Instance_t *)*phInstance;
+    if (pInstance == LVM_NULL) {
+        return;
+    }
+    if (pInstance->pData != LVM_NULL) {
+        free(pInstance->pData);
+        pInstance->pData = LVM_NULL;
+    }
+    if (pInstance->pCoef != LVM_NULL) {
+        free(pInstance->pCoef);
+        pInstance->pCoef = LVM_NULL;
+    }
+    free(pInstance);
+    *phInstance = LVM_NULL;
+}
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h b/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
index f05ea9a..377d20e 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
@@ -47,20 +47,6 @@
 /* General */
 #define    LVDBE_INVALID            0xFFFF        /* Invalid init parameter */
 
-/* Memory */
-#define LVDBE_MEMREGION_INSTANCE         0       /* Offset to the instance memory region */
-#define LVDBE_MEMREGION_PERSISTENT_DATA  1       /* Offset to persistent data memory region */
-#define LVDBE_MEMREGION_PERSISTENT_COEF  2       /* Offset to persistent coefficient region */
-#define LVDBE_MEMREGION_SCRATCH          3       /* Offset to data scratch memory region */
-
-#define LVDBE_INSTANCE_ALIGN             4       /* 32-bit alignment for structures */
-#define LVDBE_PERSISTENT_DATA_ALIGN      4       /* 32-bit alignment for data */
-#define LVDBE_PERSISTENT_COEF_ALIGN      4       /* 32-bit alignment for coef */
-#define LVDBE_SCRATCH_ALIGN              4       /* 32-bit alignment for long data */
-
-/* Number of buffers required for inplace processing */
-#define LVDBE_SCRATCHBUFFERS_INPLACE     (LVM_MAX_CHANNELS * 3)
-
 #define LVDBE_MIXER_TC                   5       /* Mixer time  */
 #define LVDBE_BYPASS_MIXER_TC            100     /* Bypass mixer time */
 
@@ -96,13 +82,13 @@
 typedef struct
 {
     /* Public parameters */
-    LVDBE_MemTab_t                MemoryTable;        /* Instance memory allocation table */
     LVDBE_Params_t                Params;             /* Instance parameters */
     LVDBE_Capabilities_t        Capabilities;         /* Instance capabilities */
 
     /* Data and coefficient pointers */
     LVDBE_Data_FLOAT_t                *pData;                /* Instance data */
     LVDBE_Coef_FLOAT_t                *pCoef;                /* Instance coefficients */
+    void                        *pScratch;             /* scratch pointer */
 } LVDBE_Instance_t;
 
 /****************************************************************************************/
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp b/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp
index cae6c4c..088de9f 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp
@@ -87,8 +87,7 @@
   const LVM_INT32 NrSamples = NrChannels * NrFrames;
 
   /* Space to store DBE path computation */
-  LVM_FLOAT * const pScratch =
-          (LVM_FLOAT *)pInstance->MemoryTable.Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress;
+  LVM_FLOAT * const pScratch = (LVM_FLOAT *)pInstance->pScratch;
 
   /*
    * Scratch for Mono path starts at offset of
diff --git a/media/libeffects/lvm/lib/Bundle/lib/LVM.h b/media/libeffects/lvm/lib/Bundle/lib/LVM.h
index 376cd20..783c3a0 100644
--- a/media/libeffects/lvm/lib/Bundle/lib/LVM.h
+++ b/media/libeffects/lvm/lib/Bundle/lib/LVM.h
@@ -67,9 +67,6 @@
 /*                                                                                      */
 /****************************************************************************************/
 
-/* Memory table*/
-#define LVM_NR_MEMORY_REGIONS                 4     /* Number of memory regions */
-
 /* Concert Sound effect level presets */
 #define LVM_CS_EFFECT_NONE                    0     /* 0% effect, minimum value */
 #define LVM_CS_EFFECT_LOW                 16384     /* 50% effect */
@@ -225,12 +222,6 @@
 /*                                                                                      */
 /****************************************************************************************/
 
-/* Memory table containing the region definitions */
-typedef struct
-{
-    LVM_MemoryRegion_st         Region[LVM_NR_MEMORY_REGIONS];  /* One definition for each region */
-} LVM_MemTab_t;
-
 /* N-Band equaliser band definition */
 typedef struct
 {
@@ -341,51 +332,14 @@
 
 /****************************************************************************************/
 /*                                                                                      */
-/* FUNCTION:                LVM_GetMemoryTable                                          */
-/*                                                                                      */
-/* DESCRIPTION:                                                                         */
-/*  This function is used for memory allocation and free. It can be called in           */
-/*  two ways:                                                                           */
-/*                                                                                      */
-/*      hInstance = NULL                Returns the memory requirements                 */
-/*      hInstance = Instance handle     Returns the memory requirements and             */
-/*                                      allocated base addresses for the instance       */
-/*                                                                                      */
-/*  When this function is called for memory allocation (hInstance=NULL) the memory      */
-/*  base address pointers are NULL on return.                                           */
-/*                                                                                      */
-/*  When the function is called for free (hInstance = Instance Handle) the memory       */
-/*  table returns the allocated memory and base addresses used during initialisation.   */
-/*                                                                                      */
-/* PARAMETERS:                                                                          */
-/*  hInstance               Instance Handle                                             */
-/*  pMemoryTable            Pointer to an empty memory definition table                 */
-/*  pInstParams             Pointer to the instance parameters                          */
-/*                                                                                      */
-/* RETURNS:                                                                             */
-/*  LVM_SUCCESS             Succeeded                                                   */
-/*  LVM_NULLADDRESS         When one of pMemoryTable or pInstParams is NULL             */
-/*  LVM_OUTOFRANGE          When any of the Instance parameters are out of range        */
-/*                                                                                      */
-/* NOTES:                                                                               */
-/*  1.  This function may be interrupted by the LVM_Process function                    */
-/*                                                                                      */
-/****************************************************************************************/
-LVM_ReturnStatus_en LVM_GetMemoryTable(LVM_Handle_t         hInstance,
-                                       LVM_MemTab_t         *pMemoryTable,
-                                       LVM_InstParams_t     *pInstParams);
-
-/****************************************************************************************/
-/*                                                                                      */
 /* FUNCTION:                LVM_GetInstanceHandle                                       */
 /*                                                                                      */
 /* DESCRIPTION:                                                                         */
-/*  This function is used to create a bundle instance. It returns the created instance  */
-/*  handle through phInstance. All parameters are set to their default, inactive state. */
+/*  This function is used to create a bundle instance.                                  */
+/*  All parameters are set to their default, inactive state.                            */
 /*                                                                                      */
 /* PARAMETERS:                                                                          */
-/*  phInstance              pointer to the instance handle                              */
-/*  pMemoryTable            Pointer to the memory definition table                      */
+/*  phInstance              Pointer to the instance handle                              */
 /*  pInstParams             Pointer to the instance parameters                          */
 /*                                                                                      */
 /* RETURNS:                                                                             */
@@ -398,11 +352,27 @@
 /*                                                                                      */
 /****************************************************************************************/
 LVM_ReturnStatus_en LVM_GetInstanceHandle(LVM_Handle_t        *phInstance,
-                                          LVM_MemTab_t        *pMemoryTable,
                                           LVM_InstParams_t    *pInstParams);
 
 /****************************************************************************************/
 /*                                                                                      */
+/* FUNCTION:                LVM_DelInstanceHandle                                       */
+/*                                                                                      */
+/* DESCRIPTION:                                                                         */
+/*  This function is used to create a bundle instance. It returns the created instance  */
+/*  handle through phInstance. All parameters are set to their default, inactive state. */
+/*                                                                                      */
+/* PARAMETERS:                                                                          */
+/*  phInstance              Pointer to the instance handle                              */
+/*                                                                                      */
+/* NOTES:                                                                               */
+/*  1. This function must not be interrupted by the LVM_Process function                */
+/*                                                                                      */
+/****************************************************************************************/
+void LVM_DelInstanceHandle(LVM_Handle_t        *phInstance);
+
+/****************************************************************************************/
+/*                                                                                      */
 /* FUNCTION:                LVM_ClearAudioBuffers                                       */
 /*                                                                                      */
 /* DESCRIPTION:                                                                         */
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp b/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp
index 6edc0a5..58c18dd 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp
@@ -20,6 +20,7 @@
 /*  Includes                                                                        */
 /*                                                                                  */
 /************************************************************************************/
+#include <stdlib.h>
 
 #include "LVM_Private.h"
 #include "LVM_Tables.h"
@@ -28,479 +29,31 @@
 
 /****************************************************************************************/
 /*                                                                                      */
-/* FUNCTION:                LVM_GetMemoryTable                                          */
-/*                                                                                      */
-/* DESCRIPTION:                                                                         */
-/*  This function is used for memory allocation and free. It can be called in           */
-/*  two ways:                                                                           */
-/*                                                                                      */
-/*      hInstance = NULL                Returns the memory requirements                 */
-/*      hInstance = Instance handle     Returns the memory requirements and             */
-/*                                      allocated base addresses for the instance       */
-/*                                                                                      */
-/*  When this function is called for memory allocation (hInstance=NULL) the memory      */
-/*  base address pointers are NULL on return.                                           */
-/*                                                                                      */
-/*  When the function is called for free (hInstance = Instance Handle) the memory       */
-/*  table returns the allocated memory and base addresses used during initialisation.   */
-/*                                                                                      */
-/* PARAMETERS:                                                                          */
-/*  hInstance               Instance Handle                                             */
-/*  pMemoryTable            Pointer to an empty memory definition table                 */
-/*  pCapabilities           Pointer to the default capabilities                         */
-/*                                                                                      */
-/* RETURNS:                                                                             */
-/*  LVM_SUCCESS             Succeeded                                                   */
-/*  LVM_NULLADDRESS         When one of pMemoryTable or pInstParams is NULL             */
-/*  LVM_OUTOFRANGE          When any of the Instance parameters are out of range        */
-/*                                                                                      */
-/* NOTES:                                                                               */
-/*  1.  This function may be interrupted by the LVM_Process function                    */
-/*  2.  The scratch memory is the largest required by any of the sub-modules plus any   */
-/*      additional scratch requirements of the bundle                                   */
-/*                                                                                      */
-/****************************************************************************************/
-
-/*
- * 4 Types of Memory Regions of LVM
- * TODO: Allocate on the fly.
- * i)   LVM_MEMREGION_PERSISTENT_SLOW_DATA - For Instance Handles
- * ii)  LVM_MEMREGION_PERSISTENT_FAST_DATA - Persistent Buffers
- * iii) LVM_MEMREGION_PERSISTENT_FAST_COEF - For Holding Structure values
- * iv)  LVM_MEMREGION_TEMPORARY_FAST       - For Holding Structure values
- *
- * LVM_MEMREGION_PERSISTENT_SLOW_DATA:
- *   Total Memory size:
- *     sizeof(LVM_Instance_t) + \
- *     sizeof(LVM_Buffer_t) + \
- *     sizeof(LVPSA_InstancePr_t) + \
- *     sizeof(LVM_Buffer_t) - needed if buffer mode is LVM_MANAGED_BUFFER
- *
- * LVM_MEMREGION_PERSISTENT_FAST_DATA:
- *   Total Memory size:
- *     sizeof(LVM_TE_Data_t) + \
- *     2 * pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t) + \
- *     sizeof(LVCS_Data_t) + \
- *     sizeof(LVDBE_Data_FLOAT_t) + \
- *     sizeof(Biquad_2I_Order2_FLOAT_Taps_t) + \
- *     sizeof(Biquad_2I_Order2_FLOAT_Taps_t) + \
- *     pInstParams->EQNB_NumBands * sizeof(Biquad_2I_Order2_FLOAT_Taps_t) + \
- *     pInstParams->EQNB_NumBands * sizeof(LVEQNB_BandDef_t) + \
- *     pInstParams->EQNB_NumBands * sizeof(LVEQNB_BiquadType_en) + \
- *     2 * LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t) + \
- *     PSA_InitParams.nBands * sizeof(Biquad_1I_Order2_Taps_t) + \
- *     PSA_InitParams.nBands * sizeof(QPD_Taps_t)
- *
- * LVM_MEMREGION_PERSISTENT_FAST_COEF:
- *   Total Memory size:
- *     sizeof(LVM_TE_Coefs_t) + \
- *     sizeof(LVCS_Coefficient_t) + \
- *     sizeof(LVDBE_Coef_FLOAT_t) + \
- *     sizeof(Biquad_FLOAT_Instance_t) + \
- *     sizeof(Biquad_FLOAT_Instance_t) + \
- *     pInstParams->EQNB_NumBands * sizeof(Biquad_FLOAT_Instance_t) + \
- *     PSA_InitParams.nBands * sizeof(Biquad_Instance_t) + \
- *     PSA_InitParams.nBands * sizeof(QPD_State_t)
- *
- * LVM_MEMREGION_TEMPORARY_FAST (Scratch):
- *   Total Memory Size:
- *     BundleScratchSize + \
- *     MAX_INTERNAL_BLOCKSIZE * sizeof(LVM_FLOAT) + \
- *     MaxScratchOf (CS, EQNB, DBE, PSA)
- *
- *     a)BundleScratchSize:
- *         3 * LVM_MAX_CHANNELS \
- *         * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) * sizeof(LVM_FLOAT)
- *       This Memory is allocated only when Buffer mode is LVM_MANAGED_BUFFER.
- *     b)MaxScratchOf (CS, EQNB, DBE, PSA)
- *       This Memory is needed for scratch usage for CS, EQNB, DBE, PSA.
- *       CS   = (LVCS_SCRATCHBUFFERS * sizeof(LVM_FLOAT)
- *               * pCapabilities->MaxBlockSize)
- *       EQNB = (LVEQNB_SCRATCHBUFFERS * sizeof(LVM_FLOAT)
- *               * pCapabilities->MaxBlockSize)
- *       DBE  = (LVDBE_SCRATCHBUFFERS_INPLACE*sizeof(LVM_FLOAT)
- *               * pCapabilities->MaxBlockSize)
- *       PSA  = (2 * pInitParams->MaxInputBlockSize * sizeof(LVM_FLOAT))
- *              one MaxInputBlockSize for input and another for filter output
- *     c)MAX_INTERNAL_BLOCKSIZE
- *       This Memory is needed for PSAInput - Temp memory to store output
- *       from McToMono block and given as input to PSA block
- */
-
-LVM_ReturnStatus_en LVM_GetMemoryTable(LVM_Handle_t         hInstance,
-                                       LVM_MemTab_t         *pMemoryTable,
-                                       LVM_InstParams_t     *pInstParams)
-{
-
-    LVM_Instance_t      *pInstance = (LVM_Instance_t *)hInstance;
-    LVM_UINT32          AlgScratchSize;
-    LVM_UINT32          BundleScratchSize;
-    LVM_UINT16          InternalBlockSize;
-    INST_ALLOC          AllocMem[LVM_NR_MEMORY_REGIONS];
-    LVM_INT16           i;
-
-    /*
-     * Check parameters
-     */
-    if(pMemoryTable == LVM_NULL)
-    {
-        return LVM_NULLADDRESS;
-    }
-
-    /*
-     * Return memory table if the instance has already been created
-     */
-    if (hInstance != LVM_NULL)
-    {
-       /* Read back memory allocation table */
-        *pMemoryTable = pInstance->MemoryTable;
-        return(LVM_SUCCESS);
-    }
-
-    if(pInstParams == LVM_NULL)
-    {
-        return LVM_NULLADDRESS;
-    }
-
-    /*
-     *  Power Spectrum Analyser
-     */
-    if(pInstParams->PSA_Included > LVM_PSA_ON)
-    {
-        return (LVM_OUTOFRANGE);
-    }
-
-    /*
-     * Check the instance parameters
-     */
-    if( (pInstParams->BufferMode != LVM_MANAGED_BUFFERS) && (pInstParams->BufferMode != LVM_UNMANAGED_BUFFERS) )
-    {
-        return (LVM_OUTOFRANGE);
-    }
-
-    /* N-Band Equalizer */
-    if( pInstParams->EQNB_NumBands > 32 )
-    {
-        return (LVM_OUTOFRANGE);
-    }
-
-    if(pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
-    {
-        if( (pInstParams->MaxBlockSize < LVM_MIN_MAXBLOCKSIZE ) || (pInstParams->MaxBlockSize > LVM_MANAGED_MAX_MAXBLOCKSIZE ) )
-        {
-            return (LVM_OUTOFRANGE);
-        }
-    }
-    else
-    {
-        if( (pInstParams->MaxBlockSize < LVM_MIN_MAXBLOCKSIZE ) || (pInstParams->MaxBlockSize > LVM_UNMANAGED_MAX_MAXBLOCKSIZE) )
-        {
-            return (LVM_OUTOFRANGE);
-        }
-    }
-
-    /*
-    * Initialise the AllocMem structures
-    */
-    for (i=0; i<LVM_NR_MEMORY_REGIONS; i++)
-    {
-        InstAlloc_Init(&AllocMem[i], LVM_NULL);
-    }
-    InternalBlockSize = (LVM_UINT16)((pInstParams->MaxBlockSize) & MIN_INTERNAL_BLOCKMASK); /* Force to a multiple of MIN_INTERNAL_BLOCKSIZE */
-
-    if (InternalBlockSize < MIN_INTERNAL_BLOCKSIZE)
-    {
-        InternalBlockSize = MIN_INTERNAL_BLOCKSIZE;
-    }
-
-    /* Maximum Internal Black Size should not be more than MAX_INTERNAL_BLOCKSIZE*/
-    if(InternalBlockSize > MAX_INTERNAL_BLOCKSIZE)
-    {
-        InternalBlockSize = MAX_INTERNAL_BLOCKSIZE;
-    }
-
-    /*
-    * Bundle requirements
-    */
-    InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
-        sizeof(LVM_Instance_t));
-
-    /*
-     * Set the algorithm and bundle scratch requirements
-     */
-    AlgScratchSize    = 0;
-    if (pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
-    {
-        BundleScratchSize = 3 * LVM_MAX_CHANNELS \
-                            * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) \
-                            * sizeof(LVM_FLOAT);
-        InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],        /* Scratch buffer */
-                            BundleScratchSize);
-        InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
-                            sizeof(LVM_Buffer_t));
-    }
-
-    /*
-     * Treble Enhancement requirements
-     */
-    InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                        sizeof(LVM_TE_Data_t));
-    InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
-                        sizeof(LVM_TE_Coefs_t));
-
-    /*
-     * N-Band Equalizer requirements
-     */
-    InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],      /* Local storage */
-                        (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
-    InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],      /* User storage */
-                        (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
-
-    /*
-     * Concert Sound requirements
-     */
-    {
-        LVCS_MemTab_t           CS_MemTab;
-        LVCS_Capabilities_t     CS_Capabilities;
-
-        /*
-         * Set the capabilities
-         */
-        CS_Capabilities.MaxBlockSize     = InternalBlockSize;
-
-        /*
-         * Get the memory requirements
-         */
-        LVCS_Memory(LVM_NULL,
-                    &CS_MemTab,
-                    &CS_Capabilities);
-
-        /*
-         * Update the memory allocation structures
-         */
-        InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                            CS_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size);
-        InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
-                            CS_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size);
-        if (CS_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size > AlgScratchSize) AlgScratchSize = CS_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size;
-
-    }
-
-    /*
-     * Dynamic Bass Enhancement requirements
-     */
-    {
-        LVDBE_MemTab_t          DBE_MemTab;
-        LVDBE_Capabilities_t    DBE_Capabilities;
-
-        /*
-         * Set the capabilities
-         */
-        DBE_Capabilities.SampleRate      = LVDBE_CAP_FS_8000 | LVDBE_CAP_FS_11025 |
-                                           LVDBE_CAP_FS_12000 | LVDBE_CAP_FS_16000 |
-                                           LVDBE_CAP_FS_22050 | LVDBE_CAP_FS_24000 |
-                                           LVDBE_CAP_FS_32000 | LVDBE_CAP_FS_44100 |
-                                           LVDBE_CAP_FS_48000 | LVDBE_CAP_FS_88200 |
-                                           LVDBE_CAP_FS_96000 | LVDBE_CAP_FS_176400 |
-                                           LVDBE_CAP_FS_192000;
-        DBE_Capabilities.CentreFrequency = LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_66Hz | LVDBE_CAP_CENTRE_78Hz | LVDBE_CAP_CENTRE_90Hz;
-        DBE_Capabilities.MaxBlockSize    = InternalBlockSize;
-
-        /*
-         * Get the memory requirements
-         */
-        LVDBE_Memory(LVM_NULL,
-                    &DBE_MemTab,
-
-                    &DBE_Capabilities);
-        /*
-         * Update the bundle table
-         */
-        InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                            DBE_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size);
-        InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
-                            DBE_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size);
-        if (DBE_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size > AlgScratchSize) AlgScratchSize = DBE_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size;
-
-    }
-
-    /*
-     * N-Band equaliser requirements
-     */
-    {
-        LVEQNB_MemTab_t         EQNB_MemTab;            /* For N-Band Equaliser */
-        LVEQNB_Capabilities_t   EQNB_Capabilities;
-
-        /*
-         * Set the capabilities
-         */
-        EQNB_Capabilities.SampleRate   = LVEQNB_CAP_FS_8000 | LVEQNB_CAP_FS_11025 |
-                                         LVEQNB_CAP_FS_12000 | LVEQNB_CAP_FS_16000 |
-                                         LVEQNB_CAP_FS_22050 | LVEQNB_CAP_FS_24000 |
-                                         LVEQNB_CAP_FS_32000 | LVEQNB_CAP_FS_44100 |
-                                         LVEQNB_CAP_FS_48000 | LVEQNB_CAP_FS_88200 |
-                                         LVEQNB_CAP_FS_96000 | LVEQNB_CAP_FS_176400 |
-                                         LVEQNB_CAP_FS_192000;
-        EQNB_Capabilities.SourceFormat = LVEQNB_CAP_STEREO | LVEQNB_CAP_MONOINSTEREO;
-        EQNB_Capabilities.MaxBlockSize = InternalBlockSize;
-        EQNB_Capabilities.MaxBands     = pInstParams->EQNB_NumBands;
-
-        /*
-         * Get the memory requirements
-         */
-        LVEQNB_Memory(LVM_NULL,
-                      &EQNB_MemTab,
-                      &EQNB_Capabilities);
-
-        /*
-         * Update the bundle table
-         */
-        InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                            EQNB_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size);
-        InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
-                            EQNB_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size);
-        if (EQNB_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size > AlgScratchSize) AlgScratchSize = EQNB_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size;
-
-    }
-
-    /*
-     * Headroom management memory allocation
-     */
-    InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                       (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
-    InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                       (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
-
-    /*
-     * Spectrum Analyzer memory requirements
-     */
-    {
-        pLVPSA_Handle_t     hPSAInst = LVM_NULL;
-        LVPSA_MemTab_t      PSA_MemTab;
-        LVPSA_InitParams_t  PSA_InitParams;
-        LVPSA_FilterParam_t FiltersParams[9];
-        LVPSA_RETURN        PSA_Status;
-
-        if(pInstParams->PSA_Included == LVM_PSA_ON)
-        {
-            PSA_InitParams.SpectralDataBufferDuration   = (LVM_UINT16) 500;
-            PSA_InitParams.MaxInputBlockSize            = (LVM_UINT16) 1000;
-            PSA_InitParams.nBands                       = (LVM_UINT16) 9;
-
-            PSA_InitParams.pFiltersParams = &FiltersParams[0];
-            for(i = 0; i < PSA_InitParams.nBands; i++)
-            {
-                FiltersParams[i].CenterFrequency    = (LVM_UINT16) 1000;
-                FiltersParams[i].QFactor            = (LVM_UINT16) 25;
-                FiltersParams[i].PostGain           = (LVM_INT16)  0;
-            }
-
-            /*
-            * Get the memory requirements
-            */
-            PSA_Status = LVPSA_Memory (hPSAInst,
-                                        &PSA_MemTab,
-                                        &PSA_InitParams);
-
-            if (PSA_Status != LVPSA_OK)
-            {
-                return((LVM_ReturnStatus_en) LVM_ALGORITHMPSA);
-            }
-
-            /*
-            * Update the bundle table
-            */
-            /* Slow Data */
-            InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
-                PSA_MemTab.Region[LVM_PERSISTENT_SLOW_DATA].Size);
-
-            /* Fast Data */
-            InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                PSA_MemTab.Region[LVM_PERSISTENT_FAST_DATA].Size);
-
-            /* Fast Coef */
-            InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
-                PSA_MemTab.Region[LVM_PERSISTENT_FAST_COEF].Size);
-
-            /* Fast Temporary */
-            InstAlloc_AddMember(&AllocMem[LVM_TEMPORARY_FAST],
-                                MAX_INTERNAL_BLOCKSIZE * sizeof(LVM_FLOAT));
-
-            if (PSA_MemTab.Region[LVM_TEMPORARY_FAST].Size > AlgScratchSize)
-            {
-                AlgScratchSize = PSA_MemTab.Region[LVM_TEMPORARY_FAST].Size;
-            }
-        }
-    }
-
-    /*
-     * Return the memory table
-     */
-    pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_SLOW_DATA].Size         = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA]);
-    pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_SLOW_DATA].Type         = LVM_PERSISTENT_SLOW_DATA;
-    pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress = LVM_NULL;
-
-    pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size         = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA]);
-    pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Type         = LVM_PERSISTENT_FAST_DATA;
-    pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress = LVM_NULL;
-    if (pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size < 4)
-    {
-        pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size = 0;
-    }
-
-    pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size         = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF]);
-    pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Type         = LVM_PERSISTENT_FAST_COEF;
-    pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress = LVM_NULL;
-    if (pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size < 4)
-    {
-        pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size = 0;
-    }
-
-    InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
-                        AlgScratchSize);
-    pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Size             = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST]);
-    pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Type             = LVM_TEMPORARY_FAST;
-    pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].pBaseAddress     = LVM_NULL;
-    if (pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Size < 4)
-    {
-        pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Size = 0;
-    }
-
-    return(LVM_SUCCESS);
-
-}
-
-/****************************************************************************************/
-/*                                                                                      */
 /* FUNCTION:                LVM_GetInstanceHandle                                       */
 /*                                                                                      */
 /* DESCRIPTION:                                                                         */
-/*  This function is used to create a bundle instance. It returns the created instance  */
-/*  handle through phInstance. All parameters are set to their default, inactive state. */
+/*  This function is used to create a bundle instance.                                  */
+/*  All parameters are set to their default, inactive state.                            */
 /*                                                                                      */
 /* PARAMETERS:                                                                          */
-/*  phInstance              pointer to the instance handle                              */
-/*  pMemoryTable            Pointer to the memory definition table                      */
-/*  pInstParams             Pointer to the initialisation capabilities                  */
+/*  phInstance              Pointer to the instance handle                              */
+/*  pInstParams             Pointer to the instance parameters                          */
 /*                                                                                      */
 /* RETURNS:                                                                             */
 /*  LVM_SUCCESS             Initialisation succeeded                                    */
+/*  LVM_NULLADDRESS         One or more memory has a NULL pointer                       */
 /*  LVM_OUTOFRANGE          When any of the Instance parameters are out of range        */
-/*  LVM_NULLADDRESS         When one of phInstance, pMemoryTable or pInstParams are NULL*/
 /*                                                                                      */
 /* NOTES:                                                                               */
 /*  1. This function must not be interrupted by the LVM_Process function                */
 /*                                                                                      */
 /****************************************************************************************/
-
 LVM_ReturnStatus_en LVM_GetInstanceHandle(LVM_Handle_t           *phInstance,
-                                          LVM_MemTab_t           *pMemoryTable,
                                           LVM_InstParams_t       *pInstParams)
 {
 
     LVM_ReturnStatus_en     Status = LVM_SUCCESS;
     LVM_Instance_t          *pInstance;
-    INST_ALLOC              AllocMem[LVM_NR_MEMORY_REGIONS];
     LVM_INT16               i;
     LVM_UINT16              InternalBlockSize;
     LVM_INT32               BundleScratchSize;
@@ -508,24 +61,12 @@
     /*
      * Check valid points have been given
      */
-    if ((phInstance == LVM_NULL) || (pMemoryTable == LVM_NULL) || (pInstParams == LVM_NULL))
+    if ((phInstance == LVM_NULL) || (pInstParams == LVM_NULL))
     {
         return (LVM_NULLADDRESS);
     }
 
     /*
-     * Check the memory table for NULL pointers
-     */
-    for (i=0; i<LVM_NR_MEMORY_REGIONS; i++)
-    {
-        if ((pMemoryTable->Region[i].Size != 0) &&
-            (pMemoryTable->Region[i].pBaseAddress==LVM_NULL))
-        {
-            return(LVM_NULLADDRESS);
-        }
-    }
-
-    /*
      * Check the instance parameters
      */
     if( (pInstParams->BufferMode != LVM_MANAGED_BUFFERS) && (pInstParams->BufferMode != LVM_UNMANAGED_BUFFERS) )
@@ -559,29 +100,19 @@
     }
 
     /*
-     * Initialise the AllocMem structures
+     * Create the instance handle
      */
-    for (i=0; i<LVM_NR_MEMORY_REGIONS; i++)
+    *phInstance  = (LVM_Handle_t)calloc(1, sizeof(*pInstance));
+    if (*phInstance == LVM_NULL)
     {
-        InstAlloc_Init(&AllocMem[i],
-                       pMemoryTable->Region[i].pBaseAddress);
+        return LVM_NULLADDRESS;
     }
+    pInstance = (LVM_Instance_t  *)*phInstance;
+
+    pInstance->InstParams = *pInstParams;
 
     /*
-     * Set the instance handle
-     */
-    *phInstance  = (LVM_Handle_t)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
-                                                     sizeof(LVM_Instance_t));
-    pInstance =(LVM_Instance_t  *)*phInstance;
-
-    /*
-     * Save the memory table, parameters and capabilities
-     */
-    pInstance->MemoryTable    = *pMemoryTable;
-    pInstance->InstParams     = *pInstParams;
-
-    /*
-     * Set the bundle scratch memory and initialse the buffer management
+     * Create the bundle scratch memory and initialse the buffer management
      */
     InternalBlockSize = (LVM_UINT16)((pInstParams->MaxBlockSize) & MIN_INTERNAL_BLOCKMASK); /* Force to a multiple of MIN_INTERNAL_BLOCKSIZE */
     if (InternalBlockSize < MIN_INTERNAL_BLOCKSIZE)
@@ -600,23 +131,31 @@
      * Common settings for managed and unmanaged buffers
      */
     pInstance->SamplesToProcess = 0;                /* No samples left to process */
+    BundleScratchSize = (LVM_INT32)
+                        (3 * LVM_MAX_CHANNELS \
+                         * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) \
+                         * sizeof(LVM_FLOAT));
+    pInstance->pScratch = calloc(1, BundleScratchSize);
+    if (pInstance->pScratch == LVM_NULL)
+    {
+        return LVM_NULLADDRESS;
+    }
+
     if (pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
     {
         /*
          * Managed buffers required
          */
         pInstance->pBufferManagement = (LVM_Buffer_t *)
-            InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
-                                                           sizeof(LVM_Buffer_t));
-        BundleScratchSize = (LVM_INT32)
-                            (3 * LVM_MAX_CHANNELS \
-                             * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) \
-                             * sizeof(LVM_FLOAT));
-        pInstance->pBufferManagement->pScratch = (LVM_FLOAT *)
-            InstAlloc_AddMember(
-                         &AllocMem[LVM_MEMREGION_TEMPORARY_FAST], /* Scratch 1 buffer */
-                                                  (LVM_UINT32)BundleScratchSize);
-        LoadConst_Float(0,                                   /* Clear the input delay buffer */
+                    calloc(1, sizeof(*(pInstance->pBufferManagement)));
+        if (pInstance->pBufferManagement == LVM_NULL)
+        {
+            return LVM_NULLADDRESS;
+        }
+
+        pInstance->pBufferManagement->pScratch = (LVM_FLOAT *)pInstance->pScratch;
+
+        LoadConst_Float(0, /* Clear the input delay buffer */
                         (LVM_FLOAT *)&pInstance->pBufferManagement->InDelayBuffer,
                         (LVM_INT16)(LVM_MAX_CHANNELS * MIN_INTERNAL_BLOCKSIZE));
         pInstance->pBufferManagement->InDelaySamples = MIN_INTERNAL_BLOCKSIZE; /* Set the number of delay samples */
@@ -647,11 +186,16 @@
     /*
      * Treble Enhancement
      */
-    pInstance->pTE_Taps  = (LVM_TE_Data_t *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                                                                sizeof(LVM_TE_Data_t));
-
-    pInstance->pTE_State = (LVM_TE_Coefs_t *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
-                                                                 sizeof(LVM_TE_Coefs_t));
+    pInstance->pTE_Taps  = (LVM_TE_Data_t *)calloc(1, sizeof(*(pInstance->pTE_Taps)));
+    if (pInstance->pTE_Taps == LVM_NULL)
+    {
+        return LVM_NULLADDRESS;
+    }
+    pInstance->pTE_State = (LVM_TE_Coefs_t *)calloc(1, sizeof(*(pInstance->pTE_State)));
+    if (pInstance->pTE_State == LVM_NULL)
+    {
+        return LVM_NULLADDRESS;
+    }
     pInstance->Params.TE_OperatingMode = LVM_TE_OFF;
     pInstance->Params.TE_EffectLevel   = 0;
     pInstance->TE_Active               = LVM_FALSE;
@@ -695,21 +239,26 @@
     LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],LVM_VC_MIXER_TIME,LVM_FS_8000,2);
 
     /*
-     * Set the default EQNB pre-gain and pointer to the band definitions
+     * Create the default EQNB pre-gain and pointer to the band definitions
      */
-    pInstance->pEQNB_BandDefs =
-        (LVM_EQNB_BandDef_t *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                                   (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
-    pInstance->pEQNB_UserDefs =
-        (LVM_EQNB_BandDef_t *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                                   (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
+    pInstance->pEQNB_BandDefs = (LVM_EQNB_BandDef_t *)
+        calloc(pInstParams->EQNB_NumBands, sizeof(*(pInstance->pEQNB_BandDefs)));
+    if (pInstance->pEQNB_BandDefs == LVM_NULL)
+    {
+        return LVM_NULLADDRESS;
+    }
+    pInstance->pEQNB_UserDefs = (LVM_EQNB_BandDef_t *)
+         calloc(pInstParams->EQNB_NumBands, sizeof(*(pInstance->pEQNB_UserDefs)));
+    if (pInstance->pEQNB_UserDefs == LVM_NULL)
+    {
+        return LVM_NULLADDRESS;
+    }
 
     /*
      * Initialise the Concert Sound module
      */
     {
         LVCS_Handle_t           hCSInstance;                /* Instance handle */
-        LVCS_MemTab_t           CS_MemTab;                  /* Memory table */
         LVCS_Capabilities_t     CS_Capabilities;            /* Initial capabilities */
         LVCS_ReturnStatus_en    LVCS_Status;                /* Function call status */
 
@@ -729,26 +278,12 @@
         CS_Capabilities.pBundleInstance = (void*)pInstance;
 
         /*
-         * Get the memory requirements and then set the address pointers, forcing alignment
-         */
-        LVCS_Status = LVCS_Memory(LVM_NULL,                /* Get the memory requirements */
-                                  &CS_MemTab,
-                                  &CS_Capabilities);
-        CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress = &pInstance->CS_Instance;
-        CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                                                                                                         CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].Size);
-        CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
-                                                                                                         CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].Size);
-        CS_MemTab.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress       = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
-                                                                                                         0);
-
-        /*
          * Initialise the Concert Sound instance and save the instance handle
          */
         hCSInstance = LVM_NULL;                            /* Set to NULL to return handle */
-        LVCS_Status = LVCS_Init(&hCSInstance,              /* Initiailse */
-                                &CS_MemTab,
-                                &CS_Capabilities);
+        LVCS_Status = LVCS_Init(&hCSInstance,              /* Create and initiailse */
+                                &CS_Capabilities,
+                                pInstance->pScratch);
         if (LVCS_Status != LVCS_SUCCESS) return((LVM_ReturnStatus_en)LVCS_Status);
         pInstance->hCSInstance = hCSInstance;              /* Save the instance handle */
 
@@ -759,7 +294,6 @@
      */
     {
         LVDBE_Handle_t          hDBEInstance;               /* Instance handle */
-        LVDBE_MemTab_t          DBE_MemTab;                 /* Memory table */
         LVDBE_Capabilities_t    DBE_Capabilities;           /* Initial capabilities */
         LVDBE_ReturnStatus_en   LVDBE_Status;               /* Function call status */
 
@@ -783,30 +317,19 @@
                                            LVDBE_CAP_FS_48000 | LVDBE_CAP_FS_88200 |
                                            LVDBE_CAP_FS_96000 | LVDBE_CAP_FS_176400 |
                                            LVDBE_CAP_FS_192000;
-        DBE_Capabilities.CentreFrequency = LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_66Hz | LVDBE_CAP_CENTRE_78Hz | LVDBE_CAP_CENTRE_90Hz;
-        DBE_Capabilities.MaxBlockSize    = (LVM_UINT16)InternalBlockSize;
 
-        /*
-         * Get the memory requirements and then set the address pointers
-         */
-        LVDBE_Status = LVDBE_Memory(LVM_NULL,               /* Get the memory requirements */
-                                    &DBE_MemTab,
-                                    &DBE_Capabilities);
-        DBE_MemTab.Region[LVDBE_MEMREGION_INSTANCE].pBaseAddress        = &pInstance->DBE_Instance;
-        DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                                                                                                      DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_DATA].Size);
-        DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
-                                                                                                      DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size);
-        DBE_MemTab.Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress         = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
-                                                                                                      0);
+        DBE_Capabilities.CentreFrequency = LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_55Hz |
+                                            LVDBE_CAP_CENTRE_66Hz | LVDBE_CAP_CENTRE_78Hz |
+                                            LVDBE_CAP_CENTRE_90Hz;
+        DBE_Capabilities.MaxBlockSize    = (LVM_UINT16)InternalBlockSize;
 
         /*
          * Initialise the Dynamic Bass Enhancement instance and save the instance handle
          */
         hDBEInstance = LVM_NULL;                            /* Set to NULL to return handle */
-        LVDBE_Status = LVDBE_Init(&hDBEInstance,            /* Initiailse */
-                                  &DBE_MemTab,
-                                  &DBE_Capabilities);
+        LVDBE_Status = LVDBE_Init(&hDBEInstance,            /* Create and initiailse */
+                                  &DBE_Capabilities,
+                                  pInstance->pScratch);
         if (LVDBE_Status != LVDBE_SUCCESS) return((LVM_ReturnStatus_en)LVDBE_Status);
         pInstance->hDBEInstance = hDBEInstance;             /* Save the instance handle */
     }
@@ -816,7 +339,6 @@
      */
     {
         LVEQNB_Handle_t          hEQNBInstance;             /* Instance handle */
-        LVEQNB_MemTab_t          EQNB_MemTab;               /* Memory table */
         LVEQNB_Capabilities_t    EQNB_Capabilities;         /* Initial capabilities */
         LVEQNB_ReturnStatus_en   LVEQNB_Status;             /* Function call status */
 
@@ -838,6 +360,7 @@
                                             LVEQNB_CAP_FS_48000 | LVEQNB_CAP_FS_88200 |
                                             LVEQNB_CAP_FS_96000 | LVEQNB_CAP_FS_176400 |
                                             LVEQNB_CAP_FS_192000;
+
         EQNB_Capabilities.MaxBlockSize    = (LVM_UINT16)InternalBlockSize;
         EQNB_Capabilities.MaxBands        = pInstParams->EQNB_NumBands;
         EQNB_Capabilities.SourceFormat    = LVEQNB_CAP_STEREO | LVEQNB_CAP_MONOINSTEREO;
@@ -845,26 +368,12 @@
         EQNB_Capabilities.pBundleInstance  = (void*)pInstance;
 
         /*
-         * Get the memory requirements and then set the address pointers, forcing alignment
-         */
-        LVEQNB_Status = LVEQNB_Memory(LVM_NULL,             /* Get the memory requirements */
-                                      &EQNB_MemTab,
-                                      &EQNB_Capabilities);
-        EQNB_MemTab.Region[LVEQNB_MEMREGION_INSTANCE].pBaseAddress        = &pInstance->EQNB_Instance;
-        EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                                                                                                        EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Size);
-        EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
-                                                                                                        EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Size);
-        EQNB_MemTab.Region[LVEQNB_MEMREGION_SCRATCH].pBaseAddress         = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
-                                                                                                        0);
-
-        /*
          * Initialise the Dynamic Bass Enhancement instance and save the instance handle
          */
         hEQNBInstance = LVM_NULL;                           /* Set to NULL to return handle */
-        LVEQNB_Status = LVEQNB_Init(&hEQNBInstance,         /* Initiailse */
-                                    &EQNB_MemTab,
-                                    &EQNB_Capabilities);
+        LVEQNB_Status = LVEQNB_Init(&hEQNBInstance,         /* Create and initiailse */
+                                    &EQNB_Capabilities,
+                                    pInstance->pScratch);
         if (LVEQNB_Status != LVEQNB_SUCCESS) return((LVM_ReturnStatus_en)LVEQNB_Status);
         pInstance->hEQNBInstance = hEQNBInstance;           /* Save the instance handle */
     }
@@ -874,11 +383,17 @@
      */
     {
         pInstance->pHeadroom_BandDefs = (LVM_HeadroomBandDef_t *)
-              InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                                       (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
+            calloc(LVM_HEADROOM_MAX_NBANDS, sizeof(*(pInstance->pHeadroom_BandDefs)));
+        if (pInstance->pHeadroom_BandDefs == LVM_NULL)
+        {
+            return LVM_NULLADDRESS;
+        }
         pInstance->pHeadroom_UserDefs = (LVM_HeadroomBandDef_t *)
-              InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                                       (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
+            calloc(LVM_HEADROOM_MAX_NBANDS, sizeof(*(pInstance->pHeadroom_UserDefs)));
+        if (pInstance->pHeadroom_UserDefs == LVM_NULL)
+        {
+            return LVM_NULLADDRESS;
+        }
 
         /* Headroom management parameters initialisation */
         pInstance->NewHeadroomParams.NHeadroomBands = 2;
@@ -899,7 +414,6 @@
      */
     {
         pLVPSA_Handle_t     hPSAInstance = LVM_NULL;   /* Instance handle */
-        LVPSA_MemTab_t      PSA_MemTab;
         LVPSA_RETURN        PSA_Status;                 /* Function call status */
         LVPSA_FilterParam_t FiltersParams[9];
 
@@ -916,41 +430,18 @@
                 FiltersParams[i].PostGain           = (LVM_INT16)  0;
             }
 
-            /*Get the memory requirements and then set the address pointers*/
-            PSA_Status = LVPSA_Memory (hPSAInstance,
-                                          &PSA_MemTab,
-                                          &pInstance->PSA_InitParams);
-
-            if (PSA_Status != LVPSA_OK)
-            {
-                return((LVM_ReturnStatus_en) LVM_ALGORITHMPSA);
-            }
-
-            /* Slow Data */
-            PSA_MemTab.Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
-                PSA_MemTab.Region[LVM_PERSISTENT_SLOW_DATA].Size);
-
-            /* Fast Data */
-            PSA_MemTab.Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
-                PSA_MemTab.Region[LVM_PERSISTENT_FAST_DATA].Size);
-
-            /* Fast Coef */
-            PSA_MemTab.Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
-                PSA_MemTab.Region[LVM_PERSISTENT_FAST_COEF].Size);
-
-            /* Fast Temporary */
-            pInstance->pPSAInput = (LVM_FLOAT *)InstAlloc_AddMember(&AllocMem[LVM_TEMPORARY_FAST],
-                                                       (LVM_UINT32) MAX_INTERNAL_BLOCKSIZE * \
-                                                       sizeof(LVM_FLOAT));
-            PSA_MemTab.Region[LVM_TEMPORARY_FAST].pBaseAddress       = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],0);
-
             /*Initialise PSA instance and save the instance handle*/
             pInstance->PSA_ControlParams.Fs = LVM_FS_48000;
             pInstance->PSA_ControlParams.LevelDetectionSpeed  = LVPSA_SPEED_MEDIUM;
+            pInstance->pPSAInput = (LVM_FLOAT *)calloc(MAX_INTERNAL_BLOCKSIZE, sizeof(LVM_FLOAT));
+            if (pInstance->pPSAInput == LVM_NULL)
+            {
+                return LVM_NULLADDRESS;
+            }
             PSA_Status = LVPSA_Init (&hPSAInstance,
                                     &pInstance->PSA_InitParams,
                                     &pInstance->PSA_ControlParams,
-                                    &PSA_MemTab);
+                                    pInstance->pScratch);
 
             if (PSA_Status != LVPSA_OK)
             {
@@ -1003,6 +494,111 @@
 
     return(Status);
 }
+/****************************************************************************************/
+/*                                                                                      */
+/* FUNCTION:                LVM_DelInstanceHandle                                       */
+/*                                                                                      */
+/* DESCRIPTION:                                                                         */
+/*  This function is used to create a bundle instance. It returns the created instance  */
+/*  handle through phInstance. All parameters are set to their default, inactive state. */
+/*                                                                                      */
+/* PARAMETERS:                                                                          */
+/*  phInstance              Pointer to the instance handle                              */
+/*                                                                                      */
+/* NOTES:                                                                               */
+/*  1. This function must not be interrupted by the LVM_Process function                */
+/*                                                                                      */
+/****************************************************************************************/
+void LVM_DelInstanceHandle(LVM_Handle_t *phInstance)
+{
+    LVM_Instance_t *pInstance = (LVM_Instance_t *)*phInstance;
+
+    if (pInstance->pScratch != LVM_NULL) {
+        free(pInstance->pScratch);
+        pInstance->pScratch = LVM_NULL;
+    }
+
+    if (pInstance->InstParams.BufferMode == LVM_MANAGED_BUFFERS) {
+        /*
+         * Managed buffers required
+         */
+        if (pInstance->pBufferManagement != LVM_NULL) {
+            free(pInstance->pBufferManagement);
+            pInstance->pBufferManagement = LVM_NULL;
+        }
+    }
+
+    /*
+     * Treble Enhancement
+     */
+    if (pInstance->pTE_Taps != LVM_NULL) {
+        free(pInstance->pTE_Taps);
+        pInstance->pTE_Taps = LVM_NULL;
+    }
+    if (pInstance->pTE_State != LVM_NULL) {
+        free(pInstance->pTE_State);
+        pInstance->pTE_State = LVM_NULL;
+    }
+
+    /*
+     * Free the default EQNB pre-gain and pointer to the band definitions
+     */
+    if (pInstance->pEQNB_BandDefs != LVM_NULL) {
+        free(pInstance->pEQNB_BandDefs);
+        pInstance->pEQNB_BandDefs = LVM_NULL;
+    }
+    if (pInstance->pEQNB_UserDefs != LVM_NULL) {
+        free(pInstance->pEQNB_UserDefs);
+        pInstance->pEQNB_UserDefs = LVM_NULL;
+    }
+
+    /*
+     * De-initialise the Concert Sound module
+     */
+    if (pInstance->hCSInstance != LVM_NULL) {
+        LVCS_DeInit(&pInstance->hCSInstance);
+    }
+
+    /*
+     * De-initialise the Bass Enhancement module
+     */
+    if (pInstance->hDBEInstance != LVM_NULL) {
+        LVDBE_DeInit(&pInstance->hDBEInstance);
+    }
+
+    /*
+     * De-initialise the N-Band Equaliser module
+     */
+    if (pInstance->hEQNBInstance != LVM_NULL) {
+        LVEQNB_DeInit(&pInstance->hEQNBInstance);
+    }
+
+    /*
+     * Free Headroom management memory.
+     */
+    if (pInstance->pHeadroom_BandDefs != LVM_NULL) {
+        free(pInstance->pHeadroom_BandDefs);
+        pInstance->pHeadroom_BandDefs = LVM_NULL;
+    }
+    if (pInstance->pHeadroom_UserDefs != LVM_NULL) {
+        free(pInstance->pHeadroom_UserDefs);
+        pInstance->pHeadroom_UserDefs = LVM_NULL;
+    }
+
+    /*
+     * De-initialise the PSA module
+     */
+    if (pInstance->hPSAInstance != LVM_NULL) {
+        LVPSA_DeInit(&pInstance->hPSAInstance);
+    }
+    if (pInstance->pPSAInput != LVM_NULL) {
+        free(pInstance->pPSAInput);
+        pInstance->pPSAInput = LVM_NULL;
+    }
+
+    free(*phInstance);
+    return;
+}
 
 /****************************************************************************************/
 /*                                                                                      */
@@ -1025,7 +621,6 @@
 
 LVM_ReturnStatus_en LVM_ClearAudioBuffers(LVM_Handle_t  hInstance)
 {
-    LVM_MemTab_t            MemTab;                                     /* Memory table */
     LVM_InstParams_t        InstParams;                                 /* Instance parameters */
     LVM_ControlParams_t     Params;                                     /* Control Parameters */
     LVM_Instance_t          *pInstance  = (LVM_Instance_t  *)hInstance; /* Pointer to Instance */
@@ -1041,17 +636,11 @@
     /*Save the headroom parameters*/
     LVM_GetHeadroomParams(hInstance, &HeadroomParams);
 
-    /*  Retrieve allocated buffers in memtab */
-    LVM_GetMemoryTable(hInstance, &MemTab,  LVM_NULL);
 
     /*  Save the instance parameters */
     InstParams = pInstance->InstParams;
 
     /*  Call  LVM_GetInstanceHandle to re-initialise the bundle */
-    LVM_GetInstanceHandle( &hInstance,
-                           &MemTab,
-                           &InstParams);
-
     /* Restore control parameters */ /* coverity[unchecked_value] */ /* Do not check return value internal function calls */
     LVM_SetControlParameters(hInstance, &Params);
 
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h b/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
index 3ca8139..a9492a1 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
@@ -113,21 +113,6 @@
 /*                                                                                  */
 /************************************************************************************/
 
-/* Memory region definition */
-typedef struct
-{
-    LVM_UINT32              Size;               /* Region size in bytes */
-    LVM_UINT16              Alignment;          /* Byte alignment */
-    LVM_MemoryTypes_en      Type;               /* Region type */
-    void                    *pBaseAddress;      /* Pointer to the region base address */
-} LVM_IntMemoryRegion_t;
-
-/* Memory table containing the region definitions */
-typedef struct
-{
-    LVM_IntMemoryRegion_t   Region[LVM_NR_MEMORY_REGIONS];  /* One definition for each region */
-} LVM_IntMemTab_t;
-
 /* Buffer Management */
 typedef struct
 {
@@ -157,7 +142,6 @@
 typedef struct
 {
     /* Public parameters */
-    LVM_MemTab_t            MemoryTable;        /* Instance memory allocation table */
     LVM_ControlParams_t     Params;             /* Control parameters */
     LVM_InstParams_t        InstParams;         /* Instance parameters */
 
@@ -228,6 +212,7 @@
 
     LVM_INT16              NrChannels;
     LVM_INT32              ChMask;
+    void                   *pScratch;           /* Pointer to bundle scratch buffer*/
 
 } LVM_Instance_t;
 
diff --git a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
index d07a5ca..008d192 100644
--- a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
+++ b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
@@ -54,26 +54,6 @@
 
 #define LVM_NR_MEMORY_REGIONS                   4   /* Number of memory regions */
 
-/* Memory partition type */
-#define LVM_MEM_PARTITION0      0                   /* 1st memory partition */
-#define LVM_MEM_PARTITION1      1                   /* 2nd memory partition */
-#define LVM_MEM_PARTITION2      2                   /* 3rd memory partition */
-#define LVM_MEM_PARTITION3      3                   /* 4th memory partition */
-
-/* Use type */
-#define LVM_MEM_PERSISTENT      0                   /* Persistent memory type */
-#define LVM_MEM_SCRATCH         4                   /* Scratch  memory type */
-
-/* Access type */
-#define LVM_MEM_INTERNAL        0                   /* Internal (fast) access memory */
-#define LVM_MEM_EXTERNAL        8                   /* External (slow) access memory */
-
-/* Platform specific */
-#define LVM_PERSISTENT          (LVM_MEM_PARTITION0+LVM_MEM_PERSISTENT+LVM_MEM_INTERNAL)
-#define LVM_PERSISTENT_DATA     (LVM_MEM_PARTITION1+LVM_MEM_PERSISTENT+LVM_MEM_INTERNAL)
-#define LVM_PERSISTENT_COEF     (LVM_MEM_PARTITION2+LVM_MEM_PERSISTENT+LVM_MEM_INTERNAL)
-#define LVM_SCRATCH             (LVM_MEM_PARTITION3+LVM_MEM_SCRATCH+LVM_MEM_INTERNAL)
-
 /****************************************************************************************/
 /*                                                                                      */
 /*  Basic types                                                                         */
diff --git a/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h b/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
index cf2bacc..41e2bb5 100644
--- a/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
+++ b/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
@@ -86,13 +86,6 @@
 /*                                                                                      */
 /****************************************************************************************/
 
-/* Memory table */
-#define LVEQNB_MEMREGION_INSTANCE          0   /* Offset to the instance memory region */
-#define LVEQNB_MEMREGION_PERSISTENT_DATA   1   /* Offset to persistent data memory region */
-#define LVEQNB_MEMREGION_PERSISTENT_COEF   2   /* Offset to persistent coefficient region */
-#define LVEQNB_MEMREGION_SCRATCH           3   /* Offset to data scratch memory region */
-#define LVEQNB_NR_MEMORY_REGIONS           4   /* Number of memory regions */
-
 /* Callback events */
 #define LVEQNB_EVENT_NONE                   0x0000    /* Not a valid event */
 #define LVEQNB_EVENT_ALGOFF                 0x0001    /* EQNB has completed switch off */
@@ -122,16 +115,6 @@
     LVEQNB_FILTER_DUMMY = LVM_MAXINT_32
 } LVEQNB_FilterMode_en;
 
-/* Memory Types */
-typedef enum
-{
-    LVEQNB_PERSISTENT      = 0,
-    LVEQNB_PERSISTENT_DATA = 1,
-    LVEQNB_PERSISTENT_COEF = 2,
-    LVEQNB_SCRATCH         = 3,
-    LVEQNB_MEMORY_MAX      = LVM_MAXINT_32
-} LVEQNB_MemoryTypes_en;
-
 /* Function return status */
 typedef enum
 {
@@ -218,21 +201,6 @@
 /*                                                                                      */
 /****************************************************************************************/
 
-/* Memory region definition */
-typedef struct
-{
-    LVM_UINT32                  Size;                   /* Region size in bytes */
-    LVM_UINT16                  Alignment;              /* Region alignment in bytes */
-    LVEQNB_MemoryTypes_en       Type;                   /* Region type */
-    void                        *pBaseAddress;          /* Pointer to the region base address */
-} LVEQNB_MemoryRegion_t;
-
-/* Memory table containing the region definitions */
-typedef struct
-{
-    LVEQNB_MemoryRegion_t       Region[LVEQNB_NR_MEMORY_REGIONS];  /* One definition for each region */
-} LVEQNB_MemTab_t;
-
 /* Equaliser band definition */
 typedef struct
 {
@@ -279,78 +247,44 @@
 
 /****************************************************************************************/
 /*                                                                                      */
-/* FUNCTION:                LVEQNB_Memory                                               */
-/*                                                                                      */
-/* DESCRIPTION:                                                                         */
-/*  This function is used for memory allocation and free. It can be called in           */
-/*  two ways:                                                                           */
-/*                                                                                      */
-/*      hInstance = NULL                Returns the memory requirements                 */
-/*      hInstance = Instance handle     Returns the memory requirements and             */
-/*                                      allocated base addresses for the instance       */
-/*                                                                                      */
-/*  When this function is called for memory allocation (hInstance=NULL) the memory      */
-/*  base address pointers are NULL on return.                                           */
-/*                                                                                      */
-/*  When the function is called for free (hInstance = Instance Handle) the memory       */
-/*  table returns the allocated memory and base addresses used during initialisation.   */
-/*                                                                                      */
-/* PARAMETERS:                                                                          */
-/*  hInstance               Instance Handle                                             */
-/*  pMemoryTable            Pointer to an empty memory definition table                 */
-/*  pCapabilities           Pointer to the default capabilities                         */
-/*                                                                                      */
-/* RETURNS:                                                                             */
-/*  LVEQNB_SUCCESS          Succeeded                                                   */
-/*  LVEQNB_NULLADDRESS      When any of pMemoryTable and pCapabilities is NULL address  */
-/*                                                                                      */
-/* NOTES:                                                                               */
-/*  1.  This function may be interrupted by the LVEQNB_Process function                 */
-/*                                                                                      */
-/****************************************************************************************/
-
-LVEQNB_ReturnStatus_en LVEQNB_Memory(LVEQNB_Handle_t            hInstance,
-                                     LVEQNB_MemTab_t            *pMemoryTable,
-                                     LVEQNB_Capabilities_t      *pCapabilities);
-
-/****************************************************************************************/
-/*                                                                                      */
 /* FUNCTION:                LVEQNB_Init                                                 */
 /*                                                                                      */
 /* DESCRIPTION:                                                                         */
-/*  Create and initialisation function for the N-Band equalliser module                 */
-/*                                                                                      */
-/*  This function can be used to create an algorithm instance by calling with           */
-/*  hInstance set to NULL. In this case the algorithm returns the new instance          */
-/*  handle.                                                                             */
-/*                                                                                      */
-/*  This function can be used to force a full re-initialisation of the algorithm        */
-/*  by calling with hInstance = Instance Handle. In this case the memory table          */
-/*  should be correct for the instance, this can be ensured by calling the function     */
-/*  LVEQNB_Memory before calling this function.                                         */
+/*  Create and initialisation function for the N-Band equaliser module.                 */
 /*                                                                                      */
 /* PARAMETERS:                                                                          */
-/*  hInstance               Instance handle                                             */
-/*  pMemoryTable            Pointer to the memory definition table                      */
+/*  phInstance              Pointer to instance handle                                  */
 /*  pCapabilities           Pointer to the initialisation capabilities                  */
+/*  pScratch                Pointer to bundle scratch buffer                            */
 /*                                                                                      */
 /* RETURNS:                                                                             */
 /*  LVEQNB_SUCCESS          Initialisation succeeded                                    */
-/*  LVEQNB_NULLADDRESS        When pCapabilities or pMemoryTableis or phInstance are NULL */
-/*  LVEQNB_NULLADDRESS        One or more of the memory regions has a NULL base address   */
-/*                          pointer for a memory region with a non-zero size.           */
-/*                                                                                      */
+/*  LVEQNB_NULLADDRESS      When pCapabilities or phInstance are NULL                   */
+/*  LVEQNB_NULLADDRESS      When allocated memory has a NULL base address               */
 /*                                                                                      */
 /* NOTES:                                                                               */
-/*  1.  The instance handle is the pointer to the base address of the first memory      */
-/*      region.                                                                         */
-/*  2.  This function must not be interrupted by the LVEQNB_Process function            */
+/*  1.  This function must not be interrupted by the LVEQNB_Process function            */
 /*                                                                                      */
 /****************************************************************************************/
-
 LVEQNB_ReturnStatus_en LVEQNB_Init(LVEQNB_Handle_t          *phInstance,
-                                   LVEQNB_MemTab_t          *pMemoryTable,
-                                   LVEQNB_Capabilities_t    *pCapabilities);
+                                   LVEQNB_Capabilities_t    *pCapabilities,
+                                   void                     *pScratch);
+
+/****************************************************************************************/
+/*                                                                                      */
+/* FUNCTION:                LVEQNB_DeInit                                               */
+/*                                                                                      */
+/* DESCRIPTION:                                                                         */
+/*    Free the memories created during LVEQNB_Init including instance handle            */
+/*                                                                                      */
+/* PARAMETERS:                                                                          */
+/*  phInstance              Pointer to instance handle                                  */
+/*                                                                                      */
+/* NOTES:                                                                               */
+/*  1.  This function must not be interrupted by the LVEQNB_Process function            */
+/*                                                                                      */
+/****************************************************************************************/
+void LVEQNB_DeInit(LVEQNB_Handle_t        *phInstance);
 
 /****************************************************************************************/
 /*                                                                                      */
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp
index 271a914..932af71 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp
@@ -21,6 +21,7 @@
 /*                                                                                      */
 /****************************************************************************************/
 
+#include <stdlib.h>
 #include "LVEQNB.h"
 #include "LVEQNB_Private.h"
 #include "InstAlloc.h"
@@ -28,255 +29,75 @@
 
 /****************************************************************************************/
 /*                                                                                      */
-/* FUNCTION:                LVEQNB_Memory                                               */
-/*                                                                                      */
-/* DESCRIPTION:                                                                         */
-/*  This function is used for memory allocation and free. It can be called in           */
-/*  two ways:                                                                           */
-/*                                                                                      */
-/*      hInstance = NULL                Returns the memory requirements                 */
-/*      hInstance = Instance handle     Returns the memory requirements and             */
-/*                                      allocated base addresses for the instance       */
-/*                                                                                      */
-/*  When this function is called for memory allocation (hInstance=NULL) the memory      */
-/*  base address pointers are NULL on return.                                           */
-/*                                                                                      */
-/*  When the function is called for free (hInstance = Instance Handle) the memory       */
-/*  table returns the allocated memory and base addresses used during initialisation.   */
-/*                                                                                      */
-/* PARAMETERS:                                                                          */
-/*  hInstance               Instance Handle                                             */
-/*  pMemoryTable            Pointer to an empty memory definition table                 */
-/*  pCapabilities           Pointer to the instance capabilities                        */
-/*                                                                                      */
-/* RETURNS:                                                                             */
-/*  LVEQNB_SUCCESS          Succeeded                                                   */
-/*  LVEQNB_NULLADDRESS      When any of pMemoryTable and pCapabilities is NULL address  */
-/*                                                                                      */
-/* NOTES:                                                                               */
-/*  1.  This function may be interrupted by the LVEQNB_Process function                 */
-/*                                                                                      */
-/****************************************************************************************/
-
-LVEQNB_ReturnStatus_en LVEQNB_Memory(LVEQNB_Handle_t            hInstance,
-                                     LVEQNB_MemTab_t            *pMemoryTable,
-                                     LVEQNB_Capabilities_t      *pCapabilities)
-{
-
-    INST_ALLOC          AllocMem;
-    LVEQNB_Instance_t   *pInstance = (LVEQNB_Instance_t *)hInstance;
-
-    if((pMemoryTable == LVM_NULL)|| (pCapabilities == LVM_NULL))
-    {
-        return LVEQNB_NULLADDRESS;
-    }
-
-    /*
-     * Fill in the memory table
-     */
-    if (hInstance == LVM_NULL)
-    {
-        /*
-         * Instance memory
-         */
-        InstAlloc_Init(&AllocMem,
-                       LVM_NULL);
-        InstAlloc_AddMember(&AllocMem,                              /* Low pass filter */
-                            sizeof(LVEQNB_Instance_t));
-        pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].Size         = InstAlloc_GetTotal(&AllocMem);
-        pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].Alignment    = LVEQNB_INSTANCE_ALIGN;
-        pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].Type         = LVEQNB_PERSISTENT;
-        pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].pBaseAddress = LVM_NULL;
-
-        /*
-         * Persistant data memory
-         */
-        InstAlloc_Init(&AllocMem,
-                       LVM_NULL);
-        InstAlloc_AddMember(&AllocMem,                              /* Low pass filter */
-                            sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
-        InstAlloc_AddMember(&AllocMem,                              /* High pass filter */
-                            sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
-        /* Equaliser Biquad Taps */
-        InstAlloc_AddMember(&AllocMem,
-                            (pCapabilities->MaxBands * sizeof(Biquad_2I_Order2_FLOAT_Taps_t)));
-        /* Filter definitions */
-        InstAlloc_AddMember(&AllocMem,
-                            (pCapabilities->MaxBands * sizeof(LVEQNB_BandDef_t)));
-        /* Biquad types */
-        InstAlloc_AddMember(&AllocMem,
-                            (pCapabilities->MaxBands * sizeof(LVEQNB_BiquadType_en)));
-        pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Size         = InstAlloc_GetTotal(&AllocMem);
-        pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Alignment    = LVEQNB_DATA_ALIGN;
-        pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Type         = LVEQNB_PERSISTENT_DATA;
-        pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].pBaseAddress = LVM_NULL;
-
-        /*
-         * Persistant coefficient memory
-         */
-        InstAlloc_Init(&AllocMem,
-                       LVM_NULL);
-        InstAlloc_AddMember(&AllocMem,                              /* Low pass filter */
-                            sizeof(Biquad_FLOAT_Instance_t));
-        InstAlloc_AddMember(&AllocMem,                              /* High pass filter */
-                            sizeof(Biquad_FLOAT_Instance_t));
-        /* Equaliser Biquad Instance */
-        InstAlloc_AddMember(&AllocMem,
-                            pCapabilities->MaxBands * sizeof(Biquad_FLOAT_Instance_t));
-        pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Size         = InstAlloc_GetTotal(&AllocMem);
-        pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Alignment    = LVEQNB_COEF_ALIGN;
-        pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Type         = LVEQNB_PERSISTENT_COEF;
-        pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].pBaseAddress = LVM_NULL;
-
-        /*
-         * Scratch memory
-         */
-        InstAlloc_Init(&AllocMem,
-                       LVM_NULL);
-        InstAlloc_AddMember(&AllocMem,                              /* Low pass filter */
-                            LVEQNB_SCRATCHBUFFERS * sizeof(LVM_FLOAT) * \
-                                             pCapabilities->MaxBlockSize);
-        pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Size              = InstAlloc_GetTotal(&AllocMem);
-        pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Alignment         = LVEQNB_SCRATCH_ALIGN;
-        pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Type              = LVEQNB_SCRATCH;
-        pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].pBaseAddress      = LVM_NULL;
-    }
-    else
-    {
-        /* Read back memory allocation table */
-        *pMemoryTable = pInstance->MemoryTable;
-    }
-
-    return(LVEQNB_SUCCESS);
-}
-
-/****************************************************************************************/
-/*                                                                                      */
 /* FUNCTION:                LVEQNB_Init                                                 */
 /*                                                                                      */
 /* DESCRIPTION:                                                                         */
-/*  Create and initialisation function for the N-Band equaliser module                  */
-/*                                                                                      */
-/*  This function can be used to create an algorithm instance by calling with           */
-/*  hInstance set to NULL. In this case the algorithm returns the new instance          */
-/*  handle.                                                                             */
-/*                                                                                      */
-/*  This function can be used to force a full re-initialisation of the algorithm        */
-/*  by calling with hInstance = Instance Handle. In this case the memory table          */
-/*  should be correct for the instance, this can be ensured by calling the function     */
-/*  DBE_Memory before calling this function.                                            */
+/*  Create and initialisation function for the N-Band equaliser module.                 */
 /*                                                                                      */
 /* PARAMETERS:                                                                          */
-/*  hInstance               Instance handle                                             */
-/*  pMemoryTable            Pointer to the memory definition table                      */
-/*  pCapabilities           Pointer to the instance capabilities                        */
+/*  phInstance              Pointer to instance handle                                  */
+/*  pCapabilities           Pointer to the initialisation capabilities                  */
+/*  pScratch                Pointer to bundle scratch buffer                            */
 /*                                                                                      */
 /* RETURNS:                                                                             */
 /*  LVEQNB_SUCCESS          Initialisation succeeded                                    */
-/*  LVEQNB_NULLADDRESS        When pCapabilities or pMemoryTableis or phInstance are NULL */
-/*  LVEQNB_NULLADDRESS        One or more of the memory regions has a NULL base address   */
-/*                          pointer for a memory region with a non-zero size.           */
+/*  LVEQNB_NULLADDRESS      One or more memory has a NULL pointer - malloc failure      */
 /*                                                                                      */
 /* NOTES:                                                                               */
-/*  1.  The instance handle is the pointer to the base address of the first memory      */
-/*      region.                                                                         */
-/*  2.  This function must not be interrupted by the LVEQNB_Process function            */
+/*  1.  This function must not be interrupted by the LVEQNB_Process function            */
 /*                                                                                      */
 /****************************************************************************************/
 
 LVEQNB_ReturnStatus_en LVEQNB_Init(LVEQNB_Handle_t          *phInstance,
-                                   LVEQNB_MemTab_t          *pMemoryTable,
-                                   LVEQNB_Capabilities_t    *pCapabilities)
+                                   LVEQNB_Capabilities_t    *pCapabilities,
+                                   void                     *pScratch)
 {
 
     LVEQNB_Instance_t   *pInstance;
-    LVM_UINT32          MemSize;
-    INST_ALLOC          AllocMem;
-    LVM_INT32           i;
 
-    /*
-     * Check for NULL pointers
-     */
-    if((phInstance == LVM_NULL) || (pMemoryTable == LVM_NULL) || (pCapabilities == LVM_NULL))
+    *phInstance = calloc(1, sizeof(*pInstance));
+    if (phInstance == LVM_NULL)
+    {
+        return LVEQNB_NULLADDRESS;
+    }
+    pInstance =(LVEQNB_Instance_t  *)*phInstance;
+
+    pInstance->Capabilities = *pCapabilities;
+    pInstance->pScratch = pScratch;
+
+    /* Equaliser Biquad Instance */
+    LVM_UINT32 MemSize = pCapabilities->MaxBands * sizeof(*(pInstance->pEQNB_FilterState_Float));
+    pInstance->pEQNB_FilterState_Float = (Biquad_FLOAT_Instance_t *)calloc(1, MemSize);
+    if (pInstance->pEQNB_FilterState_Float == LVM_NULL)
     {
         return LVEQNB_NULLADDRESS;
     }
 
-    /*
-     * Check the memory table for NULL pointers
-     */
-    for (i = 0; i < LVEQNB_NR_MEMORY_REGIONS; i++)
+    MemSize = (pCapabilities->MaxBands * sizeof(*(pInstance->pEQNB_Taps_Float)));
+    pInstance->pEQNB_Taps_Float = (Biquad_2I_Order2_FLOAT_Taps_t *)calloc(1, MemSize);
+    if (pInstance->pEQNB_Taps_Float == LVM_NULL)
     {
-        if (pMemoryTable->Region[i].Size!=0)
-        {
-            if (pMemoryTable->Region[i].pBaseAddress==LVM_NULL)
-            {
-                return(LVEQNB_NULLADDRESS);
-            }
-        }
+        return LVEQNB_NULLADDRESS;
     }
 
-    /*
-     * Set the instance handle if not already initialised
-     */
-
-    InstAlloc_Init(&AllocMem,  pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].pBaseAddress);
-
-    if (*phInstance == LVM_NULL)
+    MemSize = (pCapabilities->MaxBands * sizeof(*(pInstance->pBandDefinitions)));
+    pInstance->pBandDefinitions  = (LVEQNB_BandDef_t *)calloc(1, MemSize);
+    if (pInstance->pBandDefinitions == LVM_NULL)
     {
-        *phInstance = InstAlloc_AddMember(&AllocMem, sizeof(LVEQNB_Instance_t));
+        return LVEQNB_NULLADDRESS;
     }
-    pInstance =(LVEQNB_Instance_t  *)*phInstance;
-
-    /*
-     * Save the memory table in the instance structure
-     */
-    pInstance->Capabilities = *pCapabilities;
-
-    /*
-     * Save the memory table in the instance structure and
-     * set the structure pointers
-     */
-    pInstance->MemoryTable       = *pMemoryTable;
-
-    /*
-     * Allocate coefficient memory
-     */
-    InstAlloc_Init(&AllocMem,
-                   pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].pBaseAddress);
-
-    /* Equaliser Biquad Instance */
-    pInstance->pEQNB_FilterState_Float = (Biquad_FLOAT_Instance_t *)
-        InstAlloc_AddMember(&AllocMem, pCapabilities->MaxBands * \
-                                                       sizeof(Biquad_FLOAT_Instance_t));
-
-    /*
-     * Allocate data memory
-     */
-    InstAlloc_Init(&AllocMem,
-                   pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].pBaseAddress);
-
-    MemSize = (pCapabilities->MaxBands * sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
-    pInstance->pEQNB_Taps_Float = (Biquad_2I_Order2_FLOAT_Taps_t *)InstAlloc_AddMember(&AllocMem,
-                                                                                       MemSize);
-    MemSize = (pCapabilities->MaxBands * sizeof(LVEQNB_BandDef_t));
-    pInstance->pBandDefinitions  = (LVEQNB_BandDef_t *)InstAlloc_AddMember(&AllocMem,
-                                                                           MemSize);
     // clear all the bands, setting their gain to 0, otherwise when applying new params,
     // it will compare against uninitialized values
     memset(pInstance->pBandDefinitions, 0, MemSize);
-    MemSize = (pCapabilities->MaxBands * sizeof(LVEQNB_BiquadType_en));
-    pInstance->pBiquadType = (LVEQNB_BiquadType_en *)InstAlloc_AddMember(&AllocMem,
-                                                                         MemSize);
 
-    /*
-     * Internally map, structure and allign scratch memory
-     */
-    InstAlloc_Init(&AllocMem,
-                   pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].pBaseAddress);
+    MemSize = (pCapabilities->MaxBands * sizeof(*(pInstance->pBiquadType)));
+    pInstance->pBiquadType = (LVEQNB_BiquadType_en *)calloc(1, MemSize);
+    if (pInstance->pBiquadType == LVM_NULL)
+    {
+        return LVEQNB_NULLADDRESS;
+    }
 
-    pInstance->pFastTemporary = (LVM_FLOAT *)InstAlloc_AddMember(&AllocMem,
-                                                                 sizeof(LVM_FLOAT));
+    pInstance->pFastTemporary = (LVM_FLOAT *)pScratch;
 
     /*
      * Update the instance parameters
@@ -319,4 +140,48 @@
 
     return(LVEQNB_SUCCESS);
 }
+/****************************************************************************************/
+/*                                                                                      */
+/* FUNCTION:                LVEQNB_DeInit                                               */
+/*                                                                                      */
+/* DESCRIPTION:                                                                         */
+/*    Free the memories created during LVEQNB_Init including instance handle            */
+/*                                                                                      */
+/* PARAMETERS:                                                                          */
+/*  phInstance              Pointer to instance handle                                  */
+/*                                                                                      */
+/* NOTES:                                                                               */
+/*  1.  This function must not be interrupted by the LVEQNB_Process function            */
+/*                                                                                      */
+/****************************************************************************************/
+
+void LVEQNB_DeInit(LVEQNB_Handle_t          *phInstance)
+{
+
+    LVEQNB_Instance_t   *pInstance;
+    if (phInstance == LVM_NULL) {
+        return;
+    }
+    pInstance =(LVEQNB_Instance_t  *)*phInstance;
+
+    /* Equaliser Biquad Instance */
+    if (pInstance->pEQNB_FilterState_Float != LVM_NULL) {
+        free(pInstance->pEQNB_FilterState_Float);
+        pInstance->pEQNB_FilterState_Float = LVM_NULL;
+    }
+    if (pInstance->pEQNB_Taps_Float != LVM_NULL) {
+        free(pInstance->pEQNB_Taps_Float);
+        pInstance->pEQNB_Taps_Float = LVM_NULL;
+    }
+    if (pInstance->pBandDefinitions != LVM_NULL) {
+        free(pInstance->pBandDefinitions);
+        pInstance->pBandDefinitions = LVM_NULL;
+    }
+    if (pInstance->pBiquadType != LVM_NULL) {
+        free(pInstance->pBiquadType);
+        pInstance->pBiquadType = LVM_NULL;
+    }
+    free(pInstance);
+    *phInstance = LVM_NULL;
+}
 
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
index 1c5729e..9569d85 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
@@ -36,15 +36,6 @@
 
 /* General */
 #define LVEQNB_INVALID              0xFFFF              /* Invalid init parameter */
-
-/* Memory */
-#define LVEQNB_INSTANCE_ALIGN       4                   /* 32-bit alignment for instance structures */
-#define LVEQNB_DATA_ALIGN           4                   /* 32-bit alignment for structures */
-#define LVEQNB_COEF_ALIGN           4                   /* 32-bit alignment for long words */
-/* Number of buffers required for inplace processing */
-#define LVEQNB_SCRATCHBUFFERS       (LVM_MAX_CHANNELS * 2)
-#define LVEQNB_SCRATCH_ALIGN        4                   /* 32-bit alignment for long data */
-
 #define LVEQNB_BYPASS_MIXER_TC      100                 /* Bypass Mixer TC */
 
 /****************************************************************************************/
@@ -73,7 +64,7 @@
 typedef struct
 {
     /* Public parameters */
-    LVEQNB_MemTab_t                 MemoryTable;        /* Instance memory allocation table */
+    void                            *pScratch;          /* Pointer to bundle scratch buffer */
     LVEQNB_Params_t                 Params;             /* Instance parameters */
     LVEQNB_Capabilities_t           Capabilities;       /* Instance capabilities */
 
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h b/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h
index c9fa7ad..0ba662a 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h
@@ -22,28 +22,9 @@
 
 /****************************************************************************************/
 /*                                                                                      */
-/*  CONSTANTS DEFINITIONS                                                               */
-/*                                                                                      */
-/****************************************************************************************/
-
-/* Memory table*/
-#define     LVPSA_NR_MEMORY_REGIONS                  4      /* Number of memory regions                                          */
-
-/****************************************************************************************/
-/*                                                                                      */
 /*  TYPES DEFINITIONS                                                                   */
 /*                                                                                      */
 /****************************************************************************************/
-/* Memory Types */
-typedef enum
-{
-    LVPSA_PERSISTENT      = LVM_PERSISTENT,
-    LVPSA_PERSISTENT_DATA = LVM_PERSISTENT_DATA,
-    LVPSA_PERSISTENT_COEF = LVM_PERSISTENT_COEF,
-    LVPSA_SCRATCH         = LVM_SCRATCH,
-    LVPSA_MEMORY_DUMMY = LVM_MAXINT_32                      /* Force 32 bits enum, don't use it!                                 */
-} LVPSA_MemoryTypes_en;
-
 /* Level detection speed control parameters */
 typedef enum
 {
@@ -80,20 +61,6 @@
 
 } LVPSA_ControlParams_t, *pLVPSA_ControlParams_t;
 
-/* Memory region definition */
-typedef struct
-{
-    LVM_UINT32                 Size;                        /* Region size in bytes                                              */
-    LVPSA_MemoryTypes_en       Type;                        /* Region type                                                       */
-    void                       *pBaseAddress;               /* Pointer to the region base address                                */
-} LVPSA_MemoryRegion_t;
-
-/* Memory table containing the region definitions */
-typedef struct
-{
-    LVPSA_MemoryRegion_t       Region[LVPSA_NR_MEMORY_REGIONS];/* One definition for each region                                 */
-} LVPSA_MemTab_t;
-
 /* Audio time type */
 typedef LVM_INT32 LVPSA_Time;
 
@@ -113,62 +80,43 @@
 /*********************************************************************************************************************************
    FUNCTIONS PROTOTYPE
 **********************************************************************************************************************************/
-/*********************************************************************************************************************************/
-/*                                                                                                                               */
-/* FUNCTION:            LVPSA_Memory                                                                                         */
-/*                                                                                                                               */
-/* DESCRIPTION:                                                                                                                  */
-/*  This function is used for memory allocation and free. It can be called in                                                    */
-/*  two ways:                                                                                                                    */
-/*                                                                                                                               */
-/*      hInstance = NULL                Returns the memory requirements                                                          */
-/*      hInstance = Instance handle     Returns the memory requirements and                                                      */
-/*                                      allocated base addresses for the instance                                                */
-/*                                                                                                                               */
-/*  When this function is called for memory allocation (hInstance=NULL) the memory                                               */
-/*  base address pointers are NULL on return.                                                                                    */
-/*                                                                                                                               */
-/*  When the function is called for free (hInstance = Instance Handle) the memory                                                */
-/*  table returns the allocated memory and base addresses used during initialisation.                                            */
-/*                                                                                                                               */
-/* PARAMETERS:                                                                                                                   */
-/*  hInstance           Instance Handle                                                                                          */
-/*  pMemoryTable        Pointer to an empty memory definition table                                                              */
-/*  pInitParams         Pointer to the instance init parameters                                                                  */
-/*                                                                                                                               */
-/* RETURNS:                                                                                                                      */
-/*  LVPSA_OK            Succeeds                                                                                                 */
-/*  otherwise           Error due to bad parameters                                                                              */
-/*                                                                                                                               */
-/*********************************************************************************************************************************/
-LVPSA_RETURN LVPSA_Memory            ( pLVPSA_Handle_t             hInstance,
-                                       LVPSA_MemTab_t             *pMemoryTable,
-                                       LVPSA_InitParams_t         *pInitParams    );
+/************************************************************************************/
+/*                                                                                  */
+/* FUNCTION:            LVPSA_Init                                                  */
+/*                                                                                  */
+/* DESCRIPTION:                                                                     */
+/*  Create and Initialize the LVPSA module including instance handle                */
+/*                                                                                  */
+/*                                                                                  */
+/* PARAMETERS:                                                                      */
+/*  phInstance          Pointer to the instance handle                              */
+/*  InitParams          Init parameters structure                                   */
+/*  ControlParams       Control parameters structure                                */
+/*  pScratch            Pointer to bundle scratch memory area                       */
+/*                                                                                  */
+/*                                                                                  */
+/* RETURNS:                                                                         */
+/*  LVPSA_OK            Succeeds                                                    */
+/*  otherwise           Error due to bad parameters                                 */
+/*                                                                                  */
+/************************************************************************************/
+LVPSA_RETURN LVPSA_Init(pLVPSA_Handle_t             *phInstance,
+                        LVPSA_InitParams_t          *pInitParams,
+                        LVPSA_ControlParams_t       *pControlParams,
+                        void                        *pScratch);
 
-/*********************************************************************************************************************************/
-/*                                                                                                                               */
-/* FUNCTION:            LVPSA_Init                                                                                               */
-/*                                                                                                                               */
-/* DESCRIPTION:                                                                                                                  */
-/*  Initializes the LVPSA module.                                                                                                */
-/*                                                                                                                               */
-/*                                                                                                                               */
-/* PARAMETERS:                                                                                                                   */
-/*  phInstance          Pointer to the instance Handle                                                                           */
-/*  pInitParams         Pointer to the instance init parameters                                                                  */
-/*  pControlParams      Pointer to the instance control parameters                                                               */
-/*  pMemoryTable        Pointer to the memory definition table                                                                   */
-/*                                                                                                                               */
-/*                                                                                                                               */
-/* RETURNS:                                                                                                                      */
-/*  LVPSA_OK            Succeeds                                                                                                 */
-/*  otherwise           Error due to bad parameters                                                                              */
-/*                                                                                                                               */
-/*********************************************************************************************************************************/
-LVPSA_RETURN LVPSA_Init              ( pLVPSA_Handle_t             *phInstance,
-                                       LVPSA_InitParams_t          *pInitParams,
-                                       LVPSA_ControlParams_t       *pControlParams,
-                                       LVPSA_MemTab_t              *pMemoryTable  );
+/************************************************************************************/
+/*                                                                                  */
+/* FUNCTION:            LVPSA_DeInit                                                */
+/*                                                                                  */
+/* DESCRIPTION:                                                                     */
+/*    Free the memories created in LVPSA_Init call including instance handle        */
+/*                                                                                  */
+/* PARAMETERS:                                                                      */
+/*  phInstance          Pointer to the instance handle                              */
+/*                                                                                  */
+/************************************************************************************/
+void LVPSA_DeInit(pLVPSA_Handle_t             *phInstance);
 
 /*********************************************************************************************************************************/
 /*                                                                                                                               */
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp
index 9fcd82f..be3c68f 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 
+#include    <stdlib.h>
 #include    "LVPSA.h"
 #include    "LVPSA_Private.h"
 #include    "InstAlloc.h"
@@ -24,14 +25,14 @@
 /* FUNCTION:            LVPSA_Init                                                  */
 /*                                                                                  */
 /* DESCRIPTION:                                                                     */
-/*  Initialize the LVPSA module                                                     */
+/*  Create and Initialize the LVPSA module including instance handle                */
 /*                                                                                  */
 /*                                                                                  */
 /* PARAMETERS:                                                                      */
-/*  phInstance          Pointer to pointer to the instance                          */
+/*  phInstance          Pointer to the instance handle                              */
 /*  InitParams          Init parameters structure                                   */
 /*  ControlParams       Control parameters structure                                */
-/*  pMemoryTable        Memory table that contains memory areas definition          */
+/*  pScratch            Pointer to bundle scratch memory area                       */
 /*                                                                                  */
 /*                                                                                  */
 /* RETURNS:                                                                         */
@@ -39,10 +40,10 @@
 /*  otherwise           Error due to bad parameters                                 */
 /*                                                                                  */
 /************************************************************************************/
-LVPSA_RETURN LVPSA_Init              ( pLVPSA_Handle_t             *phInstance,
-                                       LVPSA_InitParams_t          *pInitParams,
-                                       LVPSA_ControlParams_t       *pControlParams,
-                                       LVPSA_MemTab_t              *pMemoryTable )
+LVPSA_RETURN LVPSA_Init(pLVPSA_Handle_t             *phInstance,
+                        LVPSA_InitParams_t          *pInitParams,
+                        LVPSA_ControlParams_t       *pControlParams,
+                        void                        *pScratch)
 {
     LVPSA_InstancePr_t          *pLVPSA_Inst;
     LVPSA_RETURN                errorCode       = LVPSA_OK;
@@ -50,64 +51,15 @@
     extern LVM_FLOAT            LVPSA_Float_GainTable[];
     LVM_UINT32                  BufferLength = 0;
 
-    /* Ints_Alloc instances, needed for memory alignment management */
-    INST_ALLOC          Instance;
-    INST_ALLOC          Scratch;
-    INST_ALLOC          Data;
-    INST_ALLOC          Coef;
-
-    /* Check parameters */
-    if((phInstance == LVM_NULL) || (pInitParams == LVM_NULL) || (pControlParams == LVM_NULL) || (pMemoryTable == LVM_NULL))
-    {
-        return(LVPSA_ERROR_NULLADDRESS);
-    }
-    if( (pInitParams->SpectralDataBufferDuration > LVPSA_MAXBUFFERDURATION)   ||
-        (pInitParams->SpectralDataBufferDuration == 0)                        ||
-        (pInitParams->MaxInputBlockSize > LVPSA_MAXINPUTBLOCKSIZE)      ||
-        (pInitParams->MaxInputBlockSize == 0)                           ||
-        (pInitParams->nBands < LVPSA_NBANDSMIN)                         ||
-        (pInitParams->nBands > LVPSA_NBANDSMAX)                         ||
-        (pInitParams->pFiltersParams == 0))
-    {
-        return(LVPSA_ERROR_INVALIDPARAM);
-    }
-    for(ii = 0; ii < pInitParams->nBands; ii++)
-    {
-        if((pInitParams->pFiltersParams[ii].CenterFrequency > LVPSA_MAXCENTERFREQ) ||
-           (pInitParams->pFiltersParams[ii].PostGain        > LVPSA_MAXPOSTGAIN)   ||
-           (pInitParams->pFiltersParams[ii].PostGain        < LVPSA_MINPOSTGAIN)   ||
-           (pInitParams->pFiltersParams[ii].QFactor < LVPSA_MINQFACTOR)            ||
-           (pInitParams->pFiltersParams[ii].QFactor > LVPSA_MAXQFACTOR))
-           {
-                return(LVPSA_ERROR_INVALIDPARAM);
-           }
-    }
-
-    /*Inst_Alloc instances initialization */
-    InstAlloc_Init( &Instance   , pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].pBaseAddress);
-    InstAlloc_Init( &Scratch    , pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress);
-    InstAlloc_Init( &Data       , pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].pBaseAddress);
-    InstAlloc_Init( &Coef       , pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].pBaseAddress);
-
     /* Set the instance handle if not already initialised */
+    *phInstance = calloc(1, sizeof(*pLVPSA_Inst));
     if (*phInstance == LVM_NULL)
     {
-        *phInstance = InstAlloc_AddMember( &Instance, sizeof(LVPSA_InstancePr_t) );
+        return LVPSA_ERROR_NULLADDRESS;
     }
     pLVPSA_Inst =(LVPSA_InstancePr_t*)*phInstance;
 
-    /* Check the memory table for NULL pointers */
-    for (ii = 0; ii < LVPSA_NR_MEMORY_REGIONS; ii++)
-    {
-        if (pMemoryTable->Region[ii].Size!=0)
-        {
-            if (pMemoryTable->Region[ii].pBaseAddress==LVM_NULL)
-            {
-                return(LVPSA_ERROR_NULLADDRESS);
-            }
-            pLVPSA_Inst->MemoryTable.Region[ii] = pMemoryTable->Region[ii];
-        }
-    }
+    pLVPSA_Inst->pScratch = pScratch;
 
     /* Initialize module's internal parameters */
     pLVPSA_Inst->bControlPending = LVM_FALSE;
@@ -137,31 +89,61 @@
     }
 
     /* Assign the pointers */
-    pLVPSA_Inst->pPostGains             =
-        (LVM_FLOAT *)InstAlloc_AddMember(&Instance, pInitParams->nBands * sizeof(LVM_FLOAT));
-    pLVPSA_Inst->pFiltersParams             = (LVPSA_FilterParam_t *)
-        InstAlloc_AddMember(&Instance, pInitParams->nBands * sizeof(LVPSA_FilterParam_t));
-    pLVPSA_Inst->pSpectralDataBufferStart   = (LVM_UINT8 *)
-        InstAlloc_AddMember(&Instance, pInitParams->nBands * \
-                                pLVPSA_Inst->SpectralDataBufferLength * sizeof(LVM_UINT8));
-    pLVPSA_Inst->pPreviousPeaks             = (LVM_UINT8 *)
-                  InstAlloc_AddMember(&Instance, pInitParams->nBands * sizeof(LVM_UINT8));
-    pLVPSA_Inst->pBPFiltersPrecision        = (LVPSA_BPFilterPrecision_en *)
-                  InstAlloc_AddMember(&Instance, pInitParams->nBands * \
-                                                       sizeof(LVPSA_BPFilterPrecision_en));
-    pLVPSA_Inst->pBP_Instances          = (Biquad_FLOAT_Instance_t *)
-                  InstAlloc_AddMember(&Coef, pInitParams->nBands * \
-                                                          sizeof(Biquad_FLOAT_Instance_t));
-    pLVPSA_Inst->pQPD_States            = (QPD_FLOAT_State_t *)
-                  InstAlloc_AddMember(&Coef, pInitParams->nBands * \
-                                                                sizeof(QPD_FLOAT_State_t));
-
-    pLVPSA_Inst->pBP_Taps               = (Biquad_1I_Order2_FLOAT_Taps_t *)
-        InstAlloc_AddMember(&Data, pInitParams->nBands * \
-                                                     sizeof(Biquad_1I_Order2_FLOAT_Taps_t));
-    pLVPSA_Inst->pQPD_Taps              = (QPD_FLOAT_Taps_t *)
-        InstAlloc_AddMember(&Data, pInitParams->nBands * \
-                                                    sizeof(QPD_FLOAT_Taps_t));
+    pLVPSA_Inst->pPostGains = (LVM_FLOAT *)
+                    calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pPostGains)));
+    if (pLVPSA_Inst->pPostGains == LVM_NULL)
+    {
+        return LVPSA_ERROR_NULLADDRESS;
+    }
+    pLVPSA_Inst->pFiltersParams = (LVPSA_FilterParam_t *)
+                    calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pFiltersParams)));
+    if (pLVPSA_Inst->pFiltersParams == LVM_NULL)
+    {
+        return LVPSA_ERROR_NULLADDRESS;
+    }
+    pLVPSA_Inst->pSpectralDataBufferStart = (LVM_UINT8 *)
+                    calloc(pInitParams->nBands, pLVPSA_Inst->SpectralDataBufferLength * \
+                            sizeof(*(pLVPSA_Inst->pSpectralDataBufferStart)));
+    if (pLVPSA_Inst->pSpectralDataBufferStart == LVM_NULL)
+    {
+        return LVPSA_ERROR_NULLADDRESS;
+    }
+    pLVPSA_Inst->pPreviousPeaks = (LVM_UINT8 *)
+                        calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pPreviousPeaks)));
+    if (pLVPSA_Inst->pPreviousPeaks == LVM_NULL)
+    {
+        return LVPSA_ERROR_NULLADDRESS;
+    }
+    pLVPSA_Inst->pBPFiltersPrecision = (LVPSA_BPFilterPrecision_en *)
+                        calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pBPFiltersPrecision)));
+    if (pLVPSA_Inst->pBPFiltersPrecision == LVM_NULL)
+    {
+        return LVPSA_ERROR_NULLADDRESS;
+    }
+    pLVPSA_Inst->pBP_Instances = (Biquad_FLOAT_Instance_t *)
+                        calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pBP_Instances)));
+    if (pLVPSA_Inst->pBP_Instances == LVM_NULL)
+    {
+        return LVPSA_ERROR_NULLADDRESS;
+    }
+    pLVPSA_Inst->pQPD_States = (QPD_FLOAT_State_t *)
+                        calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pQPD_States)));
+    if (pLVPSA_Inst->pQPD_States == LVM_NULL)
+    {
+        return LVPSA_ERROR_NULLADDRESS;
+    }
+    pLVPSA_Inst->pBP_Taps = (Biquad_1I_Order2_FLOAT_Taps_t *)
+                        calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pBP_Taps)));
+    if (pLVPSA_Inst->pBP_Taps == LVM_NULL)
+    {
+        return LVPSA_ERROR_NULLADDRESS;
+    }
+    pLVPSA_Inst->pQPD_Taps = (QPD_FLOAT_Taps_t *)
+                        calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pQPD_Taps)));
+    if (pLVPSA_Inst->pQPD_Taps == LVM_NULL)
+    {
+        return LVPSA_ERROR_NULLADDRESS;
+    }
 
     /* Copy filters parameters in the private instance */
     for(ii = 0; ii < pLVPSA_Inst->nBands; ii++)
@@ -195,3 +177,60 @@
     return(errorCode);
 }
 
+/************************************************************************************/
+/*                                                                                  */
+/* FUNCTION:            LVPSA_DeInit                                                */
+/*                                                                                  */
+/* DESCRIPTION:                                                                     */
+/*    Free the memories created in LVPSA_Init call including instance handle        */
+/*                                                                                  */
+/* PARAMETERS:                                                                      */
+/*  phInstance          Pointer to the instance handle                              */
+/*                                                                                  */
+/************************************************************************************/
+void LVPSA_DeInit(pLVPSA_Handle_t *phInstance)
+{
+    LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t *)*phInstance;
+    if (pLVPSA_Inst == LVM_NULL) {
+        return;
+    }
+    if (pLVPSA_Inst->pPostGains != LVM_NULL) {
+        free(pLVPSA_Inst->pPostGains);
+        pLVPSA_Inst->pPostGains = LVM_NULL;
+    }
+    if (pLVPSA_Inst->pFiltersParams != LVM_NULL) {
+        free(pLVPSA_Inst->pFiltersParams);
+        pLVPSA_Inst->pFiltersParams = LVM_NULL;
+    }
+    if (pLVPSA_Inst->pSpectralDataBufferStart != LVM_NULL) {
+        free(pLVPSA_Inst->pSpectralDataBufferStart);
+        pLVPSA_Inst->pSpectralDataBufferStart = LVM_NULL;
+    }
+    if (pLVPSA_Inst->pPreviousPeaks != LVM_NULL) {
+        free(pLVPSA_Inst->pPreviousPeaks);
+        pLVPSA_Inst->pPreviousPeaks = LVM_NULL;
+    }
+    if (pLVPSA_Inst->pBPFiltersPrecision != LVM_NULL) {
+        free(pLVPSA_Inst->pBPFiltersPrecision);
+        pLVPSA_Inst->pBPFiltersPrecision = LVM_NULL;
+    }
+    if (pLVPSA_Inst->pBP_Instances != LVM_NULL) {
+        free(pLVPSA_Inst->pBP_Instances);
+        pLVPSA_Inst->pBP_Instances = LVM_NULL;
+    }
+    if (pLVPSA_Inst->pQPD_States != LVM_NULL) {
+        free(pLVPSA_Inst->pQPD_States);
+        pLVPSA_Inst->pQPD_States = LVM_NULL;
+    }
+    if (pLVPSA_Inst->pBP_Taps != LVM_NULL) {
+        free(pLVPSA_Inst->pBP_Taps);
+        pLVPSA_Inst->pBP_Taps = LVM_NULL;
+    }
+    if (pLVPSA_Inst->pQPD_Taps != LVM_NULL) {
+        free(pLVPSA_Inst->pQPD_Taps);
+        pLVPSA_Inst->pQPD_Taps = LVM_NULL;
+    }
+    free(pLVPSA_Inst);
+    *phInstance = LVM_NULL;
+}
+
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.cpp b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.cpp
deleted file mode 100644
index eafcbe6..0000000
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * 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    "LVPSA.h"
-#include    "LVPSA_Private.h"
-#include    "InstAlloc.h"
-
-/****************************************************************************************/
-/*                                                                                      */
-/* FUNCTION:                LVEQNB_Memory                                               */
-/*                                                                                      */
-/* DESCRIPTION:                                                                         */
-/*  This function is used for memory allocation and free. It can be called in           */
-/*  two ways:                                                                           */
-/*                                                                                      */
-/*      hInstance = NULL         Returns the memory requirements                        */
-/*      hInstance = Instance handle     Returns the memory requirements and             */
-/*                                      allocated base addresses for the instance       */
-/*                                                                                      */
-/*  When this function is called for memory allocation (hInstance=NULL) the memory      */
-/*  base address pointers are NULL on return.                                           */
-/*                                                                                      */
-/*  When the function is called for free (hInstance = Instance Handle) the memory       */
-/*  table returns the allocated memory and base addresses used during initialisation.   */
-/*                                                                                      */
-/* PARAMETERS:                                                                          */
-/*  hInstance               Instance Handle                                             */
-/*  pMemoryTable            Pointer to an empty memory definition table                 */
-/*  InitParams              Pointer to the instance init parameters                     */
-/*                                                                                      */
-/* RETURNS:                                                                             */
-/*  LVPSA_OK            Succeeds                                                        */
-/*  otherwise           Error due to bad parameters                                     */
-/*                                                                                      */
-/****************************************************************************************/
-LVPSA_RETURN LVPSA_Memory            ( pLVPSA_Handle_t             hInstance,
-                                       LVPSA_MemTab_t             *pMemoryTable,
-                                       LVPSA_InitParams_t         *pInitParams    )
-{
-    LVM_UINT32          ii;
-    LVM_UINT32          BufferLength;
-    INST_ALLOC          Instance;
-    INST_ALLOC          Scratch;
-    INST_ALLOC          Data;
-    INST_ALLOC          Coef;
-    LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
-
-    InstAlloc_Init( &Instance   , LVM_NULL);
-    InstAlloc_Init( &Scratch    , LVM_NULL);
-    InstAlloc_Init( &Data       , LVM_NULL);
-    InstAlloc_Init( &Coef       , LVM_NULL);
-
-    if((pMemoryTable == LVM_NULL) || (pInitParams == LVM_NULL))
-    {
-        return(LVPSA_ERROR_NULLADDRESS);
-    }
-
-    /*
-     * Fill in the memory table
-     */
-    if (hInstance == LVM_NULL)
-    {
-
-        /* Check init parameter */
-        if( (pInitParams->SpectralDataBufferDuration > LVPSA_MAXBUFFERDURATION)   ||
-            (pInitParams->SpectralDataBufferDuration == 0)                        ||
-            (pInitParams->MaxInputBlockSize > LVPSA_MAXINPUTBLOCKSIZE)      ||
-            (pInitParams->MaxInputBlockSize == 0)                           ||
-            (pInitParams->nBands < LVPSA_NBANDSMIN)                         ||
-            (pInitParams->nBands > LVPSA_NBANDSMAX)                         ||
-            (pInitParams->pFiltersParams == 0))
-        {
-            return(LVPSA_ERROR_INVALIDPARAM);
-        }
-        for(ii = 0; ii < pInitParams->nBands; ii++)
-        {
-            if((pInitParams->pFiltersParams[ii].CenterFrequency > LVPSA_MAXCENTERFREQ) ||
-               (pInitParams->pFiltersParams[ii].PostGain        > LVPSA_MAXPOSTGAIN)   ||
-               (pInitParams->pFiltersParams[ii].PostGain        < LVPSA_MINPOSTGAIN)   ||
-               (pInitParams->pFiltersParams[ii].QFactor < LVPSA_MINQFACTOR)            ||
-               (pInitParams->pFiltersParams[ii].QFactor > LVPSA_MAXQFACTOR))
-               {
-                    return(LVPSA_ERROR_INVALIDPARAM);
-               }
-        }
-
-        /*
-         * Instance memory
-         */
-
-        InstAlloc_AddMember( &Instance, sizeof(LVPSA_InstancePr_t) );
-        InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_FLOAT) );
-        InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVPSA_FilterParam_t) );
-
-        {
-            /* for avoiding QAC warnings as MUL32x32INTO32 works on LVM_INT32 only*/
-            LVM_INT32 SDBD=(LVM_INT32)pInitParams->SpectralDataBufferDuration;
-            LVM_INT32 IRTI=(LVM_INT32)LVPSA_InternalRefreshTimeInv;
-            LVM_INT32 BL;
-
-            MUL32x32INTO32(SDBD,IRTI,BL,LVPSA_InternalRefreshTimeShift)
-            BufferLength=(LVM_UINT32)BL;
-        }
-
-        if((BufferLength * LVPSA_InternalRefreshTime) != pInitParams->SpectralDataBufferDuration)
-        {
-            BufferLength++;
-        }
-        InstAlloc_AddMember( &Instance, pInitParams->nBands * BufferLength * sizeof(LVM_UINT8) );
-        InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_UINT8) );
-        InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVPSA_BPFilterPrecision_en) );
-        pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].Size         = InstAlloc_GetTotal(&Instance);
-        pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].Type         = LVPSA_PERSISTENT;
-        pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].pBaseAddress = LVM_NULL;
-
-        /*
-         * Scratch memory
-         */
-        InstAlloc_AddMember( &Scratch, 2 * pInitParams->MaxInputBlockSize * sizeof(LVM_FLOAT) );
-        pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].Size         = InstAlloc_GetTotal(&Scratch);
-        pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].Type         = LVPSA_SCRATCH;
-        pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress = LVM_NULL;
-
-        /*
-         * Persistent coefficients memory
-         */
-        InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(Biquad_FLOAT_Instance_t) );
-        InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(QPD_FLOAT_State_t) );
-        pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].Size         = InstAlloc_GetTotal(&Coef);
-        pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].Type         = LVPSA_PERSISTENT_COEF;
-        pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].pBaseAddress = LVM_NULL;
-
-        /*
-         * Persistent data memory
-         */
-        InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(Biquad_1I_Order2_FLOAT_Taps_t) );
-        InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(QPD_FLOAT_Taps_t) );
-        pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].Size         = InstAlloc_GetTotal(&Data);
-        pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].Type         = LVPSA_PERSISTENT_DATA;
-        pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].pBaseAddress = LVM_NULL;
-
-    }
-    else
-    {
-        /* Read back memory allocation table */
-        *pMemoryTable = pLVPSA_Inst->MemoryTable;
-    }
-
-    return(LVPSA_OK);
-}
-
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h
index 61987b5..fc67a75 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h
@@ -27,16 +27,6 @@
    CONSTANT DEFINITIONS
 ***********************************************************************************/
 
-/* Memory */
-#define LVPSA_INSTANCE_ALIGN             4      /* 32-bit alignment for structures                                  */
-#define LVPSA_SCRATCH_ALIGN              4      /* 32-bit alignment for long data                                   */
-#define LVPSA_COEF_ALIGN                 4      /* 32-bit alignment for long words                                  */
-#define LVPSA_DATA_ALIGN                 4      /* 32-bit alignment for long data                                   */
-
-#define LVPSA_MEMREGION_INSTANCE         0      /* Offset to instance memory region in memory table                 */
-#define LVPSA_MEMREGION_PERSISTENT_COEF  1      /* Offset to persistent coefficients  memory region in memory table */
-#define LVPSA_MEMREGION_PERSISTENT_DATA  2      /* Offset to persistent taps  memory region in memory table         */
-#define LVPSA_MEMREGION_SCRATCH          3      /* Offset to scratch  memory region in memory table                 */
 #define LVPSA_NR_SUPPORTED_RATE          13      /* From 8000Hz to 192000Hz*/
 #define LVPSA_NR_SUPPORTED_SPEED         3      /* LOW, MEDIUM, HIGH                                                */
 
@@ -82,7 +72,8 @@
 
     LVPSA_ControlParams_t       CurrentParams;                      /* Current control parameters of the module                                                     */
     LVPSA_ControlParams_t       NewParams;                          /* New control parameters given by the user                                                     */
-    LVPSA_MemTab_t              MemoryTable;
+    void                        *pScratch;
+    /* Pointer to bundle scratch buffer */
 
     LVPSA_BPFilterPrecision_en *pBPFiltersPrecision;                /* Points a nBands elements array that contains the filter precision for each band              */
     Biquad_FLOAT_Instance_t          *pBP_Instances;
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.cpp b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.cpp
index 81a88c5..b4d111e 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.cpp
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.cpp
@@ -79,8 +79,7 @@
     {
         return(LVPSA_ERROR_INVALIDPARAM);
     }
-
-    pScratch = (LVM_FLOAT*)pLVPSA_Inst->MemoryTable.Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress;
+    pScratch = (LVM_FLOAT*)pLVPSA_Inst->pScratch;
     pWrite_Save = pLVPSA_Inst->pSpectralDataBufferWritePointer;
 
     /******************************************************************************
diff --git a/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h b/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
index b1f3452..58ba8ad 100644
--- a/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
+++ b/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
@@ -71,13 +71,6 @@
 /*                                                                                      */
 /****************************************************************************************/
 
-/* Memory table */
-#define LVCS_MEMREGION_PERSISTENT_SLOW_DATA    0    /* Offset to the instance memory region */
-#define LVCS_MEMREGION_PERSISTENT_FAST_DATA    1    /* Offset to the persistent data memory region */
-#define LVCS_MEMREGION_PERSISTENT_FAST_COEF    2    /* Offset to the persistent coefficient memory region */
-#define LVCS_MEMREGION_TEMPORARY_FAST          3    /* Offset to temporary memory region */
-#define LVCS_NR_MEMORY_REGIONS                 4    /* Number of memory regions */
-
 /* Effect Level */
 #define LVCS_EFFECT_LOW                    16384    /* Effect scaling 50% */
 #define LVCS_EFFECT_MEDIUM                 24576    /* Effect scaling 75% */
@@ -104,24 +97,12 @@
     LVCS_MAX = LVM_MAXENUM
 } LVCS_Modes_en;
 
-/* Memory Types */
-typedef enum
-{
-    LVCS_SCRATCH        = 0,
-    LVCS_DATA           = 1,
-    LVCS_COEFFICIENT    = 2,
-    LVCS_PERSISTENT     = 3,
-    LVCS_MEMORYTYPE_MAX = LVM_MAXENUM
-} LVCS_MemoryTypes_en;
-
 /* Function return status */
 typedef enum
 {
     LVCS_SUCCESS        = 0,                        /* Successful return from a routine */
-    LVCS_ALIGNMENTERROR = 1,                        /* Memory alignment error */
-    LVCS_NULLADDRESS    = 2,                        /* NULL allocation address */
-    LVCS_TOOMANYSAMPLES = 3,                        /* Maximum block size exceeded */
-    LVCS_INVALIDBUFFER  = 4,                        /* Invalid buffer processing request */
+    LVCS_NULLADDRESS    = 1,                        /* NULL allocation address */
+    LVCS_TOOMANYSAMPLES = 2,                        /* Maximum block size exceeded */
     LVCS_STATUSMAX      = LVM_MAXENUM
 } LVCS_ReturnStatus_en;
 
@@ -166,20 +147,6 @@
 /*                                                                                      */
 /****************************************************************************************/
 
-/* Memory region definition */
-typedef struct
-{
-    LVM_UINT32              Size;                   /* Region size in bytes */
-    LVCS_MemoryTypes_en     Type;                   /* Region type */
-    void                    *pBaseAddress;          /* Pointer to the region base address */
-} LVCS_MemoryRegion_t;
-
-/* Memory table containing the region definitions */
-typedef struct
-{
-    LVCS_MemoryRegion_t Region[LVCS_NR_MEMORY_REGIONS]; /* One definition for each region */
-} LVCS_MemTab_t;
-
 /* Concert Sound parameter structure */
 typedef struct
 {
@@ -211,82 +178,45 @@
 /*                                                                                      */
 /****************************************************************************************/
 
-/****************************************************************************************/
-/*                                                                                      */
-/* FUNCTION:                LVCS_Memory                                                 */
-/*                                                                                      */
-/* DESCRIPTION:                                                                         */
-/*  This function is used for memory allocation and free. It can be called in           */
-/*  two ways:                                                                           */
-/*                                                                                      */
-/*      hInstance = NULL                Returns the memory requirements                 */
-/*      hInstance = Instance handle     Returns the memory requirements and             */
-/*                                      allocated base addresses for the instance       */
-/*                                                                                      */
-/*  When this function is called for memory allocation (hInstance=NULL) it is           */
-/*  passed the default capabilities, of these only the buffer processing setting is     */
-/*  used.                                                                               */
-/*                                                                                      */
-/*  When called for memory allocation the memory base address pointers are NULL on      */
-/*  return.                                                                             */
-/*                                                                                      */
-/*  When the function is called for free (hInstance = Instance Handle) the              */
-/*  capabilities are ignored and the memory table returns the allocated memory and      */
-/*  base addresses used during initialisation.                                          */
-/*                                                                                      */
-/* PARAMETERS:                                                                          */
-/*  hInstance               Instance Handle                                             */
-/*  pMemoryTable            Pointer to an empty memory definition table                 */
-/*  pCapabilities           Pointer to the default capabilites                          */
-/*                                                                                      */
-/* RETURNS:                                                                             */
-/*  LVCS_Success            Succeeded                                                   */
-/*                                                                                      */
-/* NOTES:                                                                               */
-/*  1.  This function may be interrupted by the LVCS_Process function                   */
-/*                                                                                      */
-/****************************************************************************************/
-
-LVCS_ReturnStatus_en LVCS_Memory(LVCS_Handle_t          hInstance,
-                                 LVCS_MemTab_t          *pMemoryTable,
-                                 LVCS_Capabilities_t    *pCapabilities);
-
-/****************************************************************************************/
-/*                                                                                      */
-/* FUNCTION:                LVCS_Init                                                   */
-/*                                                                                      */
-/* DESCRIPTION:                                                                         */
-/*  Create and initialisation function for the Concert Sound module                     */
-/*                                                                                      */
-/*  This function can be used to create an algorithm instance by calling with           */
-/*  hInstance set to NULL. In this case the algorithm returns the new instance          */
-/*  handle.                                                                             */
-/*                                                                                      */
-/*  This function can be used to force a full re-initialisation of the algorithm        */
-/*  by calling with hInstance = Instance Handle. In this case the memory table          */
-/*  should be correct for the instance, this can be ensured by calling the function     */
-/*  LVCS_Memory before calling this function.                                           */
-/*                                                                                      */
-/* PARAMETERS:                                                                          */
-/*  hInstance               Instance handle                                             */
-/*  pMemoryTable            Pointer to the memory definition table                      */
-/*  pCapabilities           Pointer to the initialisation capabilities                  */
-/*                                                                                      */
-/* RETURNS:                                                                             */
-/*  LVCS_Success            Initialisation succeeded                                    */
-/*  LVCS_AlignmentError     Instance or scratch memory on incorrect alignment           */
-/*  LVCS_NullAddress        Instance or scratch memory has a NULL pointer               */
-/*                                                                                      */
-/* NOTES:                                                                               */
-/*  1.  The instance handle is the pointer to the base address of the first memory      */
-/*      region.                                                                         */
-/*  2.  This function must not be interrupted by the LVCS_Process function              */
-/*                                                                                      */
-/****************************************************************************************/
-
+/************************************************************************************/
+/*                                                                                  */
+/* FUNCTION:                LVCS_Init                                               */
+/*                                                                                  */
+/* DESCRIPTION:                                                                     */
+/*  Create and initialisation function for the Concert Sound module                 */
+/*                                                                                  */
+/* PARAMETERS:                                                                      */
+/*  phInstance              Pointer to instance handle                              */
+/*  pCapabilities           Pointer to the capabilities structure                   */
+/*  pScratch                Pointer to the scratch buffer                           */
+/*                                                                                  */
+/* RETURNS:                                                                         */
+/*  LVCS_Success            Initialisation succeeded                                */
+/*  LVDBE_NULLADDRESS       One or more memory has a NULL pointer                   */
+/*                                                                                  */
+/* NOTES:                                                                           */
+/*  1.  This function must not be interrupted by the LVCS_Process function          */
+/*                                                                                  */
+/************************************************************************************/
 LVCS_ReturnStatus_en LVCS_Init(LVCS_Handle_t            *phInstance,
-                               LVCS_MemTab_t            *pMemoryTable,
-                               LVCS_Capabilities_t      *pCapabilities);
+                               LVCS_Capabilities_t      *pCapabilities,
+                               void                     *pScratch);
+
+/************************************************************************************/
+/*                                                                                  */
+/* FUNCTION:                LVCS_DeInit                                             */
+/*                                                                                  */
+/* DESCRIPTION:                                                                     */
+/*  Free memories created during the LVCS_Init call including instance handle       */
+/*                                                                                  */
+/* PARAMETERS:                                                                      */
+/*  phInstance              Pointer to instance handle                              */
+/*                                                                                  */
+/* NOTES:                                                                           */
+/*  1.  This function must not be interrupted by the LVCS_Process function          */
+/*                                                                                  */
+/************************************************************************************/
+void LVCS_DeInit(LVCS_Handle_t          *phInstance);
 
 /****************************************************************************************/
 /*                                                                                      */
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
index 431b7e3..abadae3 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
@@ -65,11 +65,8 @@
     BQ_FLOAT_Coefs_t      Coeffs;
     const BiquadA012B12CoefsSP_t *pEqualiserCoefTable;
 
-    pData = (LVCS_Data_t *) \
-                pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
-
-    pCoefficients = (LVCS_Coefficient_t *) \
-                pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+    pData         = (LVCS_Data_t *)pInstance->pData;
+    pCoefficients = (LVCS_Coefficient_t *)pInstance->pCoeff;
     /*
      * If the sample rate changes re-initialise the filters
      */
@@ -144,8 +141,7 @@
     LVCS_Equaliser_t    *pConfig   = (LVCS_Equaliser_t  *)&pInstance->Equaliser;
     LVCS_Coefficient_t  *pCoefficients;
 
-    pCoefficients = (LVCS_Coefficient_t *) \
-                  pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+    pCoefficients = (LVCS_Coefficient_t *)pInstance->pCoeff;
 
     /*
      * Check if the equaliser is required
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp
index 630ecf7..312885c 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp
@@ -20,99 +20,11 @@
 /*  Includes                                                                        */
 /*                                                                                  */
 /************************************************************************************/
-
+#include <stdlib.h>
 #include "LVCS.h"
 #include "LVCS_Private.h"
 #include "LVCS_Tables.h"
 
-/****************************************************************************************/
-/*                                                                                      */
-/* FUNCTION:                LVCS_Memory                                                 */
-/*                                                                                      */
-/* DESCRIPTION:                                                                         */
-/*  This function is used for memory allocation and free. It can be called in           */
-/*  two ways:                                                                           */
-/*                                                                                      */
-/*      hInstance = NULL                Returns the memory requirements                 */
-/*      hInstance = Instance handle     Returns the memory requirements and             */
-/*                                      allocated base addresses for the instance       */
-/*                                                                                      */
-/*  When this function is called for memory allocation (hInstance=NULL) it is           */
-/*  passed the default capabilities.                                                    */
-/*                                                                                      */
-/*  When called for memory allocation the memory base address pointers are NULL on      */
-/*  return.                                                                             */
-/*                                                                                      */
-/*  When the function is called for free (hInstance = Instance Handle) the              */
-/*  capabilities are ignored and the memory table returns the allocated memory and      */
-/*  base addresses used during initialisation.                                          */
-/*                                                                                      */
-/* PARAMETERS:                                                                          */
-/*  hInstance               Instance Handle                                             */
-/*  pMemoryTable            Pointer to an empty memory definition table                 */
-/*  pCapabilities           Pointer to the default capabilites                          */
-/*                                                                                      */
-/* RETURNS:                                                                             */
-/*  LVCS_Success            Succeeded                                                   */
-/*                                                                                      */
-/* NOTES:                                                                               */
-/*  1.  This function may be interrupted by the LVCS_Process function                   */
-/*                                                                                      */
-/****************************************************************************************/
-
-LVCS_ReturnStatus_en LVCS_Memory(LVCS_Handle_t          hInstance,
-                                 LVCS_MemTab_t          *pMemoryTable,
-                                 LVCS_Capabilities_t    *pCapabilities)
-{
-
-    LVM_UINT32          ScratchSize;
-    LVCS_Instance_t     *pInstance = (LVCS_Instance_t *)hInstance;
-
-    /*
-     * Fill in the memory table
-     */
-    if (hInstance == LVM_NULL)
-    {
-        /*
-         * Instance memory
-         */
-        pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].Size         = (LVM_UINT32)sizeof(LVCS_Instance_t);
-        pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].Type         = LVCS_PERSISTENT;
-        pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress = LVM_NULL;
-
-        /*
-         * Data memory
-         */
-        pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].Size         = (LVM_UINT32)sizeof(LVCS_Data_t);
-        pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].Type         = LVCS_DATA;
-        pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress = LVM_NULL;
-
-        /*
-         * Coefficient memory
-         */
-        pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].Size         = (LVM_UINT32)sizeof(LVCS_Coefficient_t);
-        pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].Type         = LVCS_COEFFICIENT;
-        pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress = LVM_NULL;
-
-        /*
-         * Scratch memory
-         */
-        /* Inplace processing */
-        ScratchSize = (LVM_UINT32) \
-                        (LVCS_SCRATCHBUFFERS * sizeof(LVM_FLOAT) * pCapabilities->MaxBlockSize);
-        pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].Size         = ScratchSize;
-        pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].Type         = LVCS_SCRATCH;
-        pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress = LVM_NULL;
-    }
-    else
-    {
-        /* Read back memory allocation table */
-        *pMemoryTable = pInstance->MemoryTable;
-    }
-
-    return(LVCS_SUCCESS);
-}
-
 /************************************************************************************/
 /*                                                                                  */
 /* FUNCTION:                LVCS_Init                                               */
@@ -120,46 +32,38 @@
 /* DESCRIPTION:                                                                     */
 /*  Create and initialisation function for the Concert Sound module                 */
 /*                                                                                  */
-/*  This function can be used to create an algorithm instance by calling with       */
-/*  hInstance set to LVM_NULL. In this case the algorithm returns the new instance  */
-/*  handle.                                                                         */
-/*                                                                                  */
-/*  This function can be used to force a full re-initialisation of the algorithm    */
-/*  by calling with hInstance = Instance Handle. In this case the memory table      */
-/*  should be correct for the instance, this can be ensured by calling the function */
-/*  LVCS_Memory before calling this function.                                       */
-/*                                                                                  */
 /* PARAMETERS:                                                                      */
-/*  hInstance               Instance handle                                         */
-/*  pMemoryTable            Pointer to the memory definition table                  */
+/*  phInstance              Pointer to instance handle                              */
 /*  pCapabilities           Pointer to the capabilities structure                   */
+/*  pScratch                Pointer to scratch buffer                               */
 /*                                                                                  */
 /* RETURNS:                                                                         */
 /*  LVCS_Success            Initialisation succeeded                                */
+/*  LVDBE_NULLADDRESS       One or more memory has a NULL pointer - malloc failure  */
 /*                                                                                  */
 /* NOTES:                                                                           */
-/*  1.  The instance handle is the pointer to the base address of the first memory  */
-/*      region.                                                                     */
-/*  2.  This function must not be interrupted by the LVCS_Process function          */
-/*  3.  This function must be called with the same capabilities as used for the     */
-/*      call to the memory function                                                 */
+/*  1.  This function must not be interrupted by the LVCS_Process function          */
 /*                                                                                  */
 /************************************************************************************/
 
 LVCS_ReturnStatus_en LVCS_Init(LVCS_Handle_t         *phInstance,
-                               LVCS_MemTab_t         *pMemoryTable,
-                               LVCS_Capabilities_t   *pCapabilities)
+                               LVCS_Capabilities_t   *pCapabilities,
+                               void                  *pScratch)
 {
 
-    LVCS_Instance_t                 *pInstance;
-    LVCS_VolCorrect_t               *pLVCS_VolCorrectTable;
+    LVCS_Instance_t    *pInstance;
+    LVCS_VolCorrect_t  *pLVCS_VolCorrectTable;
 
     /*
-     * Set the instance handle if not already initialised
+     * Create the instance handle if not already initialised
      */
     if (*phInstance == LVM_NULL)
     {
-        *phInstance = (LVCS_Handle_t)pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress;
+        *phInstance = calloc(1, sizeof(*pInstance));
+    }
+    if (*phInstance == LVM_NULL)
+    {
+        return LVCS_NULLADDRESS;
     }
     pInstance =(LVCS_Instance_t  *)*phInstance;
 
@@ -168,10 +72,7 @@
      */
     pInstance->Capabilities = *pCapabilities;
 
-    /*
-     * Save the memory table in the instance structure
-     */
-    pInstance->MemoryTable = *pMemoryTable;
+    pInstance->pScratch     = pScratch;
 
     /*
      * Set all initial parameters to invalid to force a full initialisation
@@ -208,3 +109,35 @@
     return(LVCS_SUCCESS);
 }
 
+/************************************************************************************/
+/*                                                                                  */
+/* FUNCTION:                LVCS_DeInit                                             */
+/*                                                                                  */
+/* DESCRIPTION:                                                                     */
+/*  Free memories created during the LVCS_Init call including instance handle       */
+/*                                                                                  */
+/* PARAMETERS:                                                                      */
+/*  phInstance              Pointer to instance handle                              */
+/*                                                                                  */
+/* NOTES:                                                                           */
+/*  1.  This function must not be interrupted by the LVCS_Process function          */
+/*                                                                                  */
+/************************************************************************************/
+void LVCS_DeInit(LVCS_Handle_t *phInstance)
+{
+    LVCS_Instance_t *pInstance = (LVCS_Instance_t *)*phInstance;
+    if (pInstance == LVM_NULL) {
+        return;
+    }
+    if (pInstance->pCoeff != LVM_NULL) {
+        free(pInstance->pCoeff);
+        pInstance->pCoeff = LVM_NULL;
+    }
+    if (pInstance->pData != LVM_NULL) {
+        free(pInstance->pData);
+        pInstance->pData = LVM_NULL;
+    }
+    free(pInstance);
+    *phInstance = LVM_NULL;
+    return;
+}
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
index dd9166f..7adfb50 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
@@ -104,7 +104,6 @@
 typedef struct
 {
     /* Public parameters */
-    LVCS_MemTab_t           MemoryTable;        /* Instance memory allocation table */
     LVCS_Params_t           Params;             /* Instance parameters */
     LVCS_Capabilities_t     Capabilities;       /* Initialisation capabilities */
 
@@ -127,6 +126,9 @@
     LVM_INT16               bTimerDone;                         /* Timer completion flag */
     LVM_Timer_Params_t      TimerParams;                        /* Timer parameters */
     LVM_Timer_Instance_t    TimerInstance;                      /* Timer instance */
+    void                    *pCoeff;           /* pointer to buffer for equaliser filter coeffs */
+    void                    *pData;            /* pointer to buffer for equaliser filter states */
+    void                    *pScratch;         /* Pointer to bundle scratch buffer */
 
 } LVCS_Instance_t;
 
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp
index c220557..72b4c8b 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp
@@ -89,8 +89,7 @@
         channels = 2;
     }
 
-    pScratch  = (LVM_FLOAT *) \
-                  pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
+    pScratch  = (LVM_FLOAT *)pInstance->pScratch;
 
     /*
      * Check if the processing is inplace
@@ -220,10 +219,8 @@
            * second and fourth are used as input buffers by pInput and pStIn in LVCS_Process_CS.
            * Hence, pStereoOut is pointed to use unused third portion of scratch memory.
            */
-            pStereoOut = (LVM_FLOAT *) \
-                          pInstance->MemoryTable. \
-                          Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress +
-                          ((LVCS_SCRATCHBUFFERS - 4) * NrFrames);
+            pStereoOut = (LVM_FLOAT *)pInstance->pScratch +
+                                     ((LVCS_SCRATCHBUFFERS - 4) * NrFrames);
         }
         else
         {
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
index d0e6e09..441b667 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
@@ -20,7 +20,7 @@
 /*  Includes                                                                        */
 /*                                                                                  */
 /************************************************************************************/
-
+#include <stdlib.h>
 #include "LVCS.h"
 #include "LVCS_Private.h"
 #include "LVCS_ReverbGenerator.h"
@@ -70,11 +70,31 @@
     BQ_FLOAT_Coefs_t         Coeffs;
     const BiquadA012B12CoefsSP_t  *pReverbCoefTable;
 
-    pData = (LVCS_Data_t *) \
-                 pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
-
-    pCoefficients = (LVCS_Coefficient_t *) \
-                 pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+    if (pInstance->pData == LVM_NULL)
+    {
+        pInstance->pData = pData = (LVCS_Data_t *)calloc(1, sizeof(*pData));
+        if (pData == LVM_NULL)
+        {
+            return LVCS_NULLADDRESS;
+        }
+    }
+    else
+    {
+        pData = (LVCS_Data_t *)pInstance->pData;
+    }
+    if (pInstance->pCoeff == LVM_NULL)
+    {
+        pInstance->pCoeff = pCoefficients = (LVCS_Coefficient_t *)calloc(1, \
+                                                                          sizeof(*pCoefficients));
+        if (pCoefficients == LVM_NULL)
+        {
+            return LVCS_NULLADDRESS;
+        }
+    }
+    else
+    {
+        pCoefficients = (LVCS_Coefficient_t *)pInstance->pCoeff;
+    }
 
     /*
      * Initialise the delay and filters if:
@@ -192,11 +212,8 @@
     LVCS_Coefficient_t      *pCoefficients;
     LVM_FLOAT               *pScratch;
 
-    pCoefficients = (LVCS_Coefficient_t *)\
-                   pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
-
-    pScratch  = (LVM_FLOAT *)\
-                    pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
+    pCoefficients = (LVCS_Coefficient_t *)pInstance->pCoeff;
+    pScratch      = (LVM_FLOAT *)pInstance->pScratch;
 
     /*
      * Copy the data to the output in outplace processing
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
index 7fd8444..6929015 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
@@ -62,11 +62,8 @@
     BQ_FLOAT_Coefs_t          CoeffsSide;
     const BiquadA012B12CoefsSP_t *pSESideCoefs;
 
-    pData     = (LVCS_Data_t *) \
-                  pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
-
-    pCoefficient = (LVCS_Coefficient_t *) \
-                  pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+    pData        = (LVCS_Data_t *)pInstance->pData;
+    pCoefficient = (LVCS_Coefficient_t *)pInstance->pCoeff;
 
     /*
      * If the sample rate or speaker type has changed update the filters
@@ -188,12 +185,8 @@
     LVCS_StereoEnhancer_t   *pConfig   = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
     LVCS_Coefficient_t      *pCoefficient;
     LVM_FLOAT               *pScratch;
-
-    pCoefficient = (LVCS_Coefficient_t *) \
-                   pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
-
-    pScratch  = (LVM_FLOAT *) \
-                    pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
+    pCoefficient = (LVCS_Coefficient_t *)pInstance->pCoeff;
+    pScratch     = (LVM_FLOAT *)pInstance->pScratch;
     /*
      * Check if the Stereo Enhancer is enabled
      */
diff --git a/media/libeffects/lvm/tests/lvmtest.cpp b/media/libeffects/lvm/tests/lvmtest.cpp
index a4ace6c..59b27ad 100644
--- a/media/libeffects/lvm/tests/lvmtest.cpp
+++ b/media/libeffects/lvm/tests/lvmtest.cpp
@@ -182,49 +182,6 @@
   printf("\n           Enable Equalizer");
 }
 
-//----------------------------------------------------------------------------
-// LvmEffect_free()
-//----------------------------------------------------------------------------
-// Purpose: Free all memory associated with the Bundle.
-//
-// Inputs:
-//  pContext:   effect engine context
-//
-// Outputs:
-//
-//----------------------------------------------------------------------------
-
-void LvmEffect_free(struct EffectContext *pContext) {
-  LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
-  LVM_MemTab_t MemTab;
-
-  /* Free the algorithm memory */
-  LvmStatus = LVM_GetMemoryTable(pContext->pBundledContext->hInstance, &MemTab,
-                                 LVM_NULL);
-
-  LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "LvmEffect_free")
-
-  for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
-    if (MemTab.Region[i].Size != 0) {
-      if (MemTab.Region[i].pBaseAddress != NULL) {
-        ALOGV("\tLvmEffect_free - START freeing %" PRIu32
-              " bytes for region %u at %p\n",
-              MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
-
-        free(MemTab.Region[i].pBaseAddress);
-
-        ALOGV("\tLvmEffect_free - END   freeing %" PRIu32
-              " bytes for region %u at %p\n",
-              MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
-      } else {
-        ALOGE(
-            "\tLVM_ERROR : LvmEffect_free - trying to free with NULL pointer "
-            "%" PRIu32 " bytes for region %u at %p ERROR\n",
-            MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
-      }
-    }
-  }
-} /* end LvmEffect_free */
 
 //----------------------------------------------------------------------------
 // LvmBundle_init()
@@ -263,8 +220,7 @@
     ALOGV(
         "\tLvmBundle_init pContext->pBassBoost != NULL "
         "-> Calling pContext->pBassBoost->free()");
-
-    LvmEffect_free(pContext);
+    LVM_DelInstanceHandle(&pContext->pBundledContext->hInstance);
 
     ALOGV(
         "\tLvmBundle_init pContext->pBassBoost != NULL "
@@ -276,8 +232,6 @@
   LVM_EQNB_BandDef_t BandDefs[MAX_NUM_BANDS];  /* Equaliser band definitions */
   LVM_HeadroomParams_t HeadroomParams;         /* Headroom parameters */
   LVM_HeadroomBandDef_t HeadroomBandDef[LVM_HEADROOM_MAX_NBANDS];
-  LVM_MemTab_t MemTab; /* Memory allocation table */
-  bool bMallocFailure = LVM_FALSE;
 
   /* Set the capabilities */
   InstParams.BufferMode = LVM_UNMANAGED_BUFFERS;
@@ -285,63 +239,8 @@
   InstParams.EQNB_NumBands = MAX_NUM_BANDS;
   InstParams.PSA_Included = LVM_PSA_ON;
 
-  /* Allocate memory, forcing alignment */
-  LvmStatus = LVM_GetMemoryTable(LVM_NULL, &MemTab, &InstParams);
-
-  LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "LvmBundle_init");
-  if (LvmStatus != LVM_SUCCESS) return -EINVAL;
-
-  ALOGV("\tCreateInstance Succesfully called LVM_GetMemoryTable\n");
-
-  /* Allocate memory */
-  for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
-    if (MemTab.Region[i].Size != 0) {
-      MemTab.Region[i].pBaseAddress = malloc(MemTab.Region[i].Size);
-
-      if (MemTab.Region[i].pBaseAddress == LVM_NULL) {
-        ALOGE(
-            "\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate "
-            "%" PRIu32 " bytes for region %u\n",
-            MemTab.Region[i].Size, i);
-        bMallocFailure = LVM_TRUE;
-        break;
-      } else {
-        ALOGV("\tLvmBundle_init CreateInstance allocated %" PRIu32
-              " bytes for region %u at %p\n",
-              MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
-      }
-    }
-  }
-
-  /* If one or more of the memory regions failed to allocate, free the regions
-   * that were
-   * succesfully allocated and return with an error
-   */
-  if (bMallocFailure == LVM_TRUE) {
-    for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
-      if (MemTab.Region[i].pBaseAddress == LVM_NULL) {
-        ALOGE(
-            "\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate "
-            "%" PRIu32 " bytes for region %u Not freeing\n",
-            MemTab.Region[i].Size, i);
-      } else {
-        ALOGE(
-            "\tLVM_ERROR :LvmBundle_init CreateInstance Failed: but allocated "
-            "%" PRIu32 " bytes for region %u at %p- free\n",
-            MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
-        free(MemTab.Region[i].pBaseAddress);
-      }
-    }
-    return -EINVAL;
-  }
-  ALOGV("\tLvmBundle_init CreateInstance Succesfully malloc'd memory\n");
-
-  /* Initialise */
-  pContext->pBundledContext->hInstance = LVM_NULL;
-
-  /* Init sets the instance handle */
   LvmStatus = LVM_GetInstanceHandle(&pContext->pBundledContext->hInstance,
-                                    &MemTab, &InstParams);
+                                    &InstParams);
 
   LVM_ERROR_CHECK(LvmStatus, "LVM_GetInstanceHandle", "LvmBundle_init");
   if (LvmStatus != LVM_SUCCESS) return -EINVAL;
@@ -812,7 +711,7 @@
   /* Free the allocated buffers */
   if (context.pBundledContext != nullptr) {
     if (context.pBundledContext->hInstance != nullptr) {
-      LvmEffect_free(&context);
+      LVM_DelInstanceHandle(&context.pBundledContext->hInstance);
     }
     free(context.pBundledContext);
   }
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index cf74585..dac283e 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -136,7 +136,6 @@
 int  LvmBundle_init            (EffectContext *pContext);
 int  LvmEffect_enable          (EffectContext *pContext);
 int  LvmEffect_disable         (EffectContext *pContext);
-void LvmEffect_free            (EffectContext *pContext);
 int  Effect_setConfig          (EffectContext *pContext, effect_config_t *pConfig);
 void Effect_getConfig          (EffectContext *pContext, effect_config_t *pConfig);
 int  BassBoost_setParameter    (EffectContext *pContext,
@@ -433,7 +432,7 @@
         pSessionContext->bBundledEffectsEnabled = LVM_FALSE;
         pSessionContext->pBundledContext = LVM_NULL;
         ALOGV("\tEffectRelease: Freeing LVM Bundle memory\n");
-        LvmEffect_free(pContext);
+        LVM_DelInstanceHandle(&pContext->pBundledContext->hInstance);
         ALOGV("\tEffectRelease: Deleting LVM Bundle context %p\n", pContext->pBundledContext);
         if (pContext->pBundledContext->workBuffer != NULL) {
             free(pContext->pBundledContext->workBuffer);
@@ -529,8 +528,7 @@
     if (pContext->pBundledContext->hInstance != NULL){
         ALOGV("\tLvmBundle_init pContext->pBassBoost != NULL "
                 "-> Calling pContext->pBassBoost->free()");
-
-        LvmEffect_free(pContext);
+        LVM_DelInstanceHandle(&pContext->pBundledContext->hInstance);
 
         ALOGV("\tLvmBundle_init pContext->pBassBoost != NULL "
                 "-> Called pContext->pBassBoost->free()");
@@ -542,8 +540,6 @@
     LVM_EQNB_BandDef_t      BandDefs[MAX_NUM_BANDS];        /* Equaliser band definitions */
     LVM_HeadroomParams_t    HeadroomParams;                 /* Headroom parameters */
     LVM_HeadroomBandDef_t   HeadroomBandDef[LVM_HEADROOM_MAX_NBANDS];
-    LVM_MemTab_t            MemTab;                         /* Memory allocation table */
-    bool                    bMallocFailure = LVM_FALSE;
 
     /* Set the capabilities */
     InstParams.BufferMode       = LVM_UNMANAGED_BUFFERS;
@@ -551,58 +547,7 @@
     InstParams.EQNB_NumBands    = MAX_NUM_BANDS;
     InstParams.PSA_Included     = LVM_PSA_ON;
 
-    /* Allocate memory, forcing alignment */
-    LvmStatus = LVM_GetMemoryTable(LVM_NULL,
-                                  &MemTab,
-                                  &InstParams);
-
-    LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "LvmBundle_init")
-    if(LvmStatus != LVM_SUCCESS) return -EINVAL;
-
-    ALOGV("\tCreateInstance Succesfully called LVM_GetMemoryTable\n");
-
-    /* Allocate memory */
-    for (int i=0; i<LVM_NR_MEMORY_REGIONS; i++){
-        if (MemTab.Region[i].Size != 0){
-            MemTab.Region[i].pBaseAddress = malloc(MemTab.Region[i].Size);
-
-            if (MemTab.Region[i].pBaseAddress == LVM_NULL){
-                ALOGV("\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate %" PRIu32
-                        " bytes for region %u\n", MemTab.Region[i].Size, i );
-                bMallocFailure = LVM_TRUE;
-            }else{
-                ALOGV("\tLvmBundle_init CreateInstance allocated %" PRIu32
-                        " bytes for region %u at %p\n",
-                        MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
-            }
-        }
-    }
-
-    /* If one or more of the memory regions failed to allocate, free the regions that were
-     * succesfully allocated and return with an error
-     */
-    if(bMallocFailure == LVM_TRUE){
-        for (int i=0; i<LVM_NR_MEMORY_REGIONS; i++){
-            if (MemTab.Region[i].pBaseAddress == LVM_NULL){
-                ALOGV("\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate %" PRIu32
-                        " bytes for region %u Not freeing\n", MemTab.Region[i].Size, i );
-            }else{
-                ALOGV("\tLVM_ERROR :LvmBundle_init CreateInstance Failed: but allocated %" PRIu32
-                     " bytes for region %u at %p- free\n",
-                     MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
-                free(MemTab.Region[i].pBaseAddress);
-            }
-        }
-        return -EINVAL;
-    }
-    ALOGV("\tLvmBundle_init CreateInstance Succesfully malloc'd memory\n");
-
-    /* Initialise */
-    pContext->pBundledContext->hInstance = LVM_NULL;
-
-    /* Init sets the instance handle */
     LvmStatus = LVM_GetInstanceHandle(&pContext->pBundledContext->hInstance,
-                                      &MemTab,
                                       &InstParams);
 
     LVM_ERROR_CHECK(LvmStatus, "LVM_GetInstanceHandle", "LvmBundle_init")
@@ -1026,41 +971,6 @@
     return 0;
 }
 
-//----------------------------------------------------------------------------
-// LvmEffect_free()
-//----------------------------------------------------------------------------
-// Purpose: Free all memory associated with the Bundle.
-//
-// Inputs:
-//  pContext:   effect engine context
-//
-// Outputs:
-//
-//----------------------------------------------------------------------------
-
-void LvmEffect_free(EffectContext *pContext){
-    LVM_ReturnStatus_en     LvmStatus=LVM_SUCCESS;         /* Function call status */
-    LVM_MemTab_t            MemTab;
-
-    /* Free the algorithm memory */
-    LvmStatus = LVM_GetMemoryTable(pContext->pBundledContext->hInstance,
-                                   &MemTab,
-                                   LVM_NULL);
-
-    LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "LvmEffect_free")
-
-    for (int i=0; i<LVM_NR_MEMORY_REGIONS; i++){
-        if (MemTab.Region[i].Size != 0){
-            if (MemTab.Region[i].pBaseAddress != NULL){
-                free(MemTab.Region[i].pBaseAddress);
-            }else{
-                ALOGV("\tLVM_ERROR : LvmEffect_free - trying to free with NULL pointer %" PRIu32
-                        " bytes for region %u at %p ERROR\n",
-                        MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
-            }
-        }
-    }
-}    /* end LvmEffect_free */
 
 //----------------------------------------------------------------------------
 // Effect_setConfig()
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index aa3f8f3..4411a7d 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -728,7 +728,7 @@
     /* Allocate memory */
     for (int i=0; i<LVM_NR_MEMORY_REGIONS; i++){
         if (MemTab.Region[i].Size != 0){
-            MemTab.Region[i].pBaseAddress = malloc(MemTab.Region[i].Size);
+            MemTab.Region[i].pBaseAddress = calloc(1, MemTab.Region[i].Size);
 
             if (MemTab.Region[i].pBaseAddress == LVM_NULL){
                 ALOGV("\tLVREV_ERROR :Reverb_init CreateInstance Failed to allocate %" PRIu32
diff --git a/media/libmedia/MediaResource.cpp b/media/libmedia/MediaResource.cpp
index fe86d27..ec52a49 100644
--- a/media/libmedia/MediaResource.cpp
+++ b/media/libmedia/MediaResource.cpp
@@ -43,11 +43,11 @@
 }
 
 //static
-MediaResource MediaResource::CodecResource(bool secure, bool video) {
+MediaResource MediaResource::CodecResource(bool secure, bool video, int64_t instanceCount) {
     return MediaResource(
             secure ? Type::kSecureCodec : Type::kNonSecureCodec,
             video ? SubType::kVideoCodec : SubType::kAudioCodec,
-            1);
+            instanceCount);
 }
 
 //static
diff --git a/media/libmedia/include/media/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index 4927d28..4712528 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -37,7 +37,7 @@
     MediaResource(Type type, SubType subType, int64_t value);
     MediaResource(Type type, const std::vector<uint8_t> &id, int64_t value);
 
-    static MediaResource CodecResource(bool secure, bool video);
+    static MediaResource CodecResource(bool secure, bool video, int64_t instanceCount = 1);
     static MediaResource GraphicMemoryResource(int64_t value);
     static MediaResource CpuBoostResource();
     static MediaResource VideoBatteryResource();
diff --git a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
index f114046..c81a659 100644
--- a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
+++ b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
@@ -65,6 +65,14 @@
         return true;
     }
 
+    virtual bool overrideProcessInfo(
+            int /* pid */, int /* procState */, int /* oomScore */) {
+        return true;
+    }
+
+    virtual void removeProcessInfoOverride(int /* pid */) {
+    }
+
 private:
     DISALLOW_EVIL_CONSTRUCTORS(FakeProcessInfo);
 };
diff --git a/media/libmediatranscoding/Android.bp b/media/libmediatranscoding/Android.bp
index b7bad7f..128d0d8 100644
--- a/media/libmediatranscoding/Android.bp
+++ b/media/libmediatranscoding/Android.bp
@@ -54,6 +54,7 @@
     srcs: [
         "TranscodingClientManager.cpp",
         "TranscodingJobScheduler.cpp",
+        "TranscodingResourcePolicy.cpp",
         "TranscodingUidPolicy.cpp",
         "TranscoderWrapper.cpp",
     ],
@@ -67,11 +68,16 @@
         "libbinder",
         "libmediandk",
     ],
+    export_shared_lib_headers: [
+        "libmediandk",
+    ],
 
     export_include_dirs: ["include"],
 
     static_libs: [
         "mediatranscoding_aidl_interface-ndk_platform",
+        "resourcemanager_aidl_interface-ndk_platform",
+        "resourceobserver_aidl_interface-ndk_platform",
     ],
 
     cflags: [
diff --git a/media/libmediatranscoding/TranscoderWrapper.cpp b/media/libmediatranscoding/TranscoderWrapper.cpp
index bd03671..8062fcf 100644
--- a/media/libmediatranscoding/TranscoderWrapper.cpp
+++ b/media/libmediatranscoding/TranscoderWrapper.cpp
@@ -89,26 +89,40 @@
 }
 
 //static
-const char* TranscoderWrapper::toString(Event::Type type) {
-    switch (type) {
+std::string TranscoderWrapper::toString(const Event& event) {
+    std::string typeStr;
+    switch (event.type) {
     case Event::Start:
-        return "Start";
-    case Event::Pause:
-        return "Pause";
-    case Event::Resume:
-        return "Resume";
-    case Event::Stop:
-        return "Stop";
-    case Event::Finish:
-        return "Finish";
-    case Event::Error:
-        return "Error";
-    case Event::Progress:
-        return "Progress";
-    default:
+        typeStr = "Start";
         break;
+    case Event::Pause:
+        typeStr = "Pause";
+        break;
+    case Event::Resume:
+        typeStr = "Resume";
+        break;
+    case Event::Stop:
+        typeStr = "Stop";
+        break;
+    case Event::Finish:
+        typeStr = "Finish";
+        break;
+    case Event::Error:
+        typeStr = "Error";
+        break;
+    case Event::Progress:
+        typeStr = "Progress";
+        break;
+    default:
+        return "(unknown)";
     }
-    return "(unknown)";
+    std::string result;
+    result = "job {" + std::to_string(event.clientId) + "," + std::to_string(event.jobId) +
+             "}: " + typeStr;
+    if (event.type == Event::Error || event.type == Event::Progress) {
+        result += " " + std::to_string(event.arg);
+    }
+    return result;
 }
 
 class TranscoderWrapper::CallbackImpl : public MediaTranscoder::CallbackInterface {
@@ -128,7 +142,7 @@
                          media_status_t error) override {
         auto owner = mOwner.lock();
         if (owner != nullptr) {
-            owner->onError(mClientId, mJobId, toTranscodingError(error));
+            owner->onError(mClientId, mJobId, error);
         }
     }
 
@@ -160,20 +174,41 @@
     mCallback = cb;
 }
 
+static bool isResourceError(media_status_t err) {
+    return err == AMEDIACODEC_ERROR_RECLAIMED || err == AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
+}
+
+void TranscoderWrapper::reportError(ClientIdType clientId, JobIdType jobId, media_status_t err) {
+    auto callback = mCallback.lock();
+    if (callback != nullptr) {
+        if (isResourceError(err)) {
+            // Add a placeholder pause state to mPausedStateMap. This is required when resuming.
+            // TODO: remove this when transcoder pause/resume logic is ready. New logic will
+            // no longer use the pause states.
+            auto it = mPausedStateMap.find(JobKeyType(clientId, jobId));
+            if (it == mPausedStateMap.end()) {
+                mPausedStateMap.emplace(JobKeyType(clientId, jobId),
+                                        std::shared_ptr<const Parcel>());
+            }
+
+            callback->onResourceLost();
+        } else {
+            callback->onError(clientId, jobId, toTranscodingError(err));
+        }
+    }
+}
+
 void TranscoderWrapper::start(ClientIdType clientId, JobIdType jobId,
                               const TranscodingRequestParcel& request,
                               const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
     queueEvent(Event::Start, clientId, jobId, [=] {
-        TranscodingErrorCode err = handleStart(clientId, jobId, request, clientCb);
+        media_status_t err = handleStart(clientId, jobId, request, clientCb);
 
-        auto callback = mCallback.lock();
-        if (err != TranscodingErrorCode::kNoError) {
+        if (err != AMEDIA_OK) {
             cleanup();
-
-            if (callback != nullptr) {
-                callback->onError(clientId, jobId, err);
-            }
+            reportError(clientId, jobId, err);
         } else {
+            auto callback = mCallback.lock();
             if (callback != nullptr) {
                 callback->onStarted(clientId, jobId);
             }
@@ -183,15 +218,15 @@
 
 void TranscoderWrapper::pause(ClientIdType clientId, JobIdType jobId) {
     queueEvent(Event::Pause, clientId, jobId, [=] {
-        TranscodingErrorCode err = handlePause(clientId, jobId);
+        media_status_t err = handlePause(clientId, jobId);
 
         cleanup();
 
-        auto callback = mCallback.lock();
-        if (callback != nullptr) {
-            if (err != TranscodingErrorCode::kNoError) {
-                callback->onError(clientId, jobId, err);
-            } else {
+        if (err != AMEDIA_OK) {
+            reportError(clientId, jobId, err);
+        } else {
+            auto callback = mCallback.lock();
+            if (callback != nullptr) {
                 callback->onPaused(clientId, jobId);
             }
         }
@@ -202,16 +237,13 @@
                                const TranscodingRequestParcel& request,
                                const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
     queueEvent(Event::Resume, clientId, jobId, [=] {
-        TranscodingErrorCode err = handleResume(clientId, jobId, request, clientCb);
+        media_status_t err = handleResume(clientId, jobId, request, clientCb);
 
-        auto callback = mCallback.lock();
-        if (err != TranscodingErrorCode::kNoError) {
+        if (err != AMEDIA_OK) {
             cleanup();
-
-            if (callback != nullptr) {
-                callback->onError(clientId, jobId, err);
-            }
+            reportError(clientId, jobId, err);
         } else {
+            auto callback = mCallback.lock();
             if (callback != nullptr) {
                 callback->onResumed(clientId, jobId);
             }
@@ -225,7 +257,7 @@
             // Cancelling the currently running job.
             media_status_t err = mTranscoder->cancel();
             if (err != AMEDIA_OK) {
-                ALOGE("failed to stop transcoder: %d", err);
+                ALOGW("failed to stop transcoder: %d", err);
             } else {
                 ALOGI("transcoder stopped");
             }
@@ -251,41 +283,43 @@
     });
 }
 
-void TranscoderWrapper::onError(ClientIdType clientId, JobIdType jobId,
-                                TranscodingErrorCode error) {
-    queueEvent(Event::Error, clientId, jobId, [=] {
-        if (mTranscoder != nullptr && clientId == mCurrentClientId && jobId == mCurrentJobId) {
-            cleanup();
-        }
-
-        auto callback = mCallback.lock();
-        if (callback != nullptr) {
-            callback->onError(clientId, jobId, error);
-        }
-    });
+void TranscoderWrapper::onError(ClientIdType clientId, JobIdType jobId, media_status_t error) {
+    queueEvent(
+            Event::Error, clientId, jobId,
+            [=] {
+                if (mTranscoder != nullptr && clientId == mCurrentClientId &&
+                    jobId == mCurrentJobId) {
+                    cleanup();
+                }
+                reportError(clientId, jobId, error);
+            },
+            error);
 }
 
 void TranscoderWrapper::onProgress(ClientIdType clientId, JobIdType jobId, int32_t progress) {
-    queueEvent(Event::Progress, clientId, jobId, [=] {
-        auto callback = mCallback.lock();
-        if (callback != nullptr) {
-            callback->onProgressUpdate(clientId, jobId, progress);
-        }
-    });
+    queueEvent(
+            Event::Progress, clientId, jobId,
+            [=] {
+                auto callback = mCallback.lock();
+                if (callback != nullptr) {
+                    callback->onProgressUpdate(clientId, jobId, progress);
+                }
+            },
+            progress);
 }
 
-TranscodingErrorCode TranscoderWrapper::setupTranscoder(
+media_status_t TranscoderWrapper::setupTranscoder(
         ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
         const std::shared_ptr<ITranscodingClientCallback>& clientCb,
         const std::shared_ptr<const Parcel>& pausedState) {
     if (clientCb == nullptr) {
         ALOGE("client callback is null");
-        return TranscodingErrorCode::kInvalidParameter;
+        return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
     if (mTranscoder != nullptr) {
         ALOGE("transcoder already running");
-        return TranscodingErrorCode::kInvalidOperation;
+        return AMEDIA_ERROR_INVALID_OPERATION;
     }
 
     Status status;
@@ -293,7 +327,7 @@
     status = clientCb->openFileDescriptor(request.sourceFilePath, "r", &srcFd);
     if (!status.isOk() || srcFd.get() < 0) {
         ALOGE("failed to open source");
-        return TranscodingErrorCode::kErrorIO;
+        return AMEDIA_ERROR_IO;
     }
 
     // Open dest file with "rw", as the transcoder could potentially reuse part of it
@@ -302,7 +336,7 @@
     status = clientCb->openFileDescriptor(request.destinationFilePath, "rw", &dstFd);
     if (!status.isOk() || dstFd.get() < 0) {
         ALOGE("failed to open destination");
-        return TranscodingErrorCode::kErrorIO;
+        return AMEDIA_ERROR_IO;
     }
 
     mCurrentClientId = clientId;
@@ -311,19 +345,19 @@
     mTranscoder = MediaTranscoder::create(mTranscoderCb, pausedState);
     if (mTranscoder == nullptr) {
         ALOGE("failed to create transcoder");
-        return TranscodingErrorCode::kUnknown;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
     media_status_t err = mTranscoder->configureSource(srcFd.get());
     if (err != AMEDIA_OK) {
         ALOGE("failed to configure source: %d", err);
-        return toTranscodingError(err);
+        return err;
     }
 
     std::vector<std::shared_ptr<AMediaFormat>> trackFormats = mTranscoder->getTrackFormats();
     if (trackFormats.size() == 0) {
         ALOGE("failed to get track formats!");
-        return TranscodingErrorCode::kMalformed;
+        return AMEDIA_ERROR_MALFORMED;
     }
 
     for (int i = 0; i < trackFormats.size(); ++i) {
@@ -341,43 +375,43 @@
         }
         if (err != AMEDIA_OK) {
             ALOGE("failed to configure track format for track %d: %d", i, err);
-            return toTranscodingError(err);
+            return err;
         }
     }
 
     err = mTranscoder->configureDestination(dstFd.get());
     if (err != AMEDIA_OK) {
         ALOGE("failed to configure dest: %d", err);
-        return toTranscodingError(err);
+        return err;
     }
 
-    return TranscodingErrorCode::kNoError;
+    return AMEDIA_OK;
 }
 
-TranscodingErrorCode TranscoderWrapper::handleStart(
+media_status_t TranscoderWrapper::handleStart(
         ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
         const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
-    ALOGI("setting up transcoder for start");
-    TranscodingErrorCode err = setupTranscoder(clientId, jobId, request, clientCb);
-    if (err != TranscodingErrorCode::kNoError) {
+    ALOGI("%s: setting up transcoder for start", __FUNCTION__);
+    media_status_t err = setupTranscoder(clientId, jobId, request, clientCb);
+    if (err != AMEDIA_OK) {
         ALOGI("%s: failed to setup transcoder", __FUNCTION__);
         return err;
     }
 
-    media_status_t status = mTranscoder->start();
-    if (status != AMEDIA_OK) {
+    err = mTranscoder->start();
+    if (err != AMEDIA_OK) {
         ALOGE("%s: failed to start transcoder: %d", __FUNCTION__, err);
-        return toTranscodingError(status);
+        return err;
     }
 
     ALOGI("%s: transcoder started", __FUNCTION__);
-    return TranscodingErrorCode::kNoError;
+    return AMEDIA_OK;
 }
 
-TranscodingErrorCode TranscoderWrapper::handlePause(ClientIdType clientId, JobIdType jobId) {
+media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, JobIdType jobId) {
     if (mTranscoder == nullptr) {
         ALOGE("%s: transcoder is not running", __FUNCTION__);
-        return TranscodingErrorCode::kInvalidOperation;
+        return AMEDIA_ERROR_INVALID_OPERATION;
     }
 
     if (clientId != mCurrentClientId || jobId != mCurrentJobId) {
@@ -385,19 +419,21 @@
               (long long)clientId, jobId, (long long)mCurrentClientId, mCurrentJobId);
     }
 
+    ALOGI("%s: pausing transcoder", __FUNCTION__);
+
     std::shared_ptr<const Parcel> pauseStates;
     media_status_t err = mTranscoder->pause(&pauseStates);
     if (err != AMEDIA_OK) {
         ALOGE("%s: failed to pause transcoder: %d", __FUNCTION__, err);
-        return toTranscodingError(err);
+        return err;
     }
     mPausedStateMap[JobKeyType(clientId, jobId)] = pauseStates;
 
     ALOGI("%s: transcoder paused", __FUNCTION__);
-    return TranscodingErrorCode::kNoError;
+    return AMEDIA_OK;
 }
 
-TranscodingErrorCode TranscoderWrapper::handleResume(
+media_status_t TranscoderWrapper::handleResume(
         ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
         const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
     std::shared_ptr<const Parcel> pausedState;
@@ -407,24 +443,24 @@
         mPausedStateMap.erase(it);
     } else {
         ALOGE("%s: can't find paused state", __FUNCTION__);
-        return TranscodingErrorCode::kInvalidOperation;
+        return AMEDIA_ERROR_INVALID_OPERATION;
     }
 
-    ALOGI("setting up transcoder for resume");
-    TranscodingErrorCode err = setupTranscoder(clientId, jobId, request, clientCb, pausedState);
-    if (err != TranscodingErrorCode::kNoError) {
-        ALOGE("%s: failed to setup transcoder", __FUNCTION__);
+    ALOGI("%s: setting up transcoder for resume", __FUNCTION__);
+    media_status_t err = setupTranscoder(clientId, jobId, request, clientCb, pausedState);
+    if (err != AMEDIA_OK) {
+        ALOGE("%s: failed to setup transcoder: %d", __FUNCTION__, err);
         return err;
     }
 
-    media_status_t status = mTranscoder->resume();
-    if (status != AMEDIA_OK) {
+    err = mTranscoder->resume();
+    if (err != AMEDIA_OK) {
         ALOGE("%s: failed to resume transcoder: %d", __FUNCTION__, err);
-        return toTranscodingError(status);
+        return err;
     }
 
     ALOGI("%s: transcoder resumed", __FUNCTION__);
-    return TranscodingErrorCode::kNoError;
+    return AMEDIA_OK;
 }
 
 void TranscoderWrapper::cleanup() {
@@ -435,12 +471,10 @@
 }
 
 void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, JobIdType jobId,
-                                   const std::function<void()> runnable) {
-    ALOGV("%s: job {%lld, %d}: %s", __FUNCTION__, (long long)clientId, jobId, toString(type));
-
+                                   const std::function<void()> runnable, int32_t arg) {
     std::scoped_lock lock{mLock};
 
-    mQueue.push_back({type, clientId, jobId, runnable});
+    mQueue.push_back({type, clientId, jobId, runnable, arg});
     mCondition.notify_one();
 }
 
@@ -457,8 +491,7 @@
         Event event = *mQueue.begin();
         mQueue.pop_front();
 
-        ALOGD("%s: job {%lld, %d}: %s", __FUNCTION__, (long long)event.clientId, event.jobId,
-              toString(event.type));
+        ALOGD("%s: %s", __FUNCTION__, toString(event).c_str());
 
         lock.unlock();
         event.runnable();
diff --git a/media/libmediatranscoding/TranscodingClientManager.cpp b/media/libmediatranscoding/TranscodingClientManager.cpp
index ce3ac13..d9f3f28 100644
--- a/media/libmediatranscoding/TranscodingClientManager.cpp
+++ b/media/libmediatranscoding/TranscodingClientManager.cpp
@@ -23,6 +23,7 @@
 #include <inttypes.h>
 #include <media/TranscodingClientManager.h>
 #include <media/TranscodingRequest.h>
+#include <private/android_filesystem_config.h>
 #include <utils/Log.h>
 namespace android {
 
@@ -44,6 +45,26 @@
         TranscodingClientManager::sCookie2Client;
 ///////////////////////////////////////////////////////////////////////////////
 
+// Convenience methods for constructing binder::Status objects for error returns
+#define STATUS_ERROR_FMT(errorCode, errorString, ...) \
+    Status::fromServiceSpecificErrorWithMessage(      \
+            errorCode,                                \
+            String8::format("%s:%d: " errorString, __FUNCTION__, __LINE__, ##__VA_ARGS__))
+
+// Can MediaTranscoding service trust the caller based on the calling UID?
+// TODO(hkuang): Add MediaProvider's UID.
+static bool isTrustedCallingUid(uid_t uid) {
+    switch (uid) {
+    case AID_ROOT:  // root user
+    case AID_SYSTEM:
+    case AID_SHELL:
+    case AID_MEDIA:  // mediaserver
+        return true;
+    default:
+        return false;
+    }
+}
+
 /**
  * ClientImpl implements a single client and contains all its information.
  */
@@ -60,8 +81,6 @@
      * (casted to int64t_t) as the client id.
      */
     ClientIdType mClientId;
-    pid_t mClientPid;
-    uid_t mClientUid;
     std::string mClientName;
     std::string mClientOpPackageName;
 
@@ -72,7 +91,7 @@
     // Weak pointer to the client manager for this client.
     std::weak_ptr<TranscodingClientManager> mOwner;
 
-    ClientImpl(const std::shared_ptr<ITranscodingClientCallback>& callback, pid_t pid, uid_t uid,
+    ClientImpl(const std::shared_ptr<ITranscodingClientCallback>& callback,
                const std::string& clientName, const std::string& opPackageName,
                const std::weak_ptr<TranscodingClientManager>& owner);
 
@@ -88,14 +107,11 @@
 };
 
 TranscodingClientManager::ClientImpl::ClientImpl(
-        const std::shared_ptr<ITranscodingClientCallback>& callback, pid_t pid, uid_t uid,
-        const std::string& clientName, const std::string& opPackageName,
-        const std::weak_ptr<TranscodingClientManager>& owner)
+        const std::shared_ptr<ITranscodingClientCallback>& callback, const std::string& clientName,
+        const std::string& opPackageName, const std::weak_ptr<TranscodingClientManager>& owner)
       : mClientBinder((callback != nullptr) ? callback->asBinder() : nullptr),
         mClientCallback(callback),
         mClientId(sCookieCounter.fetch_add(1, std::memory_order_relaxed)),
-        mClientPid(pid),
-        mClientUid(uid),
         mClientName(clientName),
         mClientOpPackageName(opPackageName),
         mNextJobId(0),
@@ -113,14 +129,52 @@
     }
 
     if (in_request.sourceFilePath.empty() || in_request.destinationFilePath.empty()) {
-        // This is the only error we check for now.
         return Status::ok();
     }
 
+    int32_t callingPid = AIBinder_getCallingPid();
+    int32_t callingUid = AIBinder_getCallingUid();
+    int32_t in_clientUid = in_request.clientUid;
+    int32_t in_clientPid = in_request.clientPid;
+
+    // Check if we can trust clientUid. Only privilege caller could forward the
+    // uid on app client's behalf.
+    if (in_clientUid == IMediaTranscodingService::USE_CALLING_UID) {
+        in_clientUid = callingUid;
+    } else if (in_clientUid < 0) {
+        return Status::ok();
+    } else if (in_clientUid != callingUid && !isTrustedCallingUid(callingUid)) {
+        ALOGE("MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
+              "(don't trust callingUid %d)",
+              in_clientPid, in_clientUid, callingUid);
+        return STATUS_ERROR_FMT(
+                IMediaTranscodingService::ERROR_PERMISSION_DENIED,
+                "MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
+                "(don't trust callingUid %d)",
+                in_clientPid, in_clientUid, callingUid);
+    }
+
+    // Check if we can trust clientPid. Only privilege caller could forward the
+    // pid on app client's behalf.
+    if (in_clientPid == IMediaTranscodingService::USE_CALLING_PID) {
+        in_clientPid = callingPid;
+    } else if (in_clientPid < 0) {
+        return Status::ok();
+    } else if (in_clientPid != callingPid && !isTrustedCallingUid(callingUid)) {
+        ALOGE("MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
+              "(don't trust callingUid %d)",
+              in_clientPid, in_clientUid, callingUid);
+        return STATUS_ERROR_FMT(
+                IMediaTranscodingService::ERROR_PERMISSION_DENIED,
+                "MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
+                "(don't trust callingUid %d)",
+                in_clientPid, in_clientUid, callingUid);
+    }
+
     int32_t jobId = mNextJobId.fetch_add(1);
 
-    *_aidl_return =
-            owner->mJobScheduler->submit(mClientId, jobId, mClientUid, in_request, mClientCallback);
+    *_aidl_return = owner->mJobScheduler->submit(mClientId, jobId, in_clientUid, in_request,
+                                                 mClientCallback);
 
     if (*_aidl_return) {
         out_job->jobId = jobId;
@@ -246,11 +300,10 @@
 }
 
 status_t TranscodingClientManager::addClient(
-        const std::shared_ptr<ITranscodingClientCallback>& callback, pid_t pid, uid_t uid,
-        const std::string& clientName, const std::string& opPackageName,
-        std::shared_ptr<ITranscodingClient>* outClient) {
+        const std::shared_ptr<ITranscodingClientCallback>& callback, const std::string& clientName,
+        const std::string& opPackageName, std::shared_ptr<ITranscodingClient>* outClient) {
     // Validate the client.
-    if (callback == nullptr || pid < 0 || clientName.empty() || opPackageName.empty()) {
+    if (callback == nullptr || clientName.empty() || opPackageName.empty()) {
         ALOGE("Invalid client");
         return IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT;
     }
@@ -264,12 +317,11 @@
         return IMediaTranscodingService::ERROR_ALREADY_EXISTS;
     }
 
-    // Creates the client and uses its process id as client id.
+    // Creates the client (with the id assigned by ClientImpl).
     std::shared_ptr<ClientImpl> client = ::ndk::SharedRefBase::make<ClientImpl>(
-            callback, pid, uid, clientName, opPackageName, shared_from_this());
+            callback, clientName, opPackageName, shared_from_this());
 
-    ALOGD("Adding client id %lld, pid %d, uid %d, name %s, package %s",
-          (long long)client->mClientId, client->mClientPid, client->mClientUid,
+    ALOGD("Adding client id %lld, name %s, package %s", (long long)client->mClientId,
           client->mClientName.c_str(), client->mClientOpPackageName.c_str());
 
     {
diff --git a/media/libmediatranscoding/TranscodingJobScheduler.cpp b/media/libmediatranscoding/TranscodingJobScheduler.cpp
index 3e4f319..24ac682 100644
--- a/media/libmediatranscoding/TranscodingJobScheduler.cpp
+++ b/media/libmediatranscoding/TranscodingJobScheduler.cpp
@@ -38,8 +38,13 @@
 
 TranscodingJobScheduler::TranscodingJobScheduler(
         const std::shared_ptr<TranscoderInterface>& transcoder,
-        const std::shared_ptr<UidPolicyInterface>& uidPolicy)
-      : mTranscoder(transcoder), mUidPolicy(uidPolicy), mCurrentJob(nullptr), mResourceLost(false) {
+        const std::shared_ptr<UidPolicyInterface>& uidPolicy,
+        const std::shared_ptr<ResourcePolicyInterface>& resourcePolicy)
+      : mTranscoder(transcoder),
+        mUidPolicy(uidPolicy),
+        mResourcePolicy(resourcePolicy),
+        mCurrentJob(nullptr),
+        mResourceLost(false) {
     // Only push empty offline queue initially. Realtime queues are added when requests come in.
     mUidSortedList.push_back(OFFLINE_UID);
     mOfflineUidIterator = mUidSortedList.begin();
@@ -398,15 +403,24 @@
 }
 
 void TranscodingJobScheduler::onResourceLost() {
-    ALOGV("%s", __FUNCTION__);
+    ALOGI("%s", __FUNCTION__);
 
     std::scoped_lock lock{mLock};
 
+    if (mResourceLost) {
+        return;
+    }
+
     // If we receive a resource loss event, the TranscoderLibrary already paused
     // the transcoding, so we don't need to call onPaused to notify it to pause.
     // Only need to update the job state here.
     if (mCurrentJob != nullptr && mCurrentJob->state == Job::RUNNING) {
         mCurrentJob->state = Job::PAUSED;
+        // Notify the client as a paused event.
+        auto clientCallback = mCurrentJob->callback.lock();
+        if (clientCallback != nullptr) {
+            clientCallback->onTranscodingPaused(mCurrentJob->key.second);
+        }
     }
     mResourceLost = true;
 
@@ -439,10 +453,14 @@
 }
 
 void TranscodingJobScheduler::onResourceAvailable() {
-    ALOGV("%s", __FUNCTION__);
-
     std::scoped_lock lock{mLock};
 
+    if (!mResourceLost) {
+        return;
+    }
+
+    ALOGI("%s", __FUNCTION__);
+
     mResourceLost = false;
     updateCurrentJob_l();
 
diff --git a/media/libmediatranscoding/TranscodingResourcePolicy.cpp b/media/libmediatranscoding/TranscodingResourcePolicy.cpp
new file mode 100644
index 0000000..4fd8338
--- /dev/null
+++ b/media/libmediatranscoding/TranscodingResourcePolicy.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2020 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_NDEBUG 0
+#define LOG_TAG "TranscodingResourcePolicy"
+
+#include <aidl/android/media/BnResourceObserver.h>
+#include <aidl/android/media/IResourceObserverService.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/IServiceManager.h>
+#include <media/TranscodingResourcePolicy.h>
+#include <utils/Log.h>
+
+namespace android {
+
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::BnResourceObserver;
+using ::aidl::android::media::IResourceObserverService;
+using ::aidl::android::media::MediaObservableEvent;
+using ::aidl::android::media::MediaObservableFilter;
+using ::aidl::android::media::MediaObservableParcel;
+using ::aidl::android::media::MediaObservableType;
+
+static std::string toString(const MediaObservableParcel& observable) {
+    return "{" + ::aidl::android::media::toString(observable.type) + ", " +
+           std::to_string(observable.value) + "}";
+}
+
+struct TranscodingResourcePolicy::ResourceObserver : public BnResourceObserver {
+    explicit ResourceObserver(TranscodingResourcePolicy* owner) : mOwner(owner), mPid(getpid()) {}
+
+    // IResourceObserver
+    ::ndk::ScopedAStatus onStatusChanged(
+            MediaObservableEvent event, int32_t uid, int32_t pid,
+            const std::vector<MediaObservableParcel>& observables) override {
+        ALOGD("%s: %s, uid %d, pid %d, %s", __FUNCTION__,
+              ::aidl::android::media::toString(event).c_str(), uid, pid,
+              toString(observables[0]).c_str());
+
+        // Only report kIdle event for codec resources from other processes.
+        if (((uint64_t)event & (uint64_t)MediaObservableEvent::kIdle) != 0 && (pid != mPid)) {
+            for (auto& observable : observables) {
+                if (observable.type == MediaObservableType::kVideoSecureCodec ||
+                    observable.type == MediaObservableType::kVideoNonSecureCodec) {
+                    mOwner->onResourceAvailable();
+                    break;
+                }
+            }
+        }
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    TranscodingResourcePolicy* mOwner;
+    const pid_t mPid;
+};
+
+// static
+void TranscodingResourcePolicy::BinderDiedCallback(void* cookie) {
+    TranscodingResourcePolicy* owner = reinterpret_cast<TranscodingResourcePolicy*>(cookie);
+    if (owner != nullptr) {
+        owner->unregisterSelf();
+    }
+    // TODO(chz): retry to connecting to IResourceObserverService after failure.
+    // Also need to have back-up logic if IResourceObserverService is offline for
+    // Prolonged period of time. A possible alternative could be, during period where
+    // IResourceObserverService is not available, trigger onResourceAvailable() everytime
+    // when top uid changes (in hope that'll free up some codec instances that we could
+    // reclaim).
+}
+
+TranscodingResourcePolicy::TranscodingResourcePolicy()
+      : mRegistered(false), mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)) {
+    registerSelf();
+}
+
+TranscodingResourcePolicy::~TranscodingResourcePolicy() {
+    unregisterSelf();
+}
+
+void TranscodingResourcePolicy::registerSelf() {
+    ALOGI("TranscodingResourcePolicy: registerSelf");
+
+    ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_observer"));
+
+    std::scoped_lock lock{mRegisteredLock};
+
+    if (mRegistered) {
+        return;
+    }
+
+    // TODO(chz): retry to connecting to IResourceObserverService after failure.
+    mService = IResourceObserverService::fromBinder(binder);
+    if (mService == nullptr) {
+        ALOGE("Failed to get IResourceObserverService");
+        return;
+    }
+
+    // Only register filters for codec resource available.
+    mObserver = ::ndk::SharedRefBase::make<ResourceObserver>(this);
+    std::vector<MediaObservableFilter> filters = {
+            {MediaObservableType::kVideoSecureCodec, MediaObservableEvent::kIdle},
+            {MediaObservableType::kVideoNonSecureCodec, MediaObservableEvent::kIdle}};
+
+    Status status = mService->registerObserver(mObserver, filters);
+    if (!status.isOk()) {
+        ALOGE("failed to register: error %d", status.getServiceSpecificError());
+        mService = nullptr;
+        mObserver = nullptr;
+        return;
+    }
+
+    AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(), reinterpret_cast<void*>(this));
+
+    ALOGD("@@@ registered observer");
+    mRegistered = true;
+}
+
+void TranscodingResourcePolicy::unregisterSelf() {
+    ALOGI("TranscodingResourcePolicy: unregisterSelf");
+
+    std::scoped_lock lock{mRegisteredLock};
+
+    if (!mRegistered) {
+        return;
+    }
+
+    ::ndk::SpAIBinder binder = mService->asBinder();
+    if (binder.get() != nullptr) {
+        Status status = mService->unregisterObserver(mObserver);
+        AIBinder_unlinkToDeath(binder.get(), mDeathRecipient.get(), reinterpret_cast<void*>(this));
+    }
+
+    mService = nullptr;
+    mObserver = nullptr;
+    mRegistered = false;
+}
+
+void TranscodingResourcePolicy::setCallback(
+        const std::shared_ptr<ResourcePolicyCallbackInterface>& cb) {
+    std::scoped_lock lock{mCallbackLock};
+    mResourcePolicyCallback = cb;
+}
+
+void TranscodingResourcePolicy::onResourceAvailable() {
+    std::shared_ptr<ResourcePolicyCallbackInterface> cb;
+    {
+        std::scoped_lock lock{mCallbackLock};
+        cb = mResourcePolicyCallback.lock();
+    }
+
+    if (cb != nullptr) {
+        cb->onResourceAvailable();
+    }
+}
+}  // namespace android
diff --git a/media/libmediatranscoding/TranscodingUidPolicy.cpp b/media/libmediatranscoding/TranscodingUidPolicy.cpp
index b72a2b9..fd41f65 100644
--- a/media/libmediatranscoding/TranscodingUidPolicy.cpp
+++ b/media/libmediatranscoding/TranscodingUidPolicy.cpp
@@ -17,6 +17,10 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "TranscodingUidPolicy"
 
+#include <aidl/android/media/BnResourceManagerClient.h>
+#include <aidl/android/media/IResourceManagerService.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
 #include <binder/ActivityManager.h>
 #include <cutils/misc.h>  // FIRST_APPLICATION_UID
 #include <inttypes.h>
@@ -30,6 +34,43 @@
 constexpr static uid_t OFFLINE_UID = -1;
 constexpr static const char* kTranscodingTag = "transcoding";
 
+/*
+ * The OOM score we're going to ask ResourceManager to use for our native transcoding
+ * service. ResourceManager issues reclaims based on these scores. It gets the scores
+ * from ActivityManagerService, which doesn't track native services. The values of the
+ * OOM scores are defined in:
+ * frameworks/base/services/core/java/com/android/server/am/ProcessList.java
+ * We use SERVICE_ADJ which is lower priority than an app possibly visible to the
+ * user, but higher priority than a cached app (which could be killed without disruption
+ * to the user).
+ */
+constexpr static int32_t SERVICE_ADJ = 500;
+
+using Status = ::ndk::ScopedAStatus;
+using aidl::android::media::BnResourceManagerClient;
+using aidl::android::media::IResourceManagerService;
+
+/*
+ * Placeholder ResourceManagerClient for registering process info override
+ * with the IResourceManagerService. This is only used as a token by the service
+ * to get notifications about binder death, not used for reclaiming resources.
+ */
+struct TranscodingUidPolicy::ResourceManagerClient : public BnResourceManagerClient {
+    explicit ResourceManagerClient() = default;
+
+    Status reclaimResource(bool* _aidl_return) override {
+        *_aidl_return = false;
+        return Status::ok();
+    }
+
+    Status getName(::std::string* _aidl_return) override {
+        _aidl_return->clear();
+        return Status::ok();
+    }
+
+    virtual ~ResourceManagerClient() = default;
+};
+
 struct TranscodingUidPolicy::UidObserver : public BnUidObserver,
                                            public virtual IBinder::DeathRecipient {
     explicit UidObserver(TranscodingUidPolicy* owner) : mOwner(owner) {}
@@ -74,6 +115,7 @@
         mRegistered(false),
         mTopUidState(ActivityManager::PROCESS_STATE_UNKNOWN) {
     registerSelf();
+    setProcessInfoOverride();
 }
 
 TranscodingUidPolicy::~TranscodingUidPolicy() {
@@ -109,6 +151,22 @@
     ALOGI("TranscodingUidPolicy: Unregistered with ActivityManager");
 }
 
+void TranscodingUidPolicy::setProcessInfoOverride() {
+    ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
+    std::shared_ptr<IResourceManagerService> service = IResourceManagerService::fromBinder(binder);
+    if (service == nullptr) {
+        ALOGE("Failed to get IResourceManagerService");
+        return;
+    }
+
+    mProcInfoOverrideClient = ::ndk::SharedRefBase::make<ResourceManagerClient>();
+    Status status = service->overrideProcessInfo(
+            mProcInfoOverrideClient, getpid(), ActivityManager::PROCESS_STATE_SERVICE, SERVICE_ADJ);
+    if (!status.isOk()) {
+        ALOGW("Failed to setProcessInfoOverride.");
+    }
+}
+
 void TranscodingUidPolicy::setUidObserverRegistered(bool registered) {
     Mutex::Autolock _l(mUidLock);
 
diff --git a/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl b/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl
index 40ca2c2..7fc7748 100644
--- a/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl
+++ b/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl
@@ -58,17 +58,13 @@
      *        the client.
      * @param clientName name of the client.
      * @param opPackageName op package name of the client.
-     * @param clientUid user id of the client.
-     * @param clientPid process id of the client.
      * @return an ITranscodingClient interface object, with nullptr indicating
      *         failure to register.
      */
     ITranscodingClient registerClient(
             in ITranscodingClientCallback callback,
             in String clientName,
-            in String opPackageName,
-            in int clientUid,
-            in int clientPid);
+            in String opPackageName);
 
     /**
     * Returns the number of clients. This is used for debugging.
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
index 83ea707..14d19ba 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
@@ -39,6 +39,20 @@
     @utf8InCpp String destinationFilePath;
 
     /**
+     * The UID of the client that this transcoding request is for. Only privileged caller could
+     * set this Uid as only they could do the transcoding on behalf of the client.
+     * -1 means not available.
+     */
+    int clientUid = -1;
+
+    /**
+     * The PID of the client that this transcoding request is for. Only privileged caller could
+     * set this Uid as only they could do the transcoding on behalf of the client.
+     * -1 means not available.
+     */
+    int clientPid = -1;
+
+    /**
      * Type of the transcoding.
      */
     TranscodingType transcodingType;
diff --git a/media/libmediatranscoding/include/media/ResourcePolicyInterface.h b/media/libmediatranscoding/include/media/ResourcePolicyInterface.h
new file mode 100644
index 0000000..8bd7d6b
--- /dev/null
+++ b/media/libmediatranscoding/include/media/ResourcePolicyInterface.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 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_MEDIA_RESOURCE_POLICY_INTERFACE_H
+#define ANDROID_MEDIA_RESOURCE_POLICY_INTERFACE_H
+#include <memory>
+namespace android {
+
+class ResourcePolicyCallbackInterface;
+
+// Interface for the JobScheduler to control the resource status updates.
+class ResourcePolicyInterface {
+public:
+    // Set the associated callback interface to send the events when resource
+    // status changes. (Set to nullptr will stop the updates.)
+    virtual void setCallback(const std::shared_ptr<ResourcePolicyCallbackInterface>& cb) = 0;
+
+protected:
+    virtual ~ResourcePolicyInterface() = default;
+};
+
+// Interface for notifying the JobScheduler of a change in resource status.
+class ResourcePolicyCallbackInterface {
+public:
+    // Called when codec resources become available. The scheduler may use this
+    // as a signal to attempt restart transcoding jobs that were previously
+    // paused due to temporary resource loss.
+    virtual void onResourceAvailable() = 0;
+
+protected:
+    virtual ~ResourcePolicyCallbackInterface() = default;
+};
+
+}  // namespace android
+#endif  // ANDROID_MEDIA_RESOURCE_POLICY_INTERFACE_H
diff --git a/media/libmediatranscoding/include/media/TranscoderWrapper.h b/media/libmediatranscoding/include/media/TranscoderWrapper.h
index a4c92c5..c956042 100644
--- a/media/libmediatranscoding/include/media/TranscoderWrapper.h
+++ b/media/libmediatranscoding/include/media/TranscoderWrapper.h
@@ -18,6 +18,7 @@
 #define ANDROID_TRANSCODER_WRAPPER_H
 
 #include <android-base/thread_annotations.h>
+#include <media/NdkMediaError.h>
 #include <media/TranscoderInterface.h>
 
 #include <list>
@@ -55,6 +56,7 @@
         ClientIdType clientId;
         JobIdType jobId;
         std::function<void()> runnable;
+        int32_t arg;
     };
     using JobKeyType = std::pair<ClientIdType, JobIdType>;
 
@@ -68,26 +70,27 @@
     ClientIdType mCurrentClientId;
     JobIdType mCurrentJobId;
 
-    static const char* toString(Event::Type type);
+    static std::string toString(const Event& event);
     void onFinish(ClientIdType clientId, JobIdType jobId);
-    void onError(ClientIdType clientId, JobIdType jobId, TranscodingErrorCode error);
+    void onError(ClientIdType clientId, JobIdType jobId, media_status_t status);
     void onProgress(ClientIdType clientId, JobIdType jobId, int32_t progress);
 
-    TranscodingErrorCode handleStart(ClientIdType clientId, JobIdType jobId,
-                                     const TranscodingRequestParcel& request,
-                                     const std::shared_ptr<ITranscodingClientCallback>& callback);
-    TranscodingErrorCode handlePause(ClientIdType clientId, JobIdType jobId);
-    TranscodingErrorCode handleResume(ClientIdType clientId, JobIdType jobId,
-                                      const TranscodingRequestParcel& request,
-                                      const std::shared_ptr<ITranscodingClientCallback>& callback);
-    TranscodingErrorCode setupTranscoder(
-            ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
-            const std::shared_ptr<ITranscodingClientCallback>& callback,
-            const std::shared_ptr<const Parcel>& pausedState = nullptr);
+    media_status_t handleStart(ClientIdType clientId, JobIdType jobId,
+                               const TranscodingRequestParcel& request,
+                               const std::shared_ptr<ITranscodingClientCallback>& callback);
+    media_status_t handlePause(ClientIdType clientId, JobIdType jobId);
+    media_status_t handleResume(ClientIdType clientId, JobIdType jobId,
+                                const TranscodingRequestParcel& request,
+                                const std::shared_ptr<ITranscodingClientCallback>& callback);
+    media_status_t setupTranscoder(ClientIdType clientId, JobIdType jobId,
+                                   const TranscodingRequestParcel& request,
+                                   const std::shared_ptr<ITranscodingClientCallback>& callback,
+                                   const std::shared_ptr<const Parcel>& pausedState = nullptr);
 
     void cleanup();
+    void reportError(ClientIdType clientId, JobIdType jobId, media_status_t err);
     void queueEvent(Event::Type type, ClientIdType clientId, JobIdType jobId,
-                    const std::function<void()> runnable);
+                    const std::function<void()> runnable, int32_t arg = 0);
     void threadLoop();
 };
 
diff --git a/media/libmediatranscoding/include/media/TranscodingClientManager.h b/media/libmediatranscoding/include/media/TranscodingClientManager.h
index a62ad8c..015a83a 100644
--- a/media/libmediatranscoding/include/media/TranscodingClientManager.h
+++ b/media/libmediatranscoding/include/media/TranscodingClientManager.h
@@ -58,16 +58,14 @@
      * already been added, it will also return non-zero errorcode.
      *
      * @param callback client callback for the service to call this client.
-     * @param pid client's process id.
-     * @param uid client's user id.
      * @param clientName client's name.
      * @param opPackageName client's package name.
      * @param client output holding the ITranscodingClient interface for the client
      *        to use for subsequent communications with the service.
      * @return 0 if client is added successfully, non-zero errorcode otherwise.
      */
-    status_t addClient(const std::shared_ptr<ITranscodingClientCallback>& callback, pid_t pid,
-                       uid_t uid, const std::string& clientName, const std::string& opPackageName,
+    status_t addClient(const std::shared_ptr<ITranscodingClientCallback>& callback,
+                       const std::string& clientName, const std::string& opPackageName,
                        std::shared_ptr<ITranscodingClient>* client);
 
     /**
diff --git a/media/libmediatranscoding/include/media/TranscodingJobScheduler.h b/media/libmediatranscoding/include/media/TranscodingJobScheduler.h
index 5ccadad..8f5e2aa 100644
--- a/media/libmediatranscoding/include/media/TranscodingJobScheduler.h
+++ b/media/libmediatranscoding/include/media/TranscodingJobScheduler.h
@@ -18,6 +18,7 @@
 #define ANDROID_MEDIA_TRANSCODING_JOB_SCHEDULER_H
 
 #include <aidl/android/media/TranscodingJobPriority.h>
+#include <media/ResourcePolicyInterface.h>
 #include <media/SchedulerClientInterface.h>
 #include <media/TranscoderInterface.h>
 #include <media/TranscodingRequest.h>
@@ -34,7 +35,8 @@
 
 class TranscodingJobScheduler : public UidPolicyCallbackInterface,
                                 public SchedulerClientInterface,
-                                public TranscoderCallbackInterface {
+                                public TranscoderCallbackInterface,
+                                public ResourcePolicyCallbackInterface {
 public:
     virtual ~TranscodingJobScheduler();
 
@@ -58,9 +60,12 @@
 
     // UidPolicyCallbackInterface
     void onTopUidsChanged(const std::unordered_set<uid_t>& uids) override;
-    void onResourceAvailable() override;
     // ~UidPolicyCallbackInterface
 
+    // ResourcePolicyCallbackInterface
+    void onResourceAvailable() override;
+    // ~ResourcePolicyCallbackInterface
+
 private:
     friend class MediaTranscodingService;
     friend class TranscodingJobSchedulerTest;
@@ -96,13 +101,15 @@
 
     std::shared_ptr<TranscoderInterface> mTranscoder;
     std::shared_ptr<UidPolicyInterface> mUidPolicy;
+    std::shared_ptr<ResourcePolicyInterface> mResourcePolicy;
 
     Job* mCurrentJob;
     bool mResourceLost;
 
     // Only allow MediaTranscodingService and unit tests to instantiate.
     TranscodingJobScheduler(const std::shared_ptr<TranscoderInterface>& transcoder,
-                            const std::shared_ptr<UidPolicyInterface>& uidPolicy);
+                            const std::shared_ptr<UidPolicyInterface>& uidPolicy,
+                            const std::shared_ptr<ResourcePolicyInterface>& resourcePolicy);
 
     Job* getTopJob_l();
     void updateCurrentJob_l();
diff --git a/media/libmediatranscoding/include/media/TranscodingRequest.h b/media/libmediatranscoding/include/media/TranscodingRequest.h
index 63de1fb..a6cfed2 100644
--- a/media/libmediatranscoding/include/media/TranscodingRequest.h
+++ b/media/libmediatranscoding/include/media/TranscodingRequest.h
@@ -37,6 +37,8 @@
     void setTo(const TranscodingRequestParcel& parcel) {
         sourceFilePath = parcel.sourceFilePath;
         destinationFilePath = parcel.destinationFilePath;
+        clientUid = parcel.clientUid;
+        clientPid = parcel.clientPid;
         transcodingType = parcel.transcodingType;
         requestedVideoTrackFormat = parcel.requestedVideoTrackFormat;
         priority = parcel.priority;
diff --git a/media/libmediatranscoding/include/media/TranscodingResourcePolicy.h b/media/libmediatranscoding/include/media/TranscodingResourcePolicy.h
new file mode 100644
index 0000000..0836eda
--- /dev/null
+++ b/media/libmediatranscoding/include/media/TranscodingResourcePolicy.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 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_MEDIA_TRANSCODING_RESOURCE_POLICY_H
+#define ANDROID_MEDIA_TRANSCODING_RESOURCE_POLICY_H
+
+#include <android/binder_auto_utils.h>
+#include <media/ResourcePolicyInterface.h>
+#include <utils/Condition.h>
+
+#include <mutex>
+namespace aidl {
+namespace android {
+namespace media {
+class IResourceObserverService;
+}
+}  // namespace android
+}  // namespace aidl
+
+namespace android {
+
+using ::aidl::android::media::IResourceObserverService;
+
+class TranscodingResourcePolicy : public ResourcePolicyInterface {
+public:
+    explicit TranscodingResourcePolicy();
+    ~TranscodingResourcePolicy();
+
+    void setCallback(const std::shared_ptr<ResourcePolicyCallbackInterface>& cb) override;
+
+private:
+    struct ResourceObserver;
+    mutable std::mutex mRegisteredLock;
+    bool mRegistered GUARDED_BY(mRegisteredLock);
+    std::shared_ptr<IResourceObserverService> mService GUARDED_BY(mRegisteredLock);
+    std::shared_ptr<ResourceObserver> mObserver;
+
+    mutable std::mutex mCallbackLock;
+    std::weak_ptr<ResourcePolicyCallbackInterface> mResourcePolicyCallback
+            GUARDED_BY(mCallbackLock);
+
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+    static void BinderDiedCallback(void* cookie);
+
+    void registerSelf();
+    void unregisterSelf();
+    void onResourceAvailable();
+};  // class TranscodingUidPolicy
+
+}  // namespace android
+#endif  // ANDROID_MEDIA_TRANSCODING_RESOURCE_POLICY_H
diff --git a/media/libmediatranscoding/include/media/TranscodingUidPolicy.h b/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
index 27dadd2..8319eee 100644
--- a/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
+++ b/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
@@ -53,10 +53,12 @@
     void setUidObserverRegistered(bool registerd);
     void registerSelf();
     void unregisterSelf();
+    void setProcessInfoOverride();
     int32_t getProcState_l(uid_t uid) NO_THREAD_SAFETY_ANALYSIS;
     void updateTopUid_l() NO_THREAD_SAFETY_ANALYSIS;
 
     struct UidObserver;
+    struct ResourceManagerClient;
     mutable Mutex mUidLock;
     std::shared_ptr<ActivityManager> mAm;
     sp<UidObserver> mUidObserver;
@@ -65,6 +67,7 @@
     std::unordered_map<uid_t, int32_t> mUidStateMap GUARDED_BY(mUidLock);
     std::map<int32_t, std::unordered_set<uid_t>> mStateUidMap GUARDED_BY(mUidLock);
     std::weak_ptr<UidPolicyCallbackInterface> mUidPolicyCallback;
+    std::shared_ptr<ResourceManagerClient> mProcInfoOverrideClient;
 };  // class TranscodingUidPolicy
 
 }  // namespace android
diff --git a/media/libmediatranscoding/include/media/UidPolicyInterface.h b/media/libmediatranscoding/include/media/UidPolicyInterface.h
index dc28027..f88c1ed 100644
--- a/media/libmediatranscoding/include/media/UidPolicyInterface.h
+++ b/media/libmediatranscoding/include/media/UidPolicyInterface.h
@@ -41,19 +41,13 @@
     virtual ~UidPolicyInterface() = default;
 };
 
-// Interface for notifying the scheduler of a change in uid states or
-// transcoding resource availability.
+// Interface for notifying the scheduler of a change in uid states.
 class UidPolicyCallbackInterface {
 public:
     // Called when the set of uids that's top priority among the uids of interest
     // has changed. The receiver of this callback should adjust accordingly.
     virtual void onTopUidsChanged(const std::unordered_set<uid_t>& uids) = 0;
 
-    // Called when resources become available for transcoding use. The scheduler
-    // may use this as a signal to attempt restart transcoding activity that
-    // were previously paused due to temporary resource loss.
-    virtual void onResourceAvailable() = 0;
-
 protected:
     virtual ~UidPolicyCallbackInterface() = default;
 };
diff --git a/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp b/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
index 1583325..41f3ada 100644
--- a/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
@@ -43,12 +43,11 @@
 using ::aidl::android::media::TranscodingRequestParcel;
 using ::aidl::android::media::TranscodingResultParcel;
 
-constexpr pid_t kInvalidClientPid = -1;
+constexpr pid_t kInvalidClientPid = -5;
+constexpr pid_t kInvalidClientUid = -10;
 constexpr const char* kInvalidClientName = "";
 constexpr const char* kInvalidClientPackage = "";
 
-constexpr pid_t kClientPid = 2;
-constexpr uid_t kClientUid = 3;
 constexpr const char* kClientName = "TestClientName";
 constexpr const char* kClientPackage = "TestClientPackage";
 
@@ -236,17 +235,17 @@
     ~TranscodingClientManagerTest() { ALOGD("TranscodingClientManagerTest destroyed"); }
 
     void addMultipleClients() {
-        EXPECT_EQ(mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, kClientName,
+        EXPECT_EQ(mClientManager->addClient(mClientCallback1, kClientName,
                                             kClientPackage, &mClient1),
                   OK);
         EXPECT_NE(mClient1, nullptr);
 
-        EXPECT_EQ(mClientManager->addClient(mClientCallback2, kClientPid, kClientUid, kClientName,
+        EXPECT_EQ(mClientManager->addClient(mClientCallback2, kClientName,
                                             kClientPackage, &mClient2),
                   OK);
         EXPECT_NE(mClient2, nullptr);
 
-        EXPECT_EQ(mClientManager->addClient(mClientCallback3, kClientPid, kClientUid, kClientName,
+        EXPECT_EQ(mClientManager->addClient(mClientCallback3, kClientName,
                                             kClientPackage, &mClient3),
                   OK);
         EXPECT_NE(mClient3, nullptr);
@@ -274,23 +273,23 @@
 TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientCallback) {
     // Add a client with null callback and expect failure.
     std::shared_ptr<ITranscodingClient> client;
-    status_t err = mClientManager->addClient(nullptr, kClientPid, kClientUid, kClientName,
+    status_t err = mClientManager->addClient(nullptr, kClientName,
                                              kClientPackage, &client);
     EXPECT_EQ(err, IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT);
 }
-
-TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientPid) {
-    // Add a client with invalid Pid and expect failure.
-    std::shared_ptr<ITranscodingClient> client;
-    status_t err = mClientManager->addClient(mClientCallback1, kInvalidClientPid, kClientUid,
-                                             kClientName, kClientPackage, &client);
-    EXPECT_EQ(err, IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT);
-}
+//
+//TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientPid) {
+//    // Add a client with invalid Pid and expect failure.
+//    std::shared_ptr<ITranscodingClient> client;
+//    status_t err = mClientManager->addClient(mClientCallback1,
+//                                             kClientName, kClientPackage, &client);
+//    EXPECT_EQ(err, IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT);
+//}
 
 TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientName) {
     // Add a client with invalid name and expect failure.
     std::shared_ptr<ITranscodingClient> client;
-    status_t err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid,
+    status_t err = mClientManager->addClient(mClientCallback1,
                                              kInvalidClientName, kClientPackage, &client);
     EXPECT_EQ(err, IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT);
 }
@@ -298,7 +297,7 @@
 TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientPackageName) {
     // Add a client with invalid packagename and expect failure.
     std::shared_ptr<ITranscodingClient> client;
-    status_t err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, kClientName,
+    status_t err = mClientManager->addClient(mClientCallback1, kClientName,
                                              kInvalidClientPackage, &client);
     EXPECT_EQ(err, IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT);
 }
@@ -306,7 +305,7 @@
 TEST_F(TranscodingClientManagerTest, TestAddingValidClient) {
     // Add a valid client, should succeed.
     std::shared_ptr<ITranscodingClient> client;
-    status_t err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, kClientName,
+    status_t err = mClientManager->addClient(mClientCallback1, kClientName,
                                              kClientPackage, &client);
     EXPECT_EQ(err, OK);
     EXPECT_NE(client.get(), nullptr);
@@ -320,14 +319,14 @@
 
 TEST_F(TranscodingClientManagerTest, TestAddingDupliacteClient) {
     std::shared_ptr<ITranscodingClient> client;
-    status_t err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, kClientName,
+    status_t err = mClientManager->addClient(mClientCallback1, kClientName,
                                              kClientPackage, &client);
     EXPECT_EQ(err, OK);
     EXPECT_NE(client.get(), nullptr);
     EXPECT_EQ(mClientManager->getNumOfClients(), 1);
 
     std::shared_ptr<ITranscodingClient> dupClient;
-    err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, "dupClient",
+    err = mClientManager->addClient(mClientCallback1, "dupClient",
                                     "dupPackage", &dupClient);
     EXPECT_EQ(err, IMediaTranscodingService::ERROR_ALREADY_EXISTS);
     EXPECT_EQ(dupClient.get(), nullptr);
@@ -337,8 +336,7 @@
     EXPECT_TRUE(status.isOk());
     EXPECT_EQ(mClientManager->getNumOfClients(), 0);
 
-    err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, "dupClient",
-                                    "dupPackage", &dupClient);
+    err = mClientManager->addClient(mClientCallback1, "dupClient", "dupPackage", &dupClient);
     EXPECT_EQ(err, OK);
     EXPECT_NE(dupClient.get(), nullptr);
     EXPECT_EQ(mClientManager->getNumOfClients(), 1);
@@ -385,6 +383,14 @@
     EXPECT_TRUE(mClient1->submitRequest(badRequest, &job, &result).isOk());
     EXPECT_FALSE(result);
 
+    // Test submit with bad pid/uid.
+    badRequest.sourceFilePath = "test_source_file_3";
+    badRequest.destinationFilePath = "test_desintaion_file_3";
+    badRequest.clientPid = kInvalidClientPid;
+    badRequest.clientUid = kInvalidClientUid;
+    EXPECT_TRUE(mClient1->submitRequest(badRequest, &job, &result).isOk());
+    EXPECT_FALSE(result);
+
     // Test get jobs by id.
     EXPECT_TRUE(mClient1->getJobWithId(JOB(2), &job, &result).isOk());
     EXPECT_EQ(job.jobId, JOB(2));
@@ -468,7 +474,7 @@
 TEST_F(TranscodingClientManagerTest, TestUseAfterUnregister) {
     // Add a client.
     std::shared_ptr<ITranscodingClient> client;
-    status_t err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, kClientName,
+    status_t err = mClientManager->addClient(mClientCallback1, kClientName,
                                              kClientPackage, &client);
     EXPECT_EQ(err, OK);
     EXPECT_NE(client.get(), nullptr);
diff --git a/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp b/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp
index d21b595..9b9df87 100644
--- a/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp
@@ -213,7 +213,8 @@
         ALOGI("TranscodingJobSchedulerTest set up");
         mTranscoder.reset(new TestTranscoder());
         mUidPolicy.reset(new TestUidPolicy());
-        mScheduler.reset(new TranscodingJobScheduler(mTranscoder, mUidPolicy));
+        mScheduler.reset(
+                new TranscodingJobScheduler(mTranscoder, mUidPolicy, nullptr /*resourcePolicy*/));
         mUidPolicy->setCallback(mScheduler);
 
         // Set priority only, ignore other fields for now.
diff --git a/media/libmediatranscoding/transcoder/Android.bp b/media/libmediatranscoding/transcoder/Android.bp
index c153a42..258ed9a 100644
--- a/media/libmediatranscoding/transcoder/Android.bp
+++ b/media/libmediatranscoding/transcoder/Android.bp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-cc_library_shared {
-    name: "libmediatranscoder",
+cc_defaults {
+    name: "mediatranscoder_defaults",
 
     srcs: [
         "MediaSampleQueue.cpp",
@@ -60,3 +60,17 @@
         cfi: true,
     },
 }
+
+cc_library_shared {
+    name: "libmediatranscoder",
+    defaults: ["mediatranscoder_defaults"],
+}
+
+cc_library_shared {
+    name: "libmediatranscoder_asan",
+    defaults: ["mediatranscoder_defaults"],
+
+    sanitize: {
+        address: true,
+    },
+}
diff --git a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
index bb0da88..afa5021 100644
--- a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
+++ b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
@@ -72,6 +72,11 @@
     AMediaMuxer* mMuxer;
 };
 
+// static
+std::shared_ptr<MediaSampleWriter> MediaSampleWriter::Create() {
+    return std::shared_ptr<MediaSampleWriter>(new MediaSampleWriter());
+}
+
 MediaSampleWriter::~MediaSampleWriter() {
     if (mState == STARTED) {
         stop();  // Join thread.
@@ -92,7 +97,7 @@
         return false;
     }
 
-    std::scoped_lock lock(mStateMutex);
+    std::scoped_lock lock(mMutex);
     if (mState != UNINITIALIZED) {
         LOG(ERROR) << "Sample writer is already initialized";
         return false;
@@ -104,39 +109,58 @@
     return true;
 }
 
-bool MediaSampleWriter::addTrack(const std::shared_ptr<MediaSampleQueue>& sampleQueue,
-                                 const std::shared_ptr<AMediaFormat>& trackFormat) {
-    if (sampleQueue == nullptr || trackFormat == nullptr) {
-        LOG(ERROR) << "Sample queue and track format must be non-null";
-        return false;
+MediaSampleWriter::MediaSampleConsumerFunction MediaSampleWriter::addTrack(
+        const std::shared_ptr<AMediaFormat>& trackFormat) {
+    if (trackFormat == nullptr) {
+        LOG(ERROR) << "Track format must be non-null";
+        return nullptr;
     }
 
-    std::scoped_lock lock(mStateMutex);
+    std::scoped_lock lock(mMutex);
     if (mState != INITIALIZED) {
         LOG(ERROR) << "Muxer needs to be initialized when adding tracks.";
-        return false;
+        return nullptr;
     }
-    ssize_t trackIndex = mMuxer->addTrack(trackFormat.get());
-    if (trackIndex < 0) {
-        LOG(ERROR) << "Failed to add media track to muxer: " << trackIndex;
-        return false;
+    ssize_t trackIndexOrError = mMuxer->addTrack(trackFormat.get());
+    if (trackIndexOrError < 0) {
+        LOG(ERROR) << "Failed to add media track to muxer: " << trackIndexOrError;
+        return nullptr;
     }
+    const size_t trackIndex = static_cast<size_t>(trackIndexOrError);
 
     int64_t durationUs;
     if (!AMediaFormat_getInt64(trackFormat.get(), AMEDIAFORMAT_KEY_DURATION, &durationUs)) {
         durationUs = 0;
     }
 
-    mAllTracks.push_back(std::make_unique<TrackRecord>(sampleQueue, static_cast<size_t>(trackIndex),
-                                                       durationUs));
-    mSortedTracks.insert(mAllTracks.back().get());
-    return true;
+    mTracks.emplace(trackIndex, durationUs);
+    std::shared_ptr<MediaSampleWriter> thisWriter = shared_from_this();
+
+    return [self = shared_from_this(), trackIndex](const std::shared_ptr<MediaSample>& sample) {
+        self->addSampleToTrack(trackIndex, sample);
+    };
+}
+
+void MediaSampleWriter::addSampleToTrack(size_t trackIndex,
+                                         const std::shared_ptr<MediaSample>& sample) {
+    if (sample == nullptr) return;
+
+    bool wasEmpty;
+    {
+        std::scoped_lock lock(mMutex);
+        wasEmpty = mSampleQueue.empty();
+        mSampleQueue.push(std::make_pair(trackIndex, sample));
+    }
+
+    if (wasEmpty) {
+        mSampleSignal.notify_one();
+    }
 }
 
 bool MediaSampleWriter::start() {
-    std::scoped_lock lock(mStateMutex);
+    std::scoped_lock lock(mMutex);
 
-    if (mAllTracks.size() == 0) {
+    if (mTracks.size() == 0) {
         LOG(ERROR) << "No tracks to write.";
         return false;
     } else if (mState != INITIALIZED) {
@@ -144,30 +168,28 @@
         return false;
     }
 
+    mState = STARTED;
     mThread = std::thread([this] {
         media_status_t status = writeSamples();
         if (auto callbacks = mCallbacks.lock()) {
             callbacks->onFinished(this, status);
         }
     });
-    mState = STARTED;
     return true;
 }
 
 bool MediaSampleWriter::stop() {
-    std::scoped_lock lock(mStateMutex);
-
-    if (mState != STARTED) {
-        LOG(ERROR) << "Sample writer is not started.";
-        return false;
+    {
+        std::scoped_lock lock(mMutex);
+        if (mState != STARTED) {
+            LOG(ERROR) << "Sample writer is not started.";
+            return false;
+        }
+        mState = STOPPED;
     }
 
-    // Stop the sources, and wait for thread to join.
-    for (auto& track : mAllTracks) {
-        track->mSampleQueue->abort();
-    }
+    mSampleSignal.notify_all();
     mThread.join();
-    mState = STOPPED;
     return true;
 }
 
@@ -191,83 +213,69 @@
     return writeStatus != AMEDIA_OK ? writeStatus : muxerStatus;
 }
 
-std::multiset<MediaSampleWriter::TrackRecord*>::iterator MediaSampleWriter::getNextOutputTrack() {
-    // Find the first track that has samples ready in its queue AND is not more than
-    // mMaxTrackDivergenceUs ahead of the slowest track. If no such track exists then return the
-    // slowest track and let the writer wait for samples to become ready. Note that mSortedTracks is
-    // sorted by each track's previous sample timestamp in ascending order.
-    auto slowestTrack = mSortedTracks.begin();
-    if (slowestTrack == mSortedTracks.end() || !(*slowestTrack)->mSampleQueue->isEmpty()) {
-        return slowestTrack;
-    }
-
-    const int64_t slowestTimeUs = (*slowestTrack)->mPrevSampleTimeUs;
-    int64_t divergenceUs;
-
-    for (auto it = std::next(slowestTrack); it != mSortedTracks.end(); ++it) {
-        // If the current track has diverged then the rest will have too, so we can stop the search.
-        // If not and it has samples ready then return it, otherwise keep looking.
-        if (__builtin_sub_overflow((*it)->mPrevSampleTimeUs, slowestTimeUs, &divergenceUs) ||
-            divergenceUs >= mMaxTrackDivergenceUs) {
-            break;
-        } else if (!(*it)->mSampleQueue->isEmpty()) {
-            return it;
-        }
-    }
-
-    // No track with pending samples within acceptable time interval was found, so let the writer
-    // wait for the slowest track to produce a new sample.
-    return slowestTrack;
-}
-
-media_status_t MediaSampleWriter::runWriterLoop() {
+media_status_t MediaSampleWriter::runWriterLoop() NO_THREAD_SAFETY_ANALYSIS {
     AMediaCodecBufferInfo bufferInfo;
     int32_t lastProgressUpdate = 0;
+    int trackEosCount = 0;
 
     // Set the "primary" track that will be used to determine progress to the track with longest
     // duration.
     int primaryTrackIndex = -1;
     int64_t longestDurationUs = 0;
-    for (auto& track : mAllTracks) {
-        if (track->mDurationUs > longestDurationUs) {
-            primaryTrackIndex = track->mTrackIndex;
-            longestDurationUs = track->mDurationUs;
+    for (auto it = mTracks.begin(); it != mTracks.end(); ++it) {
+        if (it->second.mDurationUs > longestDurationUs) {
+            primaryTrackIndex = it->first;
+            longestDurationUs = it->second.mDurationUs;
         }
     }
 
     while (true) {
-        auto outputTrackIter = getNextOutputTrack();
-
-        // Exit if all tracks have reached end of stream.
-        if (outputTrackIter == mSortedTracks.end()) {
+        if (trackEosCount >= mTracks.size()) {
             break;
         }
 
-        // Remove the track from the set, update it, and then reinsert it to keep the set in order.
-        TrackRecord* track = *outputTrackIter;
-        mSortedTracks.erase(outputTrackIter);
-
+        size_t trackIndex;
         std::shared_ptr<MediaSample> sample;
-        if (track->mSampleQueue->dequeue(&sample)) {
-            // Track queue was aborted.
-            return AMEDIA_ERROR_UNKNOWN;  // TODO(lnilsson): Custom error code.
-        } else if (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
+        {
+            std::unique_lock lock(mMutex);
+            while (mSampleQueue.empty() && mState == STARTED) {
+                mSampleSignal.wait(lock);
+            }
+
+            if (mState != STARTED) {
+                return AMEDIA_ERROR_UNKNOWN;  // TODO(lnilsson): Custom error code.
+            }
+
+            auto& topEntry = mSampleQueue.top();
+            trackIndex = topEntry.first;
+            sample = topEntry.second;
+            mSampleQueue.pop();
+        }
+
+        TrackRecord& track = mTracks[trackIndex];
+
+        if (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
+            if (track.mReachedEos) {
+                continue;
+            }
+
             // Track reached end of stream.
-            track->mReachedEos = true;
+            track.mReachedEos = true;
+            trackEosCount++;
 
             // Preserve source track duration by setting the appropriate timestamp on the
             // empty End-Of-Stream sample.
-            if (track->mDurationUs > 0 && track->mFirstSampleTimeSet) {
-                sample->info.presentationTimeUs = track->mDurationUs + track->mFirstSampleTimeUs;
+            if (track.mDurationUs > 0 && track.mFirstSampleTimeSet) {
+                sample->info.presentationTimeUs = track.mDurationUs + track.mFirstSampleTimeUs;
             }
         }
 
-        track->mPrevSampleTimeUs = sample->info.presentationTimeUs;
-        if (!track->mFirstSampleTimeSet) {
+        track.mPrevSampleTimeUs = sample->info.presentationTimeUs;
+        if (!track.mFirstSampleTimeSet) {
             // Record the first sample's timestamp in order to translate duration to EOS
             // time for tracks that does not start at 0.
-            track->mFirstSampleTimeUs = sample->info.presentationTimeUs;
-            track->mFirstSampleTimeSet = true;
+            track.mFirstSampleTimeUs = sample->info.presentationTimeUs;
+            track.mFirstSampleTimeSet = true;
         }
 
         bufferInfo.offset = sample->dataOffset;
@@ -275,8 +283,7 @@
         bufferInfo.flags = sample->info.flags;
         bufferInfo.presentationTimeUs = sample->info.presentationTimeUs;
 
-        media_status_t status =
-                mMuxer->writeSampleData(track->mTrackIndex, sample->buffer, &bufferInfo);
+        media_status_t status = mMuxer->writeSampleData(trackIndex, sample->buffer, &bufferInfo);
         if (status != AMEDIA_OK) {
             LOG(ERROR) << "writeSampleData returned " << status;
             return status;
@@ -284,9 +291,9 @@
         sample.reset();
 
         // TODO(lnilsson): Add option to toggle progress reporting on/off.
-        if (track->mTrackIndex == primaryTrackIndex) {
-            const int64_t elapsed = track->mPrevSampleTimeUs - track->mFirstSampleTimeUs;
-            int32_t progress = (elapsed * 100) / track->mDurationUs;
+        if (trackIndex == primaryTrackIndex) {
+            const int64_t elapsed = track.mPrevSampleTimeUs - track.mFirstSampleTimeUs;
+            int32_t progress = (elapsed * 100) / track.mDurationUs;
             progress = std::clamp(progress, 0, 100);
 
             if (progress > lastProgressUpdate) {
@@ -296,10 +303,6 @@
                 lastProgressUpdate = progress;
             }
         }
-
-        if (!track->mReachedEos) {
-            mSortedTracks.insert(track);
-        }
     }
 
     return AMEDIA_OK;
diff --git a/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
index 92ce60a..698594f 100644
--- a/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
@@ -94,7 +94,10 @@
         abortTranscodeLoop();
         mMediaSampleReader->setEnforceSequentialAccess(false);
         mTranscodingThread.join();
-        mOutputQueue->abort();  // Wake up any threads waiting for samples.
+        {
+            std::scoped_lock lock{mSampleMutex};
+            mSampleQueue.abort();  // Release any buffered samples.
+        }
         mState = STOPPED;
         return true;
     }
@@ -109,8 +112,24 @@
     }
 }
 
-std::shared_ptr<MediaSampleQueue> MediaTrackTranscoder::getOutputQueue() const {
-    return mOutputQueue;
+void MediaTrackTranscoder::onOutputSampleAvailable(const std::shared_ptr<MediaSample>& sample) {
+    std::scoped_lock lock{mSampleMutex};
+    if (mSampleConsumer == nullptr) {
+        mSampleQueue.enqueue(sample);
+    } else {
+        mSampleConsumer(sample);
+    }
+}
+
+void MediaTrackTranscoder::setSampleConsumer(
+        const MediaSampleWriter::MediaSampleConsumerFunction& sampleConsumer) {
+    std::scoped_lock lock{mSampleMutex};
+    mSampleConsumer = sampleConsumer;
+
+    std::shared_ptr<MediaSample> sample;
+    while (!mSampleQueue.isEmpty() && !mSampleQueue.dequeue(&sample)) {
+        mSampleConsumer(sample);
+    }
 }
 
 }  // namespace android
diff --git a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
index fbed5c2..f35ea99 100644
--- a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
@@ -123,14 +123,16 @@
     }
 
     // Add track to the writer.
-    const bool ok =
-            mSampleWriter->addTrack(transcoder->getOutputQueue(), transcoder->getOutputFormat());
-    if (!ok) {
+    auto consumer = mSampleWriter->addTrack(transcoder->getOutputFormat());
+    if (consumer == nullptr) {
         LOG(ERROR) << "Unable to add track to sample writer.";
         sendCallback(AMEDIA_ERROR_UNKNOWN);
         return;
     }
 
+    MediaTrackTranscoder* mutableTranscoder = const_cast<MediaTrackTranscoder*>(transcoder);
+    mutableTranscoder->setSampleConsumer(consumer);
+
     mTracksAdded.insert(transcoder);
     if (mTracksAdded.size() == mTrackTranscoders.size()) {
         // Enable sequential access mode on the sample reader to achieve optimal read performance.
@@ -153,7 +155,7 @@
 }
 
 void MediaTranscoder::onTrackError(const MediaTrackTranscoder* transcoder, media_status_t status) {
-    LOG(DEBUG) << "TrackTranscoder " << transcoder << " returned error " << status;
+    LOG(ERROR) << "TrackTranscoder " << transcoder << " returned error " << status;
     sendCallback(status);
 }
 
@@ -282,7 +284,7 @@
         format = std::shared_ptr<AMediaFormat>(mergedFormat, &AMediaFormat_delete);
     }
 
-    transcoder->configure(mSampleReader, trackIndex, format);
+    status = transcoder->configure(mSampleReader, trackIndex, format);
     if (status != AMEDIA_OK) {
         LOG(ERROR) << "Configure track transcoder for track #" << trackIndex << " returned error "
                    << status;
@@ -304,7 +306,7 @@
         return AMEDIA_ERROR_INVALID_OPERATION;
     }
 
-    mSampleWriter = std::make_unique<MediaSampleWriter>();
+    mSampleWriter = MediaSampleWriter::Create();
     const bool initOk = mSampleWriter->init(fd, shared_from_this());
 
     if (!initOk) {
diff --git a/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp
index e7c0271..35b1d33 100644
--- a/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp
@@ -138,10 +138,7 @@
         }
 
         sample->info = info;
-        if (mOutputQueue->enqueue(sample)) {
-            LOG(ERROR) << "Output queue aborted";
-            return AMEDIA_ERROR_IO;
-        }
+        onOutputSampleAvailable(sample);
     }
 
     if (mStopRequested && !mEosFromSource) {
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index b0bf59f..5579868 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -40,7 +40,11 @@
 template <typename T>
 void VideoTrackTranscoder::BlockingQueue<T>::push(T const& value, bool front) {
     {
-        std::unique_lock<std::mutex> lock(mMutex);
+        std::scoped_lock lock(mMutex);
+        if (mAborted) {
+            return;
+        }
+
         if (front) {
             mQueue.push_front(value);
         } else {
@@ -52,7 +56,7 @@
 
 template <typename T>
 T VideoTrackTranscoder::BlockingQueue<T>::pop() {
-    std::unique_lock<std::mutex> lock(mMutex);
+    std::unique_lock lock(mMutex);
     while (mQueue.empty()) {
         mCondition.wait(lock);
     }
@@ -61,6 +65,14 @@
     return value;
 }
 
+// Note: Do not call if another thread might waiting in pop.
+template <typename T>
+void VideoTrackTranscoder::BlockingQueue<T>::abort() {
+    std::scoped_lock lock(mMutex);
+    mAborted = true;
+    mQueue.clear();
+}
+
 // The CodecWrapper class is used to let AMediaCodec instances outlive the transcoder object itself
 // by giving the codec a weak pointer to the transcoder. Codecs wrapped in this object are kept
 // alive by the transcoder and the codec's outstanding buffers. Once the transcoder stops and all
@@ -375,12 +387,7 @@
         sample->info.flags = bufferInfo.flags;
         sample->info.presentationTimeUs = bufferInfo.presentationTimeUs;
 
-        const bool aborted = mOutputQueue->enqueue(sample);
-        if (aborted) {
-            LOG(ERROR) << "Output sample queue was aborted. Stopping transcode.";
-            mStatus = AMEDIA_ERROR_IO;  // TODO: Define custom error codes?
-            return;
-        }
+        onOutputSampleAvailable(sample);
     } else if (bufferIndex == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
         AMediaFormat* newFormat = AMediaCodec_getOutputFormat(mEncoder->getCodec());
         LOG(DEBUG) << "Encoder output format changed: " << AMediaFormat_toString(newFormat);
@@ -489,12 +496,14 @@
         message();
     }
 
+    mCodecMessageQueue.abort();
+    AMediaCodec_stop(mDecoder);
+
     // Return error if transcoding was stopped before it finished.
     if (mStopRequested && !mEosFromEncoder && mStatus == AMEDIA_OK) {
         mStatus = AMEDIA_ERROR_UNKNOWN;  // TODO: Define custom error codes?
     }
 
-    AMediaCodec_stop(mDecoder);
     return mStatus;
 }
 
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaSampleReaderNDK.h b/media/libmediatranscoding/transcoder/include/media/MediaSampleReaderNDK.h
index 5f9822d..2032def 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaSampleReaderNDK.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaSampleReaderNDK.h
@@ -58,7 +58,6 @@
     virtual ~MediaSampleReaderNDK() override;
 
 private:
-
     /**
      * SamplePosition describes the position of a single sample in the media file using its
      * timestamp and index in the file.
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaSampleWriter.h b/media/libmediatranscoding/transcoder/include/media/MediaSampleWriter.h
index d4b1fcf..f762556 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaSampleWriter.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaSampleWriter.h
@@ -17,17 +17,19 @@
 #ifndef ANDROID_MEDIA_SAMPLE_WRITER_H
 #define ANDROID_MEDIA_SAMPLE_WRITER_H
 
-#include <media/MediaSampleQueue.h>
+#include <media/MediaSample.h>
 #include <media/NdkMediaCodec.h>
 #include <media/NdkMediaError.h>
 #include <media/NdkMediaFormat.h>
 #include <utils/Mutex.h>
 
+#include <condition_variable>
 #include <functional>
 #include <memory>
 #include <mutex>
-#include <set>
+#include <queue>
 #include <thread>
+#include <unordered_map>
 
 namespace android {
 
@@ -62,18 +64,16 @@
 };
 
 /**
- * MediaSampleWriter writes samples to a muxer while keeping its input sources synchronized. Each
- * source track have its own MediaSampleQueue from which samples are dequeued by the sample writer
- * and written to the muxer. The sample writer always prioritizes dequeueing samples from the source
- * track that is farthest behind by comparing sample timestamps. If the slowest track does not have
- * any samples pending the writer moves on to the next track but never allows tracks to diverge more
- * than a configurable duration of time. The default muxer interface implementation is based
+ * MediaSampleWriter is a wrapper around a muxer. The sample writer puts samples on a queue that
+ * is serviced by an internal thread to minimize blocking time for clients. MediaSampleWriter also
+ * provides progress reporting. The default muxer interface implementation is based
  * directly on AMediaMuxer.
  */
-class MediaSampleWriter {
+class MediaSampleWriter : public std::enable_shared_from_this<MediaSampleWriter> {
 public:
-    /** The default maximum track divergence in microseconds. */
-    static constexpr uint32_t kDefaultMaxTrackDivergenceUs = 1 * 1000 * 1000;  // 1 second.
+    /** Function prototype for delivering media samples to the writer. */
+    using MediaSampleConsumerFunction =
+            std::function<void(const std::shared_ptr<MediaSample>& sample)>;
 
     /** Callback interface. */
     class CallbackInterface {
@@ -90,18 +90,7 @@
         virtual ~CallbackInterface() = default;
     };
 
-    /**
-     * Constructor with custom maximum track divergence.
-     * @param maxTrackDivergenceUs The maximum track divergence in microseconds.
-     */
-    MediaSampleWriter(uint32_t maxTrackDivergenceUs)
-          : mMaxTrackDivergenceUs(maxTrackDivergenceUs), mMuxer(nullptr), mState(UNINITIALIZED){};
-
-    /** Constructor using the default maximum track divergence. */
-    MediaSampleWriter() : MediaSampleWriter(kDefaultMaxTrackDivergenceUs){};
-
-    /** Destructor. */
-    ~MediaSampleWriter();
+    static std::shared_ptr<MediaSampleWriter> Create();
 
     /**
      * Initializes the sample writer with its default muxer implementation. MediaSampleWriter needs
@@ -125,12 +114,12 @@
     /**
      * Adds a new track to the sample writer. Tracks must be added after the sample writer has been
      * initialized and before it is started.
-     * @param sampleQueue The MediaSampleQueue to pull samples from.
      * @param trackFormat The format of the track to add.
-     * @return True if the track was successfully added.
+     * @return A sample consumer to add samples to if the track was successfully added, or nullptr
+     * if the track could not be added.
      */
-    bool addTrack(const std::shared_ptr<MediaSampleQueue>& sampleQueue /* nonnull */,
-                  const std::shared_ptr<AMediaFormat>& trackFormat /* nonnull */);
+    MediaSampleConsumerFunction addTrack(
+            const std::shared_ptr<AMediaFormat>& trackFormat /* nonnull */);
 
     /**
      * Starts the sample writer. The sample writer will start processing samples and writing them to
@@ -150,51 +139,69 @@
      */
     bool stop();
 
+    /** Destructor. */
+    ~MediaSampleWriter();
+
 private:
     struct TrackRecord {
-        TrackRecord(const std::shared_ptr<MediaSampleQueue>& sampleQueue, size_t trackIndex,
-                    int64_t durationUs)
-              : mSampleQueue(sampleQueue),
-                mTrackIndex(trackIndex),
-                mDurationUs(durationUs),
+        TrackRecord(int64_t durationUs)
+              : mDurationUs(durationUs),
                 mFirstSampleTimeUs(0),
                 mPrevSampleTimeUs(INT64_MIN),
                 mFirstSampleTimeSet(false),
-                mReachedEos(false) {}
+                mReachedEos(false){};
 
-        std::shared_ptr<MediaSampleQueue> mSampleQueue;
-        const size_t mTrackIndex;
+        TrackRecord() : TrackRecord(0){};
+
         int64_t mDurationUs;
         int64_t mFirstSampleTimeUs;
         int64_t mPrevSampleTimeUs;
         bool mFirstSampleTimeSet;
         bool mReachedEos;
-
-        struct compare {
-            bool operator()(const TrackRecord* lhs, const TrackRecord* rhs) const {
-                return lhs->mPrevSampleTimeUs < rhs->mPrevSampleTimeUs;
-            }
-        };
     };
 
-    const uint32_t mMaxTrackDivergenceUs;
+    // Track index and sample.
+    using SampleEntry = std::pair<size_t, std::shared_ptr<MediaSample>>;
+
+    struct SampleComparator {
+        // Return true if lhs should come after rhs in the sample queue.
+        bool operator()(const SampleEntry& lhs, const SampleEntry& rhs) {
+            const bool lhsEos = lhs.second->info.flags & SAMPLE_FLAG_END_OF_STREAM;
+            const bool rhsEos = rhs.second->info.flags & SAMPLE_FLAG_END_OF_STREAM;
+
+            if (lhsEos && !rhsEos) {
+                return true;
+            } else if (!lhsEos && rhsEos) {
+                return false;
+            } else if (lhsEos && rhsEos) {
+                return lhs.first > rhs.first;
+            }
+
+            return lhs.second->info.presentationTimeUs > rhs.second->info.presentationTimeUs;
+        }
+    };
+
     std::weak_ptr<CallbackInterface> mCallbacks;
     std::shared_ptr<MediaSampleWriterMuxerInterface> mMuxer;
-    std::vector<std::unique_ptr<TrackRecord>> mAllTracks;
-    std::multiset<TrackRecord*, TrackRecord::compare> mSortedTracks;
-    std::thread mThread;
 
-    std::mutex mStateMutex;
+    std::mutex mMutex;  // Protects sample queue and state.
+    std::condition_variable mSampleSignal;
+    std::thread mThread;
+    std::unordered_map<size_t, TrackRecord> mTracks;
+    std::priority_queue<SampleEntry, std::vector<SampleEntry>, SampleComparator> mSampleQueue
+            GUARDED_BY(mMutex);
+
     enum : int {
         UNINITIALIZED,
         INITIALIZED,
         STARTED,
         STOPPED,
-    } mState GUARDED_BY(mStateMutex);
+    } mState GUARDED_BY(mMutex);
 
+    MediaSampleWriter() : mState(UNINITIALIZED){};
+    void addSampleToTrack(size_t trackIndex, const std::shared_ptr<MediaSample>& sample);
     media_status_t writeSamples();
     media_status_t runWriterLoop();
-    std::multiset<TrackRecord*>::iterator getNextOutputTrack();
 };
 
 }  // namespace android
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h b/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h
index 60a9139..c5e161c 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h
@@ -19,6 +19,7 @@
 
 #include <media/MediaSampleQueue.h>
 #include <media/MediaSampleReader.h>
+#include <media/MediaSampleWriter.h>
 #include <media/NdkMediaError.h>
 #include <media/NdkMediaFormat.h>
 #include <utils/Mutex.h>
@@ -75,10 +76,13 @@
     bool stop();
 
     /**
-     * Retrieves the track transcoder's output sample queue.
-     * @return The output sample queue.
+     * Set the sample consumer function. The MediaTrackTranscoder will deliver transcoded samples to
+     * this function. If the MediaTrackTranscoder is started before a consumer is set the transcoder
+     * will buffer a limited number of samples internally before stalling. Once a consumer has been
+     * set the internally buffered samples will be delivered to the consumer.
+     * @param sampleConsumer The sample consumer function.
      */
-    std::shared_ptr<MediaSampleQueue> getOutputQueue() const;
+    void setSampleConsumer(const MediaSampleWriter::MediaSampleConsumerFunction& sampleConsumer);
 
     /**
       * Retrieves the track transcoder's final output format. The output is available after the
@@ -91,12 +95,14 @@
 
 protected:
     MediaTrackTranscoder(const std::weak_ptr<MediaTrackTranscoderCallback>& transcoderCallback)
-          : mOutputQueue(std::make_shared<MediaSampleQueue>()),
-            mTranscoderCallback(transcoderCallback){};
+          : mTranscoderCallback(transcoderCallback){};
 
     // Called by subclasses when the actual track format becomes available.
     void notifyTrackFormatAvailable();
 
+    // Called by subclasses when a transcoded sample is available.
+    void onOutputSampleAvailable(const std::shared_ptr<MediaSample>& sample);
+
     // configureDestinationFormat needs to be implemented by subclasses, and gets called on an
     // external thread before start.
     virtual media_status_t configureDestinationFormat(
@@ -110,12 +116,14 @@
     // be aborted as soon as possible. It should be safe to call abortTranscodeLoop multiple times.
     virtual void abortTranscodeLoop() = 0;
 
-    std::shared_ptr<MediaSampleQueue> mOutputQueue;
     std::shared_ptr<MediaSampleReader> mMediaSampleReader;
     int mTrackIndex;
     std::shared_ptr<AMediaFormat> mSourceFormat;
 
 private:
+    std::mutex mSampleMutex;
+    MediaSampleQueue mSampleQueue GUARDED_BY(mSampleMutex);
+    MediaSampleWriter::MediaSampleConsumerFunction mSampleConsumer GUARDED_BY(mSampleMutex);
     const std::weak_ptr<MediaTrackTranscoderCallback> mTranscoderCallback;
     std::mutex mStateMutex;
     std::thread mTranscodingThread GUARDED_BY(mStateMutex);
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h b/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
index 8d96867..9a367ca 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
@@ -138,7 +138,7 @@
 
     std::shared_ptr<CallbackInterface> mCallbacks;
     std::shared_ptr<MediaSampleReader> mSampleReader;
-    std::unique_ptr<MediaSampleWriter> mSampleWriter;
+    std::shared_ptr<MediaSampleWriter> mSampleWriter;
     std::vector<std::shared_ptr<AMediaFormat>> mSourceTrackFormats;
     std::vector<std::shared_ptr<MediaTrackTranscoder>> mTrackTranscoders;
     std::mutex mTracksAddedMutex;
diff --git a/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h b/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
index 0a7bf33..d000d7f 100644
--- a/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
+++ b/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
@@ -51,11 +51,13 @@
     public:
         void push(T const& value, bool front = false);
         T pop();
+        void abort();
 
     private:
         std::mutex mMutex;
         std::condition_variable mCondition;
         std::deque<T> mQueue;
+        bool mAborted = false;
     };
     class CodecWrapper;
 
diff --git a/media/libmediatranscoding/transcoder/tests/Android.bp b/media/libmediatranscoding/transcoder/tests/Android.bp
index 4160c30..7ae6261 100644
--- a/media/libmediatranscoding/transcoder/tests/Android.bp
+++ b/media/libmediatranscoding/transcoder/tests/Android.bp
@@ -17,7 +17,7 @@
         "libbase",
         "libcutils",
         "libmediandk",
-        "libmediatranscoder",
+        "libmediatranscoder_asan",
         "libutils",
     ],
 
@@ -26,6 +26,15 @@
         "-Wall",
     ],
 
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        address: true,
+    },
+
     data: [":test_assets"],
     test_config_template: "AndroidTestTemplate.xml",
     test_suites: ["device-tests", "TranscoderTests"],
@@ -80,4 +89,5 @@
     name: "MediaTranscoderTests",
     defaults: ["testdefaults"],
     srcs: ["MediaTranscoderTests.cpp"],
+    shared_libs: ["libbinder_ndk"],
 }
diff --git a/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
index e8acd48..9c9c8b5 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
@@ -26,6 +26,7 @@
 #include <gtest/gtest.h>
 #include <media/MediaSampleReaderNDK.h>
 #include <utils/Timers.h>
+
 #include <cmath>
 #include <mutex>
 #include <thread>
diff --git a/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
index 64240d4..46f3e9b 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
@@ -274,102 +274,95 @@
     void SetUp() override {
         LOG(DEBUG) << "MediaSampleWriterTests set up";
         mTestMuxer = std::make_shared<TestMuxer>();
-        mSampleQueue = std::make_shared<MediaSampleQueue>();
     }
 
     void TearDown() override {
         LOG(DEBUG) << "MediaSampleWriterTests tear down";
         mTestMuxer.reset();
-        mSampleQueue.reset();
     }
 
 protected:
     std::shared_ptr<TestMuxer> mTestMuxer;
-    std::shared_ptr<MediaSampleQueue> mSampleQueue;
     std::shared_ptr<TestCallbacks> mTestCallbacks = std::make_shared<TestCallbacks>();
 };
 
 TEST_F(MediaSampleWriterTests, TestAddTrackWithoutInit) {
     const TestMediaSource& mediaSource = getMediaSource();
 
-    MediaSampleWriter writer{};
-    EXPECT_FALSE(writer.addTrack(mSampleQueue, mediaSource.mTrackFormats[0]));
+    std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+    EXPECT_EQ(writer->addTrack(mediaSource.mTrackFormats[0]), nullptr);
 }
 
 TEST_F(MediaSampleWriterTests, TestStartWithoutInit) {
-    MediaSampleWriter writer{};
-    EXPECT_FALSE(writer.start());
+    std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+    EXPECT_FALSE(writer->start());
 }
 
 TEST_F(MediaSampleWriterTests, TestStartWithoutTracks) {
-    MediaSampleWriter writer{};
-    EXPECT_TRUE(writer.init(mTestMuxer, mTestCallbacks));
-    EXPECT_FALSE(writer.start());
+    std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+    EXPECT_TRUE(writer->init(mTestMuxer, mTestCallbacks));
+    EXPECT_FALSE(writer->start());
     EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::NoEvent);
 }
 
 TEST_F(MediaSampleWriterTests, TestAddInvalidTrack) {
-    MediaSampleWriter writer{};
-    EXPECT_TRUE(writer.init(mTestMuxer, mTestCallbacks));
+    std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+    EXPECT_TRUE(writer->init(mTestMuxer, mTestCallbacks));
 
-    EXPECT_FALSE(writer.addTrack(mSampleQueue, nullptr));
-    EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::NoEvent);
-
-    const TestMediaSource& mediaSource = getMediaSource();
-    EXPECT_FALSE(writer.addTrack(nullptr, mediaSource.mTrackFormats[0]));
+    EXPECT_EQ(writer->addTrack(nullptr), nullptr);
     EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::NoEvent);
 }
 
 TEST_F(MediaSampleWriterTests, TestDoubleStartStop) {
-    MediaSampleWriter writer{};
+    std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
 
     std::shared_ptr<TestCallbacks> callbacks =
             std::make_shared<TestCallbacks>(false /* expectSuccess */);
-    EXPECT_TRUE(writer.init(mTestMuxer, callbacks));
+    EXPECT_TRUE(writer->init(mTestMuxer, callbacks));
 
     const TestMediaSource& mediaSource = getMediaSource();
-    EXPECT_TRUE(writer.addTrack(mSampleQueue, mediaSource.mTrackFormats[0]));
+    EXPECT_NE(writer->addTrack(mediaSource.mTrackFormats[0]), nullptr);
     EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::AddTrack(mediaSource.mTrackFormats[0].get()));
 
-    ASSERT_TRUE(writer.start());
-    EXPECT_FALSE(writer.start());
+    ASSERT_TRUE(writer->start());
+    EXPECT_FALSE(writer->start());
 
-    EXPECT_TRUE(writer.stop());
+    EXPECT_TRUE(writer->stop());
     EXPECT_TRUE(callbacks->hasFinished());
-    EXPECT_FALSE(writer.stop());
+    EXPECT_FALSE(writer->stop());
 }
 
 TEST_F(MediaSampleWriterTests, TestStopWithoutStart) {
-    MediaSampleWriter writer{};
-    EXPECT_TRUE(writer.init(mTestMuxer, mTestCallbacks));
+    std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+    EXPECT_TRUE(writer->init(mTestMuxer, mTestCallbacks));
 
     const TestMediaSource& mediaSource = getMediaSource();
-    EXPECT_TRUE(writer.addTrack(mSampleQueue, mediaSource.mTrackFormats[0]));
+    EXPECT_NE(writer->addTrack(mediaSource.mTrackFormats[0]), nullptr);
     EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::AddTrack(mediaSource.mTrackFormats[0].get()));
 
-    EXPECT_FALSE(writer.stop());
+    EXPECT_FALSE(writer->stop());
     EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::NoEvent);
 }
 
 TEST_F(MediaSampleWriterTests, TestStartWithoutCallback) {
-    MediaSampleWriter writer{};
+    std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
 
     std::weak_ptr<MediaSampleWriter::CallbackInterface> unassignedWp;
-    EXPECT_FALSE(writer.init(mTestMuxer, unassignedWp));
+    EXPECT_FALSE(writer->init(mTestMuxer, unassignedWp));
 
     std::shared_ptr<MediaSampleWriter::CallbackInterface> unassignedSp;
-    EXPECT_FALSE(writer.init(mTestMuxer, unassignedSp));
+    EXPECT_FALSE(writer->init(mTestMuxer, unassignedSp));
 
     const TestMediaSource& mediaSource = getMediaSource();
-    EXPECT_FALSE(writer.addTrack(mSampleQueue, mediaSource.mTrackFormats[0]));
-    ASSERT_FALSE(writer.start());
+    EXPECT_EQ(writer->addTrack(mediaSource.mTrackFormats[0]), nullptr);
+    ASSERT_FALSE(writer->start());
 }
 
 TEST_F(MediaSampleWriterTests, TestProgressUpdate) {
     const TestMediaSource& mediaSource = getMediaSource();
 
-    MediaSampleWriter writer{};
-    EXPECT_TRUE(writer.init(mTestMuxer, mTestCallbacks));
+    std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+    EXPECT_TRUE(writer->init(mTestMuxer, mTestCallbacks));
 
     std::shared_ptr<AMediaFormat> videoFormat =
             std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
@@ -377,42 +370,41 @@
                       mediaSource.mTrackFormats[mediaSource.mVideoTrackIndex].get());
 
     AMediaFormat_setInt64(videoFormat.get(), AMEDIAFORMAT_KEY_DURATION, 100);
-    EXPECT_TRUE(writer.addTrack(mSampleQueue, videoFormat));
-    ASSERT_TRUE(writer.start());
+    auto sampleConsumer = writer->addTrack(videoFormat);
+    EXPECT_NE(sampleConsumer, nullptr);
+    ASSERT_TRUE(writer->start());
 
     for (int64_t pts = 0; pts < 100; ++pts) {
-        mSampleQueue->enqueue(newSampleWithPts(pts));
+        sampleConsumer(newSampleWithPts(pts));
     }
-    mSampleQueue->enqueue(newSampleEos());
+    sampleConsumer(newSampleEos());
     mTestCallbacks->waitForWritingFinished();
 
     EXPECT_EQ(mTestCallbacks->getProgressUpdateCount(), 100);
 }
 
 TEST_F(MediaSampleWriterTests, TestInterleaving) {
-    MediaSampleWriter writer{};
-    EXPECT_TRUE(writer.init(mTestMuxer, mTestCallbacks));
+    std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+    EXPECT_TRUE(writer->init(mTestMuxer, mTestCallbacks));
 
     // Use two tracks for this test.
     static constexpr int kNumTracks = 2;
-    std::shared_ptr<MediaSampleQueue> sampleQueues[kNumTracks];
-    std::vector<std::pair<std::shared_ptr<MediaSample>, size_t>> interleavedSamples;
+    MediaSampleWriter::MediaSampleConsumerFunction sampleConsumers[kNumTracks];
+    std::vector<std::pair<std::shared_ptr<MediaSample>, size_t>> addedSamples;
     const TestMediaSource& mediaSource = getMediaSource();
 
     for (int trackIdx = 0; trackIdx < kNumTracks; ++trackIdx) {
-        sampleQueues[trackIdx] = std::make_shared<MediaSampleQueue>();
-
         auto trackFormat = mediaSource.mTrackFormats[trackIdx % mediaSource.mTrackCount];
-        EXPECT_TRUE(writer.addTrack(sampleQueues[trackIdx], trackFormat));
+        sampleConsumers[trackIdx] = writer->addTrack(trackFormat);
+        EXPECT_NE(sampleConsumers[trackIdx], nullptr);
         EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::AddTrack(trackFormat.get()));
     }
 
     // Create samples in the expected interleaved order for easy verification.
-    auto addSampleToTrackWithPts = [&interleavedSamples, &sampleQueues](int trackIndex,
-                                                                        int64_t pts) {
+    auto addSampleToTrackWithPts = [&addedSamples, &sampleConsumers](int trackIndex, int64_t pts) {
         auto sample = newSampleWithPts(pts);
-        sampleQueues[trackIndex]->enqueue(sample);
-        interleavedSamples.emplace_back(sample, trackIndex);
+        sampleConsumers[trackIndex](sample);
+        addedSamples.emplace_back(sample, trackIndex);
     };
 
     addSampleToTrackWithPts(0, 0);
@@ -431,18 +423,24 @@
     addSampleToTrackWithPts(1, 13);
 
     for (int trackIndex = 0; trackIndex < kNumTracks; ++trackIndex) {
-        sampleQueues[trackIndex]->enqueue(newSampleEos());
+        sampleConsumers[trackIndex](newSampleEos());
     }
 
     // Start the writer.
-    ASSERT_TRUE(writer.start());
+    ASSERT_TRUE(writer->start());
 
     // Wait for writer to complete.
     mTestCallbacks->waitForWritingFinished();
     EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::Start());
 
+    std::sort(addedSamples.begin(), addedSamples.end(),
+              [](const std::pair<std::shared_ptr<MediaSample>, size_t>& left,
+                 const std::pair<std::shared_ptr<MediaSample>, size_t>& right) {
+                  return left.first->info.presentationTimeUs < right.first->info.presentationTimeUs;
+              });
+
     // Verify sample order.
-    for (auto entry : interleavedSamples) {
+    for (auto entry : addedSamples) {
         auto sample = entry.first;
         auto trackIndex = entry.second;
 
@@ -470,162 +468,10 @@
     }
 
     EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::Stop());
-    EXPECT_TRUE(writer.stop());
+    EXPECT_TRUE(writer->stop());
     EXPECT_TRUE(mTestCallbacks->hasFinished());
 }
 
-TEST_F(MediaSampleWriterTests, TestMaxDivergence) {
-    static constexpr uint32_t kMaxDivergenceUs = 10;
-
-    MediaSampleWriter writer{kMaxDivergenceUs};
-    EXPECT_TRUE(writer.init(mTestMuxer, mTestCallbacks));
-
-    // Use two tracks for this test.
-    static constexpr int kNumTracks = 2;
-    std::shared_ptr<MediaSampleQueue> sampleQueues[kNumTracks];
-    const TestMediaSource& mediaSource = getMediaSource();
-
-    for (int trackIdx = 0; trackIdx < kNumTracks; ++trackIdx) {
-        sampleQueues[trackIdx] = std::make_shared<MediaSampleQueue>();
-
-        auto trackFormat = mediaSource.mTrackFormats[trackIdx % mediaSource.mTrackCount];
-        EXPECT_TRUE(writer.addTrack(sampleQueues[trackIdx], trackFormat));
-        EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::AddTrack(trackFormat.get()));
-    }
-
-    ASSERT_TRUE(writer.start());
-    EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::Start());
-
-    // The first samples of each track can be written in any order since the writer does not have
-    // any previous timestamps to compare.
-    sampleQueues[0]->enqueue(newSampleWithPtsOnly(0));
-    sampleQueues[1]->enqueue(newSampleWithPtsOnly(1));
-    mTestMuxer->popEvent(true);
-    mTestMuxer->popEvent(true);
-
-    // The writer will now be waiting on track 0 since it has the lowest previous timestamp.
-    sampleQueues[0]->enqueue(newSampleWithPtsOnly(kMaxDivergenceUs + 1));
-    sampleQueues[0]->enqueue(newSampleWithPtsOnly(kMaxDivergenceUs + 2));
-
-    // The writer should dequeue the first sample above but not the second since track 0 now is too
-    // far ahead. Instead it should wait for track 1.
-    EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::WriteSampleWithPts(0, kMaxDivergenceUs + 1));
-
-    // Enqueue a sample from track 1 that puts it within acceptable divergence range again. The
-    // writer should dequeue that sample and then go back to track 0 since track 1 is empty.
-    sampleQueues[1]->enqueue(newSampleWithPtsOnly(kMaxDivergenceUs));
-    EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::WriteSampleWithPts(1, kMaxDivergenceUs));
-    EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::WriteSampleWithPts(0, kMaxDivergenceUs + 2));
-
-    // Both tracks are now empty so the writer should wait for track 1 which is farthest behind.
-    sampleQueues[1]->enqueue(newSampleWithPtsOnly(kMaxDivergenceUs + 3));
-    EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::WriteSampleWithPts(1, kMaxDivergenceUs + 3));
-
-    for (int trackIndex = 0; trackIndex < kNumTracks; ++trackIndex) {
-        sampleQueues[trackIndex]->enqueue(newSampleEos());
-    }
-
-    // Wait for writer to complete.
-    mTestCallbacks->waitForWritingFinished();
-
-    // Verify EOS samples.
-    for (int trackIndex = 0; trackIndex < kNumTracks; ++trackIndex) {
-        auto trackFormat = mediaSource.mTrackFormats[trackIndex % mediaSource.mTrackCount];
-        int64_t duration = 0;
-        AMediaFormat_getInt64(trackFormat.get(), AMEDIAFORMAT_KEY_DURATION, &duration);
-
-        // EOS timestamp = first sample timestamp + duration.
-        const int64_t endTime = duration + (trackIndex == 1 ? 1 : 0);
-        const AMediaCodecBufferInfo info = {0, 0, endTime, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM};
-        EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::WriteSample(trackIndex, nullptr, &info));
-    }
-
-    EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::Stop());
-    EXPECT_TRUE(writer.stop());
-    EXPECT_TRUE(mTestCallbacks->hasFinished());
-}
-
-TEST_F(MediaSampleWriterTests, TestTimestampDivergenceOverflow) {
-    auto testCallbacks = std::make_shared<TestCallbacks>(false /* expectSuccess */);
-    MediaSampleWriter writer{};
-    EXPECT_TRUE(writer.init(mTestMuxer, testCallbacks));
-
-    // Use two tracks for this test.
-    static constexpr int kNumTracks = 2;
-    std::shared_ptr<MediaSampleQueue> sampleQueues[kNumTracks];
-    const TestMediaSource& mediaSource = getMediaSource();
-
-    for (int trackIdx = 0; trackIdx < kNumTracks; ++trackIdx) {
-        sampleQueues[trackIdx] = std::make_shared<MediaSampleQueue>();
-
-        auto trackFormat = mediaSource.mTrackFormats[trackIdx % mediaSource.mTrackCount];
-        EXPECT_TRUE(writer.addTrack(sampleQueues[trackIdx], trackFormat));
-        EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::AddTrack(trackFormat.get()));
-    }
-
-    // Prime track 0 with lower end of INT64 range, and track 1 with positive timestamps making the
-    // difference larger than INT64_MAX.
-    sampleQueues[0]->enqueue(newSampleWithPtsOnly(INT64_MIN + 1));
-    sampleQueues[1]->enqueue(newSampleWithPtsOnly(1000));
-    sampleQueues[1]->enqueue(newSampleWithPtsOnly(1001));
-
-    ASSERT_TRUE(writer.start());
-    EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::Start());
-
-    // The first sample of each track can be pulled in any order.
-    mTestMuxer->popEvent(true);
-    mTestMuxer->popEvent(true);
-
-    // Wait to make sure the writer compares track 0 empty against track 1 non-empty. The writer
-    // should handle the large timestamp differences and chose to wait for track 0 even though
-    // track 1 has a sample ready.
-    std::this_thread::sleep_for(std::chrono::milliseconds(20));
-
-    sampleQueues[0]->enqueue(newSampleWithPtsOnly(INT64_MIN + 2));
-    sampleQueues[0]->enqueue(newSampleWithPtsOnly(1000));  // <-- Close the gap between the tracks.
-    EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::WriteSampleWithPts(0, INT64_MIN + 2));
-    EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::WriteSampleWithPts(0, 1000));
-    EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::WriteSampleWithPts(1, 1001));
-
-    EXPECT_TRUE(writer.stop());
-    EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::Stop());
-    EXPECT_TRUE(testCallbacks->hasFinished());
-}
-
-TEST_F(MediaSampleWriterTests, TestAbortInputQueue) {
-    MediaSampleWriter writer{};
-    std::shared_ptr<TestCallbacks> callbacks =
-            std::make_shared<TestCallbacks>(false /* expectSuccess */);
-    EXPECT_TRUE(writer.init(mTestMuxer, callbacks));
-
-    // Use two tracks for this test.
-    static constexpr int kNumTracks = 2;
-    std::shared_ptr<MediaSampleQueue> sampleQueues[kNumTracks];
-    const TestMediaSource& mediaSource = getMediaSource();
-
-    for (int trackIdx = 0; trackIdx < kNumTracks; ++trackIdx) {
-        sampleQueues[trackIdx] = std::make_shared<MediaSampleQueue>();
-
-        auto trackFormat = mediaSource.mTrackFormats[trackIdx % mediaSource.mTrackCount];
-        EXPECT_TRUE(writer.addTrack(sampleQueues[trackIdx], trackFormat));
-        EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::AddTrack(trackFormat.get()));
-    }
-
-    // Start the writer.
-    ASSERT_TRUE(writer.start());
-
-    // Abort the input queues and wait for the writer to complete.
-    for (int trackIdx = 0; trackIdx < kNumTracks; ++trackIdx) {
-        sampleQueues[trackIdx]->abort();
-    }
-
-    callbacks->waitForWritingFinished();
-
-    EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::Start());
-    EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::Stop());
-    EXPECT_TRUE(writer.stop());
-}
-
 // Convenience function for reading a sample from an AMediaExtractor represented as a MediaSample.
 static std::shared_ptr<MediaSample> readSampleAndAdvance(AMediaExtractor* extractor,
                                                          size_t* trackIndexOut) {
@@ -667,36 +513,35 @@
     ASSERT_GT(destinationFd, 0);
 
     // Initialize writer.
-    MediaSampleWriter writer{};
-    EXPECT_TRUE(writer.init(destinationFd, mTestCallbacks));
+    std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+    EXPECT_TRUE(writer->init(destinationFd, mTestCallbacks));
     close(destinationFd);
 
     // Add tracks.
     const TestMediaSource& mediaSource = getMediaSource();
-    std::vector<std::shared_ptr<MediaSampleQueue>> inputQueues;
+    std::vector<MediaSampleWriter::MediaSampleConsumerFunction> sampleConsumers;
 
     for (size_t trackIndex = 0; trackIndex < mediaSource.mTrackCount; trackIndex++) {
-        inputQueues.push_back(std::make_shared<MediaSampleQueue>());
-        EXPECT_TRUE(
-                writer.addTrack(inputQueues[trackIndex], mediaSource.mTrackFormats[trackIndex]));
+        auto consumer = writer->addTrack(mediaSource.mTrackFormats[trackIndex]);
+        sampleConsumers.push_back(consumer);
     }
 
     // Start the writer.
-    ASSERT_TRUE(writer.start());
+    ASSERT_TRUE(writer->start());
 
     // Enqueue samples and finally End Of Stream.
     std::shared_ptr<MediaSample> sample;
     size_t trackIndex;
     while ((sample = readSampleAndAdvance(mediaSource.mExtractor, &trackIndex)) != nullptr) {
-        inputQueues[trackIndex]->enqueue(sample);
+        sampleConsumers[trackIndex](sample);
     }
     for (trackIndex = 0; trackIndex < mediaSource.mTrackCount; trackIndex++) {
-        inputQueues[trackIndex]->enqueue(newSampleEos());
+        sampleConsumers[trackIndex](newSampleEos());
     }
 
     // Wait for writer.
     mTestCallbacks->waitForWritingFinished();
-    EXPECT_TRUE(writer.stop());
+    EXPECT_TRUE(writer->stop());
 
     // Compare output file with source.
     mediaSource.reset();
diff --git a/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
index a46c2bd..83f0a4a 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
@@ -60,7 +60,6 @@
             break;
         }
         ASSERT_NE(mTranscoder, nullptr);
-        mTranscoderOutputQueue = mTranscoder->getOutputQueue();
 
         initSampleReader();
     }
@@ -115,34 +114,29 @@
     }
 
     // Drains the transcoder's output queue in a loop.
-    void drainOutputSampleQueue() {
-        mSampleQueueDrainThread = std::thread{[this] {
-            std::shared_ptr<MediaSample> sample;
-            bool aborted = false;
-            do {
-                aborted = mTranscoderOutputQueue->dequeue(&sample);
-            } while (!aborted && !(sample->info.flags & SAMPLE_FLAG_END_OF_STREAM));
-            mQueueWasAborted = aborted;
-            mGotEndOfStream =
-                    sample != nullptr && (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) != 0;
-        }};
+    void drainOutputSamples(int numSamplesToSave = 0) {
+        mTranscoder->setSampleConsumer(
+                [this, numSamplesToSave](const std::shared_ptr<MediaSample>& sample) {
+                    ASSERT_NE(sample, nullptr);
+
+                    mGotEndOfStream = (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) != 0;
+
+                    if (mSavedSamples.size() < numSamplesToSave) {
+                        mSavedSamples.push_back(sample);
+                    }
+
+                    if (mSavedSamples.size() == numSamplesToSave || mGotEndOfStream) {
+                        mSamplesSavedSemaphore.signal();
+                    }
+                });
     }
 
-    void joinDrainThread() {
-        if (mSampleQueueDrainThread.joinable()) {
-            mSampleQueueDrainThread.join();
-        }
-    }
-    void TearDown() override {
-        LOG(DEBUG) << "MediaTrackTranscoderTests tear down";
-        joinDrainThread();
-    }
+    void TearDown() override { LOG(DEBUG) << "MediaTrackTranscoderTests tear down"; }
 
     ~MediaTrackTranscoderTests() { LOG(DEBUG) << "MediaTrackTranscoderTests destroyed"; }
 
 protected:
     std::shared_ptr<MediaTrackTranscoder> mTranscoder;
-    std::shared_ptr<MediaSampleQueue> mTranscoderOutputQueue;
     std::shared_ptr<TestCallback> mCallback;
 
     std::shared_ptr<MediaSampleReader> mMediaSampleReader;
@@ -151,8 +145,8 @@
     std::shared_ptr<AMediaFormat> mSourceFormat;
     std::shared_ptr<AMediaFormat> mDestinationFormat;
 
-    std::thread mSampleQueueDrainThread;
-    bool mQueueWasAborted = false;
+    std::vector<std::shared_ptr<MediaSample>> mSavedSamples;
+    OneShotSemaphore mSamplesSavedSemaphore;
     bool mGotEndOfStream = false;
 };
 
@@ -161,11 +155,9 @@
     EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
               AMEDIA_OK);
     ASSERT_TRUE(mTranscoder->start());
-    drainOutputSampleQueue();
+    drainOutputSamples();
     EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
-    joinDrainThread();
     EXPECT_TRUE(mTranscoder->stop());
-    EXPECT_FALSE(mQueueWasAborted);
     EXPECT_TRUE(mGotEndOfStream);
 }
 
@@ -229,49 +221,27 @@
     EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
               AMEDIA_OK);
     ASSERT_TRUE(mTranscoder->start());
-    drainOutputSampleQueue();
+    drainOutputSamples();
     EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
-    joinDrainThread();
     EXPECT_TRUE(mTranscoder->stop());
     EXPECT_FALSE(mTranscoder->start());
-    EXPECT_FALSE(mQueueWasAborted);
     EXPECT_TRUE(mGotEndOfStream);
 }
 
-TEST_P(MediaTrackTranscoderTests, AbortOutputQueue) {
-    LOG(DEBUG) << "Testing AbortOutputQueue";
-    EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
-              AMEDIA_OK);
-    ASSERT_TRUE(mTranscoder->start());
-    mTranscoderOutputQueue->abort();
-    drainOutputSampleQueue();
-    EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_ERROR_IO);
-    joinDrainThread();
-    EXPECT_TRUE(mTranscoder->stop());
-    EXPECT_TRUE(mQueueWasAborted);
-    EXPECT_FALSE(mGotEndOfStream);
-}
-
 TEST_P(MediaTrackTranscoderTests, HoldSampleAfterTranscoderRelease) {
     LOG(DEBUG) << "Testing HoldSampleAfterTranscoderRelease";
     EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
               AMEDIA_OK);
     ASSERT_TRUE(mTranscoder->start());
-
-    std::shared_ptr<MediaSample> sample;
-    EXPECT_FALSE(mTranscoderOutputQueue->dequeue(&sample));
-
-    drainOutputSampleQueue();
+    drainOutputSamples(1 /* numSamplesToSave */);
     EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
-    joinDrainThread();
     EXPECT_TRUE(mTranscoder->stop());
-    EXPECT_FALSE(mQueueWasAborted);
     EXPECT_TRUE(mGotEndOfStream);
 
     mTranscoder.reset();
-    mTranscoderOutputQueue.reset();
+
     std::this_thread::sleep_for(std::chrono::milliseconds(20));
-    sample.reset();
+    mSavedSamples.clear();
 }
 
 TEST_P(MediaTrackTranscoderTests, HoldSampleAfterTranscoderStop) {
@@ -279,13 +249,12 @@
     EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
               AMEDIA_OK);
     ASSERT_TRUE(mTranscoder->start());
-
-    std::shared_ptr<MediaSample> sample;
-    EXPECT_FALSE(mTranscoderOutputQueue->dequeue(&sample));
+    drainOutputSamples(1 /* numSamplesToSave */);
+    mSamplesSavedSemaphore.wait();
     EXPECT_TRUE(mTranscoder->stop());
 
     std::this_thread::sleep_for(std::chrono::milliseconds(20));
-    sample.reset();
+    mSavedSamples.clear();
 }
 
 TEST_P(MediaTrackTranscoderTests, NullSampleReader) {
diff --git a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
index 53bd2a2..7a968eb 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
@@ -20,6 +20,7 @@
 #define LOG_TAG "MediaTranscoderTests"
 
 #include <android-base/logging.h>
+#include <android/binder_process.h>
 #include <fcntl.h>
 #include <gtest/gtest.h>
 #include <media/MediaSampleReaderNDK.h>
@@ -72,7 +73,13 @@
     }
 
     virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused,
-                                  int32_t progress __unused) override {}
+                                  int32_t progress) override {
+        std::unique_lock<std::mutex> lock(mMutex);
+        if (progress > 0 && !mProgressMade) {
+            mProgressMade = true;
+            mCondition.notify_all();
+        }
+    }
 
     virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
                                      const std::shared_ptr<const Parcel>& pausedState
@@ -85,12 +92,19 @@
         }
     }
 
+    void waitForProgressMade() {
+        std::unique_lock<std::mutex> lock(mMutex);
+        while (!mProgressMade && !mFinished) {
+            mCondition.wait(lock);
+        }
+    }
     media_status_t mStatus = AMEDIA_OK;
 
 private:
     std::mutex mMutex;
     std::condition_variable mCondition;
     bool mFinished = false;
+    bool mProgressMade = false;
 };
 
 // Write-only, create file if non-existent, don't overwrite existing file.
@@ -106,6 +120,7 @@
     void SetUp() override {
         LOG(DEBUG) << "MediaTranscoderTests set up";
         mCallbacks = std::make_shared<TestCallbacks>();
+        ABinderProcess_startThreadPool();
     }
 
     void TearDown() override {
@@ -126,9 +141,16 @@
         return (float)diff * 100.0f / s1.st_size;
     }
 
+    typedef enum {
+        kRunToCompletion,
+        kCancelAfterProgress,
+        kCancelAfterStart,
+    } TranscodeExecutionControl;
+
     using FormatConfigurationCallback = std::function<AMediaFormat*(AMediaFormat*)>;
     media_status_t transcodeHelper(const char* srcPath, const char* destPath,
-                                   FormatConfigurationCallback formatCallback) {
+                                   FormatConfigurationCallback formatCallback,
+                                   TranscodeExecutionControl executionControl = kRunToCompletion) {
         auto transcoder = MediaTranscoder::create(mCallbacks, nullptr);
         EXPECT_NE(transcoder, nullptr);
 
@@ -160,7 +182,18 @@
         media_status_t startStatus = transcoder->start();
         EXPECT_EQ(startStatus, AMEDIA_OK);
         if (startStatus == AMEDIA_OK) {
-            mCallbacks->waitForTranscodingFinished();
+            switch (executionControl) {
+            case kCancelAfterProgress:
+                mCallbacks->waitForProgressMade();
+                FALLTHROUGH_INTENDED;
+            case kCancelAfterStart:
+                transcoder->cancel();
+                break;
+            case kRunToCompletion:
+            default:
+                mCallbacks->waitForTranscodingFinished();
+                break;
+            }
         }
         close(srcFd);
         close(dstFd);
@@ -310,6 +343,41 @@
     EXPECT_GT(getFileSizeDiffPercent(destPath1, destPath2), 40);
 }
 
+static AMediaFormat* getAVCVideoFormat(AMediaFormat* sourceFormat) {
+    AMediaFormat* format = nullptr;
+    const char* mime = nullptr;
+    AMediaFormat_getString(sourceFormat, AMEDIAFORMAT_KEY_MIME, &mime);
+
+    if (strncmp(mime, "video/", 6) == 0) {
+        format = AMediaFormat_new();
+        AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
+    }
+
+    return format;
+}
+
+TEST_F(MediaTranscoderTests, TestCancelAfterProgress) {
+    const char* srcPath = "/data/local/tmp/TranscodingTestAssets/longtest_15s.mp4";
+    const char* destPath = "/data/local/tmp/MediaTranscoder_Cancel.MP4";
+
+    for (int i = 0; i < 32; ++i) {
+        EXPECT_EQ(transcodeHelper(srcPath, destPath, getAVCVideoFormat, kCancelAfterProgress),
+                  AMEDIA_OK);
+        mCallbacks = std::make_shared<TestCallbacks>();
+    }
+}
+
+TEST_F(MediaTranscoderTests, TestCancelAfterStart) {
+    const char* srcPath = "/data/local/tmp/TranscodingTestAssets/longtest_15s.mp4";
+    const char* destPath = "/data/local/tmp/MediaTranscoder_Cancel.MP4";
+
+    for (int i = 0; i < 32; ++i) {
+        EXPECT_EQ(transcodeHelper(srcPath, destPath, getAVCVideoFormat, kCancelAfterStart),
+                  AMEDIA_OK);
+        mCallbacks = std::make_shared<TestCallbacks>();
+    }
+}
+
 }  // namespace android
 
 int main(int argc, char** argv) {
diff --git a/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
index a2ffbe4..9713e17 100644
--- a/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
@@ -165,21 +165,23 @@
     ASSERT_TRUE(transcoder.start());
 
     // Pull transcoder's output samples and compare against input checksums.
+    bool eos = false;
     uint64_t sampleCount = 0;
-    std::shared_ptr<MediaSample> sample;
-    std::shared_ptr<MediaSampleQueue> outputQueue = transcoder.getOutputQueue();
-    while (!outputQueue->dequeue(&sample)) {
-        ASSERT_NE(sample, nullptr);
+    transcoder.setSampleConsumer(
+            [&sampleCount, &sampleChecksums, &eos](const std::shared_ptr<MediaSample>& sample) {
+                ASSERT_NE(sample, nullptr);
+                EXPECT_FALSE(eos);
 
-        if (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
-            break;
-        }
+                if (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
+                    eos = true;
+                } else {
+                    SampleID sampleId{sample->buffer, static_cast<ssize_t>(sample->info.size)};
+                    EXPECT_TRUE(sampleId == sampleChecksums[sampleCount]);
+                    ++sampleCount;
+                }
+            });
 
-        SampleID sampleId{sample->buffer, static_cast<ssize_t>(sample->info.size)};
-        EXPECT_TRUE(sampleId == sampleChecksums[sampleCount]);
-        ++sampleCount;
-    }
-
+    callback->waitUntilFinished();
     EXPECT_EQ(sampleCount, sampleChecksums.size());
     EXPECT_TRUE(transcoder.stop());
 }
diff --git a/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h b/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
index a3ddd71..8d05353 100644
--- a/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
+++ b/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
@@ -102,4 +102,25 @@
     bool mTrackFormatAvailable = false;
 };
 
+class OneShotSemaphore {
+public:
+    void wait() {
+        std::unique_lock<std::mutex> lock(mMutex);
+        while (!mSignaled) {
+            mCondition.wait(lock);
+        }
+    }
+
+    void signal() {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mSignaled = true;
+        mCondition.notify_all();
+    }
+
+private:
+    std::mutex mMutex;
+    std::condition_variable mCondition;
+    bool mSignaled = false;
+};
+
 };  // namespace android
diff --git a/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
index e809cbd..1b5bd13 100644
--- a/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
@@ -102,46 +102,40 @@
               AMEDIA_OK);
     ASSERT_TRUE(transcoder->start());
 
-    std::shared_ptr<MediaSampleQueue> outputQueue = transcoder->getOutputQueue();
-    std::thread sampleConsumerThread{[&outputQueue] {
-        uint64_t sampleCount = 0;
-        std::shared_ptr<MediaSample> sample;
-        while (!outputQueue->dequeue(&sample)) {
-            ASSERT_NE(sample, nullptr);
-            const uint32_t flags = sample->info.flags;
+    bool eos = false;
+    uint64_t sampleCount = 0;
+    transcoder->setSampleConsumer([&sampleCount, &eos](const std::shared_ptr<MediaSample>& sample) {
+        ASSERT_NE(sample, nullptr);
+        const uint32_t flags = sample->info.flags;
 
-            if (sampleCount == 0) {
-                // Expect first sample to be a codec config.
-                EXPECT_TRUE((flags & SAMPLE_FLAG_CODEC_CONFIG) != 0);
-                EXPECT_TRUE((flags & SAMPLE_FLAG_SYNC_SAMPLE) == 0);
-                EXPECT_TRUE((flags & SAMPLE_FLAG_END_OF_STREAM) == 0);
-                EXPECT_TRUE((flags & SAMPLE_FLAG_PARTIAL_FRAME) == 0);
-            } else if (sampleCount == 1) {
-                // Expect second sample to be a sync sample.
-                EXPECT_TRUE((flags & SAMPLE_FLAG_CODEC_CONFIG) == 0);
-                EXPECT_TRUE((flags & SAMPLE_FLAG_SYNC_SAMPLE) != 0);
-                EXPECT_TRUE((flags & SAMPLE_FLAG_END_OF_STREAM) == 0);
-            }
-
-            if (!(flags & SAMPLE_FLAG_END_OF_STREAM)) {
-                // Expect a valid buffer unless it is EOS.
-                EXPECT_NE(sample->buffer, nullptr);
-                EXPECT_NE(sample->bufferId, 0xBAADF00D);
-                EXPECT_GT(sample->info.size, 0);
-            }
-
-            ++sampleCount;
-            if (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
-                break;
-            }
-            sample.reset();
+        if (sampleCount == 0) {
+            // Expect first sample to be a codec config.
+            EXPECT_TRUE((flags & SAMPLE_FLAG_CODEC_CONFIG) != 0);
+            EXPECT_TRUE((flags & SAMPLE_FLAG_SYNC_SAMPLE) == 0);
+            EXPECT_TRUE((flags & SAMPLE_FLAG_END_OF_STREAM) == 0);
+            EXPECT_TRUE((flags & SAMPLE_FLAG_PARTIAL_FRAME) == 0);
+        } else if (sampleCount == 1) {
+            // Expect second sample to be a sync sample.
+            EXPECT_TRUE((flags & SAMPLE_FLAG_CODEC_CONFIG) == 0);
+            EXPECT_TRUE((flags & SAMPLE_FLAG_SYNC_SAMPLE) != 0);
+            EXPECT_TRUE((flags & SAMPLE_FLAG_END_OF_STREAM) == 0);
         }
-    }};
+
+        if (!(flags & SAMPLE_FLAG_END_OF_STREAM)) {
+            // Expect a valid buffer unless it is EOS.
+            EXPECT_NE(sample->buffer, nullptr);
+            EXPECT_NE(sample->bufferId, 0xBAADF00D);
+            EXPECT_GT(sample->info.size, 0);
+        } else {
+            EXPECT_FALSE(eos);
+            eos = true;
+        }
+
+        ++sampleCount;
+    });
 
     EXPECT_EQ(callback->waitUntilFinished(), AMEDIA_OK);
     EXPECT_TRUE(transcoder->stop());
-
-    sampleConsumerThread.join();
 }
 
 TEST_F(VideoTrackTranscoderTests, PreserveBitrate) {
@@ -167,7 +161,6 @@
     ASSERT_NE(outputFormat, nullptr);
 
     ASSERT_TRUE(transcoder->stop());
-    transcoder->getOutputQueue()->abort();
 
     int32_t outBitrate;
     EXPECT_TRUE(AMediaFormat_getInt32(outputFormat.get(), AMEDIAFORMAT_KEY_BIT_RATE, &outBitrate));
@@ -187,25 +180,7 @@
 }
 
 TEST_F(VideoTrackTranscoderTests, LingeringEncoder) {
-    struct {
-        void wait() {
-            std::unique_lock<std::mutex> lock(mMutex);
-            while (!mSignaled) {
-                mCondition.wait(lock);
-            }
-        }
-
-        void signal() {
-            std::unique_lock<std::mutex> lock(mMutex);
-            mSignaled = true;
-            mCondition.notify_all();
-        }
-
-        std::mutex mMutex;
-        std::condition_variable mCondition;
-        bool mSignaled = false;
-    } semaphore;
-
+    OneShotSemaphore semaphore;
     auto callback = std::make_shared<TestCallback>();
     auto transcoder = VideoTrackTranscoder::create(callback);
 
@@ -214,29 +189,24 @@
               AMEDIA_OK);
     ASSERT_TRUE(transcoder->start());
 
-    std::shared_ptr<MediaSampleQueue> outputQueue = transcoder->getOutputQueue();
     std::vector<std::shared_ptr<MediaSample>> samples;
-    std::thread sampleConsumerThread([&outputQueue, &samples, &semaphore] {
-        std::shared_ptr<MediaSample> sample;
-        while (samples.size() < 4 && !outputQueue->dequeue(&sample)) {
-            ASSERT_NE(sample, nullptr);
-            samples.push_back(sample);
+    transcoder->setSampleConsumer(
+            [&samples, &semaphore](const std::shared_ptr<MediaSample>& sample) {
+                if (samples.size() >= 4) return;
 
-            if (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
-                break;
-            }
-            sample.reset();
-        }
+                ASSERT_NE(sample, nullptr);
+                samples.push_back(sample);
 
-        semaphore.signal();
-    });
+                if (samples.size() == 4 || sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
+                    semaphore.signal();
+                }
+            });
 
     // Wait for the encoder to output samples before stopping and releasing the transcoder.
     semaphore.wait();
 
     EXPECT_TRUE(transcoder->stop());
     transcoder.reset();
-    sampleConsumerThread.join();
 
     // Return buffers to the codec so that it can resume processing, but keep one buffer to avoid
     // the codec being released.
diff --git a/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh b/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
index 241178d..b848b4c 100755
--- a/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
+++ b/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
@@ -25,22 +25,22 @@
 echo "========================================"
 
 echo "testing MediaSampleReaderNDK"
-adb shell /data/nativetest64/MediaSampleReaderNDKTests/MediaSampleReaderNDKTests
+adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/MediaSampleReaderNDKTests/MediaSampleReaderNDKTests
 
 echo "testing MediaSampleQueue"
-adb shell /data/nativetest64/MediaSampleQueueTests/MediaSampleQueueTests
+adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/MediaSampleQueueTests/MediaSampleQueueTests
 
 echo "testing MediaTrackTranscoder"
-adb shell /data/nativetest64/MediaTrackTranscoderTests/MediaTrackTranscoderTests
+adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/MediaTrackTranscoderTests/MediaTrackTranscoderTests
 
 echo "testing VideoTrackTranscoder"
-adb shell /data/nativetest64/VideoTrackTranscoderTests/VideoTrackTranscoderTests
+adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/VideoTrackTranscoderTests/VideoTrackTranscoderTests
 
 echo "testing PassthroughTrackTranscoder"
-adb shell /data/nativetest64/PassthroughTrackTranscoderTests/PassthroughTrackTranscoderTests
+adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/PassthroughTrackTranscoderTests/PassthroughTrackTranscoderTests
 
 echo "testing MediaSampleWriter"
-adb shell /data/nativetest64/MediaSampleWriterTests/MediaSampleWriterTests
+adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/MediaSampleWriterTests/MediaSampleWriterTests
 
 echo "testing MediaTranscoder"
-adb shell /data/nativetest64/MediaTranscoderTests/MediaTranscoderTests
+adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/MediaTranscoderTests/MediaTranscoderTests
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 382491e..8fd9dfc 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -279,6 +279,13 @@
 
     void postFillThisBuffer(BufferInfo *info);
 
+    void maybePostExtraOutputMetadataBufferRequest() {
+        if (!mPendingExtraOutputMetadataBufferRequest) {
+            (new AMessage(kWhatSubmitExtraOutputMetadataBuffer, mCodec))->post();
+            mPendingExtraOutputMetadataBufferRequest = true;
+        }
+    }
+
 private:
     // Handles an OMX message. Returns true iff message was handled.
     bool onOMXMessage(const sp<AMessage> &msg);
@@ -302,6 +309,8 @@
 
     void getMoreInputDataIfPossible();
 
+    bool mPendingExtraOutputMetadataBufferRequest;
+
     DISALLOW_EVIL_CONSTRUCTORS(BaseState);
 };
 
@@ -556,6 +565,7 @@
       mExplicitShutdown(false),
       mIsLegacyVP9Decoder(false),
       mIsStreamCorruptFree(false),
+      mIsLowLatency(false),
       mEncoderDelay(0),
       mEncoderPadding(0),
       mRotationDegrees(0),
@@ -2238,6 +2248,12 @@
             }
             err = setupG711Codec(encoder, sampleRate, numChannels);
         }
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_OPUS)) {
+        int32_t numChannels = 1, sampleRate = 48000;
+        if (msg->findInt32("channel-count", &numChannels) &&
+            msg->findInt32("sample-rate", &sampleRate)) {
+            err = setupOpusCodec(encoder, sampleRate, numChannels);
+        }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
         // numChannels needs to be set to properly communicate PCM values.
         int32_t numChannels = 2, sampleRate = 44100, compressionLevel = -1;
@@ -2416,6 +2432,7 @@
     if (err != OK) {
         ALOGE("decoder can not set low-latency to %d (err %d)", lowLatency, err);
     }
+    mIsLowLatency = (lowLatency && err == OK);
     return err;
 }
 
@@ -3117,6 +3134,26 @@
             kPortIndexInput, sampleRate, numChannels);
 }
 
+status_t ACodec::setupOpusCodec(bool encoder, int32_t sampleRate, int32_t numChannels) {
+    if (encoder) {
+        return INVALID_OPERATION;
+    }
+    OMX_AUDIO_PARAM_ANDROID_OPUSTYPE def;
+    InitOMXParams(&def);
+    def.nPortIndex = kPortIndexInput;
+    status_t err = mOMXNode->getParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidOpus, &def, sizeof(def));
+    if (err != OK) {
+        ALOGE("setupOpusCodec(): Error %d getting OMX_IndexParamAudioAndroidOpus parameter", err);
+        return err;
+    }
+    def.nSampleRate = sampleRate;
+    def.nChannels = numChannels;
+    err = mOMXNode->setParameter(
+           (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidOpus, &def, sizeof(def));
+    return err;
+}
+
 status_t ACodec::setupFlacCodec(
         bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel,
         AudioEncoding encoding) {
@@ -5752,7 +5789,8 @@
 
 ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
     : AState(parentState),
-      mCodec(codec) {
+      mCodec(codec),
+      mPendingExtraOutputMetadataBufferRequest(false) {
 }
 
 ACodec::BaseState::PortMode ACodec::BaseState::getPortMode(
@@ -5853,6 +5891,21 @@
             break;
         }
 
+        case kWhatSubmitExtraOutputMetadataBuffer: {
+            mPendingExtraOutputMetadataBufferRequest = false;
+            if (getPortMode(kPortIndexOutput) == RESUBMIT_BUFFERS && mCodec->mIsLowLatency) {
+                // Decoders often need more than one output buffer to be
+                // submitted before processing a single input buffer.
+                // For low latency codecs, we don't want to wait for more input
+                // to be queued to get those output buffers submitted.
+                if (mCodec->submitOutputMetadataBuffer() == OK
+                        && mCodec->mMetadataBuffersToSubmit > 0) {
+                    maybePostExtraOutputMetadataBufferRequest();
+                }
+            }
+            break;
+        }
+
         default:
             return false;
     }
@@ -6222,7 +6275,12 @@
                             (outputMode == FREE_BUFFERS ? "FREE" :
                              outputMode == KEEP_BUFFERS ? "KEEP" : "RESUBMIT"));
                     if (outputMode == RESUBMIT_BUFFERS) {
-                        mCodec->submitOutputMetadataBuffer();
+                        status_t err = mCodec->submitOutputMetadataBuffer();
+                        if (mCodec->mIsLowLatency
+                                && err == OK
+                                && mCodec->mMetadataBuffersToSubmit > 0) {
+                            maybePostExtraOutputMetadataBufferRequest();
+                        }
                     }
                 }
                 info->checkReadFence("onInputBufferFilled");
@@ -7368,6 +7426,9 @@
                 break;
         }
     }
+    if (mCodec->mIsLowLatency) {
+        maybePostExtraOutputMetadataBufferRequest();
+    }
 
     // *** NOTE: THE FOLLOWING WORKAROUND WILL BE REMOVED ***
     mCodec->signalSubmitOutputMetadataBufferIfEOS_workaround();
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 5015787..a872d33 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -615,7 +615,10 @@
     return new PersistentSurface(bufferProducer, bufferSource);
 }
 
-MediaCodec::MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid)
+MediaCodec::MediaCodec(
+        const sp<ALooper> &looper, pid_t pid, uid_t uid,
+        std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase,
+        std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo)
     : mState(UNINITIALIZED),
       mReleasedByResourceManager(false),
       mLooper(looper),
@@ -640,7 +643,9 @@
       mNumLowLatencyDisables(0),
       mIsLowLatencyModeOn(false),
       mIndexOfFirstFrameWhenLowLatencyOn(-1),
-      mInputBufferCounter(0) {
+      mInputBufferCounter(0),
+      mGetCodecBase(getCodecBase),
+      mGetCodecInfo(getCodecInfo) {
     if (uid == kNoUid) {
         mUid = AIBinder_getCallingUid();
     } else {
@@ -648,6 +653,33 @@
     }
     mResourceManagerProxy = new ResourceManagerServiceProxy(pid, mUid,
             ::ndk::SharedRefBase::make<ResourceManagerClient>(this));
+    if (!mGetCodecBase) {
+        mGetCodecBase = [](const AString &name, const char *owner) {
+            return GetCodecBase(name, owner);
+        };
+    }
+    if (!mGetCodecInfo) {
+        mGetCodecInfo = [](const AString &name, sp<MediaCodecInfo> *info) -> status_t {
+            *info = nullptr;
+            const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
+            if (!mcl) {
+                return NO_INIT;  // if called from Java should raise IOException
+            }
+            AString tmp = name;
+            if (tmp.endsWith(".secure")) {
+                tmp.erase(tmp.size() - 7, 7);
+            }
+            for (const AString &codecName : { name, tmp }) {
+                ssize_t codecIdx = mcl->findCodecByName(codecName.c_str());
+                if (codecIdx < 0) {
+                    continue;
+                }
+                *info = mcl->getCodecInfo(codecIdx);
+                return OK;
+            }
+            return NAME_NOT_FOUND;
+        };
+    }
 
     initMediametrics();
 }
@@ -1009,6 +1041,12 @@
     return err;
 }
 
+void MediaCodec::PostReplyWithError(const sp<AMessage> &msg, int32_t err) {
+    sp<AReplyToken> replyID;
+    CHECK(msg->senderAwaitsResponse(&replyID));
+    PostReplyWithError(replyID, err);
+}
+
 void MediaCodec::PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err) {
     int32_t finalErr = err;
     if (mReleasedByResourceManager) {
@@ -1085,40 +1123,30 @@
     bool secureCodec = false;
     const char *owner = "";
     if (!name.startsWith("android.filter.")) {
-        AString tmp = name;
-        if (tmp.endsWith(".secure")) {
-            secureCodec = true;
-            tmp.erase(tmp.size() - 7, 7);
-        }
-        const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
-        if (mcl == NULL) {
+        status_t err = mGetCodecInfo(name, &mCodecInfo);
+        if (err != OK) {
             mCodec = NULL;  // remove the codec.
-            return NO_INIT; // if called from Java should raise IOException
-        }
-        for (const AString &codecName : { name, tmp }) {
-            ssize_t codecIdx = mcl->findCodecByName(codecName.c_str());
-            if (codecIdx < 0) {
-                continue;
-            }
-            mCodecInfo = mcl->getCodecInfo(codecIdx);
-            Vector<AString> mediaTypes;
-            mCodecInfo->getSupportedMediaTypes(&mediaTypes);
-            for (size_t i = 0; i < mediaTypes.size(); i++) {
-                if (mediaTypes[i].startsWith("video/")) {
-                    mIsVideo = true;
-                    break;
-                }
-            }
-            break;
+            return err;
         }
         if (mCodecInfo == nullptr) {
+            ALOGE("Getting codec info with name '%s' failed", name.c_str());
             return NAME_NOT_FOUND;
         }
+        secureCodec = name.endsWith(".secure");
+        Vector<AString> mediaTypes;
+        mCodecInfo->getSupportedMediaTypes(&mediaTypes);
+        for (size_t i = 0; i < mediaTypes.size(); ++i) {
+            if (mediaTypes[i].startsWith("video/")) {
+                mIsVideo = true;
+                break;
+            }
+        }
         owner = mCodecInfo->getOwnerName();
     }
 
-    mCodec = GetCodecBase(name, owner);
+    mCodec = mGetCodecBase(name, owner);
     if (mCodec == NULL) {
+        ALOGE("Getting codec base with name '%s' (owner='%s') failed", name.c_str(), owner);
         return NAME_NOT_FOUND;
     }
 
@@ -1512,7 +1540,6 @@
     mStickyError = OK;
 
     // reset state not reset by setState(UNINITIALIZED)
-    mReplyID = 0;
     mDequeueInputReplyID = 0;
     mDequeueOutputReplyID = 0;
     mDequeueInputTimeoutGeneration = 0;
@@ -2165,7 +2192,7 @@
                                 if (mState == RELEASING) {
                                     mComponentName.clear();
                                 }
-                                (new AMessage)->postReply(mReplyID);
+                                postPendingRepliesAndDeferredMessages();
                                 sendErrorResponse = false;
                             }
                             break;
@@ -2191,7 +2218,7 @@
                         case FLUSHED:
                         case STARTED:
                         {
-                            sendErrorResponse = false;
+                            sendErrorResponse = (mReplyID != nullptr);
 
                             setStickyError(err);
                             postActivityNotificationIfPossible();
@@ -2221,7 +2248,7 @@
 
                         default:
                         {
-                            sendErrorResponse = false;
+                            sendErrorResponse = (mReplyID != nullptr);
 
                             setStickyError(err);
                             postActivityNotificationIfPossible();
@@ -2248,7 +2275,15 @@
                     }
 
                     if (sendErrorResponse) {
-                        PostReplyWithError(mReplyID, err);
+                        // TRICKY: replicate PostReplyWithError logic for
+                        //         err code override
+                        int32_t finalErr = err;
+                        if (mReleasedByResourceManager) {
+                            // override the err code if MediaCodec has been
+                            // released by ResourceManager.
+                            finalErr = DEAD_OBJECT;
+                        }
+                        postPendingRepliesAndDeferredMessages(finalErr);
                     }
                     break;
                 }
@@ -2296,7 +2331,7 @@
                                 MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
                     }
 
-                    (new AMessage)->postReply(mReplyID);
+                    postPendingRepliesAndDeferredMessages();
                     break;
                 }
 
@@ -2335,7 +2370,7 @@
                         mFlags |= kFlagUsesSoftwareRenderer;
                     }
                     setState(CONFIGURED);
-                    (new AMessage)->postReply(mReplyID);
+                    postPendingRepliesAndDeferredMessages();
 
                     // augment our media metrics info, now that we know more things
                     // such as what the codec extracted from any CSD passed in.
@@ -2380,6 +2415,12 @@
 
                 case kWhatInputSurfaceCreated:
                 {
+                    if (mState != CONFIGURED) {
+                        // state transitioned unexpectedly; we should have replied already.
+                        ALOGD("received kWhatInputSurfaceCreated message in state %s",
+                                stateString(mState).c_str());
+                        break;
+                    }
                     // response to initiateCreateInputSurface()
                     status_t err = NO_ERROR;
                     sp<AMessage> response = new AMessage;
@@ -2398,12 +2439,18 @@
                     } else {
                         response->setInt32("err", err);
                     }
-                    response->postReply(mReplyID);
+                    postPendingRepliesAndDeferredMessages(response);
                     break;
                 }
 
                 case kWhatInputSurfaceAccepted:
                 {
+                    if (mState != CONFIGURED) {
+                        // state transitioned unexpectedly; we should have replied already.
+                        ALOGD("received kWhatInputSurfaceAccepted message in state %s",
+                                stateString(mState).c_str());
+                        break;
+                    }
                     // response to initiateSetInputSurface()
                     status_t err = NO_ERROR;
                     sp<AMessage> response = new AMessage();
@@ -2414,19 +2461,25 @@
                     } else {
                         response->setInt32("err", err);
                     }
-                    response->postReply(mReplyID);
+                    postPendingRepliesAndDeferredMessages(response);
                     break;
                 }
 
                 case kWhatSignaledInputEOS:
                 {
+                    if (!isExecuting()) {
+                        // state transitioned unexpectedly; we should have replied already.
+                        ALOGD("received kWhatSignaledInputEOS message in state %s",
+                                stateString(mState).c_str());
+                        break;
+                    }
                     // response to signalEndOfInputStream()
                     sp<AMessage> response = new AMessage;
                     status_t err;
                     if (msg->findInt32("err", &err)) {
                         response->setInt32("err", err);
                     }
-                    response->postReply(mReplyID);
+                    postPendingRepliesAndDeferredMessages(response);
                     break;
                 }
 
@@ -2446,7 +2499,7 @@
                                 MediaResource::GraphicMemoryResource(getGraphicBufferSize()));
                     }
                     setState(STARTED);
-                    (new AMessage)->postReply(mReplyID);
+                    postPendingRepliesAndDeferredMessages();
                     break;
                 }
 
@@ -2583,7 +2636,7 @@
                         break;
                     }
                     setState(INITIALIZED);
-                    (new AMessage)->postReply(mReplyID);
+                    postPendingRepliesAndDeferredMessages();
                     break;
                 }
 
@@ -2608,7 +2661,7 @@
                     mReleaseSurface.reset();
 
                     if (mReplyID != nullptr) {
-                        (new AMessage)->postReply(mReplyID);
+                        postPendingRepliesAndDeferredMessages();
                     }
                     if (mAsyncReleaseCompleteNotification != nullptr) {
                         flushMediametrics();
@@ -2633,7 +2686,7 @@
                         mCodec->signalResume();
                     }
 
-                    (new AMessage)->postReply(mReplyID);
+                    postPendingRepliesAndDeferredMessages();
                     break;
                 }
 
@@ -2645,14 +2698,18 @@
 
         case kWhatInit:
         {
-            sp<AReplyToken> replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
             if (mState != UNINITIALIZED) {
-                PostReplyWithError(replyID, INVALID_OPERATION);
+                PostReplyWithError(msg, INVALID_OPERATION);
                 break;
             }
 
+            if (mReplyID) {
+                mDeferredMessages.push_back(msg);
+                break;
+            }
+            sp<AReplyToken> replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
             mReplyID = replyID;
             setState(INITIALIZING);
 
@@ -2714,14 +2771,18 @@
 
         case kWhatConfigure:
         {
-            sp<AReplyToken> replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
             if (mState != INITIALIZED) {
-                PostReplyWithError(replyID, INVALID_OPERATION);
+                PostReplyWithError(msg, INVALID_OPERATION);
                 break;
             }
 
+            if (mReplyID) {
+                mDeferredMessages.push_back(msg);
+                break;
+            }
+            sp<AReplyToken> replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
             sp<RefBase> obj;
             CHECK(msg->findObject("surface", &obj));
 
@@ -2859,15 +2920,19 @@
         case kWhatCreateInputSurface:
         case kWhatSetInputSurface:
         {
-            sp<AReplyToken> replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
             // Must be configured, but can't have been started yet.
             if (mState != CONFIGURED) {
-                PostReplyWithError(replyID, INVALID_OPERATION);
+                PostReplyWithError(msg, INVALID_OPERATION);
                 break;
             }
 
+            if (mReplyID) {
+                mDeferredMessages.push_back(msg);
+                break;
+            }
+            sp<AReplyToken> replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
             mReplyID = replyID;
             if (msg->what() == kWhatCreateInputSurface) {
                 mCodec->initiateCreateInputSurface();
@@ -2882,9 +2947,6 @@
         }
         case kWhatStart:
         {
-            sp<AReplyToken> replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
             if (mState == FLUSHED) {
                 setState(STARTED);
                 if (mHavePendingInputBuffers) {
@@ -2892,13 +2954,20 @@
                     mHavePendingInputBuffers = false;
                 }
                 mCodec->signalResume();
-                PostReplyWithError(replyID, OK);
+                PostReplyWithError(msg, OK);
                 break;
             } else if (mState != CONFIGURED) {
-                PostReplyWithError(replyID, INVALID_OPERATION);
+                PostReplyWithError(msg, INVALID_OPERATION);
                 break;
             }
 
+            if (mReplyID) {
+                mDeferredMessages.push_back(msg);
+                break;
+            }
+            sp<AReplyToken> replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
             mReplyID = replyID;
             setState(STARTING);
 
@@ -2906,15 +2975,42 @@
             break;
         }
 
-        case kWhatStop:
+        case kWhatStop: {
+            if (mReplyID) {
+                mDeferredMessages.push_back(msg);
+                break;
+            }
+            [[fallthrough]];
+        }
         case kWhatRelease:
         {
             State targetState =
                 (msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED;
 
+            if ((mState == RELEASING && targetState == UNINITIALIZED)
+                    || (mState == STOPPING && targetState == INITIALIZED)) {
+                mDeferredMessages.push_back(msg);
+                break;
+            }
+
             sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
+            sp<AMessage> asyncNotify;
+            (void)msg->findMessage("async", &asyncNotify);
+            // post asyncNotify if going out of scope.
+            struct AsyncNotifyPost {
+                AsyncNotifyPost(const sp<AMessage> &asyncNotify) : mAsyncNotify(asyncNotify) {}
+                ~AsyncNotifyPost() {
+                    if (mAsyncNotify) {
+                        mAsyncNotify->post();
+                    }
+                }
+                void clear() { mAsyncNotify.clear(); }
+            private:
+                sp<AMessage> mAsyncNotify;
+            } asyncNotifyPost{asyncNotify};
+
             // already stopped/released
             if (mState == UNINITIALIZED && mReleasedByResourceManager) {
                 sp<AMessage> response = new AMessage;
@@ -2926,7 +3022,13 @@
             int32_t reclaimed = 0;
             msg->findInt32("reclaimed", &reclaimed);
             if (reclaimed) {
-                mReleasedByResourceManager = true;
+                if (!mReleasedByResourceManager) {
+                    // notify the async client
+                    if (mFlags & kFlagIsAsync) {
+                        onError(DEAD_OBJECT, ACTION_CODE_FATAL);
+                    }
+                    mReleasedByResourceManager = true;
+                }
 
                 int32_t force = 0;
                 msg->findInt32("force", &force);
@@ -2938,10 +3040,6 @@
                     response->setInt32("err", WOULD_BLOCK);
                     response->postReply(replyID);
 
-                    // notify the async client
-                    if (mFlags & kFlagIsAsync) {
-                        onError(DEAD_OBJECT, ACTION_CODE_FATAL);
-                    }
                     break;
                 }
             }
@@ -2978,12 +3076,14 @@
             // after this, and we'll no longer be able to reply.
             if (mState == FLUSHING || mState == STOPPING
                     || mState == CONFIGURING || mState == STARTING) {
-                (new AMessage)->postReply(mReplyID);
+                // mReply is always set if in these states.
+                postPendingRepliesAndDeferredMessages();
             }
 
             if (mFlags & kFlagSawMediaServerDie) {
                 // It's dead, Jim. Don't expect initiateShutdown to yield
                 // any useful results now...
+                // Any pending reply would have been handled at kWhatError.
                 setState(UNINITIALIZED);
                 if (targetState == UNINITIALIZED) {
                     mComponentName.clear();
@@ -2997,12 +3097,12 @@
             // reply now with an error to unblock the client, client can
             // release after the failure (instead of ANR).
             if (msg->what() == kWhatStop && (mFlags & kFlagStickyError)) {
+                // Any pending reply would have been handled at kWhatError.
                 PostReplyWithError(replyID, getStickyError());
                 break;
             }
 
-            sp<AMessage> asyncNotify;
-            if (msg->findMessage("async", &asyncNotify) && asyncNotify != nullptr) {
+            if (asyncNotify != nullptr) {
                 if (mSurface != NULL) {
                     if (!mReleaseSurface) {
                         mReleaseSurface.reset(new ReleaseSurface);
@@ -3022,6 +3122,12 @@
                 }
             }
 
+            if (mReplyID) {
+                // State transition replies are handled above, so this reply
+                // would not be related to state transition. As we are
+                // shutting down the component, just fail the operation.
+                postPendingRepliesAndDeferredMessages(UNKNOWN_ERROR);
+            }
             mReplyID = replyID;
             setState(msg->what() == kWhatStop ? STOPPING : RELEASING);
 
@@ -3036,8 +3142,8 @@
 
             if (asyncNotify != nullptr) {
                 mResourceManagerProxy->markClientForPendingRemoval();
-                (new AMessage)->postReply(mReplyID);
-                mReplyID = 0;
+                postPendingRepliesAndDeferredMessages();
+                asyncNotifyPost.clear();
                 mAsyncReleaseCompleteNotification = asyncNotify;
             }
 
@@ -3208,17 +3314,21 @@
 
         case kWhatSignalEndOfInputStream:
         {
-            sp<AReplyToken> replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
             if (!isExecuting() || !mHaveInputSurface) {
-                PostReplyWithError(replyID, INVALID_OPERATION);
+                PostReplyWithError(msg, INVALID_OPERATION);
                 break;
             } else if (mFlags & kFlagStickyError) {
-                PostReplyWithError(replyID, getStickyError());
+                PostReplyWithError(msg, getStickyError());
                 break;
             }
 
+            if (mReplyID) {
+                mDeferredMessages.push_back(msg);
+                break;
+            }
+            sp<AReplyToken> replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
             mReplyID = replyID;
             mCodec->signalEndOfInputStream();
             break;
@@ -3260,17 +3370,21 @@
 
         case kWhatFlush:
         {
-            sp<AReplyToken> replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
             if (!isExecuting()) {
-                PostReplyWithError(replyID, INVALID_OPERATION);
+                PostReplyWithError(msg, INVALID_OPERATION);
                 break;
             } else if (mFlags & kFlagStickyError) {
-                PostReplyWithError(replyID, getStickyError());
+                PostReplyWithError(msg, getStickyError());
                 break;
             }
 
+            if (mReplyID) {
+                mDeferredMessages.push_back(msg);
+                break;
+            }
+            sp<AReplyToken> replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
             mReplyID = replyID;
             // TODO: skip flushing if already FLUSHED
             setState(FLUSHING);
@@ -4215,6 +4329,26 @@
     return OK;
 }
 
+void MediaCodec::postPendingRepliesAndDeferredMessages(status_t err /* = OK */) {
+    sp<AMessage> response{new AMessage};
+    if (err != OK) {
+        response->setInt32("err", err);
+    }
+    postPendingRepliesAndDeferredMessages(response);
+}
+
+void MediaCodec::postPendingRepliesAndDeferredMessages(const sp<AMessage> &response) {
+    CHECK(mReplyID);
+    response->postReply(mReplyID);
+    mReplyID.clear();
+    ALOGV_IF(!mDeferredMessages.empty(),
+            "posting %zu deferred messages", mDeferredMessages.size());
+    for (sp<AMessage> msg : mDeferredMessages) {
+        msg->post();
+    }
+    mDeferredMessages.clear();
+}
+
 std::string MediaCodec::stateString(State state) {
     const char *rval = NULL;
     char rawbuffer[16]; // room for "%d"
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index 8bbffd4..c91386d 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -92,7 +92,9 @@
     }
 
     sp<MetaData> trackMeta = new MetaData;
-    convertMessageToMetaData(format, trackMeta);
+    if (convertMessageToMetaData(format, trackMeta) != OK) {
+        return BAD_VALUE;
+    }
 
     sp<MediaAdapter> newTrack = new MediaAdapter(trackMeta);
     status_t result = mWriter->addSource(newTrack);
diff --git a/media/libstagefright/TEST_MAPPING b/media/libstagefright/TEST_MAPPING
index a95829c..76fc74f 100644
--- a/media/libstagefright/TEST_MAPPING
+++ b/media/libstagefright/TEST_MAPPING
@@ -29,6 +29,9 @@
           "exclude-filter": "android.media.cts.AudioRecordTest"
         }
       ]
+    },
+    {
+      "name": "mediacodecTest"
     }
   ],
   "postsubmit": [
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index d67874f..6446857 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -769,6 +769,7 @@
         { "sei", kKeySEI },
         { "text-format-data", kKeyTextFormatData },
         { "thumbnail-csd-hevc", kKeyThumbnailHVCC },
+        { "slow-motion-markers", kKeySlowMotionMarkers },
     }
 };
 
@@ -1663,13 +1664,16 @@
         meta->setInt32(kKeyColorMatrix, colorAspects.mMatrixCoeffs);
     }
 }
-
-void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
+/* Converts key and value pairs in AMessage format to MetaData format.
+ * Also checks for the presence of required keys.
+ */
+status_t convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
     AString mime;
     if (msg->findString("mime", &mime)) {
         meta->setCString(kKeyMIMEType, mime.c_str());
     } else {
-        ALOGW("did not find mime type");
+        ALOGE("did not find mime type");
+        return BAD_VALUE;
     }
 
     convertMessageToMetaDataFromMappings(msg, meta);
@@ -1718,7 +1722,8 @@
             meta->setInt32(kKeyWidth, width);
             meta->setInt32(kKeyHeight, height);
         } else {
-            ALOGV("did not find width and/or height");
+            ALOGE("did not find width and/or height");
+            return BAD_VALUE;
         }
 
         int32_t sarWidth, sarHeight;
@@ -1803,14 +1808,14 @@
             }
         }
     } else if (mime.startsWith("audio/")) {
-        int32_t numChannels;
-        if (msg->findInt32("channel-count", &numChannels)) {
-            meta->setInt32(kKeyChannelCount, numChannels);
+        int32_t numChannels, sampleRate;
+        if (!msg->findInt32("channel-count", &numChannels) ||
+                !msg->findInt32("sample-rate", &sampleRate)) {
+            ALOGE("did not find channel-count and/or sample-rate");
+            return BAD_VALUE;
         }
-        int32_t sampleRate;
-        if (msg->findInt32("sample-rate", &sampleRate)) {
-            meta->setInt32(kKeySampleRate, sampleRate);
-        }
+        meta->setInt32(kKeyChannelCount, numChannels);
+        meta->setInt32(kKeySampleRate, sampleRate);
         int32_t bitsPerSample;
         if (msg->findInt32("bits-per-sample", &bitsPerSample)) {
             meta->setInt32(kKeyBitsPerSample, bitsPerSample);
@@ -1925,7 +1930,8 @@
                     }
                 }
             } else {
-                ALOGW("We need csd-2!!. %s", msg->debugString().c_str());
+                ALOGE("We need csd-2!!. %s", msg->debugString().c_str());
+                return BAD_VALUE;
             }
         } else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) {
             meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size());
@@ -1991,6 +1997,7 @@
     ALOGI("converted %s to:", msg->debugString(0).c_str());
     meta->dumpToLog();
 #endif
+    return OK;
 }
 
 status_t sendMetaDataToHal(sp<MediaPlayerBase::AudioSink>& sink,
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_6.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_6.cpp
index 1f8018a..c306873 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_6.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_6.cpp
@@ -111,6 +111,7 @@
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
 
+__attribute__((no_sanitize("integer")))
 void pvmp3_dct_6(int32 vec[])
 {
 
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_6.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_6.cpp
index 8d80e8f..1ba080d 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_6.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_6.cpp
@@ -118,7 +118,7 @@
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
 
-
+__attribute__((no_sanitize("integer")))
 void pvmp3_mdct_6(int32 vec[], int32 *history)
 {
     int32 i;
diff --git a/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml b/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml
index 7ff9732..233f9bb 100644
--- a/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml
+++ b/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml
@@ -19,7 +19,7 @@
         <option name="cleanup" value="true" />
         <option name="push" value="Mp3DecoderTest->/data/local/tmp/Mp3DecoderTest" />
         <option name="push-file"
-            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/mp3dec/test/Mp3DecoderTest.zip?unzip=true"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/mp3dec/test/Mp3DecoderTest-1.1.zip?unzip=true"
             value="/data/local/tmp/Mp3DecoderTestRes/" />
     </target_preparer>
 
diff --git a/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
index 99553ec..0784c0c 100644
--- a/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
+++ b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
@@ -185,6 +185,7 @@
 INSTANTIATE_TEST_SUITE_P(Mp3DecoderTestAll, Mp3DecoderTest,
                          ::testing::Values(("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3"),
                                            ("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3"),
+                                           ("bug_136053885.mp3"),
                                            ("bbb_mp3_stereo_192kbps_48000hz.mp3")));
 
 int main(int argc, char **argv) {
diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
index 4f61aa8..5bb1879 100644
--- a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
+++ b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
@@ -58,6 +58,8 @@
       mInputBufferCount(0),
       mDecoder(NULL),
       mHeader(NULL),
+      mNumChannels(1),
+      mSamplingRate(kRate),
       mCodecDelay(0),
       mSeekPreRoll(0),
       mAnchorTimeUs(0),
@@ -169,11 +171,11 @@
             }
 
             opusParams->nAudioBandWidth = 0;
-            opusParams->nSampleRate = kRate;
+            opusParams->nSampleRate = mSamplingRate;
             opusParams->nBitRate = 0;
 
             if (!isConfigured()) {
-                opusParams->nChannels = 1;
+                opusParams->nChannels = mNumChannels;
             } else {
                 opusParams->nChannels = mHeader->channels;
             }
@@ -274,7 +276,8 @@
             if (opusParams->nPortIndex != 0) {
                 return OMX_ErrorUndefined;
             }
-
+            mNumChannels = opusParams->nChannels;
+            mSamplingRate = opusParams->nSampleRate;
             return OMX_ErrorNone;
         }
 
@@ -496,6 +499,8 @@
                                    *(reinterpret_cast<int64_t*>(inHeader->pBuffer +
                                                                 inHeader->nOffset)),
                                    kRate);
+                mSamplingRate = kRate;
+                mNumChannels = mHeader->channels;
                 notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
                 mOutputPortSettingsChange = AWAITING_DISABLED;
             }
diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.h b/media/libstagefright/codecs/opus/dec/SoftOpus.h
index 91cafa1..00058c8 100644
--- a/media/libstagefright/codecs/opus/dec/SoftOpus.h
+++ b/media/libstagefright/codecs/opus/dec/SoftOpus.h
@@ -70,6 +70,8 @@
     OpusMSDecoder *mDecoder;
     OpusHeader *mHeader;
 
+    int32_t mNumChannels;
+    int32_t mSamplingRate;
     int64_t mCodecDelay;
     int64_t mSeekPreRoll;
     int64_t mSamplesToDiscard;
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index cc40f76..4c97b4d 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -147,6 +147,7 @@
         kWhatReleaseCodecInstance    = 'relC',
         kWhatForceStateTransition    = 'fstt',
         kWhatCheckIfStuck            = 'Cstk',
+        kWhatSubmitExtraOutputMetadataBuffer = 'sbxo',
     };
 
     enum {
@@ -273,6 +274,7 @@
     bool mExplicitShutdown;
     bool mIsLegacyVP9Decoder;
     bool mIsStreamCorruptFree;
+    bool mIsLowLatency;
 
     // If "mKeepComponentAllocated" we only transition back to Loaded state
     // and do not release the component instance.
@@ -500,6 +502,7 @@
     status_t setupAMRCodec(bool encoder, bool isWAMR, int32_t bitRate);
     status_t setupG711Codec(bool encoder, int32_t sampleRate, int32_t numChannels);
 
+    status_t setupOpusCodec(bool encoder, int32_t sampleRate, int32_t numChannels);
     status_t setupFlacCodec(
             bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel,
             AudioEncoding encoding);
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index c4026ec..ec853e9 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -373,6 +373,7 @@
     AString mOwnerName;
     sp<MediaCodecInfo> mCodecInfo;
     sp<AReplyToken> mReplyID;
+    std::vector<sp<AMessage>> mDeferredMessages;
     uint32_t mFlags;
     status_t mStickyError;
     sp<Surface> mSurface;
@@ -435,13 +436,17 @@
 
     std::shared_ptr<BufferChannelBase> mBufferChannel;
 
-    MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid);
+    MediaCodec(
+            const sp<ALooper> &looper, pid_t pid, uid_t uid,
+            std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase = nullptr,
+            std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo = nullptr);
 
     static sp<CodecBase> GetCodecBase(const AString &name, const char *owner = nullptr);
 
     static status_t PostAndAwaitResponse(
             const sp<AMessage> &msg, sp<AMessage> *response);
 
+    void PostReplyWithError(const sp<AMessage> &msg, int32_t err);
     void PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err);
 
     status_t init(const AString &name);
@@ -493,6 +498,9 @@
     bool hasPendingBuffer(int portIndex);
     bool hasPendingBuffer();
 
+    void postPendingRepliesAndDeferredMessages(status_t err = OK);
+    void postPendingRepliesAndDeferredMessages(const sp<AMessage> &response);
+
     /* called to get the last codec error when the sticky flag is set.
      * if no such codec error is found, returns UNKNOWN_ERROR.
      */
@@ -578,6 +586,10 @@
 
     Histogram mLatencyHist;
 
+    std::function<sp<CodecBase>(const AString &, const char *)> mGetCodecBase;
+    std::function<status_t(const AString &, sp<MediaCodecInfo> *)> mGetCodecInfo;
+    friend class MediaTestHelper;
+
     DISALLOW_EVIL_CONSTRUCTORS(MediaCodec);
 };
 
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h b/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h
index f53b23e..bf85d7e 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h
@@ -19,7 +19,6 @@
 #define MEDIA_CODEC_LIST_WRITER_H_
 
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaCodecListWriter.h>
 #include <media/MediaCodecInfo.h>
 
 #include <utils/Errors.h>
@@ -65,6 +64,7 @@
     std::vector<sp<MediaCodecInfo>> mCodecInfos;
 
     friend struct MediaCodecList;
+    friend class MediaTestHelper;
 };
 
 /**
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index 2f34094..6b0d28f 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -257,6 +257,10 @@
     kKeyRtpCvoDegrees    = 'cvod', // int32_t, rtp cvo degrees as per 3GPP 26.114.
     kKeyRtpDscp          = 'dscp', // int32_t, DSCP(Differentiated services codepoint) of RFC 2474.
     kKeySocketNetwork    = 'sNet', // int64_t, socket will be bound to network handle.
+
+    // Slow-motion markers
+    kKeySlowMotionMarkers = 'slmo', // raw data, byte array following spec for
+                                    // MediaFormat#KEY_SLOW_MOTION_MARKERS
 };
 
 enum {
diff --git a/media/libstagefright/include/media/stagefright/ProcessInfo.h b/media/libstagefright/include/media/stagefright/ProcessInfo.h
index 0be1a52..b8a3c10 100644
--- a/media/libstagefright/include/media/stagefright/ProcessInfo.h
+++ b/media/libstagefright/include/media/stagefright/ProcessInfo.h
@@ -20,6 +20,9 @@
 
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/ProcessInfoInterface.h>
+#include <map>
+#include <mutex>
+#include <utils/Condition.h>
 
 namespace android {
 
@@ -28,11 +31,20 @@
 
     virtual bool getPriority(int pid, int* priority);
     virtual bool isValidPid(int pid);
+    virtual bool overrideProcessInfo(int pid, int procState, int oomScore);
+    virtual void removeProcessInfoOverride(int pid);
 
 protected:
     virtual ~ProcessInfo();
 
 private:
+    struct ProcessInfoOverride {
+        int procState;
+        int oomScore;
+    };
+    std::mutex mOverrideLock;
+    std::map<int, ProcessInfoOverride> mOverrideMap GUARDED_BY(mOverrideLock);
+
     DISALLOW_EVIL_CONSTRUCTORS(ProcessInfo);
 };
 
diff --git a/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h b/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
index b39112a..9260181 100644
--- a/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
+++ b/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
@@ -24,6 +24,8 @@
 struct ProcessInfoInterface : public RefBase {
     virtual bool getPriority(int pid, int* priority) = 0;
     virtual bool isValidPid(int pid) = 0;
+    virtual bool overrideProcessInfo(int pid, int procState, int oomScore);
+    virtual void removeProcessInfoOverride(int pid);
 
 protected:
     virtual ~ProcessInfoInterface() {}
diff --git a/media/libstagefright/include/media/stagefright/Utils.h b/media/libstagefright/include/media/stagefright/Utils.h
index 2b9b759..1673120 100644
--- a/media/libstagefright/include/media/stagefright/Utils.h
+++ b/media/libstagefright/include/media/stagefright/Utils.h
@@ -33,7 +33,7 @@
         const MetaDataBase *meta, sp<AMessage> *format);
 status_t convertMetaDataToMessage(
         const sp<MetaData> &meta, sp<AMessage> *format);
-void convertMessageToMetaData(
+status_t convertMessageToMetaData(
         const sp<AMessage> &format, sp<MetaData> &meta);
 
 // Returns a pointer to the next NAL start code in buffer of size |length| starting at |data|, or
diff --git a/media/libstagefright/tests/mediacodec/Android.bp b/media/libstagefright/tests/mediacodec/Android.bp
new file mode 100644
index 0000000..006864e
--- /dev/null
+++ b/media/libstagefright/tests/mediacodec/Android.bp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+cc_test {
+    name: "mediacodecTest",
+    gtest: true,
+
+    srcs: [
+        "MediaCodecTest.cpp",
+        "MediaTestHelper.cpp",
+    ],
+
+    shared_libs: [
+        "libmedia",
+        "libmedia_codeclist",
+        "libmediametrics",
+        "libmediandk",
+        "libstagefright",
+        "libstagefright_codecbase",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libgmock",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+
+    test_suites: [
+        "general-tests",
+    ],
+}
diff --git a/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp b/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
new file mode 100644
index 0000000..baa86c1
--- /dev/null
+++ b/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2020 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 <future>
+#include <thread>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <media/stagefright/CodecBase.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecListWriter.h>
+#include <media/MediaCodecInfo.h>
+
+#include "MediaTestHelper.h"
+
+namespace android {
+
+class MockBufferChannel : public BufferChannelBase {
+public:
+    ~MockBufferChannel() override = default;
+
+    MOCK_METHOD(void, setCrypto, (const sp<ICrypto> &crypto), (override));
+    MOCK_METHOD(void, setDescrambler, (const sp<IDescrambler> &descrambler), (override));
+    MOCK_METHOD(status_t, queueInputBuffer, (const sp<MediaCodecBuffer> &buffer), (override));
+    MOCK_METHOD(status_t, queueSecureInputBuffer,
+            (const sp<MediaCodecBuffer> &buffer,
+             bool secure,
+             const uint8_t *key,
+             const uint8_t *iv,
+             CryptoPlugin::Mode mode,
+             CryptoPlugin::Pattern pattern,
+             const CryptoPlugin::SubSample *subSamples,
+             size_t numSubSamples,
+             AString *errorDetailMsg),
+            (override));
+    MOCK_METHOD(status_t, attachBuffer,
+            (const std::shared_ptr<C2Buffer> &c2Buffer, const sp<MediaCodecBuffer> &buffer),
+            (override));
+    MOCK_METHOD(status_t, attachEncryptedBuffer,
+            (const sp<hardware::HidlMemory> &memory,
+             bool secure,
+             const uint8_t *key,
+             const uint8_t *iv,
+             CryptoPlugin::Mode mode,
+             CryptoPlugin::Pattern pattern,
+             size_t offset,
+             const CryptoPlugin::SubSample *subSamples,
+             size_t numSubSamples,
+             const sp<MediaCodecBuffer> &buffer),
+            (override));
+    MOCK_METHOD(status_t, renderOutputBuffer,
+            (const sp<MediaCodecBuffer> &buffer, int64_t timestampNs),
+            (override));
+    MOCK_METHOD(status_t, discardBuffer, (const sp<MediaCodecBuffer> &buffer), (override));
+    MOCK_METHOD(void, getInputBufferArray, (Vector<sp<MediaCodecBuffer>> *array), (override));
+    MOCK_METHOD(void, getOutputBufferArray, (Vector<sp<MediaCodecBuffer>> *array), (override));
+};
+
+class MockCodec : public CodecBase {
+public:
+    MockCodec(std::function<void(const std::shared_ptr<MockBufferChannel> &)> mock) {
+        mMockBufferChannel = std::make_shared<MockBufferChannel>();
+        mock(mMockBufferChannel);
+    }
+    ~MockCodec() override = default;
+
+    MOCK_METHOD(void, initiateAllocateComponent, (const sp<AMessage> &msg), (override));
+    MOCK_METHOD(void, initiateConfigureComponent, (const sp<AMessage> &msg), (override));
+    MOCK_METHOD(void, initiateCreateInputSurface, (), (override));
+    MOCK_METHOD(void, initiateSetInputSurface, (const sp<PersistentSurface> &surface), (override));
+    MOCK_METHOD(void, initiateStart, (), (override));
+    MOCK_METHOD(void, initiateShutdown, (bool keepComponentAllocated), (override));
+    MOCK_METHOD(void, onMessageReceived, (const sp<AMessage> &msg), (override));
+    MOCK_METHOD(status_t, setSurface, (const sp<Surface> &surface), (override));
+    MOCK_METHOD(void, signalFlush, (), (override));
+    MOCK_METHOD(void, signalResume, (), (override));
+    MOCK_METHOD(void, signalRequestIDRFrame, (), (override));
+    MOCK_METHOD(void, signalSetParameters, (const sp<AMessage> &msg), (override));
+    MOCK_METHOD(void, signalEndOfInputStream, (), (override));
+
+    std::shared_ptr<BufferChannelBase> getBufferChannel() override {
+        return mMockBufferChannel;
+    }
+
+    const std::unique_ptr<CodecCallback> &callback() {
+        return mCallback;
+    }
+
+    std::shared_ptr<MockBufferChannel> mMockBufferChannel;
+};
+
+class Counter {
+public:
+    Counter() = default;
+    explicit Counter(int32_t initCount) : mCount(initCount) {}
+    ~Counter() = default;
+
+    int32_t advance() {
+        std::unique_lock<std::mutex> lock(mMutex);
+        ++mCount;
+        mCondition.notify_all();
+        return mCount;
+    }
+
+    template <typename Rep, typename Period, typename ...Args>
+    int32_t waitFor(const std::chrono::duration<Rep, Period> &duration, Args... values) {
+        std::initializer_list<int32_t> list = {values...};
+        std::unique_lock<std::mutex> lock(mMutex);
+        mCondition.wait_for(
+                lock,
+                duration,
+                [&list, this]{
+                    return std::find(list.begin(), list.end(), mCount) != list.end();
+                });
+        return mCount;
+    }
+
+    template <typename ...Args>
+    int32_t wait(Args... values) {
+        std::initializer_list<int32_t> list = {values...};
+        std::unique_lock<std::mutex> lock(mMutex);
+        mCondition.wait(
+                lock,
+                [&list, this]{
+                    return std::find(list.begin(), list.end(), mCount) != list.end();
+                });
+        return mCount;
+    }
+
+private:
+    std::mutex mMutex;
+    std::condition_variable mCondition;
+    int32_t mCount = 0;
+};
+
+}  // namespace android
+
+using namespace android;
+using ::testing::_;
+
+TEST(MediaCodecTest, ReclaimReleaseRace) {
+    // Test scenario:
+    //
+    // 1) ResourceManager thread calls reclaim(), message posted to
+    //    MediaCodec looper thread.
+    // 2) MediaCodec looper thread calls initiateShutdown(), shutdown being
+    //    handled at the component thread.
+    // 3) Client thread calls release(), message posted to & handle at
+    //    MediaCodec looper thread.
+    // 4) MediaCodec looper thread may call initiateShutdown().
+    // 5) initiateShutdown() from 2) is handled at onReleaseComplete() event
+    //    posted to MediaCodec looper thread.
+    // 6) If called, initiateShutdown() from 4) is handled and
+    //    onReleaseComplete() event posted to MediaCodec looper thread.
+
+    static const AString kCodecName{"test.codec"};
+    static const AString kCodecOwner{"nobody"};
+    static const AString kMediaType{"video/x-test"};
+
+    enum {
+        kInit,
+        kShutdownFromReclaimReceived,
+        kReleaseCalled,
+    };
+    Counter counter{kInit};
+    sp<MockCodec> mockCodec;
+    std::function<sp<CodecBase>(const AString &name, const char *owner)> getCodecBase =
+        [&mockCodec, &counter](const AString &, const char *) {
+            mockCodec = new MockCodec([](const std::shared_ptr<MockBufferChannel> &) {
+                // No mock setup, as we don't expect any buffer operations
+                // in this scenario.
+            });
+            ON_CALL(*mockCodec, initiateAllocateComponent(_))
+                .WillByDefault([mockCodec](const sp<AMessage> &) {
+                    mockCodec->callback()->onComponentAllocated(kCodecName.c_str());
+                });
+            ON_CALL(*mockCodec, initiateShutdown(_))
+                .WillByDefault([mockCodec, &counter](bool) {
+                    int32_t stage = counter.wait(kInit, kReleaseCalled);
+                    if (stage == kInit) {
+                        // Mark that 2) happened, so test can proceed to 3)
+                        counter.advance();
+                    } else if (stage == kReleaseCalled) {
+                        // Handle 6)
+                        mockCodec->callback()->onReleaseCompleted();
+                    }
+                });
+            return mockCodec;
+        };
+
+    std::shared_ptr<MediaCodecListWriter> listWriter =
+        MediaTestHelper::CreateCodecListWriter();
+    std::unique_ptr<MediaCodecInfoWriter> infoWriter = listWriter->addMediaCodecInfo();
+    infoWriter->setName(kCodecName.c_str());
+    infoWriter->setOwner(kCodecOwner.c_str());
+    infoWriter->addMediaType(kMediaType.c_str());
+    std::vector<sp<MediaCodecInfo>> codecInfos;
+    MediaTestHelper::WriteCodecInfos(listWriter, &codecInfos);
+    std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo =
+        [codecInfos](const AString &name, sp<MediaCodecInfo> *info) -> status_t {
+            auto it = std::find_if(
+                    codecInfos.begin(), codecInfos.end(),
+                    [&name](const sp<MediaCodecInfo> &info) {
+                        return name.equalsIgnoreCase(info->getCodecName());
+                    });
+
+            *info = (it == codecInfos.end()) ? nullptr : *it;
+            return (*info) ? OK : NAME_NOT_FOUND;
+        };
+
+    sp<ALooper> looper{new ALooper};
+    looper->start();
+    sp<MediaCodec> codec = MediaTestHelper::CreateCodec(
+            kCodecName, looper, getCodecBase, getCodecInfo);
+    ASSERT_NE(nullptr, codec) << "Codec must not be null";
+    ASSERT_NE(nullptr, mockCodec) << "MockCodec must not be null";
+    std::promise<void> reclaimCompleted;
+    std::promise<void> releaseCompleted;
+    Counter threadExitCounter;
+    std::thread([codec, &reclaimCompleted]{
+        // Simulate ResourceManager thread. Proceed with 1)
+        MediaTestHelper::Reclaim(codec, true /* force */);
+        reclaimCompleted.set_value();
+    }).detach();
+    std::thread([codec, &counter, &releaseCompleted]{
+        // Simulate client thread. Wait until 2) is complete
+        (void)counter.wait(kShutdownFromReclaimReceived);
+        // Proceed to 3), and mark that 5) is ready to happen.
+        // NOTE: it's difficult to pinpoint when 4) happens, so we will sleep
+        //       to meet the timing.
+        counter.advance();
+        codec->release();
+        releaseCompleted.set_value();
+    }).detach();
+    std::thread([mockCodec, &counter]{
+        // Simulate component thread. Wait until 3) is complete
+        (void)counter.wait(kReleaseCalled);
+        // We want 4) to complete before moving forward, but it is hard to
+        // wait for this exact event. Just sleep so that the other thread can
+        // proceed and complete 4).
+        std::this_thread::sleep_for(std::chrono::milliseconds(100));
+        // Proceed to 5).
+        mockCodec->callback()->onReleaseCompleted();
+    }).detach();
+    EXPECT_EQ(
+            std::future_status::ready,
+            reclaimCompleted.get_future().wait_for(std::chrono::seconds(5)))
+        << "reclaim timed out";
+    EXPECT_EQ(
+            std::future_status::ready,
+            releaseCompleted.get_future().wait_for(std::chrono::seconds(5)))
+        << "release timed out";
+    looper->stop();
+}
diff --git a/media/libstagefright/tests/mediacodec/MediaTestHelper.cpp b/media/libstagefright/tests/mediacodec/MediaTestHelper.cpp
new file mode 100644
index 0000000..bbe3c05
--- /dev/null
+++ b/media/libstagefright/tests/mediacodec/MediaTestHelper.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 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 <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecListWriter.h>
+
+#include "MediaTestHelper.h"
+
+namespace android {
+
+// static
+sp<MediaCodec> MediaTestHelper::CreateCodec(
+        const AString &name,
+        const sp<ALooper> &looper,
+        std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase,
+        std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo) {
+    sp<MediaCodec> codec = new MediaCodec(
+            looper, MediaCodec::kNoPid, MediaCodec::kNoUid, getCodecBase, getCodecInfo);
+    if (codec->init(name) != OK) {
+        return nullptr;
+    }
+    return codec;
+}
+
+// static
+void MediaTestHelper::Reclaim(const sp<MediaCodec> &codec, bool force) {
+    codec->reclaim(force);
+}
+
+// static
+std::shared_ptr<MediaCodecListWriter> MediaTestHelper::CreateCodecListWriter() {
+    return std::shared_ptr<MediaCodecListWriter>(new MediaCodecListWriter);
+}
+
+// static
+void MediaTestHelper::WriteCodecInfos(
+        const std::shared_ptr<MediaCodecListWriter> &writer,
+        std::vector<sp<MediaCodecInfo>> *codecInfos) {
+    writer->writeCodecInfos(codecInfos);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/tests/mediacodec/MediaTestHelper.h b/media/libstagefright/tests/mediacodec/MediaTestHelper.h
new file mode 100644
index 0000000..f3d6110
--- /dev/null
+++ b/media/libstagefright/tests/mediacodec/MediaTestHelper.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020, 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 MEDIA_TEST_HELPER_H_
+
+#define MEDIA_TEST_HELPER_H_
+
+#include <media/stagefright/foundation/AString.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+struct ALooper;
+struct CodecBase;
+struct MediaCodec;
+struct MediaCodecInfo;
+struct MediaCodecListWriter;
+
+class MediaTestHelper {
+public:
+    // MediaCodec
+    static sp<MediaCodec> CreateCodec(
+            const AString &name,
+            const sp<ALooper> &looper,
+            std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase,
+            std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo);
+    static void Reclaim(const sp<MediaCodec> &codec, bool force);
+
+    // MediaCodecListWriter
+    static std::shared_ptr<MediaCodecListWriter> CreateCodecListWriter();
+    static void WriteCodecInfos(
+            const std::shared_ptr<MediaCodecListWriter> &writer,
+            std::vector<sp<MediaCodecInfo>> *codecInfos);
+};
+
+}  // namespace android
+
+#endif  // MEDIA_TEST_HELPER_H_
diff --git a/media/mtp/Android.bp b/media/mtp/Android.bp
index 66a3139..e572249 100644
--- a/media/mtp/Android.bp
+++ b/media/mtp/Android.bp
@@ -52,5 +52,6 @@
         "liblog",
         "libusbhost",
     ],
+    header_libs: ["libcutils_headers"],
 }
 
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index af21a99..d771095 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -45,6 +45,10 @@
         return AMEDIA_OK;
     } else if (err == -EAGAIN) {
         return (media_status_t) AMEDIACODEC_INFO_TRY_AGAIN_LATER;
+    } else if (err == NO_MEMORY) {
+        return AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
+    } else if (err == DEAD_OBJECT) {
+        return AMEDIACODEC_ERROR_RECLAIMED;
     }
     ALOGE("sf error code: %d", err);
     return AMEDIA_ERROR_UNKNOWN;
@@ -255,7 +259,7 @@
                          break;
                      }
                      msg->findString("detail", &detail);
-                     ALOGE("Decoder reported error(0x%x), actionCode(%d), detail(%s)",
+                     ALOGE("Codec reported error(0x%x), actionCode(%d), detail(%s)",
                            err, actionCode, detail.c_str());
 
                      Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 8680641..73c52a9 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -364,6 +364,7 @@
 EXPORT const char* AMEDIAFORMAT_KEY_SAR_WIDTH = "sar-width";
 EXPORT const char* AMEDIAFORMAT_KEY_SEI = "sei";
 EXPORT const char* AMEDIAFORMAT_KEY_SLICE_HEIGHT = "slice-height";
+EXPORT const char* AMEDIAFORMAT_KEY_SLOW_MOTION_MARKERS = "slow-motion-markers";
 EXPORT const char* AMEDIAFORMAT_KEY_STRIDE = "stride";
 EXPORT const char* AMEDIAFORMAT_KEY_TARGET_TIME = "target-time";
 EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_COUNT = "temporal-layer-count";
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 6371de4..394b972 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -322,6 +322,10 @@
 extern const char* AMEDIAFORMAT_KEY_LOW_LATENCY __INTRODUCED_IN(30);
 #endif /* __ANDROID_API__ >= 30 */
 
+#if __ANDROID_API__ >= 31
+extern const char* AMEDIAFORMAT_KEY_SLOW_MOTION_MARKERS __INTRODUCED_IN(31);
+#endif /* __ANDROID_API__ >= 31 */
+
 __END_DECLS
 
 #endif // _NDK_MEDIA_FORMAT_H
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 29f1da8..bd3337e 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -131,6 +131,7 @@
     AMEDIAFORMAT_KEY_SAR_WIDTH; # var introduced=29
     AMEDIAFORMAT_KEY_SEI; # var introduced=28
     AMEDIAFORMAT_KEY_SLICE_HEIGHT; # var introduced=28
+    AMEDIAFORMAT_KEY_SLOW_MOTION_MARKERS; # var introduced=31
     AMEDIAFORMAT_KEY_STRIDE; # var introduced=21
     AMEDIAFORMAT_KEY_TARGET_TIME; # var introduced=29
     AMEDIAFORMAT_KEY_TEMPORAL_LAYER_COUNT; # var introduced=29
diff --git a/media/utils/ProcessInfo.cpp b/media/utils/ProcessInfo.cpp
index 113e4a7..19225d3 100644
--- a/media/utils/ProcessInfo.cpp
+++ b/media/utils/ProcessInfo.cpp
@@ -27,6 +27,9 @@
 
 namespace android {
 
+static constexpr int32_t INVALID_ADJ = -10000;
+static constexpr int32_t NATIVE_ADJ = -1000;
+
 ProcessInfo::ProcessInfo() {}
 
 bool ProcessInfo::getPriority(int pid, int* priority) {
@@ -35,8 +38,6 @@
 
     size_t length = 1;
     int32_t state;
-    static const int32_t INVALID_ADJ = -10000;
-    static const int32_t NATIVE_ADJ = -1000;
     int32_t score = INVALID_ADJ;
     status_t err = service->getProcessStatesAndOomScoresFromPids(length, &pid, &state, &score);
     if (err != OK) {
@@ -45,8 +46,17 @@
     }
     ALOGV("pid %d state %d score %d", pid, state, score);
     if (score <= NATIVE_ADJ) {
-        ALOGE("pid %d invalid OOM adjustments value %d", pid, score);
-        return false;
+        std::scoped_lock lock{mOverrideLock};
+
+        // If this process if not tracked by ActivityManagerService, look for overrides.
+        auto it = mOverrideMap.find(pid);
+        if (it != mOverrideMap.end()) {
+            ALOGI("pid %d invalid OOM score %d, override to %d", pid, score, it->second.oomScore);
+            score = it->second.oomScore;
+        } else {
+            ALOGE("pid %d invalid OOM score %d", pid, score);
+            return false;
+        }
     }
 
     // Use OOM adjustments value as the priority. Lower the value, higher the priority.
@@ -61,6 +71,26 @@
     return (callingPid == getpid()) || (callingPid == pid) || (callingUid == AID_MEDIA);
 }
 
+bool ProcessInfo::overrideProcessInfo(int pid, int procState, int oomScore) {
+    std::scoped_lock lock{mOverrideLock};
+
+    mOverrideMap.erase(pid);
+
+    // Disable the override if oomScore is set to NATIVE_ADJ or below.
+    if (oomScore <= NATIVE_ADJ) {
+        return false;
+    }
+
+    mOverrideMap.emplace(pid, ProcessInfoOverride{procState, oomScore});
+    return true;
+}
+
+void ProcessInfo::removeProcessInfoOverride(int pid) {
+    std::scoped_lock lock{mOverrideLock};
+
+    mOverrideMap.erase(pid);
+}
+
 ProcessInfo::~ProcessInfo() {}
 
 }  // namespace android
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 2db902d..9885655 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -684,6 +684,7 @@
         virtual status_t createMmapBuffer(int32_t minSizeFrames,
                                           struct audio_mmap_buffer_info *info);
         virtual status_t getMmapPosition(struct audio_mmap_position *position);
+        virtual status_t getExternalPosition(uint64_t *position, int64_t *timeNanos);
         virtual status_t start(const AudioClient& client,
                                const audio_attributes_t *attr,
                                audio_port_handle_t *handle);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 2a6aeac..077447f 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2385,7 +2385,7 @@
         {
             Mutex::Autolock _atCbL(mAudioTrackCbLock);
             if (callback.get() != nullptr) {
-                mAudioTrackCallbacks.emplace(callback);
+                mAudioTrackCallbacks.emplace(track, callback);
             }
         }
 
@@ -2619,6 +2619,10 @@
     mLocalLog.log("removeTrack_l (%p) %s", track.get(), result.string());
 
     mTracks.remove(track);
+    {
+        Mutex::Autolock _atCbL(mAudioTrackCbLock);
+        mAudioTrackCallbacks.erase(track);
+    }
     if (track->isFastTrack()) {
         int index = track->mFastIndex;
         ALOG_ASSERT(0 < index && index < (int)FastMixerState::sMaxFastTracks);
@@ -2714,8 +2718,8 @@
                     audio_utils::metadata::byteStringFromData(metadata);
             std::vector metadataVec(metaDataStr.begin(), metaDataStr.end());
             Mutex::Autolock _l(mAudioTrackCbLock);
-            for (const auto& callback : mAudioTrackCallbacks) {
-                callback->onCodecFormatChanged(metadataVec);
+            for (const auto& callbackPair : mAudioTrackCallbacks) {
+                callbackPair.second->onCodecFormatChanged(metadataVec);
             }
     }).detach();
 }
@@ -8742,6 +8746,11 @@
     return mThread->getMmapPosition(position);
 }
 
+status_t AudioFlinger::MmapThreadHandle::getExternalPosition(uint64_t *position,
+                                                             int64_t *timeNanos) {
+    return mThread->getExternalPosition(position, timeNanos);
+}
+
 status_t AudioFlinger::MmapThreadHandle::start(const AudioClient& client,
         const audio_attributes_t *attr, audio_port_handle_t *handle)
 
@@ -8777,7 +8786,6 @@
 
 AudioFlinger::MmapThread::~MmapThread()
 {
-    releaseWakeLock_l();
 }
 
 void AudioFlinger::MmapThread::onFirstRef()
@@ -8827,7 +8835,6 @@
         return NO_INIT;
     }
     mStandby = true;
-    acquireWakeLock();
     return mHalStream->createMmapBuffer(minSizeFrames, info);
 }
 
@@ -8866,8 +8873,12 @@
     status_t ret;
 
     if (*handle == mPortId) {
-        // for the first track, reuse portId and session allocated when the stream was opened
-        return exitStandby();
+        // For the first track, reuse portId and session allocated when the stream was opened.
+        ret = exitStandby();
+        if (ret == NO_ERROR) {
+            acquireWakeLock();
+        }
+        return ret;
     }
 
     audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
@@ -8988,6 +8999,7 @@
 
     if (handle == mPortId) {
         mHalStream->stop();
+        releaseWakeLock();
         return NO_ERROR;
     }
 
@@ -9696,6 +9708,20 @@
     }
 }
 
+status_t AudioFlinger::MmapPlaybackThread::getExternalPosition(uint64_t *position,
+                                                               int64_t *timeNanos)
+{
+    if (mOutput == nullptr) {
+        return NO_INIT;
+    }
+    struct timespec timestamp;
+    status_t status = mOutput->getPresentationPosition(position, &timestamp);
+    if (status == NO_ERROR) {
+        *timeNanos = timestamp.tv_sec * NANOS_PER_SECOND + timestamp.tv_nsec;
+    }
+    return status;
+}
+
 void AudioFlinger::MmapPlaybackThread::dumpInternals_l(int fd, const Vector<String16>& args)
 {
     MmapThread::dumpInternals_l(fd, args);
@@ -9800,4 +9826,13 @@
     }
 }
 
+status_t AudioFlinger::MmapCaptureThread::getExternalPosition(
+        uint64_t *position, int64_t *timeNanos)
+{
+    if (mInput == nullptr) {
+        return NO_INIT;
+    }
+    return mInput->getCapturePosition((int64_t*)position, timeNanos);
+}
+
 } // namespace android
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index d59b702..014f2d7 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1219,7 +1219,7 @@
 
     Mutex                                    mAudioTrackCbLock;
     // Record of IAudioTrackCallback
-    std::set<sp<media::IAudioTrackCallback>> mAudioTrackCallbacks;
+    std::map<sp<Track>, sp<media::IAudioTrackCallback>> mAudioTrackCallbacks;
 
 private:
     // The HAL output sink is treated as non-blocking, but current implementation is blocking
@@ -1824,6 +1824,7 @@
                    audio_port_handle_t *handle);
     status_t stop(audio_port_handle_t handle);
     status_t standby();
+    virtual status_t getExternalPosition(uint64_t *position, int64_t *timeNaos) = 0;
 
     // RefBase
     virtual     void        onFirstRef();
@@ -1935,6 +1936,8 @@
 
     virtual     void        toAudioPortConfig(struct audio_port_config *config);
 
+                status_t    getExternalPosition(uint64_t *position, int64_t *timeNanos) override;
+
 protected:
                 void        dumpInternals_l(int fd, const Vector<String16>& args) override;
 
@@ -1965,6 +1968,8 @@
 
     virtual     void           toAudioPortConfig(struct audio_port_config *config);
 
+                status_t       getExternalPosition(uint64_t *position, int64_t *timeNanos) override;
+
 protected:
 
                 AudioStreamIn*  mInput;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index fbfe077..1a12a5f 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -954,6 +954,11 @@
         // initial state-stopping. next state-pausing.
         // What if resume is called ?
 
+        if (state == FLUSHED) {
+            // avoid underrun glitches when starting after flush
+            reset();
+        }
+
         if (state == PAUSED || state == PAUSING) {
             if (mResumeToStopping) {
                 // happened we need to resume to STOPPING_1
diff --git a/services/audiopolicy/config/audio_policy_configuration.xml b/services/audiopolicy/config/audio_policy_configuration.xml
index b28381b..dcdc035 100644
--- a/services/audiopolicy/config/audio_policy_configuration.xml
+++ b/services/audiopolicy/config/audio_policy_configuration.xml
@@ -91,7 +91,7 @@
                 <!-- Output devices declaration, i.e. Sink DEVICE PORT -->
                 <devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                 </devicePort>
                 <devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address="">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
diff --git a/services/audiopolicy/config/audio_policy_configuration_7_0.xml b/services/audiopolicy/config/audio_policy_configuration_7_0.xml
index 6087bf2..31c8954 100644
--- a/services/audiopolicy/config/audio_policy_configuration_7_0.xml
+++ b/services/audiopolicy/config/audio_policy_configuration_7_0.xml
@@ -62,7 +62,7 @@
                              samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                 </mixPort>
                 <mixPort name="compressed_offload" role="source"
-                         flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING">
+                         flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD AUDIO_OUTPUT_FLAG_NON_BLOCKING">
                     <profile name="" format="AUDIO_FORMAT_MP3"
                              samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000"
                              channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/>
@@ -91,7 +91,7 @@
                 <!-- Output devices declaration, i.e. Sink DEVICE PORT -->
                 <devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                 </devicePort>
                 <devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address="">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
diff --git a/services/audiopolicy/config/msd_audio_policy_configuration_7_0.xml b/services/audiopolicy/config/msd_audio_policy_configuration_7_0.xml
index ae0ba80..f167f0b 100644
--- a/services/audiopolicy/config/msd_audio_policy_configuration_7_0.xml
+++ b/services/audiopolicy/config/msd_audio_policy_configuration_7_0.xml
@@ -25,7 +25,7 @@
                      samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
         </mixPort>
         <mixPort name="ms12 compressed input" role="source"
-                flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING">
+                flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD AUDIO_OUTPUT_FLAG_NON_BLOCKING">
             <profile name="" format="AUDIO_FORMAT_AC3"
                      samplingRates="32000 44100 48000"
                      channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_5POINT1"/>
@@ -40,7 +40,7 @@
                      channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_5POINT1 AUDIO_CHANNEL_OUT_7POINT1"/>
         </mixPort>
         <!-- The HW AV Sync flag is not required, but is recommended -->
-        <mixPort name="ms12 output" role="sink" flags="AUDIO_INPUT_FLAG_HW_AV_SYNC|AUDIO_INPUT_FLAG_DIRECT">
+        <mixPort name="ms12 output" role="sink" flags="AUDIO_INPUT_FLAG_HW_AV_SYNC AUDIO_INPUT_FLAG_DIRECT">
             <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                      samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
             <profile name="" format="AUDIO_FORMAT_AC3"
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index 346ee52..cdf5a4e 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -11,6 +11,19 @@
     path: "aidl",
 }
 
+filegroup {
+    name: "resourceobserver_aidl",
+    srcs: [
+        "aidl/android/media/IResourceObserver.aidl",
+        "aidl/android/media/IResourceObserverService.aidl",
+        "aidl/android/media/MediaObservableEvent.aidl",
+        "aidl/android/media/MediaObservableFilter.aidl",
+        "aidl/android/media/MediaObservableType.aidl",
+        "aidl/android/media/MediaObservableParcel.aidl",
+    ],
+    path: "aidl",
+}
+
 aidl_interface {
     name: "resourcemanager_aidl_interface",
     unstable: true,
@@ -20,11 +33,21 @@
     ],
 }
 
+aidl_interface {
+    name: "resourceobserver_aidl_interface",
+    unstable: true,
+    local_include_dir: "aidl",
+    srcs: [
+        ":resourceobserver_aidl",
+    ],
+}
+
 cc_library {
     name: "libresourcemanagerservice",
 
     srcs: [
         "ResourceManagerService.cpp",
+        "ResourceObserverService.cpp",
         "ServiceLog.cpp",
     ],
 
@@ -37,6 +60,10 @@
         "liblog",
     ],
 
+    static_libs: [
+        "resourceobserver_aidl_interface-ndk_platform",
+    ],
+
     include_dirs: ["frameworks/av/include"],
 
     cflags: [
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 3d36f8e..90a04ac 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -36,18 +36,54 @@
 #include <unistd.h>
 
 #include "ResourceManagerService.h"
+#include "ResourceObserverService.h"
 #include "ServiceLog.h"
 
 namespace android {
 
+//static
+std::mutex ResourceManagerService::sCookieLock;
+//static
+uintptr_t ResourceManagerService::sCookieCounter = 0;
+//static
+std::map<uintptr_t, sp<DeathNotifier> > ResourceManagerService::sCookieToDeathNotifierMap;
+
+class DeathNotifier : public RefBase {
+public:
+    DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
+            int pid, int64_t clientId);
+
+    virtual ~DeathNotifier() {}
+
+    // Implement death recipient
+    static void BinderDiedCallback(void* cookie);
+    virtual void binderDied();
+
+protected:
+    std::weak_ptr<ResourceManagerService> mService;
+    int mPid;
+    int64_t mClientId;
+};
+
 DeathNotifier::DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
         int pid, int64_t clientId)
     : mService(service), mPid(pid), mClientId(clientId) {}
 
 //static
 void DeathNotifier::BinderDiedCallback(void* cookie) {
-    auto thiz = static_cast<DeathNotifier*>(cookie);
-    thiz->binderDied();
+    sp<DeathNotifier> notifier;
+    {
+        std::scoped_lock lock{ResourceManagerService::sCookieLock};
+        auto it = ResourceManagerService::sCookieToDeathNotifierMap.find(
+                reinterpret_cast<uintptr_t>(cookie));
+        if (it == ResourceManagerService::sCookieToDeathNotifierMap.end()) {
+            return;
+        }
+        notifier = it->second;
+    }
+    if (notifier.get() != nullptr) {
+        notifier->binderDied();
+    }
 }
 
 void DeathNotifier::binderDied() {
@@ -61,7 +97,27 @@
     service->overridePid(mPid, -1);
     // thiz is freed in the call below, so it must be last call referring thiz
     service->removeResource(mPid, mClientId, false);
+}
 
+class OverrideProcessInfoDeathNotifier : public DeathNotifier {
+public:
+    OverrideProcessInfoDeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
+            int pid) : DeathNotifier(service, pid, 0) {}
+
+    virtual ~OverrideProcessInfoDeathNotifier() {}
+
+    virtual void binderDied();
+};
+
+void OverrideProcessInfoDeathNotifier::binderDied() {
+    // Don't check for pid validity since we know it's already dead.
+    std::shared_ptr<ResourceManagerService> service = mService.lock();
+    if (service == nullptr) {
+        ALOGW("ResourceManagerService is dead as well.");
+        return;
+    }
+
+    service->removeProcessInfoOverride(mPid);
 }
 
 template <typename T>
@@ -116,6 +172,7 @@
         info.uid = uid;
         info.clientId = clientId;
         info.client = client;
+        info.cookie = 0;
         info.pendingRemoval = false;
 
         index = infos.add(clientId, info);
@@ -267,6 +324,13 @@
     if (status != STATUS_OK) {
         return;
     }
+
+    std::shared_ptr<ResourceObserverService> observerService =
+            ResourceObserverService::instantiate();
+
+    if (observerService != nullptr) {
+        service->setObserverService(observerService);
+    }
     // TODO: mediaserver main() is already starting the thread pool,
     // move this to mediaserver main() when other services in mediaserver
     // are converted to ndk-platform aidl.
@@ -275,6 +339,11 @@
 
 ResourceManagerService::~ResourceManagerService() {}
 
+void ResourceManagerService::setObserverService(
+        const std::shared_ptr<ResourceObserverService>& observerService) {
+    mObserverService = observerService;
+}
+
 Status ResourceManagerService::config(const std::vector<MediaResourcePolicyParcel>& policies) {
     String8 log = String8::format("config(%s)", getString(policies).string());
     mServiceLog->add(log);
@@ -358,6 +427,7 @@
     }
     ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
     ResourceInfo& info = getResourceInfoForEdit(uid, clientId, client, infos);
+    ResourceList resourceAdded;
 
     for (size_t i = 0; i < resources.size(); ++i) {
         const auto &res = resources[i];
@@ -379,11 +449,20 @@
         } else {
             mergeResources(info.resources[resType], res);
         }
+        // Add it to the list of added resources for observers.
+        auto it = resourceAdded.find(resType);
+        if (it == resourceAdded.end()) {
+            resourceAdded[resType] = res;
+        } else {
+            mergeResources(it->second, res);
+        }
     }
-    if (info.deathNotifier == nullptr && client != nullptr) {
-        info.deathNotifier = new DeathNotifier(ref<ResourceManagerService>(), pid, clientId);
-        AIBinder_linkToDeath(client->asBinder().get(),
-                mDeathRecipient.get(), info.deathNotifier.get());
+    if (info.cookie == 0 && client != nullptr) {
+        info.cookie = addCookieAndLink_l(client->asBinder(),
+                new DeathNotifier(ref<ResourceManagerService>(), pid, clientId));
+    }
+    if (mObserverService != nullptr && !resourceAdded.empty()) {
+        mObserverService->onResourceAdded(uid, pid, resourceAdded);
     }
     notifyResourceGranted(pid, resources);
     return Status::ok();
@@ -415,7 +494,7 @@
     }
 
     ResourceInfo &info = infos.editValueAt(index);
-
+    ResourceList resourceRemoved;
     for (size_t i = 0; i < resources.size(); ++i) {
         const auto &res = resources[i];
         const auto resType = std::tuple(res.type, res.subType, res.id);
@@ -427,14 +506,27 @@
         // ignore if we don't have it
         if (info.resources.find(resType) != info.resources.end()) {
             MediaResourceParcel &resource = info.resources[resType];
+            MediaResourceParcel actualRemoved = res;
             if (resource.value > res.value) {
                 resource.value -= res.value;
             } else {
                 onLastRemoved(res, info);
                 info.resources.erase(resType);
+                actualRemoved.value = resource.value;
+            }
+
+            // Add it to the list of removed resources for observers.
+            auto it = resourceRemoved.find(resType);
+            if (it == resourceRemoved.end()) {
+                resourceRemoved[resType] = actualRemoved;
+            } else {
+                mergeResources(it->second, actualRemoved);
             }
         }
     }
+    if (mObserverService != nullptr && !resourceRemoved.empty()) {
+        mObserverService->onResourceRemoved(info.uid, pid, resourceRemoved);
+    }
     return Status::ok();
 }
 
@@ -472,8 +564,11 @@
         onLastRemoved(it->second, info);
     }
 
-    AIBinder_unlinkToDeath(info.client->asBinder().get(),
-            mDeathRecipient.get(), info.deathNotifier.get());
+    removeCookieAndUnlink_l(info.client->asBinder(), info.cookie);
+
+    if (mObserverService != nullptr && !info.resources.empty()) {
+        mObserverService->onResourceRemoved(info.uid, pid, info.resources);
+    }
 
     infos.removeItemsAt(index);
     return Status::ok();
@@ -651,6 +746,83 @@
     return Status::ok();
 }
 
+Status ResourceManagerService::overrideProcessInfo(
+        const std::shared_ptr<IResourceManagerClient>& client,
+        int pid,
+        int procState,
+        int oomScore) {
+    String8 log = String8::format("overrideProcessInfo(pid %d, procState %d, oomScore %d)",
+            pid, procState, oomScore);
+    mServiceLog->add(log);
+
+    // Only allow the override if the caller already can access process state and oom scores.
+    int callingPid = AIBinder_getCallingPid();
+    if (callingPid != getpid() && (callingPid != pid || !checkCallingPermission(String16(
+            "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE")))) {
+        ALOGE("Permission Denial: overrideProcessInfo method from pid=%d", callingPid);
+        return Status::fromServiceSpecificError(PERMISSION_DENIED);
+    }
+
+    if (client == nullptr) {
+        return Status::fromServiceSpecificError(BAD_VALUE);
+    }
+
+    Mutex::Autolock lock(mLock);
+    removeProcessInfoOverride_l(pid);
+
+    if (!mProcessInfo->overrideProcessInfo(pid, procState, oomScore)) {
+        // Override value is rejected by ProcessInfo.
+        return Status::fromServiceSpecificError(BAD_VALUE);
+    }
+
+    uintptr_t cookie = addCookieAndLink_l(client->asBinder(),
+            new OverrideProcessInfoDeathNotifier(ref<ResourceManagerService>(), pid));
+
+    mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{cookie, client});
+
+    return Status::ok();
+}
+
+uintptr_t ResourceManagerService::addCookieAndLink_l(
+        ::ndk::SpAIBinder binder, const sp<DeathNotifier>& notifier) {
+    std::scoped_lock lock{sCookieLock};
+
+    uintptr_t cookie;
+    // Need to skip cookie 0 (if it wraps around). ResourceInfo has cookie initialized to 0
+    // indicating the death notifier is not created yet.
+    while ((cookie = ++sCookieCounter) == 0);
+    AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(), (void*)cookie);
+    sCookieToDeathNotifierMap.emplace(cookie, notifier);
+
+    return cookie;
+}
+
+void ResourceManagerService::removeCookieAndUnlink_l(
+        ::ndk::SpAIBinder binder, uintptr_t cookie) {
+    std::scoped_lock lock{sCookieLock};
+    AIBinder_unlinkToDeath(binder.get(), mDeathRecipient.get(), (void*)cookie);
+    sCookieToDeathNotifierMap.erase(cookie);
+}
+
+void ResourceManagerService::removeProcessInfoOverride(int pid) {
+    Mutex::Autolock lock(mLock);
+
+    removeProcessInfoOverride_l(pid);
+}
+
+void ResourceManagerService::removeProcessInfoOverride_l(int pid) {
+    auto it = mProcessInfoOverrideMap.find(pid);
+    if (it == mProcessInfoOverrideMap.end()) {
+        return;
+    }
+
+    mProcessInfo->removeProcessInfoOverride(pid);
+
+    removeCookieAndUnlink_l(it->second.client->asBinder(), it->second.cookie);
+
+    mProcessInfoOverrideMap.erase(pid);
+}
+
 Status ResourceManagerService::markClientForPendingRemoval(int32_t pid, int64_t clientId) {
     String8 log = String8::format(
             "markClientForPendingRemoval(pid %d, clientId %lld)",
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 49c247e..1aa1e09 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -19,6 +19,7 @@
 #define ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
 
 #include <map>
+#include <mutex>
 
 #include <aidl/android/media/BnResourceManagerService.h>
 #include <arpa/inet.h>
@@ -33,6 +34,7 @@
 
 class DeathNotifier;
 class ResourceManagerService;
+class ResourceObserverService;
 class ServiceLog;
 struct ProcessInfoInterface;
 
@@ -50,7 +52,7 @@
     int64_t clientId;
     uid_t uid;
     std::shared_ptr<IResourceManagerClient> client;
-    sp<DeathNotifier> deathNotifier;
+    uintptr_t cookie{0};
     ResourceList resources;
     bool pendingRemoval{false};
 };
@@ -59,22 +61,6 @@
 typedef KeyedVector<int64_t, ResourceInfo> ResourceInfos;
 typedef KeyedVector<int, ResourceInfos> PidResourceInfosMap;
 
-class DeathNotifier : public RefBase {
-public:
-    DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
-            int pid, int64_t clientId);
-
-    ~DeathNotifier() {}
-
-    // Implement death recipient
-    static void BinderDiedCallback(void* cookie);
-    void binderDied();
-
-private:
-    std::weak_ptr<ResourceManagerService> mService;
-    int mPid;
-    int64_t mClientId;
-};
 class ResourceManagerService : public BnResourceManagerService {
 public:
     struct SystemCallbackInterface : public RefBase {
@@ -95,6 +81,8 @@
             const sp<ProcessInfoInterface> &processInfo,
             const sp<SystemCallbackInterface> &systemResource);
     virtual ~ResourceManagerService();
+    void setObserverService(
+            const std::shared_ptr<ResourceObserverService>& observerService);
 
     // IResourceManagerService interface
     Status config(const std::vector<MediaResourcePolicyParcel>& policies) override;
@@ -125,12 +113,20 @@
             int originalPid,
             int newPid) override;
 
+    Status overrideProcessInfo(
+            const std::shared_ptr<IResourceManagerClient>& client,
+            int pid,
+            int procState,
+            int oomScore) override;
+
     Status markClientForPendingRemoval(int32_t pid, int64_t clientId) override;
 
     Status removeResource(int pid, int64_t clientId, bool checkValid);
 
 private:
     friend class ResourceManagerServiceTest;
+    friend class DeathNotifier;
+    friend class OverrideProcessInfoDeathNotifier;
 
     // Gets the list of all the clients who own the specified resource type.
     // Returns false if any client belongs to a process with higher priority than the
@@ -170,6 +166,12 @@
     // Get priority from process's pid
     bool getPriority_l(int pid, int* priority);
 
+    void removeProcessInfoOverride(int pid);
+
+    void removeProcessInfoOverride_l(int pid);
+    uintptr_t addCookieAndLink_l(::ndk::SpAIBinder binder, const sp<DeathNotifier>& notifier);
+    void removeCookieAndUnlink_l(::ndk::SpAIBinder binder, uintptr_t cookie);
+
     mutable Mutex mLock;
     sp<ProcessInfoInterface> mProcessInfo;
     sp<SystemCallbackInterface> mSystemCB;
@@ -179,7 +181,17 @@
     bool mSupportsSecureWithNonSecureCodec;
     int32_t mCpuBoostCount;
     ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+    struct ProcessInfoOverride {
+        uintptr_t cookie;
+        std::shared_ptr<IResourceManagerClient> client;
+    };
     std::map<int, int> mOverridePidMap;
+    std::map<pid_t, ProcessInfoOverride> mProcessInfoOverrideMap;
+    static std::mutex sCookieLock;
+    static uintptr_t sCookieCounter GUARDED_BY(sCookieLock);
+    static std::map<uintptr_t, sp<DeathNotifier> > sCookieToDeathNotifierMap
+            GUARDED_BY(sCookieLock);
+    std::shared_ptr<ResourceObserverService> mObserverService;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/services/mediaresourcemanager/ResourceObserverService.cpp b/services/mediaresourcemanager/ResourceObserverService.cpp
new file mode 100644
index 0000000..7c4c875
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceObserverService.cpp
@@ -0,0 +1,312 @@
+/**
+ *
+ * Copyright 2020, 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_NDEBUG 0
+#define LOG_TAG "ResourceObserverService"
+#include <utils/Log.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/IServiceManager.h>
+#include <utils/String16.h>
+#include <aidl/android/media/MediaResourceParcel.h>
+
+#include "ResourceObserverService.h"
+
+namespace aidl {
+namespace android {
+namespace media {
+bool operator<(const MediaObservableFilter& lhs, const MediaObservableFilter &rhs) {
+    return lhs.type < rhs.type || (lhs.type == rhs.type && lhs.eventFilter < rhs.eventFilter);
+}
+}}} // namespace ::aidl::android::media
+
+namespace android {
+
+using ::aidl::android::media::MediaResourceParcel;
+using ::aidl::android::media::MediaObservableEvent;
+
+// MediaObservableEvent will be used as uint64_t flags.
+static_assert(sizeof(MediaObservableEvent) == sizeof(uint64_t));
+
+static std::vector<MediaObservableEvent> sEvents = {
+        MediaObservableEvent::kBusy,
+        MediaObservableEvent::kIdle,
+};
+
+static MediaObservableType getObservableType(const MediaResourceParcel& res) {
+    if (res.subType == MediaResourceSubType::kVideoCodec) {
+        if (res.type == MediaResourceType::kNonSecureCodec) {
+            return MediaObservableType::kVideoNonSecureCodec;
+        }
+        if (res.type == MediaResourceType::kSecureCodec) {
+            return MediaObservableType::kVideoSecureCodec;
+        }
+    }
+    return MediaObservableType::kInvalid;
+}
+
+//static
+std::mutex ResourceObserverService::sDeathRecipientLock;
+//static
+std::map<uintptr_t, std::shared_ptr<ResourceObserverService::DeathRecipient> >
+ResourceObserverService::sDeathRecipientMap;
+
+struct ResourceObserverService::DeathRecipient {
+    DeathRecipient(ResourceObserverService* _service,
+            const std::shared_ptr<IResourceObserver>& _observer)
+        : service(_service), observer(_observer) {}
+    ~DeathRecipient() {}
+
+    void binderDied() {
+        if (service != nullptr) {
+            service->unregisterObserver(observer);
+        }
+    }
+
+    ResourceObserverService* service;
+    std::shared_ptr<IResourceObserver> observer;
+};
+
+// static
+void ResourceObserverService::BinderDiedCallback(void* cookie) {
+    uintptr_t id = reinterpret_cast<uintptr_t>(cookie);
+
+    ALOGW("Observer %lld is dead", (long long)id);
+
+    std::shared_ptr<DeathRecipient> recipient;
+
+    {
+        std::scoped_lock lock{sDeathRecipientLock};
+
+        auto it = sDeathRecipientMap.find(id);
+        if (it != sDeathRecipientMap.end()) {
+            recipient = it->second;
+        }
+    }
+
+    if (recipient != nullptr) {
+        recipient->binderDied();
+    }
+}
+
+//static
+std::shared_ptr<ResourceObserverService> ResourceObserverService::instantiate() {
+    std::shared_ptr<ResourceObserverService> observerService =
+            ::ndk::SharedRefBase::make<ResourceObserverService>();
+    binder_status_t status = AServiceManager_addService(observerService->asBinder().get(),
+            ResourceObserverService::getServiceName());
+    if (status != STATUS_OK) {
+        return nullptr;
+    }
+    return observerService;
+}
+
+ResourceObserverService::ResourceObserverService()
+    : mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)) {}
+
+binder_status_t ResourceObserverService::dump(
+        int fd, const char** /*args*/, uint32_t /*numArgs*/) {
+    String8 result;
+
+    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+        result.format("Permission Denial: "
+                "can't dump ResourceManagerService from pid=%d, uid=%d\n",
+                AIBinder_getCallingPid(),
+                AIBinder_getCallingUid());
+        write(fd, result.string(), result.size());
+        return PERMISSION_DENIED;
+    }
+
+    result.appendFormat("ResourceObserverService: %p\n", this);
+    result.appendFormat("  Registered Observers: %zu\n", mObserverInfoMap.size());
+
+    {
+        std::scoped_lock lock{mObserverLock};
+
+        for (auto &observer : mObserverInfoMap) {
+            result.appendFormat("    Observer %p:\n", observer.second.binder.get());
+            for (auto &observable : observer.second.filters) {
+                String8 enabledEventsStr;
+                for (auto &event : sEvents) {
+                    if (((uint64_t)observable.eventFilter & (uint64_t)event) != 0) {
+                        if (!enabledEventsStr.isEmpty()) {
+                            enabledEventsStr.append("|");
+                        }
+                        enabledEventsStr.append(toString(event).c_str());
+                    }
+                }
+                result.appendFormat("      %s: %s\n",
+                        toString(observable.type).c_str(), enabledEventsStr.c_str());
+            }
+        }
+    }
+
+    write(fd, result.string(), result.size());
+    return OK;
+}
+
+Status ResourceObserverService::registerObserver(
+        const std::shared_ptr<IResourceObserver>& in_observer,
+        const std::vector<MediaObservableFilter>& in_filters) {
+    // TODO(chz): Guard this by a permission.
+
+    ::ndk::SpAIBinder binder = in_observer->asBinder();
+
+    {
+        std::scoped_lock lock{mObserverLock};
+
+        if (mObserverInfoMap.find((uintptr_t)binder.get()) != mObserverInfoMap.end()) {
+            return Status::fromServiceSpecificError(ALREADY_EXISTS);
+        }
+
+        if (in_filters.empty()) {
+            return Status::fromServiceSpecificError(BAD_VALUE);
+        }
+
+        // Add observer info.
+        mObserverInfoMap.emplace((uintptr_t)binder.get(),
+                ObserverInfo{binder, in_observer, in_filters});
+
+        // Add observer to observable->subscribers map.
+        for (auto &filter : in_filters) {
+            for (auto &event : sEvents) {
+                if (!((uint64_t)filter.eventFilter & (uint64_t)event)) {
+                    continue;
+                }
+                MediaObservableFilter key{filter.type, event};
+                mObservableToSubscribersMap[key].emplace((uintptr_t)binder.get(), in_observer);
+            }
+        }
+    }
+
+    // Add death binder and link.
+    uintptr_t cookie = (uintptr_t)binder.get();
+    {
+        std::scoped_lock lock{sDeathRecipientLock};
+        sDeathRecipientMap.emplace(
+                cookie, std::make_shared<DeathRecipient>(this, in_observer));
+    }
+
+    AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(),
+                         reinterpret_cast<void*>(cookie));
+
+    return Status::ok();
+}
+
+Status ResourceObserverService::unregisterObserver(
+        const std::shared_ptr<IResourceObserver>& in_observer) {
+    // TODO(chz): Guard this by a permission.
+
+    ::ndk::SpAIBinder binder = in_observer->asBinder();
+
+    {
+        std::scoped_lock lock{mObserverLock};
+
+        auto it = mObserverInfoMap.find((uintptr_t)binder.get());
+        if (it == mObserverInfoMap.end()) {
+            return Status::fromServiceSpecificError(NAME_NOT_FOUND);
+        }
+
+        // Remove observer from observable->subscribers map.
+        for (auto &filter : it->second.filters) {
+            for (auto &event : sEvents) {
+                if (!((uint64_t)filter.eventFilter & (uint64_t)event)) {
+                    continue;
+                }
+                MediaObservableFilter key{filter.type, event};
+                mObservableToSubscribersMap[key].erase((uintptr_t)binder.get());
+
+                //Remove the entry if there's no more subscribers.
+                if (mObservableToSubscribersMap[key].empty()) {
+                    mObservableToSubscribersMap.erase(key);
+                }
+            }
+        }
+
+        // Remove observer info.
+        mObserverInfoMap.erase(it);
+    }
+
+    // Unlink and remove death binder.
+    uintptr_t cookie = (uintptr_t)binder.get();
+    AIBinder_unlinkToDeath(binder.get(), mDeathRecipient.get(),
+            reinterpret_cast<void*>(cookie));
+
+    {
+        std::scoped_lock lock{sDeathRecipientLock};
+        sDeathRecipientMap.erase(cookie);
+    }
+
+    return Status::ok();
+}
+
+void ResourceObserverService::notifyObservers(
+        MediaObservableEvent event, int uid, int pid, const ResourceList &resources) {
+    struct CalleeInfo {
+        std::shared_ptr<IResourceObserver> observer;
+        std::vector<MediaObservableParcel> monitors;
+    };
+    // Build a consolidated list of observers to call with their respective observables.
+    std::map<uintptr_t, CalleeInfo> calleeList;
+
+    {
+        std::scoped_lock lock{mObserverLock};
+
+        for (auto &res : resources) {
+            // Skip if this resource doesn't map to any observable type.
+            MediaObservableType observableType = getObservableType(res.second);
+            if (observableType == MediaObservableType::kInvalid) {
+                continue;
+            }
+            MediaObservableFilter key{observableType, event};
+            // Skip if no one subscribed to this observable.
+            auto observableIt = mObservableToSubscribersMap.find(key);
+            if (observableIt == mObservableToSubscribersMap.end()) {
+                continue;
+            }
+            // Loop through all subsribers.
+            for (auto &subscriber : observableIt->second) {
+                auto calleeIt = calleeList.find(subscriber.first);
+                if (calleeIt == calleeList.end()) {
+                    calleeList.emplace(subscriber.first, CalleeInfo{
+                        subscriber.second, {{observableType, res.second.value}}});
+                } else {
+                    calleeIt->second.monitors.push_back({observableType, res.second.value});
+                }
+            }
+        }
+    }
+
+    // Finally call the observers about the status change.
+    for (auto &calleeInfo : calleeList) {
+        calleeInfo.second.observer->onStatusChanged(
+                event, uid, pid, calleeInfo.second.monitors);
+    }
+}
+
+void ResourceObserverService::onResourceAdded(
+        int uid, int pid, const ResourceList &resources) {
+    notifyObservers(MediaObservableEvent::kBusy, uid, pid, resources);
+}
+
+void ResourceObserverService::onResourceRemoved(
+        int uid, int pid, const ResourceList &resources) {
+    notifyObservers(MediaObservableEvent::kIdle, uid, pid, resources);
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ResourceObserverService.h b/services/mediaresourcemanager/ResourceObserverService.h
new file mode 100644
index 0000000..46bc5fb
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceObserverService.h
@@ -0,0 +1,95 @@
+/**
+ *
+ * Copyright 2020, 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_MEDIA_RESOURCE_OBSERVER_SERVICE_H
+#define ANDROID_MEDIA_RESOURCE_OBSERVER_SERVICE_H
+
+#include <map>
+
+#include <aidl/android/media/BnResourceObserverService.h>
+#include "ResourceManagerService.h"
+
+namespace android {
+
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::BnResourceObserverService;
+using ::aidl::android::media::IResourceObserver;
+using ::aidl::android::media::MediaObservableFilter;
+using ::aidl::android::media::MediaObservableParcel;
+using ::aidl::android::media::MediaObservableType;
+using ::aidl::android::media::MediaObservableEvent;
+
+class ResourceObserverService : public BnResourceObserverService {
+public:
+
+    static char const *getServiceName() { return "media.resource_observer"; }
+    static std::shared_ptr<ResourceObserverService> instantiate();
+
+    virtual inline binder_status_t dump(
+            int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/);
+
+    ResourceObserverService();
+    virtual ~ResourceObserverService() {}
+
+    // IResourceObserverService interface
+    Status registerObserver(const std::shared_ptr<IResourceObserver>& in_observer,
+            const std::vector<MediaObservableFilter>& in_filters) override;
+
+    Status unregisterObserver(const std::shared_ptr<IResourceObserver>& in_observer) override;
+    // ~IResourceObserverService interface
+
+    // Called by ResourceManagerService when resources are added.
+    void onResourceAdded(int uid, int pid, const ResourceList &resources);
+
+    // Called by ResourceManagerService when resources are removed.
+    void onResourceRemoved(int uid, int pid, const ResourceList &resources);
+
+private:
+    struct ObserverInfo {
+        ::ndk::SpAIBinder binder;
+        std::shared_ptr<IResourceObserver> observer;
+        std::vector<MediaObservableFilter> filters;
+    };
+    struct DeathRecipient;
+
+    // Below maps are all keyed on the observer's binder ptr value.
+    using ObserverInfoMap = std::map<uintptr_t, ObserverInfo>;
+    using SubscriberMap = std::map<uintptr_t, std::shared_ptr<IResourceObserver>>;
+
+    std::mutex mObserverLock;
+    // Binder->ObserverInfo
+    ObserverInfoMap mObserverInfoMap GUARDED_BY(mObserverLock);
+    // Observable(<type,event>)->Subscribers
+    std::map<MediaObservableFilter, SubscriberMap> mObservableToSubscribersMap
+            GUARDED_BY(mObserverLock);
+
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+    // Binder death handling.
+    static std::mutex sDeathRecipientLock;
+    static std::map<uintptr_t, std::shared_ptr<DeathRecipient>> sDeathRecipientMap
+            GUARDED_BY(sDeathRecipientLock);
+    static void BinderDiedCallback(void* cookie);
+
+    void notifyObservers(MediaObservableEvent event,
+            int uid, int pid, const ResourceList &resources);
+};
+
+// ----------------------------------------------------------------------------
+} // namespace android
+
+#endif // ANDROID_MEDIA_RESOURCE_OBSERVER_SERVICE_H
diff --git a/services/mediaresourcemanager/TEST_MAPPING b/services/mediaresourcemanager/TEST_MAPPING
index 418b159..52ad441 100644
--- a/services/mediaresourcemanager/TEST_MAPPING
+++ b/services/mediaresourcemanager/TEST_MAPPING
@@ -5,6 +5,9 @@
     },
     {
        "name": "ServiceLog_test"
+    },
+    {
+       "name": "ResourceObserverService_test"
     }
   ]
 }
diff --git a/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl b/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl
index 1b2d522..5cf8686 100644
--- a/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl
@@ -96,6 +96,28 @@
     void overridePid(int originalPid, int newPid);
 
     /**
+     * Override the process state and OOM score of the calling process with the
+     * the specified values. This is used by native service processes to specify
+     * these values for ResourceManagerService to use. ResourceManagerService usually
+     * gets these values from ActivityManagerService, however, ActivityManagerService
+     * doesn't track native service processes.
+     *
+     * @param client a token for the ResourceManagerService to link to the caller and
+     *              receive notification if it goes away. This is needed for clearing
+     *              the overrides.
+     * @param pid pid of the calling process.
+     * @param procState the process state value that ResourceManagerService should
+     *                  use for this pid.
+     * @param oomScore the oom score value that ResourceManagerService should
+     *                  use for this pid.
+     */
+    void overrideProcessInfo(
+            IResourceManagerClient client,
+            int pid,
+            int procState,
+            int oomScore);
+
+    /**
      * Mark a client for pending removal
      *
      * @param pid pid from which the client's resources will be removed.
diff --git a/services/mediaresourcemanager/aidl/android/media/IResourceObserver.aidl b/services/mediaresourcemanager/aidl/android/media/IResourceObserver.aidl
new file mode 100644
index 0000000..462009a
--- /dev/null
+++ b/services/mediaresourcemanager/aidl/android/media/IResourceObserver.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android.media;
+
+import android.media.MediaObservableEvent;
+import android.media.MediaObservableParcel;
+
+/**
+ * IResourceObserver interface for receiving observable resource updates
+ * from IResourceObserverService.
+ *
+ * {@hide}
+ */
+interface IResourceObserver {
+    /**
+     * Called when an observed resource is granted to a client.
+     *
+     * @param event the status change that happened to the resource.
+     * @param uid uid to which the resource is associated.
+     * @param pid pid to which the resource is associated.
+     * @param observables the resources whose status has changed.
+     */
+    oneway void onStatusChanged(MediaObservableEvent event,
+        int uid, int pid, in MediaObservableParcel[] observables);
+}
diff --git a/services/mediaresourcemanager/aidl/android/media/IResourceObserverService.aidl b/services/mediaresourcemanager/aidl/android/media/IResourceObserverService.aidl
new file mode 100644
index 0000000..08f4ca0
--- /dev/null
+++ b/services/mediaresourcemanager/aidl/android/media/IResourceObserverService.aidl
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android.media;
+
+import android.media.IResourceObserver;
+import android.media.MediaObservableFilter;
+
+/**
+ * IResourceObserverService interface for registering an IResourceObserver
+ * callback to receive status updates about observable media resources.
+ *
+ * {@hide}
+ */
+interface IResourceObserverService {
+
+    /**
+     * Register an observer on the IResourceObserverService to receive
+     * status updates for observable resources.
+     *
+     * @param observer the observer to register.
+     * @param filters an array of filters for resources and events to receive
+     *                updates for.
+     */
+    void registerObserver(
+            IResourceObserver observer,
+            in MediaObservableFilter[] filters);
+
+    /**
+     * Unregister an observer from the IResourceObserverService.
+     * The observer will stop receiving the status updates.
+     *
+     * @param observer the observer to unregister.
+     */
+    void unregisterObserver(IResourceObserver observer);
+}
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaObservableEvent.aidl b/services/mediaresourcemanager/aidl/android/media/MediaObservableEvent.aidl
new file mode 100644
index 0000000..56ab24d
--- /dev/null
+++ b/services/mediaresourcemanager/aidl/android/media/MediaObservableEvent.aidl
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android.media;
+
+/**
+ * Enums for media observable events.
+ *
+ * These values are used as bitmasks to indicate the events that the
+ * observer is interested in in the MediaObservableFilter objects passed to
+ * IResourceObserverService::registerObserver().
+ *
+ * {@hide}
+ */
+@Backing(type="long")
+enum MediaObservableEvent {
+    /**
+     * A media resource is granted to a client and becomes busy.
+     */
+    kBusy = 1,
+
+    /**
+     * A media resource is released by a client and becomes idle.
+     */
+    kIdle = 2,
+
+    /**
+     * A bitmask that covers all observable events defined.
+     */
+    kAll = ~0,
+}
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaObservableFilter.aidl b/services/mediaresourcemanager/aidl/android/media/MediaObservableFilter.aidl
new file mode 100644
index 0000000..38f7e39
--- /dev/null
+++ b/services/mediaresourcemanager/aidl/android/media/MediaObservableFilter.aidl
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android.media;
+
+import android.media.MediaObservableType;
+import android.media.MediaObservableEvent;
+
+/**
+ * Description of an observable resource and its associated events that the
+ * observer is interested in.
+ *
+ * {@hide}
+ */
+parcelable MediaObservableFilter {
+    /**
+     * Type of the observable media resource.
+     */
+    MediaObservableType type;
+
+    /**
+     * Events that the observer is interested in.
+     *
+     * This field is a bitwise-OR of the events in MediaObservableEvent. If a
+     * particular event's bit is set, it means that updates should be sent for
+     * that event. For example, if the observer is only interested in receiving
+     * updates when a resource becomes available, it should only set 'kIdle'.
+     */
+    MediaObservableEvent eventFilter;
+}
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaObservableParcel.aidl b/services/mediaresourcemanager/aidl/android/media/MediaObservableParcel.aidl
new file mode 100644
index 0000000..c4233e1
--- /dev/null
+++ b/services/mediaresourcemanager/aidl/android/media/MediaObservableParcel.aidl
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android.media;
+
+import android.media.MediaObservableType;
+
+/**
+ * Description of an observable resource whose status has changed.
+ *
+ * {@hide}
+ */
+parcelable MediaObservableParcel {
+    /**
+     * Type of the observable media resource.
+     */
+    MediaObservableType type;// = MediaObservableType::kInvalid;
+
+    /**
+     * Number of units of the observable resource (number of codecs, bytes of
+     * graphic memory, etc.).
+     */
+    long value = 0;
+}
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaObservableType.aidl b/services/mediaresourcemanager/aidl/android/media/MediaObservableType.aidl
new file mode 100644
index 0000000..ed202da
--- /dev/null
+++ b/services/mediaresourcemanager/aidl/android/media/MediaObservableType.aidl
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android.media;
+
+/**
+ * Type enums of observable media resources.
+ *
+ * {@hide}
+ */
+@Backing(type="int")
+enum MediaObservableType {
+    kInvalid = 0,
+
+    //kVideoStart = 1000,
+    kVideoSecureCodec = 1000,
+    kVideoNonSecureCodec = 1001,
+
+    //kAudioStart = 2000,
+
+    //kGraphicMemory = 3000,
+}
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index 6b2ef69..308ee91 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -40,3 +40,28 @@
         "-Wall",
     ],
 }
+
+cc_test {
+    name: "ResourceObserverService_test",
+    srcs: ["ResourceObserverService_test.cpp"],
+    test_suites: ["device-tests"],
+    static_libs: [
+        "libresourcemanagerservice",
+        "resourceobserver_aidl_interface-ndk_platform",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+        "liblog",
+        "libmedia",
+        "libutils",
+    ],
+    include_dirs: [
+        "frameworks/av/include",
+        "frameworks/av/services/mediaresourcemanager",
+    ],
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+}
diff --git a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
new file mode 100644
index 0000000..4cf5f0a
--- /dev/null
+++ b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
@@ -0,0 +1,224 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "ResourceManagerService.h"
+#include <aidl/android/media/BnResourceManagerClient.h>
+#include <media/MediaResource.h>
+#include <media/MediaResourcePolicy.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/ProcessInfoInterface.h>
+
+namespace aidl {
+namespace android {
+namespace media {
+bool operator== (const MediaResourceParcel& lhs, const MediaResourceParcel& rhs) {
+    return lhs.type == rhs.type && lhs.subType == rhs.subType &&
+            lhs.id == rhs.id && lhs.value == rhs.value;
+}
+}}}
+
+namespace android {
+
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::BnResourceManagerClient;
+using ::aidl::android::media::IResourceManagerService;
+using ::aidl::android::media::IResourceManagerClient;
+using ::aidl::android::media::MediaResourceParcel;
+
+static int64_t getId(const std::shared_ptr<IResourceManagerClient>& client) {
+    return (int64_t) client.get();
+}
+
+struct TestProcessInfo : public ProcessInfoInterface {
+    TestProcessInfo() {}
+    virtual ~TestProcessInfo() {}
+
+    virtual bool getPriority(int pid, int *priority) {
+        // For testing, use pid as priority.
+        // Lower the value higher the priority.
+        *priority = pid;
+        return true;
+    }
+
+    virtual bool isValidPid(int /* pid */) {
+        return true;
+    }
+
+    virtual bool overrideProcessInfo(
+            int /* pid */, int /* procState */, int /* oomScore */) {
+        return true;
+    }
+
+    virtual void removeProcessInfoOverride(int /* pid */) {
+    }
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(TestProcessInfo);
+};
+
+struct TestSystemCallback :
+        public ResourceManagerService::SystemCallbackInterface {
+    TestSystemCallback() :
+        mLastEvent({EventType::INVALID, 0}), mEventCount(0) {}
+
+    enum EventType {
+        INVALID          = -1,
+        VIDEO_ON         = 0,
+        VIDEO_OFF        = 1,
+        VIDEO_RESET      = 2,
+        CPUSET_ENABLE    = 3,
+        CPUSET_DISABLE   = 4,
+    };
+
+    struct EventEntry {
+        EventType type;
+        int arg;
+    };
+
+    virtual void noteStartVideo(int uid) override {
+        mLastEvent = {EventType::VIDEO_ON, uid};
+        mEventCount++;
+    }
+
+    virtual void noteStopVideo(int uid) override {
+        mLastEvent = {EventType::VIDEO_OFF, uid};
+        mEventCount++;
+    }
+
+    virtual void noteResetVideo() override {
+        mLastEvent = {EventType::VIDEO_RESET, 0};
+        mEventCount++;
+    }
+
+    virtual bool requestCpusetBoost(bool enable) override {
+        mLastEvent = {enable ? EventType::CPUSET_ENABLE : EventType::CPUSET_DISABLE, 0};
+        mEventCount++;
+        return true;
+    }
+
+    size_t eventCount() { return mEventCount; }
+    EventType lastEventType() { return mLastEvent.type; }
+    EventEntry lastEvent() { return mLastEvent; }
+
+protected:
+    virtual ~TestSystemCallback() {}
+
+private:
+    EventEntry mLastEvent;
+    size_t mEventCount;
+
+    DISALLOW_EVIL_CONSTRUCTORS(TestSystemCallback);
+};
+
+
+struct TestClient : public BnResourceManagerClient {
+    TestClient(int pid, const std::shared_ptr<ResourceManagerService> &service)
+        : mReclaimed(false), mPid(pid), mService(service) {}
+
+    Status reclaimResource(bool* _aidl_return) override {
+        mService->removeClient(mPid, getId(ref<TestClient>()));
+        mReclaimed = true;
+        *_aidl_return = true;
+        return Status::ok();
+    }
+
+    Status getName(::std::string* _aidl_return) override {
+        *_aidl_return = "test_client";
+        return Status::ok();
+    }
+
+    bool reclaimed() const {
+        return mReclaimed;
+    }
+
+    void reset() {
+        mReclaimed = false;
+    }
+
+    virtual ~TestClient() {}
+
+private:
+    bool mReclaimed;
+    int mPid;
+    std::shared_ptr<ResourceManagerService> mService;
+    DISALLOW_EVIL_CONSTRUCTORS(TestClient);
+};
+
+static const int kTestPid1 = 30;
+static const int kTestUid1 = 1010;
+
+static const int kTestPid2 = 20;
+static const int kTestUid2 = 1011;
+
+static const int kLowPriorityPid = 40;
+static const int kMidPriorityPid = 25;
+static const int kHighPriorityPid = 10;
+
+using EventType = TestSystemCallback::EventType;
+using EventEntry = TestSystemCallback::EventEntry;
+bool operator== (const EventEntry& lhs, const EventEntry& rhs) {
+    return lhs.type == rhs.type && lhs.arg == rhs.arg;
+}
+
+#define CHECK_STATUS_TRUE(condition) \
+    EXPECT_TRUE((condition).isOk() && (result))
+
+#define CHECK_STATUS_FALSE(condition) \
+    EXPECT_TRUE((condition).isOk() && !(result))
+
+class ResourceManagerServiceTestBase : public ::testing::Test {
+public:
+    ResourceManagerServiceTestBase()
+        : mSystemCB(new TestSystemCallback()),
+          mService(::ndk::SharedRefBase::make<ResourceManagerService>(
+                  new TestProcessInfo, mSystemCB)),
+          mTestClient1(::ndk::SharedRefBase::make<TestClient>(kTestPid1, mService)),
+          mTestClient2(::ndk::SharedRefBase::make<TestClient>(kTestPid2, mService)),
+          mTestClient3(::ndk::SharedRefBase::make<TestClient>(kTestPid2, mService)) {
+    }
+
+    sp<TestSystemCallback> mSystemCB;
+    std::shared_ptr<ResourceManagerService> mService;
+    std::shared_ptr<IResourceManagerClient> mTestClient1;
+    std::shared_ptr<IResourceManagerClient> mTestClient2;
+    std::shared_ptr<IResourceManagerClient> mTestClient3;
+
+protected:
+    static bool isEqualResources(const std::vector<MediaResourceParcel> &resources1,
+            const ResourceList &resources2) {
+        // convert resource1 to ResourceList
+        ResourceList r1;
+        for (size_t i = 0; i < resources1.size(); ++i) {
+            const auto &res = resources1[i];
+            const auto resType = std::tuple(res.type, res.subType, res.id);
+            r1[resType] = res;
+        }
+        return r1 == resources2;
+    }
+
+    static void expectEqResourceInfo(const ResourceInfo &info,
+            int uid,
+            std::shared_ptr<IResourceManagerClient> client,
+            const std::vector<MediaResourceParcel> &resources) {
+        EXPECT_EQ(uid, info.uid);
+        EXPECT_EQ(client, info.client);
+        EXPECT_TRUE(isEqualResources(resources, info.resources));
+    }
+};
+
+} // namespace android
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 702935d..15601aa 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -16,197 +16,17 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ResourceManagerService_test"
+
 #include <utils/Log.h>
 
-#include <gtest/gtest.h>
-
+#include "ResourceManagerServiceTestUtils.h"
 #include "ResourceManagerService.h"
-#include <aidl/android/media/BnResourceManagerClient.h>
-#include <media/MediaResource.h>
-#include <media/MediaResourcePolicy.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/ProcessInfoInterface.h>
-
-namespace aidl {
-namespace android {
-namespace media {
-bool operator== (const MediaResourceParcel& lhs, const MediaResourceParcel& rhs) {
-    return lhs.type == rhs.type && lhs.subType == rhs.subType &&
-            lhs.id == rhs.id && lhs.value == rhs.value;
-}}}}
 
 namespace android {
 
-using Status = ::ndk::ScopedAStatus;
-using ::aidl::android::media::BnResourceManagerClient;
-using ::aidl::android::media::IResourceManagerService;
-using ::aidl::android::media::IResourceManagerClient;
-
-static int64_t getId(const std::shared_ptr<IResourceManagerClient>& client) {
-    return (int64_t) client.get();
-}
-
-struct TestProcessInfo : public ProcessInfoInterface {
-    TestProcessInfo() {}
-    virtual ~TestProcessInfo() {}
-
-    virtual bool getPriority(int pid, int *priority) {
-        // For testing, use pid as priority.
-        // Lower the value higher the priority.
-        *priority = pid;
-        return true;
-    }
-
-    virtual bool isValidPid(int /* pid */) {
-        return true;
-    }
-
-private:
-    DISALLOW_EVIL_CONSTRUCTORS(TestProcessInfo);
-};
-
-struct TestSystemCallback :
-        public ResourceManagerService::SystemCallbackInterface {
-    TestSystemCallback() :
-        mLastEvent({EventType::INVALID, 0}), mEventCount(0) {}
-
-    enum EventType {
-        INVALID          = -1,
-        VIDEO_ON         = 0,
-        VIDEO_OFF        = 1,
-        VIDEO_RESET      = 2,
-        CPUSET_ENABLE    = 3,
-        CPUSET_DISABLE   = 4,
-    };
-
-    struct EventEntry {
-        EventType type;
-        int arg;
-    };
-
-    virtual void noteStartVideo(int uid) override {
-        mLastEvent = {EventType::VIDEO_ON, uid};
-        mEventCount++;
-    }
-
-    virtual void noteStopVideo(int uid) override {
-        mLastEvent = {EventType::VIDEO_OFF, uid};
-        mEventCount++;
-    }
-
-    virtual void noteResetVideo() override {
-        mLastEvent = {EventType::VIDEO_RESET, 0};
-        mEventCount++;
-    }
-
-    virtual bool requestCpusetBoost(bool enable) override {
-        mLastEvent = {enable ? EventType::CPUSET_ENABLE : EventType::CPUSET_DISABLE, 0};
-        mEventCount++;
-        return true;
-    }
-
-    size_t eventCount() { return mEventCount; }
-    EventType lastEventType() { return mLastEvent.type; }
-    EventEntry lastEvent() { return mLastEvent; }
-
-protected:
-    virtual ~TestSystemCallback() {}
-
-private:
-    EventEntry mLastEvent;
-    size_t mEventCount;
-
-    DISALLOW_EVIL_CONSTRUCTORS(TestSystemCallback);
-};
-
-
-struct TestClient : public BnResourceManagerClient {
-    TestClient(int pid, const std::shared_ptr<ResourceManagerService> &service)
-        : mReclaimed(false), mPid(pid), mService(service) {}
-
-    Status reclaimResource(bool* _aidl_return) override {
-        mService->removeClient(mPid, getId(ref<TestClient>()));
-        mReclaimed = true;
-        *_aidl_return = true;
-        return Status::ok();
-    }
-
-    Status getName(::std::string* _aidl_return) override {
-        *_aidl_return = "test_client";
-        return Status::ok();
-    }
-
-    bool reclaimed() const {
-        return mReclaimed;
-    }
-
-    void reset() {
-        mReclaimed = false;
-    }
-
-    virtual ~TestClient() {}
-
-private:
-    bool mReclaimed;
-    int mPid;
-    std::shared_ptr<ResourceManagerService> mService;
-    DISALLOW_EVIL_CONSTRUCTORS(TestClient);
-};
-
-static const int kTestPid1 = 30;
-static const int kTestUid1 = 1010;
-
-static const int kTestPid2 = 20;
-static const int kTestUid2 = 1011;
-
-static const int kLowPriorityPid = 40;
-static const int kMidPriorityPid = 25;
-static const int kHighPriorityPid = 10;
-
-using EventType = TestSystemCallback::EventType;
-using EventEntry = TestSystemCallback::EventEntry;
-bool operator== (const EventEntry& lhs, const EventEntry& rhs) {
-    return lhs.type == rhs.type && lhs.arg == rhs.arg;
-}
-
-#define CHECK_STATUS_TRUE(condition) \
-    EXPECT_TRUE((condition).isOk() && (result))
-
-#define CHECK_STATUS_FALSE(condition) \
-    EXPECT_TRUE((condition).isOk() && !(result))
-
-class ResourceManagerServiceTest : public ::testing::Test {
+class ResourceManagerServiceTest : public ResourceManagerServiceTestBase {
 public:
-    ResourceManagerServiceTest()
-        : mSystemCB(new TestSystemCallback()),
-          mService(::ndk::SharedRefBase::make<ResourceManagerService>(
-                  new TestProcessInfo, mSystemCB)),
-          mTestClient1(::ndk::SharedRefBase::make<TestClient>(kTestPid1, mService)),
-          mTestClient2(::ndk::SharedRefBase::make<TestClient>(kTestPid2, mService)),
-          mTestClient3(::ndk::SharedRefBase::make<TestClient>(kTestPid2, mService)) {
-    }
-
-protected:
-    static bool isEqualResources(const std::vector<MediaResourceParcel> &resources1,
-            const ResourceList &resources2) {
-        // convert resource1 to ResourceList
-        ResourceList r1;
-        for (size_t i = 0; i < resources1.size(); ++i) {
-            const auto &res = resources1[i];
-            const auto resType = std::tuple(res.type, res.subType, res.id);
-            r1[resType] = res;
-        }
-        return r1 == resources2;
-    }
-
-    static void expectEqResourceInfo(const ResourceInfo &info,
-            int uid,
-            std::shared_ptr<IResourceManagerClient> client,
-            const std::vector<MediaResourceParcel> &resources) {
-        EXPECT_EQ(uid, info.uid);
-        EXPECT_EQ(client, info.client);
-        EXPECT_TRUE(isEqualResources(resources, info.resources));
-    }
+    ResourceManagerServiceTest() : ResourceManagerServiceTestBase() {}
 
     void verifyClients(bool c1, bool c2, bool c3) {
         TestClient *client1 = static_cast<TestClient*>(mTestClient1.get());
@@ -881,12 +701,6 @@
         EXPECT_EQ(4u, mSystemCB->eventCount());
         EXPECT_EQ(EventType::CPUSET_DISABLE, mSystemCB->lastEventType());
     }
-
-    sp<TestSystemCallback> mSystemCB;
-    std::shared_ptr<ResourceManagerService> mService;
-    std::shared_ptr<IResourceManagerClient> mTestClient1;
-    std::shared_ptr<IResourceManagerClient> mTestClient2;
-    std::shared_ptr<IResourceManagerClient> mTestClient3;
 };
 
 TEST_F(ResourceManagerServiceTest, config) {
diff --git a/services/mediaresourcemanager/test/ResourceObserverService_test.cpp b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
new file mode 100644
index 0000000..4c26246
--- /dev/null
+++ b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
@@ -0,0 +1,463 @@
+/*
+ * Copyright 2020 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_NDEBUG 0
+#define LOG_TAG "ResourceObserverService_test"
+
+#include <iostream>
+#include <list>
+
+#include <aidl/android/media/BnResourceObserver.h>
+#include <utils/Log.h>
+#include "ResourceObserverService.h"
+#include "ResourceManagerServiceTestUtils.h"
+
+namespace aidl {
+namespace android {
+namespace media {
+bool operator==(const MediaObservableParcel& lhs, const MediaObservableParcel& rhs) {
+    return lhs.type == rhs.type && lhs.value == rhs.value;
+}
+}}} // namespace ::aidl::android::media
+
+namespace android {
+
+using ::aidl::android::media::BnResourceObserver;
+using ::aidl::android::media::MediaObservableParcel;
+using ::aidl::android::media::MediaObservableType;
+
+#define BUSY ::aidl::android::media::MediaObservableEvent::kBusy
+#define IDLE ::aidl::android::media::MediaObservableEvent::kIdle
+#define ALL ::aidl::android::media::MediaObservableEvent::kAll
+
+struct EventTracker {
+    struct Event {
+        enum { NoEvent, Busy, Idle } type = NoEvent;
+        int uid = 0;
+        int pid = 0;
+        std::vector<MediaObservableParcel> observables;
+    };
+
+    static const Event NoEvent;
+
+    static std::string toString(const MediaObservableParcel& observable) {
+        return "{" + ::aidl::android::media::toString(observable.type)
+        + ", " + std::to_string(observable.value) + "}";
+    }
+    static std::string toString(const Event& event) {
+        std::string eventStr;
+        switch (event.type) {
+        case Event::Busy:
+            eventStr = "Busy";
+            break;
+        case Event::Idle:
+            eventStr = "Idle";
+            break;
+        default:
+            return "NoEvent";
+        }
+        std::string observableStr;
+        for (auto &observable : event.observables) {
+            if (!observableStr.empty()) {
+                observableStr += ", ";
+            }
+            observableStr += toString(observable);
+        }
+        return "{" + eventStr + ", " + std::to_string(event.uid) + ", "
+                + std::to_string(event.pid) + ", {" + observableStr + "}}";
+    }
+
+    static Event Busy(int uid, int pid, const std::vector<MediaObservableParcel>& observables) {
+        return { Event::Busy, uid, pid, observables };
+    }
+    static Event Idle(int uid, int pid, const std::vector<MediaObservableParcel>& observables) {
+        return { Event::Idle, uid, pid, observables };
+    }
+
+    // Pop 1 event from front, wait for up to timeoutUs if empty.
+    const Event& pop(int64_t timeoutUs = 0) {
+        std::unique_lock lock(mLock);
+
+        if (mEventQueue.empty() && timeoutUs > 0) {
+            mCondition.wait_for(lock, std::chrono::microseconds(timeoutUs));
+        }
+
+        if (mEventQueue.empty()) {
+            mPoppedEvent = NoEvent;
+        } else {
+            mPoppedEvent = *mEventQueue.begin();
+            mEventQueue.pop_front();
+        }
+
+        return mPoppedEvent;
+    }
+
+    // Push 1 event to back.
+    void append(const Event& event) {
+        ALOGD("%s", toString(event).c_str());
+
+        std::unique_lock lock(mLock);
+
+        mEventQueue.push_back(event);
+        mCondition.notify_one();
+    }
+
+private:
+    std::mutex mLock;
+    std::condition_variable mCondition;
+    Event mPoppedEvent;
+    std::list<Event> mEventQueue;
+};
+
+const EventTracker::Event EventTracker::NoEvent;
+
+// Operators for GTest macros.
+bool operator==(const EventTracker::Event& lhs, const EventTracker::Event& rhs) {
+    return lhs.type == rhs.type && lhs.uid == rhs.uid && lhs.pid == rhs.pid &&
+            lhs.observables == rhs.observables;
+}
+
+std::ostream& operator<<(std::ostream& str, const EventTracker::Event& v) {
+    str << EventTracker::toString(v);
+    return str;
+}
+
+struct TestObserver : public BnResourceObserver, public EventTracker {
+    TestObserver(const char *name) : mName(name) {}
+    ~TestObserver() = default;
+    Status onStatusChanged(MediaObservableEvent event, int32_t uid, int32_t pid,
+            const std::vector<MediaObservableParcel>& observables) override {
+        ALOGD("%s: %s", mName.c_str(), __FUNCTION__);
+        if (event == MediaObservableEvent::kBusy) {
+            append(Busy(uid, pid, observables));
+        } else {
+            append(Idle(uid, pid, observables));
+        }
+
+        return Status::ok();
+    }
+    std::string mName;
+};
+
+class ResourceObserverServiceTest : public ResourceManagerServiceTestBase {
+public:
+    ResourceObserverServiceTest() : ResourceManagerServiceTestBase(),
+        mObserverService(::ndk::SharedRefBase::make<ResourceObserverService>()),
+        mTestObserver1(::ndk::SharedRefBase::make<TestObserver>("observer1")),
+        mTestObserver2(::ndk::SharedRefBase::make<TestObserver>("observer2")),
+        mTestObserver3(::ndk::SharedRefBase::make<TestObserver>("observer3")) {
+        mService->setObserverService(mObserverService);
+    }
+
+    void registerObservers(MediaObservableEvent filter = ALL) {
+        std::vector<MediaObservableFilter> filters1, filters2, filters3;
+        filters1 = {{MediaObservableType::kVideoSecureCodec, filter}};
+        filters2 = {{MediaObservableType::kVideoNonSecureCodec, filter}};
+        filters3 = {{MediaObservableType::kVideoSecureCodec, filter},
+                   {MediaObservableType::kVideoNonSecureCodec, filter}};
+
+        // mTestObserver1 monitors secure video codecs.
+        EXPECT_TRUE(mObserverService->registerObserver(mTestObserver1, filters1).isOk());
+
+        // mTestObserver2 monitors non-secure video codecs.
+        EXPECT_TRUE(mObserverService->registerObserver(mTestObserver2, filters2).isOk());
+
+        // mTestObserver3 monitors both secure & non-secure video codecs.
+        EXPECT_TRUE(mObserverService->registerObserver(mTestObserver3, filters3).isOk());
+    }
+
+protected:
+    std::shared_ptr<ResourceObserverService> mObserverService;
+    std::shared_ptr<TestObserver> mTestObserver1;
+    std::shared_ptr<TestObserver> mTestObserver2;
+    std::shared_ptr<TestObserver> mTestObserver3;
+};
+
+TEST_F(ResourceObserverServiceTest, testRegisterObserver) {
+    std::vector<MediaObservableFilter> filters1;
+    Status status;
+
+    // Register with empty observables should fail.
+    status = mObserverService->registerObserver(mTestObserver1, filters1);
+    EXPECT_FALSE(status.isOk());
+    EXPECT_EQ(status.getServiceSpecificError(), BAD_VALUE);
+
+    // mTestObserver1 monitors secure video codecs.
+    filters1 = {{MediaObservableType::kVideoSecureCodec, ALL}};
+    EXPECT_TRUE(mObserverService->registerObserver(mTestObserver1, filters1).isOk());
+
+    // Register duplicates should fail.
+    status = mObserverService->registerObserver(mTestObserver1, filters1);
+    EXPECT_FALSE(status.isOk());
+    EXPECT_EQ(status.getServiceSpecificError(), ALREADY_EXISTS);
+}
+
+TEST_F(ResourceObserverServiceTest, testUnregisterObserver) {
+    std::vector<MediaObservableFilter> filters1;
+    Status status;
+
+    // Unregister without registering first should fail.
+    status = mObserverService->unregisterObserver(mTestObserver1);
+    EXPECT_FALSE(status.isOk());
+    EXPECT_EQ(status.getServiceSpecificError(), NAME_NOT_FOUND);
+
+    // mTestObserver1 monitors secure video codecs.
+    filters1 = {{MediaObservableType::kVideoSecureCodec, ALL}};
+    EXPECT_TRUE(mObserverService->registerObserver(mTestObserver1, filters1).isOk());
+    EXPECT_TRUE(mObserverService->unregisterObserver(mTestObserver1).isOk());
+
+    // Unregister again should fail.
+    status = mObserverService->unregisterObserver(mTestObserver1);
+    EXPECT_FALSE(status.isOk());
+    EXPECT_EQ(status.getServiceSpecificError(), NAME_NOT_FOUND);
+}
+
+TEST_F(ResourceObserverServiceTest, testAddResourceBasic) {
+    registerObservers();
+
+    std::vector<MediaObservableParcel> observables1, observables2, observables3;
+    observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
+    observables2 = {{MediaObservableType::kVideoNonSecureCodec, 1}};
+    observables3 = {{MediaObservableType::kVideoSecureCodec, 1},
+                   {MediaObservableType::kVideoNonSecureCodec, 1}};
+
+    std::vector<MediaResourceParcel> resources;
+    // Add secure video codec.
+    resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/)};
+    mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
+
+    // Add non-secure video codec.
+    resources = {MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+    mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+
+    // Add secure & non-secure video codecs.
+    resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+                 MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+    mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables3));
+
+    // Add additional audio codecs, should be ignored.
+    resources.push_back(MediaResource::CodecResource(1 /*secure*/, 0 /*video*/));
+    resources.push_back(MediaResource::CodecResource(0 /*secure*/, 0 /*video*/));
+    mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables2));
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables3));
+}
+
+TEST_F(ResourceObserverServiceTest, testAddResourceMultiple) {
+    registerObservers();
+
+    std::vector<MediaObservableParcel> observables1, observables2, observables3;
+    observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
+    observables2 = {{MediaObservableType::kVideoNonSecureCodec, 1}};
+    observables3 = {{MediaObservableType::kVideoSecureCodec, 1},
+                   {MediaObservableType::kVideoNonSecureCodec, 1}};
+
+    std::vector<MediaResourceParcel> resources;
+
+    // Add multiple secure & non-secure video codecs.
+    // Multiple entries of the same type should be merged, count should be propagated correctly.
+    resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+                 MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+                 MediaResource::CodecResource(0 /*secure*/, 1 /*video*/, 3 /*count*/)};
+    observables1 = {{MediaObservableType::kVideoSecureCodec, 2}};
+    observables2 = {{MediaObservableType::kVideoNonSecureCodec, 3}};
+    observables3 = {{MediaObservableType::kVideoSecureCodec, 2},
+                   {MediaObservableType::kVideoNonSecureCodec, 3}};
+    mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables3));
+}
+
+TEST_F(ResourceObserverServiceTest, testRemoveResourceBasic) {
+    registerObservers();
+
+    std::vector<MediaObservableParcel> observables1, observables2, observables3;
+    observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
+    observables2 = {{MediaObservableType::kVideoNonSecureCodec, 1}};
+    observables3 = {{MediaObservableType::kVideoSecureCodec, 1},
+                   {MediaObservableType::kVideoNonSecureCodec, 1}};
+
+    std::vector<MediaResourceParcel> resources;
+    // Add secure video codec to client1.
+    resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/)};
+    mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
+    // Remove secure video codec. observer 1&3 should receive updates.
+    mService->removeResource(kTestPid1, getId(mTestClient1), resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::Idle(kTestUid1, kTestPid1, observables1));
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Idle(kTestUid1, kTestPid1, observables1));
+    // Remove secure video codec again, should have no event.
+    mService->removeResource(kTestPid1, getId(mTestClient1), resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
+    // Remove client1, should have no event.
+    mService->removeClient(kTestPid1, getId(mTestClient1));
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
+
+    // Add non-secure video codec to client2.
+    resources = {MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+    mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+    // Remove client2, observer 2&3 should receive updates.
+    mService->removeClient(kTestPid2, getId(mTestClient2));
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+    // Remove non-secure codec after client2 removed, should have no event.
+    mService->removeResource(kTestPid2, getId(mTestClient2), resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
+    // Remove client2 again, should have no event.
+    mService->removeClient(kTestPid2, getId(mTestClient2));
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
+
+    // Add secure & non-secure video codecs, plus audio codecs (that's ignored).
+    resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+                 MediaResource::CodecResource(0 /*secure*/, 1 /*video*/),
+                 MediaResource::CodecResource(1 /*secure*/, 0 /*video*/),
+                 MediaResource::CodecResource(0 /*secure*/, 0 /*video*/)};
+    mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables3));
+    // Remove one audio codec, should have no event.
+    resources = {MediaResource::CodecResource(1 /*secure*/, 0 /*video*/)};
+    mService->removeResource(kTestPid2, getId(mTestClient3), resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
+    // Remove the other audio codec and the secure video codec, only secure video codec
+    // removal should be reported.
+    resources = {MediaResource::CodecResource(0 /*secure*/, 0 /*video*/),
+                 MediaResource::CodecResource(1 /*secure*/, 1 /*video*/)};
+    mService->removeResource(kTestPid2, getId(mTestClient3), resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables1));
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables1));
+    // Remove client3 entirely. Non-secure video codec removal should be reported.
+    mService->removeClient(kTestPid2, getId(mTestClient3));
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+}
+
+TEST_F(ResourceObserverServiceTest, testRemoveResourceMultiple) {
+    registerObservers();
+
+    std::vector<MediaObservableParcel> observables1, observables2, observables3;
+    observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
+    observables2 = {{MediaObservableType::kVideoNonSecureCodec, 1}};
+    observables3 = {{MediaObservableType::kVideoSecureCodec, 1},
+                    {MediaObservableType::kVideoNonSecureCodec, 1}};
+
+    std::vector<MediaResourceParcel> resources;
+
+    // Add multiple secure & non-secure video codecs, plus audio codecs (that's ignored).
+    // (ResourceManager will merge these internally.)
+    resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+                 MediaResource::CodecResource(0 /*secure*/, 1 /*video*/, 4 /*count*/),
+                 MediaResource::CodecResource(1 /*secure*/, 0 /*video*/),
+                 MediaResource::CodecResource(0 /*secure*/, 0 /*video*/)};
+    mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
+    observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
+    observables2 = {{MediaObservableType::kVideoNonSecureCodec, 4}};
+    observables3 = {{MediaObservableType::kVideoSecureCodec, 1},
+                    {MediaObservableType::kVideoNonSecureCodec, 4}};
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables3));
+    // Remove one audio codec, 2 secure video codecs and 2 non-secure video codecs.
+    // 1 secure video codec removal and 2 non-secure video codec removals should be reported.
+    resources = {MediaResource::CodecResource(0 /*secure*/, 0 /*video*/),
+                 MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+                 MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+                 MediaResource::CodecResource(0 /*secure*/, 1 /*video*/, 2 /*count*/)};
+    mService->removeResource(kTestPid2, getId(mTestClient3), resources);
+    observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
+    observables2 = {{MediaObservableType::kVideoNonSecureCodec, 2}};
+    observables3 = {{MediaObservableType::kVideoSecureCodec, 1},
+                    {MediaObservableType::kVideoNonSecureCodec, 2}};
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables1));
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables3));
+    // Remove client3 entirely. 2 non-secure video codecs removal should be reported.
+    mService->removeClient(kTestPid2, getId(mTestClient3));
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+}
+
+TEST_F(ResourceObserverServiceTest, testEventFilters) {
+    // Register observers with different event filters.
+    std::vector<MediaObservableFilter> filters1, filters2, filters3;
+    filters1 = {{MediaObservableType::kVideoSecureCodec, BUSY}};
+    filters2 = {{MediaObservableType::kVideoNonSecureCodec, IDLE}};
+    filters3 = {{MediaObservableType::kVideoSecureCodec, IDLE},
+               {MediaObservableType::kVideoNonSecureCodec, BUSY}};
+
+    // mTestObserver1 monitors secure video codecs.
+    EXPECT_TRUE(mObserverService->registerObserver(mTestObserver1, filters1).isOk());
+
+    // mTestObserver2 monitors non-secure video codecs.
+    EXPECT_TRUE(mObserverService->registerObserver(mTestObserver2, filters2).isOk());
+
+    // mTestObserver3 monitors both secure & non-secure video codecs.
+    EXPECT_TRUE(mObserverService->registerObserver(mTestObserver3, filters3).isOk());
+
+    std::vector<MediaObservableParcel> observables1, observables2;
+    observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
+    observables2 = {{MediaObservableType::kVideoNonSecureCodec, 1}};
+
+    std::vector<MediaResourceParcel> resources;
+
+    // Add secure & non-secure video codecs.
+    resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+                 MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+    mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+
+    // Remove secure & non-secure video codecs.
+    mService->removeResource(kTestPid2, getId(mTestClient3), resources);
+    EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+    EXPECT_EQ(mTestObserver2->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+    EXPECT_EQ(mTestObserver3->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables1));
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/test/build_and_run_all_unit_tests.sh b/services/mediaresourcemanager/test/build_and_run_all_unit_tests.sh
new file mode 100755
index 0000000..1c4ae98
--- /dev/null
+++ b/services/mediaresourcemanager/test/build_and_run_all_unit_tests.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# Run tests in this directory.
+#
+
+if [ "$SYNC_FINISHED" != true ]; then
+  if [ -z "$ANDROID_BUILD_TOP" ]; then
+      echo "Android build environment not set"
+      exit -1
+  fi
+
+  # ensure we have mm
+  . $ANDROID_BUILD_TOP/build/envsetup.sh
+
+  mm
+
+  echo "waiting for device"
+
+  adb root && adb wait-for-device remount && adb sync
+fi
+
+echo "========================================"
+
+echo "testing ResourceManagerService"
+#adb shell /data/nativetest64/ResourceManagerService_test/ResourceManagerService_test
+adb shell /data/nativetest/ResourceManagerService_test/ResourceManagerService_test
+
+echo "testing ServiceLog"
+#adb shell /data/nativetest64/ServiceLog_test/ServiceLog_test
+adb shell /data/nativetest/ServiceLog_test/ServiceLog_test
+
+echo "testing ResourceObserverService"
+#adb shell /data/nativetest64/ResourceObserverService_test/ResourceObserverService_test
+adb shell /data/nativetest/ResourceObserverService_test/ResourceObserverService_test
diff --git a/services/mediatranscoding/MediaTranscodingService.cpp b/services/mediatranscoding/MediaTranscodingService.cpp
index ef7d6d2..eb3a873 100644
--- a/services/mediatranscoding/MediaTranscodingService.cpp
+++ b/services/mediatranscoding/MediaTranscodingService.cpp
@@ -25,8 +25,8 @@
 #include <media/TranscoderWrapper.h>
 #include <media/TranscodingClientManager.h>
 #include <media/TranscodingJobScheduler.h>
+#include <media/TranscodingResourcePolicy.h>
 #include <media/TranscodingUidPolicy.h>
-#include <private/android_filesystem_config.h>
 #include <utils/Log.h>
 #include <utils/Vector.h>
 
@@ -40,28 +40,16 @@
             errorCode,                                \
             String8::format("%s:%d: " errorString, __FUNCTION__, __LINE__, ##__VA_ARGS__))
 
-// Can MediaTranscoding service trust the caller based on the calling UID?
-// TODO(hkuang): Add MediaProvider's UID.
-static bool isTrustedCallingUid(uid_t uid) {
-    switch (uid) {
-    case AID_ROOT:  // root user
-    case AID_SYSTEM:
-    case AID_SHELL:
-    case AID_MEDIA:  // mediaserver
-        return true;
-    default:
-        return false;
-    }
-}
-
 MediaTranscodingService::MediaTranscodingService(
         const std::shared_ptr<TranscoderInterface>& transcoder)
       : mUidPolicy(new TranscodingUidPolicy()),
-        mJobScheduler(new TranscodingJobScheduler(transcoder, mUidPolicy)),
+        mResourcePolicy(new TranscodingResourcePolicy()),
+        mJobScheduler(new TranscodingJobScheduler(transcoder, mUidPolicy, mResourcePolicy)),
         mClientManager(new TranscodingClientManager(mJobScheduler)) {
     ALOGV("MediaTranscodingService is created");
     transcoder->setCallback(mJobScheduler);
     mUidPolicy->setCallback(mJobScheduler);
+    mResourcePolicy->setCallback(mJobScheduler);
 }
 
 MediaTranscodingService::~MediaTranscodingService() {
@@ -113,51 +101,18 @@
 
 Status MediaTranscodingService::registerClient(
         const std::shared_ptr<ITranscodingClientCallback>& in_callback,
-        const std::string& in_clientName, const std::string& in_opPackageName, int32_t in_clientUid,
-        int32_t in_clientPid, std::shared_ptr<ITranscodingClient>* _aidl_return) {
+        const std::string& in_clientName, const std::string& in_opPackageName,
+        std::shared_ptr<ITranscodingClient>* _aidl_return) {
     if (in_callback == nullptr) {
         *_aidl_return = nullptr;
         return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "Client callback cannot be null!");
     }
 
-    int32_t callingPid = AIBinder_getCallingPid();
-    int32_t callingUid = AIBinder_getCallingUid();
-
-    // Check if we can trust clientUid. Only privilege caller could forward the
-    // uid on app client's behalf.
-    if (in_clientUid == USE_CALLING_UID) {
-        in_clientUid = callingUid;
-    } else if (!isTrustedCallingUid(callingUid)) {
-        ALOGE("MediaTranscodingService::registerClient failed (calling PID %d, calling UID %d) "
-              "rejected "
-              "(don't trust clientUid %d)",
-              in_clientPid, in_clientUid, in_clientUid);
-        return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
-                                "Untrusted caller (calling PID %d, UID %d) trying to "
-                                "register client",
-                                in_clientPid, in_clientUid);
-    }
-
-    // Check if we can trust clientPid. Only privilege caller could forward the
-    // pid on app client's behalf.
-    if (in_clientPid == USE_CALLING_PID) {
-        in_clientPid = callingPid;
-    } else if (!isTrustedCallingUid(callingUid)) {
-        ALOGE("MediaTranscodingService::registerClient client failed (calling PID %d, calling UID "
-              "%d) rejected "
-              "(don't trust clientPid %d)",
-              in_clientPid, in_clientUid, in_clientPid);
-        return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
-                                "Untrusted caller (calling PID %d, UID %d) trying to "
-                                "register client",
-                                in_clientPid, in_clientUid);
-    }
-
     // Creates the client and uses its process id as client id.
     std::shared_ptr<ITranscodingClient> newClient;
 
-    status_t err = mClientManager->addClient(in_callback, in_clientPid, in_clientUid, in_clientName,
-                                             in_opPackageName, &newClient);
+    status_t err =
+            mClientManager->addClient(in_callback, in_clientName, in_opPackageName, &newClient);
     if (err != OK) {
         *_aidl_return = nullptr;
         return STATUS_ERROR_FMT(err, "Failed to add client to TranscodingClientManager");
diff --git a/services/mediatranscoding/MediaTranscodingService.h b/services/mediatranscoding/MediaTranscodingService.h
index 505239c..0fe6864 100644
--- a/services/mediatranscoding/MediaTranscodingService.h
+++ b/services/mediatranscoding/MediaTranscodingService.h
@@ -32,6 +32,7 @@
 class TranscodingJobScheduler;
 class TranscoderInterface;
 class UidPolicyInterface;
+class ResourcePolicyInterface;
 
 class MediaTranscodingService : public BnMediaTranscodingService {
 public:
@@ -47,7 +48,6 @@
 
     Status registerClient(const std::shared_ptr<ITranscodingClientCallback>& in_callback,
                           const std::string& in_clientName, const std::string& in_opPackageName,
-                          int32_t in_clientUid, int32_t in_clientPid,
                           std::shared_ptr<ITranscodingClient>* _aidl_return) override;
 
     Status getNumOfClients(int32_t* _aidl_return) override;
@@ -60,6 +60,7 @@
     mutable std::mutex mServiceLock;
 
     std::shared_ptr<UidPolicyInterface> mUidPolicy;
+    std::shared_ptr<ResourcePolicyInterface> mResourcePolicy;
     std::shared_ptr<TranscodingJobScheduler> mJobScheduler;
     std::shared_ptr<TranscodingClientManager> mClientManager;
 };
diff --git a/services/mediatranscoding/tests/Android.bp b/services/mediatranscoding/tests/Android.bp
index 364a198..6497685 100644
--- a/services/mediatranscoding/tests/Android.bp
+++ b/services/mediatranscoding/tests/Android.bp
@@ -25,14 +25,6 @@
     static_libs: [
         "mediatranscoding_aidl_interface-ndk_platform",
     ],
-}
-
-// MediaTranscodingService unit test using simulated transcoder
-cc_test {
-    name: "mediatranscodingservice_simulated_tests",
-    defaults: ["mediatranscodingservice_test_defaults"],
-
-    srcs: ["mediatranscodingservice_simulated_tests.cpp"],
 
     required: [
         "TranscodingUidPolicy_TestAppA",
@@ -41,6 +33,14 @@
     ],
 }
 
+// MediaTranscodingService unit test using simulated transcoder
+cc_test {
+    name: "mediatranscodingservice_simulated_tests",
+    defaults: ["mediatranscodingservice_test_defaults"],
+
+    srcs: ["mediatranscodingservice_simulated_tests.cpp"],
+}
+
 // MediaTranscodingService unit test using real transcoder
 cc_test {
     name: "mediatranscodingservice_real_tests",
@@ -48,3 +48,11 @@
 
     srcs: ["mediatranscodingservice_real_tests.cpp"],
 }
+
+// MediaTranscodingService unit test related to resource management
+cc_test {
+    name: "mediatranscodingservice_resource_tests",
+    defaults: ["mediatranscodingservice_test_defaults"],
+
+    srcs: ["mediatranscodingservice_resource_tests.cpp"],
+}
diff --git a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
index 53fd7ec..0af572e 100644
--- a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
+++ b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
@@ -58,6 +58,9 @@
 constexpr uid_t kClientUid = 5000;
 #define UID(n) (kClientUid + (n))
 
+constexpr pid_t kClientPid = 10000;
+#define PID(n) (kClientPid + (n))
+
 constexpr int32_t kClientId = 0;
 #define CLIENT(n) (kClientId + (n))
 
@@ -168,6 +171,32 @@
         return mPoppedEvent;
     }
 
+    bool waitForSpecificEventAndPop(const Event& target, std::list<Event>* outEvents,
+                                    int64_t timeoutUs = 0) {
+        std::unique_lock lock(mLock);
+
+        auto startTime = std::chrono::system_clock::now();
+
+        std::list<Event>::iterator it;
+        while (((it = std::find(mEventQueue.begin(), mEventQueue.end(), target)) ==
+                mEventQueue.end()) &&
+               timeoutUs > 0) {
+            std::cv_status status = mCondition.wait_for(lock, std::chrono::microseconds(timeoutUs));
+            if (status == std::cv_status::timeout) {
+                break;
+            }
+            std::chrono::microseconds elapsedTime = std::chrono::system_clock::now() - startTime;
+            timeoutUs -= elapsedTime.count();
+        }
+
+        if (it == mEventQueue.end()) {
+            return false;
+        }
+        *outEvents = std::list<Event>(mEventQueue.begin(), std::next(it));
+        mEventQueue.erase(mEventQueue.begin(), std::next(it));
+        return true;
+    }
+
     // Push 1 event to back.
     void append(const Event& event,
                 const TranscodingErrorCode err = TranscodingErrorCode::kNoError) {
@@ -186,7 +215,7 @@
         mUpdateCount++;
     }
 
-    int getUpdateCount(int *lastProgress) {
+    int getUpdateCount(int* lastProgress) {
         std::unique_lock lock(mLock);
         *lastProgress = mLastProgress;
         return mUpdateCount;
@@ -217,9 +246,21 @@
     return str;
 }
 
-struct TestClientCallback : public BnTranscodingClientCallback, public EventTracker {
-    TestClientCallback(int32_t id) : mClientId(id) {
-        ALOGI("TestClientCallback %d Created", mClientId);
+static constexpr bool success = true;
+static constexpr bool fail = false;
+
+struct TestClientCallback : public BnTranscodingClientCallback,
+                            public EventTracker,
+                            public std::enable_shared_from_this<TestClientCallback> {
+    TestClientCallback(const char* packageName, int32_t id)
+          : mClientId(id), mClientPid(PID(id)), mClientUid(UID(id)), mPackageName(packageName) {
+        ALOGI("TestClientCallback %d created: pid %d, uid %d", id, PID(id), UID(id));
+
+        // Use package uid if that's available.
+        uid_t packageUid;
+        if (getUidForPackage(String16(packageName), 0 /*userId*/, packageUid) == NO_ERROR) {
+            mClientUid = packageUid;
+        }
     }
 
     virtual ~TestClientCallback() { ALOGI("TestClientCallback %d destroyed", mClientId); }
@@ -285,7 +326,99 @@
         return Status::ok();
     }
 
+    Status registerClient(const char* packageName,
+                          const std::shared_ptr<IMediaTranscodingService>& service) {
+        // Override the default uid if the package uid is found.
+        uid_t uid;
+        if (getUidForPackage(String16(packageName), 0 /*userId*/, uid) == NO_ERROR) {
+            mClientUid = uid;
+        }
+
+        ALOGD("registering %s with uid %d", packageName, mClientUid);
+
+        std::shared_ptr<ITranscodingClient> client;
+        Status status =
+                service->registerClient(shared_from_this(), kClientName, packageName, &client);
+
+        mClient = status.isOk() ? client : nullptr;
+        return status;
+    }
+
+    Status unregisterClient() {
+        Status status;
+        if (mClient != nullptr) {
+            status = mClient->unregister();
+            mClient = nullptr;
+        }
+        return status;
+    }
+
+    template <bool expectation = success>
+    bool submit(int32_t jobId, const char* sourceFilePath, const char* destinationFilePath,
+                TranscodingJobPriority priority = TranscodingJobPriority::kNormal,
+                int bitrateBps = -1, int overridePid = -1, int overrideUid = -1) {
+        constexpr bool shouldSucceed = (expectation == success);
+        bool result;
+        TranscodingRequestParcel request;
+        TranscodingJobParcel job;
+
+        request.sourceFilePath = sourceFilePath;
+        request.destinationFilePath = destinationFilePath;
+        request.priority = priority;
+        request.clientPid = (overridePid == -1) ? mClientPid : overridePid;
+        request.clientUid = (overrideUid == -1) ? mClientUid : overrideUid;
+        if (bitrateBps > 0) {
+            request.requestedVideoTrackFormat.emplace(TranscodingVideoTrackFormat());
+            request.requestedVideoTrackFormat->bitrateBps = bitrateBps;
+        }
+        Status status = mClient->submitRequest(request, &job, &result);
+
+        EXPECT_TRUE(status.isOk());
+        EXPECT_EQ(result, shouldSucceed);
+        if (shouldSucceed) {
+            EXPECT_EQ(job.jobId, jobId);
+        }
+
+        return status.isOk() && (result == shouldSucceed) && (!shouldSucceed || job.jobId == jobId);
+    }
+
+    template <bool expectation = success>
+    bool cancel(int32_t jobId) {
+        constexpr bool shouldSucceed = (expectation == success);
+        bool result;
+        Status status = mClient->cancelJob(jobId, &result);
+
+        EXPECT_TRUE(status.isOk());
+        EXPECT_EQ(result, shouldSucceed);
+
+        return status.isOk() && (result == shouldSucceed);
+    }
+
+    template <bool expectation = success>
+    bool getJob(int32_t jobId, const char* sourceFilePath, const char* destinationFilePath) {
+        constexpr bool shouldSucceed = (expectation == success);
+        bool result;
+        TranscodingJobParcel job;
+        Status status = mClient->getJobWithId(jobId, &job, &result);
+
+        EXPECT_TRUE(status.isOk());
+        EXPECT_EQ(result, shouldSucceed);
+        if (shouldSucceed) {
+            EXPECT_EQ(job.jobId, jobId);
+            EXPECT_EQ(job.request.sourceFilePath, sourceFilePath);
+        }
+
+        return status.isOk() && (result == shouldSucceed) &&
+               (!shouldSucceed ||
+                (job.jobId == jobId && job.request.sourceFilePath == sourceFilePath &&
+                 job.request.destinationFilePath == destinationFilePath));
+    }
+
     int32_t mClientId;
+    pid_t mClientPid;
+    uid_t mClientUid;
+    std::string mPackageName;
+    std::shared_ptr<ITranscodingClient> mClient;
 };
 
 class MediaTranscodingServiceTestBase : public ::testing::Test {
@@ -306,37 +439,31 @@
             ALOGE("Failed to connect to the media.trascoding service.");
             return;
         }
-        mClientCallback1 = ::ndk::SharedRefBase::make<TestClientCallback>(CLIENT(1));
-        mClientCallback2 = ::ndk::SharedRefBase::make<TestClientCallback>(CLIENT(2));
-        mClientCallback3 = ::ndk::SharedRefBase::make<TestClientCallback>(CLIENT(3));
+        mClient1 = ::ndk::SharedRefBase::make<TestClientCallback>(kClientPackageA, 1);
+        mClient2 = ::ndk::SharedRefBase::make<TestClientCallback>(kClientPackageB, 2);
+        mClient3 = ::ndk::SharedRefBase::make<TestClientCallback>(kClientPackageC, 3);
     }
 
-    std::shared_ptr<ITranscodingClient> registerOneClient(
-            const char* packageName, const std::shared_ptr<TestClientCallback>& callback,
-            uid_t defaultUid) {
-        uid_t uid;
-        if (getUidForPackage(String16(packageName), 0 /*userId*/, uid) != NO_ERROR) {
-            uid = defaultUid;
-        }
-
-        ALOGD("registering %s with uid %d", packageName, uid);
+    Status registerOneClient(const std::shared_ptr<TestClientCallback>& callback) {
+        ALOGD("registering %s with uid %d", callback->mPackageName.c_str(), callback->mClientUid);
 
         std::shared_ptr<ITranscodingClient> client;
-        Status status = mService->registerClient(callback, kClientName, packageName, uid,
-                                                 kClientUseCallingPid, &client);
-        return status.isOk() ? client : nullptr;
+        Status status =
+                mService->registerClient(callback, kClientName, callback->mPackageName, &client);
+
+        if (status.isOk()) {
+            callback->mClient = client;
+        } else {
+            callback->mClient = nullptr;
+        }
+        return status;
     }
 
     void registerMultipleClients() {
         // Register 3 clients.
-        mClient1 = registerOneClient(kClientPackageA, mClientCallback1, UID(1));
-        EXPECT_TRUE(mClient1 != nullptr);
-
-        mClient2 = registerOneClient(kClientPackageB, mClientCallback2, UID(2));
-        EXPECT_TRUE(mClient2 != nullptr);
-
-        mClient3 = registerOneClient(kClientPackageC, mClientCallback3, UID(3));
-        EXPECT_TRUE(mClient3 != nullptr);
+        EXPECT_TRUE(registerOneClient(mClient1).isOk());
+        EXPECT_TRUE(registerOneClient(mClient2).isOk());
+        EXPECT_TRUE(registerOneClient(mClient3).isOk());
 
         // Check the number of clients.
         int32_t numOfClients;
@@ -346,99 +473,24 @@
     }
 
     void unregisterMultipleClients() {
-        Status status;
-
         // Unregister the clients.
-        status = mClient1->unregister();
-        EXPECT_TRUE(status.isOk());
-
-        status = mClient2->unregister();
-        EXPECT_TRUE(status.isOk());
-
-        status = mClient3->unregister();
-        EXPECT_TRUE(status.isOk());
+        EXPECT_TRUE(mClient1->unregisterClient().isOk());
+        EXPECT_TRUE(mClient2->unregisterClient().isOk());
+        EXPECT_TRUE(mClient3->unregisterClient().isOk());
 
         // Check the number of clients.
         int32_t numOfClients;
-        status = mService->getNumOfClients(&numOfClients);
+        Status status = mService->getNumOfClients(&numOfClients);
         EXPECT_TRUE(status.isOk());
         EXPECT_EQ(0, numOfClients);
     }
 
-    static constexpr bool success = true;
-    static constexpr bool fail = false;
-
-    template <bool expectation = success>
-    bool submit(const std::shared_ptr<ITranscodingClient>& client, int32_t jobId,
-                const char* sourceFilePath, const char* destinationFilePath,
-                TranscodingJobPriority priority = TranscodingJobPriority::kNormal,
-                int bitrateBps = -1) {
-        constexpr bool shouldSucceed = (expectation == success);
-        bool result;
-        TranscodingRequestParcel request;
-        TranscodingJobParcel job;
-
-        request.sourceFilePath = sourceFilePath;
-        request.destinationFilePath = destinationFilePath;
-        request.priority = priority;
-        if (bitrateBps > 0) {
-            request.requestedVideoTrackFormat.emplace(TranscodingVideoTrackFormat());
-            request.requestedVideoTrackFormat->bitrateBps = bitrateBps;
-        }
-        Status status = client->submitRequest(request, &job, &result);
-
-        EXPECT_TRUE(status.isOk());
-        EXPECT_EQ(result, shouldSucceed);
-        if (shouldSucceed) {
-            EXPECT_EQ(job.jobId, jobId);
-        }
-
-        return status.isOk() && (result == shouldSucceed) && (!shouldSucceed || job.jobId == jobId);
-    }
-
-    template <bool expectation = success>
-    bool cancel(const std::shared_ptr<ITranscodingClient>& client, int32_t jobId) {
-        constexpr bool shouldSucceed = (expectation == success);
-        bool result;
-        Status status = client->cancelJob(jobId, &result);
-
-        EXPECT_TRUE(status.isOk());
-        EXPECT_EQ(result, shouldSucceed);
-
-        return status.isOk() && (result == shouldSucceed);
-    }
-
-    template <bool expectation = success>
-    bool getJob(const std::shared_ptr<ITranscodingClient>& client, int32_t jobId,
-                const char* sourceFilePath, const char* destinationFilePath) {
-        constexpr bool shouldSucceed = (expectation == success);
-        bool result;
-        TranscodingJobParcel job;
-        Status status = client->getJobWithId(jobId, &job, &result);
-
-        EXPECT_TRUE(status.isOk());
-        EXPECT_EQ(result, shouldSucceed);
-        if (shouldSucceed) {
-            EXPECT_EQ(job.jobId, jobId);
-            EXPECT_EQ(job.request.sourceFilePath, sourceFilePath);
-        }
-
-        return status.isOk() && (result == shouldSucceed) &&
-               (!shouldSucceed ||
-                (job.jobId == jobId && job.request.sourceFilePath == sourceFilePath &&
-                 job.request.destinationFilePath == destinationFilePath));
-    }
-
     void deleteFile(const char* path) { unlink(path); }
 
     std::shared_ptr<IMediaTranscodingService> mService;
-    std::shared_ptr<TestClientCallback> mClientCallback1;
-    std::shared_ptr<TestClientCallback> mClientCallback2;
-    std::shared_ptr<TestClientCallback> mClientCallback3;
-    std::shared_ptr<ITranscodingClient> mClient1;
-    std::shared_ptr<ITranscodingClient> mClient2;
-    std::shared_ptr<ITranscodingClient> mClient3;
-    const char* mTestName;
+    std::shared_ptr<TestClientCallback> mClient1;
+    std::shared_ptr<TestClientCallback> mClient2;
+    std::shared_ptr<TestClientCallback> mClient3;
 };
 
 }  // namespace media
diff --git a/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/TestAppA.xml b/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/TestAppA.xml
index 91c14a5..0dff171 100644
--- a/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/TestAppA.xml
+++ b/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/TestAppA.xml
@@ -28,6 +28,14 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        <activity android:name="com.android.tests.transcoding.ResourcePolicyTestActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
 
diff --git a/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/src/com/android/tests/transcoding/MainActivity.java b/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/src/com/android/tests/transcoding/MainActivity.java
index 7295073..b79164d 100644
--- a/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/src/com/android/tests/transcoding/MainActivity.java
+++ b/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/src/com/android/tests/transcoding/MainActivity.java
@@ -46,7 +46,7 @@
     // Called before subsequent visible lifetimes
     // for an activity process.
     @Override
-    public void onRestart(){
+    public void onRestart() {
         super.onRestart();
         // Load changes knowing that the Activity has already
         // been visible within this process.
@@ -54,14 +54,14 @@
 
     // Called at the start of the visible lifetime.
     @Override
-    public void onStart(){
+    public void onStart() {
         super.onStart();
         // Apply any required UI change now that the Activity is visible.
     }
 
     // Called at the start of the active lifetime.
     @Override
-    public void onResume(){
+    public void onResume() {
         super.onResume();
         // Resume any paused UI updates, threads, or processes required
         // by the Activity but suspended when it was inactive.
@@ -80,7 +80,7 @@
 
     // Called at the end of the active lifetime.
     @Override
-    public void onPause(){
+    public void onPause() {
         // Suspend UI updates, threads, or CPU intensive processes
         // that don't need to be updated when the Activity isn't
         // the active foreground Activity.
@@ -89,7 +89,7 @@
 
     // Called at the end of the visible lifetime.
     @Override
-    public void onStop(){
+    public void onStop() {
         // Suspend remaining UI updates, threads, or processing
         // that aren't required when the Activity isn't visible.
         // Persist all edits or state changes
@@ -99,10 +99,9 @@
 
     // Sometimes called at the end of the full lifetime.
     @Override
-    public void onDestroy(){
+    public void onDestroy() {
         // Clean up any resources including ending threads,
         // closing database connections etc.
         super.onDestroy();
     }
-
 }
diff --git a/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/src/com/android/tests/transcoding/ResourcePolicyTestActivity.java b/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/src/com/android/tests/transcoding/ResourcePolicyTestActivity.java
new file mode 100644
index 0000000..c9e2ddb
--- /dev/null
+++ b/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/src/com/android/tests/transcoding/ResourcePolicyTestActivity.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2020 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.
+ */
+
+package com.android.tests.transcoding;
+
+import android.app.Activity;
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecInfo.VideoCapabilities;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
+import android.os.Bundle;
+import android.util.Log;
+import java.io.IOException;
+import java.util.Vector;
+
+public class ResourcePolicyTestActivity extends Activity {
+    public static final int TYPE_NONSECURE = 0;
+    public static final int TYPE_SECURE = 1;
+    public static final int TYPE_MIX = 2;
+
+    protected String TAG;
+    private static final int FRAME_RATE = 10;
+    private static final int IFRAME_INTERVAL = 10; // 10 seconds between I-frames
+    private static final String MIME = MediaFormat.MIMETYPE_VIDEO_AVC;
+    private static final int TIMEOUT_MS = 5000;
+
+    private Vector<MediaCodec> mCodecs = new Vector<MediaCodec>();
+
+    private class TestCodecCallback extends MediaCodec.Callback {
+        @Override
+        public void onInputBufferAvailable(MediaCodec codec, int index) {
+            Log.d(TAG, "onInputBufferAvailable " + codec.toString());
+        }
+
+        @Override
+        public void onOutputBufferAvailable(
+                MediaCodec codec, int index, MediaCodec.BufferInfo info) {
+            Log.d(TAG, "onOutputBufferAvailable " + codec.toString());
+        }
+
+        @Override
+        public void onError(MediaCodec codec, MediaCodec.CodecException e) {
+            Log.d(TAG, "onError " + codec.toString() + " errorCode " + e.getErrorCode());
+        }
+
+        @Override
+        public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
+            Log.d(TAG, "onOutputFormatChanged " + codec.toString());
+        }
+    }
+
+    private MediaCodec.Callback mCallback = new TestCodecCallback();
+
+    private MediaFormat getTestFormat(CodecCapabilities caps, boolean securePlayback) {
+        VideoCapabilities vcaps = caps.getVideoCapabilities();
+        int width = vcaps.getSupportedWidths().getLower();
+        int height = vcaps.getSupportedHeightsFor(width).getLower();
+        int bitrate = vcaps.getBitrateRange().getLower();
+
+        MediaFormat format = MediaFormat.createVideoFormat(MIME, width, height);
+        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, caps.colorFormats[0]);
+        format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
+        format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
+        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
+        format.setFeatureEnabled(CodecCapabilities.FEATURE_SecurePlayback, securePlayback);
+        return format;
+    }
+
+    private MediaCodecInfo getTestCodecInfo(boolean securePlayback) {
+        // Use avc decoder for testing.
+        boolean isEncoder = false;
+
+        MediaCodecList mcl = new MediaCodecList(MediaCodecList.ALL_CODECS);
+        for (MediaCodecInfo info : mcl.getCodecInfos()) {
+            if (info.isEncoder() != isEncoder) {
+                continue;
+            }
+            CodecCapabilities caps;
+            try {
+                caps = info.getCapabilitiesForType(MIME);
+                boolean securePlaybackSupported =
+                        caps.isFeatureSupported(CodecCapabilities.FEATURE_SecurePlayback);
+                boolean securePlaybackRequired =
+                        caps.isFeatureRequired(CodecCapabilities.FEATURE_SecurePlayback);
+                if ((securePlayback && securePlaybackSupported)
+                        || (!securePlayback && !securePlaybackRequired)) {
+                    Log.d(TAG, "securePlayback " + securePlayback + " will use " + info.getName());
+                } else {
+                    Log.d(TAG, "securePlayback " + securePlayback + " skip " + info.getName());
+                    continue;
+                }
+            } catch (IllegalArgumentException e) {
+                // mime is not supported
+                continue;
+            }
+            return info;
+        }
+
+        return null;
+    }
+
+    protected int allocateCodecs(int max) {
+        Bundle extras = getIntent().getExtras();
+        int type = TYPE_NONSECURE;
+        if (extras != null) {
+            type = extras.getInt("test-type", type);
+            Log.d(TAG, "type is: " + type);
+        }
+
+        boolean shouldSkip = false;
+        boolean securePlayback;
+        if (type == TYPE_NONSECURE || type == TYPE_MIX) {
+            securePlayback = false;
+            MediaCodecInfo info = getTestCodecInfo(securePlayback);
+            if (info != null) {
+                allocateCodecs(max, info, securePlayback);
+            } else {
+                shouldSkip = true;
+            }
+        }
+
+        if (!shouldSkip) {
+            if (type == TYPE_SECURE || type == TYPE_MIX) {
+                securePlayback = true;
+                MediaCodecInfo info = getTestCodecInfo(securePlayback);
+                if (info != null) {
+                    allocateCodecs(max, info, securePlayback);
+                } else {
+                    shouldSkip = true;
+                }
+            }
+        }
+
+        if (shouldSkip) {
+            Log.d(TAG, "test skipped as there's no supported codec.");
+            finishWithResult(RESULT_OK);
+        }
+
+        Log.d(TAG, "allocateCodecs returned " + mCodecs.size());
+        return mCodecs.size();
+    }
+
+    protected void allocateCodecs(int max, MediaCodecInfo info, boolean securePlayback) {
+        String name = info.getName();
+        CodecCapabilities caps = info.getCapabilitiesForType(MIME);
+        MediaFormat format = getTestFormat(caps, securePlayback);
+        MediaCodec codec = null;
+        for (int i = mCodecs.size(); i < max; ++i) {
+            try {
+                Log.d(TAG, "Create codec " + name + " #" + i);
+                codec = MediaCodec.createByCodecName(name);
+                codec.setCallback(mCallback);
+                Log.d(TAG, "Configure codec " + format);
+                codec.configure(format, null, null, 0);
+                Log.d(TAG, "Start codec " + format);
+                codec.start();
+                mCodecs.add(codec);
+                codec = null;
+            } catch (IllegalArgumentException e) {
+                Log.d(TAG, "IllegalArgumentException " + e.getMessage());
+                break;
+            } catch (IOException e) {
+                Log.d(TAG, "IOException " + e.getMessage());
+                break;
+            } catch (MediaCodec.CodecException e) {
+                Log.d(TAG, "CodecException 0x" + Integer.toHexString(e.getErrorCode()));
+                break;
+            } finally {
+                if (codec != null) {
+                    Log.d(TAG, "release codec");
+                    codec.release();
+                    codec = null;
+                }
+            }
+        }
+    }
+
+    protected void finishWithResult(int result) {
+        for (int i = 0; i < mCodecs.size(); ++i) {
+            Log.d(TAG, "release codec #" + i);
+            mCodecs.get(i).release();
+        }
+        mCodecs.clear();
+        setResult(result);
+        finish();
+        Log.d(TAG, "activity finished");
+    }
+
+    private void doUseCodecs() {
+        int current = 0;
+        try {
+            for (current = 0; current < mCodecs.size(); ++current) {
+                mCodecs.get(current).getName();
+            }
+        } catch (MediaCodec.CodecException e) {
+            Log.d(TAG, "useCodecs got CodecException 0x" + Integer.toHexString(e.getErrorCode()));
+            if (e.getErrorCode() == MediaCodec.CodecException.ERROR_RECLAIMED) {
+                Log.d(TAG, "Remove codec " + current + " from the list");
+                mCodecs.get(current).release();
+                mCodecs.remove(current);
+                mGotReclaimedException = true;
+                mUseCodecs = false;
+            }
+            return;
+        }
+    }
+
+    private Thread mWorkerThread;
+    private volatile boolean mUseCodecs = true;
+    private volatile boolean mGotReclaimedException = false;
+    protected void useCodecs() {
+        mWorkerThread = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                long start = System.currentTimeMillis();
+                long timeSinceStartedMs = 0;
+                while (mUseCodecs && (timeSinceStartedMs < TIMEOUT_MS)) {
+                    doUseCodecs();
+                    try {
+                        Thread.sleep(50 /* millis */);
+                    } catch (InterruptedException e) {
+                    }
+                    timeSinceStartedMs = System.currentTimeMillis() - start;
+                }
+                if (mGotReclaimedException) {
+                    Log.d(TAG, "Got expected reclaim exception.");
+                }
+                finishWithResult(RESULT_OK);
+            }
+        });
+        mWorkerThread.start();
+    }
+
+    private static final int MAX_INSTANCES = 32;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        TAG = "ResourcePolicyTestActivity";
+
+        Log.d(TAG, "onCreate called.");
+        super.onCreate(savedInstanceState);
+
+        if (allocateCodecs(MAX_INSTANCES) == MAX_INSTANCES) {
+            // haven't reached the limit with MAX_INSTANCES, no need to wait for reclaim exception.
+            //mWaitForReclaim = false;
+            Log.d(TAG, "Didn't hit resource limitation");
+        }
+
+        useCodecs();
+    }
+
+    @Override
+    protected void onDestroy() {
+        Log.d(TAG, "onDestroy called.");
+        super.onDestroy();
+    }
+}
diff --git a/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh b/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh
index d66b340..1b42a22 100755
--- a/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh
+++ b/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh
@@ -37,6 +37,11 @@
 #adb shell /data/nativetest64/mediatranscodingservice_real_tests/mediatranscodingservice_real_tests
 adb shell /data/nativetest/mediatranscodingservice_real_tests/mediatranscodingservice_real_tests
 
+echo "[==========] running resource tests"
+adb shell kill -9 `pid media.transcoding`
+#adb shell /data/nativetest64/mediatranscodingservice_resource_tests/mediatranscodingservice_resource_tests
+adb shell /data/nativetest/mediatranscodingservice_resource_tests/mediatranscodingservice_resource_tests
+
 echo "[==========] removing debug properties"
 adb shell setprop debug.transcoding.simulated_transcoder \"\"
 adb shell kill -9 `pid media.transcoding`
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp
index 1def4b9..381bbf5 100644
--- a/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp
+++ b/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp
@@ -45,9 +45,11 @@
 
 class MediaTranscodingServiceRealTest : public MediaTranscodingServiceTestBase {
 public:
-    MediaTranscodingServiceRealTest() {}
+    MediaTranscodingServiceRealTest() { ALOGI("MediaTranscodingServiceResourceTest created"); }
 
-    void deleteFile(const char* path) { unlink(path); }
+    virtual ~MediaTranscodingServiceRealTest() {
+        ALOGI("MediaTranscodingServiceResourceTest destroyed");
+    }
 };
 
 TEST_F(MediaTranscodingServiceRealTest, TestInvalidSource) {
@@ -58,11 +60,11 @@
     deleteFile(dstPath);
 
     // Submit one job.
-    EXPECT_TRUE(submit(mClient1, 0, srcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
+    EXPECT_TRUE(mClient1->submit(0, srcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
 
     // Check expected error.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Failed(CLIENT(1), 0));
-    EXPECT_EQ(mClientCallback1->getLastError(), TranscodingErrorCode::kErrorIO);
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Failed(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->getLastError(), TranscodingErrorCode::kErrorIO);
 
     unregisterMultipleClients();
 }
@@ -74,11 +76,11 @@
     deleteFile(dstPath);
 
     // Submit one job.
-    EXPECT_TRUE(submit(mClient1, 0, kShortSrcPath, dstPath));
+    EXPECT_TRUE(mClient1->submit(0, kShortSrcPath, dstPath));
 
     // Wait for job to finish.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
 
     unregisterMultipleClients();
 }
@@ -91,11 +93,11 @@
 
     // Submit one job.
     EXPECT_TRUE(
-            submit(mClient1, 0, kShortSrcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
+            mClient1->submit(0, kShortSrcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
 
     // Wait for job to finish.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
 
     unregisterMultipleClients();
 }
@@ -108,16 +110,16 @@
 
     // Submit one job.
     EXPECT_TRUE(
-            submit(mClient1, 0, kLongSrcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
+            mClient1->submit(0, kLongSrcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
 
     // Wait for job to finish.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
 
     // Check the progress update messages are received. For this clip (around ~15 second long),
     // expect at least 10 updates, and the last update should be 100.
     int lastProgress;
-    EXPECT_GE(mClientCallback1->getUpdateCount(&lastProgress), 10);
+    EXPECT_GE(mClient1->getUpdateCount(&lastProgress), 10);
     EXPECT_EQ(lastProgress, 100);
 
     unregisterMultipleClients();
@@ -137,18 +139,18 @@
     deleteFile(dstPath0);
     deleteFile(dstPath1);
     // Submit one job, should start immediately.
-    EXPECT_TRUE(submit(mClient1, 0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
-    EXPECT_TRUE(getJob(mClient1, 0, srcPath0, dstPath0));
+    EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+    EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
 
     // Test cancel job immediately, getJob should fail after cancel.
-    EXPECT_TRUE(cancel(mClient1, 0));
-    EXPECT_TRUE(getJob<fail>(mClient1, 0, "", ""));
+    EXPECT_TRUE(mClient1->cancel(0));
+    EXPECT_TRUE(mClient1->getJob<fail>(0, "", ""));
 
     // Submit new job, new job should start immediately and finish.
-    EXPECT_TRUE(submit(mClient1, 1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
+    EXPECT_TRUE(mClient1->submit(1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
 
     unregisterMultipleClients();
 }
@@ -167,20 +169,20 @@
     deleteFile(dstPath0);
     deleteFile(dstPath1);
     // Submit two jobs, job 0 should start immediately, job 1 should be queued.
-    EXPECT_TRUE(submit(mClient1, 0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
-    EXPECT_TRUE(submit(mClient1, 1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
-    EXPECT_TRUE(getJob(mClient1, 0, srcPath0, dstPath0));
-    EXPECT_TRUE(getJob(mClient1, 1, srcPath1, dstPath1));
+    EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
+    EXPECT_TRUE(mClient1->submit(1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+    EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
+    EXPECT_TRUE(mClient1->getJob(1, srcPath1, dstPath1));
 
     // Job 0 (longtest) shouldn't finish in 1 seconds.
-    EXPECT_EQ(mClientCallback1->pop(1000000), EventTracker::NoEvent);
+    EXPECT_EQ(mClient1->pop(1000000), EventTracker::NoEvent);
 
     // Now cancel job 0. Job 1 should start immediately and finish.
-    EXPECT_TRUE(cancel(mClient1, 0));
-    EXPECT_TRUE(getJob<fail>(mClient1, 0, "", ""));
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
+    EXPECT_TRUE(mClient1->cancel(0));
+    EXPECT_TRUE(mClient1->getJob<fail>(0, "", ""));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
 
     unregisterMultipleClients();
 }
@@ -196,35 +198,35 @@
     deleteFile(dstPath1);
 
     // Submit one offline job, should start immediately.
-    EXPECT_TRUE(submit(mClient1, 0, srcPath0, dstPath0, TranscodingJobPriority::kUnspecified,
-                       kBitRate));
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+    EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kUnspecified,
+                                 kBitRate));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
     // Test get job after starts.
-    EXPECT_TRUE(getJob(mClient1, 0, srcPath0, dstPath0));
+    EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
 
     // Submit one realtime job.
-    EXPECT_TRUE(submit(mClient1, 1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
+    EXPECT_TRUE(mClient1->submit(1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
 
     // Offline job should pause.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
-    EXPECT_TRUE(getJob(mClient1, 0, srcPath0, dstPath0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
+    EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
 
     // Realtime job should start immediately, and run to finish.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
 
     // Test get job after finish fails.
-    EXPECT_TRUE(getJob<fail>(mClient1, 1, "", ""));
+    EXPECT_TRUE(mClient1->getJob<fail>(1, "", ""));
 
     // Then offline job should resume.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
     // Test get job after resume.
-    EXPECT_TRUE(getJob(mClient1, 0, srcPath0, dstPath0));
+    EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
 
     // Offline job should finish.
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
     // Test get job after finish fails.
-    EXPECT_TRUE(getJob<fail>(mClient1, 0, "", ""));
+    EXPECT_TRUE(mClient1->getJob<fail>(0, "", ""));
 
     unregisterMultipleClients();
 }
@@ -256,31 +258,31 @@
 
     // Submit job to Client1.
     ALOGD("Submitting job to client1 (app A) ...");
-    EXPECT_TRUE(submit(mClient1, 0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
+    EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
 
     // Client1's job should start immediately.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
 
     ALOGD("Moving app B to top...");
     EXPECT_TRUE(ShellHelper::Start(kClientPackageB, kTestActivityName));
 
     // Client1's job should continue to run, since Client2 (app B) doesn't have any job.
-    EXPECT_EQ(mClientCallback1->pop(1000000), EventTracker::NoEvent);
+    EXPECT_EQ(mClient1->pop(1000000), EventTracker::NoEvent);
 
     // Submit job to Client2.
     ALOGD("Submitting job to client2 (app B) ...");
-    EXPECT_TRUE(submit(mClient2, 0, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
+    EXPECT_TRUE(mClient2->submit(0, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
 
     // Client1's job should pause, client2's job should start.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
-    EXPECT_EQ(mClientCallback2->pop(kPaddingUs), EventTracker::Start(CLIENT(2), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
+    EXPECT_EQ(mClient2->pop(kPaddingUs), EventTracker::Start(CLIENT(2), 0));
 
     // Client2's job should finish, then Client1's job should resume.
-    EXPECT_EQ(mClientCallback2->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(2), 0));
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
+    EXPECT_EQ(mClient2->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(2), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
 
     // Client1's job should finish.
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
 
     unregisterMultipleClients();
 
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_resource_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_resource_tests.cpp
new file mode 100644
index 0000000..31697d5
--- /dev/null
+++ b/services/mediatranscoding/tests/mediatranscodingservice_resource_tests.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+// Unit Test for MediaTranscodingService.
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaTranscodingServiceRealTest"
+
+#include "MediaTranscodingServiceTestHelper.h"
+
+/*
+ * Tests media transcoding service with real transcoder.
+ *
+ * Uses the same test assets as the MediaTranscoder unit tests. Before running the test,
+ * please make sure to push the test assets to /sdcard:
+ *
+ * adb push $TOP/frameworks/av/media/libmediatranscoding/transcoder/tests/assets /data/local/tmp/TranscodingTestAssets
+ */
+namespace android {
+
+namespace media {
+
+constexpr int64_t kPaddingUs = 400000;
+constexpr int32_t kBitRate = 8 * 1000 * 1000;  // 8Mbs
+
+constexpr const char* kLongSrcPath = "/data/local/tmp/TranscodingTestAssets/longtest_15s.mp4";
+
+constexpr const char* kResourcePolicyTestActivity =
+        "/com.android.tests.transcoding.ResourcePolicyTestActivity";
+
+#define OUTPATH(name) "/data/local/tmp/MediaTranscodingService_" #name ".MP4"
+
+class MediaTranscodingServiceResourceTest : public MediaTranscodingServiceTestBase {
+public:
+    MediaTranscodingServiceResourceTest() { ALOGI("MediaTranscodingServiceResourceTest created"); }
+
+    virtual ~MediaTranscodingServiceResourceTest() {
+        ALOGI("MediaTranscodingServiceResourceTest destroyed");
+    }
+};
+
+/**
+ * Basic testing for handling resource lost.
+ *
+ * This test starts a transcoding job (that's somewhat long and takes several seconds),
+ * then launches an activity that allocates video codec instances until it hits insufficient
+ * resource error. Because the activity is running in foreground,
+ * ResourceManager would reclaim codecs from transcoding service which should
+ * cause the job to be paused. The activity will hold the codecs for a few seconds
+ * before releasing them, and the transcoding service should be able to resume
+ * and complete the job.
+ */
+TEST_F(MediaTranscodingServiceResourceTest, TestResourceLost) {
+    ALOGD("TestResourceLost starting...");
+
+    EXPECT_TRUE(ShellHelper::RunCmd("input keyevent KEYCODE_WAKEUP"));
+    EXPECT_TRUE(ShellHelper::RunCmd("wm dismiss-keyguard"));
+    EXPECT_TRUE(ShellHelper::Stop(kClientPackageA));
+
+    registerMultipleClients();
+
+    const char* srcPath0 = kLongSrcPath;
+    const char* dstPath0 = OUTPATH(TestPauseResumeMultiClients_Client0);
+    deleteFile(dstPath0);
+
+    ALOGD("Moving app A to top...");
+    EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kTestActivityName));
+
+    // Submit job to Client1.
+    ALOGD("Submitting job to client1 (app A) ...");
+    EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
+
+    // Client1's job should start immediately.
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+
+    // Launch ResourcePolicyTestActivity, which will try to allocate up to 32
+    // instances, which should trigger insufficient resources on most devices.
+    // (Note that it's possible that the device supports a very high number of
+    // resource instances, in which case we'll simply require that the job completes.)
+    ALOGD("Launch ResourcePolicyTestActivity...");
+    EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kResourcePolicyTestActivity));
+
+    // The basic requirement is that the job should complete. Wait for finish
+    // event to come and pop up all events received.
+    std::list<EventTracker::Event> events;
+    EXPECT_TRUE(mClient1->waitForSpecificEventAndPop(EventTracker::Finished(CLIENT(1), 0), &events,
+                                                     15000000));
+
+    // If there is only 1 event, it must be finish (otherwise waitForSpecificEventAndPop
+    // woudldn't pop up anything), and we're ok.
+    //
+    // TODO: If there is only 1 event (finish), and no pause/resume happened, we need
+    // to verify that the ResourcePolicyTestActivity actually was able to allocate
+    // all 32 instances without hitting insufficient resources. Otherwise, it could
+    // be that ResourceManager was not able to reclaim codecs from the transcoding
+    // service at all, which means the resource management is broken.
+    if (events.size() > 1) {
+        EXPECT_TRUE(events.size() >= 3);
+        size_t i = 0;
+        for (auto& event : events) {
+            if (i == 0) {
+                EXPECT_EQ(event, EventTracker::Pause(CLIENT(1), 0));
+            } else if (i == events.size() - 2) {
+                EXPECT_EQ(event, EventTracker::Resume(CLIENT(1), 0));
+            } else if (i == events.size() - 1) {
+                EXPECT_EQ(event, EventTracker::Finished(CLIENT(1), 0));
+            } else {
+                EXPECT_TRUE(event == EventTracker::Pause(CLIENT(1), 0) ||
+                            event == EventTracker::Resume(CLIENT(1), 0));
+            }
+            i++;
+        }
+    }
+
+    unregisterMultipleClients();
+
+    EXPECT_TRUE(ShellHelper::Stop(kClientPackageA));
+}
+
+}  // namespace media
+}  // namespace android
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp
index 42b5877..c912b03 100644
--- a/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp
+++ b/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp
@@ -47,11 +47,10 @@
 // Note that -1 is valid and means using calling pid/uid for the service. But only privilege caller could
 // use them. This test is not a privilege caller.
 constexpr int32_t kInvalidClientPid = -5;
+constexpr int32_t kInvalidClientUid = -10;
 constexpr const char* kInvalidClientName = "";
 constexpr const char* kInvalidClientOpPackageName = "";
 
-constexpr int32_t kClientUseCallingUid = IMediaTranscodingService::USE_CALLING_UID;
-
 constexpr int64_t kPaddingUs = 1000000;
 constexpr int64_t kJobWithPaddingUs = SimulatedTranscoder::kJobDurationUs + kPaddingUs;
 
@@ -59,24 +58,18 @@
 
 class MediaTranscodingServiceSimulatedTest : public MediaTranscodingServiceTestBase {
 public:
-    MediaTranscodingServiceSimulatedTest() {}
+    MediaTranscodingServiceSimulatedTest() { ALOGI("MediaTranscodingServiceResourceTest created"); }
+
+    virtual ~MediaTranscodingServiceSimulatedTest() {
+        ALOGI("MediaTranscodingServiceResourceTest destroyed");
+    }
 };
 
 TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterNullClient) {
     std::shared_ptr<ITranscodingClient> client;
 
     // Register the client with null callback.
-    Status status = mService->registerClient(nullptr, kClientName, kClientOpPackageName,
-                                             kClientUseCallingUid, kClientUseCallingPid, &client);
-    EXPECT_FALSE(status.isOk());
-}
-
-TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterClientWithInvalidClientPid) {
-    std::shared_ptr<ITranscodingClient> client;
-
-    // Register the client with the service.
-    Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
-                                             kClientUseCallingUid, kInvalidClientPid, &client);
+    Status status = mService->registerClient(nullptr, kClientName, kClientOpPackageName, &client);
     EXPECT_FALSE(status.isOk());
 }
 
@@ -84,9 +77,8 @@
     std::shared_ptr<ITranscodingClient> client;
 
     // Register the client with the service.
-    Status status = mService->registerClient(mClientCallback1, kInvalidClientName,
-                                             kInvalidClientOpPackageName, kClientUseCallingUid,
-                                             kClientUseCallingPid, &client);
+    Status status = mService->registerClient(mClient1, kInvalidClientName,
+                                             kInvalidClientOpPackageName, &client);
     EXPECT_FALSE(status.isOk());
 }
 
@@ -95,16 +87,14 @@
 
     // Register the client with the service.
     Status status =
-            mService->registerClient(mClientCallback1, kClientName, kInvalidClientOpPackageName,
-                                     kClientUseCallingUid, kClientUseCallingPid, &client);
+            mService->registerClient(mClient1, kClientName, kInvalidClientOpPackageName, &client);
     EXPECT_FALSE(status.isOk());
 }
 
 TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterOneClient) {
     std::shared_ptr<ITranscodingClient> client;
 
-    Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
-                                             kClientUseCallingUid, kClientUseCallingPid, &client);
+    Status status = mService->registerClient(mClient1, kClientName, kClientOpPackageName, &client);
     EXPECT_TRUE(status.isOk());
 
     // Validate the client.
@@ -129,8 +119,7 @@
 TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterClientTwice) {
     std::shared_ptr<ITranscodingClient> client;
 
-    Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
-                                             kClientUseCallingUid, kClientUseCallingPid, &client);
+    Status status = mService->registerClient(mClient1, kClientName, kClientOpPackageName, &client);
     EXPECT_TRUE(status.isOk());
 
     // Validate the client.
@@ -138,8 +127,7 @@
 
     // Register the client again and expects failure.
     std::shared_ptr<ITranscodingClient> client1;
-    status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
-                                      kClientUseCallingUid, kClientUseCallingPid, &client1);
+    status = mService->registerClient(mClient1, kClientName, kClientOpPackageName, &client1);
     EXPECT_FALSE(status.isOk());
 
     // Unregister the client.
@@ -156,18 +144,18 @@
     registerMultipleClients();
 
     // Submit 2 requests on client1 first.
-    EXPECT_TRUE(submit(mClient1, 0, "test_source_file", "test_destination_file"));
-    EXPECT_TRUE(submit(mClient1, 1, "test_source_file", "test_destination_file"));
+    EXPECT_TRUE(mClient1->submit(0, "test_source_file", "test_destination_file"));
+    EXPECT_TRUE(mClient1->submit(1, "test_source_file", "test_destination_file"));
 
     // Submit 2 requests on client2, jobId should be independent for each client.
-    EXPECT_TRUE(submit(mClient2, 0, "test_source_file", "test_destination_file"));
-    EXPECT_TRUE(submit(mClient2, 1, "test_source_file", "test_destination_file"));
+    EXPECT_TRUE(mClient2->submit(0, "test_source_file", "test_destination_file"));
+    EXPECT_TRUE(mClient2->submit(1, "test_source_file", "test_destination_file"));
 
     // Cancel all jobs.
-    EXPECT_TRUE(cancel(mClient1, 0));
-    EXPECT_TRUE(cancel(mClient1, 1));
-    EXPECT_TRUE(cancel(mClient2, 0));
-    EXPECT_TRUE(cancel(mClient2, 1));
+    EXPECT_TRUE(mClient1->cancel(0));
+    EXPECT_TRUE(mClient1->cancel(1));
+    EXPECT_TRUE(mClient2->cancel(0));
+    EXPECT_TRUE(mClient2->cancel(1));
 
     unregisterMultipleClients();
 }
@@ -176,32 +164,36 @@
     registerMultipleClients();
 
     // Test jobId assignment.
-    EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file"));
-    EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file"));
-    EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file"));
+    EXPECT_TRUE(mClient1->submit(0, "test_source_file_0", "test_destination_file"));
+    EXPECT_TRUE(mClient1->submit(1, "test_source_file_1", "test_destination_file"));
+    EXPECT_TRUE(mClient1->submit(2, "test_source_file_2", "test_destination_file"));
 
     // Test submit bad request (no valid sourceFilePath) fails.
-    EXPECT_TRUE(submit<fail>(mClient1, 0, "", ""));
+    EXPECT_TRUE(mClient1->submit<fail>(0, "", ""));
+
+    // Test submit bad request (no valid sourceFilePath) fails.
+    EXPECT_TRUE(mClient1->submit<fail>(0, "src", "dst", TranscodingJobPriority::kNormal, 1000000,
+                                       kInvalidClientPid, kInvalidClientUid));
 
     // Test cancel non-existent job fails.
-    EXPECT_TRUE(cancel<fail>(mClient1, 100));
+    EXPECT_TRUE(mClient1->cancel<fail>(100));
 
     // Job 0 should start immediately and finish in 2 seconds, followed by Job 1 start.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
 
     // Test cancel valid jobId in random order.
     // Test cancel finished job fails.
-    EXPECT_TRUE(cancel(mClient1, 2));
-    EXPECT_TRUE(cancel<fail>(mClient1, 0));
-    EXPECT_TRUE(cancel(mClient1, 1));
+    EXPECT_TRUE(mClient1->cancel(2));
+    EXPECT_TRUE(mClient1->cancel<fail>(0));
+    EXPECT_TRUE(mClient1->cancel(1));
 
     // Test cancel job again fails.
-    EXPECT_TRUE(cancel<fail>(mClient1, 1));
+    EXPECT_TRUE(mClient1->cancel<fail>(1));
 
     // Test no more events arriving after cancel.
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::NoEvent);
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::NoEvent);
 
     unregisterMultipleClients();
 }
@@ -210,36 +202,36 @@
     registerMultipleClients();
 
     // Submit 3 requests.
-    EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file_0"));
-    EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
-    EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
+    EXPECT_TRUE(mClient1->submit(0, "test_source_file_0", "test_destination_file_0"));
+    EXPECT_TRUE(mClient1->submit(1, "test_source_file_1", "test_destination_file_1"));
+    EXPECT_TRUE(mClient1->submit(2, "test_source_file_2", "test_destination_file_2"));
 
     // Test get jobs by id.
-    EXPECT_TRUE(getJob(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
-    EXPECT_TRUE(getJob(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
-    EXPECT_TRUE(getJob(mClient1, 0, "test_source_file_0", "test_destination_file_0"));
+    EXPECT_TRUE(mClient1->getJob(2, "test_source_file_2", "test_destination_file_2"));
+    EXPECT_TRUE(mClient1->getJob(1, "test_source_file_1", "test_destination_file_1"));
+    EXPECT_TRUE(mClient1->getJob(0, "test_source_file_0", "test_destination_file_0"));
 
     // Test get job by invalid id fails.
-    EXPECT_TRUE(getJob<fail>(mClient1, 100, "", ""));
-    EXPECT_TRUE(getJob<fail>(mClient1, -1, "", ""));
+    EXPECT_TRUE(mClient1->getJob<fail>(100, "", ""));
+    EXPECT_TRUE(mClient1->getJob<fail>(-1, "", ""));
 
     // Test get job after cancel fails.
-    EXPECT_TRUE(cancel(mClient1, 2));
-    EXPECT_TRUE(getJob<fail>(mClient1, 2, "", ""));
+    EXPECT_TRUE(mClient1->cancel(2));
+    EXPECT_TRUE(mClient1->getJob<fail>(2, "", ""));
 
     // Job 0 should start immediately and finish in 2 seconds, followed by Job 1 start.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
 
     // Test get job after finish fails.
-    EXPECT_TRUE(getJob<fail>(mClient1, 0, "", ""));
+    EXPECT_TRUE(mClient1->getJob<fail>(0, "", ""));
 
     // Test get the remaining job 1.
-    EXPECT_TRUE(getJob(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
+    EXPECT_TRUE(mClient1->getJob(1, "test_source_file_1", "test_destination_file_1"));
 
     // Cancel remaining job 1.
-    EXPECT_TRUE(cancel(mClient1, 1));
+    EXPECT_TRUE(mClient1->cancel(1));
 
     unregisterMultipleClients();
 }
@@ -248,36 +240,36 @@
     registerMultipleClients();
 
     // Submit some offline jobs first.
-    EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file_0",
-                       TranscodingJobPriority::kUnspecified));
-    EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file_1",
-                       TranscodingJobPriority::kUnspecified));
+    EXPECT_TRUE(mClient1->submit(0, "test_source_file_0", "test_destination_file_0",
+                                 TranscodingJobPriority::kUnspecified));
+    EXPECT_TRUE(mClient1->submit(1, "test_source_file_1", "test_destination_file_1",
+                                 TranscodingJobPriority::kUnspecified));
 
     // Job 0 should start immediately.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
 
     // Submit more real-time jobs.
-    EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
-    EXPECT_TRUE(submit(mClient1, 3, "test_source_file_3", "test_destination_file_3"));
+    EXPECT_TRUE(mClient1->submit(2, "test_source_file_2", "test_destination_file_2"));
+    EXPECT_TRUE(mClient1->submit(3, "test_source_file_3", "test_destination_file_3"));
 
     // Job 0 should pause immediately and job 2 should start.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 2));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 2));
 
     // Job 2 should finish in 2 seconds and job 3 should start.
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 3));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 3));
 
     // Cancel job 3 now
-    EXPECT_TRUE(cancel(mClient1, 3));
+    EXPECT_TRUE(mClient1->cancel(3));
 
     // Job 0 should resume and finish in 2 seconds, followed by job 1 start.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
 
     // Cancel remaining job 1.
-    EXPECT_TRUE(cancel(mClient1, 1));
+    EXPECT_TRUE(mClient1->cancel(1));
 
     unregisterMultipleClients();
 }
@@ -286,8 +278,7 @@
     std::shared_ptr<ITranscodingClient> client;
 
     // Register a client, then unregister.
-    Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
-                                             kClientUseCallingUid, kClientUseCallingPid, &client);
+    Status status = mService->registerClient(mClient1, kClientName, kClientOpPackageName, &client);
     EXPECT_TRUE(status.isOk());
 
     status = client->unregister();
@@ -323,41 +314,41 @@
 
     // Submit 3 requests.
     ALOGD("Submitting job to client1 (app A) ...");
-    EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file_0"));
-    EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
-    EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
+    EXPECT_TRUE(mClient1->submit(0, "test_source_file_0", "test_destination_file_0"));
+    EXPECT_TRUE(mClient1->submit(1, "test_source_file_1", "test_destination_file_1"));
+    EXPECT_TRUE(mClient1->submit(2, "test_source_file_2", "test_destination_file_2"));
 
     // Job 0 should start immediately.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
 
     ALOGD("Moving app B to top...");
     EXPECT_TRUE(ShellHelper::Start(kClientPackageB, kTestActivityName));
 
     // Job 0 should continue and finish in 2 seconds, then job 1 should start.
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
 
     ALOGD("Submitting job to client2 (app B) ...");
-    EXPECT_TRUE(submit(mClient2, 0, "test_source_file_0", "test_destination_file_0"));
+    EXPECT_TRUE(mClient2->submit(0, "test_source_file_0", "test_destination_file_0"));
 
     // Client1's job should pause, client2's job should start.
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 1));
-    EXPECT_EQ(mClientCallback2->pop(kPaddingUs), EventTracker::Start(CLIENT(2), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 1));
+    EXPECT_EQ(mClient2->pop(kPaddingUs), EventTracker::Start(CLIENT(2), 0));
 
     ALOGD("Moving app A back to top...");
     EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kTestActivityName));
 
     // Client2's job should pause, client1's job 1 should resume.
-    EXPECT_EQ(mClientCallback2->pop(kPaddingUs), EventTracker::Pause(CLIENT(2), 0));
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 1));
+    EXPECT_EQ(mClient2->pop(kPaddingUs), EventTracker::Pause(CLIENT(2), 0));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 1));
 
     // Client2's job 1 should finish in 2 seconds, then its job 2 should start.
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
-    EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 2));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
+    EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 2));
 
     // After client2's jobs finish, client1's job should resume.
-    EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
-    EXPECT_EQ(mClientCallback2->pop(kPaddingUs), EventTracker::Resume(CLIENT(2), 0));
+    EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
+    EXPECT_EQ(mClient2->pop(kPaddingUs), EventTracker::Resume(CLIENT(2), 0));
 
     unregisterMultipleClients();
 
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index 9d9ca63..3ec8dea 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -198,7 +198,7 @@
         for (const auto& serviceStream : streamsToClose) {
             aaudio_handle_t handle = serviceStream->getHandle();
             ALOGW("binderDied() close abandoned stream 0x%08X\n", handle);
-            aaudioService->closeStream(handle);
+            aaudioService->asAAudioServiceInterface().closeStream(handle);
         }
         // mStreams should be empty now
     }
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
index 943b809..facfc3b 100644
--- a/services/oboeservice/AAudioClientTracker.h
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -24,7 +24,7 @@
 #include <utils/Singleton.h>
 
 #include <aaudio/AAudio.h>
-#include "binding/IAAudioClient.h"
+#include <aaudio/IAAudioClient.h>
 #include "AAudioService.h"
 
 namespace aaudio {
@@ -46,7 +46,7 @@
      */
     std::string dump() const;
 
-    aaudio_result_t registerClient(pid_t pid, const android::sp<android::IAAudioClient>& client);
+    aaudio_result_t registerClient(pid_t pid, const android::sp<IAAudioClient>& client);
 
     void unregisterClient(pid_t pid);
 
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 22cdb35..69e58f6 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -32,26 +32,26 @@
 #include "AAudioService.h"
 #include "AAudioServiceStreamMMAP.h"
 #include "AAudioServiceStreamShared.h"
-#include "binding/IAAudioService.h"
 
 using namespace android;
 using namespace aaudio;
 
 #define MAX_STREAMS_PER_PROCESS   8
+#define AIDL_RETURN(x) *_aidl_return = (x); return Status::ok();
+
 
 using android::AAudioService;
+using binder::Status;
 
 android::AAudioService::AAudioService()
-    : BnAAudioService() {
+    : BnAAudioService(),
+      mAdapter(this) {
     mAudioClient.clientUid = getuid();   // TODO consider using geteuid()
     mAudioClient.clientPid = getpid();
     mAudioClient.packageName = String16("");
     AAudioClientTracker::getInstance().setAAudioService(this);
 }
 
-AAudioService::~AAudioService() {
-}
-
 status_t AAudioService::dump(int fd, const Vector<String16>& args) {
     std::string result;
 
@@ -72,18 +72,21 @@
     return NO_ERROR;
 }
 
-void AAudioService::registerClient(const sp<IAAudioClient>& client) {
+Status AAudioService::registerClient(const sp<IAAudioClient> &client) {
     pid_t pid = IPCThreadState::self()->getCallingPid();
     AAudioClientTracker::getInstance().registerClient(pid, client);
+    return Status::ok();
 }
 
-bool AAudioService::isCallerInService() {
-    return mAudioClient.clientPid == IPCThreadState::self()->getCallingPid() &&
-        mAudioClient.clientUid == IPCThreadState::self()->getCallingUid();
-}
+Status
+AAudioService::openStream(const StreamRequest &_request, StreamParameters* _paramsOut,
+                          int32_t *_aidl_return) {
+    static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
 
-aaudio_handle_t AAudioService::openStream(const aaudio::AAudioStreamRequest &request,
-                                          aaudio::AAudioStreamConfiguration &configurationOutput) {
+    // Create wrapper objects for simple usage of the parcelables.
+    const AAudioStreamRequest request(_request);
+    AAudioStreamConfiguration paramsOut;
+
     // A lock in is used to order the opening of endpoints when an
     // EXCLUSIVE endpoint is stolen. We want the order to be:
     // 1) Thread A opens exclusive MMAP endpoint
@@ -108,13 +111,13 @@
         if (count >= MAX_STREAMS_PER_PROCESS) {
             ALOGE("openStream(): exceeded max streams per process %d >= %d",
                   count,  MAX_STREAMS_PER_PROCESS);
-            return AAUDIO_ERROR_UNAVAILABLE;
+            AIDL_RETURN(AAUDIO_ERROR_UNAVAILABLE);
         }
     }
 
     if (sharingMode != AAUDIO_SHARING_MODE_EXCLUSIVE && sharingMode != AAUDIO_SHARING_MODE_SHARED) {
         ALOGE("openStream(): unrecognized sharing mode = %d", sharingMode);
-        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+        AIDL_RETURN(AAUDIO_ERROR_ILLEGAL_ARGUMENT);
     }
 
     if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE
@@ -147,29 +150,124 @@
 
     if (result != AAUDIO_OK) {
         serviceStream.clear();
-        return result;
+        AIDL_RETURN(result);
     } else {
         aaudio_handle_t handle = mStreamTracker.addStreamForHandle(serviceStream.get());
         serviceStream->setHandle(handle);
         pid_t pid = request.getProcessId();
         AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
-        configurationOutput.copyFrom(*serviceStream);
+        paramsOut.copyFrom(*serviceStream);
+        *_paramsOut = std::move(paramsOut).parcelable();
         // Log open in MediaMetrics after we have the handle because we need the handle to
         // create the metrics ID.
         serviceStream->logOpen(handle);
         ALOGV("%s(): return handle = 0x%08X", __func__, handle);
-        return handle;
+        AIDL_RETURN(handle);
     }
 }
 
-aaudio_result_t AAudioService::closeStream(aaudio_handle_t streamHandle) {
+Status AAudioService::closeStream(int32_t streamHandle, int32_t *_aidl_return) {
+    static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
+
     // Check permission and ownership first.
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
         ALOGE("closeStream(0x%0x), illegal stream handle", streamHandle);
-        return AAUDIO_ERROR_INVALID_HANDLE;
+        AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
     }
-    return closeStream(serviceStream);
+    AIDL_RETURN(closeStream(serviceStream));
+}
+
+Status AAudioService::getStreamDescription(int32_t streamHandle, Endpoint* endpoint,
+                                           int32_t *_aidl_return) {
+    static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
+
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
+        ALOGE("getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
+        AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
+    }
+    AudioEndpointParcelable endpointParcelable;
+    aaudio_result_t result = serviceStream->getDescription(endpointParcelable);
+    if (result == AAUDIO_OK) {
+        *endpoint = std::move(endpointParcelable).parcelable();
+    }
+    AIDL_RETURN(result);
+}
+
+Status AAudioService::startStream(int32_t streamHandle, int32_t *_aidl_return) {
+    static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
+
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
+        ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
+        AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
+    }
+    AIDL_RETURN(serviceStream->start());
+}
+
+Status AAudioService::pauseStream(int32_t streamHandle, int32_t *_aidl_return) {
+    static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
+
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
+        ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
+        AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
+    }
+    AIDL_RETURN(serviceStream->pause());
+}
+
+Status AAudioService::stopStream(int32_t streamHandle, int32_t *_aidl_return) {
+    static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
+
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
+        ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
+        AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
+    }
+    AIDL_RETURN(serviceStream->stop());
+}
+
+Status AAudioService::flushStream(int32_t streamHandle, int32_t *_aidl_return) {
+    static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
+
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
+        ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
+        AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
+    }
+    AIDL_RETURN(serviceStream->flush());
+}
+
+Status AAudioService::registerAudioThread(int32_t streamHandle, int32_t clientThreadId, int64_t periodNanoseconds,
+                                          int32_t *_aidl_return) {
+    static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
+
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
+        ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
+        AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
+    }
+    int32_t priority = isCallerInService()
+        ? kRealTimeAudioPriorityService : kRealTimeAudioPriorityClient;
+    AIDL_RETURN(serviceStream->registerAudioThread(clientThreadId, priority));
+}
+
+Status AAudioService::unregisterAudioThread(int32_t streamHandle, int32_t clientThreadId,
+                                            int32_t *_aidl_return) {
+    static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
+
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
+        ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
+        AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
+    }
+    AIDL_RETURN(serviceStream->unregisterAudioThread(clientThreadId));
+}
+
+bool AAudioService::isCallerInService() {
+    return mAudioClient.clientPid == IPCThreadState::self()->getCallingPid() &&
+        mAudioClient.clientUid == IPCThreadState::self()->getCallingUid();
 }
 
 aaudio_result_t AAudioService::closeStream(sp<AAudioServiceStreamBase> serviceStream) {
@@ -205,76 +303,6 @@
     return serviceStream;
 }
 
-aaudio_result_t AAudioService::getStreamDescription(
-                aaudio_handle_t streamHandle,
-                aaudio::AudioEndpointParcelable &parcelable) {
-    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream.get() == nullptr) {
-        ALOGE("getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
-        return AAUDIO_ERROR_INVALID_HANDLE;
-    }
-    return serviceStream->getDescription(parcelable);
-}
-
-aaudio_result_t AAudioService::startStream(aaudio_handle_t streamHandle) {
-    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream.get() == nullptr) {
-        ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
-        return AAUDIO_ERROR_INVALID_HANDLE;
-    }
-    return serviceStream->start();
-}
-
-aaudio_result_t AAudioService::pauseStream(aaudio_handle_t streamHandle) {
-    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream.get() == nullptr) {
-        ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
-        return AAUDIO_ERROR_INVALID_HANDLE;
-    }
-    return serviceStream->pause();
-}
-
-aaudio_result_t AAudioService::stopStream(aaudio_handle_t streamHandle) {
-    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream.get() == nullptr) {
-        ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
-        return AAUDIO_ERROR_INVALID_HANDLE;
-    }
-    return serviceStream->stop();
-}
-
-aaudio_result_t AAudioService::flushStream(aaudio_handle_t streamHandle) {
-    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream.get() == nullptr) {
-        ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
-        return AAUDIO_ERROR_INVALID_HANDLE;
-    }
-    return serviceStream->flush();
-}
-
-aaudio_result_t AAudioService::registerAudioThread(aaudio_handle_t streamHandle,
-                                                   pid_t clientThreadId,
-                                                   int64_t /* periodNanoseconds */) {
-    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream.get() == nullptr) {
-        ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
-        return AAUDIO_ERROR_INVALID_HANDLE;
-    }
-    int32_t priority = isCallerInService()
-        ? kRealTimeAudioPriorityService : kRealTimeAudioPriorityClient;
-    return serviceStream->registerAudioThread(clientThreadId, priority);
-}
-
-aaudio_result_t AAudioService::unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                     pid_t clientThreadId) {
-    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream.get() == nullptr) {
-        ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
-        return AAUDIO_ERROR_INVALID_HANDLE;
-    }
-    return serviceStream->unregisterAudioThread(clientThreadId);
-}
-
 aaudio_result_t AAudioService::startClient(aaudio_handle_t streamHandle,
                                            const android::AudioClient& client,
                                            const audio_attributes_t *attr,
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index caf48a5..7c1b796 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -24,69 +24,71 @@
 #include <media/AudioClient.h>
 
 #include <aaudio/AAudio.h>
+#include <aaudio/BnAAudioService.h>
 
 #include "binding/AAudioCommon.h"
+#include "binding/AAudioBinderAdapter.h"
 #include "binding/AAudioServiceInterface.h"
-#include "binding/IAAudioService.h"
 
 #include "AAudioServiceStreamBase.h"
 #include "AAudioStreamTracker.h"
 
 namespace android {
 
+#define AAUDIO_SERVICE_NAME  "media.aaudio"
+
 class AAudioService :
     public BinderService<AAudioService>,
-    public BnAAudioService,
-    public aaudio::AAudioServiceInterface
+    public aaudio::BnAAudioService
 {
     friend class BinderService<AAudioService>;
 
 public:
     AAudioService();
-    virtual ~AAudioService();
+    virtual ~AAudioService() = default;
+
+    aaudio::AAudioServiceInterface& asAAudioServiceInterface() {
+        return mAdapter;
+    }
 
     static const char* getServiceName() { return AAUDIO_SERVICE_NAME; }
 
     virtual status_t        dump(int fd, const Vector<String16>& args) override;
 
-    virtual void            registerClient(const sp<IAAudioClient>& client);
+    binder::Status registerClient(const ::android::sp<::aaudio::IAAudioClient>& client) override;
 
-    aaudio::aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
-                                       aaudio::AAudioStreamConfiguration &configurationOutput)
-                                       override;
+    binder::Status openStream(const ::aaudio::StreamRequest& request,
+                              ::aaudio::StreamParameters* paramsOut,
+                              int32_t* _aidl_return) override;
 
-    /*
-     * This is called from Binder. It checks for permissions
-     * and converts the handle passed through Binder to a stream pointer.
-     */
-    aaudio_result_t closeStream(aaudio::aaudio_handle_t streamHandle) override;
+    binder::Status closeStream(int32_t streamHandle, int32_t* _aidl_return) override;
 
-    aaudio_result_t getStreamDescription(
-                aaudio::aaudio_handle_t streamHandle,
-                aaudio::AudioEndpointParcelable &parcelable) override;
+    binder::Status
+    getStreamDescription(int32_t streamHandle, ::aaudio::Endpoint* endpoint,
+                         int32_t* _aidl_return) override;
 
-    aaudio_result_t startStream(aaudio::aaudio_handle_t streamHandle) override;
+    binder::Status startStream(int32_t streamHandle, int32_t* _aidl_return) override;
 
-    aaudio_result_t pauseStream(aaudio::aaudio_handle_t streamHandle) override;
+    binder::Status pauseStream(int32_t streamHandle, int32_t* _aidl_return) override;
 
-    aaudio_result_t stopStream(aaudio::aaudio_handle_t streamHandle) override;
+    binder::Status stopStream(int32_t streamHandle, int32_t* _aidl_return) override;
 
-    aaudio_result_t flushStream(aaudio::aaudio_handle_t streamHandle) override;
+    binder::Status flushStream(int32_t streamHandle, int32_t* _aidl_return) override;
 
-    aaudio_result_t registerAudioThread(aaudio::aaudio_handle_t streamHandle,
-                                                pid_t tid,
-                                                int64_t periodNanoseconds) override;
+    binder::Status
+    registerAudioThread(int32_t streamHandle, int32_t clientThreadId, int64_t periodNanoseconds,
+                        int32_t* _aidl_return) override;
 
-    aaudio_result_t unregisterAudioThread(aaudio::aaudio_handle_t streamHandle,
-                                                  pid_t tid) override;
+    binder::Status unregisterAudioThread(int32_t streamHandle, int32_t clientThreadId,
+                                         int32_t* _aidl_return) override;
 
     aaudio_result_t startClient(aaudio::aaudio_handle_t streamHandle,
                                 const android::AudioClient& client,
                                 const audio_attributes_t *attr,
-                                audio_port_handle_t *clientHandle) override;
+                                audio_port_handle_t *clientHandle);
 
     aaudio_result_t stopClient(aaudio::aaudio_handle_t streamHandle,
-                                       audio_port_handle_t clientHandle) override;
+                                       audio_port_handle_t clientHandle);
 
  // ===============================================================================
  // The following public methods are only called from the service and NOT by Binder.
@@ -101,6 +103,29 @@
     aaudio_result_t closeStream(sp<aaudio::AAudioServiceStreamBase> serviceStream);
 
 private:
+    class Adapter : public aaudio::AAudioBinderAdapter {
+    public:
+        explicit Adapter(AAudioService *service)
+                : aaudio::AAudioBinderAdapter(service),
+                  mService(service) {}
+
+        aaudio_result_t startClient(aaudio::aaudio_handle_t streamHandle,
+                                    const android::AudioClient &client,
+                                    const audio_attributes_t *attr,
+                                    audio_port_handle_t *clientHandle) override {
+            return mService->startClient(streamHandle, client, attr, clientHandle);
+        }
+
+        aaudio_result_t stopClient(aaudio::aaudio_handle_t streamHandle,
+                                   audio_port_handle_t clientHandle) override {
+            return mService->stopClient(streamHandle, clientHandle);
+        }
+
+    private:
+        AAudioService* const mService;
+    };
+
+    Adapter mAdapter;
 
     /** @return true if the client is the audioserver
      */
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index 1401120..b86fe9d 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -35,9 +35,9 @@
 using namespace android;  // TODO just import names needed
 using namespace aaudio;   // TODO just import names needed
 
-AAudioServiceEndpointCapture::AAudioServiceEndpointCapture(AAudioService &audioService)
-    : AAudioServiceEndpointShared(
-            (AudioStreamInternal *)(new AudioStreamInternalCapture(audioService, true))) {
+AAudioServiceEndpointCapture::AAudioServiceEndpointCapture(AAudioService& audioService)
+        : AAudioServiceEndpointShared(
+                new AudioStreamInternalCapture(audioService.asAAudioServiceInterface(), true)) {
 }
 
 aaudio_result_t AAudioServiceEndpointCapture::open(const aaudio::AAudioStreamRequest &request) {
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 04c6453..5bccfd5 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -378,3 +378,18 @@
     parcelable.mDownDataQueueParcelable.setCapacityInFrames(getBufferCapacity());
     return AAUDIO_OK;
 }
+
+aaudio_result_t AAudioServiceEndpointMMAP::getExternalPosition(uint64_t *positionFrames,
+                                                               int64_t *timeNanos)
+{
+    if (!mExternalPositionSupported) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    status_t status = mMmapStream->getExternalPosition(positionFrames, timeNanos);
+    if (status == INVALID_OPERATION) {
+        // getExternalPosition is not supported. Set mExternalPositionSupported as false
+        // so that the call will not go to the HAL next time.
+        mExternalPositionSupported = false;
+    }
+    return AAudioConvert_androidToAAudioResult(status);
+}
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h
index b6003b6..a2a0922 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.h
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.h
@@ -85,6 +85,8 @@
         return mHardwareTimeOffsetNanos;
     }
 
+    aaudio_result_t getExternalPosition(uint64_t *positionFrames, int64_t *timeNanos);
+
 private:
     MonotonicCounter                          mFramesTransferred;
 
@@ -101,6 +103,8 @@
 
     int64_t                                   mHardwareTimeOffsetNanos = 0; // TODO get from HAL
 
+    bool                                      mExternalPositionSupported = true;
+
 };
 
 } /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index 08d2319..53cb70b 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -41,10 +41,9 @@
 
 #define BURSTS_PER_BUFFER_DEFAULT   2
 
-AAudioServiceEndpointPlay::AAudioServiceEndpointPlay(AAudioService &audioService)
-    : AAudioServiceEndpointShared(
-        (AudioStreamInternal *)(new AudioStreamInternalPlay(audioService, true))) {
-}
+AAudioServiceEndpointPlay::AAudioServiceEndpointPlay(AAudioService& audioService)
+        : AAudioServiceEndpointShared(
+                new AudioStreamInternalPlay(audioService.asAAudioServiceInterface(), true)) {}
 
 aaudio_result_t AAudioServiceEndpointPlay::open(const aaudio::AAudioStreamRequest &request) {
     aaudio_result_t result = AAudioServiceEndpointShared::open(request);
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index ea691cf..9736091 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -26,7 +26,6 @@
 #include <media/TypeConverter.h>
 #include <mediautils/SchedulingPolicyService.h>
 
-#include "binding/IAAudioService.h"
 #include "binding/AAudioServiceMessage.h"
 #include "core/AudioGlobal.h"
 #include "utility/AudioClock.h"
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 51c26e9..f9efc2a 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -24,9 +24,10 @@
 #include <utils/RefBase.h>
 
 #include "fifo/FifoBuffer.h"
-#include "binding/IAAudioService.h"
 #include "binding/AudioEndpointParcelable.h"
 #include "binding/AAudioServiceMessage.h"
+#include "binding/AAudioStreamRequest.h"
+#include "core/AAudioStreamParameters.h"
 #include "utility/AAudioUtilities.h"
 #include "utility/AudioClock.h"
 
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 54d7d06..a4c064e 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -162,7 +162,8 @@
     return result;
 }
 
-// Get timestamp that was written by getFreeRunningPosition()
+// Get timestamp from presentation position.
+// If fails, get time stamp that was written by getFreeRunningPosition()
 aaudio_result_t AAudioServiceStreamMMAP::getHardwareTimestamp(int64_t *positionFrames,
                                                                 int64_t *timeNanos) {
 
@@ -174,8 +175,11 @@
     sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
             static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
 
-    // TODO Get presentation timestamp from the HAL
-    if (mAtomicStreamTimestamp.isValid()) {
+    uint64_t position;
+    if (serviceEndpointMMAP->getExternalPosition(&position, timeNanos) == AAUDIO_OK) {
+        *positionFrames = (int64_t) position;
+        return AAUDIO_OK;
+    } else if (mAtomicStreamTimestamp.isValid()) {
         Timestamp timestamp = mAtomicStreamTimestamp.read();
         *positionFrames = timestamp.getPosition();
         *timeNanos = timestamp.getNanoseconds() + serviceEndpointMMAP->getHardwareTimeOffsetNanos();
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index e88a81e..031468e 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -24,8 +24,6 @@
 
 #include <aaudio/AAudio.h>
 
-#include "binding/IAAudioService.h"
-
 #include "binding/AAudioServiceMessage.h"
 #include "AAudioServiceStreamBase.h"
 #include "AAudioServiceStreamShared.h"
diff --git a/services/oboeservice/Android.bp b/services/oboeservice/Android.bp
index 8b1e2c0..31e590e 100644
--- a/services/oboeservice/Android.bp
+++ b/services/oboeservice/Android.bp
@@ -55,6 +55,11 @@
         "libcutils",
         "liblog",
         "libutils",
+        "aaudio-aidl-cpp",
+    ],
+
+    export_shared_lib_headers: [
+        "libaaudio_internal",
     ],
 
     header_libs: [