aaudio: fix SHARED MMAP mode in server plus other bugs

Fixed some buffer miscalculations, and some NPEs in the close() code.
Added debugging and some general cleanup.
Fixed data conversion.
Fixed start/pause/flush in server.
Added reference counting in server for endpoints.
Programs can now be ran more than once.
General code cleanup.
Reconnect with service if server dies.
Move stop() logic into server for better synchronization.
Add sleep to prevent race condition when closing an MMAP stream.

Bug: 33398120
Test: two write_sine_callback.cpp can be run simultaneously
Change-Id: Ibb006215a498868c222228d675ff961d7e0bf514
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/media/libaaudio/examples/write_sine/src/SineGenerator.h b/media/libaaudio/examples/write_sine/src/SineGenerator.h
index 64b772d..f2eb984 100644
--- a/media/libaaudio/examples/write_sine/src/SineGenerator.h
+++ b/media/libaaudio/examples/write_sine/src/SineGenerator.h
@@ -79,7 +79,7 @@
         }
     }
 
-    double mAmplitude = 0.05;  // unitless scaler
+    double mAmplitude = 0.005;  // unitless scaler
     double mPhase = 0.0;
     double mPhaseIncrement = 440 * M_PI * 2 / 48000;
     double mFrameRate = 48000;
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index d8e5ec1..6525c0a 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -23,11 +23,15 @@
 #include "SineGenerator.h"
 
 #define SAMPLE_RATE   48000
-#define NUM_SECONDS   10
+#define NUM_SECONDS   5
 #define NANOS_PER_MICROSECOND ((int64_t)1000)
 #define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
 #define NANOS_PER_SECOND      (NANOS_PER_MILLISECOND * 1000)
 
+#define REQUESTED_FORMAT  AAUDIO_FORMAT_PCM_I16
+#define REQUESTED_SHARING_MODE  AAUDIO_SHARING_MODE_SHARED
+//#define REQUESTED_SHARING_MODE  AAUDIO_SHARING_MODE_EXCLUSIVE
+
 static const char *getSharingModeText(aaudio_sharing_mode_t mode) {
     const char *modeText = "unknown";
     switch (mode) {
@@ -63,23 +67,21 @@
     int actualSamplesPerFrame = 0;
     const int requestedSampleRate = SAMPLE_RATE;
     int actualSampleRate = 0;
-    const aaudio_audio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM_I16;
-    aaudio_audio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_I16;
+    aaudio_audio_format_t actualDataFormat = AAUDIO_FORMAT_UNSPECIFIED;
 
-    //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
-    const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED;
     aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
 
     AAudioStreamBuilder *aaudioBuilder = nullptr;
     AAudioStream *aaudioStream = nullptr;
     aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
-    int32_t framesPerBurst = 0;
-    int32_t framesPerWrite = 0;
-    int32_t bufferCapacity = 0;
-    int32_t framesToPlay = 0;
-    int32_t framesLeft = 0;
-    int32_t xRunCount = 0;
-    int16_t *data = nullptr;
+    int32_t  framesPerBurst = 0;
+    int32_t  framesPerWrite = 0;
+    int32_t  bufferCapacity = 0;
+    int32_t  framesToPlay = 0;
+    int32_t  framesLeft = 0;
+    int32_t  xRunCount = 0;
+    float   *floatData = nullptr;
+    int16_t *shortData = nullptr;
 
     SineGenerator sineOsc1;
     SineGenerator sineOsc2;
@@ -88,7 +90,7 @@
     // in a buffer if we hang or crash.
     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
 
-    printf("%s - Play a sine wave using AAudio\n", argv[0]);
+    printf("%s - Play a sine wave using AAudio, Z2\n", argv[0]);
 
     // Use an AAudioStreamBuilder to contain requested parameters.
     result = AAudio_createStreamBuilder(&aaudioBuilder);
@@ -99,8 +101,8 @@
     // Request stream properties.
     AAudioStreamBuilder_setSampleRate(aaudioBuilder, requestedSampleRate);
     AAudioStreamBuilder_setSamplesPerFrame(aaudioBuilder, requestedSamplesPerFrame);
-    AAudioStreamBuilder_setFormat(aaudioBuilder, requestedDataFormat);
-    AAudioStreamBuilder_setSharingMode(aaudioBuilder, requestedSharingMode);
+    AAudioStreamBuilder_setFormat(aaudioBuilder, REQUESTED_FORMAT);
+    AAudioStreamBuilder_setSharingMode(aaudioBuilder, REQUESTED_SHARING_MODE);
 
     // Create an AAudioStream using the Builder.
     result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
@@ -124,15 +126,16 @@
 
     actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
     printf("SharingMode: requested = %s, actual = %s\n",
-            getSharingModeText(requestedSharingMode),
+            getSharingModeText(REQUESTED_SHARING_MODE),
             getSharingModeText(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(aaudioStream);
-    printf("DataFormat: framesPerBurst = %d\n",framesPerBurst);
+    printf("Buffer: framesPerBurst = %d\n",framesPerBurst);
+    printf("Buffer: bufferSize = %d\n", AAudioStream_getBufferSizeInFrames(aaudioStream));
     bufferCapacity = AAudioStream_getBufferCapacityInFrames(aaudioStream);
-    printf("DataFormat: bufferCapacity = %d, remainder = %d\n",
+    printf("Buffer: bufferCapacity = %d, remainder = %d\n",
            bufferCapacity, bufferCapacity % framesPerBurst);
 
     // Some DMA might use very short bursts of 16 frames. We don't need to write such small
@@ -144,14 +147,16 @@
     printf("DataFormat: framesPerWrite = %d\n",framesPerWrite);
 
     actualDataFormat = AAudioStream_getFormat(aaudioStream);
-    printf("DataFormat: requested = %d, actual = %d\n", requestedDataFormat, actualDataFormat);
+    printf("DataFormat: requested = %d, actual = %d\n", REQUESTED_FORMAT, actualDataFormat);
     // TODO handle other data formats
 
     // Allocate a buffer for the audio data.
-    data = new int16_t[framesPerWrite * actualSamplesPerFrame];
-    if (data == nullptr) {
-        fprintf(stderr, "ERROR - could not allocate data buffer\n");
-        result = AAUDIO_ERROR_NO_MEMORY;
+    if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
+        floatData = new float[framesPerWrite * actualSamplesPerFrame];
+    } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
+        shortData = new int16_t[framesPerWrite * actualSamplesPerFrame];
+    } else {
+        printf("ERROR Unsupported data format!\n");
         goto finish;
     }
 
@@ -170,26 +175,41 @@
     framesToPlay = actualSampleRate * NUM_SECONDS;
     framesLeft = framesToPlay;
     while (framesLeft > 0) {
-        // Render sine waves to left and right channels.
-        sineOsc1.render(&data[0], actualSamplesPerFrame, framesPerWrite);
-        if (actualSamplesPerFrame > 1) {
-            sineOsc2.render(&data[1], actualSamplesPerFrame, framesPerWrite);
+
+        if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
+            // Render sine waves to left and right channels.
+            sineOsc1.render(&floatData[0], actualSamplesPerFrame, framesPerWrite);
+            if (actualSamplesPerFrame > 1) {
+                sineOsc2.render(&floatData[1], actualSamplesPerFrame, framesPerWrite);
+            }
+        } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
+            // Render sine waves to left and right channels.
+            sineOsc1.render(&shortData[0], actualSamplesPerFrame, framesPerWrite);
+            if (actualSamplesPerFrame > 1) {
+                sineOsc2.render(&shortData[1], actualSamplesPerFrame, framesPerWrite);
+            }
         }
 
         // Write audio data to the stream.
-        int64_t timeoutNanos = 100 * NANOS_PER_MILLISECOND;
-        int minFrames = (framesToPlay < framesPerWrite) ? framesToPlay : framesPerWrite;
-        int actual = AAudioStream_write(aaudioStream, data, minFrames, timeoutNanos);
+        int64_t timeoutNanos = 1000 * NANOS_PER_MILLISECOND;
+        int32_t minFrames = (framesToPlay < framesPerWrite) ? framesToPlay : framesPerWrite;
+        int32_t actual = 0;
+        if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
+            actual = AAudioStream_write(aaudioStream, floatData, minFrames, timeoutNanos);
+        } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
+            actual = AAudioStream_write(aaudioStream, shortData, minFrames, timeoutNanos);
+        }
         if (actual < 0) {
-            fprintf(stderr, "ERROR - AAudioStream_write() returned %zd\n", actual);
+            fprintf(stderr, "ERROR - AAudioStream_write() returned %d\n", actual);
             goto finish;
         } else if (actual == 0) {
-            fprintf(stderr, "WARNING - AAudioStream_write() returned %zd\n", actual);
+            fprintf(stderr, "WARNING - AAudioStream_write() returned %d\n", actual);
             goto finish;
         }
         framesLeft -= actual;
 
         // Use timestamp to estimate latency.
+        /*
         {
             int64_t presentationFrame;
             int64_t presentationTime;
@@ -208,13 +228,15 @@
                 printf("estimatedLatencyMillis %d\n", (int)estimatedLatencyMillis);
             }
         }
+         */
     }
 
     xRunCount = AAudioStream_getXRunCount(aaudioStream);
     printf("AAudioStream_getXRunCount %d\n", xRunCount);
 
 finish:
-    delete[] data;
+    delete[] floatData;
+    delete[] shortData;
     AAudioStream_close(aaudioStream);
     AAudioStreamBuilder_delete(aaudioBuilder);
     printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index 9414236..8c1072d 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -31,8 +31,6 @@
 //#define SHARING_MODE  AAUDIO_SHARING_MODE_EXCLUSIVE
 #define SHARING_MODE  AAUDIO_SHARING_MODE_SHARED
 
-#define  CALLBACK_SIZE_FRAMES    128
-
 // TODO refactor common code into a single SimpleAAudio class
 /**
  * Simple wrapper for AAudio that opens a default stream and then calls
@@ -87,8 +85,8 @@
         AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode);
         AAudioStreamBuilder_setDataCallback(mBuilder, dataProc, userContext);
         AAudioStreamBuilder_setFormat(mBuilder, AAUDIO_FORMAT_PCM_FLOAT);
-        AAudioStreamBuilder_setFramesPerDataCallback(mBuilder, CALLBACK_SIZE_FRAMES);
- //       AAudioStreamBuilder_setBufferCapacityInFrames(mBuilder, CALLBACK_SIZE_FRAMES * 4);
+ //       AAudioStreamBuilder_setFramesPerDataCallback(mBuilder, CALLBACK_SIZE_FRAMES);
+        AAudioStreamBuilder_setBufferCapacityInFrames(mBuilder, 48 * 8);
 
         // Open an AAudioStream using the Builder.
         result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
@@ -136,7 +134,7 @@
      aaudio_result_t start() {
         aaudio_result_t result = AAudioStream_requestStart(mStream);
         if (result != AAUDIO_OK) {
-            fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d %s\n",
+            printf("ERROR - AAudioStream_requestStart() returned %d %s\n",
                     result, AAudio_convertResultToText(result));
         }
         return result;
@@ -146,7 +144,7 @@
     aaudio_result_t stop() {
         aaudio_result_t result = AAudioStream_requestStop(mStream);
         if (result != AAUDIO_OK) {
-            fprintf(stderr, "ERROR - AAudioStream_requestStop() returned %d %s\n",
+            printf("ERROR - AAudioStream_requestStop() returned %d %s\n",
                     result, AAudio_convertResultToText(result));
         }
         int32_t xRunCount = AAudioStream_getXRunCount(mStream);
@@ -169,9 +167,6 @@
 typedef struct SineThreadedData_s {
     SineGenerator  sineOsc1;
     SineGenerator  sineOsc2;
-    // Remove these variables used for testing.
-    int32_t        numFrameCounts;
-    int32_t        frameCounts[MAX_FRAME_COUNT_RECORDS];
     int            scheduler;
     bool           schedulerChecked;
 } SineThreadedData_t;
@@ -186,10 +181,6 @@
 
     SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
 
-    if (sineData->numFrameCounts < MAX_FRAME_COUNT_RECORDS) {
-        sineData->frameCounts[sineData->numFrameCounts++] = numFrames;
-    }
-
     if (!sineData->schedulerChecked) {
         sineData->scheduler = sched_getscheduler(gettid());
         sineData->schedulerChecked = true;
@@ -236,11 +227,10 @@
     // Make printf print immediately so that debug info is not stuck
     // in a buffer if we hang or crash.
     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
-    printf("%s - Play a sine sweep using an AAudio callback\n", argv[0]);
+    printf("%s - Play a sine sweep using an AAudio callback, Z1\n", argv[0]);
 
     player.setSharingMode(SHARING_MODE);
 
-    myData.numFrameCounts = 0;
     myData.schedulerChecked = false;
 
     result = player.open(MyDataCallbackProc, &myData);
@@ -291,19 +281,17 @@
     }
     printf("Woke up now.\n");
 
+    printf("call stop()\n");
     result = player.stop();
     if (result != AAUDIO_OK) {
         goto error;
     }
+    printf("call close()\n");
     result = player.close();
     if (result != AAUDIO_OK) {
         goto error;
     }
 
-    // Report data gathered in the callback.
-    for (int i = 0; i < myData.numFrameCounts; i++) {
-        printf("numFrames[%4d] = %4d\n", i, myData.frameCounts[i]);
-    }
     if (myData.schedulerChecked) {
         printf("scheduler = 0x%08x, SCHED_FIFO = 0x%08X\n",
                myData.scheduler,
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
index 8315c40..3f1bba3 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.cpp
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -75,6 +75,10 @@
     return gAAudioService;
 }
 
+static void dropAAudioService() {
+    Mutex::Autolock _l(gServiceLock);
+    gAAudioService.clear(); // force a reconnect
+}
 
 AAudioBinderClient::AAudioBinderClient()
         : AAudioServiceInterface() {}
@@ -88,14 +92,26 @@
 */
 aaudio_handle_t AAudioBinderClient::openStream(const AAudioStreamRequest &request,
                                                AAudioStreamConfiguration &configurationOutput) {
+    aaudio_handle_t stream;
+    for (int i = 0; i < 2; i++) {
+        const sp<IAAudioService> &service = getAAudioService();
+        if (service == 0) {
+            return AAUDIO_ERROR_NO_SERVICE;
+        }
 
-    const sp<IAAudioService> &service = getAAudioService();
-    if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
-    return service->openStream(request, configurationOutput);
+        stream = service->openStream(request, configurationOutput);
+
+        if (stream == AAUDIO_ERROR_NO_SERVICE) {
+            ALOGE("AAudioBinderClient: lost connection to AAudioService.");
+            dropAAudioService(); // force a reconnect
+        } else {
+            break;
+        }
+    }
+    return stream;
 }
 
 aaudio_result_t AAudioBinderClient::closeStream(aaudio_handle_t streamHandle) {
-
     const sp<IAAudioService> &service = getAAudioService();
     if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
     return service->closeStream(streamHandle);
@@ -106,37 +122,33 @@
 */
 aaudio_result_t AAudioBinderClient::getStreamDescription(aaudio_handle_t streamHandle,
                                                          AudioEndpointParcelable &parcelable) {
-
     const sp<IAAudioService> &service = getAAudioService();
     if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
     return service->getStreamDescription(streamHandle, parcelable);
 }
 
-/**
-* Start the flow of data.
-*/
 aaudio_result_t AAudioBinderClient::startStream(aaudio_handle_t streamHandle) {
     const sp<IAAudioService> &service = getAAudioService();
     if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
     return service->startStream(streamHandle);
 }
 
-/**
-* Stop the flow of data such that start() can resume without loss of data.
-*/
 aaudio_result_t AAudioBinderClient::pauseStream(aaudio_handle_t streamHandle) {
     const sp<IAAudioService> &service = getAAudioService();
     if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
-    return service->startStream(streamHandle);
+    return service->pauseStream(streamHandle);
 }
 
-/**
-*  Discard any data held by the underlying HAL or Service.
-*/
+aaudio_result_t AAudioBinderClient::stopStream(aaudio_handle_t streamHandle) {
+    const sp<IAAudioService> &service = getAAudioService();
+    if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+    return service->stopStream(streamHandle);
+}
+
 aaudio_result_t AAudioBinderClient::flushStream(aaudio_handle_t streamHandle) {
     const sp<IAAudioService> &service = getAAudioService();
     if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
-    return service->startStream(streamHandle);
+    return service->flushStream(streamHandle);
 }
 
 /**
@@ -163,5 +175,3 @@
                                           clientProcessId,
                                           clientThreadId);
 }
-
-
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
index 1497177..f7f2808 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.h
+++ b/media/libaaudio/src/binding/AAudioBinderClient.h
@@ -66,6 +66,8 @@
      */
     aaudio_result_t pauseStream(aaudio_handle_t streamHandle) override;
 
+    aaudio_result_t stopStream(aaudio_handle_t streamHandle) override;
+
     /**
      *  Discard any data held by the underlying HAL or Service.
      * This is asynchronous. When complete, the service will send a FLUSHED event.
diff --git a/media/libaaudio/src/binding/AAudioServiceDefinitions.h b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
index 0d5bae5..2de560b 100644
--- a/media/libaaudio/src/binding/AAudioServiceDefinitions.h
+++ b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
@@ -35,6 +35,7 @@
     GET_STREAM_DESCRIPTION,
     START_STREAM,
     PAUSE_STREAM,
+    STOP_STREAM,
     FLUSH_STREAM,
     REGISTER_AUDIO_THREAD,
     UNREGISTER_AUDIO_THREAD
diff --git a/media/libaaudio/src/binding/AAudioServiceInterface.h b/media/libaaudio/src/binding/AAudioServiceInterface.h
index 62fd894..b565499 100644
--- a/media/libaaudio/src/binding/AAudioServiceInterface.h
+++ b/media/libaaudio/src/binding/AAudioServiceInterface.h
@@ -63,6 +63,11 @@
     virtual aaudio_result_t pauseStream(aaudio_handle_t streamHandle) = 0;
 
     /**
+     * Stop the flow of data after data currently inthe buffer has played.
+     */
+    virtual aaudio_result_t stopStream(aaudio_handle_t streamHandle) = 0;
+
+    /**
      *  Discard any data held by the underlying HAL or Service.
      */
     virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle) = 0;
diff --git a/media/libaaudio/src/binding/AAudioServiceMessage.h b/media/libaaudio/src/binding/AAudioServiceMessage.h
index 19d6d52..d75aa32 100644
--- a/media/libaaudio/src/binding/AAudioServiceMessage.h
+++ b/media/libaaudio/src/binding/AAudioServiceMessage.h
@@ -35,6 +35,7 @@
 typedef enum aaudio_service_event_e : uint32_t {
     AAUDIO_SERVICE_EVENT_STARTED,
     AAUDIO_SERVICE_EVENT_PAUSED,
+    AAUDIO_SERVICE_EVENT_STOPPED,
     AAUDIO_SERVICE_EVENT_FLUSHED,
     AAUDIO_SERVICE_EVENT_CLOSED,
     AAUDIO_SERVICE_EVENT_DISCONNECTED,
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index c2bcd05..09eaa42 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -43,7 +43,6 @@
     status = parcel->writeInt32(mSamplesPerFrame);
     if (status != NO_ERROR) goto error;
     status = parcel->writeInt32((int32_t) mSharingMode);
-    ALOGD("AAudioStreamConfiguration.writeToParcel(): mSharingMode = %d", mSharingMode);
     if (status != NO_ERROR) goto error;
     status = parcel->writeInt32((int32_t) mAudioFormat);
     if (status != NO_ERROR) goto error;
@@ -66,7 +65,6 @@
     status = parcel->readInt32(&temp);
     if (status != NO_ERROR) goto error;
     mSharingMode = (aaudio_sharing_mode_t) temp;
-    ALOGD("AAudioStreamConfiguration.readFromParcel(): mSharingMode = %d", mSharingMode);
     status = parcel->readInt32(&temp);
     if (status != NO_ERROR) goto error;
     mAudioFormat = (aaudio_audio_format_t) temp;
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
index ec21f8a..a5c27b9 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -49,6 +49,10 @@
     if (status != NO_ERROR) goto error;
     status = parcel->writeInt32((int32_t) mDirection);
     if (status != NO_ERROR) goto error;
+
+    status = parcel->writeBool(mSharingModeMatchRequired);
+    if (status != NO_ERROR) goto error;
+
     status = mConfiguration.writeToParcel(parcel);
     if (status != NO_ERROR) goto error;
     return NO_ERROR;
@@ -63,12 +67,18 @@
     status_t status = parcel->readInt32(&temp);
     if (status != NO_ERROR) goto error;
     mUserId = (uid_t) temp;
+
     status = parcel->readInt32(&temp);
     if (status != NO_ERROR) goto error;
     mProcessId = (pid_t) temp;
+
     status = parcel->readInt32(&temp);
     if (status != NO_ERROR) goto error;
     mDirection = (aaudio_direction_t) temp;
+
+    status = parcel->readBool(&mSharingModeMatchRequired);
+    if (status != NO_ERROR) goto error;
+
     status = mConfiguration.readFromParcel(parcel);
     if (status != NO_ERROR) goto error;
     return NO_ERROR;
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
index 992e978..d4bfbe1 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.h
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.h
@@ -60,6 +60,15 @@
         mDirection = direction;
     }
 
+    bool isSharingModeMatchRequired() const {
+        return mSharingModeMatchRequired;
+    }
+
+    void setSharingModeMatchRequired(bool required) {
+        mSharingModeMatchRequired = required;
+    }
+
+
     const AAudioStreamConfiguration &getConstantConfiguration() const {
         return mConfiguration;
     }
@@ -81,6 +90,7 @@
     uid_t                      mUserId;
     pid_t                      mProcessId;
     aaudio_direction_t         mDirection;
+    bool                       mSharingModeMatchRequired = false;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/binding/IAAudioService.cpp b/media/libaaudio/src/binding/IAAudioService.cpp
index 03fc088..b8ef611 100644
--- a/media/libaaudio/src/binding/IAAudioService.cpp
+++ b/media/libaaudio/src/binding/IAAudioService.cpp
@@ -45,16 +45,25 @@
         Parcel data, reply;
         // send command
         data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
-        ALOGE("BpAAudioService::client openStream request dump --------------------");
-        request.dump();
+        ALOGV("BpAAudioService::client openStream --------------------");
+        // request.dump();
         request.writeToParcel(&data);
         status_t err = remote()->transact(OPEN_STREAM, data, &reply);
+        ALOGV("BpAAudioService::client openStream returned %d", err);
         if (err != NO_ERROR) {
+            ALOGE("BpAAudioService::client openStream transact failed %d", err);
             return AAudioConvert_androidToAAudioResult(err);
         }
         // parse reply
         aaudio_handle_t stream;
-        reply.readInt32(&stream);
+        err = reply.readInt32(&stream);
+        if (err != NO_ERROR) {
+            ALOGE("BpAAudioService::client transact(OPEN_STREAM) readInt %d", err);
+            return AAudioConvert_androidToAAudioResult(err);
+        } else if (stream < 0) {
+            ALOGE("BpAAudioService::client OPEN_STREAM passed stream %d", stream);
+            return stream;
+        }
         err = configurationOutput.readFromParcel(&reply);
         if (err != NO_ERROR) {
             ALOGE("BpAAudioService::client openStream readFromParcel failed %d", err);
@@ -71,6 +80,7 @@
         data.writeInt32(streamHandle);
         status_t err = remote()->transact(CLOSE_STREAM, data, &reply);
         if (err != NO_ERROR) {
+            ALOGE("BpAAudioService::client closeStream transact failed %d", err);
             return AAudioConvert_androidToAAudioResult(err);
         }
         // parse reply
@@ -145,6 +155,21 @@
         return res;
     }
 
+    virtual aaudio_result_t stopStream(aaudio_handle_t streamHandle) override {
+        Parcel data, reply;
+        // send command
+        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
+        data.writeInt32(streamHandle);
+        status_t err = remote()->transact(STOP_STREAM, data, &reply);
+        if (err != NO_ERROR) {
+            return AAudioConvert_androidToAAudioResult(err);
+        }
+        // parse reply
+        aaudio_result_t res;
+        reply.readInt32(&res);
+        return res;
+    }
+
     virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle) override {
         Parcel data, reply;
         // send command
@@ -226,11 +251,11 @@
         case OPEN_STREAM: {
             request.readFromParcel(&data);
 
-            ALOGD("BnAAudioService::client openStream request dump --------------------");
-            request.dump();
+            //ALOGD("BnAAudioService::client openStream request dump --------------------");
+            //request.dump();
 
             stream = openStream(request, configuration);
-            ALOGV("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X", stream);
+            //ALOGD("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X", stream);
             reply->writeInt32(stream);
             configuration.writeToParcel(reply);
             return NO_ERROR;
@@ -238,18 +263,17 @@
 
         case CLOSE_STREAM: {
             data.readInt32(&stream);
-            ALOGV("BnAAudioService::onTransact CLOSE_STREAM 0x%08X", stream);
             result = closeStream(stream);
+            //ALOGD("BnAAudioService::onTransact CLOSE_STREAM 0x%08X, result = %d",
+            //      stream, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
 
         case GET_STREAM_DESCRIPTION: {
             data.readInt32(&stream);
-            ALOGI("BnAAudioService::onTransact GET_STREAM_DESCRIPTION 0x%08X", stream);
             aaudio::AudioEndpointParcelable parcelable;
             result = getStreamDescription(stream, parcelable);
-            ALOGI("BnAAudioService::onTransact getStreamDescription() returns %d", result);
             if (result != AAUDIO_OK) {
                 return AAudioConvert_aaudioToAndroidStatus(result);
             }
@@ -277,7 +301,16 @@
             data.readInt32(&stream);
             result = pauseStream(stream);
             ALOGV("BnAAudioService::onTransact PAUSE_STREAM 0x%08X, result = %d",
-                    stream, result);
+                  stream, result);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+
+        case STOP_STREAM: {
+            data.readInt32(&stream);
+            result = stopStream(stream);
+            ALOGV("BnAAudioService::onTransact STOP_STREAM 0x%08X, result = %d",
+                  stream, result);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
diff --git a/media/libaaudio/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h
index ab7fd1b..2cee651 100644
--- a/media/libaaudio/src/binding/IAAudioService.h
+++ b/media/libaaudio/src/binding/IAAudioService.h
@@ -69,6 +69,12 @@
     virtual aaudio_result_t pauseStream(aaudio::aaudio_handle_t streamHandle) = 0;
 
     /**
+     * Stop the flow of data such that the data currently in the buffer is played.
+     * This is asynchronous. When complete, the service will send a STOPPED event.
+     */
+    virtual aaudio_result_t stopStream(aaudio::aaudio_handle_t streamHandle) = 0;
+
+    /**
      *  Discard any data held by the underlying HAL or Service.
      * This is asynchronous. When complete, the service will send a FLUSHED event.
      */
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index 649c884..0f501dd 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -61,9 +61,8 @@
         return status;
     }
     if (mSizeInBytes > 0) {
-// FIXME        mFd = dup(parcel->readFileDescriptor());
-        // Why is the ALSA resource not getting freed?!
-        mFd = fcntl(parcel->readFileDescriptor(), F_DUPFD_CLOEXEC, 0);
+        int originalFD = parcel->readFileDescriptor();
+        mFd = fcntl(originalFD, F_DUPFD_CLOEXEC, 0);
         if (mFd == -1) {
             status = -errno;
             ALOGE("SharedMemoryParcelable readFileDescriptor fcntl() failed : %d", status);
@@ -101,11 +100,6 @@
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
     if (mResolvedAddress == nullptr) {
-        /* TODO remove
-        int fd = fcntl(mFd, F_DUPFD_CLOEXEC, 0);
-        ALOGE_IF(fd==-1, "cannot dup fd=%d, size=%zd, (%s)",
-                    mFd, mSizeInBytes, strerror(errno));
-        */
         mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ|PROT_WRITE,
                                           MAP_SHARED, mFd, 0);
         if (mResolvedAddress == nullptr) {
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index fe049b2..6f87df6 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -59,35 +59,35 @@
         ALOGE("AudioEndpoint_validateQueueDescriptor() NULL dataAddress");
         return AAUDIO_ERROR_NULL;
     }
-    ALOGD("AudioEndpoint_validateQueueDescriptor %s, dataAddress at %p ====================",
+    ALOGV("AudioEndpoint_validateQueueDescriptor %s, dataAddress at %p ====================",
           type,
           descriptor->dataAddress);
-    ALOGD("AudioEndpoint_validateQueueDescriptor  readCounter at %p, writeCounter at %p",
+    ALOGV("AudioEndpoint_validateQueueDescriptor  readCounter at %p, writeCounter at %p",
           descriptor->readCounterAddress,
           descriptor->writeCounterAddress);
 
     // Try to READ from the data area.
     // This code will crash if the mmap failed.
     uint8_t value = descriptor->dataAddress[0];
-    ALOGD("AudioEndpoint_validateQueueDescriptor() dataAddress[0] = %d, then try to write",
+    ALOGV("AudioEndpoint_validateQueueDescriptor() dataAddress[0] = %d, then try to write",
         (int) value);
     // Try to WRITE to the data area.
     descriptor->dataAddress[0] = value * 3;
-    ALOGD("AudioEndpoint_validateQueueDescriptor() wrote successfully");
+    ALOGV("AudioEndpoint_validateQueueDescriptor() wrote successfully");
 
     if (descriptor->readCounterAddress) {
         fifo_counter_t counter = *descriptor->readCounterAddress;
-        ALOGD("AudioEndpoint_validateQueueDescriptor() *readCounterAddress = %d, now write",
+        ALOGV("AudioEndpoint_validateQueueDescriptor() *readCounterAddress = %d, now write",
               (int) counter);
         *descriptor->readCounterAddress = counter;
-        ALOGD("AudioEndpoint_validateQueueDescriptor() wrote readCounterAddress successfully");
+        ALOGV("AudioEndpoint_validateQueueDescriptor() wrote readCounterAddress successfully");
     }
     if (descriptor->writeCounterAddress) {
         fifo_counter_t counter = *descriptor->writeCounterAddress;
-        ALOGD("AudioEndpoint_validateQueueDescriptor() *writeCounterAddress = %d, now write",
+        ALOGV("AudioEndpoint_validateQueueDescriptor() *writeCounterAddress = %d, now write",
               (int) counter);
         *descriptor->writeCounterAddress = counter;
-        ALOGD("AudioEndpoint_validateQueueDescriptor() wrote writeCounterAddress successfully");
+        ALOGV("AudioEndpoint_validateQueueDescriptor() wrote writeCounterAddress successfully");
     }
     return AAUDIO_OK;
 }
@@ -107,7 +107,7 @@
     // TODO maybe remove after debugging
     aaudio_result_t result = AudioEndpoint_validateDescriptor(pEndpointDescriptor);
     if (result != AAUDIO_OK) {
-        ALOGD("AudioEndpoint_validateQueueDescriptor returned %d %s",
+        ALOGE("AudioEndpoint_validateQueueDescriptor returned %d %s",
               result, AAudio_convertResultToText(result));
         return result;
     }
@@ -142,10 +142,10 @@
     assert(descriptor->framesPerBurst > 0);
     assert(descriptor->framesPerBurst < 8 * 1024); // FIXME just for initial debugging
     assert(descriptor->dataAddress != nullptr);
-    ALOGD("AudioEndpoint::configure() data framesPerBurst = %d", descriptor->framesPerBurst);
-    ALOGD("AudioEndpoint::configure() data readCounterAddress = %p", descriptor->readCounterAddress);
+    ALOGV("AudioEndpoint::configure() data framesPerBurst = %d", descriptor->framesPerBurst);
+    ALOGV("AudioEndpoint::configure() data readCounterAddress = %p", descriptor->readCounterAddress);
     mOutputFreeRunning = descriptor->readCounterAddress == nullptr;
-    ALOGD("AudioEndpoint::configure() mOutputFreeRunning = %d", mOutputFreeRunning ? 1 : 0);
+    ALOGV("AudioEndpoint::configure() mOutputFreeRunning = %d", mOutputFreeRunning ? 1 : 0);
     int64_t *readCounterAddress = (descriptor->readCounterAddress == nullptr)
                                   ? &mDataReadCounter
                                   : descriptor->readCounterAddress;
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 7304205..af4b93a 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -40,9 +40,6 @@
 #define LOG_TIMESTAMPS   0
 
 using android::String16;
-using android::IServiceManager;
-using android::defaultServiceManager;
-using android::interface_cast;
 using android::Mutex;
 using android::WrappingBuffer;
 
@@ -53,7 +50,10 @@
 // Wait at least this many times longer than the operation should take.
 #define MIN_TIMEOUT_OPERATIONS    4
 
-#define ALOG_CONDITION   (mInService == false)
+//static int64_t s_logCounter = 0;
+//#define MYLOG_CONDITION   (mInService == true && s_logCounter++ < 500)
+//#define MYLOG_CONDITION   (s_logCounter++ < 500000)
+#define MYLOG_CONDITION   (1)
 
 AudioStreamInternal::AudioStreamInternal(AAudioServiceInterface  &serviceInterface, bool inService)
         : AudioStream()
@@ -62,8 +62,7 @@
         , mServiceStreamHandle(AAUDIO_HANDLE_INVALID)
         , mFramesPerBurst(16)
         , mServiceInterface(serviceInterface)
-        , mInService(inService)
-{
+        , mInService(inService) {
 }
 
 AudioStreamInternal::~AudioStreamInternal() {
@@ -84,27 +83,26 @@
     if (getFormat() == AAUDIO_UNSPECIFIED) {
         setFormat(AAUDIO_FORMAT_PCM_FLOAT);
     }
+    // Request FLOAT for the shared mixer.
+    request.getConfiguration().setAudioFormat(AAUDIO_FORMAT_PCM_FLOAT);
 
     // Build the request to send to the server.
     request.setUserId(getuid());
     request.setProcessId(getpid());
     request.setDirection(getDirection());
+    request.setSharingModeMatchRequired(isSharingModeMatchRequired());
 
     request.getConfiguration().setDeviceId(getDeviceId());
     request.getConfiguration().setSampleRate(getSampleRate());
     request.getConfiguration().setSamplesPerFrame(getSamplesPerFrame());
-    request.getConfiguration().setAudioFormat(getFormat());
-    aaudio_sharing_mode_t sharingMode = getSharingMode();
-    ALOGE("AudioStreamInternal.open(): sharingMode %d", sharingMode);
-    request.getConfiguration().setSharingMode(sharingMode);
+    request.getConfiguration().setSharingMode(getSharingMode());
+
     request.getConfiguration().setBufferCapacity(builder.getBufferCapacity());
 
     mServiceStreamHandle = mServiceInterface.openStream(request, configuration);
-    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal.open(): openStream returned mServiceStreamHandle = 0x%08X",
-         (unsigned int)mServiceStreamHandle);
     if (mServiceStreamHandle < 0) {
         result = mServiceStreamHandle;
-        ALOGE("AudioStreamInternal.open(): openStream() returned %d", result);
+        ALOGE("AudioStreamInternal.open(): %s openStream() returned %d", getLocationName(), result);
     } else {
         result = configuration.validate();
         if (result != AAUDIO_OK) {
@@ -120,10 +118,9 @@
         mDeviceFormat = configuration.getAudioFormat();
 
         result = mServiceInterface.getStreamDescription(mServiceStreamHandle, mEndPointParcelable);
-        ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal.open(): getStreamDescriptor(0x%08X) returns %d",
-              mServiceStreamHandle, result);
         if (result != AAUDIO_OK) {
-            ALOGE("AudioStreamInternal.open(): getStreamDescriptor returns %d", result);
+            ALOGE("AudioStreamInternal.open(): %s getStreamDescriptor returns %d",
+                  getLocationName(), result);
             mServiceInterface.closeStream(mServiceStreamHandle);
             return result;
         }
@@ -140,8 +137,19 @@
         mAudioEndpoint.configure(&mEndpointDescriptor);
 
         mFramesPerBurst = mEndpointDescriptor.downDataQueueDescriptor.framesPerBurst;
-        assert(mFramesPerBurst >= 16);
-        assert(mEndpointDescriptor.downDataQueueDescriptor.capacityInFrames < 10 * 1024);
+        int32_t capacity = mEndpointDescriptor.downDataQueueDescriptor.capacityInFrames;
+
+        ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal.open() %s framesPerBurst = %d, capacity = %d",
+                 getLocationName(), mFramesPerBurst, capacity);
+        // Validate result from server.
+        if (mFramesPerBurst < 16 || mFramesPerBurst > 16 * 1024) {
+            ALOGE("AudioStream::open(): framesPerBurst out of range = %d", mFramesPerBurst);
+            return AAUDIO_ERROR_OUT_OF_RANGE;
+        }
+        if (capacity < mFramesPerBurst || capacity > 32 * 1024) {
+            ALOGE("AudioStream::open(): bufferCapacity out of range = %d", capacity);
+            return AAUDIO_ERROR_OUT_OF_RANGE;
+        }
 
         mClockModel.setSampleRate(getSampleRate());
         mClockModel.setFramesPerBurst(mFramesPerBurst);
@@ -149,7 +157,8 @@
         if (getDataCallbackProc()) {
             mCallbackFrames = builder.getFramesPerDataCallback();
             if (mCallbackFrames > getBufferCapacity() / 2) {
-                ALOGE("AudioStreamInternal.open(): framesPerCallback too large");
+                ALOGE("AudioStreamInternal.open(): framesPerCallback too large = %d, capacity = %d",
+                      mCallbackFrames, getBufferCapacity());
                 mServiceInterface.closeStream(mServiceStreamHandle);
                 return AAUDIO_ERROR_OUT_OF_RANGE;
 
@@ -175,7 +184,8 @@
 }
 
 aaudio_result_t AudioStreamInternal::close() {
-    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X", mServiceStreamHandle);
+    ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X",
+             mServiceStreamHandle);
     if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
         aaudio_handle_t serviceStreamHandle = mServiceStreamHandle;
         mServiceStreamHandle = AAUDIO_HANDLE_INVALID;
@@ -250,7 +260,7 @@
 aaudio_result_t AudioStreamInternal::requestStart()
 {
     int64_t startTime;
-    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): start()");
+    ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal(): start()");
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
@@ -275,8 +285,10 @@
 int64_t AudioStreamInternal::calculateReasonableTimeout(int32_t framesPerOperation) {
 
     // Wait for at least a second or some number of callbacks to join the thread.
-    int64_t timeoutNanoseconds = (MIN_TIMEOUT_OPERATIONS * framesPerOperation * AAUDIO_NANOS_PER_SECOND)
-                         / getSampleRate();
+    int64_t timeoutNanoseconds = (MIN_TIMEOUT_OPERATIONS
+                                  * framesPerOperation
+                                  * AAUDIO_NANOS_PER_SECOND)
+                                  / getSampleRate();
     if (timeoutNanoseconds < MIN_TIMEOUT_NANOS) { // arbitrary number of seconds
         timeoutNanoseconds = MIN_TIMEOUT_NANOS;
     }
@@ -295,28 +307,34 @@
 
 aaudio_result_t AudioStreamInternal::requestPauseInternal()
 {
-    ALOGD("AudioStreamInternal(): pause()");
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+        ALOGE("AudioStreamInternal(): requestPauseInternal() mServiceStreamHandle invalid = 0x%08X",
+              mServiceStreamHandle);
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
     mClockModel.stop(AudioClock::getNanoseconds());
     setState(AAUDIO_STREAM_STATE_PAUSING);
-    return mServiceInterface.startStream(mServiceStreamHandle);
+    return mServiceInterface.pauseStream(mServiceStreamHandle);
 }
 
 aaudio_result_t AudioStreamInternal::requestPause()
 {
+    ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal(): %s requestPause()", getLocationName());
     aaudio_result_t result = stopCallback();
     if (result != AAUDIO_OK) {
         return result;
     }
-    return requestPauseInternal();
+    result = requestPauseInternal();
+    ALOGD("AudioStreamInternal(): requestPause() returns %d", result);
+    return result;
 }
 
 aaudio_result_t AudioStreamInternal::requestFlush() {
-    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): flush()");
+    ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal(): requestFlush()");
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+        ALOGE("AudioStreamInternal(): requestFlush() mServiceStreamHandle invalid = 0x%08X",
+              mServiceStreamHandle);
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
@@ -325,35 +343,45 @@
 }
 
 void AudioStreamInternal::onFlushFromServer() {
-    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): onFlushFromServer()");
+    ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal(): onFlushFromServer()");
     int64_t readCounter = mAudioEndpoint.getDownDataReadCounter();
     int64_t writeCounter = mAudioEndpoint.getDownDataWriteCounter();
+
     // Bump offset so caller does not see the retrograde motion in getFramesRead().
     int64_t framesFlushed = writeCounter - readCounter;
     mFramesOffsetFromService += framesFlushed;
+
     // Flush written frames by forcing writeCounter to readCounter.
     // This is because we cannot move the read counter in the hardware.
     mAudioEndpoint.setDownDataWriteCounter(readCounter);
 }
 
+aaudio_result_t AudioStreamInternal::requestStopInternal()
+{
+    if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+        ALOGE("AudioStreamInternal(): requestStopInternal() mServiceStreamHandle invalid = 0x%08X",
+              mServiceStreamHandle);
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+
+    mClockModel.stop(AudioClock::getNanoseconds());
+    setState(AAUDIO_STREAM_STATE_STOPPING);
+    return mServiceInterface.stopStream(mServiceStreamHandle);
+}
+
 aaudio_result_t AudioStreamInternal::requestStop()
 {
-    // TODO better implementation of requestStop()
-    aaudio_result_t result = requestPause();
-    if (result == AAUDIO_OK) {
-        aaudio_stream_state_t state;
-        result = waitForStateChange(AAUDIO_STREAM_STATE_PAUSING,
-                                    &state,
-                                    500 * AAUDIO_NANOS_PER_MILLISECOND);// TODO temporary code
-        if (result == AAUDIO_OK) {
-            result = requestFlush();
-        }
+    ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal(): %s requestStop()", getLocationName());
+    aaudio_result_t result = stopCallback();
+    if (result != AAUDIO_OK) {
+        return result;
     }
+    result = requestStopInternal();
+    ALOGD("AudioStreamInternal(): requestStop() returns %d", result);
     return result;
 }
 
 aaudio_result_t AudioStreamInternal::registerThread() {
-    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): registerThread()");
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
@@ -364,7 +392,6 @@
 }
 
 aaudio_result_t AudioStreamInternal::unregisterThread() {
-    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): unregisterThread()");
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
@@ -394,16 +421,16 @@
     static int64_t oldTime = 0;
     int64_t framePosition = command.timestamp.position;
     int64_t nanoTime = command.timestamp.timestamp;
-    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal() timestamp says framePosition = %08lld at nanoTime %llu",
+    ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal() timestamp says framePosition = %08lld at nanoTime %llu",
          (long long) framePosition,
          (long long) nanoTime);
     int64_t nanosDelta = nanoTime - oldTime;
     if (nanosDelta > 0 && oldTime > 0) {
         int64_t framesDelta = framePosition - oldPosition;
         int64_t rate = (framesDelta * AAUDIO_NANOS_PER_SECOND) / nanosDelta;
-        ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal() - framesDelta = %08lld", (long long) framesDelta);
-        ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal() - nanosDelta = %08lld", (long long) nanosDelta);
-        ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal() - measured rate = %llu", (unsigned long long) rate);
+        ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal() - framesDelta = %08lld", (long long) framesDelta);
+        ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal() - nanosDelta = %08lld", (long long) nanosDelta);
+        ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal() - measured rate = %llu", (unsigned long long) rate);
     }
     oldPosition = framePosition;
     oldTime = nanoTime;
@@ -422,23 +449,27 @@
 
 aaudio_result_t AudioStreamInternal::onEventFromServer(AAudioServiceMessage *message) {
     aaudio_result_t result = AAUDIO_OK;
-    ALOGD_IF(ALOG_CONDITION, "processCommands() got event %d", message->event.event);
+    ALOGD_IF(MYLOG_CONDITION, "processCommands() got event %d", message->event.event);
     switch (message->event.event) {
         case AAUDIO_SERVICE_EVENT_STARTED:
-            ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_STARTED");
+            ALOGD_IF(MYLOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_STARTED");
             setState(AAUDIO_STREAM_STATE_STARTED);
             break;
         case AAUDIO_SERVICE_EVENT_PAUSED:
-            ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_PAUSED");
+            ALOGD_IF(MYLOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_PAUSED");
             setState(AAUDIO_STREAM_STATE_PAUSED);
             break;
+        case AAUDIO_SERVICE_EVENT_STOPPED:
+            ALOGD_IF(MYLOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_STOPPED");
+            setState(AAUDIO_STREAM_STATE_STOPPED);
+            break;
         case AAUDIO_SERVICE_EVENT_FLUSHED:
-            ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_FLUSHED");
+            ALOGD_IF(MYLOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_FLUSHED");
             setState(AAUDIO_STREAM_STATE_FLUSHED);
             onFlushFromServer();
             break;
         case AAUDIO_SERVICE_EVENT_CLOSED:
-            ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_CLOSED");
+            ALOGD_IF(MYLOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_CLOSED");
             setState(AAUDIO_STREAM_STATE_CLOSED);
             break;
         case AAUDIO_SERVICE_EVENT_DISCONNECTED:
@@ -448,7 +479,7 @@
             break;
         case AAUDIO_SERVICE_EVENT_VOLUME:
             mVolume = message->event.dataDouble;
-            ALOGD_IF(ALOG_CONDITION, "processCommands() AAUDIO_SERVICE_EVENT_VOLUME %f", mVolume);
+            ALOGD_IF(MYLOG_CONDITION, "processCommands() AAUDIO_SERVICE_EVENT_VOLUME %f", mVolume);
             break;
         default:
             ALOGW("WARNING - processCommands() Unrecognized event = %d",
@@ -463,7 +494,7 @@
     aaudio_result_t result = AAUDIO_OK;
 
     while (result == AAUDIO_OK) {
-        //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::processCommands() - looping, %d", result);
+        //ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal::processCommands() - looping, %d", result);
         AAudioServiceMessage message;
         if (mAudioEndpoint.readUpCommand(&message) != 1) {
             break; // no command this time, no problem
@@ -478,7 +509,7 @@
             break;
 
         default:
-            ALOGW("WARNING - AudioStreamInternal::processCommands() Unrecognized what = %d",
+            ALOGE("WARNING - AudioStreamInternal::processCommands() Unrecognized what = %d",
                  (int) message.what);
             result = AAUDIO_ERROR_UNEXPECTED_VALUE;
             break;
@@ -497,19 +528,13 @@
     int64_t currentTimeNanos = AudioClock::getNanoseconds();
     int64_t deadlineNanos = currentTimeNanos + timeoutNanoseconds;
     int32_t framesLeft = numFrames;
-    //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::write(%p, %d) at time %08llu , mState = %s",
-    //      buffer, numFrames, (unsigned long long) currentTimeNanos,
-    //      AAudio_convertStreamStateToText(getState()));
 
     // Write until all the data has been written or until a timeout occurs.
     while (framesLeft > 0) {
-        //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::write() loop: framesLeft = %d, loopCount = %d  =====",
-        //      framesLeft, loopCount++);
         // The call to writeNow() will not block. It will just write as much as it can.
         int64_t wakeTimeNanos = 0;
         aaudio_result_t framesWritten = writeNow(source, framesLeft,
                                                currentTimeNanos, &wakeTimeNanos);
-        //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::write() loop: framesWritten = %d", framesWritten);
         if (framesWritten < 0) {
             ALOGE("AudioStreamInternal::write() loop: writeNow returned %d", framesWritten);
             result = framesWritten;
@@ -522,7 +547,6 @@
         if (timeoutNanoseconds == 0) {
             break; // don't block
         } else if (framesLeft > 0) {
-            //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal:: original wakeTimeNanos %lld", (long long) wakeTimeNanos);
             // clip the wake time to something reasonable
             if (wakeTimeNanos < currentTimeNanos) {
                 wakeTimeNanos = currentTimeNanos;
@@ -534,16 +558,13 @@
                 break;
             }
 
-            //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal:: sleep until %lld, dur = %lld", (long long) wakeTimeNanos,
-            //        (long long) (wakeTimeNanos - currentTimeNanos));
-            AudioClock::sleepForNanos(wakeTimeNanos - currentTimeNanos);
+            int64_t sleepForNanos = wakeTimeNanos - currentTimeNanos;
+            AudioClock::sleepForNanos(sleepForNanos);
             currentTimeNanos = AudioClock::getNanoseconds();
         }
     }
 
     // return error or framesWritten
-    //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::write() result = %d, framesLeft = %d, #%d",
-    //      result, framesLeft, loopCount);
     (void) loopCount;
     return (result < 0) ? result : numFrames - framesLeft;
 }
@@ -552,17 +573,15 @@
 aaudio_result_t AudioStreamInternal::writeNow(const void *buffer, int32_t numFrames,
                                          int64_t currentNanoTime, int64_t *wakeTimePtr) {
 
-    //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow(%p) - enter", buffer);
     {
         aaudio_result_t result = processCommands();
-        //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - processCommands() returned %d", result);
         if (result != AAUDIO_OK) {
             return result;
         }
     }
 
     if (mAudioEndpoint.isOutputFreeRunning()) {
-        ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - update read counter");
+        //ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal::writeNow() - update read counter");
         // Update data queue based on the timing model.
         int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime);
         mAudioEndpoint.setDownDataReadCounter(estimatedReadCounter);
@@ -575,9 +594,9 @@
     }
 
     // Write some data to the buffer.
-    //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - writeNowWithConversion(%d)", numFrames);
+    //ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal::writeNow() - writeNowWithConversion(%d)", numFrames);
     int32_t framesWritten = writeNowWithConversion(buffer, numFrames);
-    //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - tried to write %d frames, wrote %d",
+    //ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal::writeNow() - tried to write %d frames, wrote %d",
     //    numFrames, framesWritten);
 
     // Calculate an ideal time to wake up.
@@ -585,7 +604,7 @@
         // By default wake up a few milliseconds from now.  // TODO review
         int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND);
         aaudio_stream_state_t state = getState();
-        //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - wakeTime based on %s",
+        //ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal::writeNow() - wakeTime based on %s",
         //      AAudio_convertStreamStateToText(state));
         switch (state) {
             case AAUDIO_STREAM_STATE_OPEN:
@@ -612,7 +631,7 @@
         *wakeTimePtr = wakeTime;
 
     }
-//    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow finished: now = %llu, read# = %llu, wrote# = %llu",
+//    ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal::writeNow finished: now = %llu, read# = %llu, wrote# = %llu",
 //         (unsigned long long)currentNanoTime,
 //         (unsigned long long)mAudioEndpoint.getDownDataReadCounter(),
 //         (unsigned long long)mAudioEndpoint.getDownDataWriteCounter());
@@ -623,9 +642,8 @@
 // TODO this function needs a major cleanup.
 aaudio_result_t AudioStreamInternal::writeNowWithConversion(const void *buffer,
                                        int32_t numFrames) {
-    // ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNowWithConversion(%p, %d)", buffer, numFrames);
+    // ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal::writeNowWithConversion(%p, %d)", buffer, numFrames);
     WrappingBuffer wrappingBuffer;
-    mAudioEndpoint.getEmptyRoomAvailable(&wrappingBuffer);
     uint8_t *source = (uint8_t *) buffer;
     int32_t framesLeft = numFrames;
 
@@ -640,18 +658,25 @@
             if (framesToWrite > framesAvailable) {
                 framesToWrite = framesAvailable;
             }
-            int32_t numBytes = getBytesPerFrame();
+            int32_t numBytes = getBytesPerFrame() * framesToWrite;
             // TODO handle volume scaling
             if (getFormat() == mDeviceFormat) {
                 // Copy straight through.
                 memcpy(wrappingBuffer.data[partIndex], source, numBytes);
             } else if (getFormat() == AAUDIO_FORMAT_PCM_FLOAT
-                    && mDeviceFormat == AAUDIO_FORMAT_PCM_I16) {
+                       && mDeviceFormat == AAUDIO_FORMAT_PCM_I16) {
                 // Data conversion.
                 AAudioConvert_floatToPcm16(
                         (const float *) source,
                         framesToWrite * getSamplesPerFrame(),
                         (int16_t *) wrappingBuffer.data[partIndex]);
+            } else if (getFormat() == AAUDIO_FORMAT_PCM_I16
+                       && mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT) {
+                // Data conversion.
+                AAudioConvert_pcm16ToFloat(
+                        (const int16_t *) source,
+                        framesToWrite * getSamplesPerFrame(),
+                        (float *) wrappingBuffer.data[partIndex]);
             } else {
                 // TODO handle more conversions
                 ALOGE("AudioStreamInternal::writeNowWithConversion() unsupported formats: %d, %d",
@@ -661,6 +686,8 @@
 
             source += numBytes;
             framesLeft -= framesToWrite;
+        } else {
+            break;
         }
         partIndex++;
     }
@@ -670,7 +697,7 @@
     if (framesWritten > 0) {
         incrementFramesWritten(framesWritten);
     }
-    // ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten);
+    // ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten);
     return framesWritten;
 }
 
@@ -680,7 +707,15 @@
 
 aaudio_result_t AudioStreamInternal::setBufferSize(int32_t requestedFrames) {
     int32_t actualFrames = 0;
+    // Round to the next highest burst size.
+    if (getFramesPerBurst() > 0) {
+        int32_t numBursts = (requestedFrames + getFramesPerBurst() - 1) / getFramesPerBurst();
+        requestedFrames = numBursts * getFramesPerBurst();
+    }
+
     aaudio_result_t result = mAudioEndpoint.setBufferSizeInFrames(requestedFrames, &actualFrames);
+    ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal::setBufferSize() %s req = %d => %d",
+             getLocationName(), requestedFrames, actualFrames);
     if (result < 0) {
         return result;
     } else {
@@ -714,7 +749,7 @@
     } else {
         mLastFramesRead = framesRead;
     }
-    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::getFramesRead() returns %lld", (long long)framesRead);
+    ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal::getFramesRead() returns %lld", (long long)framesRead);
     return framesRead;
 }
 
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 1aa3b0f..8244311 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -94,6 +94,7 @@
     aaudio_result_t processCommands();
 
     aaudio_result_t requestPauseInternal();
+    aaudio_result_t requestStopInternal();
 
     aaudio_result_t stopCallback();
 
@@ -129,6 +130,11 @@
                                      int32_t numFrames);
     void processTimestamp(uint64_t position, int64_t time);
 
+
+    const char *getLocationName() const {
+        return mInService ? "SERVICE" : "CLIENT";
+    }
+
     // Adjust timing model based on timestamp from service.
 
     IsochronousClockModel    mClockModel;      // timing model for chasing the HAL
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index c278c8b..21e3e70 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -101,13 +101,13 @@
             // or we may be drifting due to a slow HW clock.
             mMarkerFramePosition = framePosition;
             mMarkerNanoTime = nanoTime;
-            ALOGI("processTimestamp() - STATE_RUNNING - %d < %d micros - EARLY",
+            ALOGV("processTimestamp() - STATE_RUNNING - %d < %d micros - EARLY",
                  (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000));
         } else if (nanosDelta > (expectedNanosDelta + mMaxLatenessInNanos)) {
             // Later than expected timestamp.
             mMarkerFramePosition = framePosition;
             mMarkerNanoTime = nanoTime - mMaxLatenessInNanos;
-            ALOGI("processTimestamp() - STATE_RUNNING - %d > %d + %d micros - LATE",
+            ALOGV("processTimestamp() - STATE_RUNNING - %d > %d + %d micros - LATE",
                  (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000),
                  (int) (mMaxLatenessInNanos / 1000));
         }
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 9d69423..97726e6 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -168,16 +168,15 @@
                                                     void *userData)
 {
     AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
-    ALOGD("AAudioStreamBuilder_setCallback(): userData = %p", userData);
     streamBuilder->setDataCallbackProc(callback);
     streamBuilder->setDataCallbackUserData(userData);
 }
+
 AAUDIO_API void AAudioStreamBuilder_setErrorCallback(AAudioStreamBuilder* builder,
                                                  AAudioStream_errorCallback callback,
                                                  void *userData)
 {
     AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
-    ALOGD("AAudioStreamBuilder_setCallback(): userData = %p", userData);
     streamBuilder->setErrorCallbackProc(callback);
     streamBuilder->setErrorCallbackUserData(userData);
 }
@@ -186,10 +185,10 @@
                                                 int32_t frames)
 {
     AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
-    ALOGD("%s: frames = %d", __func__, frames);
     streamBuilder->setFramesPerDataCallback(frames);
 }
 
+// TODO merge AAudioInternal_openStream into AAudioStreamBuilder_openStream
 static aaudio_result_t  AAudioInternal_openStream(AudioStreamBuilder *streamBuilder,
                                               AAudioStream** streamPtr)
 {
@@ -206,7 +205,7 @@
 AAUDIO_API aaudio_result_t  AAudioStreamBuilder_openStream(AAudioStreamBuilder* builder,
                                                      AAudioStream** streamPtr)
 {
-    ALOGD("AAudioStreamBuilder_openStream(): builder = %p", builder);
+    ALOGD("AAudioStreamBuilder_openStream() ----------------------------------------------");
     AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(streamPtr);
     return AAudioInternal_openStream(streamBuilder, streamPtr);
 }
@@ -228,6 +227,7 @@
     if (audioStream != nullptr) {
         audioStream->close();
         delete audioStream;
+        ALOGD("AAudioStream_close() ----------------------------------------------");
         return AAUDIO_OK;
     }
     return AAUDIO_ERROR_INVALID_HANDLE;
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 7c0b5ae..9690848 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -38,7 +38,6 @@
 
 aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder)
 {
-
     // Copy parameters from the Builder because the Builder may be deleted after this call.
     mSamplesPerFrame = builder.getSamplesPerFrame();
     mSampleRate = builder.getSampleRate();
@@ -46,6 +45,7 @@
     mFormat = builder.getFormat();
     mDirection = builder.getDirection();
     mSharingMode = builder.getSharingMode();
+    mSharingModeMatchRequired = builder.isSharingModeMatchRequired();
 
     // callbacks
     mFramesPerDataCallback = builder.getFramesPerDataCallback();
@@ -53,10 +53,19 @@
     mErrorCallbackProc = builder.getErrorCallbackProc();
     mDataCallbackUserData = builder.getDataCallbackUserData();
 
-    // TODO validate more parameters.
-    if (mErrorCallbackProc != nullptr && mDataCallbackProc == nullptr) {
-        ALOGE("AudioStream::open(): disconnect callback cannot be used without a data callback.");
-        return AAUDIO_ERROR_UNEXPECTED_VALUE;
+    // This is very helpful for debugging in the future.
+    ALOGI("AudioStream.open(): rate = %d, channels = %d, format = %d, sharing = %d",
+          mSampleRate, mSamplesPerFrame, mFormat, mSharingMode);
+
+    // Check for values that are ridiculously out of range to prevent math overflow exploits.
+    // The service will do a better check.
+    if (mSamplesPerFrame < 0 || mSamplesPerFrame > 128) {
+        ALOGE("AudioStream::open(): samplesPerFrame out of range = %d", mSamplesPerFrame);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+    if (mSampleRate < 0 || mSampleRate > 1000000) {
+        ALOGE("AudioStream::open(): mSampleRate out of range = %d", mSampleRate);
+        return AAUDIO_ERROR_INVALID_RATE;
     }
     if (mDirection != AAUDIO_DIRECTION_INPUT && mDirection != AAUDIO_DIRECTION_OUTPUT) {
         ALOGE("AudioStream::open(): illegal direction %d", mDirection);
@@ -70,27 +79,6 @@
     close();
 }
 
-aaudio_result_t AudioStream::waitForStateTransition(aaudio_stream_state_t startingState,
-                                               aaudio_stream_state_t endingState,
-                                               int64_t timeoutNanoseconds)
-{
-    aaudio_stream_state_t state = getState();
-    aaudio_stream_state_t nextState = state;
-    if (state == startingState && state != endingState) {
-        aaudio_result_t result = waitForStateChange(state, &nextState, timeoutNanoseconds);
-        if (result != AAUDIO_OK) {
-            return result;
-        }
-    }
-// It's OK if the expected transition has already occurred.
-// But if we reach an unexpected state then that is an error.
-    if (nextState != endingState) {
-        return AAUDIO_ERROR_UNEXPECTED_STATE;
-    } else {
-        return AAUDIO_OK;
-    }
-}
-
 aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
                                                 aaudio_stream_state_t *nextState,
                                                 int64_t timeoutNanoseconds)
@@ -123,16 +111,15 @@
     return (state == currentState) ? AAUDIO_ERROR_TIMEOUT : AAUDIO_OK;
 }
 
-// This registers the app's background audio thread with the server before
+// This registers the callback thread with the server before
 // passing control to the app. This gives the server an opportunity to boost
 // the thread's performance characteristics.
 void* AudioStream::wrapUserThread() {
     void* procResult = nullptr;
     mThreadRegistrationResult = registerThread();
     if (mThreadRegistrationResult == AAUDIO_OK) {
-        // Call application procedure. This may take a very long time.
+        // Run callback loop. This may take a very long time.
         procResult = mThreadProc(mThreadArg);
-        ALOGD("AudioStream::mThreadProc() returned");
         mThreadRegistrationResult = unregisterThread();
     }
     return procResult;
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 073b9a1..916870b 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -154,6 +154,10 @@
         return mSharingMode;
     }
 
+    bool isSharingModeMatchRequired() const {
+        return mSharingModeMatchRequired;
+    }
+
     aaudio_direction_t getDirection() const {
         return mDirection;
     }
@@ -227,16 +231,6 @@
     }
 
     /**
-     * Wait for a transition from one state to another.
-     * @return AAUDIO_OK if the endingState was observed, or AAUDIO_ERROR_UNEXPECTED_STATE
-     *   if any state that was not the startingState or endingState was observed
-     *   or AAUDIO_ERROR_TIMEOUT
-     */
-    virtual aaudio_result_t waitForStateTransition(aaudio_stream_state_t startingState,
-                                                   aaudio_stream_state_t endingState,
-                                                   int64_t timeoutNanoseconds);
-
-    /**
      * This should not be called after the open() call.
      */
     void setSampleRate(int32_t sampleRate) {
@@ -294,6 +288,7 @@
     int32_t                mSampleRate = AAUDIO_UNSPECIFIED;
     int32_t                mDeviceId = AAUDIO_UNSPECIFIED;
     aaudio_sharing_mode_t  mSharingMode = AAUDIO_SHARING_MODE_SHARED;
+    bool                   mSharingModeMatchRequired = false; // must match sharing mode requested
     aaudio_audio_format_t  mFormat = AAUDIO_FORMAT_UNSPECIFIED;
     aaudio_direction_t     mDirection = AAUDIO_DIRECTION_OUTPUT;
     aaudio_stream_state_t  mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index b135a4b..4e0b8c6 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -30,9 +30,10 @@
 #include "legacy/AudioStreamRecord.h"
 #include "legacy/AudioStreamTrack.h"
 
-// Enable a mixer in AAudio service that will mix stream to an ALSA MMAP buffer.
+// Enable a mixer in AAudio service that will mix streams to an ALSA MMAP buffer.
 #define MMAP_SHARED_ENABLED      0
-// Enable AAUDIO_SHARING_MODE_EXCLUSIVE that uses an ALSA MMAP buffer.
+
+// Enable AAUDIO_SHARING_MODE_EXCLUSIVE that uses an ALSA MMAP buffer directly.
 #define MMAP_EXCLUSIVE_ENABLED   0
 
 using namespace aaudio;
@@ -50,7 +51,7 @@
     AudioStream* audioStream = nullptr;
     AAudioBinderClient *aaudioClient = nullptr;
     const aaudio_sharing_mode_t sharingMode = getSharingMode();
-    ALOGD("AudioStreamBuilder.build() sharingMode = %d", sharingMode);
+
     switch (getDirection()) {
 
     case AAUDIO_DIRECTION_INPUT:
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h
index c0ee6fe..25baf4c 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.h
+++ b/media/libaaudio/src/core/AudioStreamBuilder.h
@@ -82,6 +82,15 @@
         return this;
     }
 
+    bool isSharingModeMatchRequired() const {
+        return mSharingModeMatchRequired;
+    }
+
+    AudioStreamBuilder* setSharingModeMatchRequired(bool required) {
+        mSharingModeMatchRequired = required;
+        return this;
+    }
+
     int32_t getBufferCapacity() const {
         return mBufferCapacity;
     }
@@ -109,7 +118,6 @@
         return this;
     }
 
-
     void *getDataCallbackUserData() const {
         return mDataCallbackUserData;
     }
@@ -153,6 +161,7 @@
     int32_t                mSampleRate = AAUDIO_UNSPECIFIED;
     int32_t                mDeviceId = AAUDIO_DEVICE_UNSPECIFIED;
     aaudio_sharing_mode_t  mSharingMode = AAUDIO_SHARING_MODE_SHARED;
+    bool                   mSharingModeMatchRequired = false; // must match sharing mode requested
     aaudio_audio_format_t  mFormat = AAUDIO_FORMAT_UNSPECIFIED;
     aaudio_direction_t     mDirection = AAUDIO_DIRECTION_OUTPUT;
     int32_t                mBufferCapacity = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
index 857780c..6b4a772 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.cpp
+++ b/media/libaaudio/src/fifo/FifoBuffer.cpp
@@ -60,14 +60,11 @@
         , mFramesUnderrunCount(0)
         , mUnderrunCount(0)
 {
-    // TODO Handle possible failures to allocate. Move out of constructor?
     mFifo = new FifoControllerIndirect(capacityInFrames,
                                        capacityInFrames,
                                        readIndexAddress,
                                        writeIndexAddress);
     mStorageOwned = false;
-    ALOGD("FifoProcessor: capacityInFrames = %d, bytesPerFrame = %d",
-          capacityInFrames, bytesPerFrame);
 }
 
 FifoBuffer::~FifoBuffer() {
@@ -132,8 +129,6 @@
     while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
         fifo_frames_t framesToRead = framesLeft;
         fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
-        //ALOGD("FifoProcessor::read() framesAvailable = %d, partIndex = %d",
-        //      framesAvailable, partIndex);
         if (framesAvailable > 0) {
             if (framesToRead > framesAvailable) {
                 framesToRead = framesAvailable;
@@ -143,6 +138,8 @@
 
             destination += numBytes;
             framesLeft -= framesToRead;
+        } else {
+            break;
         }
         partIndex++;
     }
@@ -172,6 +169,8 @@
 
             source += numBytes;
             framesLeft -= framesToWrite;
+        } else {
+            break;
         }
         partIndex++;
     }
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index 87b8b0d..efbbfc5 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -57,7 +57,7 @@
     }
 }
 
-void AAudioConvert_pcm16ToFloat(const float *source, int32_t numSamples, int16_t *destination) {
+void AAudioConvert_pcm16ToFloat(const int16_t *source, int32_t numSamples, float *destination) {
     for (int i = 0; i < numSamples; i++) {
         destination[i] = source[i] * (1.0f / 32768.0f);
     }
@@ -78,6 +78,8 @@
         status = INVALID_OPERATION;
         break;
     case AAUDIO_ERROR_UNEXPECTED_VALUE: // TODO redundant?
+    case AAUDIO_ERROR_INVALID_RATE:
+    case AAUDIO_ERROR_INVALID_FORMAT:
     case AAUDIO_ERROR_ILLEGAL_ARGUMENT:
         status = BAD_VALUE;
         break;
@@ -103,7 +105,7 @@
         result = AAUDIO_ERROR_INVALID_HANDLE;
         break;
     case DEAD_OBJECT:
-        result = AAUDIO_ERROR_DISCONNECTED;
+        result = AAUDIO_ERROR_NO_SERVICE;
         break;
     case INVALID_OPERATION:
         result = AAUDIO_ERROR_INVALID_STATE;
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 84fa227..65b17bc 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AAudioService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
 #include <assert.h>
 #include <map>
 #include <mutex>
@@ -28,13 +32,18 @@
 ANDROID_SINGLETON_STATIC_INSTANCE(AAudioEndpointManager);
 
 AAudioEndpointManager::AAudioEndpointManager()
-        : Singleton<AAudioEndpointManager>() {
+        : Singleton<AAudioEndpointManager>()
+        , mInputs()
+        , mOutputs() {
 }
 
-AAudioServiceEndpoint *AAudioEndpointManager::findEndpoint(AAudioService &audioService, int32_t deviceId,
+AAudioServiceEndpoint *AAudioEndpointManager::openEndpoint(AAudioService &audioService, int32_t deviceId,
                                                            aaudio_direction_t direction) {
     AAudioServiceEndpoint *endpoint = nullptr;
     std::lock_guard<std::mutex> lock(mLock);
+
+    // Try to find an existing endpoint.
+    ALOGD("AAudioEndpointManager::openEndpoint(), device = %d, dir = %d", deviceId, direction);
     switch (direction) {
         case AAUDIO_DIRECTION_INPUT:
             endpoint = mInputs[deviceId];
@@ -48,11 +57,11 @@
     }
 
     // If we can't find an existing one then open one.
-    ALOGD("AAudioEndpointManager::findEndpoint(), found %p", endpoint);
+    ALOGD("AAudioEndpointManager::openEndpoint(), found %p", endpoint);
     if (endpoint == nullptr) {
         endpoint = new AAudioServiceEndpoint(audioService);
         if (endpoint->open(deviceId, direction) != AAUDIO_OK) {
-            ALOGD("AAudioEndpointManager::findEndpoint(), open failed");
+            ALOGE("AAudioEndpointManager::findEndpoint(), open failed");
             delete endpoint;
             endpoint = nullptr;
         } else {
@@ -66,22 +75,37 @@
             }
         }
     }
+
+    if (endpoint != nullptr) {
+        // Increment the reference count under this lock.
+        endpoint->setReferenceCount(endpoint->getReferenceCount() + 1);
+    }
+
     return endpoint;
 }
 
-// FIXME add reference counter for serviceEndpoints and removed on last use.
-
-void AAudioEndpointManager::removeEndpoint(AAudioServiceEndpoint *serviceEndpoint) {
-    aaudio_direction_t direction = serviceEndpoint->getDirection();
-    int32_t deviceId = serviceEndpoint->getDeviceId();
-
+void AAudioEndpointManager::closeEndpoint(AAudioServiceEndpoint *serviceEndpoint) {
     std::lock_guard<std::mutex> lock(mLock);
-    switch(direction) {
-        case AAUDIO_DIRECTION_INPUT:
-            mInputs.erase(deviceId);
-            break;
-        case AAUDIO_DIRECTION_OUTPUT:
-            mOutputs.erase(deviceId);
-            break;
+    if (serviceEndpoint == nullptr) {
+        return;
     }
-}
\ No newline at end of file
+
+    // Decrement the reference count under this lock.
+    int32_t newRefCount = serviceEndpoint->getReferenceCount() - 1;
+    serviceEndpoint->setReferenceCount(newRefCount);
+    if (newRefCount <= 0) {
+        aaudio_direction_t direction = serviceEndpoint->getDirection();
+        int32_t deviceId = serviceEndpoint->getDeviceId();
+
+        switch (direction) {
+            case AAUDIO_DIRECTION_INPUT:
+                mInputs.erase(deviceId);
+                break;
+            case AAUDIO_DIRECTION_OUTPUT:
+                mOutputs.erase(deviceId);
+                break;
+        }
+        serviceEndpoint->close();
+        delete serviceEndpoint;
+    }
+}
diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h
index 48b27f0..bbcfc1d 100644
--- a/services/oboeservice/AAudioEndpointManager.h
+++ b/services/oboeservice/AAudioEndpointManager.h
@@ -39,11 +39,11 @@
      * @param direction
      * @return endpoint or nullptr
      */
-    AAudioServiceEndpoint *findEndpoint(android::AAudioService &audioService,
+    AAudioServiceEndpoint *openEndpoint(android::AAudioService &audioService,
                                         int32_t deviceId,
                                         aaudio_direction_t direction);
 
-    void removeEndpoint(AAudioServiceEndpoint *serviceEndpoint);
+    void closeEndpoint(AAudioServiceEndpoint *serviceEndpoint);
 
 private:
 
diff --git a/services/oboeservice/AAudioMixer.cpp b/services/oboeservice/AAudioMixer.cpp
index 70da339..43203d4 100644
--- a/services/oboeservice/AAudioMixer.cpp
+++ b/services/oboeservice/AAudioMixer.cpp
@@ -41,7 +41,7 @@
     memset(mOutputBuffer, 0, mBufferSizeInBytes);
 }
 
-void AAudioMixer::mix(FifoBuffer *fifo, float volume) {
+bool AAudioMixer::mix(FifoBuffer *fifo, float volume) {
     WrappingBuffer wrappingBuffer;
     float *destination = mOutputBuffer;
     fifo_frames_t framesLeft = mFramesPerBurst;
@@ -67,9 +67,10 @@
     }
     fifo->getFifoControllerBase()->advanceReadIndex(mFramesPerBurst - framesLeft);
     if (framesLeft > 0) {
-        ALOGW("AAudioMixer::mix() UNDERFLOW by %d / %d frames ----- UNDERFLOW !!!!!!!!!!",
-              framesLeft, mFramesPerBurst);
+        //ALOGW("AAudioMixer::mix() UNDERFLOW by %d / %d frames ----- UNDERFLOW !!!!!!!!!!",
+        //      framesLeft, mFramesPerBurst);
     }
+    return (framesLeft > 0); // did not get all the frames we needed, ie. "underflow"
 }
 
 void AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames, float volume) {
diff --git a/services/oboeservice/AAudioMixer.h b/services/oboeservice/AAudioMixer.h
index 2191183..9155fec 100644
--- a/services/oboeservice/AAudioMixer.h
+++ b/services/oboeservice/AAudioMixer.h
@@ -31,7 +31,13 @@
 
     void clear();
 
-    void mix(android::FifoBuffer *fifo, float volume);
+    /**
+     * Mix from this FIFO
+     * @param fifo
+     * @param volume
+     * @return true if underflowed
+     */
+    bool mix(android::FifoBuffer *fifo, float volume);
 
     void mixPart(float *destination, float *source, int32_t numFrames, float volume);
 
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 723ef63..816d5ab 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -54,8 +54,8 @@
     aaudio_result_t result = AAUDIO_OK;
     AAudioServiceStreamBase *serviceStream = nullptr;
     const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
+    bool sharingModeMatchRequired = request.isSharingModeMatchRequired();
     aaudio_sharing_mode_t sharingMode = configurationInput.getSharingMode();
-    ALOGE("AAudioService::openStream(): sharingMode = %d", sharingMode);
 
     if (sharingMode != AAUDIO_SHARING_MODE_EXCLUSIVE && sharingMode != AAUDIO_SHARING_MODE_SHARED) {
         ALOGE("AAudioService::openStream(): unrecognized sharing mode = %d", sharingMode);
@@ -77,8 +77,9 @@
     }
 
     // if SHARED requested or if EXCLUSIVE failed
-    if (serviceStream == nullptr) {
-        ALOGD("AAudioService::openStream(), sharingMode = AAUDIO_SHARING_MODE_SHARED");
+    if (sharingMode == AAUDIO_SHARING_MODE_SHARED
+         || (serviceStream == nullptr && !sharingModeMatchRequired)) {
+        ALOGD("AAudioService::openStream(), try AAUDIO_SHARING_MODE_SHARED");
         serviceStream =  new AAudioServiceStreamShared(*this);
         result = serviceStream->open(request, configurationOutput);
         configurationOutput.setSharingMode(AAUDIO_SHARING_MODE_SHARED);
@@ -126,9 +127,7 @@
         ALOGE("AAudioService::getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
-    ALOGD("AAudioService::getStreamDescription(), handle = 0x%08x", streamHandle);
     aaudio_result_t result = serviceStream->getDescription(parcelable);
-    ALOGD("AAudioService::getStreamDescription(), result = %d", result);
     // parcelable.dump();
     return result;
 }
@@ -140,7 +139,6 @@
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     aaudio_result_t result = serviceStream->start();
-    ALOGD("AAudioService::startStream(), serviceStream->start() returned %d", result);
     return result;
 }
 
@@ -154,6 +152,16 @@
     return result;
 }
 
+aaudio_result_t AAudioService::stopStream(aaudio_handle_t streamHandle) {
+    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream == nullptr) {
+        ALOGE("AAudioService::pauseStream(), illegal stream handle = 0x%0x", streamHandle);
+        return AAUDIO_ERROR_INVALID_HANDLE;
+    }
+    aaudio_result_t result = serviceStream->stop();
+    return result;
+}
+
 aaudio_result_t AAudioService::flushStream(aaudio_handle_t streamHandle) {
     AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream == nullptr) {
@@ -168,7 +176,6 @@
                                                          pid_t clientThreadId,
                                                          int64_t periodNanoseconds) {
     AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    ALOGD("AAudioService::registerAudioThread(), serviceStream = %p", serviceStream);
     if (serviceStream == nullptr) {
         ALOGE("AAudioService::registerAudioThread(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
@@ -193,7 +200,6 @@
                                                      pid_t clientProcessId,
                                                      pid_t clientThreadId) {
     AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    ALOGI("AAudioService::unregisterAudioThread(), serviceStream = %p", serviceStream);
     if (serviceStream == nullptr) {
         ALOGE("AAudioService::unregisterAudioThread(), illegal stream handle = 0x%0x",
               streamHandle);
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index 5a7a2b6..f5a7d2f 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -57,6 +57,8 @@
 
     virtual aaudio_result_t pauseStream(aaudio_handle_t streamHandle);
 
+    virtual aaudio_result_t stopStream(aaudio_handle_t streamHandle);
+
     virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle);
 
     virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 80551c9..b197798 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -14,6 +14,17 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AAudioService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <assert.h>
+#include <map>
+#include <mutex>
+#include <utils/Singleton.h>
+
+#include "AAudioEndpointManager.h"
+#include "AAudioServiceEndpoint.h"
 #include <algorithm>
 #include <mutex>
 #include <vector>
@@ -30,6 +41,12 @@
 // Wait at least this many times longer than the operation should take.
 #define MIN_TIMEOUT_OPERATIONS    4
 
+// This is the maximum size in frames. The effective size can be tuned smaller at runtime.
+#define DEFAULT_BUFFER_CAPACITY   (48 * 8)
+
+// Use 2 for "double buffered"
+#define BUFFER_SIZE_IN_BURSTS     2
+
 // The mStreamInternal will use a service interface that does not go through Binder.
 AAudioServiceEndpoint::AAudioServiceEndpoint(AAudioService &audioService)
         : mStreamInternal(audioService, true)
@@ -43,11 +60,18 @@
 aaudio_result_t AAudioServiceEndpoint::open(int32_t deviceId, aaudio_direction_t direction) {
     AudioStreamBuilder builder;
     builder.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
+    // Don't fall back to SHARED because that would cause recursion.
+    builder.setSharingModeMatchRequired(true);
     builder.setDeviceId(deviceId);
     builder.setDirection(direction);
+    builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY);
+
     aaudio_result_t result = mStreamInternal.open(builder);
     if (result == AAUDIO_OK) {
         mMixer.allocate(mStreamInternal.getSamplesPerFrame(), mStreamInternal.getFramesPerBurst());
+
+        int32_t desiredBufferSize = BUFFER_SIZE_IN_BURSTS * mStreamInternal.getFramesPerBurst();
+        mStreamInternal.setBufferSize(desiredBufferSize);
     }
     return result;
 }
@@ -58,15 +82,12 @@
 
 // TODO, maybe use an interface to reduce exposure
 aaudio_result_t AAudioServiceEndpoint::registerStream(AAudioServiceStreamShared *sharedStream) {
-    ALOGD("AAudioServiceEndpoint::registerStream(%p)", sharedStream);
-    // TODO use real-time technique to avoid mutex, eg. atomic command FIFO
     std::lock_guard<std::mutex> lock(mLockStreams);
     mRegisteredStreams.push_back(sharedStream);
     return AAUDIO_OK;
 }
 
 aaudio_result_t AAudioServiceEndpoint::unregisterStream(AAudioServiceStreamShared *sharedStream) {
-    ALOGD("AAudioServiceEndpoint::unregisterStream(%p)", sharedStream);
     std::lock_guard<std::mutex> lock(mLockStreams);
     mRegisteredStreams.erase(std::remove(mRegisteredStreams.begin(), mRegisteredStreams.end(), sharedStream),
               mRegisteredStreams.end());
@@ -75,7 +96,6 @@
 
 aaudio_result_t AAudioServiceEndpoint::startStream(AAudioServiceStreamShared *sharedStream) {
     // TODO use real-time technique to avoid mutex, eg. atomic command FIFO
-    ALOGD("AAudioServiceEndpoint(): startStream() entering");
     std::lock_guard<std::mutex> lock(mLockStreams);
     mRunningStreams.push_back(sharedStream);
     if (mRunningStreams.size() == 1) {
@@ -106,13 +126,10 @@
 
 // Render audio in the application callback and then write the data to the stream.
 void *AAudioServiceEndpoint::callbackLoop() {
-    aaudio_result_t result = AAUDIO_OK;
-
     ALOGD("AAudioServiceEndpoint(): callbackLoop() entering");
+    int32_t underflowCount = 0;
 
-    result = mStreamInternal.requestStart();
-    ALOGD("AAudioServiceEndpoint(): callbackLoop() after requestStart()  %d, isPlaying() = %d",
-          result, (int) mStreamInternal.isPlaying());
+    aaudio_result_t result = mStreamInternal.requestStart();
 
     // result might be a frame count
     while (mCallbackEnabled.load() && mStreamInternal.isPlaying() && (result >= 0)) {
@@ -123,12 +140,14 @@
             for(AAudioServiceStreamShared *sharedStream : mRunningStreams) {
                 FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
                 float volume = 0.5; // TODO get from system
-                mMixer.mix(fifo, volume);
+                bool underflowed = mMixer.mix(fifo, volume);
+                underflowCount += underflowed ? 1 : 0;
+                // TODO log underflows in each stream
+                sharedStream->markTransferTime(AudioClock::getNanoseconds());
             }
         }
 
         // Write audio data to stream using a blocking write.
-        ALOGD("AAudioServiceEndpoint(): callbackLoop() write(%d)", getFramesPerBurst());
         int64_t timeoutNanos = calculateReasonableTimeout(mStreamInternal.getFramesPerBurst());
         result = mStreamInternal.write(mMixer.getOutputBuffer(), getFramesPerBurst(), timeoutNanos);
         if (result == AAUDIO_ERROR_DISCONNECTED) {
@@ -141,11 +160,9 @@
         }
     }
 
-    ALOGD("AAudioServiceEndpoint(): callbackLoop() exiting, result = %d, isPlaying() = %d",
-          result, (int) mStreamInternal.isPlaying());
-
     result = mStreamInternal.requestStop();
 
+    ALOGD("AAudioServiceEndpoint(): callbackLoop() exiting, %d underflows", underflowCount);
     return NULL; // TODO review
 }
 
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 020d38a..a4ceae6 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -56,6 +56,16 @@
 
     void *callbackLoop();
 
+    // This should only be called from the AAudioEndpointManager under a mutex.
+    int32_t getReferenceCount() const {
+        return mReferenceCount;
+    }
+
+    // This should only be called from the AAudioEndpointManager under a mutex.
+    void setReferenceCount(int32_t count) {
+        mReferenceCount = count;
+    }
+
 private:
     aaudio_result_t startMixer_l();
     aaudio_result_t stopMixer_l();
@@ -64,13 +74,14 @@
 
     AudioStreamInternal      mStreamInternal;
     AAudioMixer              mMixer;
-    AAudioServiceStreamMMAP  mStreamMMAP;
 
     std::atomic<bool>        mCallbackEnabled;
+    int32_t                  mReferenceCount = 0;
 
     std::mutex               mLockStreams;
     std::vector<AAudioServiceStreamShared *> mRegisteredStreams;
     std::vector<AAudioServiceStreamShared *> mRunningStreams;
+
 };
 
 } /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index b15043d..d8882c9 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -63,6 +63,7 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::start() {
+    ALOGD("AAudioServiceStreamBase::start() send AAUDIO_SERVICE_EVENT_STARTED");
     sendServiceEvent(AAUDIO_SERVICE_EVENT_STARTED);
     mState = AAUDIO_STREAM_STATE_STARTED;
     mThreadEnabled.store(true);
@@ -78,14 +79,37 @@
         processError();
         return result;
     }
+    ALOGD("AAudioServiceStreamBase::pause() send AAUDIO_SERVICE_EVENT_PAUSED");
     sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
     mState = AAUDIO_STREAM_STATE_PAUSED;
     return result;
 }
 
+aaudio_result_t AAudioServiceStreamBase::stop() {
+    // TODO wait for data to be played out
+    sendCurrentTimestamp();
+    mThreadEnabled.store(false);
+    aaudio_result_t result = mAAudioThread.stop();
+    if (result != AAUDIO_OK) {
+        processError();
+        return result;
+    }
+    ALOGD("AAudioServiceStreamBase::stop() send AAUDIO_SERVICE_EVENT_STOPPED");
+    sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
+    mState = AAUDIO_STREAM_STATE_STOPPED;
+    return result;
+}
+
+aaudio_result_t AAudioServiceStreamBase::flush() {
+    ALOGD("AAudioServiceStreamBase::flush() send AAUDIO_SERVICE_EVENT_FLUSHED");
+    sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED);
+    mState = AAUDIO_STREAM_STATE_FLUSHED;
+    return AAUDIO_OK;
+}
+
 // implement Runnable
 void AAudioServiceStreamBase::run() {
-    ALOGD("AAudioServiceStreamMMAP::run() entering ----------------");
+    ALOGD("AAudioServiceStreamBase::run() entering ----------------");
     TimestampScheduler timestampScheduler;
     timestampScheduler.setBurstPeriod(mFramesPerBurst, mSampleRate);
     timestampScheduler.start(AudioClock::getNanoseconds());
@@ -102,7 +126,7 @@
             AudioClock::sleepUntilNanoTime(nextTime);
         }
     }
-    ALOGD("AAudioServiceStreamMMAP::run() exiting ----------------");
+    ALOGD("AAudioServiceStreamBase::run() exiting ----------------");
 }
 
 void AAudioServiceStreamBase::processError() {
@@ -122,6 +146,10 @@
 
 aaudio_result_t AAudioServiceStreamBase::writeUpMessageQueue(AAudioServiceMessage *command) {
     std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
+    if (mUpMessageQueue == nullptr) {
+        ALOGE("writeUpMessageQueue(): mUpMessageQueue null! - stream not open");
+        return AAUDIO_ERROR_NULL;
+    }
     int32_t count = mUpMessageQueue->getFifoBuffer()->write(command, 1);
     if (count != 1) {
         ALOGE("writeUpMessageQueue(): Queue full. Did client die?");
@@ -133,9 +161,11 @@
 
 aaudio_result_t AAudioServiceStreamBase::sendCurrentTimestamp() {
     AAudioServiceMessage command;
+    //ALOGD("sendCurrentTimestamp() called");
     aaudio_result_t result = getFreeRunningPosition(&command.timestamp.position,
                                                     &command.timestamp.timestamp);
     if (result == AAUDIO_OK) {
+        //ALOGD("sendCurrentTimestamp(): position %d", (int) command.timestamp.position);
         command.what = AAudioServiceMessage::code::TIMESTAMP;
         result = writeUpMessageQueue(&command);
     }
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 91eec35..d6b6ee3 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -17,6 +17,7 @@
 #ifndef AAUDIO_AAUDIO_SERVICE_STREAM_BASE_H
 #define AAUDIO_AAUDIO_SERVICE_STREAM_BASE_H
 
+#include <assert.h>
 #include <mutex>
 
 #include "fifo/FifoBuffer.h"
@@ -60,17 +61,22 @@
     /**
      * Start the flow of data.
      */
-    virtual aaudio_result_t start() = 0;
+    virtual aaudio_result_t start();
 
     /**
      * Stop the flow of data such that start() can resume with loss of data.
      */
-    virtual aaudio_result_t pause() = 0;
+    virtual aaudio_result_t pause();
+
+    /**
+     * Stop the flow of data after data in buffer has played.
+     */
+    virtual aaudio_result_t stop();
 
     /**
      *  Discard any data held by the underlying HAL or Service.
      */
-    virtual aaudio_result_t flush() = 0;
+    virtual aaudio_result_t flush();
 
     // -------------------------------------------------------------------
 
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index b70c625..b2e7fc9 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -55,6 +55,11 @@
 aaudio_result_t AAudioServiceStreamMMAP::close() {
     ALOGD("AAudioServiceStreamMMAP::close() called, %p", mMmapStream.get());
     mMmapStream.clear(); // TODO review. Is that all we have to do?
+    // Apparently the above close is asynchronous. An attempt to open a new device
+    // right after a close can fail. Also some callbacks may still be in flight!
+    // FIXME Make closing synchronous.
+    AudioClock::sleepForNanos(100 * AAUDIO_NANOS_PER_MILLISECOND);
+
     return AAudioServiceStreamBase::close();
 }
 
@@ -79,8 +84,8 @@
     const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
     audio_port_handle_t deviceId = configurationInput.getDeviceId();
 
-    ALOGI("open request dump()");
-    request.dump();
+    // ALOGI("open request dump()");
+    // request.dump();
 
     mMmapClient.clientUid = request.getUserId();
     mMmapClient.clientPid = request.getProcessId();
@@ -198,16 +203,25 @@
     return (result1 != AAUDIO_OK) ? result1 : result2;
 }
 
+aaudio_result_t AAudioServiceStreamMMAP::stop() {
+    if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
+
+    aaudio_result_t result1 = AAudioServiceStreamBase::stop();
+    aaudio_result_t result2 = mMmapStream->stop(mPortHandle);
+    mFramesRead.reset32();
+    return (result1 != AAUDIO_OK) ? result1 : result2;
+}
+
 /**
  *  Discard any data held by the underlying HAL or Service.
  */
 aaudio_result_t AAudioServiceStreamMMAP::flush() {
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
     // TODO how do we flush an MMAP/NOIRQ buffer? sync pointers?
-    ALOGD("AAudioServiceStreamMMAP::pause() send AAUDIO_SERVICE_EVENT_FLUSHED");
+    ALOGD("AAudioServiceStreamMMAP::flush() send AAUDIO_SERVICE_EVENT_FLUSHED");
     sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED);
     mState = AAUDIO_STREAM_STATE_FLUSHED;
-    return AAUDIO_OK;
+    return AAudioServiceStreamBase::flush();;
 }
 
 
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index f121c5c..a8e63a6 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -66,6 +66,8 @@
     */
     aaudio_result_t pause() override;
 
+    aaudio_result_t stop() override;
+
     /**
      *  Discard any data held by the underlying HAL or Service.
      *
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index cd9336b..b5d9927 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -61,7 +61,7 @@
 
     ALOGD("AAudioServiceStreamShared::open(), direction = %d", direction);
     AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
-    mServiceEndpoint = mEndpointManager.findEndpoint(mAudioService, deviceId, direction);
+    mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService, deviceId, direction);
     ALOGD("AAudioServiceStreamShared::open(), mServiceEndPoint = %p", mServiceEndpoint);
     if (mServiceEndpoint == nullptr) {
         return AAUDIO_ERROR_UNAVAILABLE;
@@ -72,6 +72,7 @@
     if (mAudioFormat == AAUDIO_FORMAT_UNSPECIFIED) {
         mAudioFormat = AAUDIO_FORMAT_PCM_FLOAT;
     } else if (mAudioFormat != AAUDIO_FORMAT_PCM_FLOAT) {
+        ALOGE("AAudioServiceStreamShared::open(), mAudioFormat = %d, need FLOAT", mAudioFormat);
         return AAUDIO_ERROR_INVALID_FORMAT;
     }
 
@@ -79,6 +80,8 @@
     if (mSampleRate == AAUDIO_FORMAT_UNSPECIFIED) {
         mSampleRate = mServiceEndpoint->getSampleRate();
     } else if (mSampleRate != mServiceEndpoint->getSampleRate()) {
+        ALOGE("AAudioServiceStreamShared::open(), mAudioFormat = %d, need %d",
+              mSampleRate, mServiceEndpoint->getSampleRate());
         return AAUDIO_ERROR_INVALID_RATE;
     }
 
@@ -86,17 +89,22 @@
     if (mSamplesPerFrame == AAUDIO_FORMAT_UNSPECIFIED) {
         mSamplesPerFrame = mServiceEndpoint->getSamplesPerFrame();
     } else if (mSamplesPerFrame != mServiceEndpoint->getSamplesPerFrame()) {
+        ALOGE("AAudioServiceStreamShared::open(), mSamplesPerFrame = %d, need %d",
+              mSamplesPerFrame, mServiceEndpoint->getSamplesPerFrame());
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
 
     // Determine this stream's shared memory buffer capacity.
     mFramesPerBurst = mServiceEndpoint->getFramesPerBurst();
     int32_t minCapacityFrames = configurationInput.getBufferCapacity();
-    int32_t numBursts = (minCapacityFrames + mFramesPerBurst - 1) / mFramesPerBurst;
-    if (numBursts < MIN_BURSTS_PER_BUFFER) {
-        numBursts = MIN_BURSTS_PER_BUFFER;
-    } else if (numBursts > MAX_BURSTS_PER_BUFFER) {
-        numBursts = MAX_BURSTS_PER_BUFFER;
+    int32_t numBursts = MAX_BURSTS_PER_BUFFER;
+    if (minCapacityFrames != AAUDIO_UNSPECIFIED) {
+        numBursts = (minCapacityFrames + mFramesPerBurst - 1) / mFramesPerBurst;
+        if (numBursts < MIN_BURSTS_PER_BUFFER) {
+            numBursts = MIN_BURSTS_PER_BUFFER;
+        } else if (numBursts > MAX_BURSTS_PER_BUFFER) {
+            numBursts = MAX_BURSTS_PER_BUFFER;
+        }
     }
     mCapacityInFrames = numBursts * mFramesPerBurst;
     ALOGD("AAudioServiceStreamShared::open(), mCapacityInFrames = %d", mCapacityInFrames);
@@ -122,8 +130,12 @@
  * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
  */
 aaudio_result_t AAudioServiceStreamShared::start()  {
+    AAudioServiceEndpoint *endpoint = mServiceEndpoint;
+    if (endpoint == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
     // Add this stream to the mixer.
-    aaudio_result_t result = mServiceEndpoint->startStream(this);
+    aaudio_result_t result = endpoint->startStream(this);
     if (result != AAUDIO_OK) {
         ALOGE("AAudioServiceStreamShared::start() mServiceEndpoint returned %d", result);
         processError();
@@ -139,15 +151,31 @@
  * An AAUDIO_SERVICE_EVENT_PAUSED will be sent to the client when complete.
 */
 aaudio_result_t AAudioServiceStreamShared::pause()  {
+    AAudioServiceEndpoint *endpoint = mServiceEndpoint;
+    if (endpoint == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
     // Add this stream to the mixer.
-    aaudio_result_t result = mServiceEndpoint->stopStream(this);
+    aaudio_result_t result = endpoint->stopStream(this);
+    if (result != AAUDIO_OK) {
+        ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result);
+        processError();
+    }
+    return AAudioServiceStreamBase::pause();
+}
+
+aaudio_result_t AAudioServiceStreamShared::stop()  {
+    AAudioServiceEndpoint *endpoint = mServiceEndpoint;
+    if (endpoint == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    // Add this stream to the mixer.
+    aaudio_result_t result = endpoint->stopStream(this);
     if (result != AAUDIO_OK) {
         ALOGE("AAudioServiceStreamShared::stop() mServiceEndpoint returned %d", result);
         processError();
-    } else {
-        result = AAudioServiceStreamBase::start();
     }
-    return AAUDIO_OK;
+    return AAudioServiceStreamBase::stop();
 }
 
 /**
@@ -157,15 +185,21 @@
  */
 aaudio_result_t AAudioServiceStreamShared::flush()  {
     // TODO make sure we are paused
-    return AAUDIO_OK;
+    // TODO actually flush the data
+    return AAudioServiceStreamBase::flush() ;
 }
 
 aaudio_result_t AAudioServiceStreamShared::close()  {
     pause();
     // TODO wait for pause() to synchronize
-    mServiceEndpoint->unregisterStream(this);
-    mServiceEndpoint->close();
-    mServiceEndpoint = nullptr;
+    AAudioServiceEndpoint *endpoint = mServiceEndpoint;
+    if (endpoint != nullptr) {
+        endpoint->unregisterStream(this);
+
+        AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
+        mEndpointManager.closeEndpoint(endpoint);
+        mServiceEndpoint = nullptr;
+    }
     return AAudioServiceStreamBase::close();
 }
 
@@ -189,10 +223,15 @@
     mServiceEndpoint = nullptr;
 }
 
+void AAudioServiceStreamShared::markTransferTime(int64_t nanoseconds) {
+    mMarkedPosition = mAudioDataQueue->getFifoBuffer()->getReadCounter();
+    mMarkedTime = nanoseconds;
+}
 
 aaudio_result_t AAudioServiceStreamShared::getFreeRunningPosition(int64_t *positionFrames,
                                                                 int64_t *timeNanos) {
-    *positionFrames = mAudioDataQueue->getFifoBuffer()->getReadCounter();
-    *timeNanos = AudioClock::getNanoseconds();
+    // TODO get these two numbers as an atomic pair
+    *positionFrames = mMarkedPosition;
+    *timeNanos = mMarkedTime;
     return AAUDIO_OK;
 }
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index f6df7ce..b981387 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -66,6 +66,11 @@
     aaudio_result_t pause() override;
 
     /**
+     * Stop the flow of data after data in buffer has played.
+     */
+    aaudio_result_t stop() override;
+
+    /**
      *  Discard any data held by the underlying HAL or Service.
      *
      * This is not guaranteed to be synchronous but it currently is.
@@ -77,6 +82,11 @@
 
     android::FifoBuffer *getDataFifoBuffer() { return mAudioDataQueue->getFifoBuffer(); }
 
+    /* Keep a record of when a buffer transfer completed.
+     * This allows for a more accurate timing model.
+     */
+    void markTransferTime(int64_t nanoseconds);
+
     void onStop();
 
     void onDisconnect();
@@ -91,6 +101,9 @@
     android::AAudioService  &mAudioService;
     AAudioServiceEndpoint   *mServiceEndpoint = nullptr;
     SharedRingBuffer        *mAudioDataQueue;
+
+    int64_t                  mMarkedPosition = 0;
+    int64_t                  mMarkedTime = 0;
 };
 
 } /* namespace aaudio */