aaudio: command line argument parser

Generic parser that is used in multiple examples.

Added -n{numberOfBursts} for buffer size.

This is being used to test the MMAP features.

Bug: 63002656
Test: this is a test
Change-Id: Idf7560f9bb3ed7834f6c4686dd6009f27f04220e
Merged-In: Idf7560f9bb3ed7834f6c4686dd6009f27f04220e
diff --git a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
index f1593fe..910b10c 100644
--- a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
+++ b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
@@ -26,30 +26,18 @@
 #include "AAudioExampleUtils.h"
 #include "AAudioSimpleRecorder.h"
 
-#define SAMPLE_RATE        48000
-
-#define NUM_SECONDS        10
-
+// TODO support FLOAT
+#define REQUIRED_FORMAT  AAUDIO_FORMAT_PCM_I16
 #define MIN_FRAMES_TO_READ 48  /* arbitrary, 1 msec at 48000 Hz */
 
-int main(int argc, char **argv)
+int main(int argc, const char **argv)
 {
-    (void)argc; // unused
-
+    AAudioArgsParser   argParser;
     aaudio_result_t result;
     AAudioSimpleRecorder recorder;
     int actualSamplesPerFrame;
     int actualSampleRate;
-    const aaudio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM_I16;
-    aaudio_format_t actualDataFormat;
-
-    const int requestedInputChannelCount = 2; // Can affect whether we get a FAST path.
-
-    //aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
-    const aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
-    //aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
-    //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED;
-    const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
+    aaudio_format_t       actualDataFormat;
     aaudio_sharing_mode_t actualSharingMode;
 
     AAudioStream *aaudioStream = nullptr;
@@ -70,18 +58,18 @@
 
     printf("%s - Monitor input level using AAudio\n", argv[0]);
 
-    AAudio_setMMapPolicy(AAUDIO_POLICY_ALWAYS);
+    argParser.setFormat(REQUIRED_FORMAT);
+    if (argParser.parseArgs(argc, argv)) {
+        return EXIT_FAILURE;
+    }
 
-    recorder.setPerformanceMode(requestedPerformanceMode);
-    recorder.setSharingMode(requestedSharingMode);
-
-    result = recorder.open(requestedInputChannelCount, 48000, requestedDataFormat,
-                           nullptr, nullptr, nullptr);
+    result = recorder.open(argParser);
     if (result != AAUDIO_OK) {
         fprintf(stderr, "ERROR -  recorder.open() returned %d\n", result);
         goto finish;
     }
     aaudioStream = recorder.getStream();
+    argParser.compareWithStream(aaudioStream);
 
     deviceId = AAudioStream_getDeviceId(aaudioStream);
     printf("deviceId = %d\n", deviceId);
@@ -91,11 +79,6 @@
     actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
     printf("SamplesPerFrame = %d\n", actualSampleRate);
 
-    actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
-    printf("SharingMode: requested = %s, actual = %s\n",
-            getSharingModeText(requestedSharingMode),
-            getSharingModeText(actualSharingMode));
-
     // This is the number of frames that are written in one chunk by a DMA controller
     // or a DSP.
     framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
@@ -110,14 +93,12 @@
     printf("DataFormat: framesPerRead  = %d\n",framesPerRead);
 
     actualDataFormat = AAudioStream_getFormat(aaudioStream);
-    printf("DataFormat: requested      = %d, actual = %d\n", requestedDataFormat, actualDataFormat);
+    printf("DataFormat: requested      = %d, actual = %d\n",
+           REQUIRED_FORMAT, actualDataFormat);
     // TODO handle other data formats
-    assert(actualDataFormat == AAUDIO_FORMAT_PCM_I16);
+    assert(actualDataFormat == REQUIRED_FORMAT);
 
-    printf("PerformanceMode: requested = %d, actual = %d\n", requestedPerformanceMode,
-           AAudioStream_getPerformanceMode(aaudioStream));
-
-    // Allocate a buffer for the audio data.
+    // Allocate a buffer for the PCM_16 audio data.
     data = new(std::nothrow) int16_t[framesPerRead * actualSamplesPerFrame];
     if (data == nullptr) {
         fprintf(stderr, "ERROR - could not allocate data buffer\n");
@@ -136,7 +117,7 @@
     printf("after start, state = %s\n", AAudio_convertStreamStateToText(state));
 
     // Record for a while.
-    framesToRecord = actualSampleRate * NUM_SECONDS;
+    framesToRecord = actualSampleRate * argParser.getDurationSeconds();
     framesLeft = framesToRecord;
     while (framesLeft > 0) {
         // Read audio data from the stream.
@@ -176,6 +157,8 @@
         goto finish;
     }
 
+    argParser.compareWithStream(aaudioStream);
+
 finish:
     recorder.close();
     delete[] data;
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 9f06ee7..45a3beb 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -20,7 +20,6 @@
 #include <assert.h>
 #include <cctype>
 #include <math.h>
-#include <stdlib.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
new file mode 100644
index 0000000..54217a5
--- /dev/null
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAUDIO_EXAMPLE_ARGS_PARSER_H
+#define AAUDIO_EXAMPLE_ARGS_PARSER_H
+
+#include <cctype>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <aaudio/AAudio.h>
+#include <aaudio/AAudioTesting.h>
+#include <AAudioExampleUtils.h>
+
+// TODO use this as a base class within AAudio
+class AAudioParameters {
+public:
+
+    /**
+     * This is also known as samplesPerFrame.
+     */
+    int32_t getChannelCount() const {
+        return mChannelCount;
+    }
+
+    void setChannelCount(int32_t channelCount) {
+        mChannelCount = channelCount;
+    }
+
+    int32_t getSampleRate() const {
+        return mSampleRate;
+    }
+
+    void setSampleRate(int32_t sampleRate) {
+        mSampleRate = sampleRate;
+    }
+
+    aaudio_format_t getFormat() const {
+        return mFormat;
+    }
+
+    void setFormat(aaudio_format_t format) {
+        mFormat = format;
+    }
+
+    aaudio_sharing_mode_t getSharingMode() const {
+        return mSharingMode;
+    }
+
+    void setSharingMode(aaudio_sharing_mode_t sharingMode) {
+        mSharingMode = sharingMode;
+    }
+
+    int32_t getBufferCapacity() const {
+        return mBufferCapacity;
+    }
+
+    void setBufferCapacity(int32_t frames) {
+        mBufferCapacity = frames;
+    }
+
+    int32_t getPerformanceMode() const {
+        return mPerformanceMode;
+    }
+
+    void setPerformanceMode(aaudio_performance_mode_t performanceMode) {
+        mPerformanceMode = performanceMode;
+    }
+
+    int32_t getDeviceId() const {
+        return mDeviceId;
+    }
+
+    void setDeviceId(int32_t deviceId) {
+        mDeviceId = deviceId;
+    }
+
+    int32_t getNumberOfBursts() const {
+        return mNumberOfBursts;
+    }
+
+    void setNumberOfBursts(int32_t numBursts) {
+        mNumberOfBursts = numBursts;
+    }
+
+    /**
+     * Apply these parameters to a stream builder.
+     * @param builder
+     */
+    void applyParameters(AAudioStreamBuilder *builder) const {
+        AAudioStreamBuilder_setChannelCount(builder, mChannelCount);
+        AAudioStreamBuilder_setFormat(builder, mFormat);
+        AAudioStreamBuilder_setSampleRate(builder, mSampleRate);
+        AAudioStreamBuilder_setBufferCapacityInFrames(builder, mBufferCapacity);
+        AAudioStreamBuilder_setDeviceId(builder, mDeviceId);
+        AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
+        AAudioStreamBuilder_setPerformanceMode(builder, mPerformanceMode);
+    }
+
+private:
+    int32_t                    mChannelCount    = AAUDIO_UNSPECIFIED;
+    aaudio_format_t            mFormat          = AAUDIO_FORMAT_UNSPECIFIED;
+    int32_t                    mSampleRate      = AAUDIO_UNSPECIFIED;
+
+    int32_t                    mBufferCapacity  = AAUDIO_UNSPECIFIED;
+    int32_t                    mDeviceId        = AAUDIO_UNSPECIFIED;
+    aaudio_sharing_mode_t      mSharingMode     = AAUDIO_SHARING_MODE_SHARED;
+    aaudio_performance_mode_t  mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
+
+    int32_t                    mNumberOfBursts = AAUDIO_UNSPECIFIED;
+};
+
+class AAudioArgsParser : public AAudioParameters {
+public:
+    AAudioArgsParser() = default;
+    ~AAudioArgsParser() = default;
+
+    enum {
+        DEFAULT_DURATION_SECONDS = 5
+    };
+
+    /**
+     * @param arg
+     * @return true if the argument was not handled
+     */
+    bool parseArg(const char *arg) {
+        bool unrecognized = false;
+        if (arg[0] == '-') {
+            char option = arg[1];
+            switch (option) {
+                case 'b':
+                    setBufferCapacity(atoi(&arg[2]));
+                    break;
+                case 'c':
+                    setChannelCount(atoi(&arg[2]));
+                    break;
+                case 'd':
+                    mDurationSeconds = atoi(&arg[2]);
+                    break;
+                case 'm':
+                    AAudio_setMMapPolicy(AAUDIO_POLICY_AUTO);
+                    break;
+                case 'n':
+                    setNumberOfBursts(atoi(&arg[2]));
+                    break;
+                case 'p':
+                    setPerformanceMode(parsePerformanceMode(arg[2]));
+                    break;
+                case 'r':
+                    setSampleRate(atoi(&arg[2]));
+                    break;
+                case 'x':
+                    setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
+                    break;
+                default:
+                    unrecognized = true;
+                    break;
+            }
+        }
+        return unrecognized;
+    }
+
+    /**
+     *
+     * @param argc
+     * @param argv
+     * @return true if an unrecognized argument was passed
+     */
+    bool parseArgs(int argc, const char **argv) {
+        for (int i = 1; i < argc; i++) {
+            const char *arg = argv[i];
+            if (parseArg(arg)) {
+                usage();
+                return true;
+            }
+
+        }
+        return false;
+    }
+
+    static void usage() {
+        printf("-c{channels} -d{duration} -m -n{burstsPerBuffer} -p{perfMode} -r{rate} -x\n");
+        printf("      Default values are UNSPECIFIED unless otherwise stated.\n");
+        printf("      -b{bufferCapacity} frames\n");
+        printf("      -c{channels} for example 2 for stereo\n");
+        printf("      -d{duration} in seconds, default is %d\n", DEFAULT_DURATION_SECONDS);
+        printf("      -m enable MMAP\n");
+        printf("      -n{numberOfBursts} for setBufferSize\n");
+        printf("      -p{performanceMode} set output AAUDIO_PERFORMANCE_MODE*, default NONE\n");
+        printf("          n for _NONE\n");
+        printf("          l for _LATENCY\n");
+        printf("          p for _POWER_SAVING;\n");
+        printf("      -r{sampleRate} for example 44100\n");
+        printf("      -x to use EXCLUSIVE mode\n");
+    }
+
+    static aaudio_performance_mode_t parsePerformanceMode(char c) {
+        aaudio_performance_mode_t mode = AAUDIO_PERFORMANCE_MODE_NONE;
+        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 invalid performance mode %c\n", c);
+                break;
+        }
+        return mode;
+    }
+
+    /**
+     * Print stream parameters in comparison with requested values.
+     * @param stream
+     */
+    void compareWithStream(AAudioStream *stream) {
+
+        printf("  DeviceId:     requested = %d, actual = %d\n",
+               getDeviceId(), AAudioStream_getDeviceId(stream));
+
+        aaudio_stream_state_t state = AAudioStream_getState(stream);
+        printf("  State:        %s\n", AAudio_convertStreamStateToText(state));
+
+        // Check to see what kind of stream we actually got.
+        printf("  SampleRate:   requested = %d, actual = %d\n",
+               getSampleRate(), AAudioStream_getSampleRate(stream));
+
+        printf("  ChannelCount: requested = %d, actual = %d\n",
+               getChannelCount(), AAudioStream_getChannelCount(stream));
+
+        printf("  DataFormat:   requested = %d, actual = %d\n",
+               getFormat(), AAudioStream_getFormat(stream));
+
+        int32_t framesPerBurst = AAudioStream_getFramesPerBurst(stream);
+        int32_t sizeFrames = AAudioStream_getBufferSizeInFrames(stream);
+        printf("  Buffer:       burst     = %d\n", framesPerBurst);
+        if (framesPerBurst > 0) {
+            printf("  Buffer:       size      = %d = (%d * %d) + %d\n",
+                   sizeFrames,
+                   (sizeFrames / framesPerBurst),
+                   framesPerBurst,
+                   (sizeFrames % framesPerBurst));
+        }
+        printf("  Capacity:     requested = %d, actual = %d\n", getBufferCapacity(),
+               AAudioStream_getBufferCapacityInFrames(stream));
+
+        printf("  SharingMode:  requested = %s, actual = %s\n",
+               getSharingModeText(getSharingMode()),
+               getSharingModeText(AAudioStream_getSharingMode(stream)));
+
+        printf("  PerformanceMode: requested = %d, actual = %d\n",
+               getPerformanceMode(), AAudioStream_getPerformanceMode(stream));
+        printf("  Is MMAP used? %s\n", AAudioStream_isMMapUsed(stream)
+               ? "yes" : "no");
+
+    }
+
+    int32_t getDurationSeconds() const {
+        return mDurationSeconds;
+    }
+
+    void setDurationSeconds(int32_t seconds) {
+        mDurationSeconds = seconds;
+    }
+
+private:
+    int32_t      mDurationSeconds = DEFAULT_DURATION_SECONDS;
+};
+
+#endif // AAUDIO_EXAMPLE_ARGS_PARSER_H
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index aaeb25f..19f8aff 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -23,6 +23,7 @@
 #include <sched.h>
 
 #include <aaudio/AAudio.h>
+#include "AAudioArgsParser.h"
 #include "SineGenerator.h"
 
 //#define SHARING_MODE  AAUDIO_SHARING_MODE_EXCLUSIVE
@@ -55,15 +56,23 @@
         mRequestedPerformanceMode = requestedPerformanceMode;
     }
 
