libaaudio: change name from liboboe

Bug: 34749573
Test: CTS test_aaudio.cpp
Change-Id: I7e2b621488047f0798ca6f2fc00d2b5fed2bf015
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/media/libaaudio/Android.bp b/media/libaaudio/Android.bp
new file mode 100644
index 0000000..e41d62b
--- /dev/null
+++ b/media/libaaudio/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+ndk_headers {
+    name: "libAAudio_headers",
+    from: "include",
+    to: "",
+    srcs: ["include/aaudio/*.h"],
+    license: "include/aaudio/NOTICE",
+}
+
+ndk_library {
+    name: "libaaudio.ndk",
+    symbol_file: "libaaudio.map.txt",
+    first_version: "26",
+    unversioned_until: "current",
+}
diff --git a/media/libaaudio/Android.mk b/media/libaaudio/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/media/libaaudio/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/README.md b/media/libaaudio/README.md
new file mode 100644
index 0000000..f059521
--- /dev/null
+++ b/media/libaaudio/README.md
@@ -0,0 +1 @@
+AAudio input/output API
diff --git a/media/libaaudio/examples/Android.mk b/media/libaaudio/examples/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/media/libaaudio/examples/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/write_sine/Android.mk b/media/libaaudio/examples/write_sine/Android.mk
new file mode 100644
index 0000000..b56328b
--- /dev/null
+++ b/media/libaaudio/examples/write_sine/Android.mk
@@ -0,0 +1,6 @@
+# include $(call all-subdir-makefiles)
+
+# Just include static/ for now.
+LOCAL_PATH := $(call my-dir)
+#include $(LOCAL_PATH)/jni/Android.mk
+include $(LOCAL_PATH)/static/Android.mk
diff --git a/media/libaaudio/examples/write_sine/README.md b/media/libaaudio/examples/write_sine/README.md
new file mode 100644
index 0000000..b150471
--- /dev/null
+++ b/media/libaaudio/examples/write_sine/README.md
@@ -0,0 +1,7 @@
+# cd to this directory
+mkdir -p jni/include/aaudio
+ln -s $PLATFORM/frameworks/av/media/liboboe/include/aaudio/*.h jni/include/aaudio
+ln -s $PLATFORM/out/target/product/$TARGET_PRODUCT/symbols/out/soong/ndk/platforms/android-current/arch-arm64/usr/lib/liboboe.so jni
+$NDK/ndk-build
+adb push libs/arm64-v8a/write_sine_threaded /data
+adb shell /data/write_sine_threaded
diff --git a/media/libaaudio/examples/write_sine/jni/Android.mk b/media/libaaudio/examples/write_sine/jni/Android.mk
new file mode 100644
index 0000000..51a5a85
--- /dev/null
+++ b/media/libaaudio/examples/write_sine/jni/Android.mk
@@ -0,0 +1,35 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/liboboe/include
+
+LOCAL_SRC_FILES:= frameworks/av/media/liboboe/src/write_sine.cpp
+LOCAL_SHARED_LIBRARIES := libaudioutils libmedia libtinyalsa \
+        libbinder libcutils libutils
+LOCAL_STATIC_LIBRARIES := libsndfile
+LOCAL_MODULE := write_sine_ndk
+LOCAL_SHARED_LIBRARIES += liboboe_prebuilt
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/liboboe/include
+
+LOCAL_SRC_FILES:= frameworks/av/media/liboboe/src/write_sine_threaded.cpp
+LOCAL_SHARED_LIBRARIES := libaudioutils libmedia libtinyalsa \
+        libbinder libcutils libutils
+LOCAL_STATIC_LIBRARIES := libsndfile
+LOCAL_MODULE := write_sine_threaded_ndk
+LOCAL_SHARED_LIBRARIES += liboboe_prebuilt
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := liboboe_prebuilt
+LOCAL_SRC_FILES := liboboe.so
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+include $(PREBUILT_SHARED_LIBRARY)
diff --git a/media/libaaudio/examples/write_sine/jni/Application.mk b/media/libaaudio/examples/write_sine/jni/Application.mk
new file mode 100644
index 0000000..e74475c
--- /dev/null
+++ b/media/libaaudio/examples/write_sine/jni/Application.mk
@@ -0,0 +1,3 @@
+# TODO remove then when we support other architectures
+APP_ABI := arm64-v8a
+APP_CPPFLAGS += -std=c++11
diff --git a/media/libaaudio/examples/write_sine/src/SineGenerator.h b/media/libaaudio/examples/write_sine/src/SineGenerator.h
new file mode 100644
index 0000000..ade7527
--- /dev/null
+++ b/media/libaaudio/examples/write_sine/src/SineGenerator.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SINE_GENERATOR_H
+#define SINE_GENERATOR_H
+
+#include <math.h>
+
+class SineGenerator
+{
+public:
+    SineGenerator() {}
+    virtual ~SineGenerator() = default;
+
+    void setup(double frequency, double frameRate) {
+        mFrameRate = frameRate;
+        mPhaseIncrement = frequency * M_PI * 2 / frameRate;
+    }
+
+    void setSweep(double frequencyLow, double frequencyHigh, double seconds) {
+        mPhaseIncrementLow = frequencyLow * M_PI * 2 / mFrameRate;
+        mPhaseIncrementHigh = frequencyHigh * M_PI * 2 / mFrameRate;
+
+        double numFrames = seconds * mFrameRate;
+        mUpScaler = pow((frequencyHigh / frequencyLow), (1.0 / numFrames));
+        mDownScaler = 1.0 / mUpScaler;
+        mGoingUp = true;
+        mSweeping = true;
+    }
+
+    void render(int16_t *buffer, int32_t channelStride, int32_t numFrames) {
+        int sampleIndex = 0;
+        for (int i = 0; i < numFrames; i++) {
+            buffer[sampleIndex] = (int16_t) (32767 * sin(mPhase) * mAmplitude);
+            sampleIndex += channelStride;
+            advancePhase();
+        }
+    }
+    void render(float *buffer, int32_t channelStride, int32_t numFrames) {
+        int sampleIndex = 0;
+        for (int i = 0; i < numFrames; i++) {
+            buffer[sampleIndex] = sin(mPhase) * mAmplitude;
+            sampleIndex += channelStride;
+            advancePhase();
+        }
+    }
+
+private:
+    void advancePhase() {
+        mPhase += mPhaseIncrement;
+        if (mPhase > M_PI * 2) {
+            mPhase -= M_PI * 2;
+        }
+        if (mSweeping) {
+            if (mGoingUp) {
+                mPhaseIncrement *= mUpScaler;
+                if (mPhaseIncrement > mPhaseIncrementHigh) {
+                    mGoingUp = false;
+                }
+            } else {
+                mPhaseIncrement *= mDownScaler;
+                if (mPhaseIncrement < mPhaseIncrementLow) {
+                    mGoingUp = true;
+                }
+            }
+        }
+    }
+
+    double mAmplitude = 0.01;
+    double mPhase = 0.0;
+    double mPhaseIncrement = 440 * M_PI * 2 / 48000;
+    double mFrameRate = 48000;
+    double mPhaseIncrementLow;
+    double mPhaseIncrementHigh;
+    double mUpScaler = 1.0;
+    double mDownScaler = 1.0;
+    bool   mGoingUp = false;
+    bool   mSweeping = false;
+};
+
+#endif /* SINE_GENERATOR_H */
+
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
new file mode 100644
index 0000000..090f371
--- /dev/null
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Play sine waves using AAudio.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <aaudio/AAudioDefinitions.h>
+#include <aaudio/AAudio.h>
+#include "SineGenerator.h"
+
+#define SAMPLE_RATE   48000
+#define NUM_SECONDS   10
+
+static const char *getSharingModeText(aaudio_sharing_mode_t mode) {
+    const char *modeText = "unknown";
+    switch (mode) {
+    case AAUDIO_SHARING_MODE_EXCLUSIVE:
+        modeText = "EXCLUSIVE";
+        break;
+    case AAUDIO_SHARING_MODE_LEGACY:
+        modeText = "LEGACY";
+        break;
+    case AAUDIO_SHARING_MODE_SHARED:
+        modeText = "SHARED";
+        break;
+    case AAUDIO_SHARING_MODE_PUBLIC_MIX:
+        modeText = "PUBLIC_MIX";
+        break;
+    default:
+        break;
+    }
+    return modeText;
+}
+
+int main(int argc, char **argv)
+{
+    (void)argc; // unused
+
+    aaudio_result_t result = AAUDIO_OK;
+
+    const int requestedSamplesPerFrame = 2;
+    int actualSamplesPerFrame = 0;
+    const int requestedSampleRate = SAMPLE_RATE;
+    int actualSampleRate = 0;
+    const aaudio_audio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM16;
+    aaudio_audio_format_t actualDataFormat = AAUDIO_FORMAT_PCM16;
+
+    const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
+    //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_LEGACY;
+    aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_LEGACY;
+
+    AAudioStreamBuilder aaudioBuilder = AAUDIO_STREAM_BUILDER_NONE;
+    AAudioStream aaudioStream = AAUDIO_STREAM_NONE;
+    aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
+    aaudio_size_frames_t framesPerBurst = 0;
+    aaudio_size_frames_t framesToPlay = 0;
+    aaudio_size_frames_t framesLeft = 0;
+    int32_t xRunCount = 0;
+    int16_t *data = nullptr;
+
+    SineGenerator sineOsc1;
+    SineGenerator sineOsc2;
+
+    // Make printf print immediately so that debug info is not stuck
+    // in a buffer if we hang or crash.
+    setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+
+    printf("%s - Play a sine wave using AAudio\n", argv[0]);
+
+    // Use an AAudioStreamBuilder to contain requested parameters.
+    result = AAudio_createStreamBuilder(&aaudioBuilder);
+    if (result != AAUDIO_OK) {
+        goto finish;
+    }
+
+    // Request stream properties.
+    result = AAudioStreamBuilder_setSampleRate(aaudioBuilder, requestedSampleRate);
+    if (result != AAUDIO_OK) {
+        goto finish;
+    }
+    result = AAudioStreamBuilder_setSamplesPerFrame(aaudioBuilder, requestedSamplesPerFrame);
+    if (result != AAUDIO_OK) {
+        goto finish;
+    }
+    result = AAudioStreamBuilder_setFormat(aaudioBuilder, requestedDataFormat);
+    if (result != AAUDIO_OK) {
+        goto finish;
+    }
+    result = AAudioStreamBuilder_setSharingMode(aaudioBuilder, requestedSharingMode);
+    if (result != AAUDIO_OK) {
+        goto finish;
+    }
+
+    // Create an AAudioStream using the Builder.
+    result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
+    printf("aaudioStream 0x%08x\n", aaudioStream);
+    if (result != AAUDIO_OK) {
+        goto finish;
+    }
+
+    result = AAudioStream_getState(aaudioStream, &state);
+    printf("after open, state = %s\n", AAudio_convertStreamStateToText(state));
+
+    // Check to see what kind of stream we actually got.
+    result = AAudioStream_getSampleRate(aaudioStream, &actualSampleRate);
+    printf("SampleRate: requested = %d, actual = %d\n", requestedSampleRate, actualSampleRate);
+
+    sineOsc1.setup(440.0, actualSampleRate);
+    sineOsc2.setup(660.0, actualSampleRate);
+
+    result = AAudioStream_getSamplesPerFrame(aaudioStream, &actualSamplesPerFrame);
+    printf("SamplesPerFrame: requested = %d, actual = %d\n",
+            requestedSamplesPerFrame, actualSamplesPerFrame);
+
+    result = AAudioStream_getSharingMode(aaudioStream, &actualSharingMode);
+    printf("SharingMode: requested = %s, actual = %s\n",
+            getSharingModeText(requestedSharingMode),
+            getSharingModeText(actualSharingMode));
+
+    // This is the number of frames that are read in one chunk by a DMA controller
+    // or a DSP or a mixer.
+    result = AAudioStream_getFramesPerBurst(aaudioStream, &framesPerBurst);
+    printf("DataFormat: original framesPerBurst = %d\n",framesPerBurst);
+    if (result != AAUDIO_OK) {
+        fprintf(stderr, "ERROR - AAudioStream_getFramesPerBurst() returned %d\n", result);
+        goto finish;
+    }
+    // Some DMA might use very short bursts of 16 frames. We don't need to write such small
+    // buffers. But it helps to use a multiple of the burst size for predictable scheduling.
+    while (framesPerBurst < 48) {
+        framesPerBurst *= 2;
+    }
+    printf("DataFormat: final framesPerBurst = %d\n",framesPerBurst);
+
+    AAudioStream_getFormat(aaudioStream, &actualDataFormat);
+    printf("DataFormat: requested = %d, actual = %d\n", requestedDataFormat, actualDataFormat);
+    // TODO handle other data formats
+
+    // Allocate a buffer for the audio data.
+    data = new int16_t[framesPerBurst * actualSamplesPerFrame];
+    if (data == nullptr) {
+        fprintf(stderr, "ERROR - could not allocate data buffer\n");
+        result = AAUDIO_ERROR_NO_MEMORY;
+        goto finish;
+    }
+
+    // Start the stream.
+    printf("call AAudioStream_requestStart()\n");
+    result = AAudioStream_requestStart(aaudioStream);
+    if (result != AAUDIO_OK) {
+        fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d\n", result);
+        goto finish;
+    }
+
+    result = AAudioStream_getState(aaudioStream, &state);
+    printf("after start, state = %s\n", AAudio_convertStreamStateToText(state));
+
+    // Play for a while.
+    framesToPlay = actualSampleRate * NUM_SECONDS;
+    framesLeft = framesToPlay;
+    while (framesLeft > 0) {
+        // Render sine waves to left and right channels.
+        sineOsc1.render(&data[0], actualSamplesPerFrame, framesPerBurst);
+        if (actualSamplesPerFrame > 1) {
+            sineOsc2.render(&data[1], actualSamplesPerFrame, framesPerBurst);
+        }
+
+        // Write audio data to the stream.
+        aaudio_nanoseconds_t timeoutNanos = 100 * AAUDIO_NANOS_PER_MILLISECOND;
+        int minFrames = (framesToPlay < framesPerBurst) ? framesToPlay : framesPerBurst;
+        int actual = AAudioStream_write(aaudioStream, data, minFrames, timeoutNanos);
+        if (actual < 0) {
+            fprintf(stderr, "ERROR - AAudioStream_write() returned %zd\n", actual);
+            goto finish;
+        } else if (actual == 0) {
+            fprintf(stderr, "WARNING - AAudioStream_write() returned %zd\n", actual);
+            goto finish;
+        }
+        framesLeft -= actual;
+    }
+
+    result = AAudioStream_getXRunCount(aaudioStream, &xRunCount);
+    printf("AAudioStream_getXRunCount %d\n", xRunCount);
+
+finish:
+    delete[] data;
+    AAudioStream_close(aaudioStream);
+    AAudioStreamBuilder_delete(aaudioBuilder);
+    printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
+    return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_threaded.cpp b/media/libaaudio/examples/write_sine/src/write_sine_threaded.cpp
new file mode 100644
index 0000000..4ea2807
--- /dev/null
+++ b/media/libaaudio/examples/write_sine/src/write_sine_threaded.cpp
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Play sine waves using an AAudio background thread.
+
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <time.h>
+#include <aaudio/AAudioDefinitions.h>
+#include <aaudio/AAudio.h>
+#include "SineGenerator.h"
+
+#define NUM_SECONDS   10
+
+#define SHARING_MODE  AAUDIO_SHARING_MODE_EXCLUSIVE
+//#define SHARING_MODE  AAUDIO_SHARING_MODE_LEGACY
+
+// Prototype for a callback.
+typedef int audio_callback_proc_t(float *outputBuffer,
+                                     aaudio_size_frames_t numFrames,
+                                     void *userContext);
+
+static void *SimpleAAudioPlayerThreadProc(void *arg);
+
+/**
+ * Simple wrapper for AAudio that opens a default stream and then calls
+ * a callback function to fill the output buffers.
+ */
+class SimpleAAudioPlayer {
+public:
+    SimpleAAudioPlayer() {}
+    virtual ~SimpleAAudioPlayer() {
+        close();
+    };
+
+    void setSharingMode(aaudio_sharing_mode_t requestedSharingMode) {
+        mRequestedSharingMode = requestedSharingMode;
+    }
+
+    /** Also known as "sample rate"
+     */
+    int32_t getFramesPerSecond() {
+        return mFramesPerSecond;
+    }
+
+    int32_t getSamplesPerFrame() {
+        return mSamplesPerFrame;
+    }
+
+    /**
+     * Open a stream
+     */
+    aaudio_result_t open(audio_callback_proc_t *proc, void *userContext) {
+        mCallbackProc = proc;
+        mUserContext = userContext;
+        aaudio_result_t result = AAUDIO_OK;
+
+        // Use an AAudioStreamBuilder to contain requested parameters.
+        result = AAudio_createStreamBuilder(&mBuilder);
+        if (result != AAUDIO_OK) return result;
+
+        result = AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode);
+        if (result != AAUDIO_OK) goto finish1;
+
+        // Open an AAudioStream using the Builder.
+        result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
+        if (result != AAUDIO_OK) goto finish1;
+
+        // Check to see what kind of stream we actually got.
+        result = AAudioStream_getSampleRate(mStream, &mFramesPerSecond);
+        printf("open() mFramesPerSecond = %d\n", mFramesPerSecond);
+        if (result != AAUDIO_OK) goto finish2;
+
+        result = AAudioStream_getSamplesPerFrame(mStream, &mSamplesPerFrame);
+        printf("open() mSamplesPerFrame = %d\n", mSamplesPerFrame);
+        if (result != AAUDIO_OK) goto finish2;
+
+        {
+            aaudio_size_frames_t bufferCapacity;
+            result = AAudioStream_getBufferCapacity(mStream, &bufferCapacity);
+            if (result != AAUDIO_OK) goto finish2;
+            printf("open() got bufferCapacity = %d\n", bufferCapacity);
+        }
+
+        // This is the number of frames that are read in one chunk by a DMA controller
+        // or a DSP or a mixer.
+        result = AAudioStream_getFramesPerBurst(mStream, &mFramesPerBurst);
+        if (result != AAUDIO_OK) goto finish2;
+        // Some DMA might use very short bursts. We don't need to write such small
+        // buffers. But it helps to use a multiple of the burst size for predictable scheduling.
+        while (mFramesPerBurst < 48) {
+            mFramesPerBurst *= 2;
+        }
+        printf("DataFormat: final framesPerBurst = %d\n",mFramesPerBurst);
+
+        result = AAudioStream_getFormat(mStream, &mDataFormat);
+        if (result != AAUDIO_OK) {
+            fprintf(stderr, "ERROR - AAudioStream_getFormat() returned %d\n", result);
+            goto finish2;
+        }
+
+        // Allocate a buffer for the audio data.
+        mOutputBuffer = new float[mFramesPerBurst * mSamplesPerFrame];
+        if (mOutputBuffer == nullptr) {
+            fprintf(stderr, "ERROR - could not allocate data buffer\n");
+            result = AAUDIO_ERROR_NO_MEMORY;
+        }
+
+        // If needed allocate a buffer for converting float to int16_t.
+        if (mDataFormat == AAUDIO_FORMAT_PCM16) {
+            mConversionBuffer = new int16_t[mFramesPerBurst * mSamplesPerFrame];
+            if (mConversionBuffer == nullptr) {
+                fprintf(stderr, "ERROR - could not allocate conversion buffer\n");
+                result = AAUDIO_ERROR_NO_MEMORY;
+            }
+        }
+        return result;
+
+     finish2:
+        AAudioStream_close(mStream);
+        mStream = AAUDIO_HANDLE_INVALID;
+     finish1:
+        AAudioStreamBuilder_delete(mBuilder);
+        mBuilder = AAUDIO_HANDLE_INVALID;
+        return result;
+    }
+
+    aaudio_result_t close() {
+        if (mStream != AAUDIO_HANDLE_INVALID) {
+            stop();
+            printf("call AAudioStream_close(0x%08x)\n", mStream);  fflush(stdout);
+            AAudioStream_close(mStream);
+            mStream = AAUDIO_HANDLE_INVALID;
+            AAudioStreamBuilder_delete(mBuilder);
+            mBuilder = AAUDIO_HANDLE_INVALID;
+            delete mOutputBuffer;
+            mOutputBuffer = nullptr;
+            delete mConversionBuffer;
+            mConversionBuffer = nullptr;
+        }
+        return AAUDIO_OK;
+    }
+
+    // Start a thread that will call the callback proc.
+    aaudio_result_t start() {
+        mEnabled = true;
+        aaudio_nanoseconds_t nanosPerBurst = mFramesPerBurst * AAUDIO_NANOS_PER_SECOND
+                                           / mFramesPerSecond;
+        return AAudioStream_createThread(mStream, nanosPerBurst,
+                                       SimpleAAudioPlayerThreadProc,
+                                       this);
+    }
+
+    // Tell the thread to stop.
+    aaudio_result_t stop() {
+        mEnabled = false;
+        return AAudioStream_joinThread(mStream, nullptr, 2 * AAUDIO_NANOS_PER_SECOND);
+    }
+
+    aaudio_result_t callbackLoop() {
+        int32_t framesWritten = 0;
+        int32_t xRunCount = 0;
+        aaudio_result_t result = AAUDIO_OK;
+
+        result = AAudioStream_requestStart(mStream);
+        if (result != AAUDIO_OK) {
+            fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d\n", result);
+            return result;
+        }
+
+        // Give up after several burst periods have passed.
+        const int burstsPerTimeout = 8;
+        aaudio_nanoseconds_t nanosPerTimeout =
+                        burstsPerTimeout * mFramesPerBurst * AAUDIO_NANOS_PER_SECOND
+                        / mFramesPerSecond;
+
+        while (mEnabled && result >= 0) {
+            // Call application's callback function to fill the buffer.
+            if (mCallbackProc(mOutputBuffer, mFramesPerBurst, mUserContext)) {
+                mEnabled = false;
+            }
+            // if needed, convert from float to int16_t PCM
+            if (mConversionBuffer != nullptr) {
+                int32_t numSamples = mFramesPerBurst * mSamplesPerFrame;
+                for (int i = 0; i < numSamples; i++) {
+                    mConversionBuffer[i] = (int16_t)(32767.0 * mOutputBuffer[i]);
+                }
+                // Write the application data to stream.
+                result = AAudioStream_write(mStream, mConversionBuffer, mFramesPerBurst, nanosPerTimeout);
+            } else {
+                // Write the application data to stream.
+                result = AAudioStream_write(mStream, mOutputBuffer, mFramesPerBurst, nanosPerTimeout);
+            }
+            framesWritten += result;
+            if (result < 0) {
+                fprintf(stderr, "ERROR - AAudioStream_write() returned %zd\n", result);
+            }
+        }
+
+        result = AAudioStream_getXRunCount(mStream, &xRunCount);
+        printf("AAudioStream_getXRunCount %d\n", xRunCount);
+
+        result = AAudioStream_requestStop(mStream);
+        if (result != AAUDIO_OK) {
+            fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d\n", result);
+            return result;
+        }
+
+        return result;
+    }
+
+private:
+    AAudioStreamBuilder   mBuilder = AAUDIO_HANDLE_INVALID;
+    AAudioStream          mStream = AAUDIO_HANDLE_INVALID;
+    float            *  mOutputBuffer = nullptr;
+    int16_t          *  mConversionBuffer = nullptr;
+
+    audio_callback_proc_t * mCallbackProc = nullptr;
+    void             *  mUserContext = nullptr;
+    aaudio_sharing_mode_t mRequestedSharingMode = SHARING_MODE;
+    int32_t             mSamplesPerFrame = 0;
+    int32_t             mFramesPerSecond = 0;
+    aaudio_size_frames_t  mFramesPerBurst = 0;
+    aaudio_audio_format_t mDataFormat = AAUDIO_FORMAT_PCM16;
+
+    volatile bool       mEnabled = false; // used to request that callback exit its loop
+};
+
+static void *SimpleAAudioPlayerThreadProc(void *arg) {
+    SimpleAAudioPlayer *player = (SimpleAAudioPlayer *) arg;
+    player->callbackLoop();
+    return nullptr;
+}
+
+// Application data that gets passed to the callback.
+typedef struct SineThreadedData_s {
+    SineGenerator  sineOsc1;
+    SineGenerator  sineOsc2;
+    int32_t        samplesPerFrame = 0;
+} SineThreadedData_t;
+
+// Callback function that fills the audio output buffer.
+int MyCallbackProc(float *outputBuffer, int32_t numFrames, void *userContext) {
+    SineThreadedData_t *data = (SineThreadedData_t *) userContext;
+    // Render sine waves to left and right channels.
+    data->sineOsc1.render(&outputBuffer[0], data->samplesPerFrame, numFrames);
+    if (data->samplesPerFrame > 1) {
+        data->sineOsc2.render(&outputBuffer[1], data->samplesPerFrame, numFrames);
+    }
+    return 0;
+}
+
+int main(int argc, char **argv)
+{
+    (void)argc; // unused
+    SimpleAAudioPlayer player;
+    SineThreadedData_t myData;
+    aaudio_result_t result;
+
+    // Make printf print immediately so that debug info is not stuck
+    // in a buffer if we hang or crash.
+    setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+    printf("%s - Play a sine wave using an AAudio Thread\n", argv[0]);
+
+    result = player.open(MyCallbackProc, &myData);
+    if (result != AAUDIO_OK) {
+        fprintf(stderr, "ERROR -  player.open() returned %d\n", result);
+        goto error;
+    }
+    printf("player.getFramesPerSecond() = %d\n", player.getFramesPerSecond());
+    printf("player.getSamplesPerFrame() = %d\n", player.getSamplesPerFrame());
+    myData.sineOsc1.setup(440.0, 48000);
+    myData.sineOsc1.setSweep(300.0, 600.0, 5.0);
+    myData.sineOsc2.setup(660.0, 48000);
+    myData.sineOsc2.setSweep(350.0, 900.0, 7.0);
+    myData.samplesPerFrame = player.getSamplesPerFrame();
+
+    result = player.start();
+    if (result != AAUDIO_OK) {
+        fprintf(stderr, "ERROR -  player.start() returned %d\n", result);
+        goto error;
+    }
+
+    printf("Sleep for %d seconds while audio plays in a background thread.\n", NUM_SECONDS);
+    {
+        // FIXME sleep is not an NDK API
+        // sleep(NUM_SECONDS);
+        const struct timespec request = { .tv_sec = NUM_SECONDS, .tv_nsec = 0 };
+        (void) clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, &request, NULL /*remain*/);
+    }
+    printf("Woke up now.\n");
+
+    result = player.stop();
+    if (result != AAUDIO_OK) {
+        fprintf(stderr, "ERROR -  player.stop() returned %d\n", result);
+        goto error;
+    }
+    result = player.close();
+    if (result != AAUDIO_OK) {
+        fprintf(stderr, "ERROR -  player.close() returned %d\n", result);
+        goto error;
+    }
+
+    printf("SUCCESS\n");
+    return EXIT_SUCCESS;
+error:
+    player.close();
+    printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
+    return EXIT_FAILURE;
+}
+
diff --git a/media/libaaudio/examples/write_sine/static/Android.mk b/media/libaaudio/examples/write_sine/static/Android.mk
new file mode 100644
index 0000000..139b70a
--- /dev/null
+++ b/media/libaaudio/examples/write_sine/static/Android.mk
@@ -0,0 +1,34 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := examples
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/libaaudio/include
+
+# TODO reorganize folders to avoid using ../
+LOCAL_SRC_FILES:= ../src/write_sine.cpp
+
+LOCAL_SHARED_LIBRARIES := libaudioutils libmedia \
+                          libbinder libcutils libutils \
+                          libaudioclient liblog libtinyalsa
+LOCAL_STATIC_LIBRARIES := libaaudio
+
+LOCAL_MODULE := write_sine
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/libaaudio/include
+
+LOCAL_SRC_FILES:= ../src/write_sine_threaded.cpp
+
+LOCAL_SHARED_LIBRARIES := libaudioutils libmedia \
+                          libbinder libcutils libutils \
+                          libaudioclient liblog libtinyalsa
+LOCAL_STATIC_LIBRARIES := libaaudio
+
+LOCAL_MODULE := write_sine_threaded
+include $(BUILD_EXECUTABLE)
diff --git a/media/libaaudio/examples/write_sine/static/README.md b/media/libaaudio/examples/write_sine/static/README.md
new file mode 100644
index 0000000..6e26d7b
--- /dev/null
+++ b/media/libaaudio/examples/write_sine/static/README.md
@@ -0,0 +1,2 @@
+Makefile for building simple command line examples.
+They link with AAudio as a static library.
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
new file mode 100644
index 0000000..6987955
--- /dev/null
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This is the 'C' ABI for AAudio.
+ */
+#ifndef AAUDIO_AAUDIO_H
+#define AAUDIO_AAUDIO_H
+
+#include "AAudioDefinitions.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef aaudio_handle_t AAudioStream;
+typedef aaudio_handle_t AAudioStreamBuilder;
+
+#define AAUDIO_STREAM_NONE         ((AAudioStream)AAUDIO_HANDLE_INVALID)
+#define AAUDIO_STREAM_BUILDER_NONE ((AAudioStreamBuilder)AAUDIO_HANDLE_INVALID)
+
+/* AAUDIO_API will probably get defined in a Makefile for a specific platform. */
+#ifndef AAUDIO_API
+#define AAUDIO_API /* for exporting symbols */
+#endif
+
+// ============================================================
+// Audio System
+// ============================================================
+
+/**
+ * @return time in the same clock domain as the timestamps
+ */
+AAUDIO_API aaudio_nanoseconds_t AAudio_getNanoseconds(aaudio_clockid_t clockid);
+
+/**
+ * The text is the ASCII symbol corresponding to the returnCode,
+ * or an English message saying the returnCode is unrecognized.
+ * This is intended for developers to use when debugging.
+ * It is not for display to users.
+ *
+ * @return pointer to a text representation of an AAudio result code.
+ */
+AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode);
+
+/**
+ * The text is the ASCII symbol corresponding to the stream state,
+ * or an English message saying the state is unrecognized.
+ * This is intended for developers to use when debugging.
+ * It is not for display to users.
+ *
+ * @return pointer to a text representation of an AAudio state.
+ */
+AAUDIO_API const char * AAudio_convertStreamStateToText(aaudio_stream_state_t state);
+
+// ============================================================
+// StreamBuilder
+// ============================================================
+
+/**
+ * Create a StreamBuilder that can be used to open a Stream.
+ *
+ * The deviceId is initially unspecified, meaning that the current default device will be used.
+ *
+ * The default direction is AAUDIO_DIRECTION_OUTPUT.
+ * The default sharing mode is AAUDIO_SHARING_MODE_LEGACY.
+ * The data format, samplesPerFrames and sampleRate are unspecified and will be
+ * chosen by the device when it is opened.
+ *
+ * AAudioStreamBuilder_delete() must be called when you are done using the builder.
+ */
+AAUDIO_API aaudio_result_t AAudio_createStreamBuilder(AAudioStreamBuilder *builder);
+
+/**
+ * Request an audio device identified device using an ID.
+ * The ID is platform specific.
+ * On Android, for example, the ID could be obtained from the Java AudioManager.
+ *
+ * By default, the primary device will be used.
+ *
+ * @param builder handle provided by AAudio_createStreamBuilder()
+ * @param deviceId platform specific identifier or AAUDIO_DEVICE_UNSPECIFIED
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_setDeviceId(AAudioStreamBuilder builder,
+                                                     aaudio_device_id_t deviceId);
+/**
+ * Passes back requested device ID.
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_getDeviceId(AAudioStreamBuilder builder,
+                                                     aaudio_device_id_t *deviceId);
+
+/**
+ * Request a sample rate in Hz.
+ * The stream may be opened with a different sample rate.
+ * So the application should query for the actual rate after the stream is opened.
+ *
+ * Technically, this should be called the "frame rate" or "frames per second",
+ * because it refers to the number of complete frames transferred per second.
+ * But it is traditionally called "sample rate". Se we use that term.
+ *
+ * Default is AAUDIO_UNSPECIFIED.
+ *
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_setSampleRate(AAudioStreamBuilder builder,
+                                                       aaudio_sample_rate_t sampleRate);
+
+/**
+ * Returns sample rate in Hertz (samples per second).
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_getSampleRate(AAudioStreamBuilder builder,
+                                                       aaudio_sample_rate_t *sampleRate);
+
+
+/**
+ * Request a number of samples per frame.
+ * The stream may be opened with a different value.
+ * So the application should query for the actual value after the stream is opened.
+ *
+ * Default is AAUDIO_UNSPECIFIED.
+ *
+ * Note, this quantity is sometimes referred to as "channel count".
+ *
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder builder,
+                                                   int32_t samplesPerFrame);
+
+/**
+ * Note, this quantity is sometimes referred to as "channel count".
+ *
+ * @param builder handle provided by AAudio_createStreamBuilder()
+ * @param samplesPerFrame pointer to a variable to be set to samplesPerFrame.
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_getSamplesPerFrame(AAudioStreamBuilder builder,
+                                                   int32_t *samplesPerFrame);
+
+
+/**
+ * Request a sample data format, for example AAUDIO_FORMAT_PCM_I16.
+ * The application should query for the actual format after the stream is opened.
+ *
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_setFormat(AAudioStreamBuilder builder,
+                                                   aaudio_audio_format_t format);
+
+/**
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_getFormat(AAudioStreamBuilder builder,
+                                                   aaudio_audio_format_t *format);
+
+/**
+ * Request a mode for sharing the device.
+ * The requested sharing mode may not be available.
+ * So the application should query for the actual mode after the stream is opened.
+ *
+ * @param builder handle provided by AAudio_createStreamBuilder()
+ * @param sharingMode AAUDIO_SHARING_MODE_LEGACY or AAUDIO_SHARING_MODE_EXCLUSIVE
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_setSharingMode(AAudioStreamBuilder builder,
+                                                        aaudio_sharing_mode_t sharingMode);
+
+/**
+ * Return requested sharing mode.
+ * @return AAUDIO_OK or a negative error
+ */
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_getSharingMode(AAudioStreamBuilder builder,
+                                                        aaudio_sharing_mode_t *sharingMode);
+
+/**
+ * Request the direction for a stream. The default is AAUDIO_DIRECTION_OUTPUT.
+ *
+ * @param builder handle provided by AAudio_createStreamBuilder()
+ * @param direction AAUDIO_DIRECTION_OUTPUT or AAUDIO_DIRECTION_INPUT
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_setDirection(AAudioStreamBuilder builder,
+                                                            aaudio_direction_t direction);
+
+/**
+ * @param builder handle provided by AAudio_createStreamBuilder()
+ * @param direction pointer to a variable to be set to the currently requested direction.
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_getDirection(AAudioStreamBuilder builder,
+                                                            aaudio_direction_t *direction);
+
+/**
+ * Set the requested maximum buffer capacity in frames.
+ * The final AAudioStream capacity may differ, but will probably be at least this big.
+ *
+ * Default is AAUDIO_UNSPECIFIED.
+ *
+ * @param builder handle provided by AAudio_createStreamBuilder()
+ * @param frames the desired buffer capacity in frames or AAUDIO_UNSPECIFIED
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_setBufferCapacity(AAudioStreamBuilder builder,
+                                                                 aaudio_size_frames_t frames);
+
+/**
+ * Query the requested maximum buffer capacity in frames that was passed to
+ * AAudioStreamBuilder_setBufferCapacity().
+ *
+ * @param builder handle provided by AAudio_createStreamBuilder()
+ * @param frames pointer to variable to receive the requested buffer capacity
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_getBufferCapacity(AAudioStreamBuilder builder,
+                                                                 aaudio_size_frames_t *frames);
+
+/**
+ * Open a stream based on the options in the StreamBuilder.
+ *
+ * AAudioStream_close must be called when finished with the stream to recover
+ * the memory and to free the associated resources.
+ *
+ * @param builder handle provided by AAudio_createStreamBuilder()
+ * @param stream pointer to a variable to receive the new stream handle
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t  AAudioStreamBuilder_openStream(AAudioStreamBuilder builder,
+                                                     AAudioStream *stream);
+
+/**
+ * Delete the resources associated with the StreamBuilder.
+ *
+ * @param builder handle provided by AAudio_createStreamBuilder()
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t  AAudioStreamBuilder_delete(AAudioStreamBuilder builder);
+
+// ============================================================
+// Stream Control
+// ============================================================
+
+/**
+ * Free the resources associated with a stream created by AAudioStreamBuilder_openStream()
+ *
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t  AAudioStream_close(AAudioStream stream);
+
+/**
+ * Asynchronously request to start playing the stream. For output streams, one should
+ * write to the stream to fill the buffer before starting.
+ * Otherwise it will underflow.
+ * After this call the state will be in AAUDIO_STREAM_STATE_STARTING or AAUDIO_STREAM_STATE_STARTED.
+ *
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t  AAudioStream_requestStart(AAudioStream stream);
+
+/**
+ * Asynchronous request for the stream to pause.
+ * Pausing a stream will freeze the data flow but not flush any buffers.
+ * Use AAudioStream_Start() to resume playback after a pause.
+ * After this call the state will be in AAUDIO_STREAM_STATE_PAUSING or AAUDIO_STREAM_STATE_PAUSED.
+ *
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t  AAudioStream_requestPause(AAudioStream stream);
+
+/**
+ * Asynchronous request for the stream to flush.
+ * Flushing will discard any pending data.
+ * This call only works if the stream is pausing or paused. TODO review
+ * Frame counters are not reset by a flush. They may be advanced.
+ * After this call the state will be in AAUDIO_STREAM_STATE_FLUSHING or AAUDIO_STREAM_STATE_FLUSHED.
+ *
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t  AAudioStream_requestFlush(AAudioStream stream);
+
+/**
+ * Asynchronous request for the stream to stop.
+ * The stream will stop after all of the data currently buffered has been played.
+ * After this call the state will be in AAUDIO_STREAM_STATE_STOPPING or AAUDIO_STREAM_STATE_STOPPED.
+ *
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t  AAudioStream_requestStop(AAudioStream stream);
+
+/**
+ * Query the current state, eg. AAUDIO_STREAM_STATE_PAUSING
+ *
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @param state pointer to a variable that will be set to the current state
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getState(AAudioStream stream, aaudio_stream_state_t *state);
+
+/**
+ * Wait until the current state no longer matches the input state.
+ *
+ * <pre><code>
+ * aaudio_stream_state_t currentState;
+ * aaudio_result_t result = AAudioStream_getState(stream, &currentState);
+ * while (result == AAUDIO_OK && currentState != AAUDIO_STREAM_STATE_PAUSING) {
+ *     result = AAudioStream_waitForStateChange(
+ *                                   stream, currentState, &currentState, MY_TIMEOUT_NANOS);
+ * }
+ * </code></pre>
+ *
+ * @param stream A handle provided by AAudioStreamBuilder_openStream()
+ * @param inputState The state we want to avoid.
+ * @param nextState Pointer to a variable that will be set to the new state.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream stream,
+                                            aaudio_stream_state_t inputState,
+                                            aaudio_stream_state_t *nextState,
+                                            aaudio_nanoseconds_t timeoutNanoseconds);
+
+// ============================================================
+// Stream I/O
+// ============================================================
+
+/**
+ * Read data from the stream.
+ *
+ * The call will wait until the read is complete or until it runs out of time.
+ * If timeoutNanos is zero then this call will not wait.
+ *
+ * Note that timeoutNanoseconds is a relative duration in wall clock time.
+ * Time will not stop if the thread is asleep.
+ * So it will be implemented using CLOCK_BOOTTIME.
+ *
+ * This call is "strong non-blocking" unless it has to wait for data.
+ *
+ * @param stream A stream created using AAudioStreamBuilder_openStream().
+ * @param buffer The address of the first sample.
+ * @param numFrames Number of frames to read. Only complete frames will be written.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return The number of frames actually written or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_read(AAudioStream stream,
+                               void *buffer,
+                               aaudio_size_frames_t numFrames,
+                               aaudio_nanoseconds_t timeoutNanoseconds);
+
+/**
+ * Write data to the stream.
+ *
+ * The call will wait until the write is complete or until it runs out of time.
+ * If timeoutNanos is zero then this call will not wait.
+ *
+ * Note that timeoutNanoseconds is a relative duration in wall clock time.
+ * Time will not stop if the thread is asleep.
+ * So it will be implemented using CLOCK_BOOTTIME.
+ *
+ * This call is "strong non-blocking" unless it has to wait for room in the buffer.
+ *
+ * @param stream A stream created using AAudioStreamBuilder_openStream().
+ * @param buffer The address of the first sample.
+ * @param numFrames Number of frames to write. Only complete frames will be written.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return The number of frames actually written or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_write(AAudioStream stream,
+                               const void *buffer,
+                               aaudio_size_frames_t numFrames,
+                               aaudio_nanoseconds_t timeoutNanoseconds);
+
+
+// ============================================================
+// High priority audio threads
+// ============================================================
+
+typedef void *(aaudio_audio_thread_proc_t)(void *);
+
+/**
+ * Create a thread associated with a stream. The thread has special properties for
+ * low latency audio performance. This thread can be used to implement a callback API.
+ *
+ * Only one thread may be associated with a stream.
+ *
+ * Note that this API is in flux.
+ *
+ * @param stream A stream created using AAudioStreamBuilder_openStream().
+ * @param periodNanoseconds the estimated period at which the audio thread will need to wake up
+ * @param startRoutine your thread entry point
+ * @param arg an argument that will be passed to your thread entry point
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_createThread(AAudioStream stream,
+                                     aaudio_nanoseconds_t periodNanoseconds,
+                                     aaudio_audio_thread_proc_t *threadProc,
+                                     void *arg);
+
+/**
+ * Wait until the thread exits or an error occurs.
+ * The thread handle will be deleted.
+ *
+ * @param stream A stream created using AAudioStreamBuilder_openStream().
+ * @param returnArg a pointer to a variable to receive the return value
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_joinThread(AAudioStream stream,
+                                   void **returnArg,
+                                   aaudio_nanoseconds_t timeoutNanoseconds);
+
+// ============================================================
+// Stream - queries
+// ============================================================
+
+
+/**
+ * This can be used to adjust the latency of the buffer by changing
+ * the threshold where blocking will occur.
+ * By combining this with AAudioStream_getUnderrunCount(), the latency can be tuned
+ * at run-time for each device.
+ *
+ * This cannot be set higher than AAudioStream_getBufferCapacity().
+ *
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @param requestedFrames requested number of frames that can be filled without blocking
+ * @param actualFrames receives final number of frames
+ * @return AAUDIO_OK or a negative error
+ */
+AAUDIO_API aaudio_result_t AAudioStream_setBufferSize(AAudioStream stream,
+                                                      aaudio_size_frames_t requestedFrames,
+                                                      aaudio_size_frames_t *actualFrames);
+
+/**
+ * Query the maximum number of frames that can be filled without blocking.
+ *
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @param frames pointer to variable to receive the buffer size
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getBufferSize(AAudioStream stream,
+                                                      aaudio_size_frames_t *frames);
+
+/**
+ * Query the number of frames that are read or written by the endpoint at one time.
+ *
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @param frames pointer to variable to receive the burst size
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getFramesPerBurst(AAudioStream stream,
+                                                          aaudio_size_frames_t *frames);
+
+/**
+ * Query maximum buffer capacity in frames.
+ *
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @param frames pointer to variable to receive the buffer capacity
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getBufferCapacity(AAudioStream stream,
+                                                          aaudio_size_frames_t *frames);
+
+/**
+ * An XRun is an Underrun or an Overrun.
+ * During playing, an underrun will occur if the stream is not written in time
+ * and the system runs out of valid data.
+ * During recording, an overrun will occur if the stream is not read in time
+ * and there is no place to put the incoming data so it is discarded.
+ *
+ * An underrun or overrun can cause an audible "pop" or "glitch".
+ *
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @param xRunCount pointer to variable to receive the underrun or overrun count
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getXRunCount(AAudioStream stream, int32_t *xRunCount);
+
+/**
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @param sampleRate pointer to variable to receive the actual sample rate
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getSampleRate(AAudioStream stream,
+                                                      aaudio_sample_rate_t *sampleRate);
+
+/**
+ * The samplesPerFrame is also known as channelCount.
+ *
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @param samplesPerFrame pointer to variable to receive the actual samples per frame
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getSamplesPerFrame(AAudioStream stream,
+                                                           int32_t *samplesPerFrame);
+
+/**
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @param deviceId pointer to variable to receive the actual device ID
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getDeviceId(AAudioStream stream,
+                                                    aaudio_device_id_t *deviceId);
+
+/**
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @param format pointer to variable to receive the actual data format
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getFormat(AAudioStream stream,
+                                                  aaudio_audio_format_t *format);
+
+/**
+ * Provide actual sharing mode.
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @param sharingMode pointer to variable to receive the actual sharing mode
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getSharingMode(AAudioStream stream,
+                                        aaudio_sharing_mode_t *sharingMode);
+
+/**
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @param direction pointer to a variable to be set to the current direction.
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getDirection(AAudioStream stream,
+                                                     aaudio_direction_t *direction);
+
+/**
+ * Passes back the number of frames that have been written since the stream was created.
+ * For an output stream, this will be advanced by the application calling write().
+ * For an input stream, this will be advanced by the device or service.
+ *
+ * The frame position is monotonically increasing.
+ *
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @param frames pointer to variable to receive the frames written
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getFramesWritten(AAudioStream stream,
+                                                   aaudio_position_frames_t *frames);
+
+/**
+ * Passes back the number of frames that have been read since the stream was created.
+ * For an output stream, this will be advanced by the device or service.
+ * For an input stream, this will be advanced by the application calling read().
+ *
+ * The frame position is monotonically increasing.
+ *
+ * @param stream handle provided by AAudioStreamBuilder_openStream()
+ * @param frames pointer to variable to receive the frames written
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getFramesRead(AAudioStream stream,
+                                                      aaudio_position_frames_t *frames);
+
+/**
+ * Passes back the time at which a particular frame was presented.
+ * This can be used to synchronize audio with video or MIDI.
+ * It can also be used to align a recorded stream with a playback stream.
+ *
+ * Timestamps are only valid when the stream is in AAUDIO_STREAM_STATE_STARTED.
+ * AAUDIO_ERROR_INVALID_STATE will be returned if the stream is not started.
+ * Note that because requestStart() is asynchronous, timestamps will not be valid until
+ * a short time after calling requestStart().
+ * So AAUDIO_ERROR_INVALID_STATE should not be considered a fatal error.
+ * Just try calling again later.
+ *
+ * If an error occurs, then the position and time will not be modified.
+ *
+ * The position and time passed back are monotonically increasing.
+ *
+ * @param stream A handle provided by AAudioStreamBuilder_openStream()
+ * @param clockid AAUDIO_CLOCK_MONOTONIC or AAUDIO_CLOCK_BOOTTIME
+ * @param framePosition pointer to a variable to receive the position
+ * @param timeNanoseconds pointer to a variable to receive the time
+ * @return AAUDIO_OK or a negative error
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getTimestamp(AAudioStream stream,
+                                      aaudio_clockid_t clockid,
+                                      aaudio_position_frames_t *framePosition,
+                                      aaudio_nanoseconds_t *timeNanoseconds);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //AAUDIO_AAUDIO_H
diff --git a/media/libaaudio/include/aaudio/AAudioDefinitions.h b/media/libaaudio/include/aaudio/AAudioDefinitions.h
new file mode 100644
index 0000000..979b8c9
--- /dev/null
+++ b/media/libaaudio/include/aaudio/AAudioDefinitions.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAUDIO_AAUDIODEFINITIONS_H
+#define AAUDIO_AAUDIODEFINITIONS_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int32_t  aaudio_handle_t; // negative handles are error codes
+typedef int32_t  aaudio_result_t;
+/**
+ * A platform specific identifier for a device.
+ */
+typedef int32_t  aaudio_device_id_t;
+typedef int32_t  aaudio_sample_rate_t;
+/** This is used for small quantities such as the number of frames in a buffer. */
+typedef int32_t  aaudio_size_frames_t;
+/** This is used for small quantities such as the number of bytes in a frame. */
+typedef int32_t  aaudio_size_bytes_t;
+/**
+ * This is used for large quantities, such as the number of frames that have
+ * been played since a stream was started.
+ * At 48000 Hz, a 32-bit integer would wrap around in just over 12 hours.
+ */
+typedef int64_t  aaudio_position_frames_t;
+
+typedef int64_t  aaudio_nanoseconds_t;
+
+/**
+ * This is used to represent a value that has not been specified.
+ * For example, an application could use AAUDIO_UNSPECIFIED to indicate
+ * that is did not not care what the specific value of a parameter was
+ * and would accept whatever it was given.
+ */
+#define AAUDIO_UNSPECIFIED           0
+#define AAUDIO_DEVICE_UNSPECIFIED    ((aaudio_device_id_t) -1)
+#define AAUDIO_NANOS_PER_MICROSECOND ((int64_t)1000)
+#define AAUDIO_NANOS_PER_MILLISECOND (AAUDIO_NANOS_PER_MICROSECOND * 1000)
+#define AAUDIO_MILLIS_PER_SECOND     1000
+#define AAUDIO_NANOS_PER_SECOND      (AAUDIO_NANOS_PER_MILLISECOND * AAUDIO_MILLIS_PER_SECOND)
+
+#define AAUDIO_HANDLE_INVALID     ((aaudio_handle_t)-1)
+
+enum aaudio_direction_t {
+    AAUDIO_DIRECTION_OUTPUT,
+    AAUDIO_DIRECTION_INPUT,
+    AAUDIO_DIRECTION_COUNT // This should always be last.
+};
+
+enum aaudio_audio_format_t {
+    AAUDIO_FORMAT_INVALID = -1,
+    AAUDIO_FORMAT_UNSPECIFIED = 0,
+    AAUDIO_FORMAT_PCM_I16,
+    AAUDIO_FORMAT_PCM_FLOAT,
+    AAUDIO_FORMAT_PCM_I8_24,
+    AAUDIO_FORMAT_PCM_I32
+};
+
+// TODO These are deprecated. Remove these aliases once all references are replaced.
+#define AAUDIO_FORMAT_PCM16    AAUDIO_FORMAT_PCM_I16
+#define AAUDIO_FORMAT_PCM824   AAUDIO_FORMAT_PCM_I8_24
+#define AAUDIO_FORMAT_PCM32    AAUDIO_FORMAT_PCM_I32
+
+enum {
+    AAUDIO_OK,
+    AAUDIO_ERROR_BASE = -900, // TODO review
+    AAUDIO_ERROR_DISCONNECTED,
+    AAUDIO_ERROR_ILLEGAL_ARGUMENT,
+    AAUDIO_ERROR_INCOMPATIBLE,
+    AAUDIO_ERROR_INTERNAL, // an underlying API returned an error code
+    AAUDIO_ERROR_INVALID_STATE,
+    AAUDIO_ERROR_UNEXPECTED_STATE,
+    AAUDIO_ERROR_UNEXPECTED_VALUE,
+    AAUDIO_ERROR_INVALID_HANDLE,
+    AAUDIO_ERROR_INVALID_QUERY,
+    AAUDIO_ERROR_UNIMPLEMENTED,
+    AAUDIO_ERROR_UNAVAILABLE,
+    AAUDIO_ERROR_NO_FREE_HANDLES,
+    AAUDIO_ERROR_NO_MEMORY,
+    AAUDIO_ERROR_NULL,
+    AAUDIO_ERROR_TIMEOUT,
+    AAUDIO_ERROR_WOULD_BLOCK,
+    AAUDIO_ERROR_INVALID_ORDER,
+    AAUDIO_ERROR_OUT_OF_RANGE,
+    AAUDIO_ERROR_NO_SERVICE
+};
+
+typedef enum {
+    AAUDIO_CLOCK_MONOTONIC, // Clock since booted, pauses when CPU is sleeping.
+    AAUDIO_CLOCK_BOOTTIME,  // Clock since booted, runs all the time.
+    AAUDIO_CLOCK_COUNT // This should always be last.
+} aaudio_clockid_t;
+
+typedef enum
+{
+    AAUDIO_STREAM_STATE_UNINITIALIZED = 0,
+    AAUDIO_STREAM_STATE_OPEN,
+    AAUDIO_STREAM_STATE_STARTING,
+    AAUDIO_STREAM_STATE_STARTED,
+    AAUDIO_STREAM_STATE_PAUSING,
+    AAUDIO_STREAM_STATE_PAUSED,
+    AAUDIO_STREAM_STATE_FLUSHING,
+    AAUDIO_STREAM_STATE_FLUSHED,
+    AAUDIO_STREAM_STATE_STOPPING,
+    AAUDIO_STREAM_STATE_STOPPED,
+    AAUDIO_STREAM_STATE_CLOSING,
+    AAUDIO_STREAM_STATE_CLOSED,
+} aaudio_stream_state_t;
+
+// TODO review API
+typedef enum {
+    /**
+     * This will use an AudioTrack object for playing audio
+     * and an AudioRecord for recording data.
+     */
+    AAUDIO_SHARING_MODE_LEGACY,
+    /**
+     * This will be the only stream using a particular source or sink.
+     * This mode will provide the lowest possible latency.
+     * You should close EXCLUSIVE streams immediately when you are not using them.
+     */
+    AAUDIO_SHARING_MODE_EXCLUSIVE,
+    /**
+     * Multiple applications will be mixed by the AAudio Server.
+     * This will have higher latency than the EXCLUSIVE mode.
+     */
+    AAUDIO_SHARING_MODE_SHARED,
+    /**
+     * Multiple applications will do their own mixing into a memory mapped buffer.
+     * It may be possible for malicious applications to read the data produced by
+     * other apps. So do not use this for private data such as telephony or messaging.
+     */
+    AAUDIO_SHARING_MODE_PUBLIC_MIX,
+    AAUDIO_SHARING_MODE_COUNT // This should always be last.
+} aaudio_sharing_mode_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // AAUDIO_AAUDIODEFINITIONS_H
diff --git a/media/libaaudio/include/aaudio/NOTICE b/media/libaaudio/include/aaudio/NOTICE
new file mode 100644
index 0000000..d6c0922
--- /dev/null
+++ b/media/libaaudio/include/aaudio/NOTICE
@@ -0,0 +1,13 @@
+Copyright (C) 2016 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/media/libaaudio/include/aaudio/README.md b/media/libaaudio/include/aaudio/README.md
new file mode 100644
index 0000000..8c4ae51
--- /dev/null
+++ b/media/libaaudio/include/aaudio/README.md
@@ -0,0 +1,4 @@
+AAudio Audio headers
+
+This folder contains the public header files.
+
diff --git a/media/libaaudio/libaaudio.map.txt b/media/libaaudio/libaaudio.map.txt
new file mode 100644
index 0000000..ecae991
--- /dev/null
+++ b/media/libaaudio/libaaudio.map.txt
@@ -0,0 +1,46 @@
+LIBAAUDIO {
+  global:
+    AAudio_getNanoseconds;
+    AAudio_convertResultToText;
+    AAudio_convertStreamStateToText;
+    AAudio_createStreamBuilder;
+    AAudioStreamBuilder_setDeviceId;
+    AAudioStreamBuilder_setSampleRate;
+    AAudioStreamBuilder_getSampleRate;
+    AAudioStreamBuilder_setSamplesPerFrame;
+    AAudioStreamBuilder_getSamplesPerFrame;
+    AAudioStreamBuilder_setFormat;
+    AAudioStreamBuilder_getFormat;
+    AAudioStreamBuilder_setSharingMode;
+    AAudioStreamBuilder_getSharingMode;
+    AAudioStreamBuilder_setDirection;
+    AAudioStreamBuilder_getDirection;
+    AAudioStreamBuilder_openStream;
+    AAudioStreamBuilder_delete;
+    AAudioStream_close;
+    AAudioStream_requestStart;
+    AAudioStream_requestPause;
+    AAudioStream_requestFlush;
+    AAudioStream_requestStop;
+    AAudioStream_getState;
+    AAudioStream_waitForStateChange;
+    AAudioStream_read;
+    AAudioStream_write;
+    AAudioStream_createThread;
+    AAudioStream_joinThread;
+    AAudioStream_setBufferSize;
+    AAudioStream_getBufferSize;
+    AAudioStream_getFramesPerBurst;
+    AAudioStream_getBufferCapacity;
+    AAudioStream_getXRunCount;
+    AAudioStream_getSampleRate;
+    AAudioStream_getSamplesPerFrame;
+    AAudioStream_getFormat;
+    AAudioStream_getSharingMode;
+    AAudioStream_getDirection;
+    AAudioStream_getFramesWritten;
+    AAudioStream_getFramesRead;
+    AAudioStream_getTimestamp;
+  local:
+    *;
+};
diff --git a/media/libaaudio/scripts/convert_oboe_aaudio.sh b/media/libaaudio/scripts/convert_oboe_aaudio.sh
new file mode 100755
index 0000000..2bf025a
--- /dev/null
+++ b/media/libaaudio/scripts/convert_oboe_aaudio.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+# Use SED to convert the Oboe API to the AAudio API
+
+echo "Convert Oboe names to AAudio names"
+
+echo "Top is ${ANDROID_BUILD_TOP}"
+LIBOBOE_DIR=${ANDROID_BUILD_TOP}/frameworks/av/media/liboboe
+echo "LIBOBOE_DIR is ${LIBOBOE_DIR}"
+OBOESERVICE_DIR=${ANDROID_BUILD_TOP}/frameworks/av/services/oboeservice
+echo "OBOESERVICE_DIR is ${OBOESERVICE_DIR}"
+OBOETEST_DIR=${ANDROID_BUILD_TOP}/cts/tests/tests/nativemedia/aaudio/src/
+echo "OBOETEST_DIR is ${OBOETEST_DIR}"
+
+function convertPathPattern {
+    path=$1
+    pattern=$2
+    find $path -type f  -name $pattern -exec sed -i -f ${LIBOBOE_DIR}/scripts/oboe_to_aaudio.sed {} \;
+}
+
+function convertPath {
+    path=$1
+    convertPathPattern $1 '*.cpp'
+    convertPathPattern $1 '*.h'
+    # the mk match does not work!
+    convertPathPattern $1 '*.mk'
+    convertPathPattern $1 '*.md'
+    convertPathPattern $1 '*.bp'
+}
+
+#convertPath ${LIBOBOE_DIR}/examples
+#convertPath ${LIBOBOE_DIR}/include
+#convertPath ${LIBOBOE_DIR}/src
+#convertPath ${LIBOBOE_DIR}/tests
+convertPath ${LIBOBOE_DIR}
+convertPathPattern ${LIBOBOE_DIR} Android.mk
+convertPathPattern ${LIBOBOE_DIR} liboboe.map.txt
+
+convertPath ${OBOESERVICE_DIR}
+convertPathPattern ${OBOESERVICE_DIR} Android.mk
+
+convertPathPattern ${OBOETEST_DIR} test_aaudio.cpp
+
+mv ${LIBOBOE_DIR}/include/oboe ${LIBOBOE_DIR}/include/aaudio
+mv ${LIBOBOE_DIR}/include/aaudio/OboeAudio.h ${LIBOBOE_DIR}/include/aaudio/AAudio.h
+mv ${OBOESERVICE_DIR}/OboeService.h ${OBOESERVICE_DIR}/AAudioServiceDefinitions.h
+mv ${LIBOBOE_DIR}/tests/test_oboe_api.cpp ${LIBOBOE_DIR}/tests/test_aaudio_api.cpp
+
+# Rename files with Oboe in the name.
+find -name "*OboeAudioService*.cpp"      | rename -v "s/OboeAudioService/AAudioService/g"
+find -name "*OboeAudioService*.h"      | rename -v "s/OboeAudioService/AAudioService/g"
+find -name "*Oboe*.cpp"      | rename -v "s/Oboe/AAudio/g"
+find -name "*Oboe*.h"        | rename -v "s/Oboe/AAudio/g"
diff --git a/media/libaaudio/scripts/oboe_to_aaudio.sed b/media/libaaudio/scripts/oboe_to_aaudio.sed
new file mode 100644
index 0000000..7da85a0
--- /dev/null
+++ b/media/libaaudio/scripts/oboe_to_aaudio.sed
@@ -0,0 +1,16 @@
+s/liboboe/libclarinet/g
+s/oboeservice/clarinetservice/g
+
+s/OboeAudio\.h/AAudio\.h/g
+s/OboeService\.h/AAudioServiceDefinitions\.h/g
+s/OboeAudioService/AAudioService/g
+s/LOG_TAG "OboeAudio"/LOG_TAG "AAudio"/g
+s/OBOE_AUDIO_FORMAT/AAUDIO_FORMAT/g
+s/OBOEAUDIO/AAUDIO/g
+
+s/oboe/aaudio/g
+s/Oboe/AAudio/g
+s/OBOE/AAUDIO/g
+
+s/libclarinet/liboboe/g
+s/clarinetservice/oboeservice/g
diff --git a/media/libaaudio/scripts/revert_all_aaudio.sh b/media/libaaudio/scripts/revert_all_aaudio.sh
new file mode 100755
index 0000000..de3fa7a
--- /dev/null
+++ b/media/libaaudio/scripts/revert_all_aaudio.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+echo "Revert Oboe names to AAudio names"
+
+echo "Top is ${ANDROID_BUILD_TOP}"
+LIBOBOE_DIR=${ANDROID_BUILD_TOP}/frameworks/av/media/liboboe
+echo "LIBOBOE_DIR is ${LIBOBOE_DIR}"
+OBOESERVICE_DIR=${ANDROID_BUILD_TOP}/frameworks/av/services/oboeservice
+echo "OBOESERVICE_DIR is ${OBOESERVICE_DIR}"
+OBOETEST_DIR=${ANDROID_BUILD_TOP}/cts/tests/tests/nativemedia/aaudio/src/
+echo "OBOETEST_DIR is ${OBOETEST_DIR}"
+
+git checkout -- ${LIBOBOE_DIR}/examples
+git checkout -- ${LIBOBOE_DIR}/include
+git checkout -- ${LIBOBOE_DIR}/src
+git checkout -- ${LIBOBOE_DIR}/tests
+git checkout -- ${LIBOBOE_DIR}/Android.bp
+git checkout -- ${LIBOBOE_DIR}/README.md
+git checkout -- ${LIBOBOE_DIR}/liboboe.map.txt
+git checkout -- ${OBOESERVICE_DIR}
+git checkout -- ${OBOETEST_DIR}
+
+rm -rf ${LIBOBOE_DIR}/include/aaudio
+
+find . -name "*aaudio*.cpp" -print -delete
+find . -name "*AAudio*.cpp" -print -delete
+find . -name "*AAudio*.h"   -print -delete
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
new file mode 100644
index 0000000..a016b49
--- /dev/null
+++ b/media/libaaudio/src/Android.mk
@@ -0,0 +1,108 @@
+LOCAL_PATH:= $(call my-dir)
+
+# ======================= STATIC LIBRARY ==========================
+# This is being built because it make AAudio testing very easy with a complete executable.
+# TODO Remove this target later, when not needed.
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libaaudio
+LOCAL_MODULE_TAGS := optional
+
+LIBAAUDIO_DIR := $(TOP)/frameworks/av/media/libaaudio
+LIBAAUDIO_SRC_DIR := $(LIBAAUDIO_DIR)/src
+
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/native/include \
+    system/core/base/include \
+    frameworks/native/media/libaaudio/include/include \
+    frameworks/av/media/libaaudio/include \
+    frameworks/native/include \
+    $(LOCAL_PATH) \
+    $(LOCAL_PATH)/binding \
+    $(LOCAL_PATH)/client \
+    $(LOCAL_PATH)/core \
+    $(LOCAL_PATH)/fifo \
+    $(LOCAL_PATH)/legacy \
+    $(LOCAL_PATH)/utility
+
+LOCAL_SRC_FILES = \
+    core/AudioStream.cpp \
+    core/AudioStreamBuilder.cpp \
+    core/AAudioAudio.cpp \
+    legacy/AudioStreamRecord.cpp \
+    legacy/AudioStreamTrack.cpp \
+    utility/HandleTracker.cpp \
+    utility/AAudioUtilities.cpp \
+    fifo/FifoBuffer.cpp \
+    fifo/FifoControllerBase.cpp \
+    client/AudioEndpoint.cpp \
+    client/AudioStreamInternal.cpp \
+    client/IsochronousClockModel.cpp \
+    binding/SharedMemoryParcelable.cpp \
+    binding/SharedRegionParcelable.cpp \
+    binding/RingBufferParcelable.cpp \
+    binding/AudioEndpointParcelable.cpp \
+    binding/AAudioStreamRequest.cpp \
+    binding/AAudioStreamConfiguration.cpp \
+    binding/IAAudioService.cpp
+
+LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
+
+# By default, all symbols are hidden.
+# LOCAL_CFLAGS += -fvisibility=hidden
+# AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
+LOCAL_CFLAGS += -DAAUDIO_API='__attribute__((visibility("default")))'
+
+include $(BUILD_STATIC_LIBRARY)
+
+# ======================= SHARED LIBRARY ==========================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libaaudio
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/native/include \
+    system/core/base/include \
+    frameworks/native/media/libaaudio/include/include \
+    frameworks/av/media/libaaudio/include \
+    $(LOCAL_PATH) \
+    $(LOCAL_PATH)/binding \
+    $(LOCAL_PATH)/client \
+    $(LOCAL_PATH)/core \
+    $(LOCAL_PATH)/fifo \
+    $(LOCAL_PATH)/legacy \
+    $(LOCAL_PATH)/utility
+
+LOCAL_SRC_FILES = core/AudioStream.cpp \
+    core/AudioStreamBuilder.cpp \
+    core/AAudioAudio.cpp \
+    legacy/AudioStreamRecord.cpp \
+    legacy/AudioStreamTrack.cpp \
+    utility/HandleTracker.cpp \
+    utility/AAudioUtilities.cpp \
+    fifo/FifoBuffer.cpp \
+    fifo/FifoControllerBase.cpp \
+    client/AudioEndpoint.cpp \
+    client/AudioStreamInternal.cpp \
+    client/IsochronousClockModel.cpp \
+    binding/SharedMemoryParcelable.cpp \
+    binding/SharedRegionParcelable.cpp \
+    binding/RingBufferParcelable.cpp \
+    binding/AudioEndpointParcelable.cpp \
+    binding/AAudioStreamRequest.cpp \
+    binding/AAudioStreamConfiguration.cpp \
+    binding/IAAudioService.cpp
+
+LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
+
+# By default, all symbols are hidden.
+# LOCAL_CFLAGS += -fvisibility=hidden
+# AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
+LOCAL_CFLAGS += -DAAUDIO_API='__attribute__((visibility("default")))'
+
+LOCAL_SHARED_LIBRARIES := libaudioclient liblog libcutils libutils libbinder
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libaaudio/src/binding/AAudioServiceDefinitions.h b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
new file mode 100644
index 0000000..ca637ef
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BINDING_AAUDIOSERVICEDEFINITIONS_H
+#define BINDING_AAUDIOSERVICEDEFINITIONS_H
+
+#include <stdint.h>
+#include <utils/RefBase.h>
+#include <binder/TextOutput.h>
+#include <binder/IInterface.h>
+
+#include <aaudio/AAudio.h>
+
+using android::NO_ERROR;
+using android::IBinder;
+
+namespace android {
+
+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
+};
+
+} // namespace android
+
+namespace aaudio {
+
+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
+    aaudio_sample_rate_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,
+    RATE_ISOCHRONOUS = 0x0001,
+    RATE_ASYNCHRONOUS = 0x0002,
+    COHERENCY_DMA = 0x0004,
+    COHERENCY_ACQUIRE_RELEASE = 0x0008,
+    COHERENCY_AUTO = 0x0010,
+};
+
+// This is not passed through Binder.
+// Client side code will convert Binder data and fill this descriptor.
+typedef struct RingBufferDescriptor_s {
+    uint8_t* dataAddress;       // offset from read or write block
+    int64_t* writeCounterAddress;
+    int64_t* readCounterAddress;
+    int32_t  bytesPerFrame;     // index is in frames
+    int32_t  framesPerBurst;    // for ISOCHRONOUS queues
+    int32_t  capacityInFrames;  // zero if unused
+    RingbufferFlags flags;
+} RingBufferDescriptor;
+
+// This is not passed through Binder.
+// Client side code will convert Binder data and fill this descriptor.
+typedef struct EndpointDescriptor_s {
+    // Set capacityInFrames to zero if Queue is unused.
+    RingBufferDescriptor upMessageQueueDescriptor;   // server to client
+    RingBufferDescriptor downMessageQueueDescriptor; // client to server
+    RingBufferDescriptor upDataQueueDescriptor;      // eg. record
+    RingBufferDescriptor downDataQueueDescriptor;    // eg. playback
+} EndpointDescriptor;
+
+} // namespace aaudio
+
+#endif //BINDING_AAUDIOSERVICEDEFINITIONS_H
diff --git a/media/libaaudio/src/binding/AAudioServiceMessage.h b/media/libaaudio/src/binding/AAudioServiceMessage.h
new file mode 100644
index 0000000..16cb5eb
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioServiceMessage.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAUDIO_AAUDIO_SERVICE_MESSAGE_H
+#define AAUDIO_AAUDIO_SERVICE_MESSAGE_H
+
+#include <stdint.h>
+
+#include <aaudio/AAudioDefinitions.h>
+
+namespace aaudio {
+
+// TODO move this an "include" folder for the service.
+
+struct AAudioMessageTimestamp {
+    aaudio_position_frames_t position;
+    int64_t                deviceOffset; // add to client position to get device position
+    aaudio_nanoseconds_t     timestamp;
+};
+
+typedef enum aaudio_service_event_e : uint32_t {
+    AAUDIO_SERVICE_EVENT_STARTED,
+    AAUDIO_SERVICE_EVENT_PAUSED,
+    AAUDIO_SERVICE_EVENT_FLUSHED,
+    AAUDIO_SERVICE_EVENT_CLOSED,
+    AAUDIO_SERVICE_EVENT_DISCONNECTED
+} aaudio_service_event_t;
+
+struct AAudioMessageEvent {
+    aaudio_service_event_t event;
+    int32_t data1;
+    int64_t data2;
+};
+
+typedef struct AAudioServiceMessage_s {
+    enum class code : uint32_t {
+        NOTHING,
+        TIMESTAMP,
+        EVENT,
+    };
+
+    code what;
+    union {
+        AAudioMessageTimestamp timestamp;
+        AAudioMessageEvent 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
new file mode 100644
index 0000000..fe3a59f
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <sys/mman.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include <aaudio/AAudioDefinitions.h>
+
+#include "binding/AAudioStreamConfiguration.h"
+
+using android::NO_ERROR;
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+using namespace aaudio;
+
+AAudioStreamConfiguration::AAudioStreamConfiguration() {}
+AAudioStreamConfiguration::~AAudioStreamConfiguration() {}
+
+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 AAudioStreamConfiguration::readFromParcel(const Parcel* parcel) {
+    int32_t temp;
+    parcel->readInt32(&mDeviceId);
+    parcel->readInt32(&mSampleRate);
+    parcel->readInt32(&mSamplesPerFrame);
+    parcel->readInt32(&temp);
+    mAudioFormat = (aaudio_audio_format_t) temp;
+    parcel->readInt32(&mBufferCapacity);
+    return NO_ERROR; // TODO check for errors above
+}
+
+aaudio_result_t AAudioStreamConfiguration::validate() {
+    // Validate results of the open.
+    if (mSampleRate < 0 || mSampleRate >= 8 * 48000) { // TODO review limits
+        ALOGE("AAudioStreamConfiguration.validate(): invalid sampleRate = %d", mSampleRate);
+        return AAUDIO_ERROR_INTERNAL;
+    }
+
+    if (mSamplesPerFrame < 1 || mSamplesPerFrame >= 32) { // TODO review limits
+        ALOGE("AAudioStreamConfiguration.validate() invalid samplesPerFrame = %d", mSamplesPerFrame);
+        return AAUDIO_ERROR_INTERNAL;
+    }
+
+    switch (mAudioFormat) {
+    case AAUDIO_FORMAT_PCM_I16:
+    case AAUDIO_FORMAT_PCM_FLOAT:
+    case AAUDIO_FORMAT_PCM_I8_24:
+    case AAUDIO_FORMAT_PCM_I32:
+        break;
+    default:
+        ALOGE("AAudioStreamConfiguration.validate() invalid audioFormat = %d", mAudioFormat);
+        return AAUDIO_ERROR_INTERNAL;
+    }
+
+    if (mBufferCapacity < 0) {
+        ALOGE("AAudioStreamConfiguration.validate() invalid mBufferCapacity = %d", mBufferCapacity);
+        return AAUDIO_ERROR_INTERNAL;
+    }
+    return AAUDIO_OK;
+}
+
+void AAudioStreamConfiguration::dump() {
+    ALOGD("AAudioStreamConfiguration mSampleRate      = %d -----", mSampleRate);
+    ALOGD("AAudioStreamConfiguration mSamplesPerFrame = %d", mSamplesPerFrame);
+    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
new file mode 100644
index 0000000..efcdae8
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BINDING_AAUDIO_STREAM_CONFIGURATION_H
+#define BINDING_AAUDIO_STREAM_CONFIGURATION_H
+
+#include <stdint.h>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <aaudio/AAudioDefinitions.h>
+
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+namespace aaudio {
+
+class AAudioStreamConfiguration : public Parcelable {
+public:
+    AAudioStreamConfiguration();
+    virtual ~AAudioStreamConfiguration();
+
+    aaudio_device_id_t getDeviceId() const {
+        return mDeviceId;
+    }
+
+    void setDeviceId(aaudio_device_id_t deviceId) {
+        mDeviceId = deviceId;
+    }
+
+    aaudio_sample_rate_t getSampleRate() const {
+        return mSampleRate;
+    }
+
+    void setSampleRate(aaudio_sample_rate_t sampleRate) {
+        mSampleRate = sampleRate;
+    }
+
+    int32_t getSamplesPerFrame() const {
+        return mSamplesPerFrame;
+    }
+
+    void setSamplesPerFrame(int32_t samplesPerFrame) {
+        mSamplesPerFrame = samplesPerFrame;
+    }
+
+    aaudio_audio_format_t getAudioFormat() const {
+        return mAudioFormat;
+    }
+
+    void setAudioFormat(aaudio_audio_format_t audioFormat) {
+        mAudioFormat = audioFormat;
+    }
+
+    aaudio_size_frames_t getBufferCapacity() const {
+        return mBufferCapacity;
+    }
+
+    void setBufferCapacity(aaudio_size_frames_t frames) {
+        mBufferCapacity = frames;
+    }
+
+    virtual status_t writeToParcel(Parcel* parcel) const override;
+
+    virtual status_t readFromParcel(const Parcel* parcel) override;
+
+    aaudio_result_t validate();
+
+    void dump();
+
+protected:
+    aaudio_device_id_t    mDeviceId        = AAUDIO_DEVICE_UNSPECIFIED;
+    aaudio_sample_rate_t  mSampleRate      = AAUDIO_UNSPECIFIED;
+    int32_t               mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+    aaudio_audio_format_t mAudioFormat     = AAUDIO_FORMAT_UNSPECIFIED;
+    aaudio_size_frames_t  mBufferCapacity  = AAUDIO_UNSPECIFIED;
+};
+
+} /* namespace aaudio */
+
+#endif //BINDING_AAUDIO_STREAM_CONFIGURATION_H
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
new file mode 100644
index 0000000..5202b73
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <sys/mman.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include <aaudio/AAudioDefinitions.h>
+
+#include "binding/AAudioStreamConfiguration.h"
+#include "binding/AAudioStreamRequest.h"
+
+using android::NO_ERROR;
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+using namespace aaudio;
+
+AAudioStreamRequest::AAudioStreamRequest()
+    : mConfiguration()
+    {}
+
+AAudioStreamRequest::~AAudioStreamRequest() {}
+
+status_t AAudioStreamRequest::writeToParcel(Parcel* parcel) const {
+    parcel->writeInt32((int32_t) mUserId);
+    parcel->writeInt32((int32_t) mProcessId);
+    mConfiguration.writeToParcel(parcel);
+    return NO_ERROR; // TODO check for errors above
+}
+
+status_t AAudioStreamRequest::readFromParcel(const Parcel* parcel) {
+    int32_t temp;
+    parcel->readInt32(&temp);
+    mUserId = (uid_t) temp;
+    parcel->readInt32(&temp);
+    mProcessId = (pid_t) temp;
+    mConfiguration.readFromParcel(parcel);
+    return NO_ERROR; // TODO check for errors above
+}
+
+aaudio_result_t AAudioStreamRequest::validate() {
+    return mConfiguration.validate();
+}
+
+void AAudioStreamRequest::dump() {
+    ALOGD("AAudioStreamRequest mUserId = %d -----", mUserId);
+    ALOGD("AAudioStreamRequest mProcessId = %d", mProcessId);
+    mConfiguration.dump();
+}
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
new file mode 100644
index 0000000..0fd28ba
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BINDING_AAUDIO_STREAM_REQUEST_H
+#define BINDING_AAUDIO_STREAM_REQUEST_H
+
+#include <stdint.h>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <aaudio/AAudioDefinitions.h>
+
+#include "binding/AAudioStreamConfiguration.h"
+
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+namespace aaudio {
+
+class AAudioStreamRequest : public Parcelable {
+public:
+    AAudioStreamRequest();
+    virtual ~AAudioStreamRequest();
+
+    uid_t getUserId() const {
+        return mUserId;
+    }
+
+    void setUserId(uid_t userId) {
+        mUserId = userId;
+    }
+
+    pid_t getProcessId() const {
+        return mProcessId;
+    }
+
+    void setProcessId(pid_t processId) {
+        mProcessId = processId;
+    }
+
+    AAudioStreamConfiguration &getConfiguration() {
+        return mConfiguration;
+    }
+
+    virtual status_t writeToParcel(Parcel* parcel) const override;
+
+    virtual status_t readFromParcel(const Parcel* parcel) override;
+
+    aaudio_result_t validate();
+
+    void dump();
+
+protected:
+    AAudioStreamConfiguration  mConfiguration;
+    uid_t    mUserId;
+    pid_t    mProcessId;
+};
+
+} /* namespace aaudio */
+
+#endif //BINDING_AAUDIO_STREAM_REQUEST_H
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
new file mode 100644
index 0000000..f40ee02
--- /dev/null
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <sys/mman.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include "binding/AAudioServiceDefinitions.h"
+#include "binding/RingBufferParcelable.h"
+#include "binding/AudioEndpointParcelable.h"
+
+using android::NO_ERROR;
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+using namespace aaudio;
+
+/**
+ * Container for information about the message queues plus
+ * general stream information needed by AAudio clients.
+ * It contains no addresses, just sizes, offsets and file descriptors for
+ * shared memory that can be passed through Binder.
+ */
+AudioEndpointParcelable::AudioEndpointParcelable() {}
+
+AudioEndpointParcelable::~AudioEndpointParcelable() {}
+
+/**
+ * Add the file descriptor to the table.
+ * @return index in table or negative error
+ */
+int32_t AudioEndpointParcelable::addFileDescriptor(int fd, int32_t sizeInBytes) {
+    if (mNumSharedMemories >= MAX_SHARED_MEMORIES) {
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+    int32_t index = mNumSharedMemories++;
+    mSharedMemories[index].setup(fd, sizeInBytes);
+    return index;
+}
+
+/**
+ * The read and write must be symmetric.
+ */
+status_t AudioEndpointParcelable::writeToParcel(Parcel* parcel) const {
+    parcel->writeInt32(mNumSharedMemories);
+    for (int i = 0; i < mNumSharedMemories; i++) {
+        mSharedMemories[i].writeToParcel(parcel);
+    }
+    mUpMessageQueueParcelable.writeToParcel(parcel);
+    mDownMessageQueueParcelable.writeToParcel(parcel);
+    mUpDataQueueParcelable.writeToParcel(parcel);
+    mDownDataQueueParcelable.writeToParcel(parcel);
+    return NO_ERROR; // TODO check for errors above
+}
+
+status_t AudioEndpointParcelable::readFromParcel(const Parcel* parcel) {
+    parcel->readInt32(&mNumSharedMemories);
+    for (int i = 0; i < mNumSharedMemories; i++) {
+        mSharedMemories[i].readFromParcel(parcel);
+    }
+    mUpMessageQueueParcelable.readFromParcel(parcel);
+    mDownMessageQueueParcelable.readFromParcel(parcel);
+    mUpDataQueueParcelable.readFromParcel(parcel);
+    mDownDataQueueParcelable.readFromParcel(parcel);
+    return NO_ERROR; // TODO check for errors above
+}
+
+aaudio_result_t AudioEndpointParcelable::resolve(EndpointDescriptor *descriptor) {
+    // TODO error check
+    mUpMessageQueueParcelable.resolve(mSharedMemories, &descriptor->upMessageQueueDescriptor);
+    mDownMessageQueueParcelable.resolve(mSharedMemories,
+                                        &descriptor->downMessageQueueDescriptor);
+    mUpDataQueueParcelable.resolve(mSharedMemories, &descriptor->upDataQueueDescriptor);
+    mDownDataQueueParcelable.resolve(mSharedMemories, &descriptor->downDataQueueDescriptor);
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioEndpointParcelable::validate() {
+    aaudio_result_t result;
+    if (mNumSharedMemories < 0 || mNumSharedMemories >= MAX_SHARED_MEMORIES) {
+        ALOGE("AudioEndpointParcelable invalid mNumSharedMemories = %d", mNumSharedMemories);
+        return AAUDIO_ERROR_INTERNAL;
+    }
+    for (int i = 0; i < mNumSharedMemories; i++) {
+        result = mSharedMemories[i].validate();
+        if (result != AAUDIO_OK) {
+            return result;
+        }
+    }
+    if ((result = mUpMessageQueueParcelable.validate()) != AAUDIO_OK) {
+        ALOGE("AudioEndpointParcelable invalid mUpMessageQueueParcelable = %d", result);
+        return result;
+    }
+    if ((result = mDownMessageQueueParcelable.validate()) != AAUDIO_OK) {
+        ALOGE("AudioEndpointParcelable invalid mDownMessageQueueParcelable = %d", result);
+        return result;
+    }
+    if ((result = mUpDataQueueParcelable.validate()) != AAUDIO_OK) {
+        ALOGE("AudioEndpointParcelable invalid mUpDataQueueParcelable = %d", result);
+        return result;
+    }
+    if ((result = mDownDataQueueParcelable.validate()) != AAUDIO_OK) {
+        ALOGE("AudioEndpointParcelable invalid mDownDataQueueParcelable = %d", result);
+        return result;
+    }
+    return AAUDIO_OK;
+}
+
+void AudioEndpointParcelable::dump() {
+    ALOGD("AudioEndpointParcelable ======================================= BEGIN");
+    ALOGD("AudioEndpointParcelable mNumSharedMemories = %d", mNumSharedMemories);
+    for (int i = 0; i < mNumSharedMemories; i++) {
+        mSharedMemories[i].dump();
+    }
+    ALOGD("AudioEndpointParcelable mUpMessageQueueParcelable =========");
+    mUpMessageQueueParcelable.dump();
+    ALOGD("AudioEndpointParcelable mDownMessageQueueParcelable =======");
+    mDownMessageQueueParcelable.dump();
+    ALOGD("AudioEndpointParcelable mUpDataQueueParcelable ============");
+    mUpDataQueueParcelable.dump();
+    ALOGD("AudioEndpointParcelable mDownDataQueueParcelable ==========");
+    mDownDataQueueParcelable.dump();
+    ALOGD("AudioEndpointParcelable ======================================= END");
+}
+
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.h b/media/libaaudio/src/binding/AudioEndpointParcelable.h
new file mode 100644
index 0000000..d4646d0
--- /dev/null
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BINDING_AUDIOENDPOINTPARCELABLE_H
+#define BINDING_AUDIOENDPOINTPARCELABLE_H
+
+#include <stdint.h>
+
+//#include <sys/mman.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+#include "binding/AAudioServiceDefinitions.h"
+#include "binding/RingBufferParcelable.h"
+
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+namespace aaudio {
+
+/**
+ * Container for information about the message queues plus
+ * general stream information needed by AAudio clients.
+ * It contains no addresses, just sizes, offsets and file descriptors for
+ * shared memory that can be passed through Binder.
+ */
+class AudioEndpointParcelable : public Parcelable {
+public:
+    AudioEndpointParcelable();
+    virtual ~AudioEndpointParcelable();
+
+    /**
+     * Add the file descriptor to the table.
+     * @return index in table or negative error
+     */
+    int32_t addFileDescriptor(int fd, int32_t sizeInBytes);
+
+    virtual status_t writeToParcel(Parcel* parcel) const override;
+
+    virtual status_t readFromParcel(const Parcel* parcel) override;
+
+    aaudio_result_t resolve(EndpointDescriptor *descriptor);
+
+    aaudio_result_t validate();
+
+    void dump();
+
+public: // TODO add getters
+    // Set capacityInFrames to zero if Queue is unused.
+    RingBufferParcelable    mUpMessageQueueParcelable;   // server to client
+    RingBufferParcelable    mDownMessageQueueParcelable; // to server
+    RingBufferParcelable    mUpDataQueueParcelable;      // eg. record, could share same queue
+    RingBufferParcelable    mDownDataQueueParcelable;    // eg. playback
+
+private:
+    int32_t                 mNumSharedMemories = 0;
+    SharedMemoryParcelable  mSharedMemories[MAX_SHARED_MEMORIES];
+};
+
+} /* namespace aaudio */
+
+#endif //BINDING_AUDIOENDPOINTPARCELABLE_H
diff --git a/media/libaaudio/src/binding/IAAudioService.cpp b/media/libaaudio/src/binding/IAAudioService.cpp
new file mode 100644
index 0000000..899ebc0
--- /dev/null
+++ b/media/libaaudio/src/binding/IAAudioService.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aaudio/AAudioDefinitions.h>
+
+#include "binding/AudioEndpointParcelable.h"
+#include "binding/AAudioStreamRequest.h"
+#include "binding/AAudioStreamConfiguration.h"
+#include "binding/IAAudioService.h"
+#include "utility/AAudioUtilities.h"
+
+namespace android {
+
+/**
+ * This is used by the AAudio Client to talk to the AAudio Service.
+ *
+ * The order of parameters in the Parcels must match with code in AAudioService.cpp.
+ */
+class BpAAudioService : public BpInterface<IAAudioService>
+{
+public:
+    explicit BpAAudioService(const sp<IBinder>& impl)
+        : BpInterface<IAAudioService>(impl)
+    {
+    }
+
+    virtual aaudio_handle_t openStream(aaudio::AAudioStreamRequest &request,
+                                     aaudio::AAudioStreamConfiguration &configuration) override {
+        Parcel data, reply;
+        // send command
+        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
+        request.writeToParcel(&data);
+        status_t err = remote()->transact(OPEN_STREAM, data, &reply);
+        if (err != NO_ERROR) {
+            return AAudioConvert_androidToAAudioResult(err);
+        }
+        // parse reply
+        aaudio_handle_t stream;
+        reply.readInt32(&stream);
+        configuration.readFromParcel(&reply);
+        return stream;
+    }
+
+    virtual aaudio_result_t closeStream(aaudio_handle_t streamHandle) override {
+        Parcel data, reply;
+        // send command
+        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
+        data.writeInt32(streamHandle);
+        status_t err = remote()->transact(CLOSE_STREAM, data, &reply);
+        if (err != NO_ERROR) {
+            return AAudioConvert_androidToAAudioResult(err);
+        }
+        // parse reply
+        aaudio_result_t res;
+        reply.readInt32(&res);
+        return res;
+    }
+
+    virtual aaudio_result_t getStreamDescription(aaudio_handle_t streamHandle,
+                                               aaudio::AudioEndpointParcelable &parcelable)   {
+        Parcel data, reply;
+        // send command
+        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
+        data.writeInt32(streamHandle);
+        status_t err = remote()->transact(GET_STREAM_DESCRIPTION, data, &reply);
+        if (err != NO_ERROR) {
+            return AAudioConvert_androidToAAudioResult(err);
+        }
+        // parse reply
+        parcelable.readFromParcel(&reply);
+        parcelable.dump();
+        aaudio_result_t result = parcelable.validate();
+        if (result != AAUDIO_OK) {
+            return result;
+        }
+        reply.readInt32(&result);
+        return result;
+    }
+
+    // TODO should we wait for a reply?
+    virtual aaudio_result_t startStream(aaudio_handle_t streamHandle) override {
+        Parcel data, reply;
+        // send command
+        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
+        data.writeInt32(streamHandle);
+        status_t err = remote()->transact(START_STREAM, data, &reply);
+        if (err != NO_ERROR) {
+            return AAudioConvert_androidToAAudioResult(err);
+        }
+        // parse reply
+        aaudio_result_t res;
+        reply.readInt32(&res);
+        return res;
+    }
+
+    virtual aaudio_result_t pauseStream(aaudio_handle_t streamHandle) override {
+        Parcel data, reply;
+        // send command
+        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
+        data.writeInt32(streamHandle);
+        status_t err = remote()->transact(PAUSE_STREAM, data, &reply);
+        if (err != NO_ERROR) {
+            return AAudioConvert_androidToAAudioResult(err);
+        }
+        // parse reply
+        aaudio_result_t res;
+        reply.readInt32(&res);
+        return res;
+    }
+
+    virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle) override {
+        Parcel data, reply;
+        // send command
+        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
+        data.writeInt32(streamHandle);
+        status_t err = remote()->transact(FLUSH_STREAM, data, &reply);
+        if (err != NO_ERROR) {
+            return AAudioConvert_androidToAAudioResult(err);
+        }
+        // parse reply
+        aaudio_result_t res;
+        reply.readInt32(&res);
+        return res;
+    }
+
+    virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle, pid_t clientThreadId,
+                                              aaudio_nanoseconds_t periodNanoseconds)
+    override {
+        Parcel data, reply;
+        // send command
+        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
+        data.writeInt32(streamHandle);
+        data.writeInt32((int32_t) clientThreadId);
+        data.writeInt64(periodNanoseconds);
+        status_t err = remote()->transact(REGISTER_AUDIO_THREAD, data, &reply);
+        if (err != NO_ERROR) {
+            return AAudioConvert_androidToAAudioResult(err);
+        }
+        // parse reply
+        aaudio_result_t res;
+        reply.readInt32(&res);
+        return res;
+    }
+
+    virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle, pid_t clientThreadId)
+    override {
+        Parcel data, reply;
+        // send command
+        data.writeInterfaceToken(IAAudioService::getInterfaceDescriptor());
+        data.writeInt32(streamHandle);
+        data.writeInt32((int32_t) clientThreadId);
+        status_t err = remote()->transact(UNREGISTER_AUDIO_THREAD, data, &reply);
+        if (err != NO_ERROR) {
+            return AAudioConvert_androidToAAudioResult(err);
+        }
+        // parse reply
+        aaudio_result_t res;
+        reply.readInt32(&res);
+        return res;
+    }
+
+};
+
+// Implement an interface to the service.
+// This is here so that you don't have to link with liboboe static library.
+IMPLEMENT_META_INTERFACE(AAudioService, "IAAudioService");
+
+// The order of parameters in the Parcels must match with code in BpAAudioService
+
+status_t BnAAudioService::onTransact(uint32_t code, const Parcel& data,
+                                        Parcel* reply, uint32_t flags) {
+    AAudioStream stream;
+    aaudio::AAudioStreamRequest request;
+    aaudio::AAudioStreamConfiguration configuration;
+    pid_t pid;
+    aaudio_nanoseconds_t nanoseconds;
+    aaudio_result_t result;
+    ALOGV("BnAAudioService::onTransact(%i) %i", code, flags);
+    data.checkInterface(this);
+
+    switch(code) {
+        case OPEN_STREAM: {
+            request.readFromParcel(&data);
+            stream = openStream(request, configuration);
+            ALOGD("BnAAudioService::onTransact OPEN_STREAM server handle = 0x%08X", stream);
+            reply->writeInt32(stream);
+            configuration.writeToParcel(reply);
+            return NO_ERROR;
+        } break;
+
+        case CLOSE_STREAM: {
+            data.readInt32(&stream);
+            ALOGD("BnAAudioService::onTransact CLOSE_STREAM 0x%08X", stream);
+            result = closeStream(stream);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+
+        case GET_STREAM_DESCRIPTION: {
+            data.readInt32(&stream);
+            ALOGD("BnAAudioService::onTransact GET_STREAM_DESCRIPTION 0x%08X", stream);
+            aaudio::AudioEndpointParcelable parcelable;
+            result = getStreamDescription(stream, parcelable);
+            if (result != AAUDIO_OK) {
+                return AAudioConvert_aaudioToAndroidStatus(result);
+            }
+            parcelable.dump();
+            result = parcelable.validate();
+            if (result != AAUDIO_OK) {
+                return AAudioConvert_aaudioToAndroidStatus(result);
+            }
+            parcelable.writeToParcel(reply);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+
+        case START_STREAM: {
+            data.readInt32(&stream);
+            result = startStream(stream);
+            ALOGD("BnAAudioService::onTransact START_STREAM 0x%08X, result = %d",
+                    stream, result);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+
+        case PAUSE_STREAM: {
+            data.readInt32(&stream);
+            result = pauseStream(stream);
+            ALOGD("BnAAudioService::onTransact PAUSE_STREAM 0x%08X, result = %d",
+                    stream, result);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+
+        case FLUSH_STREAM: {
+            data.readInt32(&stream);
+            result = flushStream(stream);
+            ALOGD("BnAAudioService::onTransact FLUSH_STREAM 0x%08X, result = %d",
+                    stream, result);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+
+        case REGISTER_AUDIO_THREAD: {
+            data.readInt32(&stream);
+            data.readInt32(&pid);
+            data.readInt64(&nanoseconds);
+            result = registerAudioThread(stream, pid, nanoseconds);
+            ALOGD("BnAAudioService::onTransact REGISTER_AUDIO_THREAD 0x%08X, result = %d",
+                    stream, result);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+
+        case UNREGISTER_AUDIO_THREAD: {
+            data.readInt32(&stream);
+            data.readInt32(&pid);
+            result = unregisterAudioThread(stream, pid);
+            ALOGD("BnAAudioService::onTransact UNREGISTER_AUDIO_THREAD 0x%08X, result = %d",
+                    stream, result);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+
+        default:
+            // ALOGW("BnAAudioService::onTransact not handled %u", code);
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+} /* namespace android */
diff --git a/media/libaaudio/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h
new file mode 100644
index 0000000..f3b297e
--- /dev/null
+++ b/media/libaaudio/src/binding/IAAudioService.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BINDING_IAAUDIOSERVICE_H
+#define BINDING_IAAUDIOSERVICE_H
+
+#include <stdint.h>
+#include <utils/RefBase.h>
+#include <binder/TextOutput.h>
+#include <binder/IInterface.h>
+
+#include <aaudio/AAudio.h>
+
+#include "binding/AAudioServiceDefinitions.h"
+#include "binding/AudioEndpointParcelable.h"
+#include "binding/AAudioStreamRequest.h"
+#include "binding/AAudioStreamConfiguration.h"
+
+
+namespace android {
+
+// Interface (our AIDL) - Shared by server and client
+class IAAudioService : public IInterface {
+public:
+
+    DECLARE_META_INTERFACE(AAudioService);
+
+    /**
+     * @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(aaudio::AAudioStreamRequest &request,
+                                     aaudio::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,
+                                               aaudio::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 clientThreadId,
+                                              aaudio_nanoseconds_t periodNanoseconds) = 0;
+
+    virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+                                                pid_t clientThreadId) = 0;
+};
+
+class BnAAudioService : public BnInterface<IAAudioService> {
+public:
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+                                Parcel* reply, uint32_t flags = 0);
+
+};
+
+} /* namespace android */
+
+#endif //BINDING_IAAUDIOSERVICE_H
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.cpp b/media/libaaudio/src/binding/RingBufferParcelable.cpp
new file mode 100644
index 0000000..3a92929
--- /dev/null
+++ b/media/libaaudio/src/binding/RingBufferParcelable.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <binder/Parcelable.h>
+
+#include "binding/AAudioServiceDefinitions.h"
+#include "binding/SharedRegionParcelable.h"
+#include "binding/RingBufferParcelable.h"
+
+using namespace aaudio;
+
+RingBufferParcelable::RingBufferParcelable() {}
+RingBufferParcelable::~RingBufferParcelable() {}
+
+// TODO This assumes that all three use the same SharedMemoryParcelable
+void RingBufferParcelable::setupMemory(int32_t sharedMemoryIndex,
+                 int32_t dataMemoryOffset,
+                 int32_t dataSizeInBytes,
+                 int32_t readCounterOffset,
+                 int32_t writeCounterOffset,
+                 int32_t counterSizeBytes) {
+    mReadCounterParcelable.setup(sharedMemoryIndex, readCounterOffset, counterSizeBytes);
+    mWriteCounterParcelable.setup(sharedMemoryIndex, writeCounterOffset, counterSizeBytes);
+    mDataParcelable.setup(sharedMemoryIndex, dataMemoryOffset, dataSizeInBytes);
+}
+
+void RingBufferParcelable::setupMemory(int32_t sharedMemoryIndex,
+                 int32_t dataMemoryOffset,
+                 int32_t dataSizeInBytes) {
+    mReadCounterParcelable.setup(sharedMemoryIndex, 0, 0);
+    mWriteCounterParcelable.setup(sharedMemoryIndex, 0, 0);
+    mDataParcelable.setup(sharedMemoryIndex, dataMemoryOffset, dataSizeInBytes);
+}
+
+int32_t RingBufferParcelable::getBytesPerFrame() {
+    return mBytesPerFrame;
+}
+
+void RingBufferParcelable::setBytesPerFrame(int32_t bytesPerFrame) {
+    mBytesPerFrame = bytesPerFrame;
+}
+
+int32_t RingBufferParcelable::getFramesPerBurst() {
+    return mFramesPerBurst;
+}
+
+void RingBufferParcelable::setFramesPerBurst(int32_t framesPerBurst) {
+    mFramesPerBurst = framesPerBurst;
+}
+
+int32_t RingBufferParcelable::getCapacityInFrames() {
+    return mCapacityInFrames;
+}
+
+void RingBufferParcelable::setCapacityInFrames(int32_t capacityInFrames) {
+    mCapacityInFrames = capacityInFrames;
+}
+
+/**
+ * The read and write must be symmetric.
+ */
+status_t RingBufferParcelable::writeToParcel(Parcel* parcel) const {
+    parcel->writeInt32(mCapacityInFrames);
+    if (mCapacityInFrames > 0) {
+        parcel->writeInt32(mBytesPerFrame);
+        parcel->writeInt32(mFramesPerBurst);
+        parcel->writeInt32(mFlags);
+        mReadCounterParcelable.writeToParcel(parcel);
+        mWriteCounterParcelable.writeToParcel(parcel);
+        mDataParcelable.writeToParcel(parcel);
+    }
+    return NO_ERROR; // TODO check for errors above
+}
+
+status_t RingBufferParcelable::readFromParcel(const Parcel* parcel) {
+    parcel->readInt32(&mCapacityInFrames);
+    if (mCapacityInFrames > 0) {
+        parcel->readInt32(&mBytesPerFrame);
+        parcel->readInt32(&mFramesPerBurst);
+        parcel->readInt32((int32_t *)&mFlags);
+        mReadCounterParcelable.readFromParcel(parcel);
+        mWriteCounterParcelable.readFromParcel(parcel);
+        mDataParcelable.readFromParcel(parcel);
+    }
+    return NO_ERROR; // TODO check for errors above
+}
+
+aaudio_result_t RingBufferParcelable::resolve(SharedMemoryParcelable *memoryParcels, RingBufferDescriptor *descriptor) {
+    aaudio_result_t result;
+
+    result = mReadCounterParcelable.resolve(memoryParcels,
+                                            (void **) &descriptor->readCounterAddress);
+    if (result != AAUDIO_OK) {
+        return result;
+    }
+
+    result = mWriteCounterParcelable.resolve(memoryParcels,
+                                             (void **) &descriptor->writeCounterAddress);
+    if (result != AAUDIO_OK) {
+        return result;
+    }
+
+    result = mDataParcelable.resolve(memoryParcels, (void **) &descriptor->dataAddress);
+    if (result != AAUDIO_OK) {
+        return result;
+    }
+
+    descriptor->bytesPerFrame = mBytesPerFrame;
+    descriptor->framesPerBurst = mFramesPerBurst;
+    descriptor->capacityInFrames = mCapacityInFrames;
+    descriptor->flags = mFlags;
+    return AAUDIO_OK;
+}
+
+aaudio_result_t RingBufferParcelable::validate() {
+    aaudio_result_t result;
+    if (mCapacityInFrames < 0 || mCapacityInFrames >= 32 * 1024) {
+        ALOGE("RingBufferParcelable invalid mCapacityInFrames = %d", mCapacityInFrames);
+        return AAUDIO_ERROR_INTERNAL;
+    }
+    if (mBytesPerFrame < 0 || mBytesPerFrame >= 256) {
+        ALOGE("RingBufferParcelable invalid mBytesPerFrame = %d", mBytesPerFrame);
+        return AAUDIO_ERROR_INTERNAL;
+    }
+    if (mFramesPerBurst < 0 || mFramesPerBurst >= 1024) {
+        ALOGE("RingBufferParcelable invalid mFramesPerBurst = %d", mFramesPerBurst);
+        return AAUDIO_ERROR_INTERNAL;
+    }
+    if ((result = mReadCounterParcelable.validate()) != AAUDIO_OK) {
+        ALOGE("RingBufferParcelable invalid mReadCounterParcelable = %d", result);
+        return result;
+    }
+    if ((result = mWriteCounterParcelable.validate()) != AAUDIO_OK) {
+        ALOGE("RingBufferParcelable invalid mWriteCounterParcelable = %d", result);
+        return result;
+    }
+    if ((result = mDataParcelable.validate()) != AAUDIO_OK) {
+        ALOGE("RingBufferParcelable invalid mDataParcelable = %d", result);
+        return result;
+    }
+    return AAUDIO_OK;
+}
+
+
+void RingBufferParcelable::dump() {
+    ALOGD("RingBufferParcelable mCapacityInFrames = %d ---------", mCapacityInFrames);
+    if (mCapacityInFrames > 0) {
+        ALOGD("RingBufferParcelable mBytesPerFrame = %d", mBytesPerFrame);
+        ALOGD("RingBufferParcelable mFramesPerBurst = %d", mFramesPerBurst);
+        ALOGD("RingBufferParcelable mFlags = %u", mFlags);
+        mReadCounterParcelable.dump();
+        mWriteCounterParcelable.dump();
+        mDataParcelable.dump();
+    }
+}
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.h b/media/libaaudio/src/binding/RingBufferParcelable.h
new file mode 100644
index 0000000..3f82c79
--- /dev/null
+++ b/media/libaaudio/src/binding/RingBufferParcelable.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BINDING_RINGBUFFER_PARCELABLE_H
+#define BINDING_RINGBUFFER_PARCELABLE_H
+
+#include <stdint.h>
+
+#include <binder/Parcelable.h>
+
+#include "binding/AAudioServiceDefinitions.h"
+#include "binding/SharedRegionParcelable.h"
+
+namespace aaudio {
+
+class RingBufferParcelable : public Parcelable {
+public:
+    RingBufferParcelable();
+    virtual ~RingBufferParcelable();
+
+    // TODO This assumes that all three use the same SharedMemoryParcelable
+    void setupMemory(int32_t sharedMemoryIndex,
+                     int32_t dataMemoryOffset,
+                     int32_t dataSizeInBytes,
+                     int32_t readCounterOffset,
+                     int32_t writeCounterOffset,
+                     int32_t counterSizeBytes);
+
+    void setupMemory(int32_t sharedMemoryIndex,
+                     int32_t dataMemoryOffset,
+                     int32_t dataSizeInBytes);
+
+    int32_t getBytesPerFrame();
+
+    void setBytesPerFrame(int32_t bytesPerFrame);
+
+    int32_t getFramesPerBurst();
+
+    void setFramesPerBurst(int32_t framesPerBurst);
+
+    int32_t getCapacityInFrames();
+
+    void setCapacityInFrames(int32_t capacityInFrames);
+
+    /**
+     * The read and write must be symmetric.
+     */
+    virtual status_t writeToParcel(Parcel* parcel) const override;
+
+    virtual status_t readFromParcel(const Parcel* parcel) override;
+
+    aaudio_result_t resolve(SharedMemoryParcelable *memoryParcels, RingBufferDescriptor *descriptor);
+
+    aaudio_result_t validate();
+
+    void dump();
+
+private:
+    SharedRegionParcelable  mReadCounterParcelable;
+    SharedRegionParcelable  mWriteCounterParcelable;
+    SharedRegionParcelable  mDataParcelable;
+    int32_t                 mBytesPerFrame = 0;     // index is in frames
+    int32_t                 mFramesPerBurst = 0;    // for ISOCHRONOUS queues
+    int32_t                 mCapacityInFrames = 0;  // zero if unused
+    RingbufferFlags         mFlags = RingbufferFlags::NONE;
+};
+
+} /* namespace aaudio */
+
+#endif //BINDING_RINGBUFFER_PARCELABLE_H
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
new file mode 100644
index 0000000..1102dec
--- /dev/null
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <sys/mman.h>
+#include <aaudio/AAudioDefinitions.h>
+
+#include <binder/Parcelable.h>
+
+#include "binding/SharedMemoryParcelable.h"
+
+using android::NO_ERROR;
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+using namespace aaudio;
+
+SharedMemoryParcelable::SharedMemoryParcelable() {}
+SharedMemoryParcelable::~SharedMemoryParcelable() {};
+
+void SharedMemoryParcelable::setup(int fd, int32_t sizeInBytes) {
+    mFd = fd;
+    mSizeInBytes = sizeInBytes;
+}
+
+status_t SharedMemoryParcelable::writeToParcel(Parcel* parcel) const {
+    parcel->writeInt32(mSizeInBytes);
+    if (mSizeInBytes > 0) {
+        parcel->writeDupFileDescriptor(mFd);
+    }
+    return NO_ERROR; // TODO check for errors above
+}
+
+status_t SharedMemoryParcelable::readFromParcel(const Parcel* parcel) {
+    parcel->readInt32(&mSizeInBytes);
+    if (mSizeInBytes > 0) {
+        mFd = dup(parcel->readFileDescriptor());
+    }
+    return NO_ERROR; // TODO check for errors above
+}
+
+// TODO Add code to unmmap()
+
+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;
+    } else if ((offsetInBytes + sizeInBytes) > mSizeInBytes) {
+        ALOGE("SharedMemoryParcelable out of range, offsetInBytes = %d, "
+              "sizeInBytes = %d, mSizeInBytes = %d",
+              offsetInBytes, sizeInBytes, mSizeInBytes);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+    if (mResolvedAddress == nullptr) {
+        mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ|PROT_WRITE,
+                                          MAP_SHARED, mFd, 0);
+        if (mResolvedAddress == nullptr) {
+            ALOGE("SharedMemoryParcelable mmap failed for fd = %d", mFd);
+            return AAUDIO_ERROR_INTERNAL;
+        }
+    }
+    *regionAddressPtr = mResolvedAddress + offsetInBytes;
+    ALOGD("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
+    ALOGD("SharedMemoryParcelable offset by %d, *regionAddressPtr = %p",
+          offsetInBytes, *regionAddressPtr);
+    return AAUDIO_OK;
+}
+
+int32_t SharedMemoryParcelable::getSizeInBytes() {
+    return mSizeInBytes;
+}
+
+aaudio_result_t SharedMemoryParcelable::validate() {
+    if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
+        ALOGE("SharedMemoryParcelable invalid mSizeInBytes = %d", mSizeInBytes);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+    if (mSizeInBytes > 0) {
+        if (mFd == -1) {
+            ALOGE("SharedMemoryParcelable uninitialized mFd = %d", mFd);
+            return AAUDIO_ERROR_INTERNAL;
+        }
+    }
+    return AAUDIO_OK;
+}
+
+void SharedMemoryParcelable::dump() {
+    ALOGD("SharedMemoryParcelable mFd = %d", mFd);
+    ALOGD("SharedMemoryParcelable mSizeInBytes = %d", mSizeInBytes);
+    ALOGD("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
+}
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.h b/media/libaaudio/src/binding/SharedMemoryParcelable.h
new file mode 100644
index 0000000..7e0bf1a
--- /dev/null
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BINDING_SHAREDMEMORYPARCELABLE_H
+#define BINDING_SHAREDMEMORYPARCELABLE_H
+
+#include <stdint.h>
+
+#include <sys/mman.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+namespace aaudio {
+
+// Arbitrary limits for sanity checks. TODO remove after debugging.
+#define MAX_SHARED_MEMORIES (32)
+#define MAX_MMAP_OFFSET_BYTES (32 * 1024 * 8)
+#define MAX_MMAP_SIZE_BYTES (32 * 1024 * 8)
+
+/**
+ * This is a parcelable description of a shared memory referenced by a file descriptor.
+ * It may be divided into several regions.
+ */
+class SharedMemoryParcelable : public Parcelable {
+public:
+    SharedMemoryParcelable();
+    virtual ~SharedMemoryParcelable();
+
+    void setup(int fd, int32_t sizeInBytes);
+
+    virtual status_t writeToParcel(Parcel* parcel) const override;
+
+    virtual status_t readFromParcel(const Parcel* parcel) override;
+
+    aaudio_result_t resolve(int32_t offsetInBytes, int32_t sizeInBytes, void **regionAddressPtr);
+
+    int32_t getSizeInBytes();
+
+    aaudio_result_t validate();
+
+    void dump();
+
+protected:
+    int mFd = -1;
+    int32_t mSizeInBytes = 0;
+    uint8_t *mResolvedAddress = nullptr;
+};
+
+} /* namespace aaudio */
+
+#endif //BINDING_SHAREDMEMORYPARCELABLE_H
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.cpp b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
new file mode 100644
index 0000000..8ca0023
--- /dev/null
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <sys/mman.h>
+#include <binder/Parcelable.h>
+
+#include <aaudio/AAudioDefinitions.h>
+
+#include "binding/SharedMemoryParcelable.h"
+#include "binding/SharedRegionParcelable.h"
+
+using android::NO_ERROR;
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+using namespace aaudio;
+
+SharedRegionParcelable::SharedRegionParcelable() {}
+SharedRegionParcelable::~SharedRegionParcelable() {}
+
+void SharedRegionParcelable::setup(int32_t sharedMemoryIndex,
+                                   int32_t offsetInBytes,
+                                   int32_t sizeInBytes) {
+    mSharedMemoryIndex = sharedMemoryIndex;
+    mOffsetInBytes = offsetInBytes;
+    mSizeInBytes = sizeInBytes;
+}
+
+status_t SharedRegionParcelable::writeToParcel(Parcel* parcel) const {
+    parcel->writeInt32(mSizeInBytes);
+    if (mSizeInBytes > 0) {
+        parcel->writeInt32(mSharedMemoryIndex);
+        parcel->writeInt32(mOffsetInBytes);
+    }
+    return NO_ERROR; // TODO check for errors above
+}
+
+status_t SharedRegionParcelable::readFromParcel(const Parcel* parcel) {
+    parcel->readInt32(&mSizeInBytes);
+    if (mSizeInBytes > 0) {
+        parcel->readInt32(&mSharedMemoryIndex);
+        parcel->readInt32(&mOffsetInBytes);
+    }
+    return NO_ERROR; // TODO check for errors above
+}
+
+aaudio_result_t SharedRegionParcelable::resolve(SharedMemoryParcelable *memoryParcels,
+                                              void **regionAddressPtr) {
+    if (mSizeInBytes == 0) {
+        *regionAddressPtr = nullptr;
+        return AAUDIO_OK;
+    }
+    if (mSharedMemoryIndex < 0) {
+        ALOGE("SharedRegionParcelable invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
+        return AAUDIO_ERROR_INTERNAL;
+    }
+    SharedMemoryParcelable *memoryParcel = &memoryParcels[mSharedMemoryIndex];
+    return memoryParcel->resolve(mOffsetInBytes, mSizeInBytes, regionAddressPtr);
+}
+
+aaudio_result_t SharedRegionParcelable::validate() {
+    if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
+        ALOGE("SharedRegionParcelable invalid mSizeInBytes = %d", mSizeInBytes);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+    if (mSizeInBytes > 0) {
+        if (mOffsetInBytes < 0 || mOffsetInBytes >= MAX_MMAP_OFFSET_BYTES) {
+            ALOGE("SharedRegionParcelable invalid mOffsetInBytes = %d", mOffsetInBytes);
+            return AAUDIO_ERROR_OUT_OF_RANGE;
+        }
+        if (mSharedMemoryIndex < 0 || mSharedMemoryIndex >= MAX_SHARED_MEMORIES) {
+            ALOGE("SharedRegionParcelable invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
+            return AAUDIO_ERROR_INTERNAL;
+        }
+    }
+    return AAUDIO_OK;
+}
+
+void SharedRegionParcelable::dump() {
+    ALOGD("SharedRegionParcelable mSizeInBytes = %d -----", mSizeInBytes);
+    if (mSizeInBytes > 0) {
+        ALOGD("SharedRegionParcelable mSharedMemoryIndex = %d", mSharedMemoryIndex);
+        ALOGD("SharedRegionParcelable mOffsetInBytes = %d", mOffsetInBytes);
+    }
+}
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.h b/media/libaaudio/src/binding/SharedRegionParcelable.h
new file mode 100644
index 0000000..d6c2281
--- /dev/null
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BINDING_SHAREDREGIONPARCELABLE_H
+#define BINDING_SHAREDREGIONPARCELABLE_H
+
+#include <stdint.h>
+
+#include <sys/mman.h>
+#include <binder/Parcelable.h>
+
+#include <aaudio/AAudioDefinitions.h>
+
+#include "binding/SharedMemoryParcelable.h"
+
+using android::status_t;
+using android::Parcel;
+using android::Parcelable;
+
+namespace aaudio {
+
+class SharedRegionParcelable : public Parcelable {
+public:
+    SharedRegionParcelable();
+    virtual ~SharedRegionParcelable();
+
+    void setup(int32_t sharedMemoryIndex, int32_t offsetInBytes, int32_t sizeInBytes);
+
+    virtual status_t writeToParcel(Parcel* parcel) const override;
+
+    virtual status_t readFromParcel(const Parcel* parcel) override;
+
+    aaudio_result_t resolve(SharedMemoryParcelable *memoryParcels, void **regionAddressPtr);
+
+    aaudio_result_t validate();
+
+    void dump();
+
+protected:
+    int32_t mSharedMemoryIndex = -1;
+    int32_t mOffsetInBytes     = 0;
+    int32_t mSizeInBytes       = 0;
+};
+
+} /* namespace aaudio */
+
+#endif //BINDING_SHAREDREGIONPARCELABLE_H
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
new file mode 100644
index 0000000..5cd9782
--- /dev/null
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <cassert>
+#include <aaudio/AAudioDefinitions.h>
+
+#include "AudioEndpointParcelable.h"
+#include "AudioEndpoint.h"
+#include "AAudioServiceMessage.h"
+
+using namespace android;
+using namespace aaudio;
+
+AudioEndpoint::AudioEndpoint()
+    : mOutputFreeRunning(false)
+    , mDataReadCounter(0)
+    , mDataWriteCounter(0)
+{
+}
+
+AudioEndpoint::~AudioEndpoint()
+{
+}
+
+static void AudioEndpoint_validateQueueDescriptor(const char *type,
+                                                  const RingBufferDescriptor *descriptor) {
+    assert(descriptor->capacityInFrames > 0);
+    assert(descriptor->bytesPerFrame > 1);
+    assert(descriptor->dataAddress != nullptr);
+    ALOGD("AudioEndpoint_validateQueueDescriptor %s, dataAddress at %p ====================",
+          type,
+          descriptor->dataAddress);
+    ALOGD("AudioEndpoint_validateQueueDescriptor  readCounter at %p, writeCounter at %p",
+          descriptor->readCounterAddress,
+          descriptor->writeCounterAddress);
+
+    // Try to READ from the data area.
+    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;
+    ALOGD("AudioEndpoint_validateQueueDescriptor() wrote successfully");
+
+    if (descriptor->readCounterAddress) {
+        fifo_counter_t counter = *descriptor->readCounterAddress;
+        ALOGD("AudioEndpoint_validateQueueDescriptor() *readCounterAddress = %d, now write",
+              (int) counter);
+        *descriptor->readCounterAddress = counter;
+        ALOGD("AudioEndpoint_validateQueueDescriptor() wrote readCounterAddress successfully");
+    }
+    if (descriptor->writeCounterAddress) {
+        fifo_counter_t counter = *descriptor->writeCounterAddress;
+        ALOGD("AudioEndpoint_validateQueueDescriptor() *writeCounterAddress = %d, now write",
+              (int) counter);
+        *descriptor->writeCounterAddress = counter;
+        ALOGD("AudioEndpoint_validateQueueDescriptor() wrote writeCounterAddress successfully");
+    }
+}
+
+void AudioEndpoint_validateDescriptor(const EndpointDescriptor *pEndpointDescriptor) {
+    AudioEndpoint_validateQueueDescriptor("msg", &pEndpointDescriptor->upMessageQueueDescriptor);
+    AudioEndpoint_validateQueueDescriptor("data", &pEndpointDescriptor->downDataQueueDescriptor);
+}
+
+aaudio_result_t AudioEndpoint::configure(const EndpointDescriptor *pEndpointDescriptor)
+{
+    aaudio_result_t result = AAUDIO_OK;
+    AudioEndpoint_validateDescriptor(pEndpointDescriptor); // FIXME remove after debugging
+
+    const RingBufferDescriptor *descriptor = &pEndpointDescriptor->upMessageQueueDescriptor;
+    assert(descriptor->bytesPerFrame == sizeof(AAudioServiceMessage));
+    assert(descriptor->readCounterAddress != nullptr);
+    assert(descriptor->writeCounterAddress != nullptr);
+    mUpCommandQueue = new FifoBuffer(
+            descriptor->bytesPerFrame,
+            descriptor->capacityInFrames,
+            descriptor->readCounterAddress,
+            descriptor->writeCounterAddress,
+            descriptor->dataAddress
+    );
+    /* TODO mDownCommandQueue
+    if (descriptor->capacityInFrames > 0) {
+        descriptor = &pEndpointDescriptor->downMessageQueueDescriptor;
+        mDownCommandQueue = new FifoBuffer(
+                descriptor->capacityInFrames,
+                descriptor->bytesPerFrame,
+                descriptor->readCounterAddress,
+                descriptor->writeCounterAddress,
+                descriptor->dataAddress
+        );
+    }
+     */
+    descriptor = &pEndpointDescriptor->downDataQueueDescriptor;
+    assert(descriptor->capacityInFrames > 0);
+    assert(descriptor->bytesPerFrame > 1);
+    assert(descriptor->bytesPerFrame < 4 * 16); // FIXME just for initial debugging
+    assert(descriptor->framesPerBurst > 0);
+    assert(descriptor->framesPerBurst < 8 * 1024); // FIXME just for initial debugging
+    assert(descriptor->dataAddress != nullptr);
+    ALOGD("AudioEndpoint::configure() data framesPerBurst = %d", descriptor->framesPerBurst);
+    ALOGD("AudioEndpoint::configure() data readCounterAddress = %p", descriptor->readCounterAddress);
+    mOutputFreeRunning = descriptor->readCounterAddress == nullptr;
+    ALOGD("AudioEndpoint::configure() mOutputFreeRunning = %d", mOutputFreeRunning ? 1 : 0);
+    int64_t *readCounterAddress = (descriptor->readCounterAddress == nullptr)
+                                  ? &mDataReadCounter
+                                  : descriptor->readCounterAddress;
+    int64_t *writeCounterAddress = (descriptor->writeCounterAddress == nullptr)
+                                  ? &mDataWriteCounter
+                                  : descriptor->writeCounterAddress;
+    mDownDataQueue = new FifoBuffer(
+            descriptor->bytesPerFrame,
+            descriptor->capacityInFrames,
+            readCounterAddress,
+            writeCounterAddress,
+            descriptor->dataAddress
+    );
+    uint32_t threshold = descriptor->capacityInFrames / 2;
+    mDownDataQueue->setThreshold(threshold);
+    return result;
+}
+
+aaudio_result_t AudioEndpoint::readUpCommand(AAudioServiceMessage *commandPtr)
+{
+    return mUpCommandQueue->read(commandPtr, 1);
+}
+
+aaudio_result_t AudioEndpoint::writeDataNow(const void *buffer, int32_t numFrames)
+{
+    return mDownDataQueue->write(buffer, numFrames);
+}
+
+void AudioEndpoint::setDownDataReadCounter(fifo_counter_t framesRead)
+{
+    mDownDataQueue->setReadCounter(framesRead);
+}
+
+fifo_counter_t AudioEndpoint::getDownDataReadCounter()
+{
+    return mDownDataQueue->getReadCounter();
+}
+
+void AudioEndpoint::setDownDataWriteCounter(fifo_counter_t framesRead)
+{
+    mDownDataQueue->setWriteCounter(framesRead);
+}
+
+fifo_counter_t AudioEndpoint::getDownDataWriteCounter()
+{
+    return mDownDataQueue->getWriteCounter();
+}
+
+aaudio_size_frames_t AudioEndpoint::setBufferSizeInFrames(aaudio_size_frames_t requestedFrames,
+                                            aaudio_size_frames_t *actualFrames)
+{
+    if (requestedFrames < ENDPOINT_DATA_QUEUE_SIZE_MIN) {
+        requestedFrames = ENDPOINT_DATA_QUEUE_SIZE_MIN;
+    }
+    mDownDataQueue->setThreshold(requestedFrames);
+    *actualFrames = mDownDataQueue->getThreshold();
+    return AAUDIO_OK;
+}
+
+int32_t AudioEndpoint::getBufferSizeInFrames() const
+{
+    return mDownDataQueue->getThreshold();
+}
+
+int32_t AudioEndpoint::getBufferCapacityInFrames() const
+{
+    return (int32_t)mDownDataQueue->getBufferCapacityInFrames();
+}
+
+int32_t AudioEndpoint::getFullFramesAvailable()
+{
+    return mDownDataQueue->getFifoControllerBase()->getFullFramesAvailable();
+}
diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
new file mode 100644
index 0000000..e786513
--- /dev/null
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAUDIO_AUDIO_ENDPOINT_H
+#define AAUDIO_AUDIO_ENDPOINT_H
+
+#include <aaudio/AAudio.h>
+
+#include "AAudioServiceMessage.h"
+#include "AudioEndpointParcelable.h"
+#include "fifo/FifoBuffer.h"
+
+namespace aaudio {
+
+#define ENDPOINT_DATA_QUEUE_SIZE_MIN   64
+
+/**
+ * A sink for audio.
+ * Used by the client code.
+ */
+class AudioEndpoint {
+
+public:
+    AudioEndpoint();
+    virtual ~AudioEndpoint();
+
+    /**
+     * Configure based on the EndPointDescriptor_t.
+     */
+    aaudio_result_t configure(const EndpointDescriptor *pEndpointDescriptor);
+
+    /**
+     * Read from a command passed up from the Server.
+     * @return 1 if command received, 0 for no command, or negative error.
+     */
+    aaudio_result_t readUpCommand(AAudioServiceMessage *commandPtr);
+
+    /**
+     * Non-blocking write.
+     * @return framesWritten or a negative error code.
+     */
+    aaudio_result_t writeDataNow(const void *buffer, int32_t numFrames);
+
+    /**
+     * 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 setDownDataWriteCounter(fifo_counter_t framesWritten);
+    fifo_counter_t getDownDataWriteCounter();
+
+    /**
+     * The result is not valid until after configure() is called.
+     *
+     * @return true if the output buffer read position is not updated, eg. DMA
+     */
+    bool isOutputFreeRunning() const { return mOutputFreeRunning; }
+
+    int32_t setBufferSizeInFrames(aaudio_size_frames_t requestedFrames,
+                                  aaudio_size_frames_t *actualFrames);
+    aaudio_size_frames_t getBufferSizeInFrames() const;
+
+    aaudio_size_frames_t getBufferCapacityInFrames() const;
+
+    aaudio_size_frames_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
+};
+
+} // namespace aaudio
+
+#endif //AAUDIO_AUDIO_ENDPOINT_H
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
new file mode 100644
index 0000000..19f2300
--- /dev/null
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <assert.h>
+
+#include <binder/IServiceManager.h>
+#include <utils/Mutex.h>
+
+#include <aaudio/AAudio.h>
+
+#include "AudioClock.h"
+#include "AudioEndpointParcelable.h"
+#include "binding/AAudioStreamRequest.h"
+#include "binding/AAudioStreamConfiguration.h"
+#include "binding/IAAudioService.h"
+#include "binding/AAudioServiceMessage.h"
+
+#include "core/AudioStreamBuilder.h"
+#include "AudioStreamInternal.h"
+
+#define LOG_TIMESTAMPS   0
+
+using android::String16;
+using android::IServiceManager;
+using android::defaultServiceManager;
+using android::interface_cast;
+using android::Mutex;
+
+using namespace aaudio;
+
+static android::Mutex gServiceLock;
+static sp<IAAudioService>  gAAudioService;
+
+#define AAUDIO_SERVICE_NAME   "AAudioService"
+
+// 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;
+}
+
+AudioStreamInternal::AudioStreamInternal()
+        : AudioStream()
+        , mClockModel()
+        , mAudioEndpoint()
+        , mServiceStreamHandle(AAUDIO_HANDLE_INVALID)
+        , mFramesPerBurst(16)
+{
+}
+
+AudioStreamInternal::~AudioStreamInternal() {
+}
+
+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;
+
+    result = AudioStream::open(builder);
+    if (result < 0) {
+        return result;
+    }
+
+    // Build the request to send to the server.
+    request.setUserId(getuid());
+    request.setProcessId(getpid());
+    request.getConfiguration().setDeviceId(getDeviceId());
+    request.getConfiguration().setSampleRate(getSampleRate());
+    request.getConfiguration().setSamplesPerFrame(getSamplesPerFrame());
+    request.getConfiguration().setAudioFormat(getFormat());
+    request.getConfiguration().setBufferCapacity(builder.getBufferCapacity());
+    request.dump();
+
+    mServiceStreamHandle = service->openStream(request, configuration);
+    ALOGD("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);
+    } else {
+        result = configuration.validate();
+        if (result != AAUDIO_OK) {
+            close();
+            return result;
+        }
+        // Save results of the open.
+        setSampleRate(configuration.getSampleRate());
+        setSamplesPerFrame(configuration.getSamplesPerFrame());
+        setFormat(configuration.getAudioFormat());
+
+        aaudio::AudioEndpointParcelable parcelable;
+        result = service->getStreamDescription(mServiceStreamHandle, parcelable);
+        if (result != AAUDIO_OK) {
+            ALOGE("AudioStreamInternal.open(): getStreamDescriptor returns %d", result);
+            service->closeStream(mServiceStreamHandle);
+            return result;
+        }
+        // resolve parcelable into a descriptor
+        parcelable.resolve(&mEndpointDescriptor);
+
+        // Configure endpoint based on descriptor.
+        mAudioEndpoint.configure(&mEndpointDescriptor);
+
+        mFramesPerBurst = mEndpointDescriptor.downDataQueueDescriptor.framesPerBurst;
+        assert(mFramesPerBurst >= 16);
+        assert(mEndpointDescriptor.downDataQueueDescriptor.capacityInFrames < 10 * 1024);
+
+        mClockModel.setSampleRate(getSampleRate());
+        mClockModel.setFramesPerBurst(mFramesPerBurst);
+
+        setState(AAUDIO_STREAM_STATE_OPEN);
+    }
+    return result;
+}
+
+aaudio_result_t AudioStreamInternal::close() {
+    ALOGD("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);
+        return AAUDIO_OK;
+    } else {
+        return AAUDIO_ERROR_INVALID_HANDLE;
+    }
+}
+
+aaudio_result_t AudioStreamInternal::requestStart()
+{
+    aaudio_nanoseconds_t startTime;
+    ALOGD("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 = AAudio_getNanoseconds(AAUDIO_CLOCK_MONOTONIC);
+    mClockModel.start(startTime);
+    processTimestamp(0, startTime);
+    setState(AAUDIO_STREAM_STATE_STARTING);
+    return aaudioService->startStream(mServiceStreamHandle);
+}
+
+aaudio_result_t AudioStreamInternal::requestPause()
+{
+    ALOGD("AudioStreamInternal(): pause()");
+    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(AAudio_getNanoseconds(AAUDIO_CLOCK_MONOTONIC));
+    setState(AAUDIO_STREAM_STATE_PAUSING);
+    return aaudioService->pauseStream(mServiceStreamHandle);
+}
+
+aaudio_result_t AudioStreamInternal::requestFlush() {
+    ALOGD("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);
+}
+
+void AudioStreamInternal::onFlushFromServer() {
+    ALOGD("AudioStreamInternal(): onFlushFromServer()");
+    aaudio_position_frames_t readCounter = mAudioEndpoint.getDownDataReadCounter();
+    aaudio_position_frames_t writeCounter = mAudioEndpoint.getDownDataWriteCounter();
+    // Bump offset so caller does not see the retrograde motion in getFramesRead().
+    aaudio_position_frames_t framesFlushed = writeCounter - readCounter;
+    mFramesOffsetFromService += framesFlushed;
+    // Flush written frames by forcing writeCounter to readCounter.
+    // This is because we cannot move the read counter in the hardware.
+    mAudioEndpoint.setDownDataWriteCounter(readCounter);
+}
+
+aaudio_result_t AudioStreamInternal::requestStop()
+{
+    // TODO better implementation of requestStop()
+    aaudio_result_t result = requestPause();
+    if (result == AAUDIO_OK) {
+        aaudio_stream_state_t state;
+        result = waitForStateChange(AAUDIO_STREAM_STATE_PAUSING,
+                                    &state,
+                                    500 * AAUDIO_NANOS_PER_MILLISECOND);// TODO temporary code
+        if (result == AAUDIO_OK) {
+            result = requestFlush();
+        }
+    }
+    return result;
+}
+
+aaudio_result_t AudioStreamInternal::registerThread() {
+    ALOGD("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());
+}
+
+aaudio_result_t AudioStreamInternal::unregisterThread() {
+    ALOGD("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());
+}
+
+// TODO use aaudio_clockid_t all the way down to AudioClock
+aaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId,
+                           aaudio_position_frames_t *framePosition,
+                           aaudio_nanoseconds_t *timeNanoseconds) {
+// TODO implement using real HAL
+    aaudio_nanoseconds_t time = AudioClock::getNanoseconds();
+    *framePosition = mClockModel.convertTimeToPosition(time);
+    *timeNanoseconds = time + (10 * AAUDIO_NANOS_PER_MILLISECOND); // Fake hardware delay
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamInternal::updateState() {
+    return processCommands();
+}
+
+#if LOG_TIMESTAMPS
+static void AudioStreamInternal_LogTimestamp(AAudioServiceMessage &command) {
+    static int64_t oldPosition = 0;
+    static aaudio_nanoseconds_t oldTime = 0;
+    int64_t framePosition = command.timestamp.position;
+    aaudio_nanoseconds_t nanoTime = command.timestamp.timestamp;
+    ALOGD("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);
+    }
+    oldPosition = framePosition;
+    oldTime = nanoTime;
+}
+#endif
+
+aaudio_result_t AudioStreamInternal::onTimestampFromServer(AAudioServiceMessage *message) {
+    aaudio_position_frames_t framePosition = 0;
+#if LOG_TIMESTAMPS
+    AudioStreamInternal_LogTimestamp(command);
+#endif
+    framePosition = message->timestamp.position;
+    processTimestamp(framePosition, message->timestamp.timestamp);
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamInternal::onEventFromServer(AAudioServiceMessage *message) {
+    aaudio_result_t result = AAUDIO_OK;
+    ALOGD("processCommands() got event %d", message->event.event);
+    switch (message->event.event) {
+        case AAUDIO_SERVICE_EVENT_STARTED:
+            ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_STARTED");
+            setState(AAUDIO_STREAM_STATE_STARTED);
+            break;
+        case AAUDIO_SERVICE_EVENT_PAUSED:
+            ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_PAUSED");
+            setState(AAUDIO_STREAM_STATE_PAUSED);
+            break;
+        case AAUDIO_SERVICE_EVENT_FLUSHED:
+            ALOGD("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");
+            setState(AAUDIO_STREAM_STATE_CLOSED);
+            break;
+        case AAUDIO_SERVICE_EVENT_DISCONNECTED:
+            result = AAUDIO_ERROR_DISCONNECTED;
+            ALOGW("WARNING - processCommands() AAUDIO_SERVICE_EVENT_DISCONNECTED");
+            break;
+        default:
+            ALOGW("WARNING - processCommands() Unrecognized event = %d",
+                 (int) message->event.event);
+            break;
+    }
+    return result;
+}
+
+// Process all the commands coming from the server.
+aaudio_result_t AudioStreamInternal::processCommands() {
+    aaudio_result_t result = AAUDIO_OK;
+
+    while (result == AAUDIO_OK) {
+        AAudioServiceMessage message;
+        if (mAudioEndpoint.readUpCommand(&message) != 1) {
+            break; // no command this time, no problem
+        }
+        switch (message.what) {
+        case AAudioServiceMessage::code::TIMESTAMP:
+            result = onTimestampFromServer(&message);
+            break;
+
+        case AAudioServiceMessage::code::EVENT:
+            result = onEventFromServer(&message);
+            break;
+
+        default:
+            ALOGW("WARNING - AudioStreamInternal::processCommands() Unrecognized what = %d",
+                 (int) message.what);
+            result = AAUDIO_ERROR_UNEXPECTED_VALUE;
+            break;
+        }
+    }
+    return result;
+}
+
+// Write the data, block if needed and timeoutMillis > 0
+aaudio_result_t AudioStreamInternal::write(const void *buffer, int32_t numFrames,
+                                         aaudio_nanoseconds_t timeoutNanoseconds)
+{
+    aaudio_result_t result = AAUDIO_OK;
+    uint8_t* source = (uint8_t*)buffer;
+    aaudio_nanoseconds_t currentTimeNanos = AudioClock::getNanoseconds();
+    aaudio_nanoseconds_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);
+
+    // Write until all the data has been written or until a timeout occurs.
+    while (framesLeft > 0) {
+        // The call to writeNow() will not block. It will just write as much as it can.
+        aaudio_nanoseconds_t wakeTimeNanos = 0;
+        aaudio_result_t framesWritten = writeNow(source, framesLeft,
+                                               currentTimeNanos, &wakeTimeNanos);
+//        ALOGD("AudioStreamInternal::write() writeNow() framesLeft = %d --> framesWritten = %d", framesLeft, framesWritten);
+        if (framesWritten < 0) {
+            result = framesWritten;
+            break;
+        }
+        framesLeft -= (int32_t) framesWritten;
+        source += framesWritten * getBytesPerFrame();
+
+        // Should we block?
+        if (timeoutNanoseconds == 0) {
+            break; // don't block
+        } else if (framesLeft > 0) {
+            //ALOGD("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);
+                break;
+            }
+
+            //ALOGD("AudioStreamInternal:: sleep until %lld, dur = %lld", (long long) wakeTimeNanos,
+            //        (long long) (wakeTimeNanos - currentTimeNanos));
+            AudioClock::sleepForNanos(wakeTimeNanos - currentTimeNanos);
+            currentTimeNanos = AudioClock::getNanoseconds();
+        }
+    }
+
+    // return error or framesWritten
+    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,
+                                         aaudio_nanoseconds_t currentNanoTime, aaudio_nanoseconds_t *wakeTimePtr) {
+    {
+        aaudio_result_t result = processCommands();
+        if (result != AAUDIO_OK) {
+            return result;
+        }
+    }
+
+    if (mAudioEndpoint.isOutputFreeRunning()) {
+        // 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);
+    }
+    //ALOGD("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
+        aaudio_nanoseconds_t wakeTime = currentNanoTime + (2 * AAUDIO_NANOS_PER_MILLISECOND);
+        switch (getState()) {
+            case AAUDIO_STREAM_STATE_OPEN:
+            case AAUDIO_STREAM_STATE_STARTING:
+                if (framesWritten != 0) {
+                    // Don't wait to write more data. Just prime the buffer.
+                    wakeTime = currentNanoTime;
+                }
+                break;
+            case AAUDIO_STREAM_STATE_STARTED:   // When do we expect the next read burst to occur?
+                {
+                    uint32_t burstSize = mFramesPerBurst;
+                    if (burstSize < 32) {
+                        burstSize = 32; // TODO review
+                    }
+
+                    uint64_t nextReadPosition = mAudioEndpoint.getDownDataReadCounter() + burstSize;
+                    wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
+                }
+                break;
+            default:
+                break;
+        }
+        *wakeTimePtr = wakeTime;
+
+    }
+//    ALOGD("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;
+}
+
+aaudio_result_t AudioStreamInternal::waitForStateChange(aaudio_stream_state_t currentState,
+                                                      aaudio_stream_state_t *nextState,
+                                                      aaudio_nanoseconds_t timeoutNanoseconds)
+
+{
+    aaudio_result_t result = processCommands();
+//    ALOGD("AudioStreamInternal::waitForStateChange() - processCommands() returned %d", result);
+    if (result != AAUDIO_OK) {
+        return result;
+    }
+    // TODO replace this polling with a timed sleep on a futex on the message queue
+    int32_t durationNanos = 5 * AAUDIO_NANOS_PER_MILLISECOND;
+    aaudio_stream_state_t state = getState();
+//    ALOGD("AudioStreamInternal::waitForStateChange() - state = %d", state);
+    while (state == currentState && timeoutNanoseconds > 0) {
+        // TODO use futex from service message queue
+        if (durationNanos > timeoutNanoseconds) {
+            durationNanos = timeoutNanoseconds;
+        }
+        AudioClock::sleepForNanos(durationNanos);
+        timeoutNanoseconds -= durationNanos;
+
+        result = processCommands();
+        if (result != AAUDIO_OK) {
+            return result;
+        }
+
+        state = getState();
+//        ALOGD("AudioStreamInternal::waitForStateChange() - state = %d", state);
+    }
+    if (nextState != nullptr) {
+        *nextState = state;
+    }
+    return (state == currentState) ? AAUDIO_ERROR_TIMEOUT : AAUDIO_OK;
+}
+
+
+void AudioStreamInternal::processTimestamp(uint64_t position, aaudio_nanoseconds_t time) {
+    mClockModel.processTimestamp( position, time);
+}
+
+aaudio_result_t AudioStreamInternal::setBufferSize(aaudio_size_frames_t requestedFrames,
+                                        aaudio_size_frames_t *actualFrames) {
+    return mAudioEndpoint.setBufferSizeInFrames(requestedFrames, actualFrames);
+}
+
+aaudio_size_frames_t AudioStreamInternal::getBufferSize() const
+{
+    return mAudioEndpoint.getBufferSizeInFrames();
+}
+
+aaudio_size_frames_t AudioStreamInternal::getBufferCapacity() const
+{
+    return mAudioEndpoint.getBufferCapacityInFrames();
+}
+
+aaudio_size_frames_t AudioStreamInternal::getFramesPerBurst() const
+{
+    return mEndpointDescriptor.downDataQueueDescriptor.framesPerBurst;
+}
+
+aaudio_position_frames_t AudioStreamInternal::getFramesRead()
+{
+    aaudio_position_frames_t framesRead =
+            mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
+            + mFramesOffsetFromService;
+    // Prevent retrograde motion.
+    if (framesRead < mLastFramesRead) {
+        framesRead = mLastFramesRead;
+    } else {
+        mLastFramesRead = framesRead;
+    }
+    ALOGD("AudioStreamInternal::getFramesRead() returns %lld", (long long)framesRead);
+    return framesRead;
+}
+
+// TODO implement getTimestamp
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
new file mode 100644
index 0000000..666df3a
--- /dev/null
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAUDIO_AUDIOSTREAMINTERNAL_H
+#define AAUDIO_AUDIOSTREAMINTERNAL_H
+
+#include <stdint.h>
+#include <aaudio/AAudio.h>
+
+#include "binding/IAAudioService.h"
+#include "binding/AudioEndpointParcelable.h"
+#include "client/IsochronousClockModel.h"
+#include "client/AudioEndpoint.h"
+#include "core/AudioStream.h"
+
+using android::sp;
+using android::IAAudioService;
+
+namespace aaudio {
+
+// A stream that talks to the AAudioService or directly to a HAL.
+class AudioStreamInternal : public AudioStream {
+
+public:
+    AudioStreamInternal();
+    virtual ~AudioStreamInternal();
+
+    // =========== Begin ABSTRACT methods ===========================
+    virtual aaudio_result_t requestStart() override;
+
+    virtual aaudio_result_t requestPause() override;
+
+    virtual aaudio_result_t requestFlush() override;
+
+    virtual 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_position_frames_t *framePosition,
+                                       aaudio_nanoseconds_t *timeNanoseconds) override;
+
+
+    virtual aaudio_result_t updateState() override;
+    // =========== End ABSTRACT methods ===========================
+
+    virtual aaudio_result_t open(const AudioStreamBuilder &builder) override;
+
+    virtual aaudio_result_t close() override;
+
+    virtual aaudio_result_t write(const void *buffer,
+                             int32_t numFrames,
+                             aaudio_nanoseconds_t timeoutNanoseconds) override;
+
+    virtual aaudio_result_t waitForStateChange(aaudio_stream_state_t currentState,
+                                          aaudio_stream_state_t *nextState,
+                                          aaudio_nanoseconds_t timeoutNanoseconds) override;
+
+    virtual aaudio_result_t setBufferSize(aaudio_size_frames_t requestedFrames,
+                                        aaudio_size_frames_t *actualFrames) override;
+
+    virtual aaudio_size_frames_t getBufferSize() const override;
+
+    virtual aaudio_size_frames_t getBufferCapacity() const override;
+
+    virtual aaudio_size_frames_t getFramesPerBurst() const override;
+
+    virtual aaudio_position_frames_t getFramesRead() override;
+
+    virtual int32_t getXRunCount() const override {
+        return mXRunCount;
+    }
+
+    virtual aaudio_result_t registerThread() override;
+
+    virtual aaudio_result_t unregisterThread() override;
+
+protected:
+
+    aaudio_result_t processCommands();
+
+/**
+ * Low level write that will not block. It will just write as much as it can.
+ *
+ * It passed back a recommended time to wake up if wakeTimePtr is not NULL.
+ *
+ * @return the number of frames written or a negative error code.
+ */
+    virtual aaudio_result_t writeNow(const void *buffer,
+                                int32_t numFrames,
+                                aaudio_nanoseconds_t currentTimeNanos,
+                                aaudio_nanoseconds_t *wakeTimePtr);
+
+    void onFlushFromServer();
+
+    aaudio_result_t onEventFromServer(AAudioServiceMessage *message);
+
+    aaudio_result_t onTimestampFromServer(AAudioServiceMessage *message);
+
+private:
+    IsochronousClockModel    mClockModel;
+    AudioEndpoint            mAudioEndpoint;
+    aaudio_handle_t            mServiceStreamHandle;
+    EndpointDescriptor       mEndpointDescriptor;
+    // Offset from underlying frame position.
+    aaudio_position_frames_t   mFramesOffsetFromService = 0;
+    aaudio_position_frames_t   mLastFramesRead = 0;
+    aaudio_size_frames_t       mFramesPerBurst;
+    int32_t                  mXRunCount = 0;
+
+    void processTimestamp(uint64_t position, aaudio_nanoseconds_t time);
+};
+
+} /* namespace aaudio */
+
+#endif //AAUDIO_AUDIOSTREAMINTERNAL_H
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
new file mode 100644
index 0000000..bdb491d
--- /dev/null
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <aaudio/AAudioDefinitions.h>
+
+#include "IsochronousClockModel.h"
+
+#define MIN_LATENESS_NANOS (10 * AAUDIO_NANOS_PER_MICROSECOND)
+
+using namespace android;
+using namespace aaudio;
+
+IsochronousClockModel::IsochronousClockModel()
+        : mSampleRate(48000)
+        , mFramesPerBurst(64)
+        , mMaxLatenessInNanos(0)
+        , mMarkerFramePosition(0)
+        , mMarkerNanoTime(0)
+        , mState(STATE_STOPPED)
+{
+}
+
+IsochronousClockModel::~IsochronousClockModel() {
+}
+
+void IsochronousClockModel::start(aaudio_nanoseconds_t nanoTime)
+{
+    mMarkerNanoTime = nanoTime;
+    mState = STATE_STARTING;
+}
+
+void IsochronousClockModel::stop(aaudio_nanoseconds_t nanoTime)
+{
+    mMarkerNanoTime = nanoTime;
+    mMarkerFramePosition = convertTimeToPosition(nanoTime); // TODO should we do this?
+    mState = STATE_STOPPED;
+}
+
+void IsochronousClockModel::processTimestamp(aaudio_position_frames_t framePosition,
+                                             aaudio_nanoseconds_t nanoTime) {
+    int64_t framesDelta = framePosition - mMarkerFramePosition;
+    int64_t nanosDelta = nanoTime - mMarkerNanoTime;
+    if (nanosDelta < 1000) {
+        return;
+    }
+
+//    ALOGI("processTimestamp() - mMarkerFramePosition = %lld at mMarkerNanoTime %llu",
+//         (long long)mMarkerFramePosition,
+//         (long long)mMarkerNanoTime);
+//    ALOGI("processTimestamp() - framePosition = %lld at nanoTime %llu",
+//         (long long)framePosition,
+//         (long long)nanoTime);
+
+    int64_t expectedNanosDelta = convertDeltaPositionToTime(framesDelta);
+//    ALOGI("processTimestamp() - expectedNanosDelta = %lld, nanosDelta = %llu",
+//         (long long)expectedNanosDelta,
+//         (long long)nanosDelta);
+
+//    ALOGI("processTimestamp() - mSampleRate = %d", mSampleRate);
+//    ALOGI("processTimestamp() - mState = %d", mState);
+    switch (mState) {
+    case STATE_STOPPED:
+        break;
+    case STATE_STARTING:
+        mMarkerFramePosition = framePosition;
+        mMarkerNanoTime = nanoTime;
+        mState = STATE_SYNCING;
+        break;
+    case STATE_SYNCING:
+        // This will handle a burst of rapid consumption in the beginning.
+        if (nanosDelta < expectedNanosDelta) {
+            mMarkerFramePosition = framePosition;
+            mMarkerNanoTime = nanoTime;
+        } else {
+            ALOGI("processTimestamp() - advance to STATE_RUNNING");
+            mState = STATE_RUNNING;
+        }
+        break;
+    case STATE_RUNNING:
+        if (nanosDelta < expectedNanosDelta) {
+            // Earlier than expected timestamp.
+            // This data is probably more accurate so use it.
+            // or we may be drifting due to a slow HW clock.
+            mMarkerFramePosition = framePosition;
+            mMarkerNanoTime = nanoTime;
+            ALOGI("processTimestamp() - STATE_RUNNING - %d < %d micros - EARLY",
+                 (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000));
+        } else if (nanosDelta > (expectedNanosDelta + mMaxLatenessInNanos)) {
+            // Later than expected timestamp.
+            mMarkerFramePosition = framePosition;
+            mMarkerNanoTime = nanoTime - mMaxLatenessInNanos;
+            ALOGI("processTimestamp() - STATE_RUNNING - %d > %d + %d micros - LATE",
+                 (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000),
+                 (int) (mMaxLatenessInNanos / 1000));
+        }
+        break;
+    default:
+        break;
+    }
+    ++mTimestampCount;
+}
+
+void IsochronousClockModel::setSampleRate(int32_t sampleRate) {
+    mSampleRate = sampleRate;
+    update();
+}
+
+void IsochronousClockModel::setFramesPerBurst(int32_t framesPerBurst) {
+    mFramesPerBurst = framesPerBurst;
+    update();
+}
+
+void IsochronousClockModel::update() {
+    int64_t nanosLate = convertDeltaPositionToTime(mFramesPerBurst); // uses mSampleRate
+    mMaxLatenessInNanos = (nanosLate > MIN_LATENESS_NANOS) ? nanosLate : MIN_LATENESS_NANOS;
+}
+
+aaudio_nanoseconds_t IsochronousClockModel::convertDeltaPositionToTime(
+        aaudio_position_frames_t framesDelta) const {
+    return (AAUDIO_NANOS_PER_SECOND * framesDelta) / mSampleRate;
+}
+
+int64_t IsochronousClockModel::convertDeltaTimeToPosition(aaudio_nanoseconds_t nanosDelta) const {
+    return (mSampleRate * nanosDelta) / AAUDIO_NANOS_PER_SECOND;
+}
+
+aaudio_nanoseconds_t IsochronousClockModel::convertPositionToTime(
+        aaudio_position_frames_t framePosition) const {
+    if (mState == STATE_STOPPED) {
+        return mMarkerNanoTime;
+    }
+    aaudio_position_frames_t nextBurstIndex = (framePosition + mFramesPerBurst - 1) / mFramesPerBurst;
+    aaudio_position_frames_t nextBurstPosition = mFramesPerBurst * nextBurstIndex;
+    aaudio_position_frames_t framesDelta = nextBurstPosition - mMarkerFramePosition;
+    aaudio_nanoseconds_t nanosDelta = convertDeltaPositionToTime(framesDelta);
+    aaudio_nanoseconds_t time = (aaudio_nanoseconds_t) (mMarkerNanoTime + nanosDelta);
+//    ALOGI("IsochronousClockModel::convertPositionToTime: pos = %llu --> time = %llu",
+//         (unsigned long long)framePosition,
+//         (unsigned long long)time);
+    return time;
+}
+
+aaudio_position_frames_t IsochronousClockModel::convertTimeToPosition(
+        aaudio_nanoseconds_t nanoTime) const {
+    if (mState == STATE_STOPPED) {
+        return mMarkerFramePosition;
+    }
+    aaudio_nanoseconds_t nanosDelta = nanoTime - mMarkerNanoTime;
+    aaudio_position_frames_t framesDelta = convertDeltaTimeToPosition(nanosDelta);
+    aaudio_position_frames_t nextBurstPosition = mMarkerFramePosition + framesDelta;
+    aaudio_position_frames_t nextBurstIndex = nextBurstPosition / mFramesPerBurst;
+    aaudio_position_frames_t position = nextBurstIndex * mFramesPerBurst;
+//    ALOGI("IsochronousClockModel::convertTimeToPosition: time = %llu --> pos = %llu",
+//         (unsigned long long)nanoTime,
+//         (unsigned long long)position);
+//    ALOGI("IsochronousClockModel::convertTimeToPosition: framesDelta = %llu, mFramesPerBurst = %d",
+//         (long long) framesDelta, mFramesPerBurst);
+    return position;
+}
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
new file mode 100644
index 0000000..b188a3d
--- /dev/null
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAUDIO_ISOCHRONOUSCLOCKMODEL_H
+#define AAUDIO_ISOCHRONOUSCLOCKMODEL_H
+
+#include <stdint.h>
+#include <aaudio/AAudio.h>
+
+namespace aaudio {
+
+/**
+ * Model an isochronous data stream using occasional timestamps as input.
+ * This can be used to predict the position of the stream at a given time.
+ *
+ * This class is not thread safe and should only be called from one thread.
+ */
+class IsochronousClockModel {
+
+public:
+    IsochronousClockModel();
+    virtual ~IsochronousClockModel();
+
+    void start(aaudio_nanoseconds_t nanoTime);
+    void stop(aaudio_nanoseconds_t nanoTime);
+
+    void processTimestamp(aaudio_position_frames_t framePosition, aaudio_nanoseconds_t nanoTime);
+
+    /**
+     * @param sampleRate rate of the stream in frames per second
+     */
+    void setSampleRate(aaudio_sample_rate_t sampleRate);
+
+    aaudio_sample_rate_t getSampleRate() const {
+        return mSampleRate;
+    }
+
+    /**
+     * This must be set accurately in order to track the isochronous stream.
+     *
+     * @param framesPerBurst number of frames that stream advance at one time.
+     */
+    void setFramesPerBurst(aaudio_size_frames_t framesPerBurst);
+
+    aaudio_size_frames_t getFramesPerBurst() const {
+        return mFramesPerBurst;
+    }
+
+    /**
+     * Calculate an estimated time when the stream will be at that position.
+     *
+     * @param framePosition position of the stream in frames
+     * @return time in nanoseconds
+     */
+    aaudio_nanoseconds_t convertPositionToTime(aaudio_position_frames_t framePosition) const;
+
+    /**
+     * Calculate an estimated position where the stream will be at the specified time.
+     *
+     * @param nanoTime time of interest
+     * @return position in frames
+     */
+    aaudio_position_frames_t convertTimeToPosition(aaudio_nanoseconds_t nanoTime) const;
+
+    /**
+     * @param framesDelta difference in frames
+     * @return duration in nanoseconds
+     */
+    aaudio_nanoseconds_t convertDeltaPositionToTime(aaudio_position_frames_t framesDelta) const;
+
+    /**
+     * @param nanosDelta duration in nanoseconds
+     * @return frames that stream will advance in that time
+     */
+    aaudio_position_frames_t convertDeltaTimeToPosition(aaudio_nanoseconds_t nanosDelta) const;
+
+private:
+    enum clock_model_state_t {
+        STATE_STOPPED,
+        STATE_STARTING,
+        STATE_SYNCING,
+        STATE_RUNNING
+    };
+
+    aaudio_sample_rate_t     mSampleRate;
+    aaudio_size_frames_t     mFramesPerBurst;
+    int32_t                mMaxLatenessInNanos;
+    aaudio_position_frames_t mMarkerFramePosition;
+    aaudio_nanoseconds_t     mMarkerNanoTime;
+    int32_t                mTimestampCount;
+    clock_model_state_t     mState;
+
+    void update();
+};
+
+} /* namespace aaudio */
+
+#endif //AAUDIO_ISOCHRONOUSCLOCKMODEL_H
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
new file mode 100644
index 0000000..04dbda1
--- /dev/null
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -0,0 +1,582 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <time.h>
+#include <pthread.h>
+
+#include <aaudio/AAudioDefinitions.h>
+#include <aaudio/AAudio.h>
+
+#include "AudioStreamBuilder.h"
+#include "AudioStream.h"
+#include "AudioClock.h"
+#include "client/AudioStreamInternal.h"
+#include "HandleTracker.h"
+
+using namespace aaudio;
+
+// This is not the maximum theoretic possible number of handles that the HandlerTracker
+// class could support; instead it is the maximum number of handles that we are configuring
+// for our HandleTracker instance (sHandleTracker).
+#define AAUDIO_MAX_HANDLES  64
+
+// Macros for common code that includes a return.
+// TODO Consider using do{}while(0) construct. I tried but it hung AndroidStudio
+#define CONVERT_BUILDER_HANDLE_OR_RETURN() \
+    convertAAudioBuilderToStreamBuilder(builder); \
+    if (streamBuilder == nullptr) { \
+        return AAUDIO_ERROR_INVALID_HANDLE; \
+    }
+
+#define COMMON_GET_FROM_BUILDER_OR_RETURN(resultPtr) \
+    CONVERT_BUILDER_HANDLE_OR_RETURN() \
+    if ((resultPtr) == nullptr) { \
+        return AAUDIO_ERROR_NULL; \
+    }
+
+#define CONVERT_STREAM_HANDLE_OR_RETURN() \
+    convertAAudioStreamToAudioStream(stream); \
+    if (audioStream == nullptr) { \
+        return AAUDIO_ERROR_INVALID_HANDLE; \
+    }
+
+#define COMMON_GET_FROM_STREAM_OR_RETURN(resultPtr) \
+    CONVERT_STREAM_HANDLE_OR_RETURN(); \
+    if ((resultPtr) == nullptr) { \
+        return AAUDIO_ERROR_NULL; \
+    }
+
+// Static data.
+// TODO static constructors are discouraged, alternatives?
+static HandleTracker sHandleTracker(AAUDIO_MAX_HANDLES);
+
+typedef enum
+{
+    AAUDIO_HANDLE_TYPE_STREAM,
+    AAUDIO_HANDLE_TYPE_STREAM_BUILDER,
+    AAUDIO_HANDLE_TYPE_COUNT
+} aaudio_handle_type_t;
+static_assert(AAUDIO_HANDLE_TYPE_COUNT <= HANDLE_TRACKER_MAX_TYPES, "Too many handle types.");
+
+
+#define AAUDIO_CASE_ENUM(name) case name: return #name
+
+AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode) {
+    switch (returnCode) {
+        AAUDIO_CASE_ENUM(AAUDIO_OK);
+        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_INVALID_HANDLE);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_QUERY);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNIMPLEMENTED);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNAVAILABLE);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_FREE_HANDLES);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_MEMORY);
+        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_OUT_OF_RANGE);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_SERVICE);
+    }
+    return "Unrecognized AAudio error.";
+}
+
+AAUDIO_API const char * AAudio_convertStreamStateToText(aaudio_stream_state_t state) {
+    switch (state) {
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_UNINITIALIZED);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_OPEN);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STARTING);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STARTED);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_PAUSING);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_PAUSED);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHING);
+        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_CLOSING);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSED);
+    }
+    return "Unrecognized AAudio state.";
+}
+
+#undef AAUDIO_CASE_ENUM
+
+static AudioStream *convertAAudioStreamToAudioStream(AAudioStream stream)
+{
+    return (AudioStream *) sHandleTracker.get(AAUDIO_HANDLE_TYPE_STREAM,
+                                              (aaudio_handle_t) stream);
+}
+
+static AudioStreamBuilder *convertAAudioBuilderToStreamBuilder(AAudioStreamBuilder builder)
+{
+    return (AudioStreamBuilder *) sHandleTracker.get(AAUDIO_HANDLE_TYPE_STREAM_BUILDER,
+                                                     (aaudio_handle_t) builder);
+}
+
+AAUDIO_API aaudio_result_t AAudio_createStreamBuilder(AAudioStreamBuilder *builder)
+{
+    ALOGD("AAudio_createStreamBuilder(): check sHandleTracker.isInitialized ()");
+    if (!sHandleTracker.isInitialized()) {
+        return AAUDIO_ERROR_NO_MEMORY;
+    }
+    AudioStreamBuilder *audioStreamBuilder =  new AudioStreamBuilder();
+    if (audioStreamBuilder == nullptr) {
+        return AAUDIO_ERROR_NO_MEMORY;
+    }
+    ALOGD("AAudio_createStreamBuilder(): created AudioStreamBuilder = %p", audioStreamBuilder);
+    // TODO protect the put() with a Mutex
+    AAudioStreamBuilder handle = sHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM_BUILDER,
+            audioStreamBuilder);
+    if (handle < 0) {
+        delete audioStreamBuilder;
+        return static_cast<aaudio_result_t>(handle);
+    } else {
+        *builder = handle;
+    }
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_setDeviceId(AAudioStreamBuilder builder,
+                                                     aaudio_device_id_t deviceId)
+{
+    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
+    streamBuilder->setDeviceId(deviceId);
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_getDeviceId(AAudioStreamBuilder builder,
+                                              aaudio_device_id_t *deviceId)
+{
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(deviceId);
+    *deviceId = streamBuilder->getDeviceId();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_setSampleRate(AAudioStreamBuilder builder,
+                                              aaudio_sample_rate_t sampleRate)
+{
+    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
+    streamBuilder->setSampleRate(sampleRate);
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_getSampleRate(AAudioStreamBuilder builder,
+                                              aaudio_sample_rate_t *sampleRate)
+{
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(sampleRate);
+    *sampleRate = streamBuilder->getSampleRate();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder builder,
+                                                   int32_t samplesPerFrame)
+{
+    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
+    streamBuilder->setSamplesPerFrame(samplesPerFrame);
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_getSamplesPerFrame(AAudioStreamBuilder builder,
+                                                   int32_t *samplesPerFrame)
+{
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(samplesPerFrame);
+    *samplesPerFrame = streamBuilder->getSamplesPerFrame();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_setDirection(AAudioStreamBuilder builder,
+                                             aaudio_direction_t direction)
+{
+    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
+    streamBuilder->setDirection(direction);
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_getDirection(AAudioStreamBuilder builder,
+                                             aaudio_direction_t *direction)
+{
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(direction);
+    *direction = streamBuilder->getDirection();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_setFormat(AAudioStreamBuilder builder,
+                                                   aaudio_audio_format_t format)
+{
+    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
+    streamBuilder->setFormat(format);
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_getFormat(AAudioStreamBuilder builder,
+                                                   aaudio_audio_format_t *format)
+{
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(format);
+    *format = streamBuilder->getFormat();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_setSharingMode(AAudioStreamBuilder builder,
+                                                        aaudio_sharing_mode_t sharingMode)
+{
+    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
+    if ((sharingMode < 0) || (sharingMode >= AAUDIO_SHARING_MODE_COUNT)) {
+        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+    } else {
+        streamBuilder->setSharingMode(sharingMode);
+        return AAUDIO_OK;
+    }
+}
+
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_getSharingMode(AAudioStreamBuilder builder,
+                                                        aaudio_sharing_mode_t *sharingMode)
+{
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(sharingMode);
+    *sharingMode = streamBuilder->getSharingMode();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_setBufferCapacity(AAudioStreamBuilder builder,
+                                                        aaudio_size_frames_t frames)
+{
+    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
+    if (frames < 0) {
+        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+    } else {
+        streamBuilder->setBufferCapacity(frames);
+        return AAUDIO_OK;
+    }
+}
+
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_getBufferCapacity(AAudioStreamBuilder builder,
+                                                        aaudio_size_frames_t *frames)
+{
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(frames);
+    *frames = streamBuilder->getBufferCapacity();
+    return AAUDIO_OK;
+}
+
+static aaudio_result_t  AAudioInternal_openStream(AudioStreamBuilder *streamBuilder,
+                                              AAudioStream *streamPtr)
+{
+    AudioStream *audioStream = nullptr;
+    aaudio_result_t result = streamBuilder->build(&audioStream);
+    if (result != AAUDIO_OK) {
+        return result;
+    } else {
+        // Create a handle for referencing the object.
+        // TODO protect the put() with a Mutex
+        AAudioStream handle = sHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, audioStream);
+        if (handle < 0) {
+            delete audioStream;
+            return static_cast<aaudio_result_t>(handle);
+        }
+        *streamPtr = handle;
+        return AAUDIO_OK;
+    }
+}
+
+AAUDIO_API aaudio_result_t  AAudioStreamBuilder_openStream(AAudioStreamBuilder builder,
+                                                     AAudioStream *streamPtr)
+{
+    ALOGD("AAudioStreamBuilder_openStream(): builder = 0x%08X", builder);
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(streamPtr);
+    return AAudioInternal_openStream(streamBuilder, streamPtr);
+}
+
+AAUDIO_API aaudio_result_t  AAudioStreamBuilder_delete(AAudioStreamBuilder builder)
+{
+    AudioStreamBuilder *streamBuilder = (AudioStreamBuilder *)
+            sHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM_BUILDER, builder);
+    if (streamBuilder != nullptr) {
+        delete streamBuilder;
+        return AAUDIO_OK;
+    }
+    return AAUDIO_ERROR_INVALID_HANDLE;
+}
+
+AAUDIO_API aaudio_result_t  AAudioStream_close(AAudioStream stream)
+{
+    AudioStream *audioStream = (AudioStream *)
+            sHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM, (aaudio_handle_t)stream);
+    ALOGD("AAudioStream_close(0x%08X), audioStream = %p", stream, audioStream);
+    if (audioStream != nullptr) {
+        audioStream->close();
+        delete audioStream;
+        return AAUDIO_OK;
+    }
+    return AAUDIO_ERROR_INVALID_HANDLE;
+}
+
+AAUDIO_API aaudio_result_t  AAudioStream_requestStart(AAudioStream stream)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    ALOGD("AAudioStream_requestStart(0x%08X), audioStream = %p", stream, audioStream);
+    return audioStream->requestStart();
+}
+
+AAUDIO_API aaudio_result_t  AAudioStream_requestPause(AAudioStream stream)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    ALOGD("AAudioStream_requestPause(0x%08X), audioStream = %p", stream, audioStream);
+    return audioStream->requestPause();
+}
+
+AAUDIO_API aaudio_result_t  AAudioStream_requestFlush(AAudioStream stream)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    ALOGD("AAudioStream_requestFlush(0x%08X), audioStream = %p", stream, audioStream);
+    return audioStream->requestFlush();
+}
+
+AAUDIO_API aaudio_result_t  AAudioStream_requestStop(AAudioStream stream)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    ALOGD("AAudioStream_requestStop(0x%08X), audioStream = %p", stream, audioStream);
+    return audioStream->requestStop();
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream stream,
+                                            aaudio_stream_state_t inputState,
+                                            aaudio_stream_state_t *nextState,
+                                            aaudio_nanoseconds_t timeoutNanoseconds)
+{
+
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    return audioStream->waitForStateChange(inputState, nextState, timeoutNanoseconds);
+}
+
+// ============================================================
+// Stream - non-blocking I/O
+// ============================================================
+
+AAUDIO_API aaudio_result_t AAudioStream_read(AAudioStream stream,
+                               void *buffer,
+                               aaudio_size_frames_t numFrames,
+                               aaudio_nanoseconds_t timeoutNanoseconds)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    if (buffer == nullptr) {
+        return AAUDIO_ERROR_NULL;
+    }
+    if (numFrames < 0) {
+        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+    } else if (numFrames == 0) {
+        return 0;
+    }
+
+    aaudio_result_t result = audioStream->read(buffer, numFrames, timeoutNanoseconds);
+    // ALOGD("AAudioStream_read(): read returns %d", result);
+
+    return result;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_write(AAudioStream stream,
+                               const void *buffer,
+                               aaudio_size_frames_t numFrames,
+                               aaudio_nanoseconds_t timeoutNanoseconds)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    if (buffer == nullptr) {
+        return AAUDIO_ERROR_NULL;
+    }
+    if (numFrames < 0) {
+        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+    } else if (numFrames == 0) {
+        return 0;
+    }
+
+    aaudio_result_t result = audioStream->write(buffer, numFrames, timeoutNanoseconds);
+    // ALOGD("AAudioStream_write(): write returns %d", result);
+
+    return result;
+}
+
+// ============================================================
+// Miscellaneous
+// ============================================================
+
+AAUDIO_API aaudio_result_t AAudioStream_createThread(AAudioStream stream,
+                                     aaudio_nanoseconds_t periodNanoseconds,
+                                     aaudio_audio_thread_proc_t *threadProc, void *arg)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    return audioStream->createThread(periodNanoseconds, threadProc, arg);
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_joinThread(AAudioStream stream,
+                                   void **returnArg,
+                                   aaudio_nanoseconds_t timeoutNanoseconds)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    return audioStream->joinThread(returnArg, timeoutNanoseconds);
+}
+
+// ============================================================
+// Stream - queries
+// ============================================================
+
+// TODO Use aaudio_clockid_t all the way down through the C++ streams.
+static clockid_t AAudioConvert_fromAAudioClockId(aaudio_clockid_t clockid)
+{
+    clockid_t hostClockId;
+    switch (clockid) {
+        case AAUDIO_CLOCK_MONOTONIC:
+            hostClockId = CLOCK_MONOTONIC;
+            break;
+        case AAUDIO_CLOCK_BOOTTIME:
+            hostClockId = CLOCK_BOOTTIME;
+            break;
+        default:
+            hostClockId = 0; // TODO review
+    }
+    return hostClockId;
+}
+
+aaudio_nanoseconds_t AAudio_getNanoseconds(aaudio_clockid_t clockid)
+{
+    clockid_t hostClockId = AAudioConvert_fromAAudioClockId(clockid);
+   return AudioClock::getNanoseconds(hostClockId);
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getSampleRate(AAudioStream stream, aaudio_sample_rate_t *sampleRate)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(sampleRate);
+    *sampleRate = audioStream->getSampleRate();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getSamplesPerFrame(AAudioStream stream, int32_t *samplesPerFrame)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(samplesPerFrame);
+    *samplesPerFrame = audioStream->getSamplesPerFrame();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getState(AAudioStream stream, aaudio_stream_state_t *state)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(state);
+    *state = audioStream->getState();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getFormat(AAudioStream stream, aaudio_audio_format_t *format)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(format);
+    *format = audioStream->getFormat();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_setBufferSize(AAudioStream stream,
+                                                aaudio_size_frames_t requestedFrames,
+                                                aaudio_size_frames_t *actualFrames)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    return audioStream->setBufferSize(requestedFrames, actualFrames);
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getBufferSize(AAudioStream stream, aaudio_size_frames_t *frames)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(frames);
+    *frames = audioStream->getBufferSize();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getDirection(AAudioStream stream, int32_t *direction)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(direction);
+    *direction = audioStream->getDirection();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getFramesPerBurst(AAudioStream stream,
+                                                    aaudio_size_frames_t *framesPerBurst)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(framesPerBurst);
+    *framesPerBurst = audioStream->getFramesPerBurst();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getBufferCapacity(AAudioStream stream,
+                                           aaudio_size_frames_t *capacity)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(capacity);
+    *capacity = audioStream->getBufferCapacity();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getXRunCount(AAudioStream stream, int32_t *xRunCount)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(xRunCount);
+    *xRunCount = audioStream->getXRunCount();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getDeviceId(AAudioStream stream,
+                                                 aaudio_device_id_t *deviceId)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(deviceId);
+    *deviceId = audioStream->getDeviceId();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getSharingMode(AAudioStream stream,
+                                                 aaudio_sharing_mode_t *sharingMode)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(sharingMode);
+    *sharingMode = audioStream->getSharingMode();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getFramesWritten(AAudioStream stream,
+                                                   aaudio_position_frames_t *frames)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(frames);
+    *frames = audioStream->getFramesWritten();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getFramesRead(AAudioStream stream, aaudio_position_frames_t *frames)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(frames);
+    *frames = audioStream->getFramesRead();
+    return AAUDIO_OK;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getTimestamp(AAudioStream stream,
+                                      aaudio_clockid_t clockid,
+                                      aaudio_position_frames_t *framePosition,
+                                      aaudio_nanoseconds_t *timeNanoseconds)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    if (framePosition == nullptr) {
+        return AAUDIO_ERROR_NULL;
+    } else if (timeNanoseconds == nullptr) {
+        return AAUDIO_ERROR_NULL;
+    } else if (clockid != AAUDIO_CLOCK_MONOTONIC && clockid != AAUDIO_CLOCK_BOOTTIME) {
+        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+    }
+
+    clockid_t hostClockId = AAudioConvert_fromAAudioClockId(clockid);
+    return audioStream->getTimestamp(hostClockId, framePosition, timeNanoseconds);
+}
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
new file mode 100644
index 0000000..77d3cc0
--- /dev/null
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <atomic>
+#include <stdint.h>
+#include <aaudio/AAudio.h>
+
+#include "AudioStreamBuilder.h"
+#include "AudioStream.h"
+#include "AudioClock.h"
+
+using namespace aaudio;
+
+AudioStream::AudioStream() {
+    // mThread is a pthread_t of unknown size so we need memset.
+    memset(&mThread, 0, sizeof(mThread));
+    setPeriodNanoseconds(0);
+}
+
+aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder)
+{
+    // TODO validate parameters.
+    // Copy parameters from the Builder because the Builder may be deleted after this call.
+    mSamplesPerFrame = builder.getSamplesPerFrame();
+    mSampleRate = builder.getSampleRate();
+    mDeviceId = builder.getDeviceId();
+    mFormat = builder.getFormat();
+    mSharingMode = builder.getSharingMode();
+    return AAUDIO_OK;
+}
+
+AudioStream::~AudioStream() {
+    close();
+}
+
+aaudio_result_t AudioStream::waitForStateTransition(aaudio_stream_state_t startingState,
+                                               aaudio_stream_state_t endingState,
+                                               aaudio_nanoseconds_t timeoutNanoseconds)
+{
+    aaudio_stream_state_t state = getState();
+    aaudio_stream_state_t nextState = state;
+    if (state == startingState && state != endingState) {
+        aaudio_result_t result = waitForStateChange(state, &nextState, timeoutNanoseconds);
+        if (result != AAUDIO_OK) {
+            return result;
+        }
+    }
+// It's OK if the expected transition has already occurred.
+// But if we reach an unexpected state then that is an error.
+    if (nextState != endingState) {
+        return AAUDIO_ERROR_UNEXPECTED_STATE;
+    } else {
+        return AAUDIO_OK;
+    }
+}
+
+aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
+                                                aaudio_stream_state_t *nextState,
+                                                aaudio_nanoseconds_t timeoutNanoseconds)
+{
+    // TODO replace this when similar functionality added to AudioTrack.cpp
+    aaudio_nanoseconds_t durationNanos = 20 * AAUDIO_NANOS_PER_MILLISECOND;
+    aaudio_stream_state_t state = getState();
+    while (state == currentState && timeoutNanoseconds > 0) {
+        if (durationNanos > timeoutNanoseconds) {
+            durationNanos = timeoutNanoseconds;
+        }
+        AudioClock::sleepForNanos(durationNanos);
+        timeoutNanoseconds -= durationNanos;
+
+        aaudio_result_t result = updateState();
+        if (result != AAUDIO_OK) {
+            return result;
+        }
+
+        state = getState();
+    }
+    if (nextState != nullptr) {
+        *nextState = state;
+    }
+    return (state == currentState) ? AAUDIO_ERROR_TIMEOUT : AAUDIO_OK;
+}
+
+// This registers the app's background audio thread with the server before
+// passing control to the app. This gives the server an opportunity to boost
+// the thread's performance characteristics.
+void* AudioStream::wrapUserThread() {
+    void* procResult = nullptr;
+    mThreadRegistrationResult = registerThread();
+    if (mThreadRegistrationResult == AAUDIO_OK) {
+        // Call application procedure. This may take a very long time.
+        procResult = mThreadProc(mThreadArg);
+        ALOGD("AudioStream::mThreadProc() returned");
+        mThreadRegistrationResult = unregisterThread();
+    }
+    return procResult;
+}
+
+// This is the entry point for the new thread created by createThread().
+// It converts the 'C' function call to a C++ method call.
+static void* AudioStream_internalThreadProc(void* threadArg) {
+    AudioStream *audioStream = (AudioStream *) threadArg;
+    return audioStream->wrapUserThread();
+}
+
+aaudio_result_t AudioStream::createThread(aaudio_nanoseconds_t periodNanoseconds,
+                                     aaudio_audio_thread_proc_t *threadProc,
+                                     void* threadArg)
+{
+    if (mHasThread) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    if (threadProc == nullptr) {
+        return AAUDIO_ERROR_NULL;
+    }
+    // Pass input parameters to the background thread.
+    mThreadProc = threadProc;
+    mThreadArg = threadArg;
+    setPeriodNanoseconds(periodNanoseconds);
+    int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this);
+    if (err != 0) {
+        // TODO convert errno to aaudio_result_t
+        return AAUDIO_ERROR_INTERNAL;
+    } else {
+        mHasThread = true;
+        return AAUDIO_OK;
+    }
+}
+
+aaudio_result_t AudioStream::joinThread(void** returnArg, aaudio_nanoseconds_t timeoutNanoseconds)
+{
+    if (!mHasThread) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+#if 0
+    // TODO implement equivalent of pthread_timedjoin_np()
+    struct timespec abstime;
+    int err = pthread_timedjoin_np(mThread, returnArg, &abstime);
+#else
+    int err = pthread_join(mThread, returnArg);
+#endif
+    mHasThread = false;
+    // TODO convert errno to aaudio_result_t
+    return err ? AAUDIO_ERROR_INTERNAL : mThreadRegistrationResult;
+}
+
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
new file mode 100644
index 0000000..8e4aa05
--- /dev/null
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAUDIO_AUDIOSTREAM_H
+#define AAUDIO_AUDIOSTREAM_H
+
+#include <atomic>
+#include <stdint.h>
+#include <aaudio/AAudioDefinitions.h>
+#include <aaudio/AAudio.h>
+
+#include "AAudioUtilities.h"
+#include "MonotonicCounter.h"
+
+namespace aaudio {
+
+class AudioStreamBuilder;
+
+/**
+ * AAudio audio stream.
+ */
+class AudioStream {
+public:
+
+    AudioStream();
+
+    virtual ~AudioStream();
+
+
+    // =========== Begin ABSTRACT methods ===========================
+
+    /* Asynchronous requests.
+     * Use waitForStateChange() to wait for completion.
+     */
+    virtual aaudio_result_t requestStart() = 0;
+    virtual aaudio_result_t requestPause() = 0;
+    virtual aaudio_result_t requestFlush() = 0;
+    virtual aaudio_result_t requestStop() = 0;
+
+    // TODO use aaudio_clockid_t all the way down to AudioClock
+    virtual aaudio_result_t getTimestamp(clockid_t clockId,
+                                       aaudio_position_frames_t *framePosition,
+                                       aaudio_nanoseconds_t *timeNanoseconds) = 0;
+
+
+    virtual aaudio_result_t updateState() = 0;
+
+
+    // =========== End ABSTRACT methods ===========================
+
+    virtual aaudio_result_t waitForStateChange(aaudio_stream_state_t currentState,
+                                          aaudio_stream_state_t *nextState,
+                                          aaudio_nanoseconds_t timeoutNanoseconds);
+
+    /**
+     * Open the stream using the parameters in the builder.
+     * Allocate the necessary resources.
+     */
+    virtual aaudio_result_t open(const AudioStreamBuilder& builder);
+
+    /**
+     * Close the stream and deallocate any resources from the open() call.
+     * It is safe to call close() multiple times.
+     */
+    virtual aaudio_result_t close() {
+        return AAUDIO_OK;
+    }
+
+    virtual aaudio_result_t setBufferSize(aaudio_size_frames_t requestedFrames,
+                                        aaudio_size_frames_t *actualFrames) {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual aaudio_result_t createThread(aaudio_nanoseconds_t periodNanoseconds,
+                                       aaudio_audio_thread_proc_t *threadProc,
+                                       void *threadArg);
+
+    virtual aaudio_result_t joinThread(void **returnArg, aaudio_nanoseconds_t timeoutNanoseconds);
+
+    virtual aaudio_result_t registerThread() {
+        return AAUDIO_OK;
+    }
+
+    virtual aaudio_result_t unregisterThread() {
+        return AAUDIO_OK;
+    }
+
+    /**
+     * Internal function used to call the audio thread passed by the user.
+     * It is unfortunately public because it needs to be called by a static 'C' function.
+     */
+    void* wrapUserThread();
+
+    // ============== Queries ===========================
+
+    virtual aaudio_stream_state_t getState() const {
+        return mState;
+    }
+
+    virtual aaudio_size_frames_t getBufferSize() const {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual aaudio_size_frames_t getBufferCapacity() const {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual aaudio_size_frames_t getFramesPerBurst() const {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual int32_t getXRunCount() const {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
+    bool isPlaying() const {
+        return mState == AAUDIO_STREAM_STATE_STARTING || mState == AAUDIO_STREAM_STATE_STARTED;
+    }
+
+    aaudio_result_t getSampleRate() const {
+        return mSampleRate;
+    }
+
+    aaudio_audio_format_t getFormat()  const {
+        return mFormat;
+    }
+
+    aaudio_result_t getSamplesPerFrame() const {
+        return mSamplesPerFrame;
+    }
+
+    aaudio_device_id_t getDeviceId() const {
+        return mDeviceId;
+    }
+
+    aaudio_sharing_mode_t getSharingMode() const {
+        return mSharingMode;
+    }
+
+    aaudio_direction_t getDirection() const {
+        return mDirection;
+    }
+
+    aaudio_size_bytes_t getBytesPerFrame() const {
+        return mSamplesPerFrame * getBytesPerSample();
+    }
+
+    aaudio_size_bytes_t getBytesPerSample() const {
+        return AAudioConvert_formatToSizeInBytes(mFormat);
+    }
+
+    virtual aaudio_position_frames_t getFramesWritten() {
+        return mFramesWritten.get();
+    }
+
+    virtual aaudio_position_frames_t getFramesRead() {
+        return mFramesRead.get();
+    }
+
+
+    // ============== I/O ===========================
+    // A Stream will only implement read() or write() depending on its direction.
+    virtual aaudio_result_t write(const void *buffer,
+                             aaudio_size_frames_t numFrames,
+                             aaudio_nanoseconds_t timeoutNanoseconds) {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual aaudio_result_t read(void *buffer,
+                            aaudio_size_frames_t numFrames,
+                            aaudio_nanoseconds_t timeoutNanoseconds) {
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
+protected:
+
+    virtual aaudio_position_frames_t incrementFramesWritten(aaudio_size_frames_t frames) {
+        return static_cast<aaudio_position_frames_t>(mFramesWritten.increment(frames));
+    }
+
+    virtual aaudio_position_frames_t incrementFramesRead(aaudio_size_frames_t frames) {
+        return static_cast<aaudio_position_frames_t>(mFramesRead.increment(frames));
+    }
+
+    /**
+     * Wait for a transition from one state to another.
+     * @return AAUDIO_OK if the endingState was observed, or AAUDIO_ERROR_UNEXPECTED_STATE
+     *   if any state that was not the startingState or endingState was observed
+     *   or AAUDIO_ERROR_TIMEOUT
+     */
+    virtual aaudio_result_t waitForStateTransition(aaudio_stream_state_t startingState,
+                                              aaudio_stream_state_t endingState,
+                                              aaudio_nanoseconds_t timeoutNanoseconds);
+
+    /**
+     * This should not be called after the open() call.
+     */
+    void setSampleRate(aaudio_sample_rate_t sampleRate) {
+        mSampleRate = sampleRate;
+    }
+
+    /**
+     * This should not be called after the open() call.
+     */
+    void setSamplesPerFrame(int32_t samplesPerFrame) {
+        mSamplesPerFrame = samplesPerFrame;
+    }
+
+    /**
+     * This should not be called after the open() call.
+     */
+    void setSharingMode(aaudio_sharing_mode_t sharingMode) {
+        mSharingMode = sharingMode;
+    }
+
+    /**
+     * This should not be called after the open() call.
+     */
+    void setFormat(aaudio_audio_format_t format) {
+        mFormat = format;
+    }
+
+    void setState(aaudio_stream_state_t state) {
+        mState = state;
+    }
+
+
+
+protected:
+    MonotonicCounter     mFramesWritten;
+    MonotonicCounter     mFramesRead;
+
+    void setPeriodNanoseconds(aaudio_nanoseconds_t periodNanoseconds) {
+        mPeriodNanoseconds.store(periodNanoseconds, std::memory_order_release);
+    }
+
+    aaudio_nanoseconds_t getPeriodNanoseconds() {
+        return mPeriodNanoseconds.load(std::memory_order_acquire);
+    }
+
+private:
+    // These do not change after open().
+    int32_t              mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+    aaudio_sample_rate_t   mSampleRate = AAUDIO_UNSPECIFIED;
+    aaudio_stream_state_t  mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
+    aaudio_device_id_t     mDeviceId = AAUDIO_UNSPECIFIED;
+    aaudio_sharing_mode_t  mSharingMode = AAUDIO_SHARING_MODE_LEGACY;
+    aaudio_audio_format_t  mFormat = AAUDIO_FORMAT_UNSPECIFIED;
+    aaudio_direction_t     mDirection = AAUDIO_DIRECTION_OUTPUT;
+
+    // background thread ----------------------------------
+    bool                 mHasThread = false;
+    pthread_t            mThread; // initialized in constructor
+
+    // These are set by the application thread and then read by the audio pthread.
+    std::atomic<aaudio_nanoseconds_t>  mPeriodNanoseconds; // for tuning SCHED_FIFO threads
+    // TODO make atomic?
+    aaudio_audio_thread_proc_t* mThreadProc = nullptr;
+    void*                mThreadArg = nullptr;
+    aaudio_result_t        mThreadRegistrationResult = AAUDIO_OK;
+
+
+};
+
+} /* namespace aaudio */
+
+#endif /* AAUDIO_AUDIOSTREAM_H */
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
new file mode 100644
index 0000000..decd53c
--- /dev/null
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <new>
+#include <stdint.h>
+
+#include <aaudio/AAudioDefinitions.h>
+#include <aaudio/AAudio.h>
+
+#include "client/AudioStreamInternal.h"
+#include "core/AudioStream.h"
+#include "core/AudioStreamBuilder.h"
+#include "legacy/AudioStreamRecord.h"
+#include "legacy/AudioStreamTrack.h"
+
+using namespace aaudio;
+
+/*
+ * AudioStreamBuilder
+ */
+AudioStreamBuilder::AudioStreamBuilder() {
+}
+
+AudioStreamBuilder::~AudioStreamBuilder() {
+}
+
+aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) {
+    // TODO Is there a better place to put the code that decides which class to use?
+    AudioStream* audioStream = nullptr;
+    const aaudio_sharing_mode_t sharingMode = getSharingMode();
+    switch (getDirection()) {
+    case AAUDIO_DIRECTION_INPUT:
+        switch (sharingMode) {
+            case AAUDIO_SHARING_MODE_LEGACY:
+                audioStream = new(std::nothrow) AudioStreamRecord();
+                break;
+            default:
+                ALOGE("AudioStreamBuilder(): bad sharing mode = %d", sharingMode);
+                return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+                break;
+        }
+        break;
+    case AAUDIO_DIRECTION_OUTPUT:
+        switch (sharingMode) {
+            case AAUDIO_SHARING_MODE_LEGACY:
+                audioStream = new(std::nothrow) AudioStreamTrack();
+                break;
+            case AAUDIO_SHARING_MODE_EXCLUSIVE:
+                audioStream = new(std::nothrow) AudioStreamInternal();
+                break;
+            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) {
+        return AAUDIO_ERROR_NO_MEMORY;
+    }
+    ALOGD("AudioStreamBuilder(): created audioStream = %p", audioStream);
+
+    // TODO maybe move this out of build and pass the builder to the constructors
+    // Open the stream using the parameters from the builder.
+    const aaudio_result_t result = audioStream->open(*this);
+    if (result != AAUDIO_OK) {
+        delete audioStream;
+    } else {
+        *streamPtr = audioStream;
+    }
+    return result;
+}
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h
new file mode 100644
index 0000000..e72633d
--- /dev/null
+++ b/media/libaaudio/src/core/AudioStreamBuilder.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAUDIO_AUDIOSTREAMBUILDER_H
+#define AAUDIO_AUDIOSTREAMBUILDER_H
+
+#include <stdint.h>
+
+#include <aaudio/AAudioDefinitions.h>
+#include <aaudio/AAudio.h>
+
+#include "AudioStream.h"
+
+namespace aaudio {
+
+/**
+ * Factory class for an AudioStream.
+ */
+class AudioStreamBuilder {
+public:
+    AudioStreamBuilder();
+
+    ~AudioStreamBuilder();
+
+    int getSamplesPerFrame() const {
+        return mSamplesPerFrame;
+    }
+
+    /**
+     * This is also known as channelCount.
+     */
+    AudioStreamBuilder* setSamplesPerFrame(int samplesPerFrame) {
+        mSamplesPerFrame = samplesPerFrame;
+        return this;
+    }
+
+    aaudio_direction_t getDirection() const {
+        return mDirection;
+    }
+
+    AudioStreamBuilder* setDirection(aaudio_direction_t direction) {
+        mDirection = direction;
+        return this;
+    }
+
+    aaudio_sample_rate_t getSampleRate() const {
+        return mSampleRate;
+    }
+
+    AudioStreamBuilder* setSampleRate(aaudio_sample_rate_t sampleRate) {
+        mSampleRate = sampleRate;
+        return this;
+    }
+
+    aaudio_audio_format_t getFormat() const {
+        return mFormat;
+    }
+
+    AudioStreamBuilder *setFormat(aaudio_audio_format_t format) {
+        mFormat = format;
+        return this;
+    }
+
+    aaudio_sharing_mode_t getSharingMode() const {
+        return mSharingMode;
+    }
+
+    AudioStreamBuilder* setSharingMode(aaudio_sharing_mode_t sharingMode) {
+        mSharingMode = sharingMode;
+        return this;
+    }
+
+    aaudio_size_frames_t getBufferCapacity() const {
+        return mBufferCapacity;
+    }
+
+    AudioStreamBuilder* setBufferCapacity(aaudio_size_frames_t frames) {
+        mBufferCapacity = frames;
+        return this;
+    }
+
+    aaudio_device_id_t getDeviceId() const {
+        return mDeviceId;
+    }
+
+    AudioStreamBuilder* setDeviceId(aaudio_device_id_t deviceId) {
+        mDeviceId = deviceId;
+        return this;
+    }
+
+    aaudio_result_t build(AudioStream **streamPtr);
+
+private:
+    int32_t                mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+    aaudio_sample_rate_t   mSampleRate = AAUDIO_UNSPECIFIED;
+    aaudio_device_id_t     mDeviceId = AAUDIO_DEVICE_UNSPECIFIED;
+    aaudio_sharing_mode_t  mSharingMode = AAUDIO_SHARING_MODE_LEGACY;
+    aaudio_audio_format_t  mFormat = AAUDIO_FORMAT_UNSPECIFIED;
+    aaudio_direction_t     mDirection = AAUDIO_DIRECTION_OUTPUT;
+    aaudio_size_frames_t   mBufferCapacity = AAUDIO_UNSPECIFIED;
+};
+
+} /* namespace aaudio */
+
+#endif /* AAUDIO_AUDIOSTREAMBUILDER_H */
diff --git a/media/libaaudio/src/core/README.md b/media/libaaudio/src/core/README.md
new file mode 100644
index 0000000..5ce41f3
--- /dev/null
+++ b/media/libaaudio/src/core/README.md
@@ -0,0 +1,2 @@
+The core folder contains the essential AAudio files common to all implementations.
+The AAudioAudio.cpp contains the 'C' API.
diff --git a/media/libaaudio/src/core/VersionExperiment.txt b/media/libaaudio/src/core/VersionExperiment.txt
new file mode 100644
index 0000000..071239b
--- /dev/null
+++ b/media/libaaudio/src/core/VersionExperiment.txt
@@ -0,0 +1,55 @@
+
+// TODO Experiment with versioning. This may be removed or changed dramatically.
+// Please ignore for now. Do not review.
+#define OBOE_VERSION_EXPERIMENT  0
+#if OBOE_VERSION_EXPERIMENT
+
+#define OBOE_EARLIEST_SUPPORTED_VERSION  1
+#define OBOE_CURRENT_VERSION  2
+
+typedef struct OboeInterface_s {
+    int32_t size; // do not use size_t because its size can vary
+    int32_t version;
+    int32_t reserved1;
+    void *  reserved2;
+    oboe_result_t (*createStreamBuilder)(OboeStreamBuilder *);
+} OboeInterface_t;
+
+OboeInterface_t s_oboe_template = {
+        .size = sizeof(OboeInterface_t),
+        .version = OBOE_CURRENT_VERSION,
+        .reserved1 = 0,
+        .reserved2 = NULL,
+        .createStreamBuilder = Oboe_createStreamBuilder
+};
+
+oboe_result_t Oboe_Unimplemented(OboeInterface_t *oboe) {
+    (void) oboe;
+    return OBOE_ERROR_UNIMPLEMENTED;
+}
+
+typedef oboe_result_t (*OboeFunction_t)(OboeInterface_t *oboe);
+
+int32_t Oboe_Initialize(OboeInterface_t *oboe, uint32_t flags) {
+    if (oboe->version < OBOE_EARLIEST_SUPPORTED_VERSION) {
+        return OBOE_ERROR_INCOMPATIBLE;
+    }
+    // Fill in callers vector table.
+    uint8_t *start = (uint8_t*)&oboe->reserved1;
+    uint8_t *end;
+    if (oboe->size <= s_oboe_template.size) {
+        end = ((uint8_t *)oboe) + oboe->size;
+    } else {
+        end = ((uint8_t *)oboe) + s_oboe_template.size;
+        // Assume the rest of the structure is vectors.
+        // Point them all to OboeInternal_Unimplemented()
+        // Point to first vector past end of the known structure.
+        OboeFunction_t *next = (OboeFunction_t*)end;
+        while ((((uint8_t *)next) - ((uint8_t *)oboe)) < oboe->size) {
+            *next++ = Oboe_Unimplemented;
+        }
+    }
+    memcpy(&oboe->reserved1, &s_oboe_template.reserved1, end - start);
+    return OBOE_OK;
+}
+#endif /* OBOE_VERSION_EXPERIMENT -------------------------- */
diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
new file mode 100644
index 0000000..c5489f1
--- /dev/null
+++ b/media/libaaudio/src/fifo/FifoBuffer.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstring>
+#include <unistd.h>
+
+#define LOG_TAG "FifoBuffer"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "FifoControllerBase.h"
+#include "FifoController.h"
+#include "FifoControllerIndirect.h"
+#include "FifoBuffer.h"
+
+FifoBuffer::FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames)
+        : mFrameCapacity(capacityInFrames)
+        , mBytesPerFrame(bytesPerFrame)
+        , mStorage(nullptr)
+        , mFramesReadCount(0)
+        , mFramesUnderrunCount(0)
+        , mUnderrunCount(0)
+{
+    // TODO Handle possible failures to allocate. Move out of constructor?
+    mFifo = new FifoController(capacityInFrames, capacityInFrames);
+    // allocate buffer
+    int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
+    mStorage = new uint8_t[bytesPerBuffer];
+    mStorageOwned = true;
+    ALOGD("FifoBuffer: capacityInFrames = %d, bytesPerFrame = %d",
+          capacityInFrames, bytesPerFrame);
+}
+
+FifoBuffer::FifoBuffer( int32_t   bytesPerFrame,
+                        fifo_frames_t   capacityInFrames,
+                        fifo_counter_t *  readIndexAddress,
+                        fifo_counter_t *  writeIndexAddress,
+                        void *  dataStorageAddress
+                        )
+        : mFrameCapacity(capacityInFrames)
+        , mBytesPerFrame(bytesPerFrame)
+        , mStorage(static_cast<uint8_t *>(dataStorageAddress))
+        , mFramesReadCount(0)
+        , mFramesUnderrunCount(0)
+        , mUnderrunCount(0)
+{
+    // TODO Handle possible failures to allocate. Move out of constructor?
+    mFifo = new FifoControllerIndirect(capacityInFrames,
+                                       capacityInFrames,
+                                       readIndexAddress,
+                                       writeIndexAddress);
+    mStorageOwned = false;
+    ALOGD("FifoProcessor: capacityInFrames = %d, bytesPerFrame = %d",
+          capacityInFrames, bytesPerFrame);
+}
+
+FifoBuffer::~FifoBuffer() {
+    if (mStorageOwned) {
+        delete[] mStorage;
+    }
+    delete mFifo;
+}
+
+
+int32_t FifoBuffer::convertFramesToBytes(fifo_frames_t frames) {
+    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;
+    }
+
+    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);
+    } else {
+        // just read in one shot
+        numBytes = convertFramesToBytes(framesToRead);
+        memcpy(destination, source, numBytes);
+    }
+    mFifo->advanceReadIndex(framesToRead);
+
+    return framesToRead;
+}
+
+fifo_frames_t FifoBuffer::write(const void *buffer, fifo_frames_t framesToWrite) {
+    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;
+    }
+
+    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);
+
+    return framesToWrite;
+}
+
+fifo_frames_t FifoBuffer::readNow(void *buffer, fifo_frames_t numFrames) {
+    mLastReadSize = numFrames;
+    fifo_frames_t framesLeft = numFrames;
+    fifo_frames_t framesRead = read(buffer, numFrames);
+    framesLeft -= framesRead;
+    mFramesReadCount += framesRead;
+    mFramesUnderrunCount += framesLeft;
+    // Zero out any samples we could not set.
+    if (framesLeft > 0) {
+        mUnderrunCount++;
+        int32_t bytesToZero = convertFramesToBytes(framesLeft);
+        memset(buffer, 0, bytesToZero);
+    }
+
+    return framesRead;
+}
+
+fifo_frames_t FifoBuffer::getThreshold() {
+    return mFifo->getThreshold();
+}
+
+void FifoBuffer::setThreshold(fifo_frames_t threshold) {
+    mFifo->setThreshold(threshold);
+}
+
+fifo_frames_t FifoBuffer::getBufferCapacityInFrames() {
+    return mFifo->getCapacity();
+}
+
diff --git a/media/libaaudio/src/fifo/FifoBuffer.h b/media/libaaudio/src/fifo/FifoBuffer.h
new file mode 100644
index 0000000..faa9ae2
--- /dev/null
+++ b/media/libaaudio/src/fifo/FifoBuffer.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIFO_FIFO_BUFFER_H
+#define FIFO_FIFO_BUFFER_H
+
+#include <stdint.h>
+
+#include "FifoControllerBase.h"
+
+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 convertFramesToBytes(fifo_frames_t frames);
+
+    fifo_frames_t read(void *destination, fifo_frames_t framesToRead);
+
+    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();
+
+    fifo_frames_t readNow(void *buffer, fifo_frames_t numFrames);
+
+    int64_t getNextReadTime(int32_t frameRate);
+
+    int32_t getUnderrunCount() const { return mUnderrunCount; }
+
+    FifoControllerBase *getFifoControllerBase() { return mFifo; }
+
+    int32_t getBytesPerFrame() {
+        return mBytesPerFrame;
+    }
+
+    fifo_counter_t getReadCounter() {
+        return mFifo->getReadCounter();
+    }
+
+    void setReadCounter(fifo_counter_t n) {
+        mFifo->setReadCounter(n);
+    }
+
+    fifo_counter_t getWriteCounter() {
+        return mFifo->getWriteCounter();
+    }
+
+    void setWriteCounter(fifo_counter_t n) {
+        mFifo->setWriteCounter(n);
+    }
+
+private:
+    const fifo_frames_t mFrameCapacity;
+    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;
+};
+
+#endif //FIFO_FIFO_BUFFER_H
diff --git a/media/libaaudio/src/fifo/FifoController.h b/media/libaaudio/src/fifo/FifoController.h
new file mode 100644
index 0000000..7434634
--- /dev/null
+++ b/media/libaaudio/src/fifo/FifoController.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIFO_FIFO_CONTROLLER_H
+#define FIFO_FIFO_CONTROLLER_H
+
+#include <stdint.h>
+#include <atomic>
+
+#include "FifoControllerBase.h"
+
+/**
+ * A FIFO with counters contained in the class.
+ */
+class FifoController : public FifoControllerBase
+{
+public:
+    FifoController(fifo_counter_t bufferSize, fifo_counter_t threshold)
+    : FifoControllerBase(bufferSize, threshold)
+    , mReadCounter(0)
+    , mWriteCounter(0)
+    {}
+
+    virtual ~FifoController() {}
+
+    // TODO review use of memory barriers, probably incorrect
+    virtual fifo_counter_t getReadCounter() override {
+        return mReadCounter.load(std::memory_order_acquire);
+    }
+    virtual void setReadCounter(fifo_counter_t n) override {
+        mReadCounter.store(n, std::memory_order_release);
+    }
+    virtual fifo_counter_t getWriteCounter() override {
+        return mWriteCounter.load(std::memory_order_acquire);
+    }
+    virtual void setWriteCounter(fifo_counter_t n) override {
+        mWriteCounter.store(n, std::memory_order_release);
+    }
+
+private:
+    std::atomic<fifo_counter_t> mReadCounter;
+    std::atomic<fifo_counter_t> mWriteCounter;
+};
+
+
+#endif //FIFO_FIFO_CONTROLLER_H
diff --git a/media/libaaudio/src/fifo/FifoControllerBase.cpp b/media/libaaudio/src/fifo/FifoControllerBase.cpp
new file mode 100644
index 0000000..33a253e
--- /dev/null
+++ b/media/libaaudio/src/fifo/FifoControllerBase.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "FifoControllerBase"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include "FifoControllerBase.h"
+
+FifoControllerBase::FifoControllerBase(fifo_frames_t capacity, fifo_frames_t threshold)
+        : mCapacity(capacity)
+        , mThreshold(threshold)
+{
+}
+
+FifoControllerBase::~FifoControllerBase() {
+}
+
+fifo_frames_t FifoControllerBase::getFullFramesAvailable() {
+    return (fifo_frames_t) (getWriteCounter() - getReadCounter());
+}
+
+fifo_frames_t FifoControllerBase::getReadIndex() {
+    // % works with non-power of two sizes
+    return (fifo_frames_t) (getReadCounter() % mCapacity);
+}
+
+void FifoControllerBase::advanceReadIndex(fifo_frames_t numFrames) {
+    setReadCounter(getReadCounter() + numFrames);
+}
+
+fifo_frames_t FifoControllerBase::getEmptyFramesAvailable() {
+    return (int32_t)(mThreshold - getFullFramesAvailable());
+}
+
+fifo_frames_t FifoControllerBase::getWriteIndex() {
+    // % works with non-power of two sizes
+    return (fifo_frames_t) (getWriteCounter() % mCapacity);
+}
+
+void FifoControllerBase::advanceWriteIndex(fifo_frames_t numFrames) {
+    setWriteCounter(getWriteCounter() + numFrames);
+}
+
+void FifoControllerBase::setThreshold(fifo_frames_t threshold) {
+    mThreshold = threshold;
+}
diff --git a/media/libaaudio/src/fifo/FifoControllerBase.h b/media/libaaudio/src/fifo/FifoControllerBase.h
new file mode 100644
index 0000000..c543519
--- /dev/null
+++ b/media/libaaudio/src/fifo/FifoControllerBase.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIFO_FIFO_CONTROLLER_BASE_H
+#define FIFO_FIFO_CONTROLLER_BASE_H
+
+#include <stdint.h>
+
+typedef int64_t fifo_counter_t;
+typedef int32_t fifo_frames_t;
+
+/**
+ * Manage the read/write indices of a circular buffer.
+ *
+ * The caller is responsible for reading and writing the actual data.
+ * Note that the span of available frames may not be contiguous. They
+ * may wrap around from the end to the beginning of the buffer. In that
+ * case the data must be read or written in at least two blocks of frames.
+ *
+ */
+class FifoControllerBase {
+
+public:
+    /**
+     * Constructor for FifoControllerBase
+     * @param capacity Total size of the circular buffer in frames.
+     * @param threshold Number of frames to fill. Must be less than capacity.
+     */
+    FifoControllerBase(fifo_frames_t capacity, fifo_frames_t threshold);
+
+    virtual ~FifoControllerBase();
+
+    // Abstract methods to be implemented in subclasses.
+    /**
+     * @return Counter used by the reader of the FIFO.
+     */
+    virtual fifo_counter_t getReadCounter() = 0;
+
+    /**
+     * This is normally only used internally.
+     * @param count Number of frames that have been read.
+     */
+    virtual void setReadCounter(fifo_counter_t count) = 0;
+
+    /**
+     * @return Counter used by the reader of the FIFO.
+     */
+    virtual fifo_counter_t getWriteCounter() = 0;
+
+    /**
+     * This is normally only used internally.
+     * @param count Number of frames that have been read.
+     */
+    virtual void setWriteCounter(fifo_counter_t count) = 0;
+
+    /**
+     * This may be negative if an unthrottled reader has read beyond the available data.
+     * @return number of valid frames available to read. Never read more than this.
+     */
+    fifo_frames_t getFullFramesAvailable();
+
+    /**
+     * The index in a circular buffer of the next frame to read.
+     */
+    fifo_frames_t getReadIndex();
+
+    /**
+     * @param numFrames number of frames to advance the read index
+     */
+    void advanceReadIndex(fifo_frames_t numFrames);
+
+    /**
+     * @return number of frames that can be written. Never write more than this.
+     */
+    fifo_frames_t getEmptyFramesAvailable();
+
+    /**
+     * The index in a circular buffer of the next frame to write.
+     */
+    fifo_frames_t getWriteIndex();
+
+    /**
+     * @param numFrames number of frames to advance the write index
+     */
+    void advanceWriteIndex(fifo_frames_t numFrames);
+
+    /**
+     * You can request that the buffer not be filled above a maximum
+     * number of frames.
+     * @param threshold effective size of the buffer
+     */
+    void setThreshold(fifo_frames_t threshold);
+
+    fifo_frames_t getThreshold() const {
+        return mThreshold;
+    }
+
+    fifo_frames_t getCapacity() const {
+        return mCapacity;
+    }
+
+
+private:
+    fifo_frames_t mCapacity;
+    fifo_frames_t mThreshold;
+};
+
+#endif // FIFO_FIFO_CONTROLLER_BASE_H
diff --git a/media/libaaudio/src/fifo/FifoControllerIndirect.h b/media/libaaudio/src/fifo/FifoControllerIndirect.h
new file mode 100644
index 0000000..1aaf9ea
--- /dev/null
+++ b/media/libaaudio/src/fifo/FifoControllerIndirect.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIFO_FIFO_CONTROLLER_INDIRECT_H
+#define FIFO_FIFO_CONTROLLER_INDIRECT_H
+
+#include <stdint.h>
+#include <atomic>
+
+#include "FifoControllerBase.h"
+
+/**
+ * A FifoControllerBase with counters external to the class.
+ *
+ * The actual copunters may be stored in separate regions of shared memory
+ * with different access rights.
+ */
+class FifoControllerIndirect : public FifoControllerBase {
+
+public:
+    FifoControllerIndirect(fifo_frames_t capacity,
+                           fifo_frames_t threshold,
+                           fifo_counter_t * readCounterAddress,
+                           fifo_counter_t * writeCounterAddress)
+        : FifoControllerBase(capacity, threshold)
+        , mReadCounterAddress((std::atomic<fifo_counter_t> *) readCounterAddress)
+        , mWriteCounterAddress((std::atomic<fifo_counter_t> *) writeCounterAddress)
+    {
+        setReadCounter(0);
+        setWriteCounter(0);
+    }
+    virtual ~FifoControllerIndirect() {};
+
+    // TODO review use of memory barriers, probably incorrect
+    virtual fifo_counter_t getReadCounter() override {
+        return mReadCounterAddress->load(std::memory_order_acquire);
+    }
+
+    virtual void setReadCounter(fifo_counter_t count) override {
+        mReadCounterAddress->store(count, std::memory_order_release);
+    }
+
+    virtual fifo_counter_t getWriteCounter() override {
+        return mWriteCounterAddress->load(std::memory_order_acquire);
+    }
+
+    virtual void setWriteCounter(fifo_counter_t count) override {
+        mWriteCounterAddress->store(count, std::memory_order_release);
+    }
+
+private:
+    std::atomic<fifo_counter_t> * mReadCounterAddress;
+    std::atomic<fifo_counter_t> * mWriteCounterAddress;
+};
+
+#endif //FIFO_FIFO_CONTROLLER_INDIRECT_H
diff --git a/media/libaaudio/src/fifo/README.md b/media/libaaudio/src/fifo/README.md
new file mode 100644
index 0000000..5d0c471
--- /dev/null
+++ b/media/libaaudio/src/fifo/README.md
@@ -0,0 +1,9 @@
+Simple atomic FIFO for passing data between threads or processes.
+This does not require mutexes.
+
+One thread modifies the readCounter and the other thread modifies the writeCounter.
+
+TODO The internal low-level implementation might be merged in some form with audio_utils fifo
+and/or FMQ [after confirming that requirements are met].
+The higher-levels parts related to AAudio use of the FIFO such as API, fds, relative
+location of indices and data buffer, mapping, allocation of memmory will probably be kept as-is.
diff --git a/media/libaaudio/src/legacy/AAudioLegacy.h b/media/libaaudio/src/legacy/AAudioLegacy.h
new file mode 100644
index 0000000..2ceb7d4
--- /dev/null
+++ b/media/libaaudio/src/legacy/AAudioLegacy.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAUDIO_LEGACY_H
+#define AAUDIO_LEGACY_H
+
+#include <stdint.h>
+#include <aaudio/AAudio.h>
+
+/**
+ * Common code for legacy classes.
+ */
+
+/* AudioTrack uses a 32-bit frame counter that can wrap around in about a day. */
+typedef uint32_t aaudio_wrapping_frames_t;
+
+#endif /* AAUDIO_LEGACY_H */
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
new file mode 100644
index 0000000..17d0a54
--- /dev/null
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioStreamRecord"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <utils/String16.h>
+#include <media/AudioRecord.h>
+#include <aaudio/AAudio.h>
+
+#include "AudioClock.h"
+#include "AudioStreamRecord.h"
+
+using namespace android;
+using namespace aaudio;
+
+AudioStreamRecord::AudioStreamRecord()
+    : AudioStream()
+{
+}
+
+AudioStreamRecord::~AudioStreamRecord()
+{
+    const aaudio_stream_state_t state = getState();
+    bool bad = !(state == AAUDIO_STREAM_STATE_UNINITIALIZED || state == AAUDIO_STREAM_STATE_CLOSED);
+    ALOGE_IF(bad, "stream not closed, in state %d", state);
+}
+
+aaudio_result_t AudioStreamRecord::open(const AudioStreamBuilder& builder)
+{
+    aaudio_result_t result = AAUDIO_OK;
+
+    result = AudioStream::open(builder);
+    if (result != AAUDIO_OK) {
+        return result;
+    }
+
+    // Try to create an AudioRecord
+
+    // TODO Support UNSPECIFIED in AudioTrack. For now, use stereo if unspecified.
+    int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
+                              ? 2 : getSamplesPerFrame();
+    audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(samplesPerFrame);
+
+    AudioRecord::callback_t callback = nullptr;
+    audio_input_flags_t flags = (audio_input_flags_t) AUDIO_INPUT_FLAG_NONE;
+
+    size_t frameCount = (builder.getBufferCapacity() == AAUDIO_UNSPECIFIED) ? 0
+                        : builder.getBufferCapacity();
+    // TODO implement an unspecified Android format then use that.
+    audio_format_t format = (getFormat() == AAUDIO_UNSPECIFIED)
+            ? AUDIO_FORMAT_PCM_FLOAT
+            : AAudioConvert_aaudioToAndroidDataFormat(getFormat());
+
+    mAudioRecord = new AudioRecord(
+            AUDIO_SOURCE_DEFAULT,
+            getSampleRate(),
+            format,
+            channelMask,
+            mOpPackageName, // const String16& opPackageName TODO does not compile
+            frameCount,
+            callback,
+            nullptr, //    void* user = nullptr,
+            0,    //    uint32_t notificationFrames = 0,
+            AUDIO_SESSION_ALLOCATE,
+            AudioRecord::TRANSFER_DEFAULT,
+            flags
+            //   int uid = -1,
+            //   pid_t pid = -1,
+            //   const audio_attributes_t* pAttributes = nullptr
+            );
+
+    // Did we get a valid track?
+    status_t status = mAudioRecord->initCheck();
+    if (status != OK) {
+        close();
+        ALOGE("AudioStreamRecord::open(), initCheck() returned %d", status);
+        return AAudioConvert_androidToAAudioResult(status);
+    }
+
+    // Get the actual rate.
+    setSampleRate(mAudioRecord->getSampleRate());
+    setSamplesPerFrame(mAudioRecord->channelCount());
+    setFormat(AAudioConvert_androidToAAudioDataFormat(mAudioRecord->format()));
+
+    setState(AAUDIO_STREAM_STATE_OPEN);
+
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamRecord::close()
+{
+    // TODO add close() or release() to AudioRecord API then call it from here
+    if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
+        mAudioRecord.clear();
+        setState(AAUDIO_STREAM_STATE_CLOSED);
+    }
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamRecord::requestStart()
+{
+    if (mAudioRecord.get() == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    // Get current position so we can detect when the track is playing.
+    status_t err = mAudioRecord->getPosition(&mPositionWhenStarting);
+    if (err != OK) {
+        return AAudioConvert_androidToAAudioResult(err);
+    }
+    err = mAudioRecord->start();
+    if (err != OK) {
+        return AAudioConvert_androidToAAudioResult(err);
+    } else {
+        setState(AAUDIO_STREAM_STATE_STARTING);
+    }
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamRecord::requestPause()
+{
+    return AAUDIO_ERROR_UNIMPLEMENTED;
+}
+
+aaudio_result_t AudioStreamRecord::requestFlush() {
+    return AAUDIO_ERROR_UNIMPLEMENTED;
+}
+
+aaudio_result_t AudioStreamRecord::requestStop() {
+    if (mAudioRecord.get() == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    setState(AAUDIO_STREAM_STATE_STOPPING);
+    mAudioRecord->stop();
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamRecord::updateState()
+{
+    aaudio_result_t result = AAUDIO_OK;
+    aaudio_wrapping_frames_t position;
+    status_t err;
+    switch (getState()) {
+    // TODO add better state visibility to AudioRecord
+    case AAUDIO_STREAM_STATE_STARTING:
+        err = mAudioRecord->getPosition(&position);
+        if (err != OK) {
+            result = AAudioConvert_androidToAAudioResult(err);
+        } else if (position != mPositionWhenStarting) {
+            setState(AAUDIO_STREAM_STATE_STARTED);
+        }
+        break;
+    case AAUDIO_STREAM_STATE_STOPPING:
+        if (mAudioRecord->stopped()) {
+            setState(AAUDIO_STREAM_STATE_STOPPED);
+        }
+        break;
+    default:
+        break;
+    }
+    return result;
+}
+
+aaudio_result_t AudioStreamRecord::read(void *buffer,
+                                      aaudio_size_frames_t numFrames,
+                                      aaudio_nanoseconds_t timeoutNanoseconds)
+{
+    aaudio_size_frames_t bytesPerFrame = getBytesPerFrame();
+    aaudio_size_bytes_t numBytes;
+    aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes);
+    if (result != AAUDIO_OK) {
+        return result;
+    }
+
+    // TODO add timeout to AudioRecord
+    bool blocking = (timeoutNanoseconds > 0);
+    ssize_t bytesRead = mAudioRecord->read(buffer, numBytes, blocking);
+    if (bytesRead == WOULD_BLOCK) {
+        return 0;
+    } else if (bytesRead < 0) {
+        return AAudioConvert_androidToAAudioResult(bytesRead);
+    }
+    aaudio_size_frames_t framesRead = (aaudio_size_frames_t)(bytesRead / bytesPerFrame);
+    return (aaudio_result_t) framesRead;
+}
+
+aaudio_result_t AudioStreamRecord::setBufferSize(aaudio_size_frames_t requestedFrames,
+                                             aaudio_size_frames_t *actualFrames)
+{
+    *actualFrames = getBufferCapacity();
+    return AAUDIO_OK;
+}
+
+aaudio_size_frames_t AudioStreamRecord::getBufferSize() const
+{
+    return getBufferCapacity(); // TODO implement in AudioRecord?
+}
+
+aaudio_size_frames_t AudioStreamRecord::getBufferCapacity() const
+{
+    return static_cast<aaudio_size_frames_t>(mAudioRecord->frameCount());
+}
+
+int32_t AudioStreamRecord::getXRunCount() const
+{
+    return AAUDIO_ERROR_UNIMPLEMENTED; // TODO implement when AudioRecord supports it
+}
+
+aaudio_size_frames_t AudioStreamRecord::getFramesPerBurst() const
+{
+    return 192; // TODO add query to AudioRecord.cpp
+}
+
+// TODO implement getTimestamp
+
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
new file mode 100644
index 0000000..a2ac9f3
--- /dev/null
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LEGACY_AUDIO_STREAM_RECORD_H
+#define LEGACY_AUDIO_STREAM_RECORD_H
+
+#include <media/AudioRecord.h>
+#include <aaudio/AAudio.h>
+
+#include "AudioStreamBuilder.h"
+#include "AudioStream.h"
+#include "AAudioLegacy.h"
+
+namespace aaudio {
+
+/**
+ * Internal stream that uses the legacy AudioTrack path.
+ */
+class AudioStreamRecord : public AudioStream {
+public:
+    AudioStreamRecord();
+
+    virtual ~AudioStreamRecord();
+
+    virtual aaudio_result_t open(const AudioStreamBuilder & builder) override;
+    virtual aaudio_result_t close() override;
+
+    virtual aaudio_result_t requestStart() override;
+    virtual aaudio_result_t requestPause() override;
+    virtual aaudio_result_t requestFlush() override;
+    virtual aaudio_result_t requestStop() override;
+
+    virtual aaudio_result_t getTimestamp(clockid_t clockId,
+                                       aaudio_position_frames_t *framePosition,
+                                       aaudio_nanoseconds_t *timeNanoseconds) override {
+        return AAUDIO_ERROR_UNIMPLEMENTED; // TODO
+    }
+
+    virtual aaudio_result_t read(void *buffer,
+                             aaudio_size_frames_t numFrames,
+                             aaudio_nanoseconds_t timeoutNanoseconds) override;
+
+    virtual aaudio_result_t setBufferSize(aaudio_size_frames_t requestedFrames,
+                                             aaudio_size_frames_t *actualFrames) override;
+
+    virtual aaudio_size_frames_t getBufferSize() const override;
+
+    virtual aaudio_size_frames_t getBufferCapacity() const override;
+
+    virtual int32_t getXRunCount() const override;
+
+    virtual aaudio_size_frames_t getFramesPerBurst() const override;
+
+    virtual aaudio_result_t updateState() override;
+
+private:
+    android::sp<android::AudioRecord> mAudioRecord;
+    // TODO add 64-bit position reporting to AudioRecord and use it.
+    aaudio_wrapping_frames_t   mPositionWhenStarting = 0;
+    android::String16        mOpPackageName;
+};
+
+} /* namespace aaudio */
+
+#endif /* LEGACY_AUDIO_STREAM_RECORD_H */
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
new file mode 100644
index 0000000..b7d8664
--- /dev/null
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioStreamTrack"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <media/AudioTrack.h>
+
+#include <aaudio/AAudio.h>
+#include "AudioClock.h"
+#include "AudioStreamTrack.h"
+
+
+using namespace android;
+using namespace aaudio;
+
+/*
+ * Create a stream that uses the AudioTrack.
+ */
+AudioStreamTrack::AudioStreamTrack()
+    : AudioStream()
+{
+}
+
+AudioStreamTrack::~AudioStreamTrack()
+{
+    const aaudio_stream_state_t state = getState();
+    bool bad = !(state == AAUDIO_STREAM_STATE_UNINITIALIZED || state == AAUDIO_STREAM_STATE_CLOSED);
+    ALOGE_IF(bad, "stream not closed, in state %d", state);
+}
+
+aaudio_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder)
+{
+    aaudio_result_t result = AAUDIO_OK;
+
+    result = AudioStream::open(builder);
+    if (result != OK) {
+        return result;
+    }
+
+    // Try to create an AudioTrack
+    // TODO Support UNSPECIFIED in AudioTrack. For now, use stereo if unspecified.
+    int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
+                              ? 2 : getSamplesPerFrame();
+    audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame);
+    ALOGD("AudioStreamTrack::open(), samplesPerFrame = %d, channelMask = 0x%08x",
+            samplesPerFrame, channelMask);
+
+    AudioTrack::callback_t callback = nullptr;
+    // TODO add more performance options
+    audio_output_flags_t flags = (audio_output_flags_t) AUDIO_OUTPUT_FLAG_FAST;
+    size_t frameCount = (builder.getBufferCapacity() == AAUDIO_UNSPECIFIED) ? 0
+                        : builder.getBufferCapacity();
+    // TODO implement an unspecified AudioTrack format then use that.
+    audio_format_t format = (getFormat() == AAUDIO_UNSPECIFIED)
+            ? AUDIO_FORMAT_PCM_FLOAT
+            : AAudioConvert_aaudioToAndroidDataFormat(getFormat());
+
+    mAudioTrack = new AudioTrack(
+            (audio_stream_type_t) AUDIO_STREAM_MUSIC,
+            getSampleRate(),
+            format,
+            channelMask,
+            frameCount,
+            flags,
+            callback,
+            nullptr,    // user callback data
+            0,          // notificationFrames
+            AUDIO_SESSION_ALLOCATE,
+            AudioTrack::transfer_type::TRANSFER_SYNC // TODO - this does not allow FAST
+            );
+
+    // Did we get a valid track?
+    status_t status = mAudioTrack->initCheck();
+    ALOGD("AudioStreamTrack::open(), initCheck() returned %d", status);
+    if (status != NO_ERROR) {
+        close();
+        ALOGE("AudioStreamTrack::open(), initCheck() returned %d", status);
+        return AAudioConvert_androidToAAudioResult(status);
+    }
+
+    // Get the actual values from the AudioTrack.
+    setSamplesPerFrame(mAudioTrack->channelCount());
+    setSampleRate(mAudioTrack->getSampleRate());
+    setFormat(AAudioConvert_androidToAAudioDataFormat(mAudioTrack->format()));
+
+    setState(AAUDIO_STREAM_STATE_OPEN);
+
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamTrack::close()
+{
+    // TODO maybe add close() or release() to AudioTrack API then call it from here
+    if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
+        mAudioTrack.clear(); // TODO is this right?
+        setState(AAUDIO_STREAM_STATE_CLOSED);
+    }
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamTrack::requestStart()
+{
+    if (mAudioTrack.get() == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    // Get current position so we can detect when the track is playing.
+    status_t err = mAudioTrack->getPosition(&mPositionWhenStarting);
+    if (err != OK) {
+        return AAudioConvert_androidToAAudioResult(err);
+    }
+    err = mAudioTrack->start();
+    if (err != OK) {
+        return AAudioConvert_androidToAAudioResult(err);
+    } else {
+        setState(AAUDIO_STREAM_STATE_STARTING);
+    }
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamTrack::requestPause()
+{
+    if (mAudioTrack.get() == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    } else if (getState() != AAUDIO_STREAM_STATE_STARTING
+            && getState() != AAUDIO_STREAM_STATE_STARTED) {
+        ALOGE("requestPause(), called when state is %s", AAudio_convertStreamStateToText(getState()));
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    setState(AAUDIO_STREAM_STATE_PAUSING);
+    mAudioTrack->pause();
+    status_t err = mAudioTrack->getPosition(&mPositionWhenPausing);
+    if (err != OK) {
+        return AAudioConvert_androidToAAudioResult(err);
+    }
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamTrack::requestFlush() {
+    if (mAudioTrack.get() == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    } else if (getState() != AAUDIO_STREAM_STATE_PAUSED) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    setState(AAUDIO_STREAM_STATE_FLUSHING);
+    incrementFramesRead(getFramesWritten() - getFramesRead());
+    mAudioTrack->flush();
+    mFramesWritten.reset32();
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamTrack::requestStop() {
+    if (mAudioTrack.get() == nullptr) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    }
+    setState(AAUDIO_STREAM_STATE_STOPPING);
+    incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review
+    mAudioTrack->stop();
+    mFramesWritten.reset32();
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamTrack::updateState()
+{
+    status_t err;
+    aaudio_wrapping_frames_t position;
+    switch (getState()) {
+    // TODO add better state visibility to AudioTrack
+    case AAUDIO_STREAM_STATE_STARTING:
+        if (mAudioTrack->hasStarted()) {
+            setState(AAUDIO_STREAM_STATE_STARTED);
+        }
+        break;
+    case AAUDIO_STREAM_STATE_PAUSING:
+        if (mAudioTrack->stopped()) {
+            err = mAudioTrack->getPosition(&position);
+            if (err != OK) {
+                return AAudioConvert_androidToAAudioResult(err);
+            } else if (position == mPositionWhenPausing) {
+                // Has stream really stopped advancing?
+                setState(AAUDIO_STREAM_STATE_PAUSED);
+            }
+            mPositionWhenPausing = position;
+        }
+        break;
+    case AAUDIO_STREAM_STATE_FLUSHING:
+        {
+            err = mAudioTrack->getPosition(&position);
+            if (err != OK) {
+                return AAudioConvert_androidToAAudioResult(err);
+            } else if (position == 0) {
+                // Advance frames read to match written.
+                setState(AAUDIO_STREAM_STATE_FLUSHED);
+            }
+        }
+        break;
+    case AAUDIO_STREAM_STATE_STOPPING:
+        if (mAudioTrack->stopped()) {
+            setState(AAUDIO_STREAM_STATE_STOPPED);
+        }
+        break;
+    default:
+        break;
+    }
+    return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamTrack::write(const void *buffer,
+                                      aaudio_size_frames_t numFrames,
+                                      aaudio_nanoseconds_t timeoutNanoseconds)
+{
+    aaudio_size_frames_t bytesPerFrame = getBytesPerFrame();
+    aaudio_size_bytes_t numBytes;
+    aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes);
+    if (result != AAUDIO_OK) {
+        return result;
+    }
+
+    // TODO add timeout to AudioTrack
+    bool blocking = timeoutNanoseconds > 0;
+    ssize_t bytesWritten = mAudioTrack->write(buffer, numBytes, blocking);
+    if (bytesWritten == WOULD_BLOCK) {
+        return 0;
+    } else if (bytesWritten < 0) {
+        ALOGE("invalid write, returned %d", (int)bytesWritten);
+        return AAudioConvert_androidToAAudioResult(bytesWritten);
+    }
+    aaudio_size_frames_t framesWritten = (aaudio_size_frames_t)(bytesWritten / bytesPerFrame);
+    incrementFramesWritten(framesWritten);
+    return framesWritten;
+}
+
+aaudio_result_t AudioStreamTrack::setBufferSize(aaudio_size_frames_t requestedFrames,
+                                             aaudio_size_frames_t *actualFrames)
+{
+    ssize_t result = mAudioTrack->setBufferSizeInFrames(requestedFrames);
+    if (result != OK) {
+        return AAudioConvert_androidToAAudioResult(result);
+    } else {
+        *actualFrames = result;
+        return AAUDIO_OK;
+    }
+}
+
+aaudio_size_frames_t AudioStreamTrack::getBufferSize() const
+{
+    return static_cast<aaudio_size_frames_t>(mAudioTrack->getBufferSizeInFrames());
+}
+
+aaudio_size_frames_t AudioStreamTrack::getBufferCapacity() const
+{
+    return static_cast<aaudio_size_frames_t>(mAudioTrack->frameCount());
+}
+
+int32_t AudioStreamTrack::getXRunCount() const
+{
+    return static_cast<int32_t>(mAudioTrack->getUnderrunCount());
+}
+
+int32_t AudioStreamTrack::getFramesPerBurst() const
+{
+    return 192; // TODO add query to AudioTrack.cpp
+}
+
+aaudio_position_frames_t AudioStreamTrack::getFramesRead() {
+    aaudio_wrapping_frames_t position;
+    status_t result;
+    switch (getState()) {
+    case AAUDIO_STREAM_STATE_STARTING:
+    case AAUDIO_STREAM_STATE_STARTED:
+    case AAUDIO_STREAM_STATE_STOPPING:
+        result = mAudioTrack->getPosition(&position);
+        if (result == OK) {
+            mFramesRead.update32(position);
+        }
+        break;
+    default:
+        break;
+    }
+    return AudioStream::getFramesRead();
+}
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h
new file mode 100644
index 0000000..73d0cac
--- /dev/null
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LEGACY_AUDIO_STREAM_TRACK_H
+#define LEGACY_AUDIO_STREAM_TRACK_H
+
+#include <media/AudioTrack.h>
+#include <aaudio/AAudio.h>
+
+#include "AudioStreamBuilder.h"
+#include "AudioStream.h"
+#include "AAudioLegacy.h"
+
+namespace aaudio {
+
+
+/**
+ * Internal stream that uses the legacy AudioTrack path.
+ */
+class AudioStreamTrack : public AudioStream {
+public:
+    AudioStreamTrack();
+
+    virtual ~AudioStreamTrack();
+
+
+    virtual aaudio_result_t open(const AudioStreamBuilder & builder) override;
+    virtual aaudio_result_t close() override;
+
+    virtual aaudio_result_t requestStart() override;
+    virtual aaudio_result_t requestPause() override;
+    virtual aaudio_result_t requestFlush() override;
+    virtual aaudio_result_t requestStop() override;
+
+    virtual aaudio_result_t getTimestamp(clockid_t clockId,
+                                       aaudio_position_frames_t *framePosition,
+                                       aaudio_nanoseconds_t *timeNanoseconds) override {
+        return AAUDIO_ERROR_UNIMPLEMENTED; // TODO call getTimestamp(ExtendedTimestamp *timestamp);
+    }
+
+    virtual aaudio_result_t write(const void *buffer,
+                             aaudio_size_frames_t numFrames,
+                             aaudio_nanoseconds_t timeoutNanoseconds) override;
+
+    virtual aaudio_result_t setBufferSize(aaudio_size_frames_t requestedFrames,
+                                             aaudio_size_frames_t *actualFrames) override;
+    virtual aaudio_size_frames_t getBufferSize() const override;
+    virtual aaudio_size_frames_t getBufferCapacity() const override;
+    virtual aaudio_size_frames_t getFramesPerBurst()const  override;
+    virtual int32_t getXRunCount() const override;
+
+    virtual aaudio_position_frames_t getFramesRead() override;
+
+    virtual aaudio_result_t updateState() override;
+
+private:
+    android::sp<android::AudioTrack> mAudioTrack;
+    // TODO add 64-bit position reporting to AudioRecord and use it.
+    aaudio_wrapping_frames_t           mPositionWhenStarting = 0;
+    aaudio_wrapping_frames_t           mPositionWhenPausing = 0;
+};
+
+} /* namespace aaudio */
+
+#endif /* LEGACY_AUDIO_STREAM_TRACK_H */
diff --git a/media/libaaudio/src/legacy/README.md b/media/libaaudio/src/legacy/README.md
new file mode 100644
index 0000000..8805915
--- /dev/null
+++ b/media/libaaudio/src/legacy/README.md
@@ -0,0 +1,2 @@
+The legacy folder contains the classes that implement AAudio AudioStream on top of
+Android AudioTrack and AudioRecord.
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
new file mode 100644
index 0000000..34c1ae4
--- /dev/null
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+#include "aaudio/AAudioDefinitions.h"
+#include "AAudioUtilities.h"
+
+using namespace android;
+
+aaudio_size_bytes_t AAudioConvert_formatToSizeInBytes(aaudio_audio_format_t format) {
+    aaudio_size_bytes_t size = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+    switch (format) {
+        case AAUDIO_FORMAT_PCM_I16:
+            size = sizeof(int16_t);
+            break;
+        case AAUDIO_FORMAT_PCM_I32:
+        case AAUDIO_FORMAT_PCM_I8_24:
+            size = sizeof(int32_t);
+            break;
+        case AAUDIO_FORMAT_PCM_FLOAT:
+            size = sizeof(float);
+            break;
+        default:
+            break;
+    }
+    return size;
+}
+
+// TODO This similar to a function in audio_utils. Consider using that instead.
+void AAudioConvert_floatToPcm16(const float *source, int32_t numSamples, int16_t *destination) {
+    for (int i = 0; i < numSamples; i++) {
+        float fval = source[i];
+        fval += 1.0; // to avoid discontinuity at 0.0 caused by truncation
+        fval *= 32768.0f;
+        int32_t sample = (int32_t) fval;
+        // clip to 16-bit range
+        if (sample < 0) sample = 0;
+        else if (sample > 0x0FFFF) sample = 0x0FFFF;
+        sample -= 32768; // center at zero
+        destination[i] = (int16_t) sample;
+    }
+}
+
+void AAudioConvert_pcm16ToFloat(const float *source, int32_t numSamples, int16_t *destination) {
+    for (int i = 0; i < numSamples; i++) {
+        destination[i] = source[i] * (1.0f / 32768.0f);
+    }
+}
+
+status_t AAudioConvert_aaudioToAndroidStatus(aaudio_result_t result) {
+    // This covers the case for AAUDIO_OK and for positive results.
+    if (result >= 0) {
+        return result;
+    }
+    status_t status;
+    switch (result) {
+    case AAUDIO_ERROR_DISCONNECTED:
+    case AAUDIO_ERROR_INVALID_HANDLE:
+        status = DEAD_OBJECT;
+        break;
+    case AAUDIO_ERROR_INVALID_STATE:
+        status = INVALID_OPERATION;
+        break;
+    case AAUDIO_ERROR_UNEXPECTED_VALUE: // TODO redundant?
+    case AAUDIO_ERROR_ILLEGAL_ARGUMENT:
+        status = BAD_VALUE;
+        break;
+    case AAUDIO_ERROR_WOULD_BLOCK:
+        status = WOULD_BLOCK;
+        break;
+    // TODO add more result codes
+    default:
+        status = UNKNOWN_ERROR;
+        break;
+    }
+    return status;
+}
+
+aaudio_result_t AAudioConvert_androidToAAudioResult(status_t status) {
+    // This covers the case for OK and for positive result.
+    if (status >= 0) {
+        return status;
+    }
+    aaudio_result_t result;
+    switch (status) {
+    case BAD_TYPE:
+        result = AAUDIO_ERROR_INVALID_HANDLE;
+        break;
+    case DEAD_OBJECT:
+        result = AAUDIO_ERROR_DISCONNECTED;
+        break;
+    case INVALID_OPERATION:
+        result = AAUDIO_ERROR_INVALID_STATE;
+        break;
+    case BAD_VALUE:
+        result = AAUDIO_ERROR_UNEXPECTED_VALUE;
+        break;
+    case WOULD_BLOCK:
+        result = AAUDIO_ERROR_WOULD_BLOCK;
+        break;
+    // TODO add more status codes
+    default:
+        result = AAUDIO_ERROR_INTERNAL;
+        break;
+    }
+    return result;
+}
+
+audio_format_t AAudioConvert_aaudioToAndroidDataFormat(aaudio_audio_format_t aaudioFormat) {
+    audio_format_t androidFormat;
+    switch (aaudioFormat) {
+    case AAUDIO_FORMAT_PCM_I16:
+        androidFormat = AUDIO_FORMAT_PCM_16_BIT;
+        break;
+    case AAUDIO_FORMAT_PCM_FLOAT:
+        androidFormat = AUDIO_FORMAT_PCM_FLOAT;
+        break;
+    case AAUDIO_FORMAT_PCM_I8_24:
+        androidFormat = AUDIO_FORMAT_PCM_8_24_BIT;
+        break;
+    case AAUDIO_FORMAT_PCM_I32:
+        androidFormat = AUDIO_FORMAT_PCM_32_BIT;
+        break;
+    default:
+        androidFormat = AUDIO_FORMAT_DEFAULT;
+        ALOGE("AAudioConvert_aaudioToAndroidDataFormat 0x%08X unrecognized", aaudioFormat);
+        break;
+    }
+    return androidFormat;
+}
+
+aaudio_audio_format_t AAudioConvert_androidToAAudioDataFormat(audio_format_t androidFormat) {
+    aaudio_audio_format_t aaudioFormat = AAUDIO_FORMAT_INVALID;
+    switch (androidFormat) {
+    case AUDIO_FORMAT_PCM_16_BIT:
+        aaudioFormat = AAUDIO_FORMAT_PCM_I16;
+        break;
+    case AUDIO_FORMAT_PCM_FLOAT:
+        aaudioFormat = AAUDIO_FORMAT_PCM_FLOAT;
+        break;
+    case AUDIO_FORMAT_PCM_32_BIT:
+        aaudioFormat = AAUDIO_FORMAT_PCM_I32;
+        break;
+    case AUDIO_FORMAT_PCM_8_24_BIT:
+        aaudioFormat = AAUDIO_FORMAT_PCM_I8_24;
+        break;
+    default:
+        aaudioFormat = AAUDIO_FORMAT_INVALID;
+        ALOGE("AAudioConvert_androidToAAudioDataFormat 0x%08X unrecognized", androidFormat);
+        break;
+    }
+    return aaudioFormat;
+}
+
+aaudio_size_bytes_t AAudioConvert_framesToBytes(aaudio_size_frames_t numFrames,
+                                            aaudio_size_bytes_t bytesPerFrame,
+                                            aaudio_size_bytes_t *sizeInBytes) {
+    // TODO implement more elegantly
+    const int32_t maxChannels = 256; // ridiculously large
+    const aaudio_size_frames_t maxBytesPerFrame = maxChannels * sizeof(float);
+    // Prevent overflow by limiting multiplicands.
+    if (bytesPerFrame > maxBytesPerFrame || numFrames > (0x3FFFFFFF / maxBytesPerFrame)) {
+        ALOGE("size overflow, numFrames = %d, frameSize = %zd", numFrames, bytesPerFrame);
+        return AAUDIO_ERROR_OUT_OF_RANGE;
+    }
+    *sizeInBytes = numFrames * bytesPerFrame;
+    return AAUDIO_OK;
+}
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
new file mode 100644
index 0000000..38696df
--- /dev/null
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UTILITY_AAUDIO_UTILITIES_H
+#define UTILITY_AAUDIO_UTILITIES_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <hardware/audio.h>
+
+#include "aaudio/AAudioDefinitions.h"
+
+/**
+ * Convert an AAudio result into the closest matching Android status.
+ */
+android::status_t AAudioConvert_aaudioToAndroidStatus(aaudio_result_t result);
+
+/**
+ * Convert an Android status into the closest matching AAudio result.
+ */
+aaudio_result_t AAudioConvert_androidToAAudioResult(android::status_t status);
+
+void AAudioConvert_floatToPcm16(const float *source, int32_t numSamples, int16_t *destination);
+
+void AAudioConvert_pcm16ToFloat(const int16_t *source, int32_t numSamples, float *destination);
+
+/**
+ * Calculate the number of bytes and prevent numeric overflow.
+ * @param numFrames frame count
+ * @param bytesPerFrame size of a frame in bytes
+ * @param sizeInBytes total size in bytes
+ * @return AAUDIO_OK or negative error, eg. AAUDIO_ERROR_OUT_OF_RANGE
+ */
+aaudio_size_bytes_t AAudioConvert_framesToBytes(aaudio_size_frames_t numFrames,
+                                            aaudio_size_bytes_t bytesPerFrame,
+                                            aaudio_size_bytes_t *sizeInBytes);
+
+audio_format_t AAudioConvert_aaudioToAndroidDataFormat(aaudio_audio_format_t aaudio_format);
+
+aaudio_audio_format_t AAudioConvert_androidToAAudioDataFormat(audio_format_t format);
+
+/**
+ * @return the size of a sample of the given format in bytes or AAUDIO_ERROR_ILLEGAL_ARGUMENT
+ */
+aaudio_size_bytes_t AAudioConvert_formatToSizeInBytes(aaudio_audio_format_t format);
+
+#endif //UTILITY_AAUDIO_UTILITIES_H
diff --git a/media/libaaudio/src/utility/AudioClock.h b/media/libaaudio/src/utility/AudioClock.h
new file mode 100644
index 0000000..9ac21d3
--- /dev/null
+++ b/media/libaaudio/src/utility/AudioClock.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UTILITY_AUDIO_CLOCK_H
+#define UTILITY_AUDIO_CLOCK_H
+
+#include <stdint.h>
+#include <time.h>
+
+#include <aaudio/AAudioDefinitions.h>
+
+class AudioClock {
+public:
+    static aaudio_nanoseconds_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
+        struct timespec time;
+        int result = clock_gettime(clockId, &time);
+        if (result < 0) {
+            return -errno;
+        }
+        return (time.tv_sec * AAUDIO_NANOS_PER_SECOND) + time.tv_nsec;
+    }
+
+    /**
+     * Sleep until the specified absolute time.
+     * Return immediately with AAUDIO_ERROR_ILLEGAL_ARGUMENT if a negative
+     * nanoTime is specified.
+     *
+     * @param nanoTime time to wake up
+     * @param clockId CLOCK_MONOTONIC is default
+     * @return 0, a negative error, or 1 if the call is interrupted by a signal handler (EINTR)
+     */
+    static int sleepUntilNanoTime(aaudio_nanoseconds_t nanoTime,
+                                  clockid_t clockId = CLOCK_MONOTONIC) {
+        if (nanoTime > 0) {
+            struct timespec time;
+            time.tv_sec = nanoTime / AAUDIO_NANOS_PER_SECOND;
+            // Calculate the fractional nanoseconds. Avoids expensive % operation.
+            time.tv_nsec = nanoTime - (time.tv_sec * AAUDIO_NANOS_PER_SECOND);
+            int err = clock_nanosleep(clockId, TIMER_ABSTIME, &time, nullptr);
+            switch (err) {
+            case EINTR:
+                return 1;
+            case 0:
+                return 0;
+            default:
+                // Subtract because clock_nanosleep() returns a positive error number!
+                return 0 - err;
+            }
+        } else {
+            return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+        }
+    }
+
+    /**
+     * Sleep for the specified number of relative nanoseconds in real-time.
+     * Return immediately with 0 if a negative nanoseconds is specified.
+     *
+     * @param nanoseconds time to sleep
+     * @param clockId CLOCK_MONOTONIC is default
+     * @return 0, a negative error, or 1 if the call is interrupted by a signal handler (EINTR)
+     */
+    static int sleepForNanos(aaudio_nanoseconds_t nanoseconds, clockid_t clockId = CLOCK_MONOTONIC) {
+        if (nanoseconds > 0) {
+            struct timespec time;
+            time.tv_sec = nanoseconds / AAUDIO_NANOS_PER_SECOND;
+            // Calculate the fractional nanoseconds. Avoids expensive % operation.
+            time.tv_nsec = nanoseconds - (time.tv_sec * AAUDIO_NANOS_PER_SECOND);
+            const int flags = 0; // documented as relative sleep
+            int err = clock_nanosleep(clockId, flags, &time, nullptr);
+            switch (err) {
+            case EINTR:
+                return 1;
+            case 0:
+                return 0;
+            default:
+                // Subtract because clock_nanosleep() returns a positive error number!
+                return 0 - err;
+            }
+        }
+        return 0;
+    }
+};
+
+
+#endif // UTILITY_AUDIO_CLOCK_H
diff --git a/media/libaaudio/src/utility/HandleTracker.cpp b/media/libaaudio/src/utility/HandleTracker.cpp
new file mode 100644
index 0000000..c4880b8
--- /dev/null
+++ b/media/libaaudio/src/utility/HandleTracker.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#define LOG_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <assert.h>
+#include <new>
+#include <stdint.h>
+#include <utils/Mutex.h>
+
+#include <aaudio/AAudioDefinitions.h>
+#include "HandleTracker.h"
+
+using android::Mutex;
+
+// Handle format is: tgggiiii
+// where each letter is 4 bits, t=type, g=generation, i=index
+
+#define TYPE_SIZE           4
+#define GENERATION_SIZE    12
+#define INDEX_SIZE         16
+
+#define GENERATION_INVALID  0
+#define GENERATION_SHIFT    INDEX_SIZE
+
+#define TYPE_MASK           ((1 << TYPE_SIZE) - 1)
+#define GENERATION_MASK     ((1 << GENERATION_SIZE) - 1)
+#define INDEX_MASK          ((1 << INDEX_SIZE) - 1)
+
+#define SLOT_UNAVAILABLE    (-1)
+
+// Error if handle is negative so type is limited to bottom half.
+#define HANDLE_INVALID_TYPE TYPE_MASK
+
+static_assert(HANDLE_TRACKER_MAX_TYPES == (1 << (TYPE_SIZE - 1)),
+    "Mismatch between header and cpp.");
+static_assert(HANDLE_TRACKER_MAX_HANDLES == (1 << (INDEX_SIZE)),
+    "Mismatch between header and cpp.");
+
+HandleTracker::HandleTracker(uint32_t maxHandles)
+        : mMaxHandleCount(maxHandles)
+        , mHandleHeaders(nullptr)
+{
+    assert(maxHandles <= HANDLE_TRACKER_MAX_HANDLES);
+    // Allocate arrays to hold addresses and validation info.
+    mHandleAddresses = (handle_tracker_address_t *)
+            new(std::nothrow) handle_tracker_address_t[maxHandles];
+    if (mHandleAddresses != nullptr) {
+        mHandleHeaders = new(std::nothrow) handle_tracker_header_t[maxHandles];
+
+        if (mHandleHeaders != nullptr) {
+            handle_tracker_header_t initialHeader = buildHeader(0, 1);
+            // Initialize linked list of free nodes. nullptr terminated.
+            for (uint32_t i = 0; i < (maxHandles - 1); i++) {
+                mHandleAddresses[i] = &mHandleAddresses[i + 1]; // point to next node
+                mHandleHeaders[i] = initialHeader;
+            }
+            mNextFreeAddress = &mHandleAddresses[0];
+            mHandleAddresses[maxHandles - 1] = nullptr;
+            mHandleHeaders[maxHandles - 1] = 0;
+        } else {
+            delete[] mHandleAddresses; // so the class appears uninitialized
+            mHandleAddresses = nullptr;
+        }
+    }
+}
+
+HandleTracker::~HandleTracker()
+{
+    Mutex::Autolock _l(mLock);
+    delete[] mHandleAddresses;
+    delete[] mHandleHeaders;
+    mHandleAddresses = nullptr;
+}
+
+bool HandleTracker::isInitialized() const {
+    return mHandleAddresses != nullptr;
+}
+
+handle_tracker_slot_t HandleTracker::allocateSlot_l() {
+    void **allocated = mNextFreeAddress;
+    if (allocated == nullptr) {
+        return SLOT_UNAVAILABLE;
+    }
+    // Remove this slot from the head of the linked list.
+    mNextFreeAddress = (void **) *allocated;
+    return (allocated - mHandleAddresses);
+}
+
+handle_tracker_generation_t HandleTracker::nextGeneration_l(handle_tracker_slot_t index) {
+    handle_tracker_generation_t generation = (mHandleHeaders[index] + 1) & GENERATION_MASK;
+    // Avoid generation zero so that 0x0 is not a valid handle.
+    if (generation == GENERATION_INVALID) {
+        generation++;
+    }
+    return generation;
+}
+
+aaudio_handle_t HandleTracker::put(handle_tracker_type_t type, void *address)
+{
+    if (type < 0 || type >= HANDLE_TRACKER_MAX_TYPES) {
+        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_OUT_OF_RANGE);
+    }
+    if (!isInitialized()) {
+        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_MEMORY);
+    }
+
+    Mutex::Autolock _l(mLock);
+
+    // Find an empty slot.
+    handle_tracker_slot_t index = allocateSlot_l();
+    if (index == SLOT_UNAVAILABLE) {
+        ALOGE("HandleTracker::put() no room for more handles");
+        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_FREE_HANDLES);
+    }
+
+    // Cycle the generation counter so stale handles can be detected.
+    handle_tracker_generation_t generation = nextGeneration_l(index); // reads header table
+    handle_tracker_header_t inputHeader = buildHeader(type, generation);
+
+    // These two writes may need to be observed by other threads or cores during get().
+    mHandleHeaders[index] = inputHeader;
+    mHandleAddresses[index] = address;
+    // TODO use store release to enforce memory order with get()
+
+    // Generate a handle.
+    aaudio_handle_t handle = buildHandle(inputHeader, index);
+
+    ALOGV("HandleTracker::put(%p) returns 0x%08x", address, handle);
+    return handle;
+}
+
+handle_tracker_slot_t HandleTracker::handleToIndex(handle_tracker_type_t type,
+                                                   aaudio_handle_t handle) const
+{
+    // Validate the handle.
+    handle_tracker_slot_t index = extractIndex(handle);
+    if (index >= mMaxHandleCount) {
+        ALOGE("HandleTracker::handleToIndex() invalid handle = 0x%08X", handle);
+        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
+    }
+    handle_tracker_generation_t handleGeneration = extractGeneration(handle);
+    handle_tracker_header_t inputHeader = buildHeader(type, handleGeneration);
+    // We do not need to synchronize this access to mHandleHeaders because it is constant for
+    // the lifetime of the handle.
+    if (inputHeader != mHandleHeaders[index]) {
+        ALOGE("HandleTracker::handleToIndex() inputHeader = 0x%08x != mHandleHeaders[%d] = 0x%08x",
+             inputHeader, index, mHandleHeaders[index]);
+        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
+    }
+    return index;
+}
+
+handle_tracker_address_t HandleTracker::get(handle_tracker_type_t type, aaudio_handle_t handle) const
+{
+    if (!isInitialized()) {
+        return nullptr;
+    }
+    handle_tracker_slot_t index = handleToIndex(type, handle);
+    if (index >= 0) {
+        // We do not need to synchronize this access to mHandleHeaders because this slot
+        // is allocated and, therefore, not part of the linked list of free slots.
+        return mHandleAddresses[index];
+    } else {
+        return nullptr;
+    }
+}
+
+handle_tracker_address_t HandleTracker::remove(handle_tracker_type_t type, aaudio_handle_t handle) {
+    if (!isInitialized()) {
+        return nullptr;
+    }
+
+    Mutex::Autolock _l(mLock);
+
+    handle_tracker_slot_t index = handleToIndex(type,handle);
+    if (index >= 0) {
+        handle_tracker_address_t address = mHandleAddresses[index];
+
+        // Invalidate the header type but preserve the generation count.
+        handle_tracker_generation_t generation = mHandleHeaders[index] & GENERATION_MASK;
+        handle_tracker_header_t inputHeader = buildHeader(
+                (handle_tracker_type_t) HANDLE_INVALID_TYPE, generation);
+        mHandleHeaders[index] = inputHeader;
+
+        // Add this slot to the head of the linked list.
+        mHandleAddresses[index] = mNextFreeAddress;
+        mNextFreeAddress = (handle_tracker_address_t *) &mHandleAddresses[index];
+        return address;
+    } else {
+        return nullptr;
+    }
+}
+
+aaudio_handle_t HandleTracker::buildHandle(handle_tracker_header_t typeGeneration,
+                                         handle_tracker_slot_t index) {
+    return (aaudio_handle_t)((typeGeneration << GENERATION_SHIFT) | (index & INDEX_MASK));
+}
+
+handle_tracker_header_t HandleTracker::buildHeader(handle_tracker_type_t type,
+                                    handle_tracker_generation_t generation)
+{
+    return (handle_tracker_header_t) (((type & TYPE_MASK) << GENERATION_SIZE)
+        | (generation & GENERATION_MASK));
+}
+
+handle_tracker_slot_t HandleTracker::extractIndex(aaudio_handle_t handle)
+{
+    return handle & INDEX_MASK;
+}
+
+handle_tracker_generation_t HandleTracker::extractGeneration(aaudio_handle_t handle)
+{
+    return (handle >> GENERATION_SHIFT) & GENERATION_MASK;
+}
diff --git a/media/libaaudio/src/utility/HandleTracker.h b/media/libaaudio/src/utility/HandleTracker.h
new file mode 100644
index 0000000..c80860c
--- /dev/null
+++ b/media/libaaudio/src/utility/HandleTracker.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UTILITY_HANDLE_TRACKER_H
+#define UTILITY_HANDLE_TRACKER_H
+
+#include <stdint.h>
+#include <utils/Mutex.h>
+
+typedef int32_t  handle_tracker_type_t;       // what kind of handle
+typedef int32_t  handle_tracker_slot_t;       // index in allocation table
+typedef int32_t  handle_tracker_generation_t; // incremented when slot used
+typedef uint16_t handle_tracker_header_t;     // combines type and generation
+typedef void    *handle_tracker_address_t;    // address of something that is stored here
+
+#define HANDLE_TRACKER_MAX_TYPES    (1 << 3)
+#define HANDLE_TRACKER_MAX_HANDLES  (1 << 16)
+
+/**
+ * Represent Objects using an integer handle that can be used with Java.
+ * This also makes the 'C' ABI more robust.
+ *
+ * Note that this should only be called from a single thread.
+ * If you call it from more than one thread then you need to use your own mutex.
+ */
+class HandleTracker {
+
+public:
+    /**
+     * @param maxHandles cannot exceed HANDLE_TRACKER_MAX_HANDLES
+     */
+    HandleTracker(uint32_t maxHandles = 256);
+    virtual ~HandleTracker();
+
+    /**
+     * Don't use if this returns false;
+     * @return true if the internal allocation succeeded
+     */
+    bool isInitialized() const;
+
+    /**
+     * Store a pointer and return a handle that can be used to retrieve the pointer.
+     *
+     * It is safe to call put() or remove() from multiple threads.
+     *
+     * @param expectedType the type of the object to be tracked
+     * @param address pointer to be converted to a handle
+     * @return a valid handle or a negative error
+     */
+    aaudio_handle_t put(handle_tracker_type_t expectedType, handle_tracker_address_t address);
+
+    /**
+     * Get the original pointer associated with the handle.
+     * The handle will be validated to prevent stale handles from being reused.
+     * Note that the validation is designed to prevent common coding errors and not
+     * to prevent deliberate hacking.
+     *
+     * @param expectedType shouldmatch the type we passed to put()
+     * @param handle to be converted to a pointer
+     * @return address associated with handle or nullptr
+     */
+    handle_tracker_address_t get(handle_tracker_type_t expectedType, aaudio_handle_t handle) const;
+
+    /**
+     * Free up the storage associated with the handle.
+     * Subsequent attempts to use the handle will fail.
+     *
+     * Do NOT remove() a handle while get() is being called for the same handle from another thread.
+     *
+     * @param expectedType shouldmatch the type we passed to put()
+     * @param handle to be removed from tracking
+     * @return address associated with handle or nullptr if not found
+     */
+    handle_tracker_address_t remove(handle_tracker_type_t expectedType, aaudio_handle_t handle);
+
+private:
+    const int32_t               mMaxHandleCount;   // size of array
+    // This address is const after initialization.
+    handle_tracker_address_t  * mHandleAddresses;  // address of objects or a free linked list node
+    // This address is const after initialization.
+    handle_tracker_header_t   * mHandleHeaders;    // combination of type and generation
+    // head of the linked list of free nodes in mHandleAddresses
+    handle_tracker_address_t  * mNextFreeAddress;
+
+    // This Mutex protects the linked list of free nodes.
+    // The list is managed using mHandleAddresses and mNextFreeAddress.
+    // The data in mHandleHeaders is only changed by put() and remove().
+    android::Mutex              mLock;
+
+    /**
+     * Pull slot off of a list of empty slots.
+     * @return index or a negative error
+     */
+    handle_tracker_slot_t allocateSlot_l();
+
+    /**
+     * Increment the generation for the slot, avoiding zero.
+     */
+    handle_tracker_generation_t nextGeneration_l(handle_tracker_slot_t index);
+
+    /**
+     * Validate the handle and return the corresponding index.
+     * @return slot index or a negative error
+     */
+    handle_tracker_slot_t handleToIndex(aaudio_handle_t handle, handle_tracker_type_t type) const;
+
+    /**
+     * Construct a handle from a header and an index.
+     * @param header combination of a type and a generation
+     * @param index slot index returned from allocateSlot
+     * @return handle or a negative error
+     */
+    static aaudio_handle_t buildHandle(handle_tracker_header_t header, handle_tracker_slot_t index);
+
+    /**
+     * Combine a type and a generation field into a header.
+     */
+    static handle_tracker_header_t buildHeader(handle_tracker_type_t type,
+                handle_tracker_generation_t generation);
+
+    /**
+     * Extract the index from a handle.
+     * Does not validate the handle.
+     * @return index associated with a handle
+     */
+    static handle_tracker_slot_t extractIndex(aaudio_handle_t handle);
+
+    /**
+     * Extract the generation from a handle.
+     * Does not validate the handle.
+     * @return generation associated with a handle
+     */
+    static handle_tracker_generation_t extractGeneration(aaudio_handle_t handle);
+
+};
+
+#endif //UTILITY_HANDLE_TRACKER_H
diff --git a/media/libaaudio/src/utility/MonotonicCounter.h b/media/libaaudio/src/utility/MonotonicCounter.h
new file mode 100644
index 0000000..81d7f89
--- /dev/null
+++ b/media/libaaudio/src/utility/MonotonicCounter.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UTILITY_MONOTONIC_COUNTER_H
+#define UTILITY_MONOTONIC_COUNTER_H
+
+#include <stdint.h>
+
+/**
+ * Maintain a 64-bit monotonic counter.
+ * Can be used to track a 32-bit counter that wraps or gets reset.
+ *
+ * Note that this is not atomic and has no interior locks.
+ * A caller will need to provide their own exterior locking
+ * if they need to use it from multiple threads.
+ */
+class MonotonicCounter {
+
+public:
+    MonotonicCounter() {};
+    virtual ~MonotonicCounter() {};
+
+    /**
+     * @return current value of the counter
+     */
+    int64_t get() const {
+        return mCounter64;
+    }
+
+    /**
+     * Advance the counter if delta is positive.
+     * @return current value of the counter
+     */
+    int64_t increment(int64_t delta) {
+        if (delta > 0) {
+            mCounter64 += delta;
+        }
+        return mCounter64;
+    }
+
+    /**
+     * Advance the 64-bit counter if (current32 - previousCurrent32) > 0.
+     * This can be used to convert a 32-bit counter that may be wrapping into
+     * a monotonic 64-bit counter.
+     *
+     * This counter32 should NOT be allowed to advance by more than 0x7FFFFFFF between calls.
+     * Think of the wrapping counter like a sine wave. If the frequency of the signal
+     * is more than half the sampling rate (Nyquist rate) then you cannot measure it properly.
+     * If the counter wraps around every 24 hours then we should measure it with a period
+     * of less than 12 hours.
+     *
+     * @return current value of the 64-bit counter
+     */
+    int64_t update32(int32_t counter32) {
+        int32_t delta = counter32 - mCounter32;
+        // protect against the mCounter64 going backwards
+        if (delta > 0) {
+            mCounter64 += delta;
+            mCounter32 = counter32;
+        }
+        return mCounter64;
+    }
+
+    /**
+     * Reset the stored value of the 32-bit counter.
+     * This is used if your counter32 has been reset to zero.
+     */
+    void reset32() {
+        mCounter32 = 0;
+    }
+
+private:
+    int64_t mCounter64 = 0;
+    int32_t mCounter32 = 0;
+};
+
+
+#endif //UTILITY_MONOTONIC_COUNTER_H
diff --git a/media/libaaudio/src/utility/README.md b/media/libaaudio/src/utility/README.md
new file mode 100644
index 0000000..0ac74ea
--- /dev/null
+++ b/media/libaaudio/src/utility/README.md
@@ -0,0 +1,3 @@
+The utility folder contains things that may be shared between the AAudio client and server.
+They might also be handy outside AAudio.
+They generally do not depend on AAudio functionality.
diff --git a/media/libaaudio/tests/Android.mk b/media/libaaudio/tests/Android.mk
new file mode 100644
index 0000000..24dad4a
--- /dev/null
+++ b/media/libaaudio/tests/Android.mk
@@ -0,0 +1,42 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/libaaudio/include \
+    frameworks/av/media/libaaudio/src/core \
+    frameworks/av/media/libaaudio/src/utility
+LOCAL_SRC_FILES := test_aaudio_api.cpp
+LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \
+                          libcutils liblog libmedia libutils
+LOCAL_STATIC_LIBRARIES := libaaudio
+LOCAL_MODULE := test_aaudio_api
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/libaaudio/include \
+    frameworks/av/media/libaaudio/src/core \
+    frameworks/av/media/libaaudio/src/utility
+LOCAL_SRC_FILES:= test_handle_tracker.cpp
+LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \
+                          libcutils liblog libmedia libutils
+LOCAL_STATIC_LIBRARIES := libaaudio
+LOCAL_MODULE := test_handle_tracker
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/libaaudio/include \
+    frameworks/av/media/libaaudio/src \
+    frameworks/av/media/libaaudio/src/core \
+    frameworks/av/media/libaaudio/src/fifo \
+    frameworks/av/media/libaaudio/src/utility
+LOCAL_SRC_FILES:= test_marshalling.cpp
+LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \
+                          libcutils liblog libmedia libutils
+LOCAL_STATIC_LIBRARIES := libaaudio
+LOCAL_MODULE := test_marshalling
+include $(BUILD_NATIVE_TEST)
diff --git a/media/libaaudio/tests/test_aaudio_api.cpp b/media/libaaudio/tests/test_aaudio_api.cpp
new file mode 100644
index 0000000..7db3688
--- /dev/null
+++ b/media/libaaudio/tests/test_aaudio_api.cpp
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit tests for AAudio 'C' API.
+
+#include <stdlib.h>
+#include <math.h>
+
+#include <gtest/gtest.h>
+
+#include <aaudio/AAudioDefinitions.h>
+#include <aaudio/AAudio.h>
+#include "AAudioUtilities.h"
+
+#define DEFAULT_STATE_TIMEOUT  (500 * AAUDIO_NANOS_PER_MILLISECOND)
+
+// Test AAudioStreamBuilder
+TEST(test_aaudio_api, aaudio_stream_builder) {
+    const aaudio_sample_rate_t requestedSampleRate1 = 48000;
+    const aaudio_sample_rate_t requestedSampleRate2 = 44100;
+    const int32_t requestedSamplesPerFrame = 2;
+    const aaudio_audio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM16;
+
+    aaudio_sample_rate_t sampleRate = 0;
+    int32_t samplesPerFrame = 0;
+    aaudio_audio_format_t actualDataFormat;
+    AAudioStreamBuilder aaudioBuilder1;
+    AAudioStreamBuilder aaudioBuilder2;
+
+    aaudio_result_t result = AAUDIO_OK;
+
+    // Use an AAudioStreamBuilder to define the stream.
+    result = AAudio_createStreamBuilder(&aaudioBuilder1);
+    ASSERT_EQ(AAUDIO_OK, result);
+
+    // Request stream properties.
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setSampleRate(aaudioBuilder1, requestedSampleRate1));
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setSamplesPerFrame(aaudioBuilder1, requestedSamplesPerFrame));
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setFormat(aaudioBuilder1, requestedDataFormat));
+
+    // Check to make sure builder saved the properties.
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_getSampleRate(aaudioBuilder1, &sampleRate));
+    EXPECT_EQ(requestedSampleRate1, sampleRate);
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_getSamplesPerFrame(aaudioBuilder1, &samplesPerFrame));
+    EXPECT_EQ(requestedSamplesPerFrame, samplesPerFrame);
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_getFormat(aaudioBuilder1, &actualDataFormat));
+    EXPECT_EQ(requestedDataFormat, actualDataFormat);
+
+    result = AAudioStreamBuilder_getSampleRate(0x0BADCAFE, &sampleRate); // ridiculous token
+    EXPECT_EQ(AAUDIO_ERROR_INVALID_HANDLE, result);
+
+    // Create a second builder and make sure they do not collide.
+    ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder2));
+    ASSERT_NE(aaudioBuilder1, aaudioBuilder2);
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setSampleRate(aaudioBuilder2, requestedSampleRate2));
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_getSampleRate(aaudioBuilder1, &sampleRate));
+    EXPECT_EQ(requestedSampleRate1, sampleRate);
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_getSampleRate(aaudioBuilder2, &sampleRate));
+    EXPECT_EQ(requestedSampleRate2, sampleRate);
+
+    // Delete the builder.
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder1));
+
+    // Now it should no longer be valid.
+    // Note that test assumes we are using the HandleTracker. If we use plain pointers
+    // then it will be difficult to detect this kind of error.
+    result = AAudioStreamBuilder_getSampleRate(aaudioBuilder1, &sampleRate); // stale token
+    EXPECT_EQ(AAUDIO_ERROR_INVALID_HANDLE, result);
+
+    // Second builder should still be valid.
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_getSampleRate(aaudioBuilder2, &sampleRate));
+    EXPECT_EQ(requestedSampleRate2, sampleRate);
+
+    // Delete the second builder.
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder2));
+
+    // Now it should no longer be valid. Assumes HandlerTracker used.
+    EXPECT_EQ(AAUDIO_ERROR_INVALID_HANDLE, AAudioStreamBuilder_getSampleRate(aaudioBuilder2, &sampleRate));
+}
+
+// Test creating a default stream with everything unspecified.
+TEST(test_aaudio_api, aaudio_stream_unspecified) {
+    AAudioStreamBuilder aaudioBuilder;
+    AAudioStream aaudioStream;
+    aaudio_result_t result = AAUDIO_OK;
+
+    // Use an AAudioStreamBuilder to define the stream.
+    result = AAudio_createStreamBuilder(&aaudioBuilder);
+    ASSERT_EQ(AAUDIO_OK, result);
+
+    // Create an AAudioStream using the Builder.
+    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
+
+    // Cleanup
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder));
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
+}
+
+// Test Writing to an AAudioStream
+void runtest_aaudio_stream(aaudio_sharing_mode_t requestedSharingMode) {
+    const aaudio_sample_rate_t requestedSampleRate = 48000;
+    const aaudio_sample_rate_t requestedSamplesPerFrame = 2;
+    const aaudio_audio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM16;
+
+    aaudio_sample_rate_t actualSampleRate = -1;
+    int32_t actualSamplesPerFrame = -1;
+    aaudio_audio_format_t actualDataFormat = AAUDIO_FORMAT_INVALID;
+    aaudio_sharing_mode_t actualSharingMode;
+    aaudio_size_frames_t framesPerBurst = -1;
+    int writeLoops = 0;
+
+    aaudio_size_frames_t framesWritten = 0;
+    aaudio_size_frames_t framesPrimed = 0;
+    aaudio_position_frames_t framesTotal = 0;
+    aaudio_position_frames_t aaudioFramesRead = 0;
+    aaudio_position_frames_t aaudioFramesRead1 = 0;
+    aaudio_position_frames_t aaudioFramesRead2 = 0;
+    aaudio_position_frames_t aaudioFramesWritten = 0;
+
+    aaudio_nanoseconds_t timeoutNanos;
+
+    aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
+    AAudioStreamBuilder aaudioBuilder;
+    AAudioStream aaudioStream;
+
+    aaudio_result_t result = AAUDIO_OK;
+
+    // Use an AAudioStreamBuilder to define the stream.
+    result = AAudio_createStreamBuilder(&aaudioBuilder);
+    ASSERT_EQ(AAUDIO_OK, result);
+
+    // Request stream properties.
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setSampleRate(aaudioBuilder, requestedSampleRate));
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setSamplesPerFrame(aaudioBuilder, requestedSamplesPerFrame));
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setFormat(aaudioBuilder, requestedDataFormat));
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setSharingMode(aaudioBuilder, requestedSharingMode));
+
+    // Create an AAudioStream using the Builder.
+    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder));
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_getState(aaudioStream, &state));
+    EXPECT_EQ(AAUDIO_STREAM_STATE_OPEN, state);
+
+    // Check to see what kind of stream we actually got.
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_getSampleRate(aaudioStream, &actualSampleRate));
+    ASSERT_TRUE(actualSampleRate >= 44100 && actualSampleRate <= 96000);  // TODO what is range?
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_getSamplesPerFrame(aaudioStream, &actualSamplesPerFrame));
+    ASSERT_TRUE(actualSamplesPerFrame >= 1 && actualSamplesPerFrame <= 16); // TODO what is max?
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_getSharingMode(aaudioStream, &actualSharingMode));
+    ASSERT_TRUE(actualSharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE
+                || actualSharingMode == AAUDIO_SHARING_MODE_LEGACY);
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_getFormat(aaudioStream, &actualDataFormat));
+    EXPECT_NE(AAUDIO_FORMAT_INVALID, actualDataFormat);
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_getFramesPerBurst(aaudioStream, &framesPerBurst));
+    ASSERT_TRUE(framesPerBurst >= 16 && framesPerBurst <= 1024); // TODO what is min/max?
+
+    // Allocate a buffer for the audio data.
+    // TODO handle possibility of other data formats
+    ASSERT_TRUE(actualDataFormat == AAUDIO_FORMAT_PCM16);
+    size_t dataSizeSamples = framesPerBurst * actualSamplesPerFrame;
+    int16_t *data = new int16_t[dataSizeSamples];
+    ASSERT_TRUE(nullptr != data);
+    memset(data, 0, sizeof(int16_t) * dataSizeSamples);
+
+    // Prime the buffer.
+    timeoutNanos = 0;
+    do {
+        framesWritten = AAudioStream_write(aaudioStream, data, framesPerBurst, timeoutNanos);
+        // There should be some room for priming the buffer.
+        framesTotal += framesWritten;
+        ASSERT_GE(framesWritten, 0);
+        ASSERT_LE(framesWritten, framesPerBurst);
+    } while (framesWritten > 0);
+    ASSERT_TRUE(framesTotal > 0);
+
+    // Start/write/pause more than once to see if it fails after the first time.
+    // Write some data and measure the rate to see if the timing is OK.
+    for (int numLoops = 0; numLoops < 2; numLoops++) {
+        // Start and wait for server to respond.
+        ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream));
+        ASSERT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(aaudioStream,
+                                                         AAUDIO_STREAM_STATE_STARTING,
+                                                         &state,
+                                                         DEFAULT_STATE_TIMEOUT));
+        EXPECT_EQ(AAUDIO_STREAM_STATE_STARTED, state);
+
+        // Write some data while we are running. Read counter should be advancing.
+        writeLoops = 1 * actualSampleRate / framesPerBurst; // 1 second
+        ASSERT_LT(2, writeLoops); // detect absurdly high framesPerBurst
+        timeoutNanos = 10 * AAUDIO_NANOS_PER_SECOND * framesPerBurst / actualSampleRate; // bursts
+        framesWritten = 1;
+        ASSERT_EQ(AAUDIO_OK, AAudioStream_getFramesRead(aaudioStream, &aaudioFramesRead));
+        aaudioFramesRead1 = aaudioFramesRead;
+        aaudio_nanoseconds_t beginTime = AAudio_getNanoseconds(AAUDIO_CLOCK_MONOTONIC);
+        do {
+            framesWritten = AAudioStream_write(aaudioStream, data, framesPerBurst, timeoutNanos);
+            ASSERT_GE(framesWritten, 0);
+            ASSERT_LE(framesWritten, framesPerBurst);
+
+            framesTotal += framesWritten;
+            EXPECT_EQ(AAUDIO_OK, AAudioStream_getFramesWritten(aaudioStream, &aaudioFramesWritten));
+            EXPECT_EQ(framesTotal, aaudioFramesWritten);
+
+            // Try to get a more accurate measure of the sample rate.
+            if (beginTime == 0) {
+                EXPECT_EQ(AAUDIO_OK, AAudioStream_getFramesRead(aaudioStream, &aaudioFramesRead));
+                if (aaudioFramesRead > aaudioFramesRead1) { // is read pointer advancing
+                    beginTime = AAudio_getNanoseconds(AAUDIO_CLOCK_MONOTONIC);
+                    aaudioFramesRead1 = aaudioFramesRead;
+                }
+            }
+        } while (framesWritten > 0 && writeLoops-- > 0);
+
+        EXPECT_EQ(AAUDIO_OK, AAudioStream_getFramesRead(aaudioStream, &aaudioFramesRead2));
+        aaudio_nanoseconds_t endTime = AAudio_getNanoseconds(AAUDIO_CLOCK_MONOTONIC);
+        ASSERT_GT(aaudioFramesRead2, 0);
+        ASSERT_GT(aaudioFramesRead2, aaudioFramesRead1);
+        ASSERT_LE(aaudioFramesRead2, aaudioFramesWritten);
+
+        // TODO why is legacy so inaccurate?
+        const double rateTolerance = 200.0; // arbitrary tolerance for sample rate
+        if (requestedSharingMode != AAUDIO_SHARING_MODE_LEGACY) {
+            // Calculate approximate sample rate and compare with stream rate.
+            double seconds = (endTime - beginTime) / (double) AAUDIO_NANOS_PER_SECOND;
+            double measuredRate = (aaudioFramesRead2 - aaudioFramesRead1) / seconds;
+            ASSERT_NEAR(actualSampleRate, measuredRate, rateTolerance);
+        }
+
+        // Request async pause and wait for server to say that it has completed the pause.
+        ASSERT_EQ(AAUDIO_OK, AAudioStream_requestPause(aaudioStream));
+        EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(aaudioStream,
+                                                AAUDIO_STREAM_STATE_PAUSING,
+                                                &state,
+                                                DEFAULT_STATE_TIMEOUT));
+        EXPECT_EQ(AAUDIO_STREAM_STATE_PAUSED, state);
+    }
+
+    // Make sure the read counter is not advancing when we are paused.
+    ASSERT_EQ(AAUDIO_OK, AAudioStream_getFramesRead(aaudioStream, &aaudioFramesRead));
+    ASSERT_GE(aaudioFramesRead, aaudioFramesRead2); // monotonic increase
+
+    // Use this to sleep by waiting for something that won't happen.
+    AAudioStream_waitForStateChange(aaudioStream, AAUDIO_STREAM_STATE_PAUSED, &state, timeoutNanos);
+    ASSERT_EQ(AAUDIO_OK, AAudioStream_getFramesRead(aaudioStream, &aaudioFramesRead2));
+    EXPECT_EQ(aaudioFramesRead, aaudioFramesRead2);
+
+    // ------------------- TEST FLUSH -----------------
+    // Prime the buffer.
+    timeoutNanos = 0;
+    writeLoops = 100;
+    do {
+        framesWritten = AAudioStream_write(aaudioStream, data, framesPerBurst, timeoutNanos);
+        framesTotal += framesWritten;
+    } while (framesWritten > 0 && writeLoops-- > 0);
+    EXPECT_EQ(0, framesWritten);
+
+    // Flush and wait for server to respond.
+    ASSERT_EQ(AAUDIO_OK, AAudioStream_requestFlush(aaudioStream));
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(aaudioStream,
+                                                     AAUDIO_STREAM_STATE_FLUSHING,
+                                                     &state,
+                                                     DEFAULT_STATE_TIMEOUT));
+    EXPECT_EQ(AAUDIO_STREAM_STATE_FLUSHED, state);
+
+    // After a flush, the read counter should be caught up with the write counter.
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_getFramesWritten(aaudioStream, &aaudioFramesWritten));
+    EXPECT_EQ(framesTotal, aaudioFramesWritten);
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_getFramesRead(aaudioStream, &aaudioFramesRead));
+    EXPECT_EQ(aaudioFramesRead, aaudioFramesWritten);
+
+    // The buffer should be empty after a flush so we should be able to write.
+    framesWritten = AAudioStream_write(aaudioStream, data, framesPerBurst, timeoutNanos);
+    // There should be some room for priming the buffer.
+    ASSERT_TRUE(framesWritten > 0 && framesWritten <= framesPerBurst);
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
+}
+
+// Test Writing to an AAudioStream using LEGACY sharing mode.
+TEST(test_aaudio_api, aaudio_stream_legacy) {
+    runtest_aaudio_stream(AAUDIO_SHARING_MODE_LEGACY);
+}
+
+// Test Writing to an AAudioStream using EXCLUSIVE sharing mode.
+TEST(test_aaudio_api, aaudio_stream_exclusive) {
+    runtest_aaudio_stream(AAUDIO_SHARING_MODE_EXCLUSIVE);
+}
+
+#define AAUDIO_THREAD_ANSWER          1826375
+#define AAUDIO_THREAD_DURATION_MSEC       500
+
+static void *TestAAudioStreamThreadProc(void *arg) {
+    AAudioStream aaudioStream = (AAudioStream) reinterpret_cast<size_t>(arg);
+    aaudio_stream_state_t state;
+
+    // Use this to sleep by waiting for something that won't happen.
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_getState(aaudioStream, &state));
+    AAudioStream_waitForStateChange(aaudioStream, AAUDIO_STREAM_STATE_PAUSED, &state,
+            AAUDIO_THREAD_DURATION_MSEC * AAUDIO_NANOS_PER_MILLISECOND);
+    return reinterpret_cast<void *>(AAUDIO_THREAD_ANSWER);
+}
+
+// Test creating a stream related thread.
+TEST(test_aaudio_api, aaudio_stream_thread_basic) {
+    AAudioStreamBuilder aaudioBuilder;
+    AAudioStream aaudioStream;
+    aaudio_result_t result = AAUDIO_OK;
+    void *threadResult;
+
+    // Use an AAudioStreamBuilder to define the stream.
+    result = AAudio_createStreamBuilder(&aaudioBuilder);
+    ASSERT_EQ(AAUDIO_OK, result);
+
+    // Create an AAudioStream using the Builder.
+    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
+
+    // Start a thread.
+    ASSERT_EQ(AAUDIO_OK, AAudioStream_createThread(aaudioStream,
+            10 * AAUDIO_NANOS_PER_MILLISECOND,
+            TestAAudioStreamThreadProc,
+            reinterpret_cast<void *>(aaudioStream)));
+    // Thread already started.
+    ASSERT_NE(AAUDIO_OK, AAudioStream_createThread(aaudioStream,   // should fail!
+            10 * AAUDIO_NANOS_PER_MILLISECOND,
+            TestAAudioStreamThreadProc,
+            reinterpret_cast<void *>(aaudioStream)));
+
+    // Wait for the thread to finish.
+    ASSERT_EQ(AAUDIO_OK, AAudioStream_joinThread(aaudioStream,
+            &threadResult, 2 * AAUDIO_THREAD_DURATION_MSEC * AAUDIO_NANOS_PER_MILLISECOND));
+    // The thread returns a special answer.
+    ASSERT_EQ(AAUDIO_THREAD_ANSWER, (int)reinterpret_cast<size_t>(threadResult));
+
+    // Thread should already be joined.
+    ASSERT_NE(AAUDIO_OK, AAudioStream_joinThread(aaudioStream,  // should fail!
+            &threadResult, 2 * AAUDIO_THREAD_DURATION_MSEC * AAUDIO_NANOS_PER_MILLISECOND));
+
+    // Cleanup
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder));
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
+}
diff --git a/media/libaaudio/tests/test_handle_tracker.cpp b/media/libaaudio/tests/test_handle_tracker.cpp
new file mode 100644
index 0000000..e51c39c
--- /dev/null
+++ b/media/libaaudio/tests/test_handle_tracker.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit tests for AAudio Handle Tracker
+
+#include <stdlib.h>
+#include <math.h>
+
+#include <gtest/gtest.h>
+
+#include <aaudio/AAudioDefinitions.h>
+#include "HandleTracker.h"
+
+// Test adding one address.
+TEST(test_handle_tracker, aaudio_handle_tracker) {
+    const int MAX_HANDLES = 4;
+    HandleTracker tracker(MAX_HANDLES);
+    handle_tracker_type_t type = 3; // arbitrary generic type
+    int data; // something that has an address we can use
+    handle_tracker_address_t found;
+
+    // repeat the test several times to see if it breaks
+    const int SEVERAL = 5; // arbitrary
+    for (int i = 0; i < SEVERAL; i++) {
+        // should fail to find a bogus handle
+        found = tracker.get(type, 0);  // bad handle
+        EXPECT_EQ(nullptr, found);
+
+        // create a valid handle and use it to lookup the object again
+        aaudio_handle_t dataHandle = tracker.put(type, &data);
+        ASSERT_TRUE(dataHandle > 0);
+        found = tracker.get(type, dataHandle);
+        EXPECT_EQ(&data, found);
+        found = tracker.get(type, 0); // bad handle
+        EXPECT_EQ(nullptr, found);
+
+        // wrong type
+        found = tracker.get(type+1, dataHandle);
+        EXPECT_EQ(nullptr, found);
+
+        // remove from storage
+        found = tracker.remove(type, dataHandle);
+        EXPECT_EQ(&data, found);
+        // should fail the second time
+        found = tracker.remove(type, dataHandle);
+        EXPECT_EQ(nullptr, found);
+    }
+}
+
+// Test filling the tracker.
+TEST(test_handle_tracker, aaudio_full_up) {
+    const int MAX_HANDLES = 5;
+    HandleTracker tracker(MAX_HANDLES);
+    handle_tracker_type_t type = 4; // arbitrary generic type
+    int data[MAX_HANDLES];
+    aaudio_handle_t handles[MAX_HANDLES];
+    handle_tracker_address_t found;
+
+    // repeat the test several times to see if it breaks
+    const int SEVERAL = 5; // arbitrary
+    for (int i = 0; i < SEVERAL; i++) {
+        for (int i = 0; i < MAX_HANDLES; i++) {
+            // add a handle
+            handles[i] = tracker.put(type, &data[i]);
+            ASSERT_TRUE(handles[i] > 0);
+            found = tracker.get(type, handles[i]);
+            EXPECT_EQ(&data[i], found);
+        }
+
+        // Now that it is full, try to add one more.
+        aaudio_handle_t handle = tracker.put(type, &data[0]);
+        EXPECT_TRUE(handle < 0);
+
+        for (int i = 0; i < MAX_HANDLES; i++) {
+            // look up each handle
+            found = tracker.get(type, handles[i]);
+            EXPECT_EQ(&data[i], found);
+        }
+
+        // remove one from storage
+        found = tracker.remove(type, handles[2]);
+        EXPECT_EQ(&data[2], found);
+        // now try to look up the same handle and fail
+        found = tracker.get(type, handles[2]);
+        EXPECT_EQ(nullptr, found);
+
+        // add that same one back
+        handle = tracker.put(type, &data[2]);
+        ASSERT_TRUE(handle > 0);
+        found = tracker.get(type, handle);
+        EXPECT_EQ(&data[2], found);
+        // now use a stale handle again with a valid index and fail
+        found = tracker.get(type, handles[2]);
+        EXPECT_EQ(nullptr, found);
+
+        // remove them all
+        handles[2] = handle;
+        for (int i = 0; i < MAX_HANDLES; i++) {
+            // look up each handle
+            found = tracker.remove(type, handles[i]);
+            EXPECT_EQ(&data[i], found);
+        }
+    }
+}
diff --git a/media/libaaudio/tests/test_marshalling.cpp b/media/libaaudio/tests/test_marshalling.cpp
new file mode 100644
index 0000000..b1f77c0
--- /dev/null
+++ b/media/libaaudio/tests/test_marshalling.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit tests for AAudio Marshalling of RingBuffer information.
+
+#include <stdlib.h>
+#include <math.h>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <cutils/ashmem.h>
+#include <gtest/gtest.h>
+#include <sys/mman.h>
+
+#include <aaudio/AAudioDefinitions.h>
+#include <binding/AudioEndpointParcelable.h>
+
+using namespace android;
+using namespace aaudio;
+
+// Test adding one value.
+TEST(test_marshalling, aaudio_one_read_write) {
+    Parcel parcel;
+    size_t pos = parcel.dataPosition();
+    const int arbitraryValue = 235;
+    parcel.writeInt32(arbitraryValue);
+    parcel.setDataPosition(pos);
+    int32_t y;
+    parcel.readInt32(&y);
+    EXPECT_EQ(arbitraryValue, y);
+}
+
+// Test SharedMemoryParcel.
+TEST(test_marshalling, aaudio_shared_memory) {
+    SharedMemoryParcelable sharedMemoryA;
+    SharedMemoryParcelable sharedMemoryB;
+    const size_t memSizeBytes = 840;
+    int fd = ashmem_create_region("TestMarshalling", memSizeBytes);
+    ASSERT_LE(0, fd);
+    sharedMemoryA.setup(fd, memSizeBytes);
+    void *region1;
+    EXPECT_EQ(AAUDIO_OK, sharedMemoryA.resolve(0, 16, &region1)); // fits in region
+    EXPECT_NE(AAUDIO_OK, sharedMemoryA.resolve(-2, 16, &region1)); // offset is negative
+    EXPECT_NE(AAUDIO_OK, sharedMemoryA.resolve(0, memSizeBytes + 8, &region1)); // size too big
+    EXPECT_NE(AAUDIO_OK, sharedMemoryA.resolve(memSizeBytes - 8, 16, &region1)); // goes past the end
+    int32_t *buffer1 = (int32_t *)region1;
+    buffer1[0] = 98735; // arbitrary value
+
+    Parcel parcel;
+    size_t pos = parcel.dataPosition();
+    sharedMemoryA.writeToParcel(&parcel);
+
+    parcel.setDataPosition(pos);
+    sharedMemoryB.readFromParcel(&parcel);
+    EXPECT_EQ(sharedMemoryA.getSizeInBytes(), sharedMemoryB.getSizeInBytes());
+
+    // should see same value at two different addresses
+    void *region2;
+    EXPECT_EQ(AAUDIO_OK, sharedMemoryB.resolve(0, 16, &region2));
+    int32_t *buffer2 = (int32_t *)region2;
+    EXPECT_NE(buffer1, buffer2);
+    EXPECT_EQ(buffer1[0], buffer2[0]);
+}
+
+// Test SharedRegionParcel.
+TEST(test_marshalling, aaudio_shared_region) {
+    SharedMemoryParcelable sharedMemories[2];
+    SharedRegionParcelable sharedRegionA;
+    SharedRegionParcelable sharedRegionB;
+    const size_t memSizeBytes = 840;
+    int fd = ashmem_create_region("TestMarshalling", memSizeBytes);
+    ASSERT_LE(0, fd);
+    sharedMemories[0].setup(fd, memSizeBytes);
+    int32_t regionOffset1 = 32;
+    int32_t regionSize1 = 16;
+    sharedRegionA.setup(0, regionOffset1, regionSize1);
+
+    void *region1;
+    EXPECT_EQ(AAUDIO_OK, sharedRegionA.resolve(sharedMemories, &region1));
+    int32_t *buffer1 = (int32_t *)region1;
+    buffer1[0] = 336677; // arbitrary value
+
+    Parcel parcel;
+    size_t pos = parcel.dataPosition();
+    sharedRegionA.writeToParcel(&parcel);
+
+    parcel.setDataPosition(pos);
+    sharedRegionB.readFromParcel(&parcel);
+
+    // should see same value
+    void *region2;
+    EXPECT_EQ(AAUDIO_OK, sharedRegionB.resolve(sharedMemories, &region2));
+    int32_t *buffer2 = (int32_t *)region2;
+    EXPECT_EQ(buffer1[0], buffer2[0]);
+}
+
+// Test RingBufferParcelable.
+TEST(test_marshalling, aaudio_ring_buffer_parcelable) {
+    SharedMemoryParcelable sharedMemories[2];
+    RingBufferParcelable ringBufferA;
+    RingBufferParcelable ringBufferB;
+
+    const size_t bytesPerFrame = 8;
+    const size_t framesPerBurst = 32;
+    const size_t dataSizeBytes = 2048;
+    const int32_t counterSizeBytes = sizeof(int64_t);
+    const size_t memSizeBytes = dataSizeBytes + (2 * counterSizeBytes);
+
+    int fd = ashmem_create_region("TestMarshalling", memSizeBytes);
+    ASSERT_LE(0, fd);
+    sharedMemories[0].setup(fd, memSizeBytes);
+
+    int32_t sharedMemoryIndex = 0;
+    // arrange indices and data in the shared memory
+    int32_t readOffset = 0;
+    int32_t writeOffset = readOffset + counterSizeBytes;
+    int32_t dataOffset = writeOffset + counterSizeBytes;
+    ringBufferA.setupMemory(sharedMemoryIndex, dataOffset, dataSizeBytes,
+        readOffset, writeOffset, counterSizeBytes);
+    ringBufferA.setFramesPerBurst(framesPerBurst);
+    ringBufferA.setBytesPerFrame(bytesPerFrame);
+    ringBufferA.setCapacityInFrames(dataSizeBytes / bytesPerFrame);
+
+    // setup A
+    RingBufferDescriptor descriptorA;
+    EXPECT_EQ(AAUDIO_OK, ringBufferA.resolve(sharedMemories, &descriptorA));
+    descriptorA.dataAddress[0] = 95;
+    descriptorA.dataAddress[1] = 57;
+    descriptorA.readCounterAddress[0] = 17;
+    descriptorA.writeCounterAddress[0] = 39;
+
+    // write A to parcel
+    Parcel parcel;
+    size_t pos = parcel.dataPosition();
+    ringBufferA.writeToParcel(&parcel);
+
+    // read B from parcel
+    parcel.setDataPosition(pos);
+    ringBufferB.readFromParcel(&parcel);
+
+    RingBufferDescriptor descriptorB;
+    EXPECT_EQ(AAUDIO_OK, ringBufferB.resolve(sharedMemories, &descriptorB));
+
+    // A and B should match
+    EXPECT_EQ(descriptorA.dataAddress[0], descriptorB.dataAddress[0]);
+    EXPECT_EQ(descriptorA.dataAddress[1], descriptorB.dataAddress[1]);
+    EXPECT_EQ(descriptorA.readCounterAddress[0], descriptorB.readCounterAddress[0]);
+    EXPECT_EQ(descriptorA.writeCounterAddress[0], descriptorB.writeCounterAddress[0]);
+
+    EXPECT_EQ(ringBufferA.getFramesPerBurst(), ringBufferB.getFramesPerBurst());
+    EXPECT_EQ(ringBufferA.getBytesPerFrame(), ringBufferB.getBytesPerFrame());
+    EXPECT_EQ(ringBufferA.getCapacityInFrames(), ringBufferB.getCapacityInFrames());
+}