AAudioService: integrated with audioserver

Call the MmapStreamInterface from AudioFlinger instead of the FakeHAL.
Fix sending timestamps from the thread.
Add shared mode in service.

Bug: 35260844
Bug: 33398120
Test: CTS test_aaudio.cpp
Change-Id: I44c7e4ecae4ce205611b6b73a72e0ae8a5b243e5
Signed-off-by: Phil Burk <philburk@google.com>
(cherry picked from commit 7f6b40d78b1976c78d1300e8a51fda36eeb50c5d)
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
index 1ee73bf..b5bb75f 100644
--- a/media/libaaudio/src/Android.mk
+++ b/media/libaaudio/src/Android.mk
@@ -26,6 +26,7 @@
     $(LOCAL_PATH)/legacy \
     $(LOCAL_PATH)/utility
 
+# If you add a file here then also add it below in the SHARED target
 LOCAL_SRC_FILES = \
     core/AudioStream.cpp \
     core/AudioStreamBuilder.cpp \
@@ -43,13 +44,14 @@
     client/AudioEndpoint.cpp \
     client/AudioStreamInternal.cpp \
     client/IsochronousClockModel.cpp \
-    binding/SharedMemoryParcelable.cpp \
-    binding/SharedRegionParcelable.cpp \
-    binding/RingBufferParcelable.cpp \
     binding/AudioEndpointParcelable.cpp \
+    binding/AAudioBinderClient.cpp \
     binding/AAudioStreamRequest.cpp \
     binding/AAudioStreamConfiguration.cpp \
-    binding/IAAudioService.cpp
+    binding/IAAudioService.cpp \
+    binding/RingBufferParcelable.cpp \
+    binding/SharedMemoryParcelable.cpp \
+    binding/SharedRegionParcelable.cpp
 
 LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
 
@@ -96,13 +98,14 @@
     client/AudioEndpoint.cpp \
     client/AudioStreamInternal.cpp \
     client/IsochronousClockModel.cpp \
-    binding/SharedMemoryParcelable.cpp \
-    binding/SharedRegionParcelable.cpp \
-    binding/RingBufferParcelable.cpp \
     binding/AudioEndpointParcelable.cpp \
+    binding/AAudioBinderClient.cpp \
     binding/AAudioStreamRequest.cpp \
     binding/AAudioStreamConfiguration.cpp \
-    binding/IAAudioService.cpp
+    binding/IAAudioService.cpp \
+    binding/RingBufferParcelable.cpp \
+    binding/SharedMemoryParcelable.cpp \
+    binding/SharedRegionParcelable.cpp
 
 LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
 
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
new file mode 100644
index 0000000..8315c40
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <binder/IServiceManager.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+#include <aaudio/AAudio.h>
+
+#include "AudioEndpointParcelable.h"
+#include "binding/AAudioStreamRequest.h"
+#include "binding/AAudioStreamConfiguration.h"
+#include "binding/IAAudioService.h"
+#include "binding/AAudioServiceMessage.h"
+
+#include "AAudioBinderClient.h"
+#include "AAudioServiceInterface.h"
+
+using android::String16;
+using android::IServiceManager;
+using android::defaultServiceManager;
+using android::interface_cast;
+using android::IAAudioService;
+using android::Mutex;
+using android::sp;
+
+using namespace aaudio;
+
+static android::Mutex gServiceLock;
+static sp<IAAudioService>  gAAudioService;
+
+// TODO Share code with other service clients.
+// Helper function to get access to the "AAudioService" service.
+// This code was modeled after frameworks/av/media/libaudioclient/AudioSystem.cpp
+static const sp<IAAudioService> getAAudioService() {
+    sp<IBinder> binder;
+    Mutex::Autolock _l(gServiceLock);
+    if (gAAudioService == 0) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        // Try several times to get the service.
+        int retries = 4;
+        do {
+            binder = sm->getService(String16(AAUDIO_SERVICE_NAME)); // This will wait a while.
+            if (binder != 0) {
+                break;
+            }
+        } while (retries-- > 0);
+
+        if (binder != 0) {
+            // TODO Add linkToDeath() like in frameworks/av/media/libaudioclient/AudioSystem.cpp
+            // TODO Create a DeathRecipient that disconnects all active streams.
+            gAAudioService = interface_cast<IAAudioService>(binder);
+        } else {
+            ALOGE("AudioStreamInternal could not get %s", AAUDIO_SERVICE_NAME);
+        }
+    }
+    return gAAudioService;
+}
+
+
+AAudioBinderClient::AAudioBinderClient()
+        : AAudioServiceInterface() {}
+
+AAudioBinderClient::~AAudioBinderClient() {}
+
+/**
+* @param request info needed to create the stream
+* @param configuration contains information about the created stream
+* @return handle to the stream or a negative error
+*/
+aaudio_handle_t AAudioBinderClient::openStream(const AAudioStreamRequest &request,
+                                               AAudioStreamConfiguration &configurationOutput) {
+
+    const sp<IAAudioService> &service = getAAudioService();
+    if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+    return service->openStream(request, configurationOutput);
+}
+
+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);
+}
+
+/* Get an immutable description of the in-memory queues
+* used to communicate with the underlying HAL or Service.
+*/
+aaudio_result_t AAudioBinderClient::getStreamDescription(aaudio_handle_t streamHandle,
+                                                         AudioEndpointParcelable &parcelable) {
+
+    const sp<IAAudioService> &service = getAAudioService();
+    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);
+}
+
+/**
+*  Discard any data held by the underlying HAL or Service.
+*/
+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);
+}
+
+/**
+* Manage the specified thread as a low latency audio thread.
+*/
+aaudio_result_t AAudioBinderClient::registerAudioThread(aaudio_handle_t streamHandle,
+                                                        pid_t clientProcessId,
+                                                        pid_t clientThreadId,
+                                                        int64_t periodNanoseconds) {
+    const sp<IAAudioService> &service = getAAudioService();
+    if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+    return service->registerAudioThread(streamHandle,
+                                        clientProcessId,
+                                        clientThreadId,
+                                        periodNanoseconds);
+}
+
+aaudio_result_t AAudioBinderClient::unregisterAudioThread(aaudio_handle_t streamHandle,
+                                                          pid_t clientProcessId,
+                                                          pid_t clientThreadId) {
+    const sp<IAAudioService> &service = getAAudioService();
+    if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+    return service->unregisterAudioThread(streamHandle,
+                                          clientProcessId,
+                                          clientThreadId);
+}
+
+
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
new file mode 100644
index 0000000..5613d5b
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioBinderClient.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAUDIO_AAUDIO_BINDER_CLIENT_H
+#define AAUDIO_AAUDIO_BINDER_CLIENT_H
+
+#include <aaudio/AAudioDefinitions.h>
+#include "AAudioServiceDefinitions.h"
+#include "AAudioServiceInterface.h"
+#include "binding/AAudioStreamRequest.h"
+#include "binding/AAudioStreamConfiguration.h"
+#include "binding/AudioEndpointParcelable.h"
+
+/**
+ * Implements the AAudioServiceInterface by talking to the actual service through Binder.
+ */
+
+namespace aaudio {
+
+class AAudioBinderClient : public AAudioServiceInterface {
+
+public:
+
+    AAudioBinderClient();
+
+    virtual ~AAudioBinderClient();
+
+    /**
+     * @param request info needed to create the stream
+     * @param configuration contains resulting information about the created stream
+     * @return handle to the stream or a negative error
+     */
+    aaudio_handle_t openStream(const AAudioStreamRequest &request,
+                               AAudioStreamConfiguration &configurationOutput) override;
+
+    aaudio_result_t closeStream(aaudio_handle_t streamHandle) override;
+
+    /* Get an immutable description of the in-memory queues
+    * used to communicate with the underlying HAL or Service.
+    */
+    aaudio_result_t getStreamDescription(aaudio_handle_t streamHandle,
+                                                 AudioEndpointParcelable &parcelable) override;
+
+    /**
+     * Start the flow of data.
+     * This is asynchronous. When complete, the service will send a STARTED event.
+     */
+    aaudio_result_t startStream(aaudio_handle_t streamHandle) override;
+
+    /**
+     * Stop the flow of data such that start() can resume without loss of data.
+     * This is asynchronous. When complete, the service will send a PAUSED event.
+     */
+    aaudio_result_t pauseStream(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.
+     */
+    aaudio_result_t flushStream(aaudio_handle_t streamHandle) override;
+
+    /**
+     * Manage the specified thread as a low latency audio thread.
+     * TODO Consider passing this information as part of the startStream() call.
+     */
+    aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+                                                pid_t clientProcessId,
+                                                pid_t clientThreadId,
+                                                int64_t periodNanoseconds) override;
+
+    aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+                                                  pid_t clientProcessId,
+                                                  pid_t clientThreadId) override;
+};
+
+
+} /* namespace aaudio */
+
+#endif //AAUDIO_AAUDIO_BINDER_CLIENT_H
diff --git a/media/libaaudio/src/binding/AAudioServiceDefinitions.h b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
index b58d170..0d5bae5 100644
--- a/media/libaaudio/src/binding/AAudioServiceDefinitions.h
+++ b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
@@ -48,25 +48,6 @@
 
 #define AAUDIO_HANDLE_INVALID  ((aaudio_handle_t) -1)
 
-enum aaudio_commands_t {
-    OPEN_STREAM = IBinder::FIRST_CALL_TRANSACTION,
-    CLOSE_STREAM,
-    GET_STREAM_DESCRIPTION,
-    START_STREAM,
-    PAUSE_STREAM,
-    FLUSH_STREAM,
-    REGISTER_AUDIO_THREAD,
-    UNREGISTER_AUDIO_THREAD
-};
-
-// TODO Expand this to include all the open parameters.
-typedef struct AAudioServiceStreamInfo_s {
-    int32_t               deviceId;
-    int32_t               samplesPerFrame;  // number of channels
-    int32_t               sampleRate;
-    aaudio_audio_format_t audioFormat;
-} AAudioServiceStreamInfo;
-
 // This must be a fixed width so it can be in shared memory.
 enum RingbufferFlags : uint32_t {
     NONE = 0,
diff --git a/media/libaaudio/src/binding/AAudioServiceInterface.h b/media/libaaudio/src/binding/AAudioServiceInterface.h
new file mode 100644
index 0000000..62fd894
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioServiceInterface.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
+#define AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
+
+#include "binding/AAudioServiceDefinitions.h"
+#include "binding/AAudioStreamRequest.h"
+#include "binding/AAudioStreamConfiguration.h"
+#include "binding/AudioEndpointParcelable.h"
+
+/**
+ * This has the same methods as IAAudioService but without the Binder features.
+ *
+ * It allows us to abstract the Binder interface and use an AudioStreamInternal
+ * both in the client and in the service.
+ */
+namespace aaudio {
+
+class AAudioServiceInterface {
+public:
+
+    AAudioServiceInterface() {};
+    virtual ~AAudioServiceInterface() = default;
+
+    /**
+     * @param request info needed to create the stream
+     * @param configuration contains information about the created stream
+     * @return handle to the stream or a negative error
+     */
+    virtual aaudio_handle_t openStream(const AAudioStreamRequest &request,
+                                       AAudioStreamConfiguration &configuration) = 0;
+
+    virtual aaudio_result_t closeStream(aaudio_handle_t streamHandle) = 0;
+
+    /* Get an immutable description of the in-memory queues
+    * used to communicate with the underlying HAL or Service.
+    */
+    virtual aaudio_result_t getStreamDescription(aaudio_handle_t streamHandle,
+                                                 AudioEndpointParcelable &parcelable) = 0;
+
+    /**
+     * Start the flow of data.
+     */
+    virtual aaudio_result_t startStream(aaudio_handle_t streamHandle) = 0;
+
+    /**
+     * Stop the flow of data such that start() can resume without loss of data.
+     */
+    virtual aaudio_result_t pauseStream(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;
+
+    /**
+     * Manage the specified thread as a low latency audio thread.
+     */
+    virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+                                                pid_t clientProcessId,
+                                                pid_t clientThreadId,
+                                                int64_t periodNanoseconds) = 0;
+
+    virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+                                                  pid_t clientProcessId,
+                                                  pid_t clientThreadId) = 0;
+};
+
+} /* namespace aaudio */
+
+#endif //AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
diff --git a/media/libaaudio/src/binding/AAudioServiceMessage.h b/media/libaaudio/src/binding/AAudioServiceMessage.h
index cc77d59..b74b6c2 100644
--- a/media/libaaudio/src/binding/AAudioServiceMessage.h
+++ b/media/libaaudio/src/binding/AAudioServiceMessage.h
@@ -25,10 +25,11 @@
 
 // TODO move this to an "include" folder for the service.
 