+    // TODO Extract a common base class for record and playback.
     /**
      * Also known as "sample rate"
      * Only call this after open() has been called.
      */
-    int32_t getFramesPerSecond() {
+    int32_t getFramesPerSecond() const {
+        return getSampleRate(); // alias
+    }
+
+    /**
+     * Only call this after open() has been called.
+     */
+    int32_t getSampleRate() const {
         if (mStream == nullptr) {
             return AAUDIO_ERROR_INVALID_STATE;
         }
-        return AAudioStream_getSampleRate(mStream);;
+        return AAudioStream_getSampleRate(mStream);
     }
 
     /**
@@ -73,57 +82,83 @@
         if (mStream == nullptr) {
             return AAUDIO_ERROR_INVALID_STATE;
         }
-        return AAudioStream_getChannelCount(mStream);;
+        return AAudioStream_getChannelCount(mStream);
     }
 
     /**
      * Open a stream
      */
+    aaudio_result_t open(const AAudioParameters &parameters,
+                         AAudioStream_dataCallback dataCallback = nullptr,
+                         AAudioStream_errorCallback errorCallback = nullptr,
+                         void *userContext = nullptr) {
+        aaudio_result_t result = AAUDIO_OK;
+
+        // Use an AAudioStreamBuilder to contain requested parameters.
+        AAudioStreamBuilder *builder = nullptr;
+        result = AAudio_createStreamBuilder(&builder);
+        if (result != AAUDIO_OK) return result;
+
+        parameters.applyParameters(builder); // apply args
+
+        AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
+
+        if (dataCallback != nullptr) {
+            AAudioStreamBuilder_setDataCallback(builder, dataCallback, userContext);
+        }
+        if (errorCallback != nullptr) {
+            AAudioStreamBuilder_setErrorCallback(builder, errorCallback, userContext);
+        }
+        //AAudioStreamBuilder_setFramesPerDataCallback(builder, CALLBACK_SIZE_FRAMES);
+        //AAudioStreamBuilder_setBufferCapacityInFrames(builder, 48 * 8);
+
+        // Open an AAudioStream using the Builder.
+        result = AAudioStreamBuilder_openStream(builder, &mStream);
+
+        if (result == AAUDIO_OK) {
+            int32_t sizeInBursts = parameters.getNumberOfBursts();
+            if (sizeInBursts > 0) {
+                int32_t framesPerBurst = AAudioStream_getFramesPerBurst(mStream);
+                AAudioStream_setBufferSizeInFrames(mStream, sizeInBursts * framesPerBurst);
+            }
+        }
+
+        AAudioStreamBuilder_delete(builder);
+        return result;
+    }
+
     aaudio_result_t open(int channelCount, int sampSampleRate, aaudio_format_t format,
-                         AAudioStream_dataCallback dataProc, AAudioStream_errorCallback errorProc,
+                         AAudioStream_dataCallback dataProc,
+                         AAudioStream_errorCallback errorProc,
                          void *userContext) {
         aaudio_result_t result = AAUDIO_OK;
 
         // Use an AAudioStreamBuilder to contain requested parameters.
-        result = AAudio_createStreamBuilder(&mBuilder);
+        AAudioStreamBuilder *builder = nullptr;
+        result = AAudio_createStreamBuilder(&builder);
         if (result != AAUDIO_OK) return result;
 
-        //AAudioStreamBuilder_setSampleRate(mBuilder, 44100);
-        AAudioStreamBuilder_setPerformanceMode(mBuilder, mRequestedPerformanceMode);
-        AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode);
+        AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
+        AAudioStreamBuilder_setPerformanceMode(builder, mRequestedPerformanceMode);
+        AAudioStreamBuilder_setSharingMode(builder, mRequestedSharingMode);
+
+        AAudioStreamBuilder_setChannelCount(builder, channelCount);
+        AAudioStreamBuilder_setSampleRate(builder, sampSampleRate);
+        AAudioStreamBuilder_setFormat(builder, format);
+
         if (dataProc != nullptr) {
-            AAudioStreamBuilder_setDataCallback(mBuilder, dataProc, userContext);
+            AAudioStreamBuilder_setDataCallback(builder, dataProc, userContext);
         }
         if (errorProc != nullptr) {
-            AAudioStreamBuilder_setErrorCallback(mBuilder, errorProc, userContext);
+            AAudioStreamBuilder_setErrorCallback(builder, errorProc, userContext);
         }
-        AAudioStreamBuilder_setChannelCount(mBuilder, channelCount);
-        AAudioStreamBuilder_setSampleRate(mBuilder, sampSampleRate);
-        AAudioStreamBuilder_setFormat(mBuilder, format);
-        //AAudioStreamBuilder_setFramesPerDataCallback(mBuilder, CALLBACK_SIZE_FRAMES);
-        AAudioStreamBuilder_setBufferCapacityInFrames(mBuilder, 48 * 8);
-
-        //aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_NONE;
-        aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
-        //aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
-        AAudioStreamBuilder_setPerformanceMode(mBuilder, perfMode);
+        //AAudioStreamBuilder_setFramesPerDataCallback(builder, CALLBACK_SIZE_FRAMES);
+        //AAudioStreamBuilder_setBufferCapacityInFrames(builder, 48 * 8);
 
         // Open an AAudioStream using the Builder.
-        result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
-        if (result != AAUDIO_OK) goto finish1;
+        result = AAudioStreamBuilder_openStream(builder, &mStream);
 
-        printf("AAudioStream_getFramesPerBurst() = %d\n",
-               AAudioStream_getFramesPerBurst(mStream));
-        printf("AAudioStream_getBufferSizeInFrames() = %d\n",
-               AAudioStream_getBufferSizeInFrames(mStream));
-        printf("AAudioStream_getBufferCapacityInFrames() = %d\n",
-               AAudioStream_getBufferCapacityInFrames(mStream));
-        printf("AAudioStream_getPerformanceMode() = %d, requested %d\n",
-               AAudioStream_getPerformanceMode(mStream), perfMode);
-
-     finish1:
-        AAudioStreamBuilder_delete(mBuilder);
-        mBuilder = nullptr;
+        AAudioStreamBuilder_delete(builder);
         return result;
     }
 
