Merge "Camera: fix buffer leak in device error condition" into oc-dr1-dev
diff --git a/camera/Android.bp b/camera/Android.bp
index 849f560..c76ae50 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -31,9 +31,11 @@
         // include libcamera_client, at the path "aidl/package/path/BnFoo.h"
         "aidl/android/hardware/ICameraService.aidl",
         "aidl/android/hardware/ICameraServiceListener.aidl",
+        "aidl/android/hardware/ICameraServiceProxy.aidl",
         "aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl",
         "aidl/android/hardware/camera2/ICameraDeviceUser.aidl",
 
+
         // Source for camera interface parcelables, and manually-written interfaces
         "Camera.cpp",
         "CameraMetadata.cpp",
@@ -42,7 +44,6 @@
         "CameraParameters2.cpp",
         "ICamera.cpp",
         "ICameraClient.cpp",
-        "ICameraServiceProxy.cpp",
         "ICameraRecordingProxy.cpp",
         "ICameraRecordingProxyListener.cpp",
         "camera2/CaptureRequest.cpp",
diff --git a/camera/ICameraServiceProxy.cpp b/camera/ICameraServiceProxy.cpp
deleted file mode 100644
index a9d0836..0000000
--- a/camera/ICameraServiceProxy.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BpCameraServiceProxy"
-
-#include <stdint.h>
-
-#include <binder/Parcel.h>
-
-#include <camera/ICameraServiceProxy.h>
-
-namespace android {
-
-class BpCameraServiceProxy: public BpInterface<ICameraServiceProxy> {
-public:
-    explicit BpCameraServiceProxy(const sp<IBinder>& impl)
-        : BpInterface<ICameraServiceProxy>(impl) {}
-
-    virtual void pingForUserUpdate() {
-        Parcel data;
-        data.writeInterfaceToken(ICameraServiceProxy::getInterfaceDescriptor());
-        remote()->transact(BnCameraServiceProxy::PING_FOR_USER_UPDATE, data, nullptr,
-                IBinder::FLAG_ONEWAY);
-    }
-
-    virtual void notifyCameraState(String16 cameraId, CameraState newCameraState) {
-        Parcel data;
-        data.writeInterfaceToken(ICameraServiceProxy::getInterfaceDescriptor());
-        data.writeString16(cameraId);
-        data.writeInt32(newCameraState);
-        remote()->transact(BnCameraServiceProxy::NOTIFY_CAMERA_STATE, data, nullptr,
-                IBinder::FLAG_ONEWAY);
-    }
-
-};
-
-
-IMPLEMENT_META_INTERFACE(CameraServiceProxy, "android.hardware.ICameraServiceProxy");
-
-status_t BnCameraServiceProxy::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
-        uint32_t flags) {
-    switch(code) {
-        case PING_FOR_USER_UPDATE: {
-            CHECK_INTERFACE(ICameraServiceProxy, data, reply);
-            pingForUserUpdate();
-            return NO_ERROR;
-        } break;
-        case NOTIFY_CAMERA_STATE: {
-            CHECK_INTERFACE(ICameraServiceProxy, data, reply);
-            String16 cameraId = data.readString16();
-            CameraState newCameraState =
-                static_cast<CameraState>(data.readInt32());
-            notifyCameraState(cameraId, newCameraState);
-            return NO_ERROR;
-        } break;
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-}; // namespace android
diff --git a/camera/aidl/android/hardware/ICameraServiceProxy.aidl b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
index 0e654d5..5dc23eb 100644
--- a/camera/aidl/android/hardware/ICameraServiceProxy.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
@@ -31,7 +31,23 @@
     oneway void pingForUserUpdate();
 
     /**
-     * Update the status of a camera device
+     * Values for notifyCameraState newCameraState
      */
-     oneway void notifyCameraState(String cameraId, int newCameraState);
+    const int CAMERA_STATE_OPEN = 0;
+    const int CAMERA_STATE_ACTIVE = 1;
+    const int CAMERA_STATE_IDLE = 2;
+    const int CAMERA_STATE_CLOSED = 3;
+
+    /**
+     * Values for notifyCameraState facing
+     */
+    const int CAMERA_FACING_BACK = 0;
+    const int CAMERA_FACING_FRONT = 1;
+    const int CAMERA_FACING_EXTERNAL = 2;
+
+    /**
+     * Update the status of a camera device.
+     */
+    oneway void notifyCameraState(String cameraId, int facing, int newCameraState,
+            String clientName);
 }
diff --git a/camera/include/camera/ICameraServiceProxy.h b/camera/include/camera/ICameraServiceProxy.h
deleted file mode 100644
index 2613c01..0000000
--- a/camera/include/camera/ICameraServiceProxy.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_ICAMERASERVICEPROXY_H
-#define ANDROID_HARDWARE_ICAMERASERVICEPROXY_H
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-/**
- * Interface from native camera service to managed-side camera service proxy.
- *
- * Keep in sync with frameworks/base/core/java/android/hardware/ICameraServiceProxy.aidl
- *
- */
-class ICameraServiceProxy : public IInterface {
-public:
-    enum {
-        PING_FOR_USER_UPDATE = IBinder::FIRST_CALL_TRANSACTION,
-        NOTIFY_CAMERA_STATE
-    };
-
-    enum CameraState {
-        CAMERA_STATE_OPEN,
-        CAMERA_STATE_ACTIVE,
-        CAMERA_STATE_IDLE,
-        CAMERA_STATE_CLOSED
-    };
-
-    DECLARE_META_INTERFACE(CameraServiceProxy);
-
-    virtual void pingForUserUpdate() = 0;
-    virtual void notifyCameraState(String16 cameraId, CameraState newCameraState) = 0;
-};
-
-class BnCameraServiceProxy: public BnInterface<ICameraServiceProxy>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-
-
-}; // namespace android
-
-#endif // ANDROID_HARDWARE_ICAMERASERVICEPROXY_H
diff --git a/include/media/AudioClient.h b/include/media/AudioClient.h
new file mode 120000
index 0000000..a0530e4
--- /dev/null
+++ b/include/media/AudioClient.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/media/AudioClient.h
\ No newline at end of file
diff --git a/include/media/MmapStreamInterface.h b/include/media/MmapStreamInterface.h
index 7dbc19e..d689e25 100644
--- a/include/media/MmapStreamInterface.h
+++ b/include/media/MmapStreamInterface.h
@@ -18,6 +18,7 @@
 #define ANDROID_AUDIO_MMAP_STREAM_INTERFACE_H
 
 #include <system/audio.h>
+#include <media/AudioClient.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
@@ -37,12 +38,6 @@
         DIRECTION_INPUT,       /**< open a capture mmap stream */
     } stream_direction_t;
 
-    class Client {
-     public:
-        uid_t clientUid;
-        pid_t clientPid;
-        String16 packageName;
-    };
     /**
      * Open a playback or capture stream in MMAP mode at the audio HAL.
      *
@@ -53,13 +48,14 @@
      * \param[in,out] config audio parameters (sampling rate, format ...) for the stream.
      *                       Requested parameters as input,
      *                       Actual parameters as output
-     * \param[in] client a Client struct describing the first client using this stream.
+     * \param[in] client a AudioClient struct describing the first client using this stream.
      * \param[in,out] deviceId audio device the stream should preferably be routed to/from
      *                       Requested as input,
      *                       Actual as output
      * \param[in] callback the MmapStreamCallback interface used by AudioFlinger to notify
      *                     condition changes affecting the stream operation
      * \param[out] interface the MmapStreamInterface interface controlling the created stream
+     * \param[out] same unique handle as the one used for the first client stream started.
      * \return OK if the stream was successfully created.
      *         NO_INIT if AudioFlinger is not properly initialized
      *         BAD_VALUE if the stream cannot be opened because of invalid arguments
@@ -68,10 +64,11 @@
     static status_t openMmapStream(stream_direction_t direction,
                                            const audio_attributes_t *attr,
                                            audio_config_base_t *config,
-                                           const Client& client,
+                                           const AudioClient& client,
                                            audio_port_handle_t *deviceId,
                                            const sp<MmapStreamCallback>& callback,
-                                           sp<MmapStreamInterface>& interface);
+                                           sp<MmapStreamInterface>& interface,
+                                           audio_port_handle_t *handle);
 
     /**
      * Retrieve information on the mmap buffer used for audio samples transfer.
@@ -105,13 +102,13 @@
      * Start a stream operating in mmap mode.
      * createMmapBuffer() must be called before calling start()
      *
-     * \param[in] client a Client struct describing the client starting on this stream.
+     * \param[in] client a AudioClient struct describing the client starting on this stream.
      * \param[out] handle unique handle for this instance. Used with stop().
      * \return OK in case of success.
      *         NO_INIT in case of initialization error
      *         INVALID_OPERATION if called out of sequence
      */