+// Used to send information about the HAL to the client.
 struct AAudioMessageTimestamp {
-    int64_t    position;
-    int64_t    deviceOffset; // add to client position to get device position
-    int64_t    timestamp;
+    int64_t position;     // number of frames transferred so far
+    int64_t deviceOffset; // add to client position to get device position
+    int64_t timestamp;    // time when that position was reached
 };
 
 typedef enum aaudio_service_event_e : uint32_t {
@@ -36,13 +37,14 @@
     AAUDIO_SERVICE_EVENT_PAUSED,
     AAUDIO_SERVICE_EVENT_FLUSHED,
     AAUDIO_SERVICE_EVENT_CLOSED,
-    AAUDIO_SERVICE_EVENT_DISCONNECTED
+    AAUDIO_SERVICE_EVENT_DISCONNECTED,
+    AAUDIO_SERVICE_EVENT_VOLUME
 } aaudio_service_event_t;
 
 struct AAudioMessageEvent {
     aaudio_service_event_t event;
-    int32_t                data1;
-    int64_t                data2;
+    double                 dataDouble;
+    int64_t                dataLong;
 };
 
 typedef struct AAudioServiceMessage_s {
@@ -54,12 +56,11 @@
 
     code what;
     union {
-        AAudioMessageTimestamp timestamp;
-        AAudioMessageEvent event;
+        AAudioMessageTimestamp timestamp; // what == TIMESTAMP
+        AAudioMessageEvent event;         // what == EVENT
     };
 } AAudioServiceMessage;
 
-
 } /* namespace aaudio */
 
 #endif //AAUDIO_AAUDIO_SERVICE_MESSAGE_H
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index fe3a59f..ba41a3b 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -35,26 +35,50 @@
 AAudioStreamConfiguration::~AAudioStreamConfiguration() {}
 
 status_t AAudioStreamConfiguration::writeToParcel(Parcel* parcel) const {
-    parcel->writeInt32(mDeviceId);
-    parcel->writeInt32(mSampleRate);
-    parcel->writeInt32(mSamplesPerFrame);
-    parcel->writeInt32((int32_t) mAudioFormat);
-    parcel->writeInt32(mBufferCapacity);
-    return NO_ERROR; // TODO check for errors above
+    status_t status;
+    status = parcel->writeInt32(mDeviceId);
+    if (status != NO_ERROR) goto error;
+    status = parcel->writeInt32(mSampleRate);
+    if (status != NO_ERROR) goto error;
+    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;
+    status = parcel->writeInt32(mBufferCapacity);
+    if (status != NO_ERROR) goto error;
+    return NO_ERROR;
+error:
+    ALOGE("AAudioStreamConfiguration.writeToParcel(): write failed = %d", status);
+    return status;
 }
 
 status_t AAudioStreamConfiguration::readFromParcel(const Parcel* parcel) {
     int32_t temp;
-    parcel->readInt32(&mDeviceId);
-    parcel->readInt32(&mSampleRate);
-    parcel->readInt32(&mSamplesPerFrame);
-    parcel->readInt32(&temp);
+    status_t status = parcel->readInt32(&mDeviceId);
+    if (status != NO_ERROR) goto error;
+    status = parcel->readInt32(&mSampleRate);
+    if (status != NO_ERROR) goto error;
+    status = parcel->readInt32(&mSamplesPerFrame);
+    if (status != NO_ERROR) goto error;
+    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;
-    parcel->readInt32(&mBufferCapacity);
-    return NO_ERROR; // TODO check for errors above
+    status = parcel->readInt32(&mBufferCapacity);
+    if (status != NO_ERROR) goto error;
+    return NO_ERROR;
+error:
+    ALOGE("AAudioStreamConfiguration.readFromParcel(): read failed = %d", status);
+    return status;
 }
 