@@ -132,8 +167,6 @@
             printf("call AAudioStream_close(%p)\n", mStream);  fflush(stdout);
             AAudioStream_close(mStream);
             mStream = nullptr;
-            AAudioStreamBuilder_delete(mBuilder);
-            mBuilder = nullptr;
         }
         return AAUDIO_OK;
     }
@@ -178,7 +211,6 @@
     }
 
 private:
-    AAudioStreamBuilder      *mBuilder = nullptr;
     AAudioStream             *mStream = nullptr;
     aaudio_sharing_mode_t     mRequestedSharingMode = SHARING_MODE;
     aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE;
diff --git a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
index 9e7c463..cb12fda 100644
--- a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
+++ b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
@@ -20,10 +20,12 @@
 #define AAUDIO_SIMPLE_RECORDER_H
 
 #include <aaudio/AAudio.h>
+#include "AAudioArgsParser.h"
 
 //#define SHARING_MODE  AAUDIO_SHARING_MODE_EXCLUSIVE
 #define SHARING_MODE  AAUDIO_SHARING_MODE_SHARED
 #define PERFORMANCE_MODE AAUDIO_PERFORMANCE_MODE_NONE
+
 /**
  * Simple wrapper for AAudio that opens an input stream either in callback or blocking read mode.
  */