-    virtual status_t start(const Client& client, audio_port_handle_t *handle) = 0;
+    virtual status_t start(const AudioClient& client, audio_port_handle_t *handle) = 0;
 
     /**
      * Stop a stream operating in mmap mode.
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 45a3beb..57d45cd 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -17,6 +17,7 @@
 // Play an impulse and then record it.
 // Measure the round trip latency.
 
+#include <algorithm>
 #include <assert.h>
 #include <cctype>
 #include <math.h>
@@ -25,11 +26,13 @@
 #include <unistd.h>
 
 #include <aaudio/AAudio.h>
+#include <aaudio/AAudioTesting.h>
 
-#define INPUT_PEAK_THRESHOLD    0.1f
-#define SILENCE_FRAMES          10000
+// Tag for machine readable results as property = value pairs
+#define RESULT_TAG              "RESULT: "
 #define SAMPLE_RATE             48000
-#define NUM_SECONDS             7
+#define NUM_SECONDS             5
+#define NUM_INPUT_CHANNELS      1
 #define FILENAME                "/data/oboe_input.raw"
 
 #define NANOS_PER_MICROSECOND ((int64_t)1000)
@@ -37,12 +40,172 @@
 #define MILLIS_PER_SECOND     1000
 #define NANOS_PER_SECOND      (NANOS_PER_MILLISECOND * MILLIS_PER_SECOND)
 
-class AudioRecorder
+#define MAX_ZEROTH_PARTIAL_BINS   40
+
+static const float s_Impulse[] = {
+        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // silence on each side of the impulse
+        0.5f, 0.9f, 0.0f, -0.9f, -0.5f, // bipolar
+        0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
+
+
+static double calculateCorrelation(const float *a,
+                                   const float *b,
+                                   int windowSize)
+{
+    double correlation = 0.0;
+    double sumProducts = 0.0;
+    double sumSquares = 0.0;
+
+    // Correlate a against b.
+    for (int i = 0; i < windowSize; i++) {
+        float s1 = a[i];
+        float s2 = b[i];
+        // Use a normalized cross-correlation.
+        sumProducts += s1 * s2;
+        sumSquares += ((s1 * s1) + (s2 * s2));
+    }
+
+    if (sumSquares >= 0.00000001) {
+        correlation = (float) (2.0 * sumProducts / sumSquares);
+    }
+    return correlation;
+}
+
+static int calculateCorrelations(const float *haystack, int haystackSize,
+                                 const float *needle, int needleSize,
+                                 float *results, int resultSize)
+{
+    int ic;
+    int maxCorrelations = haystackSize - needleSize;
+    int numCorrelations = std::min(maxCorrelations, resultSize);
+
+    for (ic = 0; ic < numCorrelations; ic++) {
+        double correlation = calculateCorrelation(&haystack[ic], needle, needleSize);
+        results[ic] = correlation;
+    }
+
+    return numCorrelations;
+}
+
+/*==========================================================================================*/
+/**
+ * Scan until we get a correlation of a single scan that goes over the tolerance level,
+ * peaks then drops back down.
+ */
+static double findFirstMatch(const float *haystack, int haystackSize,
+                             const float *needle, int needleSize, double threshold  )
+{
+    int ic;
+    // How many correlations can we calculate?
+    int numCorrelations = haystackSize - needleSize;
+    double maxCorrelation = 0.0;
+    int peakIndex = -1;
+    double location = -1.0;
+
+    for (ic = 0; ic < numCorrelations; ic++) {
+        double correlation = calculateCorrelation(&haystack[ic], needle, needleSize);
+
+        if( (correlation > maxCorrelation) ) {
+            maxCorrelation = correlation;
+            peakIndex = ic;
+        }
+
+        //printf("PaQa_FindFirstMatch: ic = %4d, correlation = %8f, maxSum = %8f\n",
+        //    ic, correlation, maxSum );
+        // Are we past what we were looking for?
+        if((maxCorrelation > threshold) && (correlation < 0.5 * maxCorrelation)) {
+            location = peakIndex;
+            break;
+        }
+    }
+
+    return location;
+}
+
+typedef struct LatencyReport_s {
+    double latencyInFrames;
+    double confidence;
+} LatencyReport;
+
+// Apply a technique similar to Harmonic Product Spectrum Analysis to find echo fundamental.
+// Using first echo instead of the original impulse for a better match.
+int measureLatencyFromEchos(const float *haystack, int haystackSize,
+                          const float *needle, int needleSize,
+                          LatencyReport *report) {
+    double threshold = 0.1;
+
+    // Find first peak
+    int first = (int) (findFirstMatch(haystack,
+                                      haystackSize,
+                                      needle,
+                                      needleSize,
+                                      threshold) + 0.5);
+
+    // Use first echo as the needle for the other echos because
+    // it will be more similar.
+    needle = &haystack[first];
+    int again = (int) (findFirstMatch(haystack,
+                                      haystackSize,
+                                      needle,
+                                      needleSize,
+                                      threshold) + 0.5);
+
+    printf("first = %d, again at %d\n", first, again);
+    first = again;
+
+    // Allocate results array
+    int remaining = haystackSize - first;
+    int generous = 48000 * 2;
+    int numCorrelations = std::min(remaining, generous);
+    float *correlations = new float[numCorrelations];
+    float *harmonicSums = new float[numCorrelations](); // cleared to zero
+
+    // Generate correlation for every position.
+    numCorrelations = calculateCorrelations(&haystack[first], remaining,
+                                            needle, needleSize,
+                                            correlations, numCorrelations);
+
+    // Add higher harmonics mapped onto lower harmonics.
+    // This reinforces the "fundamental" echo.
+    const int numEchoes = 10;
+    for (int partial = 1; partial < numEchoes; partial++) {
+        for (int i = 0; i < numCorrelations; i++) {
+            harmonicSums[i / partial] += correlations[i] / partial;
+        }
+    }
+
+    // Find highest peak in correlation array.
+    float maxCorrelation = 0.0;
+    float sumOfPeaks = 0.0;
+    int peakIndex = 0;
+    const int skip = MAX_ZEROTH_PARTIAL_BINS; // skip low bins
+    for (int i = skip; i < numCorrelations; i++) {
+        if (harmonicSums[i] > maxCorrelation) {
+            maxCorrelation = harmonicSums[i];
+            sumOfPeaks += maxCorrelation;
+            peakIndex = i;
+            printf("maxCorrelation = %f at %d\n", maxCorrelation, peakIndex);
+        }
+    }
+
+    report->latencyInFrames = peakIndex;
+    if (sumOfPeaks < 0.0001) {
+        report->confidence = 0.0;
+    } else {
+        report->confidence = maxCorrelation / sumOfPeaks;
+    }
+
+    delete[] correlations;
+    delete[] harmonicSums;
+    return 0;
+}
+
+class AudioRecording
 {
 public:
-    AudioRecorder() {
+    AudioRecording() {
     }
-    ~AudioRecorder() {
+    ~AudioRecording() {
         delete[] mData;
     }
 
@@ -52,7 +215,8 @@
         mMaxFrames = maxFrames;
     }
 
-    void record(int16_t *inputData, int inputChannelCount, int numFrames) {
+    // Write SHORT data from the first channel.
+    int write(int16_t *inputData, int inputChannelCount, int numFrames) {
         // stop at end of buffer
         if ((mFrameCounter + numFrames) > mMaxFrames) {
             numFrames = mMaxFrames - mFrameCounter;
@@ -60,9 +224,11 @@
         for (int i = 0; i < numFrames; i++) {
             mData[mFrameCounter++] = inputData[i * inputChannelCount] * (1.0f / 32768);
         }
+        return numFrames;
     }
 
-    void record(float *inputData, int inputChannelCount, int numFrames) {
+    // Write FLOAT data from the first channel.
+    int write(float *inputData, int inputChannelCount, int numFrames) {
         // stop at end of buffer
         if ((mFrameCounter + numFrames) > mMaxFrames) {
             numFrames = mMaxFrames - mFrameCounter;
@@ -70,162 +236,253 @@
         for (int i = 0; i < numFrames; i++) {
             mData[mFrameCounter++] = inputData[i * inputChannelCount];
         }
+        return numFrames;
     }
 
-    int save(const char *fileName) {
+    int size() {
+        return mFrameCounter;
+    }
+
+    float *getData() {
+        return mData;
+    }
+
+    int save(const char *fileName, bool writeShorts = true) {
+        int written = 0;
+        const int chunkSize = 64;
         FILE *fid = fopen(fileName, "wb");
         if (fid == NULL) {
-            return errno;
+            return -errno;
         }
-        int written = fwrite(mData, sizeof(float), mFrameCounter, fid);
+
+        if (writeShorts) {
+            int16_t buffer[chunkSize];
+            int32_t framesLeft = mFrameCounter;
+            int32_t cursor = 0;
+            while (framesLeft) {
+                int32_t framesToWrite = framesLeft < chunkSize ? framesLeft : chunkSize;
+                for (int i = 0; i < framesToWrite; i++) {
+                    buffer[i] = (int16_t) (mData[cursor++] * 32767);
+                }
+                written += fwrite(buffer, sizeof(int16_t), framesToWrite, fid);
+                framesLeft -= framesToWrite;
+            }
+        } else {
+            written = fwrite(mData, sizeof(float), mFrameCounter, fid);
+        }
         fclose(fid);
         return written;
     }
 
 private:
-    float *mData = NULL;
+    float  *mData = nullptr;
     int32_t mFrameCounter = 0;
     int32_t mMaxFrames = 0;
 };
 
 // ====================================================================================
-// ========================= Loopback Processor =======================================
-// ====================================================================================
 class LoopbackProcessor {
 public:
+    virtual ~LoopbackProcessor() = default;
 
-    // Calculate mean and standard deviation.
-    double calculateAverageLatency(double *deviation) {
-        if (mLatencyCount <= 0) {
-            return -1.0;
-        }
-        double sum = 0.0;
-        for (int i = 0; i < mLatencyCount; i++) {
-            sum += mLatencyArray[i];
-        }
-        double average = sum /  mLatencyCount;
-        sum = 0.0;
-        for (int i = 0; i < mLatencyCount; i++) {
-            double error = average - mLatencyArray[i];
-            sum += error * error; // squared
-        }
-        *deviation = sqrt(sum / mLatencyCount);
-        return average;
+    virtual void process(float *inputData, int inputChannelCount,
+                 float *outputData, int outputChannelCount,
+                 int numFrames) = 0;
+
+
+    virtual void report() = 0;
+
+    void setSampleRate(int32_t sampleRate) {
+        mSampleRate = sampleRate;
     }
 
-    float getMaxAmplitude() const { return mMaxAmplitude; }
-    int   getMeasurementCount() const { return mLatencyCount; }
-    float getAverageAmplitude() const { return mAmplitudeTotal / mAmplitudeCount; }
-
-    // TODO Convert this to a feedback circuit and then use auto-correlation to measure the period.
-    void process(float *inputData, int inputChannelCount,
-            float *outputData, int outputChannelCount,
-            int numFrames) {
-        (void) outputChannelCount;
-
-        // Measure peak and average amplitude.
-        for (int i = 0; i < numFrames; i++) {
-            float sample = inputData[i * inputChannelCount];
-            if (sample > mMaxAmplitude) {
-                mMaxAmplitude = sample;
-            }
-            if (sample < 0) {
-                sample = 0 - sample;
-            }
-            mAmplitudeTotal += sample;
-            mAmplitudeCount++;
-        }
-
-        // Clear output.
-        memset(outputData, 0, numFrames * outputChannelCount * sizeof(float));
-
-        // Wait a while between hearing the pulse and starting a new one.
-        if (mState == STATE_SILENT) {
-            mCounter += numFrames;
-            if (mCounter > SILENCE_FRAMES) {
-                //printf("LoopbackProcessor send impulse, burst #%d\n", mBurstCounter);
-                // copy impulse
-                for (float sample : mImpulse) {
-                    *outputData = sample;
-                    outputData += outputChannelCount;
-                }
-                mState = STATE_LISTENING;
-                mCounter = 0;
-            }
-        }
-        // Start listening as soon as we send the impulse.
-        if (mState ==  STATE_LISTENING) {
-            for (int i = 0; i < numFrames; i++) {
-                float sample = inputData[i * inputChannelCount];
-                if (sample >= INPUT_PEAK_THRESHOLD) {
-                    mLatencyArray[mLatencyCount++] = mCounter;
-                    if (mLatencyCount >= MAX_LATENCY_VALUES) {
-                        mState = STATE_DONE;
-                    } else {
-                        mState = STATE_SILENT;
-                    }
-                    mCounter = 0;
-                    break;
-                } else {
-                    mCounter++;
-                }
-            }
-        }
+    int32_t getSampleRate() {
+        return mSampleRate;
     }
 
-    void echo(float *inputData, int inputChannelCount,
-            float *outputData, int outputChannelCount,
-            int numFrames) {
-        int channelsValid = (inputChannelCount < outputChannelCount)
-            ? inputChannelCount : outputChannelCount;
-        for (int i = 0; i < numFrames; i++) {
-            int ic;
-            for (ic = 0; ic < channelsValid; ic++) {
-                outputData[ic] = inputData[ic];
-            }
-            for (ic = 0; ic < outputChannelCount; ic++) {
-                outputData[ic] = 0;
-            }
-            inputData += inputChannelCount;
-            outputData += outputChannelCount;
-        }
-    }
 private:
-    enum {
-        STATE_SILENT,
-        STATE_LISTENING,
-        STATE_DONE
-    };
-
-    enum {
-        MAX_LATENCY_VALUES = 64
-    };
-
-    int     mState = STATE_SILENT;
-    int32_t mCounter = 0;
-    int32_t mLatencyArray[MAX_LATENCY_VALUES];
-    int32_t mLatencyCount = 0;
-    float   mMaxAmplitude = 0;
-    float   mAmplitudeTotal = 0;
-    int32_t mAmplitudeCount = 0;
-    static const float mImpulse[5];
+    int32_t mSampleRate = SAMPLE_RATE;
 };
 
-const float LoopbackProcessor::mImpulse[5] = {0.5f, 0.9f, 0.0f, -0.9f, -0.5f};
+
+// ====================================================================================
+class EchoAnalyzer : public LoopbackProcessor {
+public:
+
+    EchoAnalyzer() : LoopbackProcessor() {
+        audioRecorder.allocate(NUM_SECONDS * SAMPLE_RATE);
+    }
+
+    void setGain(float gain) {
+        mGain = gain;
+    }
+
+    float getGain() {
+        return mGain;
+    }
+
+    void report() override {
+
+        const float *needle = s_Impulse;
+        int needleSize = (int)(sizeof(s_Impulse) / sizeof(float));
+        float *haystack = audioRecorder.getData();
+        int haystackSize = audioRecorder.size();
+        int result = measureLatencyFromEchos(haystack, haystackSize,
+                                              needle, needleSize,
+                                              &latencyReport);
+        if (latencyReport.confidence < 0.01) {
+            printf(" ERROR - confidence too low = %f\n", latencyReport.confidence);
+        } else {
+            double latencyMillis = 1000.0 * latencyReport.latencyInFrames / getSampleRate();
+            printf(RESULT_TAG "latency.frames     = %8.2f\n", latencyReport.latencyInFrames);
+            printf(RESULT_TAG "latency.msec       = %8.2f\n", latencyMillis);
+            printf(RESULT_TAG "latency.confidence = %8.6f\n", latencyReport.confidence);
+        }
+    }
+
+    void process(float *inputData, int inputChannelCount,
+                 float *outputData, int outputChannelCount,
+                 int numFrames) override {
+        int channelsValid = std::min(inputChannelCount, outputChannelCount);
+
+        audioRecorder.write(inputData, inputChannelCount, numFrames);
+
+        if (mLoopCounter < mLoopStart) {
+            // Output silence at the beginning.
+            for (int i = 0; i < numFrames; i++) {
+                int ic;
+                for (ic = 0; ic < outputChannelCount; ic++) {
+                    outputData[ic] = 0;
+                }
+                inputData += inputChannelCount;
+                outputData += outputChannelCount;
+            }
+        } else if (mLoopCounter == mLoopStart) {
+            // Send a bipolar impulse that we can easily detect.
+            for (float sample : s_Impulse) {
+                *outputData = sample;
+                outputData += outputChannelCount;
+            }
+        } else {
+            // Echo input to output.
+            for (int i = 0; i < numFrames; i++) {
+                int ic;
+                for (ic = 0; ic < channelsValid; ic++) {
+                    outputData[ic] = inputData[ic] * mGain;
+                }
+                for (; ic < outputChannelCount; ic++) {
+                    outputData[ic] = 0;
+                }
+                inputData += inputChannelCount;
+                outputData += outputChannelCount;
+            }
+        }
+
+        mLoopCounter++;
+    }
+
+private:
+    int   mLoopCounter = 0;
+    int   mLoopStart = 1000;
+    float mGain = 1.0f;
+
+    AudioRecording     audioRecorder;
+    LatencyReport      latencyReport;
+};
+
+
+// ====================================================================================
+class SineAnalyzer : public LoopbackProcessor {
+public:
+
+    void report() override {
+        double magnitude = calculateMagnitude();
+        printf("sine magnitude = %7.5f\n", magnitude);
+        printf("sine frames    = %7d\n", mFrameCounter);
+        printf("sine frequency = %7.1f Hz\n", mFrequency);
+    }
+
+    double calculateMagnitude(double *phasePtr = NULL) {
+        if (mFrameCounter == 0) {
+            return 0.0;
+        }
+        double sinMean = mSinAccumulator / mFrameCounter;
+        double cosMean = mCosAccumulator / mFrameCounter;
+        double magnitude = 2.0 * sqrt( (sinMean * sinMean) + (cosMean * cosMean ));
+        if( phasePtr != NULL )
+        {
+            double phase = atan2( sinMean, cosMean );
+            *phasePtr = phase;
+        }
+        return magnitude;
+    }
+
+    void process(float *inputData, int inputChannelCount,
+                 float *outputData, int outputChannelCount,
+                 int numFrames) override {
+        double phaseIncrement = 2.0 * M_PI * mFrequency / getSampleRate();
+
+        for (int i = 0; i < numFrames; i++) {
+            // Multiply input by sine/cosine
+            float sample = inputData[i * inputChannelCount];
+            float sinOut = sinf(mPhase);
+            mSinAccumulator += sample * sinOut;
+            mCosAccumulator += sample * cosf(mPhase);
+            // Advance and wrap phase
+            mPhase += phaseIncrement;
+            if (mPhase > (2.0 * M_PI)) {
+                mPhase -= (2.0 * M_PI);
+            }
+
+            // Output sine wave so we can measure it.
+            outputData[i * outputChannelCount] = sinOut;
+        }
+        mFrameCounter += numFrames;
+
+        double magnitude = calculateMagnitude();
+        if (mWaiting) {
+            if (magnitude < 0.001) {
+                // discard silence
+                mFrameCounter = 0;
+                mSinAccumulator = 0.0;
+                mCosAccumulator = 0.0;
+            } else {
+                mWaiting = false;
+            }
+        }
+    };
+
+    void setFrequency(int32_t frequency) {
+        mFrequency = frequency;
+    }
+
+    int32_t getFrequency() {
+        return mFrequency;
+    }
+
+private:
+    double  mFrequency = 300.0;
+    double  mPhase = 0.0;
+    int32_t mFrameCounter = 0;
+    double  mSinAccumulator = 0.0;
+    double  mCosAccumulator = 0.0;
+    bool    mWaiting = true;
+};
 
 // TODO make this a class that manages its own buffer allocation
 struct LoopbackData {
-    AAudioStream     *inputStream = nullptr;
-    int32_t           inputFramesMaximum = 0;
-    int16_t          *inputData = nullptr;
-    float            *conversionBuffer = nullptr;
-    int32_t           actualInputChannelCount = 0;
-    int32_t           actualOutputChannelCount = 0;
-    int32_t           inputBuffersToDiscard = 10;
+    AAudioStream      *inputStream = nullptr;
+    int32_t            inputFramesMaximum = 0;
+    int16_t           *inputData = nullptr;
+    float             *conversionBuffer = nullptr;
+    int32_t            actualInputChannelCount = 0;
+    int32_t            actualOutputChannelCount = 0;
+    int32_t            inputBuffersToDiscard = 10;
 
-    aaudio_result_t   inputError;
-    LoopbackProcessor loopbackProcessor;
-    AudioRecorder     audioRecorder;
+    aaudio_result_t    inputError;
+    SineAnalyzer       sineAnalyzer;
+    EchoAnalyzer       echoAnalyzer;
+    LoopbackProcessor *loopbackProcessor;
 };
 
 static void convertPcm16ToFloat(const int16_t *source,
@@ -248,6 +505,7 @@
         int32_t numFrames
 ) {
     (void) outputStream;
+    aaudio_data_callback_result_t result = AAUDIO_CALLBACK_RESULT_CONTINUE;
     LoopbackData *myData = (LoopbackData *) userData;
     float  *outputData = (float  *) audioData;
 
@@ -266,6 +524,7 @@
                                        numFrames, 0);
             if (framesRead < 0) {
                 myData->inputError = framesRead;
+                result = AAUDIO_CALLBACK_RESULT_STOP;
             } else if (framesRead > 0) {
                 myData->inputBuffersToDiscard--;
             }
@@ -275,16 +534,13 @@
                                        numFrames, 0);
         if (framesRead < 0) {
             myData->inputError = framesRead;
+            result = AAUDIO_CALLBACK_RESULT_STOP;
         } else if (framesRead > 0) {
-            // Process valid input data.
-            myData->audioRecorder.record(myData->inputData,
-                                         myData->actualInputChannelCount,
-                                         framesRead);
 
             int32_t numSamples = framesRead * myData->actualInputChannelCount;
             convertPcm16ToFloat(myData->inputData, myData->conversionBuffer, numSamples);
 
-            myData->loopbackProcessor.process(myData->conversionBuffer,
+            myData->loopbackProcessor->process(myData->conversionBuffer,
                                               myData->actualInputChannelCount,
                                               outputData,
                                               myData->actualOutputChannelCount,
@@ -292,17 +548,25 @@
         }
     }
 
-    return AAUDIO_CALLBACK_RESULT_CONTINUE;
+    return result;
 }
 
+
 static void usage() {
-    printf("loopback: -b{burstsPerBuffer} -p{outputPerfMode} -P{inputPerfMode}\n");
-    printf("          -b{burstsPerBuffer} for example 2 for double buffered\n");
-    printf("          -p{outputPerfMode}  set output AAUDIO_PERFORMANCE_MODE*\n");
-    printf("          -P{inputPerfMode}   set input AAUDIO_PERFORMANCE_MODE*\n");
+    printf("loopback: -n{numBursts} -p{outPerf} -P{inPerf} -t{test} -g{gain} -f{freq}\n");
+    printf("          -c{inputChannels}\n");
+    printf("          -f{freq}  sine frequency\n");
+    printf("          -g{gain}  recirculating loopback gain\n");
+    printf("          -m enable MMAP mode\n");
+    printf("          -n{numBursts} buffer size, for example 2 for double buffered\n");
+    printf("          -p{outPerf}  set output AAUDIO_PERFORMANCE_MODE*\n");
+    printf("          -P{inPerf}   set input AAUDIO_PERFORMANCE_MODE*\n");
     printf("              n for _NONE\n");
     printf("              l for _LATENCY\n");
     printf("              p for _POWER_SAVING;\n");
+    printf("          -t{test}   select test mode\n");
+    printf("              m for sine magnitude\n");
+    printf("              e for echo latency (default)\n");
     printf("For example:  loopback -b2 -pl -Pn\n");
 }
 
@@ -320,12 +584,34 @@
             mode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
             break;
         default:
-            printf("ERROR invalue performance mode %c\n", c);
+            printf("ERROR in value performance mode %c\n", c);
             break;
     }
     return mode;
 }
 
+enum {
+    TEST_SINE_MAGNITUDE = 0,
+    TEST_ECHO_LATENCY,
+};
+
+static int parseTestMode(char c) {
+    int testMode = TEST_ECHO_LATENCY;
+    c = tolower(c);
+    switch (c) {
+        case 'm':
+            testMode = TEST_SINE_MAGNITUDE;
+            break;
+        case 'e':
+            testMode = TEST_ECHO_LATENCY;
+            break;
+        default:
+            printf("ERROR in value test mode %c\n", c);
+            break;
+    }
+    return testMode;
+}
+
 // ====================================================================================
 // TODO break up this large main() function into smaller functions
 int main(int argc, const char **argv)
@@ -334,7 +620,7 @@
     LoopbackData loopbackData;
     AAudioStream *outputStream = nullptr;
 
-    const int requestedInputChannelCount = 1;
+    int requestedInputChannelCount = NUM_INPUT_CHANNELS;
     const int requestedOutputChannelCount = AAUDIO_UNSPECIFIED;
     const int requestedSampleRate = SAMPLE_RATE;
     int actualSampleRate = 0;
@@ -342,6 +628,9 @@
     const aaudio_format_t requestedOutputFormat = AAUDIO_FORMAT_PCM_FLOAT;
     aaudio_format_t actualInputFormat;
     aaudio_format_t actualOutputFormat;
+    int testMode = TEST_ECHO_LATENCY;
+    double frequency = 1000.0;
+    double gain = 1.0;
 
     const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
     //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED;
@@ -363,7 +652,19 @@
         if (arg[0] == '-') {
             char option = arg[1];
             switch (option) {
-                case 'b':
+                case 'c':
+                    requestedInputChannelCount = atoi(&arg[2]);
+                    break;
+                case 'f':
+                    frequency = atof(&arg[2]);
+                    break;
+                case 'g':
+                    gain = atof(&arg[2]);
+                    break;
+                case 'm':
+                    AAudio_setMMapPolicy(AAUDIO_POLICY_AUTO);
+                    break;
+                case 'n':
                     burstsPerBuffer = atoi(&arg[2]);
                     break;
                 case 'p':
@@ -372,16 +673,35 @@
                 case 'P':
                     inputPerformanceLevel = parsePerformanceMode(arg[2]);
                     break;
+                case 't':
+                    testMode = parseTestMode(arg[2]);
+                    break;
                 default:
                     usage();
+                    exit(0);
                     break;
             }
         } else {
+            usage();
+            exit(0);
             break;
         }
     }
 
-    loopbackData.audioRecorder.allocate(NUM_SECONDS * SAMPLE_RATE);
+
+    switch(testMode) {
+        case TEST_SINE_MAGNITUDE:
+            loopbackData.sineAnalyzer.setFrequency(frequency);
+            loopbackData.loopbackProcessor = &loopbackData.sineAnalyzer;
+            break;
+        case TEST_ECHO_LATENCY:
+            loopbackData.echoAnalyzer.setGain(gain);
+            loopbackData.loopbackProcessor = &loopbackData.echoAnalyzer;
+            break;
+        default:
+            exit(1);
+            break;
+    }
 
     // Make printf print immediately so that debug info is not stuck
     // in a buffer if we hang or crash.
@@ -431,47 +751,68 @@
     printf("    channelCount: requested = %d, actual = %d\n", requestedInputChannelCount,
            loopbackData.actualInputChannelCount);
     printf("    framesPerBurst = %d\n", AAudioStream_getFramesPerBurst(loopbackData.inputStream));
+    printf("    bufferSize     = %d\n",
+           AAudioStream_getBufferSizeInFrames(loopbackData.inputStream));
+    printf("    bufferCapacity = %d\n",
+           AAudioStream_getBufferCapacityInFrames(loopbackData.inputStream));
+
+    actualSharingMode = AAudioStream_getSharingMode(loopbackData.inputStream);
+    printf("    sharingMode: requested = %d, actual = %d\n",
+           requestedSharingMode, actualSharingMode);
 
     actualInputFormat = AAudioStream_getFormat(loopbackData.inputStream);
-    printf("    dataFormat: requested = %d, actual = %d\n", requestedInputFormat, actualInputFormat);
+    printf("    dataFormat: requested = %d, actual = %d\n",
+           requestedInputFormat, actualInputFormat);
     assert(actualInputFormat == AAUDIO_FORMAT_PCM_I16);
 
+    printf("    is MMAP used?         = %s\n", AAudioStream_isMMapUsed(loopbackData.inputStream)
+                                               ? "yes" : "no");
+
+
     printf("Stream OUTPUT ---------------------\n");
     // Check to see what kind of stream we actually got.
     actualSampleRate = AAudioStream_getSampleRate(outputStream);
     printf("    sampleRate: requested = %d, actual = %d\n", requestedSampleRate, actualSampleRate);
+    loopbackData.echoAnalyzer.setSampleRate(actualSampleRate);
 
     loopbackData.actualOutputChannelCount = AAudioStream_getChannelCount(outputStream);
     printf("    channelCount: requested = %d, actual = %d\n", requestedOutputChannelCount,
            loopbackData.actualOutputChannelCount);
 
     actualSharingMode = AAudioStream_getSharingMode(outputStream);
-    printf("    sharingMode: requested = %d, actual = %d\n", requestedSharingMode, actualSharingMode);
+    printf("    sharingMode: requested = %d, actual = %d\n",
+           requestedSharingMode, actualSharingMode);
 
     // This is the number of frames that are read in one chunk by a DMA controller
     // or a DSP or a mixer.
     framesPerBurst = AAudioStream_getFramesPerBurst(outputStream);
     printf("    framesPerBurst = %d\n", framesPerBurst);
 
-    printf("    bufferCapacity = %d\n", AAudioStream_getBufferCapacityInFrames(outputStream));
-
-    actualOutputFormat = AAudioStream_getFormat(outputStream);
-    printf("    dataFormat: requested = %d, actual = %d\n", requestedOutputFormat, actualOutputFormat);
-    assert(actualOutputFormat == AAUDIO_FORMAT_PCM_FLOAT);
-
-    // Allocate a buffer for the audio data.
-    loopbackData.inputFramesMaximum = 32 * framesPerBurst;
-
-    loopbackData.inputData = new int16_t[loopbackData.inputFramesMaximum * loopbackData.actualInputChannelCount];
-    loopbackData.conversionBuffer = new float[loopbackData.inputFramesMaximum *
-                                              loopbackData.actualInputChannelCount];
-
     result = AAudioStream_setBufferSizeInFrames(outputStream, burstsPerBuffer * framesPerBurst);
     if (result < 0) { // may be positive buffer size
         fprintf(stderr, "ERROR - AAudioStream_setBufferSize() returned %d\n", result);
         goto finish;
     }
-    printf("AAudioStream_setBufferSize() actual = %d\n",result);
+    printf("    bufferSize     = %d\n", AAudioStream_getBufferSizeInFrames(outputStream));
+    printf("    bufferCapacity = %d\n", AAudioStream_getBufferCapacityInFrames(outputStream));
+
+    actualOutputFormat = AAudioStream_getFormat(outputStream);
+    printf("    dataFormat: requested = %d, actual = %d\n",
+           requestedOutputFormat, actualOutputFormat);
+    assert(actualOutputFormat == AAUDIO_FORMAT_PCM_FLOAT);
+
+    printf("    is MMAP used?         = %s\n", AAudioStream_isMMapUsed(outputStream)
+                                               ? "yes" : "no");
+
+    // Allocate a buffer for the audio data.
+    loopbackData.inputFramesMaximum = 32 * framesPerBurst;
+    loopbackData.inputBuffersToDiscard = 100;
+
+    loopbackData.inputData = new int16_t[loopbackData.inputFramesMaximum
+                                         * loopbackData.actualInputChannelCount];
+    loopbackData.conversionBuffer = new float[loopbackData.inputFramesMaximum *
+                                              loopbackData.actualInputChannelCount];
+
 
     // Start output first so input stream runs low.
     result = AAudioStream_requestStart(outputStream);
@@ -500,18 +841,13 @@
     printf("framesRead    = %d\n", (int) AAudioStream_getFramesRead(outputStream));
     printf("framesWritten = %d\n", (int) AAudioStream_getFramesWritten(outputStream));
 
-    latency = loopbackData.loopbackProcessor.calculateAverageLatency(&deviation);
-    printf("measured peak    = %8.5f\n", loopbackData.loopbackProcessor.getMaxAmplitude());
-    printf("threshold        = %8.5f\n", INPUT_PEAK_THRESHOLD);
-    printf("measured average = %8.5f\n", loopbackData.loopbackProcessor.getAverageAmplitude());
-    printf("# latency measurements = %d\n", loopbackData.loopbackProcessor.getMeasurementCount());
-    printf("measured latency = %8.2f +/- %4.5f frames\n", latency, deviation);
-    printf("measured latency = %8.2f msec  <===== !!\n", (1000.0 * latency / actualSampleRate));
+    loopbackData.loopbackProcessor->report();
 
-    {
-        int written = loopbackData.audioRecorder.save(FILENAME);
-        printf("wrote %d samples to %s\n", written, FILENAME);
-    }
+//    {
+//        int written = loopbackData.audioRecorder.save(FILENAME);
+//        printf("wrote %d mono samples to %s on Android device\n", written, FILENAME);
+//    }
+
 
 finish:
     AAudioStream_close(outputStream);
@@ -521,7 +857,13 @@
     delete[] outputData;
     AAudioStreamBuilder_delete(builder);
 
-    printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
-    return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS;
+    printf(RESULT_TAG "error = %d = %s\n", result, AAudio_convertResultToText(result));
+    if ((result != AAUDIO_OK)) {
+        printf("error %d = %s\n", result, AAudio_convertResultToText(result));
+        return EXIT_FAILURE;
+    } else {
+        printf("SUCCESS\n");
+        return EXIT_SUCCESS;
+    }
 }
 
diff --git a/media/libaaudio/examples/utils/dummy.cpp b/media/libaaudio/examples/utils/dummy.cpp
new file mode 100644
index 0000000..8ef7e36
--- /dev/null
+++ b/media/libaaudio/examples/utils/dummy.cpp
@@ -0,0 +1,5 @@
+/**
+ * Dummy file needed to get Android Studio to scan this folder.
+ */
+
+int g_DoNotUseThisVariable = 0;
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
index 469f0a8..89ae85c 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.h
+++ b/media/libaaudio/src/binding/AAudioBinderClient.h
@@ -97,6 +97,17 @@
     aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
                                                   pid_t clientThreadId) override;
 
+    aaudio_result_t startClient(aaudio_handle_t streamHandle __unused,
+                                      const android::AudioClient& client __unused,
+                                      audio_port_handle_t *clientHandle) override {
+        return AAUDIO_ERROR_UNAVAILABLE;
+    }
+
+    aaudio_result_t stopClient(aaudio_handle_t streamHandle __unused,
+                               audio_port_handle_t clientHandle __unused)  override {
+        return AAUDIO_ERROR_UNAVAILABLE;
+    }
+
     void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) {
         // TODO This is just a stub so we can have a client Binder to pass to the service.
         // TODO Implemented in a later CL.
diff --git a/media/libaaudio/src/binding/AAudioServiceInterface.h b/media/libaaudio/src/binding/AAudioServiceInterface.h
index 7368062..a64405b 100644
--- a/media/libaaudio/src/binding/AAudioServiceInterface.h
+++ b/media/libaaudio/src/binding/AAudioServiceInterface.h
@@ -18,6 +18,7 @@
 #define ANDROID_AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
 
 #include <utils/StrongPointer.h>
+#include <media/AudioClient.h>
 
 #include "binding/AAudioServiceDefinitions.h"
 #include "binding/AAudioStreamRequest.h"
@@ -86,6 +87,13 @@
 
     virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
                                                   pid_t clientThreadId) = 0;
+
+    virtual aaudio_result_t startClient(aaudio_handle_t streamHandle,
+                                      const android::AudioClient& client,
+                                      audio_port_handle_t *clientHandle) = 0;
+
+    virtual aaudio_result_t stopClient(aaudio_handle_t streamHandle,
+                                       audio_port_handle_t clientHandle) = 0;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
index 8a765ad..abdcf5b 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -52,8 +52,12 @@
     status = parcel->writeBool(mSharingModeMatchRequired);
     if (status != NO_ERROR) goto error;
 
+    status = parcel->writeBool(mInService);
+    if (status != NO_ERROR) goto error;
+
     status = mConfiguration.writeToParcel(parcel);
     if (status != NO_ERROR) goto error;
+
     return NO_ERROR;
 
 error:
@@ -74,8 +78,12 @@
     status = parcel->readBool(&mSharingModeMatchRequired);
     if (status != NO_ERROR) goto error;
 
+    status = parcel->readBool(&mInService);
+    if (status != NO_ERROR) goto error;
+
     status = mConfiguration.readFromParcel(parcel);
     if (status != NO_ERROR) goto error;
+
     return NO_ERROR;
 
 error:
@@ -91,5 +99,7 @@
     ALOGD("AAudioStreamRequest mUserId    = %d", mUserId);
     ALOGD("AAudioStreamRequest mProcessId = %d", mProcessId);
     ALOGD("AAudioStreamRequest mDirection = %d", mDirection);
+    ALOGD("AAudioStreamRequest mSharingModeMatchRequired = %d", mSharingModeMatchRequired);
+    ALOGD("AAudioStreamRequest mInService = %d", mInService);
     mConfiguration.dump();
 }
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
index 462246b..b0fa96a 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.h
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.h
@@ -76,6 +76,14 @@
         return mConfiguration;
     }
 
