Snap for 4448085 from 1648c8d1519adeaccc5ee7d31eccc9fcfb9a07be to oc-m3-release

Change-Id: Idde32d5a3e3ee7a6e69f3b14b646ddbb3d3a115c
diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
index 7e6297c..8620f36 100644
--- a/camera/ICameraClient.cpp
+++ b/camera/ICameraClient.cpp
@@ -192,12 +192,14 @@
             timestamps.reserve(n);
             handles.reserve(n);
             for (uint32_t i = 0; i < n; i++) {
-                res = data.readInt64(&timestamps[i]);
+                nsecs_t t;
+                res = data.readInt64(&t);
                 if (res != OK) {
                     ALOGE("%s: Failed to read timestamp[%d]: %s (%d)",
                             __FUNCTION__, i, strerror(-res), res);
                     return BAD_VALUE;
                 }
+                timestamps.push_back(t);
             }
             for (uint32_t i = 0; i < n; i++) {
                 native_handle_t* handle = data.readNativeHandle();
diff --git a/camera/ICameraRecordingProxyListener.cpp b/camera/ICameraRecordingProxyListener.cpp
index c954241..66faf8f 100644
--- a/camera/ICameraRecordingProxyListener.cpp
+++ b/camera/ICameraRecordingProxyListener.cpp
@@ -146,12 +146,14 @@
             timestamps.reserve(n);
             handles.reserve(n);
             for (uint32_t i = 0; i < n; i++) {
-                res = data.readInt64(&timestamps[i]);
+                nsecs_t t;
+                res = data.readInt64(&t);
                 if (res != OK) {
                     ALOGE("%s: Failed to read timestamp[%d]: %s (%d)",
                             __FUNCTION__, i, strerror(-res), res);
                     return BAD_VALUE;
                 }
+                timestamps.push_back(t);
             }
             for (uint32_t i = 0; i < n; i++) {
                 native_handle_t* handle = data.readNativeHandle();
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index 8308095..28252c0 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -42,7 +42,9 @@
      * Repeating request encountered an error and was stopped.
      *
      * @param lastFrameNumber Frame number of the last frame of the streaming request.
+     * @param repeatingRequestId the ID of the repeating request being stopped
      */
-    oneway void onRepeatingRequestError(in long lastFrameNumber);
+    oneway void onRepeatingRequestError(in long lastFrameNumber,
+                                        in int repeatingRequestId);
     oneway void onRequestQueueEmpty();
 }
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 229b159..af977b8 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -941,7 +941,6 @@
                     ACaptureRequest* request = allocateACaptureRequest(requestSp);
                     (*onFail)(context, session.get(), request, failure);
                     freeACaptureRequest(request);
-                    delete failure;
                     break;
                 }
                 case kWhatCaptureSeqEnd:
@@ -1353,7 +1352,8 @@
 }
 
 binder::Status
-CameraDevice::ServiceCallback::onRepeatingRequestError(int64_t lastFrameNumber) {
+CameraDevice::ServiceCallback::onRepeatingRequestError(
+        int64_t lastFrameNumber, int32_t stoppedSequenceId) {
     binder::Status ret = binder::Status::ok();
 
     sp<CameraDevice> dev = mDevice.promote();
@@ -1364,7 +1364,9 @@
     Mutex::Autolock _l(dev->mDeviceLock);
 
     int repeatingSequenceId = dev->mRepeatingSequenceId;
-    dev->mRepeatingSequenceId = REQUEST_ID_NONE;
+    if (stoppedSequenceId == repeatingSequenceId) {
+        dev->mRepeatingSequenceId = REQUEST_ID_NONE;
+    }
 
     dev->checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
 
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index c566cd2..855efe1 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -75,7 +75,8 @@
                               const CaptureResultExtras& resultExtras) override;
         binder::Status onPrepared(int streamId) override;
         binder::Status onRequestQueueEmpty() override;
-        binder::Status onRepeatingRequestError(int64_t lastFrameNumber) override;
+        binder::Status onRepeatingRequestError(int64_t lastFrameNumber,
+                int32_t stoppedSequenceId) override;
       private:
         const wp<CameraDevice> mDevice;
     };
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 946e3b8..51d9214 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -217,8 +217,10 @@
         return binder::Status::ok();
     }
 
-    virtual binder::Status onRepeatingRequestError(int64_t lastFrameNumber) {
+    virtual binder::Status onRepeatingRequestError(
+            int64_t lastFrameNumber, int32_t stoppedSequenceId) {
         (void) lastFrameNumber;
+        (void) stoppedSequenceId;
         Mutex::Autolock l(mLock);
         mLastStatus = REPEATING_REQUEST_ERROR;
         mStatusesHit.push_back(mLastStatus);
diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp
index 4e47112..8ff6e6a 100644
--- a/drm/libmediadrm/IDrm.cpp
+++ b/drm/libmediadrm/IDrm.cpp
@@ -561,8 +561,13 @@
 
 void BnDrm::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
     uint32_t size = data.readInt32();
-    vector.insertAt((size_t)0, size);
-    data.read(vector.editArray(), size);
+    if (vector.insertAt((size_t)0, size) < 0) {
+        vector.clear();
+    }
+    if (data.read(vector.editArray(), size) != NO_ERROR) {
+        vector.clear();
+        android_errorWriteWithInfoLog(0x534e4554, "62872384", -1, NULL, 0);
+    }
 }
 
 void BnDrm::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index a9302ea..57ff5b8 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -44,6 +44,13 @@
         analyticsItem.setInt64(kParentAttribute, *parentId);
     }
 
+    // Report the package name.
+    if (metricsGroup.has_app_package_name()) {
+      AString app_package_name(metricsGroup.app_package_name().c_str(),
+                               metricsGroup.app_package_name().size());
+      analyticsItem.setPkgName(app_package_name);
+    }
+
     for (int i = 0; i < metricsGroup.metric_size(); ++i) {
         const MetricsGroup_Metric& metric = metricsGroup.metric(i);
         if (!metric.has_name()) {
@@ -73,7 +80,12 @@
     }
 
     analyticsItem.setFinalized(true);
-    analyticsItem.selfrecord();
+    if (!analyticsItem.selfrecord()) {
+      // Note the cast to int is because we build on 32 and 64 bit.
+      // The cast prevents a peculiar printf problem where one format cannot
+      // satisfy both.
+      ALOGE("selfrecord() returned false. sessioId %d", (int) sessionId);
+    }
 
     for (int i = 0; i < metricsGroup.metric_sub_group_size(); ++i) {
         const MetricsGroup& subGroup = metricsGroup.metric_sub_group(i);
diff --git a/drm/libmediadrm/protos/plugin_metrics.proto b/drm/libmediadrm/protos/plugin_metrics.proto
index 2d26f14..7e3bcf5 100644
--- a/drm/libmediadrm/protos/plugin_metrics.proto
+++ b/drm/libmediadrm/protos/plugin_metrics.proto
@@ -44,4 +44,7 @@
 
   // Allow multiple sub groups of metrics.
   repeated MetricsGroup metric_sub_group = 2;
+
+  // Name of the application package associated with the metrics.
+  optional string app_package_name = 3;
 }
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
index 5fdac5c..ec07d87 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
@@ -25,10 +25,28 @@
 
 #include "Session.h"
 
+namespace {
+const android::String8 kStreaming("Streaming");
+const android::String8 kOffline("Offline");
+const android::String8 kTrue("True");
+
+const android::String8 kQueryKeyLicenseType("LicenseType");
+    // Value: "Streaming" or "Offline"
+const android::String8 kQueryKeyPlayAllowed("PlayAllowed");
+    // Value: "True" or "False"
+const android::String8 kQueryKeyRenewAllowed("RenewAllowed");
+    // Value: "True" or "False"
+};
+
 namespace clearkeydrm {
 
 using android::sp;
 
+DrmPlugin::DrmPlugin(SessionLibrary* sessionLibrary)
+        : mSessionLibrary(sessionLibrary) {
+    mPlayPolicy.clear();
+}
+
 status_t DrmPlugin::openSession(Vector<uint8_t>& sessionId) {
     sp<Session> session = mSessionLibrary->createSession();
     sessionId = session->sessionId();
@@ -60,18 +78,28 @@
     if (scope.size() == 0) {
         return android::BAD_VALUE;
     }
+
     if (keyType != kKeyType_Streaming) {
         return android::ERROR_DRM_CANNOT_HANDLE;
     }
+
     *keyRequestType = DrmPlugin::kKeyRequestType_Initial;
     defaultUrl.clear();
     sp<Session> session = mSessionLibrary->findSession(scope);
     if (!session.get()) {
         return android::ERROR_DRM_SESSION_NOT_OPENED;
     }
+
     return session->getKeyRequest(initData, mimeType, &request);
 }
 
+void DrmPlugin::setPlayPolicy() {
+    mPlayPolicy.clear();
+    mPlayPolicy.add(kQueryKeyLicenseType, kStreaming);
+    mPlayPolicy.add(kQueryKeyPlayAllowed, kTrue);
+    mPlayPolicy.add(kQueryKeyRenewAllowed, kTrue);
+}
+
 status_t DrmPlugin::provideKeyResponse(
         const Vector<uint8_t>& scope,
         const Vector<uint8_t>& response,
@@ -83,6 +111,8 @@
     if (!session.get()) {
         return android::ERROR_DRM_SESSION_NOT_OPENED;
     }
+
+    setPlayPolicy();
     status_t res = session->provideKeyResponse(response);
     if (res == android::OK) {
         // This is for testing AMediaDrm_setOnEventListener only.
@@ -111,4 +141,18 @@
     return android::OK;
 }
 
+status_t DrmPlugin::queryKeyStatus(
+        const Vector<uint8_t>& sessionId,
+        KeyedVector<String8, String8>& infoMap) const {
+
+    if (sessionId.size() == 0) {
+        return android::BAD_VALUE;
+    }
+
+    infoMap.clear();
+    for (size_t i = 0; i < mPlayPolicy.size(); ++i) {
+        infoMap.add(mPlayPolicy.keyAt(i), mPlayPolicy.valueAt(i));
+    }
+    return android::OK;
+}
 }  // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
index 58421b9..f37a706 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -39,8 +39,8 @@
 
 class DrmPlugin : public android::DrmPlugin {
 public:
-    explicit DrmPlugin(SessionLibrary* sessionLibrary)
-            : mSessionLibrary(sessionLibrary) {}
+    explicit DrmPlugin(SessionLibrary* sessionLibrary);
+
     virtual ~DrmPlugin() {}
 
     virtual status_t openSession(Vector<uint8_t>& sessionId);
@@ -81,13 +81,7 @@
 
     virtual status_t queryKeyStatus(
             const Vector<uint8_t>& sessionId,
-            KeyedVector<String8, String8>& infoMap) const {
-        if (sessionId.size() == 0) {
-            return android::BAD_VALUE;
-        }
-        UNUSED(infoMap);
-        return android::ERROR_DRM_CANNOT_HANDLE;
-    }
+            KeyedVector<String8, String8>& infoMap) const;
 
     virtual status_t getProvisionRequest(
             const String8& cert_type,
@@ -248,9 +242,12 @@
     }
 
 private:
-    DISALLOW_EVIL_CONSTRUCTORS(DrmPlugin);
+    void setPlayPolicy();
 
+    android::KeyedVector<android::String8, android::String8> mPlayPolicy;
     SessionLibrary* mSessionLibrary;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DrmPlugin);
 };
 
 } // namespace clearkeydrm
diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp
index 34c629b..474ef97 100644
--- a/media/audioserver/main_audioserver.cpp
+++ b/media/audioserver/main_audioserver.cpp
@@ -32,9 +32,11 @@
 #include <hwbinder/ProcessState.h>
 
 // from LOCAL_C_INCLUDES
+#include "aaudio/AAudioTesting.h"
 #include "AudioFlinger.h"
 #include "AudioPolicyService.h"
 #include "AAudioService.h"
+#include "utility/AAudioUtilities.h"
 #include "MediaLogService.h"
 #include "SoundTriggerHwService.h"
 
@@ -131,7 +133,16 @@
         ALOGI("ServiceManager: %p", sm.get());
         AudioFlinger::instantiate();
         AudioPolicyService::instantiate();
-        AAudioService::instantiate();
+
+        // AAudioService should only be used in OC-MR1 and later.
+        // And only enable the AAudioService if the system MMAP policy explicitly allows it.
+        // This prevents a client from misusing AAudioService when it is not supported.
+        aaudio_policy_t mmapPolicy = property_get_int32(AAUDIO_PROP_MMAP_POLICY,
+                                                        AAUDIO_POLICY_NEVER);
+        if (mmapPolicy == AAUDIO_POLICY_AUTO || mmapPolicy == AAUDIO_POLICY_ALWAYS) {
+            AAudioService::instantiate();
+        }
+
         SoundTriggerHwService::instantiate();
         ProcessState::self()->startThreadPool();
 
diff --git a/media/libaaudio/Doxyfile b/media/libaaudio/Doxyfile
index e2c4960..7298d11 100644
--- a/media/libaaudio/Doxyfile
+++ b/media/libaaudio/Doxyfile
@@ -744,12 +744,12 @@
 # Note: If this tag is empty the current directory is searched.
 
 INPUT                  = include/aaudio/AAudio.h \
+                         src/binding/AAudioCommon.h \
                          src/legacy/AudioStreamTrack.h \
                          src/legacy/AudioStreamRecord.h \
                          src/legacy/AAudioLegacy.h \
                          src/core/AudioStreamBuilder.h \
                          src/core/AudioStream.h \
-                         src/utility/HandleTracker.h \
                          src/utility/MonotonicCounter.h \
                          src/utility/AudioClock.h \
                          src/utility/AAudioUtilities.h
diff --git a/media/libaaudio/examples/utils/AAudioExampleUtils.h b/media/libaaudio/examples/utils/AAudioExampleUtils.h
index 9ef62c9..c179ce6 100644
--- a/media/libaaudio/examples/utils/AAudioExampleUtils.h
+++ b/media/libaaudio/examples/utils/AAudioExampleUtils.h
@@ -31,18 +31,51 @@
 #define NANOS_PER_SECOND      (NANOS_PER_MILLISECOND * 1000)
 
 const char *getSharingModeText(aaudio_sharing_mode_t mode) {
-    const char *modeText = "unknown";
+    const char *text = "unknown";
     switch (mode) {
-    case AAUDIO_SHARING_MODE_EXCLUSIVE:
-        modeText = "EXCLUSIVE";
-        break;
-    case AAUDIO_SHARING_MODE_SHARED:
-        modeText = "SHARED";
-        break;
-    default:
-        break;
+        case AAUDIO_SHARING_MODE_EXCLUSIVE:
+            text = "EXCLUSIVE";
+            break;
+        case AAUDIO_SHARING_MODE_SHARED:
+            text = "SHARED";
+            break;
+        default:
+            break;
     }
-    return modeText;
+    return text;
+}
+
+const char *getPerformanceModeText(aaudio_performance_mode_t mode) {
+    const char *text = "unknown";
+    switch (mode) {
+        case AAUDIO_PERFORMANCE_MODE_NONE:
+            text = "NONE";
+            break;
+        case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
+            text = "LOW_LATENCY";
+            break;
+        case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
+            text = "POWER_SAVING";
+            break;
+        default:
+            break;
+    }
+    return text;
+}
+
+const char *getDirectionText(aaudio_direction_t direction) {
+    const char *text = "unknown";
+    switch (direction) {
+        case AAUDIO_DIRECTION_INPUT:
+            text = "INPUT";
+            break;
+        case AAUDIO_DIRECTION_OUTPUT:
+            text = "OUTPUT";
+            break;
+        default:
+            break;
+    }
+    return text;
 }
 
 static void convertNanosecondsToTimespec(int64_t nanoseconds, struct timespec *time) {
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index d2e7f23..606c4ba 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -36,6 +36,13 @@
 // How long to sleep in a callback to cause an intentional glitch. For testing.
 #define FORCED_UNDERRUN_SLEEP_MICROS     (10 * 1000)
 
+#define MAX_TIMESTAMPS   16
+
+typedef struct Timestamp {
+    int64_t position;
+    int64_t nanoseconds;
+} Timestamp;
+
 /**
  * Simple wrapper for AAudio that opens an output stream either in callback or blocking write mode.
  */
@@ -227,10 +234,12 @@
 
     SineGenerator  sineOsc1;
     SineGenerator  sineOsc2;
+    Timestamp      timestamps[MAX_TIMESTAMPS];
     int64_t        framesTotal = 0;
     int64_t        nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
     int32_t        minNumFrames = INT32_MAX;
     int32_t        maxNumFrames = 0;
+    int32_t        timestampCount = 0; // in timestamps
 
     int            scheduler = 0;
     bool           schedulerChecked = false;
@@ -273,6 +282,17 @@
         sineData->schedulerChecked = true;
     }
 
+    if (sineData->timestampCount < MAX_TIMESTAMPS) {
+        Timestamp *timestamp = &sineData->timestamps[sineData->timestampCount];
+        aaudio_result_t result = AAudioStream_getTimestamp(stream,
+            CLOCK_MONOTONIC, &timestamp->position, &timestamp->nanoseconds);
+        if (result == AAUDIO_OK && // valid?
+                (sineData->timestampCount == 0 || // first one?
+                (timestamp->position != (timestamp - 1)->position))) { // advanced position?
+            sineData->timestampCount++; // keep this one
+        }
+    }
+
     if (numFrames > sineData->maxNumFrames) {
         sineData->maxNumFrames = numFrames;
     }
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index 2280b72..4f9cde6 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -120,6 +120,18 @@
         goto error;
     }
 
+    for (int i = 0; i < myData.timestampCount; i++) {
+        Timestamp *timestamp = &myData.timestamps[i];
+        bool retro = (i > 0 &&
+                      ((timestamp->position < (timestamp - 1)->position)
+                       || ((timestamp->nanoseconds < (timestamp - 1)->nanoseconds))));
+        const char *message = retro ? "  <= RETROGRADE!" : "";
+        printf("Timestamp %3d : %8lld, %8lld %s\n", i,
+               (long long) timestamp->position,
+               (long long) timestamp->nanoseconds,
+               message);
+    }
+
     if (myData.schedulerChecked) {
         printf("scheduler = 0x%08x, SCHED_FIFO = 0x%08X\n",
                myData.scheduler,
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
index cfcf27a..6861248 100644
--- a/media/libaaudio/src/Android.mk
+++ b/media/libaaudio/src/Android.mk
@@ -36,7 +36,6 @@
     legacy/AudioStreamLegacy.cpp \
     legacy/AudioStreamRecord.cpp \
     legacy/AudioStreamTrack.cpp \
-    utility/HandleTracker.cpp \
     utility/AAudioUtilities.cpp \
     utility/FixedBlockAdapter.cpp \
     utility/FixedBlockReader.cpp \
@@ -95,7 +94,6 @@
     legacy/AudioStreamLegacy.cpp \
     legacy/AudioStreamRecord.cpp \
     legacy/AudioStreamTrack.cpp \
-    utility/HandleTracker.cpp \
     utility/AAudioUtilities.cpp \
     utility/FixedBlockAdapter.cpp \
     utility/FixedBlockReader.cpp \
diff --git a/media/libaaudio/src/binding/AAudioCommon.h b/media/libaaudio/src/binding/AAudioCommon.h
new file mode 100644
index 0000000..e3e9e82
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioCommon.h
@@ -0,0 +1,32 @@
+/*
+ * 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_COMMON_H
+#define ANDROID_AAUDIO_COMMON_H
+
+#include <stdint.h>
+
+/*
+ * Internal header that is common to both client and server.
+ *
+ */
+namespace aaudio {
+
+typedef int32_t aaudio_handle_t;
+
+} /* namespace aaudio */
+
+#endif // ANDROID_AAUDIO_COMMON_H
diff --git a/media/libaaudio/src/binding/IAAudioClient.h b/media/libaaudio/src/binding/IAAudioClient.h
index 21cc33b..f21fd93 100644
--- a/media/libaaudio/src/binding/IAAudioClient.h
+++ b/media/libaaudio/src/binding/IAAudioClient.h
@@ -22,7 +22,7 @@
 
 #include <aaudio/AAudio.h>
 
-#include "utility/HandleTracker.h"
+#include "binding/AAudioCommon.h"
 
 namespace android {
 
@@ -33,7 +33,7 @@
 
     DECLARE_META_INTERFACE(AAudioClient);
 
-    virtual void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) = 0;
+    virtual void onStreamChange(aaudio::aaudio_handle_t handle, int32_t opcode, int32_t value) = 0;
 
 };
 
diff --git a/media/libaaudio/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h
index 30b3ead..6bdb826 100644
--- a/media/libaaudio/src/binding/IAAudioService.h
+++ b/media/libaaudio/src/binding/IAAudioService.h
@@ -24,12 +24,12 @@
 
 #include <aaudio/AAudio.h>
 
+#include "binding/AAudioCommon.h"
 #include "binding/AAudioServiceDefinitions.h"
-#include "binding/AudioEndpointParcelable.h"
-#include "binding/AAudioStreamRequest.h"
 #include "binding/AAudioStreamConfiguration.h"
+#include "binding/AAudioStreamRequest.h"
+#include "binding/AudioEndpointParcelable.h"
 #include "binding/IAAudioClient.h"
-#include "utility/HandleTracker.h"
 
 namespace android {
 
@@ -51,7 +51,7 @@
      * @param configuration contains information about the created stream
      * @return handle to the stream or a negative error
      */
-    virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+    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;
@@ -89,11 +89,11 @@
     /**
      * Manage the specified thread as a low latency audio thread.
      */
-    virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+    virtual aaudio_result_t registerAudioThread(aaudio::aaudio_handle_t streamHandle,
                                               pid_t clientThreadId,
                                               int64_t periodNanoseconds) = 0;
 
-    virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+    virtual aaudio_result_t unregisterAudioThread(aaudio::aaudio_handle_t streamHandle,
                                                 pid_t clientThreadId) = 0;
 };
 
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 7f2e495..2fdbfaf 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -23,7 +23,6 @@
 #define ATRACE_TAG ATRACE_TAG_AUDIO
 
 #include <stdint.h>
-#include <assert.h>
 
 #include <binder/IServiceManager.h>
 
@@ -55,7 +54,7 @@
 // Wait at least this many times longer than the operation should take.
 #define MIN_TIMEOUT_OPERATIONS    4
 
-#define LOG_TIMESTAMPS   0
+#define LOG_TIMESTAMPS            0
 
 AudioStreamInternal::AudioStreamInternal(AAudioServiceInterface  &serviceInterface, bool inService)
         : AudioStream()
@@ -63,12 +62,11 @@
         , mAudioEndpoint()
         , mServiceStreamHandle(AAUDIO_HANDLE_INVALID)
         , mFramesPerBurst(16)
-        , mStreamVolume(1.0f)
         , mInService(inService)
         , mServiceInterface(serviceInterface)
+        , mAtomicTimestamp()
         , mWakeupDelayNanos(AAudioProperty_getWakeupDelayMicros() * AAUDIO_NANOS_PER_MICROSECOND)
         , mMinimumSleepNanos(AAudioProperty_getMinimumSleepMicros() * AAUDIO_NANOS_PER_MICROSECOND)
-        , mAtomicTimestamp()
         {
     ALOGD("AudioStreamInternal(): mWakeupDelayNanos = %d, mMinimumSleepNanos = %d",
           mWakeupDelayNanos, mMinimumSleepNanos);
@@ -196,10 +194,6 @@
     }
 
     setState(AAUDIO_STREAM_STATE_OPEN);
-    // Only connect to AudioManager if this is a playback stream running in client process.
-    if (!mInService && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
-        init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
-    }
 
     return result;
 
@@ -209,7 +203,8 @@
 }
 
 aaudio_result_t AudioStreamInternal::close() {
-    ALOGD("AudioStreamInternal::close(): mServiceStreamHandle = 0x%08X",
+    aaudio_result_t result = AAUDIO_OK;
+    ALOGD("close(): mServiceStreamHandle = 0x%08X",
              mServiceStreamHandle);
     if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
         // Don't close a stream while it is running.
@@ -218,10 +213,10 @@
             requestStop();
             aaudio_stream_state_t nextState;
             int64_t timeoutNanoseconds = MIN_TIMEOUT_NANOS;
-            aaudio_result_t result = waitForStateChange(currentState, &nextState,
+            result = waitForStateChange(currentState, &nextState,
                                                        timeoutNanoseconds);
             if (result != AAUDIO_OK) {
-                ALOGE("AudioStreamInternal::close() waitForStateChange() returned %d %s",
+                ALOGE("close() waitForStateChange() returned %d %s",
                 result, AAudio_convertResultToText(result));
             }
         }
@@ -232,8 +227,11 @@
         mServiceInterface.closeStream(serviceStreamHandle);
         delete[] mCallbackBuffer;
         mCallbackBuffer = nullptr;
+
         setState(AAUDIO_STREAM_STATE_CLOSED);
-        return mEndPointParcelable.close();
+        result = mEndPointParcelable.close();
+        aaudio_result_t result2 = AudioStream::close();
+        return (result != AAUDIO_OK) ? result : result2;
     } else {
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
@@ -250,26 +248,46 @@
     }
 }
 
+/*
+ * It normally takes about 20-30 msec to start a stream on the server.
+ * But the first time can take as much as 200-300 msec. The HW
+ * starts right away so by the time the client gets a chance to write into
+ * the buffer, it is already in a deep underflow state. That can cause the
+ * XRunCount to be non-zero, which could lead an app to tune its latency higher.
+ * To avoid this problem, we set a request for the processing code to start the
+ * client stream at the same position as the server stream.
+ * The processing code will then save the current offset
+ * between client and server and apply that to any position given to the app.
+ */
 aaudio_result_t AudioStreamInternal::requestStart()
 {
     int64_t startTime;
-    ALOGD("AudioStreamInternal()::requestStart()");
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("AudioStreamInternal::requestStart() mServiceStreamHandle invalid");
+        ALOGE("requestStart() mServiceStreamHandle invalid");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     if (isActive()) {
-        ALOGE("AudioStreamInternal::requestStart() already active");
+        ALOGE("requestStart() already active");
         return AAUDIO_ERROR_INVALID_STATE;
     }
-    aaudio_stream_state_t originalState = getState();
 
+    aaudio_stream_state_t originalState = getState();
+    if (originalState == AAUDIO_STREAM_STATE_DISCONNECTED) {
+        ALOGE("requestStart() but DISCONNECTED");
+        return AAUDIO_ERROR_DISCONNECTED;
+    }
     setState(AAUDIO_STREAM_STATE_STARTING);
-    aaudio_result_t result = AAudioConvert_androidToAAudioResult(startWithStatus());
+
+    // Clear any stale timestamps from the previous run.
+    drainTimestampsFromService();
+
+    aaudio_result_t result = mServiceInterface.startStream(mServiceStreamHandle);
 
     startTime = AudioClock::getNanoseconds();
     mClockModel.start(startTime);
+    mNeedCatchUp.request();  // Ask data processing code to catch up when first timestamp received.
 
+    // Start data callback thread.
     if (result == AAUDIO_OK && getDataCallbackProc() != nullptr) {
         // Launch the callback loop thread.
         int64_t periodNanos = mCallbackFrames
@@ -314,14 +332,16 @@
 aaudio_result_t AudioStreamInternal::requestStopInternal()
 {
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("AudioStreamInternal::requestStopInternal() mServiceStreamHandle invalid = 0x%08X",
+        ALOGE("requestStopInternal() mServiceStreamHandle invalid = 0x%08X",
               mServiceStreamHandle);
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
     mClockModel.stop(AudioClock::getNanoseconds());
     setState(AAUDIO_STREAM_STATE_STOPPING);
-    return AAudioConvert_androidToAAudioResult(stopWithStatus());
+    mAtomicTimestamp.clear();
+
+    return mServiceInterface.stopStream(mServiceStreamHandle);
 }
 
 aaudio_result_t AudioStreamInternal::requestStop()
@@ -336,7 +356,7 @@
 
 aaudio_result_t AudioStreamInternal::registerThread() {
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("AudioStreamInternal::registerThread() mServiceStreamHandle invalid");
+        ALOGE("registerThread() mServiceStreamHandle invalid");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     return mServiceInterface.registerAudioThread(mServiceStreamHandle,
@@ -346,7 +366,7 @@
 
 aaudio_result_t AudioStreamInternal::unregisterThread() {
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("AudioStreamInternal::unregisterThread() mServiceStreamHandle invalid");
+        ALOGE("unregisterThread() mServiceStreamHandle invalid");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, gettid());
@@ -374,12 +394,14 @@
     // Generated in server and passed to client. Return latest.
     if (mAtomicTimestamp.isValid()) {
         Timestamp timestamp = mAtomicTimestamp.read();
-        *framePosition = timestamp.getPosition();
-        *timeNanoseconds = timestamp.getNanoseconds();
-        return AAUDIO_OK;
-    } else {
-        return AAUDIO_ERROR_UNAVAILABLE;
+        int64_t position = timestamp.getPosition() + mFramesOffsetFromService;
+        if (position >= 0) {
+            *framePosition = position;
+            *timeNanoseconds = timestamp.getNanoseconds();
+            return AAUDIO_OK;
+        }
     }
+    return AAUDIO_ERROR_INVALID_STATE;
 }
 
 aaudio_result_t AudioStreamInternal::updateStateMachine() {
@@ -394,14 +416,14 @@
     static int64_t oldTime = 0;
     int64_t framePosition = command.timestamp.position;
     int64_t nanoTime = command.timestamp.timestamp;
-    ALOGD("AudioStreamInternal: timestamp says framePosition = %08lld at nanoTime %lld",
+    ALOGD("logTimestamp: timestamp says framePosition = %8lld at nanoTime %lld",
          (long long) framePosition,
          (long long) nanoTime);
     int64_t nanosDelta = nanoTime - oldTime;
     if (nanosDelta > 0 && oldTime > 0) {
         int64_t framesDelta = framePosition - oldPosition;
         int64_t rate = (framesDelta * AAUDIO_NANOS_PER_SECOND) / nanosDelta;
-        ALOGD("AudioStreamInternal: framesDelta = %08lld, nanosDelta = %08lld, rate = %lld",
+        ALOGD("logTimestamp:     framesDelta = %8lld, nanosDelta = %8lld, rate = %lld",
               (long long) framesDelta, (long long) nanosDelta, (long long) rate);
     }
     oldPosition = framePosition;
@@ -478,6 +500,34 @@
     return result;
 }
 
+aaudio_result_t AudioStreamInternal::drainTimestampsFromService() {
+    aaudio_result_t result = AAUDIO_OK;
+
+    while (result == AAUDIO_OK) {
+        AAudioServiceMessage message;
+        if (mAudioEndpoint.readUpCommand(&message) != 1) {
+            break; // no command this time, no problem
+        }
+        switch (message.what) {
+            // ignore most messages
+            case AAudioServiceMessage::code::TIMESTAMP_SERVICE:
+            case AAudioServiceMessage::code::TIMESTAMP_HARDWARE:
+                break;
+
+            case AAudioServiceMessage::code::EVENT:
+                result = onEventFromServer(&message);
+                break;
+
+            default:
+                ALOGE("WARNING - drainTimestampsFromService() Unrecognized what = %d",
+                      (int) message.what);
+                result = AAUDIO_ERROR_INTERNAL;
+                break;
+        }
+    }
+    return result;
+}
+
 // Process all the commands coming from the server.
 aaudio_result_t AudioStreamInternal::processCommands() {
     aaudio_result_t result = AAUDIO_OK;
@@ -502,7 +552,7 @@
             break;
 
         default:
-            ALOGE("WARNING - AudioStreamInternal::processCommands() Unrecognized what = %d",
+            ALOGE("WARNING - processCommands() Unrecognized what = %d",
                  (int) message.what);
             result = AAUDIO_ERROR_INTERNAL;
             break;
@@ -613,7 +663,7 @@
     }
 
     aaudio_result_t result = mAudioEndpoint.setBufferSizeInFrames(requestedFrames, &actualFrames);
-    ALOGD("AudioStreamInternal::setBufferSize() req = %d => %d", requestedFrames, actualFrames);
+    ALOGD("setBufferSize() req = %d => %d", requestedFrames, actualFrames);
     if (result < 0) {
         return result;
     } else {
@@ -636,32 +686,3 @@
 aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) {
     return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst()));
 }
-
-void AudioStreamInternal::doSetVolume() {
-    // No pan and only left volume is taken into account from IPLayer interface
-    mVolumeRamp.setTarget(mStreamVolume * mVolumeMultiplierL /* * mPanMultiplierL */);
-}
-
-
-//------------------------------------------------------------------------------
-// Implementation of PlayerBase
-status_t AudioStreamInternal::playerStart() {
-    return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.startStream(mServiceStreamHandle));
-}
-
-status_t AudioStreamInternal::playerPause() {
-    return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.pauseStream(mServiceStreamHandle));
-}
-
-status_t AudioStreamInternal::playerStop() {
-    return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.stopStream(mServiceStreamHandle));
-}
-
-status_t AudioStreamInternal::playerSetVolume() {
-    doSetVolume();
-    return NO_ERROR;
-}
-
-void AudioStreamInternal::destroy() {
-    baseDestroy();
-}
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 3523294..47024c0 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -18,7 +18,6 @@
 #define ANDROID_AAUDIO_AUDIO_STREAM_INTERNAL_H
 
 #include <stdint.h>
-#include <media/PlayerBase.h>
 #include <aaudio/AAudio.h>
 
 #include "binding/IAAudioService.h"
@@ -36,7 +35,7 @@
 namespace aaudio {
 
 // A stream that talks to the AAudioService or directly to a HAL.
-class AudioStreamInternal : public AudioStream, public android::PlayerBase  {
+class AudioStreamInternal : public AudioStream {
 
 public:
     AudioStreamInternal(AAudioServiceInterface  &serviceInterface, bool inService);
@@ -85,9 +84,6 @@
     // Calculate timeout based on framesPerBurst
     int64_t calculateReasonableTimeout();
 
-    //PlayerBase virtuals
-    virtual void destroy();
-
     aaudio_result_t startClient(const android::AudioClient& client,
                                 audio_port_handle_t *clientHandle);
 
@@ -115,12 +111,15 @@
                             int64_t currentTimeNanos,
                             int64_t *wakeTimePtr) = 0;
 
+    aaudio_result_t drainTimestampsFromService();
+
     aaudio_result_t processCommands();
 
     aaudio_result_t requestStopInternal();
 
     aaudio_result_t stopCallback();
 
+    virtual void advanceClientToMatchServerPosition() = 0;
 
     virtual void onFlushFromServer() {}
 
@@ -135,14 +134,6 @@
     // Calculate timeout for an operation involving framesPerOperation.
     int64_t calculateReasonableTimeout(int32_t framesPerOperation);
 
-    void doSetVolume();
-
-    //PlayerBase virtuals
-    virtual status_t playerStart();
-    virtual status_t playerPause();
-    virtual status_t playerStop();
-    virtual status_t playerSetVolume();
-
     aaudio_format_t          mDeviceFormat = AAUDIO_FORMAT_UNSPECIFIED;
 
     IsochronousClockModel    mClockModel;      // timing model for chasing the HAL
@@ -153,9 +144,6 @@
     int32_t                  mFramesPerBurst;     // frames per HAL transfer
     int32_t                  mXRunCount = 0;      // how many underrun events?
 
-    LinearRamp               mVolumeRamp;
-    float                    mStreamVolume;
-
     // Offset from underlying frame position.
     int64_t                  mFramesOffsetFromService = 0; // offset for timestamps
 
@@ -167,6 +155,12 @@
 
     AAudioServiceInterface  &mServiceInterface;   // abstract interface to the service
 
+    SimpleDoubleBuffer<Timestamp>  mAtomicTimestamp;
+
+    AtomicRequestor          mNeedCatchUp;   // Ask read() or write() to sync on first timestamp.
+
+    float                    mStreamVolume = 1.0f;
+
 private:
     /*
      * Asynchronous write with data conversion.
@@ -188,10 +182,7 @@
     AudioEndpointParcelable  mEndPointParcelable; // description of the buffers filled by service
     EndpointDescriptor       mEndpointDescriptor; // buffer description with resolved addresses
 
-    SimpleDoubleBuffer<Timestamp>  mAtomicTimestamp;
-
     int64_t                  mServiceLatencyNanos = 0;
-
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 7b1e53e..b792ecd 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -39,6 +39,21 @@
 
 AudioStreamInternalCapture::~AudioStreamInternalCapture() {}
 
+void AudioStreamInternalCapture::advanceClientToMatchServerPosition() {
+    int64_t readCounter = mAudioEndpoint.getDataReadCounter();
+    int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
+
+    // Bump offset so caller does not see the retrograde motion in getFramesRead().
+    int64_t offset = readCounter - writeCounter;
+    mFramesOffsetFromService += offset;
+    ALOGD("advanceClientToMatchServerPosition() readN = %lld, writeN = %lld, offset = %lld",
+          (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
+
+    // Force readCounter to match writeCounter.
+    // This is because we cannot change the write counter in the hardware.
+    mAudioEndpoint.setDataReadCounter(writeCounter);
+}
+
 // Write the data, block if needed and timeoutMillis > 0
 aaudio_result_t AudioStreamInternalCapture::read(void *buffer, int32_t numFrames,
                                                int64_t timeoutNanoseconds)
@@ -57,6 +72,18 @@
     const char *traceName = "aaRdNow";
     ATRACE_BEGIN(traceName);
 
+    if (mClockModel.isStarting()) {
+        // Still haven't got any timestamps from server.
+        // Keep waiting until we get some valid timestamps then start writing to the
+        // current buffer position.
+        ALOGD("processDataNow() wait for valid timestamps");
+        // Sleep very briefly and hope we get a timestamp soon.
+        *wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND);
+        ATRACE_END();
+        return 0;
+    }
+    // If we have gotten this far then we have at least one timestamp from server.
+
     if (mAudioEndpoint.isFreeRunning()) {
         //ALOGD("AudioStreamInternalCapture::processDataNow() - update remote counter");
         // Update data queue based on the timing model.
@@ -65,6 +92,14 @@
         mAudioEndpoint.setDataWriteCounter(estimatedRemoteCounter);
     }
 
+    // This code assumes that we have already received valid timestamps.
+    if (mNeedCatchUp.isRequested()) {
+        // Catch an MMAP pointer that is already advancing.
+        // This will avoid initial underruns caused by a slow cold start.
+        advanceClientToMatchServerPosition();
+        mNeedCatchUp.acknowledge();
+    }
+
     // If the write index passed the read index then consider it an overrun.
     if (mAudioEndpoint.getEmptyFramesAvailable() < 0) {
         mXRunCount++;
@@ -100,8 +135,8 @@
                 // Calculate frame position based off of the readCounter because
                 // the writeCounter might have just advanced in the background,
                 // causing us to sleep until a later burst.
-                int64_t nextReadPosition = mAudioEndpoint.getDataReadCounter() + mFramesPerBurst;
-                wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
+                int64_t nextPosition = mAudioEndpoint.getDataReadCounter() + mFramesPerBurst;
+                wakeTime = mClockModel.convertPositionToTime(nextPosition);
             }
                 break;
             default:
@@ -186,8 +221,7 @@
 }
 
 int64_t AudioStreamInternalCapture::getFramesRead() {
-    int64_t frames = mAudioEndpoint.getDataWriteCounter()
-                               + mFramesOffsetFromService;
+    int64_t frames = mAudioEndpoint.getDataReadCounter() + mFramesOffsetFromService;
     //ALOGD("AudioStreamInternalCapture::getFramesRead() returns %lld", (long long)frames);
     return frames;
 }
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.h b/media/libaaudio/src/client/AudioStreamInternalCapture.h
index 17f37e8..294dbaf 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.h
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.h
@@ -46,6 +46,8 @@
     }
 protected:
 
+    void advanceClientToMatchServerPosition() override;
+
 /**
  * Low level data processing that will not block. It will just read or write as much as it can.
  *
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 31e0a40..1e02eee 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -48,7 +48,8 @@
 
     mClockModel.stop(AudioClock::getNanoseconds());
     setState(AAUDIO_STREAM_STATE_PAUSING);
-    return AAudioConvert_androidToAAudioResult(pauseWithStatus());
+    mAtomicTimestamp.clear();
+    return mServiceInterface.pauseStream(mServiceStreamHandle);
 }
 
 aaudio_result_t AudioStreamInternalPlay::requestPause()
@@ -72,21 +73,25 @@
     return mServiceInterface.flushStream(mServiceStreamHandle);
 }
 
-void AudioStreamInternalPlay::onFlushFromServer() {
+void AudioStreamInternalPlay::advanceClientToMatchServerPosition() {
     int64_t readCounter = mAudioEndpoint.getDataReadCounter();
     int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
 
     // Bump offset so caller does not see the retrograde motion in getFramesRead().
-    int64_t framesFlushed = writeCounter - readCounter;
-    mFramesOffsetFromService += framesFlushed;
-    ALOGD("AudioStreamInternal::onFlushFromServer() readN = %lld, writeN = %lld, offset = %lld",
+    int64_t offset = writeCounter - readCounter;
+    mFramesOffsetFromService += offset;
+    ALOGD("advanceClientToMatchServerPosition() readN = %lld, writeN = %lld, offset = %lld",
           (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
 
-    // Flush written frames by forcing writeCounter to readCounter.
-    // This is because we cannot move the read counter in the hardware.
+    // Force writeCounter to match readCounter.
+    // This is because we cannot change the read counter in the hardware.
     mAudioEndpoint.setDataWriteCounter(readCounter);
 }
 
+void AudioStreamInternalPlay::onFlushFromServer() {
+    advanceClientToMatchServerPosition();
+}
+
 // Write the data, block if needed and timeoutMillis > 0
 aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames,
                                            int64_t timeoutNanoseconds)
@@ -106,6 +111,18 @@
     const char *traceName = "aaWrNow";
     ATRACE_BEGIN(traceName);
 
+    if (mClockModel.isStarting()) {
+        // Still haven't got any timestamps from server.
+        // Keep waiting until we get some valid timestamps then start writing to the
+        // current buffer position.
+        ALOGD("processDataNow() wait for valid timestamps");
+        // Sleep very briefly and hope we get a timestamp soon.
+        *wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND);
+        ATRACE_END();
+        return 0;
+    }
+    // If we have gotten this far then we have at least one timestamp from server.
+
     // If a DMA channel or DSP is reading the other end then we have to update the readCounter.
     if (mAudioEndpoint.isFreeRunning()) {
         // Update data queue based on the timing model.
@@ -114,6 +131,13 @@
         mAudioEndpoint.setDataReadCounter(estimatedReadCounter);
     }
 
+    if (mNeedCatchUp.isRequested()) {
+        // Catch an MMAP pointer that is already advancing.
+        // This will avoid initial underruns caused by a slow cold start.
+        advanceClientToMatchServerPosition();
+        mNeedCatchUp.acknowledge();
+    }
+
     // If the read index passed the write index then consider it an underrun.
     if (mAudioEndpoint.getFullFramesAvailable() < 0) {
         mXRunCount++;
@@ -153,9 +177,9 @@
                 // Calculate frame position based off of the writeCounter because
                 // the readCounter might have just advanced in the background,
                 // causing us to sleep until a later burst.
-                int64_t nextReadPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
+                int64_t nextPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
                         - mAudioEndpoint.getBufferSizeInFrames();
-                wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
+                wakeTime = mClockModel.convertPositionToTime(nextPosition);
             }
                 break;
             default:
@@ -266,7 +290,6 @@
     return framesWritten;
 }
 
-
 int64_t AudioStreamInternalPlay::getFramesRead()
 {
     int64_t framesReadHardware;
@@ -340,3 +363,10 @@
           result, (int) isActive());
     return NULL;
 }
+
+//------------------------------------------------------------------------------
+// Implementation of PlayerBase
+status_t AudioStreamInternalPlay::doSetVolume() {
+    mVolumeRamp.setTarget(mStreamVolume * getDuckAndMuteVolume());
+    return android::NO_ERROR;
+}
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.h b/media/libaaudio/src/client/AudioStreamInternalPlay.h
index e59d02c..d5c1b1e 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.h
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.h
@@ -54,8 +54,12 @@
 
     aaudio_result_t requestPauseInternal();
 
+    void advanceClientToMatchServerPosition() override;
+
     void onFlushFromServer() override;
 
+    android::status_t doSetVolume() override;
+
 /**
  * Low level write that will not block. It will just write as much as it can.
  *
@@ -78,6 +82,9 @@
                                            int32_t numFrames);
 
     int64_t                  mLastFramesRead = 0; // used to prevent retrograde motion
+
+    LinearRamp               mVolumeRamp;
+
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index c06c8a9..bac69f1 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -48,19 +48,26 @@
 }
 
 void IsochronousClockModel::start(int64_t nanoTime) {
-    ALOGD("IsochronousClockModel::start(nanos = %lld)\n", (long long) nanoTime);
+    ALOGV("IsochronousClockModel::start(nanos = %lld)\n", (long long) nanoTime);
     mMarkerNanoTime = nanoTime;
     mState = STATE_STARTING;
 }
 
 void IsochronousClockModel::stop(int64_t nanoTime) {
-    ALOGD("IsochronousClockModel::stop(nanos = %lld)\n", (long long) nanoTime);
+    ALOGV("IsochronousClockModel::stop(nanos = %lld)\n", (long long) nanoTime);
     setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime);
     // TODO should we set position?
     mState = STATE_STOPPED;
 }
 
+bool IsochronousClockModel::isStarting() {
+    return mState == STATE_STARTING;
+}
+
 void IsochronousClockModel::processTimestamp(int64_t framePosition, int64_t nanoTime) {
+//    ALOGD("processTimestamp() - framePosition = %lld at nanoTime %llu",
+//         (long long)framePosition,
+//         (long long)nanoTime);
     int64_t framesDelta = framePosition - mMarkerFramePosition;
     int64_t nanosDelta = nanoTime - mMarkerNanoTime;
     if (nanosDelta < 1000) {
@@ -70,9 +77,6 @@
 //    ALOGD("processTimestamp() - mMarkerFramePosition = %lld at mMarkerNanoTime %llu",
 //         (long long)mMarkerFramePosition,
 //         (long long)mMarkerNanoTime);
-//    ALOGD("processTimestamp() - framePosition = %lld at nanoTime %llu",
-//         (long long)framePosition,
-//         (long long)nanoTime);
 
     int64_t expectedNanosDelta = convertDeltaPositionToTime(framesDelta);
 //    ALOGD("processTimestamp() - expectedNanosDelta = %lld, nanosDelta = %llu",
@@ -116,6 +120,8 @@
     default:
         break;
     }
+
+//    ALOGD("processTimestamp() - mState = %d", mState);
 }
 
 void IsochronousClockModel::setSampleRate(int32_t sampleRate) {
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
index 585f53a..7182376 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -36,6 +36,8 @@
     void start(int64_t nanoTime);
     void stop(int64_t nanoTime);
 
+    bool isStarting();
+
     void processTimestamp(int64_t framePosition, int64_t nanoTime);
 
     /**
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 5089b00..1eaee81 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -24,15 +24,14 @@
 #include <aaudio/AAudio.h>
 #include <aaudio/AAudioTesting.h>
 
+#include "AudioClock.h"
 #include "AudioStreamBuilder.h"
 #include "AudioStream.h"
-#include "AudioClock.h"
+#include "binding/AAudioCommon.h"
 #include "client/AudioStreamInternal.h"
-#include "HandleTracker.h"
 
 using namespace aaudio;
 
-
 // Macros for common code that includes a return.
 // TODO Consider using do{}while(0) construct. I tried but it hung AndroidStudio
 #define CONVERT_BUILDER_HANDLE_OR_RETURN() \
@@ -219,6 +218,7 @@
     ALOGD("AAudioStreamBuilder_openStream() returns %d = %s for (%p) ----------------",
           result, AAudio_convertResultToText(result), audioStream);
     if (result == AAUDIO_OK) {
+        audioStream->registerPlayerBase();
         *streamPtr = (AAudioStream*) audioStream;
     } else {
         *streamPtr = nullptr;
@@ -242,6 +242,7 @@
     ALOGD("AAudioStream_close(%p)", stream);
     if (audioStream != nullptr) {
         audioStream->close();
+        audioStream->unregisterPlayerBase();
         delete audioStream;
         return AAUDIO_OK;
     }
@@ -252,7 +253,7 @@
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
     ALOGD("AAudioStream_requestStart(%p) called --------------", stream);
-    aaudio_result_t result = audioStream->requestStart();
+    aaudio_result_t result = audioStream->systemStart();
     ALOGD("AAudioStream_requestStart(%p) returned %d ---------", stream, result);
     return result;
 }
@@ -261,7 +262,7 @@
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
     ALOGD("AAudioStream_requestPause(%p)", stream);
-    return audioStream->requestPause();
+    return audioStream->systemPause();
 }
 
 AAUDIO_API aaudio_result_t  AAudioStream_requestFlush(AAudioStream* stream)
@@ -275,7 +276,7 @@
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
     ALOGD("AAudioStream_requestStop(%p)", stream);
-    return audioStream->requestStop();
+    return audioStream->systemStop();
 }
 
 AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream* stream,
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 4f1cc37..8dcc37a 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AAudioStream"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -29,13 +29,26 @@
 using namespace aaudio;
 
 AudioStream::AudioStream()
-        : mCallbackEnabled(false)
+        : mPlayerBase(new MyPlayerBase(this))
 {
     // mThread is a pthread_t of unknown size so we need memset.
     memset(&mThread, 0, sizeof(mThread));
     setPeriodNanoseconds(0);
 }
 
+AudioStream::~AudioStream() {
+    ALOGD("destroying %p, state = %s", this, AAudio_convertStreamStateToText(getState()));
+    // If the stream is deleted when OPEN or in use then audio resources will leak.
+    // This would indicate an internal error. So we want to find this ASAP.
+    LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
+                          || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED
+                          || getState() == AAUDIO_STREAM_STATE_DISCONNECTED),
+                        "aaudio stream still in use, state = %s",
+                        AAudio_convertStreamStateToText(getState()));
+
+    mPlayerBase->clearParentReference(); // remove reference to this AudioStream
+}
+
 static const char *AudioStream_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) {
     const char *result;
     switch (sharingMode) {
@@ -90,9 +103,6 @@
     return AAUDIO_OK;
 }
 
-AudioStream::~AudioStream() {
-    close();
-}
 
 aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
                                                 aaudio_stream_state_t *nextState,
@@ -189,3 +199,38 @@
     return err ? AAudioConvert_androidToAAudioResult(-errno) : mThreadRegistrationResult;
 }
 
+
+#if AAUDIO_USE_VOLUME_SHAPER
+android::media::VolumeShaper::Status AudioStream::applyVolumeShaper(
+        const android::media::VolumeShaper::Configuration& configuration __unused,
+        const android::media::VolumeShaper::Operation& operation __unused) {
+    ALOGW("applyVolumeShaper() is not supported");
+    return android::media::VolumeShaper::Status::ok();
+}
+#endif
+
+AudioStream::MyPlayerBase::MyPlayerBase(AudioStream *parent) : mParent(parent) {
+}
+
+AudioStream::MyPlayerBase::~MyPlayerBase() {
+    ALOGV("MyPlayerBase::~MyPlayerBase(%p) deleted", this);
+}
+
+void AudioStream::MyPlayerBase::registerWithAudioManager() {
+    if (!mRegistered) {
+        init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
+        mRegistered = true;
+    }
+}
+
+void AudioStream::MyPlayerBase::unregisterWithAudioManager() {
+    if (mRegistered) {
+        baseDestroy();
+        mRegistered = false;
+    }
+}
+
+
+void AudioStream::MyPlayerBase::destroy() {
+    unregisterWithAudioManager();
+}
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index ad18751..34202d2 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -21,10 +21,18 @@
 #include <mutex>
 #include <stdint.h>
 #include <aaudio/AAudio.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <utils/StrongPointer.h>
 
+#include "media/VolumeShaper.h"
+#include "media/PlayerBase.h"
 #include "utility/AAudioUtilities.h"
 #include "utility/MonotonicCounter.h"
 
+// Cannot get android::media::VolumeShaper to compile!
+#define AAUDIO_USE_VOLUME_SHAPER  0
+
 namespace aaudio {
 
 typedef void *(*aaudio_audio_thread_proc_t)(void *);
@@ -234,8 +242,132 @@
         return AAUDIO_ERROR_UNIMPLEMENTED;
     }
 
+    // This is used by the AudioManager to duck and mute the stream when changing audio focus.
+    void setDuckAndMuteVolume(float duckAndMuteVolume) {
+        mDuckAndMuteVolume = duckAndMuteVolume;
+        doSetVolume(); // apply this change
+    }
+
+    float getDuckAndMuteVolume() {
+        return mDuckAndMuteVolume;
+    }
+
+    // Implement this in the output subclasses.
+    virtual android::status_t doSetVolume() { return android::NO_ERROR; }
+
+#if AAUDIO_USE_VOLUME_SHAPER
+    virtual ::android::binder::Status applyVolumeShaper(
+            const ::android::media::VolumeShaper::Configuration& configuration __unused,
+            const ::android::media::VolumeShaper::Operation& operation __unused);
+#endif
+
+    /**
+     * Register this stream's PlayerBase with the AudioManager if needed.
+     * Only register output streams.
+     * This should only be called for client streams and not for streams
+     * that run in the service.
+     */
+    void registerPlayerBase() {
+        if (getDirection() == AAUDIO_DIRECTION_OUTPUT) {
+            mPlayerBase->registerWithAudioManager();
+        }
+    }
+
+    /**
+     * Unregister this stream's PlayerBase with the AudioManager.
+     * This will only unregister if already registered.
+     */
+    void unregisterPlayerBase() {
+        mPlayerBase->unregisterWithAudioManager();
+    }
+
+    // Pass start request through PlayerBase for tracking.
+    aaudio_result_t systemStart() {
+        mPlayerBase->start();
+        // Pass aaudio_result_t around the PlayerBase interface, which uses status__t.
+        return mPlayerBase->getResult();
+    }
+
+    aaudio_result_t systemPause() {
+        mPlayerBase->pause();
+        return mPlayerBase->getResult();
+    }
+
+    aaudio_result_t systemStop() {
+        mPlayerBase->stop();
+        return mPlayerBase->getResult();
+    }
+
 protected:
 
+    // PlayerBase allows the system to control the stream.
+    // Calling through PlayerBase->start() notifies the AudioManager of the player state.
+    // The AudioManager also can start/stop a stream by calling mPlayerBase->playerStart().
+    // systemStart() ==> mPlayerBase->start()   mPlayerBase->playerStart() ==> requestStart()
+    //                        \                           /
+    //                         ------ AudioManager -------
+    class MyPlayerBase : public android::PlayerBase {
+    public:
+        explicit MyPlayerBase(AudioStream *parent);
+
+        virtual ~MyPlayerBase();
+
+        /**
+         * Register for volume changes and remote control.
+         */
+        void registerWithAudioManager();
+
+        /**
+         * UnRegister.
+         */
+        void unregisterWithAudioManager();
+
+        /**
+         * Just calls unregisterWithAudioManager().
+         */
+        void destroy() override;
+
+        void clearParentReference() { mParent = nullptr; }
+
+        android::status_t playerStart() override {
+            // mParent should NOT be null. So go ahead and crash if it is.
+            mResult = mParent->requestStart();
+            return AAudioConvert_aaudioToAndroidStatus(mResult);
+        }
+
+        android::status_t playerPause() override {
+            mResult = mParent->requestPause();
+            return AAudioConvert_aaudioToAndroidStatus(mResult);
+        }
+
+        android::status_t playerStop() override {
+            mResult = mParent->requestStop();
+            return AAudioConvert_aaudioToAndroidStatus(mResult);
+        }
+
+        android::status_t playerSetVolume() override {
+            // No pan and only left volume is taken into account from IPLayer interface
+            mParent->setDuckAndMuteVolume(mVolumeMultiplierL  /* * mPanMultiplierL */);
+            return android::NO_ERROR;
+        }
+
+#if AAUDIO_USE_VOLUME_SHAPER
+        ::android::binder::Status applyVolumeShaper(
+                const ::android::media::VolumeShaper::Configuration& configuration,
+                const ::android::media::VolumeShaper::Operation& operation) {
+            return mParent->applyVolumeShaper(configuration, operation);
+        }
+#endif
+
+        aaudio_result_t getResult() {
+            return mResult;
+        }
+
+    private:
+        AudioStream          *mParent;
+        aaudio_result_t       mResult = AAUDIO_OK;
+        bool                  mRegistered = false;
+    };
 
     /**
      * This should not be called after the open() call.
@@ -275,7 +407,9 @@
 
     std::mutex           mStreamMutex;
 
-    std::atomic<bool>    mCallbackEnabled;
+    std::atomic<bool>    mCallbackEnabled{false};
+
+    float                mDuckAndMuteVolume = 1.0f;
 
 protected:
 
@@ -288,6 +422,8 @@
     }
 
 private:
+    const android::sp<MyPlayerBase>   mPlayerBase;
+
     // These do not change after open().
     int32_t                mSamplesPerFrame = AAUDIO_UNSPECIFIED;
     int32_t                mSampleRate = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index 2816bac..ee2504d 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <utils/String16.h>
 #include <media/AudioTrack.h>
+#include <media/AudioTimestamp.h>
 #include <aaudio/AAudio.h>
 
 #include "core/AudioStream.h"
@@ -30,7 +31,8 @@
 using namespace aaudio;
 
 AudioStreamLegacy::AudioStreamLegacy()
-        : AudioStream(), mDeviceCallback(new StreamDeviceCallback(this)) {
+        : AudioStream()
+        , mDeviceCallback(new StreamDeviceCallback(this)) {
 }
 
 AudioStreamLegacy::~AudioStreamLegacy() {
@@ -46,33 +48,51 @@
     return AudioStreamLegacy_callback;
 }
 
-// Implement FixedBlockProcessor
-int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
-    int32_t frameCount = numBytes / getBytesPerFrame();
+int32_t AudioStreamLegacy::callDataCallbackFrames(uint8_t *buffer, int32_t numFrames) {
+    if (getDirection() == AAUDIO_DIRECTION_INPUT) {
+        // Increment before because we already got the data from the device.
+        incrementFramesRead(numFrames);
+    }
+
     // Call using the AAudio callback interface.
     AAudioStream_dataCallback appCallback = getDataCallbackProc();
-    return (*appCallback)(
+    aaudio_data_callback_result_t callbackResult = (*appCallback)(
             (AAudioStream *) this,
             getDataCallbackUserData(),
             buffer,
-            frameCount);
+            numFrames);
+
+    if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE
+            && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
+        // Increment after because we are going to write the data to the device.
+        incrementFramesWritten(numFrames);
+    }
+    return callbackResult;
+}
+
+// Implement FixedBlockProcessor
+int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
+    int32_t numFrames = numBytes / getBytesPerFrame();
+    return callDataCallbackFrames(buffer, numFrames);
 }
 
 void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) {
     aaudio_data_callback_result_t callbackResult;
 
-    if (!mCallbackEnabled.load()) {
-        return;
-    }
-
     switch (opcode) {
         case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: {
-            if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
-                // Note that this code assumes an AudioTrack::Buffer is the same as
-                // AudioRecord::Buffer
-                // TODO define our own AudioBuffer and pass it from the subclasses.
-                AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
-                if (audioBuffer->frameCount == 0) return;
+            checkForDisconnectRequest();
+
+            // Note that this code assumes an AudioTrack::Buffer is the same as
+            // AudioRecord::Buffer
+            // TODO define our own AudioBuffer and pass it from the subclasses.
+            AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
+            if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED || !mCallbackEnabled.load()) {
+                audioBuffer->size = 0; // silence the buffer
+            } else {
+                if (audioBuffer->frameCount == 0) {
+                    return;
+                }
 
                 // If the caller specified an exact size then use a block size adapter.
                 if (mBlockAdapter != nullptr) {
@@ -81,40 +101,28 @@
                             (uint8_t *) audioBuffer->raw, byteCount);
                 } else {
                     // Call using the AAudio callback interface.
-                    callbackResult = (*getDataCallbackProc())(
-                            (AAudioStream *) this,
-                            getDataCallbackUserData(),
-                            audioBuffer->raw,
-                            audioBuffer->frameCount
-                            );
+                    callbackResult = callDataCallbackFrames((uint8_t *)audioBuffer->raw,
+                                                            audioBuffer->frameCount);
                 }
                 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
                     audioBuffer->size = audioBuffer->frameCount * getBytesPerFrame();
-                    incrementClientFrameCounter(audioBuffer->frameCount);
                 } else {
                     audioBuffer->size = 0;
                 }
 
-                if (updateStateMachine() == AAUDIO_OK) {
-                    break; // don't fall through
+                if (updateStateMachine() != AAUDIO_OK) {
+                    forceDisconnect();
+                    mCallbackEnabled.store(false);
                 }
             }
         }
-        /// FALL THROUGH
+            break;
 
         // Stream got rerouted so we disconnect.
-        case AAUDIO_CALLBACK_OPERATION_DISCONNECTED: {
-            setState(AAUDIO_STREAM_STATE_DISCONNECTED);
+        case AAUDIO_CALLBACK_OPERATION_DISCONNECTED:
             ALOGD("processCallbackCommon() stream disconnected");
-            if (getErrorCallbackProc() != nullptr) {
-                (*getErrorCallbackProc())(
-                        (AAudioStream *) this,
-                        getErrorCallbackUserData(),
-                        AAUDIO_ERROR_DISCONNECTED
-                        );
-            }
+            forceDisconnect();
             mCallbackEnabled.store(false);
-        }
             break;
 
         default:
@@ -122,6 +130,30 @@
     }
 }
 
+
+
+void AudioStreamLegacy::checkForDisconnectRequest() {
+    if (mRequestDisconnect.isRequested()) {
+        ALOGD("checkForDisconnectRequest() mRequestDisconnect acknowledged");
+        forceDisconnect();
+        mRequestDisconnect.acknowledge();
+        mCallbackEnabled.store(false);
+    }
+}
+
+void AudioStreamLegacy::forceDisconnect() {
+    if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
+        setState(AAUDIO_STREAM_STATE_DISCONNECTED);
+        if (getErrorCallbackProc() != nullptr) {
+            (*getErrorCallbackProc())(
+                    (AAudioStream *) this,
+                    getErrorCallbackUserData(),
+                    AAUDIO_ERROR_DISCONNECTED
+            );
+        }
+    }
+}
+
 aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId,
                                                    int64_t *framePosition,
                                                    int64_t *timeNanoseconds,
@@ -139,8 +171,23 @@
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
             break;
     }
-    status_t status = extendedTimestamp->getBestTimestamp(framePosition, timeNanoseconds, timebase);
-    return AAudioConvert_androidToAAudioResult(status);
+    ExtendedTimestamp::Location location = ExtendedTimestamp::Location::LOCATION_INVALID;
+    int64_t localPosition;
+    status_t status = extendedTimestamp->getBestTimestamp(&localPosition, timeNanoseconds,
+                                                          timebase, &location);
+    // use MonotonicCounter to prevent retrograde motion.
+    mTimestampPosition.update32((int32_t)localPosition);
+    *framePosition = mTimestampPosition.get();
+
+//    ALOGD("getBestTimestamp() fposition: server = %6lld, kernel = %6lld, location = %d",
+//          (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_SERVER],
+//          (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_KERNEL],
+//          (int)location);
+    if (status == WOULD_BLOCK) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    } else {
+        return AAudioConvert_androidToAAudioResult(status);
+    }
 }
 
 void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId)
@@ -148,15 +195,18 @@
     ALOGD("onAudioDeviceUpdate() deviceId %d", (int)deviceId);
     if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId &&
             getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
-        setState(AAUDIO_STREAM_STATE_DISCONNECTED);
-        // if we have a data callback and the stream is active, send the error callback from
-        // data callback thread when it sees the DISCONNECTED state
-        if (!isDataCallbackActive() && getErrorCallbackProc() != nullptr) {
-            (*getErrorCallbackProc())(
-                    (AAudioStream *) this,
-                    getErrorCallbackUserData(),
-                    AAUDIO_ERROR_DISCONNECTED
-                    );
+        // Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING.
+        // If we have a data callback and the stream is active, then ask the data callback
+        // to DISCONNECT and call the error callback.
+        if (isDataCallbackActive()) {
+            ALOGD("onAudioDeviceUpdate() request DISCONNECT in data callback due to device change");
+            // If the stream is stopped before the data callback has a chance to handle the
+            // request then the requestStop() and requestPause() methods will handle it after
+            // the callback has stopped.
+            mRequestDisconnect.request();
+        } else {
+            ALOGD("onAudioDeviceUpdate() DISCONNECT the stream now");
+            forceDisconnect();
         }
     }
     setDeviceId(deviceId);
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.h b/media/libaaudio/src/legacy/AudioStreamLegacy.h
index d2ef3c7..7e28579 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.h
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.h
@@ -24,6 +24,7 @@
 
 #include "AudioStream.h"
 #include "AAudioLegacy.h"
+#include "utility/AAudioUtilities.h"
 #include "utility/FixedBlockAdapter.h"
 
 namespace aaudio {
@@ -63,6 +64,8 @@
 
     aaudio_legacy_callback_t getLegacyCallback();
 
+    int32_t callDataCallbackFrames(uint8_t *buffer, int32_t numFrames);
+
     // This is public so it can be called from the C callback function.
     // This is called from the AudioTrack/AudioRecord client.
     virtual void processCallback(int event, void *info) = 0;
@@ -109,6 +112,10 @@
 
     void onAudioDeviceUpdate(audio_port_handle_t deviceId);
 
+    void checkForDisconnectRequest();
+
+    void forceDisconnect();
+
     void onStart() { mCallbackEnabled.store(true); }
     void onStop() { mCallbackEnabled.store(false); }
 
@@ -122,11 +129,14 @@
 
     MonotonicCounter           mFramesWritten;
     MonotonicCounter           mFramesRead;
+    MonotonicCounter           mTimestampPosition;
 
     FixedBlockAdapter         *mBlockAdapter = nullptr;
     aaudio_wrapping_frames_t   mPositionWhenStarting = 0;
     int32_t                    mCallbackBufferSize = 0;
     const android::sp<StreamDeviceCallback>   mDeviceCallback;
+
+    AtomicRequestor            mRequestDisconnect;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 041280d..bc6e60c 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioStreamRecord"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -181,11 +181,12 @@
 {
     // TODO add close() or release() to AudioRecord API then call it from here
     if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
+        mAudioRecord->removeAudioDeviceCallback(mDeviceCallback);
         mAudioRecord.clear();
         setState(AAUDIO_STREAM_STATE_CLOSED);
     }
     mFixedBlockWriter.close();
-    return AAUDIO_OK;
+    return AudioStream::close();
 }
 
 void AudioStreamRecord::processCallback(int event, void *info) {
@@ -233,8 +234,11 @@
     onStop();
     setState(AAUDIO_STREAM_STATE_STOPPING);
     incrementFramesWritten(getFramesRead() - getFramesWritten()); // TODO review
+    mTimestampPosition.set(getFramesRead());
     mAudioRecord->stop();
     mFramesRead.reset32();
+    mTimestampPosition.reset32();
+    checkForDisconnectRequest();
     return AAUDIO_OK;
 }
 
@@ -334,7 +338,9 @@
                                                int64_t *timeNanoseconds) {
     ExtendedTimestamp extendedTimestamp;
     status_t status = mAudioRecord->getTimestamp(&extendedTimestamp);
-    if (status != NO_ERROR) {
+    if (status == WOULD_BLOCK) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    } else if (status != NO_ERROR) {
         return AAudioConvert_androidToAAudioResult(status);
     }
     return getBestTimestamp(clockId, framePosition, timeNanoseconds, &extendedTimestamp);
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 155362c..0e9aaef 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioStreamTrack"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -115,7 +115,7 @@
 
     ALOGD("AudioStreamTrack::open(), request notificationFrames = %d, frameCount = %u",
           notificationFrames, (uint)frameCount);
-    mAudioTrack = new AudioTrack();
+    mAudioTrack = new AudioTrack(); // TODO review
     if (getDeviceId() != AAUDIO_UNSPECIFIED) {
         mAudioTrack->setOutputDevice(getDeviceId());
     }
@@ -143,8 +143,7 @@
         return AAudioConvert_androidToAAudioResult(status);
     }
 
-    //TrackPlayerBase init
-    init(mAudioTrack.get(), PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
+    doSetVolume();
 
     // Get the actual values from the AudioTrack.
     setSamplesPerFrame(mAudioTrack->channelCount());
@@ -199,7 +198,7 @@
 aaudio_result_t AudioStreamTrack::close()
 {
     if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
-        destroy();
+        mAudioTrack->removeAudioDeviceCallback(mDeviceCallback);
         setState(AAUDIO_STREAM_STATE_CLOSED);
     }
     mFixedBlockReader.close();
@@ -224,8 +223,7 @@
     return;
 }
 
-aaudio_result_t AudioStreamTrack::requestStart()
-{
+aaudio_result_t AudioStreamTrack::requestStart() {
     std::lock_guard<std::mutex> lock(mStreamMutex);
 
     if (mAudioTrack.get() == nullptr) {
@@ -238,7 +236,7 @@
         return AAudioConvert_androidToAAudioResult(err);
     }
 
-    err = startWithStatus();
+    err = mAudioTrack->start();
     if (err != OK) {
         return AAudioConvert_androidToAAudioResult(err);
     } else {
@@ -248,12 +246,11 @@
     return AAUDIO_OK;
 }
 
-aaudio_result_t AudioStreamTrack::requestPause()
-{
+aaudio_result_t AudioStreamTrack::requestPause() {
     std::lock_guard<std::mutex> lock(mStreamMutex);
 
     if (mAudioTrack.get() == nullptr) {
-        ALOGE("AudioStreamTrack::requestPause() no AudioTrack");
+        ALOGE("requestPause() no AudioTrack");
         return AAUDIO_ERROR_INVALID_STATE;
     } else if (getState() != AAUDIO_STREAM_STATE_STARTING
             && getState() != AAUDIO_STREAM_STATE_STARTED) {
@@ -263,7 +260,8 @@
     }
     onStop();
     setState(AAUDIO_STREAM_STATE_PAUSING);
-    pause();
+    mAudioTrack->pause();
+    checkForDisconnectRequest();
     status_t err = mAudioTrack->getPosition(&mPositionWhenPausing);
     if (err != OK) {
         return AAudioConvert_androidToAAudioResult(err);
@@ -285,6 +283,7 @@
     incrementFramesRead(getFramesWritten() - getFramesRead());
     mAudioTrack->flush();
     mFramesWritten.reset32();
+    mTimestampPosition.reset32();
     return AAUDIO_OK;
 }
 
@@ -298,8 +297,11 @@
     onStop();
     setState(AAUDIO_STREAM_STATE_STOPPING);
     incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review
-    stop();
+    mTimestampPosition.set(getFramesWritten());
     mFramesWritten.reset32();
+    mTimestampPosition.reset32();
+    mAudioTrack->stop();
+    checkForDisconnectRequest();
     return AAUDIO_OK;
 }
 
@@ -444,8 +446,59 @@
                                      int64_t *timeNanoseconds) {
     ExtendedTimestamp extendedTimestamp;
     status_t status = mAudioTrack->getTimestamp(&extendedTimestamp);
-    if (status != NO_ERROR) {
+    if (status == WOULD_BLOCK) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    } if (status != NO_ERROR) {
         return AAudioConvert_androidToAAudioResult(status);
     }
-    return getBestTimestamp(clockId, framePosition, timeNanoseconds, &extendedTimestamp);
+    int64_t position = 0;
+    int64_t nanoseconds = 0;
+    aaudio_result_t result = getBestTimestamp(clockId, &position,
+                                              &nanoseconds, &extendedTimestamp);
+    if (result == AAUDIO_OK) {
+        if (position < getFramesWritten()) {
+            *framePosition = position;
+            *timeNanoseconds = nanoseconds;
+            return result;
+        } else {
+            return AAUDIO_ERROR_INVALID_STATE; // TODO review, documented but not consistent
+        }
+    }
+    return result;
 }
+
+status_t AudioStreamTrack::doSetVolume() {
+    status_t status = NO_INIT;
+    if (mAudioTrack.get() != nullptr) {
+        float volume = getDuckAndMuteVolume();
+        mAudioTrack->setVolume(volume, volume);
+        status = NO_ERROR;
+    }
+    return status;
+}
+
+#if AAUDIO_USE_VOLUME_SHAPER
+
+using namespace android::media::VolumeShaper;
+
+binder::Status AudioStreamTrack::applyVolumeShaper(
+        const VolumeShaper::Configuration& configuration,
+        const VolumeShaper::Operation& operation) {
+
+    sp<VolumeShaper::Configuration> spConfiguration = new VolumeShaper::Configuration(configuration);
+    sp<VolumeShaper::Operation> spOperation = new VolumeShaper::Operation(operation);
+
+    if (mAudioTrack.get() != nullptr) {
+        ALOGD("applyVolumeShaper() from IPlayer");
+        binder::Status status = mAudioTrack->applyVolumeShaper(spConfiguration, spOperation);
+        if (status < 0) { // a non-negative value is the volume shaper id.
+            ALOGE("applyVolumeShaper() failed with status %d", status);
+        }
+        return binder::Status::fromStatusT(status);
+    } else {
+        ALOGD("applyVolumeShaper()"
+                      " no AudioTrack for volume control from IPlayer");
+        return binder::Status::ok();
+    }
+}
+#endif
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h
index 3230ac8..a871db4 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.h
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.h
@@ -19,6 +19,7 @@
 
 #include <math.h>
 #include <media/TrackPlayerBase.h>
+#include <media/AudioTrack.h>
 #include <aaudio/AAudio.h>
 
 #include "AudioStreamBuilder.h"
@@ -32,7 +33,7 @@
 /**
  * Internal stream that uses the legacy AudioTrack path.
  */
-class AudioStreamTrack : public AudioStreamLegacy, public android::TrackPlayerBase {
+class AudioStreamTrack : public AudioStreamLegacy {
 public:
     AudioStreamTrack();
 
@@ -76,8 +77,18 @@
         return incrementFramesWritten(frames);
     }
 
+    android::status_t doSetVolume() override;
+
+#if AAUDIO_USE_VOLUME_SHAPER
+    virtual android::binder::Status applyVolumeShaper(
+            const android::media::VolumeShaper::Configuration& configuration,
+            const android::media::VolumeShaper::Operation& operation) override;
+#endif
+
 private:
 
+    android::sp<android::AudioTrack> mAudioTrack;
+
     // adapts between variable sized blocks and fixed size blocks
     FixedBlockReader                 mFixedBlockReader;
 
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index b0c6c94..3afa976 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -272,8 +272,7 @@
 class SimpleDoubleBuffer {
 public:
     SimpleDoubleBuffer()
-            : mValues()
-            , mCounter(0) {}
+            : mValues() {}
 
     __attribute__((no_sanitize("integer")))
     void write(T value) {
@@ -282,6 +281,14 @@
         mCounter++; // Increment AFTER updating storage, OK if it wraps.
     }
 
+    /**
+     * This should only be called by the same thread that calls write() or when
+     * no other thread is calling write.
+     */
+    void clear() {
+        mCounter.store(0);
+    }
+
     T read() const {
         T result;
         int before;
@@ -293,7 +300,7 @@
             int index = (before & 1) ^ 1;
             result = mValues[index];
             after = mCounter.load();
-        } while ((after != before) && --timeout > 0);
+        } while ((after != before) && (after > 0) && (--timeout > 0));
         return result;
     }
 
@@ -306,7 +313,7 @@
 
 private:
     T                    mValues[2];
-    std::atomic<int>     mCounter;
+    std::atomic<int>     mCounter{0};
 };
 
 class Timestamp {
@@ -328,4 +335,35 @@
     int64_t mNanoseconds;
 };
 
+
+/**
+ * Pass a request to another thread.
+ * This is used when one thread, A, wants another thread, B, to do something.
+ * A naive approach would be for A to set a flag and for B to clear it when done.
+ * But that creates a race condition. This technique avoids the race condition.
+ *
+ * Assumes only one requester and one acknowledger.
+ */
+class AtomicRequestor {
+public:
+
+    __attribute__((no_sanitize("integer")))
+    void request() {
+        mRequested++;
+    }
+
+    __attribute__((no_sanitize("integer")))
+    bool isRequested() {
+        return (mRequested.load() - mAcknowledged.load()) > 0;
+    }
+
+    __attribute__((no_sanitize("integer")))
+    void acknowledge() {
+        mAcknowledged++;
+    }
+
+private:
+    std::atomic<int> mRequested{0};
+    std::atomic<int> mAcknowledged{0};
+};
 #endif //UTILITY_AAUDIO_UTILITIES_H
diff --git a/media/libaaudio/src/utility/HandleTracker.cpp b/media/libaaudio/src/utility/HandleTracker.cpp
deleted file mode 100644
index 35ce95a..0000000
--- a/media/libaaudio/src/utility/HandleTracker.cpp
+++ /dev/null
@@ -1,276 +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 <assert.h>
-#include <functional>
-#include <iomanip>
-#include <new>
-#include <sstream>
-#include <stdint.h>
-#include <utils/Mutex.h>
-
-#include <aaudio/AAudio.h>
-#include "AAudioUtilities.h"
-#include "HandleTracker.h"
-
-using android::Mutex;
-
-// Handle format is: tgggiiii
-// where each letter is 4 bits, t=type, g=generation, i=index
-
-#define TYPE_SIZE           4
-#define GENERATION_SIZE    12
-#define INDEX_SIZE         16
-
-#define GENERATION_INVALID  0
-#define GENERATION_SHIFT    INDEX_SIZE
-
-#define TYPE_MASK           ((1 << TYPE_SIZE) - 1)
-#define GENERATION_MASK     ((1 << GENERATION_SIZE) - 1)
-#define INDEX_MASK          ((1 << INDEX_SIZE) - 1)
-
-#define SLOT_UNAVAILABLE    (-1)
-
-// Error if handle is negative so type is limited to bottom half.
-#define HANDLE_INVALID_TYPE TYPE_MASK
-
-static_assert(HANDLE_TRACKER_MAX_TYPES == (1 << (TYPE_SIZE - 1)),
-    "Mismatch between header and cpp.");
-static_assert(HANDLE_TRACKER_MAX_HANDLES == (1 << (INDEX_SIZE)),
-    "Mismatch between header and cpp.");
-
-HandleTracker::HandleTracker(uint32_t maxHandles)
-        : mMaxHandleCount(maxHandles)
-        , mHandleHeaders(nullptr)
-{
-    assert(maxHandles <= HANDLE_TRACKER_MAX_HANDLES);
-    // Allocate arrays to hold addresses and validation info.
-    mHandleAddresses = (handle_tracker_address_t *)
-            new(std::nothrow) handle_tracker_address_t[maxHandles];
-    if (mHandleAddresses != nullptr) {
-        mHandleHeaders = new(std::nothrow) handle_tracker_header_t[maxHandles];
-
-        if (mHandleHeaders != nullptr) {
-            handle_tracker_header_t initialHeader = buildHeader(0, 1);
-            // Initialize linked list of free nodes. nullptr terminated.
-            for (uint32_t i = 0; i < (maxHandles - 1); i++) {
-                mHandleAddresses[i] = &mHandleAddresses[i + 1]; // point to next node
-                mHandleHeaders[i] = initialHeader;
-            }
-            mNextFreeAddress = &mHandleAddresses[0];
-            mHandleAddresses[maxHandles - 1] = nullptr;
-            mHandleHeaders[maxHandles - 1] = 0;
-        } else {
-            delete[] mHandleAddresses; // so the class appears uninitialized
-            mHandleAddresses = nullptr;
-        }
-    }
-}
-
-HandleTracker::~HandleTracker()
-{
-    Mutex::Autolock _l(mLock);
-    delete[] mHandleAddresses;
-    delete[] mHandleHeaders;
-    mHandleAddresses = nullptr;
-}
-
-bool HandleTracker::isInitialized() const {
-    return mHandleAddresses != nullptr;
-}
-
-
-
-std::string HandleTracker::dump() const {
-    if (!isInitialized()) {
-        return "HandleTracker is not initialized\n";
-    }
-
-    std::stringstream result;
-    const bool isLocked = AAudio_tryUntilTrue(
-            [this]()->bool { return mLock.tryLock(); } /* f */,
-            50 /* times */,
-            20 /* sleepMs */);
-    if (!isLocked) {
-        result << "HandleTracker may be deadlocked\n";
-    }
-
-    result << "HandleTracker:\n";
-    result << "  HandleHeaders:\n";
-    // atLineStart() can be changed to support an arbitrary line breaking algorithm;
-    // it should return true when a new line starts.
-    // For simplicity, we will use a constant 16 items per line.
-    const auto atLineStart = [](int index) -> bool {
-        // Magic constant of 0xf used for mask to detect start every 16 items.
-        return (index & 0xf) == 0; };
-    const auto atLineEnd = [this, &atLineStart](int index) -> bool {
-        return atLineStart(index + 1) || index == mMaxHandleCount - 1; };
-
-    for (int i = 0; i < mMaxHandleCount; ++i) {
-        if (atLineStart(i)) {
-            result << "    ";
-        }
-        result << std::hex << std::setw(4) << std::setfill('0') << mHandleHeaders[i]
-               << (atLineEnd(i) ? "\n" : " ");
-    }
-
-    if (isLocked) {
-        mLock.unlock();
-    }
-    return result.str();
-}
-
-handle_tracker_slot_t HandleTracker::allocateSlot_l() {
-    void **allocated = mNextFreeAddress;
-    if (allocated == nullptr) {
-        return SLOT_UNAVAILABLE;
-    }
-    // Remove this slot from the head of the linked list.
-    mNextFreeAddress = (void **) *allocated;
-    return (allocated - mHandleAddresses);
-}
-
-handle_tracker_generation_t HandleTracker::nextGeneration_l(handle_tracker_slot_t index) {
-    handle_tracker_generation_t generation = (mHandleHeaders[index] + 1) & GENERATION_MASK;
-    // Avoid generation zero so that 0x0 is not a valid handle.
-    if (generation == GENERATION_INVALID) {
-        generation++;
-    }
-    return generation;
-}
-
-aaudio_handle_t HandleTracker::put(handle_tracker_type_t type, void *address)
-{
-    if (type < 0 || type >= HANDLE_TRACKER_MAX_TYPES) {
-        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_OUT_OF_RANGE);
-    }
-    if (!isInitialized()) {
-        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_MEMORY);
-    }
-
-    Mutex::Autolock _l(mLock);
-
-    // Find an empty slot.
-    handle_tracker_slot_t index = allocateSlot_l();
-    if (index == SLOT_UNAVAILABLE) {
-        ALOGE("HandleTracker::put() no room for more handles");
-        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_FREE_HANDLES);
-    }
-
-    // Cycle the generation counter so stale handles can be detected.
-    handle_tracker_generation_t generation = nextGeneration_l(index); // reads header table
-    handle_tracker_header_t inputHeader = buildHeader(type, generation);
-
-    // These two writes may need to be observed by other threads or cores during get().
-    mHandleHeaders[index] = inputHeader;
-    mHandleAddresses[index] = address;
-    // TODO use store release to enforce memory order with get()
-
-    // Generate a handle.
-    aaudio_handle_t handle = buildHandle(inputHeader, index);
-
-    ALOGV("HandleTracker::put(%p) returns 0x%08x", address, handle);
-    return handle;
-}
-
-handle_tracker_slot_t HandleTracker::handleToIndex(handle_tracker_type_t type,
-                                                   aaudio_handle_t handle) const
-{
-    // Validate the handle.
-    handle_tracker_slot_t index = extractIndex(handle);
-    if (index >= mMaxHandleCount) {
-        ALOGE("HandleTracker::handleToIndex() invalid handle = 0x%08X", handle);
-        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
-    }
-    handle_tracker_generation_t handleGeneration = extractGeneration(handle);
-    handle_tracker_header_t inputHeader = buildHeader(type, handleGeneration);
-    // We do not need to synchronize this access to mHandleHeaders because it is constant for
-    // the lifetime of the handle.
-    if (inputHeader != mHandleHeaders[index]) {
-        ALOGE("HandleTracker::handleToIndex() inputHeader = 0x%08x != mHandleHeaders[%d] = 0x%08x",
-             inputHeader, index, mHandleHeaders[index]);
-        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
-    }
-    return index;
-}
-
-handle_tracker_address_t HandleTracker::get(handle_tracker_type_t type, aaudio_handle_t handle) const
-{
-    if (!isInitialized()) {
-        return nullptr;
-    }
-    handle_tracker_slot_t index = handleToIndex(type, handle);
-    if (index >= 0) {
-        // We do not need to synchronize this access to mHandleHeaders because this slot
-        // is allocated and, therefore, not part of the linked list of free slots.
-        return mHandleAddresses[index];
-    } else {
-        return nullptr;
-    }
-}
-
-handle_tracker_address_t HandleTracker::remove(handle_tracker_type_t type, aaudio_handle_t handle) {
-    if (!isInitialized()) {
-        return nullptr;
-    }
-
-    Mutex::Autolock _l(mLock);
-
-    handle_tracker_slot_t index = handleToIndex(type,handle);
-    if (index >= 0) {
-        handle_tracker_address_t address = mHandleAddresses[index];
-
-        // Invalidate the header type but preserve the generation count.
-        handle_tracker_generation_t generation = mHandleHeaders[index] & GENERATION_MASK;
-        handle_tracker_header_t inputHeader = buildHeader(
-                (handle_tracker_type_t) HANDLE_INVALID_TYPE, generation);
-        mHandleHeaders[index] = inputHeader;
-
-        // Add this slot to the head of the linked list.
-        mHandleAddresses[index] = mNextFreeAddress;
-        mNextFreeAddress = (handle_tracker_address_t *) &mHandleAddresses[index];
-        return address;
-    } else {
-        return nullptr;
-    }
-}
-
-aaudio_handle_t HandleTracker::buildHandle(handle_tracker_header_t typeGeneration,
-                                         handle_tracker_slot_t index) {
-    return (aaudio_handle_t)((typeGeneration << GENERATION_SHIFT) | (index & INDEX_MASK));
-}
-
-handle_tracker_header_t HandleTracker::buildHeader(handle_tracker_type_t type,
-                                    handle_tracker_generation_t generation)
-{
-    return (handle_tracker_header_t) (((type & TYPE_MASK) << GENERATION_SIZE)
-        | (generation & GENERATION_MASK));
-}
-
-handle_tracker_slot_t HandleTracker::extractIndex(aaudio_handle_t handle)
-{
-    return handle & INDEX_MASK;
-}
-
-handle_tracker_generation_t HandleTracker::extractGeneration(aaudio_handle_t handle)
-{
-    return (handle >> GENERATION_SHIFT) & GENERATION_MASK;
-}
diff --git a/media/libaaudio/src/utility/HandleTracker.h b/media/libaaudio/src/utility/HandleTracker.h
deleted file mode 100644
index a4c51c0..0000000
--- a/media/libaaudio/src/utility/HandleTracker.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef UTILITY_HANDLE_TRACKER_H
-#define UTILITY_HANDLE_TRACKER_H
-
-#include <stdint.h>
-#include <string>
-#include <utils/Mutex.h>
-
-typedef int32_t  aaudio_handle_t;
-typedef int32_t  handle_tracker_type_t;       // what kind of handle
-typedef int32_t  handle_tracker_slot_t;       // index in allocation table
-typedef int32_t  handle_tracker_generation_t; // incremented when slot used
-typedef uint16_t handle_tracker_header_t;     // combines type and generation
-typedef void    *handle_tracker_address_t;    // address of something that is stored here
-
-#define HANDLE_TRACKER_MAX_TYPES    (1 << 3)
-#define HANDLE_TRACKER_MAX_HANDLES  (1 << 16)
-
-/**
- * Represent Objects using an integer handle that can be used with Java.
- * This also makes the 'C' ABI more robust.
- *
- * Note that this should only be called from a single thread.
- * If you call it from more than one thread then you need to use your own mutex.
- */
-class HandleTracker {
-
-public:
-    /**
-     * @param maxHandles cannot exceed HANDLE_TRACKER_MAX_HANDLES
-     */
-    HandleTracker(uint32_t maxHandles = 256);
-    virtual ~HandleTracker();
-
-    /**
-     * Don't use if this returns false;
-     * @return true if the internal allocation succeeded
-     */
-    bool isInitialized() const;
-
-    /**
-     * Returns HandleTracker information.
-     *
-     * Will attempt to get the object lock, but will proceed
-     * even if it cannot.
-     *
-     * Each line of information ends with a newline.
-     *
-     * @return a string representing the HandleTracker info.
-     */
-    std::string dump() const;
-
-    /**
-     * Store a pointer and return a handle that can be used to retrieve the pointer.
-     *
-     * It is safe to call put() or remove() from multiple threads.
-     *
-     * @param expectedType the type of the object to be tracked
-     * @param address pointer to be converted to a handle
-     * @return a valid handle or a negative error
-     */
-    aaudio_handle_t put(handle_tracker_type_t expectedType, handle_tracker_address_t address);
-
-    /**
-     * Get the original pointer associated with the handle.
-     * The handle will be validated to prevent stale handles from being reused.
-     * Note that the validation is designed to prevent common coding errors and not
-     * to prevent deliberate hacking.
-     *
-     * @param expectedType shouldmatch the type we passed to put()
-     * @param handle to be converted to a pointer
-     * @return address associated with handle or nullptr
-     */
-    handle_tracker_address_t get(handle_tracker_type_t expectedType, aaudio_handle_t handle) const;
-
-    /**
-     * Free up the storage associated with the handle.
-     * Subsequent attempts to use the handle will fail.
-     *
-     * Do NOT remove() a handle while get() is being called for the same handle from another thread.
-     *
-     * @param expectedType shouldmatch the type we passed to put()
-     * @param handle to be removed from tracking
-     * @return address associated with handle or nullptr if not found
-     */
-    handle_tracker_address_t remove(handle_tracker_type_t expectedType, aaudio_handle_t handle);
-
-private:
-    const int32_t               mMaxHandleCount;   // size of array
-    // This address is const after initialization.
-    handle_tracker_address_t  * mHandleAddresses;  // address of objects or a free linked list node
-    // This address is const after initialization.
-    handle_tracker_header_t   * mHandleHeaders;    // combination of type and generation
-    // head of the linked list of free nodes in mHandleAddresses
-    handle_tracker_address_t  * mNextFreeAddress;
-
-    // This Mutex protects the linked list of free nodes.
-    // The list is managed using mHandleAddresses and mNextFreeAddress.
-    // The data in mHandleHeaders is only changed by put() and remove().
-    mutable android::Mutex      mLock;
-
-    /**
-     * Pull slot off of a list of empty slots.
-     * @return index or a negative error
-     */
-    handle_tracker_slot_t allocateSlot_l();
-
-    /**
-     * Increment the generation for the slot, avoiding zero.
-     */
-    handle_tracker_generation_t nextGeneration_l(handle_tracker_slot_t index);
-
-    /**
-     * Validate the handle and return the corresponding index.
-     * @return slot index or a negative error
-     */
-    handle_tracker_slot_t handleToIndex(aaudio_handle_t handle, handle_tracker_type_t type) const;
-
-    /**
-     * Construct a handle from a header and an index.
-     * @param header combination of a type and a generation
-     * @param index slot index returned from allocateSlot
-     * @return handle or a negative error
-     */
-    static aaudio_handle_t buildHandle(handle_tracker_header_t header, handle_tracker_slot_t index);
-
-    /**
-     * Combine a type and a generation field into a header.
-     */
-    static handle_tracker_header_t buildHeader(handle_tracker_type_t type,
-                handle_tracker_generation_t generation);
-
-    /**
-     * Extract the index from a handle.
-     * Does not validate the handle.
-     * @return index associated with a handle
-     */
-    static handle_tracker_slot_t extractIndex(aaudio_handle_t handle);
-
-    /**
-     * Extract the generation from a handle.
-     * Does not validate the handle.
-     * @return generation associated with a handle
-     */
-    static handle_tracker_generation_t extractGeneration(aaudio_handle_t handle);
-
-};
-
-#endif //UTILITY_HANDLE_TRACKER_H
diff --git a/media/libaaudio/src/utility/MonotonicCounter.h b/media/libaaudio/src/utility/MonotonicCounter.h
index 81d7f89..5833eab 100644
--- a/media/libaaudio/src/utility/MonotonicCounter.h
+++ b/media/libaaudio/src/utility/MonotonicCounter.h
@@ -41,6 +41,13 @@
     }
 
     /**
+     * set the current value of the counter
+     */
+    void set(int64_t counter) {
+        mCounter64 = counter;
+    }
+
+    /**
      * Advance the counter if delta is positive.
      * @return current value of the counter
      */
@@ -82,6 +89,18 @@
         mCounter32 = 0;
     }
 
+    /**
+     * Round 64-bit counter up to a multiple of the period.
+     *
+     * @param period might be, for example, a buffer capacity
+     */
+    void roundUp64(int32_t period) {
+        if (period > 0) {
+            int64_t numPeriods = (mCounter64 + period - 1) / period;
+            mCounter64 = numPeriods * period;
+        }
+    }
+
 private:
     int64_t mCounter64 = 0;
     int32_t mCounter32 = 0;
diff --git a/media/libaaudio/tests/Android.mk b/media/libaaudio/tests/Android.mk
index 4402919..37b010d 100644
--- a/media/libaaudio/tests/Android.mk
+++ b/media/libaaudio/tests/Android.mk
@@ -5,16 +5,6 @@
     $(call include-path-for, audio-utils) \
     frameworks/av/media/libaaudio/include \
     frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_handle_tracker.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_handle_tracker
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/src
 LOCAL_SRC_FILES:= test_marshalling.cpp
 LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
 LOCAL_MODULE := test_aaudio_marshalling
diff --git a/media/libaaudio/tests/test_handle_tracker.cpp b/media/libaaudio/tests/test_handle_tracker.cpp
deleted file mode 100644
index c4db47a..0000000
--- a/media/libaaudio/tests/test_handle_tracker.cpp
+++ /dev/null
@@ -1,117 +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.
- */
-
-// Unit tests for AAudio Handle Tracker
-
-#include <stdlib.h>
-#include <math.h>
-
-#include <gtest/gtest.h>
-
-#include <aaudio/AAudio.h>
-#include "utility/HandleTracker.h"
-
-// Test adding one address.
-TEST(test_handle_tracker, aaudio_handle_tracker) {
-    const int MAX_HANDLES = 4;
-    HandleTracker tracker(MAX_HANDLES);
-    handle_tracker_type_t type = 3; // arbitrary generic type
-    int data; // something that has an address we can use
-    handle_tracker_address_t found;
-
-    // repeat the test several times to see if it breaks
-    const int SEVERAL = 5; // arbitrary
-    for (int i = 0; i < SEVERAL; i++) {
-        // should fail to find a bogus handle
-        found = tracker.get(type, 0);  // bad handle
-        EXPECT_EQ(nullptr, found);
-
-        // create a valid handle and use it to lookup the object again
-        aaudio_handle_t dataHandle = tracker.put(type, &data);
-        ASSERT_TRUE(dataHandle > 0);
-        found = tracker.get(type, dataHandle);
-        EXPECT_EQ(&data, found);
-        found = tracker.get(type, 0); // bad handle
-        EXPECT_EQ(nullptr, found);
-
-        // wrong type
-        found = tracker.get(type+1, dataHandle);
-        EXPECT_EQ(nullptr, found);
-
-        // remove from storage
-        found = tracker.remove(type, dataHandle);
-        EXPECT_EQ(&data, found);
-        // should fail the second time
-        found = tracker.remove(type, dataHandle);
-        EXPECT_EQ(nullptr, found);
-    }
-}
-
-// Test filling the tracker.
-TEST(test_handle_tracker, aaudio_full_up) {
-    const int MAX_HANDLES = 5;
-    HandleTracker tracker(MAX_HANDLES);
-    handle_tracker_type_t type = 4; // arbitrary generic type
-    int data[MAX_HANDLES];
-    aaudio_handle_t handles[MAX_HANDLES];
-    handle_tracker_address_t found;
-
-    // repeat the test several times to see if it breaks
-    const int SEVERAL = 5; // arbitrary
-    for (int i = 0; i < SEVERAL; i++) {
-        for (int i = 0; i < MAX_HANDLES; i++) {
-            // add a handle
-            handles[i] = tracker.put(type, &data[i]);
-            ASSERT_TRUE(handles[i] > 0);
-            found = tracker.get(type, handles[i]);
-            EXPECT_EQ(&data[i], found);
-        }
-
-        // Now that it is full, try to add one more.
-        aaudio_handle_t handle = tracker.put(type, &data[0]);
-        EXPECT_TRUE(handle < 0);
-
-        for (int i = 0; i < MAX_HANDLES; i++) {
-            // look up each handle
-            found = tracker.get(type, handles[i]);
-            EXPECT_EQ(&data[i], found);
-        }
-
-        // remove one from storage
-        found = tracker.remove(type, handles[2]);
-        EXPECT_EQ(&data[2], found);
-        // now try to look up the same handle and fail
-        found = tracker.get(type, handles[2]);
-        EXPECT_EQ(nullptr, found);
-
-        // add that same one back
-        handle = tracker.put(type, &data[2]);
-        ASSERT_TRUE(handle > 0);
-        found = tracker.get(type, handle);
-        EXPECT_EQ(&data[2], found);
-        // now use a stale handle again with a valid index and fail
-        found = tracker.get(type, handles[2]);
-        EXPECT_EQ(nullptr, found);
-
-        // remove them all
-        handles[2] = handle;
-        for (int i = 0; i < MAX_HANDLES; i++) {
-            // look up each handle
-            found = tracker.remove(type, handles[i]);
-            EXPECT_EQ(&data[i], found);
-        }
-    }
-}
diff --git a/media/libaaudio/tests/test_timestamps.cpp b/media/libaaudio/tests/test_timestamps.cpp
index d9ca391..fb363e7 100644
--- a/media/libaaudio/tests/test_timestamps.cpp
+++ b/media/libaaudio/tests/test_timestamps.cpp
@@ -17,23 +17,99 @@
 // Play silence and recover from dead servers or disconnected devices.
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 
 #include <aaudio/AAudio.h>
 #include <aaudio/AAudioTesting.h>
-
 #include "utils/AAudioExampleUtils.h"
+#include "../examples/utils/AAudioExampleUtils.h"
 
-#define DEFAULT_TIMEOUT_NANOS  ((int64_t)1000000000)
+// Arbitrary period for glitches, once per second at 48000 Hz.
+#define FORCED_UNDERRUN_PERIOD_FRAMES    48000
+// How long to sleep in a callback to cause an intentional glitch. For testing.
+#define FORCED_UNDERRUN_SLEEP_MICROS     (10 * 1000)
 
-int main(int argc, char **argv) {
-    (void) argc;
-    (void *)argv;
+#define MAX_TIMESTAMPS          1000
 
+#define DEFAULT_TIMEOUT_NANOS   ((int64_t)1000000000)
+
+#define NUM_SECONDS             1
+#define NUM_LOOPS               4
+
+typedef struct TimestampInfo {
+    int64_t         framesTotal;
+    int64_t         appPosition; // frames
+    int64_t         appNanoseconds;
+    int64_t         timestampPosition;  // frames
+    int64_t         timestampNanos;
+    aaudio_result_t result;
+} TimestampInfo;
+
+typedef struct TimestampCallbackData_s {
+    TimestampInfo  timestamps[MAX_TIMESTAMPS];
+    int64_t        framesTotal = 0;
+    int64_t        nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
+    int32_t        timestampCount = 0; // in timestamps
+    bool           forceUnderruns = false;
+} TimestampCallbackData_t;
+
+// Callback function that fills the audio output buffer.
+aaudio_data_callback_result_t timestampDataCallbackProc(
+        AAudioStream *stream,
+        void *userData,
+        void *audioData __unused,
+        int32_t numFrames
+) {
+
+    // should not happen but just in case...
+    if (userData == nullptr) {
+        printf("ERROR - SimplePlayerDataCallbackProc needs userData\n");
+        return AAUDIO_CALLBACK_RESULT_STOP;
+    }
+    TimestampCallbackData_t *timestampData = (TimestampCallbackData_t *) userData;
+
+    aaudio_direction_t direction = AAudioStream_getDirection(stream);
+    if (direction == AAUDIO_DIRECTION_INPUT) {
+        timestampData->framesTotal += numFrames;
+    }
+
+    if (timestampData->forceUnderruns) {
+        if (timestampData->framesTotal > timestampData->nextFrameToGlitch) {
+            usleep(FORCED_UNDERRUN_SLEEP_MICROS);
+            printf("Simulate glitch at %lld\n", (long long) timestampData->framesTotal);
+            timestampData->nextFrameToGlitch += FORCED_UNDERRUN_PERIOD_FRAMES;
+        }
+    }
+
+    if (timestampData->timestampCount < MAX_TIMESTAMPS) {
+        TimestampInfo *timestamp = &timestampData->timestamps[timestampData->timestampCount];
+        timestamp->result = AAudioStream_getTimestamp(stream,
+                                                      CLOCK_MONOTONIC,
+                                                      &timestamp->timestampPosition,
+                                                      &timestamp->timestampNanos);
+        timestamp->framesTotal = timestampData->framesTotal;
+        timestamp->appPosition = (direction == AAUDIO_DIRECTION_OUTPUT)
+                ? AAudioStream_getFramesWritten(stream)
+                : AAudioStream_getFramesRead(stream);
+        timestamp->appNanoseconds = getNanoseconds();
+        timestampData->timestampCount++;
+    }
+
+    if (direction == AAUDIO_DIRECTION_OUTPUT) {
+        timestampData->framesTotal += numFrames;
+    }
+    return AAUDIO_CALLBACK_RESULT_CONTINUE;
+}
+
+static TimestampCallbackData_t sTimestampData;
+
+static aaudio_result_t testTimeStamps(aaudio_policy_t mmapPolicy,
+                           aaudio_sharing_mode_t sharingMode,
+                           aaudio_performance_mode_t performanceMode,
+                           aaudio_direction_t direction) {
     aaudio_result_t result = AAUDIO_OK;
 
-    int32_t triesLeft = 3;
-    int32_t bufferCapacity;
     int32_t framesPerBurst = 0;
     float *buffer = nullptr;
 
@@ -44,22 +120,20 @@
     int32_t finalBufferSize = 0;
     aaudio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_FLOAT;
     aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
-    int32_t framesMax;
-    int64_t framesTotal;
-    int64_t printAt;
-    int samplesPerBurst;
-    int64_t previousFramePosition = -1;
+    aaudio_sharing_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
 
     AAudioStreamBuilder *aaudioBuilder = nullptr;
     AAudioStream *aaudioStream = nullptr;
 
-    // Make printf print immediately so that debug info is not stuck
-    // in a buffer if we hang or crash.
-    setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+    memset(&sTimestampData, 0, sizeof(sTimestampData));
 
-    printf("Test Timestamps V0.1.1\n");
+    printf("------------ testTimeStamps(policy = %d, sharing = %s, perf = %s, dir = %s) -----------\n",
+           mmapPolicy,
+           getSharingModeText(sharingMode),
+           getPerformanceModeText(performanceMode),
+           getDirectionText(direction));
 
-    AAudio_setMMapPolicy(AAUDIO_POLICY_AUTO);
+    AAudio_setMMapPolicy(mmapPolicy);
 
     // Use an AAudioStreamBuilder to contain requested parameters.
     result = AAudio_createStreamBuilder(&aaudioBuilder);
@@ -70,9 +144,11 @@
     }
 
     // Request stream properties.
-    AAudioStreamBuilder_setFormat(aaudioBuilder, AAUDIO_FORMAT_PCM_FLOAT);
-    //AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, AAUDIO_PERFORMANCE_MODE_NONE);
-    AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+    AAudioStreamBuilder_setFormat(aaudioBuilder, AAUDIO_FORMAT_PCM_I16);
+    AAudioStreamBuilder_setSharingMode(aaudioBuilder, sharingMode);
+    AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, performanceMode);
+    AAudioStreamBuilder_setDirection(aaudioBuilder, direction);
+    AAudioStreamBuilder_setDataCallback(aaudioBuilder, timestampDataCallbackProc, &sTimestampData);
 
     // Create an AAudioStream using the Builder.
     result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
@@ -87,10 +163,25 @@
     actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
     actualDataFormat = AAudioStream_getFormat(aaudioStream);
 
-    printf("-------- chans = %3d, rate = %6d format = %d\n",
-            actualChannelCount, actualSampleRate, actualDataFormat);
+    actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
+    if (actualSharingMode != sharingMode) {
+        printf("did not get expected sharingMode, got %3d, skipping test\n",
+               actualSharingMode);
+        result = AAUDIO_OK;
+        goto finish;
+    }
+    actualPerformanceMode = AAudioStream_getPerformanceMode(aaudioStream);
+    if (actualPerformanceMode != performanceMode) {
+        printf("did not get expected performanceMode, got %3d, skipping test\n",
+               actualPerformanceMode);
+        result = AAUDIO_OK;
+        goto finish;
+    }
+
+    printf("    chans = %3d, rate = %6d format = %d\n",
+           actualChannelCount, actualSampleRate, actualDataFormat);
     printf("    Is MMAP used? %s\n", AAudioStream_isMMapUsed(aaudioStream)
-                                   ? "yes" : "no");
+                                     ? "yes" : "no");
 
     // This is the number of frames that are read in one chunk by a DMA controller
     // or a DSP or a mixer.
@@ -98,91 +189,151 @@
     printf("    framesPerBurst = %3d\n", framesPerBurst);
 
     originalBufferSize = AAudioStream_getBufferSizeInFrames(aaudioStream);
-    requestedBufferSize = 2 * framesPerBurst;
+    requestedBufferSize = 4 * framesPerBurst;
     finalBufferSize = AAudioStream_setBufferSizeInFrames(aaudioStream, requestedBufferSize);
 
     printf("    BufferSize: original = %4d, requested = %4d, final = %4d\n",
            originalBufferSize, requestedBufferSize, finalBufferSize);
 
-    samplesPerBurst = framesPerBurst * actualChannelCount;
-    buffer = new float[samplesPerBurst];
-
-    result = AAudioStream_requestStart(aaudioStream);
-    if (result != AAUDIO_OK) {
-        printf("AAudioStream_requestStart returned %s",
+    {
+        int64_t position;
+        int64_t nanoseconds;
+        result = AAudioStream_getTimestamp(aaudioStream, CLOCK_MONOTONIC, &position, &nanoseconds);
+        printf("before start, AAudioStream_getTimestamp() returns %s\n",
                AAudio_convertResultToText(result));
-        goto finish;
     }
 
-    // Play silence very briefly.
-    framesMax = actualSampleRate * 4;
-    framesTotal = 0;
-    printAt = actualSampleRate;
-    while (result == AAUDIO_OK && framesTotal < framesMax) {
-        int32_t framesWritten = AAudioStream_write(aaudioStream,
-                                                   buffer, framesPerBurst,
-                                                   DEFAULT_TIMEOUT_NANOS);
-        if (framesWritten < 0) {
-            result = framesWritten;
-            printf("write() returned %s, frames = %d\n",
-                   AAudio_convertResultToText(result), (int)framesTotal);
-            printf("  frames = %d\n", (int)framesTotal);
-        } else if (framesWritten != framesPerBurst) {
-            printf("write() returned %d, frames = %d\n", framesWritten, (int)framesTotal);
-            result = AAUDIO_ERROR_TIMEOUT;
-        } else {
-            framesTotal += framesWritten;
-            if (framesTotal >= printAt) {
-                printf("frames = %d\n", (int)framesTotal);
-                printAt += actualSampleRate;
+    for (int runs = 0; runs < NUM_LOOPS; runs++) {
+        printf("------------------ loop #%d\n", runs);
+
+        int64_t temp = sTimestampData.framesTotal;
+        memset(&sTimestampData, 0, sizeof(sTimestampData));
+        sTimestampData.framesTotal = temp;
+
+        sTimestampData.forceUnderruns = false;
+
+        result = AAudioStream_requestStart(aaudioStream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_requestStart returned %s",
+                   AAudio_convertResultToText(result));
+            goto finish;
+        }
+
+        for (int second = 0; second < NUM_SECONDS; second++) {
+            // Give AAudio callback time to run in the background.
+            sleep(1);
+
+            // Periodically print the progress so we know it hasn't died.
+            printf("framesWritten = %d, XRuns = %d\n",
+                   (int) AAudioStream_getFramesWritten(aaudioStream),
+                   (int) AAudioStream_getXRunCount(aaudioStream)
+            );
+        }
+
+        result = AAudioStream_requestStop(aaudioStream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_requestStop returned %s\n",
+                   AAudio_convertResultToText(result));
+        }
+
+        printf("timestampCount = %d\n", sTimestampData.timestampCount);
+        int printed = 0;
+        for (int i = 0; i < sTimestampData.timestampCount; i++) {
+            TimestampInfo *timestamp = &sTimestampData.timestamps[i];
+            bool posChanged = (timestamp->timestampPosition != (timestamp - 1)->timestampPosition);
+            bool timeChanged = (timestamp->timestampNanos != (timestamp - 1)->timestampNanos);
+            if ((printed < 20) && ((i < 10) || posChanged || timeChanged)) {
+                printf("  %3d : frames %8lld, xferd %8lld", i,
+                       (long long) timestamp->framesTotal,
+                       (long long) timestamp->appPosition);
+                if (timestamp->result != AAUDIO_OK) {
+                    printf(", result = %s\n", AAudio_convertResultToText(timestamp->result));
+                } else {
+                    bool negative = timestamp->timestampPosition < 0;
+                    bool retro = (i > 0 && (timestamp->timestampPosition <
+                                            (timestamp - 1)->timestampPosition));
+                    const char *message = negative ? " <=NEGATIVE!"
+                                                   : (retro ? "  <= RETROGRADE!" : "");
+
+                    double latency = calculateLatencyMillis(timestamp->timestampPosition,
+                                             timestamp->timestampNanos,
+                                             timestamp->appPosition,
+                                             timestamp->appNanoseconds,
+                                             actualSampleRate);
+                    printf(", STAMP: pos = %8lld, nanos = %8lld, lat = %7.1f msec %s\n",
+                           (long long) timestamp->timestampPosition,
+                           (long long) timestamp->timestampNanos,
+                           latency,
+                           message);
+                }
+                printed++;
             }
         }
 
-        // Print timestamps.
-        int64_t framePosition = 0;
-        int64_t frameTime = 0;
-        aaudio_result_t timeResult;
-        timeResult = AAudioStream_getTimestamp(aaudioStream, CLOCK_MONOTONIC,
-                                           &framePosition, &frameTime);
-
-        if (timeResult == AAUDIO_OK) {
-            if (framePosition > (previousFramePosition + 5000)) {
-                int64_t realTime = getNanoseconds();
-                int64_t framesWritten = AAudioStream_getFramesWritten(aaudioStream);
-
-                double latencyMillis = calculateLatencyMillis(framePosition, frameTime,
-                                                              framesWritten, realTime,
-                                                              actualSampleRate);
-
-                printf("--- timestamp: result = %4d, position = %lld, at %lld nanos"
-                               ", latency = %7.2f msec\n",
-                       timeResult,
-                       (long long) framePosition,
-                       (long long) frameTime,
-                       latencyMillis);
-                previousFramePosition = framePosition;
-            }
-        }
+        // Avoid race conditions in AudioFlinger.
+        // There is normally a delay between a real user stopping and restarting a stream.
+        sleep(1);
     }
 
-    result = AAudioStream_requestStop(aaudioStream);
-    if (result != AAUDIO_OK) {
-        printf("AAudioStream_requestStop returned %s\n",
-               AAudio_convertResultToText(result));
-    }
-    result = AAudioStream_close(aaudioStream);
-    if (result != AAUDIO_OK) {
-        printf("AAudioStream_close returned %s\n",
-               AAudio_convertResultToText(result));
-    }
-    aaudioStream = nullptr;
-
-
 finish:
     if (aaudioStream != nullptr) {
         AAudioStream_close(aaudioStream);
     }
     AAudioStreamBuilder_delete(aaudioBuilder);
-    delete[] buffer;
     printf("result = %d = %s\n", result, AAudio_convertResultToText(result));
+
+    return result;
+}
+
+int main(int argc, char **argv) {
+    (void) argc;
+    (void *) argv;
+
+    aaudio_result_t result = AAUDIO_OK;
+
+    // Make printf print immediately so that debug info is not stuck
+    // in a buffer if we hang or crash.
+    setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+
+    printf("Test Timestamps V0.1.3\n");
+
+    // Legacy
+    aaudio_policy_t policy = AAUDIO_POLICY_NEVER;
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_SHARED,
+                            AAUDIO_PERFORMANCE_MODE_NONE,
+                            AAUDIO_DIRECTION_INPUT);
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_SHARED,
+                            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+                            AAUDIO_DIRECTION_INPUT);
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_SHARED,
+                            AAUDIO_PERFORMANCE_MODE_NONE,
+                            AAUDIO_DIRECTION_OUTPUT);
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_SHARED,
+                            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+                            AAUDIO_DIRECTION_OUTPUT);
+
+    // MMAP
+    policy = AAUDIO_POLICY_ALWAYS;
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_EXCLUSIVE,
+                            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+                            AAUDIO_DIRECTION_INPUT);
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_EXCLUSIVE,
+                            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+                            AAUDIO_DIRECTION_OUTPUT);
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_SHARED,
+                            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+                            AAUDIO_DIRECTION_INPUT);
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_SHARED,
+                            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+                            AAUDIO_DIRECTION_OUTPUT);
+
+    return (result == AAUDIO_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 611cde7..ba4acc6 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -120,7 +120,7 @@
         }
         // No lock here: worst case we remove a NULL callback which will be a nop
         if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
-            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+            AudioSystem::removeAudioDeviceCallback(this, mInput);
         }
         IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
         mAudioRecord.clear();
@@ -274,7 +274,7 @@
     mStatus = NO_ERROR;
     mUserData = user;
     // TODO: add audio hardware input latency here
-    mLatency = (1000 * mFrameCount) / mSampleRate;
+    mLatency = (1000LL * mFrameCount) / mSampleRate;
     mMarkerPosition = 0;
     mMarkerReached = false;
     mNewPosition = 0;
@@ -499,19 +499,26 @@
     return mSelectedDeviceId;
 }
 
+// must be called with mLock held
+void AudioRecord::updateRoutedDeviceId_l()
+{
+    // if the record is inactive, do not update actual device as the input stream maybe routed
+    // from a device not relevant to this client because of other active use cases.
+    if (!mActive) {
+        return;
+    }
+    if (mInput != AUDIO_IO_HANDLE_NONE) {
+        audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput);
+        if (deviceId != AUDIO_PORT_HANDLE_NONE) {
+            mRoutedDeviceId = deviceId;
+        }
+     }
+}
+
 audio_port_handle_t AudioRecord::getRoutedDeviceId() {
     AutoMutex lock(mLock);
-    if (mInput == AUDIO_IO_HANDLE_NONE) {
-        return AUDIO_PORT_HANDLE_NONE;
-    }
-    // if the input stream does not have an active audio patch, use either the device initially
-    // selected by audio policy manager or the last routed device
-    audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput);
-    if (deviceId == AUDIO_PORT_HANDLE_NONE) {
-        deviceId = mRoutedDeviceId;
-    }
-    mRoutedDeviceId = deviceId;
-    return deviceId;
+    updateRoutedDeviceId_l();
+    return mRoutedDeviceId;
 }
 
 // -------------------------------------------------------------------------
@@ -537,9 +544,6 @@
         return NO_INIT;
     }
 
-    if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
-        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
-    }
     audio_io_handle_t input;
 
     // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
@@ -744,6 +748,15 @@
     }
     mNotificationFramesAct = (uint32_t) notificationFrames;
 
+
+    //mInput != input includes the case where mInput == AUDIO_IO_HANDLE_NONE for first creation
+    if (mDeviceCallback != 0 && mInput != input) {
+        if (mInput != AUDIO_IO_HANDLE_NONE) {
+            AudioSystem::removeAudioDeviceCallback(this, mInput);
+        }
+        AudioSystem::addAudioDeviceCallback(this, input);
+    }
+
     // We retain a copy of the I/O handle, but don't own the reference
     mInput = input;
     mRefreshRemaining = true;
@@ -763,10 +776,6 @@
     mDeathNotifier = new DeathNotifier(this);
     IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
 
-    if (mDeviceCallback != 0) {
-        AudioSystem::addAudioDeviceCallback(mDeviceCallback, mInput);
-    }
-
     return NO_ERROR;
 
     // End of retry loop.
@@ -1238,7 +1247,7 @@
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
-    if (mDeviceCallback == callback) {
+    if (mDeviceCallback.unsafe_get() == callback.get()) {
         ALOGW("%s adding same callback!", __FUNCTION__);
         return INVALID_OPERATION;
     }
@@ -1246,9 +1255,9 @@
     if (mInput != AUDIO_IO_HANDLE_NONE) {
         if (mDeviceCallback != 0) {
             ALOGW("%s callback already present!", __FUNCTION__);
-            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+            AudioSystem::removeAudioDeviceCallback(this, mInput);
         }
-        status = AudioSystem::addAudioDeviceCallback(callback, mInput);
+        status = AudioSystem::addAudioDeviceCallback(this, mInput);
     }
     mDeviceCallback = callback;
     return status;
@@ -1262,17 +1271,38 @@
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
-    if (mDeviceCallback != callback) {
+    if (mDeviceCallback.unsafe_get() != callback.get()) {
         ALOGW("%s removing different callback!", __FUNCTION__);
         return INVALID_OPERATION;
     }
+    mDeviceCallback.clear();
     if (mInput != AUDIO_IO_HANDLE_NONE) {
-        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+        AudioSystem::removeAudioDeviceCallback(this, mInput);
     }
-    mDeviceCallback = 0;
     return NO_ERROR;
 }
 
+void AudioRecord::onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                 audio_port_handle_t deviceId)
+{
+    sp<AudioSystem::AudioDeviceCallback> callback;
+    {
+        AutoMutex lock(mLock);
+        if (audioIo != mInput) {
+            return;
+        }
+        callback = mDeviceCallback.promote();
+        // only update device if the record is active as route changes due to other use cases are
+        // irrelevant for this client
+        if (mActive) {
+            mRoutedDeviceId = deviceId;
+        }
+    }
+    if (callback.get() != nullptr) {
+        callback->onAudioDeviceUpdate(mInput, mRoutedDeviceId);
+    }
+}
+
 // =========================================================================
 
 void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 211bd7d..cdc75ac 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -493,14 +493,16 @@
     if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return;
 
     audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
-    Vector < sp<AudioDeviceCallback> > callbacks;
+    Vector < wp<AudioDeviceCallback> > callbacks;
 
     {
         Mutex::Autolock _l(mLock);
 
         switch (event) {
         case AUDIO_OUTPUT_OPENED:
-        case AUDIO_INPUT_OPENED: {
+        case AUDIO_OUTPUT_REGISTERED:
+        case AUDIO_INPUT_OPENED:
+        case AUDIO_INPUT_REGISTERED: {
             sp<AudioIoDescriptor> oldDesc = getIoDescriptor_l(ioDesc->mIoHandle);
             if (oldDesc == 0) {
                 mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
@@ -511,13 +513,19 @@
 
             if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
                 deviceId = ioDesc->getDeviceId();
-                ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
-                if (ioIndex >= 0) {
-                    callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+                if (event == AUDIO_OUTPUT_OPENED || event == AUDIO_INPUT_OPENED) {
+                    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
+                    if (ioIndex >= 0) {
+                        callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+                    }
                 }
             }
-            ALOGV("ioConfigChanged() new %s opened %d samplingRate %u, format %#x channel mask %#x "
-                    "frameCount %zu deviceId %d", event == AUDIO_OUTPUT_OPENED ? "output" : "input",
+            ALOGV("ioConfigChanged() new %s %s %d samplingRate %u, format %#x channel mask %#x "
+                    "frameCount %zu deviceId %d",
+                    event == AUDIO_OUTPUT_OPENED || event == AUDIO_OUTPUT_REGISTERED ?
+                            "output" : "input",
+                            event == AUDIO_OUTPUT_OPENED || event == AUDIO_INPUT_OPENED ?
+                            "opened" : "registered",
                     ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask,
                     ioDesc->mFrameCount, ioDesc->getDeviceId());
             } break;
@@ -563,9 +571,23 @@
         } break;
         }
     }
+    bool callbackRemoved = false;
     // callbacks.size() != 0 =>  ioDesc->mIoHandle and deviceId are valid
-    for (size_t i = 0; i < callbacks.size(); i++) {
-        callbacks[i]->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
+    for (size_t i = 0; i < callbacks.size(); ) {
+        sp<AudioDeviceCallback> callback = callbacks[i].promote();
+        if (callback.get() != nullptr) {
+            callback->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
+            i++;
+        } else {
+            callbacks.removeAt(i);
+            callbackRemoved = true;
+        }
+    }
+    // clean up callback list while we are here if some clients have disappeared without
+    // unregistering their callback
+    if (callbackRemoved) {
+        Mutex::Autolock _l(mLock);
+        mAudioDeviceCallbacks.replaceValueFor(ioDesc->mIoHandle, callbacks);
     }
 }
 
@@ -618,17 +640,17 @@
 }
 
 status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
-        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
     Mutex::Autolock _l(mLock);
-    Vector < sp<AudioDeviceCallback> > callbacks;
+    Vector < wp<AudioDeviceCallback> > callbacks;
     ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
     if (ioIndex >= 0) {
         callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
     }
 
     for (size_t cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
-        if (callbacks[cbIndex] == callback) {
+        if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
             return INVALID_OPERATION;
         }
     }
@@ -639,18 +661,18 @@
 }
 
 status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback(
-        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
     Mutex::Autolock _l(mLock);
     ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
     if (ioIndex < 0) {
         return INVALID_OPERATION;
     }
-    Vector < sp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+    Vector < wp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
 
     size_t cbIndex;
     for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
-        if (callbacks[cbIndex] == callback) {
+        if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
             break;
         }
     }
@@ -1128,7 +1150,7 @@
 }
 
 status_t AudioSystem::addAudioDeviceCallback(
-        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
     const sp<AudioFlingerClient> afc = getAudioFlingerClient();
     if (afc == 0) {
@@ -1145,7 +1167,7 @@
 }
 
 status_t AudioSystem::removeAudioDeviceCallback(
-        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
     const sp<AudioFlingerClient> afc = getAudioFlingerClient();
     if (afc == 0) {
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index c212112..3529d2c 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -276,7 +276,7 @@
         }
         // No lock here: worst case we remove a NULL callback which will be a nop
         if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
-            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+            AudioSystem::removeAudioDeviceCallback(this, mOutput);
         }
         IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
         mAudioTrack.clear();
@@ -615,7 +615,8 @@
                             + mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER]),
                     (long long)mStartEts.mFlushed,
                     (long long)mFramesWritten);
-            mFramesWrittenServerOffset = -mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER];
+            // mStartEts is already adjusted by mFramesWrittenServerOffset, so we delta adjust.
+            mFramesWrittenServerOffset -= mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER];
         }
         mFramesWritten = 0;
         mProxy->clearTimestamp(); // need new server push for valid timestamp
@@ -1228,19 +1229,26 @@
     return mSelectedDeviceId;
 }
 
+// must be called with mLock held
+void AudioTrack::updateRoutedDeviceId_l()
+{
+    // if the track is inactive, do not update actual device as the output stream maybe routed
+    // to a device not relevant to this client because of other active use cases.
+    if (mState != STATE_ACTIVE) {
+        return;
+    }
+    if (mOutput != AUDIO_IO_HANDLE_NONE) {
+        audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput);
+        if (deviceId != AUDIO_PORT_HANDLE_NONE) {
+            mRoutedDeviceId = deviceId;
+        }
+    }
+}
+
 audio_port_handle_t AudioTrack::getRoutedDeviceId() {
     AutoMutex lock(mLock);
-    if (mOutput == AUDIO_IO_HANDLE_NONE) {
-        return AUDIO_PORT_HANDLE_NONE;
-    }
-    // if the output stream does not have an active audio patch, use either the device initially
-    // selected by audio policy manager or the last routed device
-    audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput);
-    if (deviceId == AUDIO_PORT_HANDLE_NONE) {
-        deviceId = mRoutedDeviceId;
-    }
-    mRoutedDeviceId = deviceId;
-    return deviceId;
+    updateRoutedDeviceId_l();
+    return mRoutedDeviceId;
 }
 
 status_t AudioTrack::attachAuxEffect(int effectId)
@@ -1278,7 +1286,7 @@
         ALOGW("getLatency(%d) failed status %d", mOutput, status);
     } else {
         // FIXME don't believe this lie
-        mLatency = mAfLatency + (1000 * mFrameCount) / mSampleRate;
+        mLatency = mAfLatency + (1000LL * mFrameCount) / mSampleRate;
     }
 }
 
@@ -1304,12 +1312,10 @@
         return NO_INIT;
     }
 
-    if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
-        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
-    }
     audio_io_handle_t output;
     audio_stream_type_t streamType = mStreamType;
     audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL;
+    bool callbackAdded = false;
 
     // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
     // After fast request is denied, we will request again if IAudioTrack is re-created.
@@ -1514,12 +1520,14 @@
     sp<IMemory> iMem = track->getCblk();
     if (iMem == 0) {
         ALOGE("Could not get control block");
-        return NO_INIT;
+        status = NO_INIT;
+        goto release;
     }
     void *iMemPointer = iMem->pointer();
     if (iMemPointer == NULL) {
         ALOGE("Could not get control block pointer");
-        return NO_INIT;
+        status = NO_INIT;
+        goto release;
     }
     // invariant that mAudioTrack != 0 is true only after set() returns successfully
     if (mAudioTrack != 0) {
@@ -1581,6 +1589,15 @@
         }
     }
 
+    //mOutput != output includes the case where mOutput == AUDIO_IO_HANDLE_NONE for first creation
+    if (mDeviceCallback != 0 && mOutput != output) {
+        if (mOutput != AUDIO_IO_HANDLE_NONE) {
+            AudioSystem::removeAudioDeviceCallback(this, mOutput);
+        }
+        AudioSystem::addAudioDeviceCallback(this, output);
+        callbackAdded = true;
+    }
+
     // We retain a copy of the I/O handle, but don't own the reference
     mOutput = output;
     mRefreshRemaining = true;
@@ -1596,7 +1613,8 @@
         buffers = mSharedBuffer->pointer();
         if (buffers == NULL) {
             ALOGE("Could not get buffer pointer");
-            return NO_INIT;
+            status = NO_INIT;
+            goto release;
         }
     }
 
@@ -1641,15 +1659,15 @@
     mDeathNotifier = new DeathNotifier(this);
     IInterface::asBinder(mAudioTrack)->linkToDeath(mDeathNotifier, this);
 
-    if (mDeviceCallback != 0) {
-        AudioSystem::addAudioDeviceCallback(mDeviceCallback, mOutput);
-    }
-
     return NO_ERROR;
     }
 
 release:
     AudioSystem::releaseOutput(output, streamType, mSessionId);
+    if (callbackAdded) {
+        // note: mOutput is always valid is callbackAdded is true
+        AudioSystem::removeAudioDeviceCallback(this, mOutput);
+    }
     if (status == NO_ERROR) {
         status = NO_INIT;
     }
@@ -2096,7 +2114,14 @@
     // Convert frame units to time units
     nsecs_t ns = NS_WHENEVER;
     if (minFrames != (uint32_t) ~0) {
-        ns = framesToNanoseconds(minFrames, sampleRate, speed) + kWaitPeriodNs;
+        // AudioFlinger consumption of client data may be irregular when coming out of device
+        // standby since the kernel buffers require filling. This is throttled to no more than 2x
+        // the expected rate in the MixerThread. Hence, we reduce the estimated time to wait by one
+        // half (but no more than half a second) to improve callback accuracy during these temporary
+        // data surges.
+        const nsecs_t estimatedNs = framesToNanoseconds(minFrames, sampleRate, speed);
+        constexpr nsecs_t maxThrottleCompensationNs = 500000000LL;
+        ns = estimatedNs - min(estimatedNs / 2, maxThrottleCompensationNs) + kWaitPeriodNs;
         ns -= (timeAfterCallbacks - timeBeforeCallbacks);  // account for callback time
         // TODO: Should we warn if the callback time is too long?
         if (ns < 0) ns = 0;
@@ -2843,7 +2868,7 @@
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
-    if (mDeviceCallback == callback) {
+    if (mDeviceCallback.unsafe_get() == callback.get()) {
         ALOGW("%s adding same callback!", __FUNCTION__);
         return INVALID_OPERATION;
     }
@@ -2851,9 +2876,9 @@
     if (mOutput != AUDIO_IO_HANDLE_NONE) {
         if (mDeviceCallback != 0) {
             ALOGW("%s callback already present!", __FUNCTION__);
-            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+            AudioSystem::removeAudioDeviceCallback(this, mOutput);
         }
-        status = AudioSystem::addAudioDeviceCallback(callback, mOutput);
+        status = AudioSystem::addAudioDeviceCallback(this, mOutput);
     }
     mDeviceCallback = callback;
     return status;
@@ -2867,17 +2892,39 @@
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
-    if (mDeviceCallback != callback) {
+    if (mDeviceCallback.unsafe_get() != callback.get()) {
         ALOGW("%s removing different callback!", __FUNCTION__);
         return INVALID_OPERATION;
     }
+    mDeviceCallback.clear();
     if (mOutput != AUDIO_IO_HANDLE_NONE) {
-        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+        AudioSystem::removeAudioDeviceCallback(this, mOutput);
     }
-    mDeviceCallback = 0;
     return NO_ERROR;
 }
 
+
+void AudioTrack::onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                 audio_port_handle_t deviceId)
+{
+    sp<AudioSystem::AudioDeviceCallback> callback;
+    {
+        AutoMutex lock(mLock);
+        if (audioIo != mOutput) {
+            return;
+        }
+        callback = mDeviceCallback.promote();
+        // only update device if the track is active as route changes due to other use cases are
+        // irrelevant for this client
+        if (mState == STATE_ACTIVE) {
+            mRoutedDeviceId = deviceId;
+        }
+    }
+    if (callback.get() != nullptr) {
+        callback->onAudioDeviceUpdate(mOutput, mRoutedDeviceId);
+    }
+}
+
 status_t AudioTrack::pendingDuration(int32_t *msec, ExtendedTimestamp::Location location)
 {
     if (msec == nullptr ||
diff --git a/media/libaudioclient/include/media/AudioIoDescriptor.h b/media/libaudioclient/include/media/AudioIoDescriptor.h
index fed86c9..859f1a9 100644
--- a/media/libaudioclient/include/media/AudioIoDescriptor.h
+++ b/media/libaudioclient/include/media/AudioIoDescriptor.h
@@ -20,9 +20,11 @@
 namespace android {
 
 enum audio_io_config_event {
+    AUDIO_OUTPUT_REGISTERED,
     AUDIO_OUTPUT_OPENED,
     AUDIO_OUTPUT_CLOSED,
     AUDIO_OUTPUT_CONFIG_CHANGED,
+    AUDIO_INPUT_REGISTERED,
     AUDIO_INPUT_OPENED,
     AUDIO_INPUT_CLOSED,
     AUDIO_INPUT_CONFIG_CHANGED,
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index e6a5efb..dd72170 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -33,7 +33,7 @@
 
 // ----------------------------------------------------------------------------
 
-class AudioRecord : public RefBase
+class AudioRecord : public AudioSystem::AudioDeviceCallback
 {
 public:
 
@@ -424,7 +424,12 @@
 
      /* Returns the ID of the audio device actually used by the input to which this AudioRecord
       * is attached.
-      * A value of AUDIO_PORT_HANDLE_NONE indicates the AudioRecord is not attached to any input.
+      * The device ID is relevant only if the AudioRecord is active.
+      * When the AudioRecord is inactive, the device ID returned can be either:
+      * - AUDIO_PORT_HANDLE_NONE if the AudioRecord is not attached to any output.
+      * - The device ID used before paused or stopped.
+      * - The device ID selected by audio policy manager of setOutputDevice() if the AudioRecord
+      * has not been started yet.
       *
       * Parameters:
       *  none.
@@ -454,6 +459,10 @@
             status_t removeAudioDeviceCallback(
                     const sp<AudioSystem::AudioDeviceCallback>& callback);
 
+            // AudioSystem::AudioDeviceCallback> virtuals
+            virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                             audio_port_handle_t deviceId);
+
 private:
     /* If nonContig is non-NULL, it is an output parameter that will be set to the number of
      * additional non-contiguous frames that are predicted to be available immediately,
@@ -561,6 +570,8 @@
             // FIXME enum is faster than strcmp() for parameter 'from'
             status_t restoreRecord_l(const char *from);
 
+            void     updateRoutedDeviceId_l();
+
     sp<AudioRecordThread>   mAudioRecordThread;
     mutable Mutex           mLock;
 
@@ -665,7 +676,7 @@
     audio_port_handle_t     mRoutedDeviceId;   // Device actually selected by audio policy manager:
                                               // May not match the app selection depending on other
                                               // activity and connected devices
-    sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
+    wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
     audio_port_handle_t    mPortId;  // unique ID allocated by audio policy
 
 };
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 4d5b317..5a81d83 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -370,9 +370,9 @@
                                          audio_port_handle_t deviceId) = 0;
     };
 
-    static status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+    static status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
                                            audio_io_handle_t audioIo);
-    static status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+    static status_t removeAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
                                               audio_io_handle_t audioIo);
 
     static audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo);
@@ -403,9 +403,9 @@
                                      const sp<AudioIoDescriptor>& ioDesc);
 
 
-        status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+        status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
                                                audio_io_handle_t audioIo);
-        status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+        status_t removeAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
                                            audio_io_handle_t audioIo);
 
         audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo);
@@ -413,7 +413,7 @@
     private:
         Mutex                               mLock;
         DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> >   mIoDescriptors;
-        DefaultKeyedVector<audio_io_handle_t, Vector < sp<AudioDeviceCallback> > >
+        DefaultKeyedVector<audio_io_handle_t, Vector < wp<AudioDeviceCallback> > >
                                                                         mAudioDeviceCallbacks;
         // cached values for recording getInputBufferSize() queries
         size_t                              mInBuffSize;    // zero indicates cache is invalid
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 7ae8ec5..47d87e9 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -35,7 +35,7 @@
 
 // ----------------------------------------------------------------------------
 
-class AudioTrack : public RefBase
+class AudioTrack : public AudioSystem::AudioDeviceCallback
 {
 public:
 
@@ -605,7 +605,11 @@
 
      /* Returns the ID of the audio device actually used by the output to which this AudioTrack is
       * attached.
-      * A value of AUDIO_PORT_HANDLE_NONE indicates the audio track is not attached to any output.
+      * When the AudioTrack is inactive, the device ID returned can be either:
+      * - AUDIO_PORT_HANDLE_NONE if the AudioTrack is not attached to any output.
+      * - The device ID used before paused or stopped.
+      * - The device ID selected by audio policy manager of setOutputDevice() if the AudioTrack
+      * has not been started yet.
       *
       * Parameters:
       *  none.
@@ -845,6 +849,12 @@
             status_t removeAudioDeviceCallback(
                     const sp<AudioSystem::AudioDeviceCallback>& callback);
 
+            // AudioSystem::AudioDeviceCallback> virtuals
+            virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                             audio_port_handle_t deviceId);
+
+
+
     /* Obtain the pending duration in milliseconds for playback of pure PCM
      * (mixable without embedded timing) data remaining in AudioTrack.
      *
@@ -974,6 +984,8 @@
 
             void     restartIfDisabled();
 
+            void     updateRoutedDeviceId_l();
+
     // Next 4 fields may be changed if IAudioTrack is re-created, but always != 0
     sp<IAudioTrack>         mAudioTrack;
     sp<IMemory>             mCblkMemory;
@@ -1165,7 +1177,7 @@
     uid_t                   mClientUid;
     pid_t                   mClientPid;
 
-    sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
+    wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
     audio_port_handle_t     mPortId;  // unique ID allocated by audio policy
 };
 
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 4f1fed5..aae80b6 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -35,6 +35,15 @@
 // effect_handle_t interface implementation for bass boost
 extern "C" const struct effect_interface_s gLvmEffectInterface;
 
+// Turn on VERY_VERY_VERBOSE_LOGGING to log parameter get and set for effects.
+
+//#define VERY_VERY_VERBOSE_LOGGING
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while (false)
+#endif
+
 #define LVM_ERROR_CHECK(LvmStatus, callingFunc, calledFunc){\
         if ((LvmStatus) == LVM_NULLADDRESS){\
             ALOGV("\tLVM_ERROR : Parameter error - "\
@@ -140,26 +149,43 @@
 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, void *pParam, void *pValue);
+int  BassBoost_setParameter    (EffectContext *pContext,
+                                uint32_t       paramSize,
+                                void          *pParam,
+                                uint32_t       valueSize,
+                                void          *pValue);
 int  BassBoost_getParameter    (EffectContext *pContext,
-                               void           *pParam,
-                               uint32_t       *pValueSize,
-                               void           *pValue);
-int  Virtualizer_setParameter  (EffectContext *pContext, void *pParam, void *pValue);
-int  Virtualizer_getParameter  (EffectContext *pContext,
-                               void           *pParam,
-                               uint32_t       *pValueSize,
-                               void           *pValue);
-int  Equalizer_setParameter    (EffectContext *pContext,
-                               void *pParam,
-                               uint32_t valueSize,
-                               void *pValue);
-int  Equalizer_getParameter    (EffectContext *pContext,
+                                uint32_t       paramSize,
                                 void          *pParam,
                                 uint32_t      *pValueSize,
                                 void          *pValue);
-int  Volume_setParameter       (EffectContext *pContext, void *pParam, void *pValue);
+int  Virtualizer_setParameter  (EffectContext *pContext,
+                                uint32_t       paramSize,
+                                void          *pParam,
+                                uint32_t       valueSize,
+                                void          *pValue);
+int  Virtualizer_getParameter  (EffectContext *pContext,
+                                uint32_t       paramSize,
+                                void          *pParam,
+                                uint32_t      *pValueSize,
+                                void          *pValue);
+int  Equalizer_setParameter    (EffectContext *pContext,
+                                uint32_t       paramSize,
+                                void          *pParam,
+                                uint32_t       valueSize,
+                                void          *pValue);
+int  Equalizer_getParameter    (EffectContext *pContext,
+                                uint32_t       paramSize,
+                                void          *pParam,
+                                uint32_t      *pValueSize,
+                                void          *pValue);
+int  Volume_setParameter       (EffectContext *pContext,
+                                uint32_t       paramSize,
+                                void          *pParam,
+                                uint32_t       valueSize,
+                                void          *pValue);
 int  Volume_getParameter       (EffectContext *pContext,
+                                uint32_t       paramSize,
                                 void          *pParam,
                                 uint32_t      *pValueSize,
                                 void          *pValue);
@@ -985,8 +1011,12 @@
     float energyBassBoost = 0;
     float crossCorrection = 0;
 
+    bool eqEnabled = pContext->pBundledContext->bEqualizerEnabled == LVM_TRUE;
+    bool bbEnabled = pContext->pBundledContext->bBassEnabled == LVM_TRUE;
+    bool viEnabled = pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE;
+
     //EQ contribution
-    if (pContext->pBundledContext->bEqualizerEnabled == LVM_TRUE) {
+    if (eqEnabled) {
         for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
             float bandFactor = pContext->pBundledContext->bandGaindB[i]/15.0;
             float bandCoefficient = LimitLevel_bandEnergyCoefficient[i];
@@ -1012,35 +1042,37 @@
         }
         bandFactorSum -= 1.0;
         if (bandFactorSum > 0)
-            crossCorrection = bandFactorSum * 0.7;
+          crossCorrection = bandFactorSum * 0.7;
     }
 
     //BassBoost contribution
-    if (pContext->pBundledContext->bBassEnabled == LVM_TRUE) {
+    if (bbEnabled) {
         float boostFactor = (pContext->pBundledContext->BassStrengthSaved)/1000.0;
         float boostCoefficient = LimitLevel_bassBoostEnergyCoefficient;
 
         energyContribution += boostFactor * boostCoefficient * boostCoefficient;
 
-        for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
-            float bandFactor = pContext->pBundledContext->bandGaindB[i]/15.0;
-            float bandCrossCoefficient = LimitLevel_bassBoostEnergyCrossCoefficient[i];
-            float bandEnergy = boostFactor * bandFactor *
+        if (eqEnabled) {
+            for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
+                float bandFactor = pContext->pBundledContext->bandGaindB[i]/15.0;
+                float bandCrossCoefficient = LimitLevel_bassBoostEnergyCrossCoefficient[i];
+                float bandEnergy = boostFactor * bandFactor *
                     bandCrossCoefficient;
-            if (bandEnergy > 0)
-                energyBassBoost += bandEnergy;
+                if (bandEnergy > 0)
+                  energyBassBoost += bandEnergy;
+            }
         }
     }
 
     //Virtualizer contribution
-    if (pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE) {
+    if (viEnabled) {
         energyContribution += LimitLevel_virtualizerContribution *
                 LimitLevel_virtualizerContribution;
     }
 
     double totalEnergyEstimation = sqrt(energyContribution + energyCross + energyBassBoost) -
             crossCorrection;
-    ALOGV(" TOTAL energy estimation: %0.2f", totalEnergyEstimation);
+    ALOGV(" TOTAL energy estimation: %0.2f dB", totalEnergyEstimation);
 
     //roundoff
     int maxLevelRound = (int)(totalEnergyEstimation + 0.99);
@@ -1058,6 +1090,8 @@
     /* Activate the initial settings */
     LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams);
     LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "LvmEffect_limitLevel")
+
+    ALOGV("LVM_SetControlParameters return:%d", (int)LvmStatus);
     //ALOGV("\tLvmEffect_limitLevel just Set -> %d\n",
     //          ActiveParams.pEQNB_BandDefinition[band].Gain);
 
@@ -1308,6 +1342,8 @@
         ALOGV("\tEffect_setConfig Succesfully called LVM_SetControlParameters\n");
         pContext->pBundledContext->SampleRate = SampleRate;
 
+        LvmEffect_limitLevel(pContext);
+
     }else{
         //ALOGV("\tEffect_setConfig keep sampling rate at %d", SampleRate);
     }
@@ -2165,59 +2201,54 @@
 //
 //----------------------------------------------------------------------------
 
-int BassBoost_getParameter(EffectContext     *pContext,
-                           void              *pParam,
-                           uint32_t          *pValueSize,
-                           void              *pValue){
+int BassBoost_getParameter(EffectContext *pContext,
+                           uint32_t       paramSize,
+                           void          *pParam,
+                           uint32_t      *pValueSize,
+                           void          *pValue) {
     int status = 0;
-    int32_t *pParamTemp = (int32_t *)pParam;
-    int32_t param = *pParamTemp++;
+    int32_t *params = (int32_t *)pParam;
 
-    //ALOGV("\tBassBoost_getParameter start");
+    ALOGVV("%s start", __func__);
 
-    switch (param){
-        case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
-            if (*pValueSize != sizeof(uint32_t)){
-                ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid pValueSize1 %d", *pValueSize);
-                return -EINVAL;
-            }
-            *pValueSize = sizeof(uint32_t);
-            break;
-        case BASSBOOST_PARAM_STRENGTH:
-            if (*pValueSize != sizeof(int16_t)){
-                ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid pValueSize2 %d", *pValueSize);
-                return -EINVAL;
-            }
-            *pValueSize = sizeof(int16_t);
-            break;
-
-        default:
-            ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid param %d", param);
-            return -EINVAL;
+    if (paramSize < sizeof(int32_t)) {
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
     }
-
-    switch (param){
+    switch (params[0]) {
         case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
-            *(uint32_t *)pValue = 1;
+            if (*pValueSize != sizeof(uint32_t)) {  // legacy: check equality here.
+                ALOGV("%s BASSBOOST_PARAM_STRENGTH_SUPPORTED invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            // no need to set *pValueSize
 
-            //ALOGV("\tBassBoost_getParameter() BASSBOOST_PARAM_STRENGTH_SUPPORTED Value is %d",
-            //        *(uint32_t *)pValue);
+            *(uint32_t *)pValue = 1;
+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH_SUPPORTED %u", __func__, *(uint32_t *)pValue);
             break;
 
         case BASSBOOST_PARAM_STRENGTH:
-            *(int16_t *)pValue = BassGetStrength(pContext);
+            if (*pValueSize != sizeof(int16_t)) {  // legacy: check equality here.
+                ALOGV("%s BASSBOOST_PARAM_STRENGTH invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            // no need to set *pValueSize
 
-            //ALOGV("\tBassBoost_getParameter() BASSBOOST_PARAM_STRENGTH Value is %d",
-            //        *(int16_t *)pValue);
+            *(int16_t *)pValue = BassGetStrength(pContext);
+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH %d", __func__, *(int16_t *)pValue);
             break;
 
         default:
-            ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid param %d", param);
+            ALOGV("%s invalid param %d", __func__, params[0]);
             status = -EINVAL;
             break;
     }
 
-    //ALOGV("\tBassBoost_getParameter end");
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end BassBoost_getParameter */
 
@@ -2236,27 +2267,42 @@
 //
 //----------------------------------------------------------------------------
 
-int BassBoost_setParameter (EffectContext *pContext, void *pParam, void *pValue){
+int BassBoost_setParameter(EffectContext *pContext,
+                           uint32_t       paramSize,
+                           void          *pParam,
+                           uint32_t       valueSize,
+                           void          *pValue) {
     int status = 0;
-    int16_t strength;
-    int32_t *pParamTemp = (int32_t *)pParam;
+    int32_t *params = (int32_t *)pParam;
 
-    //ALOGV("\tBassBoost_setParameter start");
+    ALOGVV("%s start", __func__);
 
-    switch (*pParamTemp){
-        case BASSBOOST_PARAM_STRENGTH:
-            strength = *(int16_t *)pValue;
-            //ALOGV("\tBassBoost_setParameter() BASSBOOST_PARAM_STRENGTH value is %d", strength);
-            //ALOGV("\tBassBoost_setParameter() Calling pBassBoost->BassSetStrength");
+    if (paramSize != sizeof(int32_t)) {  // legacy: check equality here.
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
+    }
+    switch (params[0]) {
+        case BASSBOOST_PARAM_STRENGTH: {
+            if (valueSize < sizeof(int16_t)) {
+                ALOGV("%s BASSBOOST_PARAM_STRENGTH invalid valueSize: %u", __func__, valueSize);
+                status = -EINVAL;
+                break;
+            }
+
+            const int16_t strength = *(int16_t *)pValue;
+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH %d", __func__, strength);
+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH Calling BassSetStrength", __func__);
             BassSetStrength(pContext, (int32_t)strength);
-            //ALOGV("\tBassBoost_setParameter() Called pBassBoost->BassSetStrength");
-           break;
+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH Called BassSetStrength", __func__);
+        } break;
+
         default:
-            ALOGV("\tLVM_ERROR : BassBoost_setParameter() invalid param %d", *pParamTemp);
+            ALOGV("%s invalid param %d", __func__, params[0]);
+            status = -EINVAL;
             break;
     }
 
-    //ALOGV("\tBassBoost_setParameter end");
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end BassBoost_setParameter */
 
@@ -2281,92 +2327,97 @@
 //
 //----------------------------------------------------------------------------
 
-int Virtualizer_getParameter(EffectContext        *pContext,
-                             void                 *pParam,
-                             uint32_t             *pValueSize,
-                             void                 *pValue){
+int Virtualizer_getParameter(EffectContext *pContext,
+                             uint32_t       paramSize,
+                             void          *pParam,
+                             uint32_t      *pValueSize,
+                             void          *pValue) {
     int status = 0;
-    int32_t *pParamTemp = (int32_t *)pParam;
-    int32_t param = *pParamTemp++;
+    int32_t *params = (int32_t *)pParam;
 
-    //ALOGV("\tVirtualizer_getParameter start");
+    ALOGVV("%s start", __func__);
 
-    switch (param){
-        case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
-            if (*pValueSize != sizeof(uint32_t)){
-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
-                return -EINVAL;
-            }
-            *pValueSize = sizeof(uint32_t);
-            break;
-        case VIRTUALIZER_PARAM_STRENGTH:
-            if (*pValueSize != sizeof(int16_t)){
-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize2 %d",*pValueSize);
-                return -EINVAL;
-            }
-            *pValueSize = sizeof(int16_t);
-            break;
-        case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES:
-            // return value size can only be interpreted as relative to input value,
-            // deferring validity check to below
-            break;
-        case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE:
-            if (*pValueSize != sizeof(uint32_t)){
-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
-                return -EINVAL;
-            }
-            *pValueSize = sizeof(uint32_t);
-            break;
-        default:
-            ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid param %d", param);
-            return -EINVAL;
+    if (paramSize < sizeof(int32_t)) {
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
     }
-
-    switch (param){
+    switch (params[0]) {
         case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
-            *(uint32_t *)pValue = 1;
+            if (*pValueSize != sizeof(uint32_t)) { // legacy: check equality here.
+                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH_SUPPORTED invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            // no need to set *pValueSize
 
-            //ALOGV("\tVirtualizer_getParameter() VIRTUALIZER_PARAM_STRENGTH_SUPPORTED Value is %d",
-            //        *(uint32_t *)pValue);
+            *(uint32_t *)pValue = 1;
+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH_SUPPORTED %d", __func__, *(uint32_t *)pValue);
             break;
 
         case VIRTUALIZER_PARAM_STRENGTH:
+            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
+                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            // no need to set *pValueSize
+
             *(int16_t *)pValue = VirtualizerGetStrength(pContext);
 
-            //ALOGV("\tVirtualizer_getParameter() VIRTUALIZER_PARAM_STRENGTH Value is %d",
-            //        *(int16_t *)pValue);
+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH %d", __func__, *(int16_t *)pValue);
             break;
 
         case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES: {
-            const audio_channel_mask_t channelMask = (audio_channel_mask_t) *pParamTemp++;
-            const audio_devices_t deviceType = (audio_devices_t) *pParamTemp;
-            uint32_t nbChannels = audio_channel_count_from_out_mask(channelMask);
-            if (*pValueSize < 3 * nbChannels * sizeof(int32_t)){
-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
-                return -EINVAL;
+            if (paramSize < 3 * sizeof(int32_t)) {
+                ALOGV("%s VIRTUALIZER_PARAM_SPEAKER_ANGLES invalid paramSize: %u",
+                        __func__, paramSize);
+                status = -EINVAL;
+                break;
             }
+
+            const audio_channel_mask_t channelMask = (audio_channel_mask_t) params[1];
+            const audio_devices_t deviceType = (audio_devices_t) params[2];
+            const uint32_t nbChannels = audio_channel_count_from_out_mask(channelMask);
+            const uint32_t valueSizeRequired = 3 * nbChannels * sizeof(int32_t);
+            if (*pValueSize < valueSizeRequired) {
+                ALOGV("%s VIRTUALIZER_PARAM_SPEAKER_ANGLES invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            *pValueSize = valueSizeRequired;
+
             // verify the configuration is supported
             status = VirtualizerIsConfigurationSupported(channelMask, deviceType);
             if (status == 0) {
-                ALOGV("VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES supports mask=0x%x device=0x%x",
-                        channelMask, deviceType);
+                ALOGV("%s VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES mask=0x%x device=0x%x",
+                        __func__, channelMask, deviceType);
                 // configuration is supported, get the angles
                 VirtualizerGetSpeakerAngles(channelMask, deviceType, (int32_t *)pValue);
             }
-            }
-            break;
+        } break;
 
         case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE:
-            *(uint32_t *)pValue  = (uint32_t) VirtualizerGetVirtualizationMode(pContext);
+            if (*pValueSize != sizeof(uint32_t)) { // legacy: check equality here.
+                ALOGV("%s VIRTUALIZER_PARAM_VIRTUALIZATION_MODE invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            // no need to set *pValueSize
+
+            *(uint32_t *)pValue = (uint32_t) VirtualizerGetVirtualizationMode(pContext);
             break;
 
         default:
-            ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid param %d", param);
+            ALOGV("%s invalid param %d", __func__, params[0]);
             status = -EINVAL;
             break;
     }
 
-    ALOGV("\tVirtualizer_getParameter end returning status=%d", status);
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end Virtualizer_getParameter */
 
@@ -2385,37 +2436,57 @@
 //
 //----------------------------------------------------------------------------
 
-int Virtualizer_setParameter (EffectContext *pContext, void *pParam, void *pValue){
+int Virtualizer_setParameter(EffectContext *pContext,
+                             uint32_t       paramSize,
+                             void          *pParam,
+                             uint32_t       valueSize,
+                             void          *pValue) {
     int status = 0;
-    int16_t strength;
-    int32_t *pParamTemp = (int32_t *)pParam;
-    int32_t param = *pParamTemp++;
+    int32_t *params = (int32_t *)pParam;
 
-    //ALOGV("\tVirtualizer_setParameter start");
+    ALOGVV("%s start", __func__);
 
-    switch (param){
-        case VIRTUALIZER_PARAM_STRENGTH:
-            strength = *(int16_t *)pValue;
-            //ALOGV("\tVirtualizer_setParameter() VIRTUALIZER_PARAM_STRENGTH value is %d", strength);
-            //ALOGV("\tVirtualizer_setParameter() Calling pVirtualizer->setStrength");
+    if (paramSize != sizeof(int32_t)) { // legacy: check equality here.
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
+    }
+    switch (params[0]) {
+        case VIRTUALIZER_PARAM_STRENGTH: {
+            if (valueSize < sizeof(int16_t)) {
+                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH invalid valueSize: %u", __func__, valueSize);
+                status = -EINVAL;
+                break;
+            }
+
+            const int16_t strength = *(int16_t *)pValue;
+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH %d", __func__, strength);
+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH Calling VirtualizerSetStrength", __func__);
             VirtualizerSetStrength(pContext, (int32_t)strength);
-            //ALOGV("\tVirtualizer_setParameter() Called pVirtualizer->setStrength");
-           break;
+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH Called VirtualizerSetStrength", __func__);
+        } break;
 
         case VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE: {
-            const audio_devices_t deviceType = *(audio_devices_t *) pValue;
-            status = VirtualizerForceVirtualizationMode(pContext, deviceType);
-            //ALOGV("VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE device=0x%x result=%d",
-            //        deviceType, status);
+            if (valueSize < sizeof(int32_t)) {
+                ALOGV("%s VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE invalid valueSize: %u",
+                        __func__, valueSize);
+                android_errorWriteLog(0x534e4554, "64478003");
+                status = -EINVAL;
+                break;
             }
-            break;
+
+            const audio_devices_t deviceType = (audio_devices_t)*(int32_t *)pValue;
+            status = VirtualizerForceVirtualizationMode(pContext, deviceType);
+            ALOGVV("%s VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE device=%#x result=%d",
+                    __func__, deviceType, status);
+        } break;
 
         default:
-            ALOGV("\tLVM_ERROR : Virtualizer_setParameter() invalid param %d", param);
+            ALOGV("%s invalid param %d", __func__, params[0]);
+            status = -EINVAL;
             break;
     }
 
-    //ALOGV("\tVirtualizer_setParameter end");
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end Virtualizer_setParameter */
 
@@ -2439,174 +2510,215 @@
 // Side Effects:
 //
 //----------------------------------------------------------------------------
-int Equalizer_getParameter(EffectContext     *pContext,
-                           void              *pParam,
-                           uint32_t          *pValueSize,
-                           void              *pValue){
+int Equalizer_getParameter(EffectContext *pContext,
+                           uint32_t       paramSize,
+                           void          *pParam,
+                           uint32_t      *pValueSize,
+                           void          *pValue) {
     int status = 0;
-    int32_t *pParamTemp = (int32_t *)pParam;
-    int32_t param = *pParamTemp++;
-    int32_t param2;
-    char *name;
+    int32_t *params = (int32_t *)pParam;
 
-    //ALOGV("\tEqualizer_getParameter start");
+    ALOGVV("%s start", __func__);
 
-    switch (param) {
+    if (paramSize < sizeof(int32_t)) {
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
+    }
+    switch (params[0]) {
     case EQ_PARAM_NUM_BANDS:
+        if (*pValueSize < sizeof(uint16_t)) {
+            ALOGV("%s EQ_PARAM_NUM_BANDS invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
+        }
+        *pValueSize = sizeof(uint16_t);
+
+        *(uint16_t *)pValue = (uint16_t)FIVEBAND_NUMBANDS;
+        ALOGVV("%s EQ_PARAM_NUM_BANDS %u", __func__, *(uint16_t *)pValue);
+        break;
+
     case EQ_PARAM_CUR_PRESET:
+        if (*pValueSize < sizeof(uint16_t)) {
+            ALOGV("%s EQ_PARAM_CUR_PRESET invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
+        }
+        *pValueSize = sizeof(uint16_t);
+
+        *(uint16_t *)pValue = (uint16_t)EqualizerGetPreset(pContext);
+        ALOGVV("%s EQ_PARAM_CUR_PRESET %u", __func__, *(uint16_t *)pValue);
+        break;
+
     case EQ_PARAM_GET_NUM_OF_PRESETS:
-    case EQ_PARAM_BAND_LEVEL:
-    case EQ_PARAM_GET_BAND:
+        if (*pValueSize < sizeof(uint16_t)) {
+            ALOGV("%s EQ_PARAM_GET_NUM_OF_PRESETS invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
+        }
+        *pValueSize = sizeof(uint16_t);
+
+        *(uint16_t *)pValue = (uint16_t)EqualizerGetNumPresets();
+        ALOGVV("%s EQ_PARAM_GET_NUM_OF_PRESETS %u", __func__, *(uint16_t *)pValue);
+        break;
+
+    case EQ_PARAM_GET_BAND: {
+        if (paramSize < 2 * sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_GET_BAND invalid paramSize: %u", __func__, paramSize);
+            status = -EINVAL;
+            break;
+        }
+        if (*pValueSize < sizeof(uint16_t)) {
+            ALOGV("%s EQ_PARAM_GET_BAND invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
+        }
+        *pValueSize = sizeof(uint16_t);
+
+        const int32_t frequency = params[1];
+        *(uint16_t *)pValue = (uint16_t)EqualizerGetBand(pContext, frequency);
+        ALOGVV("%s EQ_PARAM_GET_BAND frequency %d, band %u",
+                __func__, frequency, *(uint16_t *)pValue);
+    } break;
+
+    case EQ_PARAM_BAND_LEVEL: {
+        if (paramSize < 2 * sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid paramSize %u", __func__, paramSize);
+            status = -EINVAL;
+            break;
+        }
         if (*pValueSize < sizeof(int16_t)) {
-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 1  %d", *pValueSize);
-            return -EINVAL;
+            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
         }
         *pValueSize = sizeof(int16_t);
-        break;
+
+        const int32_t band = params[1];
+        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
+            if (band < 0) {
+                android_errorWriteLog(0x534e4554, "32438598");
+                ALOGW("%s EQ_PARAM_BAND_LEVEL invalid band %d", __func__, band);
+            }
+            status = -EINVAL;
+            break;
+        }
+        *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, band);
+        ALOGVV("%s EQ_PARAM_BAND_LEVEL band %d, level %d",
+                __func__, band, *(int16_t *)pValue);
+    } break;
 
     case EQ_PARAM_LEVEL_RANGE:
         if (*pValueSize < 2 * sizeof(int16_t)) {
-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 2  %d", *pValueSize);
-            return -EINVAL;
+            ALOGV("%s EQ_PARAM_LEVEL_RANGE invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
         }
         *pValueSize = 2 * sizeof(int16_t);
-        break;
-    case EQ_PARAM_BAND_FREQ_RANGE:
-        if (*pValueSize < 2 * sizeof(int32_t)) {
-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 3  %d", *pValueSize);
-            return -EINVAL;
-        }
-        *pValueSize = 2 * sizeof(int32_t);
-        break;
 
-    case EQ_PARAM_CENTER_FREQ:
-        if (*pValueSize < sizeof(int32_t)) {
-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 5  %d", *pValueSize);
-            return -EINVAL;
-        }
-        *pValueSize = sizeof(int32_t);
-        break;
-
-    case EQ_PARAM_GET_PRESET_NAME:
-        break;
-
-    case EQ_PARAM_PROPERTIES:
-        if (*pValueSize < (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t)) {
-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 1  %d", *pValueSize);
-            return -EINVAL;
-        }
-        *pValueSize = (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t);
-        break;
-
-    default:
-        ALOGV("\tLVM_ERROR : Equalizer_getParameter unknown param %d", param);
-        return -EINVAL;
-    }
-
-    switch (param) {
-    case EQ_PARAM_NUM_BANDS:
-        *(uint16_t *)pValue = (uint16_t)FIVEBAND_NUMBANDS;
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_NUM_BANDS %d", *(int16_t *)pValue);
-        break;
-
-    case EQ_PARAM_LEVEL_RANGE:
         *(int16_t *)pValue = -1500;
         *((int16_t *)pValue + 1) = 1500;
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_LEVEL_RANGE min %d, max %d",
-        //      *(int16_t *)pValue, *((int16_t *)pValue + 1));
+        ALOGVV("%s EQ_PARAM_LEVEL_RANGE min %d, max %d",
+                __func__, *(int16_t *)pValue, *((int16_t *)pValue + 1));
         break;
 
-    case EQ_PARAM_BAND_LEVEL:
-        param2 = *pParamTemp;
-        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
+    case EQ_PARAM_BAND_FREQ_RANGE: {
+        if (paramSize < 2 * sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_BAND_FREQ_RANGE invalid paramSize: %u", __func__, paramSize);
             status = -EINVAL;
-            if (param2 < 0) {
-                android_errorWriteLog(0x534e4554, "32438598");
-                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_LEVEL band %d", param2);
-            }
             break;
         }
-        *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, param2);
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_BAND_LEVEL band %d, level %d",
-        //      param2, *(int32_t *)pValue);
-        break;
-
-    case EQ_PARAM_CENTER_FREQ:
-        param2 = *pParamTemp;
-        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
+        if (*pValueSize < 2 * sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_BAND_FREQ_RANGE invalid *pValueSize %u", __func__, *pValueSize);
             status = -EINVAL;
-            if (param2 < 0) {
-                android_errorWriteLog(0x534e4554, "32436341");
-                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_CENTER_FREQ band %d", param2);
-            }
             break;
         }
-        *(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, param2);
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_CENTER_FREQ band %d, frequency %d",
-        //      param2, *(int32_t *)pValue);
-        break;
+        *pValueSize = 2 * sizeof(int32_t);
 
-    case EQ_PARAM_BAND_FREQ_RANGE:
-        param2 = *pParamTemp;
-        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
-            status = -EINVAL;
-            if (param2 < 0) {
+        const int32_t band = params[1];
+        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
+            if (band < 0) {
                 android_errorWriteLog(0x534e4554, "32247948");
-                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d", param2);
+                ALOGW("%s EQ_PARAM_BAND_FREQ_RANGE invalid band %d",
+                        __func__, band);
             }
-            break;
-        }
-        EqualizerGetBandFreqRange(pContext, param2, (uint32_t *)pValue, ((uint32_t *)pValue + 1));
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d, min %d, max %d",
-        //      param2, *(int32_t *)pValue, *((int32_t *)pValue + 1));
-        break;
-
-    case EQ_PARAM_GET_BAND:
-        param2 = *pParamTemp;
-        *(uint16_t *)pValue = (uint16_t)EqualizerGetBand(pContext, param2);
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_BAND frequency %d, band %d",
-        //      param2, *(uint16_t *)pValue);
-        break;
-
-    case EQ_PARAM_CUR_PRESET:
-        *(uint16_t *)pValue = (uint16_t)EqualizerGetPreset(pContext);
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_CUR_PRESET %d", *(int32_t *)pValue);
-        break;
-
-    case EQ_PARAM_GET_NUM_OF_PRESETS:
-        *(uint16_t *)pValue = (uint16_t)EqualizerGetNumPresets();
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_NUM_OF_PRESETS %d", *(int16_t *)pValue);
-        break;
-
-    case EQ_PARAM_GET_PRESET_NAME:
-        param2 = *pParamTemp;
-        if ((param2 < 0 && param2 != PRESET_CUSTOM) ||  param2 >= EqualizerGetNumPresets()) {
             status = -EINVAL;
-            if (param2 < 0) {
-                android_errorWriteLog(0x534e4554, "32448258");
-                ALOGE("\tERROR Equalizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d",
-                        param2);
+            break;
+        }
+        EqualizerGetBandFreqRange(pContext, band, (uint32_t *)pValue, ((uint32_t *)pValue + 1));
+        ALOGVV("%s EQ_PARAM_BAND_FREQ_RANGE band %d, min %d, max %d",
+                __func__, band, *(int32_t *)pValue, *((int32_t *)pValue + 1));
+
+    } break;
+
+    case EQ_PARAM_CENTER_FREQ: {
+        if (paramSize < 2 * sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_CENTER_FREQ invalid paramSize: %u", __func__, paramSize);
+            status = -EINVAL;
+            break;
+        }
+        if (*pValueSize < sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_CENTER_FREQ invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
+        }
+        *pValueSize = sizeof(int32_t);
+
+        const int32_t band = params[1];
+        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
+            status = -EINVAL;
+            if (band < 0) {
+                android_errorWriteLog(0x534e4554, "32436341");
+                ALOGW("%s EQ_PARAM_CENTER_FREQ invalid band %d", __func__, band);
             }
             break;
         }
+        *(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, band);
+        ALOGVV("%s EQ_PARAM_CENTER_FREQ band %d, frequency %d",
+                __func__, band, *(int32_t *)pValue);
+    } break;
 
+    case EQ_PARAM_GET_PRESET_NAME: {
+        if (paramSize < 2 * sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_PRESET_NAME invalid paramSize: %u", __func__, paramSize);
+            status = -EINVAL;
+            break;
+        }
         if (*pValueSize < 1) {
-            status = -EINVAL;
             android_errorWriteLog(0x534e4554, "37536407");
+            status = -EINVAL;
             break;
         }
 
-        name = (char *)pValue;
-        strncpy(name, EqualizerGetPresetName(param2), *pValueSize - 1);
+        const int32_t preset = params[1];
+        if ((preset < 0 && preset != PRESET_CUSTOM) ||  preset >= EqualizerGetNumPresets()) {
+            if (preset < 0) {
+                android_errorWriteLog(0x534e4554, "32448258");
+                ALOGE("%s EQ_PARAM_GET_PRESET_NAME preset %d", __func__, preset);
+            }
+            status = -EINVAL;
+            break;
+        }
+
+        char * const name = (char *)pValue;
+        strncpy(name, EqualizerGetPresetName(preset), *pValueSize - 1);
         name[*pValueSize - 1] = 0;
         *pValueSize = strlen(name) + 1;
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d",
-        //      param2, gEqualizerPresets[param2].name, *pValueSize);
-        break;
+        ALOGVV("%s EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d",
+                __func__, preset, gEqualizerPresets[preset].name, *pValueSize);
+
+    } break;
 
     case EQ_PARAM_PROPERTIES: {
+        constexpr uint32_t requiredValueSize = (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t);
+        if (*pValueSize < requiredValueSize) {
+            ALOGV("%s EQ_PARAM_PROPERTIES invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
+        }
+        *pValueSize = requiredValueSize;
+
         int16_t *p = (int16_t *)pValue;
-        ALOGV("\tEqualizer_getParameter() EQ_PARAM_PROPERTIES");
+        ALOGV("%s EQ_PARAM_PROPERTIES", __func__);
         p[0] = (int16_t)EqualizerGetPreset(pContext);
         p[1] = (int16_t)FIVEBAND_NUMBANDS;
         for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
@@ -2615,12 +2727,12 @@
     } break;
 
     default:
-        ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid param %d", param);
+        ALOGV("%s invalid param %d", __func__, params[0]);
         status = -EINVAL;
         break;
     }
 
-    //GV("\tEqualizer_getParameter end\n");
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end Equalizer_getParameter */
 
@@ -2640,74 +2752,89 @@
 // Outputs:
 //
 //----------------------------------------------------------------------------
-int Equalizer_setParameter (EffectContext *pContext,
-                            void *pParam,
-                            uint32_t valueSize,
-                            void *pValue) {
+int Equalizer_setParameter(EffectContext *pContext,
+                           uint32_t       paramSize,
+                           void          *pParam,
+                           uint32_t       valueSize,
+                           void          *pValue) {
     int status = 0;
-    int32_t preset;
-    int32_t band;
-    int32_t level;
-    int32_t *pParamTemp = (int32_t *)pParam;
-    int32_t param = *pParamTemp++;
+    int32_t *params = (int32_t *)pParam;
 
+    ALOGVV("%s start", __func__);
 
-    //ALOGV("\tEqualizer_setParameter start");
-    switch (param) {
-    case EQ_PARAM_CUR_PRESET:
+    if (paramSize < sizeof(int32_t)) {
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
+    }
+    switch (params[0]) {
+    case EQ_PARAM_CUR_PRESET: {
         if (valueSize < sizeof(int16_t)) {
-          status = -EINVAL;
-          break;
+            ALOGV("%s EQ_PARAM_CUR_PRESET invalid valueSize %u", __func__, valueSize);
+            status = -EINVAL;
+            break;
         }
-        preset = (int32_t)(*(uint16_t *)pValue);
+        const int32_t preset = (int32_t)*(uint16_t *)pValue;
 
-        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_CUR_PRESET %d", preset);
-        if ((preset >= EqualizerGetNumPresets())||(preset < 0)) {
+        ALOGVV("%s EQ_PARAM_CUR_PRESET %d", __func__, preset);
+        if (preset >= EqualizerGetNumPresets() || preset < 0) {
+            ALOGV("%s EQ_PARAM_CUR_PRESET invalid preset %d", __func__, preset);
             status = -EINVAL;
             break;
         }
         EqualizerSetPreset(pContext, preset);
-        break;
-    case EQ_PARAM_BAND_LEVEL:
-        if (valueSize < sizeof(int16_t)) {
-          status = -EINVAL;
-          break;
-        }
-        band =  *pParamTemp;
-        level = (int32_t)(*(int16_t *)pValue);
-        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", band, level);
-        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
+    } break;
+
+    case EQ_PARAM_BAND_LEVEL: {
+        if (paramSize < 2 * sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid paramSize: %u", __func__, paramSize);
             status = -EINVAL;
+            break;
+        }
+        if (valueSize < sizeof(int16_t)) {
+            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid valueSize %u", __func__, valueSize);
+            status = -EINVAL;
+            break;
+        }
+        const int32_t band =  params[1];
+        const int32_t level = (int32_t)*(int16_t *)pValue;
+        ALOGVV("%s EQ_PARAM_BAND_LEVEL band %d, level %d", __func__, band, level);
+        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
             if (band < 0) {
                 android_errorWriteLog(0x534e4554, "32095626");
-                ALOGE("\tERROR Equalizer_setParameter() EQ_PARAM_BAND_LEVEL band %d", band);
+                ALOGE("%s EQ_PARAM_BAND_LEVEL invalid band %d", __func__, band);
             }
+            status = -EINVAL;
             break;
         }
         EqualizerSetBandLevel(pContext, band, level);
-        break;
+    } break;
+
     case EQ_PARAM_PROPERTIES: {
-        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_PROPERTIES");
+        ALOGVV("%s EQ_PARAM_PROPERTIES", __func__);
         if (valueSize < sizeof(int16_t)) {
-          status = -EINVAL;
-          break;
+            ALOGV("%s EQ_PARAM_PROPERTIES invalid valueSize %u", __func__, valueSize);
+            status = -EINVAL;
+            break;
         }
         int16_t *p = (int16_t *)pValue;
         if ((int)p[0] >= EqualizerGetNumPresets()) {
+            ALOGV("%s EQ_PARAM_PROPERTIES invalid preset %d", __func__, (int)p[0]);
             status = -EINVAL;
             break;
         }
         if (p[0] >= 0) {
             EqualizerSetPreset(pContext, (int)p[0]);
         } else {
-            if (valueSize < (2 + FIVEBAND_NUMBANDS) * sizeof(int16_t)) {
+            constexpr uint32_t valueSizeRequired = (2 + FIVEBAND_NUMBANDS) * sizeof(int16_t);
+            if (valueSize < valueSizeRequired) {
               android_errorWriteLog(0x534e4554, "37563371");
-              ALOGE("\tERROR Equalizer_setParameter() EQ_PARAM_PROPERTIES valueSize %d < %d",
-                    (int)valueSize, (int)((2 + FIVEBAND_NUMBANDS) * sizeof(int16_t)));
+              ALOGE("%s EQ_PARAM_PROPERTIES invalid valueSize %u < %u",
+                      __func__, valueSize, valueSizeRequired);
               status = -EINVAL;
               break;
             }
             if ((int)p[1] != FIVEBAND_NUMBANDS) {
+                ALOGV("%s EQ_PARAM_PROPERTIES invalid bands %d", __func__, (int)p[1]);
                 status = -EINVAL;
                 break;
             }
@@ -2716,13 +2843,14 @@
             }
         }
     } break;
+
     default:
-        ALOGV("\tLVM_ERROR : Equalizer_setParameter() invalid param %d", param);
+        ALOGV("%s invalid param %d", __func__, params[0]);
         status = -EINVAL;
         break;
     }
 
-    //ALOGV("\tEqualizer_setParameter end");
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end Equalizer_setParameter */
 
@@ -2747,79 +2875,92 @@
 //
 //----------------------------------------------------------------------------
 
-int Volume_getParameter(EffectContext     *pContext,
-                        void              *pParam,
-                        uint32_t          *pValueSize,
-                        void              *pValue){
+int Volume_getParameter(EffectContext *pContext,
+                        uint32_t       paramSize,
+                        void          *pParam,
+                        uint32_t      *pValueSize,
+                        void          *pValue) {
     int status = 0;
-    int32_t *pParamTemp = (int32_t *)pParam;
-    int32_t param = *pParamTemp++;;
+    int32_t *params = (int32_t *)pParam;
 
-    //ALOGV("\tVolume_getParameter start");
+    ALOGVV("%s start", __func__);
 
-    switch (param){
+    if (paramSize < sizeof(int32_t)) {
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
+    }
+    switch (params[0]) {
         case VOLUME_PARAM_LEVEL:
-        case VOLUME_PARAM_MAXLEVEL:
-        case VOLUME_PARAM_STEREOPOSITION:
-            if (*pValueSize != sizeof(int16_t)){
-                ALOGV("\tLVM_ERROR : Volume_getParameter() invalid pValueSize 1  %d", *pValueSize);
-                return -EINVAL;
+            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
+                ALOGV("%s VOLUME_PARAM_LEVEL invalid *pValueSize %u", __func__, *pValueSize);
+                status = -EINVAL;
+                break;
             }
-            *pValueSize = sizeof(int16_t);
+            // no need to set *pValueSize
+
+            status = VolumeGetVolumeLevel(pContext, (int16_t *)(pValue));
+            ALOGVV("%s VOLUME_PARAM_LEVEL %d", __func__, *(int16_t *)pValue);
+            break;
+
+        case VOLUME_PARAM_MAXLEVEL:
+            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
+                ALOGV("%s VOLUME_PARAM_MAXLEVEL invalid *pValueSize %u", __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            // no need to set *pValueSize
+
+            // in millibel
+            *(int16_t *)pValue = 0;
+            ALOGVV("%s VOLUME_PARAM_MAXLEVEL %d", __func__, *(int16_t *)pValue);
+            break;
+
+        case VOLUME_PARAM_STEREOPOSITION:
+            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
+                ALOGV("%s VOLUME_PARAM_STEREOPOSITION invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            // no need to set *pValueSize
+
+            VolumeGetStereoPosition(pContext, (int16_t *)pValue);
+            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION %d", __func__, *(int16_t *)pValue);
             break;
 
         case VOLUME_PARAM_MUTE:
+            if (*pValueSize < sizeof(uint32_t)) {
+                ALOGV("%s VOLUME_PARAM_MUTE invalid *pValueSize %u", __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            *pValueSize = sizeof(uint32_t);
+
+            status = VolumeGetMute(pContext, (uint32_t *)pValue);
+            ALOGV("%s VOLUME_PARAM_MUTE %u", __func__, *(uint32_t *)pValue);
+            break;
+
         case VOLUME_PARAM_ENABLESTEREOPOSITION:
-            if (*pValueSize < sizeof(int32_t)){
-                ALOGV("\tLVM_ERROR : Volume_getParameter() invalid pValueSize 2  %d", *pValueSize);
-                return -EINVAL;
+            if (*pValueSize < sizeof(int32_t)) {
+                ALOGV("%s VOLUME_PARAM_ENABLESTEREOPOSITION invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
             }
             *pValueSize = sizeof(int32_t);
-            break;
 
-        default:
-            ALOGV("\tLVM_ERROR : Volume_getParameter unknown param %d", param);
-            return -EINVAL;
-    }
-
-    switch (param){
-        case VOLUME_PARAM_LEVEL:
-            status = VolumeGetVolumeLevel(pContext, (int16_t *)(pValue));
-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_LEVEL Value is %d",
-            //        *(int16_t *)pValue);
-            break;
-
-        case VOLUME_PARAM_MAXLEVEL:
-            *(int16_t *)pValue = 0;
-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_MAXLEVEL Value is %d",
-            //        *(int16_t *)pValue);
-            break;
-
-        case VOLUME_PARAM_STEREOPOSITION:
-            VolumeGetStereoPosition(pContext, (int16_t *)pValue);
-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_STEREOPOSITION Value is %d",
-            //        *(int16_t *)pValue);
-            break;
-
-        case VOLUME_PARAM_MUTE:
-            status = VolumeGetMute(pContext, (uint32_t *)pValue);
-            ALOGV("\tVolume_getParameter() VOLUME_PARAM_MUTE Value is %d",
-                    *(uint32_t *)pValue);
-            break;
-
-        case VOLUME_PARAM_ENABLESTEREOPOSITION:
             *(int32_t *)pValue = pContext->pBundledContext->bStereoPositionEnabled;
-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_ENABLESTEREOPOSITION Value is %d",
-            //        *(uint32_t *)pValue);
+            ALOGVV("%s VOLUME_PARAM_ENABLESTEREOPOSITION %d", __func__, *(int32_t *)pValue);
+
             break;
 
         default:
-            ALOGV("\tLVM_ERROR : Volume_getParameter() invalid param %d", param);
+            ALOGV("%s invalid param %d", __func__, params[0]);
             status = -EINVAL;
             break;
     }
 
-    //ALOGV("\tVolume_getParameter end");
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end Volume_getParameter */
 
@@ -2839,55 +2980,87 @@
 //
 //----------------------------------------------------------------------------
 
-int Volume_setParameter (EffectContext *pContext, void *pParam, void *pValue){
-    int      status = 0;
-    int16_t  level;
-    int16_t  position;
-    uint32_t mute;
-    uint32_t positionEnabled;
-    int32_t *pParamTemp = (int32_t *)pParam;
-    int32_t param = *pParamTemp++;
+int Volume_setParameter(EffectContext *pContext,
+                        uint32_t       paramSize,
+                        void          *pParam,
+                        uint32_t       valueSize,
+                        void          *pValue) {
+    int status = 0;
+    int32_t *params = (int32_t *)pParam;
 
-    //ALOGV("\tVolume_setParameter start");
+    ALOGVV("%s start", __func__);
 
-    switch (param){
-        case VOLUME_PARAM_LEVEL:
-            level = *(int16_t *)pValue;
-            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_LEVEL value is %d", level);
-            //ALOGV("\tVolume_setParameter() Calling pVolume->setVolumeLevel");
-            status = VolumeSetVolumeLevel(pContext, (int16_t)level);
-            //ALOGV("\tVolume_setParameter() Called pVolume->setVolumeLevel");
-            break;
+    if (paramSize < sizeof(int32_t)) {
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
+    }
+    switch (params[0]) {
+        case VOLUME_PARAM_LEVEL: {
+            if (valueSize < sizeof(int16_t)) {
+                ALOGV("%s VOLUME_PARAM_LEVEL invalid valueSize %u", __func__, valueSize);
+                status = -EINVAL;
+                break;
+            }
 
-        case VOLUME_PARAM_MUTE:
-            mute = *(uint32_t *)pValue;
-            //ALOGV("\tVolume_setParameter() Calling pVolume->setMute, mute is %d", mute);
-            //ALOGV("\tVolume_setParameter() Calling pVolume->setMute");
+            const int16_t level = *(int16_t *)pValue;
+            ALOGVV("%s VOLUME_PARAM_LEVEL %d", __func__, level);
+            ALOGVV("%s VOLUME_PARAM_LEVEL Calling VolumeSetVolumeLevel", __func__);
+            status = VolumeSetVolumeLevel(pContext, level);
+            ALOGVV("%s VOLUME_PARAM_LEVEL Called VolumeSetVolumeLevel", __func__);
+        } break;
+
+        case VOLUME_PARAM_MUTE: {
+            if (valueSize < sizeof(uint32_t)) {
+                ALOGV("%s VOLUME_PARAM_MUTE invalid valueSize %u", __func__, valueSize);
+                android_errorWriteLog(0x534e4554, "64477217");
+                status = -EINVAL;
+                break;
+            }
+
+            const uint32_t mute = *(uint32_t *)pValue;
+            ALOGVV("%s VOLUME_PARAM_MUTE %d", __func__, mute);
+            ALOGVV("%s VOLUME_PARAM_MUTE Calling VolumeSetMute", __func__);
             status = VolumeSetMute(pContext, mute);
-            //ALOGV("\tVolume_setParameter() Called pVolume->setMute");
-            break;
+            ALOGVV("%s VOLUME_PARAM_MUTE Called VolumeSetMute", __func__);
+        } break;
 
-        case VOLUME_PARAM_ENABLESTEREOPOSITION:
-            positionEnabled = *(uint32_t *)pValue;
-            (void) VolumeEnableStereoPosition(pContext, positionEnabled);
-            (void) VolumeSetStereoPosition(pContext, pContext->pBundledContext->positionSaved);
-            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_ENABLESTEREOPOSITION called");
-            break;
+        case VOLUME_PARAM_ENABLESTEREOPOSITION: {
+            if (valueSize < sizeof(uint32_t)) {
+                ALOGV("%s VOLUME_PARAM_ENABLESTEREOPOSITION invalid valueSize %u",
+                        __func__, valueSize);
+                status = -EINVAL;
+                break;
+            }
 
-        case VOLUME_PARAM_STEREOPOSITION:
-            position = *(int16_t *)pValue;
-            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_STEREOPOSITION value is %d", position);
-            //ALOGV("\tVolume_setParameter() Calling pVolume->VolumeSetStereoPosition");
-            status = VolumeSetStereoPosition(pContext, (int16_t)position);
-            //ALOGV("\tVolume_setParameter() Called pVolume->VolumeSetStereoPosition");
-            break;
+            const uint32_t positionEnabled = *(uint32_t *)pValue;
+            status = VolumeEnableStereoPosition(pContext, positionEnabled)
+                    ?: VolumeSetStereoPosition(pContext, pContext->pBundledContext->positionSaved);
+            ALOGVV("%s VOLUME_PARAM_ENABLESTEREOPOSITION called", __func__);
+        } break;
+
+        case VOLUME_PARAM_STEREOPOSITION: {
+            if (valueSize < sizeof(int16_t)) {
+                ALOGV("%s VOLUME_PARAM_STEREOPOSITION invalid valueSize %u", __func__, valueSize);
+                status = -EINVAL;
+                break;
+            }
+
+            const int16_t position = *(int16_t *)pValue;
+            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION %d", __func__, position);
+            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION Calling VolumeSetStereoPosition",
+                    __func__);
+            status = VolumeSetStereoPosition(pContext, position);
+            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION Called VolumeSetStereoPosition",
+                    __func__);
+        } break;
 
         default:
-            ALOGV("\tLVM_ERROR : Volume_setParameter() invalid param %d", param);
+            ALOGV("%s invalid param %d", __func__, params[0]);
+            status = -EINVAL;
             break;
     }
 
-    //ALOGV("\tVolume_setParameter end");
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end Volume_setParameter */
 
@@ -3205,6 +3378,13 @@
     return status;
 }   /* end Effect_process */
 
+// The value offset of an effect parameter is computed by rounding up
+// the parameter size to the next 32 bit alignment.
+static inline uint32_t computeParamVOffset(const effect_param_t *p) {
+    return ((p->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) *
+            sizeof(int32_t);
+}
+
 /* Effect Control Interface Implementation: Command */
 int Effect_command(effect_handle_t  self,
                               uint32_t            cmdCode,
@@ -3315,8 +3495,7 @@
                 ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: psize too big");
                 return -EINVAL;
             }
-            uint32_t paddedParamSize = ((p->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) *
-                    sizeof(int32_t);
+            const uint32_t paddedParamSize = computeParamVOffset(p);
             if ((EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) < paddedParamSize) ||
                 (EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) - paddedParamSize <
                     p->vsize)) {
@@ -3338,6 +3517,7 @@
             uint32_t voffset = paddedParamSize;
             if(pContext->EffectType == LVM_BASS_BOOST){
                 p->status = android::BassBoost_getParameter(pContext,
+                                                            p->psize,
                                                             p->data,
                                                             &p->vsize,
                                                             p->data + voffset);
@@ -3350,6 +3530,7 @@
 
             if(pContext->EffectType == LVM_VIRTUALIZER){
                 p->status = android::Virtualizer_getParameter(pContext,
+                                                              p->psize,
                                                               (void *)p->data,
                                                               &p->vsize,
                                                               p->data + voffset);
@@ -3364,6 +3545,7 @@
                 //ALOGV("\tEqualizer_command cmdCode Case: "
                 //        "EFFECT_CMD_GET_PARAM start");
                 p->status = android::Equalizer_getParameter(pContext,
+                                                            p->psize,
                                                             p->data,
                                                             &p->vsize,
                                                             p->data + voffset);
@@ -3378,6 +3560,7 @@
             if(pContext->EffectType == LVM_VOLUME){
                 //ALOGV("\tVolume_command cmdCode Case: EFFECT_CMD_GET_PARAM start");
                 p->status = android::Volume_getParameter(pContext,
+                                                         p->psize,
                                                          (void *)p->data,
                                                          &p->vsize,
                                                          p->data + voffset);
@@ -3407,13 +3590,9 @@
                             "EFFECT_CMD_SET_PARAM: ERROR");
                     return -EINVAL;
                 }
-                effect_param_t *p = (effect_param_t *) pCmdData;
 
-                if (p->psize != sizeof(int32_t)){
-                    ALOGV("\tLVM_ERROR : BassBoost_command cmdCode Case: "
-                            "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
-                    return -EINVAL;
-                }
+                effect_param_t * const p = (effect_param_t *) pCmdData;
+                const uint32_t voffset = computeParamVOffset(p);
 
                 //ALOGV("\tnBassBoost_command cmdSize is %d\n"
                 //        "\tsizeof(effect_param_t) is  %d\n"
@@ -3423,8 +3602,10 @@
                 //        cmdSize, sizeof(effect_param_t), p->psize, p->vsize );
 
                 *(int *)pReplyData = android::BassBoost_setParameter(pContext,
-                                                                    (void *)p->data,
-                                                                    p->data + p->psize);
+                                                                     p->psize,
+                                                                     (void *)p->data,
+                                                                     p->vsize,
+                                                                     p->data + voffset);
             }
             if(pContext->EffectType == LVM_VIRTUALIZER){
               // Warning this log will fail to properly read an int32_t value, assumes int16_t
@@ -3442,13 +3623,9 @@
                             "EFFECT_CMD_SET_PARAM: ERROR");
                     return -EINVAL;
                 }
-                effect_param_t *p = (effect_param_t *) pCmdData;
 
-                if (p->psize != sizeof(int32_t)){
-                    ALOGV("\tLVM_ERROR : Virtualizer_command cmdCode Case: "
-                            "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
-                    return -EINVAL;
-                }
+                effect_param_t * const p = (effect_param_t *) pCmdData;
+                const uint32_t voffset = computeParamVOffset(p);
 
                 //ALOGV("\tnVirtualizer_command cmdSize is %d\n"
                 //        "\tsizeof(effect_param_t) is  %d\n"
@@ -3458,8 +3635,10 @@
                 //        cmdSize, sizeof(effect_param_t), p->psize, p->vsize );
 
                 *(int *)pReplyData = android::Virtualizer_setParameter(pContext,
-                                                                      (void *)p->data,
-                                                                       p->data + p->psize);
+                                                                       p->psize,
+                                                                       (void *)p->data,
+                                                                       p->vsize,
+                                                                       p->data + voffset);
             }
             if(pContext->EffectType == LVM_EQUALIZER){
                //ALOGV("\tEqualizer_command cmdCode Case: "
@@ -3475,12 +3654,15 @@
                             "EFFECT_CMD_SET_PARAM: ERROR");
                     return -EINVAL;
                 }
-                effect_param_t *p = (effect_param_t *) pCmdData;
+
+                effect_param_t * const p = (effect_param_t *) pCmdData;
+                const uint32_t voffset = computeParamVOffset(p);
 
                 *(int *)pReplyData = android::Equalizer_setParameter(pContext,
-                                                                    (void *)p->data,
-                                                                    p->vsize,
-                                                                    p->data + p->psize);
+                                                                     p->psize,
+                                                                     (void *)p->data,
+                                                                     p->vsize,
+                                                                     p->data + voffset);
             }
             if(pContext->EffectType == LVM_VOLUME){
                 //ALOGV("\tVolume_command cmdCode Case: EFFECT_CMD_SET_PARAM start");
@@ -3497,11 +3679,15 @@
                             "EFFECT_CMD_SET_PARAM: ERROR");
                     return -EINVAL;
                 }
-                effect_param_t *p = (effect_param_t *) pCmdData;
+
+                effect_param_t * const p = (effect_param_t *) pCmdData;
+                const uint32_t voffset = computeParamVOffset(p);
 
                 *(int *)pReplyData = android::Volume_setParameter(pContext,
-                                                                 (void *)p->data,
-                                                                 p->data + p->psize);
+                                                                  p->psize,
+                                                                  (void *)p->data,
+                                                                  p->vsize,
+                                                                  p->data + voffset);
             }
             //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_PARAM end");
         } break;
@@ -3648,10 +3834,10 @@
             if(rightdB > maxdB){
                 maxdB = rightdB;
             }
-            //ALOGV("\tEFFECT_CMD_SET_VOLUME Session: %d, SessionID: %d VOLUME is %d dB (%d), "
+            //ALOGV("\tEFFECT_CMD_SET_VOLUME Session: %d, SessionID: %d VOLUME is %d dB, "
             //      "effect is %d",
             //pContext->pBundledContext->SessionNo, pContext->pBundledContext->SessionId,
-            //(int32_t)maxdB, maxVol<<7, pContext->EffectType);
+            //(int32_t)maxdB, pContext->EffectType);
             //ALOGV("\tEFFECT_CMD_SET_VOLUME: Left is %d, Right is %d", leftVolume, rightVolume);
             //ALOGV("\tEFFECT_CMD_SET_VOLUME: Left %ddB, Right %ddB, Position %ddB",
             //        leftdB, rightdB, pandB);
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index cad89fd..291383a 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -213,7 +213,7 @@
 static const float LimitLevel_bassBoostEnergyCrossCoefficient[FIVEBAND_NUMBANDS] = {
         221.21, 208.10, 28.16, 0.0, 0.0 };
 
-static const float LimitLevel_bassBoostEnergyCoefficient = 7.12;
+static const float LimitLevel_bassBoostEnergyCoefficient = 9.00;
 
 static const float LimitLevel_virtualizerContribution = 1.9;
 
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index 115baff..4b131a7 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -401,6 +401,10 @@
                 videoFrame->getFlattenedIccData());
     }
     mFrameDecoded = true;
+
+    // Aggressive clear to avoid holding on to resources
+    mRetriever.clear();
+    mDataSource.clear();
     return true;
 }
 
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index 19b00f3..3c43a72 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -38,7 +38,8 @@
     SETMEDIACAS,
     SETUID,
     NAME,
-    GETMETRICS
+    GETMETRICS,
+    RELEASE,
 };
 
 class BpMediaExtractor : public BpInterface<IMediaExtractor> {
@@ -138,6 +139,13 @@
         ALOGV("name NOT IMPLEMENTED");
         return NULL;
     }
+
+    virtual void release() {
+        ALOGV("release");
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+        remote()->transact(RELEASE, data, &reply);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor");
@@ -215,6 +223,12 @@
             reply->writeInt32(setMediaCas(casToken));
             return OK;
         }
+        case RELEASE: {
+            ALOGV("release");
+            CHECK_INTERFACE(IMediaExtractor, data, reply);
+            release();
+            return OK;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/include/media/IMediaExtractor.h b/media/libmedia/include/media/IMediaExtractor.h
index 1e13b65..0ac7673 100644
--- a/media/libmedia/include/media/IMediaExtractor.h
+++ b/media/libmedia/include/media/IMediaExtractor.h
@@ -68,6 +68,8 @@
     virtual void setUID(uid_t uid)  = 0;
 
     virtual const char * name() = 0;
+
+    virtual void release() = 0;
 };
 
 
diff --git a/media/libmediametrics/IMediaAnalyticsService.cpp b/media/libmediametrics/IMediaAnalyticsService.cpp
index 68bafe1..28a7746 100644
--- a/media/libmediametrics/IMediaAnalyticsService.cpp
+++ b/media/libmediametrics/IMediaAnalyticsService.cpp
@@ -60,7 +60,7 @@
         data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
         err = remote()->transact(GENERATE_UNIQUE_SESSIONID, data, &reply);
         if (err != NO_ERROR) {
-            ALOGW("bad response from service");
+            ALOGW("bad response from service for generateSessionId, err=%d", err);
             return MediaAnalyticsItem::SessionIDInvalid;
         }
         sessionid = reply.readInt64();
@@ -94,6 +94,7 @@
 
         err = remote()->transact(SUBMIT_ITEM, data, &reply);
         if (err != NO_ERROR) {
+            ALOGW("bad response from service for submit, err=%d", err);
             return MediaAnalyticsItem::SessionIDInvalid;
         }
 
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index 47a147e..f968c09 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -59,6 +59,7 @@
 MediaAnalyticsItem::MediaAnalyticsItem()
     : mPid(-1),
       mUid(-1),
+      mPkgVersionCode(0),
       mSessionID(MediaAnalyticsItem::SessionIDNone),
       mTimestamp(0),
       mFinalized(0),
@@ -70,6 +71,7 @@
 MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
     : mPid(-1),
       mUid(-1),
+      mPkgVersionCode(0),
       mSessionID(MediaAnalyticsItem::SessionIDNone),
       mTimestamp(0),
       mFinalized(0),
@@ -98,7 +100,7 @@
 
     // clean attributes
     // contents of the attributes
-    for (size_t i = 0 ; i < mPropSize; i++ ) {
+    for (size_t i = 0 ; i < mPropCount; i++ ) {
         clearProp(&mProps[i]);
     }
     // the attribute records themselves
@@ -298,7 +300,8 @@
         clearProp(prop);
         if (i != mPropCount-1) {
             // in the middle, bring last one down to fill gap
-            mProps[i] = mProps[mPropCount-1];
+            copyProp(prop, &mProps[mPropCount-1]);
+            clearProp(&mProps[mPropCount-1]);
         }
         mPropCount--;
         return true;
@@ -817,11 +820,16 @@
     sp<IMediaAnalyticsService> svc = getInstance();
 
     if (svc != NULL) {
-        svc->submit(this, forcenew);
+        MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
+        if (newid == SessionIDInvalid) {
+            AString p = this->toString();
+            ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
+            return false;
+        }
         return true;
     } else {
         AString p = this->toString();
-        ALOGD("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
+        ALOGW("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
         return false;
     }
 }
@@ -830,6 +838,7 @@
 // static
 sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
 static Mutex sInitMutex;
+static int remainingBindAttempts = SVC_TRIES;
 
 //static
 bool MediaAnalyticsItem::isEnabled() {
@@ -847,10 +856,28 @@
     return true;
 }
 
+
+// monitor health of our connection to the metrics service
+class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
+        virtual void binderDied(const wp<IBinder> &) {
+            ALOGW("Reacquire service connection on next request");
+            MediaAnalyticsItem::dropInstance();
+        }
+};
+
+static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
+
+// static
+void MediaAnalyticsItem::dropInstance() {
+    Mutex::Autolock _l(sInitMutex);
+    remainingBindAttempts = SVC_TRIES;
+    sAnalyticsService = NULL;
+}
+
 //static
 sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
+
     static const char *servicename = "media.metrics";
-    static int tries_remaining = SVC_TRIES;
     int enabled = isEnabled();
 
     if (enabled == false) {
@@ -882,15 +909,20 @@
         Mutex::Autolock _l(sInitMutex);
         const char *badness = "";
 
-        // think of tries_remaining as telling us whether service==NULL because
+        // think of remainingBindAttempts as telling us whether service==NULL because
         // (1) we haven't tried to initialize it yet
         // (2) we've tried to initialize it, but failed.
-        if (sAnalyticsService == NULL && tries_remaining > 0) {
+        if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
             sp<IServiceManager> sm = defaultServiceManager();
             if (sm != NULL) {
                 sp<IBinder> binder = sm->getService(String16(servicename));
                 if (binder != NULL) {
                     sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
+                    if (sNotifier != NULL) {
+                        sNotifier = NULL;
+                    }
+                    sNotifier = new MediaMetricsDeathNotifier();
+                    binder->linkToDeath(sNotifier);
                 } else {
                     badness = "did not find service";
                 }
@@ -899,8 +931,8 @@
             }
 
             if (sAnalyticsService == NULL) {
-                if (tries_remaining > 0) {
-                    tries_remaining--;
+                if (remainingBindAttempts > 0) {
+                    remainingBindAttempts--;
                 }
                 if (DEBUG_SERVICEACCESS) {
                     ALOGD("Unable to bind to service %s: %s", servicename, badness);
@@ -912,7 +944,6 @@
     }
 }
 
-
 // merge the info from 'incoming' into this record.
 // we finish with a union of this+incoming and special handling for collisions
 bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index 41b9658..dd7452f 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -42,6 +42,7 @@
     friend class IMediaAnalyticsService;
     friend class MediaMetricsJNI;
     friend class MetricsSummarizer;
+    friend class MediaMetricsDeathNotifier;
 
     public:
 
@@ -209,6 +210,7 @@
         // let's reuse a binder connection
         static sp<IMediaAnalyticsService> sAnalyticsService;
         static sp<IMediaAnalyticsService> getInstance();
+        static void dropInstance();
 
         // tracking information
         SessionID_t mSessionID;         // grouping similar records
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index c9394bb..c44e868 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -6356,12 +6356,14 @@
             ALOGE("Unable to obtain MediaCodecList while "
                     "attempting to create codec \"%s\"",
                     componentName.c_str());
+            mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
             return false;
         }
         ssize_t index = list->findCodecByName(componentName.c_str());
         if (index < 0) {
             ALOGE("Unable to find codec \"%s\"",
                     componentName.c_str());
+            mCodec->signalError(OMX_ErrorInvalidComponent, NAME_NOT_FOUND);
             return false;
         }
         sp<MediaCodecInfo> info = list->getCodecInfo(index);
@@ -6369,6 +6371,7 @@
             ALOGE("Unexpected error (index out-of-bound) while "
                     "retrieving information for codec \"%s\"",
                     componentName.c_str());
+            mCodec->signalError(OMX_ErrorUndefined, UNKNOWN_ERROR);
             return false;
         }
         matchingCodecs.add(info->getCodecName());
diff --git a/media/libstagefright/ItemTable.cpp b/media/libstagefright/ItemTable.cpp
index 3ec416b..7bc4f3c 100644
--- a/media/libstagefright/ItemTable.cpp
+++ b/media/libstagefright/ItemTable.cpp
@@ -1409,7 +1409,14 @@
     meta->setInt32(kKeyWidth, image->width);
     meta->setInt32(kKeyHeight, image->height);
     if (image->rotation != 0) {
-        meta->setInt32(kKeyRotation, image->rotation);
+        // Rotation angle in HEIF is CCW, convert to CW here to be
+        // consistent with the other media formats.
+        switch(image->rotation) {
+            case 90: meta->setInt32(kKeyRotation, 270); break;
+            case 180: meta->setInt32(kKeyRotation, 180); break;
+            case 270: meta->setInt32(kKeyRotation, 90); break;
+            default: break; // don't set if invalid
+        }
     }
     meta->setInt32(kKeyMaxInputSize, image->width * image->height * 1.5);
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 6f59fac..9c777b3 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -354,6 +354,10 @@
 }
 
 MPEG4Extractor::~MPEG4Extractor() {
+    release();
+}
+
+void MPEG4Extractor::release() {
     Track *track = mFirstTrack;
     while (track) {
         Track *next = track->next;
@@ -375,6 +379,12 @@
     for (size_t i = 0; i < mPssh.size(); i++) {
         delete [] mPssh[i].data;
     }
+    mPssh.clear();
+
+    if (mDataSource != NULL) {
+        mDataSource->close();
+        mDataSource.clear();
+    }
 }
 
 uint32_t MPEG4Extractor::flags() const {
@@ -1666,6 +1676,9 @@
                     // ratio. Use compression ratio of 1.
                     max_size = width * height * 3 / 2;
                 }
+                // HACK: allow 10% overhead
+                // TODO: read sample size from traf atom for fragmented MPEG4.
+                max_size += max_size / 10;
                 mLastTrack->meta->setInt32(kKeyMaxInputSize, max_size);
             }
 
@@ -4684,6 +4697,8 @@
         }
         if (size > mBuffer->size()) {
             ALOGE("buffer too small: %zu > %zu", size, mBuffer->size());
+            mBuffer->release();
+            mBuffer = NULL;
             return ERROR_BUFFER_TOO_SMALL;
         }
     }
@@ -4976,6 +4991,8 @@
         }
         if (size > mBuffer->size()) {
             ALOGE("buffer too small: %zu > %zu", size, mBuffer->size());
+            mBuffer->release();
+            mBuffer = NULL;
             return ERROR_BUFFER_TOO_SMALL;
         }
     }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 3cdb49e..759e42d 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -73,6 +73,13 @@
 static const char *kCodecCrypto = "android.media.mediacodec.crypto";   /* 0,1 */
 static const char *kCodecEncoder = "android.media.mediacodec.encoder"; /* 0,1 */
 
+static const char *kCodecBytesIn = "android.media.mediacodec.bytesin";  /* 0..n */
+static const char *kCodecProfile = "android.media.mediacodec.profile";  /* 0..n */
+static const char *kCodecLevel = "android.media.mediacodec.level";  /* 0..n */
+static const char *kCodecMaxWidth = "android.media.mediacodec.maxwidth";  /* 0..n */
+static const char *kCodecMaxHeight = "android.media.mediacodec.maxheight";  /* 0..n */
+static const char *kCodecError = "android.media.mediacodec.errcode";
+static const char *kCodecErrorState = "android.media.mediacodec.errstate";
 
 
 static int64_t getId(const sp<IResourceManagerClient> &client) {
@@ -460,6 +467,7 @@
       mFlags(0),
       mStickyError(OK),
       mSoftRenderer(NULL),
+      mAnalyticsItem(NULL),
       mResourceManagerClient(new ResourceManagerClient(this)),
       mResourceManagerService(new ResourceManagerServiceProxy(pid)),
       mBatteryStatNotified(false),
@@ -478,6 +486,18 @@
     } else {
         mUid = uid;
     }
+    initAnalyticsItem();
+}
+
+MediaCodec::~MediaCodec() {
+    CHECK_EQ(mState, UNINITIALIZED);
+    mResourceManagerService->removeResource(getId(mResourceManagerClient));
+
+    flushAnalyticsItem();
+}
+
+void MediaCodec::initAnalyticsItem() {
+    CHECK(mAnalyticsItem == NULL);
     // set up our new record, get a sessionID, put it into the in-progress list
     mAnalyticsItem = new MediaAnalyticsItem(kCodecKeyName);
     if (mAnalyticsItem != NULL) {
@@ -487,11 +507,9 @@
     }
 }
 
-MediaCodec::~MediaCodec() {
-    CHECK_EQ(mState, UNINITIALIZED);
-    mResourceManagerService->removeResource(getId(mResourceManagerClient));
-
-    if (mAnalyticsItem != NULL ) {
+void MediaCodec::flushAnalyticsItem() {
+    if (mAnalyticsItem != NULL) {
+        // don't log empty records
         if (mAnalyticsItem->count() > 0) {
             mAnalyticsItem->setFinalized(true);
             mAnalyticsItem->selfrecord();
@@ -684,10 +702,21 @@
         uint32_t flags) {
     sp<AMessage> msg = new AMessage(kWhatConfigure, this);
 
+    if (mAnalyticsItem != NULL) {
+        int32_t profile = 0;
+        if (format->findInt32("profile", &profile)) {
+            mAnalyticsItem->setInt32(kCodecProfile, profile);
+        }
+        int32_t level = 0;
+        if (format->findInt32("level", &level)) {
+            mAnalyticsItem->setInt32(kCodecLevel, level);
+        }
+    }
+
     if (mIsVideo) {
         format->findInt32("width", &mVideoWidth);
         format->findInt32("height", &mVideoHeight);
-        if (!format->findInt32(kCodecRotation, &mRotationDegrees)) {
+        if (!format->findInt32("rotation-degrees", &mRotationDegrees)) {
             mRotationDegrees = 0;
         }
 
@@ -695,6 +724,14 @@
             mAnalyticsItem->setInt32(kCodecWidth, mVideoWidth);
             mAnalyticsItem->setInt32(kCodecHeight, mVideoHeight);
             mAnalyticsItem->setInt32(kCodecRotation, mRotationDegrees);
+            int32_t maxWidth = 0;
+            if (format->findInt32("max-width", &maxWidth)) {
+                mAnalyticsItem->setInt32(kCodecMaxWidth, maxWidth);
+            }
+            int32_t maxHeight = 0;
+            if (format->findInt32("max-height", &maxHeight)) {
+                mAnalyticsItem->setInt32(kCodecMaxHeight, maxHeight);
+            }
         }
 
         // Prevent possible integer overflow in downstream code.
@@ -1401,6 +1438,12 @@
 
                         case CONFIGURING:
                         {
+                            if (actionCode == ACTION_CODE_FATAL) {
+                                mAnalyticsItem->setInt32(kCodecError, err);
+                                mAnalyticsItem->setInt32(kCodecErrorState, mState);
+                                flushAnalyticsItem();
+                                initAnalyticsItem();
+                            }
                             setState(actionCode == ACTION_CODE_FATAL ?
                                     UNINITIALIZED : INITIALIZED);
                             break;
@@ -1408,6 +1451,12 @@
 
                         case STARTING:
                         {
+                            if (actionCode == ACTION_CODE_FATAL) {
+                                mAnalyticsItem->setInt32(kCodecError, err);
+                                mAnalyticsItem->setInt32(kCodecErrorState, mState);
+                                flushAnalyticsItem();
+                                initAnalyticsItem();
+                            }
                             setState(actionCode == ACTION_CODE_FATAL ?
                                     UNINITIALIZED : CONFIGURED);
                             break;
@@ -1444,6 +1493,11 @@
                         case FLUSHING:
                         {
                             if (actionCode == ACTION_CODE_FATAL) {
+                                mAnalyticsItem->setInt32(kCodecError, err);
+                                mAnalyticsItem->setInt32(kCodecErrorState, mState);
+                                flushAnalyticsItem();
+                                initAnalyticsItem();
+
                                 setState(UNINITIALIZED);
                             } else {
                                 setState(
@@ -1472,6 +1526,10 @@
                                 setState(INITIALIZED);
                                 break;
                             default:
+                                mAnalyticsItem->setInt32(kCodecError, err);
+                                mAnalyticsItem->setInt32(kCodecErrorState, mState);
+                                flushAnalyticsItem();
+                                initAnalyticsItem();
                                 setState(UNINITIALIZED);
                                 break;
                             }
@@ -1576,6 +1634,19 @@
                     }
                     setState(CONFIGURED);
                     (new AMessage)->postReply(mReplyID);
+
+                    // augment our media metrics info, now that we know more things
+                    if (mAnalyticsItem != NULL) {
+                        sp<AMessage> format;
+                        if (mConfigureMsg != NULL &&
+                            mConfigureMsg->findMessage("format", &format)) {
+                                // format includes: mime
+                                AString mime;
+                                if (format->findString("mime", &mime)) {
+                                    mAnalyticsItem->setCString(kCodecMime, mime.c_str());
+                                }
+                            }
+                    }
                     break;
                 }
 
@@ -2801,6 +2872,9 @@
         Mutex::Autolock al(mBufferLock);
         info->mOwnedByClient = false;
         info->mData.clear();
+        if (mAnalyticsItem != NULL) {
+            mAnalyticsItem->addInt64(kCodecBytesIn, size);
+        }
     }
 
     return err;
diff --git a/media/libstagefright/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
index 686bcc8..8717a79 100644
--- a/media/libstagefright/OmxInfoBuilder.cpp
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -61,9 +61,9 @@
     }
     for (const auto& attribute : node.attributes) {
         // All features have an int32 value except
-        // "feature-bitrate-control", which has a string value.
+        // "feature-bitrate-modes", which has a string value.
         if ((attribute.key.compare(0, 8, "feature-") == 0) &&
-                (attribute.key.compare(8, 15, "bitrate-control")
+                (attribute.key.compare(8, 15, "bitrate-modes")
                  != 0)) {
             // If this attribute.key is a feature that is not a bitrate
             // control, add an int32 value.
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index a53897f..103da95 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -60,6 +60,12 @@
 StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
     ALOGV("~StagefrightMetadataRetriever()");
     clearMetadata();
+    // Explicitly release extractor before continuing with the destructor,
+    // some extractors might need to callback to close off the DataSource
+    // and we need to make sure it's still there.
+    if (mExtractor != NULL) {
+        mExtractor->release();
+    }
     if (mSource != NULL) {
         mSource->close();
     }
diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
index cff4a33..4ab1ab2 100644
--- a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
@@ -126,6 +126,29 @@
         OMX_INDEXTYPE index, OMX_PTR params) {
     ALOGV("internalGetParameter: index(%x)", index);
     switch ((OMX_U32)index) {
+        case OMX_IndexParamAudioPortFormat:
+        {
+            OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (!isValidOMXParam(formatParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            formatParams->eEncoding =
+                (formatParams->nPortIndex == 0)
+                    ? OMX_AUDIO_CodingFLAC : OMX_AUDIO_CodingPCM;
+
+            return OMX_ErrorNone;
+        }
         case OMX_IndexParamAudioFlac:
         {
             OMX_AUDIO_PARAM_FLACTYPE *flacParams =
@@ -219,6 +242,29 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexParamAudioPortFormat:
+        {
+            const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (!isValidOMXParam(formatParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if ((formatParams->nPortIndex == 0
+                        && formatParams->eEncoding != OMX_AUDIO_CodingFLAC)
+                || (formatParams->nPortIndex == 1
+                        && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
         case OMX_IndexParamAudioPcm:
         {
             const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
@@ -256,10 +302,27 @@
     while (!inQueue.empty() && !outQueue.empty()) {
         BufferInfo *inInfo = *inQueue.begin();
         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+        BufferInfo *outInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
         uint8_t* inBuffer = inHeader->pBuffer + inHeader->nOffset;
         uint32_t inBufferLength = inHeader->nFilledLen;
         bool endOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0;
 
+        if (inHeader->nFilledLen == 0) {
+            if (endOfInput) {
+                outHeader->nFilledLen = 0;
+                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+                outInfo->mOwnedByUs = false;
+                outQueue.erase(outQueue.begin());
+                notifyFillBufferDone(outHeader);
+            } else {
+                ALOGE("onQueueFilled: emptyInputBuffer received");
+            }
+            inInfo->mOwnedByUs = false;
+            inQueue.erase(inQueue.begin());
+            notifyEmptyBufferDone(inHeader);
+            return;
+        }
         if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
             ALOGE("onQueueFilled: first buffer should have OMX_BUFFERFLAG_CODECCONFIG set");
             inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
@@ -297,8 +360,6 @@
             return;
         }
 
-        BufferInfo *outInfo = *outQueue.begin();
-        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
         short *outBuffer =
                 reinterpret_cast<short *>(outHeader->pBuffer + outHeader->nOffset);
         size_t outBufferSize = outHeader->nAllocLen - outHeader->nOffset;
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
index f7192b1c..7202f98 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
@@ -560,7 +560,7 @@
 
     BitstreamShow13Bits(stream, &code);
 
-    if (code == 0)
+    if (code < 8)
     {
         return VLC_CODE_ERROR;
     }
diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml
index a127843..829f403 100644
--- a/media/libstagefright/data/media_codecs_google_video.xml
+++ b/media/libstagefright/data/media_codecs_google_video.xml
@@ -35,10 +35,10 @@
         </MediaCodec>
         <MediaCodec name="OMX.google.h264.decoder" type="video/avc">
             <!-- profiles and levels:  ProfileHigh : Level52 -->
-            <Limit name="size" min="2x2" max="4096x4096" />
+            <Limit name="size" min="2x2" max="4080x4080" />
             <Limit name="alignment" value="2x2" />
             <Limit name="block-size" value="16x16" />
-            <Limit name="block-count" range="1-32768" /> <!-- max 4096x2048 -->
+            <Limit name="block-count" range="1-32768" /> <!-- max 4096x2048 equivalent -->
             <Limit name="blocks-per-second" range="1-1966080" />
             <Limit name="bitrate" range="1-48000000" />
             <Feature name="adaptive-playback" />
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index 4a4c538..c9d7dde 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -62,6 +62,7 @@
     virtual sp<MetaData> getMetaData();
     virtual uint32_t flags() const;
     virtual const char * name() { return "MPEG4Extractor"; }
+    virtual void release();
 
     // for DRM
     virtual char* getDrmTrackInfo(size_t trackID, int *len);
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 836534d..1030407 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -314,6 +314,8 @@
     SoftwareRenderer *mSoftRenderer;
 
     MediaAnalyticsItem *mAnalyticsItem;
+    void initAnalyticsItem();
+    void flushAnalyticsItem();
 
     sp<AMessage> mOutputFormat;
     sp<AMessage> mInputFormat;
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractor.h b/media/libstagefright/include/media/stagefright/MediaExtractor.h
index f12160b..6ec7eaf 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractor.h
@@ -72,6 +72,8 @@
 
     virtual const char * name() { return "<unspecified>"; }
 
+    virtual void release() {}
+
 protected:
     MediaExtractor();
     virtual ~MediaExtractor();
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
index 3697429..3201c32 100644
--- a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
@@ -67,7 +67,14 @@
         tMsg.data.eventData.data1 = dataSpace;
         tMsg.data.eventData.data2 = aspects;
         tMsg.data.eventData.data3 = pixelFormat;
-        mOmxNode->dispatchMessage(tMsg);
+        if (!mOmxNode->dispatchMessage(tMsg).isOk()) {
+            ALOGE("TWOmxNodeWrapper failed to dispatch message "
+                    "OMX_EventDataSpaceChanged: "
+                    "dataSpace = %ld, aspects = %ld, pixelFormat = %ld",
+                    static_cast<long>(dataSpace),
+                    static_cast<long>(aspects),
+                    static_cast<long>(pixelFormat));
+        }
     }
 };
 
@@ -143,10 +150,13 @@
                         outParams.data() + outParams.size(),
                         params);
             });
-    omxNode->getParameter(
+    auto transStatus = omxNode->getParameter(
             static_cast<uint32_t>(OMX_IndexParamConsumerUsageBits),
             inHidlBytes(&consumerUsage, sizeof(consumerUsage)),
             _hidl_cb);
+    if (!transStatus.isOk()) {
+        return toStatus(FAILED_TRANSACTION);
+    }
     if (fnStatus != OK) {
         consumerUsage = 0;
     }
@@ -157,10 +167,13 @@
 
     _params = &def;
     params = static_cast<uint8_t*>(_params);
-    omxNode->getParameter(
+    transStatus = omxNode->getParameter(
             static_cast<uint32_t>(OMX_IndexParamPortDefinition),
             inHidlBytes(&def, sizeof(def)),
             _hidl_cb);
+    if (!transStatus.isOk()) {
+        return toStatus(FAILED_TRANSACTION);
+    }
     if (fnStatus != NO_ERROR) {
         ALOGE("Failed to get port definition: %d", fnStatus);
         return toStatus(fnStatus);
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 109460d..1917d2a 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -956,28 +956,40 @@
     Mutex::Autolock lock(mMutex);
 
     uint64_t slotMask;
-    if (mConsumer->getReleasedBuffers(&slotMask) != NO_ERROR) {
-        ALOGW("onBuffersReleased: unable to get released buffer set");
+    uint64_t releaseMask;
+    if (mConsumer->getReleasedBuffers(&releaseMask) != NO_ERROR) {
         slotMask = 0xffffffffffffffffULL;
+        ALOGW("onBuffersReleased: unable to get released buffer set");
+    } else {
+        slotMask = releaseMask;
+        ALOGV("onBuffersReleased: 0x%016" PRIx64, slotMask);
     }
 
-    ALOGV("onBuffersReleased: 0x%016" PRIx64, slotMask);
-
+    AString unpopulated;
     for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
         if ((slotMask & 0x01) != 0) {
-            discardBufferInSlot_l(i);
+            if (!discardBufferInSlot_l(i)) {
+                if (!unpopulated.empty()) {
+                    unpopulated.append(", ");
+                }
+                unpopulated.append(i);
+            }
         }
         slotMask >>= 1;
     }
+    if (!unpopulated.empty()) {
+        ALOGW("released unpopulated slots: [%s]", unpopulated.c_str());
+    }
 }
 
-void GraphicBufferSource::discardBufferInSlot_l(GraphicBufferSource::slot_id i) {
+bool GraphicBufferSource::discardBufferInSlot_l(GraphicBufferSource::slot_id i) {
     ssize_t bsi = mBufferSlots.indexOfKey(i);
     if (bsi < 0) {
-        ALOGW("releasing an unpopulated slot: %d", i);
+        return false;
     } else {
         discardBufferAtSlotIndex_l(bsi);
         mBufferSlots.removeItemsAt(bsi);
+        return true;
     }
 }
 
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index c749454..015a148 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -372,6 +372,8 @@
     mPortMode[1] = IOMX::kPortModePresetByteBuffer;
     mSecureBufferType[0] = kSecureBufferTypeUnknown;
     mSecureBufferType[1] = kSecureBufferTypeUnknown;
+    mGraphicBufferEnabled[0] = false;
+    mGraphicBufferEnabled[1] = false;
     mIsSecure = AString(name).endsWith(".secure");
     mLegacyAdaptiveExperiment = ADebug::isExperimentEnabled("legacy-adaptive");
 }
@@ -495,6 +497,9 @@
             LOG_ALWAYS_FATAL("unknown state %s(%#x).", asString(state), state);
             break;
     }
+
+    Mutex::Autolock _l(mLock);
+
     status_t err = mOwner->freeNode(this);
 
     mDispatcher.clear();
@@ -674,6 +679,11 @@
         return BAD_VALUE;
     }
 
+    if (mSailed || mNumPortBuffers[portIndex] > 0) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return INVALID_OPERATION;
+    }
+
     CLOG_CONFIG(setPortMode, "%s(%d), port %d", asString(mode), mode, portIndex);
 
     switch (mode) {
@@ -805,6 +815,12 @@
             } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
                 mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
             }
+        } else {
+            if (err == OMX_ErrorNone) {
+                mGraphicBufferEnabled[portIndex] = enable;
+            } else if (enable) {
+                mGraphicBufferEnabled[portIndex] = false;
+            }
         }
     } else {
         CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
@@ -1073,6 +1089,12 @@
     OMX_ERRORTYPE err = OMX_ErrorNone;
     bool isMetadata = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
 
+    if (!isMetadata && mGraphicBufferEnabled[portIndex]) {
+        ALOGE("b/62948670");
+        android_errorWriteLog(0x534e4554, "62948670");
+        return INVALID_OPERATION;
+    }
+
     size_t paramsSize;
     void* paramsPointer;
     if (params != NULL && hParams != NULL) {
@@ -1258,6 +1280,13 @@
                 portIndex, graphicBuffer, buffer);
     }
 
+    if (!mGraphicBufferEnabled[portIndex]) {
+        // Report error if this is not in graphic buffer mode.
+        ALOGE("b/62948670");
+        android_errorWriteLog(0x534e4554, "62948670");
+        return INVALID_OPERATION;
+    }
+
     // See if the newer version of the extension is present.
     OMX_INDEXTYPE index;
     if (OMX_GetExtensionIndex(
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/include/media/stagefright/omx/GraphicBufferSource.h
index 0f2d9a6..84fee6f 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/GraphicBufferSource.h
@@ -264,8 +264,8 @@
     void onBufferAcquired_l(const VideoBuffer &buffer);
 
     // marks the buffer at the slot no longer cached, and accounts for the outstanding
-    // acquire count
-    void discardBufferInSlot_l(slot_id i);
+    // acquire count. Returns true if the slot was populated; otherwise, false.
+    bool discardBufferInSlot_l(slot_id i);
 
     // marks the buffer at the slot index no longer cached, and accounts for the outstanding
     // acquire count
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
index 19114e2..1065ca5 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
@@ -152,7 +152,7 @@
 
     bool mLegacyAdaptiveExperiment;
     IOMX::PortMode mPortMode[2];
-    // metadata and secure buffer type tracking
+    // metadata and secure buffer types and graphic buffer mode tracking
     MetadataBufferType mMetadataType[2];
     enum SecureBufferType {
         kSecureBufferTypeUnknown,
@@ -160,6 +160,7 @@
         kSecureBufferTypeNativeHandle,
     };
     SecureBufferType mSecureBufferType[2];
+    bool mGraphicBufferEnabled[2];
 
     // Following are OMX parameters managed by us (instead of the component)
     // OMX_IndexParamMaxFrameDurationForBitrateControl
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index bbd1807..ffd30ea 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -986,6 +986,12 @@
         for (const auto& type : typeMap) {
             const auto& typeName = type.first;
             const char* roleName = GetComponentRole(isEncoder, typeName.data());
+            if (roleName == nullptr) {
+                ALOGE("Cannot find the role for %s of type %s",
+                        isEncoder ? "an encoder" : "a decoder",
+                        typeName.data());
+                continue;
+            }
             const auto& typeAttributeMap = type.second;
 
             auto roleIterator = mRoleMap.find(roleName);
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 4132fed..8d894c1 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -62,6 +62,8 @@
 constexpr int USB_FFS_MAX_WRITE = MTP_BUFFER_SIZE;
 constexpr int USB_FFS_MAX_READ = MTP_BUFFER_SIZE;
 
+constexpr unsigned FFS_NUM_EVENTS = 5;
+
 static_assert(USB_FFS_MAX_WRITE > 0, "Max r/w values must be > 0!");
 static_assert(USB_FFS_MAX_READ > 0, "Max r/w values must be > 0!");
 
@@ -102,8 +104,11 @@
     __le32 fs_count;
     __le32 hs_count;
     __le32 ss_count;
+    __le32 os_count;
     struct func_desc fs_descs, hs_descs;
     struct ss_func_desc ss_descs;
+    struct usb_os_desc_header os_header;
+    struct usb_ext_compat_desc os_desc;
 } __attribute__((packed));
 
 const struct usb_interface_descriptor mtp_interface_desc = {
@@ -287,6 +292,36 @@
     },
 };
 
+struct usb_os_desc_header mtp_os_desc_header = {
+    .interface = htole32(1),
+    .dwLength = htole32(sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc)),
+    .bcdVersion = htole16(1),
+    .wIndex = htole16(4),
+    .bCount = htole16(1),
+    .Reserved = htole16(0),
+};
+
+struct usb_ext_compat_desc mtp_os_desc_compat = {
+    .bFirstInterfaceNumber = 0,
+    .Reserved1 = htole32(1),
+    .CompatibleID = { 'M', 'T', 'P' },
+    .SubCompatibleID = {0},
+    .Reserved2 = {0},
+};
+
+struct usb_ext_compat_desc ptp_os_desc_compat = {
+    .bFirstInterfaceNumber = 0,
+    .Reserved1 = htole32(1),
+    .CompatibleID = { 'P', 'T', 'P' },
+    .SubCompatibleID = {0},
+    .Reserved2 = {0},
+};
+
+struct mtp_device_status {
+    uint16_t  wLength;
+    uint16_t  wCode;
+};
+
 } // anonymous namespace
 
 namespace android {
@@ -311,13 +346,16 @@
     v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
     v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor));
     v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
-                                 FUNCTIONFS_HAS_SS_DESC;
+                                 FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
     v2_descriptor.fs_count = 4;
     v2_descriptor.hs_count = 4;
     v2_descriptor.ss_count = 7;
+    v2_descriptor.os_count = 1;
     v2_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
     v2_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
     v2_descriptor.ss_descs = mPtp ? ptp_ss_descriptors : mtp_ss_descriptors;
+    v2_descriptor.os_header = mtp_os_desc_header;
+    v2_descriptor.os_desc = mPtp ? ptp_os_desc_compat : mtp_os_desc_compat;
 
     if (mControl < 0) { // might have already done this before
         mControl.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP0, O_RDWR)));
@@ -361,6 +399,88 @@
     mControl.reset();
 }
 
+void MtpFfsHandle::controlLoop() {
+    while (!handleEvent()) {}
+    LOG(DEBUG) << "Mtp server shutting down";
+}
+
+int MtpFfsHandle::handleEvent() {
+    std::vector<usb_functionfs_event> events(FFS_NUM_EVENTS);
+    usb_functionfs_event *event = events.data();
+    int nbytes = TEMP_FAILURE_RETRY(::read(mControl, event,
+                events.size() * sizeof(usb_functionfs_event)));
+    if (nbytes == -1) {
+        return -1;
+    }
+    int ret = 0;
+    for (size_t n = nbytes / sizeof *event; n; --n, ++event) {
+        switch (event->type) {
+        case FUNCTIONFS_BIND:
+        case FUNCTIONFS_ENABLE:
+        case FUNCTIONFS_RESUME:
+            ret = 0;
+            errno = 0;
+            break;
+        case FUNCTIONFS_SUSPEND:
+        case FUNCTIONFS_UNBIND:
+        case FUNCTIONFS_DISABLE:
+            errno = ESHUTDOWN;
+            ret = -1;
+            break;
+        case FUNCTIONFS_SETUP:
+            if (handleControlRequest(&event->u.setup) == -1)
+                ret = -1;
+            break;
+        default:
+            LOG(DEBUG) << "Mtp Event " << event->type << " (unknown)";
+        }
+    }
+    return ret;
+}
+
+int MtpFfsHandle::handleControlRequest(const struct usb_ctrlrequest *setup) {
+    uint8_t type = setup->bRequestType;
+    uint8_t code = setup->bRequest;
+    uint16_t length = setup->wLength;
+    uint16_t index = setup->wIndex;
+    uint16_t value = setup->wValue;
+    std::vector<char> buf;
+    buf.resize(length);
+
+    if (!(type & USB_DIR_IN)) {
+        if (::read(mControl, buf.data(), length) != length) {
+            PLOG(DEBUG) << "Mtp error ctrlreq read data";
+        }
+    }
+
+    if ((type & USB_TYPE_MASK) == USB_TYPE_CLASS && index == 0 && value == 0) {
+        switch(code) {
+        case MTP_REQ_GET_DEVICE_STATUS:
+        {
+            if (length < sizeof(struct mtp_device_status)) {
+                return -1;
+            }
+            struct mtp_device_status *st = reinterpret_cast<struct mtp_device_status*>(buf.data());
+            st->wLength = htole16(sizeof(st));
+            st->wCode = MTP_RESPONSE_OK;
+            length = st->wLength;
+            break;
+        }
+        default:
+            LOG(DEBUG) << "Unrecognized Mtp class request! " << code;
+        }
+    } else {
+        LOG(DEBUG) << "Unrecognized request type " << type;
+    }
+
+    if (type & USB_DIR_IN) {
+        if (::write(mControl, buf.data(), length) != length) {
+            PLOG(DEBUG) << "Mtp error ctrlreq write data";
+        }
+    }
+    return 0;
+}
+
 int MtpFfsHandle::writeHandle(int fd, const void* data, int len) {
     LOG(VERBOSE) << "MTP about to write fd = " << fd << ", len=" << len;
     int ret = 0;
@@ -460,6 +580,10 @@
     posix_madvise(mBuffer2.data(), MAX_FILE_CHUNK_SIZE,
             POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED);
 
+    // Handle control requests.
+    std::thread t([this]() { this->controlLoop(); });
+    t.detach();
+
     // Get device specific r/w size
     mMaxWrite = android::base::GetIntProperty("sys.usb.ffs.max_write", USB_FFS_MAX_WRITE);
     mMaxRead = android::base::GetIntProperty("sys.usb.ffs.max_read", USB_FFS_MAX_READ);
@@ -542,6 +666,7 @@
     size_t length;
     bool read = false;
     bool write = false;
+    bool short_packet = false;
 
     posix_fadvise(mfr.fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE);
 
@@ -586,6 +711,7 @@
                 // For larger files, receive until a short packet is received.
                 if (static_cast<size_t>(ret) < length) {
                     file_length = 0;
+                    short_packet = true;
                 }
             } else {
                 // Receive an empty packet if size is a multiple of the endpoint size.
@@ -605,7 +731,7 @@
             read = false;
         }
     }
-    if (ret % packet_size == 0 || zero_packet) {
+    if ((ret % packet_size == 0 && !short_packet) || zero_packet) {
         if (TEMP_FAILURE_RETRY(::read(mBulkOut, data, packet_size)) != 0) {
             return -1;
         }
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
index b637d65..da0cd9f 100644
--- a/media/mtp/MtpFfsHandle.h
+++ b/media/mtp/MtpFfsHandle.h
@@ -35,6 +35,10 @@
     void closeEndpoints();
     void doSendEvent(mtp_event me);
 
+    void controlLoop();
+    int handleEvent();
+    int handleControlRequest(const struct usb_ctrlrequest *setup);
+
     bool mPtp;
 
     std::timed_mutex mLock;
diff --git a/media/mtp/mtp.h b/media/mtp/mtp.h
index 13cc859..1c7829d 100644
--- a/media/mtp/mtp.h
+++ b/media/mtp/mtp.h
@@ -494,4 +494,10 @@
 #define MTP_ASSOCIATION_TYPE_UNDEFINED              0x0000
 #define MTP_ASSOCIATION_TYPE_GENERIC_FOLDER         0x0001
 
+// MTP class reqeusts
+#define MTP_REQ_CANCEL              0x64
+#define MTP_REQ_GET_EXT_EVENT_DATA  0x65
+#define MTP_REQ_RESET               0x66
+#define MTP_REQ_GET_DEVICE_STATUS   0x67
+
 #endif // _MTP_H
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
index 6d28d1b..c4ff537 100644
--- a/media/ndk/NdkImage.cpp
+++ b/media/ndk/NdkImage.cpp
@@ -58,11 +58,13 @@
         return;
     }
     sp<AImageReader> reader = mReader.promote();
-    if (reader == nullptr) {
-        LOG_ALWAYS_FATAL("Error: AImage not closed before AImageReader close!");
-        return;
+    if (reader != nullptr) {
+        reader->releaseImageLocked(this, releaseFenceFd);
+    } else if (mBuffer != nullptr) {
+        LOG_ALWAYS_FATAL("%s: parent AImageReader closed without releasing image %p",
+                __FUNCTION__, this);
     }
-    reader->releaseImageLocked(this, releaseFenceFd);
+
     // Should have been set to nullptr in releaseImageLocked
     // Set to nullptr here for extra safety only
     mBuffer = nullptr;
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index a450dd3..fd6ecb5 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -349,7 +349,8 @@
     for (auto it = mAcquiredImages.begin();
               it != mAcquiredImages.end(); it++) {
         AImage* image = *it;
-        image->close();
+        Mutex::Autolock _l(image->mLock);
+        releaseImageLocked(image, /*releaseFenceFd*/-1);
     }
 
     // Delete Buffer Items
@@ -501,6 +502,8 @@
     mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
     returnBufferItemLocked(buffer);
     image->mBuffer = nullptr;
+    image->mLockedBuffer = nullptr;
+    image->mIsClosed = true;
 
     bool found = false;
     // cleanup acquired image list
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index 989b937..bed8a21 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -85,7 +85,7 @@
     // Called by AImageReader_acquireXXX to acquire a Buffer and setup AImage.
     media_status_t acquireImageLocked(/*out*/AImage** image, /*out*/int* fenceFd);
 
-    // Called by AImage to close image
+    // Called by AImage/~AImageReader to close image. Caller is responsible to grab AImage::mLock
     void releaseImageLocked(AImage* image, int releaseFenceFd);
 
     static int getBufferWidth(BufferItem* buffer);
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 51143ac..eecc858 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -421,7 +421,7 @@
 
     for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
         keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
-        keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
+        keyValuePairs[i].mValue = mObj->mQueryResults.valueAt(i).string();
     }
     *numPairs = mObj->mQueryResults.size();
     return AMEDIA_OK;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 13522f5..39f04fb 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -329,6 +329,11 @@
         thread->configure(attr, streamType, sessionId, callback, *deviceId, portId);
         *handle = portId;
     } else {
+        if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
+            AudioSystem::releaseOutput(io, streamType, sessionId);
+        } else {
+            AudioSystem::releaseInput(io, sessionId);
+        }
         ret = NO_INIT;
     }
 
@@ -1397,11 +1402,11 @@
     // the config change is always sent from playback or record threads to avoid deadlock
     // with AudioSystem::gLock
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-        mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_OPENED, pid);
+        mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_REGISTERED, pid);
     }
 
     for (size_t i = 0; i < mRecordThreads.size(); i++) {
-        mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_OPENED, pid);
+        mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_REGISTERED, pid);
     }
 }
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 297608c..e202ca4 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -197,7 +197,7 @@
 // Initially this heap is used to allocate client buffers for "fast" AudioRecord.
 // Eventually it will be the single buffer that FastCapture writes into via HAL read(),
 // and that all "fast" AudioRecord clients read from.  In either case, the size can be small.
-static const size_t kRecordThreadReadOnlyHeapSize = 0x2000;
+static const size_t kRecordThreadReadOnlyHeapSize = 0x4000;
 
 // ----------------------------------------------------------------------------
 
@@ -1668,7 +1668,8 @@
         mScreenState(AudioFlinger::mScreenState),
         // index 0 is reserved for normal mixer's submix
         mFastTrackAvailMask(((1 << FastMixerState::sMaxFastTracks) - 1) & ~1),
-        mHwSupportsPause(false), mHwPaused(false), mFlushPending(false)
+        mHwSupportsPause(false), mHwPaused(false), mFlushPending(false),
+        mLeftVolFloat(-1.0), mRightVolFloat(-1.0)
 {
     snprintf(mThreadName, kThreadNameLength, "AudioOut_%X", id);
     mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
@@ -2253,6 +2254,7 @@
 
     switch (event) {
     case AUDIO_OUTPUT_OPENED:
+    case AUDIO_OUTPUT_REGISTERED:
     case AUDIO_OUTPUT_CONFIG_CHANGED:
         desc->mPatch = mPatch;
         desc->mChannelMask = mChannelMask;
@@ -4294,6 +4296,7 @@
                     param = AudioMixer::RAMP_VOLUME;
                 }
                 mAudioMixer->setParameter(name, AudioMixer::RESAMPLE, AudioMixer::RESET, NULL);
+                mLeftVolFloat = -1.0;
             // FIXME should not make a decision based on mServer
             } else if (cblk->mServer != 0) {
                 // If the track is stopped before the first frame was mixed,
@@ -4304,6 +4307,10 @@
             // compute volume for this track
             uint32_t vl, vr;       // in U8.24 integer format
             float vlf, vrf, vaf;   // in [0.0, 1.0] float format
+            // read original volumes with volume control
+            float typeVolume = mStreamTypes[track->streamType()].volume;
+            float v = masterVolume * typeVolume;
+
             if (track->isPausing() || mStreamTypes[track->streamType()].mute) {
                 vl = vr = 0;
                 vlf = vrf = vaf = 0.;
@@ -4311,10 +4318,6 @@
                     track->setPaused();
                 }
             } else {
-
-                // read original volumes with volume control
-                float typeVolume = mStreamTypes[track->streamType()].volume;
-                float v = masterVolume * typeVolume;
                 sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
                 gain_minifloat_packed_t vlr = proxy->getVolumeLR();
                 vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
@@ -4366,6 +4369,25 @@
                 track->mHasVolumeController = false;
             }
 
+            // For dedicated VoIP outputs, let the HAL apply the stream volume. Track volume is
+            // still applied by the mixer.
+            if ((mOutput->flags & AUDIO_OUTPUT_FLAG_VOIP_RX) != 0) {
+                v = mStreamTypes[track->streamType()].mute ? 0.0f : v;
+                if (v != mLeftVolFloat) {
+                    status_t result = mOutput->stream->setVolume(v, v);
+                    ALOGE_IF(result != OK, "Error when setting output stream volume: %d", result);
+                    if (result == OK) {
+                        mLeftVolFloat = v;
+                    }
+                }
+                // if stream volume was successfully sent to the HAL, mLeftVolFloat == v here and we
+                // remove stream volume contribution from software volume.
+                if (v != 0.0f && mLeftVolFloat == v) {
+                   vlf = min(1.0f, vlf / v);
+                   vrf = min(1.0f, vrf / v);
+                   vaf = min(1.0f, vaf / v);
+               }
+            }
             // XXX: these things DON'T need to be done each time
             mAudioMixer->setBufferProvider(name, track);
             mAudioMixer->enable(name);
@@ -4807,7 +4829,6 @@
 AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
         AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device, bool systemReady)
     :   PlaybackThread(audioFlinger, output, id, device, DIRECT, systemReady)
-        // mLeftVolFloat, mRightVolFloat
 {
 }
 
@@ -4815,7 +4836,6 @@
         AudioStreamOut* output, audio_io_handle_t id, uint32_t device,
         ThreadBase::type_t type, bool systemReady)
     :   PlaybackThread(audioFlinger, output, id, device, type, systemReady)
-        // mLeftVolFloat, mRightVolFloat
         , mVolumeShaperActive(false)
 {
 }
@@ -7242,6 +7262,7 @@
 
     switch (event) {
     case AUDIO_INPUT_OPENED:
+    case AUDIO_INPUT_REGISTERED:
     case AUDIO_INPUT_CONFIG_CHANGED:
         desc->mPatch = mPatch;
         desc->mChannelMask = mChannelMask;
@@ -7913,8 +7934,10 @@
 
     switch (event) {
     case AUDIO_INPUT_OPENED:
+    case AUDIO_INPUT_REGISTERED:
     case AUDIO_INPUT_CONFIG_CHANGED:
     case AUDIO_OUTPUT_OPENED:
+    case AUDIO_OUTPUT_REGISTERED:
     case AUDIO_OUTPUT_CONFIG_CHANGED:
         desc->mPatch = mPatch;
         desc->mChannelMask = mChannelMask;
@@ -8125,10 +8148,8 @@
 
 void AudioFlinger::MmapThread::threadLoop_exit()
 {
-    sp<MmapStreamCallback> callback = mCallback.promote();
-    if (callback != 0) {
-        callback->onTearDown();
-    }
+    // Do not call callback->onTearDown() because it is redundant for thread exit
+    // and because it can cause a recursive mutex lock on stop().
 }
 
 status_t AudioFlinger::MmapThread::setSyncEvent(const sp<SyncEvent>& event __unused)
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 8d7bb1a..dd2b89b 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -999,6 +999,9 @@
                 bool        mHwSupportsPause;
                 bool        mHwPaused;
                 bool        mFlushPending;
+                // volumes last sent to audio HAL with stream->setVolume()
+                float mLeftVolFloat;
+                float mRightVolFloat;
 };
 
 class MixerThread : public PlaybackThread {
@@ -1116,9 +1119,6 @@
 
     virtual     void        onAddNewTrack_l();
 
-    // volumes last sent to audio HAL with stream->set_volume()
-    float mLeftVolFloat;
-    float mRightVolFloat;
     bool mVolumeShaperActive;
 
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
diff --git a/services/audiopolicy/common/managerdefinitions/src/SoundTriggerSession.cpp b/services/audiopolicy/common/managerdefinitions/src/SoundTriggerSession.cpp
index 8ca3ae0..0383b0e 100644
--- a/services/audiopolicy/common/managerdefinitions/src/SoundTriggerSession.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/SoundTriggerSession.cpp
@@ -34,7 +34,7 @@
 {
     ssize_t index = indexOfKey(session);
     if (index < 0) {
-        ALOGW("acquireSoundTriggerSession() session %d not registered", session);
+        ALOGW("releaseSession() session %d not registered", session);
         return BAD_VALUE;
     }
 
diff --git a/services/audiopolicy/config/primary_audio_policy_configuration.xml b/services/audiopolicy/config/primary_audio_policy_configuration.xml
index bf508ac..5b7ae7f 100644
--- a/services/audiopolicy/config/primary_audio_policy_configuration.xml
+++ b/services/audiopolicy/config/primary_audio_policy_configuration.xml
@@ -13,7 +13,7 @@
         </mixPort>
         <mixPort name="primary input" role="sink">
             <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                     samplingRates="8000, 16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                     samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
         </mixPort>
    </mixPorts>
    <devicePorts>
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index e6ee6c9..bdfaf2f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1499,62 +1499,13 @@
             "session %d, flags %#x",
           attr->source, config->sample_rate, config->format, config->channel_mask, session, flags);
 
-    // special case for mmap capture: if an input IO handle is specified, we reuse this input if
-    // possible
-    if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
-            *input != AUDIO_IO_HANDLE_NONE) {
-        ssize_t index = mInputs.indexOfKey(*input);
-        if (index < 0) {
-            ALOGW("getInputForAttr() unknown MMAP input %d", *input);
-            return BAD_VALUE;
-        }
-        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
-        sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
-        if (audioSession == 0) {
-            ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
-            return BAD_VALUE;
-        }
-        // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
-        // The second call is for the first active client and sets the UID. Any further call
-        // corresponds to a new client and is only permitted from the same UId.
-        if (audioSession->openCount() == 1) {
-            audioSession->setUid(uid);
-        } else if (audioSession->uid() != uid) {
-            ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
-                  uid, session, audioSession->uid());
-            return INVALID_OPERATION;
-        }
-        audioSession->changeOpenCount(1);
-        *inputType = API_INPUT_LEGACY;
-        if (*portId == AUDIO_PORT_HANDLE_NONE) {
-            *portId = AudioPort::getNextUniqueId();
-        }
-        DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice);
-        *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
-                : AUDIO_PORT_HANDLE_NONE;
-        ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
-        return NO_ERROR;
-    }
-
-    *input = AUDIO_IO_HANDLE_NONE;
-    *inputType = API_INPUT_INVALID;
-
-    audio_devices_t device;
+    status_t status = NO_ERROR;
     // handle legacy remote submix case where the address was not always specified
     String8 address = String8("");
-    audio_source_t inputSource = attr->source;
     audio_source_t halInputSource;
+    audio_source_t inputSource = attr->source;
     AudioMix *policyMix = NULL;
-
-    if (inputSource == AUDIO_SOURCE_DEFAULT) {
-        inputSource = AUDIO_SOURCE_MIC;
-    }
-    halInputSource = inputSource;
-
-    // TODO: check for existing client for this port ID
-    if (*portId == AUDIO_PORT_HANDLE_NONE) {
-        *portId = AudioPort::getNextUniqueId();
-    }
+    DeviceVector inputDevices;
 
     // Explicit routing?
     sp<DeviceDescriptor> deviceDesc;
@@ -1568,11 +1519,67 @@
     }
     mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid);
 
+    // special case for mmap capture: if an input IO handle is specified, we reuse this input if
+    // possible
+    if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
+            *input != AUDIO_IO_HANDLE_NONE) {
+        ssize_t index = mInputs.indexOfKey(*input);
+        if (index < 0) {
+            ALOGW("getInputForAttr() unknown MMAP input %d", *input);
+            status = BAD_VALUE;
+            goto error;
+        }
+        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
+        sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
+        if (audioSession == 0) {
+            ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
+            status = BAD_VALUE;
+            goto error;
+        }
+        // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
+        // The second call is for the first active client and sets the UID. Any further call
+        // corresponds to a new client and is only permitted from the same UId.
+        if (audioSession->openCount() == 1) {
+            audioSession->setUid(uid);
+        } else if (audioSession->uid() != uid) {
+            ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
+                  uid, session, audioSession->uid());
+            status = INVALID_OPERATION;
+            goto error;
+        }
+        audioSession->changeOpenCount(1);
+        *inputType = API_INPUT_LEGACY;
+        if (*portId == AUDIO_PORT_HANDLE_NONE) {
+            *portId = AudioPort::getNextUniqueId();
+        }
+        inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice);
+        *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
+                : AUDIO_PORT_HANDLE_NONE;
+        ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
+
+        return NO_ERROR;
+    }
+
+    *input = AUDIO_IO_HANDLE_NONE;
+    *inputType = API_INPUT_INVALID;
+
+    if (inputSource == AUDIO_SOURCE_DEFAULT) {
+        inputSource = AUDIO_SOURCE_MIC;
+    }
+    halInputSource = inputSource;
+
+    // TODO: check for existing client for this port ID
+    if (*portId == AUDIO_PORT_HANDLE_NONE) {
+        *portId = AudioPort::getNextUniqueId();
+    }
+
+    audio_devices_t device;
+
     if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
             strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
-        status_t ret = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
-        if (ret != NO_ERROR) {
-            return ret;
+        status = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
+        if (status != NO_ERROR) {
+            goto error;
         }
         *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
         device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
@@ -1581,7 +1588,8 @@
         device = getDeviceAndMixForInputSource(inputSource, &policyMix);
         if (device == AUDIO_DEVICE_NONE) {
             ALOGW("getInputForAttr() could not find device for source %d", inputSource);
-            return BAD_VALUE;
+            status = BAD_VALUE;
+            goto error;
         }
         if (policyMix != NULL) {
             address = policyMix->mDeviceAddress;
@@ -1610,11 +1618,11 @@
                                config->sample_rate, config->format, config->channel_mask, flags,
                                policyMix);
     if (*input == AUDIO_IO_HANDLE_NONE) {
-        mInputRoutes.removeRoute(session);
-        return INVALID_OPERATION;
+        status = INVALID_OPERATION;
+        goto error;
     }
 
-    DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(device);
+    inputDevices = mAvailableInputDevices.getDevicesFromType(device);
     *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
             : AUDIO_PORT_HANDLE_NONE;
 
@@ -1622,6 +1630,10 @@
             *input, *inputType, *selectedDeviceId);
 
     return NO_ERROR;
+
+error:
+    mInputRoutes.removeRoute(session);
+    return status;
 }
 
 
@@ -4926,12 +4938,13 @@
     // scan the whole RouteMap, for each entry, convert the stream type to a strategy
     // (getStrategy(stream)).
     // if the strategy from the stream type in the RouteMap is the same as the argument above,
-    // and activity count is non-zero
-    // the device = the device from the descriptor in the RouteMap, and exit.
+    // and activity count is non-zero and the device in the route descriptor is available
+    // then select this device.
     for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) {
         sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex);
         routing_strategy routeStrategy = getStrategy(route->mStreamType);
-        if ((routeStrategy == strategy) && route->isActive()) {
+        if ((routeStrategy == strategy) && route->isActive() &&
+                (mAvailableOutputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
             return route->mDeviceDescriptor->type();
         }
     }
@@ -5326,9 +5339,15 @@
 
 audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource)
 {
+    // Routing
+    // Scan the whole RouteMap to see if we have an explicit route:
+    // if the input source in the RouteMap is the same as the argument above,
+    // and activity count is non-zero and the device in the route descriptor is available
+    // then select this device.
     for (size_t routeIndex = 0; routeIndex < mInputRoutes.size(); routeIndex++) {
          sp<SessionRoute> route = mInputRoutes.valueAt(routeIndex);
-         if (inputSource == route->mSource && route->isActive()) {
+         if ((inputSource == route->mSource) && route->isActive() &&
+                 (mAvailableInputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
              return route->mDeviceDescriptor->type();
          }
      }
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 1d4386c..b7bce55 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -694,6 +694,7 @@
                                        audio_io_handle_t *ioHandle,
                                        audio_devices_t *device)
 {
+    Mutex::Autolock _l(mLock);
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
@@ -703,6 +704,7 @@
 
 status_t AudioPolicyService::releaseSoundTriggerSession(audio_session_t session)
 {
+    Mutex::Autolock _l(mLock);
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index f1cdea3..7ec3ccb 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -77,7 +77,8 @@
     android.hardware.camera.common@1.0 \
     android.hardware.camera.provider@2.4 \
     android.hardware.camera.device@1.0 \
-    android.hardware.camera.device@3.2
+    android.hardware.camera.device@3.2 \
+    android.hardware.camera.device@3.3
 
 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libcamera_client libfmq
 
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index a28518e..2cf648f 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -72,6 +72,20 @@
     return initializeImpl(manager);
 }
 
+bool Camera2Client::isZslEnabledInStillTemplate() {
+    bool zslEnabled = false;
+    CameraMetadata stillTemplate;
+    status_t res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_STILL_CAPTURE, &stillTemplate);
+    if (res == OK) {
+        camera_metadata_entry_t enableZsl = stillTemplate.find(ANDROID_CONTROL_ENABLE_ZSL);
+        if (enableZsl.count == 1) {
+            zslEnabled = (enableZsl.data.u8[0] == ANDROID_CONTROL_ENABLE_ZSL_TRUE);
+        }
+    }
+
+    return zslEnabled;
+}
+
 template<typename TProviderPtr>
 status_t Camera2Client::initializeImpl(TProviderPtr providerPtr)
 {
@@ -93,6 +107,8 @@
                     __FUNCTION__, mCameraId, strerror(-res), res);
             return NO_INIT;
         }
+
+        l.mParameters.isDeviceZslSupported = isZslEnabledInStillTemplate();
     }
 
     String8 threadName;
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 72315d4..5af74eb 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -224,6 +224,8 @@
 
     template<typename TProviderPtr>
     status_t initializeImpl(TProviderPtr providerPtr);
+
+    bool isZslEnabledInStillTemplate();
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
index 3f4017f..0d2dba1 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
@@ -121,18 +121,17 @@
 
     if (mCallbackStreamId != NO_STREAM) {
         // Check if stream parameters have to change
-        uint32_t currentWidth, currentHeight, currentFormat;
-        res = device->getStreamInfo(mCallbackStreamId,
-                &currentWidth, &currentHeight, &currentFormat, 0);
+        CameraDeviceBase::StreamInfo streamInfo;
+        res = device->getStreamInfo(mCallbackStreamId, &streamInfo);
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying callback output stream info: "
                     "%s (%d)", __FUNCTION__, mId,
                     strerror(-res), res);
             return res;
         }
-        if (currentWidth != (uint32_t)params.previewWidth ||
-                currentHeight != (uint32_t)params.previewHeight ||
-                currentFormat != (uint32_t)callbackFormat) {
+        if (streamInfo.width != (uint32_t)params.previewWidth ||
+                streamInfo.height != (uint32_t)params.previewHeight ||
+                !streamInfo.matchFormat((uint32_t)callbackFormat)) {
             // Since size should only change while preview is not running,
             // assuming that all existing use of old callback stream is
             // completed.
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index d6d8dde..d8b7af2 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -136,17 +136,16 @@
 
     if (mCaptureStreamId != NO_STREAM) {
         // Check if stream parameters have to change
-        uint32_t currentWidth, currentHeight;
-        res = device->getStreamInfo(mCaptureStreamId,
-                &currentWidth, &currentHeight, 0, 0);
+        CameraDeviceBase::StreamInfo streamInfo;
+        res = device->getStreamInfo(mCaptureStreamId, &streamInfo);
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying capture output stream info: "
                     "%s (%d)", __FUNCTION__,
                     mId, strerror(-res), res);
             return res;
         }
-        if (currentWidth != (uint32_t)params.pictureWidth ||
-                currentHeight != (uint32_t)params.pictureHeight) {
+        if (streamInfo.width != (uint32_t)params.pictureWidth ||
+                streamInfo.height != (uint32_t)params.pictureHeight) {
             ALOGV("%s: Camera %d: Deleting stream %d since the buffer dimensions changed",
                 __FUNCTION__, mId, mCaptureStreamId);
             res = device->deleteStream(mCaptureStreamId);
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index a305bc7..6fb5c21 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -954,7 +954,8 @@
         }
     }
 
-    if (slowJpegMode || property_get_bool("camera.disable_zsl_mode", false)) {
+    if (isDeviceZslSupported || slowJpegMode ||
+            property_get_bool("camera.disable_zsl_mode", false)) {
         ALOGI("Camera %d: Disabling ZSL mode", cameraId);
         allowZslMode = false;
     } else {
@@ -1997,7 +1998,8 @@
     if (previewFpsRange[1] > 1e9/minFrameDurationNs + FPS_MARGIN) {
         slowJpegMode = true;
     }
-    if (slowJpegMode || property_get_bool("camera.disable_zsl_mode", false)) {
+    if (isDeviceZslSupported || slowJpegMode ||
+            property_get_bool("camera.disable_zsl_mode", false)) {
         allowZslMode = false;
     } else {
         allowZslMode = isZslReprocessPresent;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index bea867a..17e3d75 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -175,6 +175,8 @@
     bool slowJpegMode;
     // Whether ZSL reprocess is supported by the device.
     bool isZslReprocessPresent;
+    // Whether the device supports enableZsl.
+    bool isDeviceZslSupported;
 
     // Overall camera state
     enum State {
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index d79e430..73dca73 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -161,18 +161,17 @@
 
     if (mPreviewStreamId != NO_STREAM) {
         // Check if stream parameters have to change
-        uint32_t currentWidth, currentHeight;
-        res = device->getStreamInfo(mPreviewStreamId,
-                &currentWidth, &currentHeight, 0, 0);
+        CameraDeviceBase::StreamInfo streamInfo;
+        res = device->getStreamInfo(mPreviewStreamId, &streamInfo);
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying preview stream info: "
                     "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
             return res;
         }
-        if (currentWidth != (uint32_t)params.previewWidth ||
-                currentHeight != (uint32_t)params.previewHeight) {
+        if (streamInfo.width != (uint32_t)params.previewWidth ||
+                streamInfo.height != (uint32_t)params.previewHeight) {
             ALOGV("%s: Camera %d: Preview size switch: %d x %d -> %d x %d",
-                    __FUNCTION__, mId, currentWidth, currentHeight,
+                    __FUNCTION__, mId, streamInfo.width, streamInfo.height,
                     params.previewWidth, params.previewHeight);
             res = device->waitUntilDrained();
             if (res != OK) {
@@ -312,10 +311,8 @@
         return INVALID_OPERATION;
     }
 
-    uint32_t currentWidth, currentHeight, currentFormat;
-    android_dataspace currentDataSpace;
-    res = device->getStreamInfo(mRecordingStreamId,
-            &currentWidth, &currentHeight, &currentFormat, &currentDataSpace);
+    CameraDeviceBase::StreamInfo streamInfo;
+    res = device->getStreamInfo(mRecordingStreamId, &streamInfo);
     if (res != OK) {
         ALOGE("%s: Camera %d: Error querying recording output stream info: "
                 "%s (%d)", __FUNCTION__, mId,
@@ -324,10 +321,10 @@
     }
 
     if (mRecordingWindow == nullptr ||
-            currentWidth != (uint32_t)params.videoWidth ||
-            currentHeight != (uint32_t)params.videoHeight ||
-            currentFormat != (uint32_t)params.videoFormat ||
-            currentDataSpace != params.videoDataSpace) {
+            streamInfo.width != (uint32_t)params.videoWidth ||
+            streamInfo.height != (uint32_t)params.videoHeight ||
+            !streamInfo.matchFormat((uint32_t)params.videoFormat) ||
+            !streamInfo.matchDataSpace(params.videoDataSpace)) {
         *needsUpdate = true;
         return res;
     }
@@ -348,22 +345,18 @@
 
     if (mRecordingStreamId != NO_STREAM) {
         // Check if stream parameters have to change
-        uint32_t currentWidth, currentHeight;
-        uint32_t currentFormat;
-        android_dataspace currentDataSpace;
-        res = device->getStreamInfo(mRecordingStreamId,
-                &currentWidth, &currentHeight,
-                &currentFormat, &currentDataSpace);
+        CameraDeviceBase::StreamInfo streamInfo;
+        res = device->getStreamInfo(mRecordingStreamId, &streamInfo);
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying recording output stream info: "
                     "%s (%d)", __FUNCTION__, mId,
                     strerror(-res), res);
             return res;
         }
-        if (currentWidth != (uint32_t)params.videoWidth ||
-                currentHeight != (uint32_t)params.videoHeight ||
-                currentFormat != (uint32_t)params.videoFormat ||
-                currentDataSpace != params.videoDataSpace) {
+        if (streamInfo.width != (uint32_t)params.videoWidth ||
+                streamInfo.height != (uint32_t)params.videoHeight ||
+                !streamInfo.matchFormat((uint32_t)params.videoFormat) ||
+                !streamInfo.matchDataSpace(params.videoDataSpace)) {
             // TODO: Should wait to be sure previous recording has finished
             res = device->deleteStream(mRecordingStreamId);
 
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 9bc31b9..b0607fb 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -233,17 +233,16 @@
 
     if ((mZslStreamId != NO_STREAM) || (mInputStreamId != NO_STREAM)) {
         // Check if stream parameters have to change
-        uint32_t currentWidth, currentHeight;
-        res = device->getStreamInfo(mZslStreamId,
-                &currentWidth, &currentHeight, 0, 0);
+        CameraDeviceBase::StreamInfo streamInfo;
+        res = device->getStreamInfo(mZslStreamId, &streamInfo);
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying capture output stream info: "
                     "%s (%d)", __FUNCTION__,
                     client->getCameraId(), strerror(-res), res);
             return res;
         }
-        if (currentWidth != (uint32_t)params.fastInfo.arrayWidth ||
-                currentHeight != (uint32_t)params.fastInfo.arrayHeight) {
+        if (streamInfo.width != (uint32_t)params.fastInfo.arrayWidth ||
+                streamInfo.height != (uint32_t)params.fastInfo.arrayHeight) {
             if (mZslStreamId != NO_STREAM) {
                 ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
                       "dimensions changed",
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 6fd9263..c03e8a2 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -1354,7 +1354,7 @@
     sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
 
     if (remoteCb != 0) {
-        remoteCb->onRepeatingRequestError(lastFrameNumber);
+        remoteCb->onRepeatingRequestError(lastFrameNumber, mStreamingRequestId);
     }
 
     Mutex::Autolock idLock(mStreamingRequestIdLock);
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 54fcb0a..3919bfa 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -142,12 +142,51 @@
     virtual status_t createInputStream(uint32_t width, uint32_t height,
             int32_t format, /*out*/ int32_t *id) = 0;
 
+    struct StreamInfo {
+        uint32_t width;
+        uint32_t height;
+
+        uint32_t format;
+        bool formatOverridden;
+        uint32_t originalFormat;
+
+        android_dataspace dataSpace;
+        bool dataSpaceOverridden;
+        android_dataspace originalDataSpace;
+
+        StreamInfo() : width(0), height(0), format(0), formatOverridden(false), originalFormat(0),
+                dataSpace(HAL_DATASPACE_UNKNOWN), dataSpaceOverridden(false),
+                originalDataSpace(HAL_DATASPACE_UNKNOWN) {}
+        /**
+         * Check whether the format matches the current or the original one in case
+         * it got overridden.
+         */
+        bool matchFormat(uint32_t clientFormat) const {
+            if ((formatOverridden && (originalFormat == clientFormat)) ||
+                    (format == clientFormat)) {
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Check whether the dataspace matches the current or the original one in case
+         * it got overridden.
+         */
+        bool matchDataSpace(android_dataspace clientDataSpace) const {
+            if ((dataSpaceOverridden && (originalDataSpace == clientDataSpace)) ||
+                    (dataSpace == clientDataSpace)) {
+                return true;
+            }
+            return false;
+        }
+
+    };
+
     /**
      * Get information about a given stream.
      */
-    virtual status_t getStreamInfo(int id,
-            uint32_t *width, uint32_t *height,
-            uint32_t *format, android_dataspace *dataSpace) = 0;
+    virtual status_t getStreamInfo(int id, StreamInfo *streamInfo) = 0;
 
     /**
      * Set stream gralloc buffer transform
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 5addaf1..e6a6a21 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -202,12 +202,17 @@
     for (auto& provider : mProviders) {
         auto deviceInfo = findDeviceInfoLocked(id);
         if (deviceInfo != nullptr) {
-            provider->mInterface->isSetTorchModeSupported(
+            auto ret = provider->mInterface->isSetTorchModeSupported(
                 [&support](auto status, bool supported) {
                     if (status == Status::OK) {
                         support = supported;
                     }
                 });
+            if (!ret.isOk()) {
+                ALOGE("%s: Transaction error checking torch mode support '%s': %s",
+                        __FUNCTION__, provider->mProviderName.c_str(), ret.description().c_str());
+            }
+            break;
         }
     }
     return support;
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
index 991b50f..522d521 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
@@ -97,58 +97,78 @@
         ALOGE("%s: CameraHeapMemory has FD %d (expect >= 0)", __FUNCTION__, memPoolId);
         return 0;
     }
+    std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
     mHidlMemPoolMap.insert(std::make_pair(memPoolId, mem));
     return memPoolId;
 }
 
 hardware::Return<void> CameraHardwareInterface::unregisterMemory(uint32_t memId) {
-    if (mHidlMemPoolMap.count(memId) == 0) {
-        ALOGE("%s: memory pool ID %d not found", __FUNCTION__, memId);
-        return hardware::Void();
+    camera_memory_t* mem = nullptr;
+    {
+        std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+        if (mHidlMemPoolMap.count(memId) == 0) {
+            ALOGE("%s: memory pool ID %d not found", __FUNCTION__, memId);
+            return hardware::Void();
+        }
+        mem = mHidlMemPoolMap.at(memId);
+        mHidlMemPoolMap.erase(memId);
     }
-    camera_memory_t* mem = mHidlMemPoolMap.at(memId);
     sPutMemory(mem);
-    mHidlMemPoolMap.erase(memId);
     return hardware::Void();
 }
 
 hardware::Return<void> CameraHardwareInterface::dataCallback(
         DataCallbackMsg msgType, uint32_t data, uint32_t bufferIndex,
         const hardware::camera::device::V1_0::CameraFrameMetadata& metadata) {
-    if (mHidlMemPoolMap.count(data) == 0) {
-        ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
-        return hardware::Void();
+    camera_memory_t* mem = nullptr;
+    {
+        std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+        if (mHidlMemPoolMap.count(data) == 0) {
+            ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
+            return hardware::Void();
+        }
+        mem = mHidlMemPoolMap.at(data);
     }
     camera_frame_metadata_t md;
     md.number_of_faces = metadata.faces.size();
     md.faces = (camera_face_t*) metadata.faces.data();
-    sDataCb((int32_t) msgType, mHidlMemPoolMap.at(data), bufferIndex, &md, this);
+    sDataCb((int32_t) msgType, mem, bufferIndex, &md, this);
     return hardware::Void();
 }
 
 hardware::Return<void> CameraHardwareInterface::dataCallbackTimestamp(
         DataCallbackMsg msgType, uint32_t data,
         uint32_t bufferIndex, int64_t timestamp) {
-    if (mHidlMemPoolMap.count(data) == 0) {
-        ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
-        return hardware::Void();
+    camera_memory_t* mem = nullptr;
+    {
+        std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+        if (mHidlMemPoolMap.count(data) == 0) {
+            ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
+            return hardware::Void();
+        }
+        mem = mHidlMemPoolMap.at(data);
     }
-    sDataCbTimestamp(timestamp, (int32_t) msgType, mHidlMemPoolMap.at(data), bufferIndex, this);
+    sDataCbTimestamp(timestamp, (int32_t) msgType, mem, bufferIndex, this);
     return hardware::Void();
 }
 
 hardware::Return<void> CameraHardwareInterface::handleCallbackTimestamp(
         DataCallbackMsg msgType, const hidl_handle& frameData, uint32_t data,
         uint32_t bufferIndex, int64_t timestamp) {
-    if (mHidlMemPoolMap.count(data) == 0) {
-        ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
-        return hardware::Void();
+    camera_memory_t* mem = nullptr;
+    {
+        std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+        if (mHidlMemPoolMap.count(data) == 0) {
+            ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
+            return hardware::Void();
+        }
+        mem = mHidlMemPoolMap.at(data);
     }
-    sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(mHidlMemPoolMap.at(data)->handle));
+    sp<CameraHeapMemory> heapMem(static_cast<CameraHeapMemory *>(mem->handle));
     VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
-            mem->mBuffers[bufferIndex]->pointer();
+            heapMem->mBuffers[bufferIndex]->pointer();
     md->pHandle = const_cast<native_handle_t*>(frameData.getNativeHandle());
-    sDataCbTimestamp(timestamp, (int32_t) msgType, mHidlMemPoolMap.at(data), bufferIndex, this);
+    sDataCbTimestamp(timestamp, (int32_t) msgType, mem, bufferIndex, this);
     return hardware::Void();
 }
 
@@ -157,27 +177,28 @@
         const hardware::hidl_vec<hardware::camera::device::V1_0::HandleTimestampMessage>& messages) {
     std::vector<android::HandleTimestampMessage> msgs;
     msgs.reserve(messages.size());
+    {
+        std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+        for (const auto& hidl_msg : messages) {
+            if (mHidlMemPoolMap.count(hidl_msg.data) == 0) {
+                ALOGE("%s: memory pool ID %d not found", __FUNCTION__, hidl_msg.data);
+                return hardware::Void();
+            }
+            sp<CameraHeapMemory> mem(
+                    static_cast<CameraHeapMemory *>(mHidlMemPoolMap.at(hidl_msg.data)->handle));
 
-    for (const auto& hidl_msg : messages) {
-        if (mHidlMemPoolMap.count(hidl_msg.data) == 0) {
-            ALOGE("%s: memory pool ID %d not found", __FUNCTION__, hidl_msg.data);
-            return hardware::Void();
+            if (hidl_msg.bufferIndex >= mem->mNumBufs) {
+                ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
+                     hidl_msg.bufferIndex, mem->mNumBufs);
+                return hardware::Void();
+            }
+            VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
+                    mem->mBuffers[hidl_msg.bufferIndex]->pointer();
+            md->pHandle = const_cast<native_handle_t*>(hidl_msg.frameData.getNativeHandle());
+
+            msgs.push_back({hidl_msg.timestamp, mem->mBuffers[hidl_msg.bufferIndex]});
         }
-        sp<CameraHeapMemory> mem(
-                static_cast<CameraHeapMemory *>(mHidlMemPoolMap.at(hidl_msg.data)->handle));
-
-        if (hidl_msg.bufferIndex >= mem->mNumBufs) {
-            ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
-                 hidl_msg.bufferIndex, mem->mNumBufs);
-            return hardware::Void();
-        }
-        VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
-                mem->mBuffers[hidl_msg.bufferIndex]->pointer();
-        md->pHandle = const_cast<native_handle_t*>(hidl_msg.frameData.getNativeHandle());
-
-        msgs.push_back({hidl_msg.timestamp, mem->mBuffers[hidl_msg.bufferIndex]});
     }
-
     mDataCbTimestampBatch((int32_t) msgType, msgs, mCbUser);
     return hardware::Void();
 }
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index 6a1b4fb..e519b04 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
@@ -479,6 +479,7 @@
     uint64_t mNextBufferId = 1;
     static const uint64_t BUFFER_ID_NO_BUFFER = 0;
 
+    std::mutex mHidlMemPoolMapLock; // protecting mHidlMemPoolMap
     std::unordered_map<int, camera_memory_t*> mHidlMemPoolMap;
 };
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 94e8f3b..ced1d3a 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -154,6 +154,15 @@
                 resultQueueRet.description().c_str());
         return DEAD_OBJECT;
     }
+    IF_ALOGV() {
+        session->interfaceChain([](
+            ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
+                ALOGV("Session interface chain:");
+                for (auto iface : interfaceChain) {
+                    ALOGV("  %s", iface.c_str());
+                }
+            });
+    }
 
     mInterface = new HalInterface(session, queue);
     std::string providerType;
@@ -460,6 +469,11 @@
     return static_cast<uint32_t>(pixelFormat);
 }
 
+android_dataspace Camera3Device::mapToFrameworkDataspace(
+        DataspaceFlags dataSpace) {
+    return static_cast<android_dataspace>(dataSpace);
+}
+
 uint64_t Camera3Device::mapConsumerToFrameworkUsage(
         BufferUsageFlags usage) {
     return usage;
@@ -1345,10 +1359,11 @@
     return OK;
 }
 
-status_t Camera3Device::getStreamInfo(int id,
-        uint32_t *width, uint32_t *height,
-        uint32_t *format, android_dataspace *dataSpace) {
+status_t Camera3Device::getStreamInfo(int id, StreamInfo *streamInfo) {
     ATRACE_CALL();
+    if (nullptr == streamInfo) {
+        return BAD_VALUE;
+    }
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
 
@@ -1375,10 +1390,14 @@
         return idx;
     }
 
-    if (width) *width  = mOutputStreams[idx]->getWidth();
-    if (height) *height = mOutputStreams[idx]->getHeight();
-    if (format) *format = mOutputStreams[idx]->getFormat();
-    if (dataSpace) *dataSpace = mOutputStreams[idx]->getDataSpace();
+    streamInfo->width  = mOutputStreams[idx]->getWidth();
+    streamInfo->height = mOutputStreams[idx]->getHeight();
+    streamInfo->format = mOutputStreams[idx]->getFormat();
+    streamInfo->dataSpace = mOutputStreams[idx]->getDataSpace();
+    streamInfo->formatOverridden = mOutputStreams[idx]->isFormatOverridden();
+    streamInfo->originalFormat = mOutputStreams[idx]->getOriginalFormat();
+    streamInfo->dataSpaceOverridden = mOutputStreams[idx]->isDataSpaceOverridden();
+    streamInfo->originalDataSpace = mOutputStreams[idx]->getOriginalDataSpace();
     return OK;
 }
 
@@ -3193,17 +3212,51 @@
 
     // Invoke configureStreams
 
-    HalStreamConfiguration finalConfiguration;
+    device::V3_3::HalStreamConfiguration finalConfiguration;
     common::V1_0::Status status;
-    auto err = mHidlSession->configureStreams(requestedConfiguration,
+
+    // See if we have v3.3 HAL
+    sp<device::V3_3::ICameraDeviceSession> hidlSession_3_3;
+    auto castResult = device::V3_3::ICameraDeviceSession::castFrom(mHidlSession);
+    if (castResult.isOk()) {
+        hidlSession_3_3 = castResult;
+    } else {
+        ALOGE("%s: Transaction error when casting ICameraDeviceSession: %s", __FUNCTION__,
+                castResult.description().c_str());
+    }
+    if (hidlSession_3_3 != nullptr) {
+        // We do; use v3.3 for the call
+        ALOGV("%s: v3.3 device found", __FUNCTION__);
+        auto err = hidlSession_3_3->configureStreams_3_3(requestedConfiguration,
             [&status, &finalConfiguration]
-            (common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) {
+            (common::V1_0::Status s, const device::V3_3::HalStreamConfiguration& halConfiguration) {
                 finalConfiguration = halConfiguration;
                 status = s;
             });
-    if (!err.isOk()) {
-        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
-        return DEAD_OBJECT;
+        if (!err.isOk()) {
+            ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+            return DEAD_OBJECT;
+        }
+    } else {
+        // We don't; use v3.2 call and construct a v3.3 HalStreamConfiguration
+        ALOGV("%s: v3.2 device found", __FUNCTION__);
+        HalStreamConfiguration finalConfiguration_3_2;
+        auto err = mHidlSession->configureStreams(requestedConfiguration,
+                [&status, &finalConfiguration_3_2]
+                (common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) {
+                    finalConfiguration_3_2 = halConfiguration;
+                    status = s;
+                });
+        if (!err.isOk()) {
+            ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+            return DEAD_OBJECT;
+        }
+        finalConfiguration.streams.resize(finalConfiguration_3_2.streams.size());
+        for (size_t i = 0; i < finalConfiguration_3_2.streams.size(); i++) {
+            finalConfiguration.streams[i].v3_2 = finalConfiguration_3_2.streams[i];
+            finalConfiguration.streams[i].overrideDataSpace =
+                    requestedConfiguration.streams[i].dataSpace;
+        }
     }
 
     if (status != common::V1_0::Status::OK ) {
@@ -3220,7 +3273,7 @@
         size_t realIdx = i;
         bool found = false;
         for (size_t idx = 0; idx < finalConfiguration.streams.size(); idx++) {
-            if (finalConfiguration.streams[realIdx].id == streamId) {
+            if (finalConfiguration.streams[realIdx].v3_2.id == streamId) {
                 found = true;
                 break;
             }
@@ -3231,38 +3284,51 @@
                     __FUNCTION__, streamId);
             return INVALID_OPERATION;
         }
-        HalStream &src = finalConfiguration.streams[realIdx];
+        device::V3_3::HalStream &src = finalConfiguration.streams[realIdx];
 
-        int overrideFormat = mapToFrameworkFormat(src.overrideFormat);
+        Camera3Stream* dstStream = Camera3Stream::cast(dst);
+        dstStream->setFormatOverride(false);
+        dstStream->setDataSpaceOverride(false);
+        int overrideFormat = mapToFrameworkFormat(src.v3_2.overrideFormat);
+        android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace);
+
         if (dst->format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
             if (dst->format != overrideFormat) {
                 ALOGE("%s: Stream %d: Format override not allowed for format 0x%x", __FUNCTION__,
                         streamId, dst->format);
             }
+            if (dst->data_space != overrideDataSpace) {
+                ALOGE("%s: Stream %d: DataSpace override not allowed for format 0x%x", __FUNCTION__,
+                        streamId, dst->format);
+            }
         } else {
+            dstStream->setFormatOverride((dst->format != overrideFormat) ? true : false);
+            dstStream->setDataSpaceOverride((dst->data_space != overrideDataSpace) ? true : false);
+
             // Override allowed with IMPLEMENTATION_DEFINED
             dst->format = overrideFormat;
+            dst->data_space = overrideDataSpace;
         }
 
         if (dst->stream_type == CAMERA3_STREAM_INPUT) {
-            if (src.producerUsage != 0) {
+            if (src.v3_2.producerUsage != 0) {
                 ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage",
                         __FUNCTION__, streamId);
                 return INVALID_OPERATION;
             }
-            Camera3Stream::cast(dst)->setUsage(
-                    mapConsumerToFrameworkUsage(src.consumerUsage));
+            dstStream->setUsage(
+                    mapConsumerToFrameworkUsage(src.v3_2.consumerUsage));
         } else {
             // OUTPUT
-            if (src.consumerUsage != 0) {
+            if (src.v3_2.consumerUsage != 0) {
                 ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage",
                         __FUNCTION__, streamId);
                 return INVALID_OPERATION;
             }
-            Camera3Stream::cast(dst)->setUsage(
-                    mapProducerToFrameworkUsage(src.producerUsage));
+            dstStream->setUsage(
+                    mapProducerToFrameworkUsage(src.v3_2.producerUsage));
         }
-        dst->max_buffers = src.maxBuffers;
+        dst->max_buffers = src.v3_2.maxBuffers;
     }
 
     return res;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 363bd88..fbbbd08 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -30,6 +30,7 @@
 
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <android/hardware/camera/device/3.2/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.2/ICameraDeviceCallback.h>
 #include <fmq/MessageQueue.h>
 #include <hardware/camera3.h>
@@ -128,9 +129,7 @@
             uint32_t width, uint32_t height, int format,
             int *id) override;
 
-    status_t getStreamInfo(int id,
-            uint32_t *width, uint32_t *height,
-            uint32_t *format, android_dataspace *dataSpace) override;
+    status_t getStreamInfo(int id, StreamInfo *streamInfo) override;
     status_t setStreamTransform(int id, int transform) override;
 
     status_t deleteStream(int id) override;
@@ -597,6 +596,8 @@
             /*out*/ hardware::camera::device::V3_2::StreamConfigurationMode *mode);
     static camera3_buffer_status_t mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status);
     static int mapToFrameworkFormat(hardware::graphics::common::V1_0::PixelFormat pixelFormat);
+    static android_dataspace mapToFrameworkDataspace(
+            hardware::camera::device::V3_2::DataspaceFlags);
     static uint64_t mapConsumerToFrameworkUsage(
             hardware::camera::device::V3_2::BufferUsageFlags usage);
     static uint64_t mapProducerToFrameworkUsage(
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 25e44a5..fbe8f4f 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -62,7 +62,9 @@
     mPrepared(false),
     mPreparedBufferIdx(0),
     mLastMaxCount(Camera3StreamInterface::ALLOCATE_PIPELINE_MAX),
-    mBufferLimitLatency(kBufferLimitLatencyBinSize) {
+    mBufferLimitLatency(kBufferLimitLatencyBinSize),
+    mFormatOverridden(false),
+    mOriginalFormat(-1) {
 
     camera3_stream::stream_type = type;
     camera3_stream::width = width;
@@ -112,6 +114,32 @@
     mUsage = usage;
 }
 
+void Camera3Stream::setFormatOverride(bool formatOverridden) {
+    mFormatOverridden = formatOverridden;
+    if (formatOverridden) mOriginalFormat = camera3_stream::format;
+}
+
+bool Camera3Stream::isFormatOverridden() const {
+    return mFormatOverridden;
+}
+
+int Camera3Stream::getOriginalFormat() const {
+    return mOriginalFormat;
+}
+
+void Camera3Stream::setDataSpaceOverride(bool dataSpaceOverridden) {
+    mDataSpaceOverridden = dataSpaceOverridden;
+    if (dataSpaceOverridden) mOriginalDataSpace = camera3_stream::data_space;
+}
+
+bool Camera3Stream::isDataSpaceOverridden() const {
+    return mDataSpaceOverridden;
+}
+
+android_dataspace Camera3Stream::getOriginalDataSpace() const {
+    return mOriginalDataSpace;
+}
+
 camera3_stream* Camera3Stream::startConfiguration() {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 9090f83..6e7912e 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -146,6 +146,12 @@
     android_dataspace getDataSpace() const;
     uint64_t          getUsage() const;
     void              setUsage(uint64_t usage);
+    void              setFormatOverride(bool formatOverriden);
+    bool              isFormatOverridden() const;
+    int               getOriginalFormat() const;
+    void              setDataSpaceOverride(bool dataSpaceOverriden);
+    bool              isDataSpaceOverridden() const;
+    android_dataspace getOriginalDataSpace() const;
 
     camera3_stream*   asHalStream() override {
         return this;
@@ -514,6 +520,15 @@
     // max_buffers.
     static const int32_t kBufferLimitLatencyBinSize = 33; //in ms
     CameraLatencyHistogram mBufferLimitLatency;
+
+    //Keep track of original format in case it gets overridden
+    bool mFormatOverridden;
+    int mOriginalFormat;
+
+    //Keep track of original dataSpace in case it gets overridden
+    bool mDataSpaceOverridden;
+    android_dataspace mOriginalDataSpace;
+
 }; // class Camera3Stream
 
 }; // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 0544a1b..cc9bf8e 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -71,6 +71,12 @@
     virtual uint32_t getHeight() const = 0;
     virtual int      getFormat() const = 0;
     virtual android_dataspace getDataSpace() const = 0;
+    virtual void setFormatOverride(bool formatOverriden) = 0;
+    virtual bool isFormatOverridden() const = 0;
+    virtual int getOriginalFormat() const = 0;
+    virtual void setDataSpaceOverride(bool dataSpaceOverriden) = 0;
+    virtual bool isDataSpaceOverridden() const = 0;
+    virtual android_dataspace getOriginalDataSpace() const = 0;
 
     /**
      * Get a HAL3 handle for the stream, without starting stream configuration.
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 2836525..c7f9270 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -222,6 +222,8 @@
 
     // we control these, generally not trusting user input
     nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+    // round nsecs to seconds
+    now = ((now + 500000000) / 1000000000) * 1000000000;
     item->setTimestamp(now);
     int pid = IPCThreadState::self()->getCallingPid();
     int uid = IPCThreadState::self()->getCallingUid();
@@ -257,9 +259,22 @@
             break;
     }
 
-    item->setPkgName(getPkgName(item->getUid(), true));
-    item->setPkgVersionCode(0);
-    ALOGV("info is from uid %d pkg '%s', version %d", item->getUid(), item->getPkgName().c_str(), item->getPkgVersionCode());
+
+    // Overwrite package name and version if the caller was untrusted.
+    if (!isTrusted) {
+      setPkgInfo(item, item->getUid(), true, true);
+    } else if (item->getPkgName().empty()) {
+      // empty, so fill out both parts
+      setPkgInfo(item, item->getUid(), true, true);
+    } else {
+      // trusted, provided a package, do nothing
+    }
+
+    ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
+          "sanitized pkg version: %d",
+          uid_given, item->getUid(),
+          item->getPkgName().c_str(),
+          item->getPkgVersionCode());
 
     mItemsSubmitted++;
 
@@ -638,11 +653,6 @@
 // are they alike enough that nitem can be folded into oitem?
 static bool compatibleItems(MediaAnalyticsItem * oitem, MediaAnalyticsItem * nitem) {
 
-    if (0) {
-        ALOGD("Compare: o %s n %s",
-              oitem->toString().c_str(), nitem->toString().c_str());
-    }
-
     // general safety
     if (nitem->getUid() != oitem->getUid()) {
         return false;
@@ -793,85 +803,155 @@
 
 }
 
-// mapping uids to package names
+// how long we hold package info before we re-fetch it
+#define PKG_EXPIRATION_NS (30*60*1000000000ll)   // 30 minutes, in nsecs
 
 // give me the package name, perhaps going to find it
-AString MediaAnalyticsService::getPkgName(uid_t uid, bool addIfMissing) {
+void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion) {
+    ALOGV("asking for packagename to go with uid=%d", uid);
+
+    if (!setName && !setVersion) {
+        // setting nothing? strange
+        return;
+    }
+
+    nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+    struct UidToPkgMap mapping;
+    mapping.uid = (-1);
+
     ssize_t i = mPkgMappings.indexOfKey(uid);
     if (i >= 0) {
-        AString pkg = mPkgMappings.valueAt(i);
-        ALOGV("returning pkg '%s' for uid %d", pkg.c_str(), uid);
-        return pkg;
-    }
-
-    AString pkg;
-
-    if (addIfMissing == false) {
-        return pkg;
-    }
-
-    struct passwd *pw = getpwuid(uid);
-    if (pw) {
-        pkg = pw->pw_name;
-    } else {
-        pkg = "-";
-    }
-
-    // find the proper value
-
-    sp<IBinder> binder = NULL;
-    sp<IServiceManager> sm = defaultServiceManager();
-    if (sm == NULL) {
-        ALOGE("defaultServiceManager failed");
-    } else {
-        binder = sm->getService(String16("package_native"));
-        if (binder == NULL) {
-            ALOGE("getService package_native failed");
+        mapping = mPkgMappings.valueAt(i);
+        ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
+              uid, mapping.expiration, now);
+        if (mapping.expiration < now) {
+            // purge our current entry and re-query
+            ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
+            mPkgMappings.removeItemsAt(i, 1);
+            // could cheat and use a goto back to the top of the routine.
+            // a good compiler should recognize the local tail recursion...
+            return setPkgInfo(item, uid, setName, setVersion);
         }
-    }
+    } else {
+        AString pkg;
+        std::string installer = "";
+        int32_t versionCode = 0;
 
-    if (binder != NULL) {
-        sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
+        struct passwd *pw = getpwuid(uid);
+        if (pw) {
+            pkg = pw->pw_name;
+        }
 
-        std::vector<int> uids;
-        std::vector<std::string> names;
+        // find the proper value -- should we cache this binder??
 
-        uids.push_back(uid);
-
-        binder::Status status = package_mgr->getNamesForUids(uids, &names);
-        if (!status.isOk()) {
-            ALOGE("package_native::getNamesForUids failed: %s",
-                  status.exceptionMessage().c_str());
+        sp<IBinder> binder = NULL;
+        sp<IServiceManager> sm = defaultServiceManager();
+        if (sm == NULL) {
+            ALOGE("defaultServiceManager failed");
         } else {
-            if (!names[0].empty()) {
-                pkg = names[0].c_str();
+            binder = sm->getService(String16("package_native"));
+            if (binder == NULL) {
+                ALOGE("getService package_native failed");
+            }
+        }
+
+        if (binder != NULL) {
+            sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
+            binder::Status status;
+
+            std::vector<int> uids;
+            std::vector<std::string> names;
+
+            uids.push_back(uid);
+
+            status = package_mgr->getNamesForUids(uids, &names);
+            if (!status.isOk()) {
+                ALOGE("package_native::getNamesForUids failed: %s",
+                      status.exceptionMessage().c_str());
+            } else {
+                if (!names[0].empty()) {
+                    pkg = names[0].c_str();
+                }
+            }
+
+            // strip any leading "shared:" strings that came back
+            if (pkg.startsWith("shared:")) {
+                pkg.erase(0, 7);
+            }
+
+            // determine how pkg was installed and the versionCode
+            //
+            if (pkg.empty()) {
+                // no name for us to manage
+            } else if (strchr(pkg.c_str(), '.') == NULL) {
+                // not of form 'com.whatever...'; assume internal and ok
+            } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
+                // android.* packages are assumed fine
+            } else {
+                String16 pkgName16(pkg.c_str());
+                status = package_mgr->getInstallerForPackage(pkgName16, &installer);
+                if (!status.isOk()) {
+                    ALOGE("package_native::getInstallerForPackage failed: %s",
+                          status.exceptionMessage().c_str());
+                }
+
+                // skip if we didn't get an installer
+                if (status.isOk()) {
+                    status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
+                    if (!status.isOk()) {
+                        ALOGE("package_native::getVersionCodeForPackage failed: %s",
+                          status.exceptionMessage().c_str());
+                    }
+                }
+
+
+                ALOGV("package '%s' installed by '%s' versioncode %d / %08x",
+                      pkg.c_str(), installer.c_str(), versionCode, versionCode);
+
+                if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
+                        // from play store, we keep info
+                } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
+                        // some google source, we keep info
+                } else if (strcmp(installer.c_str(), "preload") == 0) {
+                        // preloads, we keep the info
+                } else if (installer.c_str()[0] == '\0') {
+                        // sideload (no installer); do not report
+                        pkg = "";
+                        versionCode = 0;
+                } else {
+                        // unknown installer; do not report
+                        pkg = "";
+                        versionCode = 0;
+                }
+            }
+        }
+
+        // add it to the map, to save a subsequent lookup
+        if (!pkg.empty()) {
+            Mutex::Autolock _l(mLock_mappings);
+            ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
+            ssize_t i = mPkgMappings.indexOfKey(uid);
+            if (i < 0) {
+                mapping.uid = uid;
+                mapping.pkg = pkg;
+                mapping.installer = installer.c_str();
+                mapping.versionCode = versionCode;
+                mapping.expiration = now + PKG_EXPIRATION_NS;
+                ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
+
+                mPkgMappings.add(uid, mapping);
             }
         }
     }
 
-    // XXX determine whether package was side-loaded or from playstore.
-    // for privacy, we only list apps loaded from playstore.
-
-    // Sanitize the package name for ":"
-    // as an example, we get "shared:android.uid.systemui"
-    // replace : with something benign (I'm going to use !)
-    if (!pkg.empty()) {
-        int n = pkg.size();
-        char *p = (char *) pkg.c_str();
-        for (int i = 0 ; i < n; i++) {
-            if (p[i] == ':') {
-                p[i] = '!';
-            }
+    if (mapping.uid != (uid_t)(-1)) {
+        if (setName) {
+            item->setPkgName(mapping.pkg);
+        }
+        if (setVersion) {
+            item->setPkgVersionCode(mapping.versionCode);
         }
     }
-
-    // add it to the map, to save a subsequent lookup
-    if (!pkg.empty()) {
-        ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
-        mPkgMappings.add(uid, pkg);
-    }
-
-    return pkg;
 }
 
 } // namespace android
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index 4fe2fb2..52e4631 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -62,6 +62,7 @@
     // partitioned a bit so we don't over serialize
     mutable Mutex           mLock;
     mutable Mutex           mLock_ids;
+    mutable Mutex           mLock_mappings;
 
     // limit how many records we'll retain
     // by count (in each queue (open, finalized))
@@ -135,10 +136,13 @@
     struct UidToPkgMap {
         uid_t uid;
         AString pkg;
+        AString installer;
+        int32_t versionCode;
+        nsecs_t expiration;
     };
 
-    KeyedVector<uid_t,AString>  mPkgMappings;
-    AString getPkgName(uid_t uid, bool addIfMissing);
+    KeyedVector<uid_t,struct UidToPkgMap>  mPkgMappings;
+    void setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion);
 
 };
 
diff --git a/services/mediaanalytics/MetricsSummarizerCodec.cpp b/services/mediaanalytics/MetricsSummarizerCodec.cpp
index 8c74782..6af3c9a 100644
--- a/services/mediaanalytics/MetricsSummarizerCodec.cpp
+++ b/services/mediaanalytics/MetricsSummarizerCodec.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "MetricsSummarizerCodec"
 #include <utils/Log.h>
 
+#include <stdint.h>
+#include <inttypes.h>
 
 #include <utils/threads.h>
 #include <utils/Errors.h>
@@ -40,5 +42,4 @@
     ALOGV("MetricsSummarizerCodec::MetricsSummarizerCodec");
 }
 
-
 } // namespace android
diff --git a/services/mediaanalytics/mediametrics.rc b/services/mediaanalytics/mediametrics.rc
index 3829f8c..1efde5e 100644
--- a/services/mediaanalytics/mediametrics.rc
+++ b/services/mediaanalytics/mediametrics.rc
@@ -1,5 +1,6 @@
 service mediametrics /system/bin/mediametrics
     class main
     user media
+    group media
     ioprio rt 4
     writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index f41219e..f996f74 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -102,7 +102,7 @@
         }
     }
 
-    ALOGD("AAudioEndpointManager.findExclusiveEndpoint_l(), found %p for device = %d",
+    ALOGV("AAudioEndpointManager.findExclusiveEndpoint_l(), found %p for device = %d",
           endpoint.get(), configuration.getDeviceId());
     return endpoint;
 }
@@ -118,7 +118,7 @@
         }
     }
 
-    ALOGD("AAudioEndpointManager.findSharedEndpoint_l(), found %p for device = %d",
+    ALOGV("AAudioEndpointManager.findSharedEndpoint_l(), found %p for device = %d",
           endpoint.get(), configuration.getDeviceId());
     return endpoint;
 }
@@ -238,8 +238,6 @@
     std::lock_guard<std::mutex> lock(mExclusiveLock);
     int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
     serviceEndpoint->setOpenCount(newRefCount);
-    ALOGD("AAudioEndpointManager::closeExclusiveEndpoint(%p) newRefCount = %d",
-          serviceEndpoint.get(), newRefCount);
 
     // If no longer in use then close and delete it.
     if (newRefCount <= 0) {
@@ -262,8 +260,6 @@
     std::lock_guard<std::mutex> lock(mSharedLock);
     int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
     serviceEndpoint->setOpenCount(newRefCount);
-    ALOGD("AAudioEndpointManager::closeSharedEndpoint(%p) newRefCount = %d",
-          serviceEndpoint.get(), newRefCount);
 
     // If no longer in use then close and delete it.
     if (newRefCount <= 0) {
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 855ae69..5a3488d 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -18,9 +18,9 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <iomanip>
+#include <iostream>
 #include <sstream>
-//#include <time.h>
-//#include <pthread.h>
 
 #include <aaudio/AAudio.h>
 #include <mediautils/SchedulingPolicyService.h>
@@ -35,18 +35,13 @@
 #include "AAudioServiceStreamMMAP.h"
 #include "binding/IAAudioService.h"
 #include "ServiceUtilities.h"
-#include "utility/HandleTracker.h"
 
 using namespace android;
 using namespace aaudio;
 
 #define MAX_STREAMS_PER_PROCESS   8
 
-typedef enum
-{
-    AAUDIO_HANDLE_TYPE_STREAM
-} aaudio_service_handle_type_t;
-static_assert(AAUDIO_HANDLE_TYPE_STREAM < HANDLE_TRACKER_MAX_TYPES, "Too many handle types.");
+using android::AAudioService;
 
 android::AAudioService::AAudioService()
     : BnAAudioService() {
@@ -70,7 +65,8 @@
         result = ss.str();
         ALOGW("%s", result.c_str());
     } else {
-        result = mHandleTracker.dump()
+        result = "------------ AAudio Service ------------\n"
+                 + mStreamTracker.dump()
                  + AAudioClientTracker::getInstance().dump()
                  + AAudioEndpointManager::getInstance().dump();
     }
@@ -125,7 +121,7 @@
 
     // if SHARED requested or if EXCLUSIVE failed
     if (sharingMode == AAUDIO_SHARING_MODE_SHARED
-         || (serviceStream == nullptr && !sharingModeMatchRequired)) {
+         || (serviceStream.get() == nullptr && !sharingModeMatchRequired)) {
         serviceStream =  new AAudioServiceStreamShared(*this);
         result = serviceStream->open(request);
     }
@@ -136,18 +132,12 @@
               result, AAudio_convertResultToText(result));
         return result;
     } else {
-        aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream.get());
-        if (handle < 0) {
-            ALOGE("AAudioService::openStream(): handle table full");
-            serviceStream->close();
-            serviceStream.clear();
-        } else {
-            ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
-            serviceStream->setHandle(handle);
-            pid_t pid = request.getProcessId();
-            AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
-            configurationOutput.copyFrom(*serviceStream);
-        }
+        aaudio_handle_t handle = mStreamTracker.addStreamForHandle(serviceStream.get());
+        ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
+        serviceStream->setHandle(handle);
+        pid_t pid = request.getProcessId();
+        AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
+        configurationOutput.copyFrom(*serviceStream);
         return handle;
     }
 }
@@ -155,30 +145,32 @@
 aaudio_result_t AAudioService::closeStream(aaudio_handle_t streamHandle) {
     // Check permission and ownership first.
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
-        ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
+    if (serviceStream.get() == nullptr) {
+        ALOGE("AAudioService::closeStream(0x%0x), illegal stream handle", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
 
     ALOGD("AAudioService.closeStream(0x%08X)", streamHandle);
     // Remove handle from tracker so that we cannot look up the raw address any more.
-    serviceStream = (AAudioServiceStreamBase *)
-            mHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM,
-                                  streamHandle);
-    if (serviceStream != nullptr) {
+    // removeStreamByHandle() uses a lock so that if there are two simultaneous closes
+    // then only one will get the pointer and do the close.
+    serviceStream = mStreamTracker.removeStreamByHandle(streamHandle);
+    if (serviceStream.get() != nullptr) {
         serviceStream->close();
         pid_t pid = serviceStream->getOwnerProcessId();
         AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
         return AAUDIO_OK;
+    } else {
+        ALOGW("AAudioService::closeStream(0x%0x) being handled by another thread", streamHandle);
+        return AAUDIO_ERROR_INVALID_HANDLE;
     }
-    return AAUDIO_ERROR_INVALID_HANDLE;
 }
 
-AAudioServiceStreamBase *AAudioService::convertHandleToServiceStream(
-        aaudio_handle_t streamHandle) const {
-    AAudioServiceStreamBase *serviceStream = (AAudioServiceStreamBase *)
-            mHandleTracker.get(AAUDIO_HANDLE_TYPE_STREAM, (aaudio_handle_t)streamHandle);
-    if (serviceStream != nullptr) {
+
+sp<AAudioServiceStreamBase> AAudioService::convertHandleToServiceStream(
+        aaudio_handle_t streamHandle) {
+    sp<AAudioServiceStreamBase> serviceStream = mStreamTracker.getStreamByHandle(streamHandle);
+    if (serviceStream.get() != nullptr) {
         // Only allow owner or the aaudio service to access the stream.
         const uid_t callingUserId = IPCThreadState::self()->getCallingUid();
         const uid_t ownerUserId = serviceStream->getOwnerUserId();
@@ -198,30 +190,30 @@
 aaudio_result_t AAudioService::getStreamDescription(
                 aaudio_handle_t streamHandle,
                 aaudio::AudioEndpointParcelable &parcelable) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
+
     aaudio_result_t result = serviceStream->getDescription(parcelable);
     // parcelable.dump();
     return result;
 }
 
 aaudio_result_t AAudioService::startStream(aaudio_handle_t streamHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
 
-    aaudio_result_t result = serviceStream->start();
-    return result;
+    return serviceStream->start();
 }
 
 aaudio_result_t AAudioService::pauseStream(aaudio_handle_t streamHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::pauseStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
@@ -230,9 +222,9 @@
 }
 
 aaudio_result_t AAudioService::stopStream(aaudio_handle_t streamHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
-        ALOGE("AAudioService::pauseStream(), illegal stream handle = 0x%0x", streamHandle);
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
+        ALOGE("AAudioService::stopStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     aaudio_result_t result = serviceStream->stop();
@@ -240,8 +232,8 @@
 }
 
 aaudio_result_t AAudioService::flushStream(aaudio_handle_t streamHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::flushStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
@@ -251,8 +243,8 @@
 aaudio_result_t AAudioService::registerAudioThread(aaudio_handle_t streamHandle,
                                                    pid_t clientThreadId,
                                                    int64_t periodNanoseconds) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::registerAudioThread(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
@@ -276,8 +268,8 @@
 
 aaudio_result_t AAudioService::unregisterAudioThread(aaudio_handle_t streamHandle,
                                                      pid_t clientThreadId) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::unregisterAudioThread(), illegal stream handle = 0x%0x",
               streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
@@ -293,8 +285,8 @@
 aaudio_result_t AAudioService::startClient(aaudio_handle_t streamHandle,
                                   const android::AudioClient& client,
                                   audio_port_handle_t *clientHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::startClient(), illegal stream handle = 0x%0x",
               streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
@@ -304,8 +296,8 @@
 
 aaudio_result_t AAudioService::stopClient(aaudio_handle_t streamHandle,
                                           audio_port_handle_t clientHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::stopClient(), illegal stream handle = 0x%0x",
               streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index ffaf538..eef0824 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -24,13 +24,13 @@
 #include <media/AudioClient.h>
 
 #include <aaudio/AAudio.h>
-#include "utility/HandleTracker.h"
-#include "binding/IAAudioService.h"
-#include "binding/AAudioServiceInterface.h"
 
-namespace aaudio {
-    class AAudioServiceStreamBase;
-};
+#include "binding/AAudioCommon.h"
+#include "binding/AAudioServiceInterface.h"
+#include "binding/IAAudioService.h"
+
+#include "AAudioServiceStreamBase.h"
+#include "AAudioStreamTracker.h"
 
 namespace android {
 
@@ -51,45 +51,53 @@
 
     virtual void            registerClient(const sp<IAAudioClient>& client);
 
-    virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
-                                     aaudio::AAudioStreamConfiguration &configurationOutput);
+    aaudio::aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+                                       aaudio::AAudioStreamConfiguration &configurationOutput)
+                                       override;
 
-    virtual aaudio_result_t closeStream(aaudio_handle_t streamHandle);
+    aaudio_result_t closeStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t getStreamDescription(
-                aaudio_handle_t streamHandle,
-                aaudio::AudioEndpointParcelable &parcelable);
+    aaudio_result_t getStreamDescription(
+                aaudio::aaudio_handle_t streamHandle,
+                aaudio::AudioEndpointParcelable &parcelable) override;
 
-    virtual aaudio_result_t startStream(aaudio_handle_t streamHandle);
+    aaudio_result_t startStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t pauseStream(aaudio_handle_t streamHandle);
+    aaudio_result_t pauseStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t stopStream(aaudio_handle_t streamHandle);
+    aaudio_result_t stopStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle);
+    aaudio_result_t flushStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+    aaudio_result_t registerAudioThread(aaudio::aaudio_handle_t streamHandle,
                                                 pid_t tid,
-                                                int64_t periodNanoseconds) ;
+                                                int64_t periodNanoseconds) override;
 
-    virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                  pid_t tid);
+    aaudio_result_t unregisterAudioThread(aaudio::aaudio_handle_t streamHandle,
+                                                  pid_t tid) override;
 
-    virtual aaudio_result_t startClient(aaudio_handle_t streamHandle,
+    aaudio_result_t startClient(aaudio::aaudio_handle_t streamHandle,
                                       const android::AudioClient& client,
-                                      audio_port_handle_t *clientHandle);
+                                      audio_port_handle_t *clientHandle) override;
 
-    virtual aaudio_result_t stopClient(aaudio_handle_t streamHandle,
-                                       audio_port_handle_t clientHandle);
+    aaudio_result_t stopClient(aaudio::aaudio_handle_t streamHandle,
+                                       audio_port_handle_t clientHandle) override;
 
 private:
 
-    aaudio::AAudioServiceStreamBase *convertHandleToServiceStream(aaudio_handle_t streamHandle) const;
+    /**
+     * Lookup stream and then validate access to the stream.
+     * @param streamHandle
+     * @return
+     */
+    sp<aaudio::AAudioServiceStreamBase> convertHandleToServiceStream(
+            aaudio::aaudio_handle_t streamHandle);
 
-    HandleTracker mHandleTracker;
 
     android::AudioClient mAudioClient;
 
+    aaudio::AAudioStreamTracker                 mStreamTracker;
+
     enum constants {
         DEFAULT_AUDIO_PRIORITY = 2
     };
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index cba5bc8..3095bc9 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -60,7 +60,7 @@
     result << "    Reference Count:      " << mOpenCount << "\n";
     result << "    Requested Device Id:  " << mRequestedDeviceId << "\n";
     result << "    Device Id:            " << getDeviceId() << "\n";
-    result << "    Registered Streams:  " << "\n";
+    result << "    Registered Streams:" << "\n";
     result << AAudioServiceStreamShared::dumpHeader() << "\n";
     for (const auto stream : mRegisteredStreams) {
         result << stream->dump() << "\n";
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index 97558ca..c7d9b8e 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -84,30 +84,42 @@
             std::lock_guard <std::mutex> lock(mLockStreams);
             for (const auto clientStream : mRegisteredStreams) {
                 if (clientStream->isRunning()) {
-                    AAudioServiceStreamShared *streamShared =
+                    int64_t clientFramesWritten = 0;
+                    sp<AAudioServiceStreamShared> streamShared =
                             static_cast<AAudioServiceStreamShared *>(clientStream.get());
 
-                    FifoBuffer *fifo = streamShared->getDataFifoBuffer();
+                    {
+                        // Lock the AudioFifo to protect against close.
+                        std::lock_guard <std::mutex> lock(streamShared->getAudioDataQueueLock());
 
-                    // Determine offset between framePosition in client's stream vs the underlying
-                    // MMAP stream.
-                    int64_t clientFramesWritten = fifo->getWriteCounter();
-                    // There are two indices that refer to the same frame.
-                    int64_t positionOffset = mmapFramesRead - clientFramesWritten;
-                    streamShared->setTimestampPositionOffset(positionOffset);
+                        FifoBuffer *fifo = streamShared->getAudioDataFifoBuffer_l();
+                        if (fifo != nullptr) {
 
-                    if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
-                        getFramesPerBurst()) {
-                        underflowCount++;
-                    } else {
-                        fifo->write(mDistributionBuffer, getFramesPerBurst());
+                            // Determine offset between framePosition in client's stream
+                            // vs the underlying MMAP stream.
+                            clientFramesWritten = fifo->getWriteCounter();
+                            // There are two indices that refer to the same frame.
+                            int64_t positionOffset = mmapFramesRead - clientFramesWritten;
+                            streamShared->setTimestampPositionOffset(positionOffset);
+
+                            if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
+                                getFramesPerBurst()) {
+                                underflowCount++;
+                            } else {
+                                fifo->write(mDistributionBuffer, getFramesPerBurst());
+                            }
+                            clientFramesWritten = fifo->getWriteCounter();
+                        }
                     }
 
-                    // This timestamp represents the completion of data being written into the
-                    // client buffer. It is sent to the client and used in the timing model
-                    // to decide when data will be available to read.
-                    Timestamp timestamp(fifo->getWriteCounter(), AudioClock::getNanoseconds());
-                    streamShared->markTransferTime(timestamp);
+                    if (clientFramesWritten > 0) {
+                        // This timestamp represents the completion of data being written into the
+                        // client buffer. It is sent to the client and used in the timing model
+                        // to decide when data will be available to read.
+                        Timestamp timestamp(clientFramesWritten, AudioClock::getNanoseconds());
+                        streamShared->markTransferTime(timestamp);
+                    }
+
                 }
             }
         }
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 58213f8..7e6e247 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -250,23 +250,33 @@
 
 aaudio_result_t AAudioServiceEndpointMMAP::startStream(sp<AAudioServiceStreamBase> stream,
                                                    audio_port_handle_t *clientHandle) {
+    // Start the client on behalf of the AAudio service.
+    // Use the port handle that was provided by openMmapStream().
     return startClient(mMmapClient, &mPortHandle);
 }
 
 aaudio_result_t AAudioServiceEndpointMMAP::stopStream(sp<AAudioServiceStreamBase> stream,
                                                   audio_port_handle_t clientHandle) {
     mFramesTransferred.reset32();
+
+    // Round 64-bit counter up to a multiple of the buffer capacity.
+    // This is required because the 64-bit counter is used as an index
+    // into a circular buffer and the actual HW position is reset to zero
+    // when the stream is stopped.
+    mFramesTransferred.roundUp64(getBufferCapacity());
+
     return stopClient(mPortHandle);
 }
 
 aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
                                                        audio_port_handle_t *clientHandle) {
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
+    ALOGD("AAudioServiceEndpointMMAP::startClient(%p(uid=%d, pid=%d))",
+          &client, client.clientUid, client.clientPid);
     audio_port_handle_t originalHandle =  *clientHandle;
-    aaudio_result_t result = AAudioConvert_androidToAAudioResult(mMmapStream->start(client,
-                                                                                    clientHandle));
-    ALOGD("AAudioServiceEndpointMMAP::startClient(%p(uid=%d, pid=%d), %d => %d) returns %d",
-          &client, client.clientUid, client.clientPid,
+    status_t status = mMmapStream->start(client, clientHandle);
+    aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
+    ALOGD("AAudioServiceEndpointMMAP::startClient() , %d => %d returns %d",
           originalHandle, *clientHandle, result);
     return result;
 }
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index c42a6e2..9b1833a 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -81,32 +81,44 @@
 
             std::lock_guard <std::mutex> lock(mLockStreams);
             for (const auto clientStream : mRegisteredStreams) {
+                int64_t clientFramesRead = 0;
+
                 if (!clientStream->isRunning()) {
                     continue;
                 }
 
-                AAudioServiceStreamShared *streamShared =
+                sp<AAudioServiceStreamShared> streamShared =
                         static_cast<AAudioServiceStreamShared *>(clientStream.get());
 
-                FifoBuffer *fifo = streamShared->getDataFifoBuffer();
-                // Determine offset between framePosition in client's stream vs the underlying
-                // MMAP stream.
-                int64_t clientFramesRead = fifo->getReadCounter();
-                // These two indices refer to the same frame.
-                int64_t positionOffset = mmapFramesWritten - clientFramesRead;
-                streamShared->setTimestampPositionOffset(positionOffset);
+                {
+                    // Lock the AudioFifo to protect against close.
+                    std::lock_guard <std::mutex> lock(streamShared->getAudioDataQueueLock());
 
-                float volume = 1.0; // to match legacy volume
-                bool underflowed = mMixer.mix(index, fifo, volume);
+                    FifoBuffer *fifo = streamShared->getAudioDataFifoBuffer_l();
+                    if (fifo != nullptr) {
 
-                // This timestamp represents the completion of data being read out of the
-                // client buffer. It is sent to the client and used in the timing model
-                // to decide when the client has room to write more data.
-                Timestamp timestamp(fifo->getReadCounter(), AudioClock::getNanoseconds());
-                streamShared->markTransferTime(timestamp);
+                        // Determine offset between framePosition in client's stream
+                        // vs the underlying MMAP stream.
+                        clientFramesRead = fifo->getReadCounter();
+                        // These two indices refer to the same frame.
+                        int64_t positionOffset = mmapFramesWritten - clientFramesRead;
+                        streamShared->setTimestampPositionOffset(positionOffset);
 
-                if (underflowed) {
-                    streamShared->incrementXRunCount();
+                        float volume = 1.0; // to match legacy volume
+                        bool underflowed = mMixer.mix(index, fifo, volume);
+                        if (underflowed) {
+                            streamShared->incrementXRunCount();
+                        }
+                        clientFramesRead = fifo->getReadCounter();
+                    }
+                }
+
+                if (clientFramesRead > 0) {
+                    // This timestamp represents the completion of data being read out of the
+                    // client buffer. It is sent to the client and used in the timing model
+                    // to decide when the client has room to write more data.
+                    Timestamp timestamp(clientFramesRead, AudioClock::getNanoseconds());
+                    streamShared->markTransferTime(timestamp);
                 }
 
                 index++; // just used for labelling tracks in systrace
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 43d73b7..cd40066 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -115,16 +115,33 @@
 aaudio_result_t AAudioServiceEndpointShared::startStream(sp<AAudioServiceStreamBase> sharedStream,
                                                          audio_port_handle_t *clientHandle) {
     aaudio_result_t result = AAUDIO_OK;
-    if (++mRunningStreamCount == 1) {
-        // TODO use real-time technique to avoid mutex, eg. atomic command FIFO
+
+    {
         std::lock_guard<std::mutex> lock(mLockStreams);
-        result = getStreamInternal()->requestStart();
-        startSharingThread_l();
+        if (++mRunningStreamCount == 1) { // atomic
+            result = getStreamInternal()->requestStart();
+            if (result != AAUDIO_OK) {
+                --mRunningStreamCount;
+            } else {
+                result = startSharingThread_l();
+                if (result != AAUDIO_OK) {
+                    getStreamInternal()->requestStop();
+                    --mRunningStreamCount;
+                }
+            }
+        }
     }
+
     if (result == AAUDIO_OK) {
-        ALOGD("AAudioServiceEndpointShared::startStream() use shared stream client.");
         result = getStreamInternal()->startClient(sharedStream->getAudioClient(), clientHandle);
+        if (result != AAUDIO_OK) {
+            if (--mRunningStreamCount == 0) { // atomic
+                stopSharingThread();
+                getStreamInternal()->requestStop();
+            }
+        }
     }
+
     return result;
 }
 
@@ -142,7 +159,6 @@
     return AAUDIO_OK;
 }
 
-
 // Get timestamp that was written by the real-time service thread, eg. mixer.
 aaudio_result_t AAudioServiceEndpointShared::getFreeRunningPosition(int64_t *positionFrames,
                                                                   int64_t *timeNanos) {
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 2dc62a0..ff0b037 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -42,7 +42,7 @@
 
 AAudioServiceStreamBase::AAudioServiceStreamBase(AAudioService &audioService)
         : mUpMessageQueue(nullptr)
-        , mAAudioThread()
+        , mTimestampThread()
         , mAtomicTimestamp()
         , mAudioService(audioService) {
     mMmapClient.clientUid = -1;
@@ -54,10 +54,10 @@
     ALOGD("AAudioServiceStreamBase::~AAudioServiceStreamBase() destroying %p", this);
     // If the stream is deleted when OPEN or in use then audio resources will leak.
     // This would indicate an internal error. So we want to find this ASAP.
-    LOG_ALWAYS_FATAL_IF(!(mState == AAUDIO_STREAM_STATE_CLOSED
-                        || mState == AAUDIO_STREAM_STATE_UNINITIALIZED
-                        || mState == AAUDIO_STREAM_STATE_DISCONNECTED),
-                        "service stream still open, state = %d", mState);
+    LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
+                        || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED
+                        || getState() == AAUDIO_STREAM_STATE_DISCONNECTED),
+                        "service stream still open, state = %d", getState());
 }
 
 std::string AAudioServiceStreamBase::dumpHeader() {
@@ -71,7 +71,7 @@
            << std::dec << std::setfill(' ') ;
     result << std::setw(6) << mMmapClient.clientUid;
     result << std::setw(4) << (isRunning() ? "yes" : " no");
-    result << std::setw(6) << mState;
+    result << std::setw(6) << getState();
     result << std::setw(7) << getFormat();
     result << std::setw(6) << mFramesPerBurst;
     result << std::setw(5) << getSamplesPerFrame();
@@ -124,7 +124,7 @@
 
 aaudio_result_t AAudioServiceStreamBase::close() {
     aaudio_result_t result = AAUDIO_OK;
-    if (mState == AAUDIO_STREAM_STATE_CLOSED) {
+    if (getState() == AAUDIO_STREAM_STATE_CLOSED) {
         return AAUDIO_OK;
     }
 
@@ -146,37 +146,50 @@
         mUpMessageQueue = nullptr;
     }
 
-    mState = AAUDIO_STREAM_STATE_CLOSED;
+    setState(AAUDIO_STREAM_STATE_CLOSED);
     return result;
 }
 
+aaudio_result_t AAudioServiceStreamBase::startDevice() {
+    mClientHandle = AUDIO_PORT_HANDLE_NONE;
+    return mServiceEndpoint->startStream(this, &mClientHandle);
+}
+
 /**
  * Start the flow of audio data.
  *
  * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
  */
 aaudio_result_t AAudioServiceStreamBase::start() {
+    aaudio_result_t result = AAUDIO_OK;
     if (isRunning()) {
         return AAUDIO_OK;
     }
 
     if (mServiceEndpoint == nullptr) {
         ALOGE("AAudioServiceStreamBase::start() missing endpoint");
-        return AAUDIO_ERROR_INVALID_STATE;
+        result = AAUDIO_ERROR_INVALID_STATE;
+        goto error;
     }
+
+    // Start with fresh presentation timestamps.
+    mAtomicTimestamp.clear();
+
     mClientHandle = AUDIO_PORT_HANDLE_NONE;
-    aaudio_result_t result = mServiceEndpoint->startStream(this, &mClientHandle);
-    if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamBase::start() mServiceEndpoint returned %d", result);
-        disconnect();
-    } else {
-        if (result == AAUDIO_OK) {
-            sendServiceEvent(AAUDIO_SERVICE_EVENT_STARTED);
-            mState = AAUDIO_STREAM_STATE_STARTED;
-            mThreadEnabled.store(true);
-            result = mAAudioThread.start(this);
-        }
-    }
+    result = startDevice();
+    if (result != AAUDIO_OK) goto error;
+
+    // This should happen at the end of the start.
+    sendServiceEvent(AAUDIO_SERVICE_EVENT_STARTED);
+    setState(AAUDIO_STREAM_STATE_STARTED);
+    mThreadEnabled.store(true);
+    result = mTimestampThread.start(this);
+    if (result != AAUDIO_OK) goto error;
+
+    return result;
+
+error:
+    disconnect();
     return result;
 }
 
@@ -189,21 +202,25 @@
         ALOGE("AAudioServiceStreamShared::pause() missing endpoint");
         return AAUDIO_ERROR_INVALID_STATE;
     }
+
+    // Send it now because the timestamp gets rounded up when stopStream() is called below.
+    // Also we don't need the timestamps while we are shutting down.
+    sendCurrentTimestamp();
+
+    result = stopTimestampThread();
+    if (result != AAUDIO_OK) {
+        disconnect();
+        return result;
+    }
+
     result = mServiceEndpoint->stopStream(this, mClientHandle);
     if (result != AAUDIO_OK) {
         ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result);
         disconnect(); // TODO should we return or pause Base first?
     }
 
-    sendCurrentTimestamp();
-    mThreadEnabled.store(false);
-    result = mAAudioThread.stop();
-    if (result != AAUDIO_OK) {
-        disconnect();
-        return result;
-    }
     sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
-    mState = AAUDIO_STREAM_STATE_PAUSED;
+    setState(AAUDIO_STREAM_STATE_PAUSED);
     return result;
 }
 
@@ -218,6 +235,8 @@
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
+    // Send it now because the timestamp gets rounded up when stopStream() is called below.
+    // Also we don't need the timestamps while we are shutting down.
     sendCurrentTimestamp(); // warning - this calls a virtual function
     result = stopTimestampThread();
     if (result != AAUDIO_OK) {
@@ -234,7 +253,7 @@
     }
 
     sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
-    mState = AAUDIO_STREAM_STATE_STOPPED;
+    setState(AAUDIO_STREAM_STATE_STOPPED);
     return result;
 }
 
@@ -242,20 +261,20 @@
     aaudio_result_t result = AAUDIO_OK;
     // clear flag that tells thread to loop
     if (mThreadEnabled.exchange(false)) {
-        result = mAAudioThread.stop();
+        result = mTimestampThread.stop();
     }
     return result;
 }
 
 aaudio_result_t AAudioServiceStreamBase::flush() {
-    if (mState != AAUDIO_STREAM_STATE_PAUSED) {
+    if (getState() != AAUDIO_STREAM_STATE_PAUSED) {
         ALOGE("AAudioServiceStreamBase::flush() stream not paused, state = %s",
               AAudio_convertStreamStateToText(mState));
         return AAUDIO_ERROR_INVALID_STATE;
     }
     // Data will get flushed when the client receives the FLUSHED event.
     sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED);
-    mState = AAUDIO_STREAM_STATE_FLUSHED;
+    setState(AAUDIO_STREAM_STATE_FLUSHED);
     return AAUDIO_OK;
 }
 
@@ -283,9 +302,9 @@
 }
 
 void AAudioServiceStreamBase::disconnect() {
-    if (mState != AAUDIO_STREAM_STATE_DISCONNECTED) {
+    if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
         sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED);
-        mState = AAUDIO_STREAM_STATE_DISCONNECTED;
+        setState(AAUDIO_STREAM_STATE_DISCONNECTED);
     }
 }
 
@@ -321,6 +340,9 @@
     aaudio_result_t result = getFreeRunningPosition(&command.timestamp.position,
                                                     &command.timestamp.timestamp);
     if (result == AAUDIO_OK) {
+        ALOGV("sendCurrentTimestamp() SERVICE  %8lld at %lld",
+              (long long) command.timestamp.position,
+              (long long) command.timestamp.timestamp);
         command.what = AAudioServiceMessage::code::TIMESTAMP_SERVICE;
         result = writeUpMessageQueue(&command);
 
@@ -329,13 +351,16 @@
             result = getHardwareTimestamp(&command.timestamp.position,
                                           &command.timestamp.timestamp);
             if (result == AAUDIO_OK) {
+                ALOGV("sendCurrentTimestamp() HARDWARE %8lld at %lld",
+                      (long long) command.timestamp.position,
+                      (long long) command.timestamp.timestamp);
                 command.what = AAudioServiceMessage::code::TIMESTAMP_HARDWARE;
                 result = writeUpMessageQueue(&command);
             }
         }
     }
 
-    if (result == AAUDIO_ERROR_UNAVAILABLE) {
+    if (result == AAUDIO_ERROR_UNAVAILABLE) { // TODO review best error code
         result = AAUDIO_OK; // just not available yet, try again later
     }
     return result;
@@ -346,10 +371,17 @@
  * used to communicate with the underlying HAL or Service.
  */
 aaudio_result_t AAudioServiceStreamBase::getDescription(AudioEndpointParcelable &parcelable) {
-    // Gather information on the message queue.
-    mUpMessageQueue->fillParcelable(parcelable,
-                                    parcelable.mUpMessageQueueParcelable);
-    return getDownDataDescription(parcelable);
+    {
+        std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
+        if (mUpMessageQueue == nullptr) {
+            ALOGE("getDescription(): mUpMessageQueue null! - stream not open");
+            return AAUDIO_ERROR_NULL;
+        }
+        // Gather information on the message queue.
+        mUpMessageQueue->fillParcelable(parcelable,
+                                        parcelable.mUpMessageQueueParcelable);
+    }
+    return getAudioDataDescription(parcelable);
 }
 
 void AAudioServiceStreamBase::onVolumeChanged(float volume) {
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 301795d..af435b4 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -32,7 +32,10 @@
 
 #include "SharedRingBuffer.h"
 #include "AAudioThread.h"
-#include "AAudioService.h"
+
+namespace android {
+    class AAudioService;
+}
 
 namespace aaudio {
 
@@ -191,6 +194,12 @@
         mState = state;
     }
 
+    /**
+     * Device specific startup.
+     * @return AAUDIO_OK or negative error.
+     */
+    virtual aaudio_result_t startDevice();
+
     aaudio_result_t writeUpMessageQueue(AAudioServiceMessage *command);
 
     aaudio_result_t sendCurrentTimestamp();
@@ -204,7 +213,7 @@
 
     virtual aaudio_result_t getHardwareTimestamp(int64_t *positionFrames, int64_t *timeNanos) = 0;
 
-    virtual aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) = 0;
+    virtual aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) = 0;
 
     aaudio_stream_state_t   mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
 
@@ -213,7 +222,7 @@
     SharedRingBuffer*       mUpMessageQueue;
     std::mutex              mUpMessageQueueLock;
 
-    AAudioThread            mAAudioThread;
+    AAudioThread            mTimestampThread;
     // This is used by one thread to tell another thread to exit. So it must be atomic.
     std::atomic<bool>       mThreadEnabled{false};
 
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 47041c5..44ba1ca 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -50,7 +50,7 @@
 }
 
 aaudio_result_t AAudioServiceStreamMMAP::close() {
-    if (mState == AAUDIO_STREAM_STATE_CLOSED) {
+    if (getState() == AAUDIO_STREAM_STATE_CLOSED) {
         return AAUDIO_OK;
     }
 
@@ -67,7 +67,6 @@
     aaudio_result_t result = AAudioServiceStreamBase::open(request,
                                                            AAUDIO_SHARING_MODE_EXCLUSIVE);
     if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamBase open returned %d", result);
         return result;
     }
 
@@ -85,13 +84,10 @@
 /**
  * Start the flow of data.
  */
-aaudio_result_t AAudioServiceStreamMMAP::start() {
-    if (isRunning()) {
-        return AAUDIO_OK;
-    }
-
-    aaudio_result_t result = AAudioServiceStreamBase::start();
+aaudio_result_t AAudioServiceStreamMMAP::startDevice() {
+    aaudio_result_t result = AAudioServiceStreamBase::startDevice();
     if (!mInService && result == AAUDIO_OK) {
+        // Note that this can sometimes take 200 to 300 msec for a cold start!
         result = startClient(mMmapClient, &mClientHandle);
     }
     return result;
@@ -126,6 +122,7 @@
 
 aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
                                                        audio_port_handle_t *clientHandle) {
+    // Start the client on behalf of the application. Generate a new porthandle.
     aaudio_result_t result = mServiceEndpoint->startClient(client, clientHandle);
     return result;
 }
@@ -171,7 +168,8 @@
 /**
  * Get an immutable description of the data queue from the HAL.
  */
-aaudio_result_t AAudioServiceStreamMMAP::getDownDataDescription(AudioEndpointParcelable &parcelable)
+aaudio_result_t AAudioServiceStreamMMAP::getAudioDataDescription(
+        AudioEndpointParcelable &parcelable)
 {
     sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP{
             static_cast<AAudioServiceEndpointMMAP *>(mServiceEndpoint.get())};
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index bf0aab3..e2415d0 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -53,14 +53,6 @@
     aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
 
     /**
-     * Start the flow of audio data.
-     *
-     * This is not guaranteed to be synchronous but it currently is.
-     * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
-     */
-    aaudio_result_t start() override;
-
-    /**
      * Stop the flow of data so that start() can resume without loss of data.
      *
      * This is not guaranteed to be synchronous but it currently is.
@@ -83,12 +75,18 @@
 
 protected:
 
-    aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) override;
+    aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) override;
 
     aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override;
 
     aaudio_result_t getHardwareTimestamp(int64_t *positionFrames, int64_t *timeNanos) override;
 
+    /**
+     * Device specific startup.
+     * @return AAUDIO_OK or negative error.
+     */
+    aaudio_result_t startDevice() override;
+
 private:
 
     bool                     mInService = false;
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 834f39f..084f996 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -167,14 +167,17 @@
         goto error;
     }
 
-    // Create audio data shared memory buffer for client.
-    mAudioDataQueue = new SharedRingBuffer();
-    result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity());
-    if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames",
-              getBufferCapacity());
-        result = AAUDIO_ERROR_NO_MEMORY;
-        goto error;
+    {
+        std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
+        // Create audio data shared memory buffer for client.
+        mAudioDataQueue = new SharedRingBuffer();
+        result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity());
+        if (result != AAUDIO_OK) {
+            ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames",
+                  getBufferCapacity());
+            result = AAUDIO_ERROR_NO_MEMORY;
+            goto error;
+        }
     }
 
     ALOGD("AAudioServiceStreamShared::open() actual rate = %d, channels = %d, deviceId = %d",
@@ -197,8 +200,11 @@
 aaudio_result_t AAudioServiceStreamShared::close()  {
     aaudio_result_t result = AAudioServiceStreamBase::close();
 
-    delete mAudioDataQueue;
-    mAudioDataQueue = nullptr;
+    {
+        std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
+        delete mAudioDataQueue;
+        mAudioDataQueue = nullptr;
+    }
 
     return result;
 }
@@ -206,8 +212,14 @@
 /**
  * Get an immutable description of the data queue created by this service.
  */
-aaudio_result_t AAudioServiceStreamShared::getDownDataDescription(AudioEndpointParcelable &parcelable)
+aaudio_result_t AAudioServiceStreamShared::getAudioDataDescription(
+        AudioEndpointParcelable &parcelable)
 {
+    std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
+    if (mAudioDataQueue == nullptr) {
+        ALOGE("getAudioDataDescription(): mUpMessageQueue null! - stream not open");
+        return AAUDIO_ERROR_NULL;
+    }
     // Gather information on the data queue.
     mAudioDataQueue->fillParcelable(parcelable,
                                     parcelable.mDownDataQueueParcelable);
@@ -237,9 +249,15 @@
 aaudio_result_t AAudioServiceStreamShared::getHardwareTimestamp(int64_t *positionFrames,
                                                                 int64_t *timeNanos) {
 
-    aaudio_result_t result = mServiceEndpoint->getTimestamp(positionFrames, timeNanos);
+    int64_t position = 0;
+    aaudio_result_t result = mServiceEndpoint->getTimestamp(&position, timeNanos);
     if (result == AAUDIO_OK) {
-        *positionFrames -= mTimestampPositionOffset.load(); // Offset from shared MMAP stream
+        int64_t offset = mTimestampPositionOffset.load();
+        // TODO, do not go below starting value
+        position -= offset; // Offset from shared MMAP stream
+        ALOGV("getHardwareTimestamp() %8lld = %8lld - %8lld",
+              (long long) position, (long long) (position + offset), (long long) offset);
     }
+    *positionFrames = position;
     return result;
 }
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index bc86dcc..8499ea5 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -54,7 +54,21 @@
 
     aaudio_result_t close() override;
 
-    android::FifoBuffer *getDataFifoBuffer() { return mAudioDataQueue->getFifoBuffer(); }
+    /**
+     * This must be locked when calling getAudioDataFifoBuffer_l() and while
+     * using the FifoBuffer it returns.
+     */
+    std::mutex &getAudioDataQueueLock() {
+        return mAudioDataQueueLock;
+    }
+
+    /**
+     * This must only be call under getAudioDataQueueLock().
+     * @return
+     */
+    android::FifoBuffer *getAudioDataFifoBuffer_l() { return (mAudioDataQueue == nullptr)
+                                                      ? nullptr
+                                                      : mAudioDataQueue->getFifoBuffer(); }
 
     /* Keep a record of when a buffer transfer completed.
      * This allows for a more accurate timing model.
@@ -75,7 +89,7 @@
 
 protected:
 
-    aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) override;
+    aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) override;
 
     aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override;
 
@@ -90,7 +104,8 @@
                                             int32_t framesPerBurst);
 
 private:
-    SharedRingBuffer        *mAudioDataQueue = nullptr;
+    SharedRingBuffer        *mAudioDataQueue = nullptr; // protected by mAudioDataQueueLock
+    std::mutex               mAudioDataQueueLock;
 
     std::atomic<int64_t>     mTimestampPositionOffset;
     std::atomic<int32_t>     mXRunCount;
diff --git a/services/oboeservice/AAudioStreamTracker.cpp b/services/oboeservice/AAudioStreamTracker.cpp
new file mode 100644
index 0000000..ef88b34
--- /dev/null
+++ b/services/oboeservice/AAudioStreamTracker.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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 "AAudioStreamTracker"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include <aaudio/AAudio.h>
+#include <utils/String16.h>
+
+#include "AAudioStreamTracker.h"
+
+using namespace android;
+using namespace aaudio;
+
+sp<AAudioServiceStreamBase> AAudioStreamTracker::removeStreamByHandle(
+        aaudio_handle_t streamHandle) {
+    std::lock_guard<std::mutex> lock(mHandleLock);
+    sp<AAudioServiceStreamBase> serviceStream;
+    auto it = mStreamsByHandle.find(streamHandle);
+    if (it != mStreamsByHandle.end()) {
+        serviceStream = it->second;
+        mStreamsByHandle.erase(it);
+    }
+    return serviceStream;
+}
+
+sp<AAudioServiceStreamBase> AAudioStreamTracker::getStreamByHandle(
+        aaudio_handle_t streamHandle) {
+    std::lock_guard<std::mutex> lock(mHandleLock);
+    sp<AAudioServiceStreamBase> serviceStream;
+    auto it = mStreamsByHandle.find(streamHandle);
+    if (it != mStreamsByHandle.end()) {
+        serviceStream = it->second;
+    }
+    return serviceStream;
+}
+
+// advance to next legal handle value
+__attribute__((no_sanitize("integer")))
+aaudio_handle_t AAudioStreamTracker::bumpHandle(aaudio_handle_t handle) {
+    handle++;
+    // Only use positive integers.
+    if (handle <= 0) {
+        handle = 1;
+    }
+    return handle;
+}
+
+aaudio_handle_t AAudioStreamTracker::addStreamForHandle(sp<AAudioServiceStreamBase> serviceStream) {
+    std::lock_guard<std::mutex> lock(mHandleLock);
+    aaudio_handle_t handle = mPreviousHandle.load();
+    // Assign a unique handle.
+    while (true) {
+        handle = bumpHandle(handle);
+        sp<AAudioServiceStreamBase> oldServiceStream = mStreamsByHandle[handle];
+        // Is this an unused handle? It would be extremely unlikely to wrap
+        // around and collide with a very old handle. But just in case.
+        if (oldServiceStream.get() == nullptr) {
+            mStreamsByHandle[handle] = serviceStream;
+            break;
+        }
+    }
+    mPreviousHandle.store(handle);
+    return handle;
+}
+
+std::string AAudioStreamTracker::dump() const {
+    std::stringstream result;
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mHandleLock.try_lock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "AAudioStreamTracker may be deadlocked\n";
+    } else {
+        result << "Stream Handles:\n";
+        for (const auto&  it : mStreamsByHandle) {
+            aaudio_handle_t handle = it.second->getHandle();
+            result << "    0x" << std::setfill('0') << std::setw(8) << std::hex << handle
+                   << std::dec << std::setfill(' ') << "\n";
+        }
+
+        mHandleLock.unlock();
+    }
+    return result.str();
+}
diff --git a/services/oboeservice/AAudioStreamTracker.h b/services/oboeservice/AAudioStreamTracker.h
new file mode 100644
index 0000000..70d440d
--- /dev/null
+++ b/services/oboeservice/AAudioStreamTracker.h
@@ -0,0 +1,73 @@
+/*
+ * 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 AAUDIO_AAUDIO_STREAM_TRACKER_H
+#define AAUDIO_AAUDIO_STREAM_TRACKER_H
+
+#include <time.h>
+#include <pthread.h>
+
+#include <aaudio/AAudio.h>
+
+#include "binding/AAudioCommon.h"
+
+#include "AAudioServiceStreamBase.h"
+
+namespace aaudio {
+
+class AAudioStreamTracker {
+
+public:
+    /**
+     * Remove the stream associated with the handle.
+     * @param streamHandle
+     * @return strong pointer to the stream if found or to nullptr
+     */
+    android::sp<AAudioServiceStreamBase> removeStreamByHandle(aaudio_handle_t streamHandle);
+
+    /**
+     * Look up a stream based on the handle.
+     * @param streamHandle
+     * @return strong pointer to the stream if found or to nullptr
+     */
+    android::sp<aaudio::AAudioServiceStreamBase> getStreamByHandle(aaudio_handle_t streamHandle);
+
+    /**
+     * Store a strong pointer to the stream and return a unique handle for future reference.
+     * The handle is guaranteed not to collide with an existing stream.
+     * @param serviceStream
+     * @return handle for identifying the stream
+     */
+    aaudio_handle_t addStreamForHandle(android::sp<AAudioServiceStreamBase> serviceStream);
+
+    /**
+     * @return string that can be added to dumpsys
+     */
+    std::string dump() const;
+
+private:
+    static aaudio_handle_t bumpHandle(aaudio_handle_t handle);
+
+    // Track stream using a unique handle that wraps. Only use positive half.
+    mutable std::mutex                mHandleLock;
+    std::atomic<aaudio_handle_t>      mPreviousHandle{0};
+    std::map<aaudio_handle_t, android::sp<aaudio::AAudioServiceStreamBase>> mStreamsByHandle;
+};
+
+
+} /* namespace aaudio */
+
+#endif /* AAUDIO_AAUDIO_STREAM_TRACKER_H */
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
index 1b74ad3..584b2ef 100644
--- a/services/oboeservice/Android.mk
+++ b/services/oboeservice/Android.mk
@@ -22,7 +22,6 @@
     $(TOP)/frameworks/av/media/libaaudio/src
 
 LOCAL_SRC_FILES += \
-    $(LIBAAUDIO_SRC_DIR)/utility/HandleTracker.cpp \
     SharedMemoryProxy.cpp \
     SharedRingBuffer.cpp \
     AAudioClientTracker.cpp \
@@ -37,6 +36,7 @@
     AAudioServiceStreamBase.cpp \
     AAudioServiceStreamMMAP.cpp \
     AAudioServiceStreamShared.cpp \
+    AAudioStreamTracker.cpp \
     TimestampScheduler.cpp \
     AAudioThread.cpp
 
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 952acd7..22519a3 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -530,37 +530,45 @@
 void SoundTriggerHwService::Module::detach(const sp<ModuleClient>& moduleClient)
 {
     ALOGV("Module::detach()");
-    AutoMutex lock(mLock);
-    ssize_t index = -1;
+    Vector<audio_session_t> releasedSessions;
 
-    for (size_t i = 0; i < mModuleClients.size(); i++) {
-        if (mModuleClients[i] == moduleClient) {
-            index = i;
-            break;
-        }
-    }
-    if (index == -1) {
-        return;
-    }
+    {
+        AutoMutex lock(mLock);
+        ssize_t index = -1;
 
-    ALOGV("remove client %p", moduleClient.get());
-    mModuleClients.removeAt(index);
-
-    // Iterate in reverse order as models are removed from list inside the loop.
-    for (size_t i = mModels.size(); i > 0; i--) {
-        sp<Model> model = mModels.valueAt(i - 1);
-        if (moduleClient == model->mModuleClient) {
-            mModels.removeItemsAt(i - 1);
-            ALOGV("detach() unloading model %d", model->mHandle);
-            if (mHalInterface != 0) {
-                if (model->mState == Model::STATE_ACTIVE) {
-                    mHalInterface->stopRecognition(model->mHandle);
-                }
-                mHalInterface->unloadSoundModel(model->mHandle);
+        for (size_t i = 0; i < mModuleClients.size(); i++) {
+            if (mModuleClients[i] == moduleClient) {
+                index = i;
+                break;
             }
-            AudioSystem::releaseSoundTriggerSession(model->mCaptureSession);
-            mHalInterface->unloadSoundModel(model->mHandle);
         }
+        if (index == -1) {
+            return;
+        }
+
+        ALOGV("remove client %p", moduleClient.get());
+        mModuleClients.removeAt(index);
+
+        // Iterate in reverse order as models are removed from list inside the loop.
+        for (size_t i = mModels.size(); i > 0; i--) {
+            sp<Model> model = mModels.valueAt(i - 1);
+            if (moduleClient == model->mModuleClient) {
+                mModels.removeItemsAt(i - 1);
+                ALOGV("detach() unloading model %d", model->mHandle);
+                if (mHalInterface != 0) {
+                    if (model->mState == Model::STATE_ACTIVE) {
+                        mHalInterface->stopRecognition(model->mHandle);
+                    }
+                    mHalInterface->unloadSoundModel(model->mHandle);
+                }
+                releasedSessions.add(model->mCaptureSession);
+            }
+        }
+    }
+
+    for (size_t i = 0; i < releasedSessions.size(); i++) {
+        // do not call AudioSystem methods with mLock held
+        AudioSystem::releaseSoundTriggerSession(releasedSessions[i]);
     }
 }
 
@@ -595,61 +603,71 @@
         return BAD_VALUE;
     }
 
-    AutoMutex lock(mLock);
-
-    if (mModels.size() >= mDescriptor.properties.max_sound_models) {
-        ALOGW("loadSoundModel(): Not loading, max number of models (%d) would be exceeded",
-              mDescriptor.properties.max_sound_models);
-        return INVALID_OPERATION;
-    }
-
-    status_t status = mHalInterface->loadSoundModel(sound_model,
-                                                  SoundTriggerHwService::soundModelCallback,
-                                                  this, handle);
-
-    if (status != NO_ERROR) {
-        return status;
-    }
     audio_session_t session;
     audio_io_handle_t ioHandle;
     audio_devices_t device;
-
-    status = AudioSystem::acquireSoundTriggerSession(&session, &ioHandle, &device);
+    // do not call AudioSystem methods with mLock held
+    status_t status = AudioSystem::acquireSoundTriggerSession(&session, &ioHandle, &device);
     if (status != NO_ERROR) {
         return status;
     }
 
-    sp<Model> model = new Model(*handle, session, ioHandle, device, sound_model->type,
-                                moduleClient);
-    mModels.replaceValueFor(*handle, model);
+    {
+        AutoMutex lock(mLock);
 
+        if (mModels.size() >= mDescriptor.properties.max_sound_models) {
+            ALOGW("loadSoundModel(): Not loading, max number of models (%d) would be exceeded",
+                  mDescriptor.properties.max_sound_models);
+            status = INVALID_OPERATION;
+            goto exit;
+        }
+
+        status = mHalInterface->loadSoundModel(sound_model,
+                                                      SoundTriggerHwService::soundModelCallback,
+                                                      this, handle);
+        if (status != NO_ERROR) {
+            goto exit;
+        }
+
+        sp<Model> model = new Model(*handle, session, ioHandle, device, sound_model->type,
+                                    moduleClient);
+        mModels.replaceValueFor(*handle, model);
+    }
+exit:
+    if (status != NO_ERROR) {
+        // do not call AudioSystem methods with mLock held
+        AudioSystem::releaseSoundTriggerSession(session);
+    }
     return status;
 }
 
 status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t handle)
 {
     ALOGV("unloadSoundModel() model handle %d", handle);
-    AutoMutex lock(mLock);
-    return unloadSoundModel_l(handle);
-}
+    status_t status;
+    audio_session_t session;
 
-status_t SoundTriggerHwService::Module::unloadSoundModel_l(sound_model_handle_t handle)
-{
-    if (mHalInterface == 0) {
-        return NO_INIT;
+    {
+        AutoMutex lock(mLock);
+        if (mHalInterface == 0) {
+            return NO_INIT;
+        }
+        ssize_t index = mModels.indexOfKey(handle);
+        if (index < 0) {
+            return BAD_VALUE;
+        }
+        sp<Model> model = mModels.valueAt(index);
+        mModels.removeItem(handle);
+        if (model->mState == Model::STATE_ACTIVE) {
+            mHalInterface->stopRecognition(model->mHandle);
+            model->mState = Model::STATE_IDLE;
+        }
+        status = mHalInterface->unloadSoundModel(handle);
+        session = model->mCaptureSession;
     }
-    ssize_t index = mModels.indexOfKey(handle);
-    if (index < 0) {
-        return BAD_VALUE;
-    }
-    sp<Model> model = mModels.valueAt(index);
-    mModels.removeItem(handle);
-    if (model->mState == Model::STATE_ACTIVE) {
-        mHalInterface->stopRecognition(model->mHandle);
-        model->mState = Model::STATE_IDLE;
-    }
-    AudioSystem::releaseSoundTriggerSession(model->mCaptureSession);
-    return mHalInterface->unloadSoundModel(handle);
+    // do not call AudioSystem methods with mLock held
+    AudioSystem::releaseSoundTriggerSession(session);
+    return status;
 }
 
 status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle,
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
index 60ebb35..95efc4b 100644
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -140,8 +140,6 @@
 
     private:
 
-        status_t unloadSoundModel_l(sound_model_handle_t handle);
-
         Mutex                                  mLock;
         wp<SoundTriggerHwService>              mService;
         sp<SoundTriggerHalInterface>           mHalInterface;