@@ -54,11 +56,18 @@
      * Also known as "sample rate"
      * Only call this after open() has been called.
      */
-    int32_t getFramesPerSecond() {
+    int32_t getFramesPerSecond() const {
+        return getSampleRate(); // alias
+    }
+
+    /**
+     * Only call this after open() has been called.
+     */
+    int32_t getSampleRate() const {
         if (mStream == nullptr) {
             return AAUDIO_ERROR_INVALID_STATE;
         }
-        return AAudioStream_getSampleRate(mStream);;
+        return AAudioStream_getSampleRate(mStream);
     }
 
     /**
@@ -68,7 +77,7 @@
         if (mStream == nullptr) {
             return AAUDIO_ERROR_INVALID_STATE;
         }
-        return AAudioStream_getSamplesPerFrame(mStream);;
+        return AAudioStream_getChannelCount(mStream);
     }
     /**
      * Only call this after open() has been called.
@@ -77,53 +86,85 @@
         if (mStream == nullptr) {
             return AAUDIO_ERROR_INVALID_STATE;
         }
-        return AAudioStream_getFramesRead(mStream);;
+        return AAudioStream_getFramesRead(mStream);
+    }
+
+    aaudio_result_t open(const AAudioParameters &parameters,
+                         AAudioStream_dataCallback dataCallback = nullptr,
+                         AAudioStream_errorCallback errorCallback = nullptr,
+                         void *userContext = nullptr) {
+        aaudio_result_t result = AAUDIO_OK;
+
+        // Use an AAudioStreamBuilder to contain requested parameters.
+        AAudioStreamBuilder *builder = nullptr;
+        result = AAudio_createStreamBuilder(&builder);
+        if (result != AAUDIO_OK) return result;
+
+        parameters.applyParameters(builder); // apply args
+
+        AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT);
+
+        if (dataCallback != nullptr) {
+            AAudioStreamBuilder_setDataCallback(builder, dataCallback, userContext);
+        }
+        if (errorCallback != nullptr) {
+            AAudioStreamBuilder_setErrorCallback(builder, errorCallback, userContext);
+        }
+
+        // Open an AAudioStream using the Builder.
+        result = AAudioStreamBuilder_openStream(builder, &mStream);
+        if (result != AAUDIO_OK) {
+            fprintf(stderr, "ERROR - AAudioStreamBuilder_openStream() returned %d %s\n",
+                    result, AAudio_convertResultToText(result));
+        }
+
+        if (result == AAUDIO_OK) {
+            int32_t sizeInBursts = parameters.getNumberOfBursts();
+            if (sizeInBursts > 0) {
+                int32_t framesPerBurst = AAudioStream_getFramesPerBurst(mStream);
+                AAudioStream_setBufferSizeInFrames(mStream, sizeInBursts * framesPerBurst);
+            }
+        }
+
+        AAudioStreamBuilder_delete(builder);
+        return result;
     }
 
     /**
      * Open a stream
      */
     aaudio_result_t open(int channelCount, int sampSampleRate, aaudio_format_t format,
-                         AAudioStream_dataCallback dataProc, AAudioStream_errorCallback errorProc,
+                         AAudioStream_dataCallback dataProc,
+                         AAudioStream_errorCallback errorProc,
                          void *userContext) {
         aaudio_result_t result = AAUDIO_OK;
 
         // Use an AAudioStreamBuilder to contain requested parameters.
-        result = AAudio_createStreamBuilder(&mBuilder);
+        AAudioStreamBuilder *builder = nullptr;
+        result = AAudio_createStreamBuilder(&builder);
         if (result != AAUDIO_OK) return result;
 
-        AAudioStreamBuilder_setDirection(mBuilder, AAUDIO_DIRECTION_INPUT);
-        AAudioStreamBuilder_setPerformanceMode(mBuilder, mRequestedPerformanceMode);
-        AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode);
+        AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT);
+        AAudioStreamBuilder_setPerformanceMode(builder, mRequestedPerformanceMode);
+        AAudioStreamBuilder_setSharingMode(builder, mRequestedSharingMode);
         if (dataProc != nullptr) {
-            AAudioStreamBuilder_setDataCallback(mBuilder, dataProc, userContext);
+            AAudioStreamBuilder_setDataCallback(builder, dataProc, userContext);
         }
         if (errorProc != nullptr) {
-            AAudioStreamBuilder_setErrorCallback(mBuilder, errorProc, userContext);
+            AAudioStreamBuilder_setErrorCallback(builder, errorProc, userContext);
         }
