aaudio: fix output bugs and improve input performance, add loopback test

Support AAUDIO_PERFORMANCE_MODE in AudioStreamRecord.cpp
Fix race condition when closing a stream, which this test revealed.
Fix setting of negative notificationFrames for non-FAST tracks.

Convert test from old Oboe API to AAudio.
Add command line options to the test.
Add systrace calls.

Bug: 34093052
Bug: 38313432
Bug: 38178592
Test: loopback.cpp
Change-Id: Ib6d2995cdd3ed432937fde2f26c5394013f0d6e0
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/media/libaaudio/examples/loopback/Android.mk b/media/libaaudio/examples/loopback/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/media/libaaudio/examples/loopback/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/loopback/jni/Android.mk b/media/libaaudio/examples/loopback/jni/Android.mk
new file mode 100644
index 0000000..dc933e3
--- /dev/null
+++ b/media/libaaudio/examples/loopback/jni/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/libaaudio/include
+
+# NDK recommends using this kind of relative path instead of an absolute path.
+LOCAL_SRC_FILES:= ../src/loopback.cpp
+LOCAL_SHARED_LIBRARIES := libaaudio
+LOCAL_MODULE := aaudio_loopback
+include $(BUILD_EXECUTABLE)
diff --git a/media/libaaudio/examples/loopback/jni/Application.mk b/media/libaaudio/examples/loopback/jni/Application.mk
new file mode 100644
index 0000000..ba44f37
--- /dev/null
+++ b/media/libaaudio/examples/loopback/jni/Application.mk
@@ -0,0 +1 @@
+APP_CPPFLAGS += -std=c++11
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
new file mode 100644
index 0000000..bad21f7
--- /dev/null
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -0,0 +1,528 @@
+/*
+ * 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 an impulse and then record it.
+// Measure the round trip latency.
+
+#include <assert.h>
+#include <cctype>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <aaudio/AAudio.h>
+
+#define INPUT_PEAK_THRESHOLD    0.1f
+#define SILENCE_FRAMES          10000
+#define SAMPLE_RATE             48000
+#define NUM_SECONDS             7
+#define FILENAME                "/data/oboe_input.raw"
+
+#define NANOS_PER_MICROSECOND ((int64_t)1000)
+#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
+#define MILLIS_PER_SECOND     1000
+#define NANOS_PER_SECOND      (NANOS_PER_MILLISECOND * MILLIS_PER_SECOND)
+
+class AudioRecorder
+{
+public:
+    AudioRecorder() {
+    }
+    ~AudioRecorder() {
+        delete[] mData;
+    }
+
+    void allocate(int maxFrames) {
+        delete[] mData;
+        mData = new float[maxFrames];
+        mMaxFrames = maxFrames;
+    }
+
+    void record(int16_t *inputData, int inputChannelCount, int numFrames) {
+        // stop at end of buffer
+        if ((mFrameCounter + numFrames) > mMaxFrames) {
+            numFrames = mMaxFrames - mFrameCounter;
+        }
+        for (int i = 0; i < numFrames; i++) {
+            mData[mFrameCounter++] = inputData[i * inputChannelCount] * (1.0f / 32768);
+        }
+    }
+
+    void record(float *inputData, int inputChannelCount, int numFrames) {
+        // stop at end of buffer
+        if ((mFrameCounter + numFrames) > mMaxFrames) {
+            numFrames = mMaxFrames - mFrameCounter;
+        }
+        for (int i = 0; i < numFrames; i++) {
+            mData[mFrameCounter++] = inputData[i * inputChannelCount];
+        }
+    }
+
+    int save(const char *fileName) {
+        FILE *fid = fopen(fileName, "wb");
+        if (fid == NULL) {
+            return errno;
+        }
+        int written = fwrite(mData, sizeof(float), mFrameCounter, fid);
+        fclose(fid);
+        return written;
+    }
+
+private:
+    float *mData = NULL;
+    int32_t mFrameCounter = 0;
+    int32_t mMaxFrames = 0;
+};
+
+// ====================================================================================
+// ========================= Loopback Processor =======================================
+// ====================================================================================
+class LoopbackProcessor {
+public:
+
+    // Calculate mean and standard deviation.
+    double calculateAverageLatency(double *deviation) {
+        if (mLatencyCount <= 0) {
+            return -1.0;
+        }
+        double sum = 0.0;
+        for (int i = 0; i < mLatencyCount; i++) {
+            sum += mLatencyArray[i];
+        }
+        double average = sum /  mLatencyCount;
+        sum = 0.0;
+        for (int i = 0; i < mLatencyCount; i++) {
+            double error = average - mLatencyArray[i];
+            sum += error * error; // squared
+        }
+        *deviation = sqrt(sum / mLatencyCount);
+        return average;
+    }
+
+    float getMaxAmplitude() const { return mMaxAmplitude; }
+    int   getMeasurementCount() const { return mLatencyCount; }
+    float getAverageAmplitude() const { return mAmplitudeTotal / mAmplitudeCount; }
+
+    // TODO Convert this to a feedback circuit and then use auto-correlation to measure the period.
+    void process(float *inputData, int inputChannelCount,
+            float *outputData, int outputChannelCount,
+            int numFrames) {
+        (void) outputChannelCount;
+
+        // Measure peak and average amplitude.
+        for (int i = 0; i < numFrames; i++) {
+            float sample = inputData[i * inputChannelCount];
+            if (sample > mMaxAmplitude) {
+                mMaxAmplitude = sample;
+            }
+            if (sample < 0) {
+                sample = 0 - sample;
+            }
+            mAmplitudeTotal += sample;
+            mAmplitudeCount++;
+        }
+
+        // Clear output.
+        memset(outputData, 0, numFrames * outputChannelCount * sizeof(float));
+
+        // Wait a while between hearing the pulse and starting a new one.
+        if (mState == STATE_SILENT) {
+            mCounter += numFrames;
+            if (mCounter > SILENCE_FRAMES) {
+                //printf("LoopbackProcessor send impulse, burst #%d\n", mBurstCounter);
+                // copy impulse
+                for (float sample : mImpulse) {
+                    *outputData = sample;
+                    outputData += outputChannelCount;
+                }
+                mState = STATE_LISTENING;
+                mCounter = 0;
+            }
+        }
+        // Start listening as soon as we send the impulse.
+        if (mState ==  STATE_LISTENING) {
+            for (int i = 0; i < numFrames; i++) {
+                float sample = inputData[i * inputChannelCount];
+                if (sample >= INPUT_PEAK_THRESHOLD) {
+                    mLatencyArray[mLatencyCount++] = mCounter;
+                    if (mLatencyCount >= MAX_LATENCY_VALUES) {
+                        mState = STATE_DONE;
+                    } else {
+                        mState = STATE_SILENT;
+                    }
+                    mCounter = 0;
+                    break;
+                } else {
+                    mCounter++;
+                }
+            }
+        }
+    }
+
+    void echo(float *inputData, int inputChannelCount,
+            float *outputData, int outputChannelCount,
+            int numFrames) {
+        int channelsValid = (inputChannelCount < outputChannelCount)
+            ? inputChannelCount : outputChannelCount;
+        for (int i = 0; i < numFrames; i++) {
+            int ic;
+            for (ic = 0; ic < channelsValid; ic++) {
+                outputData[ic] = inputData[ic];
+            }
+            for (ic = 0; ic < outputChannelCount; ic++) {
+                outputData[ic] = 0;
+            }
+            inputData += inputChannelCount;
+            outputData += outputChannelCount;
+        }
+    }
+private:
+    enum {
+        STATE_SILENT,
+        STATE_LISTENING,
+        STATE_DONE
+    };
+
+    enum {
+        MAX_LATENCY_VALUES = 64
+    };
+
+    int     mState = STATE_SILENT;
+    int32_t mCounter = 0;
+    int32_t mLatencyArray[MAX_LATENCY_VALUES];
+    int32_t mLatencyCount = 0;
+    float   mMaxAmplitude = 0;
+    float   mAmplitudeTotal = 0;
+    int32_t mAmplitudeCount = 0;
+    static const float mImpulse[5];
+};
+
+const float LoopbackProcessor::mImpulse[5] = {0.5f, 0.9f, 0.0f, -0.9f, -0.5f};
+
+// TODO make this a class that manages its own buffer allocation
+struct LoopbackData {
+    AAudioStream     *inputStream = nullptr;
+    int32_t           inputFramesMaximum = 0;
+    int16_t          *inputData = nullptr;
+    float            *conversionBuffer = nullptr;
+    int32_t           actualInputChannelCount = 0;
+    int32_t           actualOutputChannelCount = 0;
+    int32_t           inputBuffersToDiscard = 10;
+
+    aaudio_result_t   inputError;
+    LoopbackProcessor loopbackProcessor;
+    AudioRecorder     audioRecorder;
+};
+
+static void convertPcm16ToFloat(const int16_t *source,
+                                float *destination,
+                                int32_t numSamples) {
+    const float scaler = 1.0f / 32768.0f;
+    for (int i = 0; i < numSamples; i++) {
+        destination[i] = source[i] * scaler;
+    }
+}
+
+// ====================================================================================
+// ========================= CALLBACK =================================================
+// ====================================================================================
+// Callback function that fills the audio output buffer.
+static aaudio_data_callback_result_t MyDataCallbackProc(
+        AAudioStream *outputStream,
+        void *userData,
+        void *audioData,
+        int32_t numFrames
+) {
+    (void) outputStream;
+    LoopbackData *myData = (LoopbackData *) userData;
+    float  *outputData = (float  *) audioData;
+
+    // Read audio data from the input stream.
+    int32_t framesRead;
+
+    if (numFrames > myData->inputFramesMaximum) {
+        myData->inputError = AAUDIO_ERROR_OUT_OF_RANGE;
+        return AAUDIO_CALLBACK_RESULT_STOP;
+    }
+
+    if (myData->inputBuffersToDiscard > 0) {
+        // Drain the input.
+        do {
+            framesRead = AAudioStream_read(myData->inputStream, myData->inputData,
+                                       numFrames, 0);
+            if (framesRead < 0) {
+                myData->inputError = framesRead;
+            } else if (framesRead > 0) {
+                myData->inputBuffersToDiscard--;
+            }
+        } while(framesRead > 0);
+    } else {
+        framesRead = AAudioStream_read(myData->inputStream, myData->inputData,
+                                       numFrames, 0);
+        if (framesRead < 0) {
+            myData->inputError = framesRead;
+        } else if (framesRead > 0) {
+            // Process valid input data.
+            myData->audioRecorder.record(myData->inputData,
+                                         myData->actualInputChannelCount,
+                                         framesRead);
+
+            int32_t numSamples = framesRead * myData->actualInputChannelCount;
+            convertPcm16ToFloat(myData->inputData, myData->conversionBuffer, numSamples);
+
+            myData->loopbackProcessor.process(myData->conversionBuffer,
+                                              myData->actualInputChannelCount,
+                                              outputData,
+                                              myData->actualOutputChannelCount,
+                                              framesRead);
+        }
+    }
+
+    return AAUDIO_CALLBACK_RESULT_CONTINUE;
+}
+
+static void usage() {
+    printf("loopback: -b{burstsPerBuffer} -p{outputPerfMode} -P{inputPerfMode}\n");
+    printf("          -b{burstsPerBuffer} for example 2 for double buffered\n");
+    printf("          -p{outputPerfMode}  set output AAUDIO_PERFORMANCE_MODE*\n");
+    printf("          -P{inputPerfMode}   set input AAUDIO_PERFORMANCE_MODE*\n");
+    printf("              n for _NONE\n");
+    printf("              l for _LATENCY\n");
+    printf("              p for _POWER_SAVING;\n");
+    printf("For example:  loopback -b2 -pl -Pn\n");
+}
+
+static aaudio_performance_mode_t parsePerformanceMode(char c) {
+    aaudio_performance_mode_t mode = AAUDIO_PERFORMANCE_MODE_NONE;
+    c = tolower(c);
+    switch (c) {
+        case 'n':
+            mode = AAUDIO_PERFORMANCE_MODE_NONE;
+            break;
+        case 'l':
+            mode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
+            break;
+        case 'p':
+            mode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
+            break;
+        default:
+            printf("ERROR invalue performance mode %c\n", c);
+            break;
+    }
+    return mode;
+}
+
+// ====================================================================================
+// TODO break up this large main() function into smaller functions
+int main(int argc, const char **argv)
+{
+    aaudio_result_t result = AAUDIO_OK;
+    LoopbackData loopbackData;
+    AAudioStream *outputStream = nullptr;
+
+    const int requestedInputChannelCount = 1;
+    const int requestedOutputChannelCount = AAUDIO_UNSPECIFIED;
+    const int requestedSampleRate = SAMPLE_RATE;
+    int actualSampleRate = 0;
+    const aaudio_audio_format_t requestedInputFormat = AAUDIO_FORMAT_PCM_I16;
+    const aaudio_audio_format_t requestedOutputFormat = AAUDIO_FORMAT_PCM_FLOAT;
+    aaudio_audio_format_t actualInputFormat;
+    aaudio_audio_format_t actualOutputFormat;
+
+    //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
+    const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED;
+    aaudio_sharing_mode_t       actualSharingMode;
+
+    AAudioStreamBuilder  *builder = nullptr;
+    aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
+    int32_t framesPerBurst = 0;
+    float *outputData = NULL;
+    double deviation;
+    double latency;
+    aaudio_performance_mode_t outputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
+    aaudio_performance_mode_t inputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
+
+    int32_t burstsPerBuffer = 1; // single buffered
+
+    for (int i = 1; i < argc; i++) {
+        const char *arg = argv[i];
+        if (arg[0] == '-') {
+            char option = arg[1];
+            switch (option) {
+                case 'b':
+                    burstsPerBuffer = atoi(&arg[2]);
+                    break;
+                case 'p':
+                    outputPerformanceLevel = parsePerformanceMode(arg[2]);
+                    break;
+                case 'P':
+                    inputPerformanceLevel = parsePerformanceMode(arg[2]);
+                    break;
+                default:
+                    usage();
+                    break;
+            }
+        } else {
+            break;
+        }
+    }
+
+    loopbackData.audioRecorder.allocate(NUM_SECONDS * SAMPLE_RATE);
+
+    // Make printf print immediately so that debug info is not stuck
+    // in a buffer if we hang or crash.
+    setvbuf(stdout, NULL, _IONBF, (size_t) 0);
+
+    printf("%s - Audio loopback using AAudio\n", argv[0]);
+
+    // Use an AAudioStreamBuilder to contain requested parameters.
+    result = AAudio_createStreamBuilder(&builder);
+    if (result < 0) {
+        goto finish;
+    }
+
+    // Request common stream properties.
+    AAudioStreamBuilder_setSampleRate(builder, requestedSampleRate);
+    AAudioStreamBuilder_setFormat(builder, requestedInputFormat);
+    AAudioStreamBuilder_setSharingMode(builder, requestedSharingMode);
+
+    // Open the input stream.
+    AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT);
+    AAudioStreamBuilder_setPerformanceMode(builder, inputPerformanceLevel);
+    AAudioStreamBuilder_setChannelCount(builder, requestedInputChannelCount);
+
+    result = AAudioStreamBuilder_openStream(builder, &loopbackData.inputStream);
+    printf("AAudioStreamBuilder_openStream(input) returned %d = %s\n",
+           result, AAudio_convertResultToText(result));
+    if (result < 0) {
+        goto finish;
+    }
+
+    // Create an output stream using the Builder.
+    AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
+    AAudioStreamBuilder_setFormat(builder, requestedOutputFormat);
+    AAudioStreamBuilder_setPerformanceMode(builder, outputPerformanceLevel);
+    AAudioStreamBuilder_setChannelCount(builder, requestedOutputChannelCount);
+    AAudioStreamBuilder_setDataCallback(builder, MyDataCallbackProc, &loopbackData);
+
+    result = AAudioStreamBuilder_openStream(builder, &outputStream);
+    printf("AAudioStreamBuilder_openStream(output) returned %d = %s\n",
+           result, AAudio_convertResultToText(result));
+    if (result != AAUDIO_OK) {
+        goto finish;
+    }
+
+    printf("Stream INPUT ---------------------\n");
+    loopbackData.actualInputChannelCount = AAudioStream_getChannelCount(loopbackData.inputStream);
+    printf("    channelCount: requested = %d, actual = %d\n", requestedInputChannelCount,
+           loopbackData.actualInputChannelCount);
+    printf("    framesPerBurst = %d\n", AAudioStream_getFramesPerBurst(loopbackData.inputStream));
+
+    actualInputFormat = AAudioStream_getFormat(loopbackData.inputStream);
+    printf("    dataFormat: requested = %d, actual = %d\n", requestedInputFormat, actualInputFormat);
+    assert(actualInputFormat == AAUDIO_FORMAT_PCM_I16);
+
+    printf("Stream OUTPUT ---------------------\n");
+    // Check to see what kind of stream we actually got.
+    actualSampleRate = AAudioStream_getSampleRate(outputStream);
+    printf("    sampleRate: requested = %d, actual = %d\n", requestedSampleRate, actualSampleRate);
+
+    loopbackData.actualOutputChannelCount = AAudioStream_getChannelCount(outputStream);
+    printf("    channelCount: requested = %d, actual = %d\n", requestedOutputChannelCount,
+           loopbackData.actualOutputChannelCount);
+
+    actualSharingMode = AAudioStream_getSharingMode(outputStream);
+    printf("    sharingMode: requested = %d, actual = %d\n", requestedSharingMode, actualSharingMode);
+
+    // This is the number of frames that are read in one chunk by a DMA controller
+    // or a DSP or a mixer.
+    framesPerBurst = AAudioStream_getFramesPerBurst(outputStream);
+    printf("    framesPerBurst = %d\n", framesPerBurst);
+
+    printf("    bufferCapacity = %d\n", AAudioStream_getBufferCapacityInFrames(outputStream));
+
+    actualOutputFormat = AAudioStream_getFormat(outputStream);
+    printf("    dataFormat: requested = %d, actual = %d\n", requestedOutputFormat, actualOutputFormat);
+    assert(actualOutputFormat == AAUDIO_FORMAT_PCM_FLOAT);
+
+    // Allocate a buffer for the audio data.
+    loopbackData.inputFramesMaximum = 32 * framesPerBurst;
+
+    loopbackData.inputData = new int16_t[loopbackData.inputFramesMaximum * loopbackData.actualInputChannelCount];
+    loopbackData.conversionBuffer = new float[loopbackData.inputFramesMaximum *
+                                              loopbackData.actualInputChannelCount];
+
+    result = AAudioStream_setBufferSizeInFrames(outputStream, burstsPerBuffer * framesPerBurst);
+    if (result < 0) { // may be positive buffer size
+        fprintf(stderr, "ERROR - AAudioStream_setBufferSize() returned %d\n", result);
+        goto finish;
+    }
+    printf("AAudioStream_setBufferSize() actual = %d\n",result);
+
+    // Start output first so input stream runs low.
+    result = AAudioStream_requestStart(outputStream);
+    if (result != AAUDIO_OK) {
+        fprintf(stderr, "ERROR - AAudioStream_requestStart(output) returned %d = %s\n",
+                result, AAudio_convertResultToText(result));
+        goto finish;
+    }
+
+    result = AAudioStream_requestStart(loopbackData.inputStream);
+    if (result != AAUDIO_OK) {
+        fprintf(stderr, "ERROR - AAudioStream_requestStart(input) returned %d = %s\n",
+                result, AAudio_convertResultToText(result));
+        goto finish;
+    }
+
+    printf("------- sleep while the callback runs --------------\n");
+    fflush(stdout);
+    sleep(NUM_SECONDS);
+
+
+    printf("input error = %d = %s\n",
+                loopbackData.inputError, AAudio_convertResultToText(loopbackData.inputError));
+
+    printf("AAudioStream_getXRunCount %d\n", AAudioStream_getXRunCount(outputStream));
+    printf("framesRead    = %d\n", (int) AAudioStream_getFramesRead(outputStream));
+    printf("framesWritten = %d\n", (int) AAudioStream_getFramesWritten(outputStream));
+
+    latency = loopbackData.loopbackProcessor.calculateAverageLatency(&deviation);
+    printf("measured peak    = %8.5f\n", loopbackData.loopbackProcessor.getMaxAmplitude());
+    printf("threshold        = %8.5f\n", INPUT_PEAK_THRESHOLD);
+    printf("measured average = %8.5f\n", loopbackData.loopbackProcessor.getAverageAmplitude());
+    printf("# latency measurements = %d\n", loopbackData.loopbackProcessor.getMeasurementCount());
+    printf("measured latency = %8.2f +/- %4.5f frames\n", latency, deviation);
+    printf("measured latency = %8.2f msec  <===== !!\n", (1000.0 * latency / actualSampleRate));
+
+    {
+        int written = loopbackData.audioRecorder.save(FILENAME);
+        printf("wrote %d samples to %s\n", written, FILENAME);
+    }
+
+finish:
+    AAudioStream_close(outputStream);
+    AAudioStream_close(loopbackData.inputStream);
+    delete[] loopbackData.conversionBuffer;
+    delete[] loopbackData.inputData;
+    delete[] outputData;
+    AAudioStreamBuilder_delete(builder);
+
+    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/jni/Application.mk b/media/libaaudio/examples/write_sine/jni/Application.mk
index e74475c..ba44f37 100644
--- a/media/libaaudio/examples/write_sine/jni/Application.mk
+++ b/media/libaaudio/examples/write_sine/jni/Application.mk
@@ -1,3 +1 @@
-# 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/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index 1a66f35..5f35c5d 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -85,11 +85,11 @@
         AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode);
         AAudioStreamBuilder_setDataCallback(mBuilder, dataProc, userContext);
         AAudioStreamBuilder_setFormat(mBuilder, AAUDIO_FORMAT_PCM_FLOAT);
- //       AAudioStreamBuilder_setFramesPerDataCallback(mBuilder, CALLBACK_SIZE_FRAMES);
-        AAudioStreamBuilder_setBufferCapacityInFrames(mBuilder, 48 * 8);
+        // AAudioStreamBuilder_setFramesPerDataCallback(mBuilder, CALLBACK_SIZE_FRAMES);
+        // AAudioStreamBuilder_setBufferCapacityInFrames(mBuilder, 48 * 8);
 
-        //AAudioStreamBuilder_setPerformanceMode(mBuilder, AAUDIO_PERFORMANCE_MODE_NONE);
-        AAudioStreamBuilder_setPerformanceMode(mBuilder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+        AAudioStreamBuilder_setPerformanceMode(mBuilder, AAUDIO_PERFORMANCE_MODE_NONE);
+        //AAudioStreamBuilder_setPerformanceMode(mBuilder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
         //AAudioStreamBuilder_setPerformanceMode(mBuilder, AAUDIO_PERFORMANCE_MODE_POWER_SAVING);
 
         // Open an AAudioStream using the Builder.
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index 027d66d..e6751c49 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -182,6 +182,15 @@
     mDownDataQueue->getEmptyRoomAvailable(wrappingBuffer);
 }
 
+int32_t AudioEndpoint::getEmptyFramesAvailable() {
+    return mDownDataQueue->getFifoControllerBase()->getEmptyFramesAvailable();
+}
+
+int32_t AudioEndpoint::getFullFramesAvailable()
+{
+    return mDownDataQueue->getFifoControllerBase()->getFullFramesAvailable();
+}
+
 void AudioEndpoint::advanceWriteIndex(int32_t deltaFrames) {
     mDownDataQueue->getFifoControllerBase()->advanceWriteIndex(deltaFrames);
 }
@@ -227,7 +236,3 @@
     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
index 46a3fc5..3a2099f 100644
--- a/media/libaaudio/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -56,6 +56,9 @@
 
     void getEmptyRoomAvailable(android::WrappingBuffer *wrappingBuffer);
 
+    int32_t getEmptyFramesAvailable();
+    int32_t getFullFramesAvailable();
+
     void advanceWriteIndex(int32_t deltaFrames);
 
     /**
@@ -81,8 +84,6 @@
 
     int32_t getBufferCapacityInFrames() const;
 
-    int32_t getFullFramesAvailable();
-
 private:
     android::FifoBuffer    *mUpCommandQueue;
     android::FifoBuffer    *mDownDataQueue;
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index eee860e..143d4b7 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -18,6 +18,8 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
 #include <stdint.h>
 #include <assert.h>
 
@@ -25,6 +27,7 @@
 
 #include <aaudio/AAudio.h>
 #include <utils/String16.h>
+#include <utils/Trace.h>
 
 #include "AudioClock.h"
 #include "AudioEndpointParcelable.h"
@@ -188,11 +191,25 @@
     ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X",
              mServiceStreamHandle);
     if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
+        // Don't close a stream while it is running.
+        aaudio_stream_state_t currentState = getState();
+        if (isPlaying()) {
+            requestStop();
+            aaudio_stream_state_t nextState;
+            int64_t timeoutNanoseconds = MIN_TIMEOUT_NANOS;
+            aaudio_result_t result = waitForStateChange(currentState, &nextState,
+                                                       timeoutNanoseconds);
+            if (result != AAUDIO_OK) {
+                ALOGE("AudioStreamInternal::close() waitForStateChange() returned %d %s",
+                result, AAudio_convertResultToText(result));
+            }
+        }
         aaudio_handle_t serviceStreamHandle = mServiceStreamHandle;
         mServiceStreamHandle = AAUDIO_HANDLE_INVALID;
 
         mServiceInterface.closeStream(serviceStreamHandle);
         delete[] mCallbackBuffer;
+        mCallbackBuffer = nullptr;
         return mEndPointParcelable.close();
     } else {
         return AAUDIO_ERROR_INVALID_HANDLE;
@@ -524,6 +541,8 @@
 aaudio_result_t AudioStreamInternal::write(const void *buffer, int32_t numFrames,
                                          int64_t timeoutNanoseconds)
 {
+    const char * traceName = (mInService) ? "aaWrtS" : "aaWrtC";
+    ATRACE_BEGIN(traceName);
     aaudio_result_t result = AAUDIO_OK;
     int32_t loopCount = 0;
     uint8_t* source = (uint8_t*)buffer;
@@ -531,6 +550,12 @@
     int64_t deadlineNanos = currentTimeNanos + timeoutNanoseconds;
     int32_t framesLeft = numFrames;
 
+    int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable();
+    if (ATRACE_ENABLED()) {
+        const char * traceName = (mInService) ? "aaFullS" : "aaFullC";
+        ATRACE_INT(traceName, fullFrames);
+    }
+
     // 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.
@@ -568,6 +593,7 @@
 
     // return error or framesWritten
     (void) loopCount;
+    ATRACE_END();
     return (result < 0) ? result : numFrames - framesLeft;
 }
 
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index eb6bfd5..a74a030 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -60,15 +60,29 @@
                               ? 2 : getSamplesPerFrame();
     audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(samplesPerFrame);
 
-    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());
 
+    audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
+    switch(getPerformanceMode()) {
+        case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
+            flags = (audio_input_flags_t) (AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW);
+            break;
+
+        case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
+        case AAUDIO_PERFORMANCE_MODE_NONE:
+        default:
+            // No flags.
+            break;
+    }
+
+    uint32_t notificationFrames = 0;
+
     // Setup the callback if there is one.
     AudioRecord::callback_t callback = nullptr;
     void *callbackData = nullptr;
@@ -77,11 +91,12 @@
         streamTransferType = AudioRecord::transfer_type::TRANSFER_CALLBACK;
         callback = getLegacyCallback();
         callbackData = this;
+        notificationFrames = builder.getFramesPerDataCallback();
     }
     mCallbackBufferSize = builder.getFramesPerDataCallback();
 
     mAudioRecord = new AudioRecord(
-            AUDIO_SOURCE_DEFAULT,
+            AUDIO_SOURCE_VOICE_RECOGNITION,
             getSampleRate(),
             format,
             channelMask,
@@ -89,7 +104,7 @@
             frameCount,
             callback,
             callbackData,
-            0,    //    uint32_t notificationFrames = 0,
+            notificationFrames,
             AUDIO_SESSION_ALLOCATE,
             streamTransferType,
             flags
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
index f4a78e1..0af6457 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.h
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -29,7 +29,7 @@
 namespace aaudio {
 
 /**
- * Internal stream that uses the legacy AudioTrack path.
+ * Internal stream that uses the legacy AudioRecord path.
  */
 class AudioStreamRecord : public AudioStreamLegacy {
 public:
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index a7c7673..8c3732e 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -105,12 +105,14 @@
         callback = getLegacyCallback();
         callbackData = this;
 
-        notificationFrames = builder.getFramesPerDataCallback();
         // If the total buffer size is unspecified then base the size on the burst size.
-        if (frameCount == AAUDIO_UNSPECIFIED) {
+        if (frameCount == 0
+                && ((flags & AUDIO_OUTPUT_FLAG_FAST) != 0)) {
             // Take advantage of a special trick that allows us to create a buffer
             // that is some multiple of the burst size.
             notificationFrames = 0 - DEFAULT_BURSTS_PER_BUFFER_CAPACITY;
+        } else {
+            notificationFrames = builder.getFramesPerDataCallback();
         }
     }
     mCallbackBufferSize = builder.getFramesPerDataCallback();