-aaudio_result_t AAudioStreamConfiguration::validate() {
+aaudio_result_t AAudioStreamConfiguration::validate() const {
     // Validate results of the open.
     if (mSampleRate < 0 || mSampleRate >= 8 * 48000) { // TODO review limits
         ALOGE("AAudioStreamConfiguration.validate(): invalid sampleRate = %d", mSampleRate);
@@ -84,9 +108,11 @@
     return AAUDIO_OK;
 }
 
-void AAudioStreamConfiguration::dump() {
-    ALOGD("AAudioStreamConfiguration mSampleRate      = %d -----", mSampleRate);
+void AAudioStreamConfiguration::dump() const {
+    ALOGD("AAudioStreamConfiguration mDeviceId        = %d", mDeviceId);
+    ALOGD("AAudioStreamConfiguration mSampleRate      = %d", mSampleRate);
     ALOGD("AAudioStreamConfiguration mSamplesPerFrame = %d", mSamplesPerFrame);
+    ALOGD("AAudioStreamConfiguration mSharingMode     = %d", (int)mSharingMode);
     ALOGD("AAudioStreamConfiguration mAudioFormat     = %d", (int)mAudioFormat);
     ALOGD("AAudioStreamConfiguration mBufferCapacity  = %d", mBufferCapacity);
 }
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.h b/media/libaaudio/src/binding/AAudioStreamConfiguration.h
index 57b1c59..b68d8b2 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.h
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.h
@@ -66,6 +66,14 @@
         mAudioFormat = audioFormat;
     }
 
+    aaudio_sharing_mode_t getSharingMode() const {
+        return mSharingMode;
+    }
+
+    void setSharingMode(aaudio_sharing_mode_t sharingMode) {
+        mSharingMode = sharingMode;
+    }
+
     int32_t getBufferCapacity() const {
         return mBufferCapacity;
     }
@@ -78,14 +86,15 @@
 
     virtual status_t readFromParcel(const Parcel* parcel) override;
 
-    aaudio_result_t validate();
+    aaudio_result_t validate() const;
 
-    void dump();
+    void dump() const;
 
-protected:
+private:
     int32_t               mDeviceId        = AAUDIO_DEVICE_UNSPECIFIED;
     int32_t               mSampleRate      = AAUDIO_UNSPECIFIED;
     int32_t               mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+    aaudio_sharing_mode_t mSharingMode     = AAUDIO_SHARING_MODE_SHARED;
     aaudio_audio_format_t mAudioFormat     = AAUDIO_FORMAT_UNSPECIFIED;
     int32_t               mBufferCapacity  = AAUDIO_UNSPECIFIED;
 };
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
index 5202b73..b8a0429 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
 #include <stdint.h>
 
 #include <sys/mman.h>
@@ -39,28 +43,48 @@
 AAudioStreamRequest::~AAudioStreamRequest() {}
 
 status_t AAudioStreamRequest::writeToParcel(Parcel* parcel) const {
-    parcel->writeInt32((int32_t) mUserId);
-    parcel->writeInt32((int32_t) mProcessId);
-    mConfiguration.writeToParcel(parcel);
-    return NO_ERROR; // TODO check for errors above
+    status_t status = parcel->writeInt32((int32_t) mUserId);
+    if (status != NO_ERROR) goto error;
+    status = parcel->writeInt32((int32_t) mProcessId);
+    if (status != NO_ERROR) goto error;
+    status = parcel->writeInt32((int32_t) mDirection);
+    if (status != NO_ERROR) goto error;
+    status = mConfiguration.writeToParcel(parcel);
+    if (status != NO_ERROR) goto error;
+    return NO_ERROR;
+
+error:
+    ALOGE("AAudioStreamRequest.writeToParcel(): write failed = %d", status);
+    return status;
 }
 
 status_t AAudioStreamRequest::readFromParcel(const Parcel* parcel) {
     int32_t temp;
-    parcel->readInt32(&temp);
+    status_t status = parcel->readInt32(&temp);
+    if (status != NO_ERROR) goto error;
     mUserId = (uid_t) temp;
-    parcel->readInt32(&temp);
+    status = parcel->readInt32(&temp);
+    if (status != NO_ERROR) goto error;
     mProcessId = (pid_t) temp;
-    mConfiguration.readFromParcel(parcel);
-    return NO_ERROR; // TODO check for errors above
+    status = parcel->readInt32(&temp);
+    if (status != NO_ERROR) goto error;
+    mDirection = (aaudio_direction_t) temp;
+    status = mConfiguration.readFromParcel(parcel);
+    if (status != NO_ERROR) goto error;
+    return NO_ERROR;
+
+error:
+    ALOGE("AAudioStreamRequest.readFromParcel(): read failed = %d", status);
+    return status;
 }
 
-aaudio_result_t AAudioStreamRequest::validate() {
+aaudio_result_t AAudioStreamRequest::validate() const {
     return mConfiguration.validate();
 }
 
-void AAudioStreamRequest::dump() {
-    ALOGD("AAudioStreamRequest mUserId = %d -----", mUserId);
+void AAudioStreamRequest::dump() const {
+    ALOGD("AAudioStreamRequest mUserId    = %d", mUserId);
     ALOGD("AAudioStreamRequest mProcessId = %d", mProcessId);
+    ALOGD("AAudioStreamRequest mDirection = %d", mDirection);
     mConfiguration.dump();
 }
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
index 0fd28ba..6546562 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.h
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.h
@@ -52,6 +52,18 @@
         mProcessId = processId;
     }
 
+    aaudio_direction_t getDirection() const {
+        return mDirection;
+    }
+
+    void setDirection(aaudio_direction_t direction) {
+        mDirection = direction;
+    }
+
+    const AAudioStreamConfiguration &getConstantConfiguration() const {
+        return mConfiguration;
+    }
+
     AAudioStreamConfiguration &getConfiguration() {
         return mConfiguration;
     }
@@ -60,14 +72,15 @@
 
     virtual status_t readFromParcel(const Parcel* parcel) override;
 
-    aaudio_result_t validate();
+    aaudio_result_t validate() const;
 
-    void dump();
+    void dump() const;
 
 protected:
     AAudioStreamConfiguration  mConfiguration;
-    uid_t    mUserId;
-    pid_t    mProcessId;
+    uid_t                      mUserId;
+    pid_t                      mProcessId;
+    aaudio_direction_t         mDirection;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
index f40ee02..ee92ee3 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
@@ -14,11 +14,15 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
 #include <stdint.h>
 
-#include <sys/mman.h>
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
+#include <utility/AAudioUtilities.h>
 
 #include "binding/AAudioServiceDefinitions.h"
 #include "binding/RingBufferParcelable.h"
@@ -82,13 +86,27 @@
 }
 
 aaudio_result_t AudioEndpointParcelable::resolve(EndpointDescriptor *descriptor) {
-    // TODO error check
-    mUpMessageQueueParcelable.resolve(mSharedMemories, &descriptor->upMessageQueueDescriptor);
-    mDownMessageQueueParcelable.resolve(mSharedMemories,
+    aaudio_result_t result = mUpMessageQueueParcelable.resolve(mSharedMemories,
+                                                           &descriptor->upMessageQueueDescriptor);
+    if (result != AAUDIO_OK) return result;
+    result = mDownMessageQueueParcelable.resolve(mSharedMemories,
                                         &descriptor->downMessageQueueDescriptor);
-    mUpDataQueueParcelable.resolve(mSharedMemories, &descriptor->upDataQueueDescriptor);
-    mDownDataQueueParcelable.resolve(mSharedMemories, &descriptor->downDataQueueDescriptor);
-    return AAUDIO_OK;
+    if (result != AAUDIO_OK) return result;
+
+    result = mUpDataQueueParcelable.resolve(mSharedMemories, &descriptor->upDataQueueDescriptor);
+    if (result != AAUDIO_OK) return result;
+    result = mDownDataQueueParcelable.resolve(mSharedMemories,
+                                              &descriptor->downDataQueueDescriptor);
+    return result;
+}
+
+aaudio_result_t AudioEndpointParcelable::close() {
+    int err = 0;
+    for (int i = 0; i < mNumSharedMemories; i++) {
+        int lastErr = mSharedMemories[i].close();
+        if (lastErr < 0) err = lastErr;
+    }
+    return AAudioConvert_androidToAAudioResult(err);
 }
 
 aaudio_result_t AudioEndpointParcelable::validate() {
@@ -100,6 +118,7 @@
     for (int i = 0; i < mNumSharedMemories; i++) {
         result = mSharedMemories[i].validate();
         if (result != AAUDIO_OK) {
+            ALOGE("AudioEndpointParcelable invalid mSharedMemories[%d] = %d", i, result);
             return result;
         }
     }
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.h b/media/libaaudio/src/binding/AudioEndpointParcelable.h
index d4646d0..4a1cb72 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.h
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.h
@@ -57,6 +57,8 @@
 
     aaudio_result_t validate();
 
+    aaudio_result_t close();
+
     void dump();
 
 public: // TODO add getters
diff --git a/media/libaaudio/src/binding/IAAudioService.cpp b/media/libaaudio/src/binding/IAAudioService.cpp
index c21033e..20cbbc8 100644
--- a/media/libaaudio/src/binding/IAAudioService.cpp
+++ b/media/libaaudio/src/binding/IAAudioService.cpp
@@ -40,11 +40,13 @@
     {
     }
 
-    virtual aaudio_handle_t openStream(aaudio::AAudioStreamRequest &request,
-                                     aaudio::AAudioStreamConfiguration &configuration) override {
+    virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+                                     aaudio::AAudioStreamConfiguration &configurationOutput) override {
         Parcel data, reply;
         // send command
         data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
+        ALOGE("BpAAudioService::client openStream request dump --------------------");
+        request.dump();
         request.writeToParcel(&data);
         status_t err = remote()->transact(OPEN_STREAM, data, &reply);
         if (err != NO_ERROR) {
@@ -53,7 +55,12 @@
         // parse reply
         aaudio_handle_t stream;
         reply.readInt32(&stream);
-        configuration.readFromParcel(&reply);
+        err = configurationOutput.readFromParcel(&reply);
+        if (err != NO_ERROR) {
+            ALOGE("BpAAudioService::client openStream readFromParcel failed %d", err);
+            closeStream(stream);
+            return AAudioConvert_androidToAAudioResult(err);
+        }
         return stream;
     }
 
@@ -80,16 +87,30 @@
         data.writeInt32(streamHandle);
         status_t err = remote()->transact(GET_STREAM_DESCRIPTION, data, &reply);
         if (err != NO_ERROR) {
+            ALOGE("BpAAudioService::client transact(GET_STREAM_DESCRIPTION) returns %d", err);
             return AAudioConvert_androidToAAudioResult(err);
         }
         // parse reply
-        parcelable.readFromParcel(&reply);
-        parcelable.dump();
-        aaudio_result_t result = parcelable.validate();
-        if (result != AAUDIO_OK) {
+        aaudio_result_t result;
+        err = reply.readInt32(&result);
+        if (err != NO_ERROR) {
+            ALOGE("BpAAudioService::client transact(GET_STREAM_DESCRIPTION) readInt %d", err);
+            return AAudioConvert_androidToAAudioResult(err);
+        } else if (result != AAUDIO_OK) {
+            ALOGE("BpAAudioService::client GET_STREAM_DESCRIPTION passed result %d", result);
             return result;
         }
-        reply.readInt32(&result);
+        err = parcelable.readFromParcel(&reply);;
+        if (err != NO_ERROR) {
+            ALOGE("BpAAudioService::client transact(GET_STREAM_DESCRIPTION) read endpoint %d", err);
+            return AAudioConvert_androidToAAudioResult(err);
+        }
+        //parcelable.dump();
+        result = parcelable.validate();
+        if (result != AAUDIO_OK) {
+            ALOGE("BpAAudioService::client GET_STREAM_DESCRIPTION validation fails %d", result);
+            return result;
+        }
         return result;
     }
 
@@ -139,13 +160,16 @@
         return res;
     }
 
-    virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle, pid_t clientThreadId,
+    virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+                                              pid_t clientProcessId,
+                                              pid_t clientThreadId,
                                               int64_t periodNanoseconds)
     override {
         Parcel data, reply;
         // send command
         data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
         data.writeInt32(streamHandle);
+        data.writeInt32((int32_t) clientProcessId);
         data.writeInt32((int32_t) clientThreadId);
         data.writeInt64(periodNanoseconds);
         status_t err = remote()->transact(REGISTER_AUDIO_THREAD, data, &reply);
@@ -158,12 +182,15 @@
         return res;
     }
 
-    virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle, pid_t clientThreadId)
+    virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+                                                  pid_t clientProcessId,
+                                                  pid_t clientThreadId)
     override {
         Parcel data, reply;
         // send command
         data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
         data.writeInt32(streamHandle);
+        data.writeInt32((int32_t) clientProcessId);
         data.writeInt32((int32_t) clientThreadId);
         status_t err = remote()->transact(UNREGISTER_AUDIO_THREAD, data, &reply);
         if (err != NO_ERROR) {
@@ -178,7 +205,7 @@
 };
 
 // Implement an interface to the service.
-// This is here so that you don't have to link with liboboe static library.
+// This is here so that you don't have to link with libaaudio static library.
 IMPLEMENT_META_INTERFACE(AAudioService, "IAAudioService");
 
 // The order of parameters in the Parcels must match with code in BpAAudioService
@@ -189,6 +216,7 @@
     aaudio::AAudioStreamRequest request;
     aaudio::AAudioStreamConfiguration configuration;
     pid_t pid;
+    pid_t tid;
     int64_t nanoseconds;
     aaudio_result_t result;
     ALOGV("BnAAudioService::onTransact(%i) %i", code, flags);
@@ -197,8 +225,12 @@
     switch(code) {
         case OPEN_STREAM: {
             request.readFromParcel(&data);
+
+            ALOGD("BnAAudioService::client openStream request dump --------------------");
+            request.dump();
+
             stream = openStream(request, configuration);
-            ALOGD("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X", stream);
+            ALOGV("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X", stream);
             reply->writeInt32(stream);
             configuration.writeToParcel(reply);
             return NO_ERROR;
@@ -206,7 +238,7 @@
 
         case CLOSE_STREAM: {
             data.readInt32(&stream);
-            ALOGD("BnAAudioService::onTransact CLOSE_STREAM 0x%08X", stream);
+            ALOGV("BnAAudioService::onTransact CLOSE_STREAM 0x%08X", stream);
             result = closeStream(stream);
             reply->writeInt32(result);
             return NO_ERROR;
@@ -214,26 +246,28 @@
 
         case GET_STREAM_DESCRIPTION: {
             data.readInt32(&stream);
-            ALOGD("BnAAudioService::onTransact GET_STREAM_DESCRIPTION 0x%08X", 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);
             }
-            parcelable.dump();
             result = parcelable.validate();
             if (result != AAUDIO_OK) {
+                ALOGE("BnAAudioService::onTransact getStreamDescription() returns %d", result);
+                parcelable.dump();
                 return AAudioConvert_aaudioToAndroidStatus(result);
             }
-            parcelable.writeToParcel(reply);
             reply->writeInt32(result);
+            parcelable.writeToParcel(reply);
             return NO_ERROR;
         } break;
 
         case START_STREAM: {
             data.readInt32(&stream);
             result = startStream(stream);
-            ALOGD("BnAAudioService::onTransact START_STREAM 0x%08X, result = %d",
+            ALOGV("BnAAudioService::onTransact START_STREAM 0x%08X, result = %d",
                     stream, result);
             reply->writeInt32(result);
             return NO_ERROR;
@@ -242,7 +276,7 @@
         case PAUSE_STREAM: {
             data.readInt32(&stream);
             result = pauseStream(stream);
-            ALOGD("BnAAudioService::onTransact PAUSE_STREAM 0x%08X, result = %d",
+            ALOGV("BnAAudioService::onTransact PAUSE_STREAM 0x%08X, result = %d",
                     stream, result);
             reply->writeInt32(result);
             return NO_ERROR;
@@ -251,7 +285,7 @@
         case FLUSH_STREAM: {
             data.readInt32(&stream);
             result = flushStream(stream);
-            ALOGD("BnAAudioService::onTransact FLUSH_STREAM 0x%08X, result = %d",
+            ALOGV("BnAAudioService::onTransact FLUSH_STREAM 0x%08X, result = %d",
                     stream, result);
             reply->writeInt32(result);
             return NO_ERROR;
@@ -260,9 +294,10 @@
         case REGISTER_AUDIO_THREAD: {
             data.readInt32(&stream);
             data.readInt32(&pid);
+            data.readInt32(&tid);
             data.readInt64(&nanoseconds);
-            result = registerAudioThread(stream, pid, nanoseconds);
-            ALOGD("BnAAudioService::onTransact REGISTER_AUDIO_THREAD 0x%08X, result = %d",
+            result = registerAudioThread(stream, pid, tid, nanoseconds);
+            ALOGV("BnAAudioService::onTransact REGISTER_AUDIO_THREAD 0x%08X, result = %d",
                     stream, result);
             reply->writeInt32(result);
             return NO_ERROR;
@@ -271,8 +306,9 @@
         case UNREGISTER_AUDIO_THREAD: {
             data.readInt32(&stream);
             data.readInt32(&pid);
-            result = unregisterAudioThread(stream, pid);
-            ALOGD("BnAAudioService::onTransact UNREGISTER_AUDIO_THREAD 0x%08X, result = %d",
+            data.readInt32(&tid);
+            result = unregisterAudioThread(stream, pid, tid);
+            ALOGV("BnAAudioService::onTransact UNREGISTER_AUDIO_THREAD 0x%08X, result = %d",
                     stream, result);
             reply->writeInt32(result);
             return NO_ERROR;
diff --git a/media/libaaudio/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h
index 53c3b45..ab7fd1b 100644
--- a/media/libaaudio/src/binding/IAAudioService.h
+++ b/media/libaaudio/src/binding/IAAudioService.h
@@ -28,9 +28,12 @@
 #include "binding/AudioEndpointParcelable.h"
 #include "binding/AAudioStreamRequest.h"
 #include "binding/AAudioStreamConfiguration.h"
+#include "utility/HandleTracker.h"
 
 namespace android {
 
+#define AAUDIO_SERVICE_NAME  "media.aaudio"
+
 // Interface (our AIDL) - Shared by server and client
 class IAAudioService : public IInterface {
 public:
@@ -42,8 +45,8 @@
      * @param configuration contains information about the created stream
      * @return handle to the stream or a negative error
      */
-    virtual aaudio::aaudio_handle_t openStream(aaudio::AAudioStreamRequest &request,
-                                     aaudio::AAudioStreamConfiguration &configuration) = 0;
+    virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+                                     aaudio::AAudioStreamConfiguration &configurationOutput) = 0;
 
     virtual aaudio_result_t closeStream(aaudio::aaudio_handle_t streamHandle) = 0;
 
@@ -55,26 +58,33 @@
 
     /**
      * Start the flow of data.
+     * This is asynchronous. When complete, the service will send a STARTED event.
      */
     virtual aaudio_result_t startStream(aaudio::aaudio_handle_t streamHandle) = 0;
 
     /**
      * Stop the flow of data such that start() can resume without loss of data.
+     * This is asynchronous. When complete, the service will send a PAUSED event.
      */
     virtual aaudio_result_t pauseStream(aaudio::aaudio_handle_t streamHandle) = 0;
 
     /**
      *  Discard any data held by the underlying HAL or Service.
+     * This is asynchronous. When complete, the service will send a FLUSHED event.
      */
     virtual aaudio_result_t flushStream(aaudio::aaudio_handle_t streamHandle) = 0;
 
     /**
      * Manage the specified thread as a low latency audio thread.
+     * TODO Consider passing this information as part of the startStream() call.
      */
-    virtual aaudio_result_t registerAudioThread(aaudio::aaudio_handle_t streamHandle, pid_t clientThreadId,
+    virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+                                              pid_t clientProcessId,
+                                              pid_t clientThreadId,
                                               int64_t periodNanoseconds) = 0;
 
-    virtual aaudio_result_t unregisterAudioThread(aaudio::aaudio_handle_t streamHandle,
+    virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+                                                pid_t clientProcessId,
                                                 pid_t clientThreadId) = 0;
 };
 
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.cpp b/media/libaaudio/src/binding/RingBufferParcelable.cpp
index 3a92929..05451f9 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.cpp
+++ b/media/libaaudio/src/binding/RingBufferParcelable.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
 #include <stdint.h>
 
 #include <binder/Parcelable.h>
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.h b/media/libaaudio/src/binding/RingBufferParcelable.h
index 3f82c79..5fc5d00 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.h
+++ b/media/libaaudio/src/binding/RingBufferParcelable.h
@@ -55,6 +55,8 @@
 
     void setCapacityInFrames(int32_t capacityInFrames);
 
+    bool isFileDescriptorSafe(SharedMemoryParcelable *memoryParcels);
+
     /**
      * The read and write must be symmetric.
      */
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index 1102dec..cfb820f 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -14,12 +14,18 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
 #include <stdint.h>
+#include <stdio.h>
 
 #include <sys/mman.h>
 #include <aaudio/AAudioDefinitions.h>
 
 #include <binder/Parcelable.h>
+#include <utility/AAudioUtilities.h>
 
 #include "binding/SharedMemoryParcelable.h"
 
@@ -36,28 +42,55 @@
 void SharedMemoryParcelable::setup(int fd, int32_t sizeInBytes) {
     mFd = fd;
     mSizeInBytes = sizeInBytes;
+
 }
 
 status_t SharedMemoryParcelable::writeToParcel(Parcel* parcel) const {
-    parcel->writeInt32(mSizeInBytes);
+    status_t status = parcel->writeInt32(mSizeInBytes);
+    if (status != NO_ERROR) return status;
     if (mSizeInBytes > 0) {
-        parcel->writeDupFileDescriptor(mFd);
+        status = parcel->writeDupFileDescriptor(mFd);
+        ALOGE_IF(status != NO_ERROR, "SharedMemoryParcelable writeDupFileDescriptor failed : %d", status);
     }
-    return NO_ERROR; // TODO check for errors above
+    return status;
 }
 
 status_t SharedMemoryParcelable::readFromParcel(const Parcel* parcel) {
-    parcel->readInt32(&mSizeInBytes);
-    if (mSizeInBytes > 0) {
-        mFd = dup(parcel->readFileDescriptor());
+    status_t status = parcel->readInt32(&mSizeInBytes);
+    if (status != NO_ERROR) {
+        return status;
     }
-    return NO_ERROR; // TODO check for errors above
+    if (mSizeInBytes > 0) {
+// FIXME        mFd = dup(parcel->readFileDescriptor());
+        // Why is the ALSA resource not getting freed?!
+        mFd = fcntl(parcel->readFileDescriptor(), F_DUPFD_CLOEXEC, 0);
+        if (mFd == -1) {
+            status = -errno;
+            ALOGE("SharedMemoryParcelable readFileDescriptor fcntl() failed : %d", status);
+        }
+    }
+    return status;
 }
 
-// TODO Add code to unmmap()
+aaudio_result_t SharedMemoryParcelable::close() {
+    if (mResolvedAddress != nullptr) {
+        int err = munmap(mResolvedAddress, mSizeInBytes);
+        if (err < 0) {
+            ALOGE("SharedMemoryParcelable::close() munmap() failed %d", err);
+            return AAudioConvert_androidToAAudioResult(err);
+        }
+        mResolvedAddress = nullptr;
+    }
+    if (mFd != -1) {
+        ::close(mFd);
+        mFd = -1;
+    }
+    return AAUDIO_OK;
+}
 
 aaudio_result_t SharedMemoryParcelable::resolve(int32_t offsetInBytes, int32_t sizeInBytes,
                                               void **regionAddressPtr) {
+
     if (offsetInBytes < 0) {
         ALOGE("SharedMemoryParcelable illegal offsetInBytes = %d", offsetInBytes);
         return AAUDIO_ERROR_OUT_OF_RANGE;
@@ -68,6 +101,11 @@
         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) {
@@ -76,8 +114,8 @@
         }
     }
     *regionAddressPtr = mResolvedAddress + offsetInBytes;
-    ALOGD("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
-    ALOGD("SharedMemoryParcelable offset by %d, *regionAddressPtr = %p",
+    ALOGV("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
+    ALOGV("SharedMemoryParcelable offset by %d, *regionAddressPtr = %p",
           offsetInBytes, *regionAddressPtr);
     return AAUDIO_OK;
 }
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.h b/media/libaaudio/src/binding/SharedMemoryParcelable.h
index 7e0bf1a..22e16f0 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.h
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.h
@@ -49,8 +49,14 @@
 
     virtual status_t readFromParcel(const Parcel* parcel) override;
 
+    // mmap() shared memory
     aaudio_result_t resolve(int32_t offsetInBytes, int32_t sizeInBytes, void **regionAddressPtr);
 
+    // munmap() any mapped memory
+    aaudio_result_t close();
+
+    bool isFileDescriptorSafe();
+
     int32_t getSizeInBytes();
 
     aaudio_result_t validate();
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.cpp b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
index 8ca0023..8e57832 100644
--- a/media/libaaudio/src/binding/SharedRegionParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
 #include <stdint.h>
 
 #include <sys/mman.h>
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.h b/media/libaaudio/src/binding/SharedRegionParcelable.h
index d6c2281..5fb2a4c 100644
--- a/media/libaaudio/src/binding/SharedRegionParcelable.h
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.h
@@ -45,6 +45,8 @@
 
     aaudio_result_t resolve(SharedMemoryParcelable *memoryParcels, void **regionAddressPtr);
 
+    bool isFileDescriptorSafe(SharedMemoryParcelable *memoryParcels);
+
     aaudio_result_t validate();
 
     void dump();
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index 90c619c..fe049b2 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -39,11 +39,26 @@
 {
 }
 
-static void AudioEndpoint_validateQueueDescriptor(const char *type,
+static aaudio_result_t AudioEndpoint_validateQueueDescriptor(const char *type,
                                                   const RingBufferDescriptor *descriptor) {
-    assert(descriptor->capacityInFrames > 0);
-    assert(descriptor->bytesPerFrame > 1);
-    assert(descriptor->dataAddress != nullptr);
+    if (descriptor == nullptr) {
+        ALOGE("AudioEndpoint_validateQueueDescriptor() NULL descriptor");
+        return AAUDIO_ERROR_NULL;
+    }
+    if (descriptor->capacityInFrames <= 0) {
+        ALOGE("AudioEndpoint_validateQueueDescriptor() bad capacityInFrames = %d",
+              descriptor->capacityInFrames);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+    if (descriptor->bytesPerFrame <= 1) {
+        ALOGE("AudioEndpoint_validateQueueDescriptor() bad bytesPerFrame = %d",
+              descriptor->bytesPerFrame);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+    if (descriptor->dataAddress == nullptr) {
+        ALOGE("AudioEndpoint_validateQueueDescriptor() NULL dataAddress");
+        return AAUDIO_ERROR_NULL;
+    }
     ALOGD("AudioEndpoint_validateQueueDescriptor %s, dataAddress at %p ====================",
           type,
           descriptor->dataAddress);
@@ -52,11 +67,12 @@
           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",
         (int) value);
     // Try to WRITE to the data area.
-    descriptor->dataAddress[0] = value;
+    descriptor->dataAddress[0] = value * 3;
     ALOGD("AudioEndpoint_validateQueueDescriptor() wrote successfully");
 
     if (descriptor->readCounterAddress) {
@@ -73,17 +89,28 @@
         *descriptor->writeCounterAddress = counter;
         ALOGD("AudioEndpoint_validateQueueDescriptor() wrote writeCounterAddress successfully");
     }
+    return AAUDIO_OK;
 }
 
-void AudioEndpoint_validateDescriptor(const EndpointDescriptor *pEndpointDescriptor) {
-    AudioEndpoint_validateQueueDescriptor("msg", &pEndpointDescriptor->upMessageQueueDescriptor);
-    AudioEndpoint_validateQueueDescriptor("data", &pEndpointDescriptor->downDataQueueDescriptor);
+aaudio_result_t AudioEndpoint_validateDescriptor(const EndpointDescriptor *pEndpointDescriptor) {
+    aaudio_result_t result = AudioEndpoint_validateQueueDescriptor("messages",
+                                    &pEndpointDescriptor->upMessageQueueDescriptor);
+    if (result == AAUDIO_OK) {
+        result = AudioEndpoint_validateQueueDescriptor("data",
+                                                &pEndpointDescriptor->downDataQueueDescriptor);
+    }
+    return result;
 }
 
 aaudio_result_t AudioEndpoint::configure(const EndpointDescriptor *pEndpointDescriptor)
 {
-    aaudio_result_t result = AAUDIO_OK;
-    AudioEndpoint_validateDescriptor(pEndpointDescriptor); // FIXME remove after debugging
+    // TODO maybe remove after debugging
+    aaudio_result_t result = AudioEndpoint_validateDescriptor(pEndpointDescriptor);
+    if (result != AAUDIO_OK) {
+        ALOGD("AudioEndpoint_validateQueueDescriptor returned %d %s",
+              result, AAudio_convertResultToText(result));
+        return result;
+    }
 
     const RingBufferDescriptor *descriptor = &pEndpointDescriptor->upMessageQueueDescriptor;
     assert(descriptor->bytesPerFrame == sizeof(AAudioServiceMessage));
@@ -125,6 +152,7 @@
     int64_t *writeCounterAddress = (descriptor->writeCounterAddress == nullptr)
                                   ? &mDataWriteCounter
                                   : descriptor->writeCounterAddress;
+
     mDownDataQueue = new FifoBuffer(
             descriptor->bytesPerFrame,
             descriptor->capacityInFrames,
@@ -144,9 +172,19 @@
 
 aaudio_result_t AudioEndpoint::writeDataNow(const void *buffer, int32_t numFrames)
 {
+    // TODO Make it easier for the AAudioStreamInternal to scale floats and write shorts
+    // TODO Similar to block adapter write through technique. Add a DataConverter.
     return mDownDataQueue->write(buffer, numFrames);
 }
 
+void AudioEndpoint::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) {
+    mDownDataQueue->getEmptyRoomAvailable(wrappingBuffer);
+}
+
+void AudioEndpoint::advanceWriteIndex(int32_t deltaFrames) {
+    mDownDataQueue->getFifoControllerBase()->advanceWriteIndex(deltaFrames);
+}
+
 void AudioEndpoint::setDownDataReadCounter(fifo_counter_t framesRead)
 {
     mDownDataQueue->setReadCounter(framesRead);
diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
index caee488..a24a705 100644
--- a/media/libaaudio/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -19,13 +19,13 @@
 
 #include <aaudio/AAudio.h>
 
-#include "AAudioServiceMessage.h"
-#include "AudioEndpointParcelable.h"
+#include "binding/AAudioServiceMessage.h"
+#include "binding/AudioEndpointParcelable.h"
 #include "fifo/FifoBuffer.h"
 
 namespace aaudio {
 
-#define ENDPOINT_DATA_QUEUE_SIZE_MIN   64
+#define ENDPOINT_DATA_QUEUE_SIZE_MIN   48
 
 /**
  * A sink for audio.
@@ -54,15 +54,19 @@
      */
     aaudio_result_t writeDataNow(const void *buffer, int32_t numFrames);
 
+    void getEmptyRoomAvailable(android::WrappingBuffer *wrappingBuffer);
+
+    void advanceWriteIndex(int32_t deltaFrames);
+
     /**
      * Set the read index in the downData queue.
      * This is needed if the reader is not updating the index itself.
      */
-    void setDownDataReadCounter(fifo_counter_t framesRead);
-    fifo_counter_t getDownDataReadCounter();
+    void setDownDataReadCounter(android::fifo_counter_t framesRead);
+    android::fifo_counter_t getDownDataReadCounter();
 
-    void setDownDataWriteCounter(fifo_counter_t framesWritten);
-    fifo_counter_t getDownDataWriteCounter();
+    void setDownDataWriteCounter(android::fifo_counter_t framesWritten);
+    android::fifo_counter_t getDownDataWriteCounter();
 
     /**
      * The result is not valid until after configure() is called.
@@ -80,11 +84,11 @@
     int32_t getFullFramesAvailable();
 
 private:
-    FifoBuffer   * mUpCommandQueue;
-    FifoBuffer   * mDownDataQueue;
-    bool           mOutputFreeRunning;
-    fifo_counter_t mDataReadCounter; // only used if free-running
-    fifo_counter_t mDataWriteCounter; // only used if free-running
+    android::FifoBuffer    *mUpCommandQueue;
+    android::FifoBuffer    *mDownDataQueue;
+    bool                    mOutputFreeRunning;
+    android::fifo_counter_t mDataReadCounter; // only used if free-running
+    android::fifo_counter_t mDataWriteCounter; // only used if free-running
 };
 
 } // namespace aaudio
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 1f9ce4f..3934a6d 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -18,19 +18,24 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <stdint.h>
 #include <assert.h>
 
 #include <binder/IServiceManager.h>
-#include <utils/Mutex.h>
 
 #include <aaudio/AAudio.h>
 #include <utils/String16.h>
 
-#include "utility/AudioClock.h"
-#include "AudioStreamInternal.h"
+#include "AudioClock.h"
+#include "AudioEndpointParcelable.h"
+#include "binding/AAudioStreamRequest.h"
+#include "binding/AAudioStreamConfiguration.h"
+#include "binding/IAAudioService.h"
 #include "binding/AAudioServiceMessage.h"
+#include "fifo/FifoBuffer.h"
 
 #include "core/AudioStreamBuilder.h"
+#include "AudioStreamInternal.h"
 
 #define LOG_TIMESTAMPS   0
 
@@ -39,52 +44,25 @@
 using android::defaultServiceManager;
 using android::interface_cast;
 using android::Mutex;
+using android::WrappingBuffer;
 
 using namespace aaudio;
 
-static android::Mutex gServiceLock;
-static sp<IAAudioService>  gAAudioService;
-
-#define AAUDIO_SERVICE_NAME   "AAudioService"
-
 #define MIN_TIMEOUT_NANOS        (1000 * AAUDIO_NANOS_PER_MILLISECOND)
 
 // Wait at least this many times longer than the operation should take.
 #define MIN_TIMEOUT_OPERATIONS    4
 
-// Helper function to get access to the "AAudioService" service.
-// This code was modeled after frameworks/av/media/libaudioclient/AudioSystem.cpp
-static const sp<IAAudioService> getAAudioService() {
-    sp<IBinder> binder;
-    Mutex::Autolock _l(gServiceLock);
-    if (gAAudioService == 0) {
-        sp<IServiceManager> sm = defaultServiceManager();
-        // Try several times to get the service.
-        int retries = 4;
-        do {
-            binder = sm->getService(String16(AAUDIO_SERVICE_NAME)); // This will wait a while.
-            if (binder != 0) {
-                break;
-            }
-        } while (retries-- > 0);
+#define ALOG_CONDITION   (mInService == false)
 
-        if (binder != 0) {
-            // TODO Add linkToDeath() like in frameworks/av/media/libaudioclient/AudioSystem.cpp
-            // TODO Create a DeathRecipient that disconnects all active streams.
-            gAAudioService = interface_cast<IAAudioService>(binder);
-        } else {
-            ALOGE("AudioStreamInternal could not get %s", AAUDIO_SERVICE_NAME);
-        }
-    }
-    return gAAudioService;
-}
-
-AudioStreamInternal::AudioStreamInternal()
+AudioStreamInternal::AudioStreamInternal(AAudioServiceInterface  &serviceInterface, bool inService)
         : AudioStream()
         , mClockModel()
         , mAudioEndpoint()
         , mServiceStreamHandle(AAUDIO_HANDLE_INVALID)
         , mFramesPerBurst(16)
+        , mServiceInterface(serviceInterface)
+        , mInService(inService)
 {
 }
 
@@ -93,9 +71,6 @@
 
 aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) {
 
-    const sp<IAAudioService>& service = getAAudioService();
-    if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
-
     aaudio_result_t result = AAUDIO_OK;
     AAudioStreamRequest request;
     AAudioStreamConfiguration configuration;
@@ -105,22 +80,31 @@
         return result;
     }
 
+    // We have to do volume scaling. So we prefer FLOAT format.
+    if (getFormat() == AAUDIO_UNSPECIFIED) {
+        setFormat(AAUDIO_FORMAT_PCM_FLOAT);
+    }
+
     // Build the request to send to the server.
     request.setUserId(getuid());
     request.setProcessId(getpid());
+    request.setDirection(getDirection());
+
     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().setBufferCapacity(builder.getBufferCapacity());
-    request.dump();
 
-    mServiceStreamHandle = service->openStream(request, configuration);
-    ALOGD("AudioStreamInternal.open(): openStream returned mServiceStreamHandle = 0x%08X",
+    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(): acquireRealtimeStream aaudio_result_t = 0x%08X", result);
+        ALOGE("AudioStreamInternal.open(): openStream() returned %d", result);
     } else {
         result = configuration.validate();
         if (result != AAUDIO_OK) {
@@ -130,17 +114,27 @@
         // Save results of the open.
         setSampleRate(configuration.getSampleRate());
         setSamplesPerFrame(configuration.getSamplesPerFrame());
-        setFormat(configuration.getAudioFormat());
+        setDeviceId(configuration.getDeviceId());
 
-        aaudio::AudioEndpointParcelable parcelable;
-        result = service->getStreamDescription(mServiceStreamHandle, parcelable);
+        // Save device format so we can do format conversion and volume scaling together.
+        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);
-            service->closeStream(mServiceStreamHandle);
+            mServiceInterface.closeStream(mServiceStreamHandle);
             return result;
         }
+
         // resolve parcelable into a descriptor
-        parcelable.resolve(&mEndpointDescriptor);
+        result = mEndPointParcelable.resolve(&mEndpointDescriptor);
+        if (result != AAUDIO_OK) {
+            ALOGE("AudioStreamInternal.open(): resolve() returns %d", result);
+            mServiceInterface.closeStream(mServiceStreamHandle);
+            return result;
+        }
 
         // Configure endpoint based on descriptor.
         mAudioEndpoint.configure(&mEndpointDescriptor);
@@ -156,12 +150,12 @@
             mCallbackFrames = builder.getFramesPerDataCallback();
             if (mCallbackFrames > getBufferCapacity() / 2) {
                 ALOGE("AudioStreamInternal.open(): framesPerCallback too large");
-                service->closeStream(mServiceStreamHandle);
+                mServiceInterface.closeStream(mServiceStreamHandle);
                 return AAUDIO_ERROR_OUT_OF_RANGE;
 
             } else if (mCallbackFrames < 0) {
                 ALOGE("AudioStreamInternal.open(): framesPerCallback negative");
-                service->closeStream(mServiceStreamHandle);
+                mServiceInterface.closeStream(mServiceStreamHandle);
                 return AAUDIO_ERROR_OUT_OF_RANGE;
 
             }
@@ -181,20 +175,20 @@
 }
 
 aaudio_result_t AudioStreamInternal::close() {
-    ALOGD("AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X", mServiceStreamHandle);
+    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X", mServiceStreamHandle);
     if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
         aaudio_handle_t serviceStreamHandle = mServiceStreamHandle;
         mServiceStreamHandle = AAUDIO_HANDLE_INVALID;
-        const sp<IAAudioService>& aaudioService = getAAudioService();
-        if (aaudioService == 0) return AAUDIO_ERROR_NO_SERVICE;
-        aaudioService->closeStream(serviceStreamHandle);
+
+        mServiceInterface.closeStream(serviceStreamHandle);
         delete[] mCallbackBuffer;
-        return AAUDIO_OK;
+        return mEndPointParcelable.close();
     } else {
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
 }
 
+
 // Render audio in the application callback and then write the data to the stream.
 void *AudioStreamInternal::callbackLoop() {
     aaudio_result_t result = AAUDIO_OK;
@@ -254,19 +248,16 @@
 aaudio_result_t AudioStreamInternal::requestStart()
 {
     int64_t startTime;
-    ALOGD("AudioStreamInternal(): start()");
+    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): start()");
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
-    const sp<IAAudioService>& aaudioService = getAAudioService();
-    if (aaudioService == 0) {
-        return AAUDIO_ERROR_NO_SERVICE;
-    }
+
     startTime = AudioClock::getNanoseconds();
     mClockModel.start(startTime);
     processTimestamp(0, startTime);
     setState(AAUDIO_STREAM_STATE_STARTING);
-    aaudio_result_t result = aaudioService->startStream(mServiceStreamHandle);
+    aaudio_result_t result = mServiceInterface.startStream(mServiceStreamHandle);;
 
     if (result == AAUDIO_OK && getDataCallbackProc() != nullptr) {
         // Launch the callback loop thread.
@@ -306,13 +297,10 @@
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
-    const sp<IAAudioService>& aaudioService = getAAudioService();
-    if (aaudioService == 0) {
-        return AAUDIO_ERROR_NO_SERVICE;
-    }
+
     mClockModel.stop(AudioClock::getNanoseconds());
     setState(AAUDIO_STREAM_STATE_PAUSING);
-    return aaudioService->pauseStream(mServiceStreamHandle);
+    return mServiceInterface.startStream(mServiceStreamHandle);
 }
 
 aaudio_result_t AudioStreamInternal::requestPause()
@@ -325,20 +313,17 @@
 }
 
 aaudio_result_t AudioStreamInternal::requestFlush() {
-    ALOGD("AudioStreamInternal(): flush()");
+    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): flush()");
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
-    const sp<IAAudioService>& aaudioService = getAAudioService();
-    if (aaudioService == 0) {
-        return AAUDIO_ERROR_NO_SERVICE;
-    }
+
     setState(AAUDIO_STREAM_STATE_FLUSHING);
-    return aaudioService->flushStream(mServiceStreamHandle);
+    return mServiceInterface.flushStream(mServiceStreamHandle);
 }
 
 void AudioStreamInternal::onFlushFromServer() {
-    ALOGD("AudioStreamInternal(): onFlushFromServer()");
+    ALOGD_IF(ALOG_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().
@@ -366,25 +351,22 @@
 }
 
 aaudio_result_t AudioStreamInternal::registerThread() {
-    ALOGD("AudioStreamInternal(): registerThread()");
+    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): registerThread()");
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
-    const sp<IAAudioService>& aaudioService = getAAudioService();
-    if (aaudioService == 0) return AAUDIO_ERROR_NO_SERVICE;
-    return aaudioService->registerAudioThread(mServiceStreamHandle,
-                                         gettid(),
-                                         getPeriodNanoseconds());
+    return mServiceInterface.registerAudioThread(mServiceStreamHandle,
+                                              getpid(),
+                                              gettid(),
+                                              getPeriodNanoseconds());
 }
 
 aaudio_result_t AudioStreamInternal::unregisterThread() {
-    ALOGD("AudioStreamInternal(): unregisterThread()");
+    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): unregisterThread()");
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
-    const sp<IAAudioService>& aaudioService = getAAudioService();
-    if (aaudioService == 0) return AAUDIO_ERROR_NO_SERVICE;
-    return aaudioService->unregisterAudioThread(mServiceStreamHandle, gettid());
+    return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, getpid(), gettid());
 }
 
 aaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId,
@@ -410,16 +392,16 @@
     static int64_t oldTime = 0;
     int64_t framePosition = command.timestamp.position;
     int64_t nanoTime = command.timestamp.timestamp;
-    ALOGD("AudioStreamInternal() timestamp says framePosition = %08lld at nanoTime %llu",
+    ALOGD_IF(ALOG_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("AudioStreamInternal() - framesDelta = %08lld", (long long) framesDelta);
-        ALOGD("AudioStreamInternal() - nanosDelta = %08lld", (long long) nanosDelta);
-        ALOGD("AudioStreamInternal() - measured rate = %llu", (unsigned long long) rate);
+        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);
     }
     oldPosition = framePosition;
     oldTime = nanoTime;
@@ -438,29 +420,34 @@
 
 aaudio_result_t AudioStreamInternal::onEventFromServer(AAudioServiceMessage *message) {
     aaudio_result_t result = AAUDIO_OK;
-    ALOGD("processCommands() got event %d", message->event.event);
+    ALOGD_IF(ALOG_CONDITION, "processCommands() got event %d", message->event.event);
     switch (message->event.event) {
         case AAUDIO_SERVICE_EVENT_STARTED:
-            ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_STARTED");
+            ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_STARTED");
             setState(AAUDIO_STREAM_STATE_STARTED);
             break;
         case AAUDIO_SERVICE_EVENT_PAUSED:
-            ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_PAUSED");
+            ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_PAUSED");
             setState(AAUDIO_STREAM_STATE_PAUSED);
             break;
         case AAUDIO_SERVICE_EVENT_FLUSHED:
-            ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_FLUSHED");
+            ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_FLUSHED");
             setState(AAUDIO_STREAM_STATE_FLUSHED);
             onFlushFromServer();
             break;
         case AAUDIO_SERVICE_EVENT_CLOSED:
-            ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_CLOSED");
+            ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_CLOSED");
             setState(AAUDIO_STREAM_STATE_CLOSED);
             break;
         case AAUDIO_SERVICE_EVENT_DISCONNECTED:
             result = AAUDIO_ERROR_DISCONNECTED;
+            setState(AAUDIO_STREAM_STATE_DISCONNECTED);
             ALOGW("WARNING - processCommands() AAUDIO_SERVICE_EVENT_DISCONNECTED");
             break;
+        case AAUDIO_SERVICE_EVENT_VOLUME:
+            mVolume = message->event.dataDouble;
+            ALOGD_IF(ALOG_CONDITION, "processCommands() AAUDIO_SERVICE_EVENT_VOLUME %f", mVolume);
+            break;
         default:
             ALOGW("WARNING - processCommands() Unrecognized event = %d",
                  (int) message->event.event);
@@ -474,6 +461,7 @@
     aaudio_result_t result = AAUDIO_OK;
 
     while (result == AAUDIO_OK) {
+        //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::processCommands() - looping, %d", result);
         AAudioServiceMessage message;
         if (mAudioEndpoint.readUpCommand(&message) != 1) {
             break; // no command this time, no problem
@@ -502,21 +490,26 @@
                                          int64_t timeoutNanoseconds)
 {
     aaudio_result_t result = AAUDIO_OK;
+    int32_t loopCount = 0;
     uint8_t* source = (uint8_t*)buffer;
     int64_t currentTimeNanos = AudioClock::getNanoseconds();
     int64_t deadlineNanos = currentTimeNanos + timeoutNanoseconds;
     int32_t framesLeft = numFrames;
-//    ALOGD("AudioStreamInternal::write(%p, %d) at time %08llu , mState = %d ------------------",
-//         buffer, numFrames, (unsigned long long) currentTimeNanos, mState);
+    //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("AudioStreamInternal::write() writeNow() framesLeft = %d --> framesWritten = %d", framesLeft, framesWritten);
+        //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::write() loop: framesWritten = %d", framesWritten);
         if (framesWritten < 0) {
+            ALOGE("AudioStreamInternal::write() loop: writeNow returned %d", framesWritten);
             result = framesWritten;
             break;
         }
@@ -527,18 +520,19 @@
         if (timeoutNanoseconds == 0) {
             break; // don't block
         } else if (framesLeft > 0) {
-            //ALOGD("AudioStreamInternal:: original wakeTimeNanos %lld", (long long) wakeTimeNanos);
+            //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal:: original wakeTimeNanos %lld", (long long) wakeTimeNanos);
             // clip the wake time to something reasonable
             if (wakeTimeNanos < currentTimeNanos) {
                 wakeTimeNanos = currentTimeNanos;
             }
             if (wakeTimeNanos > deadlineNanos) {
                 // If we time out, just return the framesWritten so far.
-                ALOGE("AudioStreamInternal::write(): timed out after %lld nanos", (long long) timeoutNanoseconds);
+                ALOGE("AudioStreamInternal::write(): timed out after %lld nanos",
+                      (long long) timeoutNanoseconds);
                 break;
             }
 
-            //ALOGD("AudioStreamInternal:: sleep until %lld, dur = %lld", (long long) wakeTimeNanos,
+            //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal:: sleep until %lld, dur = %lld", (long long) wakeTimeNanos,
             //        (long long) (wakeTimeNanos - currentTimeNanos));
             AudioClock::sleepForNanos(wakeTimeNanos - currentTimeNanos);
             currentTimeNanos = AudioClock::getNanoseconds();
@@ -546,43 +540,52 @@
     }
 
     // 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;
 }
 
 // Write as much data as we can without blocking.
 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");
         // Update data queue based on the timing model.
         int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime);
         mAudioEndpoint.setDownDataReadCounter(estimatedReadCounter);
-        // If the read index passed the write index then consider it an underrun.
-        if (mAudioEndpoint.getFullFramesAvailable() < 0) {
-            mXRunCount++;
-        }
     }
     // TODO else query from endpoint cuz set by actual reader, maybe
 
-    // Write some data to the buffer.
-    int32_t framesWritten = mAudioEndpoint.writeDataNow(buffer, numFrames);
-    if (framesWritten > 0) {
-        incrementFramesWritten(framesWritten);
+    // If the read index passed the write index then consider it an underrun.
+    if (mAudioEndpoint.getFullFramesAvailable() < 0) {
+        mXRunCount++;
     }
-    //ALOGD("AudioStreamInternal::writeNow() - tried to write %d frames, wrote %d",
+
+    // Write some data to the buffer.
+    //ALOGD_IF(ALOG_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",
     //    numFrames, framesWritten);
 
     // Calculate an ideal time to wake up.
     if (wakeTimePtr != nullptr && framesWritten >= 0) {
         // By default wake up a few milliseconds from now.  // TODO review
-        int64_t wakeTime = currentNanoTime + (2 * AAUDIO_NANOS_PER_MILLISECOND);
-        switch (getState()) {
+        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",
+        //      AAudio_convertStreamStateToText(state));
+        switch (state) {
             case AAUDIO_STREAM_STATE_OPEN:
             case AAUDIO_STREAM_STATE_STARTING:
                 if (framesWritten != 0) {
@@ -607,13 +610,68 @@
         *wakeTimePtr = wakeTime;
 
     }
-//    ALOGD("AudioStreamInternal::writeNow finished: now = %llu, read# = %llu, wrote# = %llu",
+//    ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow finished: now = %llu, read# = %llu, wrote# = %llu",
 //         (unsigned long long)currentNanoTime,
 //         (unsigned long long)mAudioEndpoint.getDownDataReadCounter(),
 //         (unsigned long long)mAudioEndpoint.getDownDataWriteCounter());
     return framesWritten;
 }
 
+
+// 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);
+    WrappingBuffer wrappingBuffer;
+    mAudioEndpoint.getEmptyRoomAvailable(&wrappingBuffer);
+    uint8_t *source = (uint8_t *) buffer;
+    int32_t framesLeft = numFrames;
+
+    mAudioEndpoint.getEmptyRoomAvailable(&wrappingBuffer);
+
+    // Read data in one or two parts.
+    int partIndex = 0;
+    while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
+        int32_t framesToWrite = framesLeft;
+        int32_t framesAvailable = wrappingBuffer.numFrames[partIndex];
+        if (framesAvailable > 0) {
+            if (framesToWrite > framesAvailable) {
+                framesToWrite = framesAvailable;
+            }
+            int32_t numBytes = getBytesPerFrame();
+            // 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) {
+                // Data conversion.
+                AAudioConvert_floatToPcm16(
+                        (const float *) source,
+                        framesToWrite * getSamplesPerFrame(),
+                        (int16_t *) wrappingBuffer.data[partIndex]);
+            } else {
+                // TODO handle more conversions
+                ALOGE("AudioStreamInternal::writeNowWithConversion() unsupported formats: %d, %d",
+                      getFormat(), mDeviceFormat);
+                return AAUDIO_ERROR_UNEXPECTED_VALUE;
+            }
+
+            source += numBytes;
+            framesLeft -= framesToWrite;
+        }
+        partIndex++;
+    }
+    int32_t framesWritten = numFrames - framesLeft;
+    mAudioEndpoint.advanceWriteIndex(framesWritten);
+
+    if (framesWritten > 0) {
+        incrementFramesWritten(framesWritten);
+    }
+    // ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten);
+    return framesWritten;
+}
+
 void AudioStreamInternal::processTimestamp(uint64_t position, int64_t time) {
     mClockModel.processTimestamp( position, time);
 }
@@ -654,7 +712,7 @@
     } else {
         mLastFramesRead = framesRead;
     }
-    ALOGD("AudioStreamInternal::getFramesRead() returns %lld", (long long)framesRead);
+    ALOGD_IF(ALOG_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 9a15a9b..1aa3b0f 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -26,6 +26,8 @@
 #include "client/AudioEndpoint.h"
 #include "core/AudioStream.h"
 
+#include "binding/AAudioServiceInterface.h"
+
 using android::sp;
 using android::IAAudioService;
 
@@ -35,52 +37,54 @@
 class AudioStreamInternal : public AudioStream {
 
 public:
-    AudioStreamInternal();
+    AudioStreamInternal(AAudioServiceInterface  &serviceInterface, bool inService = false);
     virtual ~AudioStreamInternal();
 
     // =========== Begin ABSTRACT methods ===========================
-    virtual aaudio_result_t requestStart() override;
+    aaudio_result_t requestStart() override;
 
-    virtual aaudio_result_t requestPause() override;
+    aaudio_result_t requestPause() override;
 
-    virtual aaudio_result_t requestFlush() override;
+    aaudio_result_t requestFlush() override;
 
-    virtual aaudio_result_t requestStop() override;
+    aaudio_result_t requestStop() override;
 
     // TODO use aaudio_clockid_t all the way down to AudioClock
-    virtual aaudio_result_t getTimestamp(clockid_t clockId,
+    aaudio_result_t getTimestamp(clockid_t clockId,
                                        int64_t *framePosition,
                                        int64_t *timeNanoseconds) override;
 
 
+
     virtual aaudio_result_t updateStateWhileWaiting() override;
+
     // =========== End ABSTRACT methods ===========================
 
-    virtual aaudio_result_t open(const AudioStreamBuilder &builder) override;
+    aaudio_result_t open(const AudioStreamBuilder &builder) override;
 
-    virtual aaudio_result_t close() override;
+    aaudio_result_t close() override;
 
-    virtual aaudio_result_t write(const void *buffer,
+    aaudio_result_t write(const void *buffer,
                              int32_t numFrames,
                              int64_t timeoutNanoseconds) override;
 
-    virtual aaudio_result_t setBufferSize(int32_t requestedFrames) override;
+    aaudio_result_t setBufferSize(int32_t requestedFrames) override;
 
-    virtual int32_t getBufferSize() const override;
+    int32_t getBufferSize() const override;
 
-    virtual int32_t getBufferCapacity() const override;
+    int32_t getBufferCapacity() const override;
 
-    virtual int32_t getFramesPerBurst() const override;
+    int32_t getFramesPerBurst() const override;
 
-    virtual int64_t getFramesRead() override;
+    int64_t getFramesRead() override;
 
-    virtual int32_t getXRunCount() const override {
+    int32_t getXRunCount() const override {
         return mXRunCount;
     }
 
-    virtual aaudio_result_t registerThread() override;
+    aaudio_result_t registerThread() override;
 
-    virtual aaudio_result_t unregisterThread() override;
+    aaudio_result_t unregisterThread() override;
 
     // Called internally from 'C'
     void *callbackLoop();
@@ -100,10 +104,10 @@
  *
  * @return the number of frames written or a negative error code.
  */
-    virtual aaudio_result_t writeNow(const void *buffer,
-                                int32_t numFrames,
-                                int64_t currentTimeNanos,
-                                int64_t *wakeTimePtr);
+    aaudio_result_t writeNow(const void *buffer,
+                                     int32_t numFrames,
+                                     int64_t currentTimeNanos,
+                                     int64_t *wakeTimePtr);
 
     void onFlushFromServer();
 
@@ -115,19 +119,41 @@
     int64_t calculateReasonableTimeout(int32_t framesPerOperation);
 
 private:
-    IsochronousClockModel    mClockModel;
-    AudioEndpoint            mAudioEndpoint;
-    aaudio_handle_t          mServiceStreamHandle;
-    EndpointDescriptor       mEndpointDescriptor;
+    /*
+     * Asynchronous write with data conversion.
+     * @param buffer
+     * @param numFrames
+     * @return fdrames written or negative error
+     */
+    aaudio_result_t writeNowWithConversion(const void *buffer,
+                                     int32_t numFrames);
+    void processTimestamp(uint64_t position, int64_t time);
+
+    // Adjust timing model based on timestamp from service.
+
+    IsochronousClockModel    mClockModel;      // timing model for chasing the HAL
+    AudioEndpoint            mAudioEndpoint;   // sink for writes
+    aaudio_handle_t          mServiceStreamHandle; // opaque handle returned from service
+
+    AudioEndpointParcelable  mEndPointParcelable; // description of the buffers filled by service
+    EndpointDescriptor       mEndpointDescriptor; // buffer description with resolved addresses
+
+    aaudio_audio_format_t    mDeviceFormat = AAUDIO_FORMAT_UNSPECIFIED;
+
     uint8_t                 *mCallbackBuffer = nullptr;
     int32_t                  mCallbackFrames = 0;
 
     // Offset from underlying frame position.
-    int64_t                  mFramesOffsetFromService = 0;
-    int64_t                  mLastFramesRead = 0;
-    int32_t                  mFramesPerBurst;
-    int32_t                  mXRunCount = 0;
-    void processTimestamp(uint64_t position, int64_t time);
+    int64_t                  mFramesOffsetFromService = 0; // offset for timestamps
+    int64_t                  mLastFramesRead = 0; // used to prevent retrograde motion
+    int32_t                  mFramesPerBurst;     // frames per HAL transfer
+    int32_t                  mXRunCount = 0;      // how many underrun events?
+    float                    mVolume = 1.0;       // volume that the server told us to use
+
+    AAudioServiceInterface  &mServiceInterface;   // abstract interface to the service
+
+    // The service uses this for SHARED mode.
+    bool                     mInService = false;  // Are running in the client or the service?
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index bc2f281..d91d0e4 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -49,10 +49,13 @@
 AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode) {
     switch (returnCode) {
         AAUDIO_CASE_ENUM(AAUDIO_OK);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_DISCONNECTED);
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_ILLEGAL_ARGUMENT);
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_INCOMPATIBLE);
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_INTERNAL);
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_STATE);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNEXPECTED_STATE);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNEXPECTED_VALUE);
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_HANDLE);
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_QUERY);
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNIMPLEMENTED);
@@ -62,9 +65,10 @@
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_NULL);
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_TIMEOUT);
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_WOULD_BLOCK);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_ORDER);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_FORMAT);
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_OUT_OF_RANGE);
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_SERVICE);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_RATE);
     }
     return "Unrecognized AAudio error.";
 }
@@ -82,6 +86,7 @@
         AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHED);
         AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPING);
         AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPED);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_DISCONNECTED);
         AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSING);
         AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSED);
     }
@@ -102,7 +107,6 @@
 
 AAUDIO_API aaudio_result_t AAudio_createStreamBuilder(AAudioStreamBuilder** builder)
 {
-    ALOGD("AAudio_createStreamBuilder(): check sHandleTracker.isInitialized ()");
     AudioStreamBuilder *audioStreamBuilder =  new AudioStreamBuilder();
     if (audioStreamBuilder == nullptr) {
         return AAUDIO_ERROR_NO_MEMORY;
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 68579fd..7c0b5ae 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -45,6 +45,7 @@
     mDeviceId = builder.getDeviceId();
     mFormat = builder.getFormat();
     mDirection = builder.getDirection();
+    mSharingMode = builder.getSharingMode();
 
     // callbacks
     mFramesPerDataCallback = builder.getFramesPerDataCallback();
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 1485d20..da71906 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -22,8 +22,8 @@
 #include <stdint.h>
 #include <aaudio/AAudio.h>
 
-#include "AAudioUtilities.h"
-#include "MonotonicCounter.h"
+#include "utility/AAudioUtilities.h"
+#include "utility/MonotonicCounter.h"
 
 namespace aaudio {
 
@@ -266,11 +266,14 @@
         mState = state;
     }
 
+    void setDeviceId(int32_t deviceId) {
+        mDeviceId = deviceId;
+    }
+
     std::mutex           mStreamMutex;
 
     std::atomic<bool>    mCallbackEnabled;
 
-
 protected:
     MonotonicCounter     mFramesWritten;
     MonotonicCounter     mFramesRead;
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 858ae80..c0b59bb 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -24,12 +24,18 @@
 #include <aaudio/AAudioDefinitions.h>
 #include <aaudio/AAudio.h>
 
+#include "binding/AAudioBinderClient.h"
 #include "client/AudioStreamInternal.h"
 #include "core/AudioStream.h"
 #include "core/AudioStreamBuilder.h"
 #include "legacy/AudioStreamRecord.h"
 #include "legacy/AudioStreamTrack.h"
 
+// Enable a mixer in AAudio service that will mix stream to an ALSA MMAP buffer.
+#define MMAP_SHARED_ENABLED      0
+// Enable AAUDIO_SHARING_MODE_EXCLUSIVE that uses an ALSA MMAP buffer.
+#define MMAP_EXCLUSIVE_ENABLED   1
+
 using namespace aaudio;
 
 /*
@@ -43,9 +49,11 @@
 
 aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) {
     AudioStream* audioStream = nullptr;
+    AAudioBinderClient *aaudioClient = nullptr;
     const aaudio_sharing_mode_t sharingMode = getSharingMode();
-    ALOGE("AudioStreamBuilder.build() sharingMode = %d", sharingMode);
+    ALOGD("AudioStreamBuilder.build() sharingMode = %d", sharingMode);
     switch (getDirection()) {
+
     case AAUDIO_DIRECTION_INPUT:
         switch (sharingMode) {
             case AAUDIO_SHARING_MODE_SHARED:
@@ -57,26 +65,37 @@
                 break;
         }
         break;
+
     case AAUDIO_DIRECTION_OUTPUT:
         switch (sharingMode) {
             case AAUDIO_SHARING_MODE_SHARED:
+#if MMAP_SHARED_ENABLED
+                aaudioClient = new AAudioBinderClient();
+                audioStream = new(std::nothrow) AudioStreamInternal(*aaudioClient, false);
+#else
                 audioStream = new(std::nothrow) AudioStreamTrack();
+#endif
                 break;
+#if MMAP_EXCLUSIVE_ENABLED
             case AAUDIO_SHARING_MODE_EXCLUSIVE:
-                audioStream = new(std::nothrow) AudioStreamInternal();
+                aaudioClient = new AAudioBinderClient();
+                audioStream = new(std::nothrow) AudioStreamInternal(*aaudioClient, false);
                 break;
+#endif
             default:
                 ALOGE("AudioStreamBuilder(): bad sharing mode = %d", sharingMode);
                 return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
                 break;
         }
         break;
+
     default:
         ALOGE("AudioStreamBuilder(): bad direction = %d", getDirection());
         return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
         break;
     }
     if (audioStream == nullptr) {
+        delete aaudioClient;
         return AAUDIO_ERROR_NO_MEMORY;
     }
     ALOGD("AudioStreamBuilder(): created audioStream = %p", audioStream);
diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
index c5489f1..857780c 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.cpp
+++ b/media/libaaudio/src/fifo/FifoBuffer.cpp
@@ -17,6 +17,7 @@
 #include <cstring>
 #include <unistd.h>
 
+
 #define LOG_TAG "FifoBuffer"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
@@ -26,6 +27,8 @@
 #include "FifoControllerIndirect.h"
 #include "FifoBuffer.h"
 
+using namespace android; // TODO just import names needed
+
 FifoBuffer::FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames)
         : mFrameCapacity(capacityInFrames)
         , mBytesPerFrame(bytesPerFrame)
@@ -79,80 +82,102 @@
     return frames * mBytesPerFrame;
 }
 
-fifo_frames_t FifoBuffer::read(void *buffer, fifo_frames_t numFrames) {
-    size_t numBytes;
-    fifo_frames_t framesAvailable = mFifo->getFullFramesAvailable();
-    fifo_frames_t framesToRead = numFrames;
-    // Is there enough data in the FIFO
-    if (framesToRead > framesAvailable) {
-        framesToRead = framesAvailable;
-    }
-    if (framesToRead == 0) {
-        return 0;
-    }
+void FifoBuffer::fillWrappingBuffer(WrappingBuffer *wrappingBuffer,
+                                    int32_t framesAvailable,
+                                    int32_t startIndex) {
+    wrappingBuffer->data[1] = nullptr;
+    wrappingBuffer->numFrames[1] = 0;
+    if (framesAvailable > 0) {
 
-    fifo_frames_t readIndex = mFifo->getReadIndex();
-    uint8_t *destination = (uint8_t *) buffer;
-    uint8_t *source = &mStorage[convertFramesToBytes(readIndex)];
-    if ((readIndex + framesToRead) > mFrameCapacity) {
-        // read in two parts, first part here
-        fifo_frames_t frames1 = mFrameCapacity - readIndex;
-        int32_t numBytes = convertFramesToBytes(frames1);
-        memcpy(destination, source, numBytes);
-        destination += numBytes;
-        // read second part
-        source = &mStorage[0];
-        fifo_frames_t frames2 = framesToRead - frames1;
-        numBytes = convertFramesToBytes(frames2);
-        memcpy(destination, source, numBytes);
+        uint8_t *source = &mStorage[convertFramesToBytes(startIndex)];
+        // Does the available data cross the end of the FIFO?
+        if ((startIndex + framesAvailable) > mFrameCapacity) {
+            wrappingBuffer->data[0] = source;
+            wrappingBuffer->numFrames[0] = mFrameCapacity - startIndex;
+            wrappingBuffer->data[1] = &mStorage[0];
+            wrappingBuffer->numFrames[1] = mFrameCapacity - startIndex;
+
+        } else {
+            wrappingBuffer->data[0] = source;
+            wrappingBuffer->numFrames[0] = framesAvailable;
+        }
     } else {
-        // just read in one shot
-        numBytes = convertFramesToBytes(framesToRead);
-        memcpy(destination, source, numBytes);
+        wrappingBuffer->data[0] = nullptr;
+        wrappingBuffer->numFrames[0] = 0;
     }
-    mFifo->advanceReadIndex(framesToRead);
 
-    return framesToRead;
 }
 
-fifo_frames_t FifoBuffer::write(const void *buffer, fifo_frames_t framesToWrite) {
+void FifoBuffer::getFullDataAvailable(WrappingBuffer *wrappingBuffer) {
+    fifo_frames_t framesAvailable = mFifo->getFullFramesAvailable();
+    fifo_frames_t startIndex = mFifo->getReadIndex();
+    fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
+}
+
+void FifoBuffer::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) {
     fifo_frames_t framesAvailable = mFifo->getEmptyFramesAvailable();
-//    ALOGD("FifoBuffer::write() framesToWrite = %d, framesAvailable = %d",
-//         framesToWrite, framesAvailable);
-    if (framesToWrite > framesAvailable) {
-        framesToWrite = framesAvailable;
-    }
-    if (framesToWrite <= 0) {
-        return 0;
-    }
+    fifo_frames_t startIndex = mFifo->getWriteIndex();
+    fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
+}
 
-    size_t numBytes;
-    fifo_frames_t writeIndex = mFifo->getWriteIndex();
-    int byteIndex = convertFramesToBytes(writeIndex);
-    const uint8_t *source = (const uint8_t *) buffer;
-    uint8_t *destination = &mStorage[byteIndex];
-    if ((writeIndex + framesToWrite) > mFrameCapacity) {
-        // write in two parts, first part here
-        fifo_frames_t frames1 = mFrameCapacity - writeIndex;
-        numBytes = convertFramesToBytes(frames1);
-        memcpy(destination, source, numBytes);
-//        ALOGD("FifoBuffer::write(%p to %p, numBytes = %d", source, destination, numBytes);
-        // read second part
-        source += convertFramesToBytes(frames1);
-        destination = &mStorage[0];
-        fifo_frames_t framesLeft = framesToWrite - frames1;
-        numBytes = convertFramesToBytes(framesLeft);
-//        ALOGD("FifoBuffer::write(%p to %p, numBytes = %d", source, destination, numBytes);
-        memcpy(destination, source, numBytes);
-    } else {
-        // just write in one shot
-        numBytes = convertFramesToBytes(framesToWrite);
-//        ALOGD("FifoBuffer::write(%p to %p, numBytes = %d", source, destination, numBytes);
-        memcpy(destination, source, numBytes);
-    }
-    mFifo->advanceWriteIndex(framesToWrite);
+fifo_frames_t FifoBuffer::read(void *buffer, fifo_frames_t numFrames) {
+    WrappingBuffer wrappingBuffer;
+    uint8_t *destination = (uint8_t *) buffer;
+    fifo_frames_t framesLeft = numFrames;
 
-    return framesToWrite;
+    getFullDataAvailable(&wrappingBuffer);
+
+    // Read data in one or two parts.
+    int partIndex = 0;
+    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;
+            }
+            int32_t numBytes = convertFramesToBytes(framesToRead);
+            memcpy(destination, wrappingBuffer.data[partIndex], numBytes);
+
+            destination += numBytes;
+            framesLeft -= framesToRead;
+        }
+        partIndex++;
+    }
+    fifo_frames_t framesRead = numFrames - framesLeft;
+    mFifo->advanceReadIndex(framesRead);
+    return framesRead;
+}
+
+fifo_frames_t FifoBuffer::write(const void *buffer, fifo_frames_t numFrames) {
+    WrappingBuffer wrappingBuffer;
+    uint8_t *source = (uint8_t *) buffer;
+    fifo_frames_t framesLeft = numFrames;
+
+    getEmptyRoomAvailable(&wrappingBuffer);
+
+    // Read data in one or two parts.
+    int partIndex = 0;
+    while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
+        fifo_frames_t framesToWrite = framesLeft;
+        fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
+        if (framesAvailable > 0) {
+            if (framesToWrite > framesAvailable) {
+                framesToWrite = framesAvailable;
+            }
+            int32_t numBytes = convertFramesToBytes(framesToWrite);
+            memcpy(wrappingBuffer.data[partIndex], source, numBytes);
+
+            source += numBytes;
+            framesLeft -= framesToWrite;
+        }
+        partIndex++;
+    }
+    fifo_frames_t framesWritten = numFrames - framesLeft;
+    mFifo->advanceWriteIndex(framesWritten);
+    return framesWritten;
 }
 
 fifo_frames_t FifoBuffer::readNow(void *buffer, fifo_frames_t numFrames) {
diff --git a/media/libaaudio/src/fifo/FifoBuffer.h b/media/libaaudio/src/fifo/FifoBuffer.h
index faa9ae2..2b262a1 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.h
+++ b/media/libaaudio/src/fifo/FifoBuffer.h
@@ -21,15 +21,29 @@
 
 #include "FifoControllerBase.h"
 
+namespace android {
+
+/**
+ * Structure that represents a region in a circular buffer that might be at the
+ * end of the array and split in two.
+ */
+struct WrappingBuffer {
+    enum {
+        SIZE = 2
+    };
+    void *data[SIZE];
+    int32_t numFrames[SIZE];
+};
+
 class FifoBuffer {
 public:
     FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames);
 
-    FifoBuffer(int32_t   bytesPerFrame,
-               fifo_frames_t   capacityInFrames,
-               fifo_counter_t * readCounterAddress,
-               fifo_counter_t * writeCounterAddress,
-               void * dataStorageAddress);
+    FifoBuffer(int32_t bytesPerFrame,
+               fifo_frames_t capacityInFrames,
+               fifo_counter_t *readCounterAddress,
+               fifo_counter_t *writeCounterAddress,
+               void *dataStorageAddress);
 
     ~FifoBuffer();
 
@@ -40,10 +54,33 @@
     fifo_frames_t write(const void *source, fifo_frames_t framesToWrite);
 
     fifo_frames_t getThreshold();
+
     void setThreshold(fifo_frames_t threshold);
 
     fifo_frames_t getBufferCapacityInFrames();
 
+    /**
+     * Return pointer to available full frames in data1 and set size in numFrames1.
+     * if the data is split across the end of the FIFO then set data2 and numFrames2.
+     * Other wise set them to null
+     * @param wrappingBuffer
+     */
+    void getFullDataAvailable(WrappingBuffer *wrappingBuffer);
+
+    /**
+     * Return pointer to available empty frames in data1 and set size in numFrames1.
+     * if the room is split across the end of the FIFO then set data2 and numFrames2.
+     * Other wise set them to null
+     * @param wrappingBuffer
+     */
+    void getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer);
+
+    /**
+     * Copy data from the FIFO into the buffer.
+     * @param buffer
+     * @param numFrames
+     * @return
+     */
     fifo_frames_t readNow(void *buffer, fifo_frames_t numFrames);
 
     int64_t getNextReadTime(int32_t frameRate);
@@ -73,15 +110,21 @@
     }
 
 private:
+
+    void fillWrappingBuffer(WrappingBuffer *wrappingBuffer,
+                            int32_t framesAvailable, int32_t startIndex);
+
     const fifo_frames_t mFrameCapacity;
-    const int32_t       mBytesPerFrame;
-    uint8_t *           mStorage;
-    bool                mStorageOwned; // did this object allocate the storage?
+    const int32_t mBytesPerFrame;
+    uint8_t *mStorage;
+    bool mStorageOwned; // did this object allocate the storage?
     FifoControllerBase *mFifo;
-    fifo_counter_t      mFramesReadCount;
-    fifo_counter_t      mFramesUnderrunCount;
-    int32_t             mUnderrunCount; // need? just use frames
-    int32_t             mLastReadSize;
+    fifo_counter_t mFramesReadCount;
+    fifo_counter_t mFramesUnderrunCount;
+    int32_t mUnderrunCount; // need? just use frames
+    int32_t mLastReadSize;
 };
 
+}  // android
+
 #endif //FIFO_FIFO_BUFFER_H
diff --git a/media/libaaudio/src/fifo/FifoController.h b/media/libaaudio/src/fifo/FifoController.h
index 7434634..79d98a1 100644
--- a/media/libaaudio/src/fifo/FifoController.h
+++ b/media/libaaudio/src/fifo/FifoController.h
@@ -22,6 +22,8 @@
 
 #include "FifoControllerBase.h"
 