+    bool isInService() const {
+        return mInService;
+    }
+
+    void setInService(bool inService) {
+        mInService = inService;
+    }
+
     virtual status_t writeToParcel(Parcel* parcel) const override;
 
     virtual status_t readFromParcel(const Parcel* parcel) override;
@@ -90,6 +98,7 @@
     pid_t                      mProcessId;
     aaudio_direction_t         mDirection;
     bool                       mSharingModeMatchRequired = false;
+    bool                       mInService = false; // Stream opened by AAudioservice
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index ff13fc2..7b01e44 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -16,7 +16,7 @@
 
 // This file is used in both client and server processes.
 // This is needed to make sense of the logs more easily.
-#define LOG_TAG (mInService ? "AAudioService" : "AAudio")
+#define LOG_TAG (mInService ? "AudioStreamInternal_Service" : "AudioStreamInternal_Client")
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -93,6 +93,7 @@
     request.setProcessId(getpid());
     request.setDirection(getDirection());
     request.setSharingModeMatchRequired(isSharingModeMatchRequired());
+    request.setInService(mInService);
 
     request.getConfiguration().setDeviceId(getDeviceId());
     request.getConfiguration().setSampleRate(getSampleRate());
@@ -326,6 +327,21 @@
     return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, gettid());
 }
 