-        AAudioStreamBuilder_setChannelCount(mBuilder, channelCount);
-        AAudioStreamBuilder_setSampleRate(mBuilder, sampSampleRate);
-        AAudioStreamBuilder_setFormat(mBuilder, format);
+        AAudioStreamBuilder_setChannelCount(builder, channelCount);
+        AAudioStreamBuilder_setSampleRate(builder, sampSampleRate);
+        AAudioStreamBuilder_setFormat(builder, format);
 
         // Open an AAudioStream using the Builder.
-        result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
+        result = AAudioStreamBuilder_openStream(builder, &mStream);
         if (result != AAUDIO_OK) {
             fprintf(stderr, "ERROR - AAudioStreamBuilder_openStream() returned %d %s\n",
                     result, AAudio_convertResultToText(result));
-            goto finish1;
         }
 
-        printf("AAudioStream_getFramesPerBurst() = %d\n",
-               AAudioStream_getFramesPerBurst(mStream));
-        printf("AAudioStream_getBufferSizeInFrames() = %d\n",
-               AAudioStream_getBufferSizeInFrames(mStream));
-        printf("AAudioStream_getBufferCapacityInFrames() = %d\n",
-               AAudioStream_getBufferCapacityInFrames(mStream));
-        return result;
-
-     finish1:
-        AAudioStreamBuilder_delete(mBuilder);
-        mBuilder = nullptr;
+        AAudioStreamBuilder_delete(builder);
         return result;
     }
 
@@ -132,8 +173,6 @@
             printf("call AAudioStream_close(%p)\n", mStream);  fflush(stdout);
             AAudioStream_close(mStream);
             mStream = nullptr;
-            AAudioStreamBuilder_delete(mBuilder);
-            mBuilder = nullptr;
         }
         return AAUDIO_OK;
     }
@@ -186,7 +225,6 @@
     }
 
 private:
-    AAudioStreamBuilder      *mBuilder = nullptr;
     AAudioStream             *mStream = nullptr;
     aaudio_sharing_mode_t     mRequestedSharingMode = SHARING_MODE;
     aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE;
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index b9269e6..0125c0f 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -23,39 +23,22 @@
 #include <aaudio/AAudioTesting.h>
 #include "AAudioExampleUtils.h"
 #include "AAudioSimplePlayer.h"
+#include "AAudioArgsParser.h"
 
-#define SAMPLE_RATE           48000
 #define NUM_SECONDS           4
 
-//#define MMAP_POLICY              AAUDIO_UNSPECIFIED
-//#define MMAP_POLICY              AAUDIO_POLICY_NEVER
-//#define MMAP_POLICY              AAUDIO_POLICY_AUTO
-#define MMAP_POLICY              AAUDIO_POLICY_ALWAYS
-
-#define REQUESTED_FORMAT         AAUDIO_FORMAT_PCM_I16
-
-//#define REQUESTED_SHARING_MODE   AAUDIO_SHARING_MODE_SHARED
-#define REQUESTED_SHARING_MODE   AAUDIO_SHARING_MODE_EXCLUSIVE
-
-
-int main(int argc, char **argv)
+int main(int argc, const char **argv)
 {
-    (void)argc; // unused
-
+    AAudioArgsParser   argParser;
     AAudioSimplePlayer player;
     SineThreadedData_t myData;
-    aaudio_result_t result = AAUDIO_OK;
+    aaudio_result_t    result = AAUDIO_OK;
 
-    const int requestedChannelCount = 2;
-    int actualChannelCount = 0;
-    const int requestedSampleRate = SAMPLE_RATE;
-    int actualSampleRate = 0;
-    aaudio_format_t requestedDataFormat = REQUESTED_FORMAT;
+    int32_t         actualChannelCount = 0;
+    int32_t         actualSampleRate = 0;
     aaudio_format_t actualDataFormat = AAUDIO_FORMAT_UNSPECIFIED;
-    aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
 
     AAudioStream *aaudioStream = nullptr;
-    aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
     int32_t  framesPerBurst = 0;
     int32_t  framesPerWrite = 0;
     int32_t  bufferCapacity = 0;
@@ -64,61 +47,37 @@
     int32_t  xRunCount = 0;
     float   *floatData = nullptr;
     int16_t *shortData = nullptr;
-    int32_t deviceId;
 
     // 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]);
+    printf("%s - Play a sine wave using AAudio V0.1.1\n", argv[0]);
 
-    AAudio_setMMapPolicy(MMAP_POLICY);
-    printf("requested MMapPolicy = %d\n", AAudio_getMMapPolicy());
+    if (argParser.parseArgs(argc, argv)) {
+        return EXIT_FAILURE;
+    }
 
-    player.setSharingMode(REQUESTED_SHARING_MODE);
-
-    result = player.open(requestedChannelCount, requestedSampleRate, requestedDataFormat,
-                         nullptr, nullptr, &myData);
+    result = player.open(argParser);
     if (result != AAUDIO_OK) {
         fprintf(stderr, "ERROR -  player.open() returned %d\n", result);
         goto finish;
     }
 
     aaudioStream = player.getStream();
-    // Request stream properties.
 
-    deviceId = AAudioStream_getDeviceId(aaudioStream);
-    printf("deviceId = %d\n", deviceId);
+    argParser.compareWithStream(aaudioStream);
 
-    state = AAudioStream_getState(aaudioStream);
-    printf("after open, state = %s\n", AAudio_convertStreamStateToText(state));
-
-    // Check to see what kind of stream we actually got.
+    actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
     actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
-    printf("SampleRate: requested = %d, actual = %d\n", requestedSampleRate, actualSampleRate);
+    actualDataFormat = AAudioStream_getFormat(aaudioStream);
 
     myData.sineOsc1.setup(440.0, actualSampleRate);
     myData.sineOsc2.setup(660.0, actualSampleRate);
 
-    actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
-    printf("ChannelCount: requested = %d, actual = %d\n",
-            requestedChannelCount, actualChannelCount);
-
-    actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
-    printf("SharingMode: requested = %s, actual = %s\n",
-            getSharingModeText(REQUESTED_SHARING_MODE),
-            getSharingModeText(actualSharingMode));
-
-    // This is the number of frames that are read in one chunk by a DMA controller
-    // or a DSP or a mixer.
-    framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
-    printf("Buffer: bufferSize     = %d\n", AAudioStream_getBufferSizeInFrames(aaudioStream));
-    bufferCapacity = AAudioStream_getBufferCapacityInFrames(aaudioStream);
-    printf("Buffer: bufferCapacity = %d, remainder = %d\n",
-           bufferCapacity, bufferCapacity % framesPerBurst);
-
     // Some DMA might use very short bursts of 16 frames. We don't need to write such small
     // buffers. But it helps to use a multiple of the burst size for predictable scheduling.
+    framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
     framesPerWrite = framesPerBurst;
     while (framesPerWrite < 48) {
         framesPerWrite *= 2;
@@ -126,13 +85,6 @@
     printf("Buffer: framesPerBurst = %d\n",framesPerBurst);
     printf("Buffer: framesPerWrite = %d\n",framesPerWrite);
 
-    printf("PerformanceMode        = %d\n", AAudioStream_getPerformanceMode(aaudioStream));
-    printf("is MMAP used?          = %s\n", AAudioStream_isMMapUsed(aaudioStream) ? "yes" : "no");
-
-    actualDataFormat = AAudioStream_getFormat(aaudioStream);
-    printf("DataFormat: requested  = %d, actual = %d\n", REQUESTED_FORMAT, actualDataFormat);
-    // TODO handle other data formats
-
     // Allocate a buffer for the audio data.
     if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
         floatData = new float[framesPerWrite * actualChannelCount];
@@ -151,11 +103,11 @@
         goto finish;
     }
 
-    state = AAudioStream_getState(aaudioStream);
-    printf("after start, state = %s\n", AAudio_convertStreamStateToText(state));
+    printf("after start, state = %s\n",
+            AAudio_convertStreamStateToText(AAudioStream_getState(aaudioStream)));
 
     // Play for a while.
-    framesToPlay = actualSampleRate * NUM_SECONDS;
+    framesToPlay = actualSampleRate * argParser.getDurationSeconds();
     framesLeft = framesToPlay;
     while (framesLeft > 0) {
 
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 69145aa..2211b72 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -27,36 +27,42 @@
 #include "AAudioExampleUtils.h"
 #include "AAudioSimplePlayer.h"
 
-#define NUM_SECONDS              5
-
 // Application data that gets passed to the callback.
 #define MAX_FRAME_COUNT_RECORDS    256
 
-int main(int argc, char **argv)
+int main(int argc, const char **argv)
 {
-    (void)argc; // unused
+    AAudioArgsParser   argParser;
     AAudioSimplePlayer player;
     SineThreadedData_t myData;
     aaudio_result_t result;
+    int32_t actualSampleRate;
 
     // Make printf print immediately so that debug info is not stuck
     // in a buffer if we hang or crash.
     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
-    printf("%s - Play a sine sweep using an AAudio callback\n", argv[0]);
+
+    printf("%s - Play a sine sweep using an AAudio callback V0.1.1\n", argv[0]);
 
     myData.schedulerChecked = false;
 
-    result = player.open(2, 44100, AAUDIO_FORMAT_PCM_FLOAT,
+    if (argParser.parseArgs(argc, argv)) {
+        return EXIT_FAILURE;
+    }
+
+    result = player.open(argParser,
                          SimplePlayerDataCallbackProc, SimplePlayerErrorCallbackProc, &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.getChannelCount() = %d\n", player.getChannelCount());
-    myData.sineOsc1.setup(440.0, 48000);
+
+    argParser.compareWithStream(player.getStream());
+
+    actualSampleRate = player.getSampleRate();
+    myData.sineOsc1.setup(440.0, actualSampleRate);
     myData.sineOsc1.setSweep(300.0, 600.0, 5.0);
-    myData.sineOsc2.setup(660.0, 48000);
+    myData.sineOsc2.setup(660.0, actualSampleRate);
     myData.sineOsc2.setSweep(350.0, 900.0, 7.0);
 
 #if 0
@@ -73,8 +79,9 @@
         goto error;
     }
 
-    printf("Sleep for %d seconds while audio plays in a callback thread.\n", NUM_SECONDS);
-    for (int second = 0; second < NUM_SECONDS; second++)
+    printf("Sleep for %d seconds while audio plays in a callback thread.\n",
+           argParser.getDurationSeconds());
+    for (int second = 0; second < argParser.getDurationSeconds(); second++)
     {
         const struct timespec request = { .tv_sec = 1, .tv_nsec = 0 };
         (void) clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, &request, NULL /*remain*/);