+namespace android {
+
 /**
  * A FIFO with counters contained in the class.
  */
@@ -55,5 +57,6 @@
     std::atomic<fifo_counter_t> mWriteCounter;
 };
 
+}  // android
 
 #endif //FIFO_FIFO_CONTROLLER_H
diff --git a/media/libaaudio/src/fifo/FifoControllerBase.cpp b/media/libaaudio/src/fifo/FifoControllerBase.cpp
index 33a253e..14a2be1 100644
--- a/media/libaaudio/src/fifo/FifoControllerBase.cpp
+++ b/media/libaaudio/src/fifo/FifoControllerBase.cpp
@@ -21,6 +21,8 @@
 #include <stdint.h>
 #include "FifoControllerBase.h"
 
+using namespace android;  // TODO just import names needed
+
 FifoControllerBase::FifoControllerBase(fifo_frames_t capacity, fifo_frames_t threshold)
         : mCapacity(capacity)
         , mThreshold(threshold)
diff --git a/media/libaaudio/src/fifo/FifoControllerBase.h b/media/libaaudio/src/fifo/FifoControllerBase.h
index c543519..64af777 100644
--- a/media/libaaudio/src/fifo/FifoControllerBase.h
+++ b/media/libaaudio/src/fifo/FifoControllerBase.h
@@ -19,6 +19,8 @@
 
 #include <stdint.h>
 
+namespace android {
+
 typedef int64_t fifo_counter_t;
 typedef int32_t fifo_frames_t;
 
@@ -118,4 +120,6 @@
     fifo_frames_t mThreshold;
 };
 
+}  // android
+
 #endif // FIFO_FIFO_CONTROLLER_BASE_H
diff --git a/media/libaaudio/src/fifo/FifoControllerIndirect.h b/media/libaaudio/src/fifo/FifoControllerIndirect.h
index 1aaf9ea..5832d9c 100644
--- a/media/libaaudio/src/fifo/FifoControllerIndirect.h
+++ b/media/libaaudio/src/fifo/FifoControllerIndirect.h
@@ -22,6 +22,8 @@
 
 #include "FifoControllerBase.h"
 
+namespace android {
+
 /**
  * A FifoControllerBase with counters external to the class.
  *
@@ -66,4 +68,6 @@
     std::atomic<fifo_counter_t> * mWriteCounterAddress;
 };
 
+}  // android
+
 #endif //FIFO_FIFO_CONTROLLER_INDIRECT_H
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 3b79953..8d60678 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -22,7 +22,7 @@
 #include <media/AudioTrack.h>
 
 #include <aaudio/AAudio.h>
-#include "AudioClock.h"
+#include "utility/AudioClock.h"
 #include "legacy/AudioStreamLegacy.h"
 #include "legacy/AudioStreamTrack.h"
 #include "utility/FixedBlockReader.h"
@@ -142,6 +142,7 @@
     }
 
     setState(AAUDIO_STREAM_STATE_OPEN);
+    setDeviceId(mAudioTrack->getRoutedDeviceId());
 
     return AAUDIO_OK;
 }