+aaudio_result_t AudioStreamInternal::startClient(const android::AudioClient& client,
+                                                 audio_port_handle_t *clientHandle) {
+    if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    return mServiceInterface.startClient(mServiceStreamHandle, client, clientHandle);
+}
+
+aaudio_result_t AudioStreamInternal::stopClient(audio_port_handle_t clientHandle) {
+    if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    return mServiceInterface.stopClient(mServiceStreamHandle, clientHandle);
+}
+
 aaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId,
                            int64_t *framePosition,
                            int64_t *timeNanoseconds) {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 257a702..109e425 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -87,6 +87,11 @@
     //PlayerBase virtuals
     virtual void destroy();
 
+    aaudio_result_t startClient(const android::AudioClient& client,
+                                audio_port_handle_t *clientHandle);
+
+    aaudio_result_t stopClient(audio_port_handle_t clientHandle);
+
 protected:
 
     aaudio_result_t processData(void *buffer,
@@ -170,7 +175,6 @@
 
     AudioEndpointParcelable  mEndPointParcelable; // description of the buffers filled by service
     EndpointDescriptor       mEndpointDescriptor; // buffer description with resolved addresses
-
 };
 
 } /* namespace aaudio */
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index d320320..ceba211 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -323,6 +323,7 @@
             return BAD_VALUE;
         }
         data.write(attr, sizeof(audio_attributes_t));
+        data.writeInt32(*input);
         data.writeInt32(session);
         data.writeInt32(pid);
         data.writeInt32(uid);
@@ -1024,6 +1025,7 @@
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             audio_attributes_t attr;
             data.read(&attr, sizeof(audio_attributes_t));
+            audio_io_handle_t input = (audio_io_handle_t)data.readInt32();
             audio_session_t session = (audio_session_t)data.readInt32();
             pid_t pid = (pid_t)data.readInt32();
             uid_t uid = (uid_t)data.readInt32();
@@ -1033,7 +1035,6 @@
             audio_input_flags_t flags = (audio_input_flags_t) data.readInt32();
             audio_port_handle_t selectedDeviceId = (audio_port_handle_t) data.readInt32();
             audio_port_handle_t portId = (audio_port_handle_t)data.readInt32();
-            audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
             status_t status = getInputForAttr(&attr, &input, session, pid, uid,
                                               &config,
                                               flags, &selectedDeviceId, &portId);
diff --git a/media/libaudioclient/include/media/AudioClient.h b/media/libaudioclient/include/media/AudioClient.h
new file mode 100644
index 0000000..9efd76d
--- /dev/null
+++ b/media/libaudioclient/include/media/AudioClient.h
@@ -0,0 +1,38 @@
+/*
+ * 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_AUDIO_CLIENT_H
+#define ANDROID_AUDIO_CLIENT_H
+
+#include <system/audio.h>
+#include <utils/String16.h>
+
+namespace android {
+
+class AudioClient {
+ public:
+    AudioClient() :
+        clientUid(-1), clientPid(-1), packageName("") {}
+
+    uid_t clientUid;
+    pid_t clientPid;
+    String16 packageName;
+};
+
+}; // namespace android
+
+#endif  // ANDROID_AUDIO_CLIENT_H
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index fe5a054..38c9687 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -260,10 +260,11 @@
 status_t MmapStreamInterface::openMmapStream(MmapStreamInterface::stream_direction_t direction,
                                              const audio_attributes_t *attr,
                                              audio_config_base_t *config,
-                                             const MmapStreamInterface::Client& client,
+                                             const AudioClient& client,
                                              audio_port_handle_t *deviceId,
                                              const sp<MmapStreamCallback>& callback,
-                                             sp<MmapStreamInterface>& interface)
+                                             sp<MmapStreamInterface>& interface,
+                                             audio_port_handle_t *handle)
 {
     sp<AudioFlinger> af;
     {
@@ -273,7 +274,7 @@
     status_t ret = NO_INIT;
     if (af != 0) {
         ret = af->openMmapStream(
-                direction, attr, config, client, deviceId, callback, interface);
+                direction, attr, config, client, deviceId, callback, interface, handle);
     }
     return ret;
 }
@@ -281,10 +282,11 @@
 status_t AudioFlinger::openMmapStream(MmapStreamInterface::stream_direction_t direction,
                                       const audio_attributes_t *attr,
                                       audio_config_base_t *config,
-                                      const MmapStreamInterface::Client& client,
+                                      const AudioClient& client,
                                       audio_port_handle_t *deviceId,
                                       const sp<MmapStreamCallback>& callback,
-                                      sp<MmapStreamInterface>& interface)
+                                      sp<MmapStreamInterface>& interface,
+                                      audio_port_handle_t *handle)
 {
     status_t ret = initCheck();
     if (ret != NO_ERROR) {
@@ -293,7 +295,7 @@
 
     audio_session_t sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
     audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT;
-    audio_io_handle_t io;
+    audio_io_handle_t io = AUDIO_IO_HANDLE_NONE;
     audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
     if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
         audio_config_t fullConfig = AUDIO_CONFIG_INITIALIZER;
@@ -325,6 +327,7 @@
     if (thread != 0) {
         interface = new MmapThreadHandle(thread);
         thread->configure(attr, streamType, sessionId, callback, portId);
+        *handle = portId;
     } else {
         ret = NO_INIT;
     }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 2e0bc66..8a96c1d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -294,10 +294,11 @@
     status_t openMmapStream(MmapStreamInterface::stream_direction_t direction,
                             const audio_attributes_t *attr,
                             audio_config_base_t *config,
-                            const MmapStreamInterface::Client& client,
+                            const AudioClient& client,
                             audio_port_handle_t *deviceId,
                             const sp<MmapStreamCallback>& callback,
-                            sp<MmapStreamInterface>& interface);
+                            sp<MmapStreamInterface>& interface,
+                            audio_port_handle_t *handle);
 private:
     // FIXME The 400 is temporarily too high until a leak of writers in media.log is fixed.
     static const size_t kLogMemorySize = 400 * 1024;
@@ -596,7 +597,7 @@
         virtual status_t createMmapBuffer(int32_t minSizeFrames,
                                           struct audio_mmap_buffer_info *info);
         virtual status_t getMmapPosition(struct audio_mmap_position *position);
-        virtual status_t start(const MmapStreamInterface::Client& client,
+        virtual status_t start(const AudioClient& client,
                                          audio_port_handle_t *handle);
         virtual status_t stop(audio_port_handle_t handle);
         virtual status_t standby();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 085be00..d932483 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7523,7 +7523,7 @@
     return mThread->getMmapPosition(position);
 }
 
-status_t AudioFlinger::MmapThreadHandle::start(const MmapStreamInterface::Client& client,
+status_t AudioFlinger::MmapThreadHandle::start(const AudioClient& client,
         audio_port_handle_t *handle)
 
 {
@@ -7616,77 +7616,75 @@
     return mHalStream->getMmapPosition(position);
 }
 
-status_t AudioFlinger::MmapThread::start(const MmapStreamInterface::Client& client,
+status_t AudioFlinger::MmapThread::start(const AudioClient& client,
                                          audio_port_handle_t *handle)
 {
-    ALOGV("%s clientUid %d mStandby %d", __FUNCTION__, client.clientUid, mStandby);
+    ALOGV("%s clientUid %d mStandby %d mPortId %d *handle %d", __FUNCTION__,
+          client.clientUid, mStandby, mPortId, *handle);
     if (mHalStream == 0) {
         return NO_INIT;
     }
 
     status_t ret;
-    audio_session_t sessionId;
-    audio_port_handle_t portId;
 
-    if (mActiveTracks.size() == 0) {
+    if (*handle == mPortId) {
         // for the first track, reuse portId and session allocated when the stream was opened
         ret = mHalStream->start();
         if (ret != NO_ERROR) {
             ALOGE("%s: error mHalStream->start() = %d for first track", __FUNCTION__, ret);
             return ret;
         }
-        portId = mPortId;
-        sessionId = mSessionId;
         mStandby = false;
+        return NO_ERROR;
+    }
+
+    audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+
+    audio_io_handle_t io = mId;
+    if (isOutput()) {
+        audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+        config.sample_rate = mSampleRate;
+        config.channel_mask = mChannelMask;
+        config.format = mFormat;
+        audio_stream_type_t stream = streamType();
+        audio_output_flags_t flags =
+                (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
+        audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
+        ret = AudioSystem::getOutputForAttr(&mAttr, &io,
+                                            mSessionId,
+                                            &stream,
+                                            client.clientUid,
+                                            &config,
+                                            flags,
+                                            &deviceId,
+                                            &portId);
     } else {
-        // for other tracks than first one, get a new port ID from APM.
-        sessionId = (audio_session_t)mAudioFlinger->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
-        audio_io_handle_t io;
-        if (isOutput()) {
-            audio_config_t config = AUDIO_CONFIG_INITIALIZER;
-            config.sample_rate = mSampleRate;
-            config.channel_mask = mChannelMask;
-            config.format = mFormat;
-            audio_stream_type_t stream = streamType();
-            audio_output_flags_t flags =
-                    (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
-            audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
-            ret = AudioSystem::getOutputForAttr(&mAttr, &io,
-                                                sessionId,
-                                                &stream,
-                                                client.clientUid,
-                                                &config,
-                                                flags,
-                                                &deviceId,
-                                                &portId);
-        } else {
-            audio_config_base_t config;
-            config.sample_rate = mSampleRate;
-            config.channel_mask = mChannelMask;
-            config.format = mFormat;
-            audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
-            ret = AudioSystem::getInputForAttr(&mAttr, &io,
-                                                  sessionId,
-                                                  client.clientPid,
-                                                  client.clientUid,
-                                                  &config,
-                                                  AUDIO_INPUT_FLAG_MMAP_NOIRQ,
-                                                  &deviceId,
-                                                  &portId);
-        }
-        // APM should not chose a different input or output stream for the same set of attributes
-        // and audo configuration
-        if (ret != NO_ERROR || io != mId) {
-            ALOGE("%s: error getting output or input from APM (error %d, io %d expected io %d)",
-                  __FUNCTION__, ret, io, mId);
-            return BAD_VALUE;
-        }
+        audio_config_base_t config;
+        config.sample_rate = mSampleRate;
+        config.channel_mask = mChannelMask;
+        config.format = mFormat;
+        audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
+        ret = AudioSystem::getInputForAttr(&mAttr, &io,
+                                              mSessionId,
+                                              client.clientPid,
+                                              client.clientUid,
+                                              &config,
+                                              AUDIO_INPUT_FLAG_MMAP_NOIRQ,
+                                              &deviceId,
+                                              &portId);
+    }
+    // APM should not chose a different input or output stream for the same set of attributes
+    // and audo configuration
+    if (ret != NO_ERROR || io != mId) {
+        ALOGE("%s: error getting output or input from APM (error %d, io %d expected io %d)",
+              __FUNCTION__, ret, io, mId);
+        return BAD_VALUE;
     }
 
     if (isOutput()) {
-        ret = AudioSystem::startOutput(mId, streamType(), sessionId);
+        ret = AudioSystem::startOutput(mId, streamType(), mSessionId);
     } else {
-        ret = AudioSystem::startInput(mId, sessionId);
+        ret = AudioSystem::startInput(mId, mSessionId);
     }
 
     // abort if start is rejected by audio policy manager
@@ -7694,9 +7692,9 @@
         ALOGE("%s: error start rejected by AudioPolicyManager = %d", __FUNCTION__, ret);
         if (mActiveTracks.size() != 0) {
             if (isOutput()) {
-                AudioSystem::releaseOutput(mId, streamType(), sessionId);
+                AudioSystem::releaseOutput(mId, streamType(), mSessionId);
             } else {
-                AudioSystem::releaseInput(mId, sessionId);
+                AudioSystem::releaseInput(mId, mSessionId);
             }
         } else {
             mHalStream->stop();
@@ -7704,11 +7702,11 @@
         return PERMISSION_DENIED;
     }
 
-    sp<MmapTrack> track = new MmapTrack(this, mSampleRate, mFormat, mChannelMask, sessionId,
+    sp<MmapTrack> track = new MmapTrack(this, mSampleRate, mFormat, mChannelMask, mSessionId,
                                         client.clientUid, portId);
 
     mActiveTracks.add(track);
-    sp<EffectChain> chain = getEffectChain_l(sessionId);
+    sp<EffectChain> chain = getEffectChain_l(mSessionId);
     if (chain != 0) {
         chain->setStrategy(AudioSystem::getStrategyForStream(streamType()));
         chain->incTrackCnt();
@@ -7716,10 +7714,9 @@
     }
 
     *handle = portId;
-
     broadcast_l();
 
-    ALOGV("%s DONE handle %d stream %p", __FUNCTION__, portId, mHalStream.get());
+    ALOGV("%s DONE handle %d stream %p", __FUNCTION__, *handle, mHalStream.get());
 
     return NO_ERROR;
 }
@@ -7732,6 +7729,11 @@
         return NO_INIT;
     }
 
+    if (handle == mPortId) {
+        mHalStream->stop();
+        return NO_ERROR;
+    }
+
     sp<MmapTrack> track;
     for (const sp<MmapTrack> &t : mActiveTracks) {
         if (handle == t->portId()) {
@@ -7747,14 +7749,10 @@
 
     if (isOutput()) {
         AudioSystem::stopOutput(mId, streamType(), track->sessionId());
-        if (mActiveTracks.size() != 0) {
-            AudioSystem::releaseOutput(mId, streamType(), track->sessionId());
-        }
+        AudioSystem::releaseOutput(mId, streamType(), track->sessionId());
     } else {
         AudioSystem::stopInput(mId, track->sessionId());
-        if (mActiveTracks.size() != 0) {
-            AudioSystem::releaseInput(mId, track->sessionId());
-        }
+        AudioSystem::releaseInput(mId, track->sessionId());
     }
 
     sp<EffectChain> chain = getEffectChain_l(track->sessionId());
@@ -7765,9 +7763,6 @@
 
     broadcast_l();
 
-    if (mActiveTracks.size() == 0) {
-        mHalStream->stop();
-    }
     return NO_ERROR;
 }
 
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 9db19d6..65266b0 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1478,7 +1478,7 @@
     status_t createMmapBuffer(int32_t minSizeFrames,
                                       struct audio_mmap_buffer_info *info);
     status_t getMmapPosition(struct audio_mmap_position *position);
-    status_t start(const MmapStreamInterface::Client& client, audio_port_handle_t *handle);
+    status_t start(const AudioClient& client, audio_port_handle_t *handle);
     status_t stop(audio_port_handle_t handle);
     status_t standby();
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
index 18fba25..ca070cf 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -51,6 +51,7 @@
     audio_channel_mask_t channelMask() const { return mConfig.channel_mask; }
     audio_input_flags_t flags() const { return mFlags; }
     uid_t uid() const { return mUid; }
+    void setUid(uid_t uid) { mUid = uid; }
     bool matches(const sp<AudioSession> &other) const;
     bool isSoundTrigger() const { return mIsSoundTrigger; }
     uint32_t openCount() const { return mOpenCount; } ;
@@ -68,7 +69,7 @@
     const audio_source_t mInputSource;
     const struct audio_config_base mConfig;
     const audio_input_flags_t mFlags;
-    const uid_t mUid;
+    uid_t mUid;
     bool  mIsSoundTrigger;
     uint32_t  mOpenCount;
     uint32_t  mActiveCount;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 3dcb22d..55c364f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1495,6 +1495,43 @@
             "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;
 
@@ -1898,6 +1935,11 @@
                 continue;
             }
 
+            if ((audioSession->flags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 &&
+                    activeDesc->getId() == inputDesc->getId()) {
+                continue;
+            }
+
             audio_source_t activeSource = activeDesc->inputSource(true);
             if (audioSession->inputSource() == AUDIO_SOURCE_HOTWORD) {
                 if (activeSource == AUDIO_SOURCE_HOTWORD) {
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c175259..20bd5e4 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -73,6 +73,7 @@
 using binder::Status;
 using hardware::ICamera;
 using hardware::ICameraClient;
+using hardware::ICameraServiceProxy;
 using hardware::ICameraServiceListener;
 using hardware::camera::common::V1_0::CameraDeviceStatus;
 using hardware::camera::common::V1_0::TorchModeStatus;
@@ -2213,7 +2214,7 @@
 
     // Transition device state to OPEN
     sCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_OPEN,
-            mCameraIdStr);
+            mCameraIdStr, mCameraFacing, mClientPackageName);
 
     return OK;
 }
@@ -2237,7 +2238,7 @@
 
         // Transition device state to CLOSED
         sCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_CLOSED,
-                mCameraIdStr);
+                mCameraIdStr, mCameraFacing, mClientPackageName);
     }
     // Always stop watching, even if no camera op is active
     if (mOpsCallback != NULL) {
@@ -2741,12 +2742,12 @@
     onStatusUpdatedLocked(cameraId, status);
 }
 
-void CameraService::updateProxyDeviceState(ICameraServiceProxy::CameraState newState,
-        const String8& cameraId) {
+void CameraService::updateProxyDeviceState(int newState,
+        const String8& cameraId, int facing, const String16& clientName) {
     sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
     if (proxyBinder == nullptr) return;
     String16 id(cameraId);
-    proxyBinder->notifyCameraState(id, newState);
+    proxyBinder->notifyCameraState(id, newState, facing, clientName);
 }
 
 status_t CameraService::getTorchStatusLocked(
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 87603a3..6d5dde8 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -19,6 +19,7 @@
 
 #include <android/hardware/BnCameraService.h>
 #include <android/hardware/ICameraServiceListener.h>
+#include <android/hardware/ICameraServiceProxy.h>
 
 #include <cutils/multiuser.h>
 #include <utils/Vector.h>
@@ -26,7 +27,6 @@
 #include <binder/AppOpsManager.h>
 #include <binder/BinderService.h>
 #include <binder/IAppOpsCallback.h>
-#include <camera/ICameraServiceProxy.h>
 #include <hardware/camera.h>
 
 #include <android/hardware/camera/common/1.0/types.h>
@@ -182,8 +182,10 @@
      * the camera proxy service in the system service
      */
     static void         updateProxyDeviceState(
-            ICameraServiceProxy::CameraState newState,
-            const String8& cameraId);
+            int newState,
+            const String8& cameraId,
+            int facing,
+            const String16& clientName);
 
     /////////////////////////////////////////////////////////////////////
     // CameraDeviceFactory functionality
@@ -772,7 +774,7 @@
     static StatusInternal mapToInternal(hardware::camera::common::V1_0::CameraDeviceStatus status);
     static int32_t mapToInterface(StatusInternal status);
 
-    static sp<ICameraServiceProxy> getCameraServiceProxy();
+    static sp<hardware::ICameraServiceProxy> getCameraServiceProxy();
     static void pingCameraServiceProxy();
 
 };
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index 075c2e3..a407d0b 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -256,8 +256,8 @@
     disableMsgType(CAMERA_MSG_ALL_MSGS);
     mHardware->stopPreview();
     sCameraService->updateProxyDeviceState(
-        ICameraServiceProxy::CAMERA_STATE_IDLE,
-        String8::format("%d", mCameraId));
+            hardware::ICameraServiceProxy::CAMERA_STATE_IDLE,
+            mCameraIdStr, mCameraFacing, mClientPackageName);
     mHardware->cancelPicture();
     // Release the hardware resources.
     mHardware->release();
@@ -418,8 +418,8 @@
     result = mHardware->startPreview();
     if (result == NO_ERROR) {
         sCameraService->updateProxyDeviceState(
-            ICameraServiceProxy::CAMERA_STATE_ACTIVE,
-            String8::format("%d", mCameraId));
+            hardware::ICameraServiceProxy::CAMERA_STATE_ACTIVE,
+            mCameraIdStr, mCameraFacing, mClientPackageName);
     }
     return result;
 }
@@ -461,8 +461,8 @@
     disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
     mHardware->stopPreview();
     sCameraService->updateProxyDeviceState(
-        ICameraServiceProxy::CAMERA_STATE_IDLE,
-        String8::format("%d", mCameraId));
+        hardware::ICameraServiceProxy::CAMERA_STATE_IDLE,
+        mCameraIdStr, mCameraFacing, mClientPackageName);
     mPreviewBuffer.clear();
 }
 
@@ -960,8 +960,8 @@
     // Shutters only happen in response to takePicture, so mark device as
     // idle now, until preview is restarted
     sCameraService->updateProxyDeviceState(
-        ICameraServiceProxy::CAMERA_STATE_IDLE,
-        String8::format("%d", mCameraId));
+        hardware::ICameraServiceProxy::CAMERA_STATE_IDLE,
+        mCameraIdStr, mCameraFacing, mClientPackageName);
 
     mLock.unlock();
 }
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 32ee273..51ef160 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -248,7 +248,8 @@
 void Camera2ClientBase<TClientBase>::notifyIdle() {
     if (mDeviceActive) {
         getCameraService()->updateProxyDeviceState(
-            ICameraServiceProxy::CAMERA_STATE_IDLE, TClientBase::mCameraIdStr);
+            hardware::ICameraServiceProxy::CAMERA_STATE_IDLE, TClientBase::mCameraIdStr,
+            TClientBase::mCameraFacing, TClientBase::mClientPackageName);
     }
     mDeviceActive = false;
 
@@ -263,7 +264,8 @@
 
     if (!mDeviceActive) {
         getCameraService()->updateProxyDeviceState(
-            ICameraServiceProxy::CAMERA_STATE_ACTIVE, TClientBase::mCameraIdStr);
+            hardware::ICameraServiceProxy::CAMERA_STATE_ACTIVE, TClientBase::mCameraIdStr,
+            TClientBase::mCameraFacing, TClientBase::mClientPackageName);
     }
     mDeviceActive = true;
 
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 02d4a19..ec2f5b9 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioEndpointManager"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -104,6 +104,8 @@
 
     // If we can't find an existing one then open a new one.
     if (endpoint == nullptr) {
+        // we must call openStream with audioserver identity
+        int64_t token = IPCThreadState::self()->clearCallingIdentity();
         switch(direction) {
             case AAUDIO_DIRECTION_INPUT:
                 capture = new AAudioServiceEndpointCapture(audioService);
@@ -138,6 +140,7 @@
         }
         ALOGD("AAudioEndpointManager::openEndpoint(), created %p for device = %d, dir = %d",
               endpoint, configuration.getDeviceId(), (int)direction);
+        IPCThreadState::self()->restoreCallingIdentity(token);
     }
 
     if (endpoint != nullptr) {
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 669bb54..3992719 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -50,8 +50,9 @@
 
 android::AAudioService::AAudioService()
     : BnAAudioService() {
-    mCachedProcessId = getpid();
-    mCachedUserId = getuid();   // TODO consider using geteuid()
+    mAudioClient.clientUid = getuid();   // TODO consider using geteuid()
+    mAudioClient.clientPid = getpid();
+    mAudioClient.packageName = String16("");
     AAudioClientTracker::getInstance().setAAudioService(this);
 }
 
@@ -92,7 +93,7 @@
 
     // Enforce limit on client processes.
     pid_t pid = request.getProcessId();
-    if (pid != mCachedProcessId) {
+    if (pid != mAudioClient.clientPid) {
         int32_t count = AAudioClientTracker::getInstance().getStreamCount(pid);
         if (count >= MAX_STREAMS_PER_PROCESS) {
             ALOGE("AAudioService::openStream(): exceeded max streams per process %d >= %d",
@@ -107,7 +108,13 @@
     }
 
     if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) {
-        serviceStream = new AAudioServiceStreamMMAP(mCachedUserId);
+        // only trust audioserver for in service indication
+        bool inService = false;
+        if (mAudioClient.clientPid == IPCThreadState::self()->getCallingPid() &&
+                mAudioClient.clientUid == IPCThreadState::self()->getCallingUid()) {
+            inService = request.isInService();
+        }
+        serviceStream = new AAudioServiceStreamMMAP(mAudioClient, inService);
         result = serviceStream->open(request, configurationOutput);
         if (result != AAUDIO_OK) {
             // fall back to using a shared stream
@@ -132,8 +139,6 @@
               result, AAudio_convertResultToText(result));
         return result;
     } else {
-        const uid_t ownerUserId = request.getUserId(); // only set by service, not by client
-        serviceStream->setOwnerUserId(ownerUserId);
         aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream.get());
         if (handle < 0) {
             ALOGE("AAudioService::openStream(): handle table full");
@@ -143,7 +148,6 @@
             ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
             serviceStream->setHandle(handle);
             pid_t pid = request.getProcessId();
-            serviceStream->setOwnerProcessId(pid);
             AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
         }
         return handle;
@@ -181,8 +185,8 @@
         const uid_t callingUserId = IPCThreadState::self()->getCallingUid();
         const uid_t ownerUserId = serviceStream->getOwnerUserId();
         bool callerOwnsIt = callingUserId == ownerUserId;
-        bool serverCalling = callingUserId == mCachedUserId;
-        bool serverOwnsIt = ownerUserId == mCachedUserId;
+        bool serverCalling = callingUserId == mAudioClient.clientUid;
+        bool serverOwnsIt = ownerUserId == mAudioClient.clientUid;
         bool allowed = callerOwnsIt || serverCalling || serverOwnsIt;
         if (!allowed) {
             ALOGE("AAudioService: calling uid %d cannot access stream 0x%08X owned by %d",
@@ -212,6 +216,7 @@
         ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
+
     aaudio_result_t result = serviceStream->start();
     return result;
 }
@@ -286,3 +291,26 @@
     serviceStream->setRegisteredThread(0);
     return AAUDIO_OK;
 }
+
+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) {
+        ALOGE("AAudioService::startClient(), illegal stream handle = 0x%0x",
+              streamHandle);
+        return AAUDIO_ERROR_INVALID_HANDLE;
+    }
+    return serviceStream->startClient(client, clientHandle);
+}
+
+aaudio_result_t AAudioService::stopClient(aaudio_handle_t streamHandle,
+                                          audio_port_handle_t clientHandle) {
+    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream == nullptr) {
+        ALOGE("AAudioService::stopClient(), illegal stream handle = 0x%0x",
+              streamHandle);
+        return AAUDIO_ERROR_INVALID_HANDLE;
+    }
+    return serviceStream->stopClient(clientHandle);
+}
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index f84ac4c..8421efc 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -21,6 +21,7 @@
 #include <pthread.h>
 
 #include <binder/BinderService.h>
+#include <media/AudioClient.h>
 
 #include <aaudio/AAudio.h>
 #include "utility/HandleTracker.h"
@@ -72,14 +73,20 @@
     virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
                                                   pid_t tid);
 
+    virtual aaudio_result_t startClient(aaudio_handle_t streamHandle,
+                                      const android::AudioClient& client,
+                                      audio_port_handle_t *clientHandle);
+
+    virtual aaudio_result_t stopClient(aaudio_handle_t streamHandle,
+                                       audio_port_handle_t clientHandle);
+
 private:
 
     aaudio::AAudioServiceStreamBase *convertHandleToServiceStream(aaudio_handle_t streamHandle) const;
 
     HandleTracker mHandleTracker;
 
-    uid_t   mCachedUserId = -1;
-    pid_t   mCachedProcessId = -1;
+    android::AudioClient mAudioClient;
 
     enum constants {
         DEFAULT_AUDIO_PRIORITY = 2
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index b519829..5895974 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceEndpoint"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -94,7 +94,7 @@
 }
 
 aaudio_result_t AAudioServiceEndpoint::close() {
-    return getStreamInternal()->close();
+     return getStreamInternal()->close();
 }
 
 // TODO, maybe use an interface to reduce exposure
@@ -113,26 +113,25 @@
 
 aaudio_result_t AAudioServiceEndpoint::startStream(sp<AAudioServiceStreamShared> sharedStream) {
     // TODO use real-time technique to avoid mutex, eg. atomic command FIFO
+    aaudio_result_t result = AAUDIO_OK;
     std::lock_guard<std::mutex> lock(mLockStreams);
-    mRunningStreams.push_back(sharedStream);
-    if (mRunningStreams.size() == 1) {
+    if (++mRunningStreams == 1) {
+        result = getStreamInternal()->requestStart();
         startSharingThread_l();
     }
-    return AAUDIO_OK;
+    return result;
 }
 
 aaudio_result_t AAudioServiceEndpoint::stopStream(sp<AAudioServiceStreamShared> sharedStream) {
     int numRunningStreams = 0;
     {
         std::lock_guard<std::mutex> lock(mLockStreams);
-        mRunningStreams.erase(
-                std::remove(mRunningStreams.begin(), mRunningStreams.end(), sharedStream),
-                mRunningStreams.end());
-        numRunningStreams = mRunningStreams.size();
+        numRunningStreams = --mRunningStreams;
     }
     if (numRunningStreams == 0) {
         // Don't call this under a lock because the callbackLoop also uses the lock.
         stopSharingThread();
+        getStreamInternal()->requestStop();
     }
     return AAUDIO_OK;
 }
@@ -163,11 +162,8 @@
 
 void AAudioServiceEndpoint::disconnectRegisteredStreams() {
     std::lock_guard<std::mutex> lock(mLockStreams);
-    for(auto baseStream : mRunningStreams) {
-        baseStream->onStop();
-    }
-    mRunningStreams.clear();
     for(auto sharedStream : mRegisteredStreams) {
+        sharedStream->stop();
         sharedStream->disconnect();
     }
     mRegisteredStreams.clear();
@@ -189,3 +185,4 @@
 
     return true;
 }
+
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index a78d3fa..ed995e5 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -79,7 +79,7 @@
 
     std::vector<android::sp<AAudioServiceStreamShared>> mRegisteredStreams;
 
-    std::vector<android::sp<AAudioServiceStreamShared>> mRunningStreams;
+    size_t                   mRunningStreams = 0;
 
 private:
     aaudio_result_t startSharingThread_l();
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index a144c54..6a37330 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -57,9 +57,7 @@
 void *AAudioServiceEndpointCapture::callbackLoop() {
     ALOGD("AAudioServiceEndpointCapture(): callbackLoop() entering");
     int32_t underflowCount = 0;
-
-    aaudio_result_t result = getStreamInternal()->requestStart();
-
+    aaudio_result_t result = AAUDIO_OK;
     int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout();
 
     // result might be a frame count
@@ -78,21 +76,21 @@
         // Distribute data to each active stream.
         { // use lock guard
             std::lock_guard <std::mutex> lock(mLockStreams);
-            for (sp<AAudioServiceStreamShared> sharedStream : mRunningStreams) {
-                FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
-                if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
-                    getFramesPerBurst()) {
-                    underflowCount++;
-                } else {
-                    fifo->write(mDistributionBuffer, getFramesPerBurst());
+            for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) {
+                if (sharedStream->isRunning()) {
+                    FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
+                    if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
+                        getFramesPerBurst()) {
+                        underflowCount++;
+                    } else {
+                        fifo->write(mDistributionBuffer, getFramesPerBurst());
+                    }
+                    sharedStream->markTransferTime(AudioClock::getNanoseconds());
                 }
-                sharedStream->markTransferTime(AudioClock::getNanoseconds());
             }
         }
     }
 
-    result = getStreamInternal()->requestStop();
-
     ALOGD("AAudioServiceEndpointCapture(): callbackLoop() exiting, %d underflows", underflowCount);
     return NULL; // TODO review
 }
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index 1afcc1e..86ccde0 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -68,9 +68,7 @@
 void *AAudioServiceEndpointPlay::callbackLoop() {
     ALOGD("AAudioServiceEndpointPlay(): callbackLoop() entering");
     int32_t underflowCount = 0;
-
-    aaudio_result_t result = getStreamInternal()->requestStart();
-
+    aaudio_result_t result = AAUDIO_OK;
     int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout();
 
     // result might be a frame count
@@ -79,13 +77,15 @@
         mMixer.clear();
         { // use lock guard
             std::lock_guard <std::mutex> lock(mLockStreams);
-            for (sp<AAudioServiceStreamShared> sharedStream : mRunningStreams) {
-                FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
-                float volume = 1.0; // to match legacy volume
-                bool underflowed = mMixer.mix(fifo, volume);
-                underflowCount += underflowed ? 1 : 0;
-                // TODO log underflows in each stream
-                sharedStream->markTransferTime(AudioClock::getNanoseconds());
+            for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) {
+                if (sharedStream->isRunning()) {
+                    FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
+                    float volume = 1.0; // to match legacy volume
+                    bool underflowed = mMixer.mix(fifo, volume);
+                    underflowCount += underflowed ? 1 : 0;
+                    // TODO log underflows in each stream
+                    sharedStream->markTransferTime(AudioClock::getNanoseconds());
+                }
             }
         }
 
@@ -102,8 +102,6 @@
         }
     }
 
-    result = getStreamInternal()->requestStop();
-
     ALOGD("AAudioServiceEndpointPlay(): callbackLoop() exiting, %d underflows", underflowCount);
     return NULL; // TODO review
 }
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 52b1801..e0f6ad4 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceStreamBase"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -38,6 +38,9 @@
 AAudioServiceStreamBase::AAudioServiceStreamBase()
         : mUpMessageQueue(nullptr)
         , mAAudioThread() {
+    mMmapClient.clientUid = -1;
+    mMmapClient.clientPid = -1;
+    mMmapClient.packageName = String16("");
 }
 
 AAudioServiceStreamBase::~AAudioServiceStreamBase() {
@@ -45,7 +48,8 @@
     // 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_UNINITIALIZED
+                        || mState == AAUDIO_STREAM_STATE_DISCONNECTED),
                         "service stream still open, state = %d", mState);
 }
 
@@ -58,13 +62,18 @@
     result << "      framesPerBurst = " << mFramesPerBurst << "\n";
     result << "      channelCount   = " << mSamplesPerFrame << "\n";
     result << "      capacityFrames = " << mCapacityInFrames << "\n";
-    result << "      owner uid      = " << mOwnerUserId << "\n";
+    result << "      owner uid      = " << mMmapClient.clientUid << "\n";
 
     return result.str();
 }
 
 aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request,
                      aaudio::AAudioStreamConfiguration &configurationOutput) {
+
+    mMmapClient.clientUid = request.getUserId();
+    mMmapClient.clientPid = request.getProcessId();
+    mMmapClient.packageName.setTo(String16("")); // FIXME what should we do here?
+
     std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
     if (mUpMessageQueue != nullptr) {
         return AAUDIO_ERROR_INVALID_STATE;
@@ -86,6 +95,9 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::start() {
+    if (isRunning()) {
+        return AAUDIO_OK;
+    }
     sendServiceEvent(AAUDIO_SERVICE_EVENT_STARTED);
     mState = AAUDIO_STREAM_STATE_STARTED;
     mThreadEnabled.store(true);
@@ -94,32 +106,34 @@
 
 aaudio_result_t AAudioServiceStreamBase::pause() {
     aaudio_result_t result = AAUDIO_OK;
-    if (isRunning()) {
-        sendCurrentTimestamp();
-        mThreadEnabled.store(false);
-        result = mAAudioThread.stop();
-        if (result != AAUDIO_OK) {
-            disconnect();
-            return result;
-        }
-        sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
+    if (!isRunning()) {
+        return result;
     }
+    sendCurrentTimestamp();
+    mThreadEnabled.store(false);
+    result = mAAudioThread.stop();
+    if (result != AAUDIO_OK) {
+        disconnect();
+        return result;
+    }
+    sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
     mState = AAUDIO_STREAM_STATE_PAUSED;
     return result;
 }
 
 aaudio_result_t AAudioServiceStreamBase::stop() {
     aaudio_result_t result = AAUDIO_OK;
-    if (isRunning()) {
-        // TODO wait for data to be played out
-        sendCurrentTimestamp(); // warning - this calls a virtual function
-        result = stopTimestampThread();
-        if (result != AAUDIO_OK) {
-            disconnect();
-            return result;
-        }
-        sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
+    if (!isRunning()) {
+        return result;
     }
+    // TODO wait for data to be played out
+    sendCurrentTimestamp(); // warning - this calls a virtual function
+    result = stopTimestampThread();
+    if (result != AAUDIO_OK) {
+        disconnect();
+        return result;
+    }
+    sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
     mState = AAUDIO_STREAM_STATE_STOPPED;
     return result;
 }
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index c7df6f3..93a522e 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -27,6 +27,7 @@
 #include "binding/AudioEndpointParcelable.h"
 #include "binding/AAudioServiceMessage.h"
 #include "utility/AAudioUtilities.h"
+#include <media/AudioClient.h>
 
 #include "SharedRingBuffer.h"
 #include "AAudioThread.h"
@@ -85,9 +86,19 @@
      */
     virtual aaudio_result_t flush();
 
+    virtual aaudio_result_t startClient(const android::AudioClient& client __unused,
+                                        audio_port_handle_t *clientHandle __unused) {
+        return AAUDIO_ERROR_UNAVAILABLE;
+    }
+
+    virtual aaudio_result_t stopClient(audio_port_handle_t clientHandle __unused) {
+        return AAUDIO_ERROR_UNAVAILABLE;
+    }
+
     bool isRunning() const {
         return mState == AAUDIO_STREAM_STATE_STARTED;
     }
+
     // -------------------------------------------------------------------
 
     /**
@@ -124,17 +135,11 @@
     void disconnect();
 
     uid_t getOwnerUserId() const {
-        return mOwnerUserId;
-    }
-    void setOwnerUserId(uid_t uid) {
-        mOwnerUserId = uid;
+        return mMmapClient.clientUid;
     }
 
     pid_t getOwnerProcessId() const {
-        return mOwnerProcessId;
-    }
-    void setOwnerProcessId(pid_t pid) {
-        mOwnerProcessId = pid;
+        return mMmapClient.clientPid;
     }
 
     aaudio_handle_t getHandle() const {
@@ -164,24 +169,25 @@
 
     aaudio_stream_state_t   mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
 
-    pid_t              mRegisteredClientThread = ILLEGAL_THREAD_ID;
+    pid_t                   mRegisteredClientThread = ILLEGAL_THREAD_ID;
 
-    SharedRingBuffer*  mUpMessageQueue;
-    std::mutex         mLockUpMessageQueue;
+    SharedRingBuffer*       mUpMessageQueue;
+    std::mutex              mLockUpMessageQueue;
 
-    AAudioThread       mAAudioThread;
+    AAudioThread            mAAudioThread;
     // This is used by one thread to tell another thread to exit. So it must be atomic.
-    std::atomic<bool>  mThreadEnabled;
+    std::atomic<bool>       mThreadEnabled;
 
-    aaudio_format_t    mAudioFormat = AAUDIO_FORMAT_UNSPECIFIED;
-    int32_t            mFramesPerBurst = 0;
-    int32_t            mSamplesPerFrame = AAUDIO_UNSPECIFIED;
-    int32_t            mSampleRate = AAUDIO_UNSPECIFIED;
-    int32_t            mCapacityInFrames = AAUDIO_UNSPECIFIED;
-    uid_t              mOwnerUserId = -1;
-    pid_t              mOwnerProcessId = -1;
+    aaudio_format_t         mAudioFormat = AAUDIO_FORMAT_UNSPECIFIED;
+    int32_t                 mFramesPerBurst = 0;
+    int32_t                 mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+    int32_t                 mSampleRate = AAUDIO_UNSPECIFIED;
+    int32_t                 mCapacityInFrames = AAUDIO_UNSPECIFIED;
+    android::AudioClient    mMmapClient;
+    audio_port_handle_t     mClientHandle = AUDIO_PORT_HANDLE_NONE;
+
 private:
-    aaudio_handle_t    mHandle = -1;
+    aaudio_handle_t         mHandle = -1;
 };
 
 } /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceStreamExclusive.h b/services/oboeservice/AAudioServiceStreamExclusive.h
deleted file mode 100644
index db382a3..0000000
--- a/services/oboeservice/AAudioServiceStreamExclusive.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAUDIO_AAUDIO_SERVICE_STREAM_EXCLUSIVE_H
-#define AAUDIO_AAUDIO_SERVICE_STREAM_EXCLUSIVE_H
-
-#include "AAudioServiceStreamMMAP.h"
-
-namespace aaudio {
-
-/**
- * Exclusive mode stream in the AAudio service.
- *
- * This is currently a stub.
- * We may move code from AAudioServiceStreamMMAP into this class.
- * If not, then it will be removed.
- */
-class AAudioServiceStreamExclusive : public AAudioServiceStreamMMAP {
-
-public:
-    AAudioServiceStreamExclusive() {};
-    virtual ~AAudioServiceStreamExclusive() = default;
-};
-
-} /* namespace aaudio */
-
-#endif //AAUDIO_AAUDIO_SERVICE_STREAM_EXCLUSIVE_H
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 1b80486..68be3c3 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceStreamMMAP"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -41,19 +41,21 @@
  * Service Stream that uses an MMAP buffer.
  */
 
-AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(uid_t serviceUid)
+AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(const android::AudioClient& serviceClient,
+                                                 bool inService)
         : AAudioServiceStreamBase()
         , mMmapStreamCallback(new MyMmapStreamCallback(*this))
         , mPreviousFrameCounter(0)
         , mMmapStream(nullptr)
-        , mCachedUserId(serviceUid) {
+        , mServiceClient(serviceClient)
+        , mInService(inService) {
 }
 
 aaudio_result_t AAudioServiceStreamMMAP::close() {
     if (mState == AAUDIO_STREAM_STATE_CLOSED) {
         return AAUDIO_OK;
     }
-
+    stop();
     if (mMmapStream != 0) {
         mMmapStream.clear(); // TODO review. Is that all we have to do?
         // Apparently the above close is asynchronous. An attempt to open a new device
@@ -90,9 +92,6 @@
 
     const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
     audio_port_handle_t deviceId = configurationInput.getDeviceId();
-
-    mMmapClient.clientUid = request.getUserId();
-    mMmapClient.clientPid = request.getProcessId();
     aaudio_direction_t direction = request.getDirection();
 
     // Fill in config
@@ -123,8 +122,6 @@
         return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
     }
 
-    mMmapClient.packageName.setTo(String16("aaudio_service")); // FIXME what should we do here?
-
     MmapStreamInterface::stream_direction_t streamDirection = (direction == AAUDIO_DIRECTION_OUTPUT)
         ? MmapStreamInterface::DIRECTION_OUTPUT : MmapStreamInterface::DIRECTION_INPUT;
 
@@ -135,7 +132,8 @@
                                                           mMmapClient,
                                                           &deviceId,
                                                           mMmapStreamCallback,
-                                                          mMmapStream);
+                                                          mMmapStream,
+                                                          &mPortHandle);
     if (status != OK) {
         ALOGE("openMmapStream returned status %d", status);
         return AAUDIO_ERROR_UNAVAILABLE;
@@ -172,7 +170,7 @@
         mCapacityInFrames = -mCapacityInFrames;
     } else {
         // exclusive mode is only possible if the final fd destination is inside audioserver
-        if ((mMmapClient.clientUid != mCachedUserId) &&
+        if ((mMmapClient.clientUid != mServiceClient.clientUid) &&
                 configurationInput.getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
             // Fallback is handled by caller but indicate what is possible in case
             // this is used in the future
@@ -223,15 +221,21 @@
  * Start the flow of data.
  */
 aaudio_result_t AAudioServiceStreamMMAP::start() {
+    if (isRunning()) {
+        return AAUDIO_OK;
+    }
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
     aaudio_result_t result;
-    status_t status = mMmapStream->start(mMmapClient, &mPortHandle);
+    status_t status = mMmapStream->start(mServiceClient, &mPortHandle);
     if (status != OK) {
         ALOGE("AAudioServiceStreamMMAP::start() mMmapStream->start() returned %d", status);
         disconnect();
         result = AAudioConvert_androidToAAudioResult(status);
     } else {
         result = AAudioServiceStreamBase::start();
+        if (!mInService && result == AAUDIO_OK) {
+            startClient(mMmapClient, &mClientHandle);
+        }
     }
     return result;
 }
@@ -240,18 +244,28 @@
  * Stop the flow of data such that start() can resume with loss of data.
  */
 aaudio_result_t AAudioServiceStreamMMAP::pause() {
+    if (!isRunning()) {
+        return AAUDIO_OK;
+    }
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
-
     aaudio_result_t result1 = AAudioServiceStreamBase::pause();
+    if (!mInService) {
+        stopClient(mClientHandle);
+    }
     status_t status = mMmapStream->stop(mPortHandle);
     mFramesRead.reset32();
     return (result1 != AAUDIO_OK) ? result1 : AAudioConvert_androidToAAudioResult(status);
 }
 
 aaudio_result_t AAudioServiceStreamMMAP::stop() {
+    if (!isRunning()) {
+        return AAUDIO_OK;
+    }
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
-
     aaudio_result_t result1 = AAudioServiceStreamBase::stop();
+    if (!mInService) {
+        stopClient(mClientHandle);
+    }
     aaudio_result_t status = mMmapStream->stop(mPortHandle);
     mFramesRead.reset32();
     return (result1 != AAUDIO_OK) ? result1 :  AAudioConvert_androidToAAudioResult(status);
@@ -266,6 +280,15 @@
     return AAudioServiceStreamBase::flush();;
 }
 
+aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
+                                                     audio_port_handle_t *clientHandle) {
+    return AAudioConvert_androidToAAudioResult(mMmapStream->start(client, clientHandle));
+}
+
+aaudio_result_t AAudioServiceStreamMMAP::stopClient(audio_port_handle_t clientHandle) {
+    return AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
+}
+
 aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition(int64_t *positionFrames,
                                                                 int64_t *timeNanos) {
     struct audio_mmap_position position;
@@ -301,11 +324,11 @@
 
 void AAudioServiceStreamMMAP::onRoutingChanged(audio_port_handle_t deviceId) {
     ALOGD("AAudioServiceStreamMMAP::onRoutingChanged() called with %d, old = %d",
-          deviceId, mPortHandle);
-    if (mPortHandle > 0 && mPortHandle != deviceId) {
+          deviceId, mDeviceId);
+    if (mDeviceId != AUDIO_PORT_HANDLE_NONE  && mDeviceId != deviceId) {
         disconnect();
     }
-    mPortHandle = deviceId;
+    mDeviceId = deviceId;
 };
 
 /**
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index 257bea9..533e5a8 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -43,7 +43,7 @@
     , public android::MmapStreamCallback {
 
 public:
-    AAudioServiceStreamMMAP(uid_t serviceUid);
+    AAudioServiceStreamMMAP(const android::AudioClient& serviceClient, bool inService);
     virtual ~AAudioServiceStreamMMAP() = default;
 
     aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
@@ -77,6 +77,11 @@
 
     aaudio_result_t close() override;
 
+    virtual aaudio_result_t startClient(const android::AudioClient& client,
+                                        audio_port_handle_t *clientHandle);
+
+    virtual aaudio_result_t stopClient(audio_port_handle_t clientHandle);
+
     /**
      * Send a MMAP/NOIRQ buffer timestamp to the client.
      */
@@ -131,9 +136,10 @@
     // Interface to the AudioFlinger MMAP support.
     android::sp<android::MmapStreamInterface> mMmapStream;
     struct audio_mmap_buffer_info             mMmapBufferinfo;
-    android::MmapStreamInterface::Client      mMmapClient;
-    audio_port_handle_t                       mPortHandle = -1; // TODO review best default
-    uid_t                                     mCachedUserId = -1;
+    audio_port_handle_t                       mPortHandle = AUDIO_PORT_HANDLE_NONE;
+    audio_port_handle_t                       mDeviceId = AUDIO_PORT_HANDLE_NONE;
+    android::AudioClient                      mServiceClient;
+    bool                                      mInService = false;
 };
 
 } // namespace aaudio
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 8bb34d1..fe488cb 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceStreamShared"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -191,6 +191,9 @@
  * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
  */
 aaudio_result_t AAudioServiceStreamShared::start()  {
+    if (isRunning()) {
+        return AAUDIO_OK;
+    }
     AAudioServiceEndpoint *endpoint = mServiceEndpoint;
     if (endpoint == nullptr) {
         return AAUDIO_ERROR_INVALID_STATE;
@@ -201,7 +204,10 @@
         ALOGE("AAudioServiceStreamShared::start() mServiceEndpoint returned %d", result);
         disconnect();
     } else {
-        result = AAudioServiceStreamBase::start();
+        result = endpoint->getStreamInternal()->startClient(mMmapClient, &mClientHandle);
+        if (result == AAUDIO_OK) {
+            result = AAudioServiceStreamBase::start();
+        }
     }
     return result;
 }
@@ -212,10 +218,14 @@
  * An AAUDIO_SERVICE_EVENT_PAUSED will be sent to the client when complete.
 */
 aaudio_result_t AAudioServiceStreamShared::pause()  {
+    if (!isRunning()) {
+        return AAUDIO_OK;
+    }
     AAudioServiceEndpoint *endpoint = mServiceEndpoint;
     if (endpoint == nullptr) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
+    endpoint->getStreamInternal()->stopClient(mClientHandle);
     aaudio_result_t result = endpoint->stopStream(this);
     if (result != AAUDIO_OK) {
         ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result);
@@ -225,10 +235,14 @@
 }
 
 aaudio_result_t AAudioServiceStreamShared::stop()  {
+    if (!isRunning()) {
+        return AAUDIO_OK;
+    }
     AAudioServiceEndpoint *endpoint = mServiceEndpoint;
     if (endpoint == nullptr) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
+    endpoint->getStreamInternal()->stopClient(mClientHandle);
     aaudio_result_t result = endpoint->stopStream(this);
     if (result != AAUDIO_OK) {
         ALOGE("AAudioServiceStreamShared::stop() mServiceEndpoint returned %d", result);
@@ -248,7 +262,7 @@
         return AAUDIO_ERROR_INVALID_STATE;
     }
     if (mState != AAUDIO_STREAM_STATE_PAUSED) {
-        ALOGE("AAudioServiceStreamShared::flush() stream not paused, state = %s",
+         ALOGE("AAudioServiceStreamShared::flush() stream not paused, state = %s",
             AAudio_convertStreamStateToText(mState));
         return AAUDIO_ERROR_INVALID_STATE;
     }
@@ -261,11 +275,12 @@
         return AAUDIO_OK;
     }
 
+    stop();
+
     AAudioServiceEndpoint *endpoint = mServiceEndpoint;
     if (endpoint == nullptr) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
-    endpoint->stopStream(this);
 
     endpoint->unregisterStream(this);
 
@@ -277,7 +292,6 @@
         delete mAudioDataQueue;
         mAudioDataQueue = nullptr;
     }
-
     return AAudioServiceStreamBase::close();
 }
 
@@ -293,9 +307,6 @@
     return AAUDIO_OK;
 }
 
-void AAudioServiceStreamShared::onStop() {
-}
-
 void AAudioServiceStreamShared::markTransferTime(int64_t nanoseconds) {
     mMarkedPosition = mAudioDataQueue->getFifoBuffer()->getReadCounter();
     mMarkedTime = nanoseconds;
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index 742c5af..6b67337 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -87,8 +87,6 @@
      */
     void markTransferTime(int64_t nanoseconds);
 
-    void onStop();
-
 protected:
 
     aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) override;