Merge 'aosp/upstream-main' into external/oboe am: f4b22d10c4

Original change: https://android-review.googlesource.com/c/platform/external/oboe/+/2444000

Change-Id: I603fb9ce7dfc9fe18b942b56349139cb31dabfa6
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml
new file mode 100644
index 0000000..f3f5f28
--- /dev/null
+++ b/.github/workflows/build-ci.yml
@@ -0,0 +1,37 @@
+name: Build CI
+
+on:
+  push:
+    branches: [ main ]
+  pull_request:
+    branches: [ main ]
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v2
+    - name: set up JDK 11
+      uses: actions/setup-java@v1
+      with:
+        java-version: 11
+    - name: build samples and apps
+      uses: github/codeql-action/init@v2
+      with:
+        languages: cpp
+    - run: |
+        pushd samples
+        chmod +x gradlew
+        ./gradlew -q clean bundleDebug
+        popd
+        pushd apps/OboeTester
+        chmod +x gradlew
+        ./gradlew -q clean bundleDebug
+        popd
+        pushd apps/fxlab
+        chmod +x gradlew
+        ./gradlew -q clean bundleDebug
+        popd
+    - name: Perform CodeQL Analysis
+      uses: github/codeql-action/analyze@v2
diff --git a/.github/workflows/update-docs.yml b/.github/workflows/update-docs.yml
new file mode 100644
index 0000000..a37d05e
--- /dev/null
+++ b/.github/workflows/update-docs.yml
@@ -0,0 +1,24 @@
+name: Update Docs
+
+on:
+  push:
+    branches: [ main ]
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v2
+
+    - name: Doxygen Action
+      uses: mattnotmitt/doxygen-action@v1.1.0
+      with:
+        doxyfile-path: "./Doxyfile"
+        working-directory: "."
+
+    - name: Deploy
+      uses: peaceiris/actions-gh-pages@v3
+      with:
+        github_token: ${{ secrets.GITHUB_TOKEN }}
+        publish_dir: ./docs/reference
diff --git a/Android.bp b/Android.bp
index 70f1243..3d6e7fb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -47,7 +47,6 @@
     ],
     license_text: [
         "LICENSE",
-        "NOTICE",
     ],
 }
 
@@ -65,8 +64,11 @@
         "src/common/FixedBlockReader.cpp",
         "src/common/FixedBlockWriter.cpp",
         "src/common/LatencyTuner.cpp",
+        "src/common/OboeExtensions.cpp",
         "src/common/SourceFloatCaller.cpp",
         "src/common/SourceI16Caller.cpp",
+        "src/common/SourceI24Caller.cpp",
+        "src/common/SourceI32Caller.cpp",
         "src/common/Utilities.cpp",
         "src/common/QuirksManager.cpp",
         "src/fifo/FifoBuffer.cpp",
@@ -76,17 +78,22 @@
         "src/flowgraph/FlowGraphNode.cpp",
         "src/flowgraph/ChannelCountConverter.cpp",
         "src/flowgraph/ClipToRange.cpp",
+        "src/flowgraph/Limiter.cpp",
         "src/flowgraph/ManyToMultiConverter.cpp",
+        "src/flowgraph/MonoBlend.cpp",
         "src/flowgraph/MonoToMultiConverter.cpp",
+        "src/flowgraph/MultiToManyConverter.cpp",
         "src/flowgraph/MultiToMonoConverter.cpp",
         "src/flowgraph/RampLinear.cpp",
         "src/flowgraph/SampleRateConverter.cpp",
         "src/flowgraph/SinkFloat.cpp",
         "src/flowgraph/SinkI16.cpp",
         "src/flowgraph/SinkI24.cpp",
+        "src/flowgraph/SinkI32.cpp",
         "src/flowgraph/SourceFloat.cpp",
         "src/flowgraph/SourceI16.cpp",
         "src/flowgraph/SourceI24.cpp",
+        "src/flowgraph/SourceI32.cpp",
         "src/flowgraph/resampler/IntegerRatio.cpp",
         "src/flowgraph/resampler/LinearResampler.cpp",
         "src/flowgraph/resampler/MultiChannelResampler.cpp",
@@ -122,7 +129,9 @@
         "-Wno-unused-parameter",
         "-Wno-deprecated-declarations",
         "-Ofast",
-        "-DOBOE_NO_INCLUDE_AAUDIO",
+        "-DFLOWGRAPH_ANDROID_INTERNAL=0",
+        "-DFLOWGRAPH_OUTER_NAMESPACE=oboe",
+        "-DRESAMPLER_OUTER_NAMESPACE=oboe",
     ],
     sdk_version: "current",
     stl: "libc++_static",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 51a45b2..056011c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,8 +18,11 @@
     src/common/FixedBlockReader.cpp
     src/common/FixedBlockWriter.cpp
     src/common/LatencyTuner.cpp
+    src/common/OboeExtensions.cpp
     src/common/SourceFloatCaller.cpp
     src/common/SourceI16Caller.cpp
+    src/common/SourceI24Caller.cpp
+    src/common/SourceI32Caller.cpp
     src/common/Utilities.cpp
     src/common/QuirksManager.cpp
     src/fifo/FifoBuffer.cpp
@@ -29,17 +32,22 @@
     src/flowgraph/FlowGraphNode.cpp
     src/flowgraph/ChannelCountConverter.cpp
     src/flowgraph/ClipToRange.cpp
+    src/flowgraph/Limiter.cpp
     src/flowgraph/ManyToMultiConverter.cpp
+    src/flowgraph/MonoBlend.cpp
     src/flowgraph/MonoToMultiConverter.cpp
+    src/flowgraph/MultiToManyConverter.cpp
     src/flowgraph/MultiToMonoConverter.cpp
     src/flowgraph/RampLinear.cpp
     src/flowgraph/SampleRateConverter.cpp
     src/flowgraph/SinkFloat.cpp
     src/flowgraph/SinkI16.cpp
     src/flowgraph/SinkI24.cpp
+    src/flowgraph/SinkI32.cpp
     src/flowgraph/SourceFloat.cpp
     src/flowgraph/SourceI16.cpp
     src/flowgraph/SourceI24.cpp
+    src/flowgraph/SourceI32.cpp
     src/flowgraph/resampler/IntegerRatio.cpp
     src/flowgraph/resampler/LinearResampler.cpp
     src/flowgraph/resampler/MultiChannelResampler.cpp
@@ -72,12 +80,13 @@
 #     Enable -Ofast
 target_compile_options(oboe
         PRIVATE
-        -std=c++14
+        -std=c++17
         -Wall
         -Wextra-semi
         -Wshadow
         -Wshadow-field
-        -Ofast
+        "$<$<CONFIG:RELEASE>:-Ofast>"
+        "$<$<CONFIG:DEBUG>:-O3>"
         "$<$<CONFIG:DEBUG>:-Werror>")
 
 # Enable logging of D,V for debug builds
@@ -91,4 +100,4 @@
         ARCHIVE DESTINATION lib/${ANDROID_ABI})
 
 # Also install the headers
-install(DIRECTORY include/oboe DESTINATION include)
\ No newline at end of file
+install(DIRECTORY include/oboe DESTINATION include)
diff --git a/CONTRIBUTING b/CONTRIBUTING
deleted file mode 100644
index 5d9ff17..0000000
--- a/CONTRIBUTING
+++ /dev/null
@@ -1 +0,0 @@
-Please see the CONTRIBUTING.md file for more information.
diff --git a/Doxyfile b/Doxyfile
index f0e0be3..6b87a12 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -38,7 +38,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.5
+PROJECT_NUMBER         =
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -58,7 +58,7 @@
 # entered, it will be relative to the location where doxygen was started. If
 # left blank the current directory will be used.
 
-OUTPUT_DIRECTORY       = docs
+OUTPUT_DIRECTORY       = ./docs
 
 # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
 # directories (in 2 levels) under the output directory of each output format and
diff --git a/NOTICE b/NOTICE
deleted file mode 100644
index d645695..0000000
--- a/NOTICE
+++ /dev/null
@@ -1,202 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   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/README b/README
deleted file mode 100644
index 9150edf..0000000
--- a/README
+++ /dev/null
@@ -1 +0,0 @@
-Please see the README.md file for more information.
diff --git a/README.md b/README.md
index 9bdf2a0..44acf9f 100644
--- a/README.md
+++ b/README.md
@@ -10,12 +10,12 @@
 - Automatic latency tuning
 - Modern C++ allowing you to write clean, elegant code
 - Workarounds for some known issues
-- [Used by popular apps and frameworks](docs/AppsUsingOboe.md)
+- [Used by popular apps and frameworks](https://github.com/google/oboe/wiki/AppsUsingOboe)
 
 ## Documentation
 - [Getting Started Guide](docs/GettingStarted.md)
 - [Full Guide to Oboe](docs/FullGuide.md)
-- [API reference](https://google.github.io/oboe/reference)
+- [API reference](https://google.github.io/oboe)
 - [Tech Notes](docs/notes/)
 - [History of Audio features/bugs by Android version](docs/AndroidAudioHistory.md)
 - [Migration guide for apps using OpenSL ES](docs/OpenSLESMigration.md)
@@ -27,8 +27,8 @@
 - StackOverflow: [#oboe](https://stackoverflow.com/questions/tagged/oboe)
 
 ## Testing
-- [**OboeTester** app for measuring latency, glitches, etc.](https://github.com/google/oboe/tree/master/apps/OboeTester/docs)
-- [Oboe unit tests](https://github.com/google/oboe/tree/master/tests)
+- [**OboeTester** app for measuring latency, glitches, etc.](apps/OboeTester/docs)
+- [Oboe unit tests](tests)
 
 ## Videos
 - [Getting started with Oboe](https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_duWv9IPNvx9YBudNMmLSa)
@@ -38,7 +38,7 @@
 ## Sample code and apps
 - Sample apps can be found in the [samples directory](samples). 
 - A complete "effects processor" app called FXLab can  be found in the [apps/fxlab folder](apps/fxlab). 
-- Also check out the [Rhythm Game codelab](https://codelabs.developers.google.com/codelabs/musicalgame-using-oboe/index.html#0).
+- Also check out the [Rhythm Game codelab](https://developer.android.com/codelabs/musicalgame-using-oboe?hl=en#0).
 
 ### Third party sample code
 - [Ableton Link integration demo](https://github.com/jbloit/AndroidLinkAudio) (author: jbloit)
diff --git a/apps/OboeTester/.gitignore b/apps/OboeTester/.gitignore
index e698dc3..7112e85 100644
--- a/apps/OboeTester/.gitignore
+++ b/apps/OboeTester/.gitignore
@@ -6,6 +6,8 @@
 /build/
 .idea/
 /app/build/
+/app/release/
+/app/debug/
 /app/app.iml
 *.iml
 /app/externalNativeBuild/
diff --git a/apps/OboeTester/app/CMakeLists.txt b/apps/OboeTester/app/CMakeLists.txt
index 39cda1c..8409dca 100644
--- a/apps/OboeTester/app/CMakeLists.txt
+++ b/apps/OboeTester/app/CMakeLists.txt
@@ -1,11 +1,14 @@
 cmake_minimum_required(VERSION 3.4.1)
 
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++14 -DOBOE_NO_INCLUDE_AAUDIO -fvisibility=hidden")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++17 -fvisibility=hidden")
 set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O2")
 set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
 
 link_directories(${CMAKE_CURRENT_LIST_DIR}/..)
 
+# Increment this number when adding files to OboeTester => 101
+# The change in this file will help Android Studio resync
+# and generate new build files that reference the new code.
 file(GLOB_RECURSE app_native_sources src/main/cpp/*)
 
 ### Name must match loadLibrary() call in MainActivity.java
@@ -31,4 +34,3 @@
 # link to oboe
 target_link_libraries(oboetester log oboe atomic)
 
-# bump 4 to resync CMake
diff --git a/apps/OboeTester/app/build.gradle b/apps/OboeTester/app/build.gradle
index f6e3fd5..91c62a8 100644
--- a/apps/OboeTester/app/build.gradle
+++ b/apps/OboeTester/app/build.gradle
@@ -1,18 +1,17 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 28
+    compileSdkVersion 33
     defaultConfig {
-        applicationId = "com.google.sample.oboe.manualtest"
+        applicationId = "com.mobileer.oboetester"
         minSdkVersion 23
-        targetSdkVersion 28
-        // Also update the versions in the AndroidManifest.xml file.
-        versionCode 44
-        versionName "1.6.2"
+        targetSdkVersion 33
+        versionCode 65
+        versionName "2.3.6"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
         externalNativeBuild {
             cmake {
-                cppFlags "-std=c++14"
+                cppFlags "-std=c++17"
                 abiFilters "x86", "x86_64", "armeabi-v7a", "arm64-v8a"
             }
         }
@@ -35,10 +34,10 @@
 
 dependencies {
     implementation fileTree(include: ['*.jar'], dir: 'libs')
-    implementation 'com.android.support.constraint:constraint-layout:2.0.0-beta4'
+    implementation 'com.android.support.constraint:constraint-layout:2.0.4'
 
     testImplementation 'junit:junit:4.13-beta-3'
     implementation 'com.android.support:appcompat-v7:28.0.0'
     androidTestImplementation 'com.android.support.test:runner:1.0.2'
     androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
-}
\ No newline at end of file
+}
diff --git a/apps/OboeTester/app/local.properties b/apps/OboeTester/app/local.properties
deleted file mode 100644
index 8a33ae0..0000000
--- a/apps/OboeTester/app/local.properties
+++ /dev/null
@@ -1,9 +0,0 @@
-## This file must *NOT* be checked into Version Control Systems,
-# as it contains information specific to your local configuration.
-#
-# Location of the SDK. This is only used by Gradle.
-# For customization when using a Version Control System, please read the
-# header note.
-#Thu Apr 11 16:29:25 PDT 2019
-ndk.dir=/Users/philburk/Library/Android/sdk/ndk-bundle
-sdk.dir=/Users/philburk/Library/Android/sdk
diff --git a/apps/OboeTester/app/src/main/AndroidManifest.xml b/apps/OboeTester/app/src/main/AndroidManifest.xml
index b246926..e116285 100644
--- a/apps/OboeTester/app/src/main/AndroidManifest.xml
+++ b/apps/OboeTester/app/src/main/AndroidManifest.xml
@@ -1,20 +1,27 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.google.sample.oboe.manualtest"
-    android:versionCode="44"
-    android:versionName="1.6.2">
-    <!-- versionCode and versionName also have to be updated in build.gradle -->
-
-    <uses-feature android:name="android.hardware.microphone" android:required="true" />
-    <uses-feature android:name="android.hardware.audio.output" android:required="true" />
-    <uses-feature android:name="android.software.midi" android:required="true" />
+    package="com.mobileer.oboetester">
+    <uses-feature
+        android:name="android.hardware.microphone"
+        android:required="false" />
+    <uses-feature
+        android:name="android.hardware.audio.output"
+        android:required="true" />
+    <uses-feature
+        android:name="android.hardware.touchscreen"
+        android:required="false" />
+    <uses-feature
+        android:name="android.software.midi"
+        android:required="false" />
+    <uses-feature
+        android:name="android.software.leanback"
+        android:required="false" />
 
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
     <uses-permission android:name="android.permission.INTERNET" />
-    <!-- debug-writing file need external storage writing -->
+    <!-- This is needed for sharing test results. -->
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 
@@ -24,79 +31,83 @@
         android:icon="@mipmap/ic_launcher"
         android:label="@string/app_name"
         android:supportsRtl="true"
-        android:theme="@style/AppTheme">
-
+        android:theme="@style/AppTheme"
+        android:requestLegacyExternalStorage="true"
+        android:banner="@mipmap/ic_launcher">
         <activity
-            android:name="com.google.sample.oboe.manualtest.MainActivity"
-            android:launchMode="singleTask"
+            android:name=".MainActivity"
             android:label="@string/app_name"
-            android:screenOrientation="portrait">
+            android:launchMode="singleTask"
+            android:screenOrientation="portrait"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
                 <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
             </intent-filter>
         </activity>
-
         <activity
-            android:name="com.google.sample.oboe.manualtest.TestOutputActivity"
+            android:name=".TestOutputActivity"
             android:label="@string/title_activity_test_output"
-            android:screenOrientation="portrait">
-        </activity>
-
+            android:screenOrientation="portrait" />
         <activity
-            android:name="com.google.sample.oboe.manualtest.TestInputActivity"
+            android:name=".TestInputActivity"
             android:label="@string/title_activity_test_input"
-            android:screenOrientation="portrait">
-        </activity>
-
+            android:screenOrientation="portrait" />
         <activity
-            android:name="com.google.sample.oboe.manualtest.TapToToneActivity"
+            android:name=".TapToToneActivity"
             android:label="@string/title_activity_output_latency"
-            android:screenOrientation="portrait">
-        </activity>
-
+            android:screenOrientation="portrait" />
         <activity
-            android:name="com.google.sample.oboe.manualtest.RecorderActivity"
+            android:name=".RecorderActivity"
             android:label="@string/title_activity_recorder"
-            android:screenOrientation="portrait">
-        </activity>
-
+            android:screenOrientation="portrait" />
         <activity
-            android:name="com.google.sample.oboe.manualtest.EchoActivity"
+            android:name=".EchoActivity"
             android:label="@string/title_activity_echo"
-            android:screenOrientation="portrait">
-        </activity>
-
+            android:screenOrientation="portrait" />
         <activity
-            android:name="com.google.sample.oboe.manualtest.RoundTripLatencyActivity"
+            android:name=".RoundTripLatencyActivity"
             android:label="@string/title_activity_rt_latency"
-            android:screenOrientation="portrait">
-        </activity>
-
+            android:screenOrientation="portrait" />
         <activity
-            android:name="com.google.sample.oboe.manualtest.ManualGlitchActivity"
+            android:name=".ManualGlitchActivity"
             android:label="@string/title_activity_glitches"
-            android:screenOrientation="portrait">
-        </activity>
-
+            android:screenOrientation="portrait" />
         <activity
-            android:name="com.google.sample.oboe.manualtest.AutomatedGlitchActivity"
+            android:name=".AutomatedGlitchActivity"
             android:label="@string/title_activity_auto_glitches"
-            android:screenOrientation="portrait">
-        </activity>
-
+            android:screenOrientation="portrait" />
         <activity
-            android:name="com.google.sample.oboe.manualtest.TestDisconnectActivity"
+            android:name=".TestDisconnectActivity"
             android:label="@string/title_test_disconnect"
-            android:screenOrientation="portrait">
-        </activity>
+            android:screenOrientation="portrait" />
+        <activity
+            android:name=".DeviceReportActivity"
+            android:label="@string/title_report_devices"
+            android:screenOrientation="portrait" />
+        <activity
+            android:name=".TestDataPathsActivity"
+            android:label="@string/title_data_paths"
+            android:screenOrientation="portrait" />
+        <activity
+            android:name=".ExtraTestsActivity"
+            android:exported="true"
+            android:label="@string/title_extra_tests" />
 
         <activity
-            android:name="com.google.sample.oboe.manualtest.DeviceReportActivity"
-            android:label="@string/title_report_devices"
-            android:screenOrientation="portrait">
-        </activity>
+            android:name=".ExternalTapToToneActivity"
+            android:label="@string/title_external_tap"
+            android:exported="true" />
+        <activity
+            android:name=".TestPlugLatencyActivity"
+            android:label="@string/title_plug_latency"
+            android:exported="true" />
+        <activity
+            android:name=".TestErrorCallbackActivity"
+            android:label="@string/title_error_callback"
+            android:exported="true" />
 
         <activity
             android:name="com.google.sample.oboe.manualtest.TestDataPathsActivity"
@@ -105,8 +116,9 @@
         </activity>
 
         <service
-            android:name="com.google.sample.oboe.manualtest.AudioMidiTester"
-            android:permission="android.permission.BIND_MIDI_DEVICE_SERVICE">
+            android:name=".MidiTapTester"
+            android:permission="android.permission.BIND_MIDI_DEVICE_SERVICE"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.media.midi.MidiDeviceService" />
             </intent-filter>
@@ -123,9 +135,8 @@
             android:grantUriPermissions="true">
             <meta-data
                 android:name="android.support.FILE_PROVIDER_PATHS"
-                android:resource="@xml/provider_paths"/>
+                android:resource="@xml/provider_paths" />
         </provider>
-
     </application>
 
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/apps/OboeTester/app/src/main/cpp/FormatConverterBox.cpp b/apps/OboeTester/app/src/main/cpp/FormatConverterBox.cpp
new file mode 100644
index 0000000..dd9f324
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/FormatConverterBox.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2021 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 "FormatConverterBox.h"
+
+FormatConverterBox::FormatConverterBox(int32_t numSamples,
+                                       oboe::AudioFormat inputFormat,
+                                       oboe::AudioFormat outputFormat) {
+    mInputFormat = inputFormat;
+    mOutputFormat = outputFormat;
+
+    mInputBuffer = std::make_unique<uint8_t[]>(numSamples * sizeof(int32_t));
+    mOutputBuffer = std::make_unique<uint8_t[]>(numSamples * sizeof(int32_t));
+
+    mSource.reset();
+    switch (mInputFormat) {
+        case oboe::AudioFormat::I16:
+            mSource = std::make_unique<oboe::flowgraph::SourceI16>(1);
+            break;
+        case oboe::AudioFormat::I24:
+            mSource = std::make_unique<oboe::flowgraph::SourceI24>(1);
+            break;
+        case oboe::AudioFormat::I32:
+            mSource = std::make_unique<oboe::flowgraph::SourceI32>(1);
+            break;
+        case oboe::AudioFormat::Float:
+        case oboe::AudioFormat::Invalid:
+        case oboe::AudioFormat::Unspecified:
+            mSource = std::make_unique<oboe::flowgraph::SourceFloat>(1);
+            break;
+    }
+
+    mSink.reset();
+    switch (mOutputFormat) {
+        case oboe::AudioFormat::I16:
+            mSink = std::make_unique<oboe::flowgraph::SinkI16>(1);
+            break;
+        case oboe::AudioFormat::I24:
+            mSink = std::make_unique<oboe::flowgraph::SinkI24>(1);
+            break;
+        case oboe::AudioFormat::I32:
+            mSink = std::make_unique<oboe::flowgraph::SinkI32>(1);
+            break;
+        case oboe::AudioFormat::Float:
+        case oboe::AudioFormat::Invalid:
+        case oboe::AudioFormat::Unspecified:
+            mSink = std::make_unique<oboe::flowgraph::SinkFloat>(1);
+            break;
+    }
+
+    if (mSource && mSink) {
+        mSource->output.connect(&mSink->input);
+        mSink->pullReset();
+    }
+}
+
+int32_t FormatConverterBox::convertInternalBuffers(int32_t numSamples) {
+    return convert(getOutputBuffer(), numSamples, getInputBuffer());
+}
+
+int32_t FormatConverterBox::convertToInternalOutput(int32_t numSamples, const void *inputBuffer) {
+    return convert(getOutputBuffer(), numSamples, inputBuffer);
+}
+
+int32_t FormatConverterBox::convertFromInternalInput(void *outputBuffer, int32_t numSamples) {
+    return convert(outputBuffer, numSamples, getInputBuffer());
+}
+
+int32_t FormatConverterBox::convert(void *outputBuffer, int32_t numSamples, const void *inputBuffer) {
+    mSource->setData(inputBuffer, numSamples);
+    return mSink->read(outputBuffer, numSamples);
+}
diff --git a/apps/OboeTester/app/src/main/cpp/FormatConverterBox.h b/apps/OboeTester/app/src/main/cpp/FormatConverterBox.h
new file mode 100644
index 0000000..782f9e0
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/FormatConverterBox.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2021 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 OBOETESTER_FORMAT_CONVERTER_BOX_H
+#define OBOETESTER_FORMAT_CONVERTER_BOX_H
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "oboe/Oboe.h"
+#include "flowgraph/SinkFloat.h"
+#include "flowgraph/SinkI16.h"
+#include "flowgraph/SinkI24.h"
+#include "flowgraph/SinkI32.h"
+#include "flowgraph/SourceFloat.h"
+#include "flowgraph/SourceI16.h"
+#include "flowgraph/SourceI24.h"
+#include "flowgraph/SourceI32.h"
+
+/**
+ * Use flowgraph modules to convert between the various data formats.
+ *
+ * Note that this does not do channel conversions.
+ */
+
+class FormatConverterBox {
+public:
+    FormatConverterBox(int32_t numSamples,
+                       oboe::AudioFormat inputFormat,
+                       oboe::AudioFormat outputFormat);
+
+    /**
+     * @return internal buffer used to store input data
+     */
+    void *getOutputBuffer() {
+        return (void *) mOutputBuffer.get();
+    };
+    /**
+     * @return internal buffer used to store output data
+     */
+    void *getInputBuffer() {
+        return (void *) mInputBuffer.get();
+    };
+
+    /** Convert the data from inputFormat to outputFormat
+     * using both internal buffers.
+     */
+    int32_t convertInternalBuffers(int32_t numSamples);
+
+    /**
+     * Convert data from external buffer into internal output buffer.
+     * @param numSamples
+     * @param inputBuffer
+     * @return
+     */
+    int32_t convertToInternalOutput(int32_t numSamples, const void *inputBuffer);
+
+    /**
+     *
+     * Convert data from internal input buffer into external output buffer.
+     * @param outputBuffer
+     * @param numSamples
+     * @return
+     */
+    int32_t convertFromInternalInput(void *outputBuffer, int32_t numSamples);
+
+    /**
+     * Convert data formats between the specified external buffers.
+     * @param outputBuffer
+     * @param numSamples
+     * @param inputBuffer
+     * @return
+     */
+    int32_t convert(void *outputBuffer, int32_t numSamples, const void *inputBuffer);
+
+private:
+    oboe::AudioFormat mInputFormat{oboe::AudioFormat::Invalid};
+    oboe::AudioFormat mOutputFormat{oboe::AudioFormat::Invalid};
+
+    std::unique_ptr<uint8_t[]> mInputBuffer;
+    std::unique_ptr<uint8_t[]> mOutputBuffer;
+
+    std::unique_ptr<oboe::flowgraph::FlowGraphSourceBuffered>  mSource;
+    std::unique_ptr<oboe::flowgraph::FlowGraphSink>  mSink;
+};
+
+
+#endif //OBOETESTER_FORMAT_CONVERTER_BOX_H
diff --git a/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.cpp b/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.cpp
index 2da2dfd..58252f5 100644
--- a/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.cpp
+++ b/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.cpp
@@ -20,19 +20,27 @@
 oboe::Result  FullDuplexAnalyzer::start() {
     getLoopbackProcessor()->setSampleRate(getOutputStream()->getSampleRate());
     getLoopbackProcessor()->prepareToTest();
+    mWriteReadDeltaValid = false;
     return FullDuplexStream::start();
 }
 
 oboe::DataCallbackResult FullDuplexAnalyzer::onBothStreamsReady(
-        const void *inputData,
+        const float *inputData,
         int   numInputFrames,
-        void *outputData,
+        float *outputData,
         int   numOutputFrames) {
 
     int32_t inputStride = getInputStream()->getChannelCount();
     int32_t outputStride = getOutputStream()->getChannelCount();
-    float *inputFloat = (float *) inputData;
-    float *outputFloat = (float *) outputData;
+    const float *inputFloat = inputData;
+    float *outputFloat = outputData;
+
+    // Get atomic snapshot of the relative frame positions so they
+    // can be used to calculate timestamp latency.
+    int64_t framesRead = getInputStream()->getFramesRead();
+    int64_t framesWritten = getOutputStream()->getFramesWritten();
+    mWriteReadDelta = framesWritten - framesRead;
+    mWriteReadDeltaValid = true;
 
     (void) getLoopbackProcessor()->process(inputFloat, inputStride, numInputFrames,
                                    outputFloat, outputStride, numOutputFrames);
diff --git a/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.h b/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.h
index 0227130..0473d3d 100644
--- a/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.h
+++ b/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.h
@@ -37,9 +37,9 @@
      * Caller should override this method.
      */
     oboe::DataCallbackResult onBothStreamsReady(
-            const void *inputData,
+            const float *inputData,
             int   numInputFrames,
-            void *outputData,
+            float *outputData,
             int   numOutputFrames
     ) override;
 
@@ -53,10 +53,21 @@
         mRecording = recording;
     }
 
+    bool isWriteReadDeltaValid() {
+        return mWriteReadDeltaValid;
+    }
+
+    int64_t getWriteReadDelta() {
+        return mWriteReadDelta;
+    }
+
 private:
     MultiChannelRecording  *mRecording = nullptr;
 
     LoopbackProcessor * const mLoopbackProcessor;
+
+    std::atomic<bool> mWriteReadDeltaValid{false};
+    std::atomic<int64_t> mWriteReadDelta{0};
 };
 
 
diff --git a/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.cpp b/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.cpp
index 0da2d00..9153024 100644
--- a/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.cpp
+++ b/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.cpp
@@ -24,18 +24,16 @@
 }
 
 oboe::DataCallbackResult FullDuplexEcho::onBothStreamsReady(
-        const void *inputData,
+        const float *inputData,
         int   numInputFrames,
-        void *outputData,
+        float *outputData,
         int   numOutputFrames) {
-    // FIXME only handles matching stream formats.
-    // TODO Add delay node
-    // TODO use flowgraph to handle format conversion
     int32_t framesToEcho = std::min(numInputFrames, numOutputFrames);
     float *inputFloat = (float *)inputData;
     float *outputFloat = (float *)outputData;
     // zero out entire output array
-    memset(outputFloat, 0, numOutputFrames * getOutputStream()->getBytesPerFrame());
+    memset(outputFloat, 0, static_cast<size_t>(numOutputFrames)
+            * static_cast<size_t>(getOutputStream()->getBytesPerFrame()));
 
     int32_t inputStride = getInputStream()->getChannelCount();
     int32_t outputStride = getOutputStream()->getChannelCount();
diff --git a/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.h b/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.h
index 47f7d5f..cbb69d7 100644
--- a/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.h
+++ b/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.h
@@ -35,9 +35,9 @@
      * Caller should override this method.
      */
     oboe::DataCallbackResult onBothStreamsReady(
-            const void *inputData,
+            const float *inputData,
             int   numInputFrames,
-            void *outputData,
+            float *outputData,
             int   numOutputFrames
     ) override;
 
diff --git a/apps/OboeTester/app/src/main/cpp/FullDuplexStream.cpp b/apps/OboeTester/app/src/main/cpp/FullDuplexStream.cpp
index af233aa..52e762e 100644
--- a/apps/OboeTester/app/src/main/cpp/FullDuplexStream.cpp
+++ b/apps/OboeTester/app/src/main/cpp/FullDuplexStream.cpp
@@ -17,6 +17,18 @@
 #include "common/OboeDebug.h"
 #include "FullDuplexStream.h"
 
+oboe::ResultWithValue<int32_t>  FullDuplexStream::readInput(int32_t numFrames) {
+    oboe::ResultWithValue<int32_t> result = getInputStream()->read(
+            mInputConverter->getInputBuffer(),
+            numFrames,
+            0 /* timeout */);
+    if (result == oboe::Result::OK) {
+        int32_t numSamples = result.value() * getInputStream()->getChannelCount();
+        mInputConverter->convertInternalBuffers(numSamples);
+    }
+    return result;
+}
+
 oboe::DataCallbackResult FullDuplexStream::onAudioReady(
         oboe::AudioStream *outputStream,
         void *audioData,
@@ -32,9 +44,7 @@
         // Drain the input.
         int32_t totalFramesRead = 0;
         do {
-            oboe::ResultWithValue<int32_t> result = getInputStream()->read(mInputBuffer.get(),
-                                                                           numFrames,
-                                                                           0 /* timeout */);
+            oboe::ResultWithValue<int32_t> result = readInput(numFrames);
             if (!result) {
                 // Ignore errors because input stream may not be started yet.
                 break;
@@ -62,7 +72,7 @@
         } else {
             int32_t framesAvailable = resultAvailable.value();
             if (framesAvailable >= mMinimumFramesBeforeRead) {
-                oboe::ResultWithValue<int32_t> resultRead = getInputStream()->read(mInputBuffer.get(), numFrames, 0 /* timeout */);
+                oboe::ResultWithValue<int32_t> resultRead = readInput(numFrames);
                 if (!resultRead) {
                     LOGE("%s() read() returned %s\n", __func__, convertToText(resultRead.error()));
                     callbackResult = oboe::DataCallbackResult::Stop;
@@ -79,7 +89,7 @@
             int32_t framesAvailable = resultAvailable.value();
             if (framesAvailable >= mMinimumFramesBeforeRead) {
                 // Read data into input buffer.
-                oboe::ResultWithValue<int32_t> resultRead  = getInputStream()->read(mInputBuffer.get(), numFrames, 0 /* timeout */);
+                oboe::ResultWithValue<int32_t> resultRead = readInput(numFrames);
                 if (!resultRead) {
                     LOGE("%s() read() returned %s\n", __func__, convertToText(resultRead.error()));
                     callbackResult = oboe::DataCallbackResult::Stop;
@@ -91,9 +101,11 @@
 
         if (callbackResult == oboe::DataCallbackResult::Continue) {
             callbackResult = onBothStreamsReady(
-                    mInputBuffer.get(), framesRead,
-                    audioData, numFrames);
-
+                    (const float *) mInputConverter->getOutputBuffer(),
+                    framesRead,
+                    (float *) mOutputConverter->getInputBuffer(), numFrames);
+            mOutputConverter->convertFromInternalInput( audioData,
+                                       numFrames * getOutputStream()->getChannelCount());
         }
     }
 
@@ -112,10 +124,13 @@
     // Determine maximum size that could possibly be called.
     int32_t bufferSize = getOutputStream()->getBufferCapacityInFrames()
             * getOutputStream()->getChannelCount();
-    if (bufferSize > mBufferSize) {
-        mInputBuffer = std::make_unique<float[]>(bufferSize);
-        mBufferSize = bufferSize;
-    }
+    mInputConverter = std::make_unique<FormatConverterBox>(bufferSize,
+            getInputStream()->getFormat(),
+            oboe::AudioFormat::Float);
+    mOutputConverter = std::make_unique<FormatConverterBox>(bufferSize,
+            oboe::AudioFormat::Float,
+            getOutputStream()->getFormat());
+
     oboe::Result result = getInputStream()->requestStart();
     if (result != oboe::Result::OK) {
         return result;
diff --git a/apps/OboeTester/app/src/main/cpp/FullDuplexStream.h b/apps/OboeTester/app/src/main/cpp/FullDuplexStream.h
index ccb5217..dcfb6ea 100644
--- a/apps/OboeTester/app/src/main/cpp/FullDuplexStream.h
+++ b/apps/OboeTester/app/src/main/cpp/FullDuplexStream.h
@@ -22,6 +22,8 @@
 
 #include "oboe/Oboe.h"
 
+#include "FormatConverterBox.h"
+
 class FullDuplexStream : public oboe::AudioStreamCallback {
 public:
     FullDuplexStream() {}
@@ -46,14 +48,16 @@
 
     virtual oboe::Result stop();
 
+    oboe::ResultWithValue<int32_t>  readInput(int32_t numFrames);
+
     /**
      * Called when data is available on both streams.
      * Caller should override this method.
      */
     virtual oboe::DataCallbackResult onBothStreamsReady(
-            const void *inputData,
+            const float *inputData,
             int   numInputFrames,
-            void *outputData,
+            float *outputData,
             int   numOutputFrames
             ) = 0;
 
@@ -107,8 +111,8 @@
     oboe::AudioStream   *mInputStream = nullptr;
     oboe::AudioStream   *mOutputStream = nullptr;
 
-    int32_t              mBufferSize = 0;
-    std::unique_ptr<float[]> mInputBuffer;
+    std::unique_ptr<FormatConverterBox> mInputConverter;
+    std::unique_ptr<FormatConverterBox> mOutputConverter;
 };
 
 
diff --git a/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.cpp b/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.cpp
index f9290e1..6ac3759 100644
--- a/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.cpp
+++ b/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.cpp
@@ -17,39 +17,33 @@
 #include "common/OboeDebug.h"
 #include "InputStreamCallbackAnalyzer.h"
 
+double InputStreamCallbackAnalyzer::getPeakLevel(int index) {
+    if (mPeakDetectors == nullptr) {
+        LOGE("%s() called before setup()", __func__);
+        return -1.0;
+    } else if (index < 0 || index >= mNumChannels) {
+        LOGE("%s(), index out of range, 0 <= %d < %d", __func__, index, mNumChannels);
+        return -2.0;
+    }
+    return mPeakDetectors[index].getLevel();
+}
+
 oboe::DataCallbackResult InputStreamCallbackAnalyzer::onAudioReady(
         oboe::AudioStream *audioStream,
         void *audioData,
         int numFrames) {
     int32_t channelCount = audioStream->getChannelCount();
-
     printScheduler();
-
-    if (audioStream->getFormat() == oboe::AudioFormat::I16) {
-        int16_t *shortData = (int16_t *) audioData;
-        if (mRecording != nullptr) {
-            mRecording->write(shortData, numFrames);
-        }
-        int16_t *frameData = shortData;
-        for (int iFrame = 0; iFrame < numFrames; iFrame++) {
-            for (int iChannel = 0; iChannel < channelCount; iChannel++) {
-                float sample = frameData[iChannel] / 32768.0f;
-                mPeakDetectors[iChannel].process(sample);
-            }
-            frameData += channelCount;
-        }
-    } else if (audioStream->getFormat() == oboe::AudioFormat::Float) {
-        float *floatData = (float *) audioData;
-        if (mRecording != nullptr) {
-            mRecording->write(floatData, numFrames);
-        }
-        float *frameData = floatData;
-        for (int iFrame = 0; iFrame < numFrames; iFrame++) {
-            for (int iChannel = 0; iChannel < channelCount; iChannel++) {
-                float sample = frameData[iChannel];
-                mPeakDetectors[iChannel].process(sample);
-            }
-            frameData += channelCount;
+    mInputConverter->convertToInternalOutput(numFrames * channelCount, audioData);
+    float *floatData = (float *) mInputConverter->getOutputBuffer();
+    if (mRecording != nullptr) {
+        mRecording->write(floatData, numFrames);
+    }
+    int32_t sampleIndex = 0;
+    for (int iFrame = 0; iFrame < numFrames; iFrame++) {
+        for (int iChannel = 0; iChannel < channelCount; iChannel++) {
+            float sample = floatData[sampleIndex++];
+            mPeakDetectors[iChannel].process(sample);
         }
     }
 
diff --git a/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.h b/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.h
index fc26b1f..07c4f97 100644
--- a/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.h
+++ b/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.h
@@ -23,22 +23,33 @@
 
 // TODO #include "flowgraph/FlowGraph.h"
 #include "oboe/Oboe.h"
+
+#include "analyzer/PeakDetector.h"
+#include "FormatConverterBox.h"
 #include "MultiChannelRecording.h"
 #include "OboeTesterStreamCallback.h"
-#include "analyzer/PeakDetector.h"
-
-constexpr int kMaxInputChannels = 8;
 
 class InputStreamCallbackAnalyzer : public OboeTesterStreamCallback {
 public:
 
     void reset() {
-        for (auto detector : mPeakDetectors) {
-            detector.reset();
+        for (int iChannel = 0; iChannel < mNumChannels; iChannel++) {
+            mPeakDetectors[iChannel].reset();
         }
         OboeTesterStreamCallback::reset();
     }
 
+    void setup(int32_t maxFramesPerCallback,
+               int32_t channelCount,
+               oboe::AudioFormat inputFormat) {
+        mNumChannels = channelCount;
+        mPeakDetectors = std::make_unique<PeakDetector[]>(channelCount);
+        int32_t bufferSize = maxFramesPerCallback * channelCount;
+        mInputConverter = std::make_unique<FormatConverterBox>(bufferSize,
+                                                               inputFormat,
+                                                               oboe::AudioFormat::Float);
+    }
+
     /**
      * Called by Oboe when the stream is ready to process audio.
      */
@@ -51,9 +62,7 @@
         mRecording = recording;
     }
 
-    double getPeakLevel(int index) {
-        return mPeakDetectors[index].getLevel();
-    }
+    double getPeakLevel(int index);
 
     void setMinimumFramesBeforeRead(int32_t numFrames) {
         mMinimumFramesBeforeRead = numFrames;
@@ -64,11 +73,13 @@
     }
 
 public:
-    PeakDetector            mPeakDetectors[kMaxInputChannels];
-    MultiChannelRecording  *mRecording = nullptr;
+    int32_t                         mNumChannels = 0;
+    std::unique_ptr<PeakDetector[]> mPeakDetectors;
+    MultiChannelRecording          *mRecording = nullptr;
 
 private:
-    int32_t                 mMinimumFramesBeforeRead = 0;
+    std::unique_ptr<FormatConverterBox> mInputConverter;
+    int32_t                             mMinimumFramesBeforeRead = 0;
 };
 
 #endif //NATIVEOBOE_INPUTSTREAMCALLBACKANALYZER_H
diff --git a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp
index c95e093..5e327fd 100644
--- a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp
+++ b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp
@@ -14,11 +14,21 @@
  * limitations under the License.
  */
 
+// Set to 1 for debugging race condition #1180 with mAAudioStream.
+// See also AudioStreamAAudio.cpp in Oboe.
+// This was left in the code so that we could test the fix again easily in the future.
+// We could not trigger the race condition without adding these get calls and the sleeps.
+#define DEBUG_CLOSE_RACE 0
+
 #include <fstream>
 #include <iostream>
+#if DEBUG_CLOSE_RACE
+#include <thread>
+#endif // DEBUG_CLOSE_RACE
 #include <vector>
 #include <common/AudioClock.h>
 
+#include <common/AudioClock.h>
 #include "util/WaveFileWriter.h"
 
 #include "NativeAudioContext.h"
@@ -129,23 +139,22 @@
 void ActivityContext::configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) {
     // We needed the proxy because we did not know the channelCount when we setup the Builder.
     if (mUseCallback) {
-        LOGD("ActivityContext::open() set callback to use oboeCallbackProxy, callback size = %d",
-             callbackSize);
         builder.setDataCallback(&oboeCallbackProxy);
-        builder.setFramesPerCallback(callbackSize);
     }
 }
 
 int ActivityContext::open(jint nativeApi,
                           jint sampleRate,
                           jint channelCount,
+                          jint channelMask,
                           jint format,
                           jint sharingMode,
                           jint performanceMode,
                           jint inputPreset,
+                          jint usage,
+                          jint contentType,
                           jint deviceId,
                           jint sessionId,
-                          jint framesPerBurst,
                           jboolean channelConversionAllowed,
                           jboolean formatConversionAllowed,
                           jint rateConversionQuality,
@@ -181,6 +190,8 @@
             ->setSharingMode((oboe::SharingMode) sharingMode)
             ->setPerformanceMode((oboe::PerformanceMode) performanceMode)
             ->setInputPreset((oboe::InputPreset)inputPreset)
+            ->setUsage((oboe::Usage)usage)
+            ->setContentType((oboe::ContentType)contentType)
             ->setDeviceId(deviceId)
             ->setSessionId((oboe::SessionId) sessionId)
             ->setSampleRate(sampleRate)
@@ -189,7 +200,13 @@
             ->setFormatConversionAllowed(formatConversionAllowed)
             ->setSampleRateConversionQuality((oboe::SampleRateConversionQuality) rateConversionQuality)
             ;
-
+    if (channelMask != (jint) oboe::ChannelMask::Unspecified) {
+        // Set channel mask when it is specified.
+        builder.setChannelMask((oboe::ChannelMask) channelMask);
+    }
+    if (mUseCallback) {
+        builder.setFramesPerCallback(callbackSize);
+    }
     configureBuilder(isInput, builder);
 
     builder.setAudioApi(audioApi);
@@ -251,6 +268,20 @@
         dataThread = new std::thread(threadCallback, this);
     }
 
+#if DEBUG_CLOSE_RACE
+    // Also put a sleep for 400 msec in AudioStreamAAudio::updateFramesRead().
+    if (outputStream != nullptr) {
+        std::thread raceDebugger([outputStream]() {
+            while (outputStream->getState() != StreamState::Closed) {
+                int64_t framesRead = outputStream->getFramesRead();
+                LOGD("raceDebugger, framesRead = %d, state = %d",
+                     (int) framesRead, (int) outputStream->getState());
+            }
+        });
+        raceDebugger.detach();
+    }
+#endif // DEBUG_CLOSE_RACE
+
     return result;
 }
 
@@ -305,6 +336,8 @@
     monoToMulti.reset(nullptr);
     mSinkFloat.reset();
     mSinkI16.reset();
+    mSinkI24.reset();
+    mSinkI32.reset();
 }
 
 void ActivityTestOutput::setChannelEnabled(int channelIndex, bool enabled) {
@@ -328,6 +361,9 @@
                 mExponentialShape.output.connect(&sineOscillators[channelIndex].frequency);
                 sineOscillators[channelIndex].output.connect(manyToMulti->inputs[channelIndex].get());
                 break;
+            case SignalType::WhiteNoise:
+                mWhiteNoise.output.connect(manyToMulti->inputs[channelIndex].get());
+                break;
             default:
                 break;
         }
@@ -339,8 +375,10 @@
 void ActivityTestOutput::configureForStart() {
     manyToMulti = std::make_unique<ManyToMultiConverter>(mChannelCount);
 
-    mSinkFloat = std::make_unique<SinkFloat>(mChannelCount);
-    mSinkI16 = std::make_unique<SinkI16>(mChannelCount);
+    mSinkFloat = std::make_shared<SinkFloat>(mChannelCount);
+    mSinkI16 = std::make_shared<SinkI16>(mChannelCount);
+    mSinkI24 = std::make_shared<SinkI24>(mChannelCount);
+    mSinkI32 = std::make_shared<SinkI32>(mChannelCount);
 
     std::shared_ptr<oboe::AudioStream> outputStream = getOutputStream();
 
@@ -362,17 +400,27 @@
         for (int i = 0; i < mChannelCount; i++) {
             sineOscillators[i].setSampleRate(outputStream->getSampleRate());
             sineOscillators[i].frequency.setValue(frequency);
-            frequency *= 4.0 / 3.0; // each sine is at a higher frequency
             sineOscillators[i].amplitude.setValue(AMPLITUDE_SINE);
+            sawtoothOscillators[i].setSampleRate(outputStream->getSampleRate());
+            sawtoothOscillators[i].frequency.setValue(frequency);
+            sawtoothOscillators[i].amplitude.setValue(AMPLITUDE_SAWTOOTH);
+
+            frequency *= 4.0 / 3.0; // each wave is at a higher frequency
             setChannelEnabled(i, true);
         }
     }
 
+    mWhiteNoise.amplitude.setValue(0.5);
+
     manyToMulti->output.connect(&(mSinkFloat.get()->input));
     manyToMulti->output.connect(&(mSinkI16.get()->input));
+    manyToMulti->output.connect(&(mSinkI24.get()->input));
+    manyToMulti->output.connect(&(mSinkI32.get()->input));
 
     mSinkFloat->pullReset();
     mSinkI16->pullReset();
+    mSinkI24->pullReset();
+    mSinkI32->pullReset();
 
     configureStreamGateway();
 }
@@ -381,6 +429,10 @@
     std::shared_ptr<oboe::AudioStream> outputStream = getOutputStream();
     if (outputStream->getFormat() == oboe::AudioFormat::I16) {
         audioStreamGateway.setAudioSink(mSinkI16);
+    } else if (outputStream->getFormat() == oboe::AudioFormat::I24) {
+        audioStreamGateway.setAudioSink(mSinkI24);
+    } else if (outputStream->getFormat() == oboe::AudioFormat::I32) {
+        audioStreamGateway.setAudioSink(mSinkI32);
     } else if (outputStream->getFormat() == oboe::AudioFormat::Float) {
         audioStreamGateway.setAudioSink(mSinkFloat);
     }
@@ -488,8 +540,7 @@
     builder.setChannelCount(mChannelCount)
             ->setSampleRate(mSampleRate)
             ->setFormat(oboe::AudioFormat::Float)
-            ->setCallback(&mPlayRecordingCallback)
-            ->setAudioApi(oboe::AudioApi::OpenSLES);
+            ->setCallback(&mPlayRecordingCallback);
     oboe::Result result = builder.openStream(&playbackStream);
     if (result != oboe::Result::OK) {
         delete playbackStream;
@@ -508,8 +559,10 @@
 void ActivityTapToTone::configureForStart() {
     monoToMulti = std::make_unique<MonoToMultiConverter>(mChannelCount);
 
-    mSinkFloat = std::make_unique<SinkFloat>(mChannelCount);
-    mSinkI16 = std::make_unique<SinkI16>(mChannelCount);
+    mSinkFloat = std::make_shared<SinkFloat>(mChannelCount);
+    mSinkI16 = std::make_shared<SinkI16>(mChannelCount);
+    mSinkI24 = std::make_shared<SinkI24>(mChannelCount);
+    mSinkI32 = std::make_shared<SinkI32>(mChannelCount);
 
     std::shared_ptr<oboe::AudioStream> outputStream = getOutputStream();
     sawPingGenerator.setSampleRate(outputStream->getSampleRate());
@@ -519,22 +572,26 @@
     sawPingGenerator.output.connect(&(monoToMulti->input));
     monoToMulti->output.connect(&(mSinkFloat.get()->input));
     monoToMulti->output.connect(&(mSinkI16.get()->input));
+    monoToMulti->output.connect(&(mSinkI24.get()->input));
+    monoToMulti->output.connect(&(mSinkI32.get()->input));
 
     mSinkFloat->pullReset();
     mSinkI16->pullReset();
+    mSinkI24->pullReset();
+    mSinkI32->pullReset();
 
     configureStreamGateway();
 }
 
-// ======================================================================= ActivityRoundTripLatency
+// ======================================================================= ActivityFullDuplex
 void ActivityFullDuplex::configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) {
     if (isInput) {
         // Ideally the output streams should be opened first.
         std::shared_ptr<oboe::AudioStream> outputStream = getOutputStream();
         if (outputStream != nullptr) {
-            // Make sure the capacity is bigger than two bursts.
-            int32_t burst = outputStream->getFramesPerBurst();
-            builder.setBufferCapacityInFrames(2 * burst);
+            // The input and output buffers will run in sync with input empty
+            // and output full. So set the input capacity to match the output.
+            builder.setBufferCapacityInFrames(outputStream->getBufferCapacityInFrames());
         }
     }
 }
@@ -548,7 +605,8 @@
     }
     // only output uses a callback, input is polled
     if (!isInput) {
-        builder.setCallback(mFullDuplexEcho.get());
+        builder.setCallback((oboe::AudioStreamCallback *) &oboeCallbackProxy);
+        oboeCallbackProxy.setCallback(mFullDuplexEcho.get());
     }
 }
 
@@ -565,11 +623,12 @@
     ActivityFullDuplex::configureBuilder(isInput, builder);
 
     if (mFullDuplexLatency.get() == nullptr) {
-        mFullDuplexLatency = std::make_unique<FullDuplexAnalyzer>(&mEchoAnalyzer);
+        mFullDuplexLatency = std::make_unique<FullDuplexAnalyzer>(mLatencyAnalyzer.get());
     }
     if (!isInput) {
         // only output uses a callback, input is polled
-        builder.setCallback(mFullDuplexLatency.get());
+        builder.setCallback((oboe::AudioStreamCallback *) &oboeCallbackProxy);
+        oboeCallbackProxy.setCallback(mFullDuplexLatency.get());
     }
 }
 
@@ -582,6 +641,38 @@
     }
 }
 
+// The timestamp latency is the difference between the input
+// and output times for a specific frame.
+// Start with the position and time from an input timestamp.
+// Map the input position to the corresponding position in output
+// and calculate its time.
+// Use the difference between framesWritten and framesRead to
+// convert input positions to output positions.
+jdouble ActivityRoundTripLatency::measureTimestampLatency() {
+    if (!mFullDuplexLatency->isWriteReadDeltaValid()) return -1.0;
+
+    int64_t writeReadDelta = mFullDuplexLatency->getWriteReadDelta();
+    auto inputTimestampResult = mFullDuplexLatency->getInputStream()->getTimestamp(CLOCK_MONOTONIC);
+    if (!inputTimestampResult) return -1.0;
+    auto outputTimestampResult = mFullDuplexLatency->getOutputStream()->getTimestamp(CLOCK_MONOTONIC);
+    if (!outputTimestampResult) return -1.0;
+
+    int64_t inputPosition = inputTimestampResult.value().position;
+    int64_t inputTimeNanos = inputTimestampResult.value().timestamp;
+    int64_t ouputPosition = outputTimestampResult.value().position;
+    int64_t outputTimeNanos = outputTimestampResult.value().timestamp;
+
+    // Map input frame position to the corresponding output frame.
+    int64_t mappedPosition = inputPosition + writeReadDelta;
+    // Calculate when that frame will play.
+    int32_t sampleRate = mFullDuplexLatency->getOutputStream()->getSampleRate();
+    int64_t mappedTimeNanos = outputTimeNanos + ((mappedPosition - ouputPosition) * 1e9) / sampleRate;
+
+    // Latency is the difference in time between when a frame was recorded and
+    // when its corresponding echo was played.
+    return (mappedTimeNanos - inputTimeNanos) * 1.0e-6; // convert nanos to millis
+}
+
 // ======================================================================= ActivityGlitches
 void ActivityGlitches::configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) {
     ActivityFullDuplex::configureBuilder(isInput, builder);
@@ -591,7 +682,8 @@
     }
     if (!isInput) {
         // only output uses a callback, input is polled
-        builder.setCallback(mFullDuplexGlitches.get());
+        builder.setCallback((oboe::AudioStreamCallback *) &oboeCallbackProxy);
+        oboeCallbackProxy.setCallback(mFullDuplexGlitches.get());
     }
 }
 
@@ -613,7 +705,8 @@
     }
     if (!isInput) {
         // only output uses a callback, input is polled
-        builder.setCallback(mFullDuplexDataPath.get());
+        builder.setCallback((oboe::AudioStreamCallback *) &oboeCallbackProxy);
+        oboeCallbackProxy.setCallback(mFullDuplexDataPath.get());
     }
 }
 
diff --git a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h
index 85735a4..9ffd36e 100644
--- a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h
+++ b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h
@@ -34,11 +34,14 @@
 #include "flowgraph/MonoToMultiConverter.h"
 #include "flowgraph/SinkFloat.h"
 #include "flowgraph/SinkI16.h"
+#include "flowgraph/SinkI24.h"
+#include "flowgraph/SinkI32.h"
 #include "flowunits/ExponentialShape.h"
 #include "flowunits/LinearShape.h"
 #include "flowunits/SineOscillator.h"
 #include "flowunits/SawtoothOscillator.h"
 #include "flowunits/TriangleOscillator.h"
+#include "flowunits/WhiteNoise.h"
 
 #include "FullDuplexAnalyzer.h"
 #include "FullDuplexEcho.h"
@@ -56,7 +59,7 @@
 #define NATIVE_MODE_OPENSLES     1
 #define NATIVE_MODE_AAUDIO       2
 
-#define MAX_SINE_OSCILLATORS     8
+#define MAX_SINE_OSCILLATORS     16
 #define AMPLITUDE_SINE           1.0
 #define AMPLITUDE_SAWTOOTH       0.5
 #define FREQUENCY_SAW_PING       800.0
@@ -95,6 +98,7 @@
      * @param nativeApi
      * @param sampleRate
      * @param channelCount
+     * @param channelMask
      * @param format
      * @param sharingMode
      * @param performanceMode
@@ -112,13 +116,15 @@
     int open(jint nativeApi,
              jint sampleRate,
              jint channelCount,
+             jint channelMask,
              jint format,
              jint sharingMode,
              jint performanceMode,
              jint inputPreset,
+             jint usage,
+             jint contentType,
              jint deviceId,
              jint sessionId,
-             jint framesPerBurst,
              jboolean channelConversionAllowed,
              jboolean formatConversionAllowed,
              jint rateConversionQuality,
@@ -143,6 +149,10 @@
         return oboeCallbackProxy.getCpuLoad();
     }
 
+    std::string getCallbackTimeString() {
+        return oboeCallbackProxy.getCallbackTimeString();
+    }
+
     void setWorkload(double workload) {
         oboeCallbackProxy.setWorkload(workload);
     }
@@ -298,7 +308,7 @@
     int32_t                      mSampleRate = 0; // TODO per stream
 
     std::atomic<bool>            threadEnabled{false};
-    std::thread                 *dataThread = nullptr;
+    std::thread                 *dataThread = nullptr; // FIXME never gets deleted
 
 private:
     int64_t mInputOpenedAt = 0;
@@ -322,8 +332,6 @@
 
     void runBlockingIO() override;
 
-    InputStreamCallbackAnalyzer  mInputAnalyzer;
-
     void setMinimumFramesBeforeRead(int32_t numFrames) override {
         mInputAnalyzer.setMinimumFramesBeforeRead(numFrames);
         mMinimumFramesBeforeRead = numFrames;
@@ -337,9 +345,13 @@
 
     oboe::Result startStreams() override {
         mInputAnalyzer.reset();
+        mInputAnalyzer.setup(getInputStream()->getFramesPerBurst(),
+                             getInputStream()->getChannelCount(),
+                             getInputStream()->getFormat());
         return getInputStream()->requestStart();
     }
 
+    InputStreamCallbackAnalyzer  mInputAnalyzer;
     int32_t mMinimumFramesBeforeRead = 0;
 };
 
@@ -414,15 +426,18 @@
     std::vector<SawtoothOscillator>  sawtoothOscillators;
     static constexpr float           kSweepPeriod = 10.0; // for triangle up and down
 
-    // A triangle LFO is shaped into either a linear or an exponential range.
+    // A triangle LFO is shaped into either a linear or an exponential range for sweep.
     TriangleOscillator               mTriangleOscillator;
     LinearShape                      mLinearShape;
     ExponentialShape                 mExponentialShape;
+    class WhiteNoise                 mWhiteNoise;
 
     std::unique_ptr<ManyToMultiConverter>   manyToMulti;
     std::unique_ptr<MonoToMultiConverter>   monoToMulti;
     std::shared_ptr<oboe::flowgraph::SinkFloat>   mSinkFloat;
     std::shared_ptr<oboe::flowgraph::SinkI16>     mSinkI16;
+    std::shared_ptr<oboe::flowgraph::SinkI24>     mSinkI24;
+    std::shared_ptr<oboe::flowgraph::SinkI32>     mSinkI32;
 };
 
 /**
@@ -506,6 +521,18 @@
  */
 class ActivityRoundTripLatency : public ActivityFullDuplex {
 public:
+    ActivityRoundTripLatency() {
+#define USE_WHITE_NOISE_ANALYZER 1
+#if USE_WHITE_NOISE_ANALYZER
+        // New analyzer that uses a short pattern of white noise bursts.
+        mLatencyAnalyzer = std::make_unique<WhiteNoiseLatencyAnalyzer>();
+#else
+        // Old analyzer based on encoded random bits.
+        mLatencyAnalyzer = std::make_unique<EncodedRandomLatencyAnalyzer>();
+#endif
+        mLatencyAnalyzer->setup();
+    }
+    virtual ~ActivityRoundTripLatency() = default;
 
     oboe::Result startStreams() override {
         mAnalyzerLaunched = false;
@@ -515,7 +542,7 @@
     void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override;
 
     LatencyAnalyzer *getLatencyAnalyzer() {
-        return &mEchoAnalyzer;
+        return mLatencyAnalyzer.get();
     }
 
     int32_t getState() override {
@@ -530,36 +557,38 @@
         if (!mAnalyzerLaunched) {
             mAnalyzerLaunched = launchAnalysisIfReady();
         }
-        return mEchoAnalyzer.isDone();
+        return mLatencyAnalyzer->isDone();
     }
 
     FullDuplexAnalyzer *getFullDuplexAnalyzer() override {
         return (FullDuplexAnalyzer *) mFullDuplexLatency.get();
     }
 
-    static void analyzeData(PulseLatencyAnalyzer *analyzer) {
+    static void analyzeData(LatencyAnalyzer *analyzer) {
         analyzer->analyze();
     }
 
     bool launchAnalysisIfReady() {
         // Are we ready to do the analysis?
-        if (mEchoAnalyzer.hasEnoughData()) {
+        if (mLatencyAnalyzer->hasEnoughData()) {
             // Crunch the numbers on a separate thread.
-            std::thread t(analyzeData, &mEchoAnalyzer);
+            std::thread t(analyzeData, mLatencyAnalyzer.get());
             t.detach();
             return true;
         }
         return false;
     }
 
+    jdouble measureTimestampLatency();
+
 protected:
     void finishOpen(bool isInput, oboe::AudioStream *oboeStream) override;
 
 private:
     std::unique_ptr<FullDuplexAnalyzer>   mFullDuplexLatency{};
 
-    PulseLatencyAnalyzer  mEchoAnalyzer;
-    bool                  mAnalyzerLaunched = false;
+    std::unique_ptr<LatencyAnalyzer>  mLatencyAnalyzer;
+    bool                              mAnalyzerLaunched = false;
 };
 
 /**
diff --git a/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp b/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp
index 14f8234..987a1d3 100644
--- a/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp
+++ b/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp
@@ -77,5 +77,12 @@
     double currentCpuLoad = calculationTime * inverseRealTime; // avoid a divide
     mCpuLoad = (mCpuLoad * 0.95) + (currentCpuLoad * 0.05); // simple low pass filter
 
+    int64_t currentTimeNs = getNanoseconds();
+
+    if (mPreviousCallbackTimeNs != 0) {
+        mStatistics.add((currentTimeNs - mPreviousCallbackTimeNs) * kNsToMsScaler);
+    }
+    mPreviousCallbackTimeNs = currentTimeNs;
+
     return callbackResult;
 }
diff --git a/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.h b/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.h
index 9bfeaca..3d1c897 100644
--- a/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.h
+++ b/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.h
@@ -22,12 +22,55 @@
 
 #include "oboe/Oboe.h"
 
-class OboeStreamCallbackProxy : public oboe::AudioStreamDataCallback {
+class DoubleStatistics {
 public:
+    void add(double statistic) {
+        if (skipCount < kNumberStatisticsToSkip) {
+            skipCount++;
+        } else {
+            if (statistic <= 0.0) return;
+            sum = statistic + sum;
+            count++;
+            minimum = std::min(statistic, minimum.load());
+            maximum = std::max(statistic, maximum.load());
+        }
+    }
 
+    double getAverage() const {
+        return sum / count;
+    }
+
+    std::string dump() const {
+        if (count == 0) return "?";
+        char buff[100];
+        snprintf(buff, sizeof(buff), "%3.1f/%3.1f/%3.1f ms", minimum.load(), getAverage(), maximum.load());
+        std::string buffAsStr = buff;
+        return buffAsStr;
+    }
+
+    void clear() {
+        skipCount = 0;
+        sum = 0;
+        count = 0;
+        minimum = DBL_MAX;
+        maximum = 0;
+    }
+
+private:
+    static constexpr double kNumberStatisticsToSkip = 5; // Skip the first 5 frames
+    std::atomic<int> skipCount { 0 };
+    std::atomic<double> sum { 0 };
+    std::atomic<int> count { 0 };
+    std::atomic<double> minimum { DBL_MAX };
+    std::atomic<double> maximum { 0 };
+};
+
+class OboeStreamCallbackProxy : public oboe::AudioStreamCallback {
+public:
     void setCallback(oboe::AudioStreamCallback *callback) {
         mCallback = callback;
         setCallbackCount(0);
+        mStatistics.clear();
     }
 
     static void setCallbackReturnStop(bool b) {
@@ -71,12 +114,19 @@
         return mCpuLoad;
     }
 
+    std::string getCallbackTimeString() const {
+        return mStatistics.dump();
+    }
+
     static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC);
 
 private:
     static constexpr int32_t   kWorkloadScaler = 500;
+    static constexpr double    kNsToMsScaler = 0.000001;
     double                     mWorkload = 0.0;
     std::atomic<double>        mCpuLoad{0};
+    int64_t                    mPreviousCallbackTimeNs = 0;
+    DoubleStatistics           mStatistics;
 
     oboe::AudioStreamCallback *mCallback = nullptr;
     static bool                mCallbackReturnStop;
diff --git a/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.cpp b/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.cpp
index aab60ab..583c984 100644
--- a/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.cpp
+++ b/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.cpp
@@ -37,4 +37,4 @@
         mPreviousScheduler = scheduler;
     }
 #endif
-}
\ No newline at end of file
+}
diff --git a/apps/OboeTester/app/src/main/cpp/TestErrorCallback.cpp b/apps/OboeTester/app/src/main/cpp/TestErrorCallback.cpp
new file mode 100644
index 0000000..ce4285f
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/TestErrorCallback.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2022 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 <stdlib.h>
+
+#include "common/OboeDebug.h"
+#include "TestErrorCallback.h"
+
+using namespace oboe;
+
+oboe::Result TestErrorCallback::open() {
+    mCallbackMagic = 0;
+    mDataCallback = std::make_shared<MyDataCallback>();
+    mErrorCallback = std::make_shared<MyErrorCallback>(this);
+    AudioStreamBuilder builder;
+    oboe::Result result = builder.setSharingMode(oboe::SharingMode::Exclusive)
+            ->setPerformanceMode(oboe::PerformanceMode::LowLatency)
+            ->setFormat(oboe::AudioFormat::Float)
+            ->setChannelCount(kChannelCount)
+#if 0
+            ->setDataCallback(mDataCallback.get())
+            ->setErrorCallback(mErrorCallback.get()) // This can lead to a crash or FAIL.
+#else
+            ->setDataCallback(mDataCallback)
+            ->setErrorCallback(mErrorCallback) // shared_ptr avoids a crash
+#endif
+            ->openStream(mStream);
+    return result;
+}
+
+oboe::Result TestErrorCallback::start() {
+    return mStream->requestStart();
+}
+
+oboe::Result TestErrorCallback::stop() {
+    return mStream->requestStop();
+}
+
+oboe::Result TestErrorCallback::close() {
+    return mStream->close();
+}
+
+int TestErrorCallback::test() {
+    oboe::Result result = open();
+    if (result != oboe::Result::OK) {
+        return (int) result;
+    }
+    return (int) start();
+}
+
+DataCallbackResult TestErrorCallback::MyDataCallback::onAudioReady(
+        AudioStream *audioStream,
+        void *audioData,
+        int32_t numFrames) {
+    float *output = (float *) audioData;
+    // Fill buffer with random numbers to create "white noise".
+    int numSamples = numFrames * kChannelCount;
+    for (int i = 0; i < numSamples; i++) {
+        *output++ = (float)((drand48() - 0.5) * 0.2);
+    }
+    return oboe::DataCallbackResult::Continue;
+}
diff --git a/apps/OboeTester/app/src/main/cpp/TestErrorCallback.h b/apps/OboeTester/app/src/main/cpp/TestErrorCallback.h
new file mode 100644
index 0000000..a7611fe
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/TestErrorCallback.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2022 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 OBOETESTER_TEST_ERROR_CALLBACK_H
+#define OBOETESTER_TEST_ERROR_CALLBACK_H
+
+#include "oboe/Oboe.h"
+#include <thread>
+
+/**
+ * This code is an experiment to see if we can cause a crash from the ErrorCallback.
+ */
+class TestErrorCallback {
+public:
+
+    oboe::Result open();
+    oboe::Result start();
+    oboe::Result stop();
+    oboe::Result close();
+
+    int test();
+
+    int32_t getCallbackMagic() {
+        return mCallbackMagic.load();
+    }
+
+protected:
+
+    std::atomic<int32_t> mCallbackMagic{0};
+
+private:
+
+    void cleanup() {
+        mDataCallback.reset();
+        mErrorCallback.reset();
+        mStream.reset();
+    }
+
+    class MyDataCallback : public oboe::AudioStreamDataCallback {    public:
+
+        oboe::DataCallbackResult onAudioReady(
+                oboe::AudioStream *audioStream,
+                void *audioData,
+                int32_t numFrames) override;
+
+    };
+
+    class MyErrorCallback : public oboe::AudioStreamErrorCallback {
+    public:
+
+        MyErrorCallback(TestErrorCallback *parent): mParent(parent) {}
+
+        virtual ~MyErrorCallback() {
+            // If the delete occurs before onErrorAfterClose() then this bad magic
+            // value will be seen by the Java test code, causing a failure.
+            // It is also possible that this code will just cause OboeTester to crash!
+            mMagic = 0xdeadbeef;
+            LOGE("%s() called", __func__);
+        }
+
+        void onErrorBeforeClose(oboe::AudioStream *oboeStream, oboe::Result error) override {
+            LOGE("%s() - error = %s, parent = %p",
+                 __func__, oboe::convertToText(error), &mParent);
+            // Trigger a crash by "deleting" this callback object while in use!
+            // Do not try this at home. We are just trying to reproduce the crash
+            // reported in #1603.
+            std::thread t([this]() {
+                    this->mParent->cleanup(); // Possibly delete stream and callback objects.
+                    LOGE("onErrorBeforeClose called cleanup!");
+                });
+            t.detach();
+            // There is a race condition between the deleting thread and this thread.
+            // We do not want to add synchronization because the object is getting deleted
+            // and cannot be relied on.
+            // So we sleep here to give the deleting thread a chance to win the race.
+            usleep(10 * 1000);
+        }
+
+        void onErrorAfterClose(oboe::AudioStream *oboeStream, oboe::Result error) override {
+            // The callback was probably deleted by now.
+            LOGE("%s() - error = %s, mMagic = 0x%08X",
+                 __func__, oboe::convertToText(error), mMagic.load());
+            mParent->mCallbackMagic = mMagic.load();
+        }
+
+    private:
+        TestErrorCallback *mParent;
+        // This must match the value in TestErrorCallbackActivity.java
+        static constexpr int32_t kMagicGood = 0x600DCAFE;
+        std::atomic<int32_t> mMagic{kMagicGood};
+    };
+
+    std::shared_ptr<oboe::AudioStream> mStream;
+    std::shared_ptr<MyDataCallback> mDataCallback;
+    std::shared_ptr<MyErrorCallback> mErrorCallback;
+
+    static constexpr int kChannelCount = 2;
+};
+
+#endif //OBOETESTER_TEST_ERROR_CALLBACK_H
diff --git a/apps/OboeTester/app/src/main/cpp/analyzer/BaseSineAnalyzer.h b/apps/OboeTester/app/src/main/cpp/analyzer/BaseSineAnalyzer.h
index 6601f19..37e1343 100644
--- a/apps/OboeTester/app/src/main/cpp/analyzer/BaseSineAnalyzer.h
+++ b/apps/OboeTester/app/src/main/cpp/analyzer/BaseSineAnalyzer.h
@@ -105,7 +105,7 @@
             float sinOut = sinf(mOutputPhase);
             incrementOutputPhase();
             output = (sinOut * mOutputAmplitude)
-                     + (mWhiteNoise.nextRandomDouble() * mNoiseAmplitude);
+                     + (mWhiteNoise.nextRandomDouble() * getNoiseAmplitude());
             // ALOGD("sin(%f) = %f, %f\n", mOutputPhase, sinOut,  mPhaseIncrement);
         }
         for (int i = 0; i < channelCount; i++) {
@@ -135,11 +135,18 @@
         return magnitude;
     }
 
+    /**
+     * Perform sin/cos analysis on each sample.
+     * Measure magnitude and phase on every period.
+     * @param sample
+     * @param referencePhase
+     * @return true if magnitude and phase updated
+     */
     bool transformSample(float sample, float referencePhase) {
         // Track incoming signal and slowly adjust magnitude to account
         // for drift in the DRC or AGC.
-        mSinAccumulator += sample * sinf(referencePhase);
-        mCosAccumulator += sample * cosf(referencePhase);
+        mSinAccumulator += static_cast<double>(sample) * sinf(referencePhase);
+        mCosAccumulator += static_cast<double>(sample) * cosf(referencePhase);
         mFramesAccumulated++;
         // Must be a multiple of the period or the calculation will not be accurate.
         if (mFramesAccumulated == mSinePeriod) {
@@ -163,6 +170,7 @@
     void reset() override {
         LoopbackProcessor::reset();
         resetAccumulator();
+        mMagnitude = 0.0;
     }
 
     void prepareToTest() override {
diff --git a/apps/OboeTester/app/src/main/cpp/analyzer/DataPathAnalyzer.h b/apps/OboeTester/app/src/main/cpp/analyzer/DataPathAnalyzer.h
index 31369b4..5814dcc 100644
--- a/apps/OboeTester/app/src/main/cpp/analyzer/DataPathAnalyzer.h
+++ b/apps/OboeTester/app/src/main/cpp/analyzer/DataPathAnalyzer.h
@@ -38,14 +38,14 @@
 
     DataPathAnalyzer() : BaseSineAnalyzer() {
         // Add a little bit of noise to reduce blockage by speaker protection and DRC.
-        setNoiseAmplitude(0.05);
+        setNoiseAmplitude(0.02);
     }
 
     /**
      * @param frameData contains microphone data with sine signal feedback
      * @param channelCount
      */
-    result_code processInputFrame(float *frameData, int /* channelCount */) override {
+    result_code processInputFrame(const float *frameData, int /* channelCount */) override {
         result_code result = RESULT_OK;
 
         float sample = frameData[getInputChannel()];
@@ -53,14 +53,13 @@
 
         if (transformSample(sample, mOutputPhase)) {
             resetAccumulator();
+            // Analyze magnitude and phase on every period.
+            double diff = abs(mPhaseOffset - mPreviousPhaseOffset);
+            if (diff < mPhaseTolerance) {
+                mMaxMagnitude = std::max(mMagnitude, mMaxMagnitude);
+            }
+            mPreviousPhaseOffset = mPhaseOffset;
         }
-
-        // Update MaxMagnitude if we are locked.
-        double diff = abs(mPhaseOffset - mPreviousPhaseOffset);
-        if (diff < mPhaseTolerance) {
-            mMaxMagnitude = std::max(mMagnitude, mMaxMagnitude);
-        }
-        mPreviousPhaseOffset = mPhaseOffset;
         return result;
     }
 
diff --git a/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h b/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h
index 249bdd1..52b0013 100644
--- a/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h
+++ b/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h
@@ -46,6 +46,10 @@
         return mPeakFollower.getLevel();
     }
 
+    double getSineAmplitude() const {
+        return mMagnitude;
+    }
+
     int32_t getGlitchCount() const {
         return mGlitchCount;
     }
@@ -56,14 +60,14 @@
 
     double getSignalToNoiseDB() {
         static const double threshold = 1.0e-14;
-        if (mMeanSquareSignal < threshold || mMeanSquareNoise < threshold) {
+        if (mState != STATE_LOCKED
+                || mMeanSquareSignal < threshold
+                || mMeanSquareNoise < threshold) {
             return 0.0;
         } else {
             double signalToNoise = mMeanSquareSignal / mMeanSquareNoise; // power ratio
             double signalToNoiseDB = 10.0 * log(signalToNoise);
             if (signalToNoiseDB < MIN_SNR_DB) {
-                ALOGD("ERROR - signal to noise ratio is too low! < %d dB. Adjust volume.",
-                     MIN_SNR_DB);
                 setResult(ERROR_VOLUME_TOO_LOW);
             }
             return signalToNoiseDB;
@@ -76,7 +80,7 @@
         report << LOOPBACK_RESULT_TAG "peak.amplitude     = " << std::setw(8)
                << getPeakAmplitude() << "\n";
         report << LOOPBACK_RESULT_TAG "sine.magnitude     = " << std::setw(8)
-               << mMagnitude << "\n";
+               << getSineAmplitude() << "\n";
         report << LOOPBACK_RESULT_TAG "rms.noise          = " << std::setw(8)
                << mMeanSquareNoise << "\n";
         report << LOOPBACK_RESULT_TAG "signal.to.noise.db = " << std::setw(8)
@@ -116,10 +120,10 @@
      * @param frameData contains microphone data with sine signal feedback
      * @param channelCount
      */
-    result_code processInputFrame(float *frameData, int /* channelCount */) override {
+    result_code processInputFrame(const float *frameData, int /* channelCount */) override {
         result_code result = RESULT_OK;
 
-        float sample = frameData[0];
+        float sample = frameData[getInputChannel()];
         float peak = mPeakFollower.process(sample);
         mInfiniteRecording.write(sample);
 
@@ -145,6 +149,7 @@
                     mDownCounter = IMMUNE_FRAME_COUNT;
                     mInputPhase = 0.0; // prevent spike at start
                     mOutputPhase = 0.0;
+                    resetAccumulator();
                 }
                 break;
 
@@ -164,8 +169,8 @@
                 break;
 
             case STATE_WAITING_FOR_LOCK:
-                mSinAccumulator += sample * sinf(mInputPhase);
-                mCosAccumulator += sample * cosf(mInputPhase);
+                mSinAccumulator += static_cast<double>(sample) * sinf(mInputPhase);
+                mCosAccumulator += static_cast<double>(sample) * cosf(mInputPhase);
                 mFramesAccumulated++;
                 // Must be a multiple of the period or the calculation will not be accurate.
                 if (mFramesAccumulated == mSinePeriod * PERIODS_NEEDED_FOR_LOCK) {
@@ -315,11 +320,11 @@
     // These must match the values in GlitchActivity.java
     enum sine_state_t {
         STATE_IDLE,               // beginning
-        STATE_IMMUNE,             // ignoring input, waiting fo HW to settle
+        STATE_IMMUNE,             // ignoring input, waiting for HW to settle
         STATE_WAITING_FOR_SIGNAL, // looking for a loud signal
         STATE_WAITING_FOR_LOCK,   // trying to lock onto the phase of the sine
         STATE_LOCKED,             // locked on the sine wave, looking for glitches
-        STATE_GLITCHING,           // locked on the sine wave but glitching
+        STATE_GLITCHING,          // locked on the sine wave but glitching
         NUM_STATES
     };
 
diff --git a/apps/OboeTester/app/src/main/cpp/analyzer/LatencyAnalyzer.h b/apps/OboeTester/app/src/main/cpp/analyzer/LatencyAnalyzer.h
index d78e485..b920c89 100644
--- a/apps/OboeTester/app/src/main/cpp/analyzer/LatencyAnalyzer.h
+++ b/apps/OboeTester/app/src/main/cpp/analyzer/LatencyAnalyzer.h
@@ -39,7 +39,7 @@
 #include "PseudoRandom.h"
 #include "RandomPulseGenerator.h"
 
-// This is used when the code is in Oboe.
+// This is used when the code is in not in Android.
 #ifndef ALOGD
 #define ALOGD LOGD
 #define ALOGE LOGE
@@ -51,25 +51,28 @@
 static constexpr int32_t kDefaultSampleRate = 48000;
 static constexpr int32_t kMillisPerSecond   = 1000;  // by definition
 static constexpr int32_t kMaxLatencyMillis  = 1000;  // arbitrary and generous
-static constexpr double  kMinimumConfidence = 0.2;
 
 struct LatencyReport {
     int32_t latencyInFrames = 0.0;
-    double confidence = 0.0;
+    double correlation = 0.0;
 
     void reset() {
         latencyInFrames = 0;
-        confidence = 0.0;
+        correlation = 0.0;
     }
 };
 
-// Calculate a normalized cross correlation.
-static double calculateNormalizedCorrelation(const float *a,
+/**
+ * Calculate a normalized cross correlation.
+ * @return value between -1.0 and 1.0
+ */
+
+static float calculateNormalizedCorrelation(const float *a,
                                              const float *b,
                                              int windowSize) {
-    double correlation = 0.0;
-    double sumProducts = 0.0;
-    double sumSquares = 0.0;
+    float correlation = 0.0;
+    float sumProducts = 0.0;
+    float sumSquares = 0.0;
 
     // Correlate a against b.
     for (int i = 0; i < windowSize; i++) {
@@ -89,7 +92,7 @@
 static double calculateRootMeanSquare(float *data, int32_t numSamples) {
     double sum = 0.0;
     for (int32_t i = 0; i < numSamples; i++) {
-        float sample = data[i];
+        double sample = data[i];
         sum += sample * sample;
     }
     return sqrt(sum / numSamples);
@@ -97,6 +100,7 @@
 
 /**
  * Monophonic recording with processing.
+ * Samples are stored as floats internally.
  */
 class AudioRecording
 {
@@ -105,10 +109,11 @@
     void allocate(int maxFrames) {
         mData = std::make_unique<float[]>(maxFrames);
         mMaxFrames = maxFrames;
+        mFrameCounter = 0;
     }
 
     // Write SHORT data from the first channel.
-    int32_t write(int16_t *inputData, int32_t inputChannelCount, int32_t numFrames) {
+    int32_t write(const int16_t *inputData, int32_t inputChannelCount, int32_t numFrames) {
         // stop at end of buffer
         if ((mFrameCounter + numFrames) > mMaxFrames) {
             numFrames = mMaxFrames - mFrameCounter;
@@ -120,7 +125,7 @@
     }
 
     // Write FLOAT data from the first channel.
-    int32_t write(float *inputData, int32_t inputChannelCount, int32_t numFrames) {
+    int32_t write(const float *inputData, int32_t inputChannelCount, int32_t numFrames) {
         // stop at end of buffer
         if ((mFrameCounter + numFrames) > mMaxFrames) {
             numFrames = mMaxFrames - mFrameCounter;
@@ -131,7 +136,7 @@
         return numFrames;
     }
 
-    // Write FLOAT data from the first channel.
+    // Write single FLOAT value.
     int32_t write(float sample) {
         // stop at end of buffer
         if (mFrameCounter < mMaxFrames) {
@@ -144,6 +149,7 @@
     void clear() {
         mFrameCounter = 0;
     }
+
     int32_t size() const {
         return mFrameCounter;
     }
@@ -174,6 +180,21 @@
         }
     }
 
+    // Envelope follower that rides over the peak values.
+    void detectPeaks(float decay) {
+        float level = 0.0f;
+        float *x = mData.get();
+        for (int i = 0; i < mFrameCounter; i++) {
+            level *= decay; // exponential decay
+            float input = fabs(x[i]);
+            // never fall below the input signal
+            if (input > level) {
+                level = input;
+            }
+            x[i] = level; // write result back into the array
+        }
+    }
+
     /**
      * Amplify a signal so that the peak matches the specified target.
      *
@@ -203,8 +224,7 @@
                                    AudioRecording &pulse,
                                    LatencyReport *report) {
 
-    report->latencyInFrames = 0;
-    report->confidence = 0.0;
+    report->reset();
 
     int numCorrelations = recorded.size() - pulse.size();
     if (numCorrelations < 10) {
@@ -215,9 +235,9 @@
 
     // Correlate pulse against the recorded data.
     for (int i = 0; i < numCorrelations; i++) {
-        float correlation = (float) calculateNormalizedCorrelation(&recorded.getData()[i],
-                                                                   &pulse.getData()[0],
-                                                                   pulse.size());
+        float correlation = calculateNormalizedCorrelation(&recorded.getData()[i],
+                                                           &pulse.getData()[0],
+                                                           pulse.size());
         correlations[i] = correlation;
     }
 
@@ -248,7 +268,7 @@
 #endif
 
     report->latencyInFrames = peakIndex;
-    report->confidence = peakCorrelation;
+    report->correlation = peakCorrelation;
 
     return 0;
 }
@@ -278,10 +298,10 @@
         mResetCount++;
     }
 
-    virtual result_code processInputFrame(float *frameData, int channelCount) = 0;
+    virtual result_code processInputFrame(const float *frameData, int channelCount) = 0;
     virtual result_code processOutputFrame(float *frameData, int channelCount) = 0;
 
-    void process(float *inputData, int inputChannelCount, int numInputFrames,
+    void process(const float *inputData, int inputChannelCount, int numInputFrames,
                  float *outputData, int outputChannelCount, int numOutputFrames) {
         int numBoth = std::min(numInputFrames, numOutputFrames);
         // Process one frame at a time.
@@ -361,19 +381,44 @@
     LatencyAnalyzer() : LoopbackProcessor() {}
     virtual ~LatencyAnalyzer() = default;
 
+    /**
+     * Call this after the constructor because it calls other virtual methods.
+     */
+    virtual void setup() = 0;
+
     virtual int32_t getProgress() const = 0;
 
-    virtual int getState() = 0;
+    virtual int getState() const = 0;
 
     // @return latency in frames
-    virtual int32_t getMeasuredLatency() = 0;
+    virtual int32_t getMeasuredLatency() const = 0;
 
-    virtual double getMeasuredConfidence() = 0;
+    /**
+     * This is an overall confidence in the latency result based on correlation, SNR, etc.
+     * @return probability value between 0.0 and 1.0
+     */
+    double getMeasuredConfidence() const {
+        // Limit the ratio and prevent divide-by-zero.
+        double noiseSignalRatio = getSignalRMS() <= getBackgroundRMS()
+                                  ? 1.0 : getBackgroundRMS() / getSignalRMS();
+        // Prevent high background noise and low signals from generating false matches.
+        double adjustedConfidence = getMeasuredCorrelation() - noiseSignalRatio;
+        return std::max(0.0, adjustedConfidence);
+    }
 
-    virtual double getBackgroundRMS() = 0;
+    /**
+     * Cross correlation value for the noise pulse against
+     * the corresponding position in the normalized recording.
+     *
+     * @return value between -1.0 and 1.0
+     */
+    virtual double getMeasuredCorrelation() const = 0;
 
-    virtual double getSignalRMS() = 0;
+    virtual double getBackgroundRMS() const = 0;
 
+    virtual double getSignalRMS() const = 0;
+
+    virtual bool hasEnoughData() const = 0;
 };
 
 // ====================================================================================
@@ -387,26 +432,15 @@
 class PulseLatencyAnalyzer : public LatencyAnalyzer {
 public:
 
-    PulseLatencyAnalyzer() : LatencyAnalyzer() {
+    void setup() override {
+        int32_t pulseLength = calculatePulseLength();
         int32_t maxLatencyFrames = getSampleRate() * kMaxLatencyMillis / kMillisPerSecond;
-        int32_t numPulseBits = getSampleRate() * kPulseLengthMillis
-                / (kFramesPerEncodedBit * kMillisPerSecond);
-        int32_t  pulseLength = numPulseBits * kFramesPerEncodedBit;
         mFramesToRecord = pulseLength + maxLatencyFrames;
         mAudioRecording.allocate(mFramesToRecord);
         mAudioRecording.setSampleRate(getSampleRate());
-        generateRandomPulse(pulseLength);
     }
 
-    void generateRandomPulse(int32_t pulseLength) {
-        mPulse.allocate(pulseLength);
-        RandomPulseGenerator pulser(kFramesPerEncodedBit);
-        for (int i = 0; i < pulseLength; i++) {
-            mPulse.write(pulser.nextFloat());
-        }
-    }
-
-    int getState() override {
+    int getState() const override {
         return mState;
     }
 
@@ -427,11 +461,12 @@
         mBackgroundRMS = 0.0f;
         mSignalRMS = 0.0f;
 
+        generatePulseRecording(calculatePulseLength());
         mAudioRecording.clear();
         mLatencyReport.reset();
     }
 
-    bool hasEnoughData() {
+    bool hasEnoughData() const override {
         return mAudioRecording.isFull();
     }
 
@@ -459,18 +494,18 @@
             // setResult(ERROR_INVALID_STATE);
         } else {
             float gain = mAudioRecording.normalize(1.0f);
-            measureLatencyFromPulse(mAudioRecording,
-                                    mPulse,
-                                    &mLatencyReport);
+            measureLatency();
 
-            if (mLatencyReport.confidence < kMinimumConfidence) {
+            // Calculate signalRMS even if it is bogus.
+            // Also it may be used in the confidence calculation below.
+            mSignalRMS = calculateRootMeanSquare(
+                    &mAudioRecording.getData()[mLatencyReport.latencyInFrames], mPulse.size())
+                         / gain;
+            if (getMeasuredConfidence() < getMinimumConfidence()) {
                 report << "   ERROR - confidence too low!";
                 newResult = ERROR_CONFIDENCE;
-            } else {
-                mSignalRMS = calculateRootMeanSquare(
-                        &mAudioRecording.getData()[mLatencyReport.latencyInFrames], mPulse.size())
-                                / gain;
             }
+
             double latencyMillis = kMillisPerSecond * (double) mLatencyReport.latencyInFrames
                                    / getSampleRate();
             report << LOOPBACK_RESULT_TAG "latency.frames         = " << std::setw(8)
@@ -478,7 +513,9 @@
             report << LOOPBACK_RESULT_TAG "latency.msec           = " << std::setw(8)
                    << latencyMillis << "\n";
             report << LOOPBACK_RESULT_TAG "latency.confidence     = " << std::setw(8)
-                   << mLatencyReport.confidence << "\n";
+                   << getMeasuredConfidence() << "\n";
+            report << LOOPBACK_RESULT_TAG "latency.correlation     = " << std::setw(8)
+                   << getMeasuredCorrelation() << "\n";
         }
         mState = STATE_DONE;
         if (getResult() == RESULT_OK) {
@@ -488,19 +525,19 @@
         return report.str();
     }
 
-    int32_t getMeasuredLatency() override {
+    int32_t getMeasuredLatency() const override {
         return mLatencyReport.latencyInFrames;
     }
 
-    double getMeasuredConfidence() override {
-        return mLatencyReport.confidence;
+    double getMeasuredCorrelation() const override {
+        return mLatencyReport.correlation;
     }
 
-    double getBackgroundRMS() override {
+    double getBackgroundRMS() const override {
         return mBackgroundRMS;
     }
 
-    double getSignalRMS() override {
+    double getSignalRMS() const override {
         return mSignalRMS;
     }
 
@@ -512,14 +549,15 @@
         ALOGD("latency: st = %d = %s", mState, convertStateToText(mState));
     }
 
-    result_code processInputFrame(float *frameData, int channelCount) override {
+    result_code processInputFrame(const float *frameData, int /* channelCount */) override {
         echo_state nextState = mState;
         mLoopCounter++;
+        float input = frameData[0];
 
         switch (mState) {
             case STATE_MEASURE_BACKGROUND:
                 // Measure background RMS on channel 0
-                mBackgroundSumSquare += frameData[0] * frameData[0];
+                mBackgroundSumSquare += static_cast<double>(input) * input;
                 mBackgroundSumCount++;
                 mDownCounter--;
                 if (mDownCounter <= 0) {
@@ -531,7 +569,7 @@
 
             case STATE_IN_PULSE:
                 // Record input until the mAudioRecording is full.
-                mAudioRecording.write(frameData, channelCount, 1);
+                mAudioRecording.write(input);
                 if (hasEnoughData()) {
                     nextState = STATE_GOT_DATA;
                 }
@@ -575,6 +613,27 @@
         return RESULT_OK;
     }
 
+protected:
+
+    virtual int32_t calculatePulseLength() const = 0;
+
+    virtual void generatePulseRecording(int32_t pulseLength) = 0;
+
+    virtual void measureLatency() = 0;
+
+    virtual double getMinimumConfidence() const {
+        return 0.5;
+    }
+
+    AudioRecording     mPulse;
+    AudioRecording     mAudioRecording; // contains only the input after starting the pulse
+    LatencyReport      mLatencyReport;
+
+    static constexpr int32_t kPulseLengthMillis = 500;
+    float              mPulseAmplitude = 0.5f;
+    double             mBackgroundRMS = 0.0;
+    double             mSignalRMS = 0.0;
+
 private:
 
     enum echo_state {
@@ -602,21 +661,110 @@
     int32_t         mLoopCounter = 0;
     echo_state      mState = STATE_MEASURE_BACKGROUND;
 
-    static constexpr int32_t kFramesPerEncodedBit = 8; // multiple of 2
-    static constexpr int32_t kPulseLengthMillis = 500;
     static constexpr double  kBackgroundMeasurementLengthSeconds = 0.5;
 
-    AudioRecording     mPulse;
     int32_t            mPulseCursor = 0;
 
     double             mBackgroundSumSquare = 0.0;
     int32_t            mBackgroundSumCount = 0;
-    double             mBackgroundRMS = 0.0;
-    double             mSignalRMS = 0.0;
     int32_t            mFramesToRecord = 0;
 
-    AudioRecording     mAudioRecording; // contains only the input after starting the pulse
-    LatencyReport      mLatencyReport;
+};
+
+/**
+ * This algorithm uses a series of random bits encoded using the
+ * Manchester encoder. It works well for wired loopback but not very well for
+ * through the air loopback.
+ */
+class EncodedRandomLatencyAnalyzer : public PulseLatencyAnalyzer {
+
+protected:
+
+    int32_t calculatePulseLength() const override {
+        // Calculate integer number of bits.
+        int32_t numPulseBits = getSampleRate() * kPulseLengthMillis
+                               / (kFramesPerEncodedBit * kMillisPerSecond);
+        return numPulseBits * kFramesPerEncodedBit;
+    }
+
+    void generatePulseRecording(int32_t pulseLength) override {
+        mPulse.allocate(pulseLength);
+        RandomPulseGenerator pulser(kFramesPerEncodedBit);
+        for (int i = 0; i < pulseLength; i++) {
+            mPulse.write(pulser.nextFloat() * mPulseAmplitude);
+        }
+    }
+
+    double getMinimumConfidence() const override {
+        return 0.2;
+    }
+
+    void measureLatency() override {
+        measureLatencyFromPulse(mAudioRecording,
+                                mPulse,
+                                &mLatencyReport);
+    }
+
+private:
+    static constexpr int32_t kFramesPerEncodedBit = 8; // multiple of 2
+};
+
+/**
+ * This algorithm uses White Noise sent in a short burst pattern.
+ * The original signal and the recorded signal are then run through
+ * an envelope follower to convert the fine detail into more of
+ * a rectangular block before the correlation phase.
+ */
+class WhiteNoiseLatencyAnalyzer : public PulseLatencyAnalyzer {
+
+protected:
+
+    int32_t calculatePulseLength() const override {
+        return getSampleRate() * kPulseLengthMillis / kMillisPerSecond;
+    }
+
+    void generatePulseRecording(int32_t pulseLength) override {
+        mPulse.allocate(pulseLength);
+        // Turn the noise on and off to sharpen the correlation peak.
+        // Use more zeros than ones so that the correlation will be less than 0.5 even when there
+        // is a strong background noise.
+        int8_t pattern[] = {1, 0, 0,
+                            1, 1, 0, 0, 0,
+                            1, 1, 1, 0, 0, 0, 0,
+                            1, 1, 1, 1, 0, 0, 0, 0, 0
+                            };
+        PseudoRandom random;
+        const int32_t numSections = sizeof(pattern);
+        const int32_t framesPerSection = pulseLength / numSections;
+        for (int section = 0; section < numSections; section++) {
+            if (pattern[section]) {
+                for (int i = 0; i < framesPerSection; i++) {
+                    mPulse.write((float) (random.nextRandomDouble() * mPulseAmplitude));
+                }
+            } else {
+                for (int i = 0; i < framesPerSection; i++) {
+                    mPulse.write(0.0f);
+                }
+            }
+        }
+        // Write any remaining frames.
+        int32_t framesWritten = framesPerSection * numSections;
+        for (int i = framesWritten; i < pulseLength; i++) {
+            mPulse.write(0.0f);
+        }
+    }
+
+    void measureLatency() override {
+        // Smooth out the noise so we see rectangular blocks.
+        // This improves immunity against phase cancellation and distortion.
+        static constexpr float decay = 0.99f; // just under 1.0, lower numbers decay faster
+        mAudioRecording.detectPeaks(decay);
+        mPulse.detectPeaks(decay);
+        measureLatencyFromPulse(mAudioRecording,
+                                mPulse,
+                                &mLatencyReport);
+    }
+
 };
 
 #endif // ANALYZER_LATENCY_ANALYZER_H
diff --git a/apps/OboeTester/app/src/main/cpp/flowunits/ExponentialShape.cpp b/apps/OboeTester/app/src/main/cpp/flowunits/ExponentialShape.cpp
index 4614306..4aac281 100644
--- a/apps/OboeTester/app/src/main/cpp/flowunits/ExponentialShape.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowunits/ExponentialShape.cpp
@@ -32,4 +32,4 @@
     }
 
     return numFrames;
-}
\ No newline at end of file
+}
diff --git a/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.cpp b/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.cpp
index 5bcc2aa..ebff5e2 100644
--- a/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.cpp
@@ -33,4 +33,4 @@
     }
 
     return numFrames;
-}
\ No newline at end of file
+}
diff --git a/apps/OboeTester/app/src/main/cpp/flowunits/WhiteNoise.cpp b/apps/OboeTester/app/src/main/cpp/flowunits/WhiteNoise.cpp
new file mode 100644
index 0000000..ecad91c
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowunits/WhiteNoise.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2022 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 <math.h>
+#include <unistd.h>
+
+#include "WhiteNoise.h"
+
+int32_t WhiteNoise::onProcess(int32_t numFrames) {
+    const float *amplitudes = amplitude.getBuffer();
+    float *buffer = output.getBuffer();
+
+    for (int i = 0; i < numFrames; i++) {
+        float noise = (float) mPseudoRandom.nextRandomDouble(); // -1 to +1
+        *buffer++ = noise * (*amplitudes++);
+    }
+
+    return numFrames;
+}
diff --git a/apps/OboeTester/app/src/main/cpp/flowunits/WhiteNoise.h b/apps/OboeTester/app/src/main/cpp/flowunits/WhiteNoise.h
new file mode 100644
index 0000000..262ef81
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowunits/WhiteNoise.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2022 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 FLOWGRAPH_WHITE_NOISE_H
+#define FLOWGRAPH_WHITE_NOISE_H
+
+#include <unistd.h>
+
+#include "flowgraph/FlowGraphNode.h"
+
+#include "../analyzer/PseudoRandom.h"
+
+/**
+ * White noise with equal energy in all frequencies up to the Nyquist.
+ * This is a based on random numbers with a uniform distribution.
+ */
+class WhiteNoise : public oboe::flowgraph::FlowGraphNode {
+public:
+
+    WhiteNoise()
+            : oboe::flowgraph::FlowGraphNode()
+            , amplitude(*this, 1)
+            , output(*this, 1)
+            {
+    }
+
+    virtual ~WhiteNoise() = default;
+
+    int32_t onProcess(int32_t numFrames) override;
+
+    /**
+     * Control the amplitude amplitude of the noise.
+     * Silence is 0.0.
+     * A typical full amplitude would be 1.0.
+     */
+    oboe::flowgraph::FlowGraphPortFloatInput  amplitude;
+
+    oboe::flowgraph::FlowGraphPortFloatOutput output;
+
+private:
+    PseudoRandom mPseudoRandom;
+};
+
+#endif //FLOWGRAPH_WHITE_NOISE_H
diff --git a/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp b/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp
index 39dba11..3b898a8 100644
--- a/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp
+++ b/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp
@@ -26,6 +26,7 @@
 #include "oboe/Oboe.h"
 
 #include "NativeAudioContext.h"
+#include "TestErrorCallback.h"
 
 NativeAudioContext engine;
 
@@ -35,110 +36,116 @@
 extern "C" {
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_openNative(JNIEnv *env, jobject,
+Java_com_mobileer_oboetester_OboeAudioStream_openNative(JNIEnv *env, jobject,
                                                        jint nativeApi,
                                                        jint sampleRate,
                                                        jint channelCount,
+                                                       jint channelMask,
                                                        jint format,
                                                        jint sharingMode,
                                                        jint performanceMode,
                                                        jint inputPreset,
+                                                       jint usage,
+                                                       jint contentType,
                                                        jint deviceId,
                                                        jint sessionId,
-                                                       jint framesPerBurst,
                                                        jboolean channelConversionAllowed,
                                                        jboolean formatConversionAllowed,
                                                        jint rateConversionQuality,
                                                        jboolean isMMap,
                                                        jboolean isInput);
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_close(JNIEnv *env, jobject, jint);
+Java_com_mobileer_oboetester_OboeAudioStream_close(JNIEnv *env, jobject, jint);
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_setThresholdInFrames(JNIEnv *env, jobject, jint, jint);
+Java_com_mobileer_oboetester_OboeAudioStream_setThresholdInFrames(JNIEnv *env, jobject, jint, jint);
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getThresholdInFrames(JNIEnv *env, jobject, jint);
+Java_com_mobileer_oboetester_OboeAudioStream_getThresholdInFrames(JNIEnv *env, jobject, jint);
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getBufferCapacityInFrames(JNIEnv *env, jobject, jint);
+Java_com_mobileer_oboetester_OboeAudioStream_getBufferCapacityInFrames(JNIEnv *env, jobject, jint);
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_setNativeApi(JNIEnv *env, jobject, jint, jint);
+Java_com_mobileer_oboetester_OboeAudioStream_setNativeApi(JNIEnv *env, jobject, jint, jint);
 
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_setUseCallback(JNIEnv *env, jclass type,
+Java_com_mobileer_oboetester_OboeAudioStream_setUseCallback(JNIEnv *env, jclass type,
                                                                       jboolean useCallback);
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_setCallbackReturnStop(JNIEnv *env,
+Java_com_mobileer_oboetester_OboeAudioStream_setCallbackReturnStop(JNIEnv *env,
                                                                              jclass type,
                                                                              jboolean b);
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_setCallbackSize(JNIEnv *env, jclass type,
+Java_com_mobileer_oboetester_OboeAudioStream_setCallbackSize(JNIEnv *env, jclass type,
                                                             jint callbackSize);
 
 // ================= OboeAudioOutputStream ================================
 
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioOutputStream_trigger(JNIEnv *env, jobject);
+Java_com_mobileer_oboetester_OboeAudioOutputStream_trigger(JNIEnv *env, jobject);
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioOutputStream_setToneType(JNIEnv *env, jobject, jint);
+Java_com_mobileer_oboetester_OboeAudioOutputStream_setToneType(JNIEnv *env, jobject, jint);
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioOutputStream_setAmplitude(JNIEnv *env, jobject, jdouble);
+Java_com_mobileer_oboetester_OboeAudioOutputStream_setAmplitude(JNIEnv *env, jobject, jdouble);
 
 /*********************************************************************************/
 /**********************  JNI Implementations *************************************/
 /*********************************************************************************/
 
 JNIEXPORT jboolean JNICALL
-Java_com_google_sample_oboe_manualtest_NativeEngine_isMMapSupported(JNIEnv *env, jclass type) {
+Java_com_mobileer_oboetester_NativeEngine_isMMapSupported(JNIEnv *env, jclass type) {
     return oboe::AAudioExtensions::getInstance().isMMapSupported();
 }
 
 JNIEXPORT jboolean JNICALL
-Java_com_google_sample_oboe_manualtest_NativeEngine_isMMapExclusiveSupported(JNIEnv *env, jclass type) {
+Java_com_mobileer_oboetester_NativeEngine_isMMapExclusiveSupported(JNIEnv *env, jclass type) {
     return oboe::AAudioExtensions::getInstance().isMMapExclusiveSupported();
 }
 
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_NativeEngine_setWorkaroundsEnabled(JNIEnv *env, jclass type,
+Java_com_mobileer_oboetester_NativeEngine_setWorkaroundsEnabled(JNIEnv *env, jclass type,
                                                                           jboolean enabled) {
     oboe::OboeGlobals::setWorkaroundsEnabled(enabled);
 }
 
 JNIEXPORT jboolean JNICALL
-Java_com_google_sample_oboe_manualtest_NativeEngine_areWorkaroundsEnabled(JNIEnv *env,
+Java_com_mobileer_oboetester_NativeEngine_areWorkaroundsEnabled(JNIEnv *env,
         jclass type) {
     return oboe::OboeGlobals::areWorkaroundsEnabled();
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_openNative(
+Java_com_mobileer_oboetester_OboeAudioStream_openNative(
         JNIEnv *env, jobject synth,
         jint nativeApi,
         jint sampleRate,
         jint channelCount,
+        jint channelMask,
         jint format,
         jint sharingMode,
         jint performanceMode,
         jint inputPreset,
+        jint usage,
+        jint contentType,
         jint deviceId,
         jint sessionId,
-        jint framesPerBurst,
         jboolean channelConversionAllowed,
         jboolean formatConversionAllowed,
         jint rateConversionQuality,
         jboolean isMMap,
         jboolean isInput) {
-    LOGD("OboeAudioStream_openNative: sampleRate = %d, framesPerBurst = %d", sampleRate, framesPerBurst);
+    LOGD("OboeAudioStream_openNative: sampleRate = %d", sampleRate);
 
     return (jint) engine.getCurrentActivity()->open(nativeApi,
                                                     sampleRate,
                                                     channelCount,
+                                                    channelMask,
                                                     format,
                                                     sharingMode,
                                                     performanceMode,
                                                     inputPreset,
+                                                    usage,
+                                                    contentType,
                                                     deviceId,
                                                     sessionId,
-                                                    framesPerBurst,
                                                     channelConversionAllowed,
                                                     formatConversionAllowed,
                                                     rateConversionQuality,
@@ -147,37 +154,37 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_TestAudioActivity_startNative(JNIEnv *env, jobject) {
+Java_com_mobileer_oboetester_TestAudioActivity_startNative(JNIEnv *env, jobject) {
     return (jint) engine.getCurrentActivity()->start();
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_TestAudioActivity_pauseNative(JNIEnv *env, jobject) {
+Java_com_mobileer_oboetester_TestAudioActivity_pauseNative(JNIEnv *env, jobject) {
     return (jint) engine.getCurrentActivity()->pause();
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_TestAudioActivity_stopNative(JNIEnv *env, jobject) {
+Java_com_mobileer_oboetester_TestAudioActivity_stopNative(JNIEnv *env, jobject) {
     return (jint) engine.getCurrentActivity()->stop();
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_TestAudioActivity_getFramesPerCallback(JNIEnv *env, jobject) {
+Java_com_mobileer_oboetester_TestAudioActivity_getFramesPerCallback(JNIEnv *env, jobject) {
     return (jint) engine.getCurrentActivity()->getFramesPerCallback();
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_startPlaybackNative(JNIEnv *env, jobject) {
+Java_com_mobileer_oboetester_OboeAudioStream_startPlaybackNative(JNIEnv *env, jobject) {
     return (jint) engine.getCurrentActivity()->startPlayback();
 }
 
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_close(JNIEnv *env, jobject, jint streamIndex) {
+Java_com_mobileer_oboetester_OboeAudioStream_close(JNIEnv *env, jobject, jint streamIndex) {
     engine.getCurrentActivity()->close(streamIndex);
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_setBufferSizeInFrames(
+Java_com_mobileer_oboetester_OboeAudioStream_setBufferSizeInFrames(
         JNIEnv *env, jobject, jint streamIndex, jint threshold) {
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
     if (oboeStream != nullptr) {
@@ -190,7 +197,7 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getBufferSizeInFrames(
+Java_com_mobileer_oboetester_OboeAudioStream_getBufferSizeInFrames(
         JNIEnv *env, jobject, jint streamIndex) {
     jint result = (jint) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
@@ -201,7 +208,7 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getBufferCapacityInFrames(
+Java_com_mobileer_oboetester_OboeAudioStream_getBufferCapacityInFrames(
         JNIEnv *env, jobject, jint streamIndex) {
     jint result = (jint) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
@@ -225,7 +232,7 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getNativeApi(
+Java_com_mobileer_oboetester_OboeAudioStream_getNativeApi(
         JNIEnv *env, jobject, jint streamIndex) {
     jint result = (jint) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
@@ -238,7 +245,7 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getSampleRate(
+Java_com_mobileer_oboetester_OboeAudioStream_getSampleRate(
         JNIEnv *env, jobject, jint streamIndex) {
     jint result = (jint) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
@@ -249,7 +256,7 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getSharingMode(
+Java_com_mobileer_oboetester_OboeAudioStream_getSharingMode(
         JNIEnv *env, jobject, jint streamIndex) {
     jint result = (jint) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
@@ -260,7 +267,7 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getPerformanceMode(
+Java_com_mobileer_oboetester_OboeAudioStream_getPerformanceMode(
         JNIEnv *env, jobject, jint streamIndex) {
     jint result = (jint) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
@@ -271,7 +278,7 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getInputPreset(
+Java_com_mobileer_oboetester_OboeAudioStream_getInputPreset(
         JNIEnv *env, jobject, jint streamIndex) {
     jint result = (jint) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
@@ -282,7 +289,7 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getFramesPerBurst(
+Java_com_mobileer_oboetester_OboeAudioStream_getFramesPerBurst(
         JNIEnv *env, jobject, jint streamIndex) {
     jint result = (jint) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
@@ -293,7 +300,7 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getChannelCount(
+Java_com_mobileer_oboetester_OboeAudioStream_getChannelCount(
         JNIEnv *env, jobject, jint streamIndex) {
     jint result = (jint) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
@@ -304,8 +311,19 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getFormat(JNIEnv *env, jobject instance, jint streamIndex) {
-        jint result = (jint) oboe::Result::ErrorNull;
+Java_com_mobileer_oboetester_OboeAudioStream_getChannelMask(
+        JNIEnv *env, jobject, jint streamIndex) {
+    jint result = (jint) oboe::Result::ErrorNull;
+    std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
+    if (oboeStream != nullptr) {
+        result = (jint) oboeStream->getChannelMask();
+    }
+    return result;
+}
+
+JNIEXPORT jint JNICALL
+Java_com_mobileer_oboetester_OboeAudioStream_getFormat(JNIEnv *env, jobject instance, jint streamIndex) {
+    jint result = (jint) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
     if (oboeStream != nullptr) {
         result = (jint) oboeStream->getFormat();
@@ -314,7 +332,27 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getDeviceId(
+Java_com_mobileer_oboetester_OboeAudioStream_getUsage(JNIEnv *env, jobject instance, jint streamIndex) {
+    jint result = (jint) oboe::Result::ErrorNull;
+    std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
+    if (oboeStream != nullptr) {
+        result = (jint) oboeStream->getUsage();
+    }
+    return result;
+}
+
+JNIEXPORT jint JNICALL
+Java_com_mobileer_oboetester_OboeAudioStream_getContentType(JNIEnv *env, jobject instance, jint streamIndex) {
+    jint result = (jint) oboe::Result::ErrorNull;
+    std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
+    if (oboeStream != nullptr) {
+        result = (jint) oboeStream->getContentType();
+    }
+    return result;
+}
+
+JNIEXPORT jint JNICALL
+Java_com_mobileer_oboetester_OboeAudioStream_getDeviceId(
         JNIEnv *env, jobject, jint streamIndex) {
     jint result = (jint) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
@@ -325,7 +363,7 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getSessionId(
+Java_com_mobileer_oboetester_OboeAudioStream_getSessionId(
         JNIEnv *env, jobject, jint streamIndex) {
     jint result = (jint) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
@@ -336,7 +374,7 @@
 }
 
 JNIEXPORT jlong JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getFramesWritten(
+Java_com_mobileer_oboetester_OboeAudioStream_getFramesWritten(
         JNIEnv *env, jobject, jint streamIndex) {
     jlong result = (jint) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
@@ -347,7 +385,7 @@
 }
 
 JNIEXPORT jlong JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getFramesRead(
+Java_com_mobileer_oboetester_OboeAudioStream_getFramesRead(
         JNIEnv *env, jobject, jint streamIndex) {
     jlong result = (jlong) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
@@ -358,7 +396,7 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getXRunCount(
+Java_com_mobileer_oboetester_OboeAudioStream_getXRunCount(
         JNIEnv *env, jobject, jint streamIndex) {
     jint result = (jlong) oboe::Result::ErrorNull;
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
@@ -374,13 +412,13 @@
 }
 
 JNIEXPORT jlong JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getCallbackCount(
+Java_com_mobileer_oboetester_OboeAudioStream_getCallbackCount(
         JNIEnv *env, jobject) {
     return engine.getCurrentActivity()->getCallbackCount();
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getLastErrorCallbackResult(
+Java_com_mobileer_oboetester_OboeAudioStream_getLastErrorCallbackResult(
         JNIEnv *env, jobject, jint streamIndex) {
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
     if (oboeStream != nullptr) {
@@ -390,25 +428,30 @@
 }
 
 JNIEXPORT jdouble JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getTimestampLatency(JNIEnv *env,
+Java_com_mobileer_oboetester_OboeAudioStream_getTimestampLatency(JNIEnv *env,
         jobject instance,
         jint streamIndex) {
     return engine.getCurrentActivity()->getTimestampLatency(streamIndex);
 }
 
 JNIEXPORT jdouble JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getCpuLoad(JNIEnv *env, jobject instance, jint streamIndex) {
+Java_com_mobileer_oboetester_OboeAudioStream_getCpuLoad(JNIEnv *env, jobject instance, jint streamIndex) {
     return engine.getCurrentActivity()->getCpuLoad();
 }
 
+JNIEXPORT jstring JNICALL
+Java_com_mobileer_oboetester_OboeAudioStream_getCallbackTimeString(JNIEnv *env, jobject instance) {
+    return env->NewStringUTF(engine.getCurrentActivity()->getCallbackTimeString().c_str());
+}
+
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_setWorkload(
+Java_com_mobileer_oboetester_OboeAudioStream_setWorkload(
         JNIEnv *env, jobject, jdouble workload) {
     engine.getCurrentActivity()->setWorkload(workload);
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getState(JNIEnv *env, jobject instance, jint streamIndex) {
+Java_com_mobileer_oboetester_OboeAudioStream_getState(JNIEnv *env, jobject instance, jint streamIndex) {
     std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
     if (oboeStream != nullptr) {
         auto state = oboeStream->getState();
@@ -433,64 +476,64 @@
 }
 
 JNIEXPORT jdouble JNICALL
-Java_com_google_sample_oboe_manualtest_AudioInputTester_getPeakLevel(JNIEnv *env,
+Java_com_mobileer_oboetester_AudioInputTester_getPeakLevel(JNIEnv *env,
                                                           jobject instance,
                                                           jint index) {
     return engine.getCurrentActivity()->getPeakLevel(index);
 }
 
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_setUseCallback(JNIEnv *env, jclass type,
+Java_com_mobileer_oboetester_OboeAudioStream_setUseCallback(JNIEnv *env, jclass type,
                                                                       jboolean useCallback) {
     ActivityContext::mUseCallback = useCallback;
 }
 
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_setCallbackReturnStop(JNIEnv *env, jclass type,
+Java_com_mobileer_oboetester_OboeAudioStream_setCallbackReturnStop(JNIEnv *env, jclass type,
                                                                       jboolean b) {
     OboeStreamCallbackProxy::setCallbackReturnStop(b);
 }
 
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_setCallbackSize(JNIEnv *env, jclass type,
+Java_com_mobileer_oboetester_OboeAudioStream_setCallbackSize(JNIEnv *env, jclass type,
                                                             jint callbackSize) {
     ActivityContext::callbackSize = callbackSize;
 }
 
 JNIEXPORT jboolean JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_isMMap(JNIEnv *env, jobject instance, jint streamIndex) {
+Java_com_mobileer_oboetester_OboeAudioStream_isMMap(JNIEnv *env, jobject instance, jint streamIndex) {
     return engine.getCurrentActivity()->isMMapUsed(streamIndex);
 }
 
 // ================= OboeAudioOutputStream ================================
 
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioOutputStream_trigger(
+Java_com_mobileer_oboetester_OboeAudioOutputStream_trigger(
         JNIEnv *env, jobject) {
     engine.getCurrentActivity()->trigger();
 }
 
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioOutputStream_setChannelEnabled(
+Java_com_mobileer_oboetester_OboeAudioOutputStream_setChannelEnabled(
         JNIEnv *env, jobject, jint channelIndex, jboolean enabled) {
     engine.getCurrentActivity()->setChannelEnabled(channelIndex, enabled);
 }
 
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioOutputStream_setSignalType(
+Java_com_mobileer_oboetester_OboeAudioOutputStream_setSignalType(
         JNIEnv *env, jobject, jint signalType) {
     engine.getCurrentActivity()->setSignalType(signalType);
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_OboeAudioStream_getOboeVersionNumber(JNIEnv *env,
+Java_com_mobileer_oboetester_OboeAudioStream_getOboeVersionNumber(JNIEnv *env,
                                                                           jclass type) {
     return OBOE_VERSION_NUMBER;
 }
 
 // ==========================================================================
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_TestAudioActivity_setActivityType(JNIEnv *env,
+Java_com_mobileer_oboetester_TestAudioActivity_setActivityType(JNIEnv *env,
                                                                          jobject instance,
                                                                          jint activityType) {
     engine.setActivityType(activityType);
@@ -498,7 +541,7 @@
 
 // ==========================================================================
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_TestInputActivity_saveWaveFile(JNIEnv *env,
+Java_com_mobileer_oboetester_TestInputActivity_saveWaveFile(JNIEnv *env,
                                                                         jobject instance,
                                                                         jstring fileName) {
     const char *str = env->GetStringUTFChars(fileName, nullptr);
@@ -510,7 +553,7 @@
 
 // ==========================================================================
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_TestInputActivity_setMinimumFramesBeforeRead(JNIEnv *env,
+Java_com_mobileer_oboetester_TestInputActivity_setMinimumFramesBeforeRead(JNIEnv *env,
                                                                       jobject instance,
                                                                       jint numFrames) {
     engine.getCurrentActivity()->setMinimumFramesBeforeRead(numFrames);
@@ -518,126 +561,144 @@
 
 // ==========================================================================
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_EchoActivity_setDelayTime(JNIEnv *env,
+Java_com_mobileer_oboetester_EchoActivity_setDelayTime(JNIEnv *env,
                                                                          jobject instance,
                                                                          jdouble delayTimeSeconds) {
     engine.setDelayTime(delayTimeSeconds);
 }
 
 JNIEXPORT int JNICALL
-Java_com_google_sample_oboe_manualtest_EchoActivity_getColdStartInputMillis(JNIEnv *env,
+Java_com_mobileer_oboetester_EchoActivity_getColdStartInputMillis(JNIEnv *env,
         jobject instance) {
     return engine.getCurrentActivity()->getColdStartInputMillis();
 }
 
 JNIEXPORT int JNICALL
-Java_com_google_sample_oboe_manualtest_EchoActivity_getColdStartOutputMillis(JNIEnv *env,
+Java_com_mobileer_oboetester_EchoActivity_getColdStartOutputMillis(JNIEnv *env,
                                                                             jobject instance) {
     return engine.getCurrentActivity()->getColdStartOutputMillis();
 }
 
 // ==========================================================================
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_RoundTripLatencyActivity_getAnalyzerProgress(JNIEnv *env,
+Java_com_mobileer_oboetester_RoundTripLatencyActivity_getAnalyzerProgress(JNIEnv *env,
                                                                                     jobject instance) {
     return engine.mActivityRoundTripLatency.getLatencyAnalyzer()->getProgress();
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_RoundTripLatencyActivity_getMeasuredLatency(JNIEnv *env,
+Java_com_mobileer_oboetester_RoundTripLatencyActivity_getMeasuredLatency(JNIEnv *env,
                                                                                    jobject instance) {
     return engine.mActivityRoundTripLatency.getLatencyAnalyzer()->getMeasuredLatency();
 }
 
 JNIEXPORT jdouble JNICALL
-Java_com_google_sample_oboe_manualtest_RoundTripLatencyActivity_getMeasuredConfidence(JNIEnv *env,
-                                                                                      jobject instance) {
+Java_com_mobileer_oboetester_RoundTripLatencyActivity_getMeasuredConfidence(JNIEnv *env,
+                                                                            jobject instance) {
     return engine.mActivityRoundTripLatency.getLatencyAnalyzer()->getMeasuredConfidence();
 }
 
 JNIEXPORT jdouble JNICALL
-Java_com_google_sample_oboe_manualtest_RoundTripLatencyActivity_getBackgroundRMS(JNIEnv *env,
+Java_com_mobileer_oboetester_RoundTripLatencyActivity_getMeasuredCorrelation(JNIEnv *env,
+                                                                            jobject instance) {
+    return engine.mActivityRoundTripLatency.getLatencyAnalyzer()->getMeasuredCorrelation();
+}
+
+JNIEXPORT jdouble JNICALL
+Java_com_mobileer_oboetester_RoundTripLatencyActivity_measureTimestampLatency(JNIEnv *env,
+                                                                            jobject instance) {
+    return engine.mActivityRoundTripLatency.measureTimestampLatency();
+}
+
+JNIEXPORT jdouble JNICALL
+Java_com_mobileer_oboetester_RoundTripLatencyActivity_getBackgroundRMS(JNIEnv *env,
                                                                                  jobject instance) {
     return engine.mActivityRoundTripLatency.getLatencyAnalyzer()->getBackgroundRMS();
 }
 
 JNIEXPORT jdouble JNICALL
-Java_com_google_sample_oboe_manualtest_RoundTripLatencyActivity_getSignalRMS(JNIEnv *env,
+Java_com_mobileer_oboetester_RoundTripLatencyActivity_getSignalRMS(JNIEnv *env,
                                                                                  jobject instance) {
     return engine.mActivityRoundTripLatency.getLatencyAnalyzer()->getSignalRMS();
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_AnalyzerActivity_getMeasuredResult(JNIEnv *env,
+Java_com_mobileer_oboetester_AnalyzerActivity_getMeasuredResult(JNIEnv *env,
                                                                           jobject instance) {
     return engine.mActivityRoundTripLatency.getLatencyAnalyzer()->getResult();
 }
 
 // ==========================================================================
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_AnalyzerActivity_getAnalyzerState(JNIEnv *env,
+Java_com_mobileer_oboetester_AnalyzerActivity_getAnalyzerState(JNIEnv *env,
                                                                          jobject instance) {
     return ((ActivityFullDuplex *)engine.getCurrentActivity())->getState();
 }
 
 JNIEXPORT jboolean JNICALL
-Java_com_google_sample_oboe_manualtest_AnalyzerActivity_isAnalyzerDone(JNIEnv *env,
+Java_com_mobileer_oboetester_AnalyzerActivity_isAnalyzerDone(JNIEnv *env,
                                                                        jobject instance) {
     return ((ActivityFullDuplex *)engine.getCurrentActivity())->isAnalyzerDone();
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_AnalyzerActivity_getResetCount(JNIEnv *env,
+Java_com_mobileer_oboetester_AnalyzerActivity_getResetCount(JNIEnv *env,
                                                                           jobject instance) {
     return ((ActivityFullDuplex *)engine.getCurrentActivity())->getResetCount();
 }
 
 // ==========================================================================
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_GlitchActivity_getGlitchCount(JNIEnv *env,
+Java_com_mobileer_oboetester_GlitchActivity_getGlitchCount(JNIEnv *env,
                                                                      jobject instance) {
     return engine.mActivityGlitches.getGlitchAnalyzer()->getGlitchCount();
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_GlitchActivity_getStateFrameCount(JNIEnv *env,
+Java_com_mobileer_oboetester_GlitchActivity_getStateFrameCount(JNIEnv *env,
                                                                      jobject instance,
                                                                      jint state) {
     return engine.mActivityGlitches.getGlitchAnalyzer()->getStateFrameCount(state);
 }
 
 JNIEXPORT jdouble JNICALL
-Java_com_google_sample_oboe_manualtest_GlitchActivity_getSignalToNoiseDB(JNIEnv *env,
+Java_com_mobileer_oboetester_GlitchActivity_getSignalToNoiseDB(JNIEnv *env,
                                                                          jobject instance) {
     return engine.mActivityGlitches.getGlitchAnalyzer()->getSignalToNoiseDB();
 }
 
 JNIEXPORT jdouble JNICALL
-Java_com_google_sample_oboe_manualtest_GlitchActivity_getPeakAmplitude(JNIEnv *env,
+Java_com_mobileer_oboetester_GlitchActivity_getPeakAmplitude(JNIEnv *env,
                                                                        jobject instance) {
     return engine.mActivityGlitches.getGlitchAnalyzer()->getPeakAmplitude();
 }
 
 JNIEXPORT jdouble JNICALL
-Java_com_google_sample_oboe_manualtest_TestDataPathsActivity_getMagnitude(JNIEnv *env,
+Java_com_mobileer_oboetester_GlitchActivity_getSineAmplitude(JNIEnv *env,
+                                                             jobject instance) {
+    return engine.mActivityGlitches.getGlitchAnalyzer()->getSineAmplitude();
+}
+
+JNIEXPORT jdouble JNICALL
+Java_com_mobileer_oboetester_TestDataPathsActivity_getMagnitude(JNIEnv *env,
                                                                           jobject instance) {
     return engine.mActivityDataPath.getDataPathAnalyzer()->getMagnitude();
 }
 
 JNIEXPORT jdouble JNICALL
-Java_com_google_sample_oboe_manualtest_TestDataPathsActivity_getMaxMagnitude(JNIEnv *env,
+Java_com_mobileer_oboetester_TestDataPathsActivity_getMaxMagnitude(JNIEnv *env,
                                                                           jobject instance) {
     return engine.mActivityDataPath.getDataPathAnalyzer()->getMaxMagnitude();
 }
 
 JNIEXPORT jdouble JNICALL
-Java_com_google_sample_oboe_manualtest_TestDataPathsActivity_getPhase(JNIEnv *env,
+Java_com_mobileer_oboetester_TestDataPathsActivity_getPhase(JNIEnv *env,
                                                                           jobject instance) {
     return engine.mActivityDataPath.getDataPathAnalyzer()->getPhaseOffset();
 }
 
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_GlitchActivity_setTolerance(JNIEnv *env,
+Java_com_mobileer_oboetester_GlitchActivity_setTolerance(JNIEnv *env,
                                                                    jobject instance,
                                                                    jfloat tolerance) {
     if (engine.mActivityGlitches.getGlitchAnalyzer()) {
@@ -646,7 +707,7 @@
 }
 
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_GlitchActivity_setInputChannelNative(JNIEnv *env,
+Java_com_mobileer_oboetester_GlitchActivity_setInputChannelNative(JNIEnv *env,
                                                                    jobject instance,
                                                                    jint channel) {
     if (engine.mActivityGlitches.getGlitchAnalyzer()) {
@@ -658,7 +719,7 @@
 }
 
 JNIEXPORT void JNICALL
-Java_com_google_sample_oboe_manualtest_GlitchActivity_setOutputChannelNative(JNIEnv *env,
+Java_com_mobileer_oboetester_GlitchActivity_setOutputChannelNative(JNIEnv *env,
                                                                        jobject instance,
                                                                        jint channel) {
     if (engine.mActivityGlitches.getGlitchAnalyzer()) {
@@ -670,7 +731,7 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_com_google_sample_oboe_manualtest_ManualGlitchActivity_getGlitch(JNIEnv *env, jobject instance,
+Java_com_mobileer_oboetester_ManualGlitchActivity_getGlitch(JNIEnv *env, jobject instance,
                                                                       jfloatArray waveform_) {
     float *waveform = env->GetFloatArrayElements(waveform_, nullptr);
     jsize length = env->GetArrayLength(waveform_);
@@ -684,4 +745,26 @@
     return numSamples;
 }
 
+JNIEXPORT void JNICALL
+Java_com_mobileer_oboetester_TestAudioActivity_setDefaultAudioValues(JNIEnv *env, jclass clazz,
+                                                                     jint audio_manager_sample_rate,
+                                                                     jint audio_manager_frames_per_burst) {
+    oboe::DefaultStreamValues::SampleRate = audio_manager_sample_rate;
+    oboe::DefaultStreamValues::FramesPerBurst = audio_manager_frames_per_burst;
+}
+
+static TestErrorCallback sTester;
+
+JNIEXPORT void JNICALL
+Java_com_mobileer_oboetester_TestErrorCallbackActivity_testDeleteCrash(
+        JNIEnv *env, jobject instance) {
+    sTester.test();
+}
+
+JNIEXPORT jint JNICALL
+Java_com_mobileer_oboetester_TestErrorCallbackActivity_getCallbackMagic(
+        JNIEnv *env, jobject instance) {
+    return sTester.getCallbackMagic();
+}
+
 }
diff --git a/apps/OboeTester/app/src/main/cpp/util/WaveFileWriter.h b/apps/OboeTester/app/src/main/cpp/util/WaveFileWriter.h
index 0fe7d33..56abd1c 100644
--- a/apps/OboeTester/app/src/main/cpp/util/WaveFileWriter.h
+++ b/apps/OboeTester/app/src/main/cpp/util/WaveFileWriter.h
@@ -15,7 +15,7 @@
  */
 
 // Based on the WaveFileWriter in Java from the open source JSyn library by Phil Burk
-// https://github.com/philburk/jsyn/blob/master/src/com/jsyn/util/WaveFileWriter.java
+// https://github.com/philburk/jsyn/blob/master/src/main/java/com/jsyn/util/WaveFileWriter.java
 
 #ifndef UTIL_WAVE_FILE_WRITER
 #define UTIL_WAVE_FILE_WRITER
diff --git a/apps/OboeTester/app/src/main/ic_launcher-playstore.png b/apps/OboeTester/app/src/main/ic_launcher-playstore.png
new file mode 100644
index 0000000..3e81c2c
--- /dev/null
+++ b/apps/OboeTester/app/src/main/ic_launcher-playstore.png
Binary files differ
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AnalyzerActivity.java b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AnalyzerActivity.java
deleted file mode 100644
index a287286..0000000
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AnalyzerActivity.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-package com.google.sample.oboe.manualtest;
-
-import android.Manifest;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.support.annotation.NonNull;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
-import android.util.Log;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-
-/**
- * Activity to measure latency on a full duplex stream.
- */
-public class AnalyzerActivity extends TestInputActivity {
-
-    private static final int MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE = 1001;
-
-    public static final String KEY_IN_SHARING = "in_sharing";
-    public static final String KEY_OUT_SHARING = "out_sharing";
-    public static final String VALUE_SHARING_EXCLUSIVE = "exclusive";
-    public static final String VALUE_SHARING_SHARED = "shared";
-
-    public static final String KEY_IN_PERF = "in_perf";
-    public static final String KEY_OUT_PERF = "out_perf";
-    public static final String VALUE_PERF_LOW_LATENCY = "lowlat";
-    public static final String VALUE_PERF_POWERSAVE = "powersave";
-    public static final String VALUE_PERF_NONE = "none";
-
-    public static final String KEY_IN_CHANNELS = "in_channels";
-    public static final String KEY_OUT_CHANNELS = "out_channels";
-    public static final int VALUE_DEFAULT_CHANNELS = 2;
-
-    public static final String KEY_SAMPLE_RATE = "sample_rate";
-    public static final int VALUE_DEFAULT_SAMPLE_RATE = 48000;
-
-    protected static final String KEY_FILE_NAME = "file";
-    protected static final String KEY_BUFFER_BURSTS = "buffer_bursts";
-
-    public static final String VALUE_UNSPECIFIED = "unspecified";
-    public static final String KEY_IN_API = "in_api";
-    public static final String KEY_OUT_API = "out_api";
-    public static final String VALUE_API_AAUDIO = "aaudio";
-    public static final String VALUE_API_OPENSLES = "opensles";
-
-    AudioOutputTester mAudioOutTester;
-    protected BufferSizeView mBufferSizeView;
-    protected String mResultFileName;
-    private String mTestResults;
-
-    // Note that these string must match the enum result_code in LatencyAnalyzer.h
-    String resultCodeToString(int resultCode) {
-        switch (resultCode) {
-            case 0:
-                return "OK";
-            case -99:
-                return "ERROR_NOISY";
-            case -98:
-                return "ERROR_VOLUME_TOO_LOW";
-            case -97:
-                return "ERROR_VOLUME_TOO_HIGH";
-            case -96:
-                return "ERROR_CONFIDENCE";
-            case -95:
-                return "ERROR_INVALID_STATE";
-            case -94:
-                return "ERROR_GLITCHES";
-            case -93:
-                return "ERROR_NO_LOCK";
-            default:
-                return "UNKNOWN";
-        }
-    }
-
-    public native int getAnalyzerState();
-    public native boolean isAnalyzerDone();
-    public native int getMeasuredResult();
-    public native int getResetCount();
-
-    @NonNull
-    protected String getCommonTestReport() {
-        StringBuffer report = new StringBuffer();
-        // Add some extra information for the remote tester.
-        report.append("build.fingerprint = " + Build.FINGERPRINT + "\n");
-        try {
-            PackageInfo pinfo = getPackageManager().getPackageInfo(getPackageName(), 0);
-            report.append(String.format("test.version = %s\n", pinfo.versionName));
-            report.append(String.format("test.version.code = %d\n", pinfo.versionCode));
-        } catch (PackageManager.NameNotFoundException e) {
-        }
-        report.append("time.millis = " + System.currentTimeMillis() + "\n");
-
-        // INPUT
-        report.append(mAudioInputTester.actualConfiguration.dump());
-        AudioStreamBase inStream = mAudioInputTester.getCurrentAudioStream();
-        report.append(String.format("in.burst.frames = %d\n", inStream.getFramesPerBurst()));
-        report.append(String.format("in.xruns = %d\n", inStream.getXRunCount()));
-
-        // OUTPUT
-        report.append(mAudioOutTester.actualConfiguration.dump());
-        AudioStreamBase outStream = mAudioOutTester.getCurrentAudioStream();
-        report.append(String.format("out.burst.frames = %d\n", outStream.getFramesPerBurst()));
-        int bufferSize = outStream.getBufferSizeInFrames();
-        report.append(String.format("out.buffer.size.frames = %d\n", bufferSize));
-        int bufferCapacity = outStream.getBufferCapacityInFrames();
-        report.append(String.format("out.buffer.capacity.frames = %d\n", bufferCapacity));
-        report.append(String.format("out.xruns = %d\n", outStream.getXRunCount()));
-
-        return report.toString();
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mAudioOutTester = addAudioOutputTester();
-        mBufferSizeView = (BufferSizeView) findViewById(R.id.buffer_size_view);
-    }
-
-    @Override
-    protected void resetConfiguration() {
-        super.resetConfiguration();
-        mAudioOutTester.reset();
-
-        StreamContext streamContext = getFirstInputStreamContext();
-        if (streamContext != null) {
-            if (streamContext.configurationView != null) {
-                streamContext.configurationView.setFormat(StreamConfiguration.AUDIO_FORMAT_PCM_FLOAT);
-                streamContext.configurationView.setFormatConversionAllowed(true);
-            }
-        }
-        streamContext = getFirstOutputStreamContext();
-        if (streamContext != null) {
-            if (streamContext.configurationView != null) {
-                streamContext.configurationView.setFormat(StreamConfiguration.AUDIO_FORMAT_PCM_FLOAT);
-                streamContext.configurationView.setFormatConversionAllowed(true);
-            }
-        }
-    }
-
-    @Override
-    public void openAudio() throws IOException {
-        super.openAudio();
-        if (mBufferSizeView != null) {
-            mBufferSizeView.onStreamOpened((OboeAudioStream) mAudioOutTester.getCurrentAudioStream());
-        }
-    }
-
-    public void onStreamClosed() {
-        Toast.makeText(getApplicationContext(),
-                "Stream was closed or disconnected!",
-                Toast.LENGTH_SHORT)
-                .show();
-        stopAudioTest();
-    }
-
-    public void stopAudioTest() {
-    }
-
-    private int getApiFromText(String text) {
-        if (VALUE_API_AAUDIO.equals(text)) {
-            return StreamConfiguration.NATIVE_API_AAUDIO;
-        } else if (VALUE_API_OPENSLES.equals(text)) {
-            return StreamConfiguration.NATIVE_API_OPENSLES;
-        } else {
-            return StreamConfiguration.NATIVE_API_UNSPECIFIED;
-        }
-    }
-
-    private int getPerfFromText(String text) {
-        if (VALUE_PERF_NONE.equals(text)) {
-            return StreamConfiguration.PERFORMANCE_MODE_NONE;
-        } else if (VALUE_PERF_POWERSAVE.equals(text)) {
-            return StreamConfiguration.PERFORMANCE_MODE_POWER_SAVING;
-        } else {
-            return StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY;
-        }
-    }
-
-    private int getSharingFromText(String text) {
-        if (VALUE_SHARING_SHARED.equals(text)) {
-            return StreamConfiguration.SHARING_MODE_SHARED;
-        } else {
-            return StreamConfiguration.SHARING_MODE_EXCLUSIVE;
-        }
-    }
-
-    void configureStreamsFromBundle(Bundle bundle) {
-        // Configure settings
-        StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration;
-        StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
-
-        requestedInConfig.reset();
-        requestedOutConfig.reset();
-
-        // OpenSL ES or AAudio API
-        String text = bundle.getString(KEY_IN_API, VALUE_UNSPECIFIED);
-        int audioApi = getApiFromText(text);
-        requestedInConfig.setNativeApi(audioApi);
-        text = bundle.getString(KEY_OUT_API, VALUE_UNSPECIFIED);
-        audioApi = getApiFromText(text);
-        requestedOutConfig.setNativeApi(audioApi);
-
-        // channnels
-        int inChannels = bundle.getInt(KEY_IN_CHANNELS, VALUE_DEFAULT_CHANNELS);
-        requestedInConfig.setChannelCount(inChannels);
-        int outChannels = bundle.getInt(KEY_OUT_CHANNELS, VALUE_DEFAULT_CHANNELS);
-        requestedOutConfig.setChannelCount(outChannels);
-
-        // performance mode
-        text = bundle.getString(KEY_IN_PERF, VALUE_PERF_LOW_LATENCY);
-        int perfMode = getPerfFromText(text);
-        requestedInConfig.setPerformanceMode(perfMode);
-        text = bundle.getString(KEY_OUT_PERF, VALUE_PERF_LOW_LATENCY);
-        perfMode = getPerfFromText(text);
-        requestedOutConfig.setPerformanceMode(perfMode);
-
-        int sampleRate = bundle.getInt(KEY_SAMPLE_RATE, VALUE_DEFAULT_SAMPLE_RATE);
-        requestedInConfig.setSampleRate(sampleRate);
-        requestedOutConfig.setSampleRate(sampleRate);
-
-        text = bundle.getString(KEY_IN_SHARING, VALUE_SHARING_EXCLUSIVE);
-        int sharingMode = getSharingFromText(text);
-        requestedInConfig.setSharingMode(sharingMode);
-        text = bundle.getString(KEY_OUT_SHARING, VALUE_SHARING_EXCLUSIVE);
-        sharingMode = getSharingFromText(text);
-        requestedOutConfig.setSharingMode(sharingMode);
-    }
-
-    void writeTestResultIfPermitted(String resultString) {
-        // Here, thisActivity is the current activity
-        if (ContextCompat.checkSelfPermission(this,
-                Manifest.permission.WRITE_EXTERNAL_STORAGE)
-                != PackageManager.PERMISSION_GRANTED) {
-            mTestResults = resultString;
-            ActivityCompat.requestPermissions(this,
-                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
-                    MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE);
-        } else {
-            // Permission has already been granted
-            writeTestResult(resultString);
-        }
-    }
-
-    void maybeWriteTestResult(String resultString) {
-        if (mResultFileName == null) return;
-        writeTestResultIfPermitted(resultString);
-    }
-
-    @Override
-    public void onRequestPermissionsResult(int requestCode,
-                                           String[] permissions,
-                                           int[] grantResults) {
-        switch (requestCode) {
-            case MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE: {
-                // If request is cancelled, the result arrays are empty.
-                if (grantResults.length > 0
-                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
-                    writeTestResult(mTestResults);
-                } else {
-                    showToast("Writing external storage needed for test results.");
-                }
-                return;
-            }
-        }
-    }
-
-    private void writeTestInBackground(final String resultString) {
-        new Thread() {
-            public void run() {
-                writeTestResult(resultString);
-            }
-        }.start();
-    }
-
-    // Run this in a background thread.
-    private void writeTestResult(String resultString) {
-        File resultFile = new File(mResultFileName);
-        Writer writer = null;
-        try {
-            writer = new OutputStreamWriter(new FileOutputStream(resultFile));
-            writer.write(resultString);
-        } catch (
-                IOException e) {
-            e.printStackTrace();
-            showErrorToast(" writing result file. " + e.getMessage());
-        } finally {
-            if (writer != null) {
-                try {
-                    writer.close();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-
-        mResultFileName = null;
-    }
-
-
-}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioMidiTester.java b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioMidiTester.java
deleted file mode 100644
index 0cb920c..0000000
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioMidiTester.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * 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.
- */
-package com.google.sample.oboe.manualtest;
-
-
-import android.media.midi.MidiDeviceService;
-import android.media.midi.MidiReceiver;
-import android.util.Log;
-
-import com.mobileer.miditools.MidiConstants;
-import com.mobileer.miditools.MidiFramer;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-/**
- * Measure the latency of various output paths by playing a blip.
- * Report the results back to the TestListeners.
- */
-public class AudioMidiTester extends MidiDeviceService {
-
-    // Sometimes the service can be run without the MainActivity being run!
-    static {
-        // Must match name in CMakeLists.txt
-        System.loadLibrary("oboetester");
-    }
-
-    private static final float MAX_TOUCH_LATENCY = 0.200f;
-    private static final float MAX_OUTPUT_LATENCY = 0.600f;
-    private static final float ANALYSIS_TIME_MARGIN = 0.250f;
-
-    private static final float ANALYSIS_TIME_DELAY = MAX_OUTPUT_LATENCY;
-    private static final float ANALYSIS_TIME_TOTAL = MAX_TOUCH_LATENCY + MAX_OUTPUT_LATENCY;
-    private static final float ANALYSIS_TIME_MAX = ANALYSIS_TIME_TOTAL + ANALYSIS_TIME_MARGIN;
-    private static final int ANALYSIS_SAMPLE_RATE = 48000; // need not match output rate
-
-    private ArrayList<TestListener> mListeners = new ArrayList<TestListener>();
-    private MyMidiReceiver mReceiver = new MyMidiReceiver();
-    private MidiFramer mMidiFramer = new MidiFramer(mReceiver);
-    private boolean mRecordEnabled = true;
-
-    private static AudioMidiTester mInstance;
-    private AudioRecordThread mRecorder;
-    private TapLatencyAnalyser mTapLatencyAnalyser;
-
-    private AudioOutputTester mAudioOutputTester;
-
-    public static class TestResult {
-        public float[] samples;
-        public float[] filtered;
-        public int frameRate;
-        public TapLatencyAnalyser.TapLatencyEvent[] events;
-    }
-
-    public static interface TestListener {
-        public void onTestFinished(TestResult result);
-
-        public void onNoteOn(int pitch);
-    }
-
-    /**
-     * This is a Service so it is only created when a client requests the service.
-     */
-    public AudioMidiTester() {
-        mInstance = this;
-    }
-
-    public void addTestListener(TestListener listener) {
-        mListeners.add(listener);
-    }
-
-    public void removeTestListener(TestListener listener) {
-        mListeners.remove(listener);
-    }
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        if (mRecordEnabled) {
-            mRecorder = new AudioRecordThread(ANALYSIS_SAMPLE_RATE,
-                    1,
-                    (int) (ANALYSIS_TIME_MAX * ANALYSIS_SAMPLE_RATE));
-        }
-
-        mAudioOutputTester = AudioOutputTester.getInstance();
-
-        mTapLatencyAnalyser = new TapLatencyAnalyser();
-    }
-
-    @Override
-    public void onDestroy() {
-        // do stuff here
-        super.onDestroy();
-    }
-
-    public static AudioMidiTester getInstance() {
-        return mInstance;
-    }
-
-    class MyMidiReceiver extends MidiReceiver {
-        public void onSend(byte[] data, int offset,
-                           int count, long timestamp) throws IOException {
-            // parse MIDI
-            byte command = (byte) (data[0] & 0x0F0);
-            if (command == MidiConstants.STATUS_NOTE_ON) {
-                if (data[2] == 0) {
-                    noteOff(data[1]);
-                } else {
-                    noteOn(data[1]);
-                }
-            } else if (command == MidiConstants.STATUS_NOTE_OFF) {
-                noteOff(data[1]);
-            }
-            Log.i(TapToToneActivity.TAG, "MIDI command = " + command);
-        }
-    }
-
-    private void noteOn(byte b) {
-        trigger();
-        fireNoteOn(b);
-    }
-
-    private void fireNoteOn(byte pitch) {
-        for (TestListener listener : mListeners) {
-            listener.onNoteOn(pitch);
-        }
-    }
-
-    private void noteOff(byte b) {}
-
-    @Override
-    public MidiReceiver[] onGetInputPortReceivers() {
-        return new MidiReceiver[]{mMidiFramer};
-    }
-
-
-    public void start() throws IOException {
-        if (mRecordEnabled) {
-            mRecorder.startAudio();
-        }
-    }
-
-    public void trigger() {
-        mAudioOutputTester.trigger();
-        if (mRecordEnabled) {
-            // schedule an analysis to start in the near future
-            int numSamples = (int) (mRecorder.getSampleRate() * ANALYSIS_TIME_DELAY);
-            Runnable task = new Runnable() {
-                public void run() {
-                    new Thread() {
-                        public void run() {
-                            analyzeCapturedAudio();
-                        }
-                    }.start();
-                }
-            };
-
-            mRecorder.scheduleTask(numSamples, task);
-        }
-    }
-
-    private void analyzeCapturedAudio() {
-        if (!mRecordEnabled) return;
-        int numSamples = (int) (mRecorder.getSampleRate() * ANALYSIS_TIME_TOTAL);
-        float[] buffer = new float[numSamples];
-        mRecorder.setCaptureEnabled(false); // TODO wait for it to settle
-        int numRead = mRecorder.readMostRecent(buffer);
-
-        TestResult result = new TestResult();
-        result.samples = buffer;
-        result.frameRate = mRecorder.getSampleRate();
-        result.events = mTapLatencyAnalyser.analyze(buffer, 0, numRead);
-        result.filtered = mTapLatencyAnalyser.getFilteredBuffer();
-        mRecorder.setCaptureEnabled(true);
-        // notify listeners
-        for (TestListener listener : mListeners) {
-            listener.onTestFinished(result);
-        }
-    }
-
-
-    public void stop() {
-        if (mRecordEnabled) {
-            mRecorder.stopAudio();
-        }
-    }
-
-}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/BaseAutoGlitchActivity.java b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/BaseAutoGlitchActivity.java
deleted file mode 100644
index 45d0e7c..0000000
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/BaseAutoGlitchActivity.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright 2019 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.
- */
-
-package com.google.sample.oboe.manualtest;
-
-import android.os.Bundle;
-
-import java.io.IOException;
-
-public class BaseAutoGlitchActivity extends GlitchActivity {
-
-    private static final int SETUP_TIME_SECONDS = 4; // Time for the stream to settle.
-    protected static final int DEFAULT_DURATION_SECONDS = 8; // Run time for each test.
-    private static final int DEFAULT_GAP_MILLIS = 400; // Idle time between each test.
-    private static final String TEXT_SKIP = "SKIP";
-    public static final String TEXT_PASS = "PASS";
-    public static final String TEXT_FAIL = "FAIL !!!!";
-
-    protected int mDurationSeconds = DEFAULT_DURATION_SECONDS;
-    protected int mGapMillis = DEFAULT_GAP_MILLIS;
-
-    protected AutomatedTestRunner mAutomatedTestRunner;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        mAutomatedTestRunner = findViewById(R.id.auto_test_runner);
-        mAutomatedTestRunner.setActivity(this);
-    }
-
-    protected void log(String text) {
-        mAutomatedTestRunner.log(text);
-    }
-
-    protected void appendFailedSummary(String text) {
-        mAutomatedTestRunner.appendFailedSummary(text);
-    }
-
-    protected void appendSummary(String text) {
-        mAutomatedTestRunner.appendSummary(text);
-    }
-
-    @Override
-    public void onStopTest() {
-        mAutomatedTestRunner.stopTest();
-    }
-
-    protected String getConfigText(StreamConfiguration config) {
-        int channel = (config.getDirection() == StreamConfiguration.DIRECTION_OUTPUT)
-                ? getOutputChannel() : getInputChannel();
-        return ((config.getDirection() == StreamConfiguration.DIRECTION_OUTPUT) ? "OUT" : "INP")
-                + (config.isMMap() ? "-M" : "-L")
-                + ", ID = " + String.format("%2d", config.getDeviceId())
-                + ", SR = " + String.format("%5d", config.getSampleRate())
-                + ", Perf = " + StreamConfiguration.convertPerformanceModeToText(
-                config.getPerformanceMode())
-                + ", " + StreamConfiguration.convertSharingModeToText(config.getSharingMode())
-                + ", ch = " + config.getChannelCount() + "[" + channel + "]";
-    }
-
-    public final static int TEST_RESULT_FAILED = -2;
-    public final static int TEST_RESULT_WARNING = -1;
-    public final static int TEST_RESULT_SKIPPED = 0;
-    public final static int TEST_RESULT_PASSED = 1;
-
-    // Run test based on the requested input/output configurations.
-    protected int testConfigurations() throws InterruptedException {
-        int result = TEST_RESULT_SKIPPED;
-        mAutomatedTestRunner.incrementTestCount();
-        if ((getSingleTestIndex() >= 0) && (mAutomatedTestRunner.getTestCount() != getSingleTestIndex())) {
-            return result;
-        }
-
-        log("========================== #" + mAutomatedTestRunner.getTestCount());
-
-        StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration;
-        StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
-
-        StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration;
-        StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration;
-
-        log("Requested:");
-        log("  " + getConfigText(requestedInConfig));
-        log("  " + getConfigText(requestedOutConfig));
-
-        String reason = "";
-        boolean openFailed = false;
-        try {
-            openAudio(); // this will fill in actualConfig
-            log("Actual:");
-            log("  " + getConfigText(actualInConfig));
-            log("  " + getConfigText(actualOutConfig));
-            // Set output size to a level that will avoid glitches.
-            AudioStreamBase stream = mAudioOutTester.getCurrentAudioStream();
-            int sizeFrames = stream.getBufferCapacityInFrames() / 2;
-            stream.setBufferSizeInFrames(sizeFrames);
-        } catch (Exception e) {
-            openFailed = true;
-            log(e.getMessage());
-            reason = e.getMessage();
-        }
-
-        // The test would only be worth running if we got the configuration we requested on input or output.
-        String skipReason = shouldTestBeSkipped();
-        boolean skipped = skipReason.length() > 0;
-        boolean valid = !openFailed && !skipped;
-        boolean startFailed = false;
-        if (valid) {
-            try {
-                startAudioTest();
-            } catch (IOException e) {
-                e.printStackTrace();
-                valid = false;
-                startFailed = true;
-                log(e.getMessage());
-                reason = e.getMessage();
-            }
-        }
-        mAutomatedTestRunner.flushLog();
-
-        if (valid) {
-            // Check for early return until we reach full duration.
-            long now = System.currentTimeMillis();
-            long startedAt = now;
-            long endTime = System.currentTimeMillis() + (mDurationSeconds * 1000);
-            boolean finishedEarly = false;
-            while (now < endTime && !finishedEarly) {
-                Thread.sleep(100); // Let test run.
-                now = System.currentTimeMillis();
-                finishedEarly = isFinishedEarly();
-                if (finishedEarly) {
-                    log("Finished early after " + (now - startedAt) + " msec.");
-                }
-            }
-        }
-        int inXRuns = 0;
-        int outXRuns = 0;
-
-        if (!openFailed) {
-            // get xRuns before closing the streams.
-            inXRuns = mAudioInputTester.getCurrentAudioStream().getXRunCount();
-            outXRuns = mAudioOutTester.getCurrentAudioStream().getXRunCount();
-
-            super.stopAudioTest();
-        }
-
-        if (openFailed || startFailed) {
-            appendFailedSummary("------ #" + mAutomatedTestRunner.getTestCount() + "\n");
-            appendFailedSummary(getConfigText(requestedInConfig) + "\n");
-            appendFailedSummary(getConfigText(requestedOutConfig) + "\n");
-            appendFailedSummary(reason + "\n");
-            mAutomatedTestRunner.incrementFailCount();
-        } else if (skipped) {
-            log(TEXT_SKIP + " - " + skipReason);
-        } else {
-            log("Result:");
-            reason += didTestFail();
-            boolean passed = reason.length() == 0;
-
-            String resultText = getShortReport();
-            resultText += ", xruns = " + inXRuns + "/" + outXRuns;
-            resultText += ", " + (passed ? TEXT_PASS : TEXT_FAIL);
-            resultText += reason;
-            log("  " + resultText);
-            if (!passed) {
-                appendFailedSummary("------ #" + mAutomatedTestRunner.getTestCount() + "\n");
-                appendFailedSummary("  " + getConfigText(actualInConfig) + "\n");
-                appendFailedSummary("  " + getConfigText(actualOutConfig) + "\n");
-                appendFailedSummary("    " + resultText + "\n");
-                mAutomatedTestRunner.incrementFailCount();
-                result = TEST_RESULT_FAILED;
-            } else {
-                mAutomatedTestRunner.incrementPassCount();
-                result = TEST_RESULT_PASSED;
-            }
-        }
-        mAutomatedTestRunner.flushLog();
-
-        // Give hardware time to settle between tests.
-        Thread.sleep(mGapMillis);
-        return result;
-    }
-
-    protected boolean isFinishedEarly() {
-        return false;
-    }
-
-    protected String shouldTestBeSkipped() {
-        String why = "";
-        StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration;
-        StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
-        StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration;
-        StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration;
-        // No point running the test if we don't get the sharing mode we requested.
-        if (actualInConfig.getSharingMode() != requestedInConfig.getSharingMode()
-                || actualOutConfig.getSharingMode() != requestedOutConfig.getSharingMode()) {
-            log("Did not get requested sharing mode.");
-            why += "share";
-        }
-        // We don't skip based on performance mode because if you request LOW_LATENCY you might
-        // get a smaller burst than if you request NONE.
-        return why;
-    }
-
-    public String didTestFail() {
-        String why = "";
-        if (getMaxSecondsWithNoGlitch() <= (mDurationSeconds - SETUP_TIME_SECONDS)) {
-            why += ", glitch";
-        }
-        return why;
-    }
-
-}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/StreamConfiguration.java b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/StreamConfiguration.java
deleted file mode 100644
index 8ad101e..0000000
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/StreamConfiguration.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package com.google.sample.oboe.manualtest;
-
-/**
- * Container for the properties of a Stream.
- *
- * This can be used to build a stream, or as a base class for a Stream,
- * or as a way to report the properties of a Stream.
- */
-
-public class StreamConfiguration {
-    public static final int UNSPECIFIED = 0;
-
-    // These must match order in Spinner and in native code and in AAudio.h
-    public static final int NATIVE_API_UNSPECIFIED = 0;
-    public static final int NATIVE_API_OPENSLES = 1;
-    public static final int NATIVE_API_AAUDIO = 2;
-
-    public static final int SHARING_MODE_EXCLUSIVE = 0; // must match AAUDIO
-    public static final int SHARING_MODE_SHARED = 1; // must match AAUDIO
-
-    public static final int AUDIO_FORMAT_PCM_16 = 1; // must match AAUDIO
-    public static final int AUDIO_FORMAT_PCM_FLOAT = 2; // must match AAUDIO
-
-    public static final int DIRECTION_OUTPUT = 0; // must match AAUDIO
-    public static final int DIRECTION_INPUT = 1; // must match AAUDIO
-
-    public static final int SESSION_ID_NONE = -1; // must match AAUDIO
-    public static final int SESSION_ID_ALLOCATE = 0; // must match AAUDIO
-
-    public static final int PERFORMANCE_MODE_NONE = 10; // must match AAUDIO
-    public static final int PERFORMANCE_MODE_POWER_SAVING = 11; // must match AAUDIO
-    public static final int PERFORMANCE_MODE_LOW_LATENCY = 12; // must match AAUDIO
-
-    public static final int RATE_CONVERSION_QUALITY_NONE = 0; // must match Oboe
-    public static final int RATE_CONVERSION_QUALITY_FASTEST = 1; // must match Oboe
-    public static final int RATE_CONVERSION_QUALITY_LOW = 2; // must match Oboe
-    public static final int RATE_CONVERSION_QUALITY_MEDIUM = 3; // must match Oboe
-    public static final int RATE_CONVERSION_QUALITY_HIGH = 4; // must match Oboe
-    public static final int RATE_CONVERSION_QUALITY_BEST = 5; // must match Oboe
-
-    public static final int STREAM_STATE_STARTING = 3; // must match Oboe
-    public static final int STREAM_STATE_STARTED = 4; // must match Oboe
-
-    public static final int INPUT_PRESET_GENERIC = 1; // must match Oboe
-    public static final int INPUT_PRESET_CAMCORDER = 5; // must match Oboe
-    public static final int INPUT_PRESET_VOICE_RECOGNITION = 6; // must match Oboe
-    public static final int INPUT_PRESET_VOICE_COMMUNICATION = 7; // must match Oboe
-    public static final int INPUT_PRESET_UNPROCESSED = 9; // must match Oboe
-    public static final int INPUT_PRESET_VOICE_PERFORMANCE = 10; // must match Oboe
-
-    public static final int ERROR_DISCONNECTED = -899; // must match Oboe
-
-    private int mNativeApi;
-    private int mBufferCapacityInFrames;
-    private int mChannelCount;
-    private int mDeviceId;
-    private int mSessionId;
-    private int mDirection; // does not get reset
-    private int mFormat;
-    private int mSampleRate;
-    private int mSharingMode;
-    private int mPerformanceMode;
-    private boolean mFormatConversionAllowed;
-    private boolean mChannelConversionAllowed;
-    private int mRateConversionQuality;
-    private int mInputPreset;
-
-    private int mFramesPerBurst = 0;
-
-    private boolean mMMap = false;
-
-    public StreamConfiguration() {
-        reset();
-    }
-
-    public void reset() {
-        mNativeApi = NATIVE_API_UNSPECIFIED;
-        mBufferCapacityInFrames = UNSPECIFIED;
-        mChannelCount = UNSPECIFIED;
-        mDeviceId = UNSPECIFIED;
-        mSessionId = -1;
-        mFormat = AUDIO_FORMAT_PCM_FLOAT;
-        mSampleRate = UNSPECIFIED;
-        mSharingMode = SHARING_MODE_EXCLUSIVE;
-        mPerformanceMode = PERFORMANCE_MODE_LOW_LATENCY;
-        mInputPreset = INPUT_PRESET_VOICE_RECOGNITION;
-        mFormatConversionAllowed = false;
-        mChannelConversionAllowed = false;
-        mRateConversionQuality = RATE_CONVERSION_QUALITY_NONE;
-        mMMap = NativeEngine.isMMapSupported();
-    }
-
-    public int getFramesPerBurst() {
-        return mFramesPerBurst;
-    }
-
-    public void setFramesPerBurst(int framesPerBurst) {
-        this.mFramesPerBurst = framesPerBurst;
-    }
-
-    public int getBufferCapacityInFrames() {
-        return mBufferCapacityInFrames;
-    }
-
-    public void setBufferCapacityInFrames(int bufferCapacityInFrames) {
-        this.mBufferCapacityInFrames = bufferCapacityInFrames;
-    }
-
-    public int getFormat() {
-        return mFormat;
-    }
-
-    public void setFormat(int format) {
-        this.mFormat = format;
-    }
-
-    public int getDirection() {
-        return mDirection;
-    }
-
-    public void setDirection(int direction) {
-        this.mDirection = direction;
-    }
-
-    public int getPerformanceMode() {
-        return mPerformanceMode;
-    }
-
-    public void setPerformanceMode(int performanceMode) {
-        this.mPerformanceMode = performanceMode;
-    }
-
-    static String convertPerformanceModeToText(int performanceMode) {
-        switch(performanceMode) {
-            case PERFORMANCE_MODE_NONE:
-                return "NO";
-            case PERFORMANCE_MODE_POWER_SAVING:
-                return "PS";
-            case PERFORMANCE_MODE_LOW_LATENCY:
-                return "LL";
-            default:
-                return "??";
-        }
-    }
-
-    public int getInputPreset() {
-        return mInputPreset;
-    }
-
-    public void setInputPreset(int inputPreset) {
-        this.mInputPreset = inputPreset;
-    }
-
-    public int getSharingMode() {
-        return mSharingMode;
-    }
-
-    public void setSharingMode(int sharingMode) {
-        this.mSharingMode = sharingMode;
-    }
-
-    static String convertSharingModeToText(int sharingMode) {
-        switch(sharingMode) {
-            case SHARING_MODE_SHARED:
-                return "SH";
-            case SHARING_MODE_EXCLUSIVE:
-                return "EX";
-            default:
-                return "??";
-        }
-    }
-
-    public static String convertFormatToText(int format) {
-        switch(format) {
-            case UNSPECIFIED:
-                return "Unspecified";
-            case AUDIO_FORMAT_PCM_16:
-                return "I16";
-            case AUDIO_FORMAT_PCM_FLOAT:
-                return "Float";
-            default:
-                return "Invalid";
-        }
-    }
-
-    public static String convertNativeApiToText(int api) {
-        switch(api) {
-            case NATIVE_API_UNSPECIFIED:
-                return "Unspec";
-            case NATIVE_API_AAUDIO:
-                return "AAudio";
-            case NATIVE_API_OPENSLES:
-                return "OpenSL";
-            default:
-                return "Invalid";
-        }
-    }
-
-
-    public String dump() {
-        String prefix = (getDirection() == DIRECTION_INPUT) ? "in" : "out";
-        StringBuffer message = new StringBuffer();
-        message.append(String.format("%s.channels = %d\n", prefix, mChannelCount));
-        message.append(String.format("%s.perf = %s\n", prefix,
-                convertPerformanceModeToText(mPerformanceMode).toLowerCase()));
-        if (getDirection() == DIRECTION_INPUT) {
-            message.append(String.format("%s.preset = %s\n", prefix,
-                    convertInputPresetToText(mInputPreset).toLowerCase()));
-        }
-        message.append(String.format("%s.sharing = %s\n", prefix,
-                convertSharingModeToText(mSharingMode).toLowerCase()));
-        message.append(String.format("%s.api = %s\n", prefix,
-                convertNativeApiToText(getNativeApi()).toLowerCase()));
-        message.append(String.format("%s.rate = %d\n", prefix, mSampleRate));
-        message.append(String.format("%s.device = %d\n", prefix, mDeviceId));
-        message.append(String.format("%s.mmap = %s\n", prefix, isMMap() ? "yes" : "no"));
-        message.append(String.format("%s.rate.conversion.quality = %d\n", prefix, mRateConversionQuality));
-        return message.toString();
-    }
-
-    // text must match menu values
-    public static final String NAME_INPUT_PRESET_GENERIC = "Generic";
-    public static final String NAME_INPUT_PRESET_CAMCORDER = "Camcorder";
-    public static final String NAME_INPUT_PRESET_VOICE_RECOGNITION = "VoiceRec";
-    public static final String NAME_INPUT_PRESET_VOICE_COMMUNICATION = "VoiceComm";
-    public static final String NAME_INPUT_PRESET_UNPROCESSED = "Unprocessed";
-    public static final String NAME_INPUT_PRESET_VOICE_PERFORMANCE = "Performance";
-
-    public static String convertInputPresetToText(int inputPreset) {
-        switch(inputPreset) {
-            case INPUT_PRESET_GENERIC:
-                return NAME_INPUT_PRESET_GENERIC;
-            case INPUT_PRESET_CAMCORDER:
-                return NAME_INPUT_PRESET_CAMCORDER;
-            case INPUT_PRESET_VOICE_RECOGNITION:
-                return NAME_INPUT_PRESET_VOICE_RECOGNITION;
-            case INPUT_PRESET_VOICE_COMMUNICATION:
-                return NAME_INPUT_PRESET_VOICE_COMMUNICATION;
-            case INPUT_PRESET_UNPROCESSED:
-                return NAME_INPUT_PRESET_UNPROCESSED;
-            case INPUT_PRESET_VOICE_PERFORMANCE:
-                return NAME_INPUT_PRESET_VOICE_PERFORMANCE;
-            default:
-                return "Invalid";
-        }
-    }
-
-    private static boolean matchInputPreset(String text, int preset) {
-        return convertInputPresetToText(preset).toLowerCase().equals(text);
-    }
-
-    /**
-     * Case insensitive.
-     * @param text
-     * @return inputPreset, eg. INPUT_PRESET_CAMCORDER
-     */
-    public static int convertTextToInputPreset(String text) {
-        text = text.toLowerCase();
-        if (matchInputPreset(text, INPUT_PRESET_GENERIC)) {
-            return INPUT_PRESET_GENERIC;
-        } else if (matchInputPreset(text, INPUT_PRESET_CAMCORDER)) {
-            return INPUT_PRESET_CAMCORDER;
-        } else if (matchInputPreset(text, INPUT_PRESET_VOICE_RECOGNITION)) {
-            return INPUT_PRESET_VOICE_RECOGNITION;
-        } else if (matchInputPreset(text, INPUT_PRESET_VOICE_COMMUNICATION)) {
-            return INPUT_PRESET_VOICE_COMMUNICATION;
-        } else if (matchInputPreset(text, INPUT_PRESET_UNPROCESSED)) {
-            return INPUT_PRESET_UNPROCESSED;
-        } else if (matchInputPreset(text, INPUT_PRESET_VOICE_PERFORMANCE)) {
-            return INPUT_PRESET_VOICE_PERFORMANCE;
-        }
-        return -1;
-    }
-
-    public int getChannelCount() {
-        return mChannelCount;
-    }
-
-    public void setChannelCount(int channelCount) {
-        this.mChannelCount = channelCount;
-    }
-
-    public int getSampleRate() {
-        return mSampleRate;
-    }
-
-    public void setSampleRate(int sampleRate) {
-        this.mSampleRate = sampleRate;
-    }
-
-    public int getDeviceId() {
-        return mDeviceId;
-    }
-
-    public void setDeviceId(int deviceId) {
-        this.mDeviceId = deviceId;
-    }
-
-    public int getSessionId() {
-        return mSessionId;
-    }
-
-    public void setSessionId(int sessionId) {
-        mSessionId = sessionId;
-    }
-
-    public boolean isMMap() {
-        return mMMap;
-    }
-
-    public void setMMap(boolean b) { mMMap = b; }
-
-    public int getNativeApi() {
-        return mNativeApi;
-    }
-
-    public void setNativeApi(int nativeApi) {
-        mNativeApi = nativeApi;
-    }
-
-    public void setChannelConversionAllowed(boolean b) { mChannelConversionAllowed = b; }
-
-    public boolean getChannelConversionAllowed() {
-        return mChannelConversionAllowed;
-    }
-
-    public void setFormatConversionAllowed(boolean b) {
-        mFormatConversionAllowed = b;
-    }
-
-    public boolean getFormatConversionAllowed() {
-        return mFormatConversionAllowed;
-    }
-
-    public void setRateConversionQuality(int quality) { mRateConversionQuality = quality; }
-
-    public int getRateConversionQuality() {
-        return mRateConversionQuality;
-    }
-
-}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/StreamConfigurationView.java b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/StreamConfigurationView.java
deleted file mode 100644
index 64aeb75..0000000
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/StreamConfigurationView.java
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package com.google.sample.oboe.manualtest;
-
-import android.content.Context;
-import android.media.AudioManager;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.CheckBox;
-import android.widget.Spinner;
-import android.widget.TableLayout;
-import android.widget.TableRow;
-import android.widget.TextView;
-import android.widget.LinearLayout;
-
-import com.google.sample.audio_device.AudioDeviceListEntry;
-import com.google.sample.audio_device.AudioDeviceSpinner;
-
-import java.text.BreakIterator;
-
-/**
- * View for Editing a requested StreamConfiguration
- * and displaying the actual StreamConfiguration.
- */
-
-public class StreamConfigurationView extends LinearLayout {
-
-    private StreamConfiguration  mRequestedConfiguration;
-    private StreamConfiguration  mActualConfiguration;
-
-    protected Spinner mNativeApiSpinner;
-    private TextView mActualNativeApiView;
-
-    private TextView mActualMMapView;
-    private CheckBox mRequestedMMapView;
-    private TextView mActualExclusiveView;
-    private TextView mActualPerformanceView;
-    private Spinner  mPerformanceSpinner;
-    private CheckBox mRequestedExclusiveView;
-    private CheckBox mChannelConversionBox;
-    private CheckBox mFormatConversionBox;
-    private Spinner  mChannelCountSpinner;
-    private TextView mActualChannelCountView;
-    private TextView mActualFormatView;
-
-    private TextView mActualInputPresetView;
-    private Spinner  mInputPresetSpinner;
-    private TableRow mInputPresetTableRow;
-    private Spinner  mFormatSpinner;
-    private Spinner  mSampleRateSpinner;
-    private Spinner  mRateConversionQualitySpinner;
-    private TextView mActualSampleRateView;
-    private LinearLayout mHideableView;
-
-    private AudioDeviceSpinner mDeviceSpinner;
-    private TextView mActualSessionIdView;
-    private CheckBox mRequestAudioEffect;
-
-    private TextView mStreamInfoView;
-    private TextView mStreamStatusView;
-    private TextView mOptionExpander;
-    private String mHideSettingsText;
-    private String mShowSettingsText;
-
-    // Create an anonymous implementation of OnClickListener
-    private View.OnClickListener mToggleListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            if (mHideableView.isShown()) {
-                hideSettingsView();
-            } else {
-                showSettingsView();
-            }
-        }
-    };
-
-    public static String yesOrNo(boolean b) {
-        return b ?  "YES" : "NO";
-    }
-
-    private void updateSettingsViewText() {
-        if (mHideableView.isShown()) {
-            mOptionExpander.setText(mHideSettingsText);
-        } else {
-            mOptionExpander.setText(mShowSettingsText);
-        }
-    }
-
-    public void showSettingsView() {
-        mHideableView.setVisibility(View.VISIBLE);
-        updateSettingsViewText();
-    }
-
-    public void hideSampleRateMenu() {
-        if (mSampleRateSpinner != null) {
-            mSampleRateSpinner.setVisibility(View.GONE);
-        }
-    }
-
-    public void hideSettingsView() {
-        mHideableView.setVisibility(View.GONE);
-        updateSettingsViewText();
-    }
-
-    public StreamConfigurationView(Context context) {
-        super(context);
-        initializeViews(context);
-    }
-
-    public StreamConfigurationView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        initializeViews(context);
-    }
-
-    public StreamConfigurationView(Context context,
-                                   AttributeSet attrs,
-                                   int defStyle) {
-        super(context, attrs, defStyle);
-        initializeViews(context);
-    }
-
-    /**
-     * Inflates the views in the layout.
-     *
-     * @param context
-     *           the current context for the view.
-     */
-    private void initializeViews(Context context) {
-        LayoutInflater inflater = (LayoutInflater) context
-                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        inflater.inflate(R.layout.stream_config, this);
-
-        mHideSettingsText = getResources().getString(R.string.hint_hide_settings);
-        mShowSettingsText = getResources().getString(R.string.hint_show_settings);
-
-        mHideableView = (LinearLayout) findViewById(R.id.hideableView);
-
-        mOptionExpander = (TextView) findViewById(R.id.toggle_stream_config);
-        mOptionExpander.setOnClickListener(mToggleListener);
-
-        mNativeApiSpinner = (Spinner) findViewById(R.id.spinnerNativeApi);
-        mNativeApiSpinner.setOnItemSelectedListener(new NativeApiSpinnerListener());
-        mNativeApiSpinner.setSelection(StreamConfiguration.NATIVE_API_UNSPECIFIED);
-
-        mActualNativeApiView = (TextView) findViewById(R.id.actualNativeApi);
-
-        mChannelConversionBox = (CheckBox) findViewById(R.id.checkChannelConversion);
-        mChannelConversionBox.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mRequestedConfiguration.setChannelConversionAllowed(mChannelConversionBox.isChecked());
-            }
-        });
-
-        mFormatConversionBox = (CheckBox) findViewById(R.id.checkFormatConversion);
-        mFormatConversionBox.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mRequestedConfiguration.setFormatConversionAllowed(mFormatConversionBox.isChecked());
-            }
-        });
-
-        mActualMMapView = (TextView) findViewById(R.id.actualMMap);
-        mRequestedMMapView = (CheckBox) findViewById(R.id.requestedMMapEnable);
-        mRequestedMMapView.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mRequestedConfiguration.setMMap(mRequestedMMapView.isChecked());
-            }
-        });
-        boolean mmapSupported = NativeEngine.isMMapSupported();
-        mRequestedMMapView.setEnabled(mmapSupported);
-        mRequestedMMapView.setChecked(mmapSupported);
-
-        mActualExclusiveView = (TextView) findViewById(R.id.actualExclusiveMode);
-        mRequestedExclusiveView = (CheckBox) findViewById(R.id.requestedExclusiveMode);
-        mRequestedExclusiveView.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mRequestedConfiguration.setSharingMode(mRequestedExclusiveView.isChecked()
-                        ? StreamConfiguration.SHARING_MODE_EXCLUSIVE
-                        : StreamConfiguration.SHARING_MODE_SHARED);
-            }
-        });
-
-        boolean mmapExclusiveSupported = NativeEngine.isMMapExclusiveSupported();
-        mRequestedExclusiveView.setEnabled(mmapExclusiveSupported);
-        mRequestedExclusiveView.setChecked(mmapExclusiveSupported);
-
-        mActualSessionIdView = (TextView) findViewById(R.id.sessionId);
-        mRequestAudioEffect = (CheckBox) findViewById(R.id.requestAudioEffect);
-        mRequestAudioEffect.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mRequestedConfiguration.setSessionId(mRequestAudioEffect.isChecked()
-                        ? StreamConfiguration.SESSION_ID_ALLOCATE
-                        : StreamConfiguration.SESSION_ID_NONE);
-            }
-        });
-
-        mActualSampleRateView = (TextView) findViewById(R.id.actualSampleRate);
-        mSampleRateSpinner = (Spinner) findViewById(R.id.spinnerSampleRate);
-        mSampleRateSpinner.setOnItemSelectedListener(new SampleRateSpinnerListener());
-
-        mActualChannelCountView = (TextView) findViewById(R.id.actualChannelCount);
-        mChannelCountSpinner = (Spinner) findViewById(R.id.spinnerChannelCount);
-        mChannelCountSpinner.setOnItemSelectedListener(new ChannelCountSpinnerListener());
-
-        mActualFormatView = (TextView) findViewById(R.id.actualAudioFormat);
-        mFormatSpinner = (Spinner) findViewById(R.id.spinnerFormat);
-        mFormatSpinner.setOnItemSelectedListener(new FormatSpinnerListener());
-
-        mRateConversionQualitySpinner = (Spinner) findViewById(R.id.spinnerSRCQuality);
-        mRateConversionQualitySpinner.setOnItemSelectedListener(new RateConversionQualitySpinnerListener());
-
-        mActualPerformanceView = (TextView) findViewById(R.id.actualPerformanceMode);
-        mPerformanceSpinner = (Spinner) findViewById(R.id.spinnerPerformanceMode);
-        mPerformanceSpinner.setOnItemSelectedListener(new PerformanceModeSpinnerListener());
-        mPerformanceSpinner.setSelection(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY
-                - StreamConfiguration.PERFORMANCE_MODE_NONE);
-
-        mInputPresetTableRow = (TableRow) findViewById(R.id.rowInputPreset);
-        mActualInputPresetView = (TextView) findViewById(R.id.actualInputPreset);
-        mInputPresetSpinner = (Spinner) findViewById(R.id.spinnerInputPreset);
-        mInputPresetSpinner.setOnItemSelectedListener(new InputPresetSpinnerListener());
-        mInputPresetSpinner.setSelection(2); // TODO need better way to select voice recording default
-
-        mStreamInfoView = (TextView) findViewById(R.id.streamInfo);
-
-        mStreamStatusView = (TextView) findViewById(R.id.statusView);
-
-        mDeviceSpinner = (AudioDeviceSpinner) findViewById(R.id.devices_spinner);
-        mDeviceSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
-            @Override
-            public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
-                int id =  ((AudioDeviceListEntry) mDeviceSpinner.getSelectedItem()).getId();
-                mRequestedConfiguration.setDeviceId(id);
-            }
-
-            @Override
-            public void onNothingSelected(AdapterView<?> adapterView) {
-                mRequestedConfiguration.setDeviceId(StreamConfiguration.UNSPECIFIED);
-            }
-        });
-
-        showSettingsView();
-    }
-
-    public void setOutput(boolean output) {
-        String ioText;
-        if (output) {
-            mDeviceSpinner.setDirectionType(AudioManager.GET_DEVICES_OUTPUTS);
-            ioText = "OUTPUT";
-        } else {
-            mDeviceSpinner.setDirectionType(AudioManager.GET_DEVICES_INPUTS);
-            ioText = "INPUT";
-        }
-        mHideSettingsText = getResources().getString(R.string.hint_hide_settings) + " - " + ioText;
-        mShowSettingsText = getResources().getString(R.string.hint_show_settings) + " - " + ioText;
-        updateSettingsViewText();
-
-        // Don't show InputPresets for output streams.
-        mInputPresetTableRow.setVisibility(output ? View.GONE : View.VISIBLE);
-    }
-
-    private class NativeApiSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener {
-        @Override
-        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-            mRequestedConfiguration.setNativeApi(pos);
-        }
-
-        @Override
-        public void onNothingSelected(AdapterView<?> parent) {
-            mRequestedConfiguration.setNativeApi(StreamConfiguration.NATIVE_API_UNSPECIFIED);
-        }
-    }
-
-    private class PerformanceModeSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener {
-        @Override
-        public void onItemSelected(AdapterView<?> parent, View view, int performanceMode, long id) {
-            mRequestedConfiguration.setPerformanceMode(performanceMode
-                    + StreamConfiguration.PERFORMANCE_MODE_NONE);
-        }
-
-        @Override
-        public void onNothingSelected(AdapterView<?> parent) {
-            mRequestedConfiguration.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_NONE);
-        }
-    }
-
-    private class ChannelCountSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener {
-        @Override
-        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-            mRequestedConfiguration.setChannelCount(pos);
-        }
-
-        @Override
-        public void onNothingSelected(AdapterView<?> parent) {
-            mRequestedConfiguration.setChannelCount(StreamConfiguration.UNSPECIFIED);
-        }
-    }
-
-    private class SampleRateSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener {
-        @Override
-        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-            String text = parent.getItemAtPosition(pos).toString();
-            int sampleRate = Integer.parseInt(text);
-            mRequestedConfiguration.setSampleRate(sampleRate);
-        }
-
-        @Override
-        public void onNothingSelected(AdapterView<?> parent) {
-            mRequestedConfiguration.setSampleRate(StreamConfiguration.UNSPECIFIED);
-        }
-    }
-
-    private class FormatSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener {
-        @Override
-        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-            // Menu position matches actual enum value!
-            mRequestedConfiguration.setFormat(pos);
-        }
-
-        @Override
-        public void onNothingSelected(AdapterView<?> parent) {
-            mRequestedConfiguration.setFormat(StreamConfiguration.UNSPECIFIED);
-        }
-    }
-
-    private class InputPresetSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener {
-        @Override
-        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-            String text = parent.getItemAtPosition(pos).toString();
-            int inputPreset = StreamConfiguration.convertTextToInputPreset(text);
-            mRequestedConfiguration.setInputPreset(inputPreset);
-        }
-
-        @Override
-        public void onNothingSelected(AdapterView<?> parent) {
-            mRequestedConfiguration.setInputPreset(StreamConfiguration.INPUT_PRESET_GENERIC);
-        }
-    }
-
-    private class RateConversionQualitySpinnerListener
-            implements android.widget.AdapterView.OnItemSelectedListener {
-        @Override
-        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-            // Menu position matches actual enum value!
-            mRequestedConfiguration.setRateConversionQuality(pos);
-        }
-
-        @Override
-        public void onNothingSelected(AdapterView<?> parent) {
-            mRequestedConfiguration.setRateConversionQuality(StreamConfiguration.RATE_CONVERSION_QUALITY_HIGH);
-        }
-    }
-
-    public void setChildrenEnabled(boolean enabled) {
-        mNativeApiSpinner.setEnabled(enabled);
-        mPerformanceSpinner.setEnabled(enabled);
-        mRequestedExclusiveView.setEnabled(enabled);
-        mSampleRateSpinner.setEnabled(enabled);
-        mChannelCountSpinner.setEnabled(enabled);
-        mFormatSpinner.setEnabled(enabled);
-        mDeviceSpinner.setEnabled(enabled);
-        mRequestAudioEffect.setEnabled(enabled);
-    }
-
-    // This must be called on the UI thread.
-    void updateDisplay() {
-        int value;
-
-        value = mActualConfiguration.getNativeApi();
-        mActualNativeApiView.setText(StreamConfiguration.convertNativeApiToText(value));
-
-        mActualMMapView.setText(yesOrNo(mActualConfiguration.isMMap()));
-        int sharingMode = mActualConfiguration.getSharingMode();
-        boolean isExclusive = (sharingMode == StreamConfiguration.SHARING_MODE_EXCLUSIVE);
-        mActualExclusiveView.setText(yesOrNo(isExclusive));
-
-        value = mActualConfiguration.getPerformanceMode();
-        mActualPerformanceView.setText(StreamConfiguration.convertPerformanceModeToText(value));
-        mActualPerformanceView.requestLayout();
-
-        value = mActualConfiguration.getFormat();
-        mActualFormatView.setText(StreamConfiguration.convertFormatToText(value));
-        mActualFormatView.requestLayout();
-
-        value = mActualConfiguration.getInputPreset();
-        mActualInputPresetView.setText(StreamConfiguration.convertInputPresetToText(value));
-        mActualInputPresetView.requestLayout();
-
-        mActualChannelCountView.setText(mActualConfiguration.getChannelCount() + "");
-        mActualSampleRateView.setText(mActualConfiguration.getSampleRate() + "");
-        mActualSessionIdView.setText("S#: " + mActualConfiguration.getSessionId());
-
-        boolean isMMap = mActualConfiguration.isMMap();
-        mStreamInfoView.setText("burst = " + mActualConfiguration.getFramesPerBurst()
-                + ", capacity = " + mActualConfiguration.getBufferCapacityInFrames()
-                + ", devID = " + mActualConfiguration.getDeviceId()
-                + ", " + (mActualConfiguration.isMMap() ? "MMAP" : "Legacy")
-                + (isMMap ? ", " + StreamConfiguration.convertSharingModeToText(sharingMode) : "")
-        );
-
-        mHideableView.requestLayout();
-    }
-
-    // This must be called on the UI thread.
-    public void setStatusText(String msg) {
-        mStreamStatusView.setText(msg);
-    }
-
-    protected StreamConfiguration getRequestedConfiguration() {
-        return mRequestedConfiguration;
-    }
-
-    public void setRequestedConfiguration(StreamConfiguration configuration) {
-        mRequestedConfiguration = configuration;
-        if (configuration != null) {
-            mRateConversionQualitySpinner.setSelection(configuration.getRateConversionQuality());
-            mChannelConversionBox.setChecked(configuration.getChannelConversionAllowed());
-            mFormatConversionBox.setChecked(configuration.getFormatConversionAllowed());
-        }
-    }
-
-    protected StreamConfiguration getActualConfiguration() {
-        return mActualConfiguration;
-    }
-    public void setActualConfiguration(StreamConfiguration configuration) {
-        mActualConfiguration = configuration;
-    }
-
-    public void setExclusiveMode(boolean b) {
-        mRequestedExclusiveView.setChecked(b);
-        mRequestedConfiguration.setSharingMode(b
-                ? StreamConfiguration.SHARING_MODE_EXCLUSIVE
-                : StreamConfiguration.SHARING_MODE_SHARED);
-    }
-
-    public void setFormat(int format) {
-        mFormatSpinner.setSelection(format); // position matches format
-        mRequestedConfiguration.setFormat(format);
-    }
-
-    public void setFormatConversionAllowed(boolean allowed) {
-        mFormatConversionBox.setChecked(allowed);
-        mRequestedConfiguration.setFormatConversionAllowed(allowed);
-    }
-}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TapToToneActivity.java b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TapToToneActivity.java
deleted file mode 100644
index cdb46f0..0000000
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TapToToneActivity.java
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * 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.
- */
-
-package com.google.sample.oboe.manualtest;
-
-import android.Manifest;
-import android.content.pm.PackageManager;
-import android.media.midi.MidiDevice;
-import android.media.midi.MidiDeviceInfo;
-import android.media.midi.MidiInputPort;
-import android.media.midi.MidiManager;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.mobileer.miditools.MidiOutputPortConnectionSelector;
-import com.mobileer.miditools.MidiPortConnector;
-import com.mobileer.miditools.MidiTools;
-
-import java.io.IOException;
-
-import static com.google.sample.oboe.manualtest.AudioMidiTester.TestListener;
-import static com.google.sample.oboe.manualtest.AudioMidiTester.TestResult;
-
-public class TapToToneActivity extends TestOutputActivityBase {
-    private static final int MY_PERMISSIONS_REQUEST_RECORD_AUDIO = 1234;
-    private TextView mResultView;
-    private MidiManager mMidiManager;
-    private MidiInputPort mInputPort;
-
-    protected AudioMidiTester mAudioMidiTester;
-
-    private MidiOutputPortConnectionSelector mPortSelector;
-    private MyTestListener mTestListener = new MyTestListener();
-    private WaveformView mWaveformView;
-    // Stats for latency
-    private int mMeasurementCount;
-    private int mLatencySumSamples;
-    private int mLatencyMin;
-    private int mLatencyMax;
-
-    @Override
-    protected void inflateActivity() {
-        setContentView(R.layout.activity_tap_to_tone);
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        mAudioOutTester = addAudioOutputTester();
-
-        mResultView = (TextView) findViewById(R.id.resultView);
-
-        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI)) {
-            setupMidi();
-        } else {
-            Toast.makeText(TapToToneActivity.this,
-                    "MIDI not supported!", Toast.LENGTH_LONG)
-                    .show();
-        }
-
-        mWaveformView = (WaveformView) findViewById(R.id.waveview_audio);
-
-        // Start a blip test when the waveform view is tapped.
-        mWaveformView.setOnTouchListener(new View.OnTouchListener() {
-            @Override
-            public boolean onTouch(View view, MotionEvent event) {
-                int action = event.getActionMasked();
-                switch (action) {
-                    case MotionEvent.ACTION_DOWN:
-                    case MotionEvent.ACTION_POINTER_DOWN:
-                        mAudioMidiTester.trigger();
-                        break;
-                    case MotionEvent.ACTION_MOVE:
-                        break;
-                    case MotionEvent.ACTION_UP:
-                    case MotionEvent.ACTION_POINTER_UP:
-                        break;
-                }
-                // Must return true or we do not get the ACTION_MOVE and
-                // ACTION_UP events.
-                return true;
-            }
-        });
-
-        updateEnabledWidgets();
-    }
-
-    @Override
-    int getActivityType() {
-        return ACTIVITY_TAP_TO_TONE;
-    }
-
-    @Override
-    protected void onDestroy() {
-        mAudioMidiTester.removeTestListener(mTestListener);
-        closeMidiResources();
-        super.onDestroy();
-    }
-
-    private void setupMidi() {
-        // Setup MIDI
-        mMidiManager = (MidiManager) getSystemService(MIDI_SERVICE);
-        MidiDeviceInfo[] infos = mMidiManager.getDevices();
-
-        // Open the port now so that the AudioMidiTester gets created.
-        for (MidiDeviceInfo info : infos) {
-            Bundle properties = info.getProperties();
-            String product = properties
-                    .getString(MidiDeviceInfo.PROPERTY_PRODUCT);
-
-            Log.i(TAG, "product = " + product);
-            if ("AudioLatencyTester".equals(product)) {
-                openPort(info);
-                break;
-            }
-        }
-
-    }
-
-    // These should only be set after mAudioMidiTester is set.
-    private void setSpinnerListeners() {
-        MidiDeviceInfo synthInfo = MidiTools.findDevice(mMidiManager, "AndroidTest",
-                "AudioLatencyTester");
-        Log.i(TAG, "found tester virtual device info: " + synthInfo);
-        int portIndex = 0;
-        mPortSelector = new MidiOutputPortConnectionSelector(mMidiManager, this,
-                R.id.spinner_synth_sender, synthInfo, portIndex);
-        mPortSelector.setConnectedListener(new MyPortsConnectedListener());
-
-    }
-
-    private class MyTestListener implements TestListener {
-        @Override
-        public void onTestFinished(final TestResult result) {
-            runOnUiThread(new Runnable() {
-                public void run() {
-                    showTestResults(result);
-                }
-            });
-        }
-
-        @Override
-        public void onNoteOn(final int pitch) {
-            runOnUiThread(new Runnable() {
-                public void run() {
-                    mStreamContexts.get(0).configurationView.setStatusText("MIDI pitch = " + pitch);
-                }
-            });
-        }
-    }
-
-    // Runs on UI thread.
-    private void showTestResults(TestResult result) {
-        String text;
-        int previous = 0;
-        if (result == null) {
-            text = "";
-            mWaveformView.clearSampleData();
-        } else {
-            if (result.events.length < 2) {
-                text = "Not enough edges. Use fingernail.\n";
-                mWaveformView.setCursorData(null);
-            } else if (result.events.length > 2) {
-                text = "Too many edges.\n";
-                mWaveformView.setCursorData(null);
-            } else {
-                int[] cursors = new int[2];
-                cursors[0] = result.events[0].sampleIndex;
-                cursors[1] = result.events[1].sampleIndex;
-                int latencySamples = cursors[1] - cursors[0];
-                mLatencySumSamples += latencySamples;
-                mMeasurementCount++;
-
-                int latencyMillis = 1000 * latencySamples / result.frameRate;
-                if (mLatencyMin > latencyMillis) {
-                    mLatencyMin = latencyMillis;
-                }
-                if (mLatencyMax < latencyMillis) {
-                    mLatencyMax = latencyMillis;
-                }
-
-                text = String.format("latency = %3d msec\n", latencyMillis);
-                mWaveformView.setCursorData(cursors);
-            }
-            mWaveformView.setSampleData(result.filtered);
-        }
-
-        if (mMeasurementCount > 0) {
-            int averageLatencySamples = mLatencySumSamples / mMeasurementCount;
-            int averageLatencyMillis = 1000 * averageLatencySamples / result.frameRate;
-            final String plural = (mMeasurementCount == 1) ? "test" : "tests";
-            text = text + String.format("min = %3d, avg = %3d, max = %3d, %d %s",
-                    mLatencyMin, averageLatencyMillis, mLatencyMax, mMeasurementCount, plural);
-        }
-        final String postText = text;
-        mWaveformView.post(new Runnable() {
-            public void run() {
-                mResultView.setText(postText);
-                mWaveformView.postInvalidate();
-            }
-        });
-    }
-
-    private void openPort(final MidiDeviceInfo info) {
-        mMidiManager.openDevice(info, new MidiManager.OnDeviceOpenedListener() {
-                    @Override
-                    public void onDeviceOpened(MidiDevice device) {
-                        if (device == null) {
-                            Log.e(TAG, "could not open device " + info);
-                        } else {
-                            mInputPort = device.openInputPort(0);
-                            Log.i(TAG, "opened MIDI port = " + mInputPort + " on " + info);
-                            mAudioMidiTester = AudioMidiTester.getInstance();
-
-                            Log.i(TAG, "openPort() mAudioMidiTester = " + mAudioMidiTester);
-                            // Now that we have created the AudioMidiTester, close the port so we can
-                            // open it later.
-                            try {
-                                mInputPort.close();
-                            } catch (IOException e) {
-                                e.printStackTrace();
-                            }
-                            mAudioMidiTester.addTestListener(mTestListener);
-
-                            setSpinnerListeners();
-                        }
-                    }
-                }, new Handler(Looper.getMainLooper())
-        );
-    }
-
-    // TODO Listen to the synth server
-    // for open/close events and then disable/enable the spinner.
-    private class MyPortsConnectedListener
-            implements MidiPortConnector.OnPortsConnectedListener {
-        @Override
-        public void onPortsConnected(final MidiDevice.MidiConnection connection) {
-            Log.i(TAG, "onPortsConnected, connection = " + connection);
-            runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    if (connection == null) {
-                        Toast.makeText(TapToToneActivity.this,
-                                R.string.error_port_busy, Toast.LENGTH_LONG)
-                                .show();
-                        mPortSelector.clearSelection();
-                    } else {
-                        Toast.makeText(TapToToneActivity.this,
-                                R.string.port_open_ok, Toast.LENGTH_LONG)
-                                .show();
-                    }
-                }
-            });
-        }
-    }
-
-    private void closeMidiResources() {
-        if (mPortSelector != null) {
-            mPortSelector.close();
-        }
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        // Inflate the menu; this adds items to the action bar if it is present.
-        getMenuInflater().inflate(R.menu.menu_main, menu);
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        // Handle action bar item clicks here. The action bar will
-        // automatically handle clicks on the Home/Up button, so long
-        // as you specify a parent activity in AndroidManifest.xml.
-        int id = item.getItemId();
-
-        //noinspection SimplifiableIfStatement
-        if (id == R.id.action_settings) {
-            return true;
-        }
-
-        return super.onOptionsItemSelected(item);
-    }
-
-    private boolean hasRecordAudioPermission(){
-        boolean hasPermission = (checkSelfPermission(
-                Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED);
-        Log.i(TAG, "Has RECORD_AUDIO permission? " + hasPermission);
-        return hasPermission;
-    }
-
-    private void requestRecordAudioPermission(){
-
-        String requiredPermission = Manifest.permission.RECORD_AUDIO;
-
-        // If the user previously denied this permission then show a message explaining why
-        // this permission is needed
-        if (shouldShowRequestPermissionRationale(requiredPermission)) {
-            showErrorToast("This app needs to record audio through the microphone....");
-        }
-
-        // request the permission.
-        requestPermissions(new String[]{requiredPermission},
-                MY_PERMISSIONS_REQUEST_RECORD_AUDIO);
-    }
-    @Override
-    public void onRequestPermissionsResult(int requestCode,
-                                           String permissions[], int[] grantResults) {
-        // TODO
-    }
-
-    @Override
-    public void startAudio() throws IOException {
-        if (hasRecordAudioPermission()) {
-            startAudioPermitted();
-        } else {
-            requestRecordAudioPermission();
-        }
-    }
-
-    private void startAudioPermitted() throws IOException {
-        super.startAudio();
-        resetLatency();
-        mAudioMidiTester.start();
-    }
-
-    @Override
-    public void stopAudio() {
-        mAudioMidiTester.stop();
-        super.stopAudio();
-    }
-
-    @Override
-    public void pauseAudio() {
-        mAudioMidiTester.stop();
-        super.pauseAudio();
-    }
-
-    @Override
-    public void closeAudio() {
-        mAudioMidiTester.stop();
-        super.closeAudio();
-    }
-
-    private void resetLatency() {
-        mMeasurementCount = 0;
-        mLatencySumSamples = 0;
-        mLatencyMin = Integer.MAX_VALUE;
-        mLatencyMax = 0;
-        showTestResults(null);
-    }
-
-}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestOutputActivity.java b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestOutputActivity.java
deleted file mode 100644
index 3acdb6e..0000000
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestOutputActivity.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package com.google.sample.oboe.manualtest;
-
-import android.os.Bundle;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.CheckBox;
-import android.widget.Spinner;
-
-import java.io.IOException;
-
-/**
- * Test basic output.
- */
-public final class TestOutputActivity extends TestOutputActivityBase {
-
-    public static final int MAX_CHANNEL_BOXES = 8;
-    private CheckBox[] mChannelBoxes;
-    private Spinner mNativeApiSpinner;
-
-    private class NativeApiSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener {
-        @Override
-        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-            mAudioOutTester.setSignalType(pos);
-        }
-
-        @Override
-        public void onNothingSelected(AdapterView<?> parent) {
-            mAudioOutTester.setSignalType(0);
-        }
-    }
-
-    @Override
-    protected void inflateActivity() {
-        setContentView(R.layout.activity_test_output);
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        updateEnabledWidgets();
-
-        mAudioOutTester = addAudioOutputTester();
-
-        mChannelBoxes = new CheckBox[MAX_CHANNEL_BOXES];
-        int ic = 0;
-        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox0);
-        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox1);
-        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox2);
-        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox3);
-        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox4);
-        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox5);
-        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox6);
-        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox7);
-        configureChannelBoxes(0);
-
-        mNativeApiSpinner = (Spinner) findViewById(R.id.spinnerOutputSignal);
-        mNativeApiSpinner.setOnItemSelectedListener(new NativeApiSpinnerListener());
-        mNativeApiSpinner.setSelection(StreamConfiguration.NATIVE_API_UNSPECIFIED);
-    }
-
-    @Override
-    int getActivityType() {
-        return ACTIVITY_TEST_OUTPUT;
-    }
-
-    public void openAudio() throws IOException {
-        super.openAudio();
-        int channelCount = mAudioOutTester.getCurrentAudioStream().getChannelCount();
-        configureChannelBoxes(channelCount);
-    }
-
-    private void configureChannelBoxes(int channelCount) {
-        for (int i = 0; i < mChannelBoxes.length; i++) {
-            mChannelBoxes[i].setChecked(i < channelCount);
-            mChannelBoxes[i].setEnabled(i < channelCount);
-        }
-    }
-
-    public void closeAudio() {
-        configureChannelBoxes(0);
-        super.closeAudio();
-    }
-
-    public void onChannelBoxClicked(View view) {
-        CheckBox checkBox = (CheckBox) view;
-        String text = (String) checkBox.getText();
-        int channelIndex = Integer.parseInt(text);
-        mAudioOutTester.setChannelEnabled(channelIndex, checkBox.isChecked());
-    }
-}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/VolumeBarView.java b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/VolumeBarView.java
deleted file mode 100644
index a6f562f..0000000
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/VolumeBarView.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-package com.google.sample.oboe.manualtest;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.util.AttributeSet;
-import android.view.View;
-
-public class VolumeBarView extends View {
-
-    private Paint mBarPaint;
-    private int mCurrentWidth;
-    private int mCurrentHeight;
-    private Paint mBackgroundPaint;
-    private float mVolume;
-
-    public VolumeBarView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-//        TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
-//                R.styleable.VolumeBarView, 0, 0);
-        init();
-    }
-
-    private void init() {
-        mBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mBarPaint.setColor(Color.RED);
-        mBarPaint.setStyle(Paint.Style.FILL);
-
-        mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mBackgroundPaint.setColor(Color.LTGRAY);
-        mBackgroundPaint.setStyle(Paint.Style.FILL);
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        mCurrentWidth = w;
-        mCurrentHeight = h;
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-        canvas.drawRect(0.0f, 0.0f, mCurrentWidth,
-                mCurrentHeight, mBackgroundPaint);
-        float scaledVolume = mVolume * mCurrentWidth;
-        canvas.drawRect(0.0f, 0.0f, scaledVolume,
-                mCurrentHeight, mBarPaint);
-    }
-
-    /**
-     * Set volume between 0.0 and 1.0
-     */
-    public void setVolume(float volume) {
-        mVolume = volume;
-        postInvalidate();
-    }
-
-}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/audio_device/AudioDeviceAdapter.java b/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceAdapter.java
similarity index 95%
rename from apps/OboeTester/app/src/main/java/com/google/sample/audio_device/AudioDeviceAdapter.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceAdapter.java
index 9fa0093..6e22da9 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/audio_device/AudioDeviceAdapter.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceAdapter.java
@@ -1,4 +1,4 @@
-package com.google.sample.audio_device;
+package com.mobileer.audio_device;
 /*
  * Copyright 2017 The Android Open Source Project
  *
@@ -24,7 +24,7 @@
 import android.widget.ArrayAdapter;
 import android.widget.TextView;
 
-import com.google.sample.oboe.manualtest.R;
+import com.mobileer.oboetester.R;
 
 /**
  * Provides views for a list of audio devices. Usually used as an Adapter for a Spinner or ListView.
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/audio_device/AudioDeviceInfoConverter.java b/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceInfoConverter.java
similarity index 83%
rename from apps/OboeTester/app/src/main/java/com/google/sample/audio_device/AudioDeviceInfoConverter.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceInfoConverter.java
index b1419b3..d0228fd 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/audio_device/AudioDeviceInfoConverter.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceInfoConverter.java
@@ -1,4 +1,4 @@
-package com.google.sample.audio_device;
+package com.mobileer.audio_device;
 /*
  * Copyright 2017 The Android Open Source Project
  *
@@ -88,10 +88,16 @@
      *             e.g. AudioDeviceInfo.TYPE_BUILT_IN_SPEAKER
      * @return string which describes the type of audio device
      */
-    static String typeToString(int type){
+    public static String typeToString(int type){
         switch (type) {
             case AudioDeviceInfo.TYPE_AUX_LINE:
                 return "auxiliary line-level connectors";
+            case AudioDeviceInfo.TYPE_BLE_BROADCAST:
+                return "BLE broadcast";
+            case AudioDeviceInfo.TYPE_BLE_HEADSET:
+                return "BLE headset";
+            case AudioDeviceInfo.TYPE_BLE_SPEAKER:
+                return "BLE speaker";
             case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP:
                 return "Bluetooth A2DP";
             case AudioDeviceInfo.TYPE_BLUETOOTH_SCO:
@@ -102,26 +108,36 @@
                 return "built-in microphone";
             case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER:
                 return "built-in speaker";
-            case 0x18: // AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE:
+            case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE:
                 return "built-in speaker safe";
             case AudioDeviceInfo.TYPE_BUS:
-                return "BUS";
+                return "bus";
             case AudioDeviceInfo.TYPE_DOCK:
-                return "DOCK";
+                return "dock";
+            case 31: // AudioDeviceInfo.TYPE_DOCK_ANALOG:
+                return "dock analog";
+            case 28: // AudioDeviceInfo.TYPE_ECHO_REFERENCE:
+                return "echo reference";
             case AudioDeviceInfo.TYPE_FM:
                 return "FM";
             case AudioDeviceInfo.TYPE_FM_TUNER:
                 return "FM tuner";
             case AudioDeviceInfo.TYPE_HDMI:
                 return "HDMI";
+            case AudioDeviceInfo.TYPE_HEARING_AID:
+                return "hearing aid";
             case AudioDeviceInfo.TYPE_HDMI_ARC:
                 return "HDMI audio return channel";
+            case AudioDeviceInfo.TYPE_HDMI_EARC:
+                return "HDMI enhanced ARC";
             case AudioDeviceInfo.TYPE_IP:
                 return "IP";
             case AudioDeviceInfo.TYPE_LINE_ANALOG:
                 return "line analog";
             case AudioDeviceInfo.TYPE_LINE_DIGITAL:
                 return "line digital";
+            case AudioDeviceInfo.TYPE_REMOTE_SUBMIX:
+                return "remote submix";
             case AudioDeviceInfo.TYPE_TELEPHONY:
                 return "telephony";
             case AudioDeviceInfo.TYPE_TV_TUNER:
@@ -130,6 +146,8 @@
                 return "USB accessory";
             case AudioDeviceInfo.TYPE_USB_DEVICE:
                 return "USB device";
+            case AudioDeviceInfo.TYPE_USB_HEADSET:
+                return "USB headset";
             case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
                 return "wired headphones";
             case AudioDeviceInfo.TYPE_WIRED_HEADSET:
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/audio_device/AudioDeviceListEntry.java b/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceListEntry.java
similarity index 98%
rename from apps/OboeTester/app/src/main/java/com/google/sample/audio_device/AudioDeviceListEntry.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceListEntry.java
index d79768e..a0ea183 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/audio_device/AudioDeviceListEntry.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceListEntry.java
@@ -1,4 +1,4 @@
-package com.google.sample.audio_device;
+package com.mobileer.audio_device;
 /*
  * Copyright 2017 The Android Open Source Project
  *
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/audio_device/AudioDeviceSpinner.java b/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceSpinner.java
similarity index 97%
rename from apps/OboeTester/app/src/main/java/com/google/sample/audio_device/AudioDeviceSpinner.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceSpinner.java
index 3dcdc08..3c4390a 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/audio_device/AudioDeviceSpinner.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceSpinner.java
@@ -1,4 +1,4 @@
-package com.google.sample.audio_device;
+package com.mobileer.audio_device;
 /*
  * Copyright 2017 The Android Open Source Project
  *
@@ -24,7 +24,7 @@
 import android.util.AttributeSet;
 import android.widget.Spinner;
 
-import com.google.sample.oboe.manualtest.R;
+import com.mobileer.oboetester.R;
 
 import java.util.List;
 
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/CommunicationDeviceSpinner.java b/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/CommunicationDeviceSpinner.java
new file mode 100644
index 0000000..fcdcf41
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/CommunicationDeviceSpinner.java
@@ -0,0 +1,126 @@
+package com.mobileer.audio_device;
+/*
+ * Copyright 2022 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.
+ */
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.Resources.Theme;
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.util.AttributeSet;
+import android.widget.Spinner;
+
+import com.mobileer.oboetester.R;
+
+import java.util.List;
+
+public class CommunicationDeviceSpinner extends Spinner {
+    private static final int CLEAR_DEVICE_ID = 0;
+    private static final String TAG = CommunicationDeviceSpinner.class.getName();
+    private AudioDeviceAdapter mDeviceAdapter;
+    private AudioManager mAudioManager;
+    private Context mContext;
+    AudioDeviceInfo[] mCommDeviceArray = null;
+
+    public CommunicationDeviceSpinner(Context context){
+        super(context);
+        setup(context);
+    }
+
+    public CommunicationDeviceSpinner(Context context, int mode){
+        super(context, mode);
+        setup(context);
+    }
+
+    public CommunicationDeviceSpinner(Context context, AttributeSet attrs){
+        super(context, attrs);
+        setup(context);
+    }
+
+    public CommunicationDeviceSpinner(Context context, AttributeSet attrs, int defStyleAttr){
+        super(context, attrs, defStyleAttr);
+        setup(context);
+    }
+
+    public CommunicationDeviceSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode){
+        super(context, attrs, defStyleAttr, mode);
+        setup(context);
+    }
+
+    public CommunicationDeviceSpinner(Context context, AttributeSet attrs, int defStyleAttr,
+                                      int defStyleRes, int mode){
+        super(context, attrs, defStyleAttr, defStyleRes, mode);
+        setup(context);
+    }
+
+    public CommunicationDeviceSpinner(Context context, AttributeSet attrs, int defStyleAttr,
+                                      int defStyleRes, int mode, Theme popupTheme){
+        super(context, attrs, defStyleAttr, defStyleRes, mode, popupTheme);
+        setup(context);
+    }
+
+    public AudioDeviceInfo[] getCommunicationsDevices() {
+        return mCommDeviceArray;
+    }
+
+    private void setup(Context context){
+        mContext = context;
+
+        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+
+        mDeviceAdapter = new AudioDeviceAdapter(context);
+        setAdapter(mDeviceAdapter);
+
+        // Add a default entry to the list and select it
+        mDeviceAdapter.add(new AudioDeviceListEntry(CLEAR_DEVICE_ID,
+                mContext.getString(R.string.auto_select)));
+        setSelection(0);
+        setupCommunicationDeviceListener();
+    }
+
+    @TargetApi(31)
+    private void setupCommunicationDeviceListener(){
+        // Note that we will immediately receive a call to onDevicesAdded with the list of
+        // devices which are currently connected.
+        mAudioManager.registerAudioDeviceCallback(new AudioDeviceCallback() {
+            @Override
+            public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
+                updateDeviceList();
+            }
+
+            public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
+                updateDeviceList();
+            }
+
+            private void updateDeviceList() {
+                mDeviceAdapter.clear();
+                mDeviceAdapter.add(new AudioDeviceListEntry(CLEAR_DEVICE_ID,
+                        mContext.getString(R.string.clear)));
+                setSelection(0);
+                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
+                    List<AudioDeviceInfo> commDeviceList = mAudioManager.getAvailableCommunicationDevices();
+                    mCommDeviceArray = commDeviceList.toArray(new AudioDeviceInfo[0]);
+                    // Communications Devices are always OUTPUTS.
+                    List<AudioDeviceListEntry> deviceList =
+                            AudioDeviceListEntry.createListFrom(
+                                    mCommDeviceArray, AudioManager.GET_DEVICES_OUTPUTS);
+                    mDeviceAdapter.addAll(deviceList);
+                }
+            }
+        }, null);
+    }
+}
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AnalyzerActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AnalyzerActivity.java
new file mode 100644
index 0000000..368d5bc
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AnalyzerActivity.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2018 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.
+ */
+
+package com.mobileer.oboetester;
+
+import android.Manifest;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
+import android.widget.Toast;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+/**
+ * Activity to measure latency on a full duplex stream.
+ */
+public class AnalyzerActivity extends TestInputActivity {
+
+    AudioOutputTester mAudioOutTester;
+    protected BufferSizeView mBufferSizeView;
+    protected AutomatedTestRunner mAutomatedTestRunner;
+
+    // Note that these string must match the enum result_code in LatencyAnalyzer.h
+    String resultCodeToString(int resultCode) {
+        switch (resultCode) {
+            case 0:
+                return "OK";
+            case -99:
+                return "ERROR_NOISY";
+            case -98:
+                return "ERROR_VOLUME_TOO_LOW";
+            case -97:
+                return "ERROR_VOLUME_TOO_HIGH";
+            case -96:
+                return "ERROR_CONFIDENCE";
+            case -95:
+                return "ERROR_INVALID_STATE";
+            case -94:
+                return "ERROR_GLITCHES";
+            case -93:
+                return "ERROR_NO_LOCK";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
+    public native int getAnalyzerState();
+    public native boolean isAnalyzerDone();
+    public native int getMeasuredResult();
+    public native int getResetCount();
+
+    @Override
+    @NonNull
+    protected String getCommonTestReport() {
+        StringBuffer report = new StringBuffer();
+        // Add some extra information for the remote tester.
+        report.append("build.fingerprint = " + Build.FINGERPRINT + "\n");
+        try {
+            PackageInfo pinfo = getPackageManager().getPackageInfo(getPackageName(), 0);
+            report.append(String.format("test.version = %s\n", pinfo.versionName));
+            report.append(String.format("test.version.code = %d\n", pinfo.versionCode));
+        } catch (PackageManager.NameNotFoundException e) {
+        }
+        report.append("time.millis = " + System.currentTimeMillis() + "\n");
+
+        // INPUT
+        report.append(mAudioInputTester.actualConfiguration.dump());
+        AudioStreamBase inStream = mAudioInputTester.getCurrentAudioStream();
+        report.append(String.format("in.burst.frames = %d\n", inStream.getFramesPerBurst()));
+        report.append(String.format("in.xruns = %d\n", inStream.getXRunCount()));
+
+        // OUTPUT
+        report.append(mAudioOutTester.actualConfiguration.dump());
+        AudioStreamBase outStream = mAudioOutTester.getCurrentAudioStream();
+        report.append(String.format("out.burst.frames = %d\n", outStream.getFramesPerBurst()));
+        int bufferSize = outStream.getBufferSizeInFrames();
+        report.append(String.format("out.buffer.size.frames = %d\n", bufferSize));
+        int bufferCapacity = outStream.getBufferCapacityInFrames();
+        report.append(String.format("out.buffer.capacity.frames = %d\n", bufferCapacity));
+        report.append(String.format("out.xruns = %d\n", outStream.getXRunCount()));
+
+        return report.toString();
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mAudioOutTester = addAudioOutputTester();
+        mBufferSizeView = (BufferSizeView) findViewById(R.id.buffer_size_view);
+    }
+
+    @Override
+    protected void resetConfiguration() {
+        super.resetConfiguration();
+        mAudioOutTester.reset();
+
+        StreamContext streamContext = getFirstInputStreamContext();
+        if (streamContext != null) {
+            if (streamContext.configurationView != null) {
+                streamContext.configurationView.setFormat(StreamConfiguration.AUDIO_FORMAT_PCM_FLOAT);
+                streamContext.configurationView.setFormatConversionAllowed(true);
+            }
+        }
+        streamContext = getFirstOutputStreamContext();
+        if (streamContext != null) {
+            if (streamContext.configurationView != null) {
+                streamContext.configurationView.setFormat(StreamConfiguration.AUDIO_FORMAT_PCM_FLOAT);
+                streamContext.configurationView.setFormatConversionAllowed(true);
+            }
+        }
+    }
+
+    @Override
+    public void openAudio() throws IOException {
+        super.openAudio();
+        if (mBufferSizeView != null) {
+            mBufferSizeView.onStreamOpened((OboeAudioStream) mAudioOutTester.getCurrentAudioStream());
+        }
+    }
+
+    public void onStreamClosed() {
+        Toast.makeText(getApplicationContext(),
+                "Stream was closed or disconnected!",
+                Toast.LENGTH_SHORT)
+                .show();
+        stopAudioTest();
+    }
+
+    public void stopAudioTest() {
+    }
+
+    @Override
+    public void saveIntentLog() {
+        if (mTestRunningByIntent) {
+            String report = mAutomatedTestRunner.getFullLogs();
+            maybeWriteTestResult(report);
+            mTestRunningByIntent = false;
+            mBundleFromIntent = null;
+        }
+    }
+
+    private void writeTestInBackground(final String resultString) {
+        new Thread() {
+            public void run() {
+                writeTestResult(resultString);
+            }
+        }.start();
+    }
+}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioInputTester.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioInputTester.java
similarity index 96%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioInputTester.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioInputTester.java
index 81c9cd6..a03824b 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioInputTester.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioInputTester.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.util.Log;
 
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioOutputTester.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioOutputTester.java
similarity index 87%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioOutputTester.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioOutputTester.java
index 1e90a75..2c305fb 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioOutputTester.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioOutputTester.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.util.Log;
 
@@ -50,4 +50,8 @@
     public void setSignalType(int type) {
         mOboeAudioOutputStream.setSignalType(type);
     }
+
+    public int getLastErrorCallbackResult() {return mOboeAudioOutputStream.getLastErrorCallbackResult();};
+
+    public long getFramesRead() {return mOboeAudioOutputStream.getFramesRead();};
 }
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioQueryTools.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioQueryTools.java
new file mode 100644
index 0000000..421d098
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioQueryTools.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 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.
+ */
+
+package com.mobileer.oboetester;
+
+import android.content.pm.PackageManager;
+import android.media.AudioManager;
+import android.os.Build;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+public class AudioQueryTools {
+    private static String GETPROP_EXECUTABLE_PATH = "/system/bin/getprop";
+
+    public static String getSystemProperty(String propName) {
+        Process process = null;
+        BufferedReader bufferedReader = null;
+        try {
+            process = new ProcessBuilder().command(GETPROP_EXECUTABLE_PATH, propName).redirectErrorStream(true).start();
+            bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+            String line = bufferedReader.readLine();
+            if (line == null){
+                line = ""; //prop not set
+            }
+            return line;
+        } catch (Exception e) {
+            return "";
+        } finally{
+            if (bufferedReader != null){
+                try {
+                    bufferedReader.close();
+                } catch (IOException e) {}
+            }
+            if (process != null){
+                process.destroy();
+            }
+        }
+    }
+
+    public static String getAudioFeatureReport(PackageManager packageManager) {
+        StringBuffer report = new StringBuffer();
+        report.append("\nProAudio Feature     : "
+                + packageManager.hasSystemFeature(PackageManager.FEATURE_AUDIO_PRO));
+        report.append("\nLowLatency Feature   : "
+                + packageManager.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY));
+        report.append("\nMIDI Feature         : "
+                + packageManager.hasSystemFeature(PackageManager.FEATURE_MIDI));
+        report.append("\nUSB Host Feature     : "
+                + packageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST));
+        report.append("\nUSB Accessory Feature: "
+                + packageManager.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY));
+        return report.toString();
+    }
+
+    public static String getAudioManagerReport(AudioManager audioManager) {
+        StringBuffer report = new StringBuffer();
+        String unprocessedSupport = audioManager.getParameters(AudioManager.PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED);
+        report.append("\nSUPPORT_UNPROCESSED  : " + ((unprocessedSupport == null) ? "null" : "yes"));
+        return report.toString();
+    }
+
+    private static String formatKeyValueLine(String key, String value) {
+        int numSpaces = Math.max(1, 21 - key.length());
+        String spaces = String.format("%0" + numSpaces + "d", 0).replace("0", " ");
+        return "\n" + key + spaces + ": " + value;
+    }
+
+    private static String getSystemPropertyLine(String key) {
+        return formatKeyValueLine(key, getSystemProperty(key));
+    }
+
+    public static String convertSdkToShortName(int sdk) {
+        if (sdk < 16) return "early";
+        if (sdk > 34) return "future";
+        final String[] names = {
+                "J",   // 16
+                "J+",
+                "J++",
+                "K",
+                "K+",
+                "L",   // 21
+                "L+",
+                "M",
+                "N",   // 24
+                "N_MR1",
+                "O",
+                "O_MR1",
+                "P",   // 28
+                "Q",
+                "R",
+                "S",
+                "S_V2",
+                "T",   // 33
+                "U"
+        };
+        return names[sdk - 16];
+    }
+
+    public static String getMediaPerformanceClass() {
+        int mpc = Build.VERSION.MEDIA_PERFORMANCE_CLASS;
+        String text = (mpc == 0) ? "not declared" : convertSdkToShortName(mpc);
+        return formatKeyValueLine("Media Perf Class",
+                mpc + " (" + text + ")");
+    }
+
+    public static String getAudioPropertyReport() {
+        StringBuffer report = new StringBuffer();
+        report.append(getSystemPropertyLine("aaudio.mmap_policy"));
+        report.append(getSystemPropertyLine("aaudio.mmap_exclusive_policy"));
+        report.append(getSystemPropertyLine("aaudio.mixer_bursts"));
+        report.append(getSystemPropertyLine("aaudio.wakeup_delay_usec"));
+        report.append(getSystemPropertyLine("aaudio.minimum_sleep_usec"));
+        report.append(getSystemPropertyLine("aaudio.hw_burst_min_usec"));
+        report.append(getSystemPropertyLine("aaudio.in_mmap_offset_usec"));
+        report.append(getSystemPropertyLine("aaudio.out_mmap_offset_usec"));
+        report.append(getSystemPropertyLine("ro.product.manufacturer"));
+        report.append(getSystemPropertyLine("ro.product.brand"));
+        report.append(getSystemPropertyLine("ro.product.model"));
+        report.append(getSystemPropertyLine("ro.product.name"));
+        report.append(getSystemPropertyLine("ro.product.device"));
+        report.append(getSystemPropertyLine("ro.product.cpu.abi"));
+        report.append(getSystemPropertyLine("ro.soc.manufacturer"));
+        report.append(getSystemPropertyLine("ro.soc.model"));
+        report.append(getSystemPropertyLine("ro.arch"));
+        report.append(getSystemPropertyLine("ro.hardware"));
+        report.append(getSystemPropertyLine("ro.hardware.chipname"));
+        report.append(getSystemPropertyLine("ro.board.platform"));
+        report.append(getSystemPropertyLine("ro.build.changelist"));
+        report.append(getSystemPropertyLine("ro.build.description"));
+        return report.toString();
+    }
+}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioRecordThread.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioRecordThread.java
similarity index 95%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioRecordThread.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioRecordThread.java
index 5c7bff0..7b47223 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioRecordThread.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioRecordThread.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 
 import android.media.AudioFormat;
@@ -140,6 +140,12 @@
         }
     }
 
+    /**
+     * Schedule task to be run on its own thread when numSamples more samples have been recorded.
+     *
+     * @param numSamples
+     * @param task
+     */
     public void scheduleTask(int numSamples, Runnable task) {
         mTask = task;
         mTaskCountdown = numSamples;
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioStreamBase.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamBase.java
similarity index 88%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioStreamBase.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamBase.java
index 697c28b..b6eb6ff 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioStreamBase.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamBase.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import java.io.IOException;
 
@@ -38,6 +38,7 @@
         status.callbackCount = getCallbackCount();
         status.latency = getLatency();
         mLatencyStatistics.add(status.latency);
+        status.callbackTimeStr = getCallbackTimeStr();
         status.cpuLoad = getCpuLoad();
         status.state = getState();
         return status;
@@ -53,12 +54,12 @@
         private double minimum = Double.MAX_VALUE;
         private double maximum = Double.MIN_VALUE;
 
-        void add(double latency) {
-            if (latency <= 0.0) return;
-            sum += latency;
+        void add(double statistic) {
+            if (statistic <= 0.0) return;
+            sum += statistic;
             count++;
-            minimum = Math.min(latency, minimum);
-            maximum = Math.max(latency, maximum);
+            minimum = Math.min(statistic, minimum);
+            maximum = Math.max(statistic, maximum);
         }
 
         double getAverage() {
@@ -84,6 +85,7 @@
         public long callbackCount;
         public int framesPerCallback;
         public double cpuLoad;
+        public String callbackTimeStr;
 
         // These are constantly changing.
         String dump(int framesPerBurst) {
@@ -92,8 +94,12 @@
             }
             StringBuffer buffer = new StringBuffer();
 
-            buffer.append("frames written " + framesWritten + " - read " + framesRead
-                    + " = " + (framesWritten - framesRead) + "\n");
+            buffer.append("time between callbacks = " + callbackTimeStr + "\n");
+
+            buffer.append("written "
+                    + String.format("0x%08X", framesWritten)
+                    + " - read " + String.format("0x%08X", framesRead)
+                    + " = " + (framesWritten - framesRead) + " frames\n");
 
             String cpuLoadText = String.format("%2d%c", (int)(cpuLoad * 100), '%');
             buffer.append(
@@ -111,7 +117,7 @@
                 int remainder = bufferSize - (numBuffers * framesPerBurst);
                 buffer.append(bufferSize + " = (" + numBuffers + " * " + framesPerBurst + ") + " + remainder);
             }
-            buffer.append(",   xRun# = " + ((xRunCount < 0) ? "?" : xRunCount) + "\n");
+            buffer.append(",   xRun# = " + ((xRunCount < 0) ? "?" : xRunCount));
 
             return buffer.toString();
         }
@@ -191,6 +197,8 @@
 
     public double getCpuLoad() { return 0.0; }
 
+    public String getCallbackTimeStr() { return "?"; };
+
     public int getState() { return -1; }
 
     public boolean isThresholdSupported() {
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioStreamTester.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamTester.java
similarity index 96%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioStreamTester.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamTester.java
index 6d1e3de..32bc2ae 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioStreamTester.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamTester.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import java.io.IOException;
 
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AutomatedGlitchActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedGlitchActivity.java
similarity index 94%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AutomatedGlitchActivity.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedGlitchActivity.java
index 732ff92..e8befcd 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AutomatedGlitchActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedGlitchActivity.java
@@ -1,4 +1,4 @@
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.os.Bundle;
 import android.view.View;
@@ -94,6 +94,10 @@
     @Override
     public void runTest() {
         try {
+            logDeviceInfo();
+
+            mTestResults.clear();
+
             testConfiguration(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY,
                     StreamConfiguration.SHARING_MODE_EXCLUSIVE,
                     UNSPECIFIED);
@@ -105,7 +109,13 @@
                             sampleRate);
                 }
             }
+
+            analyzeTestResults();
+
         } catch (InterruptedException e) {
+            analyzeTestResults();
+
+        } catch (Exception e) {
             log(e.getMessage());
             showErrorToast(e.getMessage());
         }
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AutomatedTestRunner.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedTestRunner.java
similarity index 80%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AutomatedTestRunner.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedTestRunner.java
index 1f9714f..8341780 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AutomatedTestRunner.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedTestRunner.java
@@ -1,15 +1,15 @@
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
-import android.text.method.ScrollingMovementMethod;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.Button;
 import android.widget.LinearLayout;
+import android.widget.ScrollView;
 import android.widget.TextView;
 
 import java.text.DateFormat;
@@ -27,9 +27,11 @@
     private Button       mStopButton;
     private Button       mShareButton;
     private TextView     mAutoTextView;
+    private ScrollView   mAutoTextScroller;
     private TextView     mSingleTestIndex;
     private StringBuffer mFailedSummary;
     private StringBuffer mSummary;
+    private StringBuffer mFullSummary;
     private int          mTestCount;
     private int          mPassCount;
     private int          mFailCount;
@@ -104,8 +106,12 @@
 
         mSingleTestIndex = (TextView) findViewById(R.id.single_test_index);
 
-        mAutoTextView = (TextView) findViewById(R.id.text_log);
-        mAutoTextView.setMovementMethod(new ScrollingMovementMethod());
+        mAutoTextScroller = (ScrollView) findViewById(R.id.text_log_auto_scroller);
+        mAutoTextView = (TextView) findViewById(R.id.text_log_auto);
+
+        mFailedSummary = new StringBuffer();
+        mSummary = new StringBuffer();
+        mFullSummary = new StringBuffer();
     }
 
     private void updateStartStopButtons(boolean running) {
@@ -124,6 +130,7 @@
     public void appendFailedSummary(String text) {
         mFailedSummary.append(text);
     }
+
     public void appendSummary(String text) {
         mSummary.append(text);
     }
@@ -143,15 +150,29 @@
         if (text == null) return;
         Log.d(TestAudioActivity.TAG, "LOG - " + text);
         mCachedTextView.append(text + "\n");
+        mFullSummary.append(text + "\n");
+        scrollToBottom();
+    }
+
+    public void scrollToBottom() {
+        mAutoTextScroller.fullScroll(View.FOCUS_DOWN);
     }
 
     // Flush any logs that are stuck in the cache.
     public void flushLog() {
         mCachedTextView.flush();
+        scrollToBottom();
     }
 
     private void logClear() {
         mCachedTextView.clear();
+        mFullSummary.delete(0, mFullSummary.length());
+        mSummary.delete(0, mSummary.length());
+        mFailedSummary.delete(0, mFailedSummary.length());
+    }
+
+    protected String getFullLogs() {
+        return mFullSummary.toString();
     }
 
     private void startAutoThread() {
@@ -175,6 +196,14 @@
         }
     }
 
+    protected void setTestIndexText(int newTestIndex) {
+        if (newTestIndex >= 0) {
+            mSingleTestIndex.setText(String.valueOf(newTestIndex));
+        } else {
+            mSingleTestIndex.setText("");
+        }
+    }
+
     private void updateTestIndex() {
         CharSequence chars = mSingleTestIndex.getText();
         String text = chars.toString();
@@ -236,11 +265,9 @@
         logClear();
         log("=== STARTED at " + new Date());
         log(mActivity.getTestName());
-        log(MainActivity.getVersiontext());
+        log(MainActivity.getVersionText());
         log(Build.MANUFACTURER + ", " + Build.MODEL + ", " + Build.PRODUCT);
         log(Build.DISPLAY);
-        mFailedSummary = new StringBuffer();
-        mSummary = new StringBuffer();
         appendFailedSummary("Summary\n");
         mTestCount = 0;
         mPassCount = 0;
@@ -252,31 +279,35 @@
             log("EXCEPTION: " + e.getMessage());
         } finally {
             mActivity.stopTest();
-            if (mThreadEnabled) {
-                log("\n==== SUMMARY ========");
-                log(mSummary.toString());
-                if (mFailCount > 0) {
-                    log("These tests FAILED:");
-                    log(mFailedSummary.toString());
-                    log("------------");
-                } else if (mPassCount > 0) {
-                    log("All " + mPassCount + " tests PASSED.");
-                } else {
-                    log("No tests were run!");
-                }
-                int skipped = mTestCount - (mPassCount + mFailCount);
-                log(mPassCount + " passed. "
-                        + mFailCount + " failed. "
-                        + skipped + " skipped. ");
-                log("== FINISHED at " + new Date());
-            } else {
+            if (!mThreadEnabled) {
                 log("== TEST STOPPED ==");
             }
+            log("\n==== SUMMARY ========");
+            log(mSummary.toString());
+            if (mFailCount > 0) {
+                log("These tests FAILED:");
+                log(mFailedSummary.toString());
+                log("------------");
+            } else if (mPassCount > 0) {
+                log("All " + mPassCount + " tests PASSED.");
+            } else {
+                log("No tests were run!");
+            }
+            int skipped = mTestCount - (mPassCount + mFailCount);
+            log(mPassCount + " passed. "
+                    + mFailCount + " failed. "
+                    + skipped + " skipped. ");
+            log("== FINISHED at " + new Date());
+
             flushLog();
+
+            mActivity.saveIntentLog();
+
             mActivity.runOnUiThread(new Runnable() {
                 @Override
                 public void run() {
                     onTestFinished();
+                    flushLog();
                 }
             });
         }
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java
new file mode 100644
index 0000000..5bc16fb
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java
@@ -0,0 +1,446 @@
+/*
+ * Copyright 2019 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.
+ */
+
+package com.mobileer.oboetester;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+public class BaseAutoGlitchActivity extends GlitchActivity {
+
+    private static final int SETUP_TIME_SECONDS = 4; // Time for the stream to settle.
+    protected static final int DEFAULT_DURATION_SECONDS = 8; // Run time for each test.
+    private static final int DEFAULT_GAP_MILLIS = 400; // Idle time between each test.
+    private static final String TEXT_SKIP = "SKIP";
+    public static final String TEXT_PASS = "PASS";
+    public static final String TEXT_FAIL = "FAIL !!!!";
+
+    protected int mDurationSeconds = DEFAULT_DURATION_SECONDS;
+    protected int mGapMillis = DEFAULT_GAP_MILLIS;
+    private String mTestName = "";
+
+    protected ArrayList<TestResult> mTestResults = new ArrayList<TestResult>();
+
+    void logDeviceInfo() {
+        log("\n############################");
+        log("\nDevice Info:");
+        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        log(AudioQueryTools.getAudioManagerReport(audioManager));
+        log(AudioQueryTools.getAudioFeatureReport(getPackageManager()));
+        log(AudioQueryTools.getAudioPropertyReport());
+        log("\n############################");
+    }
+
+    void setTestName(String name) {
+        mTestName = name;
+    }
+
+    private static class TestDirection {
+        public final int channelUsed;
+        public final int channelCount;
+        public final int deviceId;
+        public final int mmapUsed;
+        public final int performanceMode;
+        public final int sharingMode;
+
+        public TestDirection(StreamConfiguration configuration, int channelUsed) {
+            this.channelUsed = channelUsed;
+            channelCount = configuration.getChannelCount();
+            deviceId = configuration.getDeviceId();
+            mmapUsed = configuration.isMMap() ? 1 : 0;
+            performanceMode = configuration.getPerformanceMode();
+            sharingMode = configuration.getSharingMode();
+        }
+
+        int countDifferences(TestDirection other) {
+            int count = 0;
+            count += (channelUsed != other.channelUsed) ? 1 : 0;
+            count += (channelCount != other.channelCount) ? 1 : 0;
+            count += (deviceId != other.deviceId) ? 1 : 0;
+            count += (mmapUsed != other.mmapUsed) ? 1 : 0;
+            count += (performanceMode != other.performanceMode) ? 1 : 0;
+            count += (sharingMode != other.sharingMode) ? 1 : 0;
+            return count;
+        }
+
+        public String comparePassedDirection(String prefix, TestDirection passed) {
+            StringBuffer text = new StringBuffer();
+            text.append(TestDataPathsActivity.comparePassedField(prefix, this, passed, "channelUsed"));
+            text.append(TestDataPathsActivity.comparePassedField(prefix,this, passed, "channelCount"));
+            text.append(TestDataPathsActivity.comparePassedField(prefix,this, passed, "deviceId"));
+            text.append(TestDataPathsActivity.comparePassedField(prefix,this, passed, "mmapUsed"));
+            text.append(TestDataPathsActivity.comparePassedField(prefix,this, passed, "performanceMode"));
+            text.append(TestDataPathsActivity.comparePassedField(prefix,this, passed, "sharingMode"));
+            return text.toString();
+        }
+        @Override
+        public String toString() {
+            return "D=" + deviceId
+                    + ", " + ((mmapUsed > 0) ? "MMAP" : "Lgcy")
+                    + ", ch=" + channelText(channelUsed, channelCount)
+                    + "," + StreamConfiguration.convertPerformanceModeToText(performanceMode)
+                    + "," + StreamConfiguration.convertSharingModeToText(sharingMode);
+        }
+    }
+
+    protected static class TestResult {
+        final int testIndex;
+        final TestDirection input;
+        final TestDirection output;
+        public final int inputPreset;
+        public final int sampleRate;
+        final String testName; // name or purpose of test
+
+        int result = TEST_RESULT_SKIPPED; // TEST_RESULT_FAILED, etc
+        private String mComments = ""; // additional info, ideas for why it failed
+
+        public TestResult(int testIndex,
+                          String testName,
+                          StreamConfiguration inputConfiguration,
+                          int inputChannel,
+                          StreamConfiguration outputConfiguration,
+                          int outputChannel) {
+            this.testIndex = testIndex;
+            this.testName = testName;
+            input = new TestDirection(inputConfiguration, inputChannel);
+            output = new TestDirection(outputConfiguration, outputChannel);
+            sampleRate = outputConfiguration.getSampleRate();
+            this.inputPreset = inputConfiguration.getInputPreset();
+        }
+
+        int countDifferences(TestResult other) {
+            int count = 0;
+            count += input.countDifferences((other.input));
+            count += output.countDifferences((other.output));
+            count += (sampleRate != other.sampleRate) ? 1 : 0;
+            count += (inputPreset != other.inputPreset) ? 1 : 0;
+            return count;
+        }
+
+        public boolean failed() {
+            return result == TEST_RESULT_FAILED;
+        }
+
+        public boolean passed() {
+            return result == TEST_RESULT_PASSED;
+        }
+
+        public String comparePassed(TestResult passed) {
+            StringBuffer text = new StringBuffer();
+            text.append("Compare with passed test #" + passed.testIndex + "\n");
+            text.append(input.comparePassedDirection("IN", passed.input));
+            text.append(TestDataPathsActivity.comparePassedField("IN", this, passed, "inputPreset"));
+            text.append(output.comparePassedDirection("OUT", passed.output));
+            text.append(TestDataPathsActivity.comparePassedField("I/O",this, passed, "sampleRate"));
+
+            return text.toString();
+        }
+
+        @Override
+        public String toString() {
+            return "IN:  " + input + ", ip=" + inputPreset + "\n"
+                    + "OUT: " + output + ", sr=" + sampleRate
+                    + mComments;
+        }
+
+        public void addComment(String comment) {
+            mComments += "\n";
+            mComments += comment;
+        }
+
+        public void setResult(int result) {
+            this.result = result;
+        }
+        public int getResult(int result) {
+            return result;
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mAutomatedTestRunner = findViewById(R.id.auto_test_runner);
+        mAutomatedTestRunner.setActivity(this);
+    }
+
+    protected void log(String text) {
+        mAutomatedTestRunner.log(text);
+    }
+
+    protected void appendFailedSummary(String text) {
+        mAutomatedTestRunner.appendFailedSummary(text);
+    }
+
+    protected void appendSummary(String text) {
+        mAutomatedTestRunner.appendSummary(text);
+    }
+
+    @Override
+    public void onStopTest() {
+        mAutomatedTestRunner.stopTest();
+    }
+
+    static String channelText(int index, int count) {
+        return index + "/" + count;
+    }
+
+    protected String getConfigText(StreamConfiguration config) {
+        int channel = (config.getDirection() == StreamConfiguration.DIRECTION_OUTPUT)
+                ? getOutputChannel() : getInputChannel();
+        return ((config.getDirection() == StreamConfiguration.DIRECTION_OUTPUT) ? "OUT" : "INP")
+                + (config.isMMap() ? "-M" : "-L")
+                + ", ID = " + String.format("%2d", config.getDeviceId())
+                + ", SR = " + String.format("%5d", config.getSampleRate())
+                + ", Perf = " + StreamConfiguration.convertPerformanceModeToText(
+                config.getPerformanceMode())
+                + ", " + StreamConfiguration.convertSharingModeToText(config.getSharingMode())
+                + ", ch = " + channelText(channel, config.getChannelCount());
+    }
+
+    protected String getStreamText(AudioStreamBase stream) {
+        return ("burst=" + stream.getFramesPerBurst()
+                + ", size=" + stream.getBufferSizeInFrames()
+                + ", cap=" + stream.getBufferCapacityInFrames()
+        );
+    }
+
+    public final static int TEST_RESULT_FAILED = -2;
+    public final static int TEST_RESULT_WARNING = -1;
+    public final static int TEST_RESULT_SKIPPED = 0;
+    public final static int TEST_RESULT_PASSED = 1;
+
+    // Run one test based on the requested input/output configurations.
+    @Nullable
+    protected TestResult testConfigurations() throws InterruptedException {
+        int result = TEST_RESULT_SKIPPED;
+        mAutomatedTestRunner.incrementTestCount();
+        if ((getSingleTestIndex() >= 0) && (mAutomatedTestRunner.getTestCount() != getSingleTestIndex())) {
+            return null;
+        }
+
+        log("========================== #" + mAutomatedTestRunner.getTestCount());
+
+        StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration;
+        StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
+
+        StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration;
+        StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration;
+
+        log("Requested:");
+        log("  " + getConfigText(requestedInConfig));
+        log("  " + getConfigText(requestedOutConfig));
+
+        String reason = "";
+        boolean openFailed = false;
+        try {
+            openAudio(); // this will fill in actualConfig
+            log("Actual:");
+            // Set output size to a level that will avoid glitches.
+            AudioStreamBase outStream = mAudioOutTester.getCurrentAudioStream();
+            int sizeFrames = outStream.getBufferCapacityInFrames() / 2;
+            sizeFrames = Math.max(sizeFrames, 2 * outStream.getFramesPerBurst());
+            outStream.setBufferSizeInFrames(sizeFrames);
+            AudioStreamBase inStream = mAudioInputTester.getCurrentAudioStream();
+            log("  " + getConfigText(actualInConfig));
+            log("      " + getStreamText(inStream));
+            log("  " + getConfigText(actualOutConfig));
+            log("      " + getStreamText(outStream));
+        } catch (Exception e) {
+            openFailed = true;
+            log(e.getMessage());
+            reason = e.getMessage();
+        }
+
+        TestResult testResult = new TestResult(
+                mAutomatedTestRunner.getTestCount(),
+                mTestName,
+                mAudioInputTester.actualConfiguration,
+                getInputChannel(),
+                mAudioOutTester.actualConfiguration,
+                getOutputChannel()
+        );
+
+        // The test would only be worth running if we got the configuration we requested on input or output.
+        String skipReason = shouldTestBeSkipped();
+        boolean skipped = skipReason.length() > 0;
+        boolean valid = !openFailed && !skipped;
+        boolean startFailed = false;
+        if (valid) {
+            try {
+                startAudioTest();
+            } catch (IOException e) {
+                e.printStackTrace();
+                valid = false;
+                startFailed = true;
+                log(e.getMessage());
+                reason = e.getMessage();
+            }
+        }
+        mAutomatedTestRunner.flushLog();
+
+        if (valid) {
+            // Check for early return until we reach full duration.
+            long now = System.currentTimeMillis();
+            long startedAt = now;
+            long endTime = System.currentTimeMillis() + (mDurationSeconds * 1000);
+            boolean finishedEarly = false;
+            while (now < endTime && !finishedEarly) {
+                Thread.sleep(100); // Let test run.
+                now = System.currentTimeMillis();
+                finishedEarly = isFinishedEarly();
+                if (finishedEarly) {
+                    log("Finished early after " + (now - startedAt) + " msec.");
+                }
+            }
+        }
+        int inXRuns = 0;
+        int outXRuns = 0;
+
+        if (!openFailed) {
+            // get xRuns before closing the streams.
+            inXRuns = mAudioInputTester.getCurrentAudioStream().getXRunCount();
+            outXRuns = mAudioOutTester.getCurrentAudioStream().getXRunCount();
+
+            super.stopAudioTest();
+        }
+
+        if (openFailed || startFailed) {
+            appendFailedSummary("------ #" + mAutomatedTestRunner.getTestCount() + "\n");
+            appendFailedSummary(getConfigText(requestedInConfig) + "\n");
+            appendFailedSummary(getConfigText(requestedOutConfig) + "\n");
+            appendFailedSummary(reason + "\n");
+            mAutomatedTestRunner.incrementFailCount();
+        } else if (skipped) {
+            log(TEXT_SKIP + " - " + skipReason);
+        } else {
+            log("Result:");
+            reason += didTestFail();
+            boolean passed = reason.length() == 0;
+
+            String resultText = getShortReport();
+            resultText += ", xruns = " + inXRuns + "/" + outXRuns;
+            resultText += ", " + (passed ? TEXT_PASS : TEXT_FAIL);
+            resultText += reason;
+            log("  " + resultText);
+            if (!passed) {
+                appendFailedSummary("------ #" + mAutomatedTestRunner.getTestCount() + "\n");
+                appendFailedSummary("  " + getConfigText(actualInConfig) + "\n");
+                appendFailedSummary("  " + getConfigText(actualOutConfig) + "\n");
+                appendFailedSummary("    " + resultText + "\n");
+                mAutomatedTestRunner.incrementFailCount();
+                result = TEST_RESULT_FAILED;
+            } else {
+                mAutomatedTestRunner.incrementPassCount();
+                result = TEST_RESULT_PASSED;
+            }
+        }
+        mAutomatedTestRunner.flushLog();
+
+        // Give hardware time to settle between tests.
+        Thread.sleep(mGapMillis);
+
+        if (valid) {
+            testResult.setResult(result);
+            mTestResults.add(testResult);
+        }
+
+        return testResult;
+    }
+
+    protected boolean isFinishedEarly() {
+        return false;
+    }
+
+    protected String shouldTestBeSkipped() {
+        String why = "";
+        StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration;
+        StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
+        StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration;
+        StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration;
+        // No point running the test if we don't get the sharing mode we requested.
+        if (actualInConfig.getSharingMode() != requestedInConfig.getSharingMode()
+                || actualOutConfig.getSharingMode() != requestedOutConfig.getSharingMode()) {
+            log("Did not get requested sharing mode.");
+            why += "share";
+        }
+        // We don't skip based on performance mode because if you request LOW_LATENCY you might
+        // get a smaller burst than if you request NONE.
+        return why;
+    }
+
+    public String didTestFail() {
+        String why = "";
+        if (getMaxSecondsWithNoGlitch() <= (mDurationSeconds - SETUP_TIME_SECONDS)) {
+            why += ", glitch";
+        }
+        return why;
+    }
+
+    void logAnalysis(String text) {
+        appendFailedSummary(text + "\n");
+    }
+
+    protected void analyzeTestResults() {
+        logAnalysis("\n==== ANALYSIS ===========");
+        logAnalysis("Compare failed configuration with closest one that passed.");
+        // Analyze each failed test.
+        for (TestResult testResult : mTestResults) {
+            if (testResult.failed()) {
+                logAnalysis("-------------------- #" + testResult.testIndex + " FAILED");
+                String name = testResult.testName;
+                if (name.length() > 0) {
+                    logAnalysis(name);
+                }
+                TestResult[] closest = findClosestPassingTestResults(testResult);
+                for (TestResult other : closest) {
+                    logAnalysis(testResult.comparePassed(other));
+                }
+                logAnalysis(testResult.toString());
+            }
+        }
+    }
+
+    @Nullable
+    private TestResult[] findClosestPassingTestResults(TestResult testResult) {
+        int minDifferences = Integer.MAX_VALUE;
+        for (TestResult other : mTestResults) {
+            if (other.passed()) {
+                int numDifferences = testResult.countDifferences(other);
+                if (numDifferences < minDifferences) {
+                    minDifferences = numDifferences;
+                }
+            }
+        }
+        // Now find all the tests that are just as close as the closest.
+        ArrayList<TestResult> list = new ArrayList<TestResult>();
+        for (TestResult other : mTestResults) {
+            if (other.passed()) {
+                int numDifferences = testResult.countDifferences(other);
+                if (numDifferences == minDifferences) {
+                    list.add(other);
+                }
+            }
+        }
+        return list.toArray(new TestResult[0]);
+    }
+
+}
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseOboeTesterActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseOboeTesterActivity.java
new file mode 100644
index 0000000..860b814
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseOboeTesterActivity.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2021 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.
+ */
+
+package com.mobileer.oboetester;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.support.annotation.NonNull;
+import android.support.v4.app.ActivityCompat;
+import android.widget.Toast;
+
+/**
+ * Support requesting RECORD_AUDIO permission.
+ */
+
+public abstract class BaseOboeTesterActivity extends Activity
+        implements ActivityCompat.OnRequestPermissionsResultCallback {
+
+    private static final int MY_PERMISSIONS_REQUEST_RECORD_AUDIO = 938355;
+    private Class mTestClass;
+
+    protected void showErrorToast(String message) {
+        showToast("Error: " + message);
+    }
+
+    protected void showToast(final String message) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Toast.makeText(BaseOboeTesterActivity.this,
+                        message,
+                        Toast.LENGTH_SHORT).show();
+            }
+        });
+    }
+
+    private boolean isRecordPermissionGranted() {
+        return (ActivityCompat.checkSelfPermission(this,
+                Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED);
+    }
+
+    private void requestRecordPermission(){
+        ActivityCompat.requestPermissions(
+                this,
+                new String[]{Manifest.permission.RECORD_AUDIO},
+                MY_PERMISSIONS_REQUEST_RECORD_AUDIO);
+    }
+
+    @Override
+    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+                                           @NonNull int[] grantResults) {
+
+        if (MY_PERMISSIONS_REQUEST_RECORD_AUDIO != requestCode) {
+            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+            return;
+        }
+
+        if (grantResults.length != 1 ||
+                grantResults[0] != PackageManager.PERMISSION_GRANTED) {
+
+            Toast.makeText(getApplicationContext(),
+                    getString(R.string.need_record_audio_permission),
+                    Toast.LENGTH_SHORT)
+                    .show();
+        } else {
+            // Permission was granted
+            beginTestThatRequiresRecording();
+        }
+    }
+
+    /**
+     * If needed, request recording permission before running test.
+     */
+    protected void launchTestThatDoesRecording(Class clazz) {
+        mTestClass = clazz;
+        if (isRecordPermissionGranted()) {
+            beginTestThatRequiresRecording();
+        } else {
+            requestRecordPermission();
+        }
+    }
+
+    protected void launchTestActivity(Class clazz) {
+        Intent intent = new Intent(this, clazz);
+        startActivity(intent);
+    }
+
+    private void beginTestThatRequiresRecording() {
+        launchTestActivity(mTestClass);
+    }
+}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/BufferSizeView.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BufferSizeView.java
similarity index 99%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/BufferSizeView.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BufferSizeView.java
index cd7d36f..ce3b7a4 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/BufferSizeView.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BufferSizeView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.content.Context;
 import android.util.AttributeSet;
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/CachedTextViewLog.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CachedTextViewLog.java
similarity index 97%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/CachedTextViewLog.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CachedTextViewLog.java
index dfb6a16..0cc2f8d 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/CachedTextViewLog.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CachedTextViewLog.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.app.Activity;
 import android.widget.TextView;
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/CircularCaptureBuffer.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CircularCaptureBuffer.java
similarity index 98%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/CircularCaptureBuffer.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CircularCaptureBuffer.java
index bcc2d47..0e1f39c 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/CircularCaptureBuffer.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CircularCaptureBuffer.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 
 /**
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CommunicationDeviceView.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CommunicationDeviceView.java
new file mode 100644
index 0000000..4e8df13
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CommunicationDeviceView.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2022 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.
+ */
+
+package com.mobileer.oboetester;
+
+import android.content.Context;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.CheckBox;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.mobileer.audio_device.CommunicationDeviceSpinner;
+
+public class CommunicationDeviceView extends LinearLayout {
+    private CheckBox mSpeakerphoneCheckbox;
+    private TextView mIsSpeakerphoneText;
+    private AudioManager mAudioManager;
+    private CommunicationDeviceSpinner mDeviceSpinner;
+
+    public CommunicationDeviceView(Context context) {
+        super(context);
+        initializeViews(context);
+    }
+
+    public CommunicationDeviceView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        initializeViews(context);
+    }
+
+    public CommunicationDeviceView(Context context,
+                          AttributeSet attrs,
+                          int defStyle) {
+        super(context, attrs, defStyle);
+        initializeViews(context);
+    }
+
+    /**
+     * Inflates the views in the layout.
+     *
+     * @param context the current context for the view.
+     */
+    private void initializeViews(Context context) {
+        LayoutInflater inflater = (LayoutInflater) context
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        inflater.inflate(R.layout.comm_device_view, this);
+
+        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        mSpeakerphoneCheckbox = (CheckBox) findViewById(R.id.setSpeakerphoneOn);
+
+        mDeviceSpinner = (CommunicationDeviceSpinner) findViewById(R.id.comm_devices_spinner);
+        mDeviceSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
+            {
+                AudioDeviceInfo[] commDeviceArray = mDeviceSpinner.getCommunicationsDevices();
+                if (commDeviceArray != null) {
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+                        if (position == 0) {
+                            mAudioManager.clearCommunicationDevice();
+                        } else {
+                            AudioDeviceInfo selectedDevice = commDeviceArray[position - 1]; // skip "Clear"
+                            mAudioManager.setCommunicationDevice(selectedDevice);
+                        }
+                        showCommDeviceStatus();
+                    }
+                }
+            }
+            public void onNothingSelected(AdapterView<?> parent) {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+                    mAudioManager.clearCommunicationDevice();
+                }
+                showCommDeviceStatus();
+            }
+        });
+
+        mSpeakerphoneCheckbox.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                onSetSpeakerphoneOn(view);
+            }
+        });
+        mIsSpeakerphoneText = (TextView) findViewById(R.id.isSpeakerphoneOn);
+        showCommDeviceStatus();
+    }
+
+    public void cleanup() {
+        mSpeakerphoneCheckbox.setChecked(false);
+        setSpeakerPhoneOn(false);
+    }
+
+    public void onSetSpeakerphoneOn(View view) {
+        Log.d(TestAudioActivity.TAG, "onSetSpeakerphoneOn() called from Checkbox");
+        CheckBox checkBox = (CheckBox) view;
+        boolean enabled = checkBox.isChecked();
+        setSpeakerPhoneOn(enabled);
+        showCommDeviceStatus();
+    }
+
+    private void setSpeakerPhoneOn(boolean enabled) {
+        Log.d(TestAudioActivity.TAG, "call setSpeakerphoneOn(" + enabled + ")");
+        mAudioManager.setSpeakerphoneOn(enabled);
+    }
+
+    private void showCommDeviceStatus() {
+        boolean enabled = mAudioManager.isSpeakerphoneOn();
+        String text = (enabled ? "ON" : "OFF");
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
+            AudioDeviceInfo commDeviceInfo = mAudioManager.getCommunicationDevice();
+            if (commDeviceInfo != null) {
+                text += ", CommDev=" + commDeviceInfo.getId();
+            }
+        }
+        mIsSpeakerphoneText.setText(" => " + text);
+    }
+
+}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/DeviceReportActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DeviceReportActivity.java
similarity index 79%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/DeviceReportActivity.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DeviceReportActivity.java
index 2f59acb..a9e8e60 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/DeviceReportActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DeviceReportActivity.java
@@ -14,21 +14,20 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.annotation.TargetApi;
 import android.app.Activity;
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.media.AudioDeviceCallback;
 import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 import android.media.MicrophoneInfo;
+import android.os.Build;
 import android.os.Bundle;
-import android.text.method.ScrollingMovementMethod;
 import android.widget.TextView;
 
-import com.google.sample.audio_device.AudioDeviceInfoConverter;
+import com.mobileer.audio_device.AudioDeviceInfoConverter;
 
 import java.io.IOException;
 import java.util.Collection;
@@ -69,9 +68,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_device_report);
-        mAutoTextView = (TextView) findViewById(R.id.text_log);
-        mAutoTextView.setMovementMethod(new ScrollingMovementMethod());
-
+        mAutoTextView = (TextView) findViewById(R.id.text_log_device_report);
         mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
     }
 
@@ -103,13 +100,18 @@
         logClear();
         StringBuffer report = new StringBuffer();
         report.append("Device Report:\n");
+        report.append("App: ").append(MainActivity.getVersionText()).append("\n");
+        report.append("Device: ").append(Build.MANUFACTURER).append(", ").append(Build.MODEL)
+                .append(", ").append(Build.PRODUCT).append("\n");
+
+        report.append(reportExtraDeviceInfo());
+
         for (AudioDeviceInfo deviceInfo : devices) {
             report.append("\n==== Device =================== " + deviceInfo.getId() + "\n");
             String item = AudioDeviceInfoConverter.toString(deviceInfo);
             report.append(item);
         }
         report.append(reportAllMicrophones());
-        report.append(reportExtraDeviceInfo());
         log(report.toString());
     }
 
@@ -137,21 +139,13 @@
     private String reportExtraDeviceInfo() {
         StringBuffer report = new StringBuffer();
         report.append("\n\n############################");
-        report.append("\nExtras:");
-        String unprocessedSupport = mAudioManager.getParameters(AudioManager.PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED);
-        report.append("\nSUPPORT_UNPROCESSED  : " + ((unprocessedSupport == null) ?  "null" : "yes"));
-
-        report.append("\nProAudio Feature     : "
-            + getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_PRO));
-        report.append("\nLowLatency Feature   : "
-                + getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY));
-        report.append("\nMIDI Feature         : "
-                + getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI));
-        report.append("\nUSB Host Feature     : "
-                + getPackageManager().hasSystemFeature(PackageManager.FEATURE_USB_HOST));
-        report.append("\nUSB Accessory Feature: "
-                + getPackageManager().hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY));
-
+        report.append("\nAudioManager:");
+        report.append(AudioQueryTools.getAudioManagerReport(mAudioManager));
+        report.append("\n\nFeatures:");
+        report.append(AudioQueryTools.getAudioFeatureReport(getPackageManager()));
+        report.append(AudioQueryTools.getMediaPerformanceClass());
+        report.append("\n\nProperties:");
+        report.append(AudioQueryTools.getAudioPropertyReport());
         return report.toString();
     }
 
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DoubleStatistics.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DoubleStatistics.java
new file mode 100644
index 0000000..af7f86d
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DoubleStatistics.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2022 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.
+ */
+
+package com.mobileer.oboetester;
+
+import java.util.ArrayList;
+
+class DoubleStatistics {
+    ArrayList<Double> mValues = new ArrayList<Double>();
+    private double mMin = Double.MAX_VALUE;
+    private double mMax = Double.MIN_VALUE;
+    private double mSum = 0.0;
+
+    // Number of measurements.
+    public int count() {
+        return mValues.size();
+    }
+
+    public void add(double value) {
+        mValues.add(value);
+        mMin = Math.min(value, mMin);
+        mMax = Math.max(value, mMax);
+        mSum += value;
+    }
+
+    public double calculateMeanAbsoluteDeviation(double mean) {
+        double deviationSum = 0.0;
+        for (double value : mValues) {
+            deviationSum += Math.abs(value - mean);
+        }
+        return deviationSum / mValues.size();
+    }
+
+    // This will crash if there are no values added.
+    public double calculateMean() {
+        return mSum / mValues.size();
+    }
+
+    public double getMin() {
+        return mMin;
+    }
+
+    public double getMax() {
+        return mMax;
+    }
+
+    public double getSum() {
+        return mSum;
+    }
+
+    // This will crash if there are no values added.
+    public double getLast() {
+        return mValues.get(mValues.size() - 1);
+    }
+}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/EchoActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/EchoActivity.java
similarity index 94%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/EchoActivity.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/EchoActivity.java
index 29026fa..1d8e4dc 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/EchoActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/EchoActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.app.Activity;
 import android.os.Bundle;
@@ -42,6 +42,7 @@
     private Button mStartButton;
     private Button mStopButton;
     private TextView mStatusTextView;
+    private CommunicationDeviceView mCommunicationDeviceView;
 
     private ColdStartSniffer mNativeSniffer = new ColdStartSniffer(this);
 
@@ -158,9 +159,18 @@
                 100.0);
         mFaderDelayTime.setProgress(MAX_DELAY_TIME_PROGRESS / 2);
 
+        mCommunicationDeviceView = (CommunicationDeviceView) findViewById(R.id.comm_device_view);
         hideSettingsViews();
     }
 
+    @Override
+    protected void onStop() {
+        if (mCommunicationDeviceView != null) {
+            mCommunicationDeviceView.cleanup();
+        }
+        super.onStop();
+    }
+
     private void setDelayTimeByPosition(int progress) {
         mDelayTime = mTaperDelayTime.linearToExponential(
                 ((double)progress)/MAX_DELAY_TIME_PROGRESS);
@@ -174,7 +184,6 @@
         return ACTIVITY_ECHO;
     }
 
-
     @Override
     protected void resetConfiguration() {
         super.resetConfiguration();
@@ -208,8 +217,4 @@
     boolean isOutput() {
         return false;
     }
-
-    @Override
-    public void setupEffects(int sessionId) {
-    }
 }
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/ExponentialTaper.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExponentialTaper.java
similarity index 97%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/ExponentialTaper.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExponentialTaper.java
index 9867751..a6d4495 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/ExponentialTaper.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExponentialTaper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 /**
  * Maps integer range info to a double value along an exponential scale.
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExternalTapToToneActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExternalTapToToneActivity.java
new file mode 100644
index 0000000..06cf26d
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExternalTapToToneActivity.java
@@ -0,0 +1,96 @@
+package com.mobileer.oboetester;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.Toast;
+
+import java.io.IOException;
+
+/**
+ * Measure the tap-to-tone latency for other apps or devices.
+ */
+public class ExternalTapToToneActivity extends Activity {
+    private static final String TAG = "OboeTester";
+
+    protected TapToToneTester mTapToToneTester;
+    private Button mStopButton;
+    private Button mStartButton;
+    private Button mAnalyzeButton;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_external_tap_to_tone);
+
+        mTapToToneTester = new TapToToneTester(this,
+                getResources().getString(R.string.external_tap_instructions));
+
+        mStartButton = (Button) findViewById(R.id.button_start);
+        mStopButton = (Button) findViewById(R.id.button_stop);
+        mAnalyzeButton = (Button) findViewById(R.id.button_analyze);
+        updateButtons(false);
+    }
+
+    private void updateButtons(boolean running) {
+        mStartButton.setEnabled(!running);
+        mAnalyzeButton.setEnabled(running);
+        mStopButton.setEnabled(running);
+    }
+
+    public void analyseAndShowResults() {
+        TapToToneTester.TestResult result = mTapToToneTester.analyzeCapturedAudio();
+        if (result != null) {
+            mTapToToneTester.showTestResults(result);
+        }
+    }
+
+    public void analyze(View view) {
+        analyseAndShowResults();
+    }
+
+    public void startTest(View view)  {
+        try {
+            mTapToToneTester.resetLatency();
+            mTapToToneTester.start();
+            updateButtons(true);
+        } catch (IOException e) {
+            e.printStackTrace();
+            showErrorToast("Start audio failed! " + e.getMessage());
+            return;
+        }
+    }
+
+    public void stopTest(View view) {
+        mTapToToneTester.stop();
+        updateButtons(false);
+    }
+
+    @Override
+    public void onStop() {
+        mTapToToneTester.stop();
+        super.onStop();
+    }
+
+
+    protected void showErrorToast(String message) {
+        showToast("Error: " + message);
+    }
+
+    protected void showToast(final String message) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Toast.makeText(ExternalTapToToneActivity.this,
+                        message,
+                        Toast.LENGTH_SHORT).show();
+            }
+        });
+    }
+
+
+}
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExtraTestsActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExtraTestsActivity.java
new file mode 100644
index 0000000..557ceb4
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExtraTestsActivity.java
@@ -0,0 +1,32 @@
+package com.mobileer.oboetester;
+
+import android.content.Intent;
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class ExtraTestsActivity extends BaseOboeTesterActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_extra_tests);
+    }
+
+    public void onLaunchMainActivity(View view) {
+        launchTestActivity(MainActivity.class);
+    }
+
+    public void onLaunchExternalTapTest(View view) {
+        launchTestThatDoesRecording(ExternalTapToToneActivity.class);
+    }
+
+    public void onLaunchPlugLatencyTest(View view) {
+        launchTestActivity(TestPlugLatencyActivity.class);
+    }
+
+    public void onLaunchErrorCallbackTest(View view) {
+        launchTestActivity(TestErrorCallbackActivity.class);
+    }
+
+}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/FastButton.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/FastButton.java
similarity index 91%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/FastButton.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/FastButton.java
index 7abda73..5445f17 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/FastButton.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/FastButton.java
@@ -14,18 +14,11 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.drawable.Drawable;
-import android.text.TextPaint;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
-import android.view.View;
 import android.widget.TextView;
 
 import java.util.ArrayList;
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/GlitchActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/GlitchActivity.java
similarity index 88%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/GlitchActivity.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/GlitchActivity.java
index 01ac1d1..ce0182c 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/GlitchActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/GlitchActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.app.Activity;
 import android.os.Bundle;
@@ -48,6 +48,7 @@
     native int getGlitchCount();
     native double getSignalToNoiseDB();
     native double getPeakAmplitude();
+    native double getSineAmplitude();
 
     private GlitchSniffer mGlitchSniffer;
     private NativeSniffer mNativeSniffer = createNativeSniffer();
@@ -97,12 +98,12 @@
 
         private double mSignalToNoiseDB;
         private double mPeakAmplitude;
+        private double mSineAmplitude;
 
         public GlitchSniffer(Activity activity) {
             super(activity);
         }
 
-
         @Override
         public void startSniffer() {
             long now = System.currentTimeMillis();
@@ -122,10 +123,19 @@
             int state = getAnalyzerState();
             mSignalToNoiseDB = getSignalToNoiseDB();
             mPeakAmplitude = getPeakAmplitude();
+            mSineAmplitude = getSineAmplitude();
+            int glitchCount = getGlitchCount();
+            if (state != mPreviousState) {
+                if ((state == STATE_WAITING_FOR_SIGNAL || state == STATE_WAITING_FOR_LOCK)
+                        && glitchCount == 0) { // did not previously lock
+                    GlitchActivity.this.giveAdvice("Try raising volume!");
+                } else {
+                    GlitchActivity.this.giveAdvice(null);
+                }
+            }
             mPreviousState = state;
 
             long now = System.currentTimeMillis();
-            int glitchCount = getGlitchCount();
             int resetCount = getResetCount();
             mLastUnlockedFrames = getStateFrameCount(STATE_WAITING_FOR_LOCK);
             int lockedFrames = getStateFrameCount(STATE_LOCKED);
@@ -134,7 +144,9 @@
             if (glitchFrames > mLastGlitchFrames || glitchCount > mLastGlitchCount) {
                 mTimeOfLastGlitch = now;
                 mSecondsWithoutGlitches = 0.0;
-                onGlitchDetected();
+                if (glitchCount > mLastGlitchCount) {
+                    onGlitchDetected();
+                }
             } else if (lockedFrames > mLastLockedFrames) {
                 mSecondsWithoutGlitches = (now - mTimeOfLastGlitch) / 1000.0;
             }
@@ -166,13 +178,14 @@
             message.append(String.format("glitch.frames = %d\n", mLastGlitchFrames));
             message.append(String.format("reset.count = %d\n", mLastResetCount - mStartResetCount));
             message.append(String.format("peak.amplitude = %8.6f\n", mPeakAmplitude));
+            message.append(String.format("sine.amplitude = %8.6f\n", mSineAmplitude));
             if (mLastLockedFrames > 0) {
                 message.append(String.format("signal.noise.ratio.db = %5.1f\n", mSignalToNoiseDB));
             }
-            message.append(String.format("time.total = %8.2f seconds\n", totalSeconds));
+            message.append(String.format("time.total = %4.2f seconds\n", totalSeconds));
             if (mLastLockedFrames > 0) {
-                message.append(String.format("time.no.glitches = %8.2f\n", mSecondsWithoutGlitches));
-                message.append(String.format("max.time.no.glitches = %8.2f\n",
+                message.append(String.format("time.no.glitches = %4.2f\n", mSecondsWithoutGlitches));
+                message.append(String.format("max.time.no.glitches = %4.2f\n",
                         mMaxSecondsWithoutGlitches));
                 message.append(String.format("glitch.count = %d\n", mLastGlitchCount));
             }
@@ -207,6 +220,9 @@
         }
     }
 
+    public void giveAdvice(String s) {
+    }
+
     // Called on UI thread
     protected void onGlitchDetected() {
     }
@@ -272,19 +288,36 @@
     @Override
     protected void onStart() {
         super.onStart();
-        mStartButton.setEnabled(true);
-        mStopButton.setEnabled(false);
-        mShareButton.setEnabled(false);
+        setInputChannel(0);
+        setOutputChannel(0);
     }
 
     @Override
     protected void onStop() {
-        stopAudioTest();
+        if (!isBackgroundEnabled()) {
+            stopAudioTest();
+        }
         super.onStop();
     }
 
+    @Override
+    protected void onDestroy() {
+        if (isBackgroundEnabled()) {
+            stopAudioTest();
+        }
+        super.onDestroy();
+    }
+
     // Called on UI thread
-    public void onStartAudioTest(View view) throws IOException {
+    public void onStartAudioTest(View view) {
+        try {
+            openStartAudioTestUI();
+        } catch (IOException e) {
+            showErrorToast(e.getMessage());
+        }
+    }
+
+    protected void openStartAudioTestUI() throws IOException {
         openAudio();
         startAudioTest();
         mStartButton.setEnabled(false);
@@ -308,6 +341,9 @@
     public void onStopAudioTest(View view) {
         stopAudioTest();
         onTestFinished();
+        mStartButton.setEnabled(true);
+        mStopButton.setEnabled(false);
+        mShareButton.setEnabled(false);
         keepScreenOn(false);
     }
 
@@ -337,10 +373,6 @@
         return false;
     }
 
-    @Override
-    public void setupEffects(int sessionId) {
-    }
-
     public double getMaxSecondsWithNoGlitch() {
         return mGlitchSniffer.getMaxSecondsWithNoGlitch();
     }
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/InputMarginView.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/InputMarginView.java
similarity index 92%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/InputMarginView.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/InputMarginView.java
index 11b3252..32a8028 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/InputMarginView.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/InputMarginView.java
@@ -14,17 +14,13 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.CheckBox;
 import android.widget.LinearLayout;
 
-import java.util.ArrayList;
-
 /**
  * View for editing an input stream margin to avoid glitches.
  *
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/IntentBasedTestSupport.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/IntentBasedTestSupport.java
new file mode 100644
index 0000000..594e7c4
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/IntentBasedTestSupport.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2022 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.
+ */
+
+package com.mobileer.oboetester;
+
+import android.content.Intent;
+import android.media.AudioManager;
+import android.os.Bundle;
+
+public class IntentBasedTestSupport {
+
+    public static final String KEY_IN_SHARING = "in_sharing";
+    public static final String KEY_OUT_SHARING = "out_sharing";
+    public static final String VALUE_SHARING_EXCLUSIVE = "exclusive";
+    public static final String VALUE_SHARING_SHARED = "shared";
+
+    public static final String KEY_IN_PERF = "in_perf";
+    public static final String KEY_OUT_PERF = "out_perf";
+    public static final String VALUE_PERF_LOW_LATENCY = "lowlat";
+    public static final String VALUE_PERF_POWERSAVE = "powersave";
+    public static final String VALUE_PERF_NONE = "none";
+
+    public static final String KEY_IN_CHANNELS = "in_channels";
+    public static final String KEY_OUT_CHANNELS = "out_channels";
+    public static final int VALUE_DEFAULT_CHANNELS = 2;
+
+    public static final String KEY_IN_USE_MMAP = "in_use_mmap";
+    public static final String KEY_OUT_USE_MMAP = "out_use_mmap";
+    public static final boolean VALUE_DEFAULT_USE_MMAP = true;
+
+    public static final String KEY_IN_PRESET = "in_preset";
+    public static final String KEY_SAMPLE_RATE = "sample_rate";
+    public static final int VALUE_DEFAULT_SAMPLE_RATE = 48000;
+    public static final String VALUE_UNSPECIFIED = "unspecified";
+
+    public static final String KEY_IN_API = "in_api";
+    public static final String KEY_OUT_API = "out_api";
+    public static final String VALUE_API_AAUDIO = "aaudio";
+    public static final String VALUE_API_OPENSLES = "opensles";
+
+    public static final String KEY_FILE_NAME = "file";
+    public static final String KEY_BUFFER_BURSTS = "buffer_bursts";
+    public static final String KEY_BACKGROUND = "background";
+    public static final String KEY_VOLUME = "volume";
+
+    public static final String KEY_VOLUME_TYPE = "volume_type";
+    public static final float VALUE_VOLUME_INVALID = -1.0f;
+    public static final String VALUE_VOLUME_TYPE_ACCESSIBILITY = "accessibility";
+    public static final String VALUE_VOLUME_TYPE_ALARM = "alarm";
+    public static final String VALUE_VOLUME_TYPE_DTMF = "dtmf";
+    public static final String VALUE_VOLUME_TYPE_MUSIC = "music";
+    public static final String VALUE_VOLUME_TYPE_NOTIFICATION = "notification";
+    public static final String VALUE_VOLUME_TYPE_RING = "ring";
+    public static final String VALUE_VOLUME_TYPE_SYSTEM = "system";
+    public static final String VALUE_VOLUME_TYPE_VOICE_CALL = "voice_call";
+
+    public static final String KEY_IN_CHANNEL_MASK = "in_channel_mask";
+    public static final String KEY_OUT_CHANNEL_MASK = "out_channel_mask";
+    public static final String VALUE_CHANNEL_MONO = "mono";
+    public static final String VALUE_CHANNEL_STEREO = "stereo";
+    public static final String VALUE_CHANNEL_2POINT1 = "2.1";
+    public static final String VALUE_CHANNEL_TRI = "tri";
+    public static final String VALUE_CHANNEL_TRI_BACK = "triBack";
+    public static final String VALUE_CHANNEL_TRI_BACK_LOWERCASE = "triback";
+    public static final String VALUE_CHANNEL_3POINT1 = "3.1";
+    public static final String VALUE_CHANNEL_2POINT0POINT2 = "2.0.2";
+    public static final String VALUE_CHANNEL_2POINT1POINT2 = "2.1.2";
+    public static final String VALUE_CHANNEL_3POINT0POINT2 = "3.0.2";
+    public static final String VALUE_CHANNEL_3POINT1POINT2 = "3.1.2";
+    public static final String VALUE_CHANNEL_QUAD = "quad";
+    public static final String VALUE_CHANNEL_QUAD_SIDE = "quadSide";
+    public static final String VALUE_CHANNEL_QUAD_SIDE_LOWERCASE = "quadside";
+    public static final String VALUE_CHANNEL_SURROUND = "surround";
+    public static final String VALUE_CHANNEL_PENTA = "penta";
+    public static final String VALUE_CHANNEL_5POINT1 = "5.1";
+    public static final String VALUE_CHANNEL_5POINT1_SIDE = "5.1Side";
+    public static final String VALUE_CHANNEL_5POINT1_SIDE_LOWERCASE = "5.1side";
+    public static final String VALUE_CHANNEL_6POINT1 = "6.1";
+    public static final String VALUE_CHANNEL_7POINT1 = "7.1";
+    public static final String VALUE_CHANNEL_5POINT1POINT2 = "5.1.2";
+    public static final String VALUE_CHANNEL_5POINT1POINT4 = "5.1.4";
+    public static final String VALUE_CHANNEL_7POINT1POINT2 = "7.1.2";
+    public static final String VALUE_CHANNEL_7POINT1POINT4 = "7.1.4";
+    public static final String VALUE_CHANNEL_9POINT1POINT4 = "9.1.4";
+    public static final String VALUE_CHANNEL_9POINT1POINT6 = "9.1.6";
+    public static final String VALUE_CHANNEL_FRONT_BACK = "frontBack";
+    public static final String VALUE_CHANNEL_FRONT_BACK_LOWERCASE = "frontback";
+
+    public static final String KEY_SIGNAL_TYPE = "signal_type";
+    public static final String VALUE_SIGNAL_SINE = "sine";
+    public static final String VALUE_SIGNAL_SAWTOOTH = "sawtooth";
+    public static final String VALUE_SIGNAL_FREQ_SWEEP = "freq_sweep";
+    public static final String VALUE_SIGNAL_PITCH_SWEEP = "pitch_sweep";
+    public static final String VALUE_SIGNAL_WHITE_NOISE = "white_noise";
+
+    public static final String KEY_DURATION = "duration";
+    public static final int VALUE_DEFAULT_DURATION = 10;
+
+    public static int getApiFromText(String text) {
+        if (VALUE_API_AAUDIO.equals(text)) {
+            return StreamConfiguration.NATIVE_API_AAUDIO;
+        } else if (VALUE_API_OPENSLES.equals(text)) {
+            return StreamConfiguration.NATIVE_API_OPENSLES;
+        } else {
+            return StreamConfiguration.NATIVE_API_UNSPECIFIED;
+        }
+    }
+
+    public static int getPerfFromText(String text) {
+        if (VALUE_PERF_NONE.equals(text)) {
+            return StreamConfiguration.PERFORMANCE_MODE_NONE;
+        } else if (VALUE_PERF_POWERSAVE.equals(text)) {
+            return StreamConfiguration.PERFORMANCE_MODE_POWER_SAVING;
+        } else if (VALUE_PERF_LOW_LATENCY.equals(text)) {
+            return StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY;
+        } else {
+            throw new IllegalArgumentException("perf mode invalid: " + text);
+        }
+    }
+
+    public static int getSharingFromText(String text) {
+        if (VALUE_SHARING_SHARED.equals(text)) {
+            return StreamConfiguration.SHARING_MODE_SHARED;
+        } else {
+            return StreamConfiguration.SHARING_MODE_EXCLUSIVE;
+        }
+    }
+
+    public static void configureStreamsFromBundle(Bundle bundle,
+                                                  StreamConfiguration requestedInConfig,
+                                                  StreamConfiguration requestedOutConfig) {
+        configureInputStreamFromBundle(bundle, requestedInConfig);
+        configureOutputStreamFromBundle(bundle, requestedOutConfig);
+    }
+
+    public static float getNormalizedVolumeFromBundle(Bundle bundle) {
+        return bundle.getFloat(KEY_VOLUME, VALUE_VOLUME_INVALID);
+    }
+
+    /**
+     * @param bundle
+     * @return AudioManager.STREAM type or throw IllegalArgumentException
+     */
+    public static int getVolumeStreamTypeFromBundle(Bundle bundle) {
+        String typeText = bundle.getString(KEY_VOLUME_TYPE, VALUE_VOLUME_TYPE_MUSIC);
+        switch (typeText) {
+            case VALUE_VOLUME_TYPE_ACCESSIBILITY:
+                return AudioManager.STREAM_ACCESSIBILITY;
+            case VALUE_VOLUME_TYPE_ALARM:
+                return AudioManager.STREAM_ALARM;
+            case VALUE_VOLUME_TYPE_DTMF:
+                return AudioManager.STREAM_DTMF;
+            case VALUE_VOLUME_TYPE_MUSIC:
+                return AudioManager.STREAM_MUSIC;
+            case VALUE_VOLUME_TYPE_NOTIFICATION:
+                return AudioManager.STREAM_NOTIFICATION;
+            case VALUE_VOLUME_TYPE_RING:
+                return AudioManager.STREAM_RING;
+            case VALUE_VOLUME_TYPE_SYSTEM:
+                return AudioManager.STREAM_SYSTEM;
+            case VALUE_VOLUME_TYPE_VOICE_CALL:
+                return AudioManager.STREAM_VOICE_CALL;
+            default:
+               throw new IllegalArgumentException(KEY_VOLUME_TYPE + " invalid: " + typeText);
+        }
+    }
+
+    public static int getChannelMaskFromBundle(Bundle bundle, String channelMaskKey) {
+        String channelMaskText = bundle.getString(channelMaskKey);
+        if (channelMaskText == null) {
+            return StreamConfiguration.UNSPECIFIED;
+        }
+        switch (channelMaskText) {
+            case VALUE_CHANNEL_MONO:
+                return StreamConfiguration.CHANNEL_MONO;
+            case VALUE_CHANNEL_STEREO:
+                return StreamConfiguration.CHANNEL_STEREO;
+            case VALUE_CHANNEL_2POINT1:
+                return StreamConfiguration.CHANNEL_2POINT1;
+            case VALUE_CHANNEL_TRI:
+                return StreamConfiguration.CHANNEL_TRI;
+            case VALUE_CHANNEL_TRI_BACK:
+            case VALUE_CHANNEL_TRI_BACK_LOWERCASE:
+                return StreamConfiguration.CHANNEL_TRI_BACK;
+            case VALUE_CHANNEL_3POINT1:
+                return StreamConfiguration.CHANNEL_3POINT1;
+            case VALUE_CHANNEL_2POINT0POINT2:
+                return StreamConfiguration.CHANNEL_2POINT0POINT2;
+            case VALUE_CHANNEL_2POINT1POINT2:
+                return StreamConfiguration.CHANNEL_2POINT1POINT2;
+            case VALUE_CHANNEL_3POINT0POINT2:
+                return StreamConfiguration.CHANNEL_3POINT0POINT2;
+            case VALUE_CHANNEL_3POINT1POINT2:
+                return StreamConfiguration.CHANNEL_3POINT1POINT2;
+            case VALUE_CHANNEL_QUAD:
+                return StreamConfiguration.CHANNEL_QUAD;
+            case VALUE_CHANNEL_QUAD_SIDE:
+            case VALUE_CHANNEL_QUAD_SIDE_LOWERCASE:
+                return StreamConfiguration.CHANNEL_QUAD_SIDE;
+            case VALUE_CHANNEL_SURROUND:
+                return StreamConfiguration.CHANNEL_SURROUND;
+            case VALUE_CHANNEL_PENTA:
+                return StreamConfiguration.CHANNEL_PENTA;
+            case VALUE_CHANNEL_5POINT1:
+                return StreamConfiguration.CHANNEL_5POINT1;
+            case VALUE_CHANNEL_5POINT1_SIDE:
+            case VALUE_CHANNEL_5POINT1_SIDE_LOWERCASE:
+                return StreamConfiguration.CHANNEL_5POINT1_SIDE;
+            case VALUE_CHANNEL_6POINT1:
+                return StreamConfiguration.CHANNEL_6POINT1;
+            case VALUE_CHANNEL_7POINT1:
+                return StreamConfiguration.CHANNEL_7POINT1;
+            case VALUE_CHANNEL_5POINT1POINT2:
+                return StreamConfiguration.CHANNEL_5POINT1POINT2;
+            case VALUE_CHANNEL_5POINT1POINT4:
+                return StreamConfiguration.CHANNEL_5POINT1POINT4;
+            case VALUE_CHANNEL_7POINT1POINT2:
+                return StreamConfiguration.CHANNEL_7POINT1POINT2;
+            case VALUE_CHANNEL_7POINT1POINT4:
+                return StreamConfiguration.CHANNEL_7POINT1POINT4;
+            case VALUE_CHANNEL_9POINT1POINT4:
+                return StreamConfiguration.CHANNEL_9POINT1POINT4;
+            case VALUE_CHANNEL_9POINT1POINT6:
+                return StreamConfiguration.CHANNEL_9POINT1POINT6;
+            case VALUE_CHANNEL_FRONT_BACK:
+            case VALUE_CHANNEL_FRONT_BACK_LOWERCASE:
+                return StreamConfiguration.CHANNEL_FRONT_BACK;
+            default:
+                throw new IllegalArgumentException(
+                        channelMaskKey + " invalid: " + channelMaskText);
+        }
+    }
+
+    public static void configureOutputStreamFromBundle(Bundle bundle,
+                                                        StreamConfiguration requestedOutConfig) {
+        int audioApi;
+        String text;
+
+        requestedOutConfig.reset();
+
+        int sampleRate = bundle.getInt(KEY_SAMPLE_RATE, VALUE_DEFAULT_SAMPLE_RATE);
+        requestedOutConfig.setSampleRate(sampleRate);
+
+        text = bundle.getString(KEY_OUT_API, VALUE_UNSPECIFIED);
+        audioApi = getApiFromText(text);
+        requestedOutConfig.setNativeApi(audioApi);
+
+        int outChannels = bundle.getInt(KEY_OUT_CHANNELS, VALUE_DEFAULT_CHANNELS);
+        int channelMask = getChannelMaskFromBundle(bundle, KEY_OUT_CHANNEL_MASK);
+        // Respect channel mask when it is specified.
+        if (channelMask != StreamConfiguration.UNSPECIFIED) {
+            requestedOutConfig.setChannelMask(channelMask);
+        } else {
+            requestedOutConfig.setChannelCount(outChannels);
+        }
+
+        boolean outMMAP = bundle.getBoolean(KEY_OUT_USE_MMAP, VALUE_DEFAULT_USE_MMAP);
+        requestedOutConfig.setMMap(outMMAP);
+
+        text = bundle.getString(KEY_OUT_PERF, VALUE_PERF_LOW_LATENCY);
+        int perfMode = getPerfFromText(text);
+        requestedOutConfig.setPerformanceMode(perfMode);
+
+        text = bundle.getString(KEY_OUT_SHARING, VALUE_SHARING_EXCLUSIVE);
+        int sharingMode = getSharingFromText(text);
+        requestedOutConfig.setSharingMode(sharingMode);
+
+    }
+
+    public static void configureInputStreamFromBundle(Bundle bundle,
+                                                       StreamConfiguration requestedInConfig) {
+        int audioApi;
+        String text;
+
+        requestedInConfig.reset();
+
+        int sampleRate = bundle.getInt(KEY_SAMPLE_RATE, VALUE_DEFAULT_SAMPLE_RATE);
+        requestedInConfig.setSampleRate(sampleRate);
+
+        text = bundle.getString(KEY_IN_API, VALUE_UNSPECIFIED);
+        audioApi = getApiFromText(text);
+        requestedInConfig.setNativeApi(audioApi);
+
+        int inChannels = bundle.getInt(KEY_IN_CHANNELS, VALUE_DEFAULT_CHANNELS);
+        int channelMask = getChannelMaskFromBundle(bundle, KEY_IN_CHANNEL_MASK);
+        // Respect channel mask when it is specified.
+        if (channelMask != StreamConfiguration.UNSPECIFIED) {
+            requestedInConfig.setChannelMask(channelMask);
+        } else {
+            requestedInConfig.setChannelCount(inChannels);
+        }
+
+        boolean inMMAP = bundle.getBoolean(KEY_IN_USE_MMAP, VALUE_DEFAULT_USE_MMAP);
+        requestedInConfig.setMMap(inMMAP);
+
+        text = bundle.getString(KEY_IN_PERF, VALUE_PERF_LOW_LATENCY);
+        int perfMode = getPerfFromText(text);
+        requestedInConfig.setPerformanceMode(perfMode);
+
+        text = bundle.getString(KEY_IN_SHARING, VALUE_SHARING_EXCLUSIVE);
+        int sharingMode = getSharingFromText(text);
+        requestedInConfig.setSharingMode(sharingMode);
+
+        String defaultText = StreamConfiguration.convertInputPresetToText(
+                StreamConfiguration.INPUT_PRESET_VOICE_RECOGNITION);
+        text = bundle.getString(KEY_IN_PRESET, defaultText);
+        int inputPreset = StreamConfiguration.convertTextToInputPreset(text);
+        if (inputPreset < 0) throw new IllegalArgumentException(KEY_IN_PRESET + " invalid: " + text);
+        requestedInConfig.setInputPreset(inputPreset);
+    }
+
+    public static int getSignalTypeFromBundle(Bundle bundle) {
+        String signalTypeText = bundle.getString(KEY_SIGNAL_TYPE);
+        if (signalTypeText == null) {
+            return 0;
+        }
+        switch (signalTypeText) {
+            case VALUE_SIGNAL_SINE:
+                return 0;
+            case VALUE_SIGNAL_SAWTOOTH:
+                return 1;
+            case VALUE_SIGNAL_FREQ_SWEEP:
+                return 2;
+            case VALUE_SIGNAL_PITCH_SWEEP:
+                return 3;
+            case VALUE_SIGNAL_WHITE_NOISE:
+                return 4;
+            default:
+                throw new IllegalArgumentException(
+                        KEY_SIGNAL_TYPE + " invalid: " + signalTypeText);
+        }
+    }
+
+    public static int getDurationSeconds(Bundle bundle) {
+        return bundle.getInt(KEY_DURATION, VALUE_DEFAULT_DURATION);
+    }
+}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/MainActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MainActivity.java
similarity index 71%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/MainActivity.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MainActivity.java
index 0a4be58..70eca90 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/MainActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MainActivity.java
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
-import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -34,24 +33,25 @@
 import android.widget.CheckBox;
 import android.widget.Spinner;
 import android.widget.TextView;
-import android.widget.Toast;
 
 /**
  * Select various Audio tests.
  */
 
-public class MainActivity extends Activity {
+public class MainActivity extends BaseOboeTesterActivity {
 
     private static final String KEY_TEST_NAME = "test";
     public static final String VALUE_TEST_NAME_LATENCY = "latency";
     public static final String VALUE_TEST_NAME_GLITCH = "glitch";
+    public static final String VALUE_TEST_NAME_DATA_PATHS = "data_paths";
+    public static final String VALUE_TEST_NAME_OUTPUT = "output";
+    public static final String VALUE_TEST_NAME_INPUT = "input";
 
     static {
         // Must match name in CMakeLists.txt
         System.loadLibrary("oboetester");
     }
 
-
     private Spinner mModeSpinner;
     private TextView mCallbackSizeEditor;
     protected TextView mDeviceView;
@@ -61,6 +61,7 @@
     private Bundle mBundleFromIntent;
     private BroadcastReceiver mScoStateReceiver;
     private CheckBox mWorkaroundsCheckBox;
+    private CheckBox mBackgroundCheckBox;
     private static String mVersionText;
 
     @Override
@@ -78,6 +79,7 @@
 
         // Set mode, eg. MODE_IN_COMMUNICATION
         mModeSpinner = (Spinner) findViewById(R.id.spinnerAudioMode);
+        // Update AudioManager now in case user is trying to affect a different app.
         mModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
             @Override
             public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
@@ -97,8 +99,9 @@
             int oboeMajor = (oboeVersion >> 24) & 0xFF;
             int oboeMinor = (oboeVersion >> 16) & 0xFF;
             int oboePatch = oboeVersion & 0xFF;
-            mVersionText = "OboeTester (" + pinfo.versionCode + ") v " + pinfo.versionName
-                    + ", Oboe v " + oboeMajor + "." + oboeMinor + "." + oboePatch;
+            mVersionText = getString(R.string.app_name_version,
+                    pinfo.versionCode, pinfo.versionName,
+                    oboeMajor, oboeMinor, oboePatch);
             mVersionTextView.setText(mVersionText);
         } catch (PackageManager.NameNotFoundException e) {
             mVersionTextView.setText(e.getMessage());
@@ -106,8 +109,11 @@
 
         mWorkaroundsCheckBox = (CheckBox) findViewById(R.id.boxEnableWorkarounds);
         // Turn off workarounds so we can test the underlying API bugs.
+        mWorkaroundsCheckBox.setChecked(false);
         NativeEngine.setWorkaroundsEnabled(false);
 
+        mBackgroundCheckBox = (CheckBox) findViewById(R.id.boxEnableBackground);
+
         mBuildTextView = (TextView) findViewById(R.id.text_build_info);
         mBuildTextView.setText(Build.DISPLAY);
 
@@ -129,7 +135,7 @@
         saveIntentBundleForLaterProcessing(getIntent());
     }
 
-    public static String getVersiontext() {
+    public static String getVersionText() {
         return mVersionText;
     }
 
@@ -165,28 +171,50 @@
         if (mBundleFromIntent == null) {
             return;
         }
-
-        if (mBundleFromIntent.containsKey(KEY_TEST_NAME)) {
-            String testName = mBundleFromIntent.getString(KEY_TEST_NAME);
-            if (VALUE_TEST_NAME_LATENCY.equals(testName)) {
-                Intent intent = new Intent(this, RoundTripLatencyActivity.class);
-                intent.putExtras(mBundleFromIntent);
-                startActivity(intent);
-            } else if (VALUE_TEST_NAME_GLITCH.equals(testName)) {
-                Intent intent = new Intent(this, ManualGlitchActivity.class);
-                intent.putExtras(mBundleFromIntent);
-                startActivity(intent);
-            }
+        Intent intent = getTestIntent(mBundleFromIntent);
+        if (intent != null) {
+            setBackgroundFromIntent();
+            startActivity(intent);
         }
         mBundleFromIntent = null;
     }
 
+    private void setBackgroundFromIntent() {
+        boolean backgroundEnabled = mBundleFromIntent.getBoolean(
+                IntentBasedTestSupport.KEY_BACKGROUND, false);
+        TestAudioActivity.setBackgroundEnabled(backgroundEnabled);
+    }
+
+    private Intent getTestIntent(Bundle bundle) {
+        Intent intent = null;
+        if (bundle.containsKey(KEY_TEST_NAME)) {
+            String testName = bundle.getString(KEY_TEST_NAME);
+            if (VALUE_TEST_NAME_LATENCY.equals(testName)) {
+                intent = new Intent(this, RoundTripLatencyActivity.class);
+                intent.putExtras(bundle);
+            } else if (VALUE_TEST_NAME_GLITCH.equals(testName)) {
+                intent = new Intent(this, ManualGlitchActivity.class);
+                intent.putExtras(bundle);
+            } else if (VALUE_TEST_NAME_DATA_PATHS.equals(testName)) {
+                intent = new Intent(this, TestDataPathsActivity.class);
+                intent.putExtras(bundle);
+            } else if (VALUE_TEST_NAME_INPUT.equals(testName)) {
+                intent = new Intent(this, TestInputActivity.class);
+                intent.putExtras(bundle);
+            } else if (VALUE_TEST_NAME_OUTPUT.equals(testName)) {
+                intent = new Intent(this, TestOutputActivity.class);
+                intent.putExtras(bundle);
+            }
+        }
+        return intent;
+    }
+
     @Override
     public void onResume(){
         super.onResume();
         mWorkaroundsCheckBox.setChecked(NativeEngine.areWorkaroundsEnabled());
-        processBundleFromIntent();
         registerScoStateReceiver();
+        processBundleFromIntent();
     }
 
     @Override
@@ -204,51 +232,66 @@
     }
 
     public void onLaunchTestOutput(View view) {
-        onLaunchTest(TestOutputActivity.class);
+        launchTestActivity(TestOutputActivity.class);
     }
 
     public void onLaunchTestInput(View view) {
-        onLaunchTest(TestInputActivity.class);
+        launchTestThatDoesRecording(TestInputActivity.class);
     }
 
     public void onLaunchTapToTone(View view) {
-        onLaunchTest(TapToToneActivity.class);
+        launchTestThatDoesRecording(TapToToneActivity.class);
     }
 
     public void onLaunchRecorder(View view) {
-        onLaunchTest(RecorderActivity.class);
+        launchTestThatDoesRecording(RecorderActivity.class);
     }
 
     public void onLaunchEcho(View view) {
-        onLaunchTest(EchoActivity.class);
+        launchTestThatDoesRecording(EchoActivity.class);
     }
 
     public void onLaunchRoundTripLatency(View view) {
-        onLaunchTest(RoundTripLatencyActivity.class);
+        launchTestThatDoesRecording(RoundTripLatencyActivity.class);
     }
 
     public void onLaunchManualGlitchTest(View view) {
-        onLaunchTest(ManualGlitchActivity.class);
+        launchTestThatDoesRecording(ManualGlitchActivity.class);
     }
 
-    public void onLaunchAutoGlitchTest(View view) { onLaunchTest(AutomatedGlitchActivity.class); }
+    public void onLaunchAutoGlitchTest(View view) { launchTestThatDoesRecording(AutomatedGlitchActivity.class); }
 
     public void onLaunchTestDisconnect(View view) {
-        onLaunchTest(TestDisconnectActivity.class);
+        launchTestThatDoesRecording(TestDisconnectActivity.class);
     }
 
     public void onLaunchTestDataPaths(View view) {
-        onLaunchTest(TestDataPathsActivity.class);
+        launchTestThatDoesRecording(TestDataPathsActivity.class);
     }
 
     public void onLaunchTestDeviceReport(View view)  {
-        onLaunchTest(DeviceReportActivity.class);
+        launchTestActivity(DeviceReportActivity.class);
     }
 
-    private void onLaunchTest(Class clazz) {
+    public void onLaunchExtratests(View view) {
+        launchTestActivity(ExtraTestsActivity.class);
+    }
+
+    private void applyUserOptions() {
         updateCallbackSize();
-        Intent intent = new Intent(this, clazz);
-        startActivity(intent);
+
+        long mode = mModeSpinner.getSelectedItemId();
+        AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        myAudioMgr.setMode((int) mode);
+
+        NativeEngine.setWorkaroundsEnabled(mWorkaroundsCheckBox.isChecked());
+        TestAudioActivity.setBackgroundEnabled(mBackgroundCheckBox.isChecked());
+    }
+
+    @Override
+    protected void launchTestActivity(Class clazz) {
+        applyUserOptions();
+        super.launchTestActivity(clazz);
     }
 
     public void onUseCallbackClicked(View view) {
@@ -256,21 +299,6 @@
         OboeAudioStream.setUseCallback(checkBox.isChecked());
     }
 
-    protected void showErrorToast(String message) {
-        showToast("Error: " + message);
-    }
-
-    protected void showToast(final String message) {
-        runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                Toast.makeText(MainActivity.this,
-                        message,
-                        Toast.LENGTH_SHORT).show();
-            }
-        });
-    }
-
     private void updateCallbackSize() {
         CharSequence chars = mCallbackSizeEditor.getText();
         String text = chars.toString();
@@ -284,13 +312,6 @@
         OboeAudioStream.setCallbackSize(callbackSize);
     }
 
-    public void onSetSpeakerphoneOn(View view) {
-        CheckBox checkBox = (CheckBox) view;
-        boolean enabled = checkBox.isChecked();
-        AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-        myAudioMgr.setSpeakerphoneOn(enabled);
-    }
-
     public void onStartStopBluetoothSco(View view) {
         CheckBox checkBox = (CheckBox) view;
         AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
@@ -300,10 +321,4 @@
             myAudioMgr.stopBluetoothSco();
         }
     }
-
-    public void onEnableWorkarounds(View view) {
-        CheckBox checkBox = (CheckBox) view;
-        boolean enabled = checkBox.isChecked();
-        NativeEngine.setWorkaroundsEnabled(enabled);
-    }
 }
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/ManualGlitchActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java
similarity index 71%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/ManualGlitchActivity.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java
index d60f4b3..699344d 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/ManualGlitchActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
-import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -27,24 +26,20 @@
 
 public class ManualGlitchActivity extends GlitchActivity {
 
-    public static final String KEY_IN_PRESET = "in_preset";
-
-    public static final String KEY_DURATION = "duration";
-    public static final int VALUE_DEFAULT_DURATION = 10;
-
     public static final String KEY_BUFFER_BURSTS = "buffer_bursts";
     public static final int VALUE_DEFAULT_BUFFER_BURSTS = 2;
 
     public static final String KEY_TOLERANCE = "tolerance";
     private static final float DEFAULT_TOLERANCE = 0.1f;
 
+    private static final long MIN_DISPLAY_PERIOD_MILLIS = 500;
+
     private TextView mTextTolerance;
     private SeekBar mFaderTolerance;
     protected ExponentialTaper mTaperTolerance;
     private WaveformView mWaveformView;
     private float[] mWaveform = new float[256];
-    private boolean mTestRunningByIntent;
-    private Bundle mBundleFromIntent;
+    private long mLastDisplayTime;
 
     private float   mTolerance = DEFAULT_TOLERANCE;
 
@@ -73,7 +68,6 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mBundleFromIntent = getIntent().getExtras();
 
         mTextTolerance = (TextView) findViewById(R.id.textTolerance);
         mFaderTolerance = (SeekBar) findViewById(R.id.faderTolerance);
@@ -95,60 +89,25 @@
         setContentView(R.layout.activity_manual_glitches);
     }
 
-    @Override
-    public void onResume(){
-        super.onResume();
-        processBundleFromIntent();
-    }
-
-    @Override
-    public void onNewIntent(Intent intent) {
-        mBundleFromIntent = intent.getExtras();
-    }
-
-    private void processBundleFromIntent() {
-        if (mBundleFromIntent == null) {
-            return;
-        }
-        if (mTestRunningByIntent) {
-            return;
-        }
-
-        mResultFileName = null;
-        if (mBundleFromIntent.containsKey(KEY_FILE_NAME)) {
-            mTestRunningByIntent = true;
-            mResultFileName = mBundleFromIntent.getString(KEY_FILE_NAME);
-
-            // Delay the test start to avoid race conditions.
-            Handler handler = new Handler(Looper.getMainLooper()); // UI thread
-            handler.postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    startAutomaticTest();
-                }
-            }, 500); // TODO where is the race, close->open?
-
-        }
-    }
-
     void configureStreamsFromBundle(Bundle bundle) {
-        // Extract common parameters
-        super.configureStreamsFromBundle(bundle);
-
+        // Configure settings
         StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration;
         StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
+        IntentBasedTestSupport.configureStreamsFromBundle(bundle, requestedInConfig, requestedOutConfig);
 
         // Extract custom parameters from the bundle.
         float tolerance = bundle.getFloat(KEY_TOLERANCE, DEFAULT_TOLERANCE);
         setToleranceFader(tolerance);
         setTolerance(tolerance);
         mTolerance = tolerance;
+    }
 
-        String defaultText = StreamConfiguration.convertInputPresetToText(
-                StreamConfiguration.INPUT_PRESET_VOICE_RECOGNITION);
-        String text = bundle.getString(KEY_IN_PRESET, defaultText);
-        int inputPreset = StreamConfiguration.convertTextToInputPreset(text);
-        requestedInConfig.setInputPreset(inputPreset);
+    @Override
+    public void giveAdvice(String s) {
+        mWaveformView.post(() -> {
+            mWaveformView.setMessage(s);
+            mWaveformView.invalidate();
+        });
     }
 
     public void startAudioTest() throws IOException {
@@ -156,15 +115,15 @@
         setToleranceProgress(mFaderTolerance.getProgress());
     }
 
-    void startAutomaticTest() {
+    @Override
+    public void startTestUsingBundle() {
         configureStreamsFromBundle(mBundleFromIntent);
 
-        int durationSeconds = mBundleFromIntent.getInt(KEY_DURATION, VALUE_DEFAULT_DURATION);
+        int durationSeconds = IntentBasedTestSupport.getDurationSeconds(mBundleFromIntent);
         int numBursts = mBundleFromIntent.getInt(KEY_BUFFER_BURSTS, VALUE_DEFAULT_BUFFER_BURSTS);
-        mBundleFromIntent = null;
 
         try {
-            onStartAudioTest(null);
+            openStartAudioTestUI();
             int sizeFrames = mAudioOutTester.getCurrentAudioStream().getFramesPerBurst() * numBursts;
             mAudioOutTester.getCurrentAudioStream().setBufferSizeInFrames(sizeFrames);
 
@@ -180,6 +139,8 @@
             String report = "Open failed: " + e.getMessage();
             maybeWriteTestResult(report);
             mTestRunningByIntent = false;
+        } finally {
+            mBundleFromIntent = null;
         }
 
     }
@@ -198,6 +159,7 @@
     public void onTestFinished() {
         super.onTestFinished();
     }
+
     // Only call from UI thread.
     @Override
     public void onTestBegan() {
@@ -209,9 +171,13 @@
     // Called on UI thread
     @Override
     protected void onGlitchDetected() {
-        int numSamples = getGlitch(mWaveform);
-        mWaveformView.setSampleData(mWaveform, 0, numSamples);
-        mWaveformView.postInvalidate();
+        long now = System.currentTimeMillis();
+        if ((now - mLastDisplayTime) > MIN_DISPLAY_PERIOD_MILLIS) {
+            mLastDisplayTime = now;
+            int numSamples = getGlitch(mWaveform);
+            mWaveformView.setSampleData(mWaveform, 0, numSamples);
+            mWaveformView.postInvalidate();
+        }
     }
 
     private float[] getGlitchWaveform() {
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/MicrophoneInfoConverter.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MicrophoneInfoConverter.java
similarity index 98%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/MicrophoneInfoConverter.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MicrophoneInfoConverter.java
index 3494c0b..8dbe502 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/MicrophoneInfoConverter.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MicrophoneInfoConverter.java
@@ -1,4 +1,4 @@
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.media.MicrophoneInfo;
 import android.util.Pair;
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MidiTapTester.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MidiTapTester.java
new file mode 100644
index 0000000..33e2266
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MidiTapTester.java
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+package com.mobileer.oboetester;
+
+
+import android.media.midi.MidiDeviceService;
+import android.media.midi.MidiReceiver;
+import android.util.Log;
+
+import com.mobileer.miditools.MidiConstants;
+import com.mobileer.miditools.MidiFramer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * Measure the latency of various output paths by playing a blip.
+ * Report the results back to the TestListeners.
+ */
+public class MidiTapTester extends MidiDeviceService {
+    // These must match the values in service_device_info.xml
+    public static final String PRODUCT_NAME = "MidiTapLatencyTester";
+    public static final String MANUFACTURER_NAME = "Mobileer";
+
+    // Sometimes the service can be run without the MainActivity being run!
+    static {
+        // Must match name in CMakeLists.txt
+        System.loadLibrary("oboetester");
+    }
+
+    private ArrayList<NoteListener> mListeners = new ArrayList<NoteListener>();
+    private MyMidiReceiver mReceiver = new MyMidiReceiver();
+    private MidiFramer mMidiFramer = new MidiFramer(mReceiver);
+
+    private static MidiTapTester mInstance;
+
+    public static interface NoteListener {
+        public void onNoteOn(int pitch);
+    }
+
+    /**
+     * This is a Service so it is only created when a client requests the service.
+     */
+    public MidiTapTester() {
+        mInstance = this;
+    }
+
+    public void addTestListener(NoteListener listener) {
+        mListeners.add(listener);
+    }
+
+    public void removeTestListener(NoteListener listener) {
+        mListeners.remove(listener);
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+    }
+
+    @Override
+    public void onDestroy() {
+        // do stuff here
+        super.onDestroy();
+    }
+
+    public static MidiTapTester getInstanceOrNull() {
+        return mInstance;
+    }
+
+    class MyMidiReceiver extends MidiReceiver {
+        public void onSend(byte[] data, int offset,
+                           int count, long timestamp) throws IOException {
+            // parse MIDI
+            byte command = (byte) (data[0] & 0x0F0);
+            if (command == MidiConstants.STATUS_NOTE_ON) {
+                if (data[2] == 0) {
+                    noteOff(data[1]);
+                } else {
+                    noteOn(data[1]);
+                }
+            } else if (command == MidiConstants.STATUS_NOTE_OFF) {
+                noteOff(data[1]);
+            }
+            Log.i(TapToToneActivity.TAG, "MIDI command = " + command);
+        }
+    }
+
+    private void noteOn(byte b) {
+        fireNoteOn(b);
+    }
+
+    private void fireNoteOn(byte pitch) {
+        for (NoteListener listener : mListeners) {
+            listener.onNoteOn(pitch);
+        }
+    }
+
+    private void noteOff(byte b) {}
+
+    @Override
+    public MidiReceiver[] onGetInputPortReceivers() {
+        return new MidiReceiver[]{mMidiFramer};
+    }
+
+}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/NativeEngine.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeEngine.java
similarity index 85%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/NativeEngine.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeEngine.java
index ea71ec5..6978bdc 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/NativeEngine.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeEngine.java
@@ -1,4 +1,4 @@
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 public class NativeEngine {
 
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/NativeSniffer.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeSniffer.java
similarity index 97%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/NativeSniffer.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeSniffer.java
index e2c95c1..1bc1232 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/NativeSniffer.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeSniffer.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.app.Activity;
 import android.os.Handler;
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/OboeAudioInputStream.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioInputStream.java
similarity index 94%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/OboeAudioInputStream.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioInputStream.java
index f89cfea..0983121 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/OboeAudioInputStream.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioInputStream.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 class OboeAudioInputStream extends OboeAudioStream {
 
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/OboeAudioOutputStream.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioOutputStream.java
similarity index 95%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/OboeAudioOutputStream.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioOutputStream.java
index 790fc4c..92cde48 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/OboeAudioOutputStream.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioOutputStream.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 /**
  * Native synthesizer and audio output.
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/OboeAudioStream.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java
similarity index 77%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/OboeAudioStream.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java
index 9576800..5ff2dd1 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/OboeAudioStream.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import java.io.IOException;
 
@@ -59,13 +59,15 @@
         int result = openNative(requestedConfiguration.getNativeApi(),
                 requestedConfiguration.getSampleRate(),
                 requestedConfiguration.getChannelCount(),
+                requestedConfiguration.getChannelMask(),
                 requestedConfiguration.getFormat(),
                 requestedConfiguration.getSharingMode(),
                 requestedConfiguration.getPerformanceMode(),
                 requestedConfiguration.getInputPreset(),
+                requestedConfiguration.getUsage(),
+                requestedConfiguration.getContentType(),
                 requestedConfiguration.getDeviceId(),
                 requestedConfiguration.getSessionId(),
-                requestedConfiguration.getFramesPerBurst(),
                 requestedConfiguration.getChannelConversionAllowed(),
                 requestedConfiguration.getFormatConversionAllowed(),
                 requestedConfiguration.getRateConversionQuality(),
@@ -83,9 +85,12 @@
         actualConfiguration.setSharingMode(getSharingMode());
         actualConfiguration.setPerformanceMode(getPerformanceMode());
         actualConfiguration.setInputPreset(getInputPreset());
+        actualConfiguration.setUsage(getUsage());
+        actualConfiguration.setContentType(getContentType());
         actualConfiguration.setFramesPerBurst(getFramesPerBurst());
         actualConfiguration.setBufferCapacityInFrames(getBufferCapacityInFrames());
         actualConfiguration.setChannelCount(getChannelCount());
+        actualConfiguration.setChannelMask(getChannelMask());
         actualConfiguration.setDeviceId(getDeviceId());
         actualConfiguration.setSessionId(getSessionId());
         actualConfiguration.setFormat(getFormat());
@@ -99,13 +104,15 @@
             int nativeApi,
             int sampleRate,
             int channelCount,
+            int channelMask,
             int format,
             int sharingMode,
             int performanceMode,
             int inputPreset,
+            int usage,
+            int contentType,
             int deviceId,
             int sessionId,
-            int framesPerRead,
             boolean channelConversionAllowed,
             boolean formatConversionAllowed,
             int rateConversionQuality,
@@ -147,58 +154,73 @@
     public int getNativeApi() {
         return getNativeApi(streamIndex);
     }
-    public native int getNativeApi(int streamIndex);
+    private native int getNativeApi(int streamIndex);
 
     @Override
     public int getFramesPerBurst() {
         return getFramesPerBurst(streamIndex);
     }
-    public native int getFramesPerBurst(int streamIndex);
+    private native int getFramesPerBurst(int streamIndex);
 
     public int getSharingMode() {
         return getSharingMode(streamIndex);
     }
-    public native int getSharingMode(int streamIndex);
+    private native int getSharingMode(int streamIndex);
 
     public int getPerformanceMode() {
         return getPerformanceMode(streamIndex);
     }
-    public native int getPerformanceMode(int streamIndex);
+    private native int getPerformanceMode(int streamIndex);
 
     public int getInputPreset() {
         return getInputPreset(streamIndex);
     }
-    public native int getInputPreset(int streamIndex);
+    private native int getInputPreset(int streamIndex);
 
     public int getSampleRate() {
         return getSampleRate(streamIndex);
     }
-    public native int getSampleRate(int streamIndex);
+    private native int getSampleRate(int streamIndex);
 
     public int getFormat() {
         return getFormat(streamIndex);
     }
-    public native int getFormat(int streamIndex);
+    private native int getFormat(int streamIndex);
+
+    public int getUsage() {
+        return getUsage(streamIndex);
+    }
+    private native int getUsage(int streamIndex);
+
+    public int getContentType() {
+        return getContentType(streamIndex);
+    }
+    private native int getContentType(int streamIndex);
 
     public int getChannelCount() {
         return getChannelCount(streamIndex);
     }
-    public native int getChannelCount(int streamIndex);
+    private native int getChannelCount(int streamIndex);
+
+    public int getChannelMask() {
+        return getChannelMask(streamIndex);
+    }
+    private native int getChannelMask(int streamIndex);
 
     public int getDeviceId() {
         return getDeviceId(streamIndex);
     }
-    public native int getDeviceId(int streamIndex);
+    private native int getDeviceId(int streamIndex);
 
     public int getSessionId() {
         return getSessionId(streamIndex);
     }
-    public native int getSessionId(int streamIndex);
+    private native int getSessionId(int streamIndex);
 
     public boolean isMMap() {
         return isMMap(streamIndex);
     }
-    public native boolean isMMap(int streamIndex);
+    private native boolean isMMap(int streamIndex);
 
     @Override
     public native long getCallbackCount(); // TODO Move to another class?
@@ -207,37 +229,43 @@
     public int getLastErrorCallbackResult() {
         return getLastErrorCallbackResult(streamIndex);
     }
-    public native int getLastErrorCallbackResult(int streamIndex);
+    private native int getLastErrorCallbackResult(int streamIndex);
 
     @Override
     public long getFramesWritten() {
         return getFramesWritten(streamIndex);
     }
-    public native long getFramesWritten(int streamIndex);
+    private native long getFramesWritten(int streamIndex);
 
     @Override
     public long getFramesRead() {
         return getFramesRead(streamIndex);
     }
-    public native long getFramesRead(int streamIndex);
+    private native long getFramesRead(int streamIndex);
 
     @Override
     public int getXRunCount() {
         return getXRunCount(streamIndex);
     }
-    public native int getXRunCount(int streamIndex);
+    private native int getXRunCount(int streamIndex);
 
     @Override
     public double getLatency() {
         return getTimestampLatency(streamIndex);
     }
-    public native double getTimestampLatency(int streamIndex);
+    private native double getTimestampLatency(int streamIndex);
 
     @Override
     public double getCpuLoad() {
         return getCpuLoad(streamIndex);
     }
-    public native double getCpuLoad(int streamIndex);
+    private native double getCpuLoad(int streamIndex);
+
+    @Override
+    public String getCallbackTimeStr() {
+        return getCallbackTimeString();
+    }
+    public native String getCallbackTimeString();
 
     @Override
     public native void setWorkload(double workload);
@@ -246,7 +274,7 @@
     public int getState() {
         return getState(streamIndex);
     }
-    public native int getState(int streamIndex);
+    private native int getState(int streamIndex);
 
     public static native void setCallbackReturnStop(boolean b);
 
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/RecorderActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RecorderActivity.java
similarity index 98%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/RecorderActivity.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RecorderActivity.java
index 1ceb06a..48df218 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/RecorderActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RecorderActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.os.Bundle;
 import android.view.View;
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/RoundTripLatencyActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RoundTripLatencyActivity.java
similarity index 67%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/RoundTripLatencyActivity.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RoundTripLatencyActivity.java
index 5c93929..6920768 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/RoundTripLatencyActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RoundTripLatencyActivity.java
@@ -14,20 +14,19 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
-import android.content.Intent;
+import static com.mobileer.oboetester.IntentBasedTestSupport.configureStreamsFromBundle;
+
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.support.annotation.NonNull;
-import android.text.method.ScrollingMovementMethod;
 import android.view.View;
 import android.widget.Button;
 import android.widget.TextView;
 
 import java.io.IOException;
-import java.util.ArrayList;
 
 /**
  * Activity to measure latency on a full duplex stream.
@@ -49,27 +48,28 @@
     private Button   mShareButton;
     private boolean  mHasRecording = false;
 
-    private boolean mTestRunningByIntent;
-    private Bundle  mBundleFromIntent;
     private int     mBufferBursts = -1;
     private Handler mHandler = new Handler(Looper.getMainLooper()); // UI thread
 
-    // Run the test several times and report the acverage latency.
-    protected class LatencyAverager {
+    DoubleStatistics mTimestampLatencyStats = new DoubleStatistics(); // for single measurement
+
+    // Run the test several times and report the average latency.
+    protected class AverageLatencyTestRunner {
         private final static int AVERAGE_TEST_DELAY_MSEC = 1000; // arbitrary
         private static final int GOOD_RUNS_REQUIRED = 5; // arbitrary
         private static final int MAX_BAD_RUNS_ALLOWED = 5; // arbitrary
         private int mBadCount = 0; // number of bad measurements
-        private int mGoodCount = 0; // number of good measurements
 
-        ArrayList<Double> mLatencies = new ArrayList<Double>(GOOD_RUNS_REQUIRED);
-        ArrayList<Double> mConfidences = new ArrayList<Double>(GOOD_RUNS_REQUIRED);
-        private double  mLatencyMin;
-        private double  mLatencyMax;
-        private double  mConfidenceSum;
+        DoubleStatistics mLatencies = new DoubleStatistics();
+        DoubleStatistics mConfidences = new DoubleStatistics();
+        DoubleStatistics mTimestampLatencies = new DoubleStatistics(); // for multiple measurements
         private boolean mActive;
         private String  mLastReport = "";
 
+        private int getGoodCount() {
+            return mLatencies.count();
+        }
+
         // Called on UI thread.
         String onAnalyserDone() {
             String message;
@@ -88,15 +88,16 @@
                     reschedule = true;
                 }
             } else {
-                mGoodCount++;
                 double latency = getMeasuredLatencyMillis();
-                double confidence = getMeasuredConfidence();
                 mLatencies.add(latency);
+                double confidence = getMeasuredConfidence();
                 mConfidences.add(confidence);
-                mConfidenceSum += confidence;
-                mLatencyMin = Math.min(mLatencyMin, latency);
-                mLatencyMax = Math.max(mLatencyMax, latency);
-                if (mGoodCount < GOOD_RUNS_REQUIRED) {
+
+                double timestampLatency = getTimestampLatencyMillis();
+                if (timestampLatency > 0.0) {
+                    mTimestampLatencies.add(timestampLatency);
+                }
+                if (getGoodCount() < GOOD_RUNS_REQUIRED) {
                     reschedule = true;
                 } else {
                     mActive = false;
@@ -117,49 +118,45 @@
 
         private String reportAverage() {
             String message;
-            if (mGoodCount == 0 || mConfidenceSum == 0.0) {
-                message = "num.iterations = " + mGoodCount + "\n";
+            if (getGoodCount() == 0 || mConfidences.getSum() == 0.0) {
+                message = "num.iterations = " + getGoodCount() + "\n";
             } else {
-                final double mAverageConfidence = mConfidenceSum / mGoodCount;
-                double meanLatency = calculateMeanLatency();
-                double meanAbsoluteDeviation = calculateMeanAbsoluteDeviation(meanLatency);
-                message = "average.latency.msec = " + String.format(LATENCY_FORMAT, meanLatency) + "\n"
-                        + "mean.absolute.deviation = " + String.format(LATENCY_FORMAT, meanAbsoluteDeviation) + "\n"
-                        + "average.confidence = " + String.format(CONFIDENCE_FORMAT, mAverageConfidence) + "\n"
-                        + "min.latency.msec = " + String.format(LATENCY_FORMAT, mLatencyMin) + "\n"
-                        + "max.latency.msec = " + String.format(LATENCY_FORMAT, mLatencyMax) + "\n"
-                        + "num.iterations = " + mGoodCount + "\n";
+                final double mAverageConfidence = mConfidences.calculateMean();
+                double meanLatency = mLatencies.calculateMean();
+                double meanAbsoluteDeviation = mLatencies.calculateMeanAbsoluteDeviation(meanLatency);
+                double timestampLatencyMean = -1;
+                double timestampLatencyMAD = 0.0;
+                if (mTimestampLatencies.count() > 0) {
+                    timestampLatencyMean = mTimestampLatencies.calculateMean();
+                    timestampLatencyMAD =
+                            mTimestampLatencies.calculateMeanAbsoluteDeviation(timestampLatencyMean);
+                }
+                message = "average.latency.msec = "
+                        + String.format(LATENCY_FORMAT, meanLatency) + "\n"
+                        + "mean.absolute.deviation = "
+                        + String.format(LATENCY_FORMAT, meanAbsoluteDeviation) + "\n"
+                        + "average.confidence = "
+                        + String.format(CONFIDENCE_FORMAT, mAverageConfidence) + "\n"
+                        + "min.latency.msec = " + String.format(LATENCY_FORMAT, mLatencies.getMin()) + "\n"
+                        + "max.latency.msec = " + String.format(LATENCY_FORMAT, mLatencies.getMax()) + "\n"
+                        + "num.iterations = " + mLatencies.count() + "\n"
+                        + "timestamp.latency.msec = "
+                        + String.format(LATENCY_FORMAT, timestampLatencyMean) + "\n"
+                        + "timestamp.latency.mad = "
+                        + String.format(LATENCY_FORMAT, timestampLatencyMAD) + "\n";
             }
             message += "num.failed = " + mBadCount + "\n";
+            message += "\n"; // mark end of average report
             mLastReport = message;
             return message;
         }
 
-        private double calculateMeanAbsoluteDeviation(double meanLatency) {
-            double deviationSum = 0.0;
-            for (double latency : mLatencies) {
-                deviationSum += Math.abs(latency - meanLatency);
-            }
-            return deviationSum / mLatencies.size();
-        }
-
-        private double calculateMeanLatency() {
-            double latencySum = 0.0;
-            for (double latency : mLatencies) {
-                latencySum += latency;
-            }
-            return latencySum / mLatencies.size();
-        }
-
         // Called on UI thread.
         public void start() {
-            mLatencies.clear();
-            mConfidences.clear();
-            mConfidenceSum = 0.0;
-            mLatencyMax = Double.MIN_VALUE;
-            mLatencyMin = Double.MAX_VALUE;
+            mLatencies = new DoubleStatistics();
+            mConfidences = new DoubleStatistics();
+            mTimestampLatencies = new DoubleStatistics();
             mBadCount = 0;
-            mGoodCount = 0;
             mActive = true;
             mLastReport = "";
             measureSingleLatency();
@@ -182,7 +179,7 @@
             return mLastReport;
         }
     }
-    LatencyAverager mLatencyAverager = new LatencyAverager();
+    AverageLatencyTestRunner mAverageLatencyTestRunner = new AverageLatencyTestRunner();
 
     // Periodically query the status of the stream.
     protected class LatencySniffer {
@@ -194,15 +191,28 @@
         private Runnable runnableCode = new Runnable() {
             @Override
             public void run() {
-                String message;
+                double timestampLatency = -1.0;
+                int state = getAnalyzerState();
+                if (state == STATE_MEASURE_BACKGROUND || state == STATE_IN_PULSE) {
+                    timestampLatency = measureTimestampLatency();
+                    // Some configurations do not support input timestamps.
+                    if (timestampLatency > 0) {
+                        mTimestampLatencyStats.add(timestampLatency);
+                    }
+                }
 
+                String message;
                 if (isAnalyzerDone()) {
-                    message = mLatencyAverager.onAnalyserDone();
-                    message += onAnalyzerDone();
+                    if (mAverageLatencyTestRunner.isActive()) {
+                        message = mAverageLatencyTestRunner.onAnalyserDone();
+                    } else {
+                        message = getResultString();
+                    }
+                    onAnalyzerDone();
                 } else {
                     message = getProgressText();
                     message += "please wait... " + counter + "\n";
-                    message += convertStateToString(getAnalyzerState());
+                    message += convertStateToString(getAnalyzerState()) + "\n";
 
                     // Repeat this runnable code block again.
                     mHandler.postDelayed(runnableCode, SNIFFER_UPDATE_PERIOD_MSEC);
@@ -240,21 +250,19 @@
         int resetCount = getResetCount();
         String message = String.format("progress = %d\nstate = %d\n#resets = %d\n",
                 progress, state, resetCount);
-        message += mLatencyAverager.getLastReport();
+        message += mAverageLatencyTestRunner.getLastReport();
         return message;
     }
 
-    private String onAnalyzerDone() {
-        String message = getResultString();
+    private void onAnalyzerDone() {
         if (mTestRunningByIntent) {
             String report = getCommonTestReport();
-            report += message;
+            report += getResultString();
             maybeWriteTestResult(report);
         }
         mTestRunningByIntent = false;
         mHasRecording = true;
         stopAudioTest();
-        return message;
     }
 
     @NonNull
@@ -282,6 +290,16 @@
 
         message += String.format("rms.signal = %7.5f\n", getSignalRMS());
         message += String.format("rms.noise = %7.5f\n", getBackgroundRMS());
+        message += String.format("correlation = " + CONFIDENCE_FORMAT + "\n",
+                getMeasuredCorrelation());
+        double timestampLatency = getTimestampLatencyMillis();
+        message += String.format("timestamp.latency.msec = " + LATENCY_FORMAT + "\n",
+                timestampLatency);
+        if (mTimestampLatencyStats.count() > 0) {
+            message += String.format("timestamp.latency.mad = " + LATENCY_FORMAT + "\n",
+                    mTimestampLatencyStats.calculateMeanAbsoluteDeviation(timestampLatency));
+        }
+        message +=  "timestamp.latency.count = " + mTimestampLatencyStats.count() + "\n";
         message += String.format("reset.count = %d\n", resetCount);
         message += String.format("result = %d\n", result);
 
@@ -290,12 +308,20 @@
 
     private LatencySniffer mLatencySniffer = new LatencySniffer();
 
-    native int getAnalyzerProgress();
-    native int getMeasuredLatency();
     double getMeasuredLatencyMillis() {
         return getMeasuredLatency() * 1000.0 / getSampleRate();
     }
+
+    double getTimestampLatencyMillis() {
+        if (mTimestampLatencyStats.count() == 0) return -1.0;
+        else return mTimestampLatencyStats.calculateMean();
+    }
+
+    native int getAnalyzerProgress();
+    native int getMeasuredLatency();
+    native double measureTimestampLatency();
     native double getMeasuredConfidence();
+    native double getMeasuredCorrelation();
     native double getBackgroundRMS();
     native double getSignalRMS();
 
@@ -317,19 +343,11 @@
         mShareButton = (Button) findViewById(R.id.button_share);
         mShareButton.setEnabled(false);
         mAnalyzerView = (TextView) findViewById(R.id.text_status);
-        mAnalyzerView.setMovementMethod(new ScrollingMovementMethod());
         updateEnabledWidgets();
 
         hideSettingsViews();
 
         mBufferSizeView.setFaderNormalizedProgress(0.0); // for lowest latency
-
-        mBundleFromIntent = getIntent().getExtras();
-    }
-
-    @Override
-    public void onNewIntent(Intent intent) {
-        mBundleFromIntent = intent.getExtras();
     }
 
     @Override
@@ -344,43 +362,19 @@
         updateButtons(false);
     }
 
-    private void processBundleFromIntent() {
-        if (mBundleFromIntent == null) {
-            return;
-        }
-        if (mTestRunningByIntent) {
-            return;
-        }
-
-        mResultFileName = null;
-        if (mBundleFromIntent.containsKey(KEY_FILE_NAME)) {
-            mTestRunningByIntent = true;
-            mResultFileName = mBundleFromIntent.getString(KEY_FILE_NAME);
-            getFirstInputStreamContext().configurationView.setExclusiveMode(true);
-            getFirstOutputStreamContext().configurationView.setExclusiveMode(true);
-            mBufferBursts = mBundleFromIntent.getInt(KEY_BUFFER_BURSTS, mBufferBursts);
-
-            // Delay the test start to avoid race conditions.
-            Handler handler = new Handler(Looper.getMainLooper()); // UI thread
-            handler.postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    startAutomaticTest();
-                }
-            }, 500); // TODO where is the race, close->open?
-        }
-    }
-
-    void startAutomaticTest() {
-        configureStreamsFromBundle(mBundleFromIntent);
-        onMeasure(null);
-        mBundleFromIntent = null;
-    }
-
     @Override
-    public void onResume(){
-        super.onResume();
-        processBundleFromIntent();
+    public void startTestUsingBundle() {
+        try {
+            StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration;
+            StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
+            configureStreamsFromBundle(mBundleFromIntent, requestedInConfig, requestedOutConfig);
+
+            mBufferBursts = mBundleFromIntent.getInt(IntentBasedTestSupport.KEY_BUFFER_BURSTS, mBufferBursts);
+
+            onMeasure(null);
+        } finally {
+            mBundleFromIntent = null;
+        }
     }
 
     @Override
@@ -390,12 +384,12 @@
     }
 
     public void onMeasure(View view) {
-        mLatencyAverager.clear();
+        mAverageLatencyTestRunner.clear();
         measureSingleLatency();
     }
 
     void updateButtons(boolean running) {
-        boolean busy = running || mLatencyAverager.isActive();
+        boolean busy = running || mAverageLatencyTestRunner.isActive();
         mMeasureButton.setEnabled(!busy);
         mAverageButton.setEnabled(!busy);
         mCancelButton.setEnabled(running);
@@ -414,6 +408,7 @@
                 mBufferBursts = -1;
             }
             startAudio();
+            mTimestampLatencyStats  = new DoubleStatistics();
             mLatencySniffer.startSniffer();
             updateButtons(true);
         } catch (IOException e) {
@@ -422,11 +417,11 @@
     }
 
     public void onAverage(View view) {
-        mLatencyAverager.start();
+        mAverageLatencyTestRunner.start();
     }
 
     public void onCancel(View view) {
-        mLatencyAverager.cancel();
+        mAverageLatencyTestRunner.cancel();
         stopAudioTest();
     }
 
@@ -447,8 +442,4 @@
     boolean isOutput() {
         return false;
     }
-
-    @Override
-    public void setupEffects(int sessionId) {
-    }
 }
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfiguration.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfiguration.java
new file mode 100644
index 0000000..ea9a9e8
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfiguration.java
@@ -0,0 +1,729 @@
+/*
+ * Copyright 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.
+ */
+
+package com.mobileer.oboetester;
+
+import android.content.res.Resources;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Container for the properties of a Stream.
+ *
+ * This can be used to build a stream, or as a base class for a Stream,
+ * or as a way to report the properties of a Stream.
+ */
+
+public class StreamConfiguration {
+    public static final int UNSPECIFIED = 0;
+
+    // These must match order in Spinner and in native code and in AAudio.h
+    public static final int NATIVE_API_UNSPECIFIED = 0;
+    public static final int NATIVE_API_OPENSLES = 1;
+    public static final int NATIVE_API_AAUDIO = 2;
+
+    public static final int SHARING_MODE_EXCLUSIVE = 0; // must match AAUDIO
+    public static final int SHARING_MODE_SHARED = 1; // must match AAUDIO
+
+    public static final int AUDIO_FORMAT_PCM_16 = 1; // must match AAUDIO
+    public static final int AUDIO_FORMAT_PCM_FLOAT = 2; // must match AAUDIO
+    public static final int AUDIO_FORMAT_PCM_24 = 3; // must match AAUDIO
+    public static final int AUDIO_FORMAT_PCM_32 = 4; // must match AAUDIO
+
+    public static final int DIRECTION_OUTPUT = 0; // must match AAUDIO
+    public static final int DIRECTION_INPUT = 1; // must match AAUDIO
+
+    public static final int SESSION_ID_NONE = -1; // must match AAUDIO
+    public static final int SESSION_ID_ALLOCATE = 0; // must match AAUDIO
+
+    public static final int PERFORMANCE_MODE_NONE = 10; // must match AAUDIO
+    public static final int PERFORMANCE_MODE_POWER_SAVING = 11; // must match AAUDIO
+    public static final int PERFORMANCE_MODE_LOW_LATENCY = 12; // must match AAUDIO
+
+    public static final int RATE_CONVERSION_QUALITY_NONE = 0; // must match Oboe
+    public static final int RATE_CONVERSION_QUALITY_FASTEST = 1; // must match Oboe
+    public static final int RATE_CONVERSION_QUALITY_LOW = 2; // must match Oboe
+    public static final int RATE_CONVERSION_QUALITY_MEDIUM = 3; // must match Oboe
+    public static final int RATE_CONVERSION_QUALITY_HIGH = 4; // must match Oboe
+    public static final int RATE_CONVERSION_QUALITY_BEST = 5; // must match Oboe
+
+    public static final int STREAM_STATE_STARTING = 3; // must match Oboe
+    public static final int STREAM_STATE_STARTED = 4; // must match Oboe
+
+    public static final int INPUT_PRESET_GENERIC = 1; // must match Oboe
+    public static final int INPUT_PRESET_CAMCORDER = 5; // must match Oboe
+    public static final int INPUT_PRESET_VOICE_RECOGNITION = 6; // must match Oboe
+    public static final int INPUT_PRESET_VOICE_COMMUNICATION = 7; // must match Oboe
+    public static final int INPUT_PRESET_UNPROCESSED = 9; // must match Oboe
+    public static final int INPUT_PRESET_VOICE_PERFORMANCE = 10; // must match Oboe
+
+    public static final int ERROR_DISCONNECTED = -899; // must match Oboe
+
+    public static final int USAGE_MEDIA = 1;
+    public static final int USAGE_VOICE_COMMUNICATION = 2;
+    public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3;
+    public static final int USAGE_ALARM = 4;
+    public static final int USAGE_NOTIFICATION = 5;
+    public static final int USAGE_NOTIFICATION_RINGTONE = 6;
+    public static final int USAGE_NOTIFICATION_EVENT = 10;
+    public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11;
+    public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12;
+    public static final int USAGE_ASSISTANCE_SONIFICATION = 13;
+    public static final int USAGE_GAME = 14;
+    public static final int USAGE_ASSISTANT = 16;
+
+    public static final int CONTENT_TYPE_SPEECH = 1;
+    public static final int CONTENT_TYPE_MUSIC = 2;
+    public static final int CONTENT_TYPE_MOVIE = 3;
+    public static final int CONTENT_TYPE_SONIFICATION = 4;
+
+    public static final int CHANNEL_FRONT_LEFT = 1 << 0;
+    public static final int CHANNEL_FRONT_RIGHT = 1 << 1;
+    public static final int CHANNEL_FRONT_CENTER = 1 << 2;
+    public static final int CHANNEL_LOW_FREQUENCY = 1 << 3;
+    public static final int CHANNEL_BACK_LEFT = 1 << 4;
+    public static final int CHANNEL_BACK_RIGHT = 1 << 5;
+    public static final int CHANNEL_FRONT_LEFT_OF_CENTER = 1 << 6;
+    public static final int CHANNEL_FRONT_RIGHT_OF_CENTER = 1 << 7;
+    public static final int CHANNEL_BACK_CENTER = 1 << 8;
+    public static final int CHANNEL_SIDE_LEFT = 1 << 9;
+    public static final int CHANNEL_SIDE_RIGHT = 1 << 10;
+    public static final int CHANNEL_TOP_CENTER = 1 << 11;
+    public static final int CHANNEL_TOP_FRONT_LEFT = 1 << 12;
+    public static final int CHANNEL_TOP_FRONT_CENTER = 1 << 13;
+    public static final int CHANNEL_TOP_FRONT_RIGHT = 1 << 14;
+    public static final int CHANNEL_TOP_BACK_LEFT = 1 << 15;
+    public static final int CHANNEL_TOP_BACK_CENTER = 1 << 16;
+    public static final int CHANNEL_TOP_BACK_RIGHT = 1 << 17;
+    public static final int CHANNEL_TOP_SIDE_LEFT = 1 << 18;
+    public static final int CHANNEL_TOP_SIDE_RIGHT = 1 << 19;
+    public static final int CHANNEL_BOTTOM_FRONT_LEFT = 1 << 20;
+    public static final int CHANNEL_BOTTOM_FRONT_CENTER = 1 << 21;
+    public static final int CHANNEL_BOTTOM_FRONT_RIGHT = 1 << 22;
+    public static final int CHANNEL_LOW_FREQUENCY_2 = 1 << 23;
+    public static final int CHANNEL_FRONT_WIDE_LEFT = 1 << 24;
+    public static final int CHANNEL_FRONT_WIDE_RIGHT = 1 << 25;
+
+    public static final int CHANNEL_MONO = CHANNEL_FRONT_LEFT;
+    public static final int CHANNEL_STEREO = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT;
+    public static final int CHANNEL_2POINT1 = CHANNEL_FRONT_LEFT |
+                                              CHANNEL_FRONT_RIGHT |
+                                              CHANNEL_LOW_FREQUENCY;
+    public static final int CHANNEL_TRI = CHANNEL_FRONT_LEFT |
+                                          CHANNEL_FRONT_RIGHT |
+                                          CHANNEL_FRONT_CENTER;
+    public static final int CHANNEL_TRI_BACK = CHANNEL_FRONT_LEFT |
+                                               CHANNEL_FRONT_RIGHT |
+                                               CHANNEL_BACK_CENTER;
+    public static final int CHANNEL_3POINT1 = CHANNEL_FRONT_LEFT |
+                                              CHANNEL_FRONT_RIGHT |
+                                              CHANNEL_FRONT_CENTER |
+                                              CHANNEL_LOW_FREQUENCY;
+    public static final int CHANNEL_2POINT0POINT2 = CHANNEL_FRONT_LEFT |
+                                                    CHANNEL_FRONT_RIGHT |
+                                                    CHANNEL_TOP_SIDE_LEFT |
+                                                    CHANNEL_TOP_SIDE_RIGHT;
+    public static final int CHANNEL_2POINT1POINT2 = CHANNEL_2POINT0POINT2 | CHANNEL_LOW_FREQUENCY;
+    public static final int CHANNEL_3POINT0POINT2 = CHANNEL_FRONT_LEFT |
+                                                    CHANNEL_FRONT_RIGHT |
+                                                    CHANNEL_FRONT_CENTER |
+                                                    CHANNEL_TOP_SIDE_LEFT |
+                                                    CHANNEL_TOP_SIDE_RIGHT;
+    public static final int CHANNEL_3POINT1POINT2 = CHANNEL_3POINT0POINT2 | CHANNEL_LOW_FREQUENCY;
+    public static final int CHANNEL_QUAD = CHANNEL_FRONT_LEFT |
+                                           CHANNEL_FRONT_RIGHT |
+                                           CHANNEL_BACK_LEFT |
+                                           CHANNEL_BACK_RIGHT;
+    public static final int CHANNEL_QUAD_SIDE = CHANNEL_FRONT_LEFT |
+                                                CHANNEL_FRONT_RIGHT |
+                                                CHANNEL_SIDE_LEFT |
+                                                CHANNEL_SIDE_RIGHT;
+    public static final int CHANNEL_SURROUND = CHANNEL_FRONT_LEFT |
+                                               CHANNEL_FRONT_RIGHT |
+                                               CHANNEL_FRONT_CENTER |
+                                               CHANNEL_BACK_CENTER;
+    public static final int CHANNEL_PENTA = CHANNEL_QUAD | CHANNEL_FRONT_CENTER;
+    // aka 5POINT1_BACK
+    public static final int CHANNEL_5POINT1 = CHANNEL_FRONT_LEFT |
+                                              CHANNEL_FRONT_RIGHT |
+                                              CHANNEL_FRONT_CENTER |
+                                              CHANNEL_LOW_FREQUENCY |
+                                              CHANNEL_BACK_LEFT |
+                                              CHANNEL_BACK_RIGHT;
+    public static final int CHANNEL_5POINT1_SIDE = CHANNEL_FRONT_LEFT |
+                                                   CHANNEL_FRONT_RIGHT |
+                                                   CHANNEL_FRONT_CENTER |
+                                                   CHANNEL_LOW_FREQUENCY |
+                                                   CHANNEL_SIDE_LEFT |
+                                                   CHANNEL_SIDE_RIGHT;
+    public static final int CHANNEL_6POINT1 = CHANNEL_FRONT_LEFT |
+                                              CHANNEL_FRONT_RIGHT |
+                                              CHANNEL_FRONT_CENTER |
+                                              CHANNEL_LOW_FREQUENCY |
+                                              CHANNEL_BACK_LEFT |
+                                              CHANNEL_BACK_RIGHT |
+                                              CHANNEL_BACK_CENTER;
+    public static final int CHANNEL_7POINT1 = CHANNEL_5POINT1 |
+                                              CHANNEL_SIDE_LEFT |
+                                              CHANNEL_SIDE_RIGHT;
+    public static final int CHANNEL_5POINT1POINT2 = CHANNEL_5POINT1 |
+                                                    CHANNEL_TOP_SIDE_LEFT |
+                                                    CHANNEL_TOP_SIDE_RIGHT;
+    public static final int CHANNEL_5POINT1POINT4 = CHANNEL_5POINT1 |
+                                                    CHANNEL_TOP_FRONT_LEFT |
+                                                    CHANNEL_TOP_FRONT_RIGHT |
+                                                    CHANNEL_TOP_BACK_LEFT |
+                                                    CHANNEL_TOP_BACK_RIGHT;
+    public static final int CHANNEL_7POINT1POINT2 = CHANNEL_7POINT1 |
+                                                    CHANNEL_TOP_SIDE_LEFT |
+                                                    CHANNEL_TOP_SIDE_RIGHT;
+    public static final int CHANNEL_7POINT1POINT4 = CHANNEL_7POINT1 |
+                                                    CHANNEL_TOP_FRONT_LEFT |
+                                                    CHANNEL_TOP_FRONT_RIGHT |
+                                                    CHANNEL_TOP_BACK_LEFT |
+                                                    CHANNEL_TOP_BACK_RIGHT;
+    public static final int CHANNEL_9POINT1POINT4 = CHANNEL_7POINT1POINT4 |
+                                                    CHANNEL_FRONT_WIDE_LEFT |
+                                                    CHANNEL_FRONT_WIDE_RIGHT;
+    public static final int CHANNEL_9POINT1POINT6 = CHANNEL_9POINT1POINT4 |
+                                                    CHANNEL_TOP_SIDE_LEFT |
+                                                    CHANNEL_TOP_SIDE_RIGHT;
+    public static final int CHANNEL_FRONT_BACK = CHANNEL_FRONT_CENTER | CHANNEL_BACK_CENTER;
+
+    public static final int[] usages = {
+            USAGE_MEDIA,
+            USAGE_VOICE_COMMUNICATION,
+            USAGE_VOICE_COMMUNICATION_SIGNALLING,
+            USAGE_ALARM,
+            USAGE_NOTIFICATION,
+            USAGE_NOTIFICATION_RINGTONE,
+            USAGE_NOTIFICATION_EVENT,
+            USAGE_ASSISTANCE_ACCESSIBILITY,
+            USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+            USAGE_ASSISTANCE_SONIFICATION,
+            USAGE_GAME,
+            USAGE_ASSISTANT};
+
+    public static final int[] contentTypes = {
+            CONTENT_TYPE_SPEECH,
+            CONTENT_TYPE_MUSIC,
+            CONTENT_TYPE_MOVIE,
+            CONTENT_TYPE_SONIFICATION};
+
+    public static final int[] channelMasks = {
+            CHANNEL_MONO,
+            CHANNEL_STEREO,
+            CHANNEL_2POINT1,
+            CHANNEL_TRI,
+            CHANNEL_TRI_BACK,
+            CHANNEL_3POINT1,
+            CHANNEL_2POINT0POINT2,
+            CHANNEL_2POINT1POINT2,
+            CHANNEL_3POINT0POINT2,
+            CHANNEL_3POINT1POINT2,
+            CHANNEL_QUAD,
+            CHANNEL_QUAD_SIDE,
+            CHANNEL_SURROUND,
+            CHANNEL_PENTA,
+            CHANNEL_5POINT1,
+            CHANNEL_5POINT1_SIDE,
+            CHANNEL_6POINT1,
+            CHANNEL_7POINT1,
+            CHANNEL_5POINT1POINT2,
+            CHANNEL_5POINT1POINT4,
+            CHANNEL_7POINT1POINT2,
+            CHANNEL_7POINT1POINT4,
+            CHANNEL_9POINT1POINT4,
+            CHANNEL_9POINT1POINT6,
+            CHANNEL_FRONT_BACK
+    };
+
+    private static HashMap<String,Integer> mUsageStringToIntegerMap;
+    private static HashMap<String,Integer> mContentTypeStringToIntegerMap;
+    private static HashMap<String,Integer> mChannelMaskStringToIntegerMap;
+    private static List<String> mChannelMaskStrings = new ArrayList<>();
+
+    private int mNativeApi;
+    private int mBufferCapacityInFrames;
+    private int mChannelCount;
+    private int mDeviceId;
+    private int mSessionId;
+    private int mDirection; // does not get reset
+    private int mFormat;
+    private int mSampleRate;
+    private int mSharingMode;
+    private int mPerformanceMode;
+    private boolean mFormatConversionAllowed;
+    private boolean mChannelConversionAllowed;
+    private int mRateConversionQuality;
+    private int mInputPreset;
+    private int mUsage;
+    private int mContentType;
+    private int mFramesPerBurst;
+    private boolean mMMap;
+    private int mChannelMask;
+
+    public StreamConfiguration() {
+        reset();
+    }
+
+    static {
+        // Build map for Usage string-to-int conversion.
+        mUsageStringToIntegerMap = new HashMap<String,Integer>();
+        mUsageStringToIntegerMap.put(convertUsageToText(UNSPECIFIED), UNSPECIFIED);
+        for (int usage : usages) {
+            mUsageStringToIntegerMap.put(convertUsageToText(usage), usage);
+        }
+
+        // Build map for Content Type string-to-int conversion.
+        mContentTypeStringToIntegerMap = new HashMap<String,Integer>();
+        mContentTypeStringToIntegerMap.put(convertContentTypeToText(UNSPECIFIED), UNSPECIFIED);
+        for (int contentType : contentTypes) {
+            mContentTypeStringToIntegerMap.put(convertContentTypeToText(contentType), contentType);
+        }
+
+        // Build map for Channel Mask string-to-int conversion.
+        mChannelMaskStringToIntegerMap = new HashMap<String, Integer>();
+        String channelMaskStr = convertChannelMaskToText(UNSPECIFIED);
+        mChannelMaskStringToIntegerMap.put(channelMaskStr, UNSPECIFIED);
+        mChannelMaskStrings.add(channelMaskStr);
+        for (int channelMask : channelMasks) {
+            channelMaskStr = convertChannelMaskToText(channelMask);
+            mChannelMaskStringToIntegerMap.put(channelMaskStr, channelMask);
+            mChannelMaskStrings.add(channelMaskStr);
+        }
+    }
+
+    public void reset() {
+        mNativeApi = NATIVE_API_UNSPECIFIED;
+        mBufferCapacityInFrames = UNSPECIFIED;
+        mChannelCount = UNSPECIFIED;
+        mChannelMask = UNSPECIFIED;
+        mDeviceId = UNSPECIFIED;
+        mSessionId = -1;
+        mFormat = AUDIO_FORMAT_PCM_FLOAT;
+        mSampleRate = UNSPECIFIED;
+        mSharingMode = SHARING_MODE_EXCLUSIVE;
+        mPerformanceMode = PERFORMANCE_MODE_LOW_LATENCY;
+        mInputPreset = INPUT_PRESET_VOICE_RECOGNITION;
+        mUsage = UNSPECIFIED;
+        mContentType = UNSPECIFIED;
+        mFormatConversionAllowed = false;
+        mChannelConversionAllowed = false;
+        mRateConversionQuality = RATE_CONVERSION_QUALITY_NONE;
+        mMMap = NativeEngine.isMMapSupported();
+    }
+
+    public int getFramesPerBurst() {
+        return mFramesPerBurst;
+    }
+
+    public void setFramesPerBurst(int framesPerBurst) {
+        this.mFramesPerBurst = framesPerBurst;
+    }
+
+    public int getBufferCapacityInFrames() {
+        return mBufferCapacityInFrames;
+    }
+
+    public void setBufferCapacityInFrames(int bufferCapacityInFrames) {
+        this.mBufferCapacityInFrames = bufferCapacityInFrames;
+    }
+
+    public int getFormat() {
+        return mFormat;
+    }
+
+    public void setFormat(int format) {
+        this.mFormat = format;
+    }
+
+    public int getDirection() {
+        return mDirection;
+    }
+
+    public void setDirection(int direction) {
+        this.mDirection = direction;
+    }
+
+    public int getPerformanceMode() {
+        return mPerformanceMode;
+    }
+
+    public void setPerformanceMode(int performanceMode) {
+        this.mPerformanceMode = performanceMode;
+    }
+
+    static String convertPerformanceModeToText(int performanceMode) {
+        switch(performanceMode) {
+            case PERFORMANCE_MODE_NONE:
+                return "NO";
+            case PERFORMANCE_MODE_POWER_SAVING:
+                return "PS";
+            case PERFORMANCE_MODE_LOW_LATENCY:
+                return "LL";
+            default:
+                return "??";
+        }
+    }
+
+    public int getInputPreset() { return mInputPreset; }
+    public void setInputPreset(int inputPreset) {
+        this.mInputPreset = inputPreset;
+    }
+
+    public int getUsage() { return mUsage; }
+    public void setUsage(int usage) {
+        this.mUsage = usage;
+    }
+
+    public int getContentType() { return mContentType; }
+    public void setContentType(int contentType) {
+        this.mContentType = contentType;
+    }
+
+    static String convertUsageToText(int usage) {
+        switch(usage) {
+            case UNSPECIFIED:
+                return "Unspecified";
+            case USAGE_MEDIA:
+                return "Media";
+            case USAGE_VOICE_COMMUNICATION:
+                return "VoiceComm";
+            case USAGE_VOICE_COMMUNICATION_SIGNALLING:
+                return "VoiceCommSig";
+            case USAGE_ALARM:
+                return "Alarm";
+            case USAGE_NOTIFICATION:
+                return "Notification";
+            case USAGE_NOTIFICATION_RINGTONE:
+                return "Ringtone";
+            case USAGE_NOTIFICATION_EVENT:
+                return "Event";
+            case USAGE_ASSISTANCE_ACCESSIBILITY:
+                return "Accessability";
+            case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+                return "Navigation";
+            case USAGE_ASSISTANCE_SONIFICATION:
+                return "Sonification";
+            case USAGE_GAME:
+                return "Game";
+            case USAGE_ASSISTANT:
+                return "Assistant";
+            default:
+                return "?=" + usage;
+        }
+    }
+
+    public static int convertTextToUsage(String text) {
+        return mUsageStringToIntegerMap.get(text);
+    }
+
+    static String convertContentTypeToText(int contentType) {
+        switch(contentType) {
+            case UNSPECIFIED:
+                return "Unspecified";
+            case CONTENT_TYPE_SPEECH:
+                return "Speech";
+            case CONTENT_TYPE_MUSIC:
+                return "Music";
+            case CONTENT_TYPE_MOVIE:
+                return "Movie";
+            case CONTENT_TYPE_SONIFICATION:
+                return "Sonification";
+            default:
+                return "?=" + contentType;
+        }
+    }
+
+    public static int convertTextToContentType(String text) {
+        return mContentTypeStringToIntegerMap.get(text);
+    }
+
+    public int getSharingMode() {
+        return mSharingMode;
+    }
+
+    public void setSharingMode(int sharingMode) {
+        this.mSharingMode = sharingMode;
+    }
+
+    static String convertSharingModeToText(int sharingMode) {
+        switch(sharingMode) {
+            case SHARING_MODE_SHARED:
+                return "SH";
+            case SHARING_MODE_EXCLUSIVE:
+                return "EX";
+            default:
+                return "??";
+        }
+    }
+
+    public static String convertFormatToText(int format) {
+        switch(format) {
+            case UNSPECIFIED:
+                return "Unspecified";
+            case AUDIO_FORMAT_PCM_16:
+                return "I16";
+            case AUDIO_FORMAT_PCM_24:
+                return "I24";
+            case AUDIO_FORMAT_PCM_32:
+                return "I32";
+            case AUDIO_FORMAT_PCM_FLOAT:
+                return "Float";
+            default:
+                return "Invalid";
+        }
+    }
+
+    public static String convertNativeApiToText(int api) {
+        switch(api) {
+            case NATIVE_API_UNSPECIFIED:
+                return "Unspec";
+            case NATIVE_API_AAUDIO:
+                return "AAudio";
+            case NATIVE_API_OPENSLES:
+                return "OpenSL";
+            default:
+                return "Invalid";
+        }
+    }
+
+    public static String convertChannelMaskToText(int channelMask) {
+        switch (channelMask) {
+            case UNSPECIFIED:
+                return "Unspecified";
+            case CHANNEL_MONO:
+                return "Mono";
+            case CHANNEL_STEREO:
+                return "Stereo";
+            case CHANNEL_2POINT1:
+                return "2.1";
+            case CHANNEL_TRI:
+                return "Tri";
+            case CHANNEL_TRI_BACK:
+                return "TriBack";
+            case CHANNEL_3POINT1:
+                return "3.1";
+            case CHANNEL_2POINT0POINT2:
+                return "2.0.2";
+            case CHANNEL_2POINT1POINT2:
+                return "2.1.2";
+            case CHANNEL_3POINT0POINT2:
+                return "3.0.2";
+            case CHANNEL_3POINT1POINT2:
+                return "3.1.2";
+            case CHANNEL_QUAD:
+                return "Quad";
+            case CHANNEL_QUAD_SIDE:
+                return "QuadSide";
+            case CHANNEL_SURROUND:
+                return "Surround";
+            case CHANNEL_PENTA:
+                return "Penta";
+            case CHANNEL_5POINT1:
+                return "5.1";
+            case CHANNEL_5POINT1_SIDE:
+                return "5.1Side";
+            case CHANNEL_6POINT1:
+                return "6.1";
+            case CHANNEL_7POINT1:
+                return "7.1";
+            case CHANNEL_5POINT1POINT2:
+                return "5.1.2";
+            case CHANNEL_5POINT1POINT4:
+                return "5.1.4";
+            case CHANNEL_7POINT1POINT2:
+                return "7.1.2";
+            case CHANNEL_7POINT1POINT4:
+                return "7.1.4";
+            case CHANNEL_9POINT1POINT4:
+                return "9.1.4";
+            case CHANNEL_9POINT1POINT6:
+                return "9.1.6";
+            case CHANNEL_FRONT_BACK:
+                return "FrontBack";
+            default:
+                return "?=" + Integer.toHexString(channelMask);
+        }
+    }
+
+    public static int convertTextToChannelMask(String text) {
+        return mChannelMaskStringToIntegerMap.get(text);
+    }
+
+
+    public String dump() {
+        String prefix = (getDirection() == DIRECTION_INPUT) ? "in" : "out";
+        StringBuffer message = new StringBuffer();
+        message.append(String.format("%s.channels = %d\n", prefix, mChannelCount));
+        message.append(String.format("%s.perf = %s\n", prefix,
+                convertPerformanceModeToText(mPerformanceMode).toLowerCase()));
+        if (getDirection() == DIRECTION_INPUT) {
+            message.append(String.format("%s.preset = %s\n", prefix,
+                    convertInputPresetToText(mInputPreset).toLowerCase()));
+        } else {
+            message.append(String.format("%s.preset = %s\n", prefix,
+                    convertUsageToText(mUsage).toLowerCase()));
+            message.append(String.format("%s.contentType = %s\n", prefix,
+                    convertContentTypeToText(mContentType).toLowerCase()));
+        }
+        message.append(String.format("%s.sharing = %s\n", prefix,
+                convertSharingModeToText(mSharingMode).toLowerCase()));
+        message.append(String.format("%s.api = %s\n", prefix,
+                convertNativeApiToText(getNativeApi()).toLowerCase()));
+        message.append(String.format("%s.rate = %d\n", prefix, mSampleRate));
+        message.append(String.format("%s.device = %d\n", prefix, mDeviceId));
+        message.append(String.format("%s.mmap = %s\n", prefix, isMMap() ? "yes" : "no"));
+        message.append(String.format("%s.rate.conversion.quality = %d\n", prefix, mRateConversionQuality));
+        return message.toString();
+    }
+
+    // text must match menu values
+    public static final String NAME_INPUT_PRESET_GENERIC = "Generic";
+    public static final String NAME_INPUT_PRESET_CAMCORDER = "Camcorder";
+    public static final String NAME_INPUT_PRESET_VOICE_RECOGNITION = "VoiceRec";
+    public static final String NAME_INPUT_PRESET_VOICE_COMMUNICATION = "VoiceComm";
+    public static final String NAME_INPUT_PRESET_UNPROCESSED = "Unprocessed";
+    public static final String NAME_INPUT_PRESET_VOICE_PERFORMANCE = "Performance";
+
+    public static String convertInputPresetToText(int inputPreset) {
+        switch(inputPreset) {
+            case INPUT_PRESET_GENERIC:
+                return NAME_INPUT_PRESET_GENERIC;
+            case INPUT_PRESET_CAMCORDER:
+                return NAME_INPUT_PRESET_CAMCORDER;
+            case INPUT_PRESET_VOICE_RECOGNITION:
+                return NAME_INPUT_PRESET_VOICE_RECOGNITION;
+            case INPUT_PRESET_VOICE_COMMUNICATION:
+                return NAME_INPUT_PRESET_VOICE_COMMUNICATION;
+            case INPUT_PRESET_UNPROCESSED:
+                return NAME_INPUT_PRESET_UNPROCESSED;
+            case INPUT_PRESET_VOICE_PERFORMANCE:
+                return NAME_INPUT_PRESET_VOICE_PERFORMANCE;
+            default:
+                return "Invalid";
+        }
+    }
+
+    private static boolean matchInputPreset(String text, int preset) {
+        return convertInputPresetToText(preset).toLowerCase().equals(text);
+    }
+
+    /**
+     * Case insensitive.
+     * @param text
+     * @return inputPreset, eg. INPUT_PRESET_CAMCORDER
+     */
+    public static int convertTextToInputPreset(String text) {
+        text = text.toLowerCase();
+        if (matchInputPreset(text, INPUT_PRESET_GENERIC)) {
+            return INPUT_PRESET_GENERIC;
+        } else if (matchInputPreset(text, INPUT_PRESET_CAMCORDER)) {
+            return INPUT_PRESET_CAMCORDER;
+        } else if (matchInputPreset(text, INPUT_PRESET_VOICE_RECOGNITION)) {
+            return INPUT_PRESET_VOICE_RECOGNITION;
+        } else if (matchInputPreset(text, INPUT_PRESET_VOICE_COMMUNICATION)) {
+            return INPUT_PRESET_VOICE_COMMUNICATION;
+        } else if (matchInputPreset(text, INPUT_PRESET_UNPROCESSED)) {
+            return INPUT_PRESET_UNPROCESSED;
+        } else if (matchInputPreset(text, INPUT_PRESET_VOICE_PERFORMANCE)) {
+            return INPUT_PRESET_VOICE_PERFORMANCE;
+        }
+        return -1;
+    }
+
+    public int getChannelCount() {
+        return mChannelCount;
+    }
+
+    public void setChannelCount(int channelCount) {
+        this.mChannelCount = channelCount;
+    }
+
+    public int getSampleRate() {
+        return mSampleRate;
+    }
+
+    public void setSampleRate(int sampleRate) {
+        this.mSampleRate = sampleRate;
+    }
+
+    public int getDeviceId() {
+        return mDeviceId;
+    }
+
+    public void setDeviceId(int deviceId) {
+        this.mDeviceId = deviceId;
+    }
+
+    public int getSessionId() {
+        return mSessionId;
+    }
+
+    public void setSessionId(int sessionId) {
+        mSessionId = sessionId;
+    }
+
+    public boolean isMMap() {
+        return mMMap;
+    }
+
+    public void setMMap(boolean b) { mMMap = b; }
+
+    public int getNativeApi() {
+        return mNativeApi;
+    }
+
+    public void setNativeApi(int nativeApi) {
+        mNativeApi = nativeApi;
+    }
+
+    public void setChannelConversionAllowed(boolean b) { mChannelConversionAllowed = b; }
+
+    public boolean getChannelConversionAllowed() {
+        return mChannelConversionAllowed;
+    }
+
+    public void setFormatConversionAllowed(boolean b) {
+        mFormatConversionAllowed = b;
+    }
+
+    public boolean getFormatConversionAllowed() {
+        return mFormatConversionAllowed;
+    }
+
+    public void setRateConversionQuality(int quality) { mRateConversionQuality = quality; }
+
+    public int getRateConversionQuality() {
+        return mRateConversionQuality;
+    }
+
+    public int getChannelMask() {
+        return mChannelMask;
+    }
+
+    public void setChannelMask(int channelMask) {
+        this.mChannelMask = channelMask;
+    }
+
+    public static List<String> getAllChannelMasks() {
+        return mChannelMaskStrings;
+    }
+
+}
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfigurationView.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfigurationView.java
new file mode 100644
index 0000000..eeb962f
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfigurationView.java
@@ -0,0 +1,574 @@
+/*
+ * Copyright 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.
+ */
+
+package com.mobileer.oboetester;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.audiofx.AcousticEchoCanceler;
+import android.media.audiofx.AutomaticGainControl;
+import android.media.audiofx.BassBoost;
+import android.media.audiofx.LoudnessEnhancer;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+import android.widget.TableRow;
+import android.widget.TextView;
+import android.widget.LinearLayout;
+import android.util.Log;
+
+import com.mobileer.audio_device.AudioDeviceListEntry;
+import com.mobileer.audio_device.AudioDeviceSpinner;
+
+/**
+ * View for Editing a requested StreamConfiguration
+ * and displaying the actual StreamConfiguration.
+ */
+
+public class StreamConfigurationView extends LinearLayout {
+    private static final String TAG = "StreamConfigurationView";
+
+    protected Spinner mNativeApiSpinner;
+    private TextView mActualNativeApiView;
+
+    private TextView mActualMMapView;
+    private CheckBox mRequestedMMapView;
+    private TextView mActualExclusiveView;
+    private TextView mActualPerformanceView;
+    private Spinner  mPerformanceSpinner;
+    private CheckBox mRequestedExclusiveView;
+    private CheckBox mChannelConversionBox;
+    private CheckBox mFormatConversionBox;
+    private Spinner  mChannelCountSpinner;
+    private TextView mActualChannelCountView;
+    private Spinner mChannelMaskSpinner;
+    private TextView mActualChannelMaskView;
+    private TextView mActualFormatView;
+
+    private TableRow mInputPresetTableRow;
+    private Spinner  mInputPresetSpinner;
+    private TextView mActualInputPresetView;
+
+    private TableRow mUsageTableRow;
+    private Spinner  mUsageSpinner;
+    private TextView mActualUsageView;
+
+    private TableRow mContentTypeTableRow;
+    private Spinner  mContentTypeSpinner;
+    private TextView mActualContentTypeView;
+
+    private Spinner  mFormatSpinner;
+    private Spinner  mSampleRateSpinner;
+    private Spinner  mRateConversionQualitySpinner;
+    private TextView mActualSampleRateView;
+    private LinearLayout mHideableView;
+
+    private AudioDeviceSpinner mDeviceSpinner;
+    private TextView mActualSessionIdView;
+    private CheckBox mRequestAudioEffect;
+
+    private TextView mStreamInfoView;
+    private TextView mStreamStatusView;
+    private TextView mOptionExpander;
+    private String mHideSettingsText;
+    private String mShowSettingsText;
+
+    private LinearLayout mInputEffectsLayout;
+    private LinearLayout mOutputEffectsLayout;
+
+    private CheckBox mAutomaticGainControlCheckBox;
+    private CheckBox mAcousticEchoCancelerCheckBox;
+    private TextView mBassBoostTextView;
+    private SeekBar mBassBoostSeekBar;
+    private TextView mLoudnessEnhancerTextView;
+    private SeekBar mLoudnessEnhancerSeekBar;
+
+    private boolean mIsChannelMaskLastSelected;
+
+    private boolean misOutput;
+
+    private BassBoost mBassBoost;
+    private LoudnessEnhancer mLoudnessEnhancer;
+    private AcousticEchoCanceler mAcousticEchoCanceler;
+    private AutomaticGainControl mAutomaticGainControl;
+
+    // Create an anonymous implementation of OnClickListener
+    private View.OnClickListener mToggleListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            if (mHideableView.isShown()) {
+                hideSettingsView();
+            } else {
+                showSettingsView();
+            }
+        }
+    };
+
+    public static String yesOrNo(boolean b) {
+        return b ?  "YES" : "NO";
+    }
+
+    private void updateSettingsViewText() {
+        if (mHideableView.isShown()) {
+            mOptionExpander.setText(mHideSettingsText);
+        } else {
+            mOptionExpander.setText(mShowSettingsText);
+        }
+    }
+
+    public void showSettingsView() {
+        mHideableView.setVisibility(View.VISIBLE);
+        updateSettingsViewText();
+    }
+
+    public void hideSampleRateMenu() {
+        if (mSampleRateSpinner != null) {
+            mSampleRateSpinner.setVisibility(View.GONE);
+        }
+    }
+
+    public void hideSettingsView() {
+        mHideableView.setVisibility(View.GONE);
+        updateSettingsViewText();
+    }
+
+    public StreamConfigurationView(Context context) {
+        super(context);
+        initializeViews(context);
+    }
+
+    public StreamConfigurationView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        initializeViews(context);
+    }
+
+    public StreamConfigurationView(Context context,
+                                   AttributeSet attrs,
+                                   int defStyle) {
+        super(context, attrs, defStyle);
+        initializeViews(context);
+    }
+
+    /**
+     * Inflates the views in the layout.
+     *
+     * @param context
+     *           the current context for the view.
+     */
+    private void initializeViews(Context context) {
+        LayoutInflater inflater = (LayoutInflater) context
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        inflater.inflate(R.layout.stream_config, this);
+
+        mHideSettingsText = getResources().getString(R.string.hint_hide_settings);
+        mShowSettingsText = getResources().getString(R.string.hint_show_settings);
+
+        mHideableView = (LinearLayout) findViewById(R.id.hideableView);
+
+        mOptionExpander = (TextView) findViewById(R.id.toggle_stream_config);
+        mOptionExpander.setOnClickListener(mToggleListener);
+
+        mNativeApiSpinner = (Spinner) findViewById(R.id.spinnerNativeApi);
+        mNativeApiSpinner.setSelection(StreamConfiguration.NATIVE_API_UNSPECIFIED);
+
+        mActualNativeApiView = (TextView) findViewById(R.id.actualNativeApi);
+
+        mChannelConversionBox = (CheckBox) findViewById(R.id.checkChannelConversion);
+
+        mFormatConversionBox = (CheckBox) findViewById(R.id.checkFormatConversion);
+
+        mActualMMapView = (TextView) findViewById(R.id.actualMMap);
+        mRequestedMMapView = (CheckBox) findViewById(R.id.requestedMMapEnable);
+        boolean mmapSupported = NativeEngine.isMMapSupported();
+        mRequestedMMapView.setEnabled(mmapSupported);
+        mRequestedMMapView.setChecked(mmapSupported);
+
+        mActualExclusiveView = (TextView) findViewById(R.id.actualExclusiveMode);
+        mRequestedExclusiveView = (CheckBox) findViewById(R.id.requestedExclusiveMode);
+
+        boolean mmapExclusiveSupported = NativeEngine.isMMapExclusiveSupported();
+        mRequestedExclusiveView.setEnabled(mmapExclusiveSupported);
+        mRequestedExclusiveView.setChecked(mmapExclusiveSupported);
+
+        mActualSessionIdView = (TextView) findViewById(R.id.sessionId);
+        mRequestAudioEffect = (CheckBox) findViewById(R.id.requestAudioEffect);
+
+        mOutputEffectsLayout = (LinearLayout) findViewById(R.id.outputEffects);
+        mInputEffectsLayout = (LinearLayout) findViewById(R.id.inputEffects);
+
+        mRequestAudioEffect.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                onRequestAudioEffectClicked(((CheckBox) view).isChecked());
+            }
+        });
+
+        mAutomaticGainControlCheckBox = (CheckBox) findViewById(R.id.checkBoxAutomaticGainControl);
+        mAcousticEchoCancelerCheckBox = (CheckBox) findViewById(R.id.checkBoxAcousticEchoCanceler);
+        mBassBoostTextView = (TextView) findViewById(R.id.textBassBoost);
+        mBassBoostSeekBar = (SeekBar) findViewById(R.id.seekBarBassBoost);
+        mLoudnessEnhancerTextView = (TextView) findViewById(R.id.textLoudnessEnhancer);
+        mLoudnessEnhancerSeekBar = (SeekBar) findViewById(R.id.seekBarLoudnessEnhancer);
+
+        mAutomaticGainControlCheckBox.setEnabled(AutomaticGainControl.isAvailable());
+        mAcousticEchoCancelerCheckBox.setEnabled(AcousticEchoCanceler.isAvailable());
+
+        mBassBoostSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                onBassBoostSeekBarChanged(progress);
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+            }
+        });
+
+        mLoudnessEnhancerSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                onLoudnessEnhancerSeekBarChanged(progress);
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+            }
+        });
+
+        mAutomaticGainControlCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                onAutomaticGainControlCheckBoxChanged(isChecked);
+            }
+        });
+
+        mAcousticEchoCancelerCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                onAcousticEchoCancelerCheckBoxChanged(isChecked);
+            }
+        });
+
+        mActualSampleRateView = (TextView) findViewById(R.id.actualSampleRate);
+        mSampleRateSpinner = (Spinner) findViewById(R.id.spinnerSampleRate);
+        mActualChannelCountView = (TextView) findViewById(R.id.actualChannelCount);
+        mChannelCountSpinner = (Spinner) findViewById(R.id.spinnerChannelCount);
+        mChannelCountSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
+                onChannelCountSpinnerSelected();
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> adapterView) {
+                // no-op
+            }
+        });
+        mActualFormatView = (TextView) findViewById(R.id.actualAudioFormat);
+        mFormatSpinner = (Spinner) findViewById(R.id.spinnerFormat);
+        mRateConversionQualitySpinner = (Spinner) findViewById(R.id.spinnerSRCQuality);
+
+        mActualPerformanceView = (TextView) findViewById(R.id.actualPerformanceMode);
+        mPerformanceSpinner = (Spinner) findViewById(R.id.spinnerPerformanceMode);
+        mPerformanceSpinner.setSelection(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY
+                - StreamConfiguration.PERFORMANCE_MODE_NONE);
+
+        mInputPresetTableRow = (TableRow) findViewById(R.id.rowInputPreset);
+        mActualInputPresetView = (TextView) findViewById(R.id.actualInputPreset);
+        mInputPresetSpinner = (Spinner) findViewById(R.id.spinnerInputPreset);
+        mInputPresetSpinner.setSelection(2); // TODO need better way to select voice recording default
+
+        mUsageTableRow = (TableRow) findViewById(R.id.rowUsage);
+        mActualUsageView = (TextView) findViewById(R.id.actualUsage);
+        mUsageSpinner = (Spinner) findViewById(R.id.spinnerUsage);
+
+        mContentTypeTableRow = (TableRow) findViewById(R.id.rowContentType);
+        mActualContentTypeView = (TextView) findViewById(R.id.actualContentType);
+        mContentTypeSpinner = (Spinner) findViewById(R.id.spinnerContentType);
+
+        mStreamInfoView = (TextView) findViewById(R.id.streamInfo);
+
+        mStreamStatusView = (TextView) findViewById(R.id.statusView);
+
+        mDeviceSpinner = (AudioDeviceSpinner) findViewById(R.id.devices_spinner);
+
+        mActualChannelMaskView = (TextView) findViewById(R.id.actualChannelMask);
+        mChannelMaskSpinner = (Spinner) findViewById(R.id.spinnerChannelMask);
+        ArrayAdapter<String> channelMaskSpinnerArrayAdapter = new ArrayAdapter<String>(context,
+                android.R.layout.simple_spinner_item,
+                StreamConfiguration.getAllChannelMasks());
+        mChannelMaskSpinner.setAdapter(channelMaskSpinnerArrayAdapter);
+        mChannelMaskSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
+                onChannelMaskSpinnerSelected();
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> adapterView) {
+                // no-op
+            }
+        });
+
+        showSettingsView();
+    }
+
+    public void setOutput(boolean output) {
+        misOutput = output;
+        String ioText;
+        if (output) {
+            mDeviceSpinner.setDirectionType(AudioManager.GET_DEVICES_OUTPUTS);
+            ioText = "OUTPUT";
+        } else {
+            mDeviceSpinner.setDirectionType(AudioManager.GET_DEVICES_INPUTS);
+            ioText = "INPUT";
+        }
+        mHideSettingsText = getResources().getString(R.string.hint_hide_settings) + " - " + ioText;
+        mShowSettingsText = getResources().getString(R.string.hint_show_settings) + " - " + ioText;
+        updateSettingsViewText();
+
+        // Don't show InputPresets for output streams.
+        mInputPresetTableRow.setVisibility(output ? View.GONE : View.VISIBLE);
+        // Don't show Usage and Content Type for input streams.
+        mUsageTableRow.setVisibility(output ? View.VISIBLE : View.GONE);
+        mContentTypeTableRow.setVisibility(output ? View.VISIBLE : View.GONE);
+    }
+
+    public void applyToModel(StreamConfiguration config) {
+        // Menu position matches actual enum value for these properties.
+        config.setNativeApi(mNativeApiSpinner.getSelectedItemPosition());
+        config.setFormat(mFormatSpinner.getSelectedItemPosition());
+        config.setRateConversionQuality(mRateConversionQualitySpinner.getSelectedItemPosition());
+
+        int id =  ((AudioDeviceListEntry) mDeviceSpinner.getSelectedItem()).getId();
+        config.setDeviceId(id);
+
+        String text = mSampleRateSpinner.getSelectedItem().toString();
+        int sampleRate = Integer.parseInt(text);
+        config.setSampleRate(sampleRate);
+
+        text = mInputPresetSpinner.getSelectedItem().toString();
+        int inputPreset = StreamConfiguration.convertTextToInputPreset(text);
+        config.setInputPreset(inputPreset);
+
+        text = mUsageSpinner.getSelectedItem().toString();
+        int usage = StreamConfiguration.convertTextToUsage(text);
+        config.setUsage(usage);
+
+        text = mContentTypeSpinner.getSelectedItem().toString();
+        int contentType = StreamConfiguration.convertTextToContentType(text);
+        config.setContentType(contentType);
+
+        // The corresponding channel count of the selected channel mask may be different from
+        // the selected channel count, the last selected will be respected.
+        if (mIsChannelMaskLastSelected) {
+            text = mChannelMaskSpinner.getSelectedItem().toString();
+            int channelMask = StreamConfiguration.convertTextToChannelMask(text);
+            config.setChannelMask(channelMask);
+            config.setChannelCount(0);
+            Log.d(TAG, String.format("Set channel mask as %s(%#x)", text, channelMask));
+        } else {
+            config.setChannelCount(mChannelCountSpinner.getSelectedItemPosition());
+            config.setChannelMask(StreamConfiguration.UNSPECIFIED);
+            Log.d(TAG, "Set channel count as " + mChannelCountSpinner.getSelectedItemPosition());
+        }
+
+        config.setMMap(mRequestedMMapView.isChecked());
+        config.setChannelConversionAllowed(mChannelConversionBox.isChecked());
+        config.setFormatConversionAllowed(mFormatConversionBox.isChecked());
+        config.setSharingMode(mRequestedExclusiveView.isChecked()
+                ? StreamConfiguration.SHARING_MODE_EXCLUSIVE
+                : StreamConfiguration.SHARING_MODE_SHARED);
+        config.setSessionId(mRequestAudioEffect.isChecked()
+                ? StreamConfiguration.SESSION_ID_ALLOCATE
+                : StreamConfiguration.SESSION_ID_NONE);
+
+        config.setPerformanceMode(mPerformanceSpinner.getSelectedItemPosition()
+                + StreamConfiguration.PERFORMANCE_MODE_NONE);
+    }
+
+    public void setChildrenEnabled(boolean enabled) {
+        mNativeApiSpinner.setEnabled(enabled);
+        mPerformanceSpinner.setEnabled(enabled);
+        mRequestedMMapView.setEnabled(enabled && NativeEngine.isMMapSupported());
+        mRequestedExclusiveView.setEnabled(enabled && NativeEngine.isMMapExclusiveSupported());
+        mChannelConversionBox.setEnabled(enabled);
+        mFormatConversionBox.setEnabled(enabled);
+        mChannelCountSpinner.setEnabled(enabled);
+        mChannelMaskSpinner.setEnabled(enabled);
+        mInputPresetSpinner.setEnabled(enabled);
+        mUsageSpinner.setEnabled(enabled);
+        mContentTypeSpinner.setEnabled(enabled);
+        mFormatSpinner.setEnabled(enabled);
+        mSampleRateSpinner.setEnabled(enabled);
+        mRateConversionQualitySpinner.setEnabled(enabled);
+        mDeviceSpinner.setEnabled(enabled);
+        mRequestAudioEffect.setEnabled(enabled);
+    }
+
+    // This must be called on the UI thread.
+    void updateDisplay(StreamConfiguration actualConfiguration) {
+        int value;
+
+        value = actualConfiguration.getNativeApi();
+        mActualNativeApiView.setText(StreamConfiguration.convertNativeApiToText(value));
+
+        mActualMMapView.setText(yesOrNo(actualConfiguration.isMMap()));
+        int sharingMode = actualConfiguration.getSharingMode();
+        boolean isExclusive = (sharingMode == StreamConfiguration.SHARING_MODE_EXCLUSIVE);
+        mActualExclusiveView.setText(yesOrNo(isExclusive));
+
+        value = actualConfiguration.getPerformanceMode();
+        mActualPerformanceView.setText(StreamConfiguration.convertPerformanceModeToText(value));
+        mActualPerformanceView.requestLayout();
+
+        value = actualConfiguration.getFormat();
+        mActualFormatView.setText(StreamConfiguration.convertFormatToText(value));
+        mActualFormatView.requestLayout();
+
+        value = actualConfiguration.getInputPreset();
+        mActualInputPresetView.setText(StreamConfiguration.convertInputPresetToText(value));
+        mActualInputPresetView.requestLayout();
+
+        value = actualConfiguration.getUsage();
+        mActualUsageView.setText(StreamConfiguration.convertUsageToText(value));
+        mActualUsageView.requestLayout();
+
+        value = actualConfiguration.getContentType();
+        mActualContentTypeView.setText(StreamConfiguration.convertContentTypeToText(value));
+        mActualContentTypeView.requestLayout();
+
+        mActualChannelCountView.setText(actualConfiguration.getChannelCount() + "");
+        mActualSampleRateView.setText(actualConfiguration.getSampleRate() + "");
+        mActualSessionIdView.setText("S#: " + actualConfiguration.getSessionId());
+        value = actualConfiguration.getChannelMask();
+        mActualChannelMaskView.setText(StreamConfiguration.convertChannelMaskToText(value));
+
+        boolean isMMap = actualConfiguration.isMMap();
+        mStreamInfoView.setText("burst = " + actualConfiguration.getFramesPerBurst()
+                + ", capacity = " + actualConfiguration.getBufferCapacityInFrames()
+                + ", devID = " + actualConfiguration.getDeviceId()
+                + ", " + (actualConfiguration.isMMap() ? "MMAP" : "Legacy")
+                + (isMMap ? ", " + StreamConfiguration.convertSharingModeToText(sharingMode) : "")
+        );
+
+        mHideableView.requestLayout();
+    }
+
+    // This must be called on the UI thread.
+    public void setStatusText(String msg) {
+        mStreamStatusView.setText(msg);
+    }
+
+    public void setExclusiveMode(boolean b) {
+        mRequestedExclusiveView.setChecked(b);
+    }
+
+    public void setFormat(int format) {
+        mFormatSpinner.setSelection(format); // position matches format
+    }
+
+    public void setFormatConversionAllowed(boolean allowed) {
+        mFormatConversionBox.setChecked(allowed);
+    }
+
+    private void onChannelCountSpinnerSelected() {
+        mIsChannelMaskLastSelected = false;
+    }
+
+    private void onChannelMaskSpinnerSelected() {
+        mIsChannelMaskLastSelected = true;
+    }
+
+    private void onRequestAudioEffectClicked(boolean isChecked) {
+        if (isChecked){
+            if (misOutput) {
+                mOutputEffectsLayout.setVisibility(VISIBLE);
+            } else {
+                mInputEffectsLayout.setVisibility(VISIBLE);
+            }
+        } else {
+            if (misOutput) {
+                mOutputEffectsLayout.setVisibility(GONE);
+            } else {
+                mInputEffectsLayout.setVisibility(GONE);
+            }
+        }
+    }
+
+    public void setupEffects(int sessionId) {
+        if (misOutput) {
+            mBassBoost = new BassBoost(0, sessionId);
+            mBassBoost.setStrength((short) mBassBoostSeekBar.getProgress());
+            mLoudnessEnhancer = new LoudnessEnhancer(sessionId);
+            mLoudnessEnhancer.setTargetGain((short) mLoudnessEnhancerSeekBar.getProgress());
+        } else {
+            // If AEC is not available, the checkbox will be disabled in initializeViews().
+            if (mAcousticEchoCancelerCheckBox.isEnabled()) {
+                mAcousticEchoCanceler = AcousticEchoCanceler.create(sessionId);
+                if (mAcousticEchoCanceler != null) {
+                    mAcousticEchoCanceler.setEnabled(mAcousticEchoCancelerCheckBox.isChecked());
+                } else {
+                    Log.e(TAG, String.format("Could not create AcousticEchoCanceler"));
+                }
+            }
+            // If AGC is not available, the checkbox will be disabled in initializeViews().
+            if (mAutomaticGainControlCheckBox.isEnabled()) {
+                mAutomaticGainControl = AutomaticGainControl.create(sessionId);
+                if (mAutomaticGainControl != null) {
+                    mAutomaticGainControl.setEnabled(mAutomaticGainControlCheckBox.isChecked());
+                } else {
+                    Log.e(TAG, String.format("Could not create AutomaticGainControl"));
+                }
+            }
+        }
+    }
+
+    private void onLoudnessEnhancerSeekBarChanged(int progress) {
+        if (mLoudnessEnhancer != null) {
+            mLoudnessEnhancer.setTargetGain(progress);
+        }
+        mLoudnessEnhancerTextView.setText("Loudness Enhancer: " + progress);
+    }
+
+    private void onBassBoostSeekBarChanged(int progress) {
+        if (mBassBoost != null) {
+            mBassBoost.setStrength((short) progress);
+        }
+        mBassBoostTextView.setText("Bass Boost: " + progress);
+    }
+
+    private void onAutomaticGainControlCheckBoxChanged(boolean isChecked) {
+        if (mAutomaticGainControlCheckBox.isEnabled() && mAutomaticGainControl != null) {
+            mAutomaticGainControl.setEnabled(isChecked);
+        }
+    }
+
+    private void onAcousticEchoCancelerCheckBoxChanged(boolean isChecked) {
+        if (mAcousticEchoCancelerCheckBox.isEnabled() && mAcousticEchoCanceler != null) {
+            mAcousticEchoCanceler.setEnabled(isChecked);
+        }
+    }
+}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TapLatencyAnalyser.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapLatencyAnalyser.java
similarity index 72%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TapLatencyAnalyser.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapLatencyAnalyser.java
index 09e4e97..6b9d4b2 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TapLatencyAnalyser.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapLatencyAnalyser.java
@@ -13,17 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import java.util.ArrayList;
 
+/**
+ * Analyze a recording and extract edges for latency analysis.
+ */
 public class TapLatencyAnalyser {
     public static final int TYPE_TAP = 0;
     float[] mHighPassBuffer;
 
     private float mDroop = 0.995f;
-    private static float LOW_THRESHOLD = 0.01f;
-    private static float HIGH_THRESHOLD = 0.03f;
+    private static final float EDGE_THRESHOLD = 0.01f;
+    private static final float LOW_FRACTION = 0.5f;
 
     public static class TapLatencyEvent {
         public int type;
@@ -38,8 +41,10 @@
         // Use high pass filter to remove rumble from air conditioners.
         mHighPassBuffer = new float[numSamples];
         highPassFilter(buffer, offset, numSamples, mHighPassBuffer);
+        // Apply envelope follower.
         float[] peakBuffer = new float[numSamples];
         fillPeakBuffer(mHighPassBuffer, 0, numSamples, peakBuffer);
+        // Look for two attacks.
         return scanForEdges(peakBuffer, numSamples);
     }
 
@@ -47,13 +52,14 @@
         return mHighPassBuffer;
     }
 
+    // Based on https://en.wikipedia.org/wiki/High-pass_filter
     private void highPassFilter(float[] buffer, int offset, int numSamples, float[] highPassBuffer) {
         float xn1 = 0.0f;
         float yn1 = 0.0f;
-        final float alpha = 0.05f;
+        final float alpha = 0.8f;
         for (int i = 0; i < numSamples; i++) {
             float xn = buffer[i + offset];
-            float yn = alpha * yn1 + ((1.0f - alpha) * (xn - xn1));
+            float yn = alpha * (yn1 + xn - xn1);
             highPassBuffer[i] = yn;
             xn1 = xn;
             yn1 = yn;
@@ -64,31 +70,43 @@
         ArrayList<TapLatencyEvent> events = new ArrayList<TapLatencyEvent>();
         float slow = 0.0f;
         float fast = 0.0f;
-        float slowCoefficient = 0.01f;
-        float fastCoefficient = 0.10f;
+        final float slowCoefficient = 0.01f;
+        final float fastCoefficient = 0.10f;
+        float lowThreshold = EDGE_THRESHOLD;
         boolean armed = true;
         int sampleIndex = 0;
         for (float level : peakBuffer) {
             slow = slow + (level - slow) * slowCoefficient; // low pass filter
-            fast = fast + (level - fast) * fastCoefficient;
-            if (armed && (fast > HIGH_THRESHOLD) && (fast > (2.0 * slow))) {
+            fast = fast + (level - fast) * fastCoefficient; // low pass filter
+            if (armed && (fast > EDGE_THRESHOLD) && (fast > (2.0 * slow))) {
                 //System.out.println("edge at " + sampleIndex + ", slow " + slow + ", fast " + fast);
                 events.add(new TapLatencyEvent(TYPE_TAP, sampleIndex));
                 armed = false;
+                lowThreshold = fast * LOW_FRACTION;
             }
             // Use hysteresis when rearming.
-            if (!armed && (fast < LOW_THRESHOLD)) {
+            if (!armed && (fast < lowThreshold)) {
                 armed = true;
+                // slow = fast; // This seems unnecessary.
+                //events.add(new TapLatencyEvent(TYPE_TAP, sampleIndex));
             }
             sampleIndex++;
         }
         return events.toArray(new TapLatencyEvent[0]);
     }
 
+    /**
+     * Envelope follower that rides along the peaks of the waveforms
+     * and then decays exponentially.
+     *
+     * @param buffer
+     * @param offset
+     * @param numSamples
+     */
     private void fillPeakBuffer(float[] buffer, int offset, int numSamples, float[] peakBuffer) {
         float previous = 0.0f;
         for (int i = 0; i < numSamples; i++) {
-            float input = buffer[i + offset];
+            float input = Math.abs(buffer[i + offset]);
             float output = previous * mDroop;
             if (input > output) {
                 output = input;
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneActivity.java
new file mode 100644
index 0000000..2da6bf5
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneActivity.java
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ */
+
+package com.mobileer.oboetester;
+
+import android.Manifest;
+import android.content.pm.PackageManager;
+import android.media.midi.MidiDevice;
+import android.media.midi.MidiDeviceInfo;
+import android.media.midi.MidiInputPort;
+import android.media.midi.MidiManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Button;
+import android.widget.Toast;
+
+import com.mobileer.miditools.MidiOutputPortConnectionSelector;
+import com.mobileer.miditools.MidiPortConnector;
+import com.mobileer.miditools.MidiTools;
+
+import java.io.IOException;
+import java.sql.Timestamp;
+
+import static com.mobileer.oboetester.MidiTapTester.NoteListener;
+
+public class TapToToneActivity extends TestOutputActivityBase {
+    // Names from obsolete version of Oboetester.
+    public static final String OLD_PRODUCT_NAME = "AudioLatencyTester";
+    public static final String OLD_MANUFACTURER_NAME = "AndroidTest";
+
+    private MidiManager mMidiManager;
+    private MidiInputPort mInputPort;
+
+    protected MidiTapTester mMidiTapTester;
+    protected TapToToneTester mTapToToneTester;
+
+    private Button mStopButton;
+    private Button mStartButton;
+
+    private MidiOutputPortConnectionSelector mPortSelector;
+    private final MyNoteListener mTestListener = new MyNoteListener();
+
+    @Override
+    protected void inflateActivity() {
+        setContentView(R.layout.activity_tap_to_tone);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mAudioOutTester = addAudioOutputTester();
+
+        mTapToToneTester = new TapToToneTester(this,
+                getResources().getString(R.string.tap_to_tone_instructions));
+
+        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI)) {
+            setupMidi();
+        } else {
+            Toast.makeText(TapToToneActivity.this,
+                    "MIDI not supported!", Toast.LENGTH_LONG)
+                    .show();
+        }
+
+
+        // Start a blip test when the waveform view is tapped.
+        WaveformView mWaveformView = (WaveformView) findViewById(R.id.waveview_audio);
+        mWaveformView.setOnTouchListener((view, event) -> {
+            // Do not call view.performClick() because it may trigger a touch sound!
+            int action = event.getActionMasked();
+            switch (action) {
+                case MotionEvent.ACTION_DOWN:
+                case MotionEvent.ACTION_POINTER_DOWN:
+                    trigger();
+                    break;
+                case MotionEvent.ACTION_MOVE:
+                    break;
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_POINTER_UP:
+                    break;
+            }
+            // Must return true or we do not get the ACTION_MOVE and
+            // ACTION_UP events.
+            return true;
+        });
+
+        mStartButton = (Button) findViewById(R.id.button_start);
+        mStopButton = (Button) findViewById(R.id.button_stop);
+        updateButtons(false);
+
+        updateEnabledWidgets();
+    }
+
+    private void updateButtons(boolean running) {
+        mStartButton.setEnabled(!running);
+        mStopButton.setEnabled(running);
+    }
+
+    void trigger() {
+        if (mTapToToneTester.isArmed()) {
+            mAudioOutTester.trigger();
+            mTapToToneTester.analyzeLater(getString(R.string.please_wait));
+            Timestamp timestamp = new Timestamp(System.currentTimeMillis());
+            Log.d(TAG, "Tap to Tone Triggered. Timestamp: " + timestamp);
+        } else {
+            showToast(getString(R.string.no_double_tap));
+        }
+    }
+
+    @Override
+    int getActivityType() {
+        return ACTIVITY_TAP_TO_TONE;
+    }
+
+    @Override
+    protected void onDestroy() {
+        mMidiTapTester.removeTestListener(mTestListener);
+        closeMidiResources();
+        super.onDestroy();
+    }
+
+    private void setupMidi() {
+        // Setup MIDI
+        mMidiManager = (MidiManager) getSystemService(MIDI_SERVICE);
+        MidiDeviceInfo[] infos = mMidiManager.getDevices();
+
+        // Warn if old version of OboeTester found.
+        for (MidiDeviceInfo info : infos) {
+            Log.i(TAG, "MIDI info = " + info);
+            Bundle properties = info.getProperties();
+            String product = properties
+                    .getString(MidiDeviceInfo.PROPERTY_PRODUCT);
+            String manufacturer = properties
+                    .getString(MidiDeviceInfo.PROPERTY_MANUFACTURER);
+            if (OLD_PRODUCT_NAME.equals(product) && OLD_MANUFACTURER_NAME.equals(manufacturer)) {
+                showErrorToast("Please uninstall old version of OboeTester.");
+                break;
+            }
+        }
+
+        // Open the port now so that the MidiTapTester gets created.
+        for (MidiDeviceInfo info : infos) {
+            Bundle properties = info.getProperties();
+            String product = properties
+                    .getString(MidiDeviceInfo.PROPERTY_PRODUCT);
+            if (MidiTapTester.PRODUCT_NAME.equals(product)) {
+                String manufacturer = properties
+                        .getString(MidiDeviceInfo.PROPERTY_MANUFACTURER);
+                if (MidiTapTester.MANUFACTURER_NAME.equals(manufacturer)) {
+                    openPortTemporarily(info);
+                    break;
+                }
+            }
+        }
+    }
+
+    // These should only be set after mAudioMidiTester is set.
+    private void setSpinnerListeners() {
+        MidiDeviceInfo synthInfo = MidiTools.findDevice(mMidiManager, MidiTapTester.MANUFACTURER_NAME,
+                MidiTapTester.PRODUCT_NAME);
+        Log.i(TAG, "found tester virtual device info: " + synthInfo);
+        int portIndex = 0;
+        mPortSelector = new MidiOutputPortConnectionSelector(mMidiManager, this,
+                R.id.spinner_synth_sender, synthInfo, portIndex);
+        mPortSelector.setConnectedListener(new MyPortsConnectedListener());
+
+    }
+
+    private class MyNoteListener implements NoteListener {
+        @Override
+        public void onNoteOn(final int pitch) {
+            runOnUiThread(() -> {
+                trigger();
+                mStreamContexts.get(0).configurationView.setStatusText("MIDI pitch = " + pitch);
+            });
+        }
+    }
+
+    private void openPortTemporarily(final MidiDeviceInfo info) {
+        Log.i(TAG, "MIDI openPort() info = " + info);
+        mMidiManager.openDevice(info, device -> {
+            if (device == null) {
+                Log.e(TAG, "could not open device " + info);
+            } else {
+                mInputPort = device.openInputPort(0);
+                Log.i(TAG, "opened MIDI port = " + mInputPort + " on " + info);
+                mMidiTapTester = MidiTapTester.getInstanceOrNull();
+                if (mMidiTapTester == null) {
+                    Log.e(TAG, "MidiTapTester Service was not created! info = " + info);
+                    showErrorToast("MidiTapTester Service was not created!");
+                } else {
+                    Log.i(TAG, "openPort() mMidiTapTester = " + mMidiTapTester);
+                    // Now that we have created the MidiTapTester, close the port so we can
+                    // open it later.
+                    try {
+                        mInputPort.close();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                    mMidiTapTester.addTestListener(mTestListener);
+                    setSpinnerListeners();
+                }
+            }
+        }, new Handler(Looper.getMainLooper())
+        );
+    }
+
+    // TODO Listen to the synth server
+    // for open/close events and then disable/enable the spinner.
+    private class MyPortsConnectedListener
+            implements MidiPortConnector.OnPortsConnectedListener {
+        @Override
+        public void onPortsConnected(final MidiDevice.MidiConnection connection) {
+            Log.i(TAG, "onPortsConnected, connection = " + connection);
+            runOnUiThread(() -> {
+                if (connection == null) {
+                    Toast.makeText(TapToToneActivity.this,
+                            R.string.error_port_busy, Toast.LENGTH_LONG)
+                            .show();
+                    mPortSelector.clearSelection();
+                } else {
+                    Toast.makeText(TapToToneActivity.this,
+                            R.string.port_open_ok, Toast.LENGTH_LONG)
+                            .show();
+                }
+            });
+        }
+    }
+
+    private void closeMidiResources() {
+        if (mPortSelector != null) {
+            mPortSelector.close();
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate the menu; this adds items to the action bar if it is present.
+        getMenuInflater().inflate(R.menu.menu_main, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        // Handle action bar item clicks here. The action bar will
+        // automatically handle clicks on the Home/Up button, so long
+        // as you specify a parent activity in AndroidManifest.xml.
+        int id = item.getItemId();
+
+        //noinspection SimplifiableIfStatement
+        if (id == R.id.action_settings) {
+            return true;
+        }
+
+        return super.onOptionsItemSelected(item);
+    }
+
+    public void startTest(View view) {
+        try {
+            openAudio();
+        } catch (IOException e) {
+            e.printStackTrace();
+            showErrorToast("Open audio failed!");
+            return;
+        }
+        try {
+            super.startAudio();
+            mTapToToneTester.resetLatency();
+            mTapToToneTester.start();
+            updateButtons(true);
+        } catch (IOException e) {
+            e.printStackTrace();
+            showErrorToast("Start audio failed! " + e.getMessage());
+            return;
+        }
+    }
+
+    public void stopTest(View view) {
+        mTapToToneTester.stop();
+        stopAudio();
+        closeAudio();
+        updateButtons(false);
+    }
+}
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneTester.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneTester.java
new file mode 100644
index 0000000..bd93153
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneTester.java
@@ -0,0 +1,201 @@
+package com.mobileer.oboetester;
+
+import android.app.Activity;
+import android.widget.TextView;
+
+import java.io.IOException;
+
+/**
+ * Measure tap-to-tone latency by and update the waveform display.
+ */
+public class TapToToneTester {
+
+    private static final float MAX_TOUCH_LATENCY = 0.200f;
+    private static final float MAX_OUTPUT_LATENCY = 1.200f;
+    private static final float ANALYSIS_TIME_MARGIN = 0.500f;
+
+    private static final float ANALYSIS_TIME_DELAY = MAX_OUTPUT_LATENCY;
+    private static final float ANALYSIS_TIME_TOTAL = MAX_TOUCH_LATENCY + MAX_OUTPUT_LATENCY;
+    private static final int ANALYSIS_SAMPLE_RATE = 48000; // need not match output rate
+
+    private final boolean mRecordEnabled = true;
+    private final AudioRecordThread mRecorder;
+    private final TapLatencyAnalyser mTapLatencyAnalyser;
+
+    private final Activity mActivity;
+    private final WaveformView mWaveformView;
+    private final TextView mResultView;
+
+    private final String mTapInstructions;
+    private float mAnalysisTimeMargin = ANALYSIS_TIME_MARGIN;
+
+    private boolean mArmed = true;
+
+    // Stats for latency
+    private int mMeasurementCount;
+    private int mLatencySumSamples;
+    private int mLatencyMin;
+    private int mLatencyMax;
+
+    public static class TestResult {
+        public float[] samples;
+        public float[] filtered;
+        public int frameRate;
+        public TapLatencyAnalyser.TapLatencyEvent[] events;
+    }
+
+    public TapToToneTester(Activity activity, String tapInstructions) {
+        mActivity = activity;
+        mTapInstructions = tapInstructions;
+        mResultView = (TextView) activity.findViewById(R.id.resultView);
+        mWaveformView = (WaveformView) activity.findViewById(R.id.waveview_audio);
+        mWaveformView.setEnabled(false);
+
+        if (mRecordEnabled) {
+            float analysisTimeMax = ANALYSIS_TIME_TOTAL + mAnalysisTimeMargin;
+            mRecorder = new AudioRecordThread(ANALYSIS_SAMPLE_RATE,
+                    1,
+                    (int) (analysisTimeMax * ANALYSIS_SAMPLE_RATE));
+        }
+        mTapLatencyAnalyser = new TapLatencyAnalyser();
+    }
+
+    public void start() throws IOException {
+        if (mRecordEnabled) {
+            mRecorder.startAudio();
+            mWaveformView.setEnabled(true);
+        }
+    }
+
+    public void stop() {
+        if (mRecordEnabled) {
+            mRecorder.stopAudio();
+            mWaveformView.setEnabled(false);
+        }
+    }
+
+    /**
+     * @return true if ready to process a tap, false if already triggered
+     */
+    public boolean isArmed() {
+        return mArmed;
+    }
+
+    public void setArmed(boolean armed) {
+        this.mArmed = armed;
+    }
+
+    public void analyzeLater(String message) {
+        showPendingStatus(message);
+        Runnable task = this::analyseAndShowResults;
+        scheduleTaskWhenDone(task);
+        mArmed = false;
+    }
+
+    private void showPendingStatus(final String message) {
+        mWaveformView.post(() -> {
+            mWaveformView.setMessage(message);
+            mWaveformView.clearSampleData();
+            mWaveformView.invalidate();
+        });
+    }
+
+    private void scheduleTaskWhenDone(Runnable task) {
+        if (mRecordEnabled) {
+            // schedule an analysis to start in the near future
+            int numSamples = (int) (mRecorder.getSampleRate() * ANALYSIS_TIME_DELAY);
+            mRecorder.scheduleTask(numSamples, task);
+        }
+    }
+
+    private void analyseAndShowResults() {
+        TestResult result = analyzeCapturedAudio();
+        if (result != null) {
+            showTestResults(result);
+        }
+    }
+
+    public TestResult analyzeCapturedAudio() {
+        if (!mRecordEnabled) return null;
+        int numSamples = (int) (mRecorder.getSampleRate() * ANALYSIS_TIME_TOTAL);
+        float[] buffer = new float[numSamples];
+        mRecorder.setCaptureEnabled(false); // TODO wait for it to settle
+        int numRead = mRecorder.readMostRecent(buffer);
+
+        TestResult result = new TestResult();
+        result.samples = buffer;
+        result.frameRate = mRecorder.getSampleRate();
+        result.events = mTapLatencyAnalyser.analyze(buffer, 0, numRead);
+        result.filtered = mTapLatencyAnalyser.getFilteredBuffer();
+        mRecorder.setCaptureEnabled(true);
+        return result;
+    }
+
+    public void resetLatency() {
+        mMeasurementCount = 0;
+        mLatencySumSamples = 0;
+        mLatencyMin = Integer.MAX_VALUE;
+        mLatencyMax = 0;
+        showTestResults(null);
+    }
+
+    // Runs on UI thread.
+    public void showTestResults(TestResult result) {
+        String text;
+        mWaveformView.setMessage(null);
+        if (result == null) {
+            text = mTapInstructions;
+            mWaveformView.clearSampleData();
+        } else {
+            // Show edges detected.
+            if (result.events.length == 0) {
+                mWaveformView.setCursorData(null);
+            } else {
+                int numEdges = Math.min(8, result.events.length);
+                int[] cursors = new int[numEdges];
+                for (int i = 0; i < numEdges; i++) {
+                    cursors[i] = result.events[i].sampleIndex;
+                }
+                mWaveformView.setCursorData(cursors);
+            }
+            // Did we get a good measurement?
+            if (result.events.length < 2) {
+                text = "Not enough edges. Use fingernail.\n";
+            } else if (result.events.length > 2) {
+                text = "Too many edges.\n";
+            } else {
+                int latencySamples = result.events[1].sampleIndex - result.events[0].sampleIndex;
+                mLatencySumSamples += latencySamples;
+                mMeasurementCount++;
+
+                int latencyMillis = 1000 * latencySamples / result.frameRate;
+                if (mLatencyMin > latencyMillis) {
+                    mLatencyMin = latencyMillis;
+                }
+                if (mLatencyMax < latencyMillis) {
+                    mLatencyMax = latencyMillis;
+                }
+
+                text = String.format("tap-to-tone latency = %3d msec\n", latencyMillis);
+            }
+            mWaveformView.setSampleData(result.filtered);
+        }
+
+        if (mMeasurementCount > 0) {
+            int averageLatencySamples = mLatencySumSamples / mMeasurementCount;
+            int averageLatencyMillis = 1000 * averageLatencySamples / result.frameRate;
+            final String plural = (mMeasurementCount == 1) ? "test" : "tests";
+            text = text + String.format("min = %3d, avg = %3d, max = %3d, %d %s",
+                    mLatencyMin, averageLatencyMillis, mLatencyMax, mMeasurementCount, plural);
+        }
+        final String postText = text;
+        mWaveformView.post(new Runnable() {
+            public void run() {
+                mResultView.setText(postText);
+                mWaveformView.postInvalidate();
+            }
+        });
+
+        mArmed = true;
+    }
+}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestAudioActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java
similarity index 66%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestAudioActivity.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java
index a68eb3a..f61873f 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestAudioActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java
@@ -14,15 +14,23 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
+import android.Manifest;
 import android.app.Activity;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.support.annotation.NonNull;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
 import android.util.Log;
 import android.view.View;
 import android.view.WindowManager;
@@ -30,7 +38,11 @@
 import android.widget.CheckBox;
 import android.widget.Toast;
 
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
 import java.util.ArrayList;
 
 /**
@@ -40,6 +52,7 @@
     public static final String TAG = "OboeTester";
 
     protected static final int FADER_PROGRESS_MAX = 1000;
+    private static final int INTENT_TEST_DELAY_MILLIS = 1100;
 
     public static final int AUDIO_STATE_OPEN = 0;
     public static final int AUDIO_STATE_STARTED = 1;
@@ -63,9 +76,10 @@
     public static final int ACTIVITY_TEST_DISCONNECT = 7;
     public static final int ACTIVITY_DATA_PATHS = 8;
 
+    private static final int MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE = 1001;
+
     private int mAudioState = AUDIO_STATE_CLOSED;
-    protected String audioManagerSampleRate;
-    protected int audioManagerFramesPerBurst;
+
     protected ArrayList<StreamContext> mStreamContexts;
     private Button mOpenButton;
     private Button mStartButton;
@@ -75,8 +89,13 @@
     private MyStreamSniffer mStreamSniffer;
     private CheckBox mCallbackReturnStopBox;
     private int mSampleRate;
-    private boolean mScoStarted;
     private int mSingleTestIndex = -1;
+    private static boolean mBackgroundEnabled;
+
+    protected Bundle mBundleFromIntent;
+    protected boolean mTestRunningByIntent;
+    protected String mResultFileName;
+    private String mTestResults;
 
     public String getTestName() {
         return "TestAudio";
@@ -149,6 +168,14 @@
 
     }
 
+    public static void setBackgroundEnabled(boolean enabled) {
+        mBackgroundEnabled = enabled;
+    }
+
+    public static boolean isBackgroundEnabled() {
+        return mBackgroundEnabled;
+    }
+
     public void onStreamClosed() {
     }
 
@@ -162,6 +189,17 @@
         super.onCreate(savedInstanceState);
         inflateActivity();
         findAudioCommon();
+
+        mBundleFromIntent = getIntent().getExtras();
+    }
+
+    @Override
+    public void onNewIntent(Intent intent) {
+        mBundleFromIntent = intent.getExtras();
+    }
+
+    public boolean isTestConfiguredUsingBundle() {
+        return mBundleFromIntent != null;
     }
 
     public void hideSettingsViews() {
@@ -177,6 +215,7 @@
     public void setSingleTestIndex(int testIndex) {
         mSingleTestIndex = testIndex;
     }
+
     public int getSingleTestIndex() {
         return mSingleTestIndex;
     }
@@ -192,14 +231,73 @@
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+        if (mBundleFromIntent != null) {
+            processBundleFromIntent();
+        }
+    }
+
+    private void setVolumeFromIntent() {
+        float normalizedVolume = IntentBasedTestSupport.getNormalizedVolumeFromBundle(mBundleFromIntent);
+        if (normalizedVolume >= 0.0) {
+            int streamType = IntentBasedTestSupport.getVolumeStreamTypeFromBundle(mBundleFromIntent);
+            AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+            int maxVolume = audioManager.getStreamMaxVolume(streamType);
+            int requestedVolume = (int) (maxVolume * normalizedVolume);
+            audioManager.setStreamVolume(streamType, requestedVolume, 0);
+        }
+    }
+
+    private void processBundleFromIntent() {
+        if (mTestRunningByIntent) {
+            return;
+        }
+
+        // Delay the test start to avoid race conditions. See Oboe Issue #1533
+        mTestRunningByIntent = true;
+        Handler handler = new Handler(Looper.getMainLooper()); // UI thread
+        handler.postDelayed(new DelayedTestByIntentRunnable(),
+                INTENT_TEST_DELAY_MILLIS); // Delay long enough to get past the onStop() call!
+
+    }
+
+    private class DelayedTestByIntentRunnable implements Runnable {
+        @Override
+        public void run() {
+            try {
+                mResultFileName = mBundleFromIntent.getString(IntentBasedTestSupport.KEY_FILE_NAME);
+                setVolumeFromIntent();
+                startTestUsingBundle();
+            } catch( Exception e) {
+                showErrorToast(e.getMessage());
+            }
+        }
+    }
+
+    public void startTestUsingBundle() {
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+    }
+
+    @Override
     protected void onStop() {
-        Log.i(TAG, "onStop() called so stop the test =========================");
-        onStopTest();
+        if (!isBackgroundEnabled()) {
+            Log.i(TAG, "onStop() called so stop the test =========================");
+            onStopTest();
+        }
         super.onStop();
     }
 
     @Override
     protected void onDestroy() {
+        if (isBackgroundEnabled()) {
+            Log.i(TAG, "onDestroy() called so stop the test =========================");
+            onStopTest();
+        }
         mAudioState = AUDIO_STATE_CLOSED;
         super.onDestroy();
     }
@@ -223,6 +321,14 @@
         }
     }
 
+    private void applyConfigurationViewsToModels() {
+        for (StreamContext streamContext : mStreamContexts) {
+            if (streamContext.configurationView != null) {
+                streamContext.configurationView.applyToModel(streamContext.tester.requestedConfiguration);
+            }
+        }
+    }
+
     abstract boolean isOutput();
 
     public void clearStreamContexts() {
@@ -240,14 +346,11 @@
         }
         if (streamContext.configurationView != null) {
             streamContext.configurationView.setOutput(true);
-            streamContext.configurationView.setRequestedConfiguration(streamContext.tester.requestedConfiguration);
-            streamContext.configurationView.setActualConfiguration(streamContext.tester.actualConfiguration);
         }
         mStreamContexts.add(streamContext);
         return streamContext;
     }
 
-
     public AudioOutputTester addAudioOutputTester() {
         StreamContext streamContext = addOutputStreamContext();
         return (AudioOutputTester) streamContext.tester;
@@ -264,8 +367,6 @@
         }
         if (streamContext.configurationView != null) {
             streamContext.configurationView.setOutput(false);
-            streamContext.configurationView.setRequestedConfiguration(streamContext.tester.requestedConfiguration);
-            streamContext.configurationView.setActualConfiguration(streamContext.tester.actualConfiguration);
         }
         streamContext.tester = AudioInputTester.getInstance();
         mStreamContexts.add(streamContext);
@@ -280,7 +381,7 @@
     void updateStreamConfigurationViews() {
         for (StreamContext streamContext : mStreamContexts) {
             if (streamContext.configurationView != null) {
-                streamContext.configurationView.updateDisplay();
+                streamContext.configurationView.updateDisplay(streamContext.tester.actualConfiguration);
             }
         }
     }
@@ -311,8 +412,6 @@
         }
         mStreamContexts = new ArrayList<StreamContext>();
 
-        queryNativeAudioParameters();
-
         mCallbackReturnStopBox = (CheckBox) findViewById(R.id.callbackReturnStop);
         if (mCallbackReturnStopBox != null) {
             mCallbackReturnStopBox.setOnClickListener(new View.OnClickListener() {
@@ -327,17 +426,21 @@
         mStreamSniffer = new MyStreamSniffer();
     }
 
-    private void queryNativeAudioParameters() {
-        AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-        audioManagerSampleRate = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
-        String audioManagerFramesPerBurstText = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
-        audioManagerFramesPerBurst = Integer.parseInt(audioManagerFramesPerBurstText);
+    private void updateNativeAudioParameters() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+            String text = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
+            int audioManagerSampleRate = Integer.parseInt(text);
+            text = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
+            int audioManagerFramesPerBurst = Integer.parseInt(text);
+            setDefaultAudioValues(audioManagerSampleRate, audioManagerFramesPerBurst);
+        }
     }
 
-    abstract public void setupEffects(int sessionId);
-
     protected void showErrorToast(String message) {
-        showToast("Error: " + message);
+        String text = "Error: " + message;
+        Log.e(TAG, text);
+        showToast(text);
     }
 
     protected void showToast(final String message) {
@@ -394,10 +497,16 @@
     public int getSampleRate() {
         return mSampleRate;
     }
-    
+
     public void openAudio() throws IOException {
         closeAudio();
 
+        updateNativeAudioParameters();
+
+        if (!isTestConfiguredUsingBundle()) {
+            applyConfigurationViewsToModels();
+        }
+
         int sampleRate = 0;
 
         // Open output streams then open input streams.
@@ -431,7 +540,8 @@
     boolean isScoDevice(int deviceId) {
         if (deviceId == 0) return false; // Unspecified
         AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-        final AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
+        final AudioDeviceInfo[] devices = audioManager.getDevices(
+                AudioManager.GET_DEVICES_INPUTS | AudioManager.GET_DEVICES_OUTPUTS);
         for (AudioDeviceInfo device : devices) {
             if (device.getId() == deviceId) {
                 return device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO;
@@ -443,35 +553,39 @@
     private void openStreamContext(StreamContext streamContext) throws IOException {
         StreamConfiguration requestedConfig = streamContext.tester.requestedConfiguration;
         StreamConfiguration actualConfig = streamContext.tester.actualConfiguration;
-        requestedConfig.setFramesPerBurst(audioManagerFramesPerBurst);
-
-        // Start Bluetooth SCO if needed.
-        if (isScoDevice(requestedConfig.getDeviceId()) && !mScoStarted) {
-            startBluetoothSco();
-            mScoStarted = true;
-        }
 
         streamContext.tester.open(); // OPEN the stream
 
         mSampleRate = actualConfig.getSampleRate();
         mAudioState = AUDIO_STATE_OPEN;
         int sessionId = actualConfig.getSessionId();
-        if (sessionId > 0) {
-            setupEffects(sessionId);
-        }
         if (streamContext.configurationView != null) {
-            streamContext.configurationView.updateDisplay();
+            if (sessionId > 0) {
+                try {
+                    streamContext.configurationView.setupEffects(sessionId);
+                } catch (Exception e) {
+                    showErrorToast(e.getMessage());
+                }
+            }
+            streamContext.configurationView.updateDisplay(streamContext.tester.actualConfiguration);
         }
     }
 
     // Native methods
     private native int startNative();
+
     private native int pauseNative();
+
     private native int stopNative();
+
     protected native void setActivityType(int activityType);
+
     private native int getFramesPerCallback();
 
+    private static native void setDefaultAudioValues(int audioManagerSampleRate, int audioManagerFramesPerBurst);
+
     public void startAudio() throws IOException {
+        Log.i(TAG, "startAudio() called =========================");
         int result = startNative();
         if (result < 0) {
             showErrorToast("Start failed with " + result);
@@ -480,7 +594,7 @@
             for (StreamContext streamContext : mStreamContexts) {
                 StreamConfigurationView configView = streamContext.configurationView;
                 if (configView != null) {
-                    configView.updateDisplay();
+                    configView.updateDisplay(streamContext.tester.actualConfiguration);
                 }
             }
             mAudioState = AUDIO_STATE_STARTED;
@@ -512,7 +626,11 @@
         }
     }
 
-    public void runTest() {}
+    public void runTest() {
+    }
+
+    public void saveIntentLog() {
+    }
 
     // This should only be called from UI events such as onStop or a button press.
     public void onStopTest() {
@@ -552,11 +670,6 @@
             }
         }
 
-        if (mScoStarted) {
-            stopBluetoothSco();
-            mScoStarted = false;
-        }
-
         mAudioState = AUDIO_STATE_CLOSED;
         updateEnabledWidgets();
     }
@@ -571,4 +684,97 @@
         myAudioMgr.stopBluetoothSco();
     }
 
+    @Override
+    public void onRequestPermissionsResult(int requestCode,
+                                           String[] permissions,
+                                           int[] grantResults) {
+
+        if (MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE != requestCode) {
+            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+            return;
+        }
+        // If request is cancelled, the result arrays are empty.
+        if (grantResults.length > 0
+                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+            writeTestResult(mTestResults);
+        } else {
+            showToast("Writing external storage needed for test results.");
+        }
+    }
+
+    @NonNull
+    protected String getCommonTestReport() {
+        StringBuffer report = new StringBuffer();
+        // Add some extra information for the remote tester.
+        report.append("build.fingerprint = " + Build.FINGERPRINT + "\n");
+        try {
+            PackageInfo pinfo = getPackageManager().getPackageInfo(getPackageName(), 0);
+            report.append(String.format("test.version = %s\n", pinfo.versionName));
+            report.append(String.format("test.version.code = %d\n", pinfo.versionCode));
+        } catch (PackageManager.NameNotFoundException e) {
+        }
+        report.append("time.millis = " + System.currentTimeMillis() + "\n");
+
+        if (mStreamContexts.size() == 0) {
+            report.append("ERROR: no active streams" + "\n");
+        } else {
+            StreamContext streamContext = mStreamContexts.get(0);
+            AudioStreamTester streamTester = streamContext.tester;
+            report.append(streamTester.actualConfiguration.dump());
+            AudioStreamBase.StreamStatus status = streamTester.getCurrentAudioStream().getStreamStatus();
+            AudioStreamBase.DoubleStatistics latencyStatistics =
+                    streamTester.getCurrentAudioStream().getLatencyStatistics();
+            int framesPerBurst = streamTester.getCurrentAudioStream().getFramesPerBurst();
+            status.framesPerCallback = getFramesPerCallback();
+            report.append("timestamp.latency = " + latencyStatistics.dump() + "\n");
+            report.append(status.dump(framesPerBurst));
+        }
+
+        return report.toString();
+    }
+
+    void writeTestResultIfPermitted(String resultString) {
+        // Here, thisActivity is the current activity
+        if (ContextCompat.checkSelfPermission(this,
+                Manifest.permission.WRITE_EXTERNAL_STORAGE)
+                != PackageManager.PERMISSION_GRANTED) {
+            mTestResults = resultString;
+            ActivityCompat.requestPermissions(this,
+                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
+                    MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE);
+        } else {
+            // Permission has already been granted
+            writeTestResult(resultString);
+        }
+    }
+
+    void maybeWriteTestResult(String resultString) {
+        if (mResultFileName != null) {
+            writeTestResultIfPermitted(resultString);
+        };
+    }
+
+    // Run this in a background thread.
+    void writeTestResult(String resultString) {
+        File resultFile = new File(mResultFileName);
+        Writer writer = null;
+        try {
+            writer = new OutputStreamWriter(new FileOutputStream(resultFile));
+            writer.write(resultString);
+        } catch (
+                IOException e) {
+            e.printStackTrace();
+            showErrorToast(" writing result file. " + e.getMessage());
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        mResultFileName = null;
+    }
 }
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestDataPathsActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java
similarity index 64%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestDataPathsActivity.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java
index 9c6676c..b0aea93 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestDataPathsActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java
@@ -14,15 +14,24 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
+
+import static com.mobileer.oboetester.IntentBasedTestSupport.configureStreamsFromBundle;
 
 import android.app.Activity;
 import android.content.Context;
 import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.NonNull;
+import android.util.Log;
+import android.widget.CheckBox;
 
-import com.google.sample.audio_device.AudioDeviceInfoConverter;
+import com.mobileer.audio_device.AudioDeviceInfoConverter;
+
+import java.lang.reflect.Field;
 
 /**
  * Play a recognizable tone on each channel of each speaker device
@@ -40,17 +49,25 @@
  */
 public class TestDataPathsActivity  extends BaseAutoGlitchActivity {
 
+    public static final String KEY_USE_INPUT_PRESETS = "use_input_presets";
+    public static final boolean VALUE_DEFAULT_USE_INPUT_PRESETS = true;
+
+    public static final String KEY_USE_INPUT_DEVICES = "use_input_devices";
+    public static final boolean VALUE_DEFAULT_USE_INPUT_DEVICES = true;
+
+    public static final String KEY_USE_OUTPUT_DEVICES = "use_output_devices";
+    public static final boolean VALUE_DEFAULT_USE_OUTPUT_DEVICES = true;
+
+    public static final String KEY_SINGLE_TEST_INDEX = "single_test_index";
+    public static final int VALUE_DEFAULT_SINGLE_TEST_INDEX = -1;
+
     public static final int DURATION_SECONDS = 3;
     private final static double MIN_REQUIRED_MAGNITUDE = 0.001;
     private final static double MAX_SINE_FREQUENCY = 1000.0;
     private final static int TYPICAL_SAMPLE_RATE = 48000;
     private final static double FRAMES_PER_CYCLE = TYPICAL_SAMPLE_RATE / MAX_SINE_FREQUENCY;
     private final static double PHASE_PER_BIN = 2.0 * Math.PI / FRAMES_PER_CYCLE;
-    private final static double MAX_ALLOWED_JITTER = 0.5 * PHASE_PER_BIN;
-    // Start by failing then let good results drive us into a pass value.
-    private final static double INITIAL_JITTER = 2.0 * MAX_ALLOWED_JITTER;
-    // A coefficient of 0.0 is no filtering. 0.9999 is extreme low pass.
-    private final static double JITTER_FILTER_COEFFICIENT = 0.8;
+    private final static double MAX_ALLOWED_JITTER = 2.0 * PHASE_PER_BIN;
     private final static String MAGNITUDE_FORMAT = "%7.5f";
 
     final int TYPE_BUILTIN_SPEAKER_SAFE = 0x18; // API 30
@@ -59,9 +76,13 @@
     private double mMaxMagnitude;
     private int    mPhaseCount;
     private double mPhase;
-    private double mPhaseJitter;
+    private double mPhaseErrorSum;
+    private double mPhaseErrorCount;
 
     AudioManager   mAudioManager;
+    private CheckBox mCheckBoxInputPresets;
+    private CheckBox mCheckBoxInputDevices;
+    private CheckBox mCheckBoxOutputDevices;
 
     private static final int[] INPUT_PRESETS = {
             // VOICE_RECOGNITION gets tested in testInputs()
@@ -69,11 +90,39 @@
             StreamConfiguration.INPUT_PRESET_GENERIC,
             StreamConfiguration.INPUT_PRESET_CAMCORDER,
             // TODO Resolve issue with echo cancellation killing the signal.
-            // TODO StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION,
+            StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION,
             StreamConfiguration.INPUT_PRESET_UNPROCESSED,
             StreamConfiguration.INPUT_PRESET_VOICE_PERFORMANCE,
     };
 
+    @NonNull
+    public static String comparePassedField(String prefix, Object failed, Object passed, String name) {
+        try {
+            Field field = failed.getClass().getField(name);
+            int failedValue = field.getInt(failed);
+            int passedValue = field.getInt(passed);
+            return (failedValue == passedValue) ? ""
+                :  (prefix + " " + name + ": passed = " + passedValue + ", failed = " + failedValue + "\n");
+        } catch (NoSuchFieldException e) {
+            return "ERROR - no such field  " + name;
+        } catch (IllegalAccessException e) {
+            return "ERROR - cannot access  " + name;
+        }
+    }
+
+    public static double calculatePhaseError(double p1, double p2) {
+        double diff = Math.abs(p1 - p2);
+        // Wrap around the circle.
+        while (diff > (2 * Math.PI)) {
+            diff -= (2 * Math.PI);
+        }
+        // A phase error close to 2*PI is actually a small phase error.
+        if (diff > Math.PI) {
+            diff = (2 * Math.PI) - diff;
+        }
+        return diff;
+    }
+
     // Periodically query for magnitude and phase from the native detector.
     protected class DataPathSniffer extends NativeSniffer {
 
@@ -87,7 +136,8 @@
             mMaxMagnitude = -1.0;
             mPhaseCount = 0;
             mPhase = 0.0;
-            mPhaseJitter = INITIAL_JITTER;
+            mPhaseErrorSum = 0.0;
+            mPhaseErrorCount = 0;
             super.startSniffer();
         }
 
@@ -95,14 +145,21 @@
         public void run() {
             mMagnitude = getMagnitude();
             mMaxMagnitude = getMaxMagnitude();
+            Log.d(TAG, String.format("magnitude = %7.4f, maxMagnitude = %7.4f",
+                    mMagnitude, mMaxMagnitude));
             // Only look at the phase if we have a signal.
             if (mMagnitude >= MIN_REQUIRED_MAGNITUDE) {
                 double phase = getPhase();
-                if (mPhaseCount > 3) {
-                    double diff = Math.abs(phase - mPhase);
+                // Wait for the analyzer to get a lock on the signal.
+                // Arbitrary number of phase measurements before we start measuring jitter.
+                final int kMinPhaseMeasurementsRequired = 4;
+                if (mPhaseCount >= kMinPhaseMeasurementsRequired) {
+                    double phaseError = calculatePhaseError(phase, mPhase);
                     // low pass filter
-                    mPhaseJitter = (mPhaseJitter * JITTER_FILTER_COEFFICIENT)
-                            + ((diff * (1.0 - JITTER_FILTER_COEFFICIENT)));
+                    mPhaseErrorSum += phaseError;
+                    mPhaseErrorCount++;
+                    Log.d(TAG, String.format("phase = %7.4f, diff = %7.4f, jitter = %7.4f",
+                            phase, phaseError, getAveragePhaseError()));
                 }
                 mPhase = phase;
                 mPhaseCount++;
@@ -116,7 +173,8 @@
                     "magnitude = " + getMagnitudeText(mMagnitude)
                     + ", max = " + getMagnitudeText(mMaxMagnitude)
                     + "\nphase = " + getMagnitudeText(mPhase)
-                    + ", jitter = " + getMagnitudeText(mPhaseJitter)
+                    + ", jitter = " + getJitterText()
+                    + ", #" + mPhaseCount
                     + "\n");
             return message.toString();
         }
@@ -124,15 +182,20 @@
         @Override
         public String getShortReport() {
             return "maxMag = " + getMagnitudeText(mMaxMagnitude)
-                    + ", jitter = " + getMagnitudeText(mPhaseJitter);
+                    + ", jitter = " + getJitterText();
         }
 
         @Override
         public void updateStatusText() {
             mLastGlitchReport = getCurrentStatusReport();
-            setAnalyzerText(mLastGlitchReport);
+            runOnUiThread(() -> {
+                setAnalyzerText(mLastGlitchReport);
+            });
         }
+    }
 
+    private String getJitterText() {
+        return isPhaseJitterValid() ? getMagnitudeText(getAveragePhaseError()) : "?";
     }
 
     @Override
@@ -153,6 +216,9 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        mCheckBoxInputPresets = (CheckBox)findViewById(R.id.checkbox_paths_input_presets);
+        mCheckBoxInputDevices = (CheckBox)findViewById(R.id.checkbox_paths_input_devices);
+        mCheckBoxOutputDevices = (CheckBox)findViewById(R.id.checkbox_paths_output_devices);
     }
 
     @Override
@@ -165,7 +231,7 @@
         return ACTIVITY_DATA_PATHS;
     }
 
-    String getMagnitudeText(double value) {
+    static String getMagnitudeText(double value) {
         return String.format(MAGNITUDE_FORMAT, value);
     }
 
@@ -184,12 +250,16 @@
         StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
         StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration;
         StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration;
-        // No point running the test if we don't get the sharing mode we requested.
-        if (actualInConfig.isMMap() != requestedInConfig.isMMap()
-                || actualOutConfig.isMMap() != requestedOutConfig.isMMap()) {
-            log("Did not get requested MMap stream");
+        // No point running the test if we don't get the data path we requested.
+        if (actualInConfig.isMMap() != requestedInConfig.isMMap()) {
+            log("Did not get requested MMap input stream");
             why += "mmap";
-        }        // Did we request a device and not get that device?
+        }
+        if (actualOutConfig.isMMap() != requestedOutConfig.isMMap()) {
+            log("Did not get requested MMap output stream");
+            why += "mmap";
+        }
+        // Did we request a device and not get that device?
         if (requestedInConfig.getDeviceId() != 0
                 && (requestedInConfig.getDeviceId() != actualInConfig.getDeviceId())) {
             why += ", inDev(" + requestedInConfig.getDeviceId()
@@ -209,7 +279,9 @@
 
     @Override
     protected boolean isFinishedEarly() {
-        return (mMaxMagnitude > MIN_REQUIRED_MAGNITUDE) && (mPhaseJitter < MAX_ALLOWED_JITTER);
+        return (mMaxMagnitude > MIN_REQUIRED_MAGNITUDE)
+                && (getAveragePhaseError() < MAX_ALLOWED_JITTER)
+                && isPhaseJitterValid();
     }
 
     // @return reasons for failure of empty string
@@ -220,26 +292,39 @@
         StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
         StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration;
         StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration;
-        boolean passed = true;
         if (mMaxMagnitude <= MIN_REQUIRED_MAGNITUDE) {
             why += ", mag";
         }
-        if (mPhaseJitter > MAX_ALLOWED_JITTER) {
-            why += ", jitter";
+        if (!isPhaseJitterValid()) {
+            why += ", jitterUnknown";
+        } else if (getAveragePhaseError() > MAX_ALLOWED_JITTER) {
+            why += ", jitterHigh";
         }
         return why;
     }
 
+    private double getAveragePhaseError() {
+        // If we have no measurements then return maximum possible phase jitter
+        // to avoid dividing by zero.
+        return (mPhaseErrorCount > 0) ? (mPhaseErrorSum / mPhaseErrorCount) : Math.PI;
+    }
+
+    private boolean isPhaseJitterValid() {
+        // Arbitrary number of measurements to be considered valid.
+        final int kMinPhaseErrorCount = 5;
+        return mPhaseErrorCount >= kMinPhaseErrorCount;
+    }
+
     String getOneLineSummary() {
         StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration;
         StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration;
         return "#" + mAutomatedTestRunner.getTestCount()
                 + ", IN" + (actualInConfig.isMMap() ? "-M" : "-L")
                 + " D=" + actualInConfig.getDeviceId()
-                + ", ch=" + actualInConfig.getChannelCount() + "[" + getInputChannel() + "]"
+                + ", ch=" + channelText(getInputChannel(), actualInConfig.getChannelCount())
                 + ", OUT" + (actualOutConfig.isMMap() ? "-M" : "-L")
-                + " D=" + (actualOutConfig.isMMap() ? "-M" : "-L")
-                + ", ch=" + actualOutConfig.getChannelCount() + "[" + getOutputChannel() + "]"
+                + " D=" + actualOutConfig.getDeviceId()
+                + ", ch=" + channelText(getOutputChannel(), actualOutConfig.getChannelCount())
                 + ", mag = " + getMagnitudeText(mMaxMagnitude);
     }
 
@@ -270,6 +355,15 @@
         setOutputChannel(outputChannel);
     }
 
+    private TestResult testConfigurationsAddMagJitter() throws InterruptedException {
+        TestResult testResult = testConfigurations();
+        if (testResult != null) {
+            testResult.addComment("mag = " + TestDataPathsActivity.getMagnitudeText(mMagnitude)
+                    + ", jitter = " + getJitterText());
+        }
+        return testResult;
+    }
+
     void testPresetCombo(int inputPreset,
                          int numInputChannels,
                          int inputChannel,
@@ -277,7 +371,6 @@
                          int outputChannel,
                          boolean mmapEnabled
                    ) throws InterruptedException {
-
         setupDeviceCombo(numInputChannels, inputChannel, numOutputChannels, outputChannel);
 
         StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration;
@@ -285,16 +378,19 @@
         requestedInConfig.setMMap(mmapEnabled);
 
         mMagnitude = -1.0;
-        int result = testConfigurations();
-        if (result != TEST_RESULT_SKIPPED) {
+        TestResult testResult = testConfigurationsAddMagJitter();
+        if (testResult != null) {
+            int result = testResult.result;
             String summary = getOneLineSummary()
                     + ", inPre = "
                     + StreamConfiguration.convertInputPresetToText(inputPreset)
                     + "\n";
             appendSummary(summary);
             if (result == TEST_RESULT_FAILED) {
-                if (inputPreset == StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION) {
-                    logFailed("Maybe sine wave blocked by Echo Cancellation!");
+                if (getMagnitude() < 0.000001) {
+                    testResult.addComment("The input is completely SILENT!");
+                } else if (inputPreset == StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION) {
+                    testResult.addComment("Maybe sine wave blocked by Echo Cancellation!");
                 }
             }
         }
@@ -315,6 +411,7 @@
     }
 
     void testPresetCombo(int inputPreset) throws InterruptedException {
+        setTestName("Test InPreset = " + StreamConfiguration.convertInputPresetToText(inputPreset));
         testPresetCombo(inputPreset, 1, 0, 1, 0);
     }
 
@@ -348,15 +445,20 @@
         requestedInConfig.setMMap(mmapEnabled);
 
         mMagnitude = -1.0;
-        int result = testConfigurations();
-        if (result != TEST_RESULT_SKIPPED) {
+        TestResult testResult = testConfigurationsAddMagJitter();
+        if (testResult != null) {
             appendSummary(getOneLineSummary() + "\n");
         }
     }
 
     void testInputDeviceCombo(int deviceId,
+                              int deviceType,
                               int numInputChannels,
                               int inputChannel) throws InterruptedException {
+
+        String typeString = AudioDeviceInfoConverter.typeToString(deviceType);
+        setTestName("Test InDev: #" + deviceId + " " + typeString
+                + "_" + inputChannel + "/" + numInputChannels);
         if (NativeEngine.isMMapSupported()) {
             testInputDeviceCombo(deviceId, numInputChannels, inputChannel, true);
         }
@@ -372,21 +474,22 @@
             log("----\n"
                     + AudioDeviceInfoConverter.toString(deviceInfo) + "\n");
             if (!deviceInfo.isSource()) continue; // FIXME log as error?!
-            if (deviceInfo.getType() == AudioDeviceInfo.TYPE_BUILTIN_MIC) {
+            int deviceType = deviceInfo.getType();
+            if (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC) {
                 int id = deviceInfo.getId();
                 int[] channelCounts = deviceInfo.getChannelCounts();
                 numTested++;
                 // Always test mono and stereo.
-                testInputDeviceCombo(id, 1, 0);
-                testInputDeviceCombo(id, 2, 0);
-                testInputDeviceCombo(id, 2, 1);
+                testInputDeviceCombo(id, deviceType, 1, 0);
+                testInputDeviceCombo(id, deviceType, 2, 0);
+                testInputDeviceCombo(id, deviceType, 2, 1);
                 if (channelCounts.length > 0) {
                     for (int numChannels : channelCounts) {
                         // Test higher channel counts.
                         if (numChannels > 2) {
                             log("numChannels = " + numChannels + "\n");
                             for (int channel = 0; channel < numChannels; channel++) {
-                                testInputDeviceCombo(id, numChannels, channel);
+                                testInputDeviceCombo(id, deviceType, numChannels, channel);
                             }
                         }
                     }
@@ -414,19 +517,20 @@
         requestedOutConfig.setMMap(mmapEnabled);
 
         mMagnitude = -1.0;
-        int result = testConfigurations();
-        if (result != TEST_RESULT_SKIPPED) {
+        TestResult testResult = testConfigurationsAddMagJitter();
+        if (testResult != null) {
+            int result = testResult.result;
             appendSummary(getOneLineSummary() + "\n");
             if (result == TEST_RESULT_FAILED) {
                 if (deviceType == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE
                         && numOutputChannels == 2
                         && outputChannel == 1) {
-                    logFailed("Maybe EARPIECE does not mix stereo to mono!");
+                    testResult.addComment("Maybe EARPIECE does not mix stereo to mono!");
                 }
                 if (deviceType == TYPE_BUILTIN_SPEAKER_SAFE
                         && numOutputChannels == 2
                         && outputChannel == 0) {
-                    logFailed("Maybe SPEAKER_SAFE blocked channel 0!");
+                    testResult.addComment("Maybe SPEAKER_SAFE dropped channel zero!");
                 }
             }
         }
@@ -436,6 +540,9 @@
                                int deviceType,
                                int numOutputChannels,
                                int outputChannel) throws InterruptedException {
+        String typeString = AudioDeviceInfoConverter.typeToString(deviceType);
+        setTestName("Test OutDev: #" + deviceId + " " + typeString
+                + "_" + outputChannel + "/" + numOutputChannels);
         if (NativeEngine.isMMapSupported()) {
             testOutputDeviceCombo(deviceId, deviceType, numOutputChannels, outputChannel, true);
         }
@@ -446,9 +553,10 @@
         log(text);
         appendSummary(text + "\n");
     }
+
     void logFailed(String text) {
         log(text);
-        appendFailedSummary(text + "\n");
+        logAnalysis(text + "\n");
     }
 
     void testOutputDevices() throws InterruptedException {
@@ -494,19 +602,65 @@
     @Override
     public void runTest() {
         try {
-            mDurationSeconds = DURATION_SECONDS;
-
+            logDeviceInfo();
             log("min.required.magnitude = " + MIN_REQUIRED_MAGNITUDE);
             log("max.allowed.jitter = " + MAX_ALLOWED_JITTER);
             log("test.gap.msec = " + mGapMillis);
+            
+            mTestResults.clear();
+            mDurationSeconds = DURATION_SECONDS;
 
-            testInputPresets();
-            testInputDevices();
-            testOutputDevices();
+            if (mCheckBoxInputPresets.isChecked()) {
+                runOnUiThread(() -> mCheckBoxInputPresets.setEnabled(false));
+                testInputPresets();
+            }
+            if (mCheckBoxInputDevices.isChecked()) {
+                runOnUiThread(() -> mCheckBoxInputDevices.setEnabled(false));
+                testInputDevices();
+            }
+            if (mCheckBoxOutputDevices.isChecked()) {
+                runOnUiThread(() -> mCheckBoxOutputDevices.setEnabled(false));
+                testOutputDevices();
+            }
+
+            analyzeTestResults();
+
+        } catch (InterruptedException e) {
+            analyzeTestResults();
         } catch (Exception e) {
             log(e.getMessage());
             showErrorToast(e.getMessage());
+        } finally {
+            runOnUiThread(() -> {
+                mCheckBoxInputPresets.setEnabled(true);
+                mCheckBoxInputDevices.setEnabled(true);
+                mCheckBoxOutputDevices.setEnabled(true);
+            });
         }
     }
 
+    @Override
+    public void startTestUsingBundle() {
+        StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration;
+        StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
+        configureStreamsFromBundle(mBundleFromIntent, requestedInConfig, requestedOutConfig);
+
+        boolean shouldUseInputPresets = mBundleFromIntent.getBoolean(KEY_USE_INPUT_PRESETS,
+                VALUE_DEFAULT_USE_INPUT_PRESETS);
+        boolean shouldUseInputDevices = mBundleFromIntent.getBoolean(KEY_USE_INPUT_DEVICES,
+                VALUE_DEFAULT_USE_INPUT_DEVICES);
+        boolean shouldUseOutputDevices = mBundleFromIntent.getBoolean(KEY_USE_OUTPUT_DEVICES,
+                VALUE_DEFAULT_USE_OUTPUT_DEVICES);
+        int singleTestIndex = mBundleFromIntent.getInt(KEY_SINGLE_TEST_INDEX,
+                VALUE_DEFAULT_SINGLE_TEST_INDEX);
+
+        runOnUiThread(() -> {
+            mCheckBoxInputPresets.setChecked(shouldUseInputPresets);
+            mCheckBoxInputDevices.setChecked(shouldUseInputDevices);
+            mCheckBoxOutputDevices.setChecked(shouldUseOutputDevices);
+            mAutomatedTestRunner.setTestIndexText(singleTestIndex);
+        });
+
+        mAutomatedTestRunner.startTest();
+    }
 }
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestDisconnectActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java
similarity index 98%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestDisconnectActivity.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java
index 31208c7..2f3c78c 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestDisconnectActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -104,10 +104,6 @@
         return true;
     }
 
-    @Override
-    public void setupEffects(int sessionId) {
-    }
-
     private void updateFailSkipButton(final boolean running) {
         runOnUiThread(new Runnable() {
             @Override
@@ -207,6 +203,11 @@
                                    int sharingMode,
                                    int sampleRate,
                                    boolean requestPlugin) throws InterruptedException {
+        if ((getSingleTestIndex() >= 0) && (mAutomatedTestRunner.getTestCount() != getSingleTestIndex())) {
+            mAutomatedTestRunner.incrementTestCount();
+            return;
+        }
+
         String actualConfigText = "none";
         mSkipTest = false;
 
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestErrorCallbackActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestErrorCallbackActivity.java
new file mode 100644
index 0000000..b3b4497
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestErrorCallbackActivity.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2022 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.
+ */
+
+package com.mobileer.oboetester;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.View;
+import android.widget.TextView;
+
+public class TestErrorCallbackActivity extends Activity {
+
+    private TextView mStatusDeleteCallback;
+    // This must match the value in TestErrorCallback.h
+    private static final int MAGIC_GOOD = 0x600DCAFE;
+    private MyStreamSniffer mStreamSniffer;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_error_callback);
+
+        mStreamSniffer = new MyStreamSniffer();
+        mStatusDeleteCallback = (TextView) findViewById(R.id.text_callback_status);
+    }
+
+    public void onTestDeleteCrash(View view) {
+        mStatusDeleteCallback.setText(getString(R.string.plug_or_unplug));
+        mStreamSniffer.startStreamSniffer();
+        testDeleteCrash();
+    }
+
+
+    // Periodically query the status of the streams.
+    protected class MyStreamSniffer {
+        public static final int SNIFFER_UPDATE_PERIOD_MSEC = 150;
+        public static final int SNIFFER_UPDATE_DELAY_MSEC = 300;
+
+        private Handler mHandler;
+
+        // Display status info for the stream.
+        private Runnable runnableCode = new Runnable() {
+            @Override
+            public void run() {
+                int magic = getCallbackMagic();
+                updateMagicDisplay(magic);
+                mHandler.postDelayed(runnableCode, SNIFFER_UPDATE_PERIOD_MSEC);
+            }
+        };
+
+        private void startStreamSniffer() {
+            stopStreamSniffer();
+            mHandler = new Handler(Looper.getMainLooper());
+            // Start the initial runnable task by posting through the handler
+            mHandler.postDelayed(runnableCode, SNIFFER_UPDATE_DELAY_MSEC);
+        }
+
+        private void stopStreamSniffer() {
+            if (mHandler != null) {
+                mHandler.removeCallbacks(runnableCode);
+            }
+        }
+    }
+
+    private void updateMagicDisplay(int magic) {
+        if (magic != 0) {
+            String text = getString(R.string.report_magic_pass, MAGIC_GOOD);
+            if (magic != MAGIC_GOOD) {
+                text = getString(R.string.report_magic_fail,
+                        magic, MAGIC_GOOD);
+            }
+            mStatusDeleteCallback.setText(text);
+        }
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mStreamSniffer.stopStreamSniffer();
+    }
+
+    private native void testDeleteCrash();
+    private native int getCallbackMagic();
+
+}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestInputActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestInputActivity.java
similarity index 73%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestInputActivity.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestInputActivity.java
index bb03496..7f33d80 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestInputActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestInputActivity.java
@@ -14,22 +14,20 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
-import android.Manifest;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.media.audiofx.AcousticEchoCanceler;
 import android.media.audiofx.AutomaticGainControl;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
 import android.support.annotation.NonNull;
-import android.support.v4.app.ActivityCompat;
 import android.support.v4.content.FileProvider;
 import android.view.View;
 import android.widget.RadioButton;
-import android.widget.Toast;
 
 import java.io.File;
 import java.io.IOException;
@@ -38,16 +36,15 @@
  * Test Oboe Capture
  */
 
-public class TestInputActivity  extends TestAudioActivity
-        implements ActivityCompat.OnRequestPermissionsResultCallback {
+public class TestInputActivity  extends TestAudioActivity {
 
-    private static final int AUDIO_ECHO_REQUEST = 0;
     protected AudioInputTester mAudioInputTester;
     private static final int NUM_VOLUME_BARS = 4;
     private VolumeBarView[] mVolumeBars = new VolumeBarView[NUM_VOLUME_BARS];
     private InputMarginView mInputMarginView;
     private int mInputMarginBursts = 0;
     private WorkloadView mWorkloadView;
+    private CommunicationDeviceView mCommunicationDeviceView;
 
     public native void setMinimumFramesBeforeRead(int frames);
     public native int saveWaveFile(String absolutePath);
@@ -81,6 +78,16 @@
         if (mWorkloadView != null) {
             mWorkloadView.setAudioStreamTester(mAudioInputTester);
         }
+
+        mCommunicationDeviceView = (CommunicationDeviceView) findViewById(R.id.comm_device_view);
+    }
+
+    @Override
+    protected void onStop() {
+        if (mCommunicationDeviceView != null) {
+            mCommunicationDeviceView.cleanup();
+        }
+        super.onStop();
     }
 
     @Override
@@ -103,14 +110,14 @@
         for (int i = 0; i < numChannels; i++) {
             if (mVolumeBars[i] == null) break;
             double level = mAudioInputTester.getPeakLevel(i);
-            mVolumeBars[i].setVolume((float) level);
+            mVolumeBars[i].setAmplitude((float) level);
         }
     }
 
     void resetVolumeBars() {
         for (int i = 0; i < mVolumeBars.length; i++) {
             if (mVolumeBars[i] == null) break;
-            mVolumeBars[i].setVolume((float) 0.0);
+            mVolumeBars[i].setAmplitude((float) 0.0);
         }
     }
 
@@ -122,11 +129,16 @@
     }
 
     @Override
-    public void openAudio() throws IOException {
-        if (!isRecordPermissionGranted()){
-            requestRecordPermission();
-            return;
+    public void openAudio(View view) {
+        try {
+            openAudio();
+        } catch (Exception e) {
+            showErrorToast(e.getMessage());
         }
+    }
+
+    @Override
+    public void openAudio() throws IOException {
         super.openAudio();
         setMinimumBurstsBeforeRead(mInputMarginBursts);
         resetVolumeBars();
@@ -143,57 +155,6 @@
         showToast("Pause not implemented. Returned " + result);
     }
 
-    private boolean isRecordPermissionGranted() {
-        return (ActivityCompat.checkSelfPermission(this,
-                Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED);
-    }
-
-    private void requestRecordPermission(){
-        ActivityCompat.requestPermissions(
-                this,
-                new String[]{Manifest.permission.RECORD_AUDIO},
-                AUDIO_ECHO_REQUEST);
-    }
-
-    @Override
-    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
-                                           @NonNull int[] grantResults) {
-
-        if (AUDIO_ECHO_REQUEST != requestCode) {
-            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
-            return;
-        }
-
-        if (grantResults.length != 1 ||
-                grantResults[0] != PackageManager.PERMISSION_GRANTED) {
-
-            Toast.makeText(getApplicationContext(),
-                    getString(R.string.need_record_audio_permission),
-                    Toast.LENGTH_SHORT)
-                    .show();
-        } else {
-            // Permission was granted
-            try {
-                super.openAudio();
-            } catch (IOException e) {
-                showErrorToast(e.getMessage());
-            }
-        }
-    }
-
-    public void setupAGC(int sessionId) {
-        AutomaticGainControl effect =  AutomaticGainControl.create(sessionId);
-    }
-
-    public void setupAEC(int sessionId) {
-        AcousticEchoCanceler effect =  AcousticEchoCanceler.create(sessionId);
-    }
-
-    @Override
-    public void setupEffects(int sessionId) {
-        setupAEC(sessionId);
-    }
-
     protected int saveWaveFile(File file) {
         // Pass filename to native to write WAV file
         int result = saveWaveFile(file.getAbsolutePath());
@@ -244,4 +205,38 @@
         mInputMarginBursts = Integer.parseInt(text);
         setMinimumBurstsBeforeRead(mInputMarginBursts);
     }
+
+    @Override
+    public void startTestUsingBundle() {
+        try {
+            StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration;
+            IntentBasedTestSupport.configureInputStreamFromBundle(mBundleFromIntent, requestedInConfig);
+
+            openAudio();
+            startAudio();
+
+            int durationSeconds = IntentBasedTestSupport.getDurationSeconds(mBundleFromIntent);
+            if (durationSeconds > 0) {
+                // Schedule the end of the test.
+                Handler handler = new Handler(Looper.getMainLooper()); // UI thread
+                handler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        stopAutomaticTest();
+                    }
+                }, durationSeconds * 1000);
+            }
+        } catch (Exception e) {
+            showErrorToast(e.getMessage());
+        } finally {
+            mBundleFromIntent = null;
+        }
+    }
+
+    void stopAutomaticTest() {
+        String report = getCommonTestReport();
+        stopAudio();
+        maybeWriteTestResult(report);
+        mTestRunningByIntent = false;
+    }
 }
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestOutputActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestOutputActivity.java
new file mode 100644
index 0000000..0d5d0ce
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestOutputActivity.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 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.
+ */
+
+package com.mobileer.oboetester;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.CheckBox;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import java.io.IOException;
+
+/**
+ * Test basic output.
+ */
+public final class TestOutputActivity extends TestOutputActivityBase {
+
+    public static final int MAX_CHANNEL_BOXES = 16;
+    private CheckBox[] mChannelBoxes;
+    private Spinner mOutputSignalSpinner;
+    protected CommunicationDeviceView mCommunicationDeviceView;
+
+    private class OutputSignalSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener {
+        @Override
+        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+            mAudioOutTester.setSignalType(pos);
+        }
+
+        @Override
+        public void onNothingSelected(AdapterView<?> parent) {
+            mAudioOutTester.setSignalType(0);
+        }
+    }
+
+    @Override
+    protected void inflateActivity() {
+        setContentView(R.layout.activity_test_output);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        updateEnabledWidgets();
+
+        mAudioOutTester = addAudioOutputTester();
+
+        mChannelBoxes = new CheckBox[MAX_CHANNEL_BOXES];
+        int ic = 0;
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox0);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox1);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox2);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox3);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox4);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox5);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox6);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox7);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox8);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox9);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox10);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox11);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox12);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox13);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox14);
+        mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox15);
+        configureChannelBoxes(0);
+
+        mOutputSignalSpinner = (Spinner) findViewById(R.id.spinnerOutputSignal);
+        mOutputSignalSpinner.setOnItemSelectedListener(new OutputSignalSpinnerListener());
+        mOutputSignalSpinner.setSelection(StreamConfiguration.NATIVE_API_UNSPECIFIED);
+
+        mCommunicationDeviceView = (CommunicationDeviceView) findViewById(R.id.comm_device_view);
+    }
+
+    @Override
+    int getActivityType() {
+        return ACTIVITY_TEST_OUTPUT;
+    }
+
+    @Override
+    protected void onStop() {
+        if (mCommunicationDeviceView != null) {
+            mCommunicationDeviceView.cleanup();
+        }
+        super.onStop();
+    }
+
+    public void openAudio() throws IOException {
+        super.openAudio();
+    }
+
+    private void configureChannelBoxes(int channelCount) {
+        for (int i = 0; i < mChannelBoxes.length; i++) {
+            mChannelBoxes[i].setChecked(i < channelCount);
+            mChannelBoxes[i].setEnabled(i < channelCount);
+        }
+    }
+
+    public void stopAudio() {
+        configureChannelBoxes(0);
+        mOutputSignalSpinner.setEnabled(true);
+        super.stopAudio();
+    }
+
+    public void pauseAudio() {
+        configureChannelBoxes(0);
+        mOutputSignalSpinner.setEnabled(true);
+        super.pauseAudio();
+    }
+
+    public void closeAudio() {
+        configureChannelBoxes(0);
+        mOutputSignalSpinner.setEnabled(true);
+        super.closeAudio();
+    }
+
+    public void startAudio() throws IOException {
+        super.startAudio();
+        int channelCount = mAudioOutTester.getCurrentAudioStream().getChannelCount();
+        configureChannelBoxes(channelCount);
+        mOutputSignalSpinner.setEnabled(false);
+    }
+
+    public void onChannelBoxClicked(View view) {
+        CheckBox checkBox = (CheckBox) view;
+        String text = (String) checkBox.getText();
+        int channelIndex = Integer.parseInt(text);
+        mAudioOutTester.setChannelEnabled(channelIndex, checkBox.isChecked());
+    }
+
+    @Override
+    public void startTestUsingBundle() {
+        try {
+            StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration;
+            IntentBasedTestSupport.configureOutputStreamFromBundle(mBundleFromIntent, requestedOutConfig);
+
+            int signalType = IntentBasedTestSupport.getSignalTypeFromBundle(mBundleFromIntent);
+            mAudioOutTester.setSignalType(signalType);
+
+            openAudio();
+            startAudio();
+
+            int durationSeconds = IntentBasedTestSupport.getDurationSeconds(mBundleFromIntent);
+            if (durationSeconds > 0) {
+                // Schedule the end of the test.
+                Handler handler = new Handler(Looper.getMainLooper()); // UI thread
+                handler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        stopAutomaticTest();
+                    }
+                }, durationSeconds * 1000);
+            }
+        } catch (Exception e) {
+            showErrorToast(e.getMessage());
+        } finally {
+            mBundleFromIntent = null;
+        }
+    }
+
+    void stopAutomaticTest() {
+        String report = getCommonTestReport();
+        stopAudio();
+        maybeWriteTestResult(report);
+        mTestRunningByIntent = false;
+    }
+}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestOutputActivityBase.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestOutputActivityBase.java
similarity index 65%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestOutputActivityBase.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestOutputActivityBase.java
index f757838..5c17e92 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestOutputActivityBase.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestOutputActivityBase.java
@@ -14,17 +14,14 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.media.audiofx.Equalizer;
 import android.media.audiofx.PresetReverb;
 import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
 
 import java.io.IOException;
 
-
 abstract class TestOutputActivityBase extends TestAudioActivity {
     AudioOutputTester mAudioOutTester;
 
@@ -59,30 +56,4 @@
             mBufferSizeView.onStreamOpened((OboeAudioStream) mAudioOutTester.getCurrentAudioStream());
         }
     }
-
-    // TODO Add editor
-    public void setupEqualizer(int sessionId) {
-        Equalizer equalizer = new Equalizer(0, sessionId);
-        int numBands = equalizer.getNumberOfBands();
-        Log.d(TAG, "numBands " + numBands);
-        for (short band = 0; band < numBands; band++) {
-            String msg = "band " + band
-                    + ", center = " + equalizer.getCenterFreq(band)
-                    + ", level = " + equalizer.getBandLevel(band);
-            Log.d(TAG, msg);
-            equalizer.setBandLevel(band, (short)40);
-        }
-
-        equalizer.setBandLevel((short) 1, (short) 300);
-    }
-
-    public void setupReverb(int sessionId) {
-        PresetReverb effect = new PresetReverb(0, sessionId);
-    }
-
-    @Override
-    public void setupEffects(int sessionId) {
-        // setupEqualizer(sessionId);
-        // setupReverb(sessionId);
-    }
-}
\ No newline at end of file
+}
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestPlugLatencyActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestPlugLatencyActivity.java
new file mode 100644
index 0000000..3110447
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestPlugLatencyActivity.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2019 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.
+ */
+
+package com.mobileer.oboetester;
+
+import android.annotation.TargetApi;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.mobileer.audio_device.AudioDeviceInfoConverter;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * Tests the latency of plugging in or unplugging an audio device.
+ */
+public class TestPlugLatencyActivity extends TestAudioActivity {
+
+    public static final int POLL_DURATION_MILLIS = 1;
+
+    private TextView     mInstructionsTextView;
+    private TextView     mPlugTextView;
+    private TextView     mAutoTextView;
+    MyAudioDeviceCallback mDeviceCallback = new MyAudioDeviceCallback();
+    private AudioManager mAudioManager;
+
+    private volatile int mPlugCount = 0;
+
+    private AudioOutputTester   mAudioOutTester;
+
+    class MyAudioDeviceCallback extends AudioDeviceCallback {
+        private HashMap<Integer, AudioDeviceInfo> mDevices
+                = new HashMap<Integer, AudioDeviceInfo>();
+
+        @Override
+        public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
+            boolean isBootingUp = mDevices.isEmpty();
+            for (AudioDeviceInfo info : addedDevices) {
+                mDevices.put(info.getId(), info);
+                if (!isBootingUp)
+                {
+                    log("Device Added");
+                    log(adiToString(info));
+                }
+
+            }
+
+            if (isBootingUp) {
+                log("Starting stream with existing audio devices");
+            }
+            updateLatency(false /* wasDeviceRemoved */);
+        }
+
+        public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
+            for (AudioDeviceInfo info : removedDevices) {
+                mDevices.remove(info.getId());
+                log("Device Removed");
+                log(adiToString(info));
+            }
+
+            updateLatency(true /* wasDeviceRemoved */);
+        }
+    }
+
+    @Override
+    protected void inflateActivity() {
+        setContentView(R.layout.activity_test_plug_latency);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mInstructionsTextView = (TextView) findViewById(R.id.text_instructions);
+        mPlugTextView = (TextView) findViewById(R.id.text_plug_events);
+        mAutoTextView = (TextView) findViewById(R.id.text_log_device_report);
+
+        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        addAudioDeviceCallback();
+    }
+
+    @Override
+    protected void onStop() {
+        removeAudioDeviceCallback();
+        super.onStop();
+    }
+
+    @TargetApi(23)
+    private void addAudioDeviceCallback(){
+        // Note that we will immediately receive a call to onDevicesAdded with the list of
+        // devices which are currently connected.
+        mAudioManager.registerAudioDeviceCallback(mDeviceCallback, null);
+    }
+
+    @TargetApi(23)
+    private void removeAudioDeviceCallback(){
+        mAudioManager.unregisterAudioDeviceCallback(mDeviceCallback);
+    }
+
+    @Override
+    public String getTestName() {
+        return "Plug Latency";
+    }
+
+    int getActivityType() {
+        return ACTIVITY_TEST_DISCONNECT;
+    }
+
+    @Override
+    boolean isOutput() {
+        return true;
+    }
+
+    // Write to status and command view
+    private void setInstructionsText(final String text) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mInstructionsTextView.setText(text);
+            }
+        });
+    }
+
+    public void startAudioTest() throws IOException {
+        startAudio();
+    }
+
+    private long calculateLatencyMs(boolean wasDeviceRemoved) {
+
+        long startMillis = System.currentTimeMillis();
+
+        try {
+            if (wasDeviceRemoved && (mAudioOutTester != null)) {
+                // Keep querying as long as error is ok
+                while (mAudioOutTester.getLastErrorCallbackResult() == 0) {
+                    Thread.sleep(POLL_DURATION_MILLIS);
+                }
+                log("Error callback at " + (System.currentTimeMillis() - startMillis) + " ms");
+            }
+            closeAudio();
+            log("Audio closed at " + (System.currentTimeMillis() - startMillis) + " ms");
+            clearStreamContexts();
+            mAudioOutTester = addAudioOutputTester();
+            openAudio();
+            log("Audio opened at " + (System.currentTimeMillis() - startMillis) + " ms");
+            AudioStreamBase stream = mAudioOutTester.getCurrentAudioStream();
+            startAudioTest();
+            log("Audio starting at " + (System.currentTimeMillis() - startMillis) + " ms");
+            while (stream.getState() == StreamConfiguration.STREAM_STATE_STARTING) {
+                Thread.sleep(POLL_DURATION_MILLIS);
+            }
+            log("Audio started at " + (System.currentTimeMillis() - startMillis) + " ms");
+            while (mAudioOutTester.getFramesRead() == 0) {
+                Thread.sleep(POLL_DURATION_MILLIS);
+            }
+            log("First frame read at " + (System.currentTimeMillis() - startMillis) + " ms");
+        } catch (IOException | InterruptedException e) {
+            e.printStackTrace();
+            return -1;
+        }
+
+        return System.currentTimeMillis() - startMillis;
+    }
+
+    public static String adiToString(AudioDeviceInfo adi) {
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("Id: ");
+        sb.append(adi.getId());
+
+        sb.append("\nProduct name: ");
+        sb.append(adi.getProductName());
+
+        sb.append("\nType: ");
+        sb.append(AudioDeviceInfoConverter.typeToString(adi.getType()));
+
+        sb.append("\nIsSource: ");
+        sb.append(String.valueOf(adi.isSource()));
+        sb.append(", IsSink: ");
+        sb.append(String.valueOf(adi.isSink()));
+
+        return sb.toString();
+    }
+
+    // Write to scrollable TextView
+    private void log(final String text) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mAutoTextView.append(text);
+                mAutoTextView.append("\n");
+            }
+        });
+    }
+
+    private void updateLatency(boolean wasDeviceRemoved) {
+        mPlugCount++;
+        log("\nOperation #" + mPlugCount + " starting");
+        long latencyMs = calculateLatencyMs(wasDeviceRemoved);
+        String message = "Operation #" + mPlugCount + " latency: "+ latencyMs + " ms\n";
+        log(message);
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mPlugTextView.setText(message);
+            }
+        });
+    }
+}
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/VolumeBarView.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/VolumeBarView.java
new file mode 100644
index 0000000..c6a2dc2
--- /dev/null
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/VolumeBarView.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.mobileer.oboetester;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * Display volume in dB as a red bar.
+ * Display the amplitude, 0.0 to 1.0, as text in the bar.
+ */
+public class VolumeBarView extends View {
+
+    private static final float MIN_VOLUME_DB = -84;
+    private static final float MIN_AMPLITUDE_AT_MIN_VOLUME_DB =
+            (float) Math.pow(10.0, MIN_VOLUME_DB / 20);
+    public static final String FORMAT_AMPLITUDE = "%8.6f";
+
+    private float mClippedAmplitude;
+    private float mVolume = MIN_VOLUME_DB;
+
+    private Paint mBarPaint;
+    private Paint mTextPaint;
+    private Paint mBackgroundPaint;
+    private int mCurrentWidth;
+    private int mCurrentHeight;
+    private final Rect mTextBounds = new Rect();
+
+    public VolumeBarView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+//        TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
+//                R.styleable.VolumeBarView, 0, 0);
+        init();
+    }
+
+    private void init() {
+        mBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mBarPaint.setColor(Color.rgb(240, 100, 100));
+        mBarPaint.setStyle(Paint.Style.FILL);
+
+        mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mBackgroundPaint.setColor(Color.LTGRAY);
+        mBackgroundPaint.setStyle(Paint.Style.FILL);
+
+        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mTextPaint.setColor(Color.BLACK);
+        mTextPaint.setStyle(Paint.Style.FILL);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        mCurrentWidth = w;
+        mCurrentHeight = h;
+        mTextPaint.setTextSize(0.8f * h);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        canvas.drawRect(0.0f, 0.0f, mCurrentWidth,
+                mCurrentHeight, mBackgroundPaint);
+        float volumeWidth = ((MIN_VOLUME_DB - mVolume) / MIN_VOLUME_DB) * mCurrentWidth;
+        canvas.drawRect(0.0f, 0.0f, volumeWidth,
+                mCurrentHeight, mBarPaint);
+        String text = String.format(FORMAT_AMPLITUDE, mClippedAmplitude);
+        mTextPaint.getTextBounds(text, 0, text.length(), mTextBounds);
+        canvas.drawText(text,
+                20.0f,
+                (mCurrentHeight/2) - mTextBounds.exactCenterY(),
+                mTextPaint);
+    }
+
+    /**
+     * Set peak amplitude of the signal.
+     * Should be between 0.0 and 1.0
+     */
+    public void setAmplitude(float amplitude) {
+        mClippedAmplitude = (float) Math.min(1.0, Math.max(0.0, amplitude));
+        if (amplitude < MIN_AMPLITUDE_AT_MIN_VOLUME_DB) {
+            mVolume = MIN_VOLUME_DB;
+        } else {
+            mVolume = 20.0f * (float)Math.log10(amplitude);
+        }
+        postInvalidate();
+    }
+
+}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/WaveformView.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WaveformView.java
similarity index 87%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/WaveformView.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WaveformView.java
index 580f4c9..fb50914 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/WaveformView.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WaveformView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.content.Context;
 import android.content.res.Resources;
@@ -25,22 +25,23 @@
 import android.util.AttributeSet;
 import android.view.View;
 
-import com.google.sample.oboe.manualtest.R;
-
 /**
  * Display an audio waveform in a custom View.
  */
 public class WaveformView extends View {
+    private static final float MESSAGE_TEXT_SIZE = 80;
     private Paint mWavePaint;
+    private Paint mBackgroundPaint;
+    private Paint mMessagePaint;
     private int mCurrentWidth;
     private int mCurrentHeight;
-    private Paint mBackgroundPaint;
     private float[] mData;
     private int mSampleCount;
     private int mSampleOffset;
     private float mOffsetY;
     private float mScaleY;
     private int[] mCursors;
+    private String mMessage;
     private Paint mCursorPaint;
 
     public WaveformView(Context context, AttributeSet attrs) {
@@ -65,6 +66,10 @@
         mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
         mBackgroundPaint.setColor(res.getColor(R.color.waveform_background));
         mBackgroundPaint.setStyle(Paint.Style.FILL);
+
+        mMessagePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mMessagePaint.setColor(res.getColor(R.color.waveform_line));
+        mMessagePaint.setTextSize(MESSAGE_TEXT_SIZE);
     }
 
     @Override
@@ -75,12 +80,28 @@
         mScaleY = 0.0f - mOffsetY;
     }
 
+    public String getMessage() {
+        return mMessage;
+    }
+
+    /**
+     * Set message to be displayed over the waveform.
+     * Set null for no message.
+     * @param message text or null
+     */
+    public void setMessage(String message) {
+        this.mMessage = message;
+    }
+
     @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
         float [] localData = mData;
         canvas.drawRect(0.0f, 0.0f, mCurrentWidth,
                 mCurrentHeight, mBackgroundPaint);
+        if (mMessage != null) {
+            canvas.drawText(mMessage, 20, mCurrentHeight - 20, mMessagePaint);
+        }
         if (localData == null || mSampleCount == 0) {
             return;
         }
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/WorkloadView.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WorkloadView.java
similarity index 98%
rename from apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/WorkloadView.java
rename to apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WorkloadView.java
index c3a9dba..78d78df 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/WorkloadView.java
+++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WorkloadView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.sample.oboe.manualtest;
+package com.mobileer.oboetester;
 
 import android.content.Context;
 import android.util.AttributeSet;
diff --git a/apps/OboeTester/app/src/main/res/drawable/ic_launcher_background.xml b/apps/OboeTester/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..ca3826a
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector
+    android:height="108dp"
+    android:width="108dp"
+    android:viewportHeight="108"
+    android:viewportWidth="108"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#3DDC84"
+          android:pathData="M0,0h108v108h-108z"/>
+    <path android:fillColor="#00000000" android:pathData="M9,0L9,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,0L19,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M29,0L29,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M39,0L39,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M49,0L49,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M59,0L59,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M69,0L69,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M79,0L79,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M89,0L89,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M99,0L99,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,9L108,9"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,19L108,19"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,29L108,29"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,39L108,39"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,49L108,49"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,59L108,59"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,69L108,69"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,79L108,79"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,89L108,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,99L108,99"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,29L89,29"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,39L89,39"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,49L89,49"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,59L89,59"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,69L89,69"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,79L89,79"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M29,19L29,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M39,19L39,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M49,19L49,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M59,19L59,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M69,19L69,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M79,19L79,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+</vector>
diff --git a/apps/OboeTester/app/src/main/res/drawable/ic_launcher_foreground.xml b/apps/OboeTester/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..c6b7285
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108"
+    android:tint="#0D49B0">
+  <group android:scaleX="2.61"
+      android:scaleY="2.61"
+      android:translateX="22.68"
+      android:translateY="22.68">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M17,16.99c-1.35,0 -2.2,0.42 -2.95,0.8 -0.65,0.33 -1.18,0.6 -2.05,0.6 -0.9,0 -1.4,-0.25 -2.05,-0.6 -0.75,-0.38 -1.57,-0.8 -2.95,-0.8s-2.2,0.42 -2.95,0.8c-0.65,0.33 -1.17,0.6 -2.05,0.6v1.95c1.35,0 2.2,-0.42 2.95,-0.8 0.65,-0.33 1.17,-0.6 2.05,-0.6s1.4,0.25 2.05,0.6c0.75,0.38 1.57,0.8 2.95,0.8s2.2,-0.42 2.95,-0.8c0.65,-0.33 1.18,-0.6 2.05,-0.6 0.9,0 1.4,0.25 2.05,0.6 0.75,0.38 1.58,0.8 2.95,0.8v-1.95c-0.9,0 -1.4,-0.25 -2.05,-0.6 -0.75,-0.38 -1.6,-0.8 -2.95,-0.8zM17,12.54c-1.35,0 -2.2,0.43 -2.95,0.8 -0.65,0.32 -1.18,0.6 -2.05,0.6 -0.9,0 -1.4,-0.25 -2.05,-0.6 -0.75,-0.38 -1.57,-0.8 -2.95,-0.8s-2.2,0.43 -2.95,0.8c-0.65,0.32 -1.17,0.6 -2.05,0.6v1.95c1.35,0 2.2,-0.43 2.95,-0.8 0.65,-0.35 1.15,-0.6 2.05,-0.6s1.4,0.25 2.05,0.6c0.75,0.38 1.57,0.8 2.95,0.8s2.2,-0.43 2.95,-0.8c0.65,-0.35 1.15,-0.6 2.05,-0.6s1.4,0.25 2.05,0.6c0.75,0.38 1.58,0.8 2.95,0.8v-1.95c-0.9,0 -1.4,-0.25 -2.05,-0.6 -0.75,-0.38 -1.6,-0.8 -2.95,-0.8zM19.95,4.46c-0.75,-0.38 -1.58,-0.8 -2.95,-0.8s-2.2,0.42 -2.95,0.8c-0.65,0.32 -1.18,0.6 -2.05,0.6 -0.9,0 -1.4,-0.25 -2.05,-0.6 -0.75,-0.37 -1.57,-0.8 -2.95,-0.8s-2.2,0.42 -2.95,0.8c-0.65,0.33 -1.17,0.6 -2.05,0.6v1.93c1.35,0 2.2,-0.43 2.95,-0.8 0.65,-0.33 1.17,-0.6 2.05,-0.6s1.4,0.25 2.05,0.6c0.75,0.38 1.57,0.8 2.95,0.8s2.2,-0.43 2.95,-0.8c0.65,-0.32 1.18,-0.6 2.05,-0.6 0.9,0 1.4,0.25 2.05,0.6 0.75,0.38 1.58,0.8 2.95,0.8L22,5.04c-0.9,0 -1.4,-0.25 -2.05,-0.58zM17,8.09c-1.35,0 -2.2,0.43 -2.95,0.8 -0.65,0.35 -1.15,0.6 -2.05,0.6s-1.4,-0.25 -2.05,-0.6c-0.75,-0.38 -1.57,-0.8 -2.95,-0.8s-2.2,0.43 -2.95,0.8c-0.65,0.35 -1.15,0.6 -2.05,0.6v1.95c1.35,0 2.2,-0.43 2.95,-0.8 0.65,-0.32 1.18,-0.6 2.05,-0.6s1.4,0.25 2.05,0.6c0.75,0.38 1.57,0.8 2.95,0.8s2.2,-0.43 2.95,-0.8c0.65,-0.32 1.18,-0.6 2.05,-0.6 0.9,0 1.4,0.25 2.05,0.6 0.75,0.38 1.58,0.8 2.95,0.8L22,9.49c-0.9,0 -1.4,-0.25 -2.05,-0.6 -0.75,-0.38 -1.6,-0.8 -2.95,-0.8z"/>
+  </group>
+</vector>
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_auto_glitches.xml b/apps/OboeTester/app/src/main/res/layout/activity_auto_glitches.xml
index a017668..6980163 100644
--- a/apps/OboeTester/app/src/main/res/layout/activity_auto_glitches.xml
+++ b/apps/OboeTester/app/src/main/res/layout/activity_auto_glitches.xml
@@ -1,14 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
+    android:fillViewport="true"
+    tools:context="com.mobileer.oboetester.AutomatedGlitchActivity" >
+<LinearLayout
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
     android:orientation="vertical"
     android:paddingBottom="@dimen/activity_vertical_margin"
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
-    android:paddingTop="@dimen/activity_vertical_margin"
-    tools:context="com.google.sample.oboe.manualtest.AutomatedGlitchActivity">
+    android:paddingTop="@dimen/activity_vertical_margin" >
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -33,10 +38,11 @@
             />
     </LinearLayout>
 
-    <com.google.sample.oboe.manualtest.AutomatedTestRunner
+    <com.mobileer.oboetester.AutomatedTestRunner
         android:id="@+id/auto_test_runner"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         android:orientation="vertical" />
 
 </LinearLayout>
+</ScrollView>
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml b/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml
index deb6a3c..c635400 100644
--- a/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml
+++ b/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml
@@ -8,19 +8,46 @@
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
     android:paddingTop="@dimen/activity_vertical_margin"
-    tools:context="com.google.sample.oboe.manualtest.TestDataPathsActivity">
+    tools:context="com.mobileer.oboetester.TestDataPathsActivity">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <CheckBox
+            android:id="@+id/checkbox_paths_input_presets"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:checked="true"
+            android:text="InPre" />
+
+        <CheckBox
+            android:id="@+id/checkbox_paths_input_devices"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:checked="true"
+            android:text="InDev" />
+
+        <CheckBox
+            android:id="@+id/checkbox_paths_output_devices"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:checked="true"
+            android:text="OutDev" />
+    </LinearLayout>
 
     <TextView
         android:id="@+id/text_instructions"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:lines="1"
-        android:text="@string/test_disconnect_instructions"
+        android:lines="2"
+        android:text="@string/test_datapath_instructions"
         android:textColor="#F44336"
         android:textSize="18sp"
         android:textStyle="bold" />
 
-    <com.google.sample.oboe.manualtest.AutomatedTestRunner
+    <com.mobileer.oboetester.AutomatedTestRunner
         android:id="@+id/auto_test_runner"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_device_report.xml b/apps/OboeTester/app/src/main/res/layout/activity_device_report.xml
index 8815ae9..6d59534 100644
--- a/apps/OboeTester/app/src/main/res/layout/activity_device_report.xml
+++ b/apps/OboeTester/app/src/main/res/layout/activity_device_report.xml
@@ -8,10 +8,14 @@
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
     android:paddingTop="@dimen/activity_vertical_margin"
-    tools:context="com.google.sample.oboe.manualtest.DeviceReportActivity">
+    tools:context="com.mobileer.oboetester.DeviceReportActivity">
 
+    <ScrollView
+        android:id="@+id/text_log_device_scroller"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
     <TextView
-        android:id="@+id/text_log"
+        android:id="@+id/text_log_device_report"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:fontFamily="monospace"
@@ -19,5 +23,6 @@
         android:scrollbars="vertical"
         android:text="@string/device_report"
         />
+    </ScrollView>
 
 </LinearLayout>
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_echo.xml b/apps/OboeTester/app/src/main/res/layout/activity_echo.xml
index 34bb49d..65cd6ea 100644
--- a/apps/OboeTester/app/src/main/res/layout/activity_echo.xml
+++ b/apps/OboeTester/app/src/main/res/layout/activity_echo.xml
@@ -2,12 +2,13 @@
 <ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
-    tools:context="com.google.sample.oboe.manualtest.EchoActivity"
+    tools:context="com.mobileer.oboetester.EchoActivity"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="wrap_content"
+    android:fillViewport="true" >
     <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         android:orientation="vertical"
         android:paddingBottom="@dimen/activity_vertical_margin"
         android:paddingLeft="@dimen/activity_horizontal_margin"
@@ -15,20 +16,20 @@
         android:paddingTop="@dimen/activity_vertical_margin"
         >
 
-        <com.google.sample.oboe.manualtest.StreamConfigurationView
+        <com.mobileer.oboetester.StreamConfigurationView
             android:id="@+id/inputStreamConfiguration"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:gravity="center"
             android:orientation="horizontal" />
 
-        <com.google.sample.oboe.manualtest.InputMarginView
+        <com.mobileer.oboetester.InputMarginView
             android:id="@+id/input_margin_view"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:gravity="center" />
 
-        <com.google.sample.oboe.manualtest.StreamConfigurationView
+        <com.mobileer.oboetester.StreamConfigurationView
             android:id="@+id/outputStreamConfiguration"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -76,6 +77,12 @@
                 android:progress="1000" />
         </LinearLayout>
 
+        <com.mobileer.oboetester.CommunicationDeviceView
+            android:id="@+id/comm_device_view"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:orientation="horizontal" />
 
         <TextView
             android:id="@+id/text_status"
@@ -85,6 +92,7 @@
             android:text="@string/echo_instructions"
             android:textSize="14sp"
             android:textStyle="bold" />
-
+≈
     </LinearLayout>
-</ScrollView>
\ No newline at end of file
+
+</ScrollView>
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_error_callback.xml b/apps/OboeTester/app/src/main/res/layout/activity_error_callback.xml
new file mode 100644
index 0000000..3abc11e
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/layout/activity_error_callback.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".TestErrorCallbackActivity">
+
+    <GridLayout
+        android:id="@+id/buttonGrid"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:columnCount="1">
+
+    <Button
+        android:id="@+id/buttonTestDeleteCrash"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_columnWeight="1"
+        android:layout_gravity="fill"
+        android:backgroundTint="@color/button_tint"
+        android:onClick="onTestDeleteCrash"
+        android:text="Delete Callback" />
+
+    <TextView
+        android:id="@+id/text_callback_status"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:fontFamily="monospace"
+        android:gravity="bottom"
+        android:text="@string/init_status"
+        />
+
+</GridLayout>
+</android.support.constraint.ConstraintLayout>
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_external_tap_to_tone.xml b/apps/OboeTester/app/src/main/res/layout/activity_external_tap_to_tone.xml
new file mode 100644
index 0000000..9202131
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/layout/activity_external_tap_to_tone.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    tools:context=".ExternalTapToToneActivity">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/button_start"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@xml/button_color_selector"
+            android:backgroundTintMode="src_atop"
+            android:onClick="startTest"
+            android:text="@string/startAudio" />
+
+        <Button
+            android:id="@+id/button_analyze"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@xml/button_color_selector"
+            android:backgroundTintMode="src_atop"
+            android:onClick="analyze"
+            android:text="@string/analyze" />
+
+        <Button
+            android:id="@+id/button_stop"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@xml/button_color_selector"
+            android:backgroundTintMode="src_atop"
+            android:onClick="stopTest"
+            android:text="@string/stopAudio" />
+
+    </LinearLayout>
+
+    <TextView
+        android:id="@+id/resultView"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:lines="2"
+        android:textSize="18sp"
+        android:textStyle="bold"
+        android:text="@string/tap_help" />
+
+    <com.mobileer.oboetester.WaveformView
+        android:id="@+id/waveview_audio"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent" />
+
+</LinearLayout>
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_extra_tests.xml b/apps/OboeTester/app/src/main/res/layout/activity_extra_tests.xml
new file mode 100644
index 0000000..dbd0d37
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/layout/activity_extra_tests.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".ExtraTestsActivity">
+
+    <GridLayout
+        android:id="@+id/buttonGrid"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:columnCount="2">
+
+    <Button
+        android:id="@+id/buttonBackToMain"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_columnWeight="1"
+        android:layout_gravity="fill"
+        android:backgroundTint="@color/button_tint"
+        android:onClick="onLaunchMainActivity"
+        android:text="Back to Main" />
+
+    <Button
+        android:id="@+id/buttonExternalTap"
+        android:layout_gravity="fill"
+        android:layout_width="0dp"
+        android:layout_columnWeight="1"
+        android:layout_height="wrap_content"
+        android:backgroundTint="@color/button_tint"
+        android:onClick="onLaunchExternalTapTest"
+        android:text="External Tap" />
+
+    <Button
+        android:id="@+id/buttonPlugLatency"
+        android:layout_gravity="fill"
+        android:layout_width="0dp"
+        android:layout_columnWeight="1"
+        android:layout_height="wrap_content"
+        android:backgroundTint="@color/button_tint"
+        android:onClick="onLaunchPlugLatencyTest"
+        android:text="Plug Latency" />
+
+    <Button
+        android:id="@+id/buttonErrorCallback"
+        android:layout_gravity="fill"
+        android:layout_width="0dp"
+        android:layout_columnWeight="1"
+        android:layout_height="wrap_content"
+        android:backgroundTint="@color/button_tint"
+        android:onClick="onLaunchErrorCallbackTest"
+        android:text="Error Callback" />
+</GridLayout>
+</android.support.constraint.ConstraintLayout>
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_main.xml b/apps/OboeTester/app/src/main/res/layout/activity_main.xml
index 248f572..56bafeb 100644
--- a/apps/OboeTester/app/src/main/res/layout/activity_main.xml
+++ b/apps/OboeTester/app/src/main/res/layout/activity_main.xml
@@ -8,7 +8,7 @@
     android:layout_marginLeft="4dp"
     android:layout_marginRight="4dp"
     android:background="@color/version_release"
-    tools:context="com.google.sample.oboe.manualtest.MainActivity">
+    tools:context="com.mobileer.oboetester.MainActivity">
 
     <TextView
         android:id="@+id/versionText"
@@ -26,98 +26,126 @@
         android:columnCount="2"
         app:layout_constraintTop_toBottomOf="@+id/versionText">
 
-    <Button
-        android:id="@+id/buttonTestOutput"
-        android:layout_gravity="fill"
-        android:layout_width="0dp"
-        android:layout_columnWeight="1"
-        android:layout_height="wrap_content"
-        android:onClick="onLaunchTestOutput"
-        android:text="Test Output"
-        />
+        <Button
+            android:id="@+id/buttonTestOutput"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_columnWeight="1"
+            android:layout_gravity="fill"
+            android:backgroundTint="@color/button_tint"
+            android:onClick="onLaunchTestOutput"
+            android:text="Test Output" />
 
-    <Button
-        android:id="@+id/buttonTestInput"
-        android:layout_gravity="fill"
-        android:layout_width="0dp"
-        android:layout_columnWeight="1"
-        android:layout_height="wrap_content"
-        android:onClick="onLaunchTestInput"
-        android:text="Test Input" />
+        <Button
+            android:id="@+id/buttonTestInput"
+            android:layout_gravity="fill"
+            android:layout_width="0dp"
+            android:layout_columnWeight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@color/button_tint"
+            android:onClick="onLaunchTestInput"
+            android:text="Test Input" />
 
-    <Button
-        android:id="@+id/buttonTapToTone"
-        android:layout_gravity="fill"
-        android:layout_width="0dp"
-        android:layout_columnWeight="1"
-        android:layout_height="wrap_content"
-        android:onClick="onLaunchTapToTone"
-        android:text="Tap to Tone Latency"
-        />
+        <Button
+            android:id="@+id/buttonTapToTone"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_columnWeight="1"
+            android:layout_gravity="fill"
+            android:backgroundTint="@color/button_tint"
+            android:onClick="onLaunchTapToTone"
+            android:text="Tap to Tone Latency" />
 
-    <Button
-        android:id="@+id/button_rt_latency"
-        android:layout_gravity="fill"
-        android:layout_width="0dp"
-        android:layout_columnWeight="1"
-        android:layout_height="wrap_content"
-        android:onClick="onLaunchRoundTripLatency"
-        android:text="Round Trip Latency" />
+        <Button
+            android:id="@+id/button_rt_latency"
+            android:layout_gravity="fill"
+            android:layout_width="0dp"
+            android:layout_columnWeight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@color/button_tint"
+            android:onClick="onLaunchRoundTripLatency"
+            android:text="Round Trip Latency" />
 
-    <Button
-        android:id="@+id/buttonEcho"
-        android:layout_gravity="fill"
-        android:layout_width="0dp"
-        android:layout_columnWeight="1"
-        android:layout_height="wrap_content"
-        android:onClick="onLaunchEcho"
-        android:text="Echo Input to Output" />
+        <Button
+            android:id="@+id/buttonEcho"
+            android:layout_gravity="fill"
+            android:layout_width="0dp"
+            android:layout_columnWeight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@color/button_tint"
+            android:onClick="onLaunchEcho"
+            android:text="Echo Input to Output" />
 
-    <Button
-        android:id="@+id/buttonRecorder"
-        android:layout_gravity="fill"
-        android:layout_width="0dp"
-        android:layout_columnWeight="1"
-        android:layout_height="wrap_content"
-        android:onClick="onLaunchRecorder"
-        android:text="Record and Play"
-        />
+        <Button
+            android:id="@+id/buttonRecorder"
+            android:layout_gravity="fill"
+            android:layout_width="0dp"
+            android:layout_columnWeight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@color/button_tint"
+            android:onClick="onLaunchRecorder"
+            android:text="Record and Play"
+            />
 
-    <Button
-        android:id="@+id/button_manual_glitches"
-        android:layout_gravity="fill"
-        android:layout_width="0dp"
-        android:layout_columnWeight="1"
-        android:layout_height="wrap_content"
-        android:onClick="onLaunchManualGlitchTest"
-        android:text="Glitch Test" />
+        <Button
+            android:id="@+id/button_manual_glitches"
+            android:layout_gravity="fill"
+            android:layout_width="0dp"
+            android:layout_columnWeight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@color/button_tint"
+            android:onClick="onLaunchManualGlitchTest"
+            android:text="Glitch Test" />
 
-    <Button
-        android:id="@+id/button_auto_glitches"
-        android:layout_gravity="fill"
-        android:layout_width="0dp"
-        android:layout_columnWeight="1"
-        android:layout_height="wrap_content"
-        android:onClick="onLaunchAutoGlitchTest"
-        android:text="Auto Glitch Test" />
+        <Button
+            android:id="@+id/button_auto_glitches"
+            android:layout_gravity="fill"
+            android:layout_width="0dp"
+            android:layout_columnWeight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@color/button_tint"
+            android:onClick="onLaunchAutoGlitchTest"
+            android:text="Auto Glitch Test" />
 
-    <Button
-        android:id="@+id/button_test_disconnect"
-        android:layout_gravity="fill"
-        android:layout_width="0dp"
-        android:layout_columnWeight="1"
-        android:layout_height="wrap_content"
-        android:onClick="onLaunchTestDisconnect"
-        android:text="Test Disconnect" />
+        <Button
+            android:id="@+id/button_test_disconnect"
+            android:layout_gravity="fill"
+            android:layout_width="0dp"
+            android:layout_columnWeight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@color/button_tint"
+            android:onClick="onLaunchTestDisconnect"
+            android:text="Test Disconnect" />
 
-    <Button
-        android:id="@+id/button_test_device_report"
-        android:layout_gravity="fill"
-        android:layout_width="0dp"
-        android:layout_columnWeight="1"
-        android:layout_height="wrap_content"
-        android:onClick="onLaunchTestDeviceReport"
-        android:text="@string/title_report_devices" />
+        <Button
+            android:id="@+id/button_test_device_report"
+            android:layout_gravity="fill"
+            android:layout_width="0dp"
+            android:layout_columnWeight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@color/button_tint"
+            android:onClick="onLaunchTestDeviceReport"
+            android:text="@string/title_report_devices" />
+
+        <Button
+            android:id="@+id/button_test_data_paths"
+            android:layout_gravity="fill"
+            android:layout_width="0dp"
+            android:layout_columnWeight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@color/button_tint"
+            android:onClick="onLaunchTestDataPaths"
+            android:text="Data Paths" />
+
+        <Button
+            android:id="@+id/button_extra_tests"
+            android:layout_gravity="fill"
+            android:layout_width="0dp"
+            android:layout_columnWeight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@color/button_tint"
+            android:onClick="onLaunchExtratests"
+            android:text="Extras..." />
 
     <Button
         android:id="@+id/button_test_data_paths"
@@ -163,25 +191,13 @@
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toEndOf="@+id/textView" />
 
-
-    <CheckBox
-        android:id="@+id/setSpeakerphoneOn"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="6dp"
-        android:checked="false"
-        android:onClick="onSetSpeakerphoneOn"
-        android:text="setSpeakerphoneOn/Off()"
-        app:layout_constraintStart_toStartOf="@+id/useCallback"
-        app:layout_constraintTop_toBottomOf="@+id/useCallback" />
-
     <LinearLayout
         android:id="@+id/layoutBluetoothSco"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="horizontal"
-        app:layout_constraintStart_toStartOf="@+id/setSpeakerphoneOn"
-        app:layout_constraintTop_toBottomOf="@+id/setSpeakerphoneOn"
+        app:layout_constraintStart_toStartOf="@+id/callbackSize"
+        app:layout_constraintTop_toBottomOf="@+id/callbackSize"
         >
         <CheckBox
             android:id="@+id/setBluetoothScoOn"
@@ -208,11 +224,20 @@
         android:layout_height="wrap_content"
         android:layout_marginTop="6dp"
         android:checked="false"
-        android:onClick="onEnableWorkarounds"
         android:text="enable Oboe workarounds"
         app:layout_constraintStart_toStartOf="@+id/layoutBluetoothSco"
         app:layout_constraintTop_toBottomOf="@+id/layoutBluetoothSco" />
 
+    <CheckBox
+        android:id="@+id/boxEnableBackground"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="6dp"
+        android:checked="false"
+        android:text="enable background operation"
+        app:layout_constraintStart_toStartOf="@+id/boxEnableWorkarounds"
+        app:layout_constraintTop_toBottomOf="@+id/boxEnableWorkarounds" />
+
 
     <TextView
         android:id="@+id/textView2"
@@ -220,7 +245,7 @@
         android:layout_height="wrap_content"
         android:text="Mode:"
         app:layout_constraintBaseline_toBaselineOf="@+id/spinnerAudioMode"
-        app:layout_constraintStart_toStartOf="@+id/boxEnableWorkarounds" />
+        app:layout_constraintStart_toStartOf="@+id/boxEnableBackground" />
 
     <Spinner
         android:id="@+id/spinnerAudioMode"
@@ -229,7 +254,7 @@
         android:entries="@array/audio_modes"
         android:prompt="@string/audio_mode_prompt"
         app:layout_constraintStart_toEndOf="@+id/textView2"
-        app:layout_constraintTop_toBottomOf="@+id/boxEnableWorkarounds" />
+        app:layout_constraintTop_toBottomOf="@+id/boxEnableBackground" />
 
     <TextView
         android:id="@+id/deviceView"
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_manual_glitches.xml b/apps/OboeTester/app/src/main/res/layout/activity_manual_glitches.xml
index fb09141..5798e2e 100644
--- a/apps/OboeTester/app/src/main/res/layout/activity_manual_glitches.xml
+++ b/apps/OboeTester/app/src/main/res/layout/activity_manual_glitches.xml
@@ -1,36 +1,42 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
+    android:fillViewport="true"
+    tools:context="com.mobileer.oboetester.ManualGlitchActivity"
+    >
+<LinearLayout
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
     android:orientation="vertical"
     android:paddingBottom="@dimen/activity_vertical_margin"
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
-    android:paddingTop="@dimen/activity_vertical_margin"
-    tools:context="com.google.sample.oboe.manualtest.ManualGlitchActivity">
+    android:paddingTop="@dimen/activity_vertical_margin">
 
-    <com.google.sample.oboe.manualtest.StreamConfigurationView
+    <com.mobileer.oboetester.StreamConfigurationView
         android:id="@+id/inputStreamConfiguration"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center"
         android:orientation="horizontal" />
 
-    <com.google.sample.oboe.manualtest.InputMarginView
+    <com.mobileer.oboetester.InputMarginView
         android:id="@+id/input_margin_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center" />
 
-    <com.google.sample.oboe.manualtest.StreamConfigurationView
+    <com.mobileer.oboetester.StreamConfigurationView
         android:id="@+id/outputStreamConfiguration"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center"
         android:orientation="horizontal" />
 
-    <com.google.sample.oboe.manualtest.BufferSizeView
+    <com.mobileer.oboetester.BufferSizeView
         android:id="@+id/buffer_size_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -92,13 +98,16 @@
         android:id="@+id/text_status"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:lines="11"
+        android:lines="12"
         android:text="@string/loopback_instructions_glitch"
         android:textSize="14sp"
         android:textStyle="bold" />
 
-    <com.google.sample.oboe.manualtest.WaveformView
+    <com.mobileer.oboetester.WaveformView
         android:id="@+id/waveview_audio"
         android:layout_width="fill_parent"
-        android:layout_height="fill_parent" />
+        android:layout_height="fill_parent"
+        android:minHeight="100dp"
+        />
 </LinearLayout>
+</ScrollView>
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_recorder.xml b/apps/OboeTester/app/src/main/res/layout/activity_recorder.xml
index 963e6b9..4ee772f 100644
--- a/apps/OboeTester/app/src/main/res/layout/activity_recorder.xml
+++ b/apps/OboeTester/app/src/main/res/layout/activity_recorder.xml
@@ -1,23 +1,28 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
+    android:fillViewport="true"
+    tools:context="com.mobileer.oboetester.RecorderActivity" >
+<LinearLayout
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
     android:orientation="vertical"
     android:paddingBottom="@dimen/activity_vertical_margin"
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
-    android:paddingTop="@dimen/activity_vertical_margin"
-    tools:context="com.google.sample.oboe.manualtest.RecorderActivity">
+    android:paddingTop="@dimen/activity_vertical_margin" >
 
-    <com.google.sample.oboe.manualtest.StreamConfigurationView
+    <com.mobileer.oboetester.StreamConfigurationView
         android:id="@+id/streamConfiguration"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center"
         android:orientation="horizontal" />
 
-    <com.google.sample.oboe.manualtest.InputMarginView
+    <com.mobileer.oboetester.InputMarginView
         android:id="@+id/input_margin_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -71,28 +76,29 @@
         android:lines="3"
         android:text="@string/init_status" />
 
-    <com.google.sample.oboe.manualtest.VolumeBarView
+    <com.mobileer.oboetester.VolumeBarView
         android:id="@+id/volumeBar0"
         android:layout_width="fill_parent"
         android:layout_marginBottom="4dp"
         android:layout_height="20dp" />
 
-    <com.google.sample.oboe.manualtest.VolumeBarView
+    <com.mobileer.oboetester.VolumeBarView
         android:id="@+id/volumeBar1"
         android:layout_width="fill_parent"
         android:layout_marginBottom="4dp"
         android:layout_height="20dp" />
 
-    <com.google.sample.oboe.manualtest.VolumeBarView
+    <com.mobileer.oboetester.VolumeBarView
         android:id="@+id/volumeBar2"
         android:layout_width="fill_parent"
         android:layout_marginBottom="4dp"
         android:layout_height="20dp" />
 
-    <com.google.sample.oboe.manualtest.VolumeBarView
+    <com.mobileer.oboetester.VolumeBarView
         android:id="@+id/volumeBar3"
         android:layout_width="fill_parent"
         android:layout_marginBottom="4dp"
         android:layout_height="20dp" />
 
 </LinearLayout>
+</ScrollView>
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_rt_latency.xml b/apps/OboeTester/app/src/main/res/layout/activity_rt_latency.xml
index 7780985..09728da 100644
--- a/apps/OboeTester/app/src/main/res/layout/activity_rt_latency.xml
+++ b/apps/OboeTester/app/src/main/res/layout/activity_rt_latency.xml
@@ -1,43 +1,48 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
+    android:fillViewport="true"
+    tools:context="com.mobileer.oboetester.RoundTripLatencyActivity" >
+<LinearLayout
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
     android:orientation="vertical"
     android:paddingBottom="@dimen/activity_vertical_margin"
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
-    android:paddingTop="@dimen/activity_vertical_margin"
-    tools:context="com.google.sample.oboe.manualtest.RoundTripLatencyActivity">
+    android:paddingTop="@dimen/activity_vertical_margin" >
 
-    <com.google.sample.oboe.manualtest.StreamConfigurationView
+    <com.mobileer.oboetester.StreamConfigurationView
         android:id="@+id/inputStreamConfiguration"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center"
         android:orientation="horizontal" />
 
-    <com.google.sample.oboe.manualtest.InputMarginView
+    <com.mobileer.oboetester.InputMarginView
         android:id="@+id/input_margin_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center" />
 
-    <com.google.sample.oboe.manualtest.StreamConfigurationView
+    <com.mobileer.oboetester.StreamConfigurationView
         android:id="@+id/outputStreamConfiguration"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center"
         android:orientation="horizontal" />
 
-    <com.google.sample.oboe.manualtest.BufferSizeView
+    <com.mobileer.oboetester.BufferSizeView
         android:id="@+id/buffer_size_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center"
         android:orientation="horizontal" />
 
-    <com.google.sample.oboe.manualtest.WorkloadView
+    <com.mobileer.oboetester.WorkloadView
         android:id="@+id/workload_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -97,3 +102,4 @@
         android:textStyle="bold" />
 
 </LinearLayout>
+</ScrollView>
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_tap_to_tone.xml b/apps/OboeTester/app/src/main/res/layout/activity_tap_to_tone.xml
index 9580399..6390e79 100644
--- a/apps/OboeTester/app/src/main/res/layout/activity_tap_to_tone.xml
+++ b/apps/OboeTester/app/src/main/res/layout/activity_tap_to_tone.xml
@@ -1,15 +1,22 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
+    android:fillViewport="true"
+    tools:context="com.mobileer.oboetester.TapToToneActivity"
+    >
+<LinearLayout
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
     android:orientation="vertical"
     android:paddingBottom="@dimen/activity_vertical_margin"
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
-    android:paddingTop="@dimen/activity_vertical_margin"
-    tools:context="com.google.sample.oboe.manualtest.TapToToneActivity">
+    android:paddingTop="@dimen/activity_vertical_margin">
 
-    <include layout="@layout/merge_audio_common"/>
+    <include layout="@layout/merge_audio_simple"/>
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -36,13 +43,13 @@
         android:lines="2"
         android:textSize="18sp"
         android:textStyle="bold"
-        android:text="@string/init_result" />
+        android:text="@string/tap_help" />
 
-    <com.google.sample.oboe.manualtest.WaveformView
+    <com.mobileer.oboetester.WaveformView
         android:id="@+id/waveview_audio"
         android:layout_width="fill_parent"
-        android:layout_height="fill_parent" />
-
-
+        android:layout_height="fill_parent"
+        android:minHeight="100dp"
+        />
 </LinearLayout>
-
+</ScrollView>
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_test_disconnect.xml b/apps/OboeTester/app/src/main/res/layout/activity_test_disconnect.xml
index fa11eed..cc417ec 100644
--- a/apps/OboeTester/app/src/main/res/layout/activity_test_disconnect.xml
+++ b/apps/OboeTester/app/src/main/res/layout/activity_test_disconnect.xml
@@ -8,13 +8,13 @@
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
     android:paddingTop="@dimen/activity_vertical_margin"
-    tools:context="com.google.sample.oboe.manualtest.TestDisconnectActivity">
+    tools:context="com.mobileer.oboetester.TestDisconnectActivity">
 
     <TextView
         android:id="@+id/text_instructions"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:lines="1"
+        android:lines="2"
         android:text="@string/test_disconnect_instructions"
         android:textColor="#F44336"
         android:textSize="18sp"
@@ -54,7 +54,7 @@
 
     </LinearLayout>
 
-    <com.google.sample.oboe.manualtest.AutomatedTestRunner
+    <com.mobileer.oboetester.AutomatedTestRunner
         android:id="@+id/auto_test_runner"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_test_input.xml b/apps/OboeTester/app/src/main/res/layout/activity_test_input.xml
index 925272d..27c99eb 100644
--- a/apps/OboeTester/app/src/main/res/layout/activity_test_input.xml
+++ b/apps/OboeTester/app/src/main/res/layout/activity_test_input.xml
@@ -1,38 +1,53 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
+    android:fillViewport="true"
+    tools:context="com.mobileer.oboetester.TestInputActivity"
+    >
+<LinearLayout
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
     android:orientation="vertical"
     android:paddingBottom="@dimen/activity_vertical_margin"
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
     android:paddingTop="@dimen/activity_vertical_margin"
-    tools:context="com.google.sample.oboe.manualtest.TestInputActivity">
+    >
 
     <include layout="@layout/merge_audio_common"/>
 
-    <com.google.sample.oboe.manualtest.VolumeBarView
+    <com.mobileer.oboetester.CommunicationDeviceView
+        android:id="@+id/comm_device_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:orientation="horizontal" />
+
+    <com.mobileer.oboetester.VolumeBarView
         android:id="@+id/volumeBar0"
         android:layout_marginBottom="4dp"
         android:layout_width="fill_parent"
         android:layout_height="20dp" />
 
-    <com.google.sample.oboe.manualtest.VolumeBarView
+    <com.mobileer.oboetester.VolumeBarView
         android:id="@+id/volumeBar1"
         android:layout_marginBottom="4dp"
         android:layout_width="fill_parent"
         android:layout_height="20dp" />
 
-    <com.google.sample.oboe.manualtest.VolumeBarView
+    <com.mobileer.oboetester.VolumeBarView
         android:id="@+id/volumeBar2"
         android:layout_marginBottom="4dp"
         android:layout_width="fill_parent"
         android:layout_height="20dp" />
 
-    <com.google.sample.oboe.manualtest.VolumeBarView
+    <com.mobileer.oboetester.VolumeBarView
         android:id="@+id/volumeBar3"
         android:layout_marginBottom="4dp"
         android:layout_width="fill_parent"
         android:layout_height="20dp" />
 </LinearLayout>
+</ScrollView>
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_test_output.xml b/apps/OboeTester/app/src/main/res/layout/activity_test_output.xml
index eda8a0c..639eae7 100644
--- a/apps/OboeTester/app/src/main/res/layout/activity_test_output.xml
+++ b/apps/OboeTester/app/src/main/res/layout/activity_test_output.xml
@@ -1,85 +1,152 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
+    android:fillViewport="true"
+    tools:context="com.mobileer.oboetester.TestOutputActivity"
+    >
+<LinearLayout
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
     android:orientation="vertical"
     android:paddingBottom="@dimen/activity_vertical_margin"
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
     android:paddingTop="@dimen/activity_vertical_margin"
-    tools:context="com.google.sample.oboe.manualtest.TestOutputActivity">
+    >
 
     <include layout="@layout/merge_audio_common"/>
 
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-
-        <TextView
-            android:id="@+id/channelText"
-            android:layout_width="wrap_content"
+    <HorizontalScrollView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+        <LinearLayout
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:text="Channels:" />
+            android:orientation="horizontal">
 
-        <CheckBox
-            android:id="@+id/channelBox0"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="onChannelBoxClicked"
-            android:text="0" />
+            <TextView
+                android:id="@+id/channelText"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Channels:" />
 
-        <CheckBox
-            android:id="@+id/channelBox1"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="onChannelBoxClicked"
-            android:text="1" />
+            <CheckBox
+                android:id="@+id/channelBox0"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="0" />
 
-        <CheckBox
-            android:id="@+id/channelBox2"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="onChannelBoxClicked"
-            android:text="2" />
+            <CheckBox
+                android:id="@+id/channelBox1"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="1" />
 
-        <CheckBox
-            android:id="@+id/channelBox3"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="onChannelBoxClicked"
-            android:text="3" />
+            <CheckBox
+                android:id="@+id/channelBox2"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="2" />
 
-        <CheckBox
-            android:id="@+id/channelBox4"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="onChannelBoxClicked"
-            android:text="4" />
+            <CheckBox
+                android:id="@+id/channelBox3"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="3" />
 
-        <CheckBox
-            android:id="@+id/channelBox5"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="onChannelBoxClicked"
-            android:text="5" />
+            <CheckBox
+                android:id="@+id/channelBox4"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="4" />
 
-        <CheckBox
-            android:id="@+id/channelBox6"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="onChannelBoxClicked"
-            android:text="6" />
+            <CheckBox
+                android:id="@+id/channelBox5"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="5" />
 
-        <CheckBox
-            android:id="@+id/channelBox7"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="onChannelBoxClicked"
-            android:text="7" />
+            <CheckBox
+                android:id="@+id/channelBox6"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="6" />
 
-    </LinearLayout>
+            <CheckBox
+                android:id="@+id/channelBox7"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="7" />
+
+            <CheckBox
+                android:id="@+id/channelBox8"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="8" />
+
+            <CheckBox
+                android:id="@+id/channelBox9"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="9" />
+
+            <CheckBox
+                android:id="@+id/channelBox10"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="10" />
+
+            <CheckBox
+                android:id="@+id/channelBox11"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="11" />
+
+            <CheckBox
+                android:id="@+id/channelBox12"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="12" />
+
+            <CheckBox
+                android:id="@+id/channelBox13"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="13" />
+
+            <CheckBox
+                android:id="@+id/channelBox14"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="14" />
+
+            <CheckBox
+                android:id="@+id/channelBox15"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="onChannelBoxClicked"
+                android:text="15" />
+
+        </LinearLayout>
+    </HorizontalScrollView>
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -96,4 +163,13 @@
             android:entries="@array/output_signals"
             android:prompt="@string/output_signal_prompt" />
     </LinearLayout>
+
+    <com.mobileer.oboetester.CommunicationDeviceView
+        android:id="@+id/comm_device_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:orientation="horizontal" />
+
 </LinearLayout>
+</ScrollView>
diff --git a/apps/OboeTester/app/src/main/res/layout/activity_test_plug_latency.xml b/apps/OboeTester/app/src/main/res/layout/activity_test_plug_latency.xml
new file mode 100644
index 0000000..4f6db22
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/layout/activity_test_plug_latency.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    tools:context="com.mobileer.oboetester.TestPlugLatencyActivity">
+
+    <TextView
+        android:id="@+id/text_instructions"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:lines="2"
+        android:text="Plug in and remove audio devices. The latency of the operation will be shown."
+        android:textColor="#F44336"
+        android:textSize="18sp"
+        android:textStyle="bold" />
+
+    <TextView
+        android:id="@+id/text_plug_events"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:lines="1"
+        android:text="plug #"
+        android:textSize="18sp"
+        android:textStyle="bold"
+        />
+
+    <ScrollView
+        android:id="@+id/text_log_device_scroller"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+        <TextView
+            android:id="@+id/text_log_device_report"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:fontFamily="monospace"
+            android:gravity="bottom"
+            android:scrollbars="vertical"
+            android:text=""
+            />
+    </ScrollView>
+</LinearLayout>
diff --git a/apps/OboeTester/app/src/main/res/layout/auto_test_runner.xml b/apps/OboeTester/app/src/main/res/layout/auto_test_runner.xml
index 05e030b..acbcb59 100644
--- a/apps/OboeTester/app/src/main/res/layout/auto_test_runner.xml
+++ b/apps/OboeTester/app/src/main/res/layout/auto_test_runner.xml
@@ -3,7 +3,7 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:orientation="vertical"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="wrap_content">
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -58,19 +58,23 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:minLines="2"
-        android:maxLines="12"
+        android:maxLines="13"
         android:text="@string/auto_default_status"
         android:textSize="18sp"
         android:textStyle="bold"
         />
-
+    <ScrollView
+        android:id="@+id/text_log_auto_scroller"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
     <TextView
-        android:id="@+id/text_log"
+        android:id="@+id/text_log_auto"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         android:scrollbars = "vertical"
         android:gravity="bottom"
         android:text="@string/log_of_test_results"
         />
+    </ScrollView>
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/apps/OboeTester/app/src/main/res/layout/buffer_size_view.xml b/apps/OboeTester/app/src/main/res/layout/buffer_size_view.xml
index 04d4fad..d4dc063 100644
--- a/apps/OboeTester/app/src/main/res/layout/buffer_size_view.xml
+++ b/apps/OboeTester/app/src/main/res/layout/buffer_size_view.xml
@@ -50,4 +50,4 @@
         android:progress="1000" />
 
     </LinearLayout>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/apps/OboeTester/app/src/main/res/layout/comm_device_view.xml b/apps/OboeTester/app/src/main/res/layout/comm_device_view.xml
new file mode 100644
index 0000000..6144f8c
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/layout/comm_device_view.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <CheckBox
+            android:id="@+id/setSpeakerphoneOn"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:checked="false"
+            android:text="setSpeakerphoneOn" />
+
+        <TextView
+            android:id="@+id/isSpeakerphoneOn"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text=" => ?" />
+
+    </LinearLayout>
+
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Comm Device: " />
+
+        <com.mobileer.audio_device.CommunicationDeviceSpinner
+            android:id="@+id/comm_devices_spinner"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/OboeTester/app/src/main/res/layout/input_margin_view.xml b/apps/OboeTester/app/src/main/res/layout/input_margin_view.xml
index b921aa6..7209c48 100644
--- a/apps/OboeTester/app/src/main/res/layout/input_margin_view.xml
+++ b/apps/OboeTester/app/src/main/res/layout/input_margin_view.xml
@@ -51,4 +51,4 @@
             android:onClick="onMarginBoxClicked"
             android:text="4" />
     </RadioGroup>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/apps/OboeTester/app/src/main/res/layout/merge_audio_common.xml b/apps/OboeTester/app/src/main/res/layout/merge_audio_common.xml
index 3767e3c..cee7bed 100644
--- a/apps/OboeTester/app/src/main/res/layout/merge_audio_common.xml
+++ b/apps/OboeTester/app/src/main/res/layout/merge_audio_common.xml
@@ -2,21 +2,21 @@
 <merge xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent" android:layout_height="match_parent">
 
-    <com.google.sample.oboe.manualtest.StreamConfigurationView
+    <com.mobileer.oboetester.StreamConfigurationView
         android:id="@+id/streamConfiguration"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center"
         android:orientation="horizontal" />
 
-    <com.google.sample.oboe.manualtest.BufferSizeView
+    <com.mobileer.oboetester.BufferSizeView
         android:id="@+id/buffer_size_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center"
         android:orientation="horizontal" />
 
-    <com.google.sample.oboe.manualtest.WorkloadView
+    <com.mobileer.oboetester.WorkloadView
         android:id="@+id/workload_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -33,6 +33,8 @@
             android:layout_width="0dp"
             android:layout_weight="1"
             android:layout_height="wrap_content"
+            android:backgroundTint="@xml/button_color_selector"
+            android:backgroundTintMode="src_atop"
             android:onClick="openAudio"
             android:text="@string/openAudio" />
 
@@ -41,6 +43,8 @@
             android:layout_width="0dp"
             android:layout_weight="1"
             android:layout_height="wrap_content"
+            android:backgroundTint="@xml/button_color_selector"
+            android:backgroundTintMode="src_atop"
             android:onClick="startAudio"
             android:text="@string/startAudio" />
 
@@ -49,6 +53,8 @@
             android:layout_width="0dp"
             android:layout_weight="1"
             android:layout_height="wrap_content"
+            android:backgroundTint="@xml/button_color_selector"
+            android:backgroundTintMode="src_atop"
             android:onClick="pauseAudio"
             android:text="@string/pauseAudio" />
 
@@ -57,6 +63,8 @@
             android:layout_width="0dp"
             android:layout_weight="1"
             android:layout_height="wrap_content"
+            android:backgroundTint="@xml/button_color_selector"
+            android:backgroundTintMode="src_atop"
             android:onClick="stopAudio"
             android:text="@string/stopAudio" />
 
@@ -65,6 +73,8 @@
             android:layout_width="0dp"
             android:layout_weight="1"
             android:layout_height="wrap_content"
+            android:backgroundTint="@xml/button_color_selector"
+            android:backgroundTintMode="src_atop"
             android:onClick="closeAudio"
             android:text="@string/closeAudio" />
 
diff --git a/apps/OboeTester/app/src/main/res/layout/merge_audio_simple.xml b/apps/OboeTester/app/src/main/res/layout/merge_audio_simple.xml
new file mode 100644
index 0000000..f989b99
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/layout/merge_audio_simple.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent" android:layout_height="match_parent">
+
+    <com.mobileer.oboetester.StreamConfigurationView
+        android:id="@+id/streamConfiguration"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:orientation="horizontal" />
+
+    <com.mobileer.oboetester.BufferSizeView
+        android:id="@+id/buffer_size_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:orientation="horizontal" />
+
+    <com.mobileer.oboetester.WorkloadView
+        android:id="@+id/workload_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:orientation="horizontal" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/button_start"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@xml/button_color_selector"
+            android:backgroundTintMode="src_atop"
+            android:onClick="startTest"
+            android:text="@string/startAudio" />
+
+        <Button
+            android:id="@+id/button_stop"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="wrap_content"
+            android:backgroundTint="@xml/button_color_selector"
+            android:backgroundTintMode="src_atop"
+            android:onClick="stopTest"
+            android:text="@string/stopAudio" />
+
+    </LinearLayout>
+
+</merge>
diff --git a/apps/OboeTester/app/src/main/res/layout/sample_fast_button.xml b/apps/OboeTester/app/src/main/res/layout/sample_fast_button.xml
index f092b5a..8610d16 100644
--- a/apps/OboeTester/app/src/main/res/layout/sample_fast_button.xml
+++ b/apps/OboeTester/app/src/main/res/layout/sample_fast_button.xml
@@ -1,9 +1,9 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res/com.google.sample.oboe.manualtest"
+    xmlns:app="http://schemas.android.com/apk/res/com.mobileer.oboetester"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <com.google.sample.oboe.manualtest.FastButton
+    <com.mobileer.oboetester.FastButton
         android:layout_width="300dp"
         android:layout_height="300dp"
         android:background="#ccc"
diff --git a/apps/OboeTester/app/src/main/res/layout/stream_config.xml b/apps/OboeTester/app/src/main/res/layout/stream_config.xml
index 16aab9d..9609fd0 100644
--- a/apps/OboeTester/app/src/main/res/layout/stream_config.xml
+++ b/apps/OboeTester/app/src/main/res/layout/stream_config.xml
@@ -53,7 +53,7 @@
                     android:layout_height="wrap_content"
                     android:text="Device: " />
 
-                <com.google.sample.audio_device.AudioDeviceSpinner
+                <com.mobileer.audio_device.AudioDeviceSpinner
                     android:id="@+id/devices_spinner"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"/>
@@ -109,6 +109,27 @@
                 <TextView
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
+                    android:text="@string/channel_mask_prompt" />
+
+                <Spinner
+                    android:id="@+id/spinnerChannelMask"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:prompt="@string/channel_mask_prompt" />
+
+                <TextView
+                    android:id="@+id/actualChannelMask"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="\?" />
+
+            </TableRow>
+
+            <TableRow>
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
                     android:text="@string/format_prompt"/>
 
                 <Spinner
@@ -169,6 +190,51 @@
                     android:text="\?" />
 
             </TableRow>
+
+            <TableRow
+                android:id="@+id/rowUsage">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/usage_prompt"/>
+
+                <Spinner
+                    android:id="@+id/spinnerUsage"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:entries="@array/audio_usages" />
+
+                <TextView
+                    android:id="@+id/actualUsage"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="\?" />
+
+            </TableRow>
+
+            <TableRow
+                android:id="@+id/rowContentType">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Content Type:"/>
+
+                <Spinner
+                    android:id="@+id/spinnerContentType"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:entries="@array/audio_content_types" />
+
+                <TextView
+                    android:id="@+id/actualContentType"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="\?" />
+
+            </TableRow>
+
         </TableLayout>
 
         <LinearLayout
@@ -227,6 +293,63 @@
         </LinearLayout>
 
         <LinearLayout
+            android:id="@+id/inputEffects"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:visibility="gone">
+
+            <CheckBox
+                android:id="@+id/checkBoxAutomaticGainControl"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginRight="8sp"
+                android:text="Automatic Gain Control" />
+
+            <CheckBox
+                android:id="@+id/checkBoxAcousticEchoCanceler"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginRight="8sp"
+                android:text="Acoustic Echo Canceler" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/outputEffects"
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone">
+
+            <TextView
+                android:id="@+id/textBassBoost"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Bass Boost" />
+
+            <SeekBar
+                android:id="@+id/seekBarBassBoost"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:max="1000"
+                android:progress="0" />
+
+            <TextView
+                android:id="@+id/textLoudnessEnhancer"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Loudness Enhancer" />
+
+            <SeekBar
+                android:id="@+id/seekBarLoudnessEnhancer"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:max="5000"
+                android:progress="0" />
+        </LinearLayout>
+
+        <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:orientation="horizontal">
@@ -272,7 +395,7 @@
             android:id="@+id/statusView"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:lines="4"
+            android:lines="5"
             android:text="@string/init_status" />
     </LinearLayout>
 
diff --git a/apps/OboeTester/app/src/main/res/layout/workload_view.xml b/apps/OboeTester/app/src/main/res/layout/workload_view.xml
index 2c8f2ed..2cb90bb 100644
--- a/apps/OboeTester/app/src/main/res/layout/workload_view.xml
+++ b/apps/OboeTester/app/src/main/res/layout/workload_view.xml
@@ -17,4 +17,4 @@
         android:max="1000"
         android:progress="0" />
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/apps/OboeTester/app/src/main/res/menu/menu_main.xml b/apps/OboeTester/app/src/main/res/menu/menu_main.xml
index 51f264b..d2a67ee 100644
--- a/apps/OboeTester/app/src/main/res/menu/menu_main.xml
+++ b/apps/OboeTester/app/src/main/res/menu/menu_main.xml
@@ -1,5 +1,5 @@
 <menu xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools" tools:context="com.google.sample.oboe.manualtest.TapToToneActivity">
+    xmlns:tools="http://schemas.android.com/tools" tools:context="com.mobileer.oboetester.TapToToneActivity">
     <item android:id="@+id/action_settings" android:title="@string/action_settings"
         android:orderInCategory="100" android:showAsAction="never" />
 </menu>
diff --git a/apps/OboeTester/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/apps/OboeTester/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..bbd3e02
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background"/>
+    <foreground android:drawable="@drawable/ic_launcher_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/apps/OboeTester/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/apps/OboeTester/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..bbd3e02
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background"/>
+    <foreground android:drawable="@drawable/ic_launcher_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/apps/OboeTester/app/src/main/res/mipmap-hdpi/ic_launcher.png b/apps/OboeTester/app/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index cde69bc..0000000
--- a/apps/OboeTester/app/src/main/res/mipmap-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/apps/OboeTester/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/apps/OboeTester/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..bc6229f
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/apps/OboeTester/app/src/main/res/mipmap-mdpi/ic_launcher.png b/apps/OboeTester/app/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index c133a0c..0000000
--- a/apps/OboeTester/app/src/main/res/mipmap-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/apps/OboeTester/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/apps/OboeTester/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..bf6cd2c
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/apps/OboeTester/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/apps/OboeTester/app/src/main/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index bfa42f0..0000000
--- a/apps/OboeTester/app/src/main/res/mipmap-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/apps/OboeTester/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/apps/OboeTester/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..538f152
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/apps/OboeTester/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/apps/OboeTester/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 324e72c..0000000
--- a/apps/OboeTester/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/apps/OboeTester/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/apps/OboeTester/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..0dc60de
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/apps/OboeTester/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/apps/OboeTester/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..127d162
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/apps/OboeTester/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/apps/OboeTester/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..60f7116
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/apps/OboeTester/app/src/main/res/values/arrays.xml b/apps/OboeTester/app/src/main/res/values/arrays.xml
index 55344e5..045e125 100644
--- a/apps/OboeTester/app/src/main/res/values/arrays.xml
+++ b/apps/OboeTester/app/src/main/res/values/arrays.xml
@@ -1,3 +1,3 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/apps/OboeTester/app/src/main/res/values/attrs_waveform.xml b/apps/OboeTester/app/src/main/res/values/attrs_waveform.xml
index 69b1940..4dcb7ea 100644
--- a/apps/OboeTester/app/src/main/res/values/attrs_waveform.xml
+++ b/apps/OboeTester/app/src/main/res/values/attrs_waveform.xml
@@ -19,4 +19,4 @@
        <attr name="showZero"
            format="boolean" />
    </declare-styleable>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/apps/OboeTester/app/src/main/res/values/colors.xml b/apps/OboeTester/app/src/main/res/values/colors.xml
index fb81fc2..fbef9c5 100644
--- a/apps/OboeTester/app/src/main/res/values/colors.xml
+++ b/apps/OboeTester/app/src/main/res/values/colors.xml
@@ -19,4 +19,5 @@
     <color name="waveform_background">#ffc0f0c0</color>
     <color name="version_draft">#ffffb0b0</color>
     <color name="version_release">#fff0f0f0</color>
+    <color name="button_tint">#ffe0f0e0</color>
 </resources>
diff --git a/apps/OboeTester/app/src/main/res/values/strings.xml b/apps/OboeTester/app/src/main/res/values/strings.xml
index 6ad1537..a89ed94 100644
--- a/apps/OboeTester/app/src/main/res/values/strings.xml
+++ b/apps/OboeTester/app/src/main/res/values/strings.xml
@@ -1,8 +1,9 @@
 <resources>
     <string name="app_name">Oboe Tester</string>
+    <string name="app_name_version">Oboe Tester,(%d) v %s, Oboe v %d.%d.%d"</string>
     <string name="init_device">Device:</string>
     <string name="init_status">Status:</string>
-    <string name="init_result">Result:</string>
+    <string name="tap_help">Click START button!</string>
     <string name="action_settings">Settings</string>
     <string name="openAudio">Open</string>
     <string name="startAudio">Start</string>
@@ -13,12 +14,21 @@
     <string name="playAudio">Play</string>
     <string name="measure">Measure</string>
     <string name="cancel">Cancel</string>
+    <string name="clear">Clear</string>
 
     <string name="GetParam">Get Param</string>
     <string name="device_name">Device Name</string>
     <string name="auto_select">Auto select</string>
     <string name="hint_hide_settings">Hide Settings</string>
     <string name="hint_show_settings">Show Settings</string>
+    <string name="please_wait">Measuring, please wait...</string>
+    <string name="tap_to_tone_instructions">
+        Tap in green box!\nNo tap-to-tone results yet.
+    </string>
+    <string name="external_tap_instructions">
+        Trigger sound on other device.\nThen quickly tap ANALYZE.
+    </string>
+    <string name="no_double_tap">Please do not tap while measuring.</string>
     <string name="loopback_instructions_glitch">
         Click Show Settings to configure.\n
         This glitch measurement plays\n
@@ -76,6 +86,8 @@
         <item>Unspecified</item>
         <item>PCM_I16</item>
         <item>PCM_FLOAT</item>
+        <item>PCM_I24</item>
+        <item>PCM_I32</item>
     </string-array>
 
     <string name="input_preset_prompt">InPreset:</string>
@@ -88,6 +100,31 @@
         <item>Performance</item>
     </string-array>
 
+    <string name="usage_prompt">Usage:</string>
+    <string-array name="audio_usages">
+        <item>Unspecified</item>
+        <item>Media</item>
+        <item>VoiceComm</item>
+        <item>VoiceCommSig</item>
+        <item>Alarm</item>
+        <item>Notification</item>
+        <item>Ringtone</item>
+        <item>Event</item>
+        <item>Accessability</item>
+        <item>Navigation</item>
+        <item>Sonification</item>
+        <item>Game</item>
+        <item>Assistant</item>
+    </string-array>
+
+    <string-array name="audio_content_types">
+        <item>Unspecified</item>
+        <item>Speech</item>
+        <item>Music</item>
+        <item>Movie</item>
+        <item>Sonification</item>
+    </string-array>
+
     <string name="channel_count_prompt">Channels:</string>
     <string-array name="channel_counts">
         <item>0</item>
@@ -100,6 +137,10 @@
         <item>7</item>
         <item>8</item>
         <item>9</item>
+        <item>10</item>
+        <item>11</item>
+        <item>12</item>
+        <item>13</item>
     </string-array>
 
     <string-array name="glitch_times">
@@ -117,13 +158,14 @@
         <item>LOW_LATENCY</item>
     </string-array>
 
-<!--Must match SignalType in NativeAudioContext.h-->
+    <!--Must match SignalType in NativeAudioContext.h-->
     <string name="output_signal_prompt">choose a signal</string>
     <string-array name="output_signals">
         <item>Sine</item>
         <item>Sawtooth</item>
         <item>Freq Sweep</item>
         <item>Pitch Sweep</item>
+        <item>White Noise</item>
     </string-array>
 
     <string name="synth_sender_text">Select Sender for Synth</string>
@@ -143,8 +185,9 @@
     <string name="title_activity_glitches">Test Glitches</string>
     <string name="title_activity_auto_glitches">Auto Glitches</string>
     <string name="title_test_disconnect">Test Disconnect</string>
-    <string name="title_report_devices">Report Devices</string>
+    <string name="title_report_devices">Device Report</string>
     <string name="title_data_paths">Data Paths</string>
+    <string name="title_extra_tests">Extra Tests</string>
 
     <string name="need_record_audio_permission">"This app needs RECORD_AUDIO permission"</string>
     <string name="share">Share</string>
@@ -152,6 +195,9 @@
     <string name="duration">Duration:</string>
     <string name="auto_default_status">Status...</string>
     <string name="device_report">Device Report</string>
+    <string name="plug_or_unplug">Plug in or Unplug a Headset</string>
+    <string name="report_magic_pass">PASS, got %X"</string>
+    <string name="report_magic_fail">FAIL, got %X, expected %X"</string>
     <string name="log_of_test_results">Log of Test Results</string>
     <string name="save_file">Save</string>
 
@@ -159,7 +205,12 @@
     <string name="average">Average</string>
     <string name="failTest">Fail</string>
     <string name="skipTest">Skip</string>
-    <string name="test_disconnect_instructions">Unplug headsets, volume up, [START]</string>
+    <string name="test_datapath_instructions">Disconnect all headsets.\nIn quiet room, volume up, [START]</string>
+    <string name="test_disconnect_instructions">Disconnect all headsets.\nPress [START]</string>
+    <string name="title_external_tap">External Tap To Tone</string>
+    <string name="title_plug_latency">Plug Latency Test</string>
+    <string name="title_error_callback">Error Callback Test</string>
+    <string name="analyze">Analyze</string>
 
     <string-array name="conversion_qualities">
         <item>None</item>
@@ -170,4 +221,6 @@
         <item>Best</item>
     </string-array>
 
+    <string name="channel_mask_prompt">ChannelMask:</string>
+
 </resources>
diff --git a/apps/OboeTester/app/src/main/res/xml/button_color_selector.xml b/apps/OboeTester/app/src/main/res/xml/button_color_selector.xml
new file mode 100644
index 0000000..451d33e
--- /dev/null
+++ b/apps/OboeTester/app/src/main/res/xml/button_color_selector.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:color="#3f000000"/>
+    <item android:state_focused="true" android:color="#0f000000"/>
+</selector>
diff --git a/apps/OboeTester/app/src/main/res/xml/provider_paths.xml b/apps/OboeTester/app/src/main/res/xml/provider_paths.xml
index ffa74ab..4ff8931 100644
--- a/apps/OboeTester/app/src/main/res/xml/provider_paths.xml
+++ b/apps/OboeTester/app/src/main/res/xml/provider_paths.xml
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <paths xmlns:android="http://schemas.android.com/apk/res/android">
     <external-path name="external_files" path="."/>
-</paths>
\ No newline at end of file
+</paths>
diff --git a/apps/OboeTester/app/src/main/res/xml/service_device_info.xml b/apps/OboeTester/app/src/main/res/xml/service_device_info.xml
index 1cebab7..09f49f5 100644
--- a/apps/OboeTester/app/src/main/res/xml/service_device_info.xml
+++ b/apps/OboeTester/app/src/main/res/xml/service_device_info.xml
@@ -12,7 +12,8 @@
 -->
 
 <devices>
-    <device manufacturer="AndroidTest" product="AudioLatencyTester">
+    <!-- These must match the values in MidiTaptester.java -->
+    <device manufacturer="Mobileer" product="MidiTapLatencyTester">
         <input-port name="input" />
     </device>
 </devices>
diff --git a/apps/OboeTester/build.gradle b/apps/OboeTester/build.gradle
index c5dded3..3e8fe4d 100644
--- a/apps/OboeTester/build.gradle
+++ b/apps/OboeTester/build.gradle
@@ -6,7 +6,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:4.0.0'
+        classpath 'com.android.tools.build:gradle:7.2.2'
     }
 }
 
diff --git a/apps/OboeTester/docs/AutomatedTesting.md b/apps/OboeTester/docs/AutomatedTesting.md
index 77a5096..ebe4f34 100644
--- a/apps/OboeTester/docs/AutomatedTesting.md
+++ b/apps/OboeTester/docs/AutomatedTesting.md
@@ -2,27 +2,36 @@
 
 # Automated Testing
 
-OboeTester can be used to measure the round trip latency and glitches. 
+OboeTester can be used to measure the round trip latency and glitches.
 It can be launched from a shell script by using an Android Intent.
 
 Before running the app from an Intent, it should be launched manually and a Round Trip Latency test run. Then you can give permission for using the microphone to record the looped back sound, and give permission to write to external storage for saving the test result.
 
 ## Requirements
 
+All tests require:
+
 * host computer
+* ADB installed
 * ADB USB cable
+  
+The latency, glitch and data_paths tests also need:
+
 * [loopback adapter](https://source.android.com/devices/audio/latency/loopback)
 * a 3.5 mm jack on the phone*
 
-\* If you don't have a 3.5 mm jack then you can use a USB-C to 3.5mm adapter. Then you will also need a USB switching device such as [TigerTail](https://go/tigertail).
+\* If you don't have a 3.5 mm jack then you can use a USB-C to 3.5mm adapter.
+In order to use ADB at the same time you will also need a USB switching device
+or  use ADB/Wifi.
+Internally at Google, the [TigerTail](https://go/tigertail) device can be used for USB.
 
 ## Start App from Intent
 
 The app can be started by sending a Start comment to the OboeTester class.
 The app will run and the results will be written to a file.
 
-    adb shell am start -n com.google.sample.oboe.manualtest/.MainActivity {parameters}
-    
+    adb shell am start -n com.mobileer.oboetester/.MainActivity {parameters}
+
 String parameters are sent using:
 
     --es {parameterName} {parameterValue}
@@ -34,55 +43,95 @@
 Integer parameters are sent using:
 
     --ei {parameterName} {parameterValue}
-    
+
 For example:
 
     --ei buffer_bursts 8
 
+Boolean parameters are sent using:
+
+    --ez {parameterName} {parameterValue}
+
+For example:
+
+    --ez use_input_devices false
+
 ## Parameters
 
-There are two required parameters:
+There are two required parameters for all tests:
 
-    --es test {latency, glitch}
+    --es test {latency, glitch, data_paths, input, output}
             The "latency" test will perform a Round Trip Latency test.
             It will request EXCLUSIVE mode for minimal latency.
             The "glitch" test will perform a single Glitch test.
-    --es file {full path for resulting file}
-    
-There are several optional parameter in common for all tests:
+            The "data_paths" test will verify input and output streams in many possible configurations.
+            The "input" test will open and start an input stream.
+            The "output" test will open and start an output stream.
+
+    --es file {full path for resulting file} // We recommend using the "/sdcard/Download" folder
+
+There are some optional parameter in common for all tests:
+
+    --ef volume             {volume} // normalized volume in the range of 0.0 to 1.0
+    --es volume_type        {"accessibility", "alarm", "dtmf", "music", "notification", "ring", "system", "voice_call"}
+                            Stream type for the setStreamVolume() call. Default is "music".
+    --ez background         {"true", 1, "false", 0} // if true then Oboetester will continue to run in the background
+
+There are several optional parameters in common for glitch, latency, input, and output tests:
 
     --ei buffer_bursts      {bursts}     // number of bursts in the buffer, 2 for "double buffered"
     --es in_api             {"unspecified", "opensles", "aaudio"}  // native input API, default is "unspecified"
     --es out_api            {"unspecified", "opensles", "aaudio"}  // native output API, default is "unspecified"
-    --ei in_channels        {samples}    // number of input channels, default is 2
-    --ei out_channels       {samples}    // number of output channels, default is 2
+    --es in_channel_mask    {"mono", "stereo", "2.1", "tri", "triBack", "3.1", "2.0.2", "2.1.2", "3.0.2", "3.1.2", "quad", "quadSide", "surround", "penta", "5.1", "5.1Side", "6.1", "7.1", "5.1.2", "5.1.4", "7.1.2", "7.1.4", "9.1.4", "9.1.6", "frontBack"}
+    --es out_channel_mask    {"mono", "stereo", "2.1", "tri", "triBack", "3.1", "2.0.2", "2.1.2", "3.0.2", "3.1.2", "quad", "quadSide", "surround", "penta", "5.1", "5.1Side", "6.1", "7.1", "5.1.2", "5.1.4", "7.1.2", "7.1.4", "9.1.4", "9.1.6", "frontBack"}
+    --ei in_channels        {samples}    // number of input channels, default is 2. This is ignored if in_channel_mask is set.
+    --ei out_channels       {samples}    // number of output channels, default is 2. This is ignored if out_channel_mask is set.
     --ei sample_rate        {hertz}
     --es in_perf            {"none", "lowlat", "powersave"}  // input performance mode, default is "lowlat"
     --es out_perf           {"none", "lowlat", "powersave"}  // output performance mode, default is "lowlat"
     --es in_sharing         {"shared", "exclusive"} // input sharing mode, default is "exclusive"
     --es out_sharing        {"shared", "exclusive"} // output sharing mode, default is "exclusive"
-    
+    --ez in_use_mmap        {"true", 1, "false", 0} // if true then MMAP is allowed, if false then MMAP will be disabled
+    --ez out_use_mmap       {"true", 1, "false", 0} // if true then MMAP is allowed, if false then MMAP will be disabled
+
+There are some optional parameters in common for glitch, input, and output tests:
+
+    --ei duration           {seconds}    // glitch test duration, default is 10 seconds
+
 There are several optional parameters for just the "glitch" test:
 
     --ef tolerance          {tolerance}  // amount of deviation from expected that is considered a glitch
                                          // Range of tolerance is 0.0 to 1.0. Default is 0.1. Note use of "-ef".
-    --ei duration           {seconds}    // glitch test duration, default is 10 seconds
                             // input preset, default is "voicerec"
     --es in_preset          ("generic", "camcorder", "voicerec", "voicecomm", "unprocessed", "performance"}
 
+There are several optional parameters for just the "data_paths" test:
+
+    --ez use_input_presets  {"true", 1, "false", 0}  // Whether to test various input presets. Note use of "-ez"
+    --ez use_input_devices  {"true", 1, "false", 0}  // Whether to test various input devices. Note use of "-ez"
+    --ez use_output_devices {"true", 1, "false", 0}  // Whether to test various output devices. Note use of "-ez"
+    --ei single_test_index  {testId}  // Index for testing one specific test
+
+There are some optional parameters for just the "output" test:
+
+    --es signal_type        {sine, sawtooth, freq_sweep, pitch_sweep, white_noise} // type of sound to play, default is sine
+
 For example, a complete command for a "latency" test might be:
 
-    adb shell am start -n com.google.sample.oboe.manualtest/.MainActivity \
+    adb shell am start -n com.mobileer.oboetester/.MainActivity \
         --es test latency \
-        --es file /sdcard/latency20190903.txt \
+        --es file /sdcard/Download/latency20190903.txt \
+        --ei buffer_bursts 2 \
+        --ef volume 0.8 \
+        --es volume_type music \
         --ei buffer_bursts 2 \
         --ei out_channels 1
-        
+
 or for a "glitch" test:
 
-    adb shell am start -n com.google.sample.oboe.manualtest/.MainActivity \
+    adb shell am start -n com.mobileer.oboetester/.MainActivity \
         --es test glitch \
-        --es file /sdcard/glitch20190903.txt \
+        --es file /sdcard/Download/glitch20190903.txt \
         --es in_perf lowlat \
         --es out_perf lowlat \
         --es in_sharing exclusive \
@@ -92,14 +141,23 @@
         --ef tolerance 0.123 \
         --ei in_channels 2 \
 
+or for a "data_paths" test:
+
+    adb shell am start -n com.mobileer.oboetester/.MainActivity \
+        --es test data_paths \
+        --es file /sdcard/data_paths20190903.txt
+        --ez use_input_presets true
+        --ez use_input_devices false
+        --ez use_output_devices true
+
 ## Interpreting Test Results
 
 Test results are simple files with "name = value" pairs.
 The test results can be obtained using adb pull.
 
     adb pull /sdcard/test20190611.txt .
-    
-The beginning of the report is common to all tests:
+
+The beginning of the report is common to latency and glitch tests:
 
     build.fingerprint = google/bonito/bonito:10/QP1A.190711.017/5771233:userdebug/dev-keys
     test.version = 1.5.10
@@ -151,7 +209,7 @@
     result = -96
     result.text = ERROR_CONFIDENCE
     confidence =  0.009
-        
+
 ### Glitch Report
 
 Here is a report from a good test. The '#' comments were added for this document and are not in the report.
@@ -165,10 +223,10 @@
     peak.amplitude = 0.057714  # peak amplitude of the input signal, between 0.0 and 1.0
     signal.noise.ratio.db =  96.3
     time.total =     9.96 seconds  # close to your specified duration
-    time.no.glitches =     9.96    # time we have been running with no glitches 
+    time.no.glitches =     9.96    # time we have been running with no glitches
     max.time.no.glitches =     9.96 # max time with no glitches
     glitch.count = 0               # number of glitch events, actual number may be higher if close together
-    
+
 Here is a report from a test that failed because the output was muted. Note the glitch.count is missing because it could not be measured.
 
     state = WAITING_FOR_SIGNAL
@@ -177,3 +235,11 @@
     glitch.frames = 0
     reset.count = 1
     time.total =     9.95 seconds
+
+### Data Paths Report
+
+The report first goes through the info about the specific device before going through input preset tests,
+input devices tests, and output tests.
+Each will show the specific configuration of a test before showing whether it passed or failed.
+At the end of the report, an analysis of the failed tests will be given
+followed by the number of passed, failed, and skipped tests.
diff --git a/apps/OboeTester/docs/Build.md b/apps/OboeTester/docs/Build.md
index 9be3611..e4baf13 100644
--- a/apps/OboeTester/docs/Build.md
+++ b/apps/OboeTester/docs/Build.md
@@ -2,6 +2,9 @@
 
 # How to Build OboeTester
 
+Note that you can now [download OboeTester from the Play Store](https://play.google.com/store/apps/details?id=com.mobileer.oboetester).
+
+But if you want the latest version, or if you want to debug OboeTester, then you can build it using Android Studio.
 Download the top level oboe repository from GitHub.
 Then use Android Studio (3.3 or above) to build the app in this "apps/OboeTester".
 
diff --git a/apps/OboeTester/docs/PrivacyPolicy.md b/apps/OboeTester/docs/PrivacyPolicy.md
new file mode 100644
index 0000000..f1f2f86
--- /dev/null
+++ b/apps/OboeTester/docs/PrivacyPolicy.md
@@ -0,0 +1,39 @@
+[Home](README.md)
+
+# OboeTester Privacy Policy
+
+## Recorded Audio
+
+[OboeTester](README.md) can record audio.
+The data is only used to test the audio recording capability of your device.
+These tests include:
+
+* measuring round-trip audio latency
+* measuring glitches by listening to an output sine wave
+* recording audio for immediate playback and listening
+
+Audio recording is always initiated by a button press.
+
+It is possible for you, the user, to share WAV files that have been recorded.
+You can email them to someone, or upload them to Google Drive, or send them to other Sharing destinations.
+This is optional. No recorded audio is uploaded or saved by the program unless the user requests it.
+
+## Phone State
+
+OboeTester can also check and modify the phone state. This is only used for testing modes like "Speaker Phone" or turning on or off Bluetooth SCO.
+
+## Test Results
+
+The user can ask OboeTester to run automated tests that look for audio bugs or measure performance.
+These generate reports that contain the results of the test plus information about the phone including:
+
+* manufacturer (eg. Samsung)
+* model (eg. S10)
+* version and build information (eg. Pie 9.0)
+* audio performance metrics (eg. latency, glitch rate)
+* audio feature support (eg. AAudio MMAP)
+
+But you, the user, can can email them to someone, or upload them to Google Drive, or send them to other Sharing destinations.
+This is optional. No reports are uploaded or saved by the program unless the user requests it.
+
+The source code for Oboetester is available [here](https://github.com/google/oboe/tree/main/apps/OboeTester) on GitHub.
diff --git a/apps/OboeTester/docs/README.md b/apps/OboeTester/docs/README.md
index f6c219b..81db8b1 100644
--- a/apps/OboeTester/docs/README.md
+++ b/apps/OboeTester/docs/README.md
@@ -6,8 +6,14 @@
 OboeTester can be run as an interactive app.
 It can also be run as part of an [automated test using Intents](AutomatedTesting.md)
 
-## [How to Build OboeTester](Build.md)
+## Install OboeTester
+
+You have two options:
+1) Download OboeTester from [Play Store](https://play.google.com/store/apps/details?id=com.mobileer.oboetester)
+2) OR [Build latest OboeTester using Android Studio](Build.md)
 
 ## [How to Use OboeTester Interactively](Usage.md)
 
 ## [Automated Testing with OboeTester](AutomatedTesting.md)
+
+-- [Privacy Policy](PrivacyPolicy.md) --
diff --git a/apps/OboeTester/docs/TestOutput.md b/apps/OboeTester/docs/TestOutput.md
new file mode 100644
index 0000000..9e7e539
--- /dev/null
+++ b/apps/OboeTester/docs/TestOutput.md
@@ -0,0 +1,30 @@
+# Test Output
+
+DRAFT for testing image embedding.
+
+
+<table style="width:100%">
+  <tr>
+    <th>Notes</th>
+    <th>Screenshot</th> 
+  </tr>
+  <tr>
+    <td>
+      Tap on the green bar to hide or show the detailed settings dialog.<br/>
+      The resulting setting will displayed on the far right when the stream is opened.<br/>
+      API: select between OpenSL ES or AAudio (default)<br/>
+      Device: setect output device by type.<br/>
+      Format: note that the 24 and 32-bit formats are only supported in Android 12+<br/>
+      MMAP: will be disabled if device does not support MMAP<br/>
+      Effect: will enable a simple effect, may prevent LOW_LATENCY<br/>
+      Convert: conversion done in Oboe may allow you to get LOW_LATENCY<br/>
+      SRC: sample rate conversion quality<br/>
+      <br/><br/><br/><br/><br/><br/><br/><br/>
+    </td>
+    <td><img src="/apps/OboeTester/docs/images/test_output.png" width=400></td>
+  </tr>
+</table>
+
+
+
+
diff --git a/apps/OboeTester/docs/Usage.md b/apps/OboeTester/docs/Usage.md
index dcedfc6..050e834 100644
--- a/apps/OboeTester/docs/Usage.md
+++ b/apps/OboeTester/docs/Usage.md
@@ -2,6 +2,13 @@
 
 # How to Use OboeTester
 
+## Loopback Adapter Needed for Some Tests
+
+Some of these tests require an [audio Loopback Adapter](https://source.android.com/devices/audio/latency/loopback) that plugs into a 3.5 mm jack.
+If the phone does not have a 3.5 mm jack then you can combine that with a USB to 3.5mm adapter.
+
+Loopback adapters can be purchased from [PassMark Software](https://www.passmark.com/products/audio-loopback-plug/). 
+
 ## Test Activities
 
 Launch OboeTester and then select one of the test Activities.
@@ -22,7 +29,13 @@
 The audio is expected to glitch when the workload is high because there is too much work
 and the audio task misses its delivery deadlines.
 
-The extra workload is generated by calculating a random number in a loop and then adding the result to the output at an inaudible level. This technique prevents the compiler optimizer from skipping the work.
+The extra workload is generated by calculating a random number in a loop and then adding the result to the output at an inaudible level. This technique prevents the compiler optimizer from skipping the work. The workload fader is in arbitrary units that determines the number of loops.
+You can see the affect of the changing workload in the "% cpu" report in the status area.
+The extra workload will always cause glitching when you get close to 100% CPU load.
+If the workload is causing glitching at a low % CPU load then there may be a problem with the callback timing.
+
+Instructions for using TEST OUTPUT for 4 or more chanels is in
+[Wiki/OboeTester_MultiChannelOutput](https://github.com/google/oboe/wiki/OboeTester_MultiChannelOutput).
 
 ### Test Input
 
@@ -34,9 +47,13 @@
 Open, Start, then tap on the screen with your fingertip.
 The app will listen for the sound of your fingernail tapping the screen
 and the resulting beep, and then measure the time between them.
+
 If you use headphones then you can eliminate the latency caused by speaker protection.
 If you use USB-MIDI input then you can eliminate the latency due to the touch screen, which is around 15-30 msec.
 MIDI latency is generally under 1 msec.
+This test works well for measuring the latency of Bluetooth headsets.
+
+More instructions in the [Wiki/OboeTester_TapToTone](https://github.com/google/oboe/wiki/OboeTester_TapToTone).
 
 ### Record and Play
 
@@ -59,11 +76,19 @@
 This test works with either a [loopback adapter](https://source.android.com/devices/audio/latency/loopback) or through speakers.
 Latency through the speakers will probably be higher.
 It measures the input and output latency combined.
-Set the volume somewhere in the middle.
 
-The test works by sending a random series of bits encoded using smoothed Manchester Encoding.
-This signal has a very sharp peak when we correlate output and input.
-So it works at almost any volume. But the confidence will be higher at higher volumes.
+1. Set the Input or Output settings by tapping the green bar to expose the controls.
+2. Set the volume somewhere above the middle. The test works at almost any volume. But the confidence will be higher at higher volumes.
+3. Tap "MEASURE" to make a single measurement.
+4. Or tap "AVERAGE" to run the test several times and report an average and Mean Absolute Deviation.
+
+The test starts by setting up a stable full-duplex stream.
+Then it outputs a random series of bits encoded using smoothed Manchester Encoding.
+We record the Input and Output stream together for about a second.
+Then we correlate the two streams by sliding the portion of the output stream that contains the random bits over the input stream at different time offsets.
+The Manchaster Encoded signal provide a very sharp peak when the offset matches the combined input and output latency.
+
+Source code for the analyzer in [LatencyAnalyzer.h](https://github.com/google/oboe/blob/main/apps/OboeTester/app/src/main/cpp/analyzer/LatencyAnalyzer.h).
 
 ### Glitch Test
 
diff --git a/apps/OboeTester/gradle/wrapper/gradle-wrapper.properties b/apps/OboeTester/gradle/wrapper/gradle-wrapper.properties
index 1ef4ec2..3751824 100644
--- a/apps/OboeTester/gradle/wrapper/gradle-wrapper.properties
+++ b/apps/OboeTester/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
diff --git a/apps/OboeTester/scripts/dsp_timing.py b/apps/OboeTester/scripts/dsp_timing.py
index 9ad33d7..1fd6889 100644
--- a/apps/OboeTester/scripts/dsp_timing.py
+++ b/apps/OboeTester/scripts/dsp_timing.py
@@ -20,7 +20,7 @@
 # Print a CSV table of offsets and glitch counts.
 #
 # Run Automated Test using an Intent
-# https://github.com/google/oboe/blob/master/apps/OboeTester/docs/AutomatedTesting.md
+# https://github.com/google/oboe/blob/main/apps/OboeTester/docs/AutomatedTesting.md
 
 import array
 import collections
@@ -42,7 +42,7 @@
 
 def launchLatencyTest():
     command = ["adb", "shell", "am", \
-               "start", "-n", "com.google.sample.oboe.manualtest/.MainActivity", \
+               "start", "-n", "com.mobileer.oboetester/.MainActivity", \
                "--es", "test", "latency", \
                "--es", "file", gOutputFile, \
                "--ei", "buffer_bursts", "1"]
@@ -50,7 +50,7 @@
 
 def launchGlitchTest():
     command = ["adb", "shell", "am", \
-               "start", "-n", "com.google.sample.oboe.manualtest/.MainActivity", \
+               "start", "-n", "com.mobileer.oboetester/.MainActivity", \
                "--es", "test", "glitch", \
                "--es", "file", gOutputFile, \
                "--es", "in_perf", "lowlat", \
diff --git a/apps/fxlab/app/build.gradle b/apps/fxlab/app/build.gradle
index da60ff9..0dbca63 100644
--- a/apps/fxlab/app/build.gradle
+++ b/apps/fxlab/app/build.gradle
@@ -23,7 +23,7 @@
 apply plugin: 'kotlin-kapt'
 
 android {
-    compileSdkVersion 29
+    compileSdkVersion 33
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_8
         targetCompatibility JavaVersion.VERSION_1_8
@@ -31,7 +31,7 @@
     defaultConfig {
         applicationId "com.mobileer.androidfxlab"
         minSdkVersion 21
-        targetSdkVersion 29
+        targetSdkVersion 33
         versionCode 1
         versionName "1.0"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/apps/fxlab/app/src/main/AndroidManifest.xml b/apps/fxlab/app/src/main/AndroidManifest.xml
index 9523923..87375b4 100644
--- a/apps/fxlab/app/src/main/AndroidManifest.xml
+++ b/apps/fxlab/app/src/main/AndroidManifest.xml
@@ -25,7 +25,9 @@
             android:roundIcon="@mipmap/ic_launcher_round"
             android:supportsRtl="true"
             android:theme="@style/AppTheme">
-        <activity android:name="com.mobileer.androidfxlab.MainActivity">
+        <activity android:name="com.mobileer.androidfxlab.MainActivity"
+            android:exported="true"
+            android:configChanges="orientation|screenSize|keyboardHidden">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
@@ -36,4 +38,4 @@
 
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
 
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/apps/fxlab/app/src/main/cpp/effects/descrip/TremoloDescription.h b/apps/fxlab/app/src/main/cpp/effects/descrip/TremoloDescription.h
index 1341468..2abff9b 100644
--- a/apps/fxlab/app/src/main/cpp/effects/descrip/TremoloDescription.h
+++ b/apps/fxlab/app/src/main/cpp/effects/descrip/TremoloDescription.h
@@ -43,4 +43,4 @@
     }
 };
 } // namespace Effect
-#endif // ANDROID_FXLAB_TREMOLODESCRIPTION_H
\ No newline at end of file
+#endif // ANDROID_FXLAB_TREMOLODESCRIPTION_H
diff --git a/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/EffectsAdapter.kt b/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/EffectsAdapter.kt
index 756c064..bccefa0 100644
--- a/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/EffectsAdapter.kt
+++ b/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/EffectsAdapter.kt
@@ -92,8 +92,9 @@
                 minLabelView.text = floatFormat.format(param.minValue)
                 maxLabelView.text = floatFormat.format(param.maxValue)
                 seekBar.progress =
-                    ((param.defaultValue - param.minValue) * 100 / (param.maxValue - param.minValue)).toInt()
-                curLabelView.text = floatFormat.format(param.defaultValue)
+                    ((effectList[index].paramValues[counter] - param.minValue) * 100 / (param.maxValue
+                            - param.minValue)).toInt()
+                curLabelView.text = floatFormat.format(effectList[index].paramValues[counter])
                 // Bind param listeners to effects
                 seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
                     val paramInd = counter
diff --git a/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/datatype/Effect.kt b/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/datatype/Effect.kt
index 641b691..7abeffc 100644
--- a/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/datatype/Effect.kt
+++ b/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/datatype/Effect.kt
@@ -25,4 +25,4 @@
         i -> effectDescription.paramValues[i].defaultValue
     }
     var enable: Boolean = true
-}
\ No newline at end of file
+}
diff --git a/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/datatype/ParamDescription.kt b/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/datatype/ParamDescription.kt
index 8909f94..b330770 100644
--- a/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/datatype/ParamDescription.kt
+++ b/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/datatype/ParamDescription.kt
@@ -20,4 +20,4 @@
     val paramName: String,
     val minValue: Float,
     val maxValue: Float,
-    val defaultValue: Float)
\ No newline at end of file
+    val defaultValue: Float)
diff --git a/apps/fxlab/app/src/main/res/layout/effect_header.xml b/apps/fxlab/app/src/main/res/layout/effect_header.xml
index 78a30bb..4a26f98 100644
--- a/apps/fxlab/app/src/main/res/layout/effect_header.xml
+++ b/apps/fxlab/app/src/main/res/layout/effect_header.xml
@@ -62,4 +62,4 @@
                         tools:targetApi="jelly_bean" />
         </LinearLayout>
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/apps/fxlab/app/src/main/res/layout/effect_view.xml b/apps/fxlab/app/src/main/res/layout/effect_view.xml
index e009293..a8f8b7d 100644
--- a/apps/fxlab/app/src/main/res/layout/effect_view.xml
+++ b/apps/fxlab/app/src/main/res/layout/effect_view.xml
@@ -35,4 +35,4 @@
             android:orientation="vertical"/>
 
 
-</com.google.android.material.card.MaterialCardView>
\ No newline at end of file
+</com.google.android.material.card.MaterialCardView>
diff --git a/apps/fxlab/app/src/main/res/layout/param_seek.xml b/apps/fxlab/app/src/main/res/layout/param_seek.xml
index d0ece96..74bc5ff 100644
--- a/apps/fxlab/app/src/main/res/layout/param_seek.xml
+++ b/apps/fxlab/app/src/main/res/layout/param_seek.xml
@@ -56,4 +56,4 @@
             android:layout_weight="0.25"
             android:textAppearance="@style/TextAppearance.MaterialComponents.Caption" />
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/apps/fxlab/app/src/main/res/menu/add_menu.xml b/apps/fxlab/app/src/main/res/menu/add_menu.xml
index f66dae1..4987cb0 100644
--- a/apps/fxlab/app/src/main/res/menu/add_menu.xml
+++ b/apps/fxlab/app/src/main/res/menu/add_menu.xml
@@ -16,4 +16,4 @@
   -->
 
 <menu>
-</menu>
\ No newline at end of file
+</menu>
diff --git a/apps/fxlab/build.gradle b/apps/fxlab/build.gradle
index 57266f6..228fb6b 100644
--- a/apps/fxlab/build.gradle
+++ b/apps/fxlab/build.gradle
@@ -17,14 +17,14 @@
 // Top-level build file where you can add configuration options common to all sub-projects/modules.
 
 buildscript {
-    ext.kotlin_version = '1.3.31'
+    ext.kotlin_version = '1.7.0'
     repositories {
         google()
         jcenter()
         
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:4.2.0-beta02'
+        classpath 'com.android.tools.build:gradle:7.2.1'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
diff --git a/apps/fxlab/gradle/wrapper/gradle-wrapper.properties b/apps/fxlab/gradle/wrapper/gradle-wrapper.properties
index 1a55b24..3bd6ace 100644
--- a/apps/fxlab/gradle/wrapper/gradle-wrapper.properties
+++ b/apps/fxlab/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https://services.gradle.org/distributions/gradle-6.7.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
diff --git a/build_all_android.sh b/build_all_android.sh
index 005e4cc..50502ab 100755
--- a/build_all_android.sh
+++ b/build_all_android.sh
@@ -30,7 +30,7 @@
 
 CMAKE_ARGS="-H. \
   -DBUILD_SHARED_LIBS=true \
-  -DCMAKE_BUILD_TYPE=Release \
+  -DCMAKE_BUILD_TYPE=RelWithDebInfo \
   -DANDROID_TOOLCHAIN=clang \
   -DANDROID_STL=c++_shared \
   -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake \
diff --git a/docs/AppsUsingOboe.md b/docs/AppsUsingOboe.md
index 1b2c033..e6594ca 100644
--- a/docs/AppsUsingOboe.md
+++ b/docs/AppsUsingOboe.md
@@ -1,38 +1,3 @@
 # Projects using Oboe or AAudio
-Based on Google Play data there are over 200 apps using Oboe, with over 4 billion installs. Here is a list of those who have given permission to be listed publicly. 
 
-Want your project added? [Add a comment to issue #214](https://github.com/google/oboe/issues/214) with 
-your project name and Play Store URL. 
-
-| Name | Description | Publisher | Notes |
-|:--|:--|:--|:--|
-| [4Beats](https://play.google.com/store/apps/details?id=com.fourbeats) | Easy song creation tool | Code sign | 44100 Hz so no MMAP |
-| [Audio Evolution Mobile Studio](https://play.google.com/store/apps/details?id=com.extreamsd.aemobile) | Digital Audio Workstation app | eXtream Software Development | Oboe implemented in version 4.9.8.1 |
-| [AudioLab - Audio Editor Recorder & Ringtone Maker](https://play.google.com/store/apps/details?id=com.hitrolab.audioeditor) | THE ONLY AUDIO EDITOR APP YOU WILL EVER NEED | HitroLab | Using Oboe in AudioLab Karaoke offline feature to record audio with the lowest latency |
-| BeatScratch [Free](https://play.google.com/store/apps/details?id=com.jonlatane.beatpad.free), [Pro](https://play.google.com/store/apps/details?id=com.jonlatane.beatpad) | 3-instrument MIDI controller, sequencer, and 5-part musical notepad | Jon Latané | Using FluidSynth's Oboe Driver |
-| [Best Piano](https://play.google.com/store/apps/details?id=com.netigen.piano) | Piano tutor app  | Netigen | Stream is opened with 44100 Hz so it will not get an MMAP stream on Pixel |
-| [CSound for Android](https://play.google.com/store/apps/details?id=com.csounds.Csound6) | Audio synthesis app, using CSound framework | Irreducible Productions | [Oboe implementation source code](https://github.com/gogins/csound-extended/blob/develop/CsoundForAndroid/CsoundAndroid/jni/csound_oboe.hpp) |
-| [Faust](https://github.com/grame-cncm/faust) | DSP language, exports to Android | [Grame](https://www.grame.fr/) | [Oboe implementation source code](https://github.com/grame-cncm/faust/blob/master-dev/architecture/faust/audio/oboe-dsp.h) |
-| [FluidSynth](https://github.com/FluidSynth/fluidsynth) | MIDI synthesizer based on SoundFont 2 | [fluidsynth.org](http://www.fluidsynth.org) | drivers for Oboe and OpenSL ES |
-| [Grainstorm](https://play.google.com/store/apps/details?id=me.rocks.grainstorm) | Granular synthesizer app | The Secret Laboratory | |
-| [G-Stomper apps](https://play.google.com/store/apps/dev?id=5200192441928542082) | Mobile music production software | planet-h.com | Uses AAudio if you enable it in Settings (Setup->AUD->Audio System->AAudio). |
-| [JUCE](https://juce.com/) | Middleware framework | [ROLI](https://www.roli.com) | Oboe support enabled as experimental feature in Projucer |
-| [ktnes](https://github.com/felipecsl/ktnes) | A NES emulator implemented in Kotlin using multiplatform support and Kotlin/Native. | Felipe Lima | | 
-| [Les Talens Lyriques apps](https://play.google.com/store/apps/developer?id=Les+Talens+Lyriques) | Music education apps | Les Talens Lyriques |  Stream opened with 44100 Hz so it will not get an MMAP stream on Pixel |
-| [libGDX Oboe](https://github.com/barsoosayque/libgdx-oboe) | Middleware | barsoosayque |  Libgdx audio replacement for Android built on top of Oboe. |
-| [Koala Sampler](https://play.google.com/store/apps/details?id=com.elf.koalasampler) | Koala is the ultimate pocket-sized sampler. Record anything with your phone's mic instantly. Use Koala to create beats with those samples, add effects and create a track! | elf audio |
-| [Mini Piano Lite](https://play.google.com/store/apps/details?id=umito.android.minipiano) | Piano keyboard | Umito | Using AAudio  |
-| [Mini Tunes](https://play.google.com/store/apps/details?id=com.minitunes) | Microtonal Synthesizer for Android | Fade Apps | Oboe implemented in version 2.0 | 
-| [Music Speed Changer](https://play.google.com/store/apps/details?id=com.smp.musicspeed) | Play song files while changing the pitch and tempo. | Single Minded Productions |  | 
-| [Musician's Aide](https://play.google.com/store/apps/details?id=com.musiciansAide.app) | Musician's Aide strives to simplify your practice sessions and double your efficiency. | Astar App Foundry |  | 
-| [n-Track Studio](https://play.google.com/store/apps/details?id=com.ntrack.studio.demo) | Mobile audio workstation | n-Track Software | Settings->Select AAudio for input and/or output->OK |
-| [Pinoy Piano](https://play.google.com/store/apps/details?id=kheldiente.midien.pinoypiano) | Piano rhythm game. Play and Listen to your favorite Filipino songs. | Michael Diente | |
-| [Pocket Shruti Box: Carnatic Tambura](https://play.google.com/store/apps/details?id=org.kuyil.shrutibox) | High quality Tambura accompaniment for carnatic musicians and students | [Kuyil Carnatic Apps](https://kuyil.org/) |
-| [Quieter Calm](https://play.google.com/store/apps/details?id=quieter.app.calm) | Calming soundscapes and visuals | [Quieter](https://quieter.net/calm/) |
-| [RemixLive](https://www.mixvibes.com/remixlive-remix-app/) | Loop sequences, create beats | [Mixvibes](https://www.mixvibes.com/) | using AAudio |
-| [AudioSerial](https://davidawehr.com/blog/audioserial/) | Serial communication via audio | David Wehr | blog and source code |
-| [Sound Amplifier](https://play.google.com/store/apps/details?id=com.google.android.accessibility.soundamplifier) | Hearing assistant | Google | Enable through Settings > Accessability |
-| [SoundCloud](https://play.google.com/store/apps/details?id=com.soundcloud.android) | Music streaming app | SoundCloud | They [wrote an article](https://developers.soundcloud.com/blog/soundcloud-is-playing-the-oboe) about the integration |
-| [Shruti Carnatic Tuner](https://play.google.com/store/apps/details?id=org.kuyil.shruti) | Shruti helps to tune your instruments or voice to accurate Carnatic swarams. | Kuyil |  |
-| Volcano Mobile apps | MIDI synthesizer apps: [FluidSynth](https://play.google.com/store/apps/details?id=net.volcanomobile.fluidsynthmidi), [OPL3 MIDI Synth FM](https://play.google.com/store/apps/details?id=net.volcanomobile.opl3midisynth), [MIDI Sequencer](https://play.google.com/store/apps/details?id=net.volcanomobile.midisequencer) | Volcano Mobile |  MIDI Sequencer app is very handy for testing. |
-
+This page was moved to the Wiki at [AppsUsingOboe](https://github.com/google/oboe/wiki/AppsUsingOboe).
diff --git a/docs/FAQ.md b/docs/FAQ.md
index 00d86bb..b11cfe7 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -1,11 +1,10 @@
 # Frequently Asked Questions (FAQ)
 
-## Can I write audio data from Java to Oboe?
+## Can I write audio data from Java/Kotlin to Oboe?
 
 Oboe is a native library written in C++ which uses the Android NDK. To move data from Java to C++ you can use [JNI](https://developer.android.com/training/articles/perf-jni). 
 
-That said, if you are generating your audio in Java you'll get better performance using the [Java AudioTrack class](https://developer.android.com/reference/android/media/AudioTrack). This can be 
-created with low latency using the AudioTrack.Builder method [`setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY)`](https://developer.android.com/reference/android/media/AudioTrack#PERFORMANCE_MODE_LOW_LATENCY).
+If you're generating audio data in Java or Kotlin you should consider whether the reduced latency which Oboe gives you (particularly on high-end devices) is worth the extra complexity of passing data via JNI. An alternative is to use [Java AudioTrack](https://developer.android.com/reference/android/media/AudioTrack). This can be created with low latency using the AudioTrack.Builder method [`setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY)`](https://developer.android.com/reference/android/media/AudioTrack#PERFORMANCE_MODE_LOW_LATENCY).
 
 You can dynamically tune the latency of the stream just like in Oboe using [`setBufferSizeInFrames(int)`](https://developer.android.com/reference/android/media/AudioTrack.html#setBufferSizeInFrames(int))
 Also you can use blocking writes with the Java AudioTrack and still get a low latency stream.
@@ -14,12 +13,12 @@
 Note that [`AudioTrack.PERFORMANCE_MODE_LOW_LATENCY`](https://developer.android.com/reference/android/media/AudioTrack#PERFORMANCE_MODE_LOW_LATENCY) was added in API 26, For API 24 or 25 use [`AudioAttributes.FLAG_LOW_LATENCY`](https://developer.android.com/reference/kotlin/android/media/AudioAttributes#flag_low_latency). That was deprecated but will still work with later APIs.
 
 ## Can I use Oboe to play compressed audio files, such as MP3 or AAC?
-Oboe only works with PCM data. It does not include any extraction or decoding classes. However, the [RhythmGame sample](https://github.com/google/oboe/tree/master/samples/RhythmGame) includes extractors for both NDK and FFmpeg. 
+Oboe only works with PCM data. It does not include any extraction or decoding classes. However, the [RhythmGame sample](https://github.com/google/oboe/tree/main/samples/RhythmGame) includes extractors for both NDK and FFmpeg. 
 
 For more information on using FFmpeg in your app [check out this article](https://medium.com/@donturner/using-ffmpeg-for-faster-audio-decoding-967894e94e71).
 
 ## Android Studio doesn't find the Oboe symbols, how can I fix this?
-Start by ensuring that your project builds successfully. The main thing to do is ensure that the Oboe include paths are set correctly in your project's `CMakeLists.txt`. [Full instructions here](https://github.com/google/oboe/blob/master/docs/GettingStarted.md#2-update-cmakeliststxt).
+Start by ensuring that your project builds successfully. The main thing to do is ensure that the Oboe include paths are set correctly in your project's `CMakeLists.txt`. [Full instructions here](https://github.com/google/oboe/blob/main/docs/GettingStarted.md#2-update-cmakeliststxt).
 
 If that doesn't fix it try the following: 
 
@@ -32,10 +31,10 @@
 Usually if you call `builder.setPerformanceMode(PerformanceMode::LowLatency)` and don't specify other stream properties you will get a `LowLatency` stream. The most common reasons for not receiving one are: 
 
 - You are opening an output stream and did not specify a **data callback**.
-- You requested a **sample** rate which does not match the audio device's native sample rate. For playback streams, this means the audio data you write into the stream must be resampled before it's sent to the audio device. For recording streams, the  audio data must be resampled before you can read it. In both cases the resampling process (performed by the Android audio framework) adds latency and therefore providing a `LowLatency` stream is not possible. To avoid the resampler on API 26 and below you can specify a default value for the sample rate [as detailed here](https://github.com/google/oboe/blob/master/docs/GettingStarted.md#obtaining-optimal-latency).  Or you can use the [new resampler](https://google.github.io/oboe/reference/classoboe_1_1_audio_stream_builder.html#af7d24a9ec975d430732151e5ee0d1027) in Oboe, which allows the lower level code to run at the optimal rate and provide lower latency.
-- If you request **AudioFormat::Float on an Input** stream before Android 9.0 then you will **not** get a FAST track. You need to either request AudioFormat::Int16 or [enable format conversion by Oboe](https://google.github.io/oboe/reference/classoboe_1_1_audio_stream_builder.html#a7ec5f427cd6fe55cb1ce536ff0cbb4d2).
+- You requested a **sample** rate which does not match the audio device's native sample rate. For playback streams, this means the audio data you write into the stream must be resampled before it's sent to the audio device. For recording streams, the  audio data must be resampled before you can read it. In both cases the resampling process (performed by the Android audio framework) adds latency and therefore providing a `LowLatency` stream is not possible. To avoid the resampler on API 26 and below you can specify a default value for the sample rate [as detailed here](https://github.com/google/oboe/blob/main/docs/GettingStarted.md#obtaining-optimal-latency).  Or you can enable sample rate conversion by calling [AudioStreamBuilder::setSampleRateConversionQuality()](https://google.github.io/oboe/classoboe_1_1_audio_stream_builder.html#a0c98d21da654da6d197b004d29d8499c) in Oboe, which allows the lower level code to run at the optimal rate and provide lower latency.
+- If you request **AudioFormat::Float on an Input** stream before Android 9.0 then you will **not** get a FAST track. You need to either request AudioFormat::Int16 or enable format conversion by calling [AudioStreamBuilder::setFormatConversionAllowed()](https://google.github.io/oboe/classoboe_1_1_audio_stream_builder.html#aa30150d2d0b3c925b545646962dffca0) in Oboe.
 - The audio **device** does not support `LowLatency` streams, for example Bluetooth. 
-- You requested a **channel count** which is not supported natively by the audio device. On most devices and Android API levels it is possible to obtain a `LowLatency` stream for both mono and stereo, however, there are a few exceptions, some of which are listed [here](https://github.com/google/oboe/blob/master/docs/AndroidAudioHistory.md). 
+- You requested a **channel count** which is not supported natively by the audio device. On most devices and Android API levels it is possible to obtain a `LowLatency` stream for both mono and stereo, however, there are a few exceptions, some of which are listed [here](https://github.com/google/oboe/blob/main/docs/AndroidAudioHistory.md). 
 - The **maximum number** of `LowLatency` streams has been reached. This could be by your app, or by other apps. This is often caused by opening multiple playback streams for different "tracks". To avoid this open a single audio stream and perform 
 your own mixing in the app. 
 - You are on Android 7.0 or below and are receiving `PerformanceMode::None`. The ability to query the performance mode of a stream was added in Android 7.1 (Nougat MR1). Low latency streams (aka FAST tracks) _are available_ on Android 7.0 and below but there is no programmatic way of knowing whether yours is one. [Question on StackOverflow](https://stackoverflow.com/questions/56828501/does-opensl-es-support-performancemodelowlatency/5683499)
diff --git a/docs/FullGuide.md b/docs/FullGuide.md
index d928a1f..405e48f 100644
--- a/docs/FullGuide.md
+++ b/docs/FullGuide.md
@@ -92,9 +92,13 @@
 
 ### Open the Stream
 
+Declare a **shared pointer** for the stream. Make sure it is declared with the appropriate scope. The best place is as a member variable in a managing class or as a global. Avoid declaring it as a local variable because the stream may get deleted when the function returns.
+
+    std::shared_ptr<oboe::AudioStream> mStream;
+
 After you've configured the `AudioStreamBuilder`, call `openStream()` to open the stream:
 
-    Result result = streamBuilder.openStream(&stream_);
+    Result result = streamBuilder.openStream(mStream);
     if (result != OK){
         __android_log_print(ANDROID_LOG_ERROR,
                             "AudioEngine",
@@ -296,19 +300,19 @@
 audio glitch. You can pad the buffer with zeros to create a
 silent dropout:
 
-    Result result = stream.read(audioData, numFrames, timeout);
+    Result result = mStream->read(audioData, numFrames, timeout);
     if (result < 0) {
         // Error!
     }
     if (result != numFrames) {
         // pad the buffer with zeros
         memset(static_cast<sample_type*>(audioData) + result * samplesPerFrame, 0,
-               (numFrames - result) * stream.getBytesPerFrame());
+               (numFrames - result) * mStream->getBytesPerFrame());
     }
 
 You can prime the stream's buffer before starting the stream by writing data or silence into it. This must be done in a non-blocking call with timeoutNanos set to zero.
 
-The data in the buffer must match the data format returned by `stream.getDataFormat()`.
+The data in the buffer must match the data format returned by `mStream->getDataFormat()`.
 
 ### Closing an audio stream
 
@@ -329,7 +333,7 @@
 When a stream is disconnected, it has the state "Disconnected" and calls to `write()` or other functions will return `Result::ErrorDisconnected`.  When a stream is disconnected, all you can do is close it.
 
 If you need to be informed when an audio device is disconnected, write a class
-which extends `AudioStreamErrorCallback` and then register your class using `builder.setErrorCallback(yourCallbackClass)`.
+which extends `AudioStreamErrorCallback` and then register your class using `builder.setErrorCallback(yourCallbackClass)`. It is recommended to pass a shared_ptr.
 If you register a callback, then it will automatically close the stream in a separate thread if the stream is disconnected.
 
 Your callback can implement the following methods (called in a separate thread): 
@@ -345,6 +349,7 @@
 Opening a separate stream is also a valid use of this callback, especially if the error received is `Error::Disconnected`. 
 However, it is important to note that the new audio device may have vastly different properties than the stream that was disconnected.
 
+See the SoundBoard sample for an example of setErrorCallback.
 
 ## Optimizing performance
 
@@ -484,10 +489,6 @@
 AudioStreamBuilder builder;
 builder.setDataCallback(myCallback);
 builder.setPerformanceMode(PerformanceMode::LowLatency);
-
-// Use it to create the stream
-AudioStream *stream;
-builder.openStream(&stream);
 ```
 
 ## Thread safety
diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md
index dd8915e..5d1d379 100644
--- a/docs/GettingStarted.md
+++ b/docs/GettingStarted.md
@@ -9,12 +9,12 @@
 
 ## Option 1) Using pre-built binaries and headers
 
-Oboe is distributed as a [prefab](https://github.com/google/prefab) package via [Google Maven](https://maven.google.com/web/index.html) (search for "oboe"). [Prefab support was added](https://android-developers.googleblog.com/2020/02/native-dependencies-in-android-studio-40.html) to [Android Studio Preview 4.0 Canary 9](https://developer.android.com/studio/preview) so you'll need to be using this version of Android Studio or above. 
+Oboe is distributed as a [prefab](https://github.com/google/prefab) package via [Google Maven](https://maven.google.com/web/index.html) (search for "oboe"). [Prefab support was added](https://android-developers.googleblog.com/2020/02/native-dependencies-in-android-studio-40.html) to [Android Studio 4.0](https://developer.android.com/studio) so you'll need to be using this version of Android Studio or above. 
 
-Add the oboe dependency to your app's `build.gradle` file. Replace "1.4.3" with the [latest stable version](https://github.com/google/oboe/releases/) of Oboe:
+Add the oboe dependency to your app's `build.gradle` file. Replace "X.X.X" with the [latest stable version](https://github.com/google/oboe/releases/) of Oboe:
 
     dependencies {
-        implementation 'com.google.oboe:oboe:1.4.3'
+        implementation 'com.google.oboe:oboe:X.X.X'
     }
 
 Also enable prefab by adding:
@@ -28,7 +28,7 @@
 Include and link to oboe by updating your `CMakeLists.txt`: 
 
     find_package (oboe REQUIRED CONFIG)
-    target_link_libraries(app oboe::oboe) # You may have other libraries here such as `log`.
+    target_link_libraries(native-lib oboe::oboe) # You may have other libraries here such as `log`.
 
 Here's a complete example `CMakeLists.txt` file:
 
@@ -41,7 +41,7 @@
     find_package (oboe REQUIRED CONFIG)
 
     # Specify the libraries which our native library is dependent on, including Oboe
-    target_link_libraries(app log oboe::oboe)
+    target_link_libraries(native-lib log oboe::oboe)
 
 Configure your app to use the shared STL by updating your `app/build.gradle`: 
 
@@ -52,7 +52,7 @@
                     arguments "-DANDROID_STL=c++_shared"
                 }
 	        }
-	    }
+        }
     }
 
 ## Option 2) Building from source
@@ -60,7 +60,7 @@
 ### 1. Clone the github repository
 Start by cloning the [latest stable release](https://github.com/google/oboe/releases/) of the Oboe repository, for example:
 
-    git clone -b 1.4-stable https://github.com/google/oboe
+    git clone -b 1.6-stable https://github.com/google/oboe
 
 **Make a note of the path which you cloned oboe into - you will need it shortly**
 
@@ -159,8 +159,9 @@
         oboe::DataCallbackResult
         onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) {
             
-            // We requested AudioFormat::Float so we assume we got it.
-            // For production code always check what format
+            // We requested AudioFormat::Float. So if the stream opens
+	    // we know we got the Float format.
+            // If you do not specify a format then you should check what format
             // the stream has and cast to the appropriate type.
             auto *outputData = static_cast<float *>(audioData);
 	    
@@ -184,10 +185,10 @@
 
     builder.setDataCallback(&myCallback);
     
-Declare a shared pointer for the stream. Make sure it is declared in an appropriate scope (e.g.the member of a managing class). Avoid declaring it as a global.
-```
-std::shared_ptr<oboe::AudioStream> mStream;
-```
+Declare a shared pointer for the stream. Make sure it is declared with the appropriate scope. The best place is as a member variable in a managing class or as a global. Avoid declaring it as a local variable because the stream may get deleted when the function returns.
+
+    std::shared_ptr<oboe::AudioStream> mStream;
+
 Open the stream:
 
     oboe::Result result = builder.openStream(mStream);
@@ -247,6 +248,7 @@
 ```
 #include <oboe/Oboe.h>
 #include <math.h>
+using namespace oboe;
 
 class OboeSinePlayer: public oboe::AudioStreamDataCallback {
 public:
@@ -262,7 +264,7 @@
                 ->setPerformanceMode(oboe::PerformanceMode::LowLatency)
                 ->setChannelCount(kChannelCount)
                 ->setSampleRate(kSampleRate)
-		->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Medium);
+		->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Medium)
                 ->setFormat(oboe::AudioFormat::Float)
                 ->setDataCallback(this)
                 ->openStream(mStream);
@@ -319,7 +321,7 @@
 Additionally, best practice is to implement a separate data callback class, rather
 than managing the stream and defining its data callback in the same class.
 
-For more examples on how to use Oboe look in the [samples](https://github.com/google/oboe/tree/master/samples) folder.
+For more examples on how to use Oboe look in the [samples](https://github.com/google/oboe/tree/main/samples) folder.
 
 ## Obtaining optimal latency
 One of the goals of the Oboe library is to provide low latency audio streams on the widest range of hardware configurations.
@@ -355,5 +357,5 @@
 Note that the values from Java are for built-in audio devices. Peripheral devices, such as Bluetooth may need larger framesPerBurst.
 
 # Further information
-- [Code samples](https://github.com/google/oboe/tree/master/samples)
+- [Code samples](https://github.com/google/oboe/tree/main/samples)
 - [Full guide to Oboe](FullGuide.md)
diff --git a/docs/OpenSLESMigration.md b/docs/OpenSLESMigration.md
index ecdf588..9f64233 100644
--- a/docs/OpenSLESMigration.md
+++ b/docs/OpenSLESMigration.md
@@ -5,7 +5,7 @@
 
 This guide will show you how to migrate your code from [OpenSL ES for Android](https://developer.android.com/ndk/guides/audio/opensl/opensl-for-android) (just OpenSL from now on) to Oboe. 
 
-To familiarise yourself with Oboe, please read the [Getting Started guide](https://github.com/google/oboe/blob/master/docs/GettingStarted.md) and ensure that Oboe has been added as a dependency in your project.
+To familiarise yourself with Oboe, please read the [Getting Started guide](https://github.com/google/oboe/blob/main/docs/GettingStarted.md) and ensure that Oboe has been added as a dependency in your project.
 
 
 # Concepts
@@ -84,7 +84,7 @@
 ```
 
 
-You supply your implementation of `onAudioReady` when building the audio stream by constructing an `AudioStreamDataCallback` object. [Here's an example.](https://github.com/google/oboe/blob/master/docs/GettingStarted.md#creating-an-audio-stream)
+You supply your implementation of `onAudioReady` when building the audio stream by constructing an `AudioStreamDataCallback` object. [Here's an example.](https://github.com/google/oboe/blob/main/docs/GettingStarted.md#creating-an-audio-stream)
 
 
 ### Buffer sizes
@@ -101,7 +101,7 @@
 ```
 
 
-**Note:** because Oboe uses OpenSL under-the-hood on older devices which does not provide the same information about audio devices, it still needs to know [sensible default values for the burst to be used with OpenSL](https://github.com/google/oboe/blob/master/docs/GettingStarted.md#obtaining-optimal-latency).
+**Note:** because Oboe uses OpenSL under-the-hood on older devices which does not provide the same information about audio devices, it still needs to know [sensible default values for the burst to be used with OpenSL](https://github.com/google/oboe/blob/main/docs/GettingStarted.md#obtaining-optimal-latency).
 
 
 ## Audio stream properties
@@ -117,14 +117,14 @@
 ```
 
 
-However, you may want to specify some properties. These are set using the `AudioStreamBuilder` ([example](https://github.com/google/oboe/blob/master/docs/FullGuide.md#set-the-audio-stream-configuration-using-an-audiostreambuilder)).
+However, you may want to specify some properties. These are set using the `AudioStreamBuilder` ([example](https://github.com/google/oboe/blob/main/docs/FullGuide.md#set-the-audio-stream-configuration-using-an-audiostreambuilder)).
 
 
 ## Stream disconnection
 
 OpenSL has no mechanism, other than stopping callbacks, to indicate that an audio device has been disconnected - for example, when headphones are unplugged.
 
-In Oboe, you can be notified of stream disconnection by overriding one of the `onError` methods in `AudioStreamErrorCallback`. This allows you to clean up any resources associated with the audio stream and create a new stream with optimal properties for the current audio device ([more info](https://github.com/google/oboe/blob/master/docs/FullGuide.md#disconnected-audio-stream)).
+In Oboe, you can be notified of stream disconnection by overriding one of the `onError` methods in `AudioStreamErrorCallback`. This allows you to clean up any resources associated with the audio stream and create a new stream with optimal properties for the current audio device ([more info](https://github.com/google/oboe/blob/main/docs/FullGuide.md#disconnected-audio-stream)).
 
 
 # Unsupported features
@@ -141,7 +141,7 @@
 *   The OpenSL ES implementation has performance and reliability issues.
 *   It keeps the Oboe API and the underlying implementation simple.
 
-Extraction and decoding can be done either through the NDK [Media APIs](https://developer.android.com/ndk/reference/group/media) or by using a third party library like [FFmpeg](https://ffmpeg.org/). An example of both these approaches can be seen in the [RhythmGame sample](https://github.com/google/oboe/tree/master/samples/RhythmGame).
+Extraction and decoding can be done either through the NDK [Media APIs](https://developer.android.com/ndk/reference/group/media) or by using a third party library like [FFmpeg](https://ffmpeg.org/). An example of both these approaches can be seen in the [RhythmGame sample](https://github.com/google/oboe/tree/main/samples/RhythmGame).
 
 
 ## Miscellaneous features
@@ -153,7 +153,7 @@
 *   Channel masks - only [indexed channel masks](https://developer.android.com/reference/kotlin/android/media/AudioFormat#channel-index-masks) are supported.
 *   Playing audio content from a file pathname or [URI](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier).
 *   Notification callbacks for position updates.
-*   Platform output effects on API 27 and below. [They are supported from API 28 and above.](https://github.com/google/oboe/blob/master/docs/notes/effects.md)
+*   Platform output effects on API 27 and below. [They are supported from API 28 and above.](https://github.com/google/oboe/blob/main/docs/notes/effects.md)
 
 
 # Summary
@@ -164,6 +164,6 @@
 *   Use your value for `numBuffers` to set the audio stream's buffer size as a multiple of the burst size. For example: `audioStream.setBufferSizeInFrames(audioStream.getFramesPerBurst * numBuffers)`.
 *   Create an `AudioStreamDataCallback` object and move your OpenSL callback code inside the `onAudioReady` method.
 *   Handle stream disconnect events by creating an `AudioStreamErrorCallback` object and overriding one of its `onError` methods.
-*   Pass sensible default sample rate and buffer size values to Oboe from `AudioManager` [using this method](https://github.com/google/oboe/blob/master/docs/GettingStarted.md#obtaining-optimal-latency) so that your app is still performant on older devices.
+*   Pass sensible default sample rate and buffer size values to Oboe from `AudioManager` [using this method](https://github.com/google/oboe/blob/main/docs/GettingStarted.md#obtaining-optimal-latency) so that your app is still performant on older devices.
 
-For more information please read the [Full Guide to Oboe](https://github.com/google/oboe/blob/master/docs/FullGuide.md).
+For more information please read the [Full Guide to Oboe](https://github.com/google/oboe/blob/main/docs/FullGuide.md).
diff --git a/docs/PrivacyPolicy.md b/docs/PrivacyPolicy.md
new file mode 100644
index 0000000..4d8b23e
--- /dev/null
+++ b/docs/PrivacyPolicy.md
@@ -0,0 +1,11 @@
+[Home](README.md)
+
+# Oboe Privacy Policy
+
+Oboe is a library that simply passes audio between the application and the native Android APIs.
+
+Oboe does not collect any user data or information.
+
+Oboe does not create Cookies.
+
+Oboe is considered "kid safe".
diff --git a/docs/README.md b/docs/README.md
index a72b7db..6e7853d 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,7 +1,7 @@
 Oboe documentation
 ===
 - [Android Audio History](AndroidAudioHistory.md)
-- [API reference](https://google.github.io/oboe/reference/)
+- [API reference](https://google.github.io/oboe/)
 - [Apps using Oboe](AppsUsingOboe.md)
 - [Changelog](ChangeLog.md)
 - [FAQs](FAQ.md)
@@ -10,6 +10,4 @@
 - [Tech Notes](notes/)
   - [Using Audio Effects with Oboe](notes/effects.md)
   - [Disconnected Streams](notes/disconnect.md)
-
-
-
+- [Privacy Policy](PrivacyPolicy.md)
diff --git a/docs/index.html b/docs/index.html
deleted file mode 100644
index 38b689b..0000000
--- a/docs/index.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-   <!-- HTML meta refresh URL redirection -->
-   <meta http-equiv="refresh"
-   content="0; url=reference/">
-</head>
-<body>
-   <p><a href="reference/">Oboe API reference</a></p>
-</body>
-</html>
\ No newline at end of file
diff --git a/docs/notes/README.md b/docs/notes/README.md
index 386d761..db6e131 100644
--- a/docs/notes/README.md
+++ b/docs/notes/README.md
@@ -1,7 +1,11 @@
-[Oboe Docs Home](https://github.com/google/oboe/blob/master/docs/README.md)
+[Oboe Docs Home](https://github.com/google/oboe/blob/main/docs/README.md)
+
+Note that the Tech Notes are moving to here: https://github.com/google/oboe/wiki#tech-notes
 
 # Oboe Tech Notes
 
+* [Buffer Terminology - Frames, Capacity, Size, Burst](https://github.com/google/oboe/wiki/TechNote_BufferTerminology)
 * [Using Audio Effects with Oboe](effects.md)
 * [Disconnected Streams](disconnect.md) - Responding to Plugging In and Unplugging Headsets
 * [Assert in releaseBuffer()](rlsbuffer.md)
+* [Glitches and Latency](https://github.com/google/oboe/wiki/TechNote_Glitches)
diff --git a/docs/notes/disconnect.md b/docs/notes/disconnect.md
index 08ee633..26bab98 100644
--- a/docs/notes/disconnect.md
+++ b/docs/notes/disconnect.md
@@ -19,13 +19,15 @@
 The app should then stop() and close() the stream.
 An app may then choose to reopen a stream.
 
-## Workaround for not Disconnecting Properly
+## Bug in P and Q
 
-On some versions of Android P the disconnect message does not reach AAudio and the app will not
-know that the device has changed. There is a "Test Disconnects" option in
-[OboeTester](https://github.com/google/oboe/tree/master/apps/OboeTester/docs)
+On some versions of Android P (9), and some early versions of Q (10), the disconnect message does not reach AAudio and the app will not
+know that the device has changed. There is a "TEST DISCONNECT" option in
+[OboeTester](https://github.com/google/oboe/tree/main/apps/OboeTester/docs)
 that can be used to diagnose this problem.
 
+## Workaround for not Disconnecting Properly
+
 As a workaround you can listen for a Java [Intent.ACTION_HEADSET_PLUG](https://developer.android.com/reference/android/content/Intent#ACTION_HEADSET_PLUG),
 which is fired when a head set is plugged in or out. If your min SDK is LOLLIPOP or later then you can use [AudioManager.ACTION_HEADSET_PLUG](https://developer.android.com/reference/android/media/AudioManager#ACTION_HEADSET_PLUG) instead.
 
@@ -60,6 +62,7 @@
   * [#381](https://github.com/google/oboe/issues/381) Connecting headphones does not trigger any event. S9
   * [#893](https://github.com/google/oboe/issues/893) onErrorBeforeClose and onErrorAfterClose not called, S10
   * [#908](https://github.com/google/oboe/issues/908) Huawei MAR-LX3A
+  * [#1350](https://github.com/google/oboe/issues/1350) SM-G977B fails "Test Disconnects"
 * This issue is tracked internally as b/111711159.
 * A fix in AOSP is [here](https://android-review.googlesource.com/c/platform/frameworks/av/+/836184)
 * A fix was also merged into pi-dev on July 30, 2018.
diff --git a/docs/notes/effects.md b/docs/notes/effects.md
index f01e901..1f7d5f7 100644
--- a/docs/notes/effects.md
+++ b/docs/notes/effects.md
@@ -33,7 +33,7 @@
     
 Pass the audioSessionId to your C++ code using JNI. Then use it when opening your Oboe streams:
 
-    builder->setSessionId(sessionId);
+    builder->setSessionId((oboe::SessionId) audioSessionId);
 
 Note that these streams will probably not have low latency. So you may want to do your own effects processing.
 
diff --git a/docs/notes/rlsbuffer.md b/docs/notes/rlsbuffer.md
index df7e61c..ff30819 100644
--- a/docs/notes/rlsbuffer.md
+++ b/docs/notes/rlsbuffer.md
@@ -36,7 +36,7 @@
 1. user plugs in headphones, which invalidates the audio device
 1. app is called (callback) to render audio using the buffer
 1. the app or Oboe calls getFramesRead() or getTimestamp(), which calls down to AudioTrack::getPosition() or AudioTrack::getTimestamp()
-1. device routing change occurs because the audio device is [invalid](https://cs.android.com/android/platform/superproject/+/master:frameworks/av/media/libaudioclient/AudioTrack.cpp;l=1239;drc=48e98cf8dbd9fa212a0e129822929dc40e6c3898)
+1. device routing change occurs because the audio device is [invalid](https://cs.android.com/android/platform/superproject/+/primary:frameworks/av/media/libaudioclient/AudioTrack.cpp;l=1239;drc=48e98cf8dbd9fa212a0e129822929dc40e6c3898)
 1. callback ends by releasing the buffer back to a different device
 1. AudioTrackShared::releaseBuffer() checks to make sure the device matches the one in ObtainBuffer() and asserts if they do not match.
 
diff --git a/docs/reference/_audio_stream_8h_source.html b/docs/reference/_audio_stream_8h_source.html
deleted file mode 100644
index e3d4e56..0000000
--- a/docs/reference/_audio_stream_8h_source.html
+++ /dev/null
@@ -1,140 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: include/oboe/AudioStream.h Source File</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="dir_d44c64559bbebec7f509842c48db8b23.html">include</a></li><li class="navelem"><a class="el" href="dir_768f6301d9838e45d679001914ab2803.html">oboe</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">AudioStream.h</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;<span class="comment">/*</span></div><div class="line"><a name="l00002"></a><span class="lineno">    2</span>&#160;<span class="comment"> * Copyright 2016 The Android Open Source Project</span></div><div class="line"><a name="l00003"></a><span class="lineno">    3</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00004"></a><span class="lineno">    4</span>&#160;<span class="comment"> * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></div><div class="line"><a name="l00005"></a><span class="lineno">    5</span>&#160;<span class="comment"> * you may not use this file except in compliance with the License.</span></div><div class="line"><a name="l00006"></a><span class="lineno">    6</span>&#160;<span class="comment"> * You may obtain a copy of the License at</span></div><div class="line"><a name="l00007"></a><span class="lineno">    7</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00008"></a><span class="lineno">    8</span>&#160;<span class="comment"> *      http://www.apache.org/licenses/LICENSE-2.0</span></div><div class="line"><a name="l00009"></a><span class="lineno">    9</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00010"></a><span class="lineno">   10</span>&#160;<span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></div><div class="line"><a name="l00011"></a><span class="lineno">   11</span>&#160;<span class="comment"> * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</span></div><div class="line"><a name="l00012"></a><span class="lineno">   12</span>&#160;<span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></div><div class="line"><a name="l00013"></a><span class="lineno">   13</span>&#160;<span class="comment"> * See the License for the specific language governing permissions and</span></div><div class="line"><a name="l00014"></a><span class="lineno">   14</span>&#160;<span class="comment"> * limitations under the License.</span></div><div class="line"><a name="l00015"></a><span class="lineno">   15</span>&#160;<span class="comment"> */</span></div><div class="line"><a name="l00016"></a><span class="lineno">   16</span>&#160;</div><div class="line"><a name="l00017"></a><span class="lineno">   17</span>&#160;<span class="preprocessor">#ifndef OBOE_STREAM_H_</span></div><div class="line"><a name="l00018"></a><span class="lineno">   18</span>&#160;<span class="preprocessor">#define OBOE_STREAM_H_</span></div><div class="line"><a name="l00019"></a><span class="lineno">   19</span>&#160;</div><div class="line"><a name="l00020"></a><span class="lineno">   20</span>&#160;<span class="preprocessor">#include &lt;atomic&gt;</span></div><div class="line"><a name="l00021"></a><span class="lineno">   21</span>&#160;<span class="preprocessor">#include &lt;cstdint&gt;</span></div><div class="line"><a name="l00022"></a><span class="lineno">   22</span>&#160;<span class="preprocessor">#include &lt;ctime&gt;</span></div><div class="line"><a name="l00023"></a><span class="lineno">   23</span>&#160;<span class="preprocessor">#include &lt;mutex&gt;</span></div><div class="line"><a name="l00024"></a><span class="lineno">   24</span>&#160;<span class="preprocessor">#include &quot;oboe/Definitions.h&quot;</span></div><div class="line"><a name="l00025"></a><span class="lineno">   25</span>&#160;<span class="preprocessor">#include &quot;oboe/ResultWithValue.h&quot;</span></div><div class="line"><a name="l00026"></a><span class="lineno">   26</span>&#160;<span class="preprocessor">#include &quot;oboe/AudioStreamBuilder.h&quot;</span></div><div class="line"><a name="l00027"></a><span class="lineno">   27</span>&#160;<span class="preprocessor">#include &quot;oboe/AudioStreamBase.h&quot;</span></div><div class="line"><a name="l00028"></a><span class="lineno">   28</span>&#160;</div><div class="line"><a name="l00031"></a><span class="lineno"><a class="line" href="namespaceoboe.html">   31</a></span>&#160;<span class="keyword">namespace </span><a class="code" href="namespaceoboe.html">oboe</a> {</div><div class="line"><a name="l00032"></a><span class="lineno">   32</span>&#160;</div><div class="line"><a name="l00039"></a><span class="lineno"><a class="line" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">   39</a></span>&#160;constexpr int64_t <a class="code" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">kDefaultTimeoutNanos</a> = (2000 * <a class="code" href="namespaceoboe.html#a831e887150474c087170679eaca8672b">kNanosPerMillisecond</a>);</div><div class="line"><a name="l00040"></a><span class="lineno">   40</span>&#160;</div><div class="line"><a name="l00044"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html">   44</a></span>&#160;<span class="keyword">class </span><a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a> : <span class="keyword">public</span> <a class="code" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> {</div><div class="line"><a name="l00045"></a><span class="lineno">   45</span>&#160;    <span class="keyword">friend</span> <span class="keyword">class </span><a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>; <span class="comment">// allow access to setWeakThis() and lockWeakThis()</span></div><div class="line"><a name="l00046"></a><span class="lineno">   46</span>&#160;<span class="keyword">public</span>:</div><div class="line"><a name="l00047"></a><span class="lineno">   47</span>&#160;</div><div class="line"><a name="l00048"></a><span class="lineno">   48</span>&#160;    <a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a>() {}</div><div class="line"><a name="l00049"></a><span class="lineno">   49</span>&#160;</div><div class="line"><a name="l00055"></a><span class="lineno">   55</span>&#160;    <span class="keyword">explicit</span> <a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a>(<span class="keyword">const</span> <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> &amp;builder);</div><div class="line"><a name="l00056"></a><span class="lineno">   56</span>&#160;</div><div class="line"><a name="l00057"></a><span class="lineno">   57</span>&#160;    <span class="keyword">virtual</span> ~<a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a>() = <span class="keywordflow">default</span>;</div><div class="line"><a name="l00058"></a><span class="lineno">   58</span>&#160;</div><div class="line"><a name="l00067"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#a686c6ce8a29051c858fd1de386805dc6">   67</a></span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream.html#a686c6ce8a29051c858fd1de386805dc6">open</a>() {</div><div class="line"><a name="l00068"></a><span class="lineno">   68</span>&#160;        <span class="keywordflow">return</span> Result::OK; <span class="comment">// Called by subclasses. Might do more in the future.</span></div><div class="line"><a name="l00069"></a><span class="lineno">   69</span>&#160;    }</div><div class="line"><a name="l00070"></a><span class="lineno">   70</span>&#160;</div><div class="line"><a name="l00074"></a><span class="lineno">   74</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream.html#a9c8ea30e30e513766d5e996c370eb8d8">close</a>();</div><div class="line"><a name="l00075"></a><span class="lineno">   75</span>&#160;</div><div class="line"><a name="l00080"></a><span class="lineno">   80</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream.html#af04f03eb6b64b564f1c4401688987d21">start</a>(int64_t timeoutNanoseconds = <a class="code" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">kDefaultTimeoutNanos</a>);</div><div class="line"><a name="l00081"></a><span class="lineno">   81</span>&#160;</div><div class="line"><a name="l00086"></a><span class="lineno">   86</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream.html#a04f29836748a8e5842aef2be200022ad">pause</a>(int64_t timeoutNanoseconds = <a class="code" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">kDefaultTimeoutNanos</a>);</div><div class="line"><a name="l00087"></a><span class="lineno">   87</span>&#160;</div><div class="line"><a name="l00092"></a><span class="lineno">   92</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream.html#a32c25c0333eab3d65ce02275ad4acb3d">flush</a>(int64_t timeoutNanoseconds = <a class="code" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">kDefaultTimeoutNanos</a>);</div><div class="line"><a name="l00093"></a><span class="lineno">   93</span>&#160;</div><div class="line"><a name="l00098"></a><span class="lineno">   98</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream.html#aec093859d42f0470c884edd1e976d9f3">stop</a>(int64_t timeoutNanoseconds = <a class="code" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">kDefaultTimeoutNanos</a>);</div><div class="line"><a name="l00099"></a><span class="lineno">   99</span>&#160;</div><div class="line"><a name="l00100"></a><span class="lineno">  100</span>&#160;    <span class="comment">/* Asynchronous requests.</span></div><div class="line"><a name="l00101"></a><span class="lineno">  101</span>&#160;<span class="comment">     * Use waitForStateChange() if you need to wait for completion.</span></div><div class="line"><a name="l00102"></a><span class="lineno">  102</span>&#160;<span class="comment">     */</span></div><div class="line"><a name="l00103"></a><span class="lineno">  103</span>&#160;</div><div class="line"><a name="l00108"></a><span class="lineno">  108</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream.html#a3c484e314dee8dfed1d419f487b5d601">requestStart</a>() = 0;</div><div class="line"><a name="l00109"></a><span class="lineno">  109</span>&#160;</div><div class="line"><a name="l00114"></a><span class="lineno">  114</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream.html#a7f18bb3cc5490fd7fbc1f6da63c730f6">requestPause</a>() = 0;</div><div class="line"><a name="l00115"></a><span class="lineno">  115</span>&#160;</div><div class="line"><a name="l00120"></a><span class="lineno">  120</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream.html#a6bd5d633ff999e4da1faf3cd949aa602">requestFlush</a>() = 0;</div><div class="line"><a name="l00121"></a><span class="lineno">  121</span>&#160;</div><div class="line"><a name="l00126"></a><span class="lineno">  126</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream.html#a820e634f741e6b5efdcef8104cecb919">requestStop</a>() = 0;</div><div class="line"><a name="l00127"></a><span class="lineno">  127</span>&#160;</div><div class="line"><a name="l00133"></a><span class="lineno">  133</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a> <a class="code" href="classoboe_1_1_audio_stream.html#a9d37cc6513823c685ae892626ff83ea8">getState</a>() <span class="keyword">const</span> = 0;</div><div class="line"><a name="l00134"></a><span class="lineno">  134</span>&#160;</div><div class="line"><a name="l00162"></a><span class="lineno">  162</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream.html#a0c865a5501f369d959c39d8ab8b46a07">waitForStateChange</a>(<a class="code" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a> inputState,</div><div class="line"><a name="l00163"></a><span class="lineno">  163</span>&#160;                                          <a class="code" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a> *nextState,</div><div class="line"><a name="l00164"></a><span class="lineno">  164</span>&#160;                                          int64_t timeoutNanoseconds) = 0;</div><div class="line"><a name="l00165"></a><span class="lineno">  165</span>&#160;</div><div class="line"><a name="l00178"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#a06e3f9e133b3a75515e7793939d1cd03">  178</a></span>&#160;    <span class="keyword">virtual</span> <a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue&lt;int32_t&gt;</a> <a class="code" href="classoboe_1_1_audio_stream.html#a06e3f9e133b3a75515e7793939d1cd03">setBufferSizeInFrames</a>(int32_t <span class="comment">/* requestedFrames  */</span>) {</div><div class="line"><a name="l00179"></a><span class="lineno">  179</span>&#160;        <span class="keywordflow">return</span> Result::ErrorUnimplemented;</div><div class="line"><a name="l00180"></a><span class="lineno">  180</span>&#160;    }</div><div class="line"><a name="l00181"></a><span class="lineno">  181</span>&#160;</div><div class="line"><a name="l00194"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#ad1a1d3bbf3b348ed92b7ed18ce9cc261">  194</a></span>&#160;    <span class="keyword">virtual</span> <a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue&lt;int32_t&gt;</a> <a class="code" href="classoboe_1_1_audio_stream.html#ad1a1d3bbf3b348ed92b7ed18ce9cc261">getXRunCount</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00195"></a><span class="lineno">  195</span>&#160;        <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue&lt;int32_t&gt;</a>(Result::ErrorUnimplemented);</div><div class="line"><a name="l00196"></a><span class="lineno">  196</span>&#160;    }</div><div class="line"><a name="l00197"></a><span class="lineno">  197</span>&#160;</div><div class="line"><a name="l00201"></a><span class="lineno">  201</span>&#160;    <span class="keyword">virtual</span> <span class="keywordtype">bool</span> <a class="code" href="classoboe_1_1_audio_stream.html#a43d8a098440cde28f4ee8bedd6d107c4">isXRunCountSupported</a>() <span class="keyword">const</span> = 0;</div><div class="line"><a name="l00202"></a><span class="lineno">  202</span>&#160;</div><div class="line"><a name="l00208"></a><span class="lineno">  208</span>&#160;    <span class="keyword">virtual</span> int32_t <a class="code" href="classoboe_1_1_audio_stream.html#ac160acb656515814fa6fdd157c131a0a">getFramesPerBurst</a>() = 0;</div><div class="line"><a name="l00209"></a><span class="lineno">  209</span>&#160;</div><div class="line"><a name="l00217"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#a5c01907a59d5f89a5e4b819fe66b08bc">  217</a></span>&#160;    int32_t <a class="code" href="classoboe_1_1_audio_stream.html#a5c01907a59d5f89a5e4b819fe66b08bc">getBytesPerFrame</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">mChannelCount</a> * <a class="code" href="classoboe_1_1_audio_stream.html#a44dda61e6e948e49b68f87172f084d62">getBytesPerSample</a>(); }</div><div class="line"><a name="l00218"></a><span class="lineno">  218</span>&#160;</div><div class="line"><a name="l00225"></a><span class="lineno">  225</span>&#160;    int32_t <a class="code" href="classoboe_1_1_audio_stream.html#a44dda61e6e948e49b68f87172f084d62">getBytesPerSample</a>() <span class="keyword">const</span>;</div><div class="line"><a name="l00226"></a><span class="lineno">  226</span>&#160;</div><div class="line"><a name="l00233"></a><span class="lineno">  233</span>&#160;    <span class="keyword">virtual</span> int64_t <a class="code" href="classoboe_1_1_audio_stream.html#ab43dd4074e1de57bac1c3fd111430341">getFramesWritten</a>();</div><div class="line"><a name="l00234"></a><span class="lineno">  234</span>&#160;</div><div class="line"><a name="l00241"></a><span class="lineno">  241</span>&#160;    <span class="keyword">virtual</span> int64_t <a class="code" href="classoboe_1_1_audio_stream.html#aeebfc59abd978cd6dff07c16cfe266df">getFramesRead</a>();</div><div class="line"><a name="l00242"></a><span class="lineno">  242</span>&#160;</div><div class="line"><a name="l00266"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#ae023cb001f3261d064f423101798d6be">  266</a></span>&#160;    <span class="keyword">virtual</span> <a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue&lt;double&gt;</a> <a class="code" href="classoboe_1_1_audio_stream.html#ae023cb001f3261d064f423101798d6be">calculateLatencyMillis</a>() {</div><div class="line"><a name="l00267"></a><span class="lineno">  267</span>&#160;        <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue&lt;double&gt;</a>(Result::ErrorUnimplemented);</div><div class="line"><a name="l00268"></a><span class="lineno">  268</span>&#160;    }</div><div class="line"><a name="l00269"></a><span class="lineno">  269</span>&#160;</div><div class="line"><a name="l00287"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#acb8edbc17ff79993a8ed996d216fe6f3">  287</a></span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream.html#acb8edbc17ff79993a8ed996d216fe6f3">getTimestamp</a>(clockid_t <span class="comment">/* clockId  */</span>,</div><div class="line"><a name="l00288"></a><span class="lineno">  288</span>&#160;                                int64_t* <span class="comment">/* framePosition */</span>,</div><div class="line"><a name="l00289"></a><span class="lineno">  289</span>&#160;                                int64_t* <span class="comment">/* timeNanoseconds */</span>) {</div><div class="line"><a name="l00290"></a><span class="lineno">  290</span>&#160;        <span class="keywordflow">return</span> Result::ErrorUnimplemented;</div><div class="line"><a name="l00291"></a><span class="lineno">  291</span>&#160;    }</div><div class="line"><a name="l00292"></a><span class="lineno">  292</span>&#160;</div><div class="line"><a name="l00308"></a><span class="lineno">  308</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue&lt;FrameTimestamp&gt;</a> <a class="code" href="classoboe_1_1_audio_stream.html#acb8edbc17ff79993a8ed996d216fe6f3">getTimestamp</a>(clockid_t <span class="comment">/* clockId */</span>);</div><div class="line"><a name="l00309"></a><span class="lineno">  309</span>&#160;</div><div class="line"><a name="l00310"></a><span class="lineno">  310</span>&#160;    <span class="comment">// ============== I/O ===========================</span></div><div class="line"><a name="l00323"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#a3612c05ed6b01a213dde67d913c07e11">  323</a></span>&#160;<span class="comment"></span>    <span class="keyword">virtual</span> <a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue&lt;int32_t&gt;</a> <a class="code" href="classoboe_1_1_audio_stream.html#a3612c05ed6b01a213dde67d913c07e11">write</a>(<span class="keyword">const</span> <span class="keywordtype">void</span>* <span class="comment">/* buffer */</span>,</div><div class="line"><a name="l00324"></a><span class="lineno">  324</span>&#160;                             int32_t <span class="comment">/* numFrames */</span>,</div><div class="line"><a name="l00325"></a><span class="lineno">  325</span>&#160;                             int64_t <span class="comment">/* timeoutNanoseconds */</span> ) {</div><div class="line"><a name="l00326"></a><span class="lineno">  326</span>&#160;        <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue&lt;int32_t&gt;</a>(Result::ErrorUnimplemented);</div><div class="line"><a name="l00327"></a><span class="lineno">  327</span>&#160;    }</div><div class="line"><a name="l00328"></a><span class="lineno">  328</span>&#160;</div><div class="line"><a name="l00341"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#a8089f0a0cb68d4039cf33e6584129978">  341</a></span>&#160;    <span class="keyword">virtual</span> <a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue&lt;int32_t&gt;</a> <a class="code" href="classoboe_1_1_audio_stream.html#a8089f0a0cb68d4039cf33e6584129978">read</a>(<span class="keywordtype">void</span>* <span class="comment">/* buffer */</span>,</div><div class="line"><a name="l00342"></a><span class="lineno">  342</span>&#160;                            int32_t <span class="comment">/* numFrames */</span>,</div><div class="line"><a name="l00343"></a><span class="lineno">  343</span>&#160;                            int64_t <span class="comment">/* timeoutNanoseconds */</span>) {</div><div class="line"><a name="l00344"></a><span class="lineno">  344</span>&#160;        <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue&lt;int32_t&gt;</a>(Result::ErrorUnimplemented);</div><div class="line"><a name="l00345"></a><span class="lineno">  345</span>&#160;    }</div><div class="line"><a name="l00346"></a><span class="lineno">  346</span>&#160;</div><div class="line"><a name="l00352"></a><span class="lineno">  352</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">AudioApi</a> <a class="code" href="classoboe_1_1_audio_stream.html#a2b7a3cee7444114843dbdd1fc705f6bb">getAudioApi</a>() <span class="keyword">const</span> = 0;</div><div class="line"><a name="l00353"></a><span class="lineno">  353</span>&#160;</div><div class="line"><a name="l00359"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#a15cdaaaa4c1e8da322d6da33334c8147">  359</a></span>&#160;    <span class="keywordtype">bool</span> <a class="code" href="classoboe_1_1_audio_stream.html#a15cdaaaa4c1e8da322d6da33334c8147">usesAAudio</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00360"></a><span class="lineno">  360</span>&#160;        <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream.html#a2b7a3cee7444114843dbdd1fc705f6bb">getAudioApi</a>() == <a class="code" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a99780b1e8d754eb42abed0ca5253e55b">AudioApi::AAudio</a>;</div><div class="line"><a name="l00361"></a><span class="lineno">  361</span>&#160;    }</div><div class="line"><a name="l00362"></a><span class="lineno">  362</span>&#160;</div><div class="line"><a name="l00371"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#a5458d7130415eb4defe3dbc11d479e2f">  371</a></span>&#160;    <span class="keyword">virtual</span> <span class="keywordtype">void</span> *<a class="code" href="classoboe_1_1_audio_stream.html#a5458d7130415eb4defe3dbc11d479e2f">getUnderlyingStream</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00372"></a><span class="lineno">  372</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">nullptr</span>;</div><div class="line"><a name="l00373"></a><span class="lineno">  373</span>&#160;    }</div><div class="line"><a name="l00374"></a><span class="lineno">  374</span>&#160;</div><div class="line"><a name="l00378"></a><span class="lineno">  378</span>&#160;    <span class="keywordtype">void</span> <a class="code" href="classoboe_1_1_audio_stream.html#aa5f4801cca6877eeaa4735b93933269d">launchStopThread</a>();</div><div class="line"><a name="l00379"></a><span class="lineno">  379</span>&#160;</div><div class="line"><a name="l00384"></a><span class="lineno">  384</span>&#160;    <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a class="code" href="classoboe_1_1_audio_stream.html#a64ad978c5f70ced17ef5a96605496515">updateFramesWritten</a>() = 0;</div><div class="line"><a name="l00385"></a><span class="lineno">  385</span>&#160;</div><div class="line"><a name="l00390"></a><span class="lineno">  390</span>&#160;    <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a class="code" href="classoboe_1_1_audio_stream.html#a462358ddab709c79d1a7968d6d55b727">updateFramesRead</a>() = 0;</div><div class="line"><a name="l00391"></a><span class="lineno">  391</span>&#160;</div><div class="line"><a name="l00392"></a><span class="lineno">  392</span>&#160;    <span class="comment">/*</span></div><div class="line"><a name="l00393"></a><span class="lineno">  393</span>&#160;<span class="comment">     * Swap old callback for new callback.</span></div><div class="line"><a name="l00394"></a><span class="lineno">  394</span>&#160;<span class="comment">     * This not atomic.</span></div><div class="line"><a name="l00395"></a><span class="lineno">  395</span>&#160;<span class="comment">     * This should only be used internally.</span></div><div class="line"><a name="l00396"></a><span class="lineno">  396</span>&#160;<span class="comment">     * @param dataCallback</span></div><div class="line"><a name="l00397"></a><span class="lineno">  397</span>&#160;<span class="comment">     * @return previous dataCallback</span></div><div class="line"><a name="l00398"></a><span class="lineno">  398</span>&#160;<span class="comment">     */</span></div><div class="line"><a name="l00399"></a><span class="lineno">  399</span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> *swapDataCallback(<a class="code" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> *dataCallback) {</div><div class="line"><a name="l00400"></a><span class="lineno">  400</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> *previousCallback = <a class="code" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">mDataCallback</a>;</div><div class="line"><a name="l00401"></a><span class="lineno">  401</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">mDataCallback</a> = dataCallback;</div><div class="line"><a name="l00402"></a><span class="lineno">  402</span>&#160;        <span class="keywordflow">return</span> previousCallback;</div><div class="line"><a name="l00403"></a><span class="lineno">  403</span>&#160;    }</div><div class="line"><a name="l00404"></a><span class="lineno">  404</span>&#160;</div><div class="line"><a name="l00405"></a><span class="lineno">  405</span>&#160;    <span class="comment">/*</span></div><div class="line"><a name="l00406"></a><span class="lineno">  406</span>&#160;<span class="comment">     * Swap old callback for new callback.</span></div><div class="line"><a name="l00407"></a><span class="lineno">  407</span>&#160;<span class="comment">     * This not atomic.</span></div><div class="line"><a name="l00408"></a><span class="lineno">  408</span>&#160;<span class="comment">     * This should only be used internally.</span></div><div class="line"><a name="l00409"></a><span class="lineno">  409</span>&#160;<span class="comment">     * @param errorCallback</span></div><div class="line"><a name="l00410"></a><span class="lineno">  410</span>&#160;<span class="comment">     * @return previous errorCallback</span></div><div class="line"><a name="l00411"></a><span class="lineno">  411</span>&#160;<span class="comment">     */</span></div><div class="line"><a name="l00412"></a><span class="lineno">  412</span>&#160;    AudioStreamErrorCallback *swapErrorCallback(AudioStreamErrorCallback *errorCallback) {</div><div class="line"><a name="l00413"></a><span class="lineno">  413</span>&#160;        AudioStreamErrorCallback *previousCallback = <a class="code" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">mErrorCallback</a>;</div><div class="line"><a name="l00414"></a><span class="lineno">  414</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">mErrorCallback</a> = errorCallback;</div><div class="line"><a name="l00415"></a><span class="lineno">  415</span>&#160;        <span class="keywordflow">return</span> previousCallback;</div><div class="line"><a name="l00416"></a><span class="lineno">  416</span>&#160;    }</div><div class="line"><a name="l00417"></a><span class="lineno">  417</span>&#160;</div><div class="line"><a name="l00421"></a><span class="lineno">  421</span>&#160;    ResultWithValue&lt;int32_t&gt; <a class="code" href="classoboe_1_1_audio_stream.html#afa35ee4b8629fbffe26b9be7c7ed55d2">getAvailableFrames</a>();</div><div class="line"><a name="l00422"></a><span class="lineno">  422</span>&#160;</div><div class="line"><a name="l00432"></a><span class="lineno">  432</span>&#160;    ResultWithValue&lt;int32_t&gt; <a class="code" href="classoboe_1_1_audio_stream.html#afddb0962863ccf9ec6672a042fe15941">waitForAvailableFrames</a>(int32_t numFrames,</div><div class="line"><a name="l00433"></a><span class="lineno">  433</span>&#160;                                                    int64_t timeoutNanoseconds);</div><div class="line"><a name="l00434"></a><span class="lineno">  434</span>&#160;</div><div class="line"><a name="l00438"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#a8fe8afdf164a1fe835c514f709743d75">  438</a></span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a> <a class="code" href="classoboe_1_1_audio_stream.html#a8fe8afdf164a1fe835c514f709743d75">getLastErrorCallbackResult</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00439"></a><span class="lineno">  439</span>&#160;        <span class="keywordflow">return</span> mErrorCallbackResult;</div><div class="line"><a name="l00440"></a><span class="lineno">  440</span>&#160;    }</div><div class="line"><a name="l00441"></a><span class="lineno">  441</span>&#160;</div><div class="line"><a name="l00442"></a><span class="lineno">  442</span>&#160;<span class="keyword">protected</span>:</div><div class="line"><a name="l00443"></a><span class="lineno">  443</span>&#160;</div><div class="line"><a name="l00453"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#aa48da7bf28026b7cccee73e6b054af28">  453</a></span>&#160;    <span class="keywordtype">bool</span> <a class="code" href="classoboe_1_1_audio_stream.html#aa48da7bf28026b7cccee73e6b054af28">wasErrorCallbackCalled</a>() {</div><div class="line"><a name="l00454"></a><span class="lineno">  454</span>&#160;        <span class="keywordflow">return</span> mErrorCallbackCalled.exchange(<span class="keyword">true</span>);</div><div class="line"><a name="l00455"></a><span class="lineno">  455</span>&#160;    }</div><div class="line"><a name="l00456"></a><span class="lineno">  456</span>&#160;</div><div class="line"><a name="l00463"></a><span class="lineno">  463</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream.html#a8adbacd6a55a94a532916ab037fba1d6">waitForStateTransition</a>(<a class="code" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a> startingState,</div><div class="line"><a name="l00464"></a><span class="lineno">  464</span>&#160;                                          <a class="code" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a> endingState,</div><div class="line"><a name="l00465"></a><span class="lineno">  465</span>&#160;                                          int64_t timeoutNanoseconds);</div><div class="line"><a name="l00466"></a><span class="lineno">  466</span>&#160;</div><div class="line"><a name="l00474"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#a0ea79e60f5a3d29fc5a1a116aba11dfe">  474</a></span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a> <a class="code" href="classoboe_1_1_audio_stream.html#a0ea79e60f5a3d29fc5a1a116aba11dfe">onDefaultCallback</a>(<span class="keywordtype">void</span>* <span class="comment">/* audioData  */</span>, <span class="keywordtype">int</span> <span class="comment">/* numFrames */</span>) {</div><div class="line"><a name="l00475"></a><span class="lineno">  475</span>&#160;        <span class="keywordflow">return</span> DataCallbackResult::Stop;</div><div class="line"><a name="l00476"></a><span class="lineno">  476</span>&#160;    }</div><div class="line"><a name="l00477"></a><span class="lineno">  477</span>&#160;</div><div class="line"><a name="l00486"></a><span class="lineno">  486</span>&#160;    <a class="code" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a> <a class="code" href="classoboe_1_1_audio_stream.html#ab7a8cfe5d6039386bc5850fd5ee9bd62">fireDataCallback</a>(<span class="keywordtype">void</span> *audioData, <span class="keywordtype">int</span> numFrames);</div><div class="line"><a name="l00487"></a><span class="lineno">  487</span>&#160;</div><div class="line"><a name="l00491"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#add85011ba825f74931deeb92c5edf831">  491</a></span>&#160;    <span class="keywordtype">bool</span> <a class="code" href="classoboe_1_1_audio_stream.html#add85011ba825f74931deeb92c5edf831">isDataCallbackEnabled</a>() {</div><div class="line"><a name="l00492"></a><span class="lineno">  492</span>&#160;        <span class="keywordflow">return</span> mDataCallbackEnabled;</div><div class="line"><a name="l00493"></a><span class="lineno">  493</span>&#160;    }</div><div class="line"><a name="l00494"></a><span class="lineno">  494</span>&#160;</div><div class="line"><a name="l00499"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#a0faa6d3a6fd4f367e6f80d5a29e6dcba">  499</a></span>&#160;    <span class="keywordtype">void</span> <a class="code" href="classoboe_1_1_audio_stream.html#a0faa6d3a6fd4f367e6f80d5a29e6dcba">setDataCallbackEnabled</a>(<span class="keywordtype">bool</span> enabled) {</div><div class="line"><a name="l00500"></a><span class="lineno">  500</span>&#160;        mDataCallbackEnabled = enabled;</div><div class="line"><a name="l00501"></a><span class="lineno">  501</span>&#160;    }</div><div class="line"><a name="l00502"></a><span class="lineno">  502</span>&#160;</div><div class="line"><a name="l00503"></a><span class="lineno">  503</span>&#160;    <span class="comment">/*</span></div><div class="line"><a name="l00504"></a><span class="lineno">  504</span>&#160;<span class="comment">     * Set a weak_ptr to this stream from the shared_ptr so that we can</span></div><div class="line"><a name="l00505"></a><span class="lineno">  505</span>&#160;<span class="comment">     * later use a shared_ptr in the error callback.</span></div><div class="line"><a name="l00506"></a><span class="lineno">  506</span>&#160;<span class="comment">     */</span></div><div class="line"><a name="l00507"></a><span class="lineno">  507</span>&#160;    <span class="keywordtype">void</span> setWeakThis(std::shared_ptr&lt;oboe::AudioStream&gt; &amp;sharedStream) {</div><div class="line"><a name="l00508"></a><span class="lineno">  508</span>&#160;        mWeakThis = sharedStream;</div><div class="line"><a name="l00509"></a><span class="lineno">  509</span>&#160;    }</div><div class="line"><a name="l00510"></a><span class="lineno">  510</span>&#160;</div><div class="line"><a name="l00511"></a><span class="lineno">  511</span>&#160;    <span class="comment">/*</span></div><div class="line"><a name="l00512"></a><span class="lineno">  512</span>&#160;<span class="comment">     * Make a shared_ptr that will prevent this stream from being deleted.</span></div><div class="line"><a name="l00513"></a><span class="lineno">  513</span>&#160;<span class="comment">     */</span></div><div class="line"><a name="l00514"></a><span class="lineno">  514</span>&#160;    std::shared_ptr&lt;oboe::AudioStream&gt; lockWeakThis() {</div><div class="line"><a name="l00515"></a><span class="lineno">  515</span>&#160;        <span class="keywordflow">return</span> mWeakThis.lock();</div><div class="line"><a name="l00516"></a><span class="lineno">  516</span>&#160;    }</div><div class="line"><a name="l00517"></a><span class="lineno">  517</span>&#160;</div><div class="line"><a name="l00518"></a><span class="lineno">  518</span>&#160;    std::weak_ptr&lt;AudioStream&gt; mWeakThis; <span class="comment">// weak pointer to this object</span></div><div class="line"><a name="l00519"></a><span class="lineno">  519</span>&#160;</div><div class="line"><a name="l00526"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#a88a63317b7c58815bac074976b00aa23">  526</a></span>&#160;    std::atomic&lt;int64_t&gt; <a class="code" href="classoboe_1_1_audio_stream.html#a88a63317b7c58815bac074976b00aa23">mFramesWritten</a>{};</div><div class="line"><a name="l00527"></a><span class="lineno">  527</span>&#160;</div><div class="line"><a name="l00534"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream.html#a07e82f9b9e2e4800f23ae9a7193c3b58">  534</a></span>&#160;    std::atomic&lt;int64_t&gt; <a class="code" href="classoboe_1_1_audio_stream.html#a07e82f9b9e2e4800f23ae9a7193c3b58">mFramesRead</a>{};</div><div class="line"><a name="l00535"></a><span class="lineno">  535</span>&#160;</div><div class="line"><a name="l00536"></a><span class="lineno">  536</span>&#160;    std::mutex           mLock; <span class="comment">// for synchronizing start/stop/close</span></div><div class="line"><a name="l00537"></a><span class="lineno">  537</span>&#160;</div><div class="line"><a name="l00538"></a><span class="lineno">  538</span>&#160;    <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a>         mErrorCallbackResult = oboe::Result::OK;</div><div class="line"><a name="l00539"></a><span class="lineno">  539</span>&#160;</div><div class="line"><a name="l00540"></a><span class="lineno">  540</span>&#160;<span class="keyword">private</span>:</div><div class="line"><a name="l00541"></a><span class="lineno">  541</span>&#160;</div><div class="line"><a name="l00542"></a><span class="lineno">  542</span>&#160;    <span class="comment">// Log the scheduler if it changes.</span></div><div class="line"><a name="l00543"></a><span class="lineno">  543</span>&#160;    <span class="keywordtype">void</span>                 checkScheduler();</div><div class="line"><a name="l00544"></a><span class="lineno">  544</span>&#160;    <span class="keywordtype">int</span>                  mPreviousScheduler = -1;</div><div class="line"><a name="l00545"></a><span class="lineno">  545</span>&#160;</div><div class="line"><a name="l00546"></a><span class="lineno">  546</span>&#160;    std::atomic&lt;bool&gt;    mDataCallbackEnabled{<span class="keyword">false</span>};</div><div class="line"><a name="l00547"></a><span class="lineno">  547</span>&#160;    std::atomic&lt;bool&gt;    mErrorCallbackCalled{<span class="keyword">false</span>};</div><div class="line"><a name="l00548"></a><span class="lineno">  548</span>&#160;</div><div class="line"><a name="l00549"></a><span class="lineno">  549</span>&#160;};</div><div class="line"><a name="l00550"></a><span class="lineno">  550</span>&#160;</div><div class="line"><a name="l00555"></a><span class="lineno"><a class="line" href="structoboe_1_1_stream_deleter_functor.html">  555</a></span>&#160;    <span class="keyword">struct </span><a class="code" href="structoboe_1_1_stream_deleter_functor.html">StreamDeleterFunctor</a> {</div><div class="line"><a name="l00556"></a><span class="lineno">  556</span>&#160;        <span class="keywordtype">void</span> operator()(<a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a>  *audioStream) {</div><div class="line"><a name="l00557"></a><span class="lineno">  557</span>&#160;            <span class="keywordflow">if</span> (audioStream) {</div><div class="line"><a name="l00558"></a><span class="lineno">  558</span>&#160;                audioStream-&gt;<a class="code" href="classoboe_1_1_audio_stream.html#a9c8ea30e30e513766d5e996c370eb8d8">close</a>();</div><div class="line"><a name="l00559"></a><span class="lineno">  559</span>&#160;            }</div><div class="line"><a name="l00560"></a><span class="lineno">  560</span>&#160;            <span class="keyword">delete</span> audioStream;</div><div class="line"><a name="l00561"></a><span class="lineno">  561</span>&#160;        }</div><div class="line"><a name="l00562"></a><span class="lineno">  562</span>&#160;    };</div><div class="line"><a name="l00563"></a><span class="lineno">  563</span>&#160;} <span class="comment">// namespace oboe</span></div><div class="line"><a name="l00564"></a><span class="lineno">  564</span>&#160;</div><div class="line"><a name="l00565"></a><span class="lineno">  565</span>&#160;<span class="preprocessor">#endif </span><span class="comment">/* OBOE_STREAM_H_ */</span><span class="preprocessor"></span></div><div class="ttc" id="classoboe_1_1_audio_stream_html_a0ea79e60f5a3d29fc5a1a116aba11dfe"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a0ea79e60f5a3d29fc5a1a116aba11dfe">oboe::AudioStream::onDefaultCallback</a></div><div class="ttdeci">virtual DataCallbackResult onDefaultCallback(void *, int)</div><div class="ttdef"><b>Definition:</b> AudioStream.h:474</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_aec093859d42f0470c884edd1e976d9f3"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#aec093859d42f0470c884edd1e976d9f3">oboe::AudioStream::stop</a></div><div class="ttdeci">virtual Result stop(int64_t timeoutNanoseconds=kDefaultTimeoutNanos)</div></div>
-<div class="ttc" id="namespaceoboe_html_a92972414867c81d5974cb2ed7abefbf6a99780b1e8d754eb42abed0ca5253e55b"><div class="ttname"><a href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a99780b1e8d754eb42abed0ca5253e55b">oboe::AudioApi::AAudio</a></div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:33</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_afa35ee4b8629fbffe26b9be7c7ed55d2"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#afa35ee4b8629fbffe26b9be7c7ed55d2">oboe::AudioStream::getAvailableFrames</a></div><div class="ttdeci">ResultWithValue&lt; int32_t &gt; getAvailableFrames()</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a0faa6d3a6fd4f367e6f80d5a29e6dcba"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a0faa6d3a6fd4f367e6f80d5a29e6dcba">oboe::AudioStream::setDataCallbackEnabled</a></div><div class="ttdeci">void setDataCallbackEnabled(bool enabled)</div><div class="ttdef"><b>Definition:</b> AudioStream.h:499</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a15cdaaaa4c1e8da322d6da33334c8147"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a15cdaaaa4c1e8da322d6da33334c8147">oboe::AudioStream::usesAAudio</a></div><div class="ttdeci">bool usesAAudio() const</div><div class="ttdef"><b>Definition:</b> AudioStream.h:359</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a32c25c0333eab3d65ce02275ad4acb3d"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a32c25c0333eab3d65ce02275ad4acb3d">oboe::AudioStream::flush</a></div><div class="ttdeci">virtual Result flush(int64_t timeoutNanoseconds=kDefaultTimeoutNanos)</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a6d8493f66a945cb426506c70f0358e5f"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">oboe::AudioStreamBase::mDataCallback</a></div><div class="ttdeci">AudioStreamDataCallback * mDataCallback</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:182</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a5c01907a59d5f89a5e4b819fe66b08bc"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a5c01907a59d5f89a5e4b819fe66b08bc">oboe::AudioStream::getBytesPerFrame</a></div><div class="ttdeci">int32_t getBytesPerFrame() const</div><div class="ttdef"><b>Definition:</b> AudioStream.h:217</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_af04f03eb6b64b564f1c4401688987d21"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#af04f03eb6b64b564f1c4401688987d21">oboe::AudioStream::start</a></div><div class="ttdeci">virtual Result start(int64_t timeoutNanoseconds=kDefaultTimeoutNanos)</div></div>
-<div class="ttc" id="namespaceoboe_html_aab8f5f081a8b2147e16ec920347c1b5c"><div class="ttname"><a href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">oboe::kDefaultTimeoutNanos</a></div><div class="ttdeci">constexpr int64_t kDefaultTimeoutNanos</div><div class="ttdef"><b>Definition:</b> AudioStream.h:39</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_ad1a1d3bbf3b348ed92b7ed18ce9cc261"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#ad1a1d3bbf3b348ed92b7ed18ce9cc261">oboe::AudioStream::getXRunCount</a></div><div class="ttdeci">virtual ResultWithValue&lt; int32_t &gt; getXRunCount() const</div><div class="ttdef"><b>Definition:</b> AudioStream.h:194</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a88a63317b7c58815bac074976b00aa23"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a88a63317b7c58815bac074976b00aa23">oboe::AudioStream::mFramesWritten</a></div><div class="ttdeci">std::atomic&lt; int64_t &gt; mFramesWritten</div><div class="ttdef"><b>Definition:</b> AudioStream.h:526</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_ab7a8cfe5d6039386bc5850fd5ee9bd62"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#ab7a8cfe5d6039386bc5850fd5ee9bd62">oboe::AudioStream::fireDataCallback</a></div><div class="ttdeci">DataCallbackResult fireDataCallback(void *audioData, int numFrames)</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a5458d7130415eb4defe3dbc11d479e2f"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a5458d7130415eb4defe3dbc11d479e2f">oboe::AudioStream::getUnderlyingStream</a></div><div class="ttdeci">virtual void * getUnderlyingStream() const</div><div class="ttdef"><b>Definition:</b> AudioStream.h:371</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a64ad978c5f70ced17ef5a96605496515"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a64ad978c5f70ced17ef5a96605496515">oboe::AudioStream::updateFramesWritten</a></div><div class="ttdeci">virtual void updateFramesWritten()=0</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_ab43dd4074e1de57bac1c3fd111430341"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#ab43dd4074e1de57bac1c3fd111430341">oboe::AudioStream::getFramesWritten</a></div><div class="ttdeci">virtual int64_t getFramesWritten()</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_afddb0962863ccf9ec6672a042fe15941"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#afddb0962863ccf9ec6672a042fe15941">oboe::AudioStream::waitForAvailableFrames</a></div><div class="ttdeci">ResultWithValue&lt; int32_t &gt; waitForAvailableFrames(int32_t numFrames, int64_t timeoutNanoseconds)</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_data_callback_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a></div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:34</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a5ff460bac9d14dfeac4eeddfcbb6e206"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">oboe::AudioStreamBase::mChannelCount</a></div><div class="ttdeci">int32_t mChannelCount</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:190</div></div>
-<div class="ttc" id="namespaceoboe_html_af85fc9910a287df6c5df0ed396bb75cd"><div class="ttname"><a href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">oboe::DataCallbackResult</a></div><div class="ttdeci">DataCallbackResult</div><div class="ttdef"><b>Definition:</b> Definitions.h:119</div></div>
-<div class="ttc" id="namespaceoboe_html_a92972414867c81d5974cb2ed7abefbf6"><div class="ttname"><a href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">oboe::AudioApi</a></div><div class="ttdeci">AudioApi</div><div class="ttdef"><b>Definition:</b> Definitions.h:213</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a8adbacd6a55a94a532916ab037fba1d6"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a8adbacd6a55a94a532916ab037fba1d6">oboe::AudioStream::waitForStateTransition</a></div><div class="ttdeci">virtual Result waitForStateTransition(StreamState startingState, StreamState endingState, int64_t timeoutNanoseconds)</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_ac160acb656515814fa6fdd157c131a0a"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#ac160acb656515814fa6fdd157c131a0a">oboe::AudioStream::getFramesPerBurst</a></div><div class="ttdeci">virtual int32_t getFramesPerBurst()=0</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a9c8ea30e30e513766d5e996c370eb8d8"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a9c8ea30e30e513766d5e996c370eb8d8">oboe::AudioStream::close</a></div><div class="ttdeci">virtual Result close()</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a06e3f9e133b3a75515e7793939d1cd03"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a06e3f9e133b3a75515e7793939d1cd03">oboe::AudioStream::setBufferSizeInFrames</a></div><div class="ttdeci">virtual ResultWithValue&lt; int32_t &gt; setBufferSizeInFrames(int32_t)</div><div class="ttdef"><b>Definition:</b> AudioStream.h:178</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_ae023cb001f3261d064f423101798d6be"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#ae023cb001f3261d064f423101798d6be">oboe::AudioStream::calculateLatencyMillis</a></div><div class="ttdeci">virtual ResultWithValue&lt; double &gt; calculateLatencyMillis()</div><div class="ttdef"><b>Definition:</b> AudioStream.h:266</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_acb8edbc17ff79993a8ed996d216fe6f3"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#acb8edbc17ff79993a8ed996d216fe6f3">oboe::AudioStream::getTimestamp</a></div><div class="ttdeci">virtual Result getTimestamp(clockid_t, int64_t *, int64_t *)</div><div class="ttdef"><b>Definition:</b> AudioStream.h:287</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a686c6ce8a29051c858fd1de386805dc6"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a686c6ce8a29051c858fd1de386805dc6">oboe::AudioStream::open</a></div><div class="ttdeci">virtual Result open()</div><div class="ttdef"><b>Definition:</b> AudioStream.h:67</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_aeebfc59abd978cd6dff07c16cfe266df"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#aeebfc59abd978cd6dff07c16cfe266df">oboe::AudioStream::getFramesRead</a></div><div class="ttdeci">virtual int64_t getFramesRead()</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html"><div class="ttname"><a href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:44</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_add85011ba825f74931deeb92c5edf831"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#add85011ba825f74931deeb92c5edf831">oboe::AudioStream::isDataCallbackEnabled</a></div><div class="ttdeci">bool isDataCallbackEnabled()</div><div class="ttdef"><b>Definition:</b> AudioStream.h:491</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a8089f0a0cb68d4039cf33e6584129978"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a8089f0a0cb68d4039cf33e6584129978">oboe::AudioStream::read</a></div><div class="ttdeci">virtual ResultWithValue&lt; int32_t &gt; read(void *, int32_t, int64_t)</div><div class="ttdef"><b>Definition:</b> AudioStream.h:341</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a7f18bb3cc5490fd7fbc1f6da63c730f6"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a7f18bb3cc5490fd7fbc1f6da63c730f6">oboe::AudioStream::requestPause</a></div><div class="ttdeci">virtual Result requestPause()=0</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a3612c05ed6b01a213dde67d913c07e11"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a3612c05ed6b01a213dde67d913c07e11">oboe::AudioStream::write</a></div><div class="ttdeci">virtual ResultWithValue&lt; int32_t &gt; write(const void *, int32_t, int64_t)</div><div class="ttdef"><b>Definition:</b> AudioStream.h:323</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a07e82f9b9e2e4800f23ae9a7193c3b58"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a07e82f9b9e2e4800f23ae9a7193c3b58">oboe::AudioStream::mFramesRead</a></div><div class="ttdeci">std::atomic&lt; int64_t &gt; mFramesRead</div><div class="ttdef"><b>Definition:</b> AudioStream.h:534</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:29</div></div>
-<div class="ttc" id="namespaceoboe_html_a831e887150474c087170679eaca8672b"><div class="ttname"><a href="namespaceoboe.html#a831e887150474c087170679eaca8672b">oboe::kNanosPerMillisecond</a></div><div class="ttdeci">constexpr int64_t kNanosPerMillisecond</div><div class="ttdef"><b>Definition:</b> Definitions.h:43</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a820e634f741e6b5efdcef8104cecb919"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a820e634f741e6b5efdcef8104cecb919">oboe::AudioStream::requestStop</a></div><div class="ttdeci">virtual Result requestStop()=0</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a2b7a3cee7444114843dbdd1fc705f6bb"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a2b7a3cee7444114843dbdd1fc705f6bb">oboe::AudioStream::getAudioApi</a></div><div class="ttdeci">virtual AudioApi getAudioApi() const =0</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_aa5f4801cca6877eeaa4735b93933269d"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#aa5f4801cca6877eeaa4735b93933269d">oboe::AudioStream::launchStopThread</a></div><div class="ttdeci">void launchStopThread()</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a0c865a5501f369d959c39d8ab8b46a07"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a0c865a5501f369d959c39d8ab8b46a07">oboe::AudioStream::waitForStateChange</a></div><div class="ttdeci">virtual Result waitForStateChange(StreamState inputState, StreamState *nextState, int64_t timeoutNanoseconds)=0</div></div>
-<div class="ttc" id="namespaceoboe_html_a486512e787b609c80ba4436f23929af1"><div class="ttname"><a href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a></div><div class="ttdeci">Result</div><div class="ttdef"><b>Definition:</b> Definitions.h:131</div></div>
-<div class="ttc" id="structoboe_1_1_stream_deleter_functor_html"><div class="ttname"><a href="structoboe_1_1_stream_deleter_functor.html">oboe::StreamDeleterFunctor</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:555</div></div>
-<div class="ttc" id="namespaceoboe_html"><div class="ttname"><a href="namespaceoboe.html">oboe</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:31</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_aa48da7bf28026b7cccee73e6b054af28"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#aa48da7bf28026b7cccee73e6b054af28">oboe::AudioStream::wasErrorCallbackCalled</a></div><div class="ttdeci">bool wasErrorCallbackCalled()</div><div class="ttdef"><b>Definition:</b> AudioStream.h:453</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a43d8a098440cde28f4ee8bedd6d107c4"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a43d8a098440cde28f4ee8bedd6d107c4">oboe::AudioStream::isXRunCountSupported</a></div><div class="ttdeci">virtual bool isXRunCountSupported() const =0</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a3c484e314dee8dfed1d419f487b5d601"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a3c484e314dee8dfed1d419f487b5d601">oboe::AudioStream::requestStart</a></div><div class="ttdeci">virtual Result requestStart()=0</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a8fe8afdf164a1fe835c514f709743d75"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a8fe8afdf164a1fe835c514f709743d75">oboe::AudioStream::getLastErrorCallbackResult</a></div><div class="ttdeci">virtual oboe::Result getLastErrorCallbackResult() const</div><div class="ttdef"><b>Definition:</b> AudioStream.h:438</div></div>
-<div class="ttc" id="namespaceoboe_html_a89fa2ce046723764618c29db737917f6"><div class="ttname"><a href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">oboe::StreamState</a></div><div class="ttdeci">StreamState</div><div class="ttdef"><b>Definition:</b> Definitions.h:58</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a9d37cc6513823c685ae892626ff83ea8"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a9d37cc6513823c685ae892626ff83ea8">oboe::AudioStream::getState</a></div><div class="ttdeci">virtual StreamState getState() const =0</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a04f29836748a8e5842aef2be200022ad"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a04f29836748a8e5842aef2be200022ad">oboe::AudioStream::pause</a></div><div class="ttdeci">virtual Result pause(int64_t timeoutNanoseconds=kDefaultTimeoutNanos)</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a6bd5d633ff999e4da1faf3cd949aa602"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a6bd5d633ff999e4da1faf3cd949aa602">oboe::AudioStream::requestFlush</a></div><div class="ttdeci">virtual Result requestFlush()=0</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a462358ddab709c79d1a7968d6d55b727"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a462358ddab709c79d1a7968d6d55b727">oboe::AudioStream::updateFramesRead</a></div><div class="ttdeci">virtual void updateFramesRead()=0</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_adc0c8cc54adb6d3350c62b8a74b9c57b"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">oboe::AudioStreamBase::mErrorCallback</a></div><div class="ttdeci">AudioStreamErrorCallback * mErrorCallback</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:185</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html_a44dda61e6e948e49b68f87172f084d62"><div class="ttname"><a href="classoboe_1_1_audio_stream.html#a44dda61e6e948e49b68f87172f084d62">oboe::AudioStream::getBytesPerSample</a></div><div class="ttdeci">int32_t getBytesPerSample() const</div></div>
-<div class="ttc" id="classoboe_1_1_result_with_value_html"><div class="ttname"><a href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue</a></div><div class="ttdef"><b>Definition:</b> ResultWithValue.h:47</div></div>
-</div><!-- fragment --></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/_audio_stream_base_8h_source.html b/docs/reference/_audio_stream_base_8h_source.html
deleted file mode 100644
index ce322da..0000000
--- a/docs/reference/_audio_stream_base_8h_source.html
+++ /dev/null
@@ -1,145 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: include/oboe/AudioStreamBase.h Source File</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="dir_d44c64559bbebec7f509842c48db8b23.html">include</a></li><li class="navelem"><a class="el" href="dir_768f6301d9838e45d679001914ab2803.html">oboe</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">AudioStreamBase.h</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;<span class="comment">/*</span></div><div class="line"><a name="l00002"></a><span class="lineno">    2</span>&#160;<span class="comment"> * Copyright 2015 The Android Open Source Project</span></div><div class="line"><a name="l00003"></a><span class="lineno">    3</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00004"></a><span class="lineno">    4</span>&#160;<span class="comment"> * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></div><div class="line"><a name="l00005"></a><span class="lineno">    5</span>&#160;<span class="comment"> * you may not use this file except in compliance with the License.</span></div><div class="line"><a name="l00006"></a><span class="lineno">    6</span>&#160;<span class="comment"> * You may obtain a copy of the License at</span></div><div class="line"><a name="l00007"></a><span class="lineno">    7</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00008"></a><span class="lineno">    8</span>&#160;<span class="comment"> *      http://www.apache.org/licenses/LICENSE-2.0</span></div><div class="line"><a name="l00009"></a><span class="lineno">    9</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00010"></a><span class="lineno">   10</span>&#160;<span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></div><div class="line"><a name="l00011"></a><span class="lineno">   11</span>&#160;<span class="comment"> * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</span></div><div class="line"><a name="l00012"></a><span class="lineno">   12</span>&#160;<span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></div><div class="line"><a name="l00013"></a><span class="lineno">   13</span>&#160;<span class="comment"> * See the License for the specific language governing permissions and</span></div><div class="line"><a name="l00014"></a><span class="lineno">   14</span>&#160;<span class="comment"> * limitations under the License.</span></div><div class="line"><a name="l00015"></a><span class="lineno">   15</span>&#160;<span class="comment"> */</span></div><div class="line"><a name="l00016"></a><span class="lineno">   16</span>&#160;</div><div class="line"><a name="l00017"></a><span class="lineno">   17</span>&#160;<span class="preprocessor">#ifndef OBOE_STREAM_BASE_H_</span></div><div class="line"><a name="l00018"></a><span class="lineno">   18</span>&#160;<span class="preprocessor">#define OBOE_STREAM_BASE_H_</span></div><div class="line"><a name="l00019"></a><span class="lineno">   19</span>&#160;</div><div class="line"><a name="l00020"></a><span class="lineno">   20</span>&#160;<span class="preprocessor">#include &lt;memory&gt;</span></div><div class="line"><a name="l00021"></a><span class="lineno">   21</span>&#160;<span class="preprocessor">#include &quot;oboe/AudioStreamCallback.h&quot;</span></div><div class="line"><a name="l00022"></a><span class="lineno">   22</span>&#160;<span class="preprocessor">#include &quot;oboe/Definitions.h&quot;</span></div><div class="line"><a name="l00023"></a><span class="lineno">   23</span>&#160;</div><div class="line"><a name="l00024"></a><span class="lineno">   24</span>&#160;<span class="keyword">namespace </span><a class="code" href="namespaceoboe.html">oboe</a> {</div><div class="line"><a name="l00025"></a><span class="lineno">   25</span>&#160;</div><div class="line"><a name="l00029"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html">   29</a></span>&#160;<span class="keyword">class </span><a class="code" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> {</div><div class="line"><a name="l00030"></a><span class="lineno">   30</span>&#160;</div><div class="line"><a name="l00031"></a><span class="lineno">   31</span>&#160;<span class="keyword">public</span>:</div><div class="line"><a name="l00032"></a><span class="lineno">   32</span>&#160;</div><div class="line"><a name="l00033"></a><span class="lineno">   33</span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a>() {}</div><div class="line"><a name="l00034"></a><span class="lineno">   34</span>&#160;</div><div class="line"><a name="l00035"></a><span class="lineno">   35</span>&#160;    <span class="keyword">virtual</span> ~<a class="code" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a>() = <span class="keywordflow">default</span>;</div><div class="line"><a name="l00036"></a><span class="lineno">   36</span>&#160;</div><div class="line"><a name="l00037"></a><span class="lineno">   37</span>&#160;    <span class="comment">// This class only contains primitives so we can use default constructor and copy methods.</span></div><div class="line"><a name="l00038"></a><span class="lineno">   38</span>&#160;</div><div class="line"><a name="l00042"></a><span class="lineno">   42</span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a>(<span class="keyword">const</span> <a class="code" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a>&amp;) = <span class="keywordflow">default</span>;</div><div class="line"><a name="l00043"></a><span class="lineno">   43</span>&#160;</div><div class="line"><a name="l00047"></a><span class="lineno">   47</span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a>&amp; <a class="code" href="classoboe_1_1_audio_stream_base.html#aa9c987a59555d7a60b9f7a63f4afc7fc">operator=</a>(<span class="keyword">const</span> <a class="code" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a>&amp;) = <span class="keywordflow">default</span>;</div><div class="line"><a name="l00048"></a><span class="lineno">   48</span>&#160;</div><div class="line"><a name="l00052"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a87e6bf37d6a2a5e983b8ca8d29aea575">   52</a></span>&#160;    int32_t <a class="code" href="classoboe_1_1_audio_stream_base.html#a87e6bf37d6a2a5e983b8ca8d29aea575">getChannelCount</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">mChannelCount</a>; }</div><div class="line"><a name="l00053"></a><span class="lineno">   53</span>&#160;</div><div class="line"><a name="l00057"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a6f86f2233a04c5a0b056f0c1c261f1b1">   57</a></span>&#160;    <a class="code" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a> <a class="code" href="classoboe_1_1_audio_stream_base.html#a6f86f2233a04c5a0b056f0c1c261f1b1">getDirection</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880">mDirection</a>; }</div><div class="line"><a name="l00058"></a><span class="lineno">   58</span>&#160;</div><div class="line"><a name="l00062"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#ae9d32f3e09174bad69e74f147ee33087">   62</a></span>&#160;    int32_t <a class="code" href="classoboe_1_1_audio_stream_base.html#ae9d32f3e09174bad69e74f147ee33087">getSampleRate</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea">mSampleRate</a>; }</div><div class="line"><a name="l00063"></a><span class="lineno">   63</span>&#160;</div><div class="line"><a name="l00067"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a8878a90949badbb5486cc2e022a57086">   67</a></span>&#160;    int32_t <a class="code" href="classoboe_1_1_audio_stream_base.html#a8878a90949badbb5486cc2e022a57086">getFramesPerCallback</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#abc3ee2815568b425d15a40e132aa8e38">getFramesPerDataCallback</a>(); }</div><div class="line"><a name="l00068"></a><span class="lineno">   68</span>&#160;</div><div class="line"><a name="l00072"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#abc3ee2815568b425d15a40e132aa8e38">   72</a></span>&#160;    int32_t <a class="code" href="classoboe_1_1_audio_stream_base.html#abc3ee2815568b425d15a40e132aa8e38">getFramesPerDataCallback</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899">mFramesPerCallback</a>; }</div><div class="line"><a name="l00073"></a><span class="lineno">   73</span>&#160;</div><div class="line"><a name="l00077"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#ab1e640461d7bf9d596decb913da7ac86">   77</a></span>&#160;    <a class="code" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a> <a class="code" href="classoboe_1_1_audio_stream_base.html#ab1e640461d7bf9d596decb913da7ac86">getFormat</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">mFormat</a>; }</div><div class="line"><a name="l00078"></a><span class="lineno">   78</span>&#160;</div><div class="line"><a name="l00085"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#af5217ab05bfde0d7637024b599302d0b">   85</a></span>&#160;    <span class="keyword">virtual</span> int32_t <a class="code" href="classoboe_1_1_audio_stream_base.html#af5217ab05bfde0d7637024b599302d0b">getBufferSizeInFrames</a>() { <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#a3b65595d26d1eae1b8ce9925a5b98f6a">mBufferSizeInFrames</a>; }</div><div class="line"><a name="l00086"></a><span class="lineno">   86</span>&#160;</div><div class="line"><a name="l00090"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#ab1531253e64aaebe9e9eddbafb9098fc">   90</a></span>&#160;    <span class="keyword">virtual</span> int32_t <a class="code" href="classoboe_1_1_audio_stream_base.html#ab1531253e64aaebe9e9eddbafb9098fc">getBufferCapacityInFrames</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6">mBufferCapacityInFrames</a>; }</div><div class="line"><a name="l00091"></a><span class="lineno">   91</span>&#160;</div><div class="line"><a name="l00095"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a1fb033fc963f971bd1aa8f6707e49b41">   95</a></span>&#160;    <a class="code" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a> <a class="code" href="classoboe_1_1_audio_stream_base.html#a1fb033fc963f971bd1aa8f6707e49b41">getSharingMode</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473">mSharingMode</a>; }</div><div class="line"><a name="l00096"></a><span class="lineno">   96</span>&#160;</div><div class="line"><a name="l00100"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a2ddb935de0e24dd7ae8e2cfbecac9fdc">  100</a></span>&#160;    <a class="code" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a> <a class="code" href="classoboe_1_1_audio_stream_base.html#a2ddb935de0e24dd7ae8e2cfbecac9fdc">getPerformanceMode</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765">mPerformanceMode</a>; }</div><div class="line"><a name="l00101"></a><span class="lineno">  101</span>&#160;</div><div class="line"><a name="l00105"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a093057d625bc896864b959974c265f21">  105</a></span>&#160;    int32_t <a class="code" href="classoboe_1_1_audio_stream_base.html#a093057d625bc896864b959974c265f21">getDeviceId</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8">mDeviceId</a>; }</div><div class="line"><a name="l00106"></a><span class="lineno">  106</span>&#160;</div><div class="line"><a name="l00111"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a9fb2f34ae62dbda2c10e8513b754fa0c">  111</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> *<a class="code" href="classoboe_1_1_audio_stream_base.html#a9fb2f34ae62dbda2c10e8513b754fa0c">getDataCallback</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00112"></a><span class="lineno">  112</span>&#160;        <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">mDataCallback</a>;</div><div class="line"><a name="l00113"></a><span class="lineno">  113</span>&#160;    }</div><div class="line"><a name="l00114"></a><span class="lineno">  114</span>&#160;</div><div class="line"><a name="l00119"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a1328fb9288166ff325995ce1ea1867f0">  119</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a> *<a class="code" href="classoboe_1_1_audio_stream_base.html#a1328fb9288166ff325995ce1ea1867f0">getErrorCallback</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00120"></a><span class="lineno">  120</span>&#160;        <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">mErrorCallback</a>;</div><div class="line"><a name="l00121"></a><span class="lineno">  121</span>&#160;    }</div><div class="line"><a name="l00122"></a><span class="lineno">  122</span>&#160;</div><div class="line"><a name="l00126"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a9a54d38b985a2eb12c6972104dc0ce73">  126</a></span>&#160;    <span class="keywordtype">bool</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#a9a54d38b985a2eb12c6972104dc0ce73">isDataCallbackSpecified</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00127"></a><span class="lineno">  127</span>&#160;        <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">mDataCallback</a> != <span class="keyword">nullptr</span>;</div><div class="line"><a name="l00128"></a><span class="lineno">  128</span>&#160;    }</div><div class="line"><a name="l00129"></a><span class="lineno">  129</span>&#160;</div><div class="line"><a name="l00135"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#aef579f6d1f779c89d051f0963f2976b3">  135</a></span>&#160;    <span class="keywordtype">bool</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#aef579f6d1f779c89d051f0963f2976b3">isErrorCallbackSpecified</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00136"></a><span class="lineno">  136</span>&#160;        <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">mErrorCallback</a> != <span class="keyword">nullptr</span>;</div><div class="line"><a name="l00137"></a><span class="lineno">  137</span>&#160;    }</div><div class="line"><a name="l00138"></a><span class="lineno">  138</span>&#160;</div><div class="line"><a name="l00142"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a0bcfb2f8bd11c92b541fd910da9af397">  142</a></span>&#160;    <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a> <a class="code" href="classoboe_1_1_audio_stream_base.html#a0bcfb2f8bd11c92b541fd910da9af397">getUsage</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c">mUsage</a>; }</div><div class="line"><a name="l00143"></a><span class="lineno">  143</span>&#160;</div><div class="line"><a name="l00147"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#ab12e2d068fa87e0553b01a400d96eb82">  147</a></span>&#160;    <a class="code" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a> <a class="code" href="classoboe_1_1_audio_stream_base.html#ab12e2d068fa87e0553b01a400d96eb82">getContentType</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b">mContentType</a>; }</div><div class="line"><a name="l00148"></a><span class="lineno">  148</span>&#160;</div><div class="line"><a name="l00152"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a5c773b93b8aa38191c7199cab023428a">  152</a></span>&#160;    <a class="code" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a> <a class="code" href="classoboe_1_1_audio_stream_base.html#a5c773b93b8aa38191c7199cab023428a">getInputPreset</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589">mInputPreset</a>; }</div><div class="line"><a name="l00153"></a><span class="lineno">  153</span>&#160;</div><div class="line"><a name="l00157"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#aa3c502ce09bbad7690a2dd6acaf8892e">  157</a></span>&#160;    <a class="code" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a> <a class="code" href="classoboe_1_1_audio_stream_base.html#aa3c502ce09bbad7690a2dd6acaf8892e">getSessionId</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737">mSessionId</a>; }</div><div class="line"><a name="l00158"></a><span class="lineno">  158</span>&#160;</div><div class="line"><a name="l00162"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#aa4ec3aa76e69350fbce6f00786211495">  162</a></span>&#160;    <span class="keywordtype">bool</span> <a class="code" href="classoboe_1_1_audio_stream_base.html#aa4ec3aa76e69350fbce6f00786211495">isChannelConversionAllowed</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00163"></a><span class="lineno">  163</span>&#160;        <span class="keywordflow">return</span> mChannelConversionAllowed;</div><div class="line"><a name="l00164"></a><span class="lineno">  164</span>&#160;    }</div><div class="line"><a name="l00165"></a><span class="lineno">  165</span>&#160;</div><div class="line"><a name="l00169"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#ace3625a7332bf02a86818fdf63fcccb4">  169</a></span>&#160;    <span class="keywordtype">bool</span>  <a class="code" href="classoboe_1_1_audio_stream_base.html#ace3625a7332bf02a86818fdf63fcccb4">isFormatConversionAllowed</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00170"></a><span class="lineno">  170</span>&#160;        <span class="keywordflow">return</span> mFormatConversionAllowed;</div><div class="line"><a name="l00171"></a><span class="lineno">  171</span>&#160;    }</div><div class="line"><a name="l00172"></a><span class="lineno">  172</span>&#160;</div><div class="line"><a name="l00176"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a1de8d6982d411a0cf50a32efba0ca3f2">  176</a></span>&#160;    <a class="code" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">SampleRateConversionQuality</a> <a class="code" href="classoboe_1_1_audio_stream_base.html#a1de8d6982d411a0cf50a32efba0ca3f2">getSampleRateConversionQuality</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00177"></a><span class="lineno">  177</span>&#160;        <span class="keywordflow">return</span> mSampleRateConversionQuality;</div><div class="line"><a name="l00178"></a><span class="lineno">  178</span>&#160;    }</div><div class="line"><a name="l00179"></a><span class="lineno">  179</span>&#160;</div><div class="line"><a name="l00180"></a><span class="lineno">  180</span>&#160;<span class="keyword">protected</span>:</div><div class="line"><a name="l00182"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">  182</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a>        *<a class="code" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">mDataCallback</a> = <span class="keyword">nullptr</span>;</div><div class="line"><a name="l00183"></a><span class="lineno">  183</span>&#160;</div><div class="line"><a name="l00185"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">  185</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a>       *<a class="code" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">mErrorCallback</a> = <span class="keyword">nullptr</span>;</div><div class="line"><a name="l00186"></a><span class="lineno">  186</span>&#160;</div><div class="line"><a name="l00188"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899">  188</a></span>&#160;    int32_t                         <a class="code" href="classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899">mFramesPerCallback</a> = <a class="code" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a>;</div><div class="line"><a name="l00190"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">  190</a></span>&#160;    int32_t                         <a class="code" href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">mChannelCount</a> = <a class="code" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a>;</div><div class="line"><a name="l00192"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea">  192</a></span>&#160;    int32_t                         <a class="code" href="classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea">mSampleRate</a> = <a class="code" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a>;</div><div class="line"><a name="l00194"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8">  194</a></span>&#160;    int32_t                         <a class="code" href="classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8">mDeviceId</a> = <a class="code" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a>;</div><div class="line"><a name="l00196"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6">  196</a></span>&#160;    int32_t                         <a class="code" href="classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6">mBufferCapacityInFrames</a> = <a class="code" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a>;</div><div class="line"><a name="l00198"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a3b65595d26d1eae1b8ce9925a5b98f6a">  198</a></span>&#160;    int32_t                         <a class="code" href="classoboe_1_1_audio_stream_base.html#a3b65595d26d1eae1b8ce9925a5b98f6a">mBufferSizeInFrames</a> = <a class="code" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a>;</div><div class="line"><a name="l00203"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a54061319ed348329a29d883a5de2482e">  203</a></span>&#160;    int32_t                         <a class="code" href="classoboe_1_1_audio_stream_base.html#a54061319ed348329a29d883a5de2482e">mFramesPerBurst</a> = <a class="code" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a>;</div><div class="line"><a name="l00204"></a><span class="lineno">  204</span>&#160;</div><div class="line"><a name="l00206"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473">  206</a></span>&#160;    <a class="code" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a>                     <a class="code" href="classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473">mSharingMode</a> = <a class="code" href="namespaceoboe.html#a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca">SharingMode::Shared</a>;</div><div class="line"><a name="l00208"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">  208</a></span>&#160;    <a class="code" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a>                     <a class="code" href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">mFormat</a> = AudioFormat::Unspecified;</div><div class="line"><a name="l00210"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880">  210</a></span>&#160;    <a class="code" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a>                       <a class="code" href="classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880">mDirection</a> = <a class="code" href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54">Direction::Output</a>;</div><div class="line"><a name="l00212"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765">  212</a></span>&#160;    <a class="code" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a>                 <a class="code" href="classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765">mPerformanceMode</a> = PerformanceMode::None;</div><div class="line"><a name="l00213"></a><span class="lineno">  213</span>&#160;</div><div class="line"><a name="l00215"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c">  215</a></span>&#160;    <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a>                           <a class="code" href="classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c">mUsage</a> = <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74">Usage::Media</a>;</div><div class="line"><a name="l00217"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b">  217</a></span>&#160;    <a class="code" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a>                     <a class="code" href="classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b">mContentType</a> = ContentType::Music;</div><div class="line"><a name="l00221"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589">  221</a></span>&#160;    <a class="code" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a>                     <a class="code" href="classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589">mInputPreset</a> = InputPreset::VoiceRecognition;</div><div class="line"><a name="l00223"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737">  223</a></span>&#160;    <a class="code" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a>                       <a class="code" href="classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737">mSessionId</a> = SessionId::None;</div><div class="line"><a name="l00224"></a><span class="lineno">  224</span>&#160;</div><div class="line"><a name="l00225"></a><span class="lineno">  225</span>&#160;    <span class="comment">// Control whether Oboe can convert channel counts to achieve optimal results.</span></div><div class="line"><a name="l00226"></a><span class="lineno">  226</span>&#160;    <span class="keywordtype">bool</span>                            mChannelConversionAllowed = <span class="keyword">false</span>;</div><div class="line"><a name="l00227"></a><span class="lineno">  227</span>&#160;    <span class="comment">// Control whether Oboe can convert data formats to achieve optimal results.</span></div><div class="line"><a name="l00228"></a><span class="lineno">  228</span>&#160;    <span class="keywordtype">bool</span>                            mFormatConversionAllowed = <span class="keyword">false</span>;</div><div class="line"><a name="l00229"></a><span class="lineno">  229</span>&#160;    <span class="comment">// Control whether and how Oboe can convert sample rates to achieve optimal results.</span></div><div class="line"><a name="l00230"></a><span class="lineno">  230</span>&#160;    <a class="code" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">SampleRateConversionQuality</a>     mSampleRateConversionQuality = SampleRateConversionQuality::None;</div><div class="line"><a name="l00231"></a><span class="lineno">  231</span>&#160;</div><div class="line"><a name="l00233"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_base.html#a5d5e07e98921d0193a5c0ccbe06f68c2">  233</a></span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream_base.html#a5d5e07e98921d0193a5c0ccbe06f68c2">isValidConfig</a>() {</div><div class="line"><a name="l00234"></a><span class="lineno">  234</span>&#160;        <span class="keywordflow">switch</span> (<a class="code" href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">mFormat</a>) {</div><div class="line"><a name="l00235"></a><span class="lineno">  235</span>&#160;            <span class="keywordflow">case</span> AudioFormat::Unspecified:</div><div class="line"><a name="l00236"></a><span class="lineno">  236</span>&#160;            <span class="keywordflow">case</span> <a class="code" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6abcd774f891b5f9df7099f3ea75dadf8d">AudioFormat::I16</a>:</div><div class="line"><a name="l00237"></a><span class="lineno">  237</span>&#160;            <span class="keywordflow">case</span> <a class="code" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6a22ae0e2b89e5e3d477f988cc36d3272b">AudioFormat::Float</a>:</div><div class="line"><a name="l00238"></a><span class="lineno">  238</span>&#160;                <span class="keywordflow">break</span>;</div><div class="line"><a name="l00239"></a><span class="lineno">  239</span>&#160;</div><div class="line"><a name="l00240"></a><span class="lineno">  240</span>&#160;            <span class="keywordflow">default</span>:</div><div class="line"><a name="l00241"></a><span class="lineno">  241</span>&#160;                <span class="keywordflow">return</span> Result::ErrorInvalidFormat;</div><div class="line"><a name="l00242"></a><span class="lineno">  242</span>&#160;        }</div><div class="line"><a name="l00243"></a><span class="lineno">  243</span>&#160;</div><div class="line"><a name="l00244"></a><span class="lineno">  244</span>&#160;        <span class="keywordflow">switch</span> (mSampleRateConversionQuality) {</div><div class="line"><a name="l00245"></a><span class="lineno">  245</span>&#160;            <span class="keywordflow">case</span> SampleRateConversionQuality::None:</div><div class="line"><a name="l00246"></a><span class="lineno">  246</span>&#160;            <span class="keywordflow">case</span> <a class="code" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1da90fd7fdf6f41406a75e5265b9583bb4e">SampleRateConversionQuality::Fastest</a>:</div><div class="line"><a name="l00247"></a><span class="lineno">  247</span>&#160;            <span class="keywordflow">case</span> SampleRateConversionQuality::Low:</div><div class="line"><a name="l00248"></a><span class="lineno">  248</span>&#160;            <span class="keywordflow">case</span> SampleRateConversionQuality::Medium:</div><div class="line"><a name="l00249"></a><span class="lineno">  249</span>&#160;            <span class="keywordflow">case</span> SampleRateConversionQuality::High:</div><div class="line"><a name="l00250"></a><span class="lineno">  250</span>&#160;            <span class="keywordflow">case</span> <a class="code" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1da68ef004de6166492c1d668eb8efe09bd">SampleRateConversionQuality::Best</a>:</div><div class="line"><a name="l00251"></a><span class="lineno">  251</span>&#160;                <span class="keywordflow">return</span> Result::OK;</div><div class="line"><a name="l00252"></a><span class="lineno">  252</span>&#160;            <span class="keywordflow">default</span>:</div><div class="line"><a name="l00253"></a><span class="lineno">  253</span>&#160;                <span class="keywordflow">return</span> Result::ErrorIllegalArgument;</div><div class="line"><a name="l00254"></a><span class="lineno">  254</span>&#160;        }</div><div class="line"><a name="l00255"></a><span class="lineno">  255</span>&#160;    }</div><div class="line"><a name="l00256"></a><span class="lineno">  256</span>&#160;};</div><div class="line"><a name="l00257"></a><span class="lineno">  257</span>&#160;</div><div class="line"><a name="l00258"></a><span class="lineno">  258</span>&#160;} <span class="comment">// namespace oboe</span></div><div class="line"><a name="l00259"></a><span class="lineno">  259</span>&#160;</div><div class="line"><a name="l00260"></a><span class="lineno">  260</span>&#160;<span class="preprocessor">#endif </span><span class="comment">/* OBOE_STREAM_BASE_H_ */</span><span class="preprocessor"></span></div><div class="ttc" id="classoboe_1_1_audio_stream_base_html_a9fb2f34ae62dbda2c10e8513b754fa0c"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a9fb2f34ae62dbda2c10e8513b754fa0c">oboe::AudioStreamBase::getDataCallback</a></div><div class="ttdeci">AudioStreamDataCallback * getDataCallback() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:111</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_aa4ec3aa76e69350fbce6f00786211495"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#aa4ec3aa76e69350fbce6f00786211495">oboe::AudioStreamBase::isChannelConversionAllowed</a></div><div class="ttdeci">bool isChannelConversionAllowed() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:162</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a3b65595d26d1eae1b8ce9925a5b98f6a"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a3b65595d26d1eae1b8ce9925a5b98f6a">oboe::AudioStreamBase::mBufferSizeInFrames</a></div><div class="ttdeci">int32_t mBufferSizeInFrames</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:198</div></div>
-<div class="ttc" id="namespaceoboe_html_af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54"><div class="ttname"><a href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54">oboe::Direction::Output</a></div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_abe1c1e9cada1ced9b5c1504ac9b07737"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737">oboe::AudioStreamBase::mSessionId</a></div><div class="ttdeci">SessionId mSessionId</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:223</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a26e9294721561d3b16bcaeec5faf4880"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880">oboe::AudioStreamBase::mDirection</a></div><div class="ttdeci">Direction mDirection</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:210</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a093057d625bc896864b959974c265f21"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a093057d625bc896864b959974c265f21">oboe::AudioStreamBase::getDeviceId</a></div><div class="ttdeci">int32_t getDeviceId() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:105</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a6d8493f66a945cb426506c70f0358e5f"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">oboe::AudioStreamBase::mDataCallback</a></div><div class="ttdeci">AudioStreamDataCallback * mDataCallback</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:182</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a7869f04836c2c2bdc10c7309ad4b8e09"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">oboe::AudioStreamBase::mFormat</a></div><div class="ttdeci">AudioFormat mFormat</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:208</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_aef579f6d1f779c89d051f0963f2976b3"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#aef579f6d1f779c89d051f0963f2976b3">oboe::AudioStreamBase::isErrorCallbackSpecified</a></div><div class="ttdeci">bool isErrorCallbackSpecified() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:135</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a8878a90949badbb5486cc2e022a57086"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a8878a90949badbb5486cc2e022a57086">oboe::AudioStreamBase::getFramesPerCallback</a></div><div class="ttdeci">int32_t getFramesPerCallback() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:67</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a5f8f0e5add381b841856de80ea4cdb2b"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b">oboe::AudioStreamBase::mContentType</a></div><div class="ttdeci">ContentType mContentType</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:217</div></div>
-<div class="ttc" id="namespaceoboe_html_a1068781f3920654b1bfd7ed136468184"><div class="ttname"><a href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">oboe::PerformanceMode</a></div><div class="ttdeci">PerformanceMode</div><div class="ttdef"><b>Definition:</b> Definitions.h:192</div></div>
-<div class="ttc" id="namespaceoboe_html_a5752250c10e96179e3618d7f72937eaf"><div class="ttname"><a href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">oboe::SessionId</a></div><div class="ttdeci">SessionId</div><div class="ttdef"><b>Definition:</b> Definitions.h:414</div></div>
-<div class="ttc" id="namespaceoboe_html_a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca"><div class="ttname"><a href="namespaceoboe.html#a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca">oboe::SharingMode::Shared</a></div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_ab99671c2d0552557e75dc7b4afe91765"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765">oboe::AudioStreamBase::mPerformanceMode</a></div><div class="ttdeci">PerformanceMode mPerformanceMode</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:212</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a2ddb935de0e24dd7ae8e2cfbecac9fdc"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a2ddb935de0e24dd7ae8e2cfbecac9fdc">oboe::AudioStreamBase::getPerformanceMode</a></div><div class="ttdeci">PerformanceMode getPerformanceMode() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:100</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a87e6bf37d6a2a5e983b8ca8d29aea575"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a87e6bf37d6a2a5e983b8ca8d29aea575">oboe::AudioStreamBase::getChannelCount</a></div><div class="ttdeci">int32_t getChannelCount() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:52</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_aa3c502ce09bbad7690a2dd6acaf8892e"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#aa3c502ce09bbad7690a2dd6acaf8892e">oboe::AudioStreamBase::getSessionId</a></div><div class="ttdeci">SessionId getSessionId() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:157</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_data_callback_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a></div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:34</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_ae9187492b679c97a0963e264954be473"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473">oboe::AudioStreamBase::mSharingMode</a></div><div class="ttdeci">SharingMode mSharingMode</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:206</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a5ff460bac9d14dfeac4eeddfcbb6e206"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">oboe::AudioStreamBase::mChannelCount</a></div><div class="ttdeci">int32_t mChannelCount</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:190</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_ace3625a7332bf02a86818fdf63fcccb4"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#ace3625a7332bf02a86818fdf63fcccb4">oboe::AudioStreamBase::isFormatConversionAllowed</a></div><div class="ttdeci">bool isFormatConversionAllowed() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:169</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_ab1e640461d7bf9d596decb913da7ac86"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#ab1e640461d7bf9d596decb913da7ac86">oboe::AudioStreamBase::getFormat</a></div><div class="ttdeci">AudioFormat getFormat() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:77</div></div>
-<div class="ttc" id="namespaceoboe_html_a2a3cec6f021c1a324df60273710c604b"><div class="ttname"><a href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">oboe::ContentType</a></div><div class="ttdeci">ContentType</div><div class="ttdef"><b>Definition:</b> Definitions.h:339</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_abc3ee2815568b425d15a40e132aa8e38"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#abc3ee2815568b425d15a40e132aa8e38">oboe::AudioStreamBase::getFramesPerDataCallback</a></div><div class="ttdeci">int32_t getFramesPerDataCallback() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:72</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a23dafa12fb1a6242b088ebd5a52798c8"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8">oboe::AudioStreamBase::mDeviceId</a></div><div class="ttdeci">int32_t mDeviceId</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:194</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a5d5e07e98921d0193a5c0ccbe06f68c2"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a5d5e07e98921d0193a5c0ccbe06f68c2">oboe::AudioStreamBase::isValidConfig</a></div><div class="ttdeci">virtual Result isValidConfig()</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:233</div></div>
-<div class="ttc" id="namespaceoboe_html_a82f3720eba7654aceb7282be36f9ff1da68ef004de6166492c1d668eb8efe09bd"><div class="ttname"><a href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1da68ef004de6166492c1d668eb8efe09bd">oboe::SampleRateConversionQuality::Best</a></div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_ab12e2d068fa87e0553b01a400d96eb82"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#ab12e2d068fa87e0553b01a400d96eb82">oboe::AudioStreamBase::getContentType</a></div><div class="ttdeci">ContentType getContentType() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:147</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a5b518e82f39c9fcbd7050fd66adb253c"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c">oboe::AudioStreamBase::mUsage</a></div><div class="ttdeci">Usage mUsage</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:215</div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">oboe::Usage</a></div><div class="ttdeci">Usage</div><div class="ttdef"><b>Definition:</b> Definitions.h:263</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_error_callback_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:97</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_ae9d32f3e09174bad69e74f147ee33087"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#ae9d32f3e09174bad69e74f147ee33087">oboe::AudioStreamBase::getSampleRate</a></div><div class="ttdeci">int32_t getSampleRate() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:62</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a998885bb6c4f37e145f4626ad4177dea"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea">oboe::AudioStreamBase::mSampleRate</a></div><div class="ttdeci">int32_t mSampleRate</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:192</div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74">oboe::Usage::Media</a></div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a54061319ed348329a29d883a5de2482e"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a54061319ed348329a29d883a5de2482e">oboe::AudioStreamBase::mFramesPerBurst</a></div><div class="ttdeci">int32_t mFramesPerBurst</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:203</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a1fb033fc963f971bd1aa8f6707e49b41"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a1fb033fc963f971bd1aa8f6707e49b41">oboe::AudioStreamBase::getSharingMode</a></div><div class="ttdeci">SharingMode getSharingMode() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:95</div></div>
-<div class="ttc" id="namespaceoboe_html_a92afc593e856571aacbfd02e57075df6abcd774f891b5f9df7099f3ea75dadf8d"><div class="ttname"><a href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6abcd774f891b5f9df7099f3ea75dadf8d">oboe::AudioFormat::I16</a></div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:29</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_ac81d4719b350f8138aad1af38f0873b6"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6">oboe::AudioStreamBase::mBufferCapacityInFrames</a></div><div class="ttdeci">int32_t mBufferCapacityInFrames</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:196</div></div>
-<div class="ttc" id="namespaceoboe_html_a92afc593e856571aacbfd02e57075df6a22ae0e2b89e5e3d477f988cc36d3272b"><div class="ttname"><a href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6a22ae0e2b89e5e3d477f988cc36d3272b">oboe::AudioFormat::Float</a></div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a1de8d6982d411a0cf50a32efba0ca3f2"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a1de8d6982d411a0cf50a32efba0ca3f2">oboe::AudioStreamBase::getSampleRateConversionQuality</a></div><div class="ttdeci">SampleRateConversionQuality getSampleRateConversionQuality() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:176</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_aa9c987a59555d7a60b9f7a63f4afc7fc"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#aa9c987a59555d7a60b9f7a63f4afc7fc">oboe::AudioStreamBase::operator=</a></div><div class="ttdeci">AudioStreamBase &amp; operator=(const AudioStreamBase &amp;)=default</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_af5217ab05bfde0d7637024b599302d0b"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#af5217ab05bfde0d7637024b599302d0b">oboe::AudioStreamBase::getBufferSizeInFrames</a></div><div class="ttdeci">virtual int32_t getBufferSizeInFrames()</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:85</div></div>
-<div class="ttc" id="namespaceoboe_html_a92afc593e856571aacbfd02e57075df6"><div class="ttname"><a href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">oboe::AudioFormat</a></div><div class="ttdeci">AudioFormat</div><div class="ttdef"><b>Definition:</b> Definitions.h:94</div></div>
-<div class="ttc" id="namespaceoboe_html_a486512e787b609c80ba4436f23929af1"><div class="ttname"><a href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a></div><div class="ttdeci">Result</div><div class="ttdef"><b>Definition:</b> Definitions.h:131</div></div>
-<div class="ttc" id="namespaceoboe_html_ab0772052200184e514082eaa89be7905"><div class="ttname"><a href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">oboe::kUnspecified</a></div><div class="ttdeci">constexpr int32_t kUnspecified</div><div class="ttdef"><b>Definition:</b> Definitions.h:32</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_ab1531253e64aaebe9e9eddbafb9098fc"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#ab1531253e64aaebe9e9eddbafb9098fc">oboe::AudioStreamBase::getBufferCapacityInFrames</a></div><div class="ttdeci">virtual int32_t getBufferCapacityInFrames() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:90</div></div>
-<div class="ttc" id="namespaceoboe_html"><div class="ttname"><a href="namespaceoboe.html">oboe</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:31</div></div>
-<div class="ttc" id="namespaceoboe_html_a82f3720eba7654aceb7282be36f9ff1d"><div class="ttname"><a href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">oboe::SampleRateConversionQuality</a></div><div class="ttdeci">SampleRateConversionQuality</div><div class="ttdef"><b>Definition:</b> Definitions.h:235</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a1e5d4f5b30c4cc36f81ffd858cc00589"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589">oboe::AudioStreamBase::mInputPreset</a></div><div class="ttdeci">InputPreset mInputPreset</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:221</div></div>
-<div class="ttc" id="namespaceoboe_html_af2147500089212955498a08ef2edb5ae"><div class="ttname"><a href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">oboe::Direction</a></div><div class="ttdeci">Direction</div><div class="ttdef"><b>Definition:</b> Definitions.h:78</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a6f86f2233a04c5a0b056f0c1c261f1b1"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a6f86f2233a04c5a0b056f0c1c261f1b1">oboe::AudioStreamBase::getDirection</a></div><div class="ttdeci">Direction getDirection() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:57</div></div>
-<div class="ttc" id="namespaceoboe_html_a8330247b25429953a08354f41834d520"><div class="ttname"><a href="namespaceoboe.html#a8330247b25429953a08354f41834d520">oboe::SharingMode</a></div><div class="ttdeci">SharingMode</div><div class="ttdef"><b>Definition:</b> Definitions.h:167</div></div>
-<div class="ttc" id="namespaceoboe_html_a4477ed232b02e2694d9309baf55a8f06"><div class="ttname"><a href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">oboe::InputPreset</a></div><div class="ttdeci">InputPreset</div><div class="ttdef"><b>Definition:</b> Definitions.h:372</div></div>
-<div class="ttc" id="namespaceoboe_html_a82f3720eba7654aceb7282be36f9ff1da90fd7fdf6f41406a75e5265b9583bb4e"><div class="ttname"><a href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1da90fd7fdf6f41406a75e5265b9583bb4e">oboe::SampleRateConversionQuality::Fastest</a></div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a3962eb94420ad0ecea70029236001899"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899">oboe::AudioStreamBase::mFramesPerCallback</a></div><div class="ttdeci">int32_t mFramesPerCallback</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:188</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a9a54d38b985a2eb12c6972104dc0ce73"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a9a54d38b985a2eb12c6972104dc0ce73">oboe::AudioStreamBase::isDataCallbackSpecified</a></div><div class="ttdeci">bool isDataCallbackSpecified() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:126</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a0bcfb2f8bd11c92b541fd910da9af397"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a0bcfb2f8bd11c92b541fd910da9af397">oboe::AudioStreamBase::getUsage</a></div><div class="ttdeci">Usage getUsage() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:142</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_adc0c8cc54adb6d3350c62b8a74b9c57b"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">oboe::AudioStreamBase::mErrorCallback</a></div><div class="ttdeci">AudioStreamErrorCallback * mErrorCallback</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:185</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a5c773b93b8aa38191c7199cab023428a"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a5c773b93b8aa38191c7199cab023428a">oboe::AudioStreamBase::getInputPreset</a></div><div class="ttdeci">InputPreset getInputPreset() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:152</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a1328fb9288166ff325995ce1ea1867f0"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a1328fb9288166ff325995ce1ea1867f0">oboe::AudioStreamBase::getErrorCallback</a></div><div class="ttdeci">AudioStreamErrorCallback * getErrorCallback() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:119</div></div>
-</div><!-- fragment --></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/_audio_stream_builder_8h_source.html b/docs/reference/_audio_stream_builder_8h_source.html
deleted file mode 100644
index 9d354d3..0000000
--- a/docs/reference/_audio_stream_builder_8h_source.html
+++ /dev/null
@@ -1,143 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: include/oboe/AudioStreamBuilder.h Source File</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="dir_d44c64559bbebec7f509842c48db8b23.html">include</a></li><li class="navelem"><a class="el" href="dir_768f6301d9838e45d679001914ab2803.html">oboe</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">AudioStreamBuilder.h</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;<span class="comment">/*</span></div><div class="line"><a name="l00002"></a><span class="lineno">    2</span>&#160;<span class="comment"> * Copyright 2015 The Android Open Source Project</span></div><div class="line"><a name="l00003"></a><span class="lineno">    3</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00004"></a><span class="lineno">    4</span>&#160;<span class="comment"> * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></div><div class="line"><a name="l00005"></a><span class="lineno">    5</span>&#160;<span class="comment"> * you may not use this file except in compliance with the License.</span></div><div class="line"><a name="l00006"></a><span class="lineno">    6</span>&#160;<span class="comment"> * You may obtain a copy of the License at</span></div><div class="line"><a name="l00007"></a><span class="lineno">    7</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00008"></a><span class="lineno">    8</span>&#160;<span class="comment"> *      http://www.apache.org/licenses/LICENSE-2.0</span></div><div class="line"><a name="l00009"></a><span class="lineno">    9</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00010"></a><span class="lineno">   10</span>&#160;<span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></div><div class="line"><a name="l00011"></a><span class="lineno">   11</span>&#160;<span class="comment"> * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</span></div><div class="line"><a name="l00012"></a><span class="lineno">   12</span>&#160;<span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></div><div class="line"><a name="l00013"></a><span class="lineno">   13</span>&#160;<span class="comment"> * See the License for the specific language governing permissions and</span></div><div class="line"><a name="l00014"></a><span class="lineno">   14</span>&#160;<span class="comment"> * limitations under the License.</span></div><div class="line"><a name="l00015"></a><span class="lineno">   15</span>&#160;<span class="comment"> */</span></div><div class="line"><a name="l00016"></a><span class="lineno">   16</span>&#160;</div><div class="line"><a name="l00017"></a><span class="lineno">   17</span>&#160;<span class="preprocessor">#ifndef OBOE_STREAM_BUILDER_H_</span></div><div class="line"><a name="l00018"></a><span class="lineno">   18</span>&#160;<span class="preprocessor">#define OBOE_STREAM_BUILDER_H_</span></div><div class="line"><a name="l00019"></a><span class="lineno">   19</span>&#160;</div><div class="line"><a name="l00020"></a><span class="lineno">   20</span>&#160;<span class="preprocessor">#include &quot;oboe/Definitions.h&quot;</span></div><div class="line"><a name="l00021"></a><span class="lineno">   21</span>&#160;<span class="preprocessor">#include &quot;oboe/AudioStreamBase.h&quot;</span></div><div class="line"><a name="l00022"></a><span class="lineno">   22</span>&#160;<span class="preprocessor">#include &quot;ResultWithValue.h&quot;</span></div><div class="line"><a name="l00023"></a><span class="lineno">   23</span>&#160;</div><div class="line"><a name="l00024"></a><span class="lineno">   24</span>&#160;<span class="keyword">namespace </span><a class="code" href="namespaceoboe.html">oboe</a> {</div><div class="line"><a name="l00025"></a><span class="lineno">   25</span>&#160;</div><div class="line"><a name="l00026"></a><span class="lineno">   26</span>&#160;    <span class="comment">// This depends on AudioStream, so we use forward declaration, it will close and delete the stream</span></div><div class="line"><a name="l00027"></a><span class="lineno">   27</span>&#160;    <span class="keyword">struct </span>StreamDeleterFunctor;</div><div class="line"><a name="l00028"></a><span class="lineno">   28</span>&#160;    <span class="keyword">using</span> ManagedStream = std::unique_ptr&lt;AudioStream, StreamDeleterFunctor&gt;;</div><div class="line"><a name="l00029"></a><span class="lineno">   29</span>&#160;</div><div class="line"><a name="l00033"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html">   33</a></span>&#160;<span class="keyword">class </span><a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> : <span class="keyword">public</span> <a class="code" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> {</div><div class="line"><a name="l00034"></a><span class="lineno">   34</span>&#160;<span class="keyword">public</span>:</div><div class="line"><a name="l00035"></a><span class="lineno">   35</span>&#160;</div><div class="line"><a name="l00036"></a><span class="lineno">   36</span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>() : <a class="code" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a>() {}</div><div class="line"><a name="l00037"></a><span class="lineno">   37</span>&#160;</div><div class="line"><a name="l00038"></a><span class="lineno">   38</span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>(<span class="keyword">const</span> <a class="code" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> &amp;audioStreamBase): <a class="code" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a>(audioStreamBase) {}</div><div class="line"><a name="l00039"></a><span class="lineno">   39</span>&#160;</div><div class="line"><a name="l00046"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#a075d10291e1f998d90c2f73ef767b5a7">   46</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#a075d10291e1f998d90c2f73ef767b5a7">setChannelCount</a>(<span class="keywordtype">int</span> channelCount) {</div><div class="line"><a name="l00047"></a><span class="lineno">   47</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">mChannelCount</a> = channelCount;</div><div class="line"><a name="l00048"></a><span class="lineno">   48</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00049"></a><span class="lineno">   49</span>&#160;    }</div><div class="line"><a name="l00050"></a><span class="lineno">   50</span>&#160;</div><div class="line"><a name="l00056"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#ab3fbd47b06197619c26393637e26354c">   56</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#ab3fbd47b06197619c26393637e26354c">setDirection</a>(<a class="code" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a> direction) {</div><div class="line"><a name="l00057"></a><span class="lineno">   57</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880">mDirection</a> = direction;</div><div class="line"><a name="l00058"></a><span class="lineno">   58</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00059"></a><span class="lineno">   59</span>&#160;    }</div><div class="line"><a name="l00060"></a><span class="lineno">   60</span>&#160;</div><div class="line"><a name="l00072"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#a30ef3d5f51d56a9f980dc09600ed139d">   72</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#a30ef3d5f51d56a9f980dc09600ed139d">setSampleRate</a>(int32_t sampleRate) {</div><div class="line"><a name="l00073"></a><span class="lineno">   73</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea">mSampleRate</a> = sampleRate;</div><div class="line"><a name="l00074"></a><span class="lineno">   74</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00075"></a><span class="lineno">   75</span>&#160;    }</div><div class="line"><a name="l00076"></a><span class="lineno">   76</span>&#160;</div><div class="line"><a name="l00080"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#a3f397821f61eabaeedaf31064c859a54">   80</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#a3f397821f61eabaeedaf31064c859a54">setFramesPerCallback</a>(<span class="keywordtype">int</span> framesPerCallback) {</div><div class="line"><a name="l00081"></a><span class="lineno">   81</span>&#160;        <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_audio_stream_builder.html#afb8e95e80df7edd1af27af490438785e">setFramesPerDataCallback</a>(framesPerCallback);</div><div class="line"><a name="l00082"></a><span class="lineno">   82</span>&#160;    }</div><div class="line"><a name="l00083"></a><span class="lineno">   83</span>&#160;</div><div class="line"><a name="l00098"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#afb8e95e80df7edd1af27af490438785e">   98</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#afb8e95e80df7edd1af27af490438785e">setFramesPerDataCallback</a>(<span class="keywordtype">int</span> framesPerCallback) {</div><div class="line"><a name="l00099"></a><span class="lineno">   99</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899">mFramesPerCallback</a> = framesPerCallback;</div><div class="line"><a name="l00100"></a><span class="lineno">  100</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00101"></a><span class="lineno">  101</span>&#160;    }</div><div class="line"><a name="l00102"></a><span class="lineno">  102</span>&#160;</div><div class="line"><a name="l00109"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#aa2e1d2d73cd6c2eb9f349bf2fe5f6515">  109</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#aa2e1d2d73cd6c2eb9f349bf2fe5f6515">setFormat</a>(<a class="code" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a> format) {</div><div class="line"><a name="l00110"></a><span class="lineno">  110</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">mFormat</a> = format;</div><div class="line"><a name="l00111"></a><span class="lineno">  111</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00112"></a><span class="lineno">  112</span>&#160;    }</div><div class="line"><a name="l00113"></a><span class="lineno">  113</span>&#160;</div><div class="line"><a name="l00126"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#abaff480867af51ca0899bfa6fd7cc3ef">  126</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#abaff480867af51ca0899bfa6fd7cc3ef">setBufferCapacityInFrames</a>(int32_t bufferCapacityInFrames) {</div><div class="line"><a name="l00127"></a><span class="lineno">  127</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6">mBufferCapacityInFrames</a> = bufferCapacityInFrames;</div><div class="line"><a name="l00128"></a><span class="lineno">  128</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00129"></a><span class="lineno">  129</span>&#160;    }</div><div class="line"><a name="l00130"></a><span class="lineno">  130</span>&#160;</div><div class="line"><a name="l00141"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#ac9d41811c297fd28bc61833f640bb8d0">  141</a></span>&#160;    <a class="code" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">AudioApi</a> <a class="code" href="classoboe_1_1_audio_stream_builder.html#ac9d41811c297fd28bc61833f640bb8d0">getAudioApi</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> mAudioApi; }</div><div class="line"><a name="l00142"></a><span class="lineno">  142</span>&#160;</div><div class="line"><a name="l00156"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#a38c6d6c5e718df1e3ac69daaac47c391">  156</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#a38c6d6c5e718df1e3ac69daaac47c391">setAudioApi</a>(<a class="code" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">AudioApi</a> audioApi) {</div><div class="line"><a name="l00157"></a><span class="lineno">  157</span>&#160;        mAudioApi = audioApi;</div><div class="line"><a name="l00158"></a><span class="lineno">  158</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00159"></a><span class="lineno">  159</span>&#160;    }</div><div class="line"><a name="l00160"></a><span class="lineno">  160</span>&#160;</div><div class="line"><a name="l00168"></a><span class="lineno">  168</span>&#160;    <span class="keyword">static</span> <span class="keywordtype">bool</span> <a class="code" href="classoboe_1_1_audio_stream_builder.html#a18e7b5f7554a4c2ca763e35e8117d699">isAAudioSupported</a>();</div><div class="line"><a name="l00169"></a><span class="lineno">  169</span>&#160;</div><div class="line"><a name="l00178"></a><span class="lineno">  178</span>&#160;    <span class="keyword">static</span> <span class="keywordtype">bool</span> <a class="code" href="classoboe_1_1_audio_stream_builder.html#a622732bbe5c6577356d749f7dc2108df">isAAudioRecommended</a>();</div><div class="line"><a name="l00179"></a><span class="lineno">  179</span>&#160;</div><div class="line"><a name="l00188"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#a3e991742acbbfb6fe5ebcf592c478654">  188</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#a3e991742acbbfb6fe5ebcf592c478654">setSharingMode</a>(<a class="code" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a> sharingMode) {</div><div class="line"><a name="l00189"></a><span class="lineno">  189</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473">mSharingMode</a> = sharingMode;</div><div class="line"><a name="l00190"></a><span class="lineno">  190</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00191"></a><span class="lineno">  191</span>&#160;    }</div><div class="line"><a name="l00192"></a><span class="lineno">  192</span>&#160;</div><div class="line"><a name="l00201"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#a6cd1d65612e844e59da71a68ea0ab3ee">  201</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#a6cd1d65612e844e59da71a68ea0ab3ee">setPerformanceMode</a>(<a class="code" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a> performanceMode) {</div><div class="line"><a name="l00202"></a><span class="lineno">  202</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765">mPerformanceMode</a> = performanceMode;</div><div class="line"><a name="l00203"></a><span class="lineno">  203</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00204"></a><span class="lineno">  204</span>&#160;    }</div><div class="line"><a name="l00205"></a><span class="lineno">  205</span>&#160;</div><div class="line"><a name="l00206"></a><span class="lineno">  206</span>&#160;</div><div class="line"><a name="l00220"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#a593255a2f5eb972665775cfc5bc58f6a">  220</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#a593255a2f5eb972665775cfc5bc58f6a">setUsage</a>(<a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a> usage) {</div><div class="line"><a name="l00221"></a><span class="lineno">  221</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c">mUsage</a> = usage;</div><div class="line"><a name="l00222"></a><span class="lineno">  222</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00223"></a><span class="lineno">  223</span>&#160;    }</div><div class="line"><a name="l00224"></a><span class="lineno">  224</span>&#160;</div><div class="line"><a name="l00238"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#a6a17bafc217c2b624179fbbf77fe4468">  238</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#a6a17bafc217c2b624179fbbf77fe4468">setContentType</a>(<a class="code" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a> contentType) {</div><div class="line"><a name="l00239"></a><span class="lineno">  239</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b">mContentType</a> = contentType;</div><div class="line"><a name="l00240"></a><span class="lineno">  240</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00241"></a><span class="lineno">  241</span>&#160;    }</div><div class="line"><a name="l00242"></a><span class="lineno">  242</span>&#160;</div><div class="line"><a name="l00258"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#a144a3d095fd668210282f1a91f23e1f0">  258</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#a144a3d095fd668210282f1a91f23e1f0">setInputPreset</a>(<a class="code" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a> inputPreset) {</div><div class="line"><a name="l00259"></a><span class="lineno">  259</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589">mInputPreset</a> = inputPreset;</div><div class="line"><a name="l00260"></a><span class="lineno">  260</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00261"></a><span class="lineno">  261</span>&#160;    }</div><div class="line"><a name="l00262"></a><span class="lineno">  262</span>&#160;</div><div class="line"><a name="l00287"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#a54c1651bdbe089d0d714af499e8a5f1d">  287</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#a54c1651bdbe089d0d714af499e8a5f1d">setSessionId</a>(<a class="code" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a> sessionId) {</div><div class="line"><a name="l00288"></a><span class="lineno">  288</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737">mSessionId</a> = sessionId;</div><div class="line"><a name="l00289"></a><span class="lineno">  289</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00290"></a><span class="lineno">  290</span>&#160;    }</div><div class="line"><a name="l00291"></a><span class="lineno">  291</span>&#160;</div><div class="line"><a name="l00310"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#af36ddcd00686a9e1de661bdac0685a8e">  310</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#af36ddcd00686a9e1de661bdac0685a8e">setDeviceId</a>(int32_t deviceId) {</div><div class="line"><a name="l00311"></a><span class="lineno">  311</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8">mDeviceId</a> = deviceId;</div><div class="line"><a name="l00312"></a><span class="lineno">  312</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00313"></a><span class="lineno">  313</span>&#160;    }</div><div class="line"><a name="l00314"></a><span class="lineno">  314</span>&#160;</div><div class="line"><a name="l00324"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#acad307720e0f370267b4e2f9a626ae70">  324</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#acad307720e0f370267b4e2f9a626ae70">setDataCallback</a>(<a class="code" href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a> *dataCallback) {</div><div class="line"><a name="l00325"></a><span class="lineno">  325</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">mDataCallback</a> = dataCallback;</div><div class="line"><a name="l00326"></a><span class="lineno">  326</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00327"></a><span class="lineno">  327</span>&#160;    }</div><div class="line"><a name="l00328"></a><span class="lineno">  328</span>&#160;</div><div class="line"><a name="l00344"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#aacb66f530bfc6f545911b5e169774567">  344</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#aacb66f530bfc6f545911b5e169774567">setErrorCallback</a>(<a class="code" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a> *errorCallback) {</div><div class="line"><a name="l00345"></a><span class="lineno">  345</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">mErrorCallback</a> = errorCallback;</div><div class="line"><a name="l00346"></a><span class="lineno">  346</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00347"></a><span class="lineno">  347</span>&#160;    }</div><div class="line"><a name="l00348"></a><span class="lineno">  348</span>&#160;</div><div class="line"><a name="l00372"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#a698cefa9af73bc97c020c004821fccbd">  372</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#a698cefa9af73bc97c020c004821fccbd">setCallback</a>(<a class="code" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a> *streamCallback) {</div><div class="line"><a name="l00373"></a><span class="lineno">  373</span>&#160;        <span class="comment">// Use the same callback object for both, dual inheritance.</span></div><div class="line"><a name="l00374"></a><span class="lineno">  374</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">mDataCallback</a> = streamCallback;</div><div class="line"><a name="l00375"></a><span class="lineno">  375</span>&#160;        <a class="code" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">mErrorCallback</a> = streamCallback;</div><div class="line"><a name="l00376"></a><span class="lineno">  376</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00377"></a><span class="lineno">  377</span>&#160;    }</div><div class="line"><a name="l00378"></a><span class="lineno">  378</span>&#160;</div><div class="line"><a name="l00388"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#ad50f5d20cdf420d982bf499790cd3563">  388</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#ad50f5d20cdf420d982bf499790cd3563">setChannelConversionAllowed</a>(<span class="keywordtype">bool</span> allowed) {</div><div class="line"><a name="l00389"></a><span class="lineno">  389</span>&#160;        mChannelConversionAllowed = allowed;</div><div class="line"><a name="l00390"></a><span class="lineno">  390</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00391"></a><span class="lineno">  391</span>&#160;    }</div><div class="line"><a name="l00392"></a><span class="lineno">  392</span>&#160;</div><div class="line"><a name="l00400"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#a7ec5f427cd6fe55cb1ce536ff0cbb4d2">  400</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#a7ec5f427cd6fe55cb1ce536ff0cbb4d2">setFormatConversionAllowed</a>(<span class="keywordtype">bool</span> allowed) {</div><div class="line"><a name="l00401"></a><span class="lineno">  401</span>&#160;        mFormatConversionAllowed = allowed;</div><div class="line"><a name="l00402"></a><span class="lineno">  402</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00403"></a><span class="lineno">  403</span>&#160;    }</div><div class="line"><a name="l00404"></a><span class="lineno">  404</span>&#160;</div><div class="line"><a name="l00416"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#af7d24a9ec975d430732151e5ee0d1027">  416</a></span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *<a class="code" href="classoboe_1_1_audio_stream_builder.html#af7d24a9ec975d430732151e5ee0d1027">setSampleRateConversionQuality</a>(<a class="code" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">SampleRateConversionQuality</a> quality) {</div><div class="line"><a name="l00417"></a><span class="lineno">  417</span>&#160;        mSampleRateConversionQuality = quality;</div><div class="line"><a name="l00418"></a><span class="lineno">  418</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">this</span>;</div><div class="line"><a name="l00419"></a><span class="lineno">  419</span>&#160;    }</div><div class="line"><a name="l00420"></a><span class="lineno">  420</span>&#160;</div><div class="line"><a name="l00424"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_builder.html#aa07ea100fcb107d9f7913f206c2214f4">  424</a></span>&#160;    <span class="keywordtype">bool</span> <a class="code" href="classoboe_1_1_audio_stream_builder.html#aa07ea100fcb107d9f7913f206c2214f4">willUseAAudio</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00425"></a><span class="lineno">  425</span>&#160;        <span class="keywordflow">return</span> (mAudioApi == <a class="code" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a99780b1e8d754eb42abed0ca5253e55b">AudioApi::AAudio</a> &amp;&amp; <a class="code" href="classoboe_1_1_audio_stream_builder.html#a18e7b5f7554a4c2ca763e35e8117d699">isAAudioSupported</a>())</div><div class="line"><a name="l00426"></a><span class="lineno">  426</span>&#160;                || (mAudioApi == AudioApi::Unspecified &amp;&amp; <a class="code" href="classoboe_1_1_audio_stream_builder.html#a622732bbe5c6577356d749f7dc2108df">isAAudioRecommended</a>());</div><div class="line"><a name="l00427"></a><span class="lineno">  427</span>&#160;    }</div><div class="line"><a name="l00428"></a><span class="lineno">  428</span>&#160;</div><div class="line"><a name="l00438"></a><span class="lineno">  438</span>&#160;    <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream_builder.html#a86b94cfa47729bef2e04dce1a9086074">openStream</a>(<a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a> **stream);</div><div class="line"><a name="l00439"></a><span class="lineno">  439</span>&#160;</div><div class="line"><a name="l00450"></a><span class="lineno">  450</span>&#160;    <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream_builder.html#a86b94cfa47729bef2e04dce1a9086074">openStream</a>(std::shared_ptr&lt;oboe::AudioStream&gt; &amp;stream);</div><div class="line"><a name="l00451"></a><span class="lineno">  451</span>&#160;</div><div class="line"><a name="l00461"></a><span class="lineno">  461</span>&#160;    <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_audio_stream_builder.html#a7ab172a9be4fca2489aa5cbcc48c20ff">openManagedStream</a>(ManagedStream &amp;stream);</div><div class="line"><a name="l00462"></a><span class="lineno">  462</span>&#160;</div><div class="line"><a name="l00463"></a><span class="lineno">  463</span>&#160;<span class="keyword">private</span>:</div><div class="line"><a name="l00464"></a><span class="lineno">  464</span>&#160;</div><div class="line"><a name="l00469"></a><span class="lineno">  469</span>&#160;    <span class="keywordtype">bool</span> isCompatible(<a class="code" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> &amp;other);</div><div class="line"><a name="l00470"></a><span class="lineno">  470</span>&#160;</div><div class="line"><a name="l00478"></a><span class="lineno">  478</span>&#160;    <a class="code" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a> *build();</div><div class="line"><a name="l00479"></a><span class="lineno">  479</span>&#160;</div><div class="line"><a name="l00480"></a><span class="lineno">  480</span>&#160;    <a class="code" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">AudioApi</a>       mAudioApi = AudioApi::Unspecified;</div><div class="line"><a name="l00481"></a><span class="lineno">  481</span>&#160;};</div><div class="line"><a name="l00482"></a><span class="lineno">  482</span>&#160;</div><div class="line"><a name="l00483"></a><span class="lineno">  483</span>&#160;} <span class="comment">// namespace oboe</span></div><div class="line"><a name="l00484"></a><span class="lineno">  484</span>&#160;</div><div class="line"><a name="l00485"></a><span class="lineno">  485</span>&#160;<span class="preprocessor">#endif </span><span class="comment">/* OBOE_STREAM_BUILDER_H_ */</span><span class="preprocessor"></span></div><div class="ttc" id="classoboe_1_1_audio_stream_builder_html_af36ddcd00686a9e1de661bdac0685a8e"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#af36ddcd00686a9e1de661bdac0685a8e">oboe::AudioStreamBuilder::setDeviceId</a></div><div class="ttdeci">AudioStreamBuilder * setDeviceId(int32_t deviceId)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:310</div></div>
-<div class="ttc" id="namespaceoboe_html_a92972414867c81d5974cb2ed7abefbf6a99780b1e8d754eb42abed0ca5253e55b"><div class="ttname"><a href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a99780b1e8d754eb42abed0ca5253e55b">oboe::AudioApi::AAudio</a></div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:33</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_abe1c1e9cada1ced9b5c1504ac9b07737"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737">oboe::AudioStreamBase::mSessionId</a></div><div class="ttdeci">SessionId mSessionId</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:223</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a6cd1d65612e844e59da71a68ea0ab3ee"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a6cd1d65612e844e59da71a68ea0ab3ee">oboe::AudioStreamBuilder::setPerformanceMode</a></div><div class="ttdeci">AudioStreamBuilder * setPerformanceMode(PerformanceMode performanceMode)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:201</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a26e9294721561d3b16bcaeec5faf4880"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880">oboe::AudioStreamBase::mDirection</a></div><div class="ttdeci">Direction mDirection</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:210</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a6d8493f66a945cb426506c70f0358e5f"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">oboe::AudioStreamBase::mDataCallback</a></div><div class="ttdeci">AudioStreamDataCallback * mDataCallback</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:182</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a7869f04836c2c2bdc10c7309ad4b8e09"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">oboe::AudioStreamBase::mFormat</a></div><div class="ttdeci">AudioFormat mFormat</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:208</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a5f8f0e5add381b841856de80ea4cdb2b"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b">oboe::AudioStreamBase::mContentType</a></div><div class="ttdeci">ContentType mContentType</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:217</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a622732bbe5c6577356d749f7dc2108df"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a622732bbe5c6577356d749f7dc2108df">oboe::AudioStreamBuilder::isAAudioRecommended</a></div><div class="ttdeci">static bool isAAudioRecommended()</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_af7d24a9ec975d430732151e5ee0d1027"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#af7d24a9ec975d430732151e5ee0d1027">oboe::AudioStreamBuilder::setSampleRateConversionQuality</a></div><div class="ttdeci">AudioStreamBuilder * setSampleRateConversionQuality(SampleRateConversionQuality quality)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:416</div></div>
-<div class="ttc" id="namespaceoboe_html_a1068781f3920654b1bfd7ed136468184"><div class="ttname"><a href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">oboe::PerformanceMode</a></div><div class="ttdeci">PerformanceMode</div><div class="ttdef"><b>Definition:</b> Definitions.h:192</div></div>
-<div class="ttc" id="namespaceoboe_html_a5752250c10e96179e3618d7f72937eaf"><div class="ttname"><a href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">oboe::SessionId</a></div><div class="ttdeci">SessionId</div><div class="ttdef"><b>Definition:</b> Definitions.h:414</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a54c1651bdbe089d0d714af499e8a5f1d"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a54c1651bdbe089d0d714af499e8a5f1d">oboe::AudioStreamBuilder::setSessionId</a></div><div class="ttdeci">AudioStreamBuilder * setSessionId(SessionId sessionId)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:287</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_ab99671c2d0552557e75dc7b4afe91765"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765">oboe::AudioStreamBase::mPerformanceMode</a></div><div class="ttdeci">PerformanceMode mPerformanceMode</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:212</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_data_callback_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a></div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:34</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_callback_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_callback.html">oboe::AudioStreamCallback</a></div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:181</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_ae9187492b679c97a0963e264954be473"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473">oboe::AudioStreamBase::mSharingMode</a></div><div class="ttdeci">SharingMode mSharingMode</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:206</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a6a17bafc217c2b624179fbbf77fe4468"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a6a17bafc217c2b624179fbbf77fe4468">oboe::AudioStreamBuilder::setContentType</a></div><div class="ttdeci">AudioStreamBuilder * setContentType(ContentType contentType)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:238</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a5ff460bac9d14dfeac4eeddfcbb6e206"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">oboe::AudioStreamBase::mChannelCount</a></div><div class="ttdeci">int32_t mChannelCount</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:190</div></div>
-<div class="ttc" id="namespaceoboe_html_a92972414867c81d5974cb2ed7abefbf6"><div class="ttname"><a href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">oboe::AudioApi</a></div><div class="ttdeci">AudioApi</div><div class="ttdef"><b>Definition:</b> Definitions.h:213</div></div>
-<div class="ttc" id="namespaceoboe_html_a2a3cec6f021c1a324df60273710c604b"><div class="ttname"><a href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">oboe::ContentType</a></div><div class="ttdeci">ContentType</div><div class="ttdef"><b>Definition:</b> Definitions.h:339</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a593255a2f5eb972665775cfc5bc58f6a"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a593255a2f5eb972665775cfc5bc58f6a">oboe::AudioStreamBuilder::setUsage</a></div><div class="ttdeci">AudioStreamBuilder * setUsage(Usage usage)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:220</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a23dafa12fb1a6242b088ebd5a52798c8"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8">oboe::AudioStreamBase::mDeviceId</a></div><div class="ttdeci">int32_t mDeviceId</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:194</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a18e7b5f7554a4c2ca763e35e8117d699"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a18e7b5f7554a4c2ca763e35e8117d699">oboe::AudioStreamBuilder::isAAudioSupported</a></div><div class="ttdeci">static bool isAAudioSupported()</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_ad50f5d20cdf420d982bf499790cd3563"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#ad50f5d20cdf420d982bf499790cd3563">oboe::AudioStreamBuilder::setChannelConversionAllowed</a></div><div class="ttdeci">AudioStreamBuilder * setChannelConversionAllowed(bool allowed)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:388</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a3f397821f61eabaeedaf31064c859a54"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a3f397821f61eabaeedaf31064c859a54">oboe::AudioStreamBuilder::setFramesPerCallback</a></div><div class="ttdeci">AudioStreamBuilder * setFramesPerCallback(int framesPerCallback)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:80</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_ab3fbd47b06197619c26393637e26354c"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#ab3fbd47b06197619c26393637e26354c">oboe::AudioStreamBuilder::setDirection</a></div><div class="ttdeci">AudioStreamBuilder * setDirection(Direction direction)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:56</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_aa2e1d2d73cd6c2eb9f349bf2fe5f6515"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#aa2e1d2d73cd6c2eb9f349bf2fe5f6515">oboe::AudioStreamBuilder::setFormat</a></div><div class="ttdeci">AudioStreamBuilder * setFormat(AudioFormat format)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:109</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a5b518e82f39c9fcbd7050fd66adb253c"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c">oboe::AudioStreamBase::mUsage</a></div><div class="ttdeci">Usage mUsage</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:215</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html"><div class="ttname"><a href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:44</div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">oboe::Usage</a></div><div class="ttdeci">Usage</div><div class="ttdef"><b>Definition:</b> Definitions.h:263</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_error_callback_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:97</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a38c6d6c5e718df1e3ac69daaac47c391"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a38c6d6c5e718df1e3ac69daaac47c391">oboe::AudioStreamBuilder::setAudioApi</a></div><div class="ttdeci">AudioStreamBuilder * setAudioApi(AudioApi audioApi)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:156</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a144a3d095fd668210282f1a91f23e1f0"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a144a3d095fd668210282f1a91f23e1f0">oboe::AudioStreamBuilder::setInputPreset</a></div><div class="ttdeci">AudioStreamBuilder * setInputPreset(InputPreset inputPreset)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:258</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a7ab172a9be4fca2489aa5cbcc48c20ff"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a7ab172a9be4fca2489aa5cbcc48c20ff">oboe::AudioStreamBuilder::openManagedStream</a></div><div class="ttdeci">Result openManagedStream(ManagedStream &amp;stream)</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a30ef3d5f51d56a9f980dc09600ed139d"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a30ef3d5f51d56a9f980dc09600ed139d">oboe::AudioStreamBuilder::setSampleRate</a></div><div class="ttdeci">AudioStreamBuilder * setSampleRate(int32_t sampleRate)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:72</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a998885bb6c4f37e145f4626ad4177dea"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea">oboe::AudioStreamBase::mSampleRate</a></div><div class="ttdeci">int32_t mSampleRate</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:192</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:29</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_ac81d4719b350f8138aad1af38f0873b6"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6">oboe::AudioStreamBase::mBufferCapacityInFrames</a></div><div class="ttdeci">int32_t mBufferCapacityInFrames</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:196</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_abaff480867af51ca0899bfa6fd7cc3ef"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#abaff480867af51ca0899bfa6fd7cc3ef">oboe::AudioStreamBuilder::setBufferCapacityInFrames</a></div><div class="ttdeci">AudioStreamBuilder * setBufferCapacityInFrames(int32_t bufferCapacityInFrames)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:126</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_afb8e95e80df7edd1af27af490438785e"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#afb8e95e80df7edd1af27af490438785e">oboe::AudioStreamBuilder::setFramesPerDataCallback</a></div><div class="ttdeci">AudioStreamBuilder * setFramesPerDataCallback(int framesPerCallback)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:98</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a86b94cfa47729bef2e04dce1a9086074"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a86b94cfa47729bef2e04dce1a9086074">oboe::AudioStreamBuilder::openStream</a></div><div class="ttdeci">Result openStream(AudioStream **stream)</div></div>
-<div class="ttc" id="namespaceoboe_html_a92afc593e856571aacbfd02e57075df6"><div class="ttname"><a href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">oboe::AudioFormat</a></div><div class="ttdeci">AudioFormat</div><div class="ttdef"><b>Definition:</b> Definitions.h:94</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_aacb66f530bfc6f545911b5e169774567"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#aacb66f530bfc6f545911b5e169774567">oboe::AudioStreamBuilder::setErrorCallback</a></div><div class="ttdeci">AudioStreamBuilder * setErrorCallback(oboe::AudioStreamErrorCallback *errorCallback)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:344</div></div>
-<div class="ttc" id="namespaceoboe_html_a486512e787b609c80ba4436f23929af1"><div class="ttname"><a href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a></div><div class="ttdeci">Result</div><div class="ttdef"><b>Definition:</b> Definitions.h:131</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a3e991742acbbfb6fe5ebcf592c478654"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a3e991742acbbfb6fe5ebcf592c478654">oboe::AudioStreamBuilder::setSharingMode</a></div><div class="ttdeci">AudioStreamBuilder * setSharingMode(SharingMode sharingMode)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:188</div></div>
-<div class="ttc" id="namespaceoboe_html"><div class="ttname"><a href="namespaceoboe.html">oboe</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:31</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_aa07ea100fcb107d9f7913f206c2214f4"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#aa07ea100fcb107d9f7913f206c2214f4">oboe::AudioStreamBuilder::willUseAAudio</a></div><div class="ttdeci">bool willUseAAudio() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:424</div></div>
-<div class="ttc" id="namespaceoboe_html_a82f3720eba7654aceb7282be36f9ff1d"><div class="ttname"><a href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">oboe::SampleRateConversionQuality</a></div><div class="ttdeci">SampleRateConversionQuality</div><div class="ttdef"><b>Definition:</b> Definitions.h:235</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a1e5d4f5b30c4cc36f81ffd858cc00589"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589">oboe::AudioStreamBase::mInputPreset</a></div><div class="ttdeci">InputPreset mInputPreset</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:221</div></div>
-<div class="ttc" id="namespaceoboe_html_af2147500089212955498a08ef2edb5ae"><div class="ttname"><a href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">oboe::Direction</a></div><div class="ttdeci">Direction</div><div class="ttdef"><b>Definition:</b> Definitions.h:78</div></div>
-<div class="ttc" id="namespaceoboe_html_a8330247b25429953a08354f41834d520"><div class="ttname"><a href="namespaceoboe.html#a8330247b25429953a08354f41834d520">oboe::SharingMode</a></div><div class="ttdeci">SharingMode</div><div class="ttdef"><b>Definition:</b> Definitions.h:167</div></div>
-<div class="ttc" id="namespaceoboe_html_a4477ed232b02e2694d9309baf55a8f06"><div class="ttname"><a href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">oboe::InputPreset</a></div><div class="ttdeci">InputPreset</div><div class="ttdef"><b>Definition:</b> Definitions.h:372</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a075d10291e1f998d90c2f73ef767b5a7"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a075d10291e1f998d90c2f73ef767b5a7">oboe::AudioStreamBuilder::setChannelCount</a></div><div class="ttdeci">AudioStreamBuilder * setChannelCount(int channelCount)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:46</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a698cefa9af73bc97c020c004821fccbd"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a698cefa9af73bc97c020c004821fccbd">oboe::AudioStreamBuilder::setCallback</a></div><div class="ttdeci">AudioStreamBuilder * setCallback(AudioStreamCallback *streamCallback)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:372</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_acad307720e0f370267b4e2f9a626ae70"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#acad307720e0f370267b4e2f9a626ae70">oboe::AudioStreamBuilder::setDataCallback</a></div><div class="ttdeci">AudioStreamBuilder * setDataCallback(oboe::AudioStreamDataCallback *dataCallback)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:324</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_a3962eb94420ad0ecea70029236001899"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899">oboe::AudioStreamBase::mFramesPerCallback</a></div><div class="ttdeci">int32_t mFramesPerCallback</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:188</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_a7ec5f427cd6fe55cb1ce536ff0cbb4d2"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#a7ec5f427cd6fe55cb1ce536ff0cbb4d2">oboe::AudioStreamBuilder::setFormatConversionAllowed</a></div><div class="ttdeci">AudioStreamBuilder * setFormatConversionAllowed(bool allowed)</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:400</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_builder_html_ac9d41811c297fd28bc61833f640bb8d0"><div class="ttname"><a href="classoboe_1_1_audio_stream_builder.html#ac9d41811c297fd28bc61833f640bb8d0">oboe::AudioStreamBuilder::getAudioApi</a></div><div class="ttdeci">AudioApi getAudioApi() const</div><div class="ttdef"><b>Definition:</b> AudioStreamBuilder.h:141</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_base_html_adc0c8cc54adb6d3350c62b8a74b9c57b"><div class="ttname"><a href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">oboe::AudioStreamBase::mErrorCallback</a></div><div class="ttdeci">AudioStreamErrorCallback * mErrorCallback</div><div class="ttdef"><b>Definition:</b> AudioStreamBase.h:185</div></div>
-</div><!-- fragment --></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/_audio_stream_callback_8h_source.html b/docs/reference/_audio_stream_callback_8h_source.html
deleted file mode 100644
index cb0e798..0000000
--- a/docs/reference/_audio_stream_callback_8h_source.html
+++ /dev/null
@@ -1,93 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: include/oboe/AudioStreamCallback.h Source File</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="dir_d44c64559bbebec7f509842c48db8b23.html">include</a></li><li class="navelem"><a class="el" href="dir_768f6301d9838e45d679001914ab2803.html">oboe</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">AudioStreamCallback.h</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;<span class="comment">/*</span></div><div class="line"><a name="l00002"></a><span class="lineno">    2</span>&#160;<span class="comment"> * Copyright (C) 2016 The Android Open Source Project</span></div><div class="line"><a name="l00003"></a><span class="lineno">    3</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00004"></a><span class="lineno">    4</span>&#160;<span class="comment"> * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></div><div class="line"><a name="l00005"></a><span class="lineno">    5</span>&#160;<span class="comment"> * you may not use this file except in compliance with the License.</span></div><div class="line"><a name="l00006"></a><span class="lineno">    6</span>&#160;<span class="comment"> * You may obtain a copy of the License at</span></div><div class="line"><a name="l00007"></a><span class="lineno">    7</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00008"></a><span class="lineno">    8</span>&#160;<span class="comment"> *      http://www.apache.org/licenses/LICENSE-2.0</span></div><div class="line"><a name="l00009"></a><span class="lineno">    9</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00010"></a><span class="lineno">   10</span>&#160;<span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></div><div class="line"><a name="l00011"></a><span class="lineno">   11</span>&#160;<span class="comment"> * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</span></div><div class="line"><a name="l00012"></a><span class="lineno">   12</span>&#160;<span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></div><div class="line"><a name="l00013"></a><span class="lineno">   13</span>&#160;<span class="comment"> * See the License for the specific language governing permissions and</span></div><div class="line"><a name="l00014"></a><span class="lineno">   14</span>&#160;<span class="comment"> * limitations under the License.</span></div><div class="line"><a name="l00015"></a><span class="lineno">   15</span>&#160;<span class="comment"> */</span></div><div class="line"><a name="l00016"></a><span class="lineno">   16</span>&#160;</div><div class="line"><a name="l00017"></a><span class="lineno">   17</span>&#160;<span class="preprocessor">#ifndef OBOE_STREAM_CALLBACK_H</span></div><div class="line"><a name="l00018"></a><span class="lineno">   18</span>&#160;<span class="preprocessor">#define OBOE_STREAM_CALLBACK_H</span></div><div class="line"><a name="l00019"></a><span class="lineno">   19</span>&#160;</div><div class="line"><a name="l00020"></a><span class="lineno">   20</span>&#160;<span class="preprocessor">#include &quot;oboe/Definitions.h&quot;</span></div><div class="line"><a name="l00021"></a><span class="lineno">   21</span>&#160;</div><div class="line"><a name="l00022"></a><span class="lineno">   22</span>&#160;<span class="keyword">namespace </span><a class="code" href="namespaceoboe.html">oboe</a> {</div><div class="line"><a name="l00023"></a><span class="lineno">   23</span>&#160;</div><div class="line"><a name="l00024"></a><span class="lineno">   24</span>&#160;<span class="keyword">class </span>AudioStream;</div><div class="line"><a name="l00025"></a><span class="lineno">   25</span>&#160;</div><div class="line"><a name="l00034"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_data_callback.html">   34</a></span>&#160;<span class="keyword">class </span><a class="code" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> {</div><div class="line"><a name="l00035"></a><span class="lineno">   35</span>&#160;<span class="keyword">public</span>:</div><div class="line"><a name="l00036"></a><span class="lineno">   36</span>&#160;    <span class="keyword">virtual</span> ~<a class="code" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a>() = <span class="keywordflow">default</span>;</div><div class="line"><a name="l00037"></a><span class="lineno">   37</span>&#160;</div><div class="line"><a name="l00084"></a><span class="lineno">   84</span>&#160;    <span class="keyword">virtual</span> <a class="code" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a> <a class="code" href="classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d">onAudioReady</a>(</div><div class="line"><a name="l00085"></a><span class="lineno">   85</span>&#160;            <a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a> *audioStream,</div><div class="line"><a name="l00086"></a><span class="lineno">   86</span>&#160;            <span class="keywordtype">void</span> *audioData,</div><div class="line"><a name="l00087"></a><span class="lineno">   87</span>&#160;            int32_t numFrames) = 0;</div><div class="line"><a name="l00088"></a><span class="lineno">   88</span>&#160;};</div><div class="line"><a name="l00089"></a><span class="lineno">   89</span>&#160;</div><div class="line"><a name="l00097"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_error_callback.html">   97</a></span>&#160;<span class="keyword">class </span><a class="code" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a> {</div><div class="line"><a name="l00098"></a><span class="lineno">   98</span>&#160;<span class="keyword">public</span>:</div><div class="line"><a name="l00099"></a><span class="lineno">   99</span>&#160;    <span class="keyword">virtual</span> ~<a class="code" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a>() = <span class="keywordflow">default</span>;</div><div class="line"><a name="l00100"></a><span class="lineno">  100</span>&#160;</div><div class="line"><a name="l00127"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">  127</a></span>&#160;    <span class="keyword">virtual</span> <span class="keywordtype">bool</span> <a class="code" href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">onError</a>(<a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a>* <span class="comment">/* audioStream */</span>, <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <span class="comment">/* error */</span>) {</div><div class="line"><a name="l00128"></a><span class="lineno">  128</span>&#160;        <span class="keywordflow">return</span> <span class="keyword">false</span>;</div><div class="line"><a name="l00129"></a><span class="lineno">  129</span>&#160;    }</div><div class="line"><a name="l00130"></a><span class="lineno">  130</span>&#160;</div><div class="line"><a name="l00147"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0">  147</a></span>&#160;    <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a class="code" href="classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0">onErrorBeforeClose</a>(<a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a>* <span class="comment">/* audioStream */</span>, <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <span class="comment">/* error */</span>) {}</div><div class="line"><a name="l00148"></a><span class="lineno">  148</span>&#160;</div><div class="line"><a name="l00163"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe">  163</a></span>&#160;    <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a class="code" href="classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe">onErrorAfterClose</a>(<a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a>* <span class="comment">/* audioStream */</span>, <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <span class="comment">/* error */</span>) {}</div><div class="line"><a name="l00164"></a><span class="lineno">  164</span>&#160;</div><div class="line"><a name="l00165"></a><span class="lineno">  165</span>&#160;};</div><div class="line"><a name="l00166"></a><span class="lineno">  166</span>&#160;</div><div class="line"><a name="l00181"></a><span class="lineno"><a class="line" href="classoboe_1_1_audio_stream_callback.html">  181</a></span>&#160;<span class="keyword">class </span><a class="code" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a> : <span class="keyword">public</span> <a class="code" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a>,</div><div class="line"><a name="l00182"></a><span class="lineno">  182</span>&#160;                            <span class="keyword">public</span> <a class="code" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a> {</div><div class="line"><a name="l00183"></a><span class="lineno">  183</span>&#160;<span class="keyword">public</span>:</div><div class="line"><a name="l00184"></a><span class="lineno">  184</span>&#160;    <span class="keyword">virtual</span> ~<a class="code" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a>() = <span class="keywordflow">default</span>;</div><div class="line"><a name="l00185"></a><span class="lineno">  185</span>&#160;};</div><div class="line"><a name="l00186"></a><span class="lineno">  186</span>&#160;</div><div class="line"><a name="l00187"></a><span class="lineno">  187</span>&#160;} <span class="comment">// namespace oboe</span></div><div class="line"><a name="l00188"></a><span class="lineno">  188</span>&#160;</div><div class="line"><a name="l00189"></a><span class="lineno">  189</span>&#160;<span class="preprocessor">#endif //OBOE_STREAM_CALLBACK_H</span></div><div class="ttc" id="classoboe_1_1_audio_stream_error_callback_html_a5ad4b8936746ecbb2160a9389b117fc3"><div class="ttname"><a href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">oboe::AudioStreamErrorCallback::onError</a></div><div class="ttdeci">virtual bool onError(AudioStream *, Result)</div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:127</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_data_callback_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a></div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:34</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_callback_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_callback.html">oboe::AudioStreamCallback</a></div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:181</div></div>
-<div class="ttc" id="namespaceoboe_html_af85fc9910a287df6c5df0ed396bb75cd"><div class="ttname"><a href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">oboe::DataCallbackResult</a></div><div class="ttdeci">DataCallbackResult</div><div class="ttdef"><b>Definition:</b> Definitions.h:119</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_error_callback_html_a76bd3ef3e00396e10c21812003654cfe"><div class="ttname"><a href="classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe">oboe::AudioStreamErrorCallback::onErrorAfterClose</a></div><div class="ttdeci">virtual void onErrorAfterClose(AudioStream *, Result)</div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:163</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html"><div class="ttname"><a href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:44</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_error_callback_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:97</div></div>
-<div class="ttc" id="namespaceoboe_html_a486512e787b609c80ba4436f23929af1"><div class="ttname"><a href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a></div><div class="ttdeci">Result</div><div class="ttdef"><b>Definition:</b> Definitions.h:131</div></div>
-<div class="ttc" id="namespaceoboe_html"><div class="ttname"><a href="namespaceoboe.html">oboe</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:31</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_error_callback_html_a4eb1e4916b71d8231e97b19898bc9bf0"><div class="ttname"><a href="classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0">oboe::AudioStreamErrorCallback::onErrorBeforeClose</a></div><div class="ttdeci">virtual void onErrorBeforeClose(AudioStream *, Result)</div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:147</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_data_callback_html_ad8a3a9f609df5fd3a5d885cbe1b2204d"><div class="ttname"><a href="classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d">oboe::AudioStreamDataCallback::onAudioReady</a></div><div class="ttdeci">virtual DataCallbackResult onAudioReady(AudioStream *audioStream, void *audioData, int32_t numFrames)=0</div></div>
-</div><!-- fragment --></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/_definitions_8h_source.html b/docs/reference/_definitions_8h_source.html
deleted file mode 100644
index d24bd53..0000000
--- a/docs/reference/_definitions_8h_source.html
+++ /dev/null
@@ -1,148 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: include/oboe/Definitions.h Source File</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="dir_d44c64559bbebec7f509842c48db8b23.html">include</a></li><li class="navelem"><a class="el" href="dir_768f6301d9838e45d679001914ab2803.html">oboe</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">Definitions.h</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;<span class="comment">/*</span></div><div class="line"><a name="l00002"></a><span class="lineno">    2</span>&#160;<span class="comment"> * Copyright (C) 2016 The Android Open Source Project</span></div><div class="line"><a name="l00003"></a><span class="lineno">    3</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00004"></a><span class="lineno">    4</span>&#160;<span class="comment"> * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></div><div class="line"><a name="l00005"></a><span class="lineno">    5</span>&#160;<span class="comment"> * you may not use this file except in compliance with the License.</span></div><div class="line"><a name="l00006"></a><span class="lineno">    6</span>&#160;<span class="comment"> * You may obtain a copy of the License at</span></div><div class="line"><a name="l00007"></a><span class="lineno">    7</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00008"></a><span class="lineno">    8</span>&#160;<span class="comment"> *      http://www.apache.org/licenses/LICENSE-2.0</span></div><div class="line"><a name="l00009"></a><span class="lineno">    9</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00010"></a><span class="lineno">   10</span>&#160;<span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></div><div class="line"><a name="l00011"></a><span class="lineno">   11</span>&#160;<span class="comment"> * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</span></div><div class="line"><a name="l00012"></a><span class="lineno">   12</span>&#160;<span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></div><div class="line"><a name="l00013"></a><span class="lineno">   13</span>&#160;<span class="comment"> * See the License for the specific language governing permissions and</span></div><div class="line"><a name="l00014"></a><span class="lineno">   14</span>&#160;<span class="comment"> * limitations under the License.</span></div><div class="line"><a name="l00015"></a><span class="lineno">   15</span>&#160;<span class="comment"> */</span></div><div class="line"><a name="l00016"></a><span class="lineno">   16</span>&#160;</div><div class="line"><a name="l00017"></a><span class="lineno">   17</span>&#160;<span class="preprocessor">#ifndef OBOE_DEFINITIONS_H</span></div><div class="line"><a name="l00018"></a><span class="lineno">   18</span>&#160;<span class="preprocessor">#define OBOE_DEFINITIONS_H</span></div><div class="line"><a name="l00019"></a><span class="lineno">   19</span>&#160;</div><div class="line"><a name="l00020"></a><span class="lineno">   20</span>&#160;</div><div class="line"><a name="l00021"></a><span class="lineno">   21</span>&#160;<span class="preprocessor">#include &lt;cstdint&gt;</span></div><div class="line"><a name="l00022"></a><span class="lineno">   22</span>&#160;<span class="preprocessor">#include &lt;type_traits&gt;</span></div><div class="line"><a name="l00023"></a><span class="lineno">   23</span>&#160;</div><div class="line"><a name="l00024"></a><span class="lineno">   24</span>&#160;<span class="comment">// Oboe needs to be able to build on old NDKs so we use hard coded constants.</span></div><div class="line"><a name="l00025"></a><span class="lineno">   25</span>&#160;<span class="comment">// The correctness of these constants is verified in &quot;aaudio/AAudioLoader.cpp&quot;.</span></div><div class="line"><a name="l00026"></a><span class="lineno">   26</span>&#160;</div><div class="line"><a name="l00027"></a><span class="lineno">   27</span>&#160;<span class="keyword">namespace </span><a class="code" href="namespaceoboe.html">oboe</a> {</div><div class="line"><a name="l00028"></a><span class="lineno">   28</span>&#160;</div><div class="line"><a name="l00032"></a><span class="lineno"><a class="line" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">   32</a></span>&#160;    constexpr int32_t <a class="code" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a> = 0;</div><div class="line"><a name="l00033"></a><span class="lineno">   33</span>&#160;</div><div class="line"><a name="l00034"></a><span class="lineno">   34</span>&#160;    <span class="comment">// TODO: Investigate using std::chrono</span></div><div class="line"><a name="l00038"></a><span class="lineno"><a class="line" href="namespaceoboe.html#aedef0759ae3622b6f0324799bcbdebf0">   38</a></span>&#160;<span class="comment"></span>    constexpr int64_t <a class="code" href="namespaceoboe.html#aedef0759ae3622b6f0324799bcbdebf0">kNanosPerMicrosecond</a> =    1000;</div><div class="line"><a name="l00039"></a><span class="lineno">   39</span>&#160;</div><div class="line"><a name="l00043"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a831e887150474c087170679eaca8672b">   43</a></span>&#160;    constexpr int64_t <a class="code" href="namespaceoboe.html#a831e887150474c087170679eaca8672b">kNanosPerMillisecond</a> =    <a class="code" href="namespaceoboe.html#aedef0759ae3622b6f0324799bcbdebf0">kNanosPerMicrosecond</a> * 1000;</div><div class="line"><a name="l00044"></a><span class="lineno">   44</span>&#160;</div><div class="line"><a name="l00048"></a><span class="lineno"><a class="line" href="namespaceoboe.html#ad1bb9f5626cec20d3a052a8721959873">   48</a></span>&#160;    constexpr int64_t <a class="code" href="namespaceoboe.html#ad1bb9f5626cec20d3a052a8721959873">kMillisPerSecond</a> =        1000;</div><div class="line"><a name="l00049"></a><span class="lineno">   49</span>&#160;</div><div class="line"><a name="l00053"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a5948466b593c4eab65f7025846a39f51">   53</a></span>&#160;    constexpr int64_t <a class="code" href="namespaceoboe.html#a5948466b593c4eab65f7025846a39f51">kNanosPerSecond</a> =         <a class="code" href="namespaceoboe.html#a831e887150474c087170679eaca8672b">kNanosPerMillisecond</a> * <a class="code" href="namespaceoboe.html#ad1bb9f5626cec20d3a052a8721959873">kMillisPerSecond</a>;</div><div class="line"><a name="l00054"></a><span class="lineno">   54</span>&#160;</div><div class="line"><a name="l00058"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">   58</a></span>&#160;    <span class="keyword">enum class</span> <a class="code" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a> : int32_t { <span class="comment">// aaudio_stream_state_t</span></div><div class="line"><a name="l00059"></a><span class="lineno">   59</span>&#160;        Uninitialized = 0, <span class="comment">// AAUDIO_STREAM_STATE_UNINITIALIZED,</span></div><div class="line"><a name="l00060"></a><span class="lineno">   60</span>&#160;        Unknown = 1, <span class="comment">// AAUDIO_STREAM_STATE_UNKNOWN,</span></div><div class="line"><a name="l00061"></a><span class="lineno">   61</span>&#160;        Open = 2, <span class="comment">// AAUDIO_STREAM_STATE_OPEN,</span></div><div class="line"><a name="l00062"></a><span class="lineno">   62</span>&#160;        Starting = 3, <span class="comment">// AAUDIO_STREAM_STATE_STARTING,</span></div><div class="line"><a name="l00063"></a><span class="lineno">   63</span>&#160;        Started = 4, <span class="comment">// AAUDIO_STREAM_STATE_STARTED,</span></div><div class="line"><a name="l00064"></a><span class="lineno">   64</span>&#160;        Pausing = 5, <span class="comment">// AAUDIO_STREAM_STATE_PAUSING,</span></div><div class="line"><a name="l00065"></a><span class="lineno">   65</span>&#160;        Paused = 6, <span class="comment">// AAUDIO_STREAM_STATE_PAUSED,</span></div><div class="line"><a name="l00066"></a><span class="lineno">   66</span>&#160;        Flushing = 7, <span class="comment">// AAUDIO_STREAM_STATE_FLUSHING,</span></div><div class="line"><a name="l00067"></a><span class="lineno">   67</span>&#160;        Flushed = 8, <span class="comment">// AAUDIO_STREAM_STATE_FLUSHED,</span></div><div class="line"><a name="l00068"></a><span class="lineno">   68</span>&#160;        Stopping = 9, <span class="comment">// AAUDIO_STREAM_STATE_STOPPING,</span></div><div class="line"><a name="l00069"></a><span class="lineno">   69</span>&#160;        Stopped = 10, <span class="comment">// AAUDIO_STREAM_STATE_STOPPED,</span></div><div class="line"><a name="l00070"></a><span class="lineno">   70</span>&#160;        Closing = 11, <span class="comment">// AAUDIO_STREAM_STATE_CLOSING,</span></div><div class="line"><a name="l00071"></a><span class="lineno">   71</span>&#160;        Closed = 12, <span class="comment">// AAUDIO_STREAM_STATE_CLOSED,</span></div><div class="line"><a name="l00072"></a><span class="lineno">   72</span>&#160;        Disconnected = 13, <span class="comment">// AAUDIO_STREAM_STATE_DISCONNECTED,</span></div><div class="line"><a name="l00073"></a><span class="lineno">   73</span>&#160;    };</div><div class="line"><a name="l00074"></a><span class="lineno">   74</span>&#160;</div><div class="line"><a name="l00078"></a><span class="lineno"><a class="line" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">   78</a></span>&#160;    <span class="keyword">enum class</span> <a class="code" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a> : int32_t { <span class="comment">// aaudio_direction_t</span></div><div class="line"><a name="l00079"></a><span class="lineno">   79</span>&#160;</div><div class="line"><a name="l00083"></a><span class="lineno">   83</span>&#160;        <a class="code" href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54">Output</a> = 0, <span class="comment">// AAUDIO_DIRECTION_OUTPUT,</span></div><div class="line"><a name="l00084"></a><span class="lineno">   84</span>&#160;</div><div class="line"><a name="l00088"></a><span class="lineno">   88</span>&#160;        <a class="code" href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea324118a6721dd6b8a9b9f4e327df2bf5">Input</a> = 1, <span class="comment">// AAUDIO_DIRECTION_INPUT,</span></div><div class="line"><a name="l00089"></a><span class="lineno">   89</span>&#160;    };</div><div class="line"><a name="l00090"></a><span class="lineno">   90</span>&#160;</div><div class="line"><a name="l00094"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">   94</a></span>&#160;    <span class="keyword">enum class</span> <a class="code" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a> : int32_t { <span class="comment">// aaudio_format_t</span></div><div class="line"><a name="l00098"></a><span class="lineno">   98</span>&#160;<span class="comment"></span>        <a class="code" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6a4bbb8f967da6d1a610596d7257179c2b">Invalid</a> = -1, <span class="comment">// AAUDIO_FORMAT_INVALID,</span></div><div class="line"><a name="l00099"></a><span class="lineno">   99</span>&#160;</div><div class="line"><a name="l00103"></a><span class="lineno">  103</span>&#160;        <a class="code" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a946257a568f77c12df4fc4c49125da76">Unspecified</a> = 0, <span class="comment">// AAUDIO_FORMAT_UNSPECIFIED,</span></div><div class="line"><a name="l00104"></a><span class="lineno">  104</span>&#160;</div><div class="line"><a name="l00108"></a><span class="lineno">  108</span>&#160;        <a class="code" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6abcd774f891b5f9df7099f3ea75dadf8d">I16</a> = 1, <span class="comment">// AAUDIO_FORMAT_PCM_I16,</span></div><div class="line"><a name="l00109"></a><span class="lineno">  109</span>&#160;</div><div class="line"><a name="l00113"></a><span class="lineno">  113</span>&#160;        <a class="code" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6a22ae0e2b89e5e3d477f988cc36d3272b">Float</a> = 2, <span class="comment">// AAUDIO_FORMAT_PCM_FLOAT,</span></div><div class="line"><a name="l00114"></a><span class="lineno">  114</span>&#160;    };</div><div class="line"><a name="l00115"></a><span class="lineno">  115</span>&#160;</div><div class="line"><a name="l00119"></a><span class="lineno"><a class="line" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">  119</a></span>&#160;    <span class="keyword">enum class</span> <a class="code" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a> : int32_t { <span class="comment">// aaudio_data_callback_result_t</span></div><div class="line"><a name="l00120"></a><span class="lineno">  120</span>&#160;        <span class="comment">// Indicates to the caller that the callbacks should continue.</span></div><div class="line"><a name="l00121"></a><span class="lineno">  121</span>&#160;        Continue = 0, <span class="comment">// AAUDIO_CALLBACK_RESULT_CONTINUE,</span></div><div class="line"><a name="l00122"></a><span class="lineno">  122</span>&#160;</div><div class="line"><a name="l00123"></a><span class="lineno">  123</span>&#160;        <span class="comment">// Indicates to the caller that the callbacks should stop immediately.</span></div><div class="line"><a name="l00124"></a><span class="lineno">  124</span>&#160;        Stop = 1, <span class="comment">// AAUDIO_CALLBACK_RESULT_STOP,</span></div><div class="line"><a name="l00125"></a><span class="lineno">  125</span>&#160;    };</div><div class="line"><a name="l00126"></a><span class="lineno">  126</span>&#160;</div><div class="line"><a name="l00131"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">  131</a></span>&#160;    <span class="keyword">enum class</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> : int32_t { <span class="comment">// aaudio_result_t</span></div><div class="line"><a name="l00132"></a><span class="lineno">  132</span>&#160;        OK = 0, <span class="comment">// AAUDIO_OK</span></div><div class="line"><a name="l00133"></a><span class="lineno">  133</span>&#160;        ErrorBase = -900, <span class="comment">// AAUDIO_ERROR_BASE,</span></div><div class="line"><a name="l00134"></a><span class="lineno">  134</span>&#160;        ErrorDisconnected = -899, <span class="comment">// AAUDIO_ERROR_DISCONNECTED,</span></div><div class="line"><a name="l00135"></a><span class="lineno">  135</span>&#160;        ErrorIllegalArgument = -898, <span class="comment">// AAUDIO_ERROR_ILLEGAL_ARGUMENT,</span></div><div class="line"><a name="l00136"></a><span class="lineno">  136</span>&#160;        ErrorInternal = -896, <span class="comment">// AAUDIO_ERROR_INTERNAL,</span></div><div class="line"><a name="l00137"></a><span class="lineno">  137</span>&#160;        ErrorInvalidState = -895, <span class="comment">// AAUDIO_ERROR_INVALID_STATE,</span></div><div class="line"><a name="l00138"></a><span class="lineno">  138</span>&#160;        ErrorInvalidHandle = -892, <span class="comment">// AAUDIO_ERROR_INVALID_HANDLE,</span></div><div class="line"><a name="l00139"></a><span class="lineno">  139</span>&#160;        ErrorUnimplemented = -890, <span class="comment">// AAUDIO_ERROR_UNIMPLEMENTED,</span></div><div class="line"><a name="l00140"></a><span class="lineno">  140</span>&#160;        ErrorUnavailable = -889, <span class="comment">// AAUDIO_ERROR_UNAVAILABLE,</span></div><div class="line"><a name="l00141"></a><span class="lineno">  141</span>&#160;        ErrorNoFreeHandles = -888, <span class="comment">// AAUDIO_ERROR_NO_FREE_HANDLES,</span></div><div class="line"><a name="l00142"></a><span class="lineno">  142</span>&#160;        ErrorNoMemory = -887, <span class="comment">// AAUDIO_ERROR_NO_MEMORY,</span></div><div class="line"><a name="l00143"></a><span class="lineno">  143</span>&#160;        ErrorNull = -886, <span class="comment">// AAUDIO_ERROR_NULL,</span></div><div class="line"><a name="l00144"></a><span class="lineno">  144</span>&#160;        ErrorTimeout = -885, <span class="comment">// AAUDIO_ERROR_TIMEOUT,</span></div><div class="line"><a name="l00145"></a><span class="lineno">  145</span>&#160;        ErrorWouldBlock = -884, <span class="comment">// AAUDIO_ERROR_WOULD_BLOCK,</span></div><div class="line"><a name="l00146"></a><span class="lineno">  146</span>&#160;        ErrorInvalidFormat = -883, <span class="comment">// AAUDIO_ERROR_INVALID_FORMAT,</span></div><div class="line"><a name="l00147"></a><span class="lineno">  147</span>&#160;        ErrorOutOfRange = -882, <span class="comment">// AAUDIO_ERROR_OUT_OF_RANGE,</span></div><div class="line"><a name="l00148"></a><span class="lineno">  148</span>&#160;        ErrorNoService = -881, <span class="comment">// AAUDIO_ERROR_NO_SERVICE,</span></div><div class="line"><a name="l00149"></a><span class="lineno">  149</span>&#160;        ErrorInvalidRate = -880, <span class="comment">// AAUDIO_ERROR_INVALID_RATE,</span></div><div class="line"><a name="l00150"></a><span class="lineno">  150</span>&#160;        <span class="comment">// Reserved for future AAudio result types</span></div><div class="line"><a name="l00151"></a><span class="lineno">  151</span>&#160;        Reserved1,</div><div class="line"><a name="l00152"></a><span class="lineno">  152</span>&#160;        Reserved2,</div><div class="line"><a name="l00153"></a><span class="lineno">  153</span>&#160;        Reserved3,</div><div class="line"><a name="l00154"></a><span class="lineno">  154</span>&#160;        Reserved4,</div><div class="line"><a name="l00155"></a><span class="lineno">  155</span>&#160;        Reserved5,</div><div class="line"><a name="l00156"></a><span class="lineno">  156</span>&#160;        Reserved6,</div><div class="line"><a name="l00157"></a><span class="lineno">  157</span>&#160;        Reserved7,</div><div class="line"><a name="l00158"></a><span class="lineno">  158</span>&#160;        Reserved8,</div><div class="line"><a name="l00159"></a><span class="lineno">  159</span>&#160;        Reserved9,</div><div class="line"><a name="l00160"></a><span class="lineno">  160</span>&#160;        Reserved10,</div><div class="line"><a name="l00161"></a><span class="lineno">  161</span>&#160;        ErrorClosed,</div><div class="line"><a name="l00162"></a><span class="lineno">  162</span>&#160;    };</div><div class="line"><a name="l00163"></a><span class="lineno">  163</span>&#160;</div><div class="line"><a name="l00167"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">  167</a></span>&#160;    <span class="keyword">enum class</span> <a class="code" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a> : int32_t { <span class="comment">// aaudio_sharing_mode_t</span></div><div class="line"><a name="l00168"></a><span class="lineno">  168</span>&#160;</div><div class="line"><a name="l00177"></a><span class="lineno">  177</span>&#160;        <a class="code" href="namespaceoboe.html#a8330247b25429953a08354f41834d520a2ef50b4c466304dc6ac77bac8a779971">Exclusive</a> = 0, <span class="comment">// AAUDIO_SHARING_MODE_EXCLUSIVE,</span></div><div class="line"><a name="l00178"></a><span class="lineno">  178</span>&#160;</div><div class="line"><a name="l00186"></a><span class="lineno">  186</span>&#160;        <a class="code" href="namespaceoboe.html#a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca">Shared</a> = 1, <span class="comment">// AAUDIO_SHARING_MODE_SHARED,</span></div><div class="line"><a name="l00187"></a><span class="lineno">  187</span>&#160;    };</div><div class="line"><a name="l00188"></a><span class="lineno">  188</span>&#160;</div><div class="line"><a name="l00192"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">  192</a></span>&#160;    <span class="keyword">enum class</span> <a class="code" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a> : int32_t { <span class="comment">// aaudio_performance_mode_t</span></div><div class="line"><a name="l00193"></a><span class="lineno">  193</span>&#160;</div><div class="line"><a name="l00197"></a><span class="lineno">  197</span>&#160;        <a class="code" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa58c518b26e83ea48393a76f6c9ecb51f">None</a> = 10, <span class="comment">// AAUDIO_PERFORMANCE_MODE_NONE,</span></div><div class="line"><a name="l00198"></a><span class="lineno">  198</span>&#160;</div><div class="line"><a name="l00202"></a><span class="lineno">  202</span>&#160;        <a class="code" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184abbad080463ed11f9d77797c04aa1e5b1">PowerSaving</a> = 11, <span class="comment">// AAUDIO_PERFORMANCE_MODE_POWER_SAVING,</span></div><div class="line"><a name="l00203"></a><span class="lineno">  203</span>&#160;</div><div class="line"><a name="l00207"></a><span class="lineno">  207</span>&#160;        <a class="code" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184a611907b5ab1865515c35357efa41a9b9">LowLatency</a> = 12, <span class="comment">// AAUDIO_PERFORMANCE_MODE_LOW_LATENCY</span></div><div class="line"><a name="l00208"></a><span class="lineno">  208</span>&#160;    };</div><div class="line"><a name="l00209"></a><span class="lineno">  209</span>&#160;</div><div class="line"><a name="l00213"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">  213</a></span>&#160;    <span class="keyword">enum class</span> <a class="code" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">AudioApi</a> : int32_t {</div><div class="line"><a name="l00217"></a><span class="lineno">  217</span>&#160;        <a class="code" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a946257a568f77c12df4fc4c49125da76">Unspecified</a> = <a class="code" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a>,</div><div class="line"><a name="l00218"></a><span class="lineno">  218</span>&#160;</div><div class="line"><a name="l00222"></a><span class="lineno">  222</span>&#160;        <a class="code" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a24e758ea9c1e842ef71cc8ff8b63fa9b">OpenSLES</a>,</div><div class="line"><a name="l00223"></a><span class="lineno">  223</span>&#160;</div><div class="line"><a name="l00227"></a><span class="lineno">  227</span>&#160;        <a class="code" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a99780b1e8d754eb42abed0ca5253e55b">AAudio</a></div><div class="line"><a name="l00228"></a><span class="lineno">  228</span>&#160;    };</div><div class="line"><a name="l00229"></a><span class="lineno">  229</span>&#160;</div><div class="line"><a name="l00235"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">  235</a></span>&#160;    <span class="keyword">enum class</span> <a class="code" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">SampleRateConversionQuality</a> : int32_t {</div><div class="line"><a name="l00239"></a><span class="lineno">  239</span>&#160;        <a class="code" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa58c518b26e83ea48393a76f6c9ecb51f">None</a>,</div><div class="line"><a name="l00244"></a><span class="lineno">  244</span>&#160;        <a class="code" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1da90fd7fdf6f41406a75e5265b9583bb4e">Fastest</a>,</div><div class="line"><a name="l00245"></a><span class="lineno">  245</span>&#160;        Low,</div><div class="line"><a name="l00246"></a><span class="lineno">  246</span>&#160;        Medium,</div><div class="line"><a name="l00247"></a><span class="lineno">  247</span>&#160;        High,</div><div class="line"><a name="l00251"></a><span class="lineno">  251</span>&#160;        <a class="code" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1da68ef004de6166492c1d668eb8efe09bd">Best</a>,</div><div class="line"><a name="l00252"></a><span class="lineno">  252</span>&#160;    };</div><div class="line"><a name="l00253"></a><span class="lineno">  253</span>&#160;</div><div class="line"><a name="l00263"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">  263</a></span>&#160;    <span class="keyword">enum class</span> <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a> : int32_t { <span class="comment">// aaudio_usage_t</span></div><div class="line"><a name="l00267"></a><span class="lineno">  267</span>&#160;<span class="comment"></span>        <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74">Media</a> =  1, <span class="comment">// AAUDIO_USAGE_MEDIA</span></div><div class="line"><a name="l00268"></a><span class="lineno">  268</span>&#160;</div><div class="line"><a name="l00272"></a><span class="lineno">  272</span>&#160;        <a class="code" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a1862e72c9730c448fbec6f61a5d8234d">VoiceCommunication</a> = 2, <span class="comment">// AAUDIO_USAGE_VOICE_COMMUNICATION</span></div><div class="line"><a name="l00273"></a><span class="lineno">  273</span>&#160;</div><div class="line"><a name="l00277"></a><span class="lineno">  277</span>&#160;        <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a404f62633744bf4da0c6a27a2b78ce74">VoiceCommunicationSignalling</a> = 3, <span class="comment">// AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING</span></div><div class="line"><a name="l00278"></a><span class="lineno">  278</span>&#160;</div><div class="line"><a name="l00282"></a><span class="lineno">  282</span>&#160;        <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a46c4c4d980dfe025ae5b35aa0011dde4">Alarm</a> = 4, <span class="comment">// AAUDIO_USAGE_ALARM</span></div><div class="line"><a name="l00283"></a><span class="lineno">  283</span>&#160;</div><div class="line"><a name="l00288"></a><span class="lineno">  288</span>&#160;        <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a96d008db67fc0b5551a926842bbb6a71">Notification</a> = 5, <span class="comment">// AAUDIO_USAGE_NOTIFICATION</span></div><div class="line"><a name="l00289"></a><span class="lineno">  289</span>&#160;</div><div class="line"><a name="l00293"></a><span class="lineno">  293</span>&#160;        <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a4e7a4b08274d472394b740a20d3bbdaf">NotificationRingtone</a> = 6, <span class="comment">// AAUDIO_USAGE_NOTIFICATION_RINGTONE</span></div><div class="line"><a name="l00294"></a><span class="lineno">  294</span>&#160;</div><div class="line"><a name="l00298"></a><span class="lineno">  298</span>&#160;        <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a089240b5380dbd12f1eac0ec258a3b2f">NotificationEvent</a> = 10, <span class="comment">// AAUDIO_USAGE_NOTIFICATION_EVENT</span></div><div class="line"><a name="l00299"></a><span class="lineno">  299</span>&#160;</div><div class="line"><a name="l00303"></a><span class="lineno">  303</span>&#160;        <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a639ffd54516c1a84a288a363c9469df8">AssistanceAccessibility</a> = 11, <span class="comment">// AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY</span></div><div class="line"><a name="l00304"></a><span class="lineno">  304</span>&#160;</div><div class="line"><a name="l00308"></a><span class="lineno">  308</span>&#160;        <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0ade058a1314f9a8504593259ff4f21a1e">AssistanceNavigationGuidance</a> = 12, <span class="comment">// AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE</span></div><div class="line"><a name="l00309"></a><span class="lineno">  309</span>&#160;</div><div class="line"><a name="l00313"></a><span class="lineno">  313</span>&#160;        <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a1ce57a0572748beebfc0c664ca1077e7">AssistanceSonification</a> = 13, <span class="comment">// AAUDIO_USAGE_ASSISTANCE_SONIFICATION</span></div><div class="line"><a name="l00314"></a><span class="lineno">  314</span>&#160;</div><div class="line"><a name="l00318"></a><span class="lineno">  318</span>&#160;        <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a63d72051e901c069f8aa1b32aa0c43bb">Game</a> = 14, <span class="comment">// AAUDIO_USAGE_GAME</span></div><div class="line"><a name="l00319"></a><span class="lineno">  319</span>&#160;</div><div class="line"><a name="l00323"></a><span class="lineno">  323</span>&#160;        <a class="code" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a9b1363da9503dbd4142c0274a88e8d4b">Assistant</a> = 16, <span class="comment">// AAUDIO_USAGE_ASSISTANT</span></div><div class="line"><a name="l00324"></a><span class="lineno">  324</span>&#160;    };</div><div class="line"><a name="l00325"></a><span class="lineno">  325</span>&#160;</div><div class="line"><a name="l00326"></a><span class="lineno">  326</span>&#160;</div><div class="line"><a name="l00339"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">  339</a></span>&#160;    <span class="keyword">enum</span> <a class="code" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a> : int32_t { <span class="comment">// aaudio_content_type_t</span></div><div class="line"><a name="l00340"></a><span class="lineno">  340</span>&#160;</div><div class="line"><a name="l00344"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba3dc48a4b4619aa4edd1da7b937b4dcd1">  344</a></span>&#160;        <a class="code" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba3dc48a4b4619aa4edd1da7b937b4dcd1">Speech</a> = 1, <span class="comment">// AAUDIO_CONTENT_TYPE_SPEECH</span></div><div class="line"><a name="l00345"></a><span class="lineno">  345</span>&#160;</div><div class="line"><a name="l00349"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604bac156fcc7b29059305cef26f3904d4517">  349</a></span>&#160;        <a class="code" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604bac156fcc7b29059305cef26f3904d4517">Music</a> = 2, <span class="comment">// AAUDIO_CONTENT_TYPE_MUSIC</span></div><div class="line"><a name="l00350"></a><span class="lineno">  350</span>&#160;</div><div class="line"><a name="l00354"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba8b3b366178c2b7b1688bca6cd33758b1">  354</a></span>&#160;        <a class="code" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba8b3b366178c2b7b1688bca6cd33758b1">Movie</a> = 3, <span class="comment">// AAUDIO_CONTENT_TYPE_MOVIE</span></div><div class="line"><a name="l00355"></a><span class="lineno">  355</span>&#160;</div><div class="line"><a name="l00360"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba0885eef555037e94a7cf39fe683c2799">  360</a></span>&#160;        <a class="code" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba0885eef555037e94a7cf39fe683c2799">Sonification</a> = 4, <span class="comment">// AAUDIO_CONTENT_TYPE_SONIFICATION</span></div><div class="line"><a name="l00361"></a><span class="lineno">  361</span>&#160;    };</div><div class="line"><a name="l00362"></a><span class="lineno">  362</span>&#160;</div><div class="line"><a name="l00372"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">  372</a></span>&#160;    <span class="keyword">enum</span> <a class="code" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a> : int32_t { <span class="comment">// aaudio_input_preset_t</span></div><div class="line"><a name="l00376"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a0ba6f369e7f8a700c14afe2992290544">  376</a></span>&#160;<span class="comment"></span>        <a class="code" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a0ba6f369e7f8a700c14afe2992290544">Generic</a> = 1, <span class="comment">// AAUDIO_INPUT_PRESET_GENERIC</span></div><div class="line"><a name="l00377"></a><span class="lineno">  377</span>&#160;</div><div class="line"><a name="l00381"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a6e8ef178769235d18b44fe2bb5ab33fe">  381</a></span>&#160;        <a class="code" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a6e8ef178769235d18b44fe2bb5ab33fe">Camcorder</a> = 5, <span class="comment">// AAUDIO_INPUT_PRESET_CAMCORDER</span></div><div class="line"><a name="l00382"></a><span class="lineno">  382</span>&#160;</div><div class="line"><a name="l00386"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06af6e440b4e9edf49afe18aa4be77be6fc">  386</a></span>&#160;        <a class="code" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06af6e440b4e9edf49afe18aa4be77be6fc">VoiceRecognition</a> = 6, <span class="comment">// AAUDIO_INPUT_PRESET_VOICE_RECOGNITION</span></div><div class="line"><a name="l00387"></a><span class="lineno">  387</span>&#160;</div><div class="line"><a name="l00391"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a1862e72c9730c448fbec6f61a5d8234d">  391</a></span>&#160;        <a class="code" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a1862e72c9730c448fbec6f61a5d8234d">VoiceCommunication</a> = 7, <span class="comment">// AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION</span></div><div class="line"><a name="l00392"></a><span class="lineno">  392</span>&#160;</div><div class="line"><a name="l00398"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06acad9424158aefae0af7975901b11d85f">  398</a></span>&#160;        <a class="code" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06acad9424158aefae0af7975901b11d85f">Unprocessed</a> = 9, <span class="comment">// AAUDIO_INPUT_PRESET_UNPROCESSED</span></div><div class="line"><a name="l00399"></a><span class="lineno">  399</span>&#160;</div><div class="line"><a name="l00405"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06ad19edec0a23e435c774bf3bbcf1d999c">  405</a></span>&#160;         <a class="code" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06ad19edec0a23e435c774bf3bbcf1d999c">VoicePerformance</a> = 10, <span class="comment">// AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE</span></div><div class="line"><a name="l00406"></a><span class="lineno">  406</span>&#160;</div><div class="line"><a name="l00407"></a><span class="lineno">  407</span>&#160;    };</div><div class="line"><a name="l00408"></a><span class="lineno">  408</span>&#160;</div><div class="line"><a name="l00414"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">  414</a></span>&#160;    <span class="keyword">enum</span> <a class="code" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a> {</div><div class="line"><a name="l00420"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa58c518b26e83ea48393a76f6c9ecb51f">  420</a></span>&#160;         <a class="code" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa58c518b26e83ea48393a76f6c9ecb51f">None</a> = -1, <span class="comment">// AAUDIO_SESSION_ID_NONE</span></div><div class="line"><a name="l00421"></a><span class="lineno">  421</span>&#160;</div><div class="line"><a name="l00429"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa8485ca716c8cd4aafee372fd7028c123">  429</a></span>&#160;         <a class="code" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa8485ca716c8cd4aafee372fd7028c123">Allocate</a> = 0, <span class="comment">// AAUDIO_SESSION_ID_ALLOCATE</span></div><div class="line"><a name="l00430"></a><span class="lineno">  430</span>&#160;    };</div><div class="line"><a name="l00431"></a><span class="lineno">  431</span>&#160;</div><div class="line"><a name="l00442"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029">  442</a></span>&#160;    <span class="keyword">enum</span> <a class="code" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029">ChannelCount</a> : int32_t {</div><div class="line"><a name="l00446"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a946257a568f77c12df4fc4c49125da76">  446</a></span>&#160;      <a class="code" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a946257a568f77c12df4fc4c49125da76">Unspecified</a> = <a class="code" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a>,</div><div class="line"><a name="l00447"></a><span class="lineno">  447</span>&#160;</div><div class="line"><a name="l00451"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a8be103218645e121b51078620f452c79">  451</a></span>&#160;      <a class="code" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a8be103218645e121b51078620f452c79">Mono</a> = 1,</div><div class="line"><a name="l00452"></a><span class="lineno">  452</span>&#160;</div><div class="line"><a name="l00456"></a><span class="lineno"><a class="line" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a534e646333ca7568317b171ea96b89ba">  456</a></span>&#160;      <a class="code" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a534e646333ca7568317b171ea96b89ba">Stereo</a> = 2,</div><div class="line"><a name="l00457"></a><span class="lineno">  457</span>&#160;    };</div><div class="line"><a name="l00458"></a><span class="lineno">  458</span>&#160;</div><div class="line"><a name="l00477"></a><span class="lineno"><a class="line" href="classoboe_1_1_default_stream_values.html">  477</a></span>&#160;    <span class="keyword">class </span><a class="code" href="classoboe_1_1_default_stream_values.html">DefaultStreamValues</a> {</div><div class="line"><a name="l00478"></a><span class="lineno">  478</span>&#160;</div><div class="line"><a name="l00479"></a><span class="lineno">  479</span>&#160;    <span class="keyword">public</span>:</div><div class="line"><a name="l00480"></a><span class="lineno">  480</span>&#160;</div><div class="line"><a name="l00482"></a><span class="lineno"><a class="line" href="classoboe_1_1_default_stream_values.html#a46a5d9a653f2153f618cadcab764e1b1">  482</a></span>&#160;        <span class="keyword">static</span> int32_t <a class="code" href="classoboe_1_1_default_stream_values.html#a46a5d9a653f2153f618cadcab764e1b1">SampleRate</a>;</div><div class="line"><a name="l00484"></a><span class="lineno"><a class="line" href="classoboe_1_1_default_stream_values.html#ab5ea5576699cebc56193f5c297d3e300">  484</a></span>&#160;        <span class="keyword">static</span> int32_t <a class="code" href="classoboe_1_1_default_stream_values.html#ab5ea5576699cebc56193f5c297d3e300">FramesPerBurst</a>;</div><div class="line"><a name="l00486"></a><span class="lineno"><a class="line" href="classoboe_1_1_default_stream_values.html#ad5dce538d5963c81bf58350ab730962d">  486</a></span>&#160;        <span class="keyword">static</span> int32_t <a class="code" href="classoboe_1_1_default_stream_values.html#ad5dce538d5963c81bf58350ab730962d">ChannelCount</a>;</div><div class="line"><a name="l00487"></a><span class="lineno">  487</span>&#160;</div><div class="line"><a name="l00488"></a><span class="lineno">  488</span>&#160;    };</div><div class="line"><a name="l00489"></a><span class="lineno">  489</span>&#160;</div><div class="line"><a name="l00493"></a><span class="lineno"><a class="line" href="structoboe_1_1_frame_timestamp.html">  493</a></span>&#160;    <span class="keyword">struct </span><a class="code" href="structoboe_1_1_frame_timestamp.html">FrameTimestamp</a> {</div><div class="line"><a name="l00494"></a><span class="lineno">  494</span>&#160;        int64_t position; <span class="comment">// in frames</span></div><div class="line"><a name="l00495"></a><span class="lineno">  495</span>&#160;        int64_t timestamp; <span class="comment">// in nanoseconds</span></div><div class="line"><a name="l00496"></a><span class="lineno">  496</span>&#160;    };</div><div class="line"><a name="l00497"></a><span class="lineno">  497</span>&#160;</div><div class="line"><a name="l00498"></a><span class="lineno"><a class="line" href="classoboe_1_1_oboe_globals.html">  498</a></span>&#160;    <span class="keyword">class </span><a class="code" href="classoboe_1_1_oboe_globals.html">OboeGlobals</a> {</div><div class="line"><a name="l00499"></a><span class="lineno">  499</span>&#160;    <span class="keyword">public</span>:</div><div class="line"><a name="l00500"></a><span class="lineno">  500</span>&#160;</div><div class="line"><a name="l00501"></a><span class="lineno">  501</span>&#160;        <span class="keyword">static</span> <span class="keywordtype">bool</span> areWorkaroundsEnabled() {</div><div class="line"><a name="l00502"></a><span class="lineno">  502</span>&#160;            <span class="keywordflow">return</span> mWorkaroundsEnabled;</div><div class="line"><a name="l00503"></a><span class="lineno">  503</span>&#160;        }</div><div class="line"><a name="l00504"></a><span class="lineno">  504</span>&#160;</div><div class="line"><a name="l00510"></a><span class="lineno"><a class="line" href="classoboe_1_1_oboe_globals.html#af2b8af764c5a5e6fc007b7725117303b">  510</a></span>&#160;        <span class="keyword">static</span> <span class="keywordtype">void</span> <a class="code" href="classoboe_1_1_oboe_globals.html#af2b8af764c5a5e6fc007b7725117303b">setWorkaroundsEnabled</a>(<span class="keywordtype">bool</span> enabled) {</div><div class="line"><a name="l00511"></a><span class="lineno">  511</span>&#160;            mWorkaroundsEnabled = enabled;</div><div class="line"><a name="l00512"></a><span class="lineno">  512</span>&#160;        }</div><div class="line"><a name="l00513"></a><span class="lineno">  513</span>&#160;</div><div class="line"><a name="l00514"></a><span class="lineno">  514</span>&#160;    <span class="keyword">private</span>:</div><div class="line"><a name="l00515"></a><span class="lineno">  515</span>&#160;        <span class="keyword">static</span> <span class="keywordtype">bool</span> mWorkaroundsEnabled;</div><div class="line"><a name="l00516"></a><span class="lineno">  516</span>&#160;    };</div><div class="line"><a name="l00517"></a><span class="lineno">  517</span>&#160;} <span class="comment">// namespace oboe</span></div><div class="line"><a name="l00518"></a><span class="lineno">  518</span>&#160;</div><div class="line"><a name="l00519"></a><span class="lineno">  519</span>&#160;<span class="preprocessor">#endif // OBOE_DEFINITIONS_H</span></div><div class="ttc" id="namespaceoboe_html_aedef0759ae3622b6f0324799bcbdebf0"><div class="ttname"><a href="namespaceoboe.html#aedef0759ae3622b6f0324799bcbdebf0">oboe::kNanosPerMicrosecond</a></div><div class="ttdeci">constexpr int64_t kNanosPerMicrosecond</div><div class="ttdef"><b>Definition:</b> Definitions.h:38</div></div>
-<div class="ttc" id="namespaceoboe_html_a92972414867c81d5974cb2ed7abefbf6a99780b1e8d754eb42abed0ca5253e55b"><div class="ttname"><a href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a99780b1e8d754eb42abed0ca5253e55b">oboe::AudioApi::AAudio</a></div></div>
-<div class="ttc" id="namespaceoboe_html_af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54"><div class="ttname"><a href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54">oboe::Direction::Output</a></div></div>
-<div class="ttc" id="classoboe_1_1_oboe_globals_html"><div class="ttname"><a href="classoboe_1_1_oboe_globals.html">oboe::OboeGlobals</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:498</div></div>
-<div class="ttc" id="namespaceoboe_html_a5752250c10e96179e3618d7f72937eafa8485ca716c8cd4aafee372fd7028c123"><div class="ttname"><a href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa8485ca716c8cd4aafee372fd7028c123">oboe::Allocate</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:429</div></div>
-<div class="ttc" id="namespaceoboe_html_a4477ed232b02e2694d9309baf55a8f06af6e440b4e9edf49afe18aa4be77be6fc"><div class="ttname"><a href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06af6e440b4e9edf49afe18aa4be77be6fc">oboe::VoiceRecognition</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:386</div></div>
-<div class="ttc" id="namespaceoboe_html_a5752250c10e96179e3618d7f72937eafa58c518b26e83ea48393a76f6c9ecb51f"><div class="ttname"><a href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa58c518b26e83ea48393a76f6c9ecb51f">oboe::None</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:420</div></div>
-<div class="ttc" id="namespaceoboe_html_a5948466b593c4eab65f7025846a39f51"><div class="ttname"><a href="namespaceoboe.html#a5948466b593c4eab65f7025846a39f51">oboe::kNanosPerSecond</a></div><div class="ttdeci">constexpr int64_t kNanosPerSecond</div><div class="ttdef"><b>Definition:</b> Definitions.h:53</div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0a9b1363da9503dbd4142c0274a88e8d4b"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a9b1363da9503dbd4142c0274a88e8d4b">oboe::Usage::Assistant</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0a639ffd54516c1a84a288a363c9469df8"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a639ffd54516c1a84a288a363c9469df8">oboe::Usage::AssistanceAccessibility</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a1068781f3920654b1bfd7ed136468184abbad080463ed11f9d77797c04aa1e5b1"><div class="ttname"><a href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184abbad080463ed11f9d77797c04aa1e5b1">oboe::PerformanceMode::PowerSaving</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a8330247b25429953a08354f41834d520a2ef50b4c466304dc6ac77bac8a779971"><div class="ttname"><a href="namespaceoboe.html#a8330247b25429953a08354f41834d520a2ef50b4c466304dc6ac77bac8a779971">oboe::SharingMode::Exclusive</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a1068781f3920654b1bfd7ed136468184"><div class="ttname"><a href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">oboe::PerformanceMode</a></div><div class="ttdeci">PerformanceMode</div><div class="ttdef"><b>Definition:</b> Definitions.h:192</div></div>
-<div class="ttc" id="namespaceoboe_html_a5752250c10e96179e3618d7f72937eaf"><div class="ttname"><a href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">oboe::SessionId</a></div><div class="ttdeci">SessionId</div><div class="ttdef"><b>Definition:</b> Definitions.h:414</div></div>
-<div class="ttc" id="namespaceoboe_html_a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca"><div class="ttname"><a href="namespaceoboe.html#a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca">oboe::SharingMode::Shared</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0a1ce57a0572748beebfc0c664ca1077e7"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a1ce57a0572748beebfc0c664ca1077e7">oboe::Usage::AssistanceSonification</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a2a3cec6f021c1a324df60273710c604ba8b3b366178c2b7b1688bca6cd33758b1"><div class="ttname"><a href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba8b3b366178c2b7b1688bca6cd33758b1">oboe::Movie</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:354</div></div>
-<div class="ttc" id="namespaceoboe_html_a4477ed232b02e2694d9309baf55a8f06a0ba6f369e7f8a700c14afe2992290544"><div class="ttname"><a href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a0ba6f369e7f8a700c14afe2992290544">oboe::Generic</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:376</div></div>
-<div class="ttc" id="namespaceoboe_html_a1068781f3920654b1bfd7ed136468184a611907b5ab1865515c35357efa41a9b9"><div class="ttname"><a href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184a611907b5ab1865515c35357efa41a9b9">oboe::PerformanceMode::LowLatency</a></div></div>
-<div class="ttc" id="namespaceoboe_html_af85fc9910a287df6c5df0ed396bb75cd"><div class="ttname"><a href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">oboe::DataCallbackResult</a></div><div class="ttdeci">DataCallbackResult</div><div class="ttdef"><b>Definition:</b> Definitions.h:119</div></div>
-<div class="ttc" id="classoboe_1_1_oboe_globals_html_af2b8af764c5a5e6fc007b7725117303b"><div class="ttname"><a href="classoboe_1_1_oboe_globals.html#af2b8af764c5a5e6fc007b7725117303b">oboe::OboeGlobals::setWorkaroundsEnabled</a></div><div class="ttdeci">static void setWorkaroundsEnabled(bool enabled)</div><div class="ttdef"><b>Definition:</b> Definitions.h:510</div></div>
-<div class="ttc" id="namespaceoboe_html_a92972414867c81d5974cb2ed7abefbf6"><div class="ttname"><a href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">oboe::AudioApi</a></div><div class="ttdeci">AudioApi</div><div class="ttdef"><b>Definition:</b> Definitions.h:213</div></div>
-<div class="ttc" id="namespaceoboe_html_a2a3cec6f021c1a324df60273710c604b"><div class="ttname"><a href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">oboe::ContentType</a></div><div class="ttdeci">ContentType</div><div class="ttdef"><b>Definition:</b> Definitions.h:339</div></div>
-<div class="ttc" id="classoboe_1_1_default_stream_values_html"><div class="ttname"><a href="classoboe_1_1_default_stream_values.html">oboe::DefaultStreamValues</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:477</div></div>
-<div class="ttc" id="namespaceoboe_html_a92972414867c81d5974cb2ed7abefbf6a24e758ea9c1e842ef71cc8ff8b63fa9b"><div class="ttname"><a href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a24e758ea9c1e842ef71cc8ff8b63fa9b">oboe::AudioApi::OpenSLES</a></div></div>
-<div class="ttc" id="structoboe_1_1_frame_timestamp_html"><div class="ttname"><a href="structoboe_1_1_frame_timestamp.html">oboe::FrameTimestamp</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:493</div></div>
-<div class="ttc" id="namespaceoboe_html_a82f3720eba7654aceb7282be36f9ff1da68ef004de6166492c1d668eb8efe09bd"><div class="ttname"><a href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1da68ef004de6166492c1d668eb8efe09bd">oboe::SampleRateConversionQuality::Best</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0a4e7a4b08274d472394b740a20d3bbdaf"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a4e7a4b08274d472394b740a20d3bbdaf">oboe::Usage::NotificationRingtone</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">oboe::Usage</a></div><div class="ttdeci">Usage</div><div class="ttdef"><b>Definition:</b> Definitions.h:263</div></div>
-<div class="ttc" id="namespaceoboe_html_a522e6806948369987639a0d1df03c029a534e646333ca7568317b171ea96b89ba"><div class="ttname"><a href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a534e646333ca7568317b171ea96b89ba">oboe::Stereo</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:456</div></div>
-<div class="ttc" id="namespaceoboe_html_a4477ed232b02e2694d9309baf55a8f06a1862e72c9730c448fbec6f61a5d8234d"><div class="ttname"><a href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a1862e72c9730c448fbec6f61a5d8234d">oboe::VoiceCommunication</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:391</div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74">oboe::Usage::Media</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a92afc593e856571aacbfd02e57075df6abcd774f891b5f9df7099f3ea75dadf8d"><div class="ttname"><a href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6abcd774f891b5f9df7099f3ea75dadf8d">oboe::AudioFormat::I16</a></div></div>
-<div class="ttc" id="classoboe_1_1_default_stream_values_html_ab5ea5576699cebc56193f5c297d3e300"><div class="ttname"><a href="classoboe_1_1_default_stream_values.html#ab5ea5576699cebc56193f5c297d3e300">oboe::DefaultStreamValues::FramesPerBurst</a></div><div class="ttdeci">static int32_t FramesPerBurst</div><div class="ttdef"><b>Definition:</b> Definitions.h:484</div></div>
-<div class="ttc" id="namespaceoboe_html_a4477ed232b02e2694d9309baf55a8f06a6e8ef178769235d18b44fe2bb5ab33fe"><div class="ttname"><a href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a6e8ef178769235d18b44fe2bb5ab33fe">oboe::Camcorder</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:381</div></div>
-<div class="ttc" id="namespaceoboe_html_a831e887150474c087170679eaca8672b"><div class="ttname"><a href="namespaceoboe.html#a831e887150474c087170679eaca8672b">oboe::kNanosPerMillisecond</a></div><div class="ttdeci">constexpr int64_t kNanosPerMillisecond</div><div class="ttdef"><b>Definition:</b> Definitions.h:43</div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0a63d72051e901c069f8aa1b32aa0c43bb"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a63d72051e901c069f8aa1b32aa0c43bb">oboe::Usage::Game</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a92afc593e856571aacbfd02e57075df6a22ae0e2b89e5e3d477f988cc36d3272b"><div class="ttname"><a href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6a22ae0e2b89e5e3d477f988cc36d3272b">oboe::AudioFormat::Float</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a4477ed232b02e2694d9309baf55a8f06acad9424158aefae0af7975901b11d85f"><div class="ttname"><a href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06acad9424158aefae0af7975901b11d85f">oboe::Unprocessed</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:398</div></div>
-<div class="ttc" id="namespaceoboe_html_a522e6806948369987639a0d1df03c029a8be103218645e121b51078620f452c79"><div class="ttname"><a href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a8be103218645e121b51078620f452c79">oboe::Mono</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:451</div></div>
-<div class="ttc" id="namespaceoboe_html_a92afc593e856571aacbfd02e57075df6"><div class="ttname"><a href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">oboe::AudioFormat</a></div><div class="ttdeci">AudioFormat</div><div class="ttdef"><b>Definition:</b> Definitions.h:94</div></div>
-<div class="ttc" id="namespaceoboe_html_af2147500089212955498a08ef2edb5aea324118a6721dd6b8a9b9f4e327df2bf5"><div class="ttname"><a href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea324118a6721dd6b8a9b9f4e327df2bf5">oboe::Direction::Input</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a2a3cec6f021c1a324df60273710c604ba0885eef555037e94a7cf39fe683c2799"><div class="ttname"><a href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba0885eef555037e94a7cf39fe683c2799">oboe::Sonification</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:360</div></div>
-<div class="ttc" id="namespaceoboe_html_a522e6806948369987639a0d1df03c029"><div class="ttname"><a href="namespaceoboe.html#a522e6806948369987639a0d1df03c029">oboe::ChannelCount</a></div><div class="ttdeci">ChannelCount</div><div class="ttdef"><b>Definition:</b> Definitions.h:442</div></div>
-<div class="ttc" id="namespaceoboe_html_a92afc593e856571aacbfd02e57075df6a4bbb8f967da6d1a610596d7257179c2b"><div class="ttname"><a href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6a4bbb8f967da6d1a610596d7257179c2b">oboe::AudioFormat::Invalid</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a486512e787b609c80ba4436f23929af1"><div class="ttname"><a href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a></div><div class="ttdeci">Result</div><div class="ttdef"><b>Definition:</b> Definitions.h:131</div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0ade058a1314f9a8504593259ff4f21a1e"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0ade058a1314f9a8504593259ff4f21a1e">oboe::Usage::AssistanceNavigationGuidance</a></div></div>
-<div class="ttc" id="namespaceoboe_html_ab0772052200184e514082eaa89be7905"><div class="ttname"><a href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">oboe::kUnspecified</a></div><div class="ttdeci">constexpr int32_t kUnspecified</div><div class="ttdef"><b>Definition:</b> Definitions.h:32</div></div>
-<div class="ttc" id="namespaceoboe_html"><div class="ttname"><a href="namespaceoboe.html">oboe</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:31</div></div>
-<div class="ttc" id="namespaceoboe_html_ad1bb9f5626cec20d3a052a8721959873"><div class="ttname"><a href="namespaceoboe.html#ad1bb9f5626cec20d3a052a8721959873">oboe::kMillisPerSecond</a></div><div class="ttdeci">constexpr int64_t kMillisPerSecond</div><div class="ttdef"><b>Definition:</b> Definitions.h:48</div></div>
-<div class="ttc" id="namespaceoboe_html_a82f3720eba7654aceb7282be36f9ff1d"><div class="ttname"><a href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">oboe::SampleRateConversionQuality</a></div><div class="ttdeci">SampleRateConversionQuality</div><div class="ttdef"><b>Definition:</b> Definitions.h:235</div></div>
-<div class="ttc" id="namespaceoboe_html_a522e6806948369987639a0d1df03c029a946257a568f77c12df4fc4c49125da76"><div class="ttname"><a href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a946257a568f77c12df4fc4c49125da76">oboe::Unspecified</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:446</div></div>
-<div class="ttc" id="namespaceoboe_html_af2147500089212955498a08ef2edb5ae"><div class="ttname"><a href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">oboe::Direction</a></div><div class="ttdeci">Direction</div><div class="ttdef"><b>Definition:</b> Definitions.h:78</div></div>
-<div class="ttc" id="namespaceoboe_html_a8330247b25429953a08354f41834d520"><div class="ttname"><a href="namespaceoboe.html#a8330247b25429953a08354f41834d520">oboe::SharingMode</a></div><div class="ttdeci">SharingMode</div><div class="ttdef"><b>Definition:</b> Definitions.h:167</div></div>
-<div class="ttc" id="namespaceoboe_html_a4477ed232b02e2694d9309baf55a8f06"><div class="ttname"><a href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">oboe::InputPreset</a></div><div class="ttdeci">InputPreset</div><div class="ttdef"><b>Definition:</b> Definitions.h:372</div></div>
-<div class="ttc" id="namespaceoboe_html_a89fa2ce046723764618c29db737917f6"><div class="ttname"><a href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">oboe::StreamState</a></div><div class="ttdeci">StreamState</div><div class="ttdef"><b>Definition:</b> Definitions.h:58</div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0a404f62633744bf4da0c6a27a2b78ce74"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a404f62633744bf4da0c6a27a2b78ce74">oboe::Usage::VoiceCommunicationSignalling</a></div></div>
-<div class="ttc" id="classoboe_1_1_default_stream_values_html_a46a5d9a653f2153f618cadcab764e1b1"><div class="ttname"><a href="classoboe_1_1_default_stream_values.html#a46a5d9a653f2153f618cadcab764e1b1">oboe::DefaultStreamValues::SampleRate</a></div><div class="ttdeci">static int32_t SampleRate</div><div class="ttdef"><b>Definition:</b> Definitions.h:482</div></div>
-<div class="ttc" id="classoboe_1_1_default_stream_values_html_ad5dce538d5963c81bf58350ab730962d"><div class="ttname"><a href="classoboe_1_1_default_stream_values.html#ad5dce538d5963c81bf58350ab730962d">oboe::DefaultStreamValues::ChannelCount</a></div><div class="ttdeci">static int32_t ChannelCount</div><div class="ttdef"><b>Definition:</b> Definitions.h:486</div></div>
-<div class="ttc" id="namespaceoboe_html_a4477ed232b02e2694d9309baf55a8f06ad19edec0a23e435c774bf3bbcf1d999c"><div class="ttname"><a href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06ad19edec0a23e435c774bf3bbcf1d999c">oboe::VoicePerformance</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:405</div></div>
-<div class="ttc" id="namespaceoboe_html_a2a3cec6f021c1a324df60273710c604bac156fcc7b29059305cef26f3904d4517"><div class="ttname"><a href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604bac156fcc7b29059305cef26f3904d4517">oboe::Music</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:349</div></div>
-<div class="ttc" id="namespaceoboe_html_a82f3720eba7654aceb7282be36f9ff1da90fd7fdf6f41406a75e5265b9583bb4e"><div class="ttname"><a href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1da90fd7fdf6f41406a75e5265b9583bb4e">oboe::SampleRateConversionQuality::Fastest</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a2a3cec6f021c1a324df60273710c604ba3dc48a4b4619aa4edd1da7b937b4dcd1"><div class="ttname"><a href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba3dc48a4b4619aa4edd1da7b937b4dcd1">oboe::Speech</a></div><div class="ttdef"><b>Definition:</b> Definitions.h:344</div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0a089240b5380dbd12f1eac0ec258a3b2f"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a089240b5380dbd12f1eac0ec258a3b2f">oboe::Usage::NotificationEvent</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0a96d008db67fc0b5551a926842bbb6a71"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a96d008db67fc0b5551a926842bbb6a71">oboe::Usage::Notification</a></div></div>
-<div class="ttc" id="namespaceoboe_html_a104ee8396c173fefac429759ea3c21a0a46c4c4d980dfe025ae5b35aa0011dde4"><div class="ttname"><a href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a46c4c4d980dfe025ae5b35aa0011dde4">oboe::Usage::Alarm</a></div></div>
-</div><!-- fragment --></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/_latency_tuner_8h_source.html b/docs/reference/_latency_tuner_8h_source.html
deleted file mode 100644
index c9481df..0000000
--- a/docs/reference/_latency_tuner_8h_source.html
+++ /dev/null
@@ -1,92 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: include/oboe/LatencyTuner.h Source File</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="dir_d44c64559bbebec7f509842c48db8b23.html">include</a></li><li class="navelem"><a class="el" href="dir_768f6301d9838e45d679001914ab2803.html">oboe</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">LatencyTuner.h</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;<span class="comment">/*</span></div><div class="line"><a name="l00002"></a><span class="lineno">    2</span>&#160;<span class="comment"> * Copyright 2017 The Android Open Source Project</span></div><div class="line"><a name="l00003"></a><span class="lineno">    3</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00004"></a><span class="lineno">    4</span>&#160;<span class="comment"> * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></div><div class="line"><a name="l00005"></a><span class="lineno">    5</span>&#160;<span class="comment"> * you may not use this file except in compliance with the License.</span></div><div class="line"><a name="l00006"></a><span class="lineno">    6</span>&#160;<span class="comment"> * You may obtain a copy of the License at</span></div><div class="line"><a name="l00007"></a><span class="lineno">    7</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00008"></a><span class="lineno">    8</span>&#160;<span class="comment"> *      http://www.apache.org/licenses/LICENSE-2.0</span></div><div class="line"><a name="l00009"></a><span class="lineno">    9</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00010"></a><span class="lineno">   10</span>&#160;<span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></div><div class="line"><a name="l00011"></a><span class="lineno">   11</span>&#160;<span class="comment"> * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</span></div><div class="line"><a name="l00012"></a><span class="lineno">   12</span>&#160;<span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></div><div class="line"><a name="l00013"></a><span class="lineno">   13</span>&#160;<span class="comment"> * See the License for the specific language governing permissions and</span></div><div class="line"><a name="l00014"></a><span class="lineno">   14</span>&#160;<span class="comment"> * limitations under the License.</span></div><div class="line"><a name="l00015"></a><span class="lineno">   15</span>&#160;<span class="comment"> */</span></div><div class="line"><a name="l00016"></a><span class="lineno">   16</span>&#160;</div><div class="line"><a name="l00017"></a><span class="lineno">   17</span>&#160;<span class="preprocessor">#ifndef OBOE_LATENCY_TUNER_</span></div><div class="line"><a name="l00018"></a><span class="lineno">   18</span>&#160;<span class="preprocessor">#define OBOE_LATENCY_TUNER_</span></div><div class="line"><a name="l00019"></a><span class="lineno">   19</span>&#160;</div><div class="line"><a name="l00020"></a><span class="lineno">   20</span>&#160;<span class="preprocessor">#include &lt;atomic&gt;</span></div><div class="line"><a name="l00021"></a><span class="lineno">   21</span>&#160;<span class="preprocessor">#include &lt;cstdint&gt;</span></div><div class="line"><a name="l00022"></a><span class="lineno">   22</span>&#160;<span class="preprocessor">#include &quot;oboe/Definitions.h&quot;</span></div><div class="line"><a name="l00023"></a><span class="lineno">   23</span>&#160;<span class="preprocessor">#include &quot;oboe/AudioStream.h&quot;</span></div><div class="line"><a name="l00024"></a><span class="lineno">   24</span>&#160;</div><div class="line"><a name="l00025"></a><span class="lineno">   25</span>&#160;<span class="keyword">namespace </span><a class="code" href="namespaceoboe.html">oboe</a> {</div><div class="line"><a name="l00026"></a><span class="lineno">   26</span>&#160;</div><div class="line"><a name="l00041"></a><span class="lineno"><a class="line" href="classoboe_1_1_latency_tuner.html">   41</a></span>&#160;<span class="keyword">class </span><a class="code" href="classoboe_1_1_latency_tuner.html">LatencyTuner</a> {</div><div class="line"><a name="l00042"></a><span class="lineno">   42</span>&#160;<span class="keyword">public</span>:</div><div class="line"><a name="l00043"></a><span class="lineno">   43</span>&#160;</div><div class="line"><a name="l00049"></a><span class="lineno">   49</span>&#160;    <span class="keyword">explicit</span> <a class="code" href="classoboe_1_1_latency_tuner.html#a0263b9a55825c0a403653b2b508073ea">LatencyTuner</a>(<a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a> &amp;stream);</div><div class="line"><a name="l00050"></a><span class="lineno">   50</span>&#160;</div><div class="line"><a name="l00057"></a><span class="lineno">   57</span>&#160;    <span class="keyword">explicit</span> <a class="code" href="classoboe_1_1_latency_tuner.html#a0263b9a55825c0a403653b2b508073ea">LatencyTuner</a>(<a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a> &amp;stream, int32_t maximumBufferSize);</div><div class="line"><a name="l00058"></a><span class="lineno">   58</span>&#160;</div><div class="line"><a name="l00067"></a><span class="lineno">   67</span>&#160;    <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> <a class="code" href="classoboe_1_1_latency_tuner.html#ad2be756965e6a9af3114008eda892174">tune</a>();</div><div class="line"><a name="l00068"></a><span class="lineno">   68</span>&#160;</div><div class="line"><a name="l00077"></a><span class="lineno">   77</span>&#160;    <span class="keywordtype">void</span> <a class="code" href="classoboe_1_1_latency_tuner.html#a6c0142e08dc65eda8f758b4794450867">requestReset</a>();</div><div class="line"><a name="l00078"></a><span class="lineno">   78</span>&#160;</div><div class="line"><a name="l00084"></a><span class="lineno">   84</span>&#160;    <span class="keywordtype">bool</span> <a class="code" href="classoboe_1_1_latency_tuner.html#a45c013fd6787ad09d328385d6314c4d4">isAtMaximumBufferSize</a>();</div><div class="line"><a name="l00085"></a><span class="lineno">   85</span>&#160;</div><div class="line"><a name="l00091"></a><span class="lineno"><a class="line" href="classoboe_1_1_latency_tuner.html#adc96aa53b18a051b6ccdacb838139bf8">   91</a></span>&#160;    <span class="keywordtype">void</span> <a class="code" href="classoboe_1_1_latency_tuner.html#adc96aa53b18a051b6ccdacb838139bf8">setMinimumBufferSize</a>(int32_t bufferSize) {</div><div class="line"><a name="l00092"></a><span class="lineno">   92</span>&#160;        mMinimumBufferSize = bufferSize;</div><div class="line"><a name="l00093"></a><span class="lineno">   93</span>&#160;    }</div><div class="line"><a name="l00094"></a><span class="lineno">   94</span>&#160;</div><div class="line"><a name="l00095"></a><span class="lineno">   95</span>&#160;    int32_t getMinimumBufferSize()<span class="keyword"> const </span>{</div><div class="line"><a name="l00096"></a><span class="lineno">   96</span>&#160;        <span class="keywordflow">return</span> mMinimumBufferSize;</div><div class="line"><a name="l00097"></a><span class="lineno">   97</span>&#160;    }</div><div class="line"><a name="l00098"></a><span class="lineno">   98</span>&#160;</div><div class="line"><a name="l00108"></a><span class="lineno"><a class="line" href="classoboe_1_1_latency_tuner.html#a2684b30205126c8acd2f75d01cce05db">  108</a></span>&#160;    <span class="keywordtype">void</span> <a class="code" href="classoboe_1_1_latency_tuner.html#a2684b30205126c8acd2f75d01cce05db">setBufferSizeIncrement</a>(int32_t sizeIncrement) {</div><div class="line"><a name="l00109"></a><span class="lineno">  109</span>&#160;        mBufferSizeIncrement = sizeIncrement;</div><div class="line"><a name="l00110"></a><span class="lineno">  110</span>&#160;    }</div><div class="line"><a name="l00111"></a><span class="lineno">  111</span>&#160;</div><div class="line"><a name="l00112"></a><span class="lineno">  112</span>&#160;    int32_t getBufferSizeIncrement()<span class="keyword"> const </span>{</div><div class="line"><a name="l00113"></a><span class="lineno">  113</span>&#160;        <span class="keywordflow">return</span> mBufferSizeIncrement;</div><div class="line"><a name="l00114"></a><span class="lineno">  114</span>&#160;    }</div><div class="line"><a name="l00115"></a><span class="lineno">  115</span>&#160;</div><div class="line"><a name="l00116"></a><span class="lineno">  116</span>&#160;<span class="keyword">private</span>:</div><div class="line"><a name="l00117"></a><span class="lineno">  117</span>&#160;</div><div class="line"><a name="l00124"></a><span class="lineno">  124</span>&#160;    <span class="keywordtype">void</span> reset();</div><div class="line"><a name="l00125"></a><span class="lineno">  125</span>&#160;</div><div class="line"><a name="l00126"></a><span class="lineno">  126</span>&#160;    <span class="keyword">enum class</span> State {</div><div class="line"><a name="l00127"></a><span class="lineno">  127</span>&#160;        Idle,</div><div class="line"><a name="l00128"></a><span class="lineno">  128</span>&#160;        Active,</div><div class="line"><a name="l00129"></a><span class="lineno">  129</span>&#160;        AtMax,</div><div class="line"><a name="l00130"></a><span class="lineno">  130</span>&#160;        Unsupported</div><div class="line"><a name="l00131"></a><span class="lineno">  131</span>&#160;    } ;</div><div class="line"><a name="l00132"></a><span class="lineno">  132</span>&#160;</div><div class="line"><a name="l00133"></a><span class="lineno">  133</span>&#160;    <span class="comment">// arbitrary number of calls to wait before bumping up the latency</span></div><div class="line"><a name="l00134"></a><span class="lineno">  134</span>&#160;    <span class="keyword">static</span> constexpr int32_t kIdleCount = 8;</div><div class="line"><a name="l00135"></a><span class="lineno">  135</span>&#160;    <span class="keyword">static</span> constexpr int32_t kDefaultNumBursts = 2;</div><div class="line"><a name="l00136"></a><span class="lineno">  136</span>&#160;</div><div class="line"><a name="l00137"></a><span class="lineno">  137</span>&#160;    AudioStream           &amp;mStream;</div><div class="line"><a name="l00138"></a><span class="lineno">  138</span>&#160;    State                 mState = State::Idle;</div><div class="line"><a name="l00139"></a><span class="lineno">  139</span>&#160;    int32_t               mMaxBufferSize = 0;</div><div class="line"><a name="l00140"></a><span class="lineno">  140</span>&#160;    int32_t               mPreviousXRuns = 0;</div><div class="line"><a name="l00141"></a><span class="lineno">  141</span>&#160;    int32_t               mIdleCountDown = 0;</div><div class="line"><a name="l00142"></a><span class="lineno">  142</span>&#160;    int32_t               mMinimumBufferSize;</div><div class="line"><a name="l00143"></a><span class="lineno">  143</span>&#160;    int32_t               mBufferSizeIncrement;</div><div class="line"><a name="l00144"></a><span class="lineno">  144</span>&#160;    std::atomic&lt;int32_t&gt;  mLatencyTriggerRequests{0}; <span class="comment">// TODO user atomic requester from AAudio</span></div><div class="line"><a name="l00145"></a><span class="lineno">  145</span>&#160;    std::atomic&lt;int32_t&gt;  mLatencyTriggerResponses{0};</div><div class="line"><a name="l00146"></a><span class="lineno">  146</span>&#160;};</div><div class="line"><a name="l00147"></a><span class="lineno">  147</span>&#160;</div><div class="line"><a name="l00148"></a><span class="lineno">  148</span>&#160;} <span class="comment">// namespace oboe</span></div><div class="line"><a name="l00149"></a><span class="lineno">  149</span>&#160;</div><div class="line"><a name="l00150"></a><span class="lineno">  150</span>&#160;<span class="preprocessor">#endif // OBOE_LATENCY_TUNER_</span></div><div class="ttc" id="classoboe_1_1_latency_tuner_html_a2684b30205126c8acd2f75d01cce05db"><div class="ttname"><a href="classoboe_1_1_latency_tuner.html#a2684b30205126c8acd2f75d01cce05db">oboe::LatencyTuner::setBufferSizeIncrement</a></div><div class="ttdeci">void setBufferSizeIncrement(int32_t sizeIncrement)</div><div class="ttdef"><b>Definition:</b> LatencyTuner.h:108</div></div>
-<div class="ttc" id="classoboe_1_1_latency_tuner_html_a6c0142e08dc65eda8f758b4794450867"><div class="ttname"><a href="classoboe_1_1_latency_tuner.html#a6c0142e08dc65eda8f758b4794450867">oboe::LatencyTuner::requestReset</a></div><div class="ttdeci">void requestReset()</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html"><div class="ttname"><a href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:44</div></div>
-<div class="ttc" id="classoboe_1_1_latency_tuner_html_a45c013fd6787ad09d328385d6314c4d4"><div class="ttname"><a href="classoboe_1_1_latency_tuner.html#a45c013fd6787ad09d328385d6314c4d4">oboe::LatencyTuner::isAtMaximumBufferSize</a></div><div class="ttdeci">bool isAtMaximumBufferSize()</div></div>
-<div class="ttc" id="classoboe_1_1_latency_tuner_html_a0263b9a55825c0a403653b2b508073ea"><div class="ttname"><a href="classoboe_1_1_latency_tuner.html#a0263b9a55825c0a403653b2b508073ea">oboe::LatencyTuner::LatencyTuner</a></div><div class="ttdeci">LatencyTuner(AudioStream &amp;stream)</div></div>
-<div class="ttc" id="classoboe_1_1_latency_tuner_html_ad2be756965e6a9af3114008eda892174"><div class="ttname"><a href="classoboe_1_1_latency_tuner.html#ad2be756965e6a9af3114008eda892174">oboe::LatencyTuner::tune</a></div><div class="ttdeci">Result tune()</div></div>
-<div class="ttc" id="namespaceoboe_html_a486512e787b609c80ba4436f23929af1"><div class="ttname"><a href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a></div><div class="ttdeci">Result</div><div class="ttdef"><b>Definition:</b> Definitions.h:131</div></div>
-<div class="ttc" id="classoboe_1_1_latency_tuner_html"><div class="ttname"><a href="classoboe_1_1_latency_tuner.html">oboe::LatencyTuner</a></div><div class="ttdef"><b>Definition:</b> LatencyTuner.h:41</div></div>
-<div class="ttc" id="classoboe_1_1_latency_tuner_html_adc96aa53b18a051b6ccdacb838139bf8"><div class="ttname"><a href="classoboe_1_1_latency_tuner.html#adc96aa53b18a051b6ccdacb838139bf8">oboe::LatencyTuner::setMinimumBufferSize</a></div><div class="ttdeci">void setMinimumBufferSize(int32_t bufferSize)</div><div class="ttdef"><b>Definition:</b> LatencyTuner.h:91</div></div>
-<div class="ttc" id="namespaceoboe_html"><div class="ttname"><a href="namespaceoboe.html">oboe</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:31</div></div>
-</div><!-- fragment --></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/_oboe_8h_source.html b/docs/reference/_oboe_8h_source.html
deleted file mode 100644
index c808909..0000000
--- a/docs/reference/_oboe_8h_source.html
+++ /dev/null
@@ -1,82 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: include/oboe/Oboe.h Source File</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="dir_d44c64559bbebec7f509842c48db8b23.html">include</a></li><li class="navelem"><a class="el" href="dir_768f6301d9838e45d679001914ab2803.html">oboe</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">Oboe.h</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;<span class="comment">/*</span></div><div class="line"><a name="l00002"></a><span class="lineno">    2</span>&#160;<span class="comment"> * Copyright (C) 2016 The Android Open Source Project</span></div><div class="line"><a name="l00003"></a><span class="lineno">    3</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00004"></a><span class="lineno">    4</span>&#160;<span class="comment"> * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></div><div class="line"><a name="l00005"></a><span class="lineno">    5</span>&#160;<span class="comment"> * you may not use this file except in compliance with the License.</span></div><div class="line"><a name="l00006"></a><span class="lineno">    6</span>&#160;<span class="comment"> * You may obtain a copy of the License at</span></div><div class="line"><a name="l00007"></a><span class="lineno">    7</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00008"></a><span class="lineno">    8</span>&#160;<span class="comment"> *      http://www.apache.org/licenses/LICENSE-2.0</span></div><div class="line"><a name="l00009"></a><span class="lineno">    9</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00010"></a><span class="lineno">   10</span>&#160;<span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></div><div class="line"><a name="l00011"></a><span class="lineno">   11</span>&#160;<span class="comment"> * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</span></div><div class="line"><a name="l00012"></a><span class="lineno">   12</span>&#160;<span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></div><div class="line"><a name="l00013"></a><span class="lineno">   13</span>&#160;<span class="comment"> * See the License for the specific language governing permissions and</span></div><div class="line"><a name="l00014"></a><span class="lineno">   14</span>&#160;<span class="comment"> * limitations under the License.</span></div><div class="line"><a name="l00015"></a><span class="lineno">   15</span>&#160;<span class="comment"> */</span></div><div class="line"><a name="l00016"></a><span class="lineno">   16</span>&#160;</div><div class="line"><a name="l00017"></a><span class="lineno">   17</span>&#160;<span class="preprocessor">#ifndef OBOE_OBOE_H</span></div><div class="line"><a name="l00018"></a><span class="lineno">   18</span>&#160;<span class="preprocessor">#define OBOE_OBOE_H</span></div><div class="line"><a name="l00019"></a><span class="lineno">   19</span>&#160;</div><div class="line"><a name="l00027"></a><span class="lineno">   27</span>&#160;<span class="preprocessor">#include &quot;oboe/Definitions.h&quot;</span></div><div class="line"><a name="l00028"></a><span class="lineno">   28</span>&#160;<span class="preprocessor">#include &quot;oboe/ResultWithValue.h&quot;</span></div><div class="line"><a name="l00029"></a><span class="lineno">   29</span>&#160;<span class="preprocessor">#include &quot;oboe/LatencyTuner.h&quot;</span></div><div class="line"><a name="l00030"></a><span class="lineno">   30</span>&#160;<span class="preprocessor">#include &quot;oboe/AudioStream.h&quot;</span></div><div class="line"><a name="l00031"></a><span class="lineno">   31</span>&#160;<span class="preprocessor">#include &quot;oboe/AudioStreamBase.h&quot;</span></div><div class="line"><a name="l00032"></a><span class="lineno">   32</span>&#160;<span class="preprocessor">#include &quot;oboe/AudioStreamBuilder.h&quot;</span></div><div class="line"><a name="l00033"></a><span class="lineno">   33</span>&#160;<span class="preprocessor">#include &quot;oboe/Utilities.h&quot;</span></div><div class="line"><a name="l00034"></a><span class="lineno">   34</span>&#160;<span class="preprocessor">#include &quot;oboe/Version.h&quot;</span></div><div class="line"><a name="l00035"></a><span class="lineno">   35</span>&#160;<span class="preprocessor">#include &quot;oboe/StabilizedCallback.h&quot;</span></div><div class="line"><a name="l00036"></a><span class="lineno">   36</span>&#160;</div><div class="line"><a name="l00037"></a><span class="lineno">   37</span>&#160;<span class="preprocessor">#endif //OBOE_OBOE_H</span></div></div><!-- fragment --></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/_result_with_value_8h_source.html b/docs/reference/_result_with_value_8h_source.html
deleted file mode 100644
index c4f798d..0000000
--- a/docs/reference/_result_with_value_8h_source.html
+++ /dev/null
@@ -1,93 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: include/oboe/ResultWithValue.h Source File</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="dir_d44c64559bbebec7f509842c48db8b23.html">include</a></li><li class="navelem"><a class="el" href="dir_768f6301d9838e45d679001914ab2803.html">oboe</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">ResultWithValue.h</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;<span class="comment">/*</span></div><div class="line"><a name="l00002"></a><span class="lineno">    2</span>&#160;<span class="comment"> * Copyright (C) 2018 The Android Open Source Project</span></div><div class="line"><a name="l00003"></a><span class="lineno">    3</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00004"></a><span class="lineno">    4</span>&#160;<span class="comment"> * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></div><div class="line"><a name="l00005"></a><span class="lineno">    5</span>&#160;<span class="comment"> * you may not use this file except in compliance with the License.</span></div><div class="line"><a name="l00006"></a><span class="lineno">    6</span>&#160;<span class="comment"> * You may obtain a copy of the License at</span></div><div class="line"><a name="l00007"></a><span class="lineno">    7</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00008"></a><span class="lineno">    8</span>&#160;<span class="comment"> *      http://www.apache.org/licenses/LICENSE-2.0</span></div><div class="line"><a name="l00009"></a><span class="lineno">    9</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00010"></a><span class="lineno">   10</span>&#160;<span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></div><div class="line"><a name="l00011"></a><span class="lineno">   11</span>&#160;<span class="comment"> * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</span></div><div class="line"><a name="l00012"></a><span class="lineno">   12</span>&#160;<span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></div><div class="line"><a name="l00013"></a><span class="lineno">   13</span>&#160;<span class="comment"> * See the License for the specific language governing permissions and</span></div><div class="line"><a name="l00014"></a><span class="lineno">   14</span>&#160;<span class="comment"> * limitations under the License.</span></div><div class="line"><a name="l00015"></a><span class="lineno">   15</span>&#160;<span class="comment"> */</span></div><div class="line"><a name="l00016"></a><span class="lineno">   16</span>&#160;</div><div class="line"><a name="l00017"></a><span class="lineno">   17</span>&#160;<span class="preprocessor">#ifndef OBOE_RESULT_WITH_VALUE_H</span></div><div class="line"><a name="l00018"></a><span class="lineno">   18</span>&#160;<span class="preprocessor">#define OBOE_RESULT_WITH_VALUE_H</span></div><div class="line"><a name="l00019"></a><span class="lineno">   19</span>&#160;</div><div class="line"><a name="l00020"></a><span class="lineno">   20</span>&#160;<span class="preprocessor">#include &quot;oboe/Definitions.h&quot;</span></div><div class="line"><a name="l00021"></a><span class="lineno">   21</span>&#160;<span class="preprocessor">#include &lt;iostream&gt;</span></div><div class="line"><a name="l00022"></a><span class="lineno">   22</span>&#160;<span class="preprocessor">#include &lt;sstream&gt;</span></div><div class="line"><a name="l00023"></a><span class="lineno">   23</span>&#160;</div><div class="line"><a name="l00024"></a><span class="lineno">   24</span>&#160;<span class="keyword">namespace </span><a class="code" href="namespaceoboe.html">oboe</a> {</div><div class="line"><a name="l00025"></a><span class="lineno">   25</span>&#160;</div><div class="line"><a name="l00046"></a><span class="lineno">   46</span>&#160;<span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</div><div class="line"><a name="l00047"></a><span class="lineno"><a class="line" href="classoboe_1_1_result_with_value.html">   47</a></span>&#160;<span class="keyword">class </span><a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> {</div><div class="line"><a name="l00048"></a><span class="lineno">   48</span>&#160;<span class="keyword">public</span>:</div><div class="line"><a name="l00049"></a><span class="lineno">   49</span>&#160;</div><div class="line"><a name="l00055"></a><span class="lineno"><a class="line" href="classoboe_1_1_result_with_value.html#aae75caa0d16a9e23a012f77fb50c5927">   55</a></span>&#160;    <a class="code" href="classoboe_1_1_result_with_value.html#aae75caa0d16a9e23a012f77fb50c5927">ResultWithValue</a>(<a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a> <a class="code" href="classoboe_1_1_result_with_value.html#adfc76ae6db81535c2e82b856975eed41">error</a>)</div><div class="line"><a name="l00056"></a><span class="lineno">   56</span>&#160;            : mValue{}</div><div class="line"><a name="l00057"></a><span class="lineno">   57</span>&#160;            , mError(<a class="code" href="classoboe_1_1_result_with_value.html#adfc76ae6db81535c2e82b856975eed41">error</a>) {}</div><div class="line"><a name="l00058"></a><span class="lineno">   58</span>&#160;</div><div class="line"><a name="l00064"></a><span class="lineno"><a class="line" href="classoboe_1_1_result_with_value.html#a600309367db58d71f0ec16e90f7ebea5">   64</a></span>&#160;    <span class="keyword">explicit</span> <a class="code" href="classoboe_1_1_result_with_value.html#a600309367db58d71f0ec16e90f7ebea5">ResultWithValue</a>(T <a class="code" href="classoboe_1_1_result_with_value.html#a45f5c99a2c9f8fbaca502276f7ebb434">value</a>)</div><div class="line"><a name="l00065"></a><span class="lineno">   65</span>&#160;            : mValue(<a class="code" href="classoboe_1_1_result_with_value.html#a45f5c99a2c9f8fbaca502276f7ebb434">value</a>)</div><div class="line"><a name="l00066"></a><span class="lineno">   66</span>&#160;            , mError(<a class="code" href="namespaceoboe.html">oboe</a>::<a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>::OK) {}</div><div class="line"><a name="l00067"></a><span class="lineno">   67</span>&#160;</div><div class="line"><a name="l00073"></a><span class="lineno"><a class="line" href="classoboe_1_1_result_with_value.html#adfc76ae6db81535c2e82b856975eed41">   73</a></span>&#160;    <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a> <a class="code" href="classoboe_1_1_result_with_value.html#adfc76ae6db81535c2e82b856975eed41">error</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00074"></a><span class="lineno">   74</span>&#160;        <span class="keywordflow">return</span> mError;</div><div class="line"><a name="l00075"></a><span class="lineno">   75</span>&#160;    }</div><div class="line"><a name="l00076"></a><span class="lineno">   76</span>&#160;</div><div class="line"><a name="l00081"></a><span class="lineno"><a class="line" href="classoboe_1_1_result_with_value.html#a45f5c99a2c9f8fbaca502276f7ebb434">   81</a></span>&#160;    T <a class="code" href="classoboe_1_1_result_with_value.html#a45f5c99a2c9f8fbaca502276f7ebb434">value</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00082"></a><span class="lineno">   82</span>&#160;        <span class="keywordflow">return</span> mValue;</div><div class="line"><a name="l00083"></a><span class="lineno">   83</span>&#160;    }</div><div class="line"><a name="l00084"></a><span class="lineno">   84</span>&#160;</div><div class="line"><a name="l00088"></a><span class="lineno"><a class="line" href="classoboe_1_1_result_with_value.html#ae32b1953b777af7d1d0c94862ca39986">   88</a></span>&#160;    <span class="keyword">explicit</span> <span class="keyword">operator</span> bool()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> mError == oboe::Result::OK; }</div><div class="line"><a name="l00089"></a><span class="lineno">   89</span>&#160;</div><div class="line"><a name="l00100"></a><span class="lineno"><a class="line" href="classoboe_1_1_result_with_value.html#a6fb3c61c5716a045ba48dc5a5dfc8169">  100</a></span>&#160;    <span class="keywordtype">bool</span> <a class="code" href="classoboe_1_1_result_with_value.html#a6fb3c61c5716a045ba48dc5a5dfc8169">operator !</a>()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> mError != oboe::Result::OK; }</div><div class="line"><a name="l00101"></a><span class="lineno">  101</span>&#160;</div><div class="line"><a name="l00110"></a><span class="lineno"><a class="line" href="classoboe_1_1_result_with_value.html#af62107817c0bc76047e6b655a78504ba">  110</a></span>&#160;    <span class="keyword">operator</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>()<span class="keyword"> const </span>{</div><div class="line"><a name="l00111"></a><span class="lineno">  111</span>&#160;        <span class="keywordflow">return</span> mError;</div><div class="line"><a name="l00112"></a><span class="lineno">  112</span>&#160;    }</div><div class="line"><a name="l00113"></a><span class="lineno">  113</span>&#160;</div><div class="line"><a name="l00121"></a><span class="lineno"><a class="line" href="classoboe_1_1_result_with_value.html#a2304c6120e2aad8f2189383a98c7b0a7">  121</a></span>&#160;    <span class="keyword">static</span> <a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue&lt;T&gt;</a> <a class="code" href="classoboe_1_1_result_with_value.html#a2304c6120e2aad8f2189383a98c7b0a7">createBasedOnSign</a>(T numericResult){</div><div class="line"><a name="l00122"></a><span class="lineno">  122</span>&#160;</div><div class="line"><a name="l00123"></a><span class="lineno">  123</span>&#160;        <span class="comment">// Ensure that the type is either an integer or float</span></div><div class="line"><a name="l00124"></a><span class="lineno">  124</span>&#160;        static_assert(std::is_arithmetic&lt;T&gt;::value,</div><div class="line"><a name="l00125"></a><span class="lineno">  125</span>&#160;                      <span class="stringliteral">&quot;createBasedOnSign can only be called for numeric types (int or float)&quot;</span>);</div><div class="line"><a name="l00126"></a><span class="lineno">  126</span>&#160;</div><div class="line"><a name="l00127"></a><span class="lineno">  127</span>&#160;        <span class="keywordflow">if</span> (numericResult &gt;= 0){</div><div class="line"><a name="l00128"></a><span class="lineno">  128</span>&#160;            <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue&lt;T&gt;</a>(numericResult);</div><div class="line"><a name="l00129"></a><span class="lineno">  129</span>&#160;        } <span class="keywordflow">else</span> {</div><div class="line"><a name="l00130"></a><span class="lineno">  130</span>&#160;            <span class="keywordflow">return</span> <a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue&lt;T&gt;</a>(static_cast&lt;Result&gt;(numericResult));</div><div class="line"><a name="l00131"></a><span class="lineno">  131</span>&#160;        }</div><div class="line"><a name="l00132"></a><span class="lineno">  132</span>&#160;    }</div><div class="line"><a name="l00133"></a><span class="lineno">  133</span>&#160;</div><div class="line"><a name="l00134"></a><span class="lineno">  134</span>&#160;<span class="keyword">private</span>:</div><div class="line"><a name="l00135"></a><span class="lineno">  135</span>&#160;    <span class="keyword">const</span> T             mValue;</div><div class="line"><a name="l00136"></a><span class="lineno">  136</span>&#160;    <span class="keyword">const</span> <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a>  mError;</div><div class="line"><a name="l00137"></a><span class="lineno">  137</span>&#160;};</div><div class="line"><a name="l00138"></a><span class="lineno">  138</span>&#160;</div><div class="line"><a name="l00142"></a><span class="lineno">  142</span>&#160;<span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</div><div class="line"><a name="l00143"></a><span class="lineno"><a class="line" href="namespaceoboe.html#aa403103686222502d1cfc47bafc10aeb">  143</a></span>&#160;std::ostream&amp; <a class="code" href="namespaceoboe.html#aa403103686222502d1cfc47bafc10aeb">operator&lt;&lt;</a>(std::ostream &amp;strm, <span class="keyword">const</span> <a class="code" href="classoboe_1_1_result_with_value.html">ResultWithValue&lt;T&gt;</a> &amp;result) {</div><div class="line"><a name="l00144"></a><span class="lineno">  144</span>&#160;    <span class="keywordflow">if</span> (!result) {</div><div class="line"><a name="l00145"></a><span class="lineno">  145</span>&#160;        strm &lt;&lt; <a class="code" href="namespaceoboe.html#af65aaea3c5d82eee6906664d61c094b3">convertToText</a>(result.<a class="code" href="classoboe_1_1_result_with_value.html#adfc76ae6db81535c2e82b856975eed41">error</a>());</div><div class="line"><a name="l00146"></a><span class="lineno">  146</span>&#160;    } <span class="keywordflow">else</span> {</div><div class="line"><a name="l00147"></a><span class="lineno">  147</span>&#160;        strm &lt;&lt; result.<a class="code" href="classoboe_1_1_result_with_value.html#a45f5c99a2c9f8fbaca502276f7ebb434">value</a>();</div><div class="line"><a name="l00148"></a><span class="lineno">  148</span>&#160;    }</div><div class="line"><a name="l00149"></a><span class="lineno">  149</span>&#160;   <span class="keywordflow">return</span> strm;</div><div class="line"><a name="l00150"></a><span class="lineno">  150</span>&#160;}</div><div class="line"><a name="l00151"></a><span class="lineno">  151</span>&#160;</div><div class="line"><a name="l00152"></a><span class="lineno">  152</span>&#160;} <span class="comment">// namespace oboe</span></div><div class="line"><a name="l00153"></a><span class="lineno">  153</span>&#160;</div><div class="line"><a name="l00154"></a><span class="lineno">  154</span>&#160;</div><div class="line"><a name="l00155"></a><span class="lineno">  155</span>&#160;<span class="preprocessor">#endif //OBOE_RESULT_WITH_VALUE_H</span></div><div class="ttc" id="classoboe_1_1_result_with_value_html_a45f5c99a2c9f8fbaca502276f7ebb434"><div class="ttname"><a href="classoboe_1_1_result_with_value.html#a45f5c99a2c9f8fbaca502276f7ebb434">oboe::ResultWithValue::value</a></div><div class="ttdeci">T value() const</div><div class="ttdef"><b>Definition:</b> ResultWithValue.h:81</div></div>
-<div class="ttc" id="classoboe_1_1_result_with_value_html_aae75caa0d16a9e23a012f77fb50c5927"><div class="ttname"><a href="classoboe_1_1_result_with_value.html#aae75caa0d16a9e23a012f77fb50c5927">oboe::ResultWithValue::ResultWithValue</a></div><div class="ttdeci">ResultWithValue(oboe::Result error)</div><div class="ttdef"><b>Definition:</b> ResultWithValue.h:55</div></div>
-<div class="ttc" id="classoboe_1_1_result_with_value_html_a2304c6120e2aad8f2189383a98c7b0a7"><div class="ttname"><a href="classoboe_1_1_result_with_value.html#a2304c6120e2aad8f2189383a98c7b0a7">oboe::ResultWithValue::createBasedOnSign</a></div><div class="ttdeci">static ResultWithValue&lt; T &gt; createBasedOnSign(T numericResult)</div><div class="ttdef"><b>Definition:</b> ResultWithValue.h:121</div></div>
-<div class="ttc" id="namespaceoboe_html_aa403103686222502d1cfc47bafc10aeb"><div class="ttname"><a href="namespaceoboe.html#aa403103686222502d1cfc47bafc10aeb">oboe::operator&lt;&lt;</a></div><div class="ttdeci">std::ostream &amp; operator&lt;&lt;(std::ostream &amp;strm, const ResultWithValue&lt; T &gt; &amp;result)</div><div class="ttdef"><b>Definition:</b> ResultWithValue.h:143</div></div>
-<div class="ttc" id="namespaceoboe_html_af65aaea3c5d82eee6906664d61c094b3"><div class="ttname"><a href="namespaceoboe.html#af65aaea3c5d82eee6906664d61c094b3">oboe::convertToText</a></div><div class="ttdeci">const char * convertToText(FromType input)</div></div>
-<div class="ttc" id="classoboe_1_1_result_with_value_html_adfc76ae6db81535c2e82b856975eed41"><div class="ttname"><a href="classoboe_1_1_result_with_value.html#adfc76ae6db81535c2e82b856975eed41">oboe::ResultWithValue::error</a></div><div class="ttdeci">oboe::Result error() const</div><div class="ttdef"><b>Definition:</b> ResultWithValue.h:73</div></div>
-<div class="ttc" id="classoboe_1_1_result_with_value_html_a6fb3c61c5716a045ba48dc5a5dfc8169"><div class="ttname"><a href="classoboe_1_1_result_with_value.html#a6fb3c61c5716a045ba48dc5a5dfc8169">oboe::ResultWithValue::operator !</a></div><div class="ttdeci">bool operator !() const</div><div class="ttdef"><b>Definition:</b> ResultWithValue.h:100</div></div>
-<div class="ttc" id="namespaceoboe_html_a486512e787b609c80ba4436f23929af1"><div class="ttname"><a href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a></div><div class="ttdeci">Result</div><div class="ttdef"><b>Definition:</b> Definitions.h:131</div></div>
-<div class="ttc" id="classoboe_1_1_result_with_value_html_a600309367db58d71f0ec16e90f7ebea5"><div class="ttname"><a href="classoboe_1_1_result_with_value.html#a600309367db58d71f0ec16e90f7ebea5">oboe::ResultWithValue::ResultWithValue</a></div><div class="ttdeci">ResultWithValue(T value)</div><div class="ttdef"><b>Definition:</b> ResultWithValue.h:64</div></div>
-<div class="ttc" id="namespaceoboe_html"><div class="ttname"><a href="namespaceoboe.html">oboe</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:31</div></div>
-<div class="ttc" id="classoboe_1_1_result_with_value_html"><div class="ttname"><a href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue</a></div><div class="ttdef"><b>Definition:</b> ResultWithValue.h:47</div></div>
-</div><!-- fragment --></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/_stabilized_callback_8h_source.html b/docs/reference/_stabilized_callback_8h_source.html
deleted file mode 100644
index 695cc28..0000000
--- a/docs/reference/_stabilized_callback_8h_source.html
+++ /dev/null
@@ -1,93 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: include/oboe/StabilizedCallback.h Source File</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="dir_d44c64559bbebec7f509842c48db8b23.html">include</a></li><li class="navelem"><a class="el" href="dir_768f6301d9838e45d679001914ab2803.html">oboe</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">StabilizedCallback.h</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;<span class="comment">/*</span></div><div class="line"><a name="l00002"></a><span class="lineno">    2</span>&#160;<span class="comment"> * Copyright 2018 The Android Open Source Project</span></div><div class="line"><a name="l00003"></a><span class="lineno">    3</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00004"></a><span class="lineno">    4</span>&#160;<span class="comment"> * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></div><div class="line"><a name="l00005"></a><span class="lineno">    5</span>&#160;<span class="comment"> * you may not use this file except in compliance with the License.</span></div><div class="line"><a name="l00006"></a><span class="lineno">    6</span>&#160;<span class="comment"> * You may obtain a copy of the License at</span></div><div class="line"><a name="l00007"></a><span class="lineno">    7</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00008"></a><span class="lineno">    8</span>&#160;<span class="comment"> *      http://www.apache.org/licenses/LICENSE-2.0</span></div><div class="line"><a name="l00009"></a><span class="lineno">    9</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00010"></a><span class="lineno">   10</span>&#160;<span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></div><div class="line"><a name="l00011"></a><span class="lineno">   11</span>&#160;<span class="comment"> * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</span></div><div class="line"><a name="l00012"></a><span class="lineno">   12</span>&#160;<span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></div><div class="line"><a name="l00013"></a><span class="lineno">   13</span>&#160;<span class="comment"> * See the License for the specific language governing permissions and</span></div><div class="line"><a name="l00014"></a><span class="lineno">   14</span>&#160;<span class="comment"> * limitations under the License.</span></div><div class="line"><a name="l00015"></a><span class="lineno">   15</span>&#160;<span class="comment"> */</span></div><div class="line"><a name="l00016"></a><span class="lineno">   16</span>&#160;</div><div class="line"><a name="l00017"></a><span class="lineno">   17</span>&#160;<span class="preprocessor">#ifndef OBOE_STABILIZEDCALLBACK_H</span></div><div class="line"><a name="l00018"></a><span class="lineno">   18</span>&#160;<span class="preprocessor">#define OBOE_STABILIZEDCALLBACK_H</span></div><div class="line"><a name="l00019"></a><span class="lineno">   19</span>&#160;</div><div class="line"><a name="l00020"></a><span class="lineno">   20</span>&#160;<span class="preprocessor">#include &lt;cstdint&gt;</span></div><div class="line"><a name="l00021"></a><span class="lineno">   21</span>&#160;<span class="preprocessor">#include &quot;oboe/AudioStream.h&quot;</span></div><div class="line"><a name="l00022"></a><span class="lineno">   22</span>&#160;</div><div class="line"><a name="l00023"></a><span class="lineno">   23</span>&#160;<span class="keyword">namespace </span><a class="code" href="namespaceoboe.html">oboe</a> {</div><div class="line"><a name="l00024"></a><span class="lineno">   24</span>&#160;</div><div class="line"><a name="l00025"></a><span class="lineno"><a class="line" href="classoboe_1_1_stabilized_callback.html">   25</a></span>&#160;<span class="keyword">class </span><a class="code" href="classoboe_1_1_stabilized_callback.html">StabilizedCallback</a> : <span class="keyword">public</span> <a class="code" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a> {</div><div class="line"><a name="l00026"></a><span class="lineno">   26</span>&#160;</div><div class="line"><a name="l00027"></a><span class="lineno">   27</span>&#160;<span class="keyword">public</span>:</div><div class="line"><a name="l00028"></a><span class="lineno">   28</span>&#160;    <span class="keyword">explicit</span> <a class="code" href="classoboe_1_1_stabilized_callback.html">StabilizedCallback</a>(<a class="code" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a> *callback);</div><div class="line"><a name="l00029"></a><span class="lineno">   29</span>&#160;</div><div class="line"><a name="l00030"></a><span class="lineno">   30</span>&#160;    <a class="code" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a></div><div class="line"><a name="l00031"></a><span class="lineno">   31</span>&#160;    <a class="code" href="classoboe_1_1_stabilized_callback.html#ad447e12ebf732cf151655c1fbaf58a49">onAudioReady</a>(<a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a> *oboeStream, <span class="keywordtype">void</span> *audioData, int32_t numFrames) <span class="keyword">override</span>;</div><div class="line"><a name="l00032"></a><span class="lineno">   32</span>&#160;</div><div class="line"><a name="l00033"></a><span class="lineno"><a class="line" href="classoboe_1_1_stabilized_callback.html#a7ec0e9fca3181962ab78716bcda83e10">   33</a></span>&#160;    <span class="keywordtype">void</span> <a class="code" href="classoboe_1_1_stabilized_callback.html#a7ec0e9fca3181962ab78716bcda83e10">onErrorBeforeClose</a>(<a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a> *oboeStream, <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> error)<span class="keyword"> override </span>{</div><div class="line"><a name="l00034"></a><span class="lineno">   34</span>&#160;        <span class="keywordflow">return</span> mCallback-&gt;<a class="code" href="classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0">onErrorBeforeClose</a>(oboeStream, error);</div><div class="line"><a name="l00035"></a><span class="lineno">   35</span>&#160;    }</div><div class="line"><a name="l00036"></a><span class="lineno">   36</span>&#160;</div><div class="line"><a name="l00037"></a><span class="lineno"><a class="line" href="classoboe_1_1_stabilized_callback.html#af7521da42c4b08a71e6102994f6f41f4">   37</a></span>&#160;    <span class="keywordtype">void</span> <a class="code" href="classoboe_1_1_stabilized_callback.html#af7521da42c4b08a71e6102994f6f41f4">onErrorAfterClose</a>(<a class="code" href="classoboe_1_1_audio_stream.html">AudioStream</a> *oboeStream, <a class="code" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> error)<span class="keyword"> override </span>{</div><div class="line"><a name="l00038"></a><span class="lineno">   38</span>&#160;</div><div class="line"><a name="l00039"></a><span class="lineno">   39</span>&#160;        <span class="comment">// Reset all fields now that the stream has been closed</span></div><div class="line"><a name="l00040"></a><span class="lineno">   40</span>&#160;        mFrameCount = 0;</div><div class="line"><a name="l00041"></a><span class="lineno">   41</span>&#160;        mEpochTimeNanos = 0;</div><div class="line"><a name="l00042"></a><span class="lineno">   42</span>&#160;        mOpsPerNano = 1;</div><div class="line"><a name="l00043"></a><span class="lineno">   43</span>&#160;        <span class="keywordflow">return</span> mCallback-&gt;<a class="code" href="classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe">onErrorAfterClose</a>(oboeStream, error);</div><div class="line"><a name="l00044"></a><span class="lineno">   44</span>&#160;    }</div><div class="line"><a name="l00045"></a><span class="lineno">   45</span>&#160;</div><div class="line"><a name="l00046"></a><span class="lineno">   46</span>&#160;<span class="keyword">private</span>:</div><div class="line"><a name="l00047"></a><span class="lineno">   47</span>&#160;</div><div class="line"><a name="l00048"></a><span class="lineno">   48</span>&#160;    <a class="code" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a> *mCallback = <span class="keyword">nullptr</span>;</div><div class="line"><a name="l00049"></a><span class="lineno">   49</span>&#160;    int64_t mFrameCount = 0;</div><div class="line"><a name="l00050"></a><span class="lineno">   50</span>&#160;    int64_t mEpochTimeNanos = 0;</div><div class="line"><a name="l00051"></a><span class="lineno">   51</span>&#160;    <span class="keywordtype">double</span>  mOpsPerNano = 1;</div><div class="line"><a name="l00052"></a><span class="lineno">   52</span>&#160;</div><div class="line"><a name="l00053"></a><span class="lineno">   53</span>&#160;    <span class="keywordtype">void</span> generateLoad(int64_t durationNanos);</div><div class="line"><a name="l00054"></a><span class="lineno">   54</span>&#160;};</div><div class="line"><a name="l00055"></a><span class="lineno">   55</span>&#160;</div><div class="line"><a name="l00060"></a><span class="lineno">   60</span>&#160;<span class="preprocessor">#if defined(__i386__) || defined(__x86_64__)</span></div><div class="line"><a name="l00061"></a><span class="lineno">   61</span>&#160;<span class="preprocessor">#define cpu_relax() asm volatile(&quot;rep; nop&quot; ::: &quot;memory&quot;);</span></div><div class="line"><a name="l00062"></a><span class="lineno">   62</span>&#160;</div><div class="line"><a name="l00063"></a><span class="lineno">   63</span>&#160;<span class="preprocessor">#elif defined(__arm__) || defined(__mips__)</span></div><div class="line"><a name="l00064"></a><span class="lineno">   64</span>&#160;<span class="preprocessor">    #define cpu_relax() asm volatile(&quot;&quot;:::&quot;memory&quot;)</span></div><div class="line"><a name="l00065"></a><span class="lineno">   65</span>&#160;</div><div class="line"><a name="l00066"></a><span class="lineno">   66</span>&#160;<span class="preprocessor">#elif defined(__aarch64__)</span></div><div class="line"><a name="l00067"></a><span class="lineno">   67</span>&#160;<span class="preprocessor">#define cpu_relax() asm volatile(&quot;yield&quot; ::: &quot;memory&quot;)</span></div><div class="line"><a name="l00068"></a><span class="lineno">   68</span>&#160;</div><div class="line"><a name="l00069"></a><span class="lineno">   69</span>&#160;<span class="preprocessor">#else</span></div><div class="line"><a name="l00070"></a><span class="lineno">   70</span>&#160;<span class="preprocessor">#error &quot;cpu_relax is not defined for this architecture&quot;</span></div><div class="line"><a name="l00071"></a><span class="lineno">   71</span>&#160;<span class="preprocessor">#endif</span></div><div class="line"><a name="l00072"></a><span class="lineno">   72</span>&#160;</div><div class="line"><a name="l00073"></a><span class="lineno">   73</span>&#160;}</div><div class="line"><a name="l00074"></a><span class="lineno">   74</span>&#160;</div><div class="line"><a name="l00075"></a><span class="lineno">   75</span>&#160;<span class="preprocessor">#endif //OBOE_STABILIZEDCALLBACK_H</span></div><div class="ttc" id="classoboe_1_1_stabilized_callback_html_ad447e12ebf732cf151655c1fbaf58a49"><div class="ttname"><a href="classoboe_1_1_stabilized_callback.html#ad447e12ebf732cf151655c1fbaf58a49">oboe::StabilizedCallback::onAudioReady</a></div><div class="ttdeci">DataCallbackResult onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numFrames) override</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_callback_html"><div class="ttname"><a href="classoboe_1_1_audio_stream_callback.html">oboe::AudioStreamCallback</a></div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:181</div></div>
-<div class="ttc" id="namespaceoboe_html_af85fc9910a287df6c5df0ed396bb75cd"><div class="ttname"><a href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">oboe::DataCallbackResult</a></div><div class="ttdeci">DataCallbackResult</div><div class="ttdef"><b>Definition:</b> Definitions.h:119</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_error_callback_html_a76bd3ef3e00396e10c21812003654cfe"><div class="ttname"><a href="classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe">oboe::AudioStreamErrorCallback::onErrorAfterClose</a></div><div class="ttdeci">virtual void onErrorAfterClose(AudioStream *, Result)</div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:163</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_html"><div class="ttname"><a href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:44</div></div>
-<div class="ttc" id="namespaceoboe_html_a486512e787b609c80ba4436f23929af1"><div class="ttname"><a href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a></div><div class="ttdeci">Result</div><div class="ttdef"><b>Definition:</b> Definitions.h:131</div></div>
-<div class="ttc" id="classoboe_1_1_stabilized_callback_html"><div class="ttname"><a href="classoboe_1_1_stabilized_callback.html">oboe::StabilizedCallback</a></div><div class="ttdef"><b>Definition:</b> StabilizedCallback.h:25</div></div>
-<div class="ttc" id="namespaceoboe_html"><div class="ttname"><a href="namespaceoboe.html">oboe</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:31</div></div>
-<div class="ttc" id="classoboe_1_1_stabilized_callback_html_af7521da42c4b08a71e6102994f6f41f4"><div class="ttname"><a href="classoboe_1_1_stabilized_callback.html#af7521da42c4b08a71e6102994f6f41f4">oboe::StabilizedCallback::onErrorAfterClose</a></div><div class="ttdeci">void onErrorAfterClose(AudioStream *oboeStream, Result error) override</div><div class="ttdef"><b>Definition:</b> StabilizedCallback.h:37</div></div>
-<div class="ttc" id="classoboe_1_1_stabilized_callback_html_a7ec0e9fca3181962ab78716bcda83e10"><div class="ttname"><a href="classoboe_1_1_stabilized_callback.html#a7ec0e9fca3181962ab78716bcda83e10">oboe::StabilizedCallback::onErrorBeforeClose</a></div><div class="ttdeci">void onErrorBeforeClose(AudioStream *oboeStream, Result error) override</div><div class="ttdef"><b>Definition:</b> StabilizedCallback.h:33</div></div>
-<div class="ttc" id="classoboe_1_1_audio_stream_error_callback_html_a4eb1e4916b71d8231e97b19898bc9bf0"><div class="ttname"><a href="classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0">oboe::AudioStreamErrorCallback::onErrorBeforeClose</a></div><div class="ttdeci">virtual void onErrorBeforeClose(AudioStream *, Result)</div><div class="ttdef"><b>Definition:</b> AudioStreamCallback.h:147</div></div>
-</div><!-- fragment --></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/_utilities_8h_source.html b/docs/reference/_utilities_8h_source.html
deleted file mode 100644
index 3b508ae..0000000
--- a/docs/reference/_utilities_8h_source.html
+++ /dev/null
@@ -1,91 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: include/oboe/Utilities.h Source File</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="dir_d44c64559bbebec7f509842c48db8b23.html">include</a></li><li class="navelem"><a class="el" href="dir_768f6301d9838e45d679001914ab2803.html">oboe</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">Utilities.h</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;<span class="comment">/*</span></div><div class="line"><a name="l00002"></a><span class="lineno">    2</span>&#160;<span class="comment"> * Copyright 2016 The Android Open Source Project</span></div><div class="line"><a name="l00003"></a><span class="lineno">    3</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00004"></a><span class="lineno">    4</span>&#160;<span class="comment"> * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></div><div class="line"><a name="l00005"></a><span class="lineno">    5</span>&#160;<span class="comment"> * you may not use this file except in compliance with the License.</span></div><div class="line"><a name="l00006"></a><span class="lineno">    6</span>&#160;<span class="comment"> * You may obtain a copy of the License at</span></div><div class="line"><a name="l00007"></a><span class="lineno">    7</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00008"></a><span class="lineno">    8</span>&#160;<span class="comment"> *      http://www.apache.org/licenses/LICENSE-2.0</span></div><div class="line"><a name="l00009"></a><span class="lineno">    9</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00010"></a><span class="lineno">   10</span>&#160;<span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></div><div class="line"><a name="l00011"></a><span class="lineno">   11</span>&#160;<span class="comment"> * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</span></div><div class="line"><a name="l00012"></a><span class="lineno">   12</span>&#160;<span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></div><div class="line"><a name="l00013"></a><span class="lineno">   13</span>&#160;<span class="comment"> * See the License for the specific language governing permissions and</span></div><div class="line"><a name="l00014"></a><span class="lineno">   14</span>&#160;<span class="comment"> * limitations under the License.</span></div><div class="line"><a name="l00015"></a><span class="lineno">   15</span>&#160;<span class="comment"> */</span></div><div class="line"><a name="l00016"></a><span class="lineno">   16</span>&#160;</div><div class="line"><a name="l00017"></a><span class="lineno">   17</span>&#160;<span class="preprocessor">#ifndef OBOE_UTILITIES_H</span></div><div class="line"><a name="l00018"></a><span class="lineno">   18</span>&#160;<span class="preprocessor">#define OBOE_UTILITIES_H</span></div><div class="line"><a name="l00019"></a><span class="lineno">   19</span>&#160;</div><div class="line"><a name="l00020"></a><span class="lineno">   20</span>&#160;<span class="preprocessor">#include &lt;unistd.h&gt;</span></div><div class="line"><a name="l00021"></a><span class="lineno">   21</span>&#160;<span class="preprocessor">#include &lt;sys/types.h&gt;</span></div><div class="line"><a name="l00022"></a><span class="lineno">   22</span>&#160;<span class="preprocessor">#include &lt;string&gt;</span></div><div class="line"><a name="l00023"></a><span class="lineno">   23</span>&#160;<span class="preprocessor">#include &quot;oboe/Definitions.h&quot;</span></div><div class="line"><a name="l00024"></a><span class="lineno">   24</span>&#160;</div><div class="line"><a name="l00025"></a><span class="lineno">   25</span>&#160;<span class="keyword">namespace </span><a class="code" href="namespaceoboe.html">oboe</a> {</div><div class="line"><a name="l00026"></a><span class="lineno">   26</span>&#160;</div><div class="line"><a name="l00034"></a><span class="lineno">   34</span>&#160;<span class="keywordtype">void</span> <a class="code" href="namespaceoboe.html#adbda063116feb9fa98a31ee820170060">convertFloatToPcm16</a>(<span class="keyword">const</span> <span class="keywordtype">float</span> *source, int16_t *destination, int32_t numSamples);</div><div class="line"><a name="l00035"></a><span class="lineno">   35</span>&#160;</div><div class="line"><a name="l00043"></a><span class="lineno">   43</span>&#160;<span class="keywordtype">void</span> <a class="code" href="namespaceoboe.html#ad17bee42828d13f2ef62a889e175c643">convertPcm16ToFloat</a>(<span class="keyword">const</span> int16_t *source, <span class="keywordtype">float</span> *destination, int32_t numSamples);</div><div class="line"><a name="l00044"></a><span class="lineno">   44</span>&#160;</div><div class="line"><a name="l00048"></a><span class="lineno">   48</span>&#160;int32_t <a class="code" href="namespaceoboe.html#ac67383a3df0f6e7a51f8415ffd9fdaca">convertFormatToSizeInBytes</a>(<a class="code" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a> format);</div><div class="line"><a name="l00049"></a><span class="lineno">   49</span>&#160;</div><div class="line"><a name="l00059"></a><span class="lineno">   59</span>&#160;<span class="keyword">template</span> &lt;<span class="keyword">typename</span> FromType&gt;</div><div class="line"><a name="l00060"></a><span class="lineno">   60</span>&#160;<span class="keyword">const</span> <span class="keywordtype">char</span> * <a class="code" href="namespaceoboe.html#af65aaea3c5d82eee6906664d61c094b3">convertToText</a>(FromType input);</div><div class="line"><a name="l00061"></a><span class="lineno">   61</span>&#160;</div><div class="line"><a name="l00066"></a><span class="lineno">   66</span>&#160;std::string <a class="code" href="namespaceoboe.html#a1ff1f1323d722494dac353a6b4d1bd5b">getPropertyString</a>(<span class="keyword">const</span> <span class="keywordtype">char</span> * name);</div><div class="line"><a name="l00067"></a><span class="lineno">   67</span>&#160;</div><div class="line"><a name="l00073"></a><span class="lineno">   73</span>&#160;<span class="keywordtype">int</span> <a class="code" href="namespaceoboe.html#a4284cffcf4d852ca4f357429303d7af5">getPropertyInteger</a>(<span class="keyword">const</span> <span class="keywordtype">char</span> * name, <span class="keywordtype">int</span> defaultValue);</div><div class="line"><a name="l00074"></a><span class="lineno">   74</span>&#160;</div><div class="line"><a name="l00083"></a><span class="lineno">   83</span>&#160;<span class="keywordtype">int</span> <a class="code" href="namespaceoboe.html#a54528938e9fccab7ad8947ccf0e409db">getSdkVersion</a>();</div><div class="line"><a name="l00084"></a><span class="lineno">   84</span>&#160;</div><div class="line"><a name="l00085"></a><span class="lineno">   85</span>&#160;} <span class="comment">// namespace oboe</span></div><div class="line"><a name="l00086"></a><span class="lineno">   86</span>&#160;</div><div class="line"><a name="l00087"></a><span class="lineno">   87</span>&#160;<span class="preprocessor">#endif //OBOE_UTILITIES_H</span></div><div class="ttc" id="namespaceoboe_html_adbda063116feb9fa98a31ee820170060"><div class="ttname"><a href="namespaceoboe.html#adbda063116feb9fa98a31ee820170060">oboe::convertFloatToPcm16</a></div><div class="ttdeci">void convertFloatToPcm16(const float *source, int16_t *destination, int32_t numSamples)</div></div>
-<div class="ttc" id="namespaceoboe_html_af65aaea3c5d82eee6906664d61c094b3"><div class="ttname"><a href="namespaceoboe.html#af65aaea3c5d82eee6906664d61c094b3">oboe::convertToText</a></div><div class="ttdeci">const char * convertToText(FromType input)</div></div>
-<div class="ttc" id="namespaceoboe_html_a1ff1f1323d722494dac353a6b4d1bd5b"><div class="ttname"><a href="namespaceoboe.html#a1ff1f1323d722494dac353a6b4d1bd5b">oboe::getPropertyString</a></div><div class="ttdeci">std::string getPropertyString(const char *name)</div></div>
-<div class="ttc" id="namespaceoboe_html_a4284cffcf4d852ca4f357429303d7af5"><div class="ttname"><a href="namespaceoboe.html#a4284cffcf4d852ca4f357429303d7af5">oboe::getPropertyInteger</a></div><div class="ttdeci">int getPropertyInteger(const char *name, int defaultValue)</div></div>
-<div class="ttc" id="namespaceoboe_html_ad17bee42828d13f2ef62a889e175c643"><div class="ttname"><a href="namespaceoboe.html#ad17bee42828d13f2ef62a889e175c643">oboe::convertPcm16ToFloat</a></div><div class="ttdeci">void convertPcm16ToFloat(const int16_t *source, float *destination, int32_t numSamples)</div></div>
-<div class="ttc" id="namespaceoboe_html_a92afc593e856571aacbfd02e57075df6"><div class="ttname"><a href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">oboe::AudioFormat</a></div><div class="ttdeci">AudioFormat</div><div class="ttdef"><b>Definition:</b> Definitions.h:94</div></div>
-<div class="ttc" id="namespaceoboe_html_ac67383a3df0f6e7a51f8415ffd9fdaca"><div class="ttname"><a href="namespaceoboe.html#ac67383a3df0f6e7a51f8415ffd9fdaca">oboe::convertFormatToSizeInBytes</a></div><div class="ttdeci">int32_t convertFormatToSizeInBytes(AudioFormat format)</div></div>
-<div class="ttc" id="namespaceoboe_html"><div class="ttname"><a href="namespaceoboe.html">oboe</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:31</div></div>
-<div class="ttc" id="namespaceoboe_html_a54528938e9fccab7ad8947ccf0e409db"><div class="ttname"><a href="namespaceoboe.html#a54528938e9fccab7ad8947ccf0e409db">oboe::getSdkVersion</a></div><div class="ttdeci">int getSdkVersion()</div></div>
-</div><!-- fragment --></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/_version_8h_source.html b/docs/reference/_version_8h_source.html
deleted file mode 100644
index db8a456..0000000
--- a/docs/reference/_version_8h_source.html
+++ /dev/null
@@ -1,89 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: include/oboe/Version.h Source File</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="dir_d44c64559bbebec7f509842c48db8b23.html">include</a></li><li class="navelem"><a class="el" href="dir_768f6301d9838e45d679001914ab2803.html">oboe</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">Version.h</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;<span class="comment">/*</span></div><div class="line"><a name="l00002"></a><span class="lineno">    2</span>&#160;<span class="comment"> * Copyright 2017 The Android Open Source Project</span></div><div class="line"><a name="l00003"></a><span class="lineno">    3</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00004"></a><span class="lineno">    4</span>&#160;<span class="comment"> * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></div><div class="line"><a name="l00005"></a><span class="lineno">    5</span>&#160;<span class="comment"> * you may not use this file except in compliance with the License.</span></div><div class="line"><a name="l00006"></a><span class="lineno">    6</span>&#160;<span class="comment"> * You may obtain a copy of the License at</span></div><div class="line"><a name="l00007"></a><span class="lineno">    7</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00008"></a><span class="lineno">    8</span>&#160;<span class="comment"> *      http://www.apache.org/licenses/LICENSE-2.0</span></div><div class="line"><a name="l00009"></a><span class="lineno">    9</span>&#160;<span class="comment"> *</span></div><div class="line"><a name="l00010"></a><span class="lineno">   10</span>&#160;<span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></div><div class="line"><a name="l00011"></a><span class="lineno">   11</span>&#160;<span class="comment"> * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</span></div><div class="line"><a name="l00012"></a><span class="lineno">   12</span>&#160;<span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></div><div class="line"><a name="l00013"></a><span class="lineno">   13</span>&#160;<span class="comment"> * See the License for the specific language governing permissions and</span></div><div class="line"><a name="l00014"></a><span class="lineno">   14</span>&#160;<span class="comment"> * limitations under the License.</span></div><div class="line"><a name="l00015"></a><span class="lineno">   15</span>&#160;<span class="comment"> */</span></div><div class="line"><a name="l00016"></a><span class="lineno">   16</span>&#160;</div><div class="line"><a name="l00017"></a><span class="lineno">   17</span>&#160;<span class="preprocessor">#ifndef OBOE_VERSIONINFO_H</span></div><div class="line"><a name="l00018"></a><span class="lineno">   18</span>&#160;<span class="preprocessor">#define OBOE_VERSIONINFO_H</span></div><div class="line"><a name="l00019"></a><span class="lineno">   19</span>&#160;</div><div class="line"><a name="l00020"></a><span class="lineno">   20</span>&#160;<span class="preprocessor">#include &lt;cstdint&gt;</span></div><div class="line"><a name="l00021"></a><span class="lineno">   21</span>&#160;</div><div class="line"><a name="l00033"></a><span class="lineno">   33</span>&#160;<span class="comment">// Type: 8-bit unsigned int. Min value: 0 Max value: 255. See below for description.</span></div><div class="line"><a name="l00034"></a><span class="lineno">   34</span>&#160;<span class="preprocessor">#define OBOE_VERSION_MAJOR 1</span></div><div class="line"><a name="l00035"></a><span class="lineno">   35</span>&#160;</div><div class="line"><a name="l00036"></a><span class="lineno">   36</span>&#160;<span class="comment">// Type: 8-bit unsigned int. Min value: 0 Max value: 255. See below for description.</span></div><div class="line"><a name="l00037"></a><span class="lineno">   37</span>&#160;<span class="preprocessor">#define OBOE_VERSION_MINOR 5</span></div><div class="line"><a name="l00038"></a><span class="lineno">   38</span>&#160;</div><div class="line"><a name="l00039"></a><span class="lineno">   39</span>&#160;<span class="comment">// Type: 16-bit unsigned int. Min value: 0 Max value: 65535. See below for description.</span></div><div class="line"><a name="l00040"></a><span class="lineno">   40</span>&#160;<span class="preprocessor">#define OBOE_VERSION_PATCH 0</span></div><div class="line"><a name="l00041"></a><span class="lineno">   41</span>&#160;</div><div class="line"><a name="l00042"></a><span class="lineno">   42</span>&#160;<span class="preprocessor">#define OBOE_STRINGIFY(x) #x</span></div><div class="line"><a name="l00043"></a><span class="lineno">   43</span>&#160;<span class="preprocessor">#define OBOE_TOSTRING(x) OBOE_STRINGIFY(x)</span></div><div class="line"><a name="l00044"></a><span class="lineno">   44</span>&#160;</div><div class="line"><a name="l00045"></a><span class="lineno">   45</span>&#160;<span class="comment">// Type: String literal. See below for description.</span></div><div class="line"><a name="l00046"></a><span class="lineno">   46</span>&#160;<span class="preprocessor">#define OBOE_VERSION_TEXT \</span></div><div class="line"><a name="l00047"></a><span class="lineno">   47</span>&#160;<span class="preprocessor">        OBOE_TOSTRING(OBOE_VERSION_MAJOR) &quot;.&quot; \</span></div><div class="line"><a name="l00048"></a><span class="lineno">   48</span>&#160;<span class="preprocessor">        OBOE_TOSTRING(OBOE_VERSION_MINOR) &quot;.&quot; \</span></div><div class="line"><a name="l00049"></a><span class="lineno">   49</span>&#160;<span class="preprocessor">        OBOE_TOSTRING(OBOE_VERSION_PATCH)</span></div><div class="line"><a name="l00050"></a><span class="lineno">   50</span>&#160;</div><div class="line"><a name="l00051"></a><span class="lineno">   51</span>&#160;<span class="comment">// Type: 32-bit unsigned int. See below for description.</span></div><div class="line"><a name="l00052"></a><span class="lineno">   52</span>&#160;<span class="preprocessor">#define OBOE_VERSION_NUMBER ((OBOE_VERSION_MAJOR &lt;&lt; 24) | (OBOE_VERSION_MINOR &lt;&lt; 16) | OBOE_VERSION_PATCH)</span></div><div class="line"><a name="l00053"></a><span class="lineno">   53</span>&#160;</div><div class="line"><a name="l00054"></a><span class="lineno">   54</span>&#160;<span class="keyword">namespace </span><a class="code" href="namespaceoboe.html">oboe</a> {</div><div class="line"><a name="l00055"></a><span class="lineno">   55</span>&#160;</div><div class="line"><a name="l00056"></a><span class="lineno">   56</span>&#160;<span class="keyword">const</span> <span class="keywordtype">char</span> * getVersionText();</div><div class="line"><a name="l00057"></a><span class="lineno">   57</span>&#160;</div><div class="line"><a name="l00061"></a><span class="lineno"><a class="line" href="structoboe_1_1_version.html">   61</a></span>&#160;<span class="keyword">struct </span><a class="code" href="structoboe_1_1_version.html">Version</a> {</div><div class="line"><a name="l00065"></a><span class="lineno"><a class="line" href="structoboe_1_1_version.html#a270f2e92582d5187be339eeda8e2b276">   65</a></span>&#160;    <span class="keyword">static</span> constexpr uint8_t <a class="code" href="structoboe_1_1_version.html#a270f2e92582d5187be339eeda8e2b276">Major</a> = OBOE_VERSION_MAJOR;</div><div class="line"><a name="l00066"></a><span class="lineno">   66</span>&#160;</div><div class="line"><a name="l00071"></a><span class="lineno"><a class="line" href="structoboe_1_1_version.html#ae460bb95e3a9099696205a35fffb5469">   71</a></span>&#160;    <span class="keyword">static</span> constexpr uint8_t <a class="code" href="structoboe_1_1_version.html#ae460bb95e3a9099696205a35fffb5469">Minor</a> = OBOE_VERSION_MINOR;</div><div class="line"><a name="l00072"></a><span class="lineno">   72</span>&#160;</div><div class="line"><a name="l00077"></a><span class="lineno"><a class="line" href="structoboe_1_1_version.html#a690110f2b3e887892da8f29ab5c057b2">   77</a></span>&#160;    <span class="keyword">static</span> constexpr uint16_t <a class="code" href="structoboe_1_1_version.html#a690110f2b3e887892da8f29ab5c057b2">Patch</a> = OBOE_VERSION_PATCH;</div><div class="line"><a name="l00078"></a><span class="lineno">   78</span>&#160;</div><div class="line"><a name="l00082"></a><span class="lineno"><a class="line" href="structoboe_1_1_version.html#a2c86e578b827fbca5f40c460a7754503">   82</a></span>&#160;    <span class="keyword">static</span> constexpr <span class="keyword">const</span> <span class="keywordtype">char</span> * <a class="code" href="structoboe_1_1_version.html#a2c86e578b827fbca5f40c460a7754503">Text</a> = OBOE_VERSION_TEXT;</div><div class="line"><a name="l00083"></a><span class="lineno">   83</span>&#160;</div><div class="line"><a name="l00088"></a><span class="lineno"><a class="line" href="structoboe_1_1_version.html#ac579661e79bcee45dc676d4647891de0">   88</a></span>&#160;    <span class="keyword">static</span> constexpr uint32_t <a class="code" href="structoboe_1_1_version.html#ac579661e79bcee45dc676d4647891de0">Number</a> = OBOE_VERSION_NUMBER;</div><div class="line"><a name="l00089"></a><span class="lineno">   89</span>&#160;};</div><div class="line"><a name="l00090"></a><span class="lineno">   90</span>&#160;</div><div class="line"><a name="l00091"></a><span class="lineno">   91</span>&#160;} <span class="comment">// namespace oboe</span></div><div class="line"><a name="l00092"></a><span class="lineno">   92</span>&#160;<span class="preprocessor">#endif //OBOE_VERSIONINFO_H</span></div><div class="ttc" id="structoboe_1_1_version_html"><div class="ttname"><a href="structoboe_1_1_version.html">oboe::Version</a></div><div class="ttdef"><b>Definition:</b> Version.h:61</div></div>
-<div class="ttc" id="structoboe_1_1_version_html_ae460bb95e3a9099696205a35fffb5469"><div class="ttname"><a href="structoboe_1_1_version.html#ae460bb95e3a9099696205a35fffb5469">oboe::Version::Minor</a></div><div class="ttdeci">static constexpr uint8_t Minor</div><div class="ttdef"><b>Definition:</b> Version.h:71</div></div>
-<div class="ttc" id="structoboe_1_1_version_html_a270f2e92582d5187be339eeda8e2b276"><div class="ttname"><a href="structoboe_1_1_version.html#a270f2e92582d5187be339eeda8e2b276">oboe::Version::Major</a></div><div class="ttdeci">static constexpr uint8_t Major</div><div class="ttdef"><b>Definition:</b> Version.h:65</div></div>
-<div class="ttc" id="structoboe_1_1_version_html_ac579661e79bcee45dc676d4647891de0"><div class="ttname"><a href="structoboe_1_1_version.html#ac579661e79bcee45dc676d4647891de0">oboe::Version::Number</a></div><div class="ttdeci">static constexpr uint32_t Number</div><div class="ttdef"><b>Definition:</b> Version.h:88</div></div>
-<div class="ttc" id="structoboe_1_1_version_html_a2c86e578b827fbca5f40c460a7754503"><div class="ttname"><a href="structoboe_1_1_version.html#a2c86e578b827fbca5f40c460a7754503">oboe::Version::Text</a></div><div class="ttdeci">static constexpr const char * Text</div><div class="ttdef"><b>Definition:</b> Version.h:82</div></div>
-<div class="ttc" id="namespaceoboe_html"><div class="ttname"><a href="namespaceoboe.html">oboe</a></div><div class="ttdef"><b>Definition:</b> AudioStream.h:31</div></div>
-<div class="ttc" id="structoboe_1_1_version_html_a690110f2b3e887892da8f29ab5c057b2"><div class="ttname"><a href="structoboe_1_1_version.html#a690110f2b3e887892da8f29ab5c057b2">oboe::Version::Patch</a></div><div class="ttdeci">static constexpr uint16_t Patch</div><div class="ttdef"><b>Definition:</b> Version.h:77</div></div>
-</div><!-- fragment --></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/annotated.html b/docs/reference/annotated.html
deleted file mode 100644
index 2fdbca7..0000000
--- a/docs/reference/annotated.html
+++ /dev/null
@@ -1,97 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Class List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="header">
-  <div class="headertitle">
-<div class="title">Class List</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="textblock">Here are the classes, structs, unions and interfaces with brief descriptions:</div><div class="directory">
-<div class="levels">[detail level <span onclick="javascript:toggleLevel(1);">1</span><span onclick="javascript:toggleLevel(2);">2</span>]</div><table class="directory">
-<tr id="row_0_" class="even"><td class="entry"><span style="width:0px;display:inline-block;">&#160;</span><span id="arr_0_" class="arrow" onclick="toggleFolder('0_')">&#9660;</span><span class="icona"><span class="icon">N</span></span><a class="el" href="namespaceoboe.html" target="_self">oboe</a></td><td class="desc"></td></tr>
-<tr id="row_0_0_"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_audio_stream.html" target="_self">AudioStream</a></td><td class="desc"></td></tr>
-<tr id="row_0_1_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_audio_stream_base.html" target="_self">AudioStreamBase</a></td><td class="desc"></td></tr>
-<tr id="row_0_2_"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_audio_stream_builder.html" target="_self">AudioStreamBuilder</a></td><td class="desc"></td></tr>
-<tr id="row_0_3_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_audio_stream_callback.html" target="_self">AudioStreamCallback</a></td><td class="desc"></td></tr>
-<tr id="row_0_4_"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_audio_stream_data_callback.html" target="_self">AudioStreamDataCallback</a></td><td class="desc"></td></tr>
-<tr id="row_0_5_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_audio_stream_error_callback.html" target="_self">AudioStreamErrorCallback</a></td><td class="desc"></td></tr>
-<tr id="row_0_6_"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_default_stream_values.html" target="_self">DefaultStreamValues</a></td><td class="desc"></td></tr>
-<tr id="row_0_7_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structoboe_1_1_frame_timestamp.html" target="_self">FrameTimestamp</a></td><td class="desc"></td></tr>
-<tr id="row_0_8_"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_latency_tuner.html" target="_self">LatencyTuner</a></td><td class="desc"></td></tr>
-<tr id="row_0_9_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_oboe_globals.html" target="_self">OboeGlobals</a></td><td class="desc"></td></tr>
-<tr id="row_0_10_"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_result_with_value.html" target="_self">ResultWithValue</a></td><td class="desc"></td></tr>
-<tr id="row_0_11_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_stabilized_callback.html" target="_self">StabilizedCallback</a></td><td class="desc"></td></tr>
-<tr id="row_0_12_"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structoboe_1_1_stream_deleter_functor.html" target="_self">StreamDeleterFunctor</a></td><td class="desc"></td></tr>
-<tr id="row_0_13_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structoboe_1_1_version.html" target="_self">Version</a></td><td class="desc"></td></tr>
-</table>
-</div><!-- directory -->
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/bc_s.png b/docs/reference/bc_s.png
deleted file mode 100644
index 224b29a..0000000
--- a/docs/reference/bc_s.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/bdwn.png b/docs/reference/bdwn.png
deleted file mode 100644
index 940a0b9..0000000
--- a/docs/reference/bdwn.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/classes.html b/docs/reference/classes.html
deleted file mode 100644
index 8209573..0000000
--- a/docs/reference/classes.html
+++ /dev/null
@@ -1,99 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Class Index</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="header">
-  <div class="headertitle">
-<div class="title">Class Index</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="qindex"><a class="qindex" href="#letter_a">a</a>&#160;|&#160;<a class="qindex" href="#letter_d">d</a>&#160;|&#160;<a class="qindex" href="#letter_f">f</a>&#160;|&#160;<a class="qindex" href="#letter_l">l</a>&#160;|&#160;<a class="qindex" href="#letter_o">o</a>&#160;|&#160;<a class="qindex" href="#letter_r">r</a>&#160;|&#160;<a class="qindex" href="#letter_s">s</a>&#160;|&#160;<a class="qindex" href="#letter_v">v</a></div>
-<table class="classindex">
-<tr><td rowspan="2" valign="bottom"><a name="letter_a"></a><table border="0" cellspacing="0" cellpadding="0"><tr><td><div class="ah">&#160;&#160;a&#160;&#160;</div></td></tr></table>
-</td><td valign="top"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> (<a class="el" href="namespaceoboe.html">oboe</a>)&#160;&#160;&#160;</td><td rowspan="2" valign="bottom"><a name="letter_l"></a><table border="0" cellspacing="0" cellpadding="0"><tr><td><div class="ah">&#160;&#160;l&#160;&#160;</div></td></tr></table>
-</td><td rowspan="2" valign="bottom"><a name="letter_r"></a><table border="0" cellspacing="0" cellpadding="0"><tr><td><div class="ah">&#160;&#160;r&#160;&#160;</div></td></tr></table>
-</td><td valign="top"><a class="el" href="structoboe_1_1_stream_deleter_functor.html">StreamDeleterFunctor</a> (<a class="el" href="namespaceoboe.html">oboe</a>)&#160;&#160;&#160;</td></tr>
-<tr><td></td><td valign="top"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a> (<a class="el" href="namespaceoboe.html">oboe</a>)&#160;&#160;&#160;</td><td></td><td></td><td rowspan="2" valign="bottom"><a name="letter_v"></a><table border="0" cellspacing="0" cellpadding="0"><tr><td><div class="ah">&#160;&#160;v&#160;&#160;</div></td></tr></table>
-</td></tr>
-<tr><td valign="top"><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> (<a class="el" href="namespaceoboe.html">oboe</a>)&#160;&#160;&#160;</td><td rowspan="2" valign="bottom"><a name="letter_d"></a><table border="0" cellspacing="0" cellpadding="0"><tr><td><div class="ah">&#160;&#160;d&#160;&#160;</div></td></tr></table>
-</td><td valign="top"><a class="el" href="classoboe_1_1_latency_tuner.html">LatencyTuner</a> (<a class="el" href="namespaceoboe.html">oboe</a>)&#160;&#160;&#160;</td><td valign="top"><a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> (<a class="el" href="namespaceoboe.html">oboe</a>)&#160;&#160;&#160;</td><td></td></tr>
-<tr><td valign="top"><a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> (<a class="el" href="namespaceoboe.html">oboe</a>)&#160;&#160;&#160;</td><td></td><td rowspan="2" valign="bottom"><a name="letter_o"></a><table border="0" cellspacing="0" cellpadding="0"><tr><td><div class="ah">&#160;&#160;o&#160;&#160;</div></td></tr></table>
-</td><td rowspan="2" valign="bottom"><a name="letter_s"></a><table border="0" cellspacing="0" cellpadding="0"><tr><td><div class="ah">&#160;&#160;s&#160;&#160;</div></td></tr></table>
-</td><td valign="top"><a class="el" href="structoboe_1_1_version.html">Version</a> (<a class="el" href="namespaceoboe.html">oboe</a>)&#160;&#160;&#160;</td></tr>
-<tr><td valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> (<a class="el" href="namespaceoboe.html">oboe</a>)&#160;&#160;&#160;</td><td valign="top"><a class="el" href="classoboe_1_1_default_stream_values.html">DefaultStreamValues</a> (<a class="el" href="namespaceoboe.html">oboe</a>)&#160;&#160;&#160;</td><td></td><td></td><td></td></tr>
-<tr><td valign="top"><a class="el" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a> (<a class="el" href="namespaceoboe.html">oboe</a>)&#160;&#160;&#160;</td><td rowspan="2" valign="bottom"><a name="letter_f"></a><table border="0" cellspacing="0" cellpadding="0"><tr><td><div class="ah">&#160;&#160;f&#160;&#160;</div></td></tr></table>
-</td><td valign="top"><a class="el" href="classoboe_1_1_oboe_globals.html">OboeGlobals</a> (<a class="el" href="namespaceoboe.html">oboe</a>)&#160;&#160;&#160;</td><td valign="top"><a class="el" href="classoboe_1_1_stabilized_callback.html">StabilizedCallback</a> (<a class="el" href="namespaceoboe.html">oboe</a>)&#160;&#160;&#160;</td><td></td></tr>
-<tr><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td></td><td valign="top"><a class="el" href="structoboe_1_1_frame_timestamp.html">FrameTimestamp</a> (<a class="el" href="namespaceoboe.html">oboe</a>)&#160;&#160;&#160;</td><td></td><td></td><td></td></tr>
-<tr><td></td><td></td><td></td><td></td><td></td></tr>
-</table>
-<div class="qindex"><a class="qindex" href="#letter_a">a</a>&#160;|&#160;<a class="qindex" href="#letter_d">d</a>&#160;|&#160;<a class="qindex" href="#letter_f">f</a>&#160;|&#160;<a class="qindex" href="#letter_l">l</a>&#160;|&#160;<a class="qindex" href="#letter_o">o</a>&#160;|&#160;<a class="qindex" href="#letter_r">r</a>&#160;|&#160;<a class="qindex" href="#letter_s">s</a>&#160;|&#160;<a class="qindex" href="#letter_v">v</a></div>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_audio_stream-members.html b/docs/reference/classoboe_1_1_audio_stream-members.html
deleted file mode 100644
index b00cb36..0000000
--- a/docs/reference/classoboe_1_1_audio_stream-members.html
+++ /dev/null
@@ -1,185 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Member List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe::AudioStream Member List</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p>This is the complete list of members for <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a>, including all inherited members.</p>
-<table class="directory">
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>AudioStream</b>() (defined in <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a8ebb587a07bf62c864fd62c63b241fd4">AudioStream</a>(const AudioStreamBuilder &amp;builder)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">explicit</span></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>AudioStreamBase</b>() (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa6b103e1b0f808bbc4949d56f0829f98">AudioStreamBase</a>(const AudioStreamBase &amp;)=default</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>AudioStreamBuilder</b> (defined in <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">friend</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#ae023cb001f3261d064f423101798d6be">calculateLatencyMillis</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a9c8ea30e30e513766d5e996c370eb8d8">close</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#ab7a8cfe5d6039386bc5850fd5ee9bd62">fireDataCallback</a>(void *audioData, int numFrames)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a32c25c0333eab3d65ce02275ad4acb3d">flush</a>(int64_t timeoutNanoseconds=kDefaultTimeoutNanos)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a2b7a3cee7444114843dbdd1fc705f6bb">getAudioApi</a>() const =0</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">pure virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#afa35ee4b8629fbffe26b9be7c7ed55d2">getAvailableFrames</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab1531253e64aaebe9e9eddbafb9098fc">getBufferCapacityInFrames</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#af5217ab05bfde0d7637024b599302d0b">getBufferSizeInFrames</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a5c01907a59d5f89a5e4b819fe66b08bc">getBytesPerFrame</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a44dda61e6e948e49b68f87172f084d62">getBytesPerSample</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a87e6bf37d6a2a5e983b8ca8d29aea575">getChannelCount</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab12e2d068fa87e0553b01a400d96eb82">getContentType</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a9fb2f34ae62dbda2c10e8513b754fa0c">getDataCallback</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a093057d625bc896864b959974c265f21">getDeviceId</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a6f86f2233a04c5a0b056f0c1c261f1b1">getDirection</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1328fb9288166ff325995ce1ea1867f0">getErrorCallback</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab1e640461d7bf9d596decb913da7ac86">getFormat</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#ac160acb656515814fa6fdd157c131a0a">getFramesPerBurst</a>()=0</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">pure virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a8878a90949badbb5486cc2e022a57086">getFramesPerCallback</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#abc3ee2815568b425d15a40e132aa8e38">getFramesPerDataCallback</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#aeebfc59abd978cd6dff07c16cfe266df">getFramesRead</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#ab43dd4074e1de57bac1c3fd111430341">getFramesWritten</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5c773b93b8aa38191c7199cab023428a">getInputPreset</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a8fe8afdf164a1fe835c514f709743d75">getLastErrorCallbackResult</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a2ddb935de0e24dd7ae8e2cfbecac9fdc">getPerformanceMode</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ae9d32f3e09174bad69e74f147ee33087">getSampleRate</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1de8d6982d411a0cf50a32efba0ca3f2">getSampleRateConversionQuality</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa3c502ce09bbad7690a2dd6acaf8892e">getSessionId</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1fb033fc963f971bd1aa8f6707e49b41">getSharingMode</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a9d37cc6513823c685ae892626ff83ea8">getState</a>() const =0</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">pure virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#acb8edbc17ff79993a8ed996d216fe6f3">getTimestamp</a>(clockid_t, int64_t *, int64_t *)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a49254e6b1b19cb6d0ca6c63058029771">getTimestamp</a>(clockid_t)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a5458d7130415eb4defe3dbc11d479e2f">getUnderlyingStream</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a0bcfb2f8bd11c92b541fd910da9af397">getUsage</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#ad1a1d3bbf3b348ed92b7ed18ce9cc261">getXRunCount</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa4ec3aa76e69350fbce6f00786211495">isChannelConversionAllowed</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#add85011ba825f74931deeb92c5edf831">isDataCallbackEnabled</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a9a54d38b985a2eb12c6972104dc0ce73">isDataCallbackSpecified</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aef579f6d1f779c89d051f0963f2976b3">isErrorCallbackSpecified</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ace3625a7332bf02a86818fdf63fcccb4">isFormatConversionAllowed</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5d5e07e98921d0193a5c0ccbe06f68c2">isValidConfig</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">protected</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a43d8a098440cde28f4ee8bedd6d107c4">isXRunCountSupported</a>() const =0</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">pure virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#aa5f4801cca6877eeaa4735b93933269d">launchStopThread</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>lockWeakThis</b>() (defined in <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6">mBufferCapacityInFrames</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a3b65595d26d1eae1b8ce9925a5b98f6a">mBufferSizeInFrames</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>mChannelConversionAllowed</b> (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">mChannelCount</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b">mContentType</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">mDataCallback</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8">mDeviceId</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880">mDirection</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">mErrorCallback</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>mErrorCallbackResult</b> (defined in <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">mFormat</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>mFormatConversionAllowed</b> (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a54061319ed348329a29d883a5de2482e">mFramesPerBurst</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899">mFramesPerCallback</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a07e82f9b9e2e4800f23ae9a7193c3b58">mFramesRead</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a88a63317b7c58815bac074976b00aa23">mFramesWritten</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589">mInputPreset</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>mLock</b> (defined in <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765">mPerformanceMode</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea">mSampleRate</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>mSampleRateConversionQuality</b> (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737">mSessionId</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473">mSharingMode</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c">mUsage</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>mWeakThis</b> (defined in <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a0ea79e60f5a3d29fc5a1a116aba11dfe">onDefaultCallback</a>(void *, int)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">protected</span><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a686c6ce8a29051c858fd1de386805dc6">open</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa9c987a59555d7a60b9f7a63f4afc7fc">operator=</a>(const AudioStreamBase &amp;)=default</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a04f29836748a8e5842aef2be200022ad">pause</a>(int64_t timeoutNanoseconds=kDefaultTimeoutNanos)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a8089f0a0cb68d4039cf33e6584129978">read</a>(void *, int32_t, int64_t)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a6bd5d633ff999e4da1faf3cd949aa602">requestFlush</a>()=0</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">pure virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a7f18bb3cc5490fd7fbc1f6da63c730f6">requestPause</a>()=0</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">pure virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a3c484e314dee8dfed1d419f487b5d601">requestStart</a>()=0</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">pure virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a820e634f741e6b5efdcef8104cecb919">requestStop</a>()=0</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">pure virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a06e3f9e133b3a75515e7793939d1cd03">setBufferSizeInFrames</a>(int32_t)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a0faa6d3a6fd4f367e6f80d5a29e6dcba">setDataCallbackEnabled</a>(bool enabled)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">protected</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>setWeakThis</b>(std::shared_ptr&lt; oboe::AudioStream &gt; &amp;sharedStream) (defined in <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#af04f03eb6b64b564f1c4401688987d21">start</a>(int64_t timeoutNanoseconds=kDefaultTimeoutNanos)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#aec093859d42f0470c884edd1e976d9f3">stop</a>(int64_t timeoutNanoseconds=kDefaultTimeoutNanos)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>swapDataCallback</b>(AudioStreamDataCallback *dataCallback) (defined in <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>swapErrorCallback</b>(AudioStreamErrorCallback *errorCallback) (defined in <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a462358ddab709c79d1a7968d6d55b727">updateFramesRead</a>()=0</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">pure virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a64ad978c5f70ced17ef5a96605496515">updateFramesWritten</a>()=0</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">pure virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a15cdaaaa4c1e8da322d6da33334c8147">usesAAudio</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#afddb0962863ccf9ec6672a042fe15941">waitForAvailableFrames</a>(int32_t numFrames, int64_t timeoutNanoseconds)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a0c865a5501f369d959c39d8ab8b46a07">waitForStateChange</a>(StreamState inputState, StreamState *nextState, int64_t timeoutNanoseconds)=0</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">pure virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a8adbacd6a55a94a532916ab037fba1d6">waitForStateTransition</a>(StreamState startingState, StreamState endingState, int64_t timeoutNanoseconds)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">protected</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#aa48da7bf28026b7cccee73e6b054af28">wasErrorCallbackCalled</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html#a3612c05ed6b01a213dde67d913c07e11">write</a>(const void *, int32_t, int64_t)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>~AudioStream</b>()=default (defined in <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>~AudioStreamBase</b>()=default (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-</table></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_audio_stream.html b/docs/reference/classoboe_1_1_audio_stream.html
deleted file mode 100644
index 20c89c6..0000000
--- a/docs/reference/classoboe_1_1_audio_stream.html
+++ /dev/null
@@ -1,1653 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe::AudioStream Class Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="#pub-methods">Public Member Functions</a> &#124;
-<a href="#pro-methods">Protected Member Functions</a> &#124;
-<a href="#pro-attribs">Protected Attributes</a> &#124;
-<a href="#friends">Friends</a> &#124;
-<a href="classoboe_1_1_audio_stream-members.html">List of all members</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe::AudioStream Class Reference<span class="mlabels"><span class="mlabel">abstract</span></span></div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p><code>#include &lt;<a class="el" href="_audio_stream_8h_source.html">AudioStream.h</a>&gt;</code></p>
-<div class="dynheader">
-Inheritance diagram for oboe::AudioStream:</div>
-<div class="dyncontent">
- <div class="center">
-  <img src="classoboe_1_1_audio_stream.png" usemap="#oboe::AudioStream_map" alt=""/>
-  <map id="oboe::AudioStream_map" name="oboe::AudioStream_map">
-<area href="classoboe_1_1_audio_stream_base.html" alt="oboe::AudioStreamBase" shape="rect" coords="0,0,146,24"/>
-  </map>
-</div></div>
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-methods"></a>
-Public Member Functions</h2></td></tr>
-<tr class="memitem:a8ebb587a07bf62c864fd62c63b241fd4"><td class="memItemLeft" align="right" valign="top">&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a8ebb587a07bf62c864fd62c63b241fd4">AudioStream</a> (const <a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> &amp;builder)</td></tr>
-<tr class="separator:a8ebb587a07bf62c864fd62c63b241fd4"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a686c6ce8a29051c858fd1de386805dc6"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a686c6ce8a29051c858fd1de386805dc6">open</a> ()</td></tr>
-<tr class="separator:a686c6ce8a29051c858fd1de386805dc6"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a9c8ea30e30e513766d5e996c370eb8d8"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a9c8ea30e30e513766d5e996c370eb8d8">close</a> ()</td></tr>
-<tr class="separator:a9c8ea30e30e513766d5e996c370eb8d8"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:af04f03eb6b64b564f1c4401688987d21"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#af04f03eb6b64b564f1c4401688987d21">start</a> (int64_t timeoutNanoseconds=<a class="el" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">kDefaultTimeoutNanos</a>)</td></tr>
-<tr class="separator:af04f03eb6b64b564f1c4401688987d21"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a04f29836748a8e5842aef2be200022ad"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a04f29836748a8e5842aef2be200022ad">pause</a> (int64_t timeoutNanoseconds=<a class="el" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">kDefaultTimeoutNanos</a>)</td></tr>
-<tr class="separator:a04f29836748a8e5842aef2be200022ad"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a32c25c0333eab3d65ce02275ad4acb3d"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a32c25c0333eab3d65ce02275ad4acb3d">flush</a> (int64_t timeoutNanoseconds=<a class="el" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">kDefaultTimeoutNanos</a>)</td></tr>
-<tr class="separator:a32c25c0333eab3d65ce02275ad4acb3d"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aec093859d42f0470c884edd1e976d9f3"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#aec093859d42f0470c884edd1e976d9f3">stop</a> (int64_t timeoutNanoseconds=<a class="el" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">kDefaultTimeoutNanos</a>)</td></tr>
-<tr class="separator:aec093859d42f0470c884edd1e976d9f3"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a3c484e314dee8dfed1d419f487b5d601"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a3c484e314dee8dfed1d419f487b5d601">requestStart</a> ()=0</td></tr>
-<tr class="separator:a3c484e314dee8dfed1d419f487b5d601"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a7f18bb3cc5490fd7fbc1f6da63c730f6"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a7f18bb3cc5490fd7fbc1f6da63c730f6">requestPause</a> ()=0</td></tr>
-<tr class="separator:a7f18bb3cc5490fd7fbc1f6da63c730f6"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a6bd5d633ff999e4da1faf3cd949aa602"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a6bd5d633ff999e4da1faf3cd949aa602">requestFlush</a> ()=0</td></tr>
-<tr class="separator:a6bd5d633ff999e4da1faf3cd949aa602"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a820e634f741e6b5efdcef8104cecb919"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a820e634f741e6b5efdcef8104cecb919">requestStop</a> ()=0</td></tr>
-<tr class="separator:a820e634f741e6b5efdcef8104cecb919"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a9d37cc6513823c685ae892626ff83ea8"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a9d37cc6513823c685ae892626ff83ea8">getState</a> () const =0</td></tr>
-<tr class="separator:a9d37cc6513823c685ae892626ff83ea8"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a0c865a5501f369d959c39d8ab8b46a07"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a0c865a5501f369d959c39d8ab8b46a07">waitForStateChange</a> (<a class="el" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a> inputState, <a class="el" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a> *nextState, int64_t timeoutNanoseconds)=0</td></tr>
-<tr class="separator:a0c865a5501f369d959c39d8ab8b46a07"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a06e3f9e133b3a75515e7793939d1cd03"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt; int32_t &gt;&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a06e3f9e133b3a75515e7793939d1cd03">setBufferSizeInFrames</a> (int32_t)</td></tr>
-<tr class="separator:a06e3f9e133b3a75515e7793939d1cd03"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ad1a1d3bbf3b348ed92b7ed18ce9cc261"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt; int32_t &gt;&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#ad1a1d3bbf3b348ed92b7ed18ce9cc261">getXRunCount</a> () const</td></tr>
-<tr class="separator:ad1a1d3bbf3b348ed92b7ed18ce9cc261"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a43d8a098440cde28f4ee8bedd6d107c4"><td class="memItemLeft" align="right" valign="top">virtual bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a43d8a098440cde28f4ee8bedd6d107c4">isXRunCountSupported</a> () const =0</td></tr>
-<tr class="separator:a43d8a098440cde28f4ee8bedd6d107c4"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ac160acb656515814fa6fdd157c131a0a"><td class="memItemLeft" align="right" valign="top">virtual int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#ac160acb656515814fa6fdd157c131a0a">getFramesPerBurst</a> ()=0</td></tr>
-<tr class="separator:ac160acb656515814fa6fdd157c131a0a"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5c01907a59d5f89a5e4b819fe66b08bc"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a5c01907a59d5f89a5e4b819fe66b08bc">getBytesPerFrame</a> () const</td></tr>
-<tr class="separator:a5c01907a59d5f89a5e4b819fe66b08bc"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a44dda61e6e948e49b68f87172f084d62"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a44dda61e6e948e49b68f87172f084d62">getBytesPerSample</a> () const</td></tr>
-<tr class="separator:a44dda61e6e948e49b68f87172f084d62"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab43dd4074e1de57bac1c3fd111430341"><td class="memItemLeft" align="right" valign="top">virtual int64_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#ab43dd4074e1de57bac1c3fd111430341">getFramesWritten</a> ()</td></tr>
-<tr class="separator:ab43dd4074e1de57bac1c3fd111430341"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aeebfc59abd978cd6dff07c16cfe266df"><td class="memItemLeft" align="right" valign="top">virtual int64_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#aeebfc59abd978cd6dff07c16cfe266df">getFramesRead</a> ()</td></tr>
-<tr class="separator:aeebfc59abd978cd6dff07c16cfe266df"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ae023cb001f3261d064f423101798d6be"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt; double &gt;&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#ae023cb001f3261d064f423101798d6be">calculateLatencyMillis</a> ()</td></tr>
-<tr class="separator:ae023cb001f3261d064f423101798d6be"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:acb8edbc17ff79993a8ed996d216fe6f3"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#acb8edbc17ff79993a8ed996d216fe6f3">getTimestamp</a> (clockid_t, int64_t *, int64_t *)</td></tr>
-<tr class="separator:acb8edbc17ff79993a8ed996d216fe6f3"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a49254e6b1b19cb6d0ca6c63058029771"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt; <a class="el" href="structoboe_1_1_frame_timestamp.html">FrameTimestamp</a> &gt;&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a49254e6b1b19cb6d0ca6c63058029771">getTimestamp</a> (clockid_t)</td></tr>
-<tr class="separator:a49254e6b1b19cb6d0ca6c63058029771"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a3612c05ed6b01a213dde67d913c07e11"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt; int32_t &gt;&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a3612c05ed6b01a213dde67d913c07e11">write</a> (const void *, int32_t, int64_t)</td></tr>
-<tr class="separator:a3612c05ed6b01a213dde67d913c07e11"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a8089f0a0cb68d4039cf33e6584129978"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt; int32_t &gt;&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a8089f0a0cb68d4039cf33e6584129978">read</a> (void *, int32_t, int64_t)</td></tr>
-<tr class="separator:a8089f0a0cb68d4039cf33e6584129978"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a2b7a3cee7444114843dbdd1fc705f6bb"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">AudioApi</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a2b7a3cee7444114843dbdd1fc705f6bb">getAudioApi</a> () const =0</td></tr>
-<tr class="separator:a2b7a3cee7444114843dbdd1fc705f6bb"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a15cdaaaa4c1e8da322d6da33334c8147"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a15cdaaaa4c1e8da322d6da33334c8147">usesAAudio</a> () const</td></tr>
-<tr class="separator:a15cdaaaa4c1e8da322d6da33334c8147"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5458d7130415eb4defe3dbc11d479e2f"><td class="memItemLeft" align="right" valign="top">virtual void *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a5458d7130415eb4defe3dbc11d479e2f">getUnderlyingStream</a> () const</td></tr>
-<tr class="separator:a5458d7130415eb4defe3dbc11d479e2f"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aa5f4801cca6877eeaa4735b93933269d"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#aa5f4801cca6877eeaa4735b93933269d">launchStopThread</a> ()</td></tr>
-<tr class="separator:aa5f4801cca6877eeaa4735b93933269d"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a64ad978c5f70ced17ef5a96605496515"><td class="memItemLeft" align="right" valign="top">virtual void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a64ad978c5f70ced17ef5a96605496515">updateFramesWritten</a> ()=0</td></tr>
-<tr class="separator:a64ad978c5f70ced17ef5a96605496515"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a462358ddab709c79d1a7968d6d55b727"><td class="memItemLeft" align="right" valign="top">virtual void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a462358ddab709c79d1a7968d6d55b727">updateFramesRead</a> ()=0</td></tr>
-<tr class="separator:a462358ddab709c79d1a7968d6d55b727"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab1748ad90d9ff9210f0fee19cea71224"><td class="memItemLeft" align="right" valign="top"><a id="ab1748ad90d9ff9210f0fee19cea71224"></a>
-<a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> *&#160;</td><td class="memItemRight" valign="bottom"><b>swapDataCallback</b> (<a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> *dataCallback)</td></tr>
-<tr class="separator:ab1748ad90d9ff9210f0fee19cea71224"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aa75bb1b45bee873715a674df5dac0ef9"><td class="memItemLeft" align="right" valign="top"><a id="aa75bb1b45bee873715a674df5dac0ef9"></a>
-<a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a> *&#160;</td><td class="memItemRight" valign="bottom"><b>swapErrorCallback</b> (<a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a> *errorCallback)</td></tr>
-<tr class="separator:aa75bb1b45bee873715a674df5dac0ef9"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:afa35ee4b8629fbffe26b9be7c7ed55d2"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt; int32_t &gt;&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#afa35ee4b8629fbffe26b9be7c7ed55d2">getAvailableFrames</a> ()</td></tr>
-<tr class="separator:afa35ee4b8629fbffe26b9be7c7ed55d2"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:afddb0962863ccf9ec6672a042fe15941"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt; int32_t &gt;&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#afddb0962863ccf9ec6672a042fe15941">waitForAvailableFrames</a> (int32_t numFrames, int64_t timeoutNanoseconds)</td></tr>
-<tr class="separator:afddb0962863ccf9ec6672a042fe15941"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a8fe8afdf164a1fe835c514f709743d75"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a8fe8afdf164a1fe835c514f709743d75">getLastErrorCallbackResult</a> () const</td></tr>
-<tr class="separator:a8fe8afdf164a1fe835c514f709743d75"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="inherit_header pub_methods_classoboe_1_1_audio_stream_base"><td colspan="2" onclick="javascript:toggleInherit('pub_methods_classoboe_1_1_audio_stream_base')"><img src="closed.png" alt="-"/>&#160;Public Member Functions inherited from <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td></tr>
-<tr class="memitem:aa6b103e1b0f808bbc4949d56f0829f98 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa6b103e1b0f808bbc4949d56f0829f98">AudioStreamBase</a> (const <a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> &amp;)=default</td></tr>
-<tr class="separator:aa6b103e1b0f808bbc4949d56f0829f98 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aa9c987a59555d7a60b9f7a63f4afc7fc inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> &amp;&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa9c987a59555d7a60b9f7a63f4afc7fc">operator=</a> (const <a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> &amp;)=default</td></tr>
-<tr class="separator:aa9c987a59555d7a60b9f7a63f4afc7fc inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a87e6bf37d6a2a5e983b8ca8d29aea575 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a87e6bf37d6a2a5e983b8ca8d29aea575">getChannelCount</a> () const</td></tr>
-<tr class="separator:a87e6bf37d6a2a5e983b8ca8d29aea575 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a6f86f2233a04c5a0b056f0c1c261f1b1 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a6f86f2233a04c5a0b056f0c1c261f1b1">getDirection</a> () const</td></tr>
-<tr class="separator:a6f86f2233a04c5a0b056f0c1c261f1b1 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ae9d32f3e09174bad69e74f147ee33087 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ae9d32f3e09174bad69e74f147ee33087">getSampleRate</a> () const</td></tr>
-<tr class="separator:ae9d32f3e09174bad69e74f147ee33087 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a8878a90949badbb5486cc2e022a57086 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a8878a90949badbb5486cc2e022a57086">getFramesPerCallback</a> () const</td></tr>
-<tr class="separator:a8878a90949badbb5486cc2e022a57086 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:abc3ee2815568b425d15a40e132aa8e38 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#abc3ee2815568b425d15a40e132aa8e38">getFramesPerDataCallback</a> () const</td></tr>
-<tr class="separator:abc3ee2815568b425d15a40e132aa8e38 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab1e640461d7bf9d596decb913da7ac86 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab1e640461d7bf9d596decb913da7ac86">getFormat</a> () const</td></tr>
-<tr class="separator:ab1e640461d7bf9d596decb913da7ac86 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:af5217ab05bfde0d7637024b599302d0b inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">virtual int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#af5217ab05bfde0d7637024b599302d0b">getBufferSizeInFrames</a> ()</td></tr>
-<tr class="separator:af5217ab05bfde0d7637024b599302d0b inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab1531253e64aaebe9e9eddbafb9098fc inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">virtual int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab1531253e64aaebe9e9eddbafb9098fc">getBufferCapacityInFrames</a> () const</td></tr>
-<tr class="separator:ab1531253e64aaebe9e9eddbafb9098fc inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a1fb033fc963f971bd1aa8f6707e49b41 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1fb033fc963f971bd1aa8f6707e49b41">getSharingMode</a> () const</td></tr>
-<tr class="separator:a1fb033fc963f971bd1aa8f6707e49b41 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a2ddb935de0e24dd7ae8e2cfbecac9fdc inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a2ddb935de0e24dd7ae8e2cfbecac9fdc">getPerformanceMode</a> () const</td></tr>
-<tr class="separator:a2ddb935de0e24dd7ae8e2cfbecac9fdc inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a093057d625bc896864b959974c265f21 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a093057d625bc896864b959974c265f21">getDeviceId</a> () const</td></tr>
-<tr class="separator:a093057d625bc896864b959974c265f21 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a9fb2f34ae62dbda2c10e8513b754fa0c inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a9fb2f34ae62dbda2c10e8513b754fa0c">getDataCallback</a> () const</td></tr>
-<tr class="separator:a9fb2f34ae62dbda2c10e8513b754fa0c inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a1328fb9288166ff325995ce1ea1867f0 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1328fb9288166ff325995ce1ea1867f0">getErrorCallback</a> () const</td></tr>
-<tr class="separator:a1328fb9288166ff325995ce1ea1867f0 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a9a54d38b985a2eb12c6972104dc0ce73 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a9a54d38b985a2eb12c6972104dc0ce73">isDataCallbackSpecified</a> () const</td></tr>
-<tr class="separator:a9a54d38b985a2eb12c6972104dc0ce73 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aef579f6d1f779c89d051f0963f2976b3 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aef579f6d1f779c89d051f0963f2976b3">isErrorCallbackSpecified</a> () const</td></tr>
-<tr class="separator:aef579f6d1f779c89d051f0963f2976b3 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a0bcfb2f8bd11c92b541fd910da9af397 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a0bcfb2f8bd11c92b541fd910da9af397">getUsage</a> () const</td></tr>
-<tr class="separator:a0bcfb2f8bd11c92b541fd910da9af397 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab12e2d068fa87e0553b01a400d96eb82 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab12e2d068fa87e0553b01a400d96eb82">getContentType</a> () const</td></tr>
-<tr class="separator:ab12e2d068fa87e0553b01a400d96eb82 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5c773b93b8aa38191c7199cab023428a inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5c773b93b8aa38191c7199cab023428a">getInputPreset</a> () const</td></tr>
-<tr class="separator:a5c773b93b8aa38191c7199cab023428a inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aa3c502ce09bbad7690a2dd6acaf8892e inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa3c502ce09bbad7690a2dd6acaf8892e">getSessionId</a> () const</td></tr>
-<tr class="separator:aa3c502ce09bbad7690a2dd6acaf8892e inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aa4ec3aa76e69350fbce6f00786211495 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa4ec3aa76e69350fbce6f00786211495">isChannelConversionAllowed</a> () const</td></tr>
-<tr class="separator:aa4ec3aa76e69350fbce6f00786211495 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ace3625a7332bf02a86818fdf63fcccb4 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ace3625a7332bf02a86818fdf63fcccb4">isFormatConversionAllowed</a> () const</td></tr>
-<tr class="separator:ace3625a7332bf02a86818fdf63fcccb4 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a1de8d6982d411a0cf50a32efba0ca3f2 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">SampleRateConversionQuality</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1de8d6982d411a0cf50a32efba0ca3f2">getSampleRateConversionQuality</a> () const</td></tr>
-<tr class="separator:a1de8d6982d411a0cf50a32efba0ca3f2 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table><table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pro-methods"></a>
-Protected Member Functions</h2></td></tr>
-<tr class="memitem:aa48da7bf28026b7cccee73e6b054af28"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#aa48da7bf28026b7cccee73e6b054af28">wasErrorCallbackCalled</a> ()</td></tr>
-<tr class="separator:aa48da7bf28026b7cccee73e6b054af28"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a8adbacd6a55a94a532916ab037fba1d6"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a8adbacd6a55a94a532916ab037fba1d6">waitForStateTransition</a> (<a class="el" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a> startingState, <a class="el" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a> endingState, int64_t timeoutNanoseconds)</td></tr>
-<tr class="separator:a8adbacd6a55a94a532916ab037fba1d6"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a0ea79e60f5a3d29fc5a1a116aba11dfe"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a0ea79e60f5a3d29fc5a1a116aba11dfe">onDefaultCallback</a> (void *, int)</td></tr>
-<tr class="separator:a0ea79e60f5a3d29fc5a1a116aba11dfe"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab7a8cfe5d6039386bc5850fd5ee9bd62"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#ab7a8cfe5d6039386bc5850fd5ee9bd62">fireDataCallback</a> (void *audioData, int numFrames)</td></tr>
-<tr class="separator:ab7a8cfe5d6039386bc5850fd5ee9bd62"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:add85011ba825f74931deeb92c5edf831"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#add85011ba825f74931deeb92c5edf831">isDataCallbackEnabled</a> ()</td></tr>
-<tr class="separator:add85011ba825f74931deeb92c5edf831"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a0faa6d3a6fd4f367e6f80d5a29e6dcba"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a0faa6d3a6fd4f367e6f80d5a29e6dcba">setDataCallbackEnabled</a> (bool enabled)</td></tr>
-<tr class="separator:a0faa6d3a6fd4f367e6f80d5a29e6dcba"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a68b28845855f7391c24ed0c7cee26ffe"><td class="memItemLeft" align="right" valign="top"><a id="a68b28845855f7391c24ed0c7cee26ffe"></a>
-void&#160;</td><td class="memItemRight" valign="bottom"><b>setWeakThis</b> (std::shared_ptr&lt; <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a> &gt; &amp;sharedStream)</td></tr>
-<tr class="separator:a68b28845855f7391c24ed0c7cee26ffe"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a4882ba4180fa2a984fb9a2002651d50b"><td class="memItemLeft" align="right" valign="top"><a id="a4882ba4180fa2a984fb9a2002651d50b"></a>
-std::shared_ptr&lt; <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a> &gt;&#160;</td><td class="memItemRight" valign="bottom"><b>lockWeakThis</b> ()</td></tr>
-<tr class="separator:a4882ba4180fa2a984fb9a2002651d50b"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="inherit_header pro_methods_classoboe_1_1_audio_stream_base"><td colspan="2" onclick="javascript:toggleInherit('pro_methods_classoboe_1_1_audio_stream_base')"><img src="closed.png" alt="-"/>&#160;Protected Member Functions inherited from <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td></tr>
-<tr class="memitem:a5d5e07e98921d0193a5c0ccbe06f68c2 inherit pro_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5d5e07e98921d0193a5c0ccbe06f68c2">isValidConfig</a> ()</td></tr>
-<tr class="separator:a5d5e07e98921d0193a5c0ccbe06f68c2 inherit pro_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table><table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pro-attribs"></a>
-Protected Attributes</h2></td></tr>
-<tr class="memitem:addb945e8ab2bc395cc99c8ae6504c2cd"><td class="memItemLeft" align="right" valign="top"><a id="addb945e8ab2bc395cc99c8ae6504c2cd"></a>
-std::weak_ptr&lt; <a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> &gt;&#160;</td><td class="memItemRight" valign="bottom"><b>mWeakThis</b></td></tr>
-<tr class="separator:addb945e8ab2bc395cc99c8ae6504c2cd"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a88a63317b7c58815bac074976b00aa23"><td class="memItemLeft" align="right" valign="top">std::atomic&lt; int64_t &gt;&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a88a63317b7c58815bac074976b00aa23">mFramesWritten</a> {}</td></tr>
-<tr class="separator:a88a63317b7c58815bac074976b00aa23"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a07e82f9b9e2e4800f23ae9a7193c3b58"><td class="memItemLeft" align="right" valign="top">std::atomic&lt; int64_t &gt;&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html#a07e82f9b9e2e4800f23ae9a7193c3b58">mFramesRead</a> {}</td></tr>
-<tr class="separator:a07e82f9b9e2e4800f23ae9a7193c3b58"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ad23416968eb9479c300e4a94841bdde4"><td class="memItemLeft" align="right" valign="top"><a id="ad23416968eb9479c300e4a94841bdde4"></a>
-std::mutex&#160;</td><td class="memItemRight" valign="bottom"><b>mLock</b></td></tr>
-<tr class="separator:ad23416968eb9479c300e4a94841bdde4"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:af4e4e04b87a53e6b286a6059be32b053"><td class="memItemLeft" align="right" valign="top"><a id="af4e4e04b87a53e6b286a6059be32b053"></a>
-<a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a>&#160;</td><td class="memItemRight" valign="bottom"><b>mErrorCallbackResult</b> = oboe::Result::OK</td></tr>
-<tr class="separator:af4e4e04b87a53e6b286a6059be32b053"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="inherit_header pro_attribs_classoboe_1_1_audio_stream_base"><td colspan="2" onclick="javascript:toggleInherit('pro_attribs_classoboe_1_1_audio_stream_base')"><img src="closed.png" alt="-"/>&#160;Protected Attributes inherited from <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td></tr>
-<tr class="memitem:a6d8493f66a945cb426506c70f0358e5f inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">mDataCallback</a> = nullptr</td></tr>
-<tr class="separator:a6d8493f66a945cb426506c70f0358e5f inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:adc0c8cc54adb6d3350c62b8a74b9c57b inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">mErrorCallback</a> = nullptr</td></tr>
-<tr class="separator:adc0c8cc54adb6d3350c62b8a74b9c57b inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a3962eb94420ad0ecea70029236001899 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899">mFramesPerCallback</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a3962eb94420ad0ecea70029236001899 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5ff460bac9d14dfeac4eeddfcbb6e206 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">mChannelCount</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a5ff460bac9d14dfeac4eeddfcbb6e206 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a998885bb6c4f37e145f4626ad4177dea inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea">mSampleRate</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a998885bb6c4f37e145f4626ad4177dea inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a23dafa12fb1a6242b088ebd5a52798c8 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8">mDeviceId</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a23dafa12fb1a6242b088ebd5a52798c8 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ac81d4719b350f8138aad1af38f0873b6 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6">mBufferCapacityInFrames</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:ac81d4719b350f8138aad1af38f0873b6 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a3b65595d26d1eae1b8ce9925a5b98f6a inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a3b65595d26d1eae1b8ce9925a5b98f6a">mBufferSizeInFrames</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a3b65595d26d1eae1b8ce9925a5b98f6a inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a54061319ed348329a29d883a5de2482e inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a54061319ed348329a29d883a5de2482e">mFramesPerBurst</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a54061319ed348329a29d883a5de2482e inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ae9187492b679c97a0963e264954be473 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473">mSharingMode</a> = <a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca">SharingMode::Shared</a></td></tr>
-<tr class="separator:ae9187492b679c97a0963e264954be473 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a7869f04836c2c2bdc10c7309ad4b8e09 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">mFormat</a> = AudioFormat::Unspecified</td></tr>
-<tr class="separator:a7869f04836c2c2bdc10c7309ad4b8e09 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a26e9294721561d3b16bcaeec5faf4880 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880">mDirection</a> = <a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54">Direction::Output</a></td></tr>
-<tr class="separator:a26e9294721561d3b16bcaeec5faf4880 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab99671c2d0552557e75dc7b4afe91765 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765">mPerformanceMode</a> = PerformanceMode::None</td></tr>
-<tr class="separator:ab99671c2d0552557e75dc7b4afe91765 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5b518e82f39c9fcbd7050fd66adb253c inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c">mUsage</a> = <a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74">Usage::Media</a></td></tr>
-<tr class="separator:a5b518e82f39c9fcbd7050fd66adb253c inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5f8f0e5add381b841856de80ea4cdb2b inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b">mContentType</a> = ContentType::Music</td></tr>
-<tr class="separator:a5f8f0e5add381b841856de80ea4cdb2b inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a1e5d4f5b30c4cc36f81ffd858cc00589 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589">mInputPreset</a> = InputPreset::VoiceRecognition</td></tr>
-<tr class="separator:a1e5d4f5b30c4cc36f81ffd858cc00589 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:abe1c1e9cada1ced9b5c1504ac9b07737 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737">mSessionId</a> = SessionId::None</td></tr>
-<tr class="separator:abe1c1e9cada1ced9b5c1504ac9b07737 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ae47a39b573250751f933dd159d09bf0f inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a id="ae47a39b573250751f933dd159d09bf0f"></a>
-bool&#160;</td><td class="memItemRight" valign="bottom"><b>mChannelConversionAllowed</b> = false</td></tr>
-<tr class="separator:ae47a39b573250751f933dd159d09bf0f inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a9394a88eb5f8b74fa72eabf28f403f87 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a id="a9394a88eb5f8b74fa72eabf28f403f87"></a>
-bool&#160;</td><td class="memItemRight" valign="bottom"><b>mFormatConversionAllowed</b> = false</td></tr>
-<tr class="separator:a9394a88eb5f8b74fa72eabf28f403f87 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a2dd35a6f009f36172838260144218f6d inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a id="a2dd35a6f009f36172838260144218f6d"></a>
-<a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">SampleRateConversionQuality</a>&#160;</td><td class="memItemRight" valign="bottom"><b>mSampleRateConversionQuality</b> = SampleRateConversionQuality::None</td></tr>
-<tr class="separator:a2dd35a6f009f36172838260144218f6d inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table><table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="friends"></a>
-Friends</h2></td></tr>
-<tr class="memitem:a8468a51a2352c31aef00fade27a43e9e"><td class="memItemLeft" align="right" valign="top"><a id="a8468a51a2352c31aef00fade27a43e9e"></a>
-class&#160;</td><td class="memItemRight" valign="bottom"><b>AudioStreamBuilder</b></td></tr>
-<tr class="separator:a8468a51a2352c31aef00fade27a43e9e"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
-<div class="textblock"><p>Base class for Oboe C++ audio stream. </p>
-</div><h2 class="groupheader">Constructor &amp; Destructor Documentation</h2>
-<a id="a8ebb587a07bf62c864fd62c63b241fd4"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a8ebb587a07bf62c864fd62c63b241fd4">&#9670;&nbsp;</a></span>AudioStream()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">oboe::AudioStream::AudioStream </td>
-          <td>(</td>
-          <td class="paramtype">const <a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> &amp;&#160;</td>
-          <td class="paramname"><em>builder</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">explicit</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Construct an <code><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a></code> using the given <code><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a></code></p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">builder</td><td>containing all the stream's attributes </td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<h2 class="groupheader">Member Function Documentation</h2>
-<a id="ae023cb001f3261d064f423101798d6be"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ae023cb001f3261d064f423101798d6be">&#9670;&nbsp;</a></span>calculateLatencyMillis()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt;double&gt; oboe::AudioStream::calculateLatencyMillis </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Calculate the latency of a stream based on <a class="el" href="classoboe_1_1_audio_stream.html#acb8edbc17ff79993a8ed996d216fe6f3">getTimestamp()</a>.</p>
-<p>Output latency is the time it takes for a given frame to travel from the app to some type of digital-to-analog converter. If the DAC is external, for example in a USB interface or a TV connected by HDMI, then there may be additional latency that the Android device is unaware of.</p>
-<p>Input latency is the time it takes to a given frame to travel from an analog-to-digital converter (ADC) to the app.</p>
-<p>Note that the latency of an OUTPUT stream will increase abruptly when you write data to it and then decrease slowly over time as the data is consumed.</p>
-<p>The latency of an INPUT stream will decrease abruptly when you read data from it and then increase slowly over time as more data arrives.</p>
-<p>The latency of an OUTPUT stream is generally higher than the INPUT latency because an app generally tries to keep the OUTPUT buffer full and the INPUT buffer empty.</p>
-<dl class="section return"><dt>Returns</dt><dd>a <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> which has a result of Result::OK and a value containing the latency in milliseconds, or a result of Result::Error*. </dd></dl>
-
-</div>
-</div>
-<a id="a9c8ea30e30e513766d5e996c370eb8d8"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a9c8ea30e30e513766d5e996c370eb8d8">&#9670;&nbsp;</a></span>close()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStream::close </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Close the stream and deallocate any resources from the <a class="el" href="classoboe_1_1_audio_stream.html#a686c6ce8a29051c858fd1de386805dc6">open()</a> call. </p>
-
-</div>
-</div>
-<a id="ab7a8cfe5d6039386bc5850fd5ee9bd62"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ab7a8cfe5d6039386bc5850fd5ee9bd62">&#9670;&nbsp;</a></span>fireDataCallback()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a> oboe::AudioStream::fireDataCallback </td>
-          <td>(</td>
-          <td class="paramtype">void *&#160;</td>
-          <td class="paramname"><em>audioData</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>numFrames</em>&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Override this to provide your own behaviour for the audio callback</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">audioData</td><td>container array which audio frames will be written into or read from </td></tr>
-    <tr><td class="paramname">numFrames</td><td>number of frames which were read/written </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>the result of the callback: stop or continue </dd></dl>
-
-</div>
-</div>
-<a id="a32c25c0333eab3d65ce02275ad4acb3d"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a32c25c0333eab3d65ce02275ad4acb3d">&#9670;&nbsp;</a></span>flush()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStream::flush </td>
-          <td>(</td>
-          <td class="paramtype">int64_t&#160;</td>
-          <td class="paramname"><em>timeoutNanoseconds</em> = <code><a class="el" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">kDefaultTimeoutNanos</a></code></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Flush the stream. This will block until the stream has been flushed, an error occurs or <code>timeoutNanoseconds</code> has been reached. </p>
-
-</div>
-</div>
-<a id="a2b7a3cee7444114843dbdd1fc705f6bb"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a2b7a3cee7444114843dbdd1fc705f6bb">&#9670;&nbsp;</a></span>getAudioApi()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">AudioApi</a> oboe::AudioStream::getAudioApi </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">pure virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Get the underlying audio API which the stream uses.</p>
-<dl class="section return"><dt>Returns</dt><dd>the API that this stream uses. </dd></dl>
-
-</div>
-</div>
-<a id="afa35ee4b8629fbffe26b9be7c7ed55d2"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#afa35ee4b8629fbffe26b9be7c7ed55d2">&#9670;&nbsp;</a></span>getAvailableFrames()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt;int32_t&gt; oboe::AudioStream::getAvailableFrames </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>number of frames of data currently in the buffer </dd></dl>
-
-</div>
-</div>
-<a id="a5c01907a59d5f89a5e4b819fe66b08bc"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a5c01907a59d5f89a5e4b819fe66b08bc">&#9670;&nbsp;</a></span>getBytesPerFrame()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::AudioStream::getBytesPerFrame </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Get the number of bytes in each audio frame. This is calculated using the channel count and the sample format. For example, a 2 channel floating point stream will have 2 * 4 = 8 bytes per frame.</p>
-<dl class="section return"><dt>Returns</dt><dd>number of bytes in each audio frame. </dd></dl>
-
-</div>
-</div>
-<a id="a44dda61e6e948e49b68f87172f084d62"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a44dda61e6e948e49b68f87172f084d62">&#9670;&nbsp;</a></span>getBytesPerSample()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::AudioStream::getBytesPerSample </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>Get the number of bytes per sample. This is calculated using the sample format. For example, a stream using 16-bit integer samples will have 2 bytes per sample.</p>
-<dl class="section return"><dt>Returns</dt><dd>the number of bytes per sample. </dd></dl>
-
-</div>
-</div>
-<a id="ac160acb656515814fa6fdd157c131a0a"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ac160acb656515814fa6fdd157c131a0a">&#9670;&nbsp;</a></span>getFramesPerBurst()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual int32_t oboe::AudioStream::getFramesPerBurst </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">pure virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Query the number of frames that are read or written by the endpoint at one time.</p>
-<dl class="section return"><dt>Returns</dt><dd>burst size </dd></dl>
-
-</div>
-</div>
-<a id="aeebfc59abd978cd6dff07c16cfe266df"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aeebfc59abd978cd6dff07c16cfe266df">&#9670;&nbsp;</a></span>getFramesRead()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual int64_t oboe::AudioStream::getFramesRead </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The number of audio frames read from the stream. This monotonic counter will never get reset.</p>
-<dl class="section return"><dt>Returns</dt><dd>the number of frames read so far </dd></dl>
-
-</div>
-</div>
-<a id="ab43dd4074e1de57bac1c3fd111430341"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ab43dd4074e1de57bac1c3fd111430341">&#9670;&nbsp;</a></span>getFramesWritten()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual int64_t oboe::AudioStream::getFramesWritten </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The number of audio frames written into the stream. This monotonic counter will never get reset.</p>
-<dl class="section return"><dt>Returns</dt><dd>the number of frames written so far </dd></dl>
-
-</div>
-</div>
-<a id="a8fe8afdf164a1fe835c514f709743d75"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a8fe8afdf164a1fe835c514f709743d75">&#9670;&nbsp;</a></span>getLastErrorCallbackResult()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a> oboe::AudioStream::getLastErrorCallbackResult </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>last result passed from an error callback </dd></dl>
-
-</div>
-</div>
-<a id="a9d37cc6513823c685ae892626ff83ea8"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a9d37cc6513823c685ae892626ff83ea8">&#9670;&nbsp;</a></span>getState()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a> oboe::AudioStream::getState </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">pure virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Query the current state, eg. StreamState::Pausing</p>
-<dl class="section return"><dt>Returns</dt><dd>state or a negative error. </dd></dl>
-
-</div>
-</div>
-<a id="acb8edbc17ff79993a8ed996d216fe6f3"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#acb8edbc17ff79993a8ed996d216fe6f3">&#9670;&nbsp;</a></span>getTimestamp() <span class="overload">[1/2]</span></h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStream::getTimestamp </td>
-          <td>(</td>
-          <td class="paramtype">clockid_t&#160;</td>
-          <td class="paramname">, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int64_t *&#160;</td>
-          <td class="paramname">, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int64_t *&#160;</td>
-          <td class="paramname">&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Get the estimated time that the frame at <code>framePosition</code> entered or left the audio processing pipeline.</p>
-<p>This can be used to coordinate events and interactions with the external environment, and to estimate the latency of an audio stream. An example of usage can be found in the hello-oboe sample (search for "calculateCurrentOutputLatencyMillis").</p>
-<p>The time is based on the implementation's best effort, using whatever knowledge is available to the system, but cannot account for any delay unknown to the implementation.</p>
-<dl class="deprecated"><dt><b><a class="el" href="deprecated.html#_deprecated000001">Deprecated:</a></b></dt><dd>since 1.0, use <a class="el" href="classoboe_1_1_audio_stream.html#a49254e6b1b19cb6d0ca6c63058029771">AudioStream::getTimestamp(clockid_t clockId)</a> instead, which returns <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> </dd></dl>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">clockId</td><td>the type of clock to use e.g. CLOCK_MONOTONIC </td></tr>
-    <tr><td class="paramname">framePosition</td><td>the frame number to query </td></tr>
-    <tr><td class="paramname">timeNanoseconds</td><td>an output parameter which will contain the presentation timestamp </td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<a id="a49254e6b1b19cb6d0ca6c63058029771"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a49254e6b1b19cb6d0ca6c63058029771">&#9670;&nbsp;</a></span>getTimestamp() <span class="overload">[2/2]</span></h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt;<a class="el" href="structoboe_1_1_frame_timestamp.html">FrameTimestamp</a>&gt; oboe::AudioStream::getTimestamp </td>
-          <td>(</td>
-          <td class="paramtype">clockid_t&#160;</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Get the estimated time that the frame at <code>framePosition</code> entered or left the audio processing pipeline.</p>
-<p>This can be used to coordinate events and interactions with the external environment, and to estimate the latency of an audio stream. An example of usage can be found in the hello-oboe sample (search for "calculateCurrentOutputLatencyMillis").</p>
-<p>The time is based on the implementation's best effort, using whatever knowledge is available to the system, but cannot account for any delay unknown to the implementation.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">clockId</td><td>the type of clock to use e.g. CLOCK_MONOTONIC </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>a <a class="el" href="structoboe_1_1_frame_timestamp.html">FrameTimestamp</a> containing the position and time at which a particular audio frame entered or left the audio processing pipeline, or an error if the operation failed. </dd></dl>
-
-</div>
-</div>
-<a id="a5458d7130415eb4defe3dbc11d479e2f"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a5458d7130415eb4defe3dbc11d479e2f">&#9670;&nbsp;</a></span>getUnderlyingStream()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual void* oboe::AudioStream::getUnderlyingStream </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Only for debugging. Do not use in production. If you need to call this method something is wrong. If you think you need it for production then please let us know so we can modify Oboe so that you don't need this.</p>
-<dl class="section return"><dt>Returns</dt><dd>nullptr or a pointer to a stream from the system API </dd></dl>
-
-</div>
-</div>
-<a id="ad1a1d3bbf3b348ed92b7ed18ce9cc261"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ad1a1d3bbf3b348ed92b7ed18ce9cc261">&#9670;&nbsp;</a></span>getXRunCount()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt;int32_t&gt; oboe::AudioStream::getXRunCount </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>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.</p>
-<p>An underrun or overrun can cause an audible "pop" or "glitch".</p>
-<dl class="section return"><dt>Returns</dt><dd>a result which is either Result::OK with the xRun count as the value, or a Result::Error* code </dd></dl>
-
-</div>
-</div>
-<a id="add85011ba825f74931deeb92c5edf831"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#add85011ba825f74931deeb92c5edf831">&#9670;&nbsp;</a></span>isDataCallbackEnabled()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">bool oboe::AudioStream::isDataCallbackEnabled </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>true if callbacks may be called </dd></dl>
-
-</div>
-</div>
-<a id="a43d8a098440cde28f4ee8bedd6d107c4"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a43d8a098440cde28f4ee8bedd6d107c4">&#9670;&nbsp;</a></span>isXRunCountSupported()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual bool oboe::AudioStream::isXRunCountSupported </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">pure virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>true if XRun counts are supported on the stream </dd></dl>
-
-</div>
-</div>
-<a id="aa5f4801cca6877eeaa4735b93933269d"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aa5f4801cca6877eeaa4735b93933269d">&#9670;&nbsp;</a></span>launchStopThread()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">void oboe::AudioStream::launchStopThread </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>Launch a thread that will stop the stream. </p>
-
-</div>
-</div>
-<a id="a0ea79e60f5a3d29fc5a1a116aba11dfe"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a0ea79e60f5a3d29fc5a1a116aba11dfe">&#9670;&nbsp;</a></span>onDefaultCallback()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a> oboe::AudioStream::onDefaultCallback </td>
-          <td>(</td>
-          <td class="paramtype">void *&#160;</td>
-          <td class="paramname">, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname">&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">protected</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Override this to provide a default for when the application did not specify a callback.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">audioData</td><td></td></tr>
-    <tr><td class="paramname">numFrames</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>result </dd></dl>
-
-</div>
-</div>
-<a id="a686c6ce8a29051c858fd1de386805dc6"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a686c6ce8a29051c858fd1de386805dc6">&#9670;&nbsp;</a></span>open()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStream::open </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Open a stream based on the current settings.</p>
-<p>Note that we do not recommend re-opening a stream that has been closed. TODO Should we prevent re-opening?</p>
-<dl class="section return"><dt>Returns</dt><dd></dd></dl>
-
-</div>
-</div>
-<a id="a04f29836748a8e5842aef2be200022ad"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a04f29836748a8e5842aef2be200022ad">&#9670;&nbsp;</a></span>pause()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStream::pause </td>
-          <td>(</td>
-          <td class="paramtype">int64_t&#160;</td>
-          <td class="paramname"><em>timeoutNanoseconds</em> = <code><a class="el" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">kDefaultTimeoutNanos</a></code></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Pause the stream. This will block until the stream has been paused, an error occurs or <code>timeoutNanoseconds</code> has been reached. </p>
-
-</div>
-</div>
-<a id="a8089f0a0cb68d4039cf33e6584129978"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a8089f0a0cb68d4039cf33e6584129978">&#9670;&nbsp;</a></span>read()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt;int32_t&gt; oboe::AudioStream::read </td>
-          <td>(</td>
-          <td class="paramtype">void *&#160;</td>
-          <td class="paramname">, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int32_t&#160;</td>
-          <td class="paramname">, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int64_t&#160;</td>
-          <td class="paramname">&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Read data into the supplied buffer from the stream. This method will block until the read is complete or it runs out of time.</p>
-<p>If <code>timeoutNanoseconds</code> is zero then this call will not wait.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">buffer</td><td>The address of the first sample. </td></tr>
-    <tr><td class="paramname">numFrames</td><td>Number of frames to read. Only complete frames will be read. </td></tr>
-    <tr><td class="paramname">timeoutNanoseconds</td><td>Maximum number of nanoseconds to wait for completion. </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>a <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> which has a result of Result::OK and a value containing the number of frames actually read, or result of Result::Error*. </dd></dl>
-
-</div>
-</div>
-<a id="a6bd5d633ff999e4da1faf3cd949aa602"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a6bd5d633ff999e4da1faf3cd949aa602">&#9670;&nbsp;</a></span>requestFlush()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStream::requestFlush </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">pure virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Flush the stream asynchronously. Returns immediately (does not block). Equivalent to calling <code>flush(0)</code>. </p>
-
-</div>
-</div>
-<a id="a7f18bb3cc5490fd7fbc1f6da63c730f6"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a7f18bb3cc5490fd7fbc1f6da63c730f6">&#9670;&nbsp;</a></span>requestPause()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStream::requestPause </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">pure virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Pause the stream asynchronously. Returns immediately (does not block). Equivalent to calling <code>pause(0)</code>. </p>
-
-</div>
-</div>
-<a id="a3c484e314dee8dfed1d419f487b5d601"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a3c484e314dee8dfed1d419f487b5d601">&#9670;&nbsp;</a></span>requestStart()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStream::requestStart </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">pure virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Start the stream asynchronously. Returns immediately (does not block). Equivalent to calling <code>start(0)</code>. </p>
-
-</div>
-</div>
-<a id="a820e634f741e6b5efdcef8104cecb919"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a820e634f741e6b5efdcef8104cecb919">&#9670;&nbsp;</a></span>requestStop()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStream::requestStop </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">pure virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Stop the stream asynchronously. Returns immediately (does not block). Equivalent to calling <code>stop(0)</code>. </p>
-
-</div>
-</div>
-<a id="a06e3f9e133b3a75515e7793939d1cd03"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a06e3f9e133b3a75515e7793939d1cd03">&#9670;&nbsp;</a></span>setBufferSizeInFrames()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt;int32_t&gt; oboe::AudioStream::setBufferSizeInFrames </td>
-          <td>(</td>
-          <td class="paramtype">int32_t&#160;</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>This can be used to adjust the latency of the buffer by changing the threshold where blocking will occur. By combining this with <a class="el" href="classoboe_1_1_audio_stream.html#ad1a1d3bbf3b348ed92b7ed18ce9cc261">getXRunCount()</a>, the latency can be tuned at run-time for each device.</p>
-<p>This cannot be set higher than getBufferCapacity().</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">requestedFrames</td><td>requested number of frames that can be filled without blocking </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>the resulting buffer size in frames (obtained using value()) or an error (obtained using error()) </dd></dl>
-
-</div>
-</div>
-<a id="a0faa6d3a6fd4f367e6f80d5a29e6dcba"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a0faa6d3a6fd4f367e6f80d5a29e6dcba">&#9670;&nbsp;</a></span>setDataCallbackEnabled()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">void oboe::AudioStream::setDataCallbackEnabled </td>
-          <td>(</td>
-          <td class="paramtype">bool&#160;</td>
-          <td class="paramname"><em>enabled</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>This can be set false internally to prevent callbacks after DataCallbackResult::Stop has been returned. </p>
-
-</div>
-</div>
-<a id="af04f03eb6b64b564f1c4401688987d21"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#af04f03eb6b64b564f1c4401688987d21">&#9670;&nbsp;</a></span>start()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStream::start </td>
-          <td>(</td>
-          <td class="paramtype">int64_t&#160;</td>
-          <td class="paramname"><em>timeoutNanoseconds</em> = <code><a class="el" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">kDefaultTimeoutNanos</a></code></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Start the stream. This will block until the stream has been started, an error occurs or <code>timeoutNanoseconds</code> has been reached. </p>
-
-</div>
-</div>
-<a id="aec093859d42f0470c884edd1e976d9f3"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aec093859d42f0470c884edd1e976d9f3">&#9670;&nbsp;</a></span>stop()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStream::stop </td>
-          <td>(</td>
-          <td class="paramtype">int64_t&#160;</td>
-          <td class="paramname"><em>timeoutNanoseconds</em> = <code><a class="el" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">kDefaultTimeoutNanos</a></code></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Stop the stream. This will block until the stream has been stopped, an error occurs or <code>timeoutNanoseconds</code> has been reached. </p>
-
-</div>
-</div>
-<a id="a462358ddab709c79d1a7968d6d55b727"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a462358ddab709c79d1a7968d6d55b727">&#9670;&nbsp;</a></span>updateFramesRead()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual void oboe::AudioStream::updateFramesRead </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">pure virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Update mFramesRead. For internal use only. </p>
-
-</div>
-</div>
-<a id="a64ad978c5f70ced17ef5a96605496515"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a64ad978c5f70ced17ef5a96605496515">&#9670;&nbsp;</a></span>updateFramesWritten()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual void oboe::AudioStream::updateFramesWritten </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">pure virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Update mFramesWritten. For internal use only. </p>
-
-</div>
-</div>
-<a id="a15cdaaaa4c1e8da322d6da33334c8147"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a15cdaaaa4c1e8da322d6da33334c8147">&#9670;&nbsp;</a></span>usesAAudio()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">bool oboe::AudioStream::usesAAudio </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Returns true if the underlying audio API is AAudio.</p>
-<dl class="section return"><dt>Returns</dt><dd>true if this stream is implemented using the AAudio API. </dd></dl>
-
-</div>
-</div>
-<a id="afddb0962863ccf9ec6672a042fe15941"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#afddb0962863ccf9ec6672a042fe15941">&#9670;&nbsp;</a></span>waitForAvailableFrames()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt;int32_t&gt; oboe::AudioStream::waitForAvailableFrames </td>
-          <td>(</td>
-          <td class="paramtype">int32_t&#160;</td>
-          <td class="paramname"><em>numFrames</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int64_t&#160;</td>
-          <td class="paramname"><em>timeoutNanoseconds</em>&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>Wait until the stream has a minimum amount of data available in its buffer. This can be used with an EXCLUSIVE MMAP input stream to avoid reading data too close to the DSP write position, which may cause glitches.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">numFrames</td><td>minimum frames available </td></tr>
-    <tr><td class="paramname">timeoutNanoseconds</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>number of frames available, ErrorTimeout </dd></dl>
-
-</div>
-</div>
-<a id="a0c865a5501f369d959c39d8ab8b46a07"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a0c865a5501f369d959c39d8ab8b46a07">&#9670;&nbsp;</a></span>waitForStateChange()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStream::waitForStateChange </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a>&#160;</td>
-          <td class="paramname"><em>inputState</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a> *&#160;</td>
-          <td class="paramname"><em>nextState</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int64_t&#160;</td>
-          <td class="paramname"><em>timeoutNanoseconds</em>&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">pure virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Wait until the stream's current state no longer matches the input state. The input state is passed to avoid race conditions caused by the state changing between calls.</p>
-<p>Note that generally applications do not need to call this. It is considered an advanced technique and is mostly used for testing.</p>
-<pre><code>
-int64_t timeoutNanos = 500 * kNanosPerMillisecond; // arbitrary 1/2 second
-StreamState currentState = stream-&gt;<a class="el" href="classoboe_1_1_audio_stream.html#a9d37cc6513823c685ae892626ff83ea8">getState()</a>;
-StreamState nextState = StreamState::Unknown;
-while (result == Result::OK &amp;&amp; currentState != StreamState::Paused) {
-    result = stream-&gt;waitForStateChange(
-                                  currentState, &amp;nextState, timeoutNanos);
-    currentState = nextState;
-}
-</code></pre><p>If the state does not change within the timeout period then it will return ErrorTimeout. This is true even if timeoutNanoseconds is zero.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">inputState</td><td>The state we want to change away from. </td></tr>
-    <tr><td class="paramname">nextState</td><td>Pointer to a variable that will be set to the new state. </td></tr>
-    <tr><td class="paramname">timeoutNanoseconds</td><td>The maximum time to wait in nanoseconds. </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>Result::OK or a Result::Error. </dd></dl>
-
-</div>
-</div>
-<a id="a8adbacd6a55a94a532916ab037fba1d6"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a8adbacd6a55a94a532916ab037fba1d6">&#9670;&nbsp;</a></span>waitForStateTransition()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStream::waitForStateTransition </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a>&#160;</td>
-          <td class="paramname"><em>startingState</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a>&#160;</td>
-          <td class="paramname"><em>endingState</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int64_t&#160;</td>
-          <td class="paramname"><em>timeoutNanoseconds</em>&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Wait for a transition from one state to another. </p><dl class="section return"><dt>Returns</dt><dd>OK if the endingState was observed, or ErrorUnexpectedState if any state that was not the startingState or endingState was observed or ErrorTimeout. </dd></dl>
-
-</div>
-</div>
-<a id="aa48da7bf28026b7cccee73e6b054af28"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aa48da7bf28026b7cccee73e6b054af28">&#9670;&nbsp;</a></span>wasErrorCallbackCalled()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">bool oboe::AudioStream::wasErrorCallbackCalled </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>This is used to detect more than one error callback from a stream. These were bugs in some versions of Android that caused multiple error callbacks. Internal bug b/63087953</p>
-<p>Calling this sets an atomic&lt;bool&gt; true and returns the previous value.</p>
-<dl class="section return"><dt>Returns</dt><dd>false on first call, true on subsequent calls </dd></dl>
-
-</div>
-</div>
-<a id="a3612c05ed6b01a213dde67d913c07e11"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a3612c05ed6b01a213dde67d913c07e11">&#9670;&nbsp;</a></span>write()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt;int32_t&gt; oboe::AudioStream::write </td>
-          <td>(</td>
-          <td class="paramtype">const void *&#160;</td>
-          <td class="paramname">, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int32_t&#160;</td>
-          <td class="paramname">, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int64_t&#160;</td>
-          <td class="paramname">&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Write data from the supplied buffer into the stream. This method will block until the write is complete or it runs out of time.</p>
-<p>If <code>timeoutNanoseconds</code> is zero then this call will not wait.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">buffer</td><td>The address of the first sample. </td></tr>
-    <tr><td class="paramname">numFrames</td><td>Number of frames to write. Only complete frames will be written. </td></tr>
-    <tr><td class="paramname">timeoutNanoseconds</td><td>Maximum number of nanoseconds to wait for completion. </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>a <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> which has a result of Result::OK and a value containing the number of frames actually written, or result of Result::Error*. </dd></dl>
-
-</div>
-</div>
-<h2 class="groupheader">Member Data Documentation</h2>
-<a id="a07e82f9b9e2e4800f23ae9a7193c3b58"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a07e82f9b9e2e4800f23ae9a7193c3b58">&#9670;&nbsp;</a></span>mFramesRead</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">std::atomic&lt;int64_t&gt; oboe::AudioStream::mFramesRead {}</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Number of frames which have been read from the stream.</p>
-<p>This is signed integer to match the counters in AAudio. At audio rates, the counter will overflow in about six million years. </p>
-
-</div>
-</div>
-<a id="a88a63317b7c58815bac074976b00aa23"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a88a63317b7c58815bac074976b00aa23">&#9670;&nbsp;</a></span>mFramesWritten</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">std::atomic&lt;int64_t&gt; oboe::AudioStream::mFramesWritten {}</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Number of frames which have been written into the stream</p>
-<p>This is signed integer to match the counters in AAudio. At audio rates, the counter will overflow in about six million years. </p>
-
-</div>
-</div>
-<hr/>The documentation for this class was generated from the following file:<ul>
-<li>include/oboe/<a class="el" href="_audio_stream_8h_source.html">AudioStream.h</a></li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_audio_stream.png b/docs/reference/classoboe_1_1_audio_stream.png
deleted file mode 100644
index a479d65..0000000
--- a/docs/reference/classoboe_1_1_audio_stream.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/classoboe_1_1_audio_stream_base-members.html b/docs/reference/classoboe_1_1_audio_stream_base-members.html
deleted file mode 100644
index 9fde259..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_base-members.html
+++ /dev/null
@@ -1,132 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Member List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe::AudioStreamBase Member List</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p>This is the complete list of members for <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>, including all inherited members.</p>
-<table class="directory">
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>AudioStreamBase</b>() (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa6b103e1b0f808bbc4949d56f0829f98">AudioStreamBase</a>(const AudioStreamBase &amp;)=default</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab1531253e64aaebe9e9eddbafb9098fc">getBufferCapacityInFrames</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#af5217ab05bfde0d7637024b599302d0b">getBufferSizeInFrames</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a87e6bf37d6a2a5e983b8ca8d29aea575">getChannelCount</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab12e2d068fa87e0553b01a400d96eb82">getContentType</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a9fb2f34ae62dbda2c10e8513b754fa0c">getDataCallback</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a093057d625bc896864b959974c265f21">getDeviceId</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a6f86f2233a04c5a0b056f0c1c261f1b1">getDirection</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1328fb9288166ff325995ce1ea1867f0">getErrorCallback</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab1e640461d7bf9d596decb913da7ac86">getFormat</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a8878a90949badbb5486cc2e022a57086">getFramesPerCallback</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#abc3ee2815568b425d15a40e132aa8e38">getFramesPerDataCallback</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5c773b93b8aa38191c7199cab023428a">getInputPreset</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a2ddb935de0e24dd7ae8e2cfbecac9fdc">getPerformanceMode</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ae9d32f3e09174bad69e74f147ee33087">getSampleRate</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1de8d6982d411a0cf50a32efba0ca3f2">getSampleRateConversionQuality</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa3c502ce09bbad7690a2dd6acaf8892e">getSessionId</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1fb033fc963f971bd1aa8f6707e49b41">getSharingMode</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a0bcfb2f8bd11c92b541fd910da9af397">getUsage</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa4ec3aa76e69350fbce6f00786211495">isChannelConversionAllowed</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a9a54d38b985a2eb12c6972104dc0ce73">isDataCallbackSpecified</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aef579f6d1f779c89d051f0963f2976b3">isErrorCallbackSpecified</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ace3625a7332bf02a86818fdf63fcccb4">isFormatConversionAllowed</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5d5e07e98921d0193a5c0ccbe06f68c2">isValidConfig</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">protected</span><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6">mBufferCapacityInFrames</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a3b65595d26d1eae1b8ce9925a5b98f6a">mBufferSizeInFrames</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>mChannelConversionAllowed</b> (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">mChannelCount</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b">mContentType</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">mDataCallback</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8">mDeviceId</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880">mDirection</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">mErrorCallback</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">mFormat</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>mFormatConversionAllowed</b> (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a54061319ed348329a29d883a5de2482e">mFramesPerBurst</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899">mFramesPerCallback</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589">mInputPreset</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765">mPerformanceMode</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea">mSampleRate</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>mSampleRateConversionQuality</b> (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737">mSessionId</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473">mSharingMode</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c">mUsage</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa9c987a59555d7a60b9f7a63f4afc7fc">operator=</a>(const AudioStreamBase &amp;)=default</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>~AudioStreamBase</b>()=default (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-</table></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_audio_stream_base.html b/docs/reference/classoboe_1_1_audio_stream_base.html
deleted file mode 100644
index 093eb46..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_base.html
+++ /dev/null
@@ -1,1254 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe::AudioStreamBase Class Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="#pub-methods">Public Member Functions</a> &#124;
-<a href="#pro-methods">Protected Member Functions</a> &#124;
-<a href="#pro-attribs">Protected Attributes</a> &#124;
-<a href="classoboe_1_1_audio_stream_base-members.html">List of all members</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe::AudioStreamBase Class Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p><code>#include &lt;<a class="el" href="_audio_stream_base_8h_source.html">AudioStreamBase.h</a>&gt;</code></p>
-<div class="dynheader">
-Inheritance diagram for oboe::AudioStreamBase:</div>
-<div class="dyncontent">
- <div class="center">
-  <img src="classoboe_1_1_audio_stream_base.png" usemap="#oboe::AudioStreamBase_map" alt=""/>
-  <map id="oboe::AudioStreamBase_map" name="oboe::AudioStreamBase_map">
-<area href="classoboe_1_1_audio_stream.html" alt="oboe::AudioStream" shape="rect" coords="0,56,158,80"/>
-<area href="classoboe_1_1_audio_stream_builder.html" alt="oboe::AudioStreamBuilder" shape="rect" coords="168,56,326,80"/>
-  </map>
-</div></div>
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-methods"></a>
-Public Member Functions</h2></td></tr>
-<tr class="memitem:aa6b103e1b0f808bbc4949d56f0829f98"><td class="memItemLeft" align="right" valign="top">&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa6b103e1b0f808bbc4949d56f0829f98">AudioStreamBase</a> (const <a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> &amp;)=default</td></tr>
-<tr class="separator:aa6b103e1b0f808bbc4949d56f0829f98"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aa9c987a59555d7a60b9f7a63f4afc7fc"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> &amp;&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa9c987a59555d7a60b9f7a63f4afc7fc">operator=</a> (const <a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> &amp;)=default</td></tr>
-<tr class="separator:aa9c987a59555d7a60b9f7a63f4afc7fc"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a87e6bf37d6a2a5e983b8ca8d29aea575"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a87e6bf37d6a2a5e983b8ca8d29aea575">getChannelCount</a> () const</td></tr>
-<tr class="separator:a87e6bf37d6a2a5e983b8ca8d29aea575"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a6f86f2233a04c5a0b056f0c1c261f1b1"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a6f86f2233a04c5a0b056f0c1c261f1b1">getDirection</a> () const</td></tr>
-<tr class="separator:a6f86f2233a04c5a0b056f0c1c261f1b1"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ae9d32f3e09174bad69e74f147ee33087"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ae9d32f3e09174bad69e74f147ee33087">getSampleRate</a> () const</td></tr>
-<tr class="separator:ae9d32f3e09174bad69e74f147ee33087"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a8878a90949badbb5486cc2e022a57086"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a8878a90949badbb5486cc2e022a57086">getFramesPerCallback</a> () const</td></tr>
-<tr class="separator:a8878a90949badbb5486cc2e022a57086"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:abc3ee2815568b425d15a40e132aa8e38"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#abc3ee2815568b425d15a40e132aa8e38">getFramesPerDataCallback</a> () const</td></tr>
-<tr class="separator:abc3ee2815568b425d15a40e132aa8e38"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab1e640461d7bf9d596decb913da7ac86"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab1e640461d7bf9d596decb913da7ac86">getFormat</a> () const</td></tr>
-<tr class="separator:ab1e640461d7bf9d596decb913da7ac86"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:af5217ab05bfde0d7637024b599302d0b"><td class="memItemLeft" align="right" valign="top">virtual int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#af5217ab05bfde0d7637024b599302d0b">getBufferSizeInFrames</a> ()</td></tr>
-<tr class="separator:af5217ab05bfde0d7637024b599302d0b"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab1531253e64aaebe9e9eddbafb9098fc"><td class="memItemLeft" align="right" valign="top">virtual int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab1531253e64aaebe9e9eddbafb9098fc">getBufferCapacityInFrames</a> () const</td></tr>
-<tr class="separator:ab1531253e64aaebe9e9eddbafb9098fc"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a1fb033fc963f971bd1aa8f6707e49b41"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1fb033fc963f971bd1aa8f6707e49b41">getSharingMode</a> () const</td></tr>
-<tr class="separator:a1fb033fc963f971bd1aa8f6707e49b41"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a2ddb935de0e24dd7ae8e2cfbecac9fdc"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a2ddb935de0e24dd7ae8e2cfbecac9fdc">getPerformanceMode</a> () const</td></tr>
-<tr class="separator:a2ddb935de0e24dd7ae8e2cfbecac9fdc"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a093057d625bc896864b959974c265f21"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a093057d625bc896864b959974c265f21">getDeviceId</a> () const</td></tr>
-<tr class="separator:a093057d625bc896864b959974c265f21"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a9fb2f34ae62dbda2c10e8513b754fa0c"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a9fb2f34ae62dbda2c10e8513b754fa0c">getDataCallback</a> () const</td></tr>
-<tr class="separator:a9fb2f34ae62dbda2c10e8513b754fa0c"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a1328fb9288166ff325995ce1ea1867f0"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1328fb9288166ff325995ce1ea1867f0">getErrorCallback</a> () const</td></tr>
-<tr class="separator:a1328fb9288166ff325995ce1ea1867f0"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a9a54d38b985a2eb12c6972104dc0ce73"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a9a54d38b985a2eb12c6972104dc0ce73">isDataCallbackSpecified</a> () const</td></tr>
-<tr class="separator:a9a54d38b985a2eb12c6972104dc0ce73"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aef579f6d1f779c89d051f0963f2976b3"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aef579f6d1f779c89d051f0963f2976b3">isErrorCallbackSpecified</a> () const</td></tr>
-<tr class="separator:aef579f6d1f779c89d051f0963f2976b3"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a0bcfb2f8bd11c92b541fd910da9af397"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a0bcfb2f8bd11c92b541fd910da9af397">getUsage</a> () const</td></tr>
-<tr class="separator:a0bcfb2f8bd11c92b541fd910da9af397"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab12e2d068fa87e0553b01a400d96eb82"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab12e2d068fa87e0553b01a400d96eb82">getContentType</a> () const</td></tr>
-<tr class="separator:ab12e2d068fa87e0553b01a400d96eb82"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5c773b93b8aa38191c7199cab023428a"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5c773b93b8aa38191c7199cab023428a">getInputPreset</a> () const</td></tr>
-<tr class="separator:a5c773b93b8aa38191c7199cab023428a"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aa3c502ce09bbad7690a2dd6acaf8892e"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa3c502ce09bbad7690a2dd6acaf8892e">getSessionId</a> () const</td></tr>
-<tr class="separator:aa3c502ce09bbad7690a2dd6acaf8892e"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aa4ec3aa76e69350fbce6f00786211495"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa4ec3aa76e69350fbce6f00786211495">isChannelConversionAllowed</a> () const</td></tr>
-<tr class="separator:aa4ec3aa76e69350fbce6f00786211495"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ace3625a7332bf02a86818fdf63fcccb4"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ace3625a7332bf02a86818fdf63fcccb4">isFormatConversionAllowed</a> () const</td></tr>
-<tr class="separator:ace3625a7332bf02a86818fdf63fcccb4"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a1de8d6982d411a0cf50a32efba0ca3f2"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">SampleRateConversionQuality</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1de8d6982d411a0cf50a32efba0ca3f2">getSampleRateConversionQuality</a> () const</td></tr>
-<tr class="separator:a1de8d6982d411a0cf50a32efba0ca3f2"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table><table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pro-methods"></a>
-Protected Member Functions</h2></td></tr>
-<tr class="memitem:a5d5e07e98921d0193a5c0ccbe06f68c2"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5d5e07e98921d0193a5c0ccbe06f68c2">isValidConfig</a> ()</td></tr>
-<tr class="separator:a5d5e07e98921d0193a5c0ccbe06f68c2"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table><table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pro-attribs"></a>
-Protected Attributes</h2></td></tr>
-<tr class="memitem:a6d8493f66a945cb426506c70f0358e5f"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">mDataCallback</a> = nullptr</td></tr>
-<tr class="separator:a6d8493f66a945cb426506c70f0358e5f"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:adc0c8cc54adb6d3350c62b8a74b9c57b"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">mErrorCallback</a> = nullptr</td></tr>
-<tr class="separator:adc0c8cc54adb6d3350c62b8a74b9c57b"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a3962eb94420ad0ecea70029236001899"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899">mFramesPerCallback</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a3962eb94420ad0ecea70029236001899"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5ff460bac9d14dfeac4eeddfcbb6e206"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">mChannelCount</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a5ff460bac9d14dfeac4eeddfcbb6e206"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a998885bb6c4f37e145f4626ad4177dea"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea">mSampleRate</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a998885bb6c4f37e145f4626ad4177dea"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a23dafa12fb1a6242b088ebd5a52798c8"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8">mDeviceId</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a23dafa12fb1a6242b088ebd5a52798c8"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ac81d4719b350f8138aad1af38f0873b6"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6">mBufferCapacityInFrames</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:ac81d4719b350f8138aad1af38f0873b6"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a3b65595d26d1eae1b8ce9925a5b98f6a"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a3b65595d26d1eae1b8ce9925a5b98f6a">mBufferSizeInFrames</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a3b65595d26d1eae1b8ce9925a5b98f6a"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a54061319ed348329a29d883a5de2482e"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a54061319ed348329a29d883a5de2482e">mFramesPerBurst</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a54061319ed348329a29d883a5de2482e"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ae9187492b679c97a0963e264954be473"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473">mSharingMode</a> = <a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca">SharingMode::Shared</a></td></tr>
-<tr class="separator:ae9187492b679c97a0963e264954be473"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a7869f04836c2c2bdc10c7309ad4b8e09"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">mFormat</a> = AudioFormat::Unspecified</td></tr>
-<tr class="separator:a7869f04836c2c2bdc10c7309ad4b8e09"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a26e9294721561d3b16bcaeec5faf4880"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880">mDirection</a> = <a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54">Direction::Output</a></td></tr>
-<tr class="separator:a26e9294721561d3b16bcaeec5faf4880"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab99671c2d0552557e75dc7b4afe91765"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765">mPerformanceMode</a> = PerformanceMode::None</td></tr>
-<tr class="separator:ab99671c2d0552557e75dc7b4afe91765"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5b518e82f39c9fcbd7050fd66adb253c"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c">mUsage</a> = <a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74">Usage::Media</a></td></tr>
-<tr class="separator:a5b518e82f39c9fcbd7050fd66adb253c"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5f8f0e5add381b841856de80ea4cdb2b"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b">mContentType</a> = ContentType::Music</td></tr>
-<tr class="separator:a5f8f0e5add381b841856de80ea4cdb2b"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a1e5d4f5b30c4cc36f81ffd858cc00589"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589">mInputPreset</a> = InputPreset::VoiceRecognition</td></tr>
-<tr class="separator:a1e5d4f5b30c4cc36f81ffd858cc00589"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:abe1c1e9cada1ced9b5c1504ac9b07737"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737">mSessionId</a> = SessionId::None</td></tr>
-<tr class="separator:abe1c1e9cada1ced9b5c1504ac9b07737"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ae47a39b573250751f933dd159d09bf0f"><td class="memItemLeft" align="right" valign="top"><a id="ae47a39b573250751f933dd159d09bf0f"></a>
-bool&#160;</td><td class="memItemRight" valign="bottom"><b>mChannelConversionAllowed</b> = false</td></tr>
-<tr class="separator:ae47a39b573250751f933dd159d09bf0f"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a9394a88eb5f8b74fa72eabf28f403f87"><td class="memItemLeft" align="right" valign="top"><a id="a9394a88eb5f8b74fa72eabf28f403f87"></a>
-bool&#160;</td><td class="memItemRight" valign="bottom"><b>mFormatConversionAllowed</b> = false</td></tr>
-<tr class="separator:a9394a88eb5f8b74fa72eabf28f403f87"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a2dd35a6f009f36172838260144218f6d"><td class="memItemLeft" align="right" valign="top"><a id="a2dd35a6f009f36172838260144218f6d"></a>
-<a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">SampleRateConversionQuality</a>&#160;</td><td class="memItemRight" valign="bottom"><b>mSampleRateConversionQuality</b> = SampleRateConversionQuality::None</td></tr>
-<tr class="separator:a2dd35a6f009f36172838260144218f6d"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
-<div class="textblock"><p>Base class containing parameters for audio streams and builders. </p>
-</div><h2 class="groupheader">Constructor &amp; Destructor Documentation</h2>
-<a id="aa6b103e1b0f808bbc4949d56f0829f98"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aa6b103e1b0f808bbc4949d56f0829f98">&#9670;&nbsp;</a></span>AudioStreamBase()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">oboe::AudioStreamBase::AudioStreamBase </td>
-          <td>(</td>
-          <td class="paramtype">const <a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> &amp;&#160;</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">default</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Default copy constructor </p>
-
-</div>
-</div>
-<h2 class="groupheader">Member Function Documentation</h2>
-<a id="ab1531253e64aaebe9e9eddbafb9098fc"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ab1531253e64aaebe9e9eddbafb9098fc">&#9670;&nbsp;</a></span>getBufferCapacityInFrames()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual int32_t oboe::AudioStreamBase::getBufferCapacityInFrames </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>capacityInFrames or kUnspecified </dd></dl>
-
-</div>
-</div>
-<a id="af5217ab05bfde0d7637024b599302d0b"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#af5217ab05bfde0d7637024b599302d0b">&#9670;&nbsp;</a></span>getBufferSizeInFrames()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual int32_t oboe::AudioStreamBase::getBufferSizeInFrames </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Query the maximum number of frames that can be filled without blocking. If the stream has been closed the last known value will be returned.</p>
-<dl class="section return"><dt>Returns</dt><dd>buffer size </dd></dl>
-
-</div>
-</div>
-<a id="a87e6bf37d6a2a5e983b8ca8d29aea575"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a87e6bf37d6a2a5e983b8ca8d29aea575">&#9670;&nbsp;</a></span>getChannelCount()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::AudioStreamBase::getChannelCount </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>number of channels, for example 2 for stereo, or kUnspecified </dd></dl>
-
-</div>
-</div>
-<a id="ab12e2d068fa87e0553b01a400d96eb82"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ab12e2d068fa87e0553b01a400d96eb82">&#9670;&nbsp;</a></span>getContentType()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a> oboe::AudioStreamBase::getContentType </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>the stream's content type. </dd></dl>
-
-</div>
-</div>
-<a id="a9fb2f34ae62dbda2c10e8513b754fa0c"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a9fb2f34ae62dbda2c10e8513b754fa0c">&#9670;&nbsp;</a></span>getDataCallback()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a>* oboe::AudioStreamBase::getDataCallback </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>For internal use only. </p><dl class="section return"><dt>Returns</dt><dd>the data callback object for this stream, if set. </dd></dl>
-
-</div>
-</div>
-<a id="a093057d625bc896864b959974c265f21"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a093057d625bc896864b959974c265f21">&#9670;&nbsp;</a></span>getDeviceId()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::AudioStreamBase::getDeviceId </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>the device ID of the stream. </dd></dl>
-
-</div>
-</div>
-<a id="a6f86f2233a04c5a0b056f0c1c261f1b1"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a6f86f2233a04c5a0b056f0c1c261f1b1">&#9670;&nbsp;</a></span>getDirection()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a> oboe::AudioStreamBase::getDirection </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd><a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea324118a6721dd6b8a9b9f4e327df2bf5">Direction::Input</a> or <a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54">Direction::Output</a> </dd></dl>
-
-</div>
-</div>
-<a id="a1328fb9288166ff325995ce1ea1867f0"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a1328fb9288166ff325995ce1ea1867f0">&#9670;&nbsp;</a></span>getErrorCallback()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a>* oboe::AudioStreamBase::getErrorCallback </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>For internal use only. </p><dl class="section return"><dt>Returns</dt><dd>the error callback object for this stream, if set. </dd></dl>
-
-</div>
-</div>
-<a id="ab1e640461d7bf9d596decb913da7ac86"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ab1e640461d7bf9d596decb913da7ac86">&#9670;&nbsp;</a></span>getFormat()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a> oboe::AudioStreamBase::getFormat </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>the audio sample format (e.g. Float or I16) </dd></dl>
-
-</div>
-</div>
-<a id="a8878a90949badbb5486cc2e022a57086"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a8878a90949badbb5486cc2e022a57086">&#9670;&nbsp;</a></span>getFramesPerCallback()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::AudioStreamBase::getFramesPerCallback </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="deprecated"><dt><b><a class="el" href="deprecated.html#_deprecated000002">Deprecated:</a></b></dt><dd>use <code>getFramesPerDataCallback</code> instead. </dd></dl>
-
-</div>
-</div>
-<a id="abc3ee2815568b425d15a40e132aa8e38"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#abc3ee2815568b425d15a40e132aa8e38">&#9670;&nbsp;</a></span>getFramesPerDataCallback()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::AudioStreamBase::getFramesPerDataCallback </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>the number of frames in each data callback or kUnspecified. </dd></dl>
-
-</div>
-</div>
-<a id="a5c773b93b8aa38191c7199cab023428a"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a5c773b93b8aa38191c7199cab023428a">&#9670;&nbsp;</a></span>getInputPreset()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a> oboe::AudioStreamBase::getInputPreset </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>the stream's input preset. </dd></dl>
-
-</div>
-</div>
-<a id="a2ddb935de0e24dd7ae8e2cfbecac9fdc"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a2ddb935de0e24dd7ae8e2cfbecac9fdc">&#9670;&nbsp;</a></span>getPerformanceMode()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a> oboe::AudioStreamBase::getPerformanceMode </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>the performance mode of the stream. </dd></dl>
-
-</div>
-</div>
-<a id="ae9d32f3e09174bad69e74f147ee33087"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ae9d32f3e09174bad69e74f147ee33087">&#9670;&nbsp;</a></span>getSampleRate()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::AudioStreamBase::getSampleRate </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>sample rate for the stream or kUnspecified </dd></dl>
-
-</div>
-</div>
-<a id="a1de8d6982d411a0cf50a32efba0ca3f2"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a1de8d6982d411a0cf50a32efba0ca3f2">&#9670;&nbsp;</a></span>getSampleRateConversionQuality()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">SampleRateConversionQuality</a> oboe::AudioStreamBase::getSampleRateConversionQuality </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>whether and how Oboe can convert sample rates to achieve optimal results. </dd></dl>
-
-</div>
-</div>
-<a id="aa3c502ce09bbad7690a2dd6acaf8892e"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aa3c502ce09bbad7690a2dd6acaf8892e">&#9670;&nbsp;</a></span>getSessionId()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a> oboe::AudioStreamBase::getSessionId </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>the stream's session ID allocation strategy (None or Allocate). </dd></dl>
-
-</div>
-</div>
-<a id="a1fb033fc963f971bd1aa8f6707e49b41"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a1fb033fc963f971bd1aa8f6707e49b41">&#9670;&nbsp;</a></span>getSharingMode()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a> oboe::AudioStreamBase::getSharingMode </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>the sharing mode of the stream. </dd></dl>
-
-</div>
-</div>
-<a id="a0bcfb2f8bd11c92b541fd910da9af397"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a0bcfb2f8bd11c92b541fd910da9af397">&#9670;&nbsp;</a></span>getUsage()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a> oboe::AudioStreamBase::getUsage </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>the usage for this stream. </dd></dl>
-
-</div>
-</div>
-<a id="aa4ec3aa76e69350fbce6f00786211495"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aa4ec3aa76e69350fbce6f00786211495">&#9670;&nbsp;</a></span>isChannelConversionAllowed()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">bool oboe::AudioStreamBase::isChannelConversionAllowed </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>true if Oboe can convert channel counts to achieve optimal results. </dd></dl>
-
-</div>
-</div>
-<a id="a9a54d38b985a2eb12c6972104dc0ce73"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a9a54d38b985a2eb12c6972104dc0ce73">&#9670;&nbsp;</a></span>isDataCallbackSpecified()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">bool oboe::AudioStreamBase::isDataCallbackSpecified </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>true if a data callback was set for this stream </dd></dl>
-
-</div>
-</div>
-<a id="aef579f6d1f779c89d051f0963f2976b3"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aef579f6d1f779c89d051f0963f2976b3">&#9670;&nbsp;</a></span>isErrorCallbackSpecified()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">bool oboe::AudioStreamBase::isErrorCallbackSpecified </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Note that if the app does not set an error callback then a default one may be provided. </p><dl class="section return"><dt>Returns</dt><dd>true if an error callback was set for this stream </dd></dl>
-
-</div>
-</div>
-<a id="ace3625a7332bf02a86818fdf63fcccb4"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ace3625a7332bf02a86818fdf63fcccb4">&#9670;&nbsp;</a></span>isFormatConversionAllowed()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">bool oboe::AudioStreamBase::isFormatConversionAllowed </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>true if Oboe can convert data formats to achieve optimal results. </dd></dl>
-
-</div>
-</div>
-<a id="a5d5e07e98921d0193a5c0ccbe06f68c2"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a5d5e07e98921d0193a5c0ccbe06f68c2">&#9670;&nbsp;</a></span>isValidConfig()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStreamBase::isValidConfig </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">protected</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Validate stream parameters that might not be checked in lower layers </p>
-
-</div>
-</div>
-<a id="aa9c987a59555d7a60b9f7a63f4afc7fc"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aa9c987a59555d7a60b9f7a63f4afc7fc">&#9670;&nbsp;</a></span>operator=()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a>&amp; oboe::AudioStreamBase::operator= </td>
-          <td>(</td>
-          <td class="paramtype">const <a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> &amp;&#160;</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">default</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Default assignment operator </p>
-
-</div>
-</div>
-<h2 class="groupheader">Member Data Documentation</h2>
-<a id="ac81d4719b350f8138aad1af38f0873b6"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ac81d4719b350f8138aad1af38f0873b6">&#9670;&nbsp;</a></span>mBufferCapacityInFrames</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::AudioStreamBase::mBufferCapacityInFrames = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Stream buffer capacity specified as a number of audio frames </p>
-
-</div>
-</div>
-<a id="a3b65595d26d1eae1b8ce9925a5b98f6a"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a3b65595d26d1eae1b8ce9925a5b98f6a">&#9670;&nbsp;</a></span>mBufferSizeInFrames</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::AudioStreamBase::mBufferSizeInFrames = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Stream buffer size specified as a number of audio frames </p>
-
-</div>
-</div>
-<a id="a5ff460bac9d14dfeac4eeddfcbb6e206"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a5ff460bac9d14dfeac4eeddfcbb6e206">&#9670;&nbsp;</a></span>mChannelCount</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::AudioStreamBase::mChannelCount = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Stream channel count </p>
-
-</div>
-</div>
-<a id="a5f8f0e5add381b841856de80ea4cdb2b"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a5f8f0e5add381b841856de80ea4cdb2b">&#9670;&nbsp;</a></span>mContentType</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a> oboe::AudioStreamBase::mContentType = ContentType::Music</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Stream content type. Only active on Android 28+ </p>
-
-</div>
-</div>
-<a id="a6d8493f66a945cb426506c70f0358e5f"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a6d8493f66a945cb426506c70f0358e5f">&#9670;&nbsp;</a></span>mDataCallback</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a>* oboe::AudioStreamBase::mDataCallback = nullptr</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The callback which will be fired when new data is ready to be read/written. </p>
-
-</div>
-</div>
-<a id="a23dafa12fb1a6242b088ebd5a52798c8"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a23dafa12fb1a6242b088ebd5a52798c8">&#9670;&nbsp;</a></span>mDeviceId</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::AudioStreamBase::mDeviceId = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Stream audio device ID </p>
-
-</div>
-</div>
-<a id="a26e9294721561d3b16bcaeec5faf4880"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a26e9294721561d3b16bcaeec5faf4880">&#9670;&nbsp;</a></span>mDirection</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a> oboe::AudioStreamBase::mDirection = <a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54">Direction::Output</a></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Stream direction </p>
-
-</div>
-</div>
-<a id="adc0c8cc54adb6d3350c62b8a74b9c57b"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#adc0c8cc54adb6d3350c62b8a74b9c57b">&#9670;&nbsp;</a></span>mErrorCallback</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a>* oboe::AudioStreamBase::mErrorCallback = nullptr</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The callback which will be fired when an error or a disconnect occurs. </p>
-
-</div>
-</div>
-<a id="a7869f04836c2c2bdc10c7309ad4b8e09"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a7869f04836c2c2bdc10c7309ad4b8e09">&#9670;&nbsp;</a></span>mFormat</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a> oboe::AudioStreamBase::mFormat = AudioFormat::Unspecified</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Format of audio frames </p>
-
-</div>
-</div>
-<a id="a54061319ed348329a29d883a5de2482e"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a54061319ed348329a29d883a5de2482e">&#9670;&nbsp;</a></span>mFramesPerBurst</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::AudioStreamBase::mFramesPerBurst = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Number of frames which will be copied to/from the audio device in a single read/write operation </p>
-
-</div>
-</div>
-<a id="a3962eb94420ad0ecea70029236001899"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a3962eb94420ad0ecea70029236001899">&#9670;&nbsp;</a></span>mFramesPerCallback</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::AudioStreamBase::mFramesPerCallback = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Number of audio frames which will be requested in each callback </p>
-
-</div>
-</div>
-<a id="a1e5d4f5b30c4cc36f81ffd858cc00589"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a1e5d4f5b30c4cc36f81ffd858cc00589">&#9670;&nbsp;</a></span>mInputPreset</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a> oboe::AudioStreamBase::mInputPreset = InputPreset::VoiceRecognition</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Stream input preset. Only active on Android 28+ TODO InputPreset::Unspecified should be considered as a possible default alternative. </p>
-
-</div>
-</div>
-<a id="ab99671c2d0552557e75dc7b4afe91765"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ab99671c2d0552557e75dc7b4afe91765">&#9670;&nbsp;</a></span>mPerformanceMode</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a> oboe::AudioStreamBase::mPerformanceMode = PerformanceMode::None</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Stream performance mode </p>
-
-</div>
-</div>
-<a id="a998885bb6c4f37e145f4626ad4177dea"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a998885bb6c4f37e145f4626ad4177dea">&#9670;&nbsp;</a></span>mSampleRate</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::AudioStreamBase::mSampleRate = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Stream sample rate </p>
-
-</div>
-</div>
-<a id="abe1c1e9cada1ced9b5c1504ac9b07737"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#abe1c1e9cada1ced9b5c1504ac9b07737">&#9670;&nbsp;</a></span>mSessionId</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a> oboe::AudioStreamBase::mSessionId = SessionId::None</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Stream session ID allocation strategy. Only active on Android 28+ </p>
-
-</div>
-</div>
-<a id="ae9187492b679c97a0963e264954be473"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ae9187492b679c97a0963e264954be473">&#9670;&nbsp;</a></span>mSharingMode</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a> oboe::AudioStreamBase::mSharingMode = <a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca">SharingMode::Shared</a></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Stream sharing mode </p>
-
-</div>
-</div>
-<a id="a5b518e82f39c9fcbd7050fd66adb253c"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a5b518e82f39c9fcbd7050fd66adb253c">&#9670;&nbsp;</a></span>mUsage</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a> oboe::AudioStreamBase::mUsage = <a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74">Usage::Media</a></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">protected</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Stream usage. Only active on Android 28+ </p>
-
-</div>
-</div>
-<hr/>The documentation for this class was generated from the following file:<ul>
-<li>include/oboe/<a class="el" href="_audio_stream_base_8h_source.html">AudioStreamBase.h</a></li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_audio_stream_base.png b/docs/reference/classoboe_1_1_audio_stream_base.png
deleted file mode 100644
index b6af24a..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_base.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/classoboe_1_1_audio_stream_builder-members.html b/docs/reference/classoboe_1_1_audio_stream_builder-members.html
deleted file mode 100644
index 8356cd9..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_builder-members.html
+++ /dev/null
@@ -1,162 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Member List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe::AudioStreamBuilder Member List</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p>This is the complete list of members for <a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a>, including all inherited members.</p>
-<table class="directory">
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>AudioStreamBase</b>() (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa6b103e1b0f808bbc4949d56f0829f98">AudioStreamBase</a>(const AudioStreamBase &amp;)=default</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>AudioStreamBuilder</b>() (defined in <a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>AudioStreamBuilder</b>(const AudioStreamBase &amp;audioStreamBase) (defined in <a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#ac9d41811c297fd28bc61833f640bb8d0">getAudioApi</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab1531253e64aaebe9e9eddbafb9098fc">getBufferCapacityInFrames</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#af5217ab05bfde0d7637024b599302d0b">getBufferSizeInFrames</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a87e6bf37d6a2a5e983b8ca8d29aea575">getChannelCount</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab12e2d068fa87e0553b01a400d96eb82">getContentType</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a9fb2f34ae62dbda2c10e8513b754fa0c">getDataCallback</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a093057d625bc896864b959974c265f21">getDeviceId</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a6f86f2233a04c5a0b056f0c1c261f1b1">getDirection</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1328fb9288166ff325995ce1ea1867f0">getErrorCallback</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab1e640461d7bf9d596decb913da7ac86">getFormat</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a8878a90949badbb5486cc2e022a57086">getFramesPerCallback</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#abc3ee2815568b425d15a40e132aa8e38">getFramesPerDataCallback</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5c773b93b8aa38191c7199cab023428a">getInputPreset</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a2ddb935de0e24dd7ae8e2cfbecac9fdc">getPerformanceMode</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ae9d32f3e09174bad69e74f147ee33087">getSampleRate</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1de8d6982d411a0cf50a32efba0ca3f2">getSampleRateConversionQuality</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa3c502ce09bbad7690a2dd6acaf8892e">getSessionId</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1fb033fc963f971bd1aa8f6707e49b41">getSharingMode</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a0bcfb2f8bd11c92b541fd910da9af397">getUsage</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a622732bbe5c6577356d749f7dc2108df">isAAudioRecommended</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">static</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a18e7b5f7554a4c2ca763e35e8117d699">isAAudioSupported</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">static</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa4ec3aa76e69350fbce6f00786211495">isChannelConversionAllowed</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a9a54d38b985a2eb12c6972104dc0ce73">isDataCallbackSpecified</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aef579f6d1f779c89d051f0963f2976b3">isErrorCallbackSpecified</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ace3625a7332bf02a86818fdf63fcccb4">isFormatConversionAllowed</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5d5e07e98921d0193a5c0ccbe06f68c2">isValidConfig</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">protected</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6">mBufferCapacityInFrames</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a3b65595d26d1eae1b8ce9925a5b98f6a">mBufferSizeInFrames</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>mChannelConversionAllowed</b> (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">mChannelCount</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b">mContentType</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">mDataCallback</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8">mDeviceId</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880">mDirection</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">mErrorCallback</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">mFormat</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>mFormatConversionAllowed</b> (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a54061319ed348329a29d883a5de2482e">mFramesPerBurst</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899">mFramesPerCallback</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589">mInputPreset</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765">mPerformanceMode</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea">mSampleRate</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>mSampleRateConversionQuality</b> (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737">mSessionId</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473">mSharingMode</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c">mUsage</a></td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a7ab172a9be4fca2489aa5cbcc48c20ff">openManagedStream</a>(ManagedStream &amp;stream)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a86b94cfa47729bef2e04dce1a9086074">openStream</a>(AudioStream **stream)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a44b68216c48f8fb08a9e63178e0b0eeb">openStream</a>(std::shared_ptr&lt; oboe::AudioStream &gt; &amp;stream)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa9c987a59555d7a60b9f7a63f4afc7fc">operator=</a>(const AudioStreamBase &amp;)=default</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a38c6d6c5e718df1e3ac69daaac47c391">setAudioApi</a>(AudioApi audioApi)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#abaff480867af51ca0899bfa6fd7cc3ef">setBufferCapacityInFrames</a>(int32_t bufferCapacityInFrames)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a698cefa9af73bc97c020c004821fccbd">setCallback</a>(AudioStreamCallback *streamCallback)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#ad50f5d20cdf420d982bf499790cd3563">setChannelConversionAllowed</a>(bool allowed)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a075d10291e1f998d90c2f73ef767b5a7">setChannelCount</a>(int channelCount)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a6a17bafc217c2b624179fbbf77fe4468">setContentType</a>(ContentType contentType)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#acad307720e0f370267b4e2f9a626ae70">setDataCallback</a>(oboe::AudioStreamDataCallback *dataCallback)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#af36ddcd00686a9e1de661bdac0685a8e">setDeviceId</a>(int32_t deviceId)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#ab3fbd47b06197619c26393637e26354c">setDirection</a>(Direction direction)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#aacb66f530bfc6f545911b5e169774567">setErrorCallback</a>(oboe::AudioStreamErrorCallback *errorCallback)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#aa2e1d2d73cd6c2eb9f349bf2fe5f6515">setFormat</a>(AudioFormat format)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a7ec5f427cd6fe55cb1ce536ff0cbb4d2">setFormatConversionAllowed</a>(bool allowed)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a3f397821f61eabaeedaf31064c859a54">setFramesPerCallback</a>(int framesPerCallback)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#afb8e95e80df7edd1af27af490438785e">setFramesPerDataCallback</a>(int framesPerCallback)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a144a3d095fd668210282f1a91f23e1f0">setInputPreset</a>(InputPreset inputPreset)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a6cd1d65612e844e59da71a68ea0ab3ee">setPerformanceMode</a>(PerformanceMode performanceMode)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a30ef3d5f51d56a9f980dc09600ed139d">setSampleRate</a>(int32_t sampleRate)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#af7d24a9ec975d430732151e5ee0d1027">setSampleRateConversionQuality</a>(SampleRateConversionQuality quality)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a54c1651bdbe089d0d714af499e8a5f1d">setSessionId</a>(SessionId sessionId)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a3e991742acbbfb6fe5ebcf592c478654">setSharingMode</a>(SharingMode sharingMode)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a593255a2f5eb972665775cfc5bc58f6a">setUsage</a>(Usage usage)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html#aa07ea100fcb107d9f7913f206c2214f4">willUseAAudio</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_builder.html">oboe::AudioStreamBuilder</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>~AudioStreamBase</b>()=default (defined in <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-</table></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_audio_stream_builder.html b/docs/reference/classoboe_1_1_audio_stream_builder.html
deleted file mode 100644
index 78c1e16..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_builder.html
+++ /dev/null
@@ -1,1162 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe::AudioStreamBuilder Class Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="#pub-methods">Public Member Functions</a> &#124;
-<a href="#pub-static-methods">Static Public Member Functions</a> &#124;
-<a href="classoboe_1_1_audio_stream_builder-members.html">List of all members</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe::AudioStreamBuilder Class Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p><code>#include &lt;<a class="el" href="_audio_stream_builder_8h_source.html">AudioStreamBuilder.h</a>&gt;</code></p>
-<div class="dynheader">
-Inheritance diagram for oboe::AudioStreamBuilder:</div>
-<div class="dyncontent">
- <div class="center">
-  <img src="classoboe_1_1_audio_stream_builder.png" usemap="#oboe::AudioStreamBuilder_map" alt=""/>
-  <map id="oboe::AudioStreamBuilder_map" name="oboe::AudioStreamBuilder_map">
-<area href="classoboe_1_1_audio_stream_base.html" alt="oboe::AudioStreamBase" shape="rect" coords="0,0,158,24"/>
-  </map>
-</div></div>
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-methods"></a>
-Public Member Functions</h2></td></tr>
-<tr class="memitem:a8f2cc75bfce8d839bf72ca8fb4a0793a"><td class="memItemLeft" align="right" valign="top"><a id="a8f2cc75bfce8d839bf72ca8fb4a0793a"></a>
-&#160;</td><td class="memItemRight" valign="bottom"><b>AudioStreamBuilder</b> (const <a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> &amp;audioStreamBase)</td></tr>
-<tr class="separator:a8f2cc75bfce8d839bf72ca8fb4a0793a"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a075d10291e1f998d90c2f73ef767b5a7"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a075d10291e1f998d90c2f73ef767b5a7">setChannelCount</a> (int channelCount)</td></tr>
-<tr class="separator:a075d10291e1f998d90c2f73ef767b5a7"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab3fbd47b06197619c26393637e26354c"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#ab3fbd47b06197619c26393637e26354c">setDirection</a> (<a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a> direction)</td></tr>
-<tr class="separator:ab3fbd47b06197619c26393637e26354c"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a30ef3d5f51d56a9f980dc09600ed139d"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a30ef3d5f51d56a9f980dc09600ed139d">setSampleRate</a> (int32_t sampleRate)</td></tr>
-<tr class="separator:a30ef3d5f51d56a9f980dc09600ed139d"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a3f397821f61eabaeedaf31064c859a54"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a3f397821f61eabaeedaf31064c859a54">setFramesPerCallback</a> (int framesPerCallback)</td></tr>
-<tr class="separator:a3f397821f61eabaeedaf31064c859a54"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:afb8e95e80df7edd1af27af490438785e"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#afb8e95e80df7edd1af27af490438785e">setFramesPerDataCallback</a> (int framesPerCallback)</td></tr>
-<tr class="separator:afb8e95e80df7edd1af27af490438785e"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aa2e1d2d73cd6c2eb9f349bf2fe5f6515"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#aa2e1d2d73cd6c2eb9f349bf2fe5f6515">setFormat</a> (<a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a> format)</td></tr>
-<tr class="separator:aa2e1d2d73cd6c2eb9f349bf2fe5f6515"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:abaff480867af51ca0899bfa6fd7cc3ef"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#abaff480867af51ca0899bfa6fd7cc3ef">setBufferCapacityInFrames</a> (int32_t bufferCapacityInFrames)</td></tr>
-<tr class="separator:abaff480867af51ca0899bfa6fd7cc3ef"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ac9d41811c297fd28bc61833f640bb8d0"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">AudioApi</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#ac9d41811c297fd28bc61833f640bb8d0">getAudioApi</a> () const</td></tr>
-<tr class="separator:ac9d41811c297fd28bc61833f640bb8d0"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a38c6d6c5e718df1e3ac69daaac47c391"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a38c6d6c5e718df1e3ac69daaac47c391">setAudioApi</a> (<a class="el" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">AudioApi</a> audioApi)</td></tr>
-<tr class="separator:a38c6d6c5e718df1e3ac69daaac47c391"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a3e991742acbbfb6fe5ebcf592c478654"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a3e991742acbbfb6fe5ebcf592c478654">setSharingMode</a> (<a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a> sharingMode)</td></tr>
-<tr class="separator:a3e991742acbbfb6fe5ebcf592c478654"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a6cd1d65612e844e59da71a68ea0ab3ee"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a6cd1d65612e844e59da71a68ea0ab3ee">setPerformanceMode</a> (<a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a> performanceMode)</td></tr>
-<tr class="separator:a6cd1d65612e844e59da71a68ea0ab3ee"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a593255a2f5eb972665775cfc5bc58f6a"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a593255a2f5eb972665775cfc5bc58f6a">setUsage</a> (<a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a> usage)</td></tr>
-<tr class="separator:a593255a2f5eb972665775cfc5bc58f6a"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a6a17bafc217c2b624179fbbf77fe4468"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a6a17bafc217c2b624179fbbf77fe4468">setContentType</a> (<a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a> contentType)</td></tr>
-<tr class="separator:a6a17bafc217c2b624179fbbf77fe4468"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a144a3d095fd668210282f1a91f23e1f0"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a144a3d095fd668210282f1a91f23e1f0">setInputPreset</a> (<a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a> inputPreset)</td></tr>
-<tr class="separator:a144a3d095fd668210282f1a91f23e1f0"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a54c1651bdbe089d0d714af499e8a5f1d"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a54c1651bdbe089d0d714af499e8a5f1d">setSessionId</a> (<a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a> sessionId)</td></tr>
-<tr class="separator:a54c1651bdbe089d0d714af499e8a5f1d"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:af36ddcd00686a9e1de661bdac0685a8e"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#af36ddcd00686a9e1de661bdac0685a8e">setDeviceId</a> (int32_t deviceId)</td></tr>
-<tr class="separator:af36ddcd00686a9e1de661bdac0685a8e"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:acad307720e0f370267b4e2f9a626ae70"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#acad307720e0f370267b4e2f9a626ae70">setDataCallback</a> (<a class="el" href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a> *dataCallback)</td></tr>
-<tr class="separator:acad307720e0f370267b4e2f9a626ae70"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aacb66f530bfc6f545911b5e169774567"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#aacb66f530bfc6f545911b5e169774567">setErrorCallback</a> (<a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a> *errorCallback)</td></tr>
-<tr class="separator:aacb66f530bfc6f545911b5e169774567"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a698cefa9af73bc97c020c004821fccbd"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a698cefa9af73bc97c020c004821fccbd">setCallback</a> (<a class="el" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a> *streamCallback)</td></tr>
-<tr class="separator:a698cefa9af73bc97c020c004821fccbd"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ad50f5d20cdf420d982bf499790cd3563"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#ad50f5d20cdf420d982bf499790cd3563">setChannelConversionAllowed</a> (bool allowed)</td></tr>
-<tr class="separator:ad50f5d20cdf420d982bf499790cd3563"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a7ec5f427cd6fe55cb1ce536ff0cbb4d2"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a7ec5f427cd6fe55cb1ce536ff0cbb4d2">setFormatConversionAllowed</a> (bool allowed)</td></tr>
-<tr class="separator:a7ec5f427cd6fe55cb1ce536ff0cbb4d2"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:af7d24a9ec975d430732151e5ee0d1027"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#af7d24a9ec975d430732151e5ee0d1027">setSampleRateConversionQuality</a> (<a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">SampleRateConversionQuality</a> quality)</td></tr>
-<tr class="separator:af7d24a9ec975d430732151e5ee0d1027"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aa07ea100fcb107d9f7913f206c2214f4"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#aa07ea100fcb107d9f7913f206c2214f4">willUseAAudio</a> () const</td></tr>
-<tr class="separator:aa07ea100fcb107d9f7913f206c2214f4"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a86b94cfa47729bef2e04dce1a9086074"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a86b94cfa47729bef2e04dce1a9086074">openStream</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> **stream)</td></tr>
-<tr class="separator:a86b94cfa47729bef2e04dce1a9086074"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a44b68216c48f8fb08a9e63178e0b0eeb"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a44b68216c48f8fb08a9e63178e0b0eeb">openStream</a> (std::shared_ptr&lt; <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a> &gt; &amp;stream)</td></tr>
-<tr class="separator:a44b68216c48f8fb08a9e63178e0b0eeb"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a7ab172a9be4fca2489aa5cbcc48c20ff"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a7ab172a9be4fca2489aa5cbcc48c20ff">openManagedStream</a> (ManagedStream &amp;stream)</td></tr>
-<tr class="separator:a7ab172a9be4fca2489aa5cbcc48c20ff"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="inherit_header pub_methods_classoboe_1_1_audio_stream_base"><td colspan="2" onclick="javascript:toggleInherit('pub_methods_classoboe_1_1_audio_stream_base')"><img src="closed.png" alt="-"/>&#160;Public Member Functions inherited from <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td></tr>
-<tr class="memitem:aa6b103e1b0f808bbc4949d56f0829f98 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa6b103e1b0f808bbc4949d56f0829f98">AudioStreamBase</a> (const <a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> &amp;)=default</td></tr>
-<tr class="separator:aa6b103e1b0f808bbc4949d56f0829f98 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aa9c987a59555d7a60b9f7a63f4afc7fc inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> &amp;&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa9c987a59555d7a60b9f7a63f4afc7fc">operator=</a> (const <a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a> &amp;)=default</td></tr>
-<tr class="separator:aa9c987a59555d7a60b9f7a63f4afc7fc inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a87e6bf37d6a2a5e983b8ca8d29aea575 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a87e6bf37d6a2a5e983b8ca8d29aea575">getChannelCount</a> () const</td></tr>
-<tr class="separator:a87e6bf37d6a2a5e983b8ca8d29aea575 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a6f86f2233a04c5a0b056f0c1c261f1b1 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a6f86f2233a04c5a0b056f0c1c261f1b1">getDirection</a> () const</td></tr>
-<tr class="separator:a6f86f2233a04c5a0b056f0c1c261f1b1 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ae9d32f3e09174bad69e74f147ee33087 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ae9d32f3e09174bad69e74f147ee33087">getSampleRate</a> () const</td></tr>
-<tr class="separator:ae9d32f3e09174bad69e74f147ee33087 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a8878a90949badbb5486cc2e022a57086 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a8878a90949badbb5486cc2e022a57086">getFramesPerCallback</a> () const</td></tr>
-<tr class="separator:a8878a90949badbb5486cc2e022a57086 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:abc3ee2815568b425d15a40e132aa8e38 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#abc3ee2815568b425d15a40e132aa8e38">getFramesPerDataCallback</a> () const</td></tr>
-<tr class="separator:abc3ee2815568b425d15a40e132aa8e38 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab1e640461d7bf9d596decb913da7ac86 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab1e640461d7bf9d596decb913da7ac86">getFormat</a> () const</td></tr>
-<tr class="separator:ab1e640461d7bf9d596decb913da7ac86 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:af5217ab05bfde0d7637024b599302d0b inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">virtual int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#af5217ab05bfde0d7637024b599302d0b">getBufferSizeInFrames</a> ()</td></tr>
-<tr class="separator:af5217ab05bfde0d7637024b599302d0b inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab1531253e64aaebe9e9eddbafb9098fc inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">virtual int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab1531253e64aaebe9e9eddbafb9098fc">getBufferCapacityInFrames</a> () const</td></tr>
-<tr class="separator:ab1531253e64aaebe9e9eddbafb9098fc inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a1fb033fc963f971bd1aa8f6707e49b41 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1fb033fc963f971bd1aa8f6707e49b41">getSharingMode</a> () const</td></tr>
-<tr class="separator:a1fb033fc963f971bd1aa8f6707e49b41 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a2ddb935de0e24dd7ae8e2cfbecac9fdc inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a2ddb935de0e24dd7ae8e2cfbecac9fdc">getPerformanceMode</a> () const</td></tr>
-<tr class="separator:a2ddb935de0e24dd7ae8e2cfbecac9fdc inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a093057d625bc896864b959974c265f21 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a093057d625bc896864b959974c265f21">getDeviceId</a> () const</td></tr>
-<tr class="separator:a093057d625bc896864b959974c265f21 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a9fb2f34ae62dbda2c10e8513b754fa0c inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a9fb2f34ae62dbda2c10e8513b754fa0c">getDataCallback</a> () const</td></tr>
-<tr class="separator:a9fb2f34ae62dbda2c10e8513b754fa0c inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a1328fb9288166ff325995ce1ea1867f0 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1328fb9288166ff325995ce1ea1867f0">getErrorCallback</a> () const</td></tr>
-<tr class="separator:a1328fb9288166ff325995ce1ea1867f0 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a9a54d38b985a2eb12c6972104dc0ce73 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a9a54d38b985a2eb12c6972104dc0ce73">isDataCallbackSpecified</a> () const</td></tr>
-<tr class="separator:a9a54d38b985a2eb12c6972104dc0ce73 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aef579f6d1f779c89d051f0963f2976b3 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aef579f6d1f779c89d051f0963f2976b3">isErrorCallbackSpecified</a> () const</td></tr>
-<tr class="separator:aef579f6d1f779c89d051f0963f2976b3 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a0bcfb2f8bd11c92b541fd910da9af397 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a0bcfb2f8bd11c92b541fd910da9af397">getUsage</a> () const</td></tr>
-<tr class="separator:a0bcfb2f8bd11c92b541fd910da9af397 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab12e2d068fa87e0553b01a400d96eb82 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab12e2d068fa87e0553b01a400d96eb82">getContentType</a> () const</td></tr>
-<tr class="separator:ab12e2d068fa87e0553b01a400d96eb82 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5c773b93b8aa38191c7199cab023428a inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5c773b93b8aa38191c7199cab023428a">getInputPreset</a> () const</td></tr>
-<tr class="separator:a5c773b93b8aa38191c7199cab023428a inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aa3c502ce09bbad7690a2dd6acaf8892e inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa3c502ce09bbad7690a2dd6acaf8892e">getSessionId</a> () const</td></tr>
-<tr class="separator:aa3c502ce09bbad7690a2dd6acaf8892e inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aa4ec3aa76e69350fbce6f00786211495 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#aa4ec3aa76e69350fbce6f00786211495">isChannelConversionAllowed</a> () const</td></tr>
-<tr class="separator:aa4ec3aa76e69350fbce6f00786211495 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ace3625a7332bf02a86818fdf63fcccb4 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ace3625a7332bf02a86818fdf63fcccb4">isFormatConversionAllowed</a> () const</td></tr>
-<tr class="separator:ace3625a7332bf02a86818fdf63fcccb4 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a1de8d6982d411a0cf50a32efba0ca3f2 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">SampleRateConversionQuality</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1de8d6982d411a0cf50a32efba0ca3f2">getSampleRateConversionQuality</a> () const</td></tr>
-<tr class="separator:a1de8d6982d411a0cf50a32efba0ca3f2 inherit pub_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table><table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-static-methods"></a>
-Static Public Member Functions</h2></td></tr>
-<tr class="memitem:a18e7b5f7554a4c2ca763e35e8117d699"><td class="memItemLeft" align="right" valign="top">static bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a18e7b5f7554a4c2ca763e35e8117d699">isAAudioSupported</a> ()</td></tr>
-<tr class="separator:a18e7b5f7554a4c2ca763e35e8117d699"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a622732bbe5c6577356d749f7dc2108df"><td class="memItemLeft" align="right" valign="top">static bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html#a622732bbe5c6577356d749f7dc2108df">isAAudioRecommended</a> ()</td></tr>
-<tr class="separator:a622732bbe5c6577356d749f7dc2108df"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table><table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="inherited"></a>
-Additional Inherited Members</h2></td></tr>
-<tr class="inherit_header pro_methods_classoboe_1_1_audio_stream_base"><td colspan="2" onclick="javascript:toggleInherit('pro_methods_classoboe_1_1_audio_stream_base')"><img src="closed.png" alt="-"/>&#160;Protected Member Functions inherited from <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td></tr>
-<tr class="memitem:a5d5e07e98921d0193a5c0ccbe06f68c2 inherit pro_methods_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5d5e07e98921d0193a5c0ccbe06f68c2">isValidConfig</a> ()</td></tr>
-<tr class="separator:a5d5e07e98921d0193a5c0ccbe06f68c2 inherit pro_methods_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="inherit_header pro_attribs_classoboe_1_1_audio_stream_base"><td colspan="2" onclick="javascript:toggleInherit('pro_attribs_classoboe_1_1_audio_stream_base')"><img src="closed.png" alt="-"/>&#160;Protected Attributes inherited from <a class="el" href="classoboe_1_1_audio_stream_base.html">oboe::AudioStreamBase</a></td></tr>
-<tr class="memitem:a6d8493f66a945cb426506c70f0358e5f inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">mDataCallback</a> = nullptr</td></tr>
-<tr class="separator:a6d8493f66a945cb426506c70f0358e5f inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:adc0c8cc54adb6d3350c62b8a74b9c57b inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">mErrorCallback</a> = nullptr</td></tr>
-<tr class="separator:adc0c8cc54adb6d3350c62b8a74b9c57b inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a3962eb94420ad0ecea70029236001899 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899">mFramesPerCallback</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a3962eb94420ad0ecea70029236001899 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5ff460bac9d14dfeac4eeddfcbb6e206 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">mChannelCount</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a5ff460bac9d14dfeac4eeddfcbb6e206 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a998885bb6c4f37e145f4626ad4177dea inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea">mSampleRate</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a998885bb6c4f37e145f4626ad4177dea inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a23dafa12fb1a6242b088ebd5a52798c8 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8">mDeviceId</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a23dafa12fb1a6242b088ebd5a52798c8 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ac81d4719b350f8138aad1af38f0873b6 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6">mBufferCapacityInFrames</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:ac81d4719b350f8138aad1af38f0873b6 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a3b65595d26d1eae1b8ce9925a5b98f6a inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a3b65595d26d1eae1b8ce9925a5b98f6a">mBufferSizeInFrames</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a3b65595d26d1eae1b8ce9925a5b98f6a inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a54061319ed348329a29d883a5de2482e inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a54061319ed348329a29d883a5de2482e">mFramesPerBurst</a> = <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a></td></tr>
-<tr class="separator:a54061319ed348329a29d883a5de2482e inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ae9187492b679c97a0963e264954be473 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473">mSharingMode</a> = <a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca">SharingMode::Shared</a></td></tr>
-<tr class="separator:ae9187492b679c97a0963e264954be473 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a7869f04836c2c2bdc10c7309ad4b8e09 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">mFormat</a> = AudioFormat::Unspecified</td></tr>
-<tr class="separator:a7869f04836c2c2bdc10c7309ad4b8e09 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a26e9294721561d3b16bcaeec5faf4880 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880">mDirection</a> = <a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54">Direction::Output</a></td></tr>
-<tr class="separator:a26e9294721561d3b16bcaeec5faf4880 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab99671c2d0552557e75dc7b4afe91765 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765">mPerformanceMode</a> = PerformanceMode::None</td></tr>
-<tr class="separator:ab99671c2d0552557e75dc7b4afe91765 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5b518e82f39c9fcbd7050fd66adb253c inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c">mUsage</a> = <a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74">Usage::Media</a></td></tr>
-<tr class="separator:a5b518e82f39c9fcbd7050fd66adb253c inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5f8f0e5add381b841856de80ea4cdb2b inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b">mContentType</a> = ContentType::Music</td></tr>
-<tr class="separator:a5f8f0e5add381b841856de80ea4cdb2b inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a1e5d4f5b30c4cc36f81ffd858cc00589 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589">mInputPreset</a> = InputPreset::VoiceRecognition</td></tr>
-<tr class="separator:a1e5d4f5b30c4cc36f81ffd858cc00589 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:abe1c1e9cada1ced9b5c1504ac9b07737 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737">mSessionId</a> = SessionId::None</td></tr>
-<tr class="separator:abe1c1e9cada1ced9b5c1504ac9b07737 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ae47a39b573250751f933dd159d09bf0f inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a id="ae47a39b573250751f933dd159d09bf0f"></a>
-bool&#160;</td><td class="memItemRight" valign="bottom"><b>mChannelConversionAllowed</b> = false</td></tr>
-<tr class="separator:ae47a39b573250751f933dd159d09bf0f inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a9394a88eb5f8b74fa72eabf28f403f87 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a id="a9394a88eb5f8b74fa72eabf28f403f87"></a>
-bool&#160;</td><td class="memItemRight" valign="bottom"><b>mFormatConversionAllowed</b> = false</td></tr>
-<tr class="separator:a9394a88eb5f8b74fa72eabf28f403f87 inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a2dd35a6f009f36172838260144218f6d inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memItemLeft" align="right" valign="top"><a id="a2dd35a6f009f36172838260144218f6d"></a>
-<a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">SampleRateConversionQuality</a>&#160;</td><td class="memItemRight" valign="bottom"><b>mSampleRateConversionQuality</b> = SampleRateConversionQuality::None</td></tr>
-<tr class="separator:a2dd35a6f009f36172838260144218f6d inherit pro_attribs_classoboe_1_1_audio_stream_base"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
-<div class="textblock"><p>Factory class for an audio Stream. </p>
-</div><h2 class="groupheader">Member Function Documentation</h2>
-<a id="ac9d41811c297fd28bc61833f640bb8d0"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ac9d41811c297fd28bc61833f640bb8d0">&#9670;&nbsp;</a></span>getAudioApi()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">AudioApi</a> oboe::AudioStreamBuilder::getAudioApi </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Get the audio API which will be requested when opening the stream. No guarantees that this is the API which will actually be used. Query the stream itself to find out the API which is being used.</p>
-<p>If you do not specify the API, then AAudio will be used if <a class="el" href="classoboe_1_1_audio_stream_builder.html#a622732bbe5c6577356d749f7dc2108df">isAAudioRecommended()</a> returns true. Otherwise OpenSL ES will be used.</p>
-<dl class="section return"><dt>Returns</dt><dd>the requested audio API </dd></dl>
-
-</div>
-</div>
-<a id="a622732bbe5c6577356d749f7dc2108df"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a622732bbe5c6577356d749f7dc2108df">&#9670;&nbsp;</a></span>isAAudioRecommended()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">static bool oboe::AudioStreamBuilder::isAAudioRecommended </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">static</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Is the AAudio API recommended this device?</p>
-<p>AAudio may be supported but not recommended because of version specific issues. AAudio is not recommended for Android 8.0 or earlier versions.</p>
-<dl class="section return"><dt>Returns</dt><dd>true if recommended </dd></dl>
-
-</div>
-</div>
-<a id="a18e7b5f7554a4c2ca763e35e8117d699"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a18e7b5f7554a4c2ca763e35e8117d699">&#9670;&nbsp;</a></span>isAAudioSupported()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">static bool oboe::AudioStreamBuilder::isAAudioSupported </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">static</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Is the AAudio API supported on this device?</p>
-<p>AAudio was introduced in the Oreo 8.0 release.</p>
-<dl class="section return"><dt>Returns</dt><dd>true if supported </dd></dl>
-
-</div>
-</div>
-<a id="a7ab172a9be4fca2489aa5cbcc48c20ff"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a7ab172a9be4fca2489aa5cbcc48c20ff">&#9670;&nbsp;</a></span>openManagedStream()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStreamBuilder::openManagedStream </td>
-          <td>(</td>
-          <td class="paramtype">ManagedStream &amp;&#160;</td>
-          <td class="paramname"><em>stream</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>Create and open a ManagedStream object based on the current builder state.</p>
-<p>The caller must create a unique ptr, and pass by reference so it can be modified to point to an opened stream. The caller owns the unique ptr, and it will be automatically closed and deleted when going out of scope. </p><dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">stream</td><td>Reference to the ManagedStream (uniqueptr) used to keep track of stream </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>OBOE_OK if successful or a negative error code. </dd></dl>
-
-</div>
-</div>
-<a id="a86b94cfa47729bef2e04dce1a9086074"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a86b94cfa47729bef2e04dce1a9086074">&#9670;&nbsp;</a></span>openStream() <span class="overload">[1/2]</span></h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStreamBuilder::openStream </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> **&#160;</td>
-          <td class="paramname"><em>stream</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>Create and open a stream object based on the current settings.</p>
-<p>The caller owns the pointer to the <a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> object.</p>
-<dl class="deprecated"><dt><b><a class="el" href="deprecated.html#_deprecated000004">Deprecated:</a></b></dt><dd>Use <a class="el" href="classoboe_1_1_audio_stream_builder.html#a44b68216c48f8fb08a9e63178e0b0eeb">openStream(std::shared_ptr&lt;oboe::AudioStream&gt; &amp;stream)</a> instead. </dd></dl>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">stream</td><td>pointer to a variable to receive the stream address </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>OBOE_OK if successful or a negative error code </dd></dl>
-
-</div>
-</div>
-<a id="a44b68216c48f8fb08a9e63178e0b0eeb"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a44b68216c48f8fb08a9e63178e0b0eeb">&#9670;&nbsp;</a></span>openStream() <span class="overload">[2/2]</span></h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::AudioStreamBuilder::openStream </td>
-          <td>(</td>
-          <td class="paramtype">std::shared_ptr&lt; <a class="el" href="classoboe_1_1_audio_stream.html">oboe::AudioStream</a> &gt; &amp;&#160;</td>
-          <td class="paramname"><em>stream</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>Create and open a stream object based on the current settings.</p>
-<p>The caller shares the pointer to the <a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> object. The shared_ptr is used internally by Oboe to prevent the stream from being deleted while it is being used by callbacks.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">stream</td><td>reference to a shared_ptr to receive the stream address </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>OBOE_OK if successful or a negative error code </dd></dl>
-
-</div>
-</div>
-<a id="a38c6d6c5e718df1e3ac69daaac47c391"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a38c6d6c5e718df1e3ac69daaac47c391">&#9670;&nbsp;</a></span>setAudioApi()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setAudioApi </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">AudioApi</a>&#160;</td>
-          <td class="paramname"><em>audioApi</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>If you leave this unspecified then Oboe will choose the best API for the device and SDK version at runtime.</p>
-<p>This should almost always be left unspecified, except for debugging purposes. Specifying AAudio will force Oboe to use AAudio on 8.0, which is extremely risky. Specifying OpenSLES should mainly be used to test legacy performance/functionality.</p>
-<p>If the caller requests AAudio and it is supported then AAudio will be used.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">audioApi</td><td>Must be AudioApi::Unspecified, <a class="el" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a24e758ea9c1e842ef71cc8ff8b63fa9b">AudioApi::OpenSLES</a> or <a class="el" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a99780b1e8d754eb42abed0ca5253e55b">AudioApi::AAudio</a>. </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>pointer to the builder so calls can be chained </dd></dl>
-
-</div>
-</div>
-<a id="abaff480867af51ca0899bfa6fd7cc3ef"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#abaff480867af51ca0899bfa6fd7cc3ef">&#9670;&nbsp;</a></span>setBufferCapacityInFrames()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setBufferCapacityInFrames </td>
-          <td>(</td>
-          <td class="paramtype">int32_t&#160;</td>
-          <td class="paramname"><em>bufferCapacityInFrames</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Set the requested buffer capacity in frames. BufferCapacityInFrames is the maximum possible BufferSizeInFrames.</p>
-<p>The final stream capacity may differ. For AAudio it should be at least this big. For OpenSL ES, it could be smaller.</p>
-<p>Default is kUnspecified.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">bufferCapacityInFrames</td><td>the desired buffer capacity in frames or kUnspecified </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>pointer to the builder so calls can be chained </dd></dl>
-
-</div>
-</div>
-<a id="a698cefa9af73bc97c020c004821fccbd"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a698cefa9af73bc97c020c004821fccbd">&#9670;&nbsp;</a></span>setCallback()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setCallback </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a> *&#160;</td>
-          <td class="paramname"><em>streamCallback</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Specifies an object to handle data or error related callbacks from the underlying API.</p>
-<p>This is the equivalent of calling both <a class="el" href="classoboe_1_1_audio_stream_builder.html#acad307720e0f370267b4e2f9a626ae70">setDataCallback()</a> and <a class="el" href="classoboe_1_1_audio_stream_builder.html#aacb66f530bfc6f545911b5e169774567">setErrorCallback()</a>.</p>
-<p><b>Important: See <a class="el" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a> for restrictions on what may be called from the callback methods.</b></p>
-<p>When an error callback occurs, the associated stream will be stopped and closed in a separate thread.</p>
-<p>A note on why the streamCallback parameter is a raw pointer rather than a smart pointer:</p>
-<p>The caller should retain ownership of the object streamCallback points to. At first glance weak_ptr may seem like a good candidate for streamCallback as this implies temporary ownership. However, a weak_ptr can only be created from a shared_ptr. A shared_ptr incurs some performance overhead. The callback object is likely to be accessed every few milliseconds when the stream requires new data so this overhead is something we want to avoid.</p>
-<p>This leaves a raw pointer as the logical type choice. The only caveat being that the caller must not destroy the callback before the stream has been closed.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">streamCallback</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>pointer to the builder so calls can be chained </dd></dl>
-
-</div>
-</div>
-<a id="ad50f5d20cdf420d982bf499790cd3563"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ad50f5d20cdf420d982bf499790cd3563">&#9670;&nbsp;</a></span>setChannelConversionAllowed()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setChannelConversionAllowed </td>
-          <td>(</td>
-          <td class="paramtype">bool&#160;</td>
-          <td class="paramname"><em>allowed</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>If true then Oboe might convert channel counts to achieve optimal results. On some versions of Android for example, stereo streams could not use a FAST track. So a mono stream might be used instead and duplicated to two channels. On some devices, mono streams might be broken, so a stereo stream might be opened and converted to mono.</p>
-<p>Default is true. </p>
-
-</div>
-</div>
-<a id="a075d10291e1f998d90c2f73ef767b5a7"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a075d10291e1f998d90c2f73ef767b5a7">&#9670;&nbsp;</a></span>setChannelCount()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setChannelCount </td>
-          <td>(</td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>channelCount</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Request a specific number of channels.</p>
-<p>Default is kUnspecified. If the value is unspecified then the application should query for the actual value after the stream is opened. </p>
-
-</div>
-</div>
-<a id="a6a17bafc217c2b624179fbbf77fe4468"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a6a17bafc217c2b624179fbbf77fe4468">&#9670;&nbsp;</a></span>setContentType()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setContentType </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a>&#160;</td>
-          <td class="paramname"><em>contentType</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Set the type of audio data that an output stream will carry.</p>
-<p>The system will use this information to optimize the behavior of the stream. This could, for example, affect whether a stream is paused when a notification occurs. The contentType is ignored for input streams.</p>
-<p>The default, if you do not call this function, is ContentType::Music.</p>
-<p>Added in API level 28.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">contentType</td><td>the type of audio data, eg. ContentType::Speech </td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<a id="acad307720e0f370267b4e2f9a626ae70"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#acad307720e0f370267b4e2f9a626ae70">&#9670;&nbsp;</a></span>setDataCallback()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setDataCallback </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a> *&#160;</td>
-          <td class="paramname"><em>dataCallback</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Specifies an object to handle data related callbacks from the underlying API.</p>
-<p><b>Important: See <a class="el" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a> for restrictions on what may be called from the callback methods.</b></p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">dataCallback</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>pointer to the builder so calls can be chained </dd></dl>
-
-</div>
-</div>
-<a id="af36ddcd00686a9e1de661bdac0685a8e"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#af36ddcd00686a9e1de661bdac0685a8e">&#9670;&nbsp;</a></span>setDeviceId()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setDeviceId </td>
-          <td>(</td>
-          <td class="paramtype">int32_t&#160;</td>
-          <td class="paramname"><em>deviceId</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Request a stream to a specific audio input/output device given an audio device ID.</p>
-<p>In most cases, the primary device will be the appropriate device to use, and the deviceId can be left kUnspecified.</p>
-<p>On Android, for example, the ID could be obtained from the Java AudioManager. AudioManager.getDevices() returns an array of AudioDeviceInfo[], which contains a getId() method (as well as other type information), that should be passed to this method.</p>
-<p>Note that when using OpenSL ES, this will be ignored and the created stream will have deviceId kUnspecified.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">deviceId</td><td>device identifier or kUnspecified </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>pointer to the builder so calls can be chained </dd></dl>
-
-</div>
-</div>
-<a id="ab3fbd47b06197619c26393637e26354c"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ab3fbd47b06197619c26393637e26354c">&#9670;&nbsp;</a></span>setDirection()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setDirection </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a>&#160;</td>
-          <td class="paramname"><em>direction</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Request the direction for a stream. The default is <a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54">Direction::Output</a>.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">direction</td><td><a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54">Direction::Output</a> or <a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea324118a6721dd6b8a9b9f4e327df2bf5">Direction::Input</a> </td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<a id="aacb66f530bfc6f545911b5e169774567"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aacb66f530bfc6f545911b5e169774567">&#9670;&nbsp;</a></span>setErrorCallback()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setErrorCallback </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a> *&#160;</td>
-          <td class="paramname"><em>errorCallback</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Specifies an object to handle error related callbacks from the underlying API. This can occur when a stream is disconnected because a headset is plugged in or unplugged. It can also occur if the audio service fails or if an exclusive stream is stolen by another stream.</p>
-<p><b>Important: See <a class="el" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a> for restrictions on what may be called from the callback methods.</b></p>
-<p><b>When an error callback occurs, the associated stream must be stopped and closed in a separate thread.</b></p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">errorCallback</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>pointer to the builder so calls can be chained </dd></dl>
-
-</div>
-</div>
-<a id="aa2e1d2d73cd6c2eb9f349bf2fe5f6515"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aa2e1d2d73cd6c2eb9f349bf2fe5f6515">&#9670;&nbsp;</a></span>setFormat()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setFormat </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a>&#160;</td>
-          <td class="paramname"><em>format</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Request a sample data format, for example <a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6a22ae0e2b89e5e3d477f988cc36d3272b">Format::Float</a>.</p>
-<p>Default is Format::Unspecified. If the value is unspecified then the application should query for the actual value after the stream is opened. </p>
-
-</div>
-</div>
-<a id="a7ec5f427cd6fe55cb1ce536ff0cbb4d2"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a7ec5f427cd6fe55cb1ce536ff0cbb4d2">&#9670;&nbsp;</a></span>setFormatConversionAllowed()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setFormatConversionAllowed </td>
-          <td>(</td>
-          <td class="paramtype">bool&#160;</td>
-          <td class="paramname"><em>allowed</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>If true then Oboe might convert data formats to achieve optimal results. On some versions of Android, for example, a float stream could not get a low latency data path. So an I16 stream might be opened and converted to float.</p>
-<p>Default is true. </p>
-
-</div>
-</div>
-<a id="a3f397821f61eabaeedaf31064c859a54"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a3f397821f61eabaeedaf31064c859a54">&#9670;&nbsp;</a></span>setFramesPerCallback()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setFramesPerCallback </td>
-          <td>(</td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>framesPerCallback</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="deprecated"><dt><b><a class="el" href="deprecated.html#_deprecated000003">Deprecated:</a></b></dt><dd>use <code>setFramesPerDataCallback</code> instead. </dd></dl>
-
-</div>
-</div>
-<a id="afb8e95e80df7edd1af27af490438785e"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#afb8e95e80df7edd1af27af490438785e">&#9670;&nbsp;</a></span>setFramesPerDataCallback()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setFramesPerDataCallback </td>
-          <td>(</td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>framesPerCallback</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Request a specific number of frames for the data callback.</p>
-<p>Default is kUnspecified. If the value is unspecified then the actual number may vary from callback to callback.</p>
-<p>If an application can handle a varying number of frames then we recommend leaving this unspecified. This allow the underlying API to optimize the callbacks. But if your application is, for example, doing FFTs or other block oriented operations, then call this function to get the sizes you need.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">framesPerCallback</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>pointer to the builder so calls can be chained </dd></dl>
-
-</div>
-</div>
-<a id="a144a3d095fd668210282f1a91f23e1f0"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a144a3d095fd668210282f1a91f23e1f0">&#9670;&nbsp;</a></span>setInputPreset()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setInputPreset </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a>&#160;</td>
-          <td class="paramname"><em>inputPreset</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Set the input (capture) preset for the stream.</p>
-<p>The system will use this information to optimize the behavior of the stream. This could, for example, affect which microphones are used and how the recorded data is processed.</p>
-<p>The default, if you do not call this function, is InputPreset::VoiceRecognition. That is because VoiceRecognition is the preset with the lowest latency on many platforms.</p>
-<p>Added in API level 28.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">inputPreset</td><td>the desired configuration for recording </td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<a id="a6cd1d65612e844e59da71a68ea0ab3ee"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a6cd1d65612e844e59da71a68ea0ab3ee">&#9670;&nbsp;</a></span>setPerformanceMode()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setPerformanceMode </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a>&#160;</td>
-          <td class="paramname"><em>performanceMode</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Request a performance level for the stream. This will determine the latency, the power consumption, and the level of protection from glitches.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">performanceMode</td><td>for example, <a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184a611907b5ab1865515c35357efa41a9b9">PerformanceMode::LowLatency</a> </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>pointer to the builder so calls can be chained </dd></dl>
-
-</div>
-</div>
-<a id="a30ef3d5f51d56a9f980dc09600ed139d"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a30ef3d5f51d56a9f980dc09600ed139d">&#9670;&nbsp;</a></span>setSampleRate()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setSampleRate </td>
-          <td>(</td>
-          <td class="paramtype">int32_t&#160;</td>
-          <td class="paramname"><em>sampleRate</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Request a specific sample rate in Hz.</p>
-<p>Default is kUnspecified. If the value is unspecified then the application should query for the actual value after the stream is opened.</p>
-<p>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. </p>
-
-</div>
-</div>
-<a id="af7d24a9ec975d430732151e5ee0d1027"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#af7d24a9ec975d430732151e5ee0d1027">&#9670;&nbsp;</a></span>setSampleRateConversionQuality()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setSampleRateConversionQuality </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">SampleRateConversionQuality</a>&#160;</td>
-          <td class="paramname"><em>quality</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Specify the quality of the sample rate converter in Oboe.</p>
-<p>If set to None then Oboe will not do sample rate conversion. But the underlying APIs might still do sample rate conversion if you specify a sample rate. That can prevent you from getting a low latency stream.</p>
-<p>If you do the conversion in Oboe then you might still get a low latency stream.</p>
-<p>Default is SampleRateConversionQuality::None </p>
-
-</div>
-</div>
-<a id="a54c1651bdbe089d0d714af499e8a5f1d"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a54c1651bdbe089d0d714af499e8a5f1d">&#9670;&nbsp;</a></span>setSessionId()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setSessionId </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a>&#160;</td>
-          <td class="paramname"><em>sessionId</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Set the requested session ID.</p>
-<p>The session ID can be used to associate a stream with effects processors. The effects are controlled using the Android AudioEffect Java API.</p>
-<p>The default, if you do not call this function, is SessionId::None.</p>
-<p>If set to SessionId::Allocate then a session ID will be allocated when the stream is opened.</p>
-<p>The allocated session ID can be obtained by calling <a class="el" href="classoboe_1_1_audio_stream_base.html#aa3c502ce09bbad7690a2dd6acaf8892e">AudioStream::getSessionId()</a> and then used with this function when opening another stream. This allows effects to be shared between streams.</p>
-<p>Session IDs from Oboe can be used the Android Java APIs and vice versa. So a session ID from an Oboe stream can be passed to Java and effects applied using the Java AudioEffect API.</p>
-<p>Allocated session IDs will always be positive and nonzero.</p>
-<p>Added in API level 28.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">sessionId</td><td>an allocated sessionID or SessionId::Allocate </td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<a id="a3e991742acbbfb6fe5ebcf592c478654"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a3e991742acbbfb6fe5ebcf592c478654">&#9670;&nbsp;</a></span>setSharingMode()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setSharingMode </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a>&#160;</td>
-          <td class="paramname"><em>sharingMode</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>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.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">sharingMode</td><td><a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca">SharingMode::Shared</a> or <a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520a2ef50b4c466304dc6ac77bac8a779971">SharingMode::Exclusive</a> </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>pointer to the builder so calls can be chained </dd></dl>
-
-</div>
-</div>
-<a id="a593255a2f5eb972665775cfc5bc58f6a"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a593255a2f5eb972665775cfc5bc58f6a">&#9670;&nbsp;</a></span>setUsage()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a>* oboe::AudioStreamBuilder::setUsage </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a>&#160;</td>
-          <td class="paramname"><em>usage</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Set the intended use case for an output stream.</p>
-<p>The system will use this information to optimize the behavior of the stream. This could, for example, affect how volume and focus is handled for the stream. The usage is ignored for input streams.</p>
-<p>The default, if you do not call this function, is <a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74">Usage::Media</a>.</p>
-<p>Added in API level 28.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">usage</td><td>the desired usage, eg. <a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a63d72051e901c069f8aa1b32aa0c43bb">Usage::Game</a> </td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<a id="aa07ea100fcb107d9f7913f206c2214f4"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aa07ea100fcb107d9f7913f206c2214f4">&#9670;&nbsp;</a></span>willUseAAudio()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">bool oboe::AudioStreamBuilder::willUseAAudio </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>true if AAudio will be used based on the current settings. </dd></dl>
-
-</div>
-</div>
-<hr/>The documentation for this class was generated from the following file:<ul>
-<li>include/oboe/<a class="el" href="_audio_stream_builder_8h_source.html">AudioStreamBuilder.h</a></li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_audio_stream_builder.png b/docs/reference/classoboe_1_1_audio_stream_builder.png
deleted file mode 100644
index 5ce6556..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_builder.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/classoboe_1_1_audio_stream_callback-members.html b/docs/reference/classoboe_1_1_audio_stream_callback-members.html
deleted file mode 100644
index fac5145..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_callback-members.html
+++ /dev/null
@@ -1,92 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Member List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe::AudioStreamCallback Member List</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p>This is the complete list of members for <a class="el" href="classoboe_1_1_audio_stream_callback.html">oboe::AudioStreamCallback</a>, including all inherited members.</p>
-<table class="directory">
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d">onAudioReady</a>(AudioStream *audioStream, void *audioData, int32_t numFrames)=0</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a></td><td class="entry"><span class="mlabel">pure virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">onError</a>(AudioStream *, Result)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe">onErrorAfterClose</a>(AudioStream *, Result)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0">onErrorBeforeClose</a>(AudioStream *, Result)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>~AudioStreamCallback</b>()=default (defined in <a class="el" href="classoboe_1_1_audio_stream_callback.html">oboe::AudioStreamCallback</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_callback.html">oboe::AudioStreamCallback</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>~AudioStreamDataCallback</b>()=default (defined in <a class="el" href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>~AudioStreamErrorCallback</b>()=default (defined in <a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-</table></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_audio_stream_callback.html b/docs/reference/classoboe_1_1_audio_stream_callback.html
deleted file mode 100644
index 8dea790..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_callback.html
+++ /dev/null
@@ -1,120 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe::AudioStreamCallback Class Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="classoboe_1_1_audio_stream_callback-members.html">List of all members</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe::AudioStreamCallback Class Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p><code>#include &lt;<a class="el" href="_audio_stream_callback_8h_source.html">AudioStreamCallback.h</a>&gt;</code></p>
-<div class="dynheader">
-Inheritance diagram for oboe::AudioStreamCallback:</div>
-<div class="dyncontent">
- <div class="center">
-  <img src="classoboe_1_1_audio_stream_callback.png" usemap="#oboe::AudioStreamCallback_map" alt=""/>
-  <map id="oboe::AudioStreamCallback_map" name="oboe::AudioStreamCallback_map">
-<area href="classoboe_1_1_audio_stream_data_callback.html" alt="oboe::AudioStreamDataCallback" shape="rect" coords="0,0,197,24"/>
-<area href="classoboe_1_1_audio_stream_error_callback.html" alt="oboe::AudioStreamErrorCallback" shape="rect" coords="207,0,404,24"/>
-<area href="classoboe_1_1_stabilized_callback.html" alt="oboe::StabilizedCallback" shape="rect" coords="103,112,300,136"/>
-  </map>
-</div></div>
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="inherited"></a>
-Additional Inherited Members</h2></td></tr>
-<tr class="inherit_header pub_methods_classoboe_1_1_audio_stream_data_callback"><td colspan="2" onclick="javascript:toggleInherit('pub_methods_classoboe_1_1_audio_stream_data_callback')"><img src="closed.png" alt="-"/>&#160;Public Member Functions inherited from <a class="el" href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a></td></tr>
-<tr class="memitem:ad8a3a9f609df5fd3a5d885cbe1b2204d inherit pub_methods_classoboe_1_1_audio_stream_data_callback"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d">onAudioReady</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *audioStream, void *audioData, int32_t numFrames)=0</td></tr>
-<tr class="separator:ad8a3a9f609df5fd3a5d885cbe1b2204d inherit pub_methods_classoboe_1_1_audio_stream_data_callback"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="inherit_header pub_methods_classoboe_1_1_audio_stream_error_callback"><td colspan="2" onclick="javascript:toggleInherit('pub_methods_classoboe_1_1_audio_stream_error_callback')"><img src="closed.png" alt="-"/>&#160;Public Member Functions inherited from <a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></td></tr>
-<tr class="memitem:a5ad4b8936746ecbb2160a9389b117fc3 inherit pub_methods_classoboe_1_1_audio_stream_error_callback"><td class="memItemLeft" align="right" valign="top">virtual bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">onError</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *, <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>)</td></tr>
-<tr class="separator:a5ad4b8936746ecbb2160a9389b117fc3 inherit pub_methods_classoboe_1_1_audio_stream_error_callback"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a4eb1e4916b71d8231e97b19898bc9bf0 inherit pub_methods_classoboe_1_1_audio_stream_error_callback"><td class="memItemLeft" align="right" valign="top">virtual void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0">onErrorBeforeClose</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *, <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>)</td></tr>
-<tr class="separator:a4eb1e4916b71d8231e97b19898bc9bf0 inherit pub_methods_classoboe_1_1_audio_stream_error_callback"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a76bd3ef3e00396e10c21812003654cfe inherit pub_methods_classoboe_1_1_audio_stream_error_callback"><td class="memItemLeft" align="right" valign="top">virtual void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe">onErrorAfterClose</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *, <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>)</td></tr>
-<tr class="separator:a76bd3ef3e00396e10c21812003654cfe inherit pub_methods_classoboe_1_1_audio_stream_error_callback"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
-<div class="textblock"><p><a class="el" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a> defines a callback interface for:</p>
-<p>1) moving data to/from an audio stream using <code>onAudioReady</code> 2) being alerted when a stream has an error using <code>onError*</code> methods</p>
-<p>It is used with <a class="el" href="classoboe_1_1_audio_stream_builder.html#a698cefa9af73bc97c020c004821fccbd">AudioStreamBuilder::setCallback()</a>.</p>
-<p>It combines the interfaces defined by <a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> and <a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a>. This was the original callback object. We now recommend using the individual interfaces and using setDataCallback() and setErrorCallback().</p>
-<dl class="deprecated"><dt><b><a class="el" href="deprecated.html#_deprecated000005">Deprecated:</a></b></dt><dd>Use <code><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a></code> and <code><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a></code> instead </dd></dl>
-</div><hr/>The documentation for this class was generated from the following file:<ul>
-<li>include/oboe/<a class="el" href="_audio_stream_callback_8h_source.html">AudioStreamCallback.h</a></li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_audio_stream_callback.png b/docs/reference/classoboe_1_1_audio_stream_callback.png
deleted file mode 100644
index 8db5436..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_callback.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/classoboe_1_1_audio_stream_data_callback-members.html b/docs/reference/classoboe_1_1_audio_stream_data_callback-members.html
deleted file mode 100644
index 89075e4..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_data_callback-members.html
+++ /dev/null
@@ -1,87 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Member List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe::AudioStreamDataCallback Member List</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p>This is the complete list of members for <a class="el" href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a>, including all inherited members.</p>
-<table class="directory">
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d">onAudioReady</a>(AudioStream *audioStream, void *audioData, int32_t numFrames)=0</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a></td><td class="entry"><span class="mlabel">pure virtual</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>~AudioStreamDataCallback</b>()=default (defined in <a class="el" href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-</table></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_audio_stream_data_callback.html b/docs/reference/classoboe_1_1_audio_stream_data_callback.html
deleted file mode 100644
index 45c65ac..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_data_callback.html
+++ /dev/null
@@ -1,196 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe::AudioStreamDataCallback Class Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="#pub-methods">Public Member Functions</a> &#124;
-<a href="classoboe_1_1_audio_stream_data_callback-members.html">List of all members</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe::AudioStreamDataCallback Class Reference<span class="mlabels"><span class="mlabel">abstract</span></span></div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p><code>#include &lt;<a class="el" href="_audio_stream_callback_8h_source.html">AudioStreamCallback.h</a>&gt;</code></p>
-<div class="dynheader">
-Inheritance diagram for oboe::AudioStreamDataCallback:</div>
-<div class="dyncontent">
- <div class="center">
-  <img src="classoboe_1_1_audio_stream_data_callback.png" usemap="#oboe::AudioStreamDataCallback_map" alt=""/>
-  <map id="oboe::AudioStreamDataCallback_map" name="oboe::AudioStreamDataCallback_map">
-<area href="classoboe_1_1_audio_stream_callback.html" alt="oboe::AudioStreamCallback" shape="rect" coords="0,56,193,80"/>
-<area href="classoboe_1_1_stabilized_callback.html" alt="oboe::StabilizedCallback" shape="rect" coords="0,112,193,136"/>
-  </map>
-</div></div>
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-methods"></a>
-Public Member Functions</h2></td></tr>
-<tr class="memitem:ad8a3a9f609df5fd3a5d885cbe1b2204d"><td class="memItemLeft" align="right" valign="top">virtual <a class="el" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d">onAudioReady</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *audioStream, void *audioData, int32_t numFrames)=0</td></tr>
-<tr class="separator:ad8a3a9f609df5fd3a5d885cbe1b2204d"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
-<div class="textblock"><p><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a> defines a callback interface for moving data to/from an audio stream using <code>onAudioReady</code> 2) being alerted when a stream has an error using <code>onError*</code> methods</p>
-<p>It is used with <a class="el" href="classoboe_1_1_audio_stream_builder.html#acad307720e0f370267b4e2f9a626ae70">AudioStreamBuilder::setDataCallback()</a>. </p>
-</div><h2 class="groupheader">Member Function Documentation</h2>
-<a id="ad8a3a9f609df5fd3a5d885cbe1b2204d"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ad8a3a9f609df5fd3a5d885cbe1b2204d">&#9670;&nbsp;</a></span>onAudioReady()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual <a class="el" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a> oboe::AudioStreamDataCallback::onAudioReady </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *&#160;</td>
-          <td class="paramname"><em>audioStream</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">void *&#160;</td>
-          <td class="paramname"><em>audioData</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int32_t&#160;</td>
-          <td class="paramname"><em>numFrames</em>&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">pure virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>A buffer is ready for processing.</p>
-<p>For an output stream, this function should render and write numFrames of data in the stream's current data format to the audioData buffer.</p>
-<p>For an input stream, this function should read and process numFrames of data from the audioData buffer.</p>
-<p>The audio data is passed through the buffer. So do NOT call read() or write() on the stream that is making the callback.</p>
-<p>Note that numFrames can vary unless <a class="el" href="classoboe_1_1_audio_stream_builder.html#a3f397821f61eabaeedaf31064c859a54">AudioStreamBuilder::setFramesPerCallback()</a> is called.</p>
-<p>Also note that this callback function should be considered a "real-time" function. It must not do anything that could cause an unbounded delay because that can cause the audio to glitch or pop.</p>
-<p>These are things the function should NOT do: </p><ul>
-<li>
-allocate memory using, for example, malloc() or new </li>
-<li>
-any file operations such as opening, closing, reading or writing </li>
-<li>
-any network operations such as streaming </li>
-<li>
-use any mutexes or other synchronization primitives </li>
-<li>
-sleep </li>
-<li>
-oboeStream-&gt;stop(), pause(), flush() or close() </li>
-<li>
-oboeStream-&gt;read() </li>
-<li>
-oboeStream-&gt;write() </li>
-</ul>
-<p>The following are OK to call from the data callback: </p><ul>
-<li>
-oboeStream-&gt;get*() </li>
-<li>
-<a class="el" href="namespaceoboe.html#af65aaea3c5d82eee6906664d61c094b3">oboe::convertToText()</a> </li>
-<li>
-oboeStream-&gt;setBufferSizeInFrames() </li>
-</ul>
-<p>If you need to move data, eg. MIDI commands, in or out of the callback function then we recommend the use of non-blocking techniques such as an atomic FIFO.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">audioStream</td><td>pointer to the associated stream </td></tr>
-    <tr><td class="paramname">audioData</td><td>buffer containing input data or a place to put output data </td></tr>
-    <tr><td class="paramname">numFrames</td><td>number of frames to be processed </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>DataCallbackResult::Continue or DataCallbackResult::Stop </dd></dl>
-
-<p>Implemented in <a class="el" href="classoboe_1_1_stabilized_callback.html#ad447e12ebf732cf151655c1fbaf58a49">oboe::StabilizedCallback</a>.</p>
-
-</div>
-</div>
-<hr/>The documentation for this class was generated from the following file:<ul>
-<li>include/oboe/<a class="el" href="_audio_stream_callback_8h_source.html">AudioStreamCallback.h</a></li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_audio_stream_data_callback.png b/docs/reference/classoboe_1_1_audio_stream_data_callback.png
deleted file mode 100644
index ac644c4..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_data_callback.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/classoboe_1_1_audio_stream_error_callback-members.html b/docs/reference/classoboe_1_1_audio_stream_error_callback-members.html
deleted file mode 100644
index 0b6309f..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_error_callback-members.html
+++ /dev/null
@@ -1,89 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Member List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe::AudioStreamErrorCallback Member List</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p>This is the complete list of members for <a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a>, including all inherited members.</p>
-<table class="directory">
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">onError</a>(AudioStream *, Result)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe">onErrorAfterClose</a>(AudioStream *, Result)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0">onErrorBeforeClose</a>(AudioStream *, Result)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>~AudioStreamErrorCallback</b>()=default (defined in <a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-</table></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_audio_stream_error_callback.html b/docs/reference/classoboe_1_1_audio_stream_error_callback.html
deleted file mode 100644
index 1569e21..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_error_callback.html
+++ /dev/null
@@ -1,260 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe::AudioStreamErrorCallback Class Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="#pub-methods">Public Member Functions</a> &#124;
-<a href="classoboe_1_1_audio_stream_error_callback-members.html">List of all members</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe::AudioStreamErrorCallback Class Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p><code>#include &lt;<a class="el" href="_audio_stream_callback_8h_source.html">AudioStreamCallback.h</a>&gt;</code></p>
-<div class="dynheader">
-Inheritance diagram for oboe::AudioStreamErrorCallback:</div>
-<div class="dyncontent">
- <div class="center">
-  <img src="classoboe_1_1_audio_stream_error_callback.png" usemap="#oboe::AudioStreamErrorCallback_map" alt=""/>
-  <map id="oboe::AudioStreamErrorCallback_map" name="oboe::AudioStreamErrorCallback_map">
-<area href="classoboe_1_1_audio_stream_callback.html" alt="oboe::AudioStreamCallback" shape="rect" coords="0,56,197,80"/>
-<area href="classoboe_1_1_stabilized_callback.html" alt="oboe::StabilizedCallback" shape="rect" coords="0,112,197,136"/>
-  </map>
-</div></div>
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-methods"></a>
-Public Member Functions</h2></td></tr>
-<tr class="memitem:a5ad4b8936746ecbb2160a9389b117fc3"><td class="memItemLeft" align="right" valign="top">virtual bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">onError</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *, <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>)</td></tr>
-<tr class="separator:a5ad4b8936746ecbb2160a9389b117fc3"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a4eb1e4916b71d8231e97b19898bc9bf0"><td class="memItemLeft" align="right" valign="top">virtual void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0">onErrorBeforeClose</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *, <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>)</td></tr>
-<tr class="separator:a4eb1e4916b71d8231e97b19898bc9bf0"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a76bd3ef3e00396e10c21812003654cfe"><td class="memItemLeft" align="right" valign="top">virtual void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe">onErrorAfterClose</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *, <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>)</td></tr>
-<tr class="separator:a76bd3ef3e00396e10c21812003654cfe"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
-<div class="textblock"><p><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a> defines a callback interface for being alerted when a stream has an error or is disconnected using <code>onError*</code> methods.</p>
-<p>It is used with <a class="el" href="classoboe_1_1_audio_stream_builder.html#aacb66f530bfc6f545911b5e169774567">AudioStreamBuilder::setErrorCallback()</a>. </p>
-</div><h2 class="groupheader">Member Function Documentation</h2>
-<a id="a5ad4b8936746ecbb2160a9389b117fc3"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a5ad4b8936746ecbb2160a9389b117fc3">&#9670;&nbsp;</a></span>onError()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual bool oboe::AudioStreamErrorCallback::onError </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *&#160;</td>
-          <td class="paramname">, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td>
-          <td class="paramname">&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>This will be called before other <code>onError</code> methods when an error occurs on a stream, such as when the stream is disconnected.</p>
-<p>It can be used to override and customize the normal error processing. Use of this method is considered an advanced technique. It might, for example, be used if an app want to use a high level lock when closing and reopening a stream. Or it might be used when an app want to signal a management thread that handles all of the stream state.</p>
-<p>If this method returns false it indicates that the stream has *not been stopped and closed by the application. In this case it will be stopped by Oboe in the following way: <a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0">onErrorBeforeClose()</a> will be called, then the stream will be closed and <a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe">onErrorAfterClose()</a> will be closed.</p>
-<p>If this method returns true it indicates that the stream <em>has</em> been stopped and closed by the application and Oboe will not do this. In that case, the app MUST stop() and close() the stream.</p>
-<p>This method will be called on a thread created by Oboe.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">audioStream</td><td>pointer to the associated stream </td></tr>
-    <tr><td class="paramname">error</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>true if the stream has been stopped and closed, false if not </dd></dl>
-
-</div>
-</div>
-<a id="a76bd3ef3e00396e10c21812003654cfe"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a76bd3ef3e00396e10c21812003654cfe">&#9670;&nbsp;</a></span>onErrorAfterClose()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual void oboe::AudioStreamErrorCallback::onErrorAfterClose </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *&#160;</td>
-          <td class="paramname">, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td>
-          <td class="paramname">&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>This will be called when an error occurs on a stream, such as when the stream is disconnected, and if <a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">onError()</a> returns false (indicating that the error has not already been handled).</p>
-<p>The underlying AAudio or OpenSL ES stream will already be stopped AND closed by Oboe. So the underlying stream cannot be referenced. But you can still query most parameters.</p>
-<p>This callback could be used to reopen a new stream on another device.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">audioStream</td><td>pointer to the associated stream </td></tr>
-    <tr><td class="paramname">error</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-
-<p>Reimplemented in <a class="el" href="classoboe_1_1_stabilized_callback.html#af7521da42c4b08a71e6102994f6f41f4">oboe::StabilizedCallback</a>.</p>
-
-</div>
-</div>
-<a id="a4eb1e4916b71d8231e97b19898bc9bf0"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a4eb1e4916b71d8231e97b19898bc9bf0">&#9670;&nbsp;</a></span>onErrorBeforeClose()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">virtual void oboe::AudioStreamErrorCallback::onErrorBeforeClose </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *&#160;</td>
-          <td class="paramname">, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td>
-          <td class="paramname">&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>This will be called when an error occurs on a stream, such as when the stream is disconnected, and if <a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">onError()</a> returns false (indicating that the error has not already been handled).</p>
-<p>Note that this will be called on a thread created by Oboe.</p>
-<p>The underlying stream will already be stopped by Oboe but not yet closed. So the stream can be queried.</p>
-<p>Do not close or delete the stream in this method because it will be closed after this method returns.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">audioStream</td><td>pointer to the associated stream </td></tr>
-    <tr><td class="paramname">error</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-
-<p>Reimplemented in <a class="el" href="classoboe_1_1_stabilized_callback.html#a7ec0e9fca3181962ab78716bcda83e10">oboe::StabilizedCallback</a>.</p>
-
-</div>
-</div>
-<hr/>The documentation for this class was generated from the following file:<ul>
-<li>include/oboe/<a class="el" href="_audio_stream_callback_8h_source.html">AudioStreamCallback.h</a></li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_audio_stream_error_callback.png b/docs/reference/classoboe_1_1_audio_stream_error_callback.png
deleted file mode 100644
index 54c5ef2..0000000
--- a/docs/reference/classoboe_1_1_audio_stream_error_callback.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/classoboe_1_1_default_stream_values-members.html b/docs/reference/classoboe_1_1_default_stream_values-members.html
deleted file mode 100644
index fe2013f..0000000
--- a/docs/reference/classoboe_1_1_default_stream_values-members.html
+++ /dev/null
@@ -1,88 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Member List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_default_stream_values.html">DefaultStreamValues</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe::DefaultStreamValues Member List</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p>This is the complete list of members for <a class="el" href="classoboe_1_1_default_stream_values.html">oboe::DefaultStreamValues</a>, including all inherited members.</p>
-<table class="directory">
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_default_stream_values.html#ad5dce538d5963c81bf58350ab730962d">ChannelCount</a></td><td class="entry"><a class="el" href="classoboe_1_1_default_stream_values.html">oboe::DefaultStreamValues</a></td><td class="entry"><span class="mlabel">static</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_default_stream_values.html#ab5ea5576699cebc56193f5c297d3e300">FramesPerBurst</a></td><td class="entry"><a class="el" href="classoboe_1_1_default_stream_values.html">oboe::DefaultStreamValues</a></td><td class="entry"><span class="mlabel">static</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_default_stream_values.html#a46a5d9a653f2153f618cadcab764e1b1">SampleRate</a></td><td class="entry"><a class="el" href="classoboe_1_1_default_stream_values.html">oboe::DefaultStreamValues</a></td><td class="entry"><span class="mlabel">static</span></td></tr>
-</table></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_default_stream_values.html b/docs/reference/classoboe_1_1_default_stream_values.html
deleted file mode 100644
index 282f323..0000000
--- a/docs/reference/classoboe_1_1_default_stream_values.html
+++ /dev/null
@@ -1,181 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe::DefaultStreamValues Class Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_default_stream_values.html">DefaultStreamValues</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="#pub-static-attribs">Static Public Attributes</a> &#124;
-<a href="classoboe_1_1_default_stream_values-members.html">List of all members</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe::DefaultStreamValues Class Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p><code>#include &lt;<a class="el" href="_definitions_8h_source.html">Definitions.h</a>&gt;</code></p>
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-static-attribs"></a>
-Static Public Attributes</h2></td></tr>
-<tr class="memitem:a46a5d9a653f2153f618cadcab764e1b1"><td class="memItemLeft" align="right" valign="top">static int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_default_stream_values.html#a46a5d9a653f2153f618cadcab764e1b1">SampleRate</a></td></tr>
-<tr class="separator:a46a5d9a653f2153f618cadcab764e1b1"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab5ea5576699cebc56193f5c297d3e300"><td class="memItemLeft" align="right" valign="top">static int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_default_stream_values.html#ab5ea5576699cebc56193f5c297d3e300">FramesPerBurst</a></td></tr>
-<tr class="separator:ab5ea5576699cebc56193f5c297d3e300"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ad5dce538d5963c81bf58350ab730962d"><td class="memItemLeft" align="right" valign="top">static int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_default_stream_values.html#ad5dce538d5963c81bf58350ab730962d">ChannelCount</a></td></tr>
-<tr class="separator:ad5dce538d5963c81bf58350ab730962d"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
-<div class="textblock"><p>On API 16 to 26 OpenSL ES will be used. When using OpenSL ES the optimal values for sampleRate and framesPerBurst are not known by the native code. On API 17+ these values should be obtained from the AudioManager using this code:</p>
-<pre><code>
-// Note that this technique only works for built-in speakers and headphones.
-AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-String sampleRateStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
-int defaultSampleRate = Integer.parseInt(sampleRateStr);
-String framesPerBurstStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
-int defaultFramesPerBurst = Integer.parseInt(framesPerBurstStr);
-</code></pre><p>It can then be passed down to Oboe through JNI.</p>
-<p>AAudio will get the optimal framesPerBurst from the HAL and will ignore this value. </p>
-</div><h2 class="groupheader">Member Data Documentation</h2>
-<a id="ad5dce538d5963c81bf58350ab730962d"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ad5dce538d5963c81bf58350ab730962d">&#9670;&nbsp;</a></span>ChannelCount</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::DefaultStreamValues::ChannelCount</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">static</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The default channel count to use when opening new audio streams </p>
-
-</div>
-</div>
-<a id="ab5ea5576699cebc56193f5c297d3e300"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ab5ea5576699cebc56193f5c297d3e300">&#9670;&nbsp;</a></span>FramesPerBurst</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::DefaultStreamValues::FramesPerBurst</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">static</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The default frames per burst to use when opening new audio streams </p>
-
-</div>
-</div>
-<a id="a46a5d9a653f2153f618cadcab764e1b1"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a46a5d9a653f2153f618cadcab764e1b1">&#9670;&nbsp;</a></span>SampleRate</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::DefaultStreamValues::SampleRate</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">static</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The default sample rate to use when opening new audio streams </p>
-
-</div>
-</div>
-<hr/>The documentation for this class was generated from the following file:<ul>
-<li>include/oboe/<a class="el" href="_definitions_8h_source.html">Definitions.h</a></li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_latency_tuner-members.html b/docs/reference/classoboe_1_1_latency_tuner-members.html
deleted file mode 100644
index 55dcbe9..0000000
--- a/docs/reference/classoboe_1_1_latency_tuner-members.html
+++ /dev/null
@@ -1,94 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Member List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_latency_tuner.html">LatencyTuner</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe::LatencyTuner Member List</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p>This is the complete list of members for <a class="el" href="classoboe_1_1_latency_tuner.html">oboe::LatencyTuner</a>, including all inherited members.</p>
-<table class="directory">
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>getBufferSizeIncrement</b>() const (defined in <a class="el" href="classoboe_1_1_latency_tuner.html">oboe::LatencyTuner</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html">oboe::LatencyTuner</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>getMinimumBufferSize</b>() const (defined in <a class="el" href="classoboe_1_1_latency_tuner.html">oboe::LatencyTuner</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html">oboe::LatencyTuner</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html#a45c013fd6787ad09d328385d6314c4d4">isAtMaximumBufferSize</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html">oboe::LatencyTuner</a></td><td class="entry"></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html#a0263b9a55825c0a403653b2b508073ea">LatencyTuner</a>(AudioStream &amp;stream)</td><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html">oboe::LatencyTuner</a></td><td class="entry"><span class="mlabel">explicit</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html#ab437bd10605af9e5733d043f8adc0b43">LatencyTuner</a>(AudioStream &amp;stream, int32_t maximumBufferSize)</td><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html">oboe::LatencyTuner</a></td><td class="entry"><span class="mlabel">explicit</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html#a6c0142e08dc65eda8f758b4794450867">requestReset</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html">oboe::LatencyTuner</a></td><td class="entry"></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html#a2684b30205126c8acd2f75d01cce05db">setBufferSizeIncrement</a>(int32_t sizeIncrement)</td><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html">oboe::LatencyTuner</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html#adc96aa53b18a051b6ccdacb838139bf8">setMinimumBufferSize</a>(int32_t bufferSize)</td><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html">oboe::LatencyTuner</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html#ad2be756965e6a9af3114008eda892174">tune</a>()</td><td class="entry"><a class="el" href="classoboe_1_1_latency_tuner.html">oboe::LatencyTuner</a></td><td class="entry"></td></tr>
-</table></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_latency_tuner.html b/docs/reference/classoboe_1_1_latency_tuner.html
deleted file mode 100644
index 4167acc..0000000
--- a/docs/reference/classoboe_1_1_latency_tuner.html
+++ /dev/null
@@ -1,321 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe::LatencyTuner Class Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_latency_tuner.html">LatencyTuner</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="#pub-methods">Public Member Functions</a> &#124;
-<a href="classoboe_1_1_latency_tuner-members.html">List of all members</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe::LatencyTuner Class Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p><code>#include &lt;<a class="el" href="_latency_tuner_8h_source.html">LatencyTuner.h</a>&gt;</code></p>
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-methods"></a>
-Public Member Functions</h2></td></tr>
-<tr class="memitem:a0263b9a55825c0a403653b2b508073ea"><td class="memItemLeft" align="right" valign="top">&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_latency_tuner.html#a0263b9a55825c0a403653b2b508073ea">LatencyTuner</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> &amp;stream)</td></tr>
-<tr class="separator:a0263b9a55825c0a403653b2b508073ea"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab437bd10605af9e5733d043f8adc0b43"><td class="memItemLeft" align="right" valign="top">&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_latency_tuner.html#ab437bd10605af9e5733d043f8adc0b43">LatencyTuner</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> &amp;stream, int32_t maximumBufferSize)</td></tr>
-<tr class="separator:ab437bd10605af9e5733d043f8adc0b43"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ad2be756965e6a9af3114008eda892174"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_latency_tuner.html#ad2be756965e6a9af3114008eda892174">tune</a> ()</td></tr>
-<tr class="separator:ad2be756965e6a9af3114008eda892174"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a6c0142e08dc65eda8f758b4794450867"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_latency_tuner.html#a6c0142e08dc65eda8f758b4794450867">requestReset</a> ()</td></tr>
-<tr class="separator:a6c0142e08dc65eda8f758b4794450867"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a45c013fd6787ad09d328385d6314c4d4"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_latency_tuner.html#a45c013fd6787ad09d328385d6314c4d4">isAtMaximumBufferSize</a> ()</td></tr>
-<tr class="separator:a45c013fd6787ad09d328385d6314c4d4"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:adc96aa53b18a051b6ccdacb838139bf8"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_latency_tuner.html#adc96aa53b18a051b6ccdacb838139bf8">setMinimumBufferSize</a> (int32_t bufferSize)</td></tr>
-<tr class="separator:adc96aa53b18a051b6ccdacb838139bf8"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aaba4b3f075ed8d7c7ad4cad392545c08"><td class="memItemLeft" align="right" valign="top"><a id="aaba4b3f075ed8d7c7ad4cad392545c08"></a>
-int32_t&#160;</td><td class="memItemRight" valign="bottom"><b>getMinimumBufferSize</b> () const</td></tr>
-<tr class="separator:aaba4b3f075ed8d7c7ad4cad392545c08"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a2684b30205126c8acd2f75d01cce05db"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_latency_tuner.html#a2684b30205126c8acd2f75d01cce05db">setBufferSizeIncrement</a> (int32_t sizeIncrement)</td></tr>
-<tr class="separator:a2684b30205126c8acd2f75d01cce05db"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5ea6114ac4f78f3e050d405168905123"><td class="memItemLeft" align="right" valign="top"><a id="a5ea6114ac4f78f3e050d405168905123"></a>
-int32_t&#160;</td><td class="memItemRight" valign="bottom"><b>getBufferSizeIncrement</b> () const</td></tr>
-<tr class="separator:a5ea6114ac4f78f3e050d405168905123"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
-<div class="textblock"><p><a class="el" href="classoboe_1_1_latency_tuner.html">LatencyTuner</a> can be used to dynamically tune the latency of an output stream. It adjusts the stream's bufferSize by monitoring the number of underruns.</p>
-<p>This only affects the latency associated with the first level of buffering that is closest to the application. It does not affect low latency in the HAL, or touch latency in the UI.</p>
-<p>Call <a class="el" href="classoboe_1_1_latency_tuner.html#ad2be756965e6a9af3114008eda892174">tune()</a> right before returning from your data callback function if using callbacks. Call <a class="el" href="classoboe_1_1_latency_tuner.html#ad2be756965e6a9af3114008eda892174">tune()</a> right before calling write() if using blocking writes.</p>
-<p>If you want to see the ongoing results of this tuning process then call stream-&gt;getBufferSize() periodically. </p>
-</div><h2 class="groupheader">Constructor &amp; Destructor Documentation</h2>
-<a id="a0263b9a55825c0a403653b2b508073ea"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a0263b9a55825c0a403653b2b508073ea">&#9670;&nbsp;</a></span>LatencyTuner() <span class="overload">[1/2]</span></h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">oboe::LatencyTuner::LatencyTuner </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> &amp;&#160;</td>
-          <td class="paramname"><em>stream</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">explicit</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Construct a new <a class="el" href="classoboe_1_1_latency_tuner.html">LatencyTuner</a> object which will act on the given audio stream</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">stream</td><td>the stream who's latency will be tuned </td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<a id="ab437bd10605af9e5733d043f8adc0b43"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ab437bd10605af9e5733d043f8adc0b43">&#9670;&nbsp;</a></span>LatencyTuner() <span class="overload">[2/2]</span></h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">oboe::LatencyTuner::LatencyTuner </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> &amp;&#160;</td>
-          <td class="paramname"><em>stream</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int32_t&#160;</td>
-          <td class="paramname"><em>maximumBufferSize</em>&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">explicit</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Construct a new <a class="el" href="classoboe_1_1_latency_tuner.html">LatencyTuner</a> object which will act on the given audio stream.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">stream</td><td>the stream who's latency will be tuned </td></tr>
-    <tr><td class="paramname">the</td><td>maximum buffer size which the <a class="el" href="classoboe_1_1_latency_tuner.html#ad2be756965e6a9af3114008eda892174">tune()</a> operation will set the buffer size to </td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<h2 class="groupheader">Member Function Documentation</h2>
-<a id="a45c013fd6787ad09d328385d6314c4d4"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a45c013fd6787ad09d328385d6314c4d4">&#9670;&nbsp;</a></span>isAtMaximumBufferSize()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">bool oboe::LatencyTuner::isAtMaximumBufferSize </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>true if the audio stream's buffer size is at the maximum value. If no maximum value was specified when constructing the <a class="el" href="classoboe_1_1_latency_tuner.html">LatencyTuner</a> then the value of stream-&gt;getBufferCapacityInFrames is used </dd></dl>
-
-</div>
-</div>
-<a id="a6c0142e08dc65eda8f758b4794450867"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a6c0142e08dc65eda8f758b4794450867">&#9670;&nbsp;</a></span>requestReset()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">void oboe::LatencyTuner::requestReset </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>This may be called from another thread. Then <a class="el" href="classoboe_1_1_latency_tuner.html#ad2be756965e6a9af3114008eda892174">tune()</a> will call reset(), which will lower the latency to the minimum and then allow it to rise back up if there are glitches.</p>
-<p>This is typically called in response to a user decision to minimize latency. In other words, call this from a button handler. </p>
-
-</div>
-</div>
-<a id="a2684b30205126c8acd2f75d01cce05db"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a2684b30205126c8acd2f75d01cce05db">&#9670;&nbsp;</a></span>setBufferSizeIncrement()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">void oboe::LatencyTuner::setBufferSizeIncrement </td>
-          <td>(</td>
-          <td class="paramtype">int32_t&#160;</td>
-          <td class="paramname"><em>sizeIncrement</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Set the amount the bufferSize will be incremented while tuning. By default, this will be one burst.</p>
-<p>Note that AAudio will quantize the buffer size to a multiple of the burstSize. So the final buffer sizes may not be a multiple of this increment.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">sizeIncrement</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<a id="adc96aa53b18a051b6ccdacb838139bf8"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#adc96aa53b18a051b6ccdacb838139bf8">&#9670;&nbsp;</a></span>setMinimumBufferSize()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">void oboe::LatencyTuner::setMinimumBufferSize </td>
-          <td>(</td>
-          <td class="paramtype">int32_t&#160;</td>
-          <td class="paramname"><em>bufferSize</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Set the minimum bufferSize in frames that is used when the tuner is reset. You may wish to call <a class="el" href="classoboe_1_1_latency_tuner.html#a6c0142e08dc65eda8f758b4794450867">requestReset()</a> after calling this. </p><dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">bufferSize</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<a id="ad2be756965e6a9af3114008eda892174"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ad2be756965e6a9af3114008eda892174">&#9670;&nbsp;</a></span>tune()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> oboe::LatencyTuner::tune </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>Adjust the bufferSizeInFrames to optimize latency. It will start with a low latency and then raise it if an underrun occurs.</p>
-<p>Latency tuning is only supported for AAudio.</p>
-<dl class="section return"><dt>Returns</dt><dd>OK or negative error, ErrorUnimplemented for OpenSL ES </dd></dl>
-
-</div>
-</div>
-<hr/>The documentation for this class was generated from the following file:<ul>
-<li>include/oboe/<a class="el" href="_latency_tuner_8h_source.html">LatencyTuner.h</a></li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_oboe_globals-members.html b/docs/reference/classoboe_1_1_oboe_globals-members.html
deleted file mode 100644
index 9ddac6f..0000000
--- a/docs/reference/classoboe_1_1_oboe_globals-members.html
+++ /dev/null
@@ -1,87 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Member List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_oboe_globals.html">OboeGlobals</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe::OboeGlobals Member List</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p>This is the complete list of members for <a class="el" href="classoboe_1_1_oboe_globals.html">oboe::OboeGlobals</a>, including all inherited members.</p>
-<table class="directory">
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>areWorkaroundsEnabled</b>() (defined in <a class="el" href="classoboe_1_1_oboe_globals.html">oboe::OboeGlobals</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_oboe_globals.html">oboe::OboeGlobals</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">static</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_oboe_globals.html#af2b8af764c5a5e6fc007b7725117303b">setWorkaroundsEnabled</a>(bool enabled)</td><td class="entry"><a class="el" href="classoboe_1_1_oboe_globals.html">oboe::OboeGlobals</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">static</span></td></tr>
-</table></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_oboe_globals.html b/docs/reference/classoboe_1_1_oboe_globals.html
deleted file mode 100644
index c582e30..0000000
--- a/docs/reference/classoboe_1_1_oboe_globals.html
+++ /dev/null
@@ -1,130 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe::OboeGlobals Class Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_oboe_globals.html">OboeGlobals</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="#pub-static-methods">Static Public Member Functions</a> &#124;
-<a href="classoboe_1_1_oboe_globals-members.html">List of all members</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe::OboeGlobals Class Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-static-methods"></a>
-Static Public Member Functions</h2></td></tr>
-<tr class="memitem:a37ba77c944e44c36a6b599eb4d630c9f"><td class="memItemLeft" align="right" valign="top"><a id="a37ba77c944e44c36a6b599eb4d630c9f"></a>
-static bool&#160;</td><td class="memItemRight" valign="bottom"><b>areWorkaroundsEnabled</b> ()</td></tr>
-<tr class="separator:a37ba77c944e44c36a6b599eb4d630c9f"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:af2b8af764c5a5e6fc007b7725117303b"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_oboe_globals.html#af2b8af764c5a5e6fc007b7725117303b">setWorkaroundsEnabled</a> (bool enabled)</td></tr>
-<tr class="separator:af2b8af764c5a5e6fc007b7725117303b"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<h2 class="groupheader">Member Function Documentation</h2>
-<a id="af2b8af764c5a5e6fc007b7725117303b"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#af2b8af764c5a5e6fc007b7725117303b">&#9670;&nbsp;</a></span>setWorkaroundsEnabled()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">static void oboe::OboeGlobals::setWorkaroundsEnabled </td>
-          <td>(</td>
-          <td class="paramtype">bool&#160;</td>
-          <td class="paramname"><em>enabled</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">static</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Disable this when writing tests to reproduce bugs in AAudio or OpenSL ES that have workarounds in Oboe. </p><dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">enabled</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<hr/>The documentation for this class was generated from the following file:<ul>
-<li>include/oboe/<a class="el" href="_definitions_8h_source.html">Definitions.h</a></li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_result_with_value-members.html b/docs/reference/classoboe_1_1_result_with_value-members.html
deleted file mode 100644
index a8fe74d..0000000
--- a/docs/reference/classoboe_1_1_result_with_value-members.html
+++ /dev/null
@@ -1,93 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Member List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe::ResultWithValue&lt; T &gt; Member List</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p>This is the complete list of members for <a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue&lt; T &gt;</a>, including all inherited members.</p>
-<table class="directory">
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html#a2304c6120e2aad8f2189383a98c7b0a7">createBasedOnSign</a>(T numericResult)</td><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue&lt; T &gt;</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">static</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html#adfc76ae6db81535c2e82b856975eed41">error</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue&lt; T &gt;</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html#a6fb3c61c5716a045ba48dc5a5dfc8169">operator !</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue&lt; T &gt;</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html#ae32b1953b777af7d1d0c94862ca39986">operator bool</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue&lt; T &gt;</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">explicit</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html#af62107817c0bc76047e6b655a78504ba">operator Result</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue&lt; T &gt;</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html#aae75caa0d16a9e23a012f77fb50c5927">ResultWithValue</a>(oboe::Result error)</td><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue&lt; T &gt;</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html#a600309367db58d71f0ec16e90f7ebea5">ResultWithValue</a>(T value)</td><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue&lt; T &gt;</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">explicit</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html#a45f5c99a2c9f8fbaca502276f7ebb434">value</a>() const</td><td class="entry"><a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue&lt; T &gt;</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-</table></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_result_with_value.html b/docs/reference/classoboe_1_1_result_with_value.html
deleted file mode 100644
index 58a0826..0000000
--- a/docs/reference/classoboe_1_1_result_with_value.html
+++ /dev/null
@@ -1,368 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe::ResultWithValue&lt; T &gt; Class Template Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="#pub-methods">Public Member Functions</a> &#124;
-<a href="#pub-static-methods">Static Public Member Functions</a> &#124;
-<a href="classoboe_1_1_result_with_value-members.html">List of all members</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe::ResultWithValue&lt; T &gt; Class Template Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p><code>#include &lt;<a class="el" href="_result_with_value_8h_source.html">ResultWithValue.h</a>&gt;</code></p>
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-methods"></a>
-Public Member Functions</h2></td></tr>
-<tr class="memitem:aae75caa0d16a9e23a012f77fb50c5927"><td class="memItemLeft" align="right" valign="top">&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_result_with_value.html#aae75caa0d16a9e23a012f77fb50c5927">ResultWithValue</a> (<a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a> <a class="el" href="classoboe_1_1_result_with_value.html#adfc76ae6db81535c2e82b856975eed41">error</a>)</td></tr>
-<tr class="separator:aae75caa0d16a9e23a012f77fb50c5927"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a600309367db58d71f0ec16e90f7ebea5"><td class="memItemLeft" align="right" valign="top">&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_result_with_value.html#a600309367db58d71f0ec16e90f7ebea5">ResultWithValue</a> (T <a class="el" href="classoboe_1_1_result_with_value.html#a45f5c99a2c9f8fbaca502276f7ebb434">value</a>)</td></tr>
-<tr class="separator:a600309367db58d71f0ec16e90f7ebea5"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:adfc76ae6db81535c2e82b856975eed41"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_result_with_value.html#adfc76ae6db81535c2e82b856975eed41">error</a> () const</td></tr>
-<tr class="separator:adfc76ae6db81535c2e82b856975eed41"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a45f5c99a2c9f8fbaca502276f7ebb434"><td class="memItemLeft" align="right" valign="top">T&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_result_with_value.html#a45f5c99a2c9f8fbaca502276f7ebb434">value</a> () const</td></tr>
-<tr class="separator:a45f5c99a2c9f8fbaca502276f7ebb434"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ae32b1953b777af7d1d0c94862ca39986"><td class="memItemLeft" align="right" valign="top">&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_result_with_value.html#ae32b1953b777af7d1d0c94862ca39986">operator bool</a> () const</td></tr>
-<tr class="separator:ae32b1953b777af7d1d0c94862ca39986"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a6fb3c61c5716a045ba48dc5a5dfc8169"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_result_with_value.html#a6fb3c61c5716a045ba48dc5a5dfc8169">operator !</a> () const</td></tr>
-<tr class="separator:a6fb3c61c5716a045ba48dc5a5dfc8169"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:af62107817c0bc76047e6b655a78504ba"><td class="memItemLeft" align="right" valign="top">&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_result_with_value.html#af62107817c0bc76047e6b655a78504ba">operator Result</a> () const</td></tr>
-<tr class="separator:af62107817c0bc76047e6b655a78504ba"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table><table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-static-methods"></a>
-Static Public Member Functions</h2></td></tr>
-<tr class="memitem:a2304c6120e2aad8f2189383a98c7b0a7"><td class="memItemLeft" align="right" valign="top">static <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt; T &gt;&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_result_with_value.html#a2304c6120e2aad8f2189383a98c7b0a7">createBasedOnSign</a> (T numericResult)</td></tr>
-<tr class="separator:a2304c6120e2aad8f2189383a98c7b0a7"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
-<div class="textblock"><h3>template&lt;typename T&gt;<br />
-class oboe::ResultWithValue&lt; T &gt;</h3>
-
-<p>A <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> can store both the result of an operation (either OK or an error) and a value.</p>
-<p>It has been designed for cases where the caller needs to know whether an operation succeeded and, if it did, a value which was obtained during the operation.</p>
-<p>For example, when reading from a stream the caller needs to know the result of the read operation and, if it was successful, how many frames were read. Note that <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> can be evaluated as a boolean so it's simple to check whether the result is OK.</p>
-<p><code> ResultWithValue&lt;int32_t&gt; resultOfRead = myStream.read(&amp;buffer, numFrames, timeoutNanoseconds);</code></p>
-<p><code>if (resultOfRead) { LOGD("Frames read: %d", resultOfRead.value()); } else { LOGD("Error reading from stream: %s", resultOfRead.error()); } </code> </p>
-</div><h2 class="groupheader">Constructor &amp; Destructor Documentation</h2>
-<a id="aae75caa0d16a9e23a012f77fb50c5927"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aae75caa0d16a9e23a012f77fb50c5927">&#9670;&nbsp;</a></span>ResultWithValue() <span class="overload">[1/2]</span></h2>
-
-<div class="memitem">
-<div class="memproto">
-<div class="memtemplate">
-template&lt;typename T&gt; </div>
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue</a>&lt; T &gt;::<a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a>&#160;</td>
-          <td class="paramname"><em>error</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Construct a <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> containing an error result.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">error</td><td>The error </td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<a id="a600309367db58d71f0ec16e90f7ebea5"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a600309367db58d71f0ec16e90f7ebea5">&#9670;&nbsp;</a></span>ResultWithValue() <span class="overload">[2/2]</span></h2>
-
-<div class="memitem">
-<div class="memproto">
-<div class="memtemplate">
-template&lt;typename T&gt; </div>
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue</a>&lt; T &gt;::<a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> </td>
-          <td>(</td>
-          <td class="paramtype">T&#160;</td>
-          <td class="paramname"><em>value</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">explicit</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Construct a <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> containing an OK result and a value.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">value</td><td>the value to store </td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<h2 class="groupheader">Member Function Documentation</h2>
-<a id="a2304c6120e2aad8f2189383a98c7b0a7"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a2304c6120e2aad8f2189383a98c7b0a7">&#9670;&nbsp;</a></span>createBasedOnSign()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<div class="memtemplate">
-template&lt;typename T&gt; </div>
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">static <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt;T&gt; <a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue</a>&lt; T &gt;::createBasedOnSign </td>
-          <td>(</td>
-          <td class="paramtype">T&#160;</td>
-          <td class="paramname"><em>numericResult</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">static</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Create a <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> from a number. If the number is positive the <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> will have a result of Result::OK and the value will contain the number. If the number is negative the result will be obtained from the negative number (numeric error codes can be found in AAudio.h) and the value will be null. </p>
-
-</div>
-</div>
-<a id="adfc76ae6db81535c2e82b856975eed41"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#adfc76ae6db81535c2e82b856975eed41">&#9670;&nbsp;</a></span>error()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<div class="memtemplate">
-template&lt;typename T&gt; </div>
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a> <a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue</a>&lt; T &gt;::error </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Get the result.</p>
-<dl class="section return"><dt>Returns</dt><dd>the result </dd></dl>
-
-</div>
-</div>
-<a id="a6fb3c61c5716a045ba48dc5a5dfc8169"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a6fb3c61c5716a045ba48dc5a5dfc8169">&#9670;&nbsp;</a></span>operator !()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<div class="memtemplate">
-template&lt;typename T&gt; </div>
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">bool <a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue</a>&lt; T &gt;::operator ! </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Quick way to check for an error.</p>
-<p>The caller could write something like this: <code> if (!result) { printf("Got error %s\n", convertToText(result.error())); } </code></p>
-<dl class="section return"><dt>Returns</dt><dd>true if an error occurred </dd></dl>
-
-</div>
-</div>
-<a id="ae32b1953b777af7d1d0c94862ca39986"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ae32b1953b777af7d1d0c94862ca39986">&#9670;&nbsp;</a></span>operator bool()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<div class="memtemplate">
-template&lt;typename T&gt; </div>
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue</a>&lt; T &gt;::operator bool </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">explicit</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>true if OK </dd></dl>
-
-</div>
-</div>
-<a id="af62107817c0bc76047e6b655a78504ba"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#af62107817c0bc76047e6b655a78504ba">&#9670;&nbsp;</a></span>operator Result()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<div class="memtemplate">
-template&lt;typename T&gt; </div>
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue</a>&lt; T &gt;::operator <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Implicitly convert to a Result. This enables easy comparison with Result values. Example:</p>
-<p><code> <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a> result = openStream(); if (result == Result::ErrorNoMemory){ // tell user they're out of memory } </code> </p>
-
-</div>
-</div>
-<a id="a45f5c99a2c9f8fbaca502276f7ebb434"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a45f5c99a2c9f8fbaca502276f7ebb434">&#9670;&nbsp;</a></span>value()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<div class="memtemplate">
-template&lt;typename T&gt; </div>
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">T <a class="el" href="classoboe_1_1_result_with_value.html">oboe::ResultWithValue</a>&lt; T &gt;::value </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td> const</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Get the value </p><dl class="section return"><dt>Returns</dt><dd></dd></dl>
-
-</div>
-</div>
-<hr/>The documentation for this class was generated from the following file:<ul>
-<li>include/oboe/<a class="el" href="_result_with_value_8h_source.html">ResultWithValue.h</a></li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_stabilized_callback-members.html b/docs/reference/classoboe_1_1_stabilized_callback-members.html
deleted file mode 100644
index 5b58d7b..0000000
--- a/docs/reference/classoboe_1_1_stabilized_callback-members.html
+++ /dev/null
@@ -1,93 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Member List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_stabilized_callback.html">StabilizedCallback</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe::StabilizedCallback Member List</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p>This is the complete list of members for <a class="el" href="classoboe_1_1_stabilized_callback.html">oboe::StabilizedCallback</a>, including all inherited members.</p>
-<table class="directory">
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_stabilized_callback.html#ad447e12ebf732cf151655c1fbaf58a49">onAudioReady</a>(AudioStream *oboeStream, void *audioData, int32_t numFrames) override</td><td class="entry"><a class="el" href="classoboe_1_1_stabilized_callback.html">oboe::StabilizedCallback</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">onError</a>(AudioStream *, Result)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classoboe_1_1_stabilized_callback.html#af7521da42c4b08a71e6102994f6f41f4">onErrorAfterClose</a>(AudioStream *oboeStream, Result error) override</td><td class="entry"><a class="el" href="classoboe_1_1_stabilized_callback.html">oboe::StabilizedCallback</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr><td class="entry"><a class="el" href="classoboe_1_1_stabilized_callback.html#a7ec0e9fca3181962ab78716bcda83e10">onErrorBeforeClose</a>(AudioStream *oboeStream, Result error) override</td><td class="entry"><a class="el" href="classoboe_1_1_stabilized_callback.html">oboe::StabilizedCallback</a></td><td class="entry"><span class="mlabel">inline</span><span class="mlabel">virtual</span></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>StabilizedCallback</b>(AudioStreamCallback *callback) (defined in <a class="el" href="classoboe_1_1_stabilized_callback.html">oboe::StabilizedCallback</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_stabilized_callback.html">oboe::StabilizedCallback</a></td><td class="entry"><span class="mlabel">explicit</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>~AudioStreamCallback</b>()=default (defined in <a class="el" href="classoboe_1_1_audio_stream_callback.html">oboe::AudioStreamCallback</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_callback.html">oboe::AudioStreamCallback</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>~AudioStreamDataCallback</b>()=default (defined in <a class="el" href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">oboe::AudioStreamDataCallback</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>~AudioStreamErrorCallback</b>()=default (defined in <a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a>)</td><td class="entry"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
-</table></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_stabilized_callback.html b/docs/reference/classoboe_1_1_stabilized_callback.html
deleted file mode 100644
index 0026cd0..0000000
--- a/docs/reference/classoboe_1_1_stabilized_callback.html
+++ /dev/null
@@ -1,299 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe::StabilizedCallback Class Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="classoboe_1_1_stabilized_callback.html">StabilizedCallback</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="#pub-methods">Public Member Functions</a> &#124;
-<a href="classoboe_1_1_stabilized_callback-members.html">List of all members</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe::StabilizedCallback Class Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="dynheader">
-Inheritance diagram for oboe::StabilizedCallback:</div>
-<div class="dyncontent">
- <div class="center">
-  <img src="classoboe_1_1_stabilized_callback.png" usemap="#oboe::StabilizedCallback_map" alt=""/>
-  <map id="oboe::StabilizedCallback_map" name="oboe::StabilizedCallback_map">
-<area href="classoboe_1_1_audio_stream_callback.html" alt="oboe::AudioStreamCallback" shape="rect" coords="103,56,300,80"/>
-<area href="classoboe_1_1_audio_stream_data_callback.html" alt="oboe::AudioStreamDataCallback" shape="rect" coords="0,0,197,24"/>
-<area href="classoboe_1_1_audio_stream_error_callback.html" alt="oboe::AudioStreamErrorCallback" shape="rect" coords="207,0,404,24"/>
-  </map>
-</div></div>
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-methods"></a>
-Public Member Functions</h2></td></tr>
-<tr class="memitem:a2db099d5fcac6fb939f40be16a3abeae"><td class="memItemLeft" align="right" valign="top"><a id="a2db099d5fcac6fb939f40be16a3abeae"></a>
-&#160;</td><td class="memItemRight" valign="bottom"><b>StabilizedCallback</b> (<a class="el" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a> *callback)</td></tr>
-<tr class="separator:a2db099d5fcac6fb939f40be16a3abeae"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ad447e12ebf732cf151655c1fbaf58a49"><td class="memItemLeft" align="right" valign="top"><a class="el" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_stabilized_callback.html#ad447e12ebf732cf151655c1fbaf58a49">onAudioReady</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *oboeStream, void *audioData, int32_t numFrames) override</td></tr>
-<tr class="separator:ad447e12ebf732cf151655c1fbaf58a49"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a7ec0e9fca3181962ab78716bcda83e10"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_stabilized_callback.html#a7ec0e9fca3181962ab78716bcda83e10">onErrorBeforeClose</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *oboeStream, <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> error) override</td></tr>
-<tr class="separator:a7ec0e9fca3181962ab78716bcda83e10"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:af7521da42c4b08a71e6102994f6f41f4"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_stabilized_callback.html#af7521da42c4b08a71e6102994f6f41f4">onErrorAfterClose</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *oboeStream, <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> error) override</td></tr>
-<tr class="separator:af7521da42c4b08a71e6102994f6f41f4"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="inherit_header pub_methods_classoboe_1_1_audio_stream_error_callback"><td colspan="2" onclick="javascript:toggleInherit('pub_methods_classoboe_1_1_audio_stream_error_callback')"><img src="closed.png" alt="-"/>&#160;Public Member Functions inherited from <a class="el" href="classoboe_1_1_audio_stream_error_callback.html">oboe::AudioStreamErrorCallback</a></td></tr>
-<tr class="memitem:a5ad4b8936746ecbb2160a9389b117fc3 inherit pub_methods_classoboe_1_1_audio_stream_error_callback"><td class="memItemLeft" align="right" valign="top">virtual bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">onError</a> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *, <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>)</td></tr>
-<tr class="separator:a5ad4b8936746ecbb2160a9389b117fc3 inherit pub_methods_classoboe_1_1_audio_stream_error_callback"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<h2 class="groupheader">Member Function Documentation</h2>
-<a id="ad447e12ebf732cf151655c1fbaf58a49"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ad447e12ebf732cf151655c1fbaf58a49">&#9670;&nbsp;</a></span>onAudioReady()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname"><a class="el" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a> oboe::StabilizedCallback::onAudioReady </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *&#160;</td>
-          <td class="paramname"><em>audioStream</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">void *&#160;</td>
-          <td class="paramname"><em>audioData</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int32_t&#160;</td>
-          <td class="paramname"><em>numFrames</em>&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">override</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>A buffer is ready for processing.</p>
-<p>For an output stream, this function should render and write numFrames of data in the stream's current data format to the audioData buffer.</p>
-<p>For an input stream, this function should read and process numFrames of data from the audioData buffer.</p>
-<p>The audio data is passed through the buffer. So do NOT call read() or write() on the stream that is making the callback.</p>
-<p>Note that numFrames can vary unless <a class="el" href="classoboe_1_1_audio_stream_builder.html#a3f397821f61eabaeedaf31064c859a54">AudioStreamBuilder::setFramesPerCallback()</a> is called.</p>
-<p>Also note that this callback function should be considered a "real-time" function. It must not do anything that could cause an unbounded delay because that can cause the audio to glitch or pop.</p>
-<p>These are things the function should NOT do: </p><ul>
-<li>
-allocate memory using, for example, malloc() or new </li>
-<li>
-any file operations such as opening, closing, reading or writing </li>
-<li>
-any network operations such as streaming </li>
-<li>
-use any mutexes or other synchronization primitives </li>
-<li>
-sleep </li>
-<li>
-oboeStream-&gt;stop(), pause(), flush() or close() </li>
-<li>
-oboeStream-&gt;read() </li>
-<li>
-oboeStream-&gt;write() </li>
-</ul>
-<p>The following are OK to call from the data callback: </p><ul>
-<li>
-oboeStream-&gt;get*() </li>
-<li>
-<a class="el" href="namespaceoboe.html#af65aaea3c5d82eee6906664d61c094b3">oboe::convertToText()</a> </li>
-<li>
-oboeStream-&gt;setBufferSizeInFrames() </li>
-</ul>
-<p>If you need to move data, eg. MIDI commands, in or out of the callback function then we recommend the use of non-blocking techniques such as an atomic FIFO.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">audioStream</td><td>pointer to the associated stream </td></tr>
-    <tr><td class="paramname">audioData</td><td>buffer containing input data or a place to put output data </td></tr>
-    <tr><td class="paramname">numFrames</td><td>number of frames to be processed </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>DataCallbackResult::Continue or DataCallbackResult::Stop </dd></dl>
-
-<p>Implements <a class="el" href="classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d">oboe::AudioStreamDataCallback</a>.</p>
-
-</div>
-</div>
-<a id="af7521da42c4b08a71e6102994f6f41f4"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#af7521da42c4b08a71e6102994f6f41f4">&#9670;&nbsp;</a></span>onErrorAfterClose()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">void oboe::StabilizedCallback::onErrorAfterClose </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *&#160;</td>
-          <td class="paramname">, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td>
-          <td class="paramname">&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">override</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>This will be called when an error occurs on a stream, such as when the stream is disconnected, and if <a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">onError()</a> returns false (indicating that the error has not already been handled).</p>
-<p>The underlying AAudio or OpenSL ES stream will already be stopped AND closed by Oboe. So the underlying stream cannot be referenced. But you can still query most parameters.</p>
-<p>This callback could be used to reopen a new stream on another device.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">audioStream</td><td>pointer to the associated stream </td></tr>
-    <tr><td class="paramname">error</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-
-<p>Reimplemented from <a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe">oboe::AudioStreamErrorCallback</a>.</p>
-
-</div>
-</div>
-<a id="a7ec0e9fca3181962ab78716bcda83e10"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a7ec0e9fca3181962ab78716bcda83e10">&#9670;&nbsp;</a></span>onErrorBeforeClose()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">void oboe::StabilizedCallback::onErrorBeforeClose </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *&#160;</td>
-          <td class="paramname">, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a>&#160;</td>
-          <td class="paramname">&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">inline</span><span class="mlabel">override</span><span class="mlabel">virtual</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>This will be called when an error occurs on a stream, such as when the stream is disconnected, and if <a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">onError()</a> returns false (indicating that the error has not already been handled).</p>
-<p>Note that this will be called on a thread created by Oboe.</p>
-<p>The underlying stream will already be stopped by Oboe but not yet closed. So the stream can be queried.</p>
-<p>Do not close or delete the stream in this method because it will be closed after this method returns.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">audioStream</td><td>pointer to the associated stream </td></tr>
-    <tr><td class="paramname">error</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-
-<p>Reimplemented from <a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0">oboe::AudioStreamErrorCallback</a>.</p>
-
-</div>
-</div>
-<hr/>The documentation for this class was generated from the following file:<ul>
-<li>include/oboe/<a class="el" href="_stabilized_callback_8h_source.html">StabilizedCallback.h</a></li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/classoboe_1_1_stabilized_callback.png b/docs/reference/classoboe_1_1_stabilized_callback.png
deleted file mode 100644
index f3748f8..0000000
--- a/docs/reference/classoboe_1_1_stabilized_callback.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/closed.png b/docs/reference/closed.png
deleted file mode 100644
index 98cc2c9..0000000
--- a/docs/reference/closed.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/deprecated.html b/docs/reference/deprecated.html
deleted file mode 100644
index 6d2aa37..0000000
--- a/docs/reference/deprecated.html
+++ /dev/null
@@ -1,91 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Deprecated List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-</div><!-- top -->
-<div class="PageDoc"><div class="header">
-  <div class="headertitle">
-<div class="title">Deprecated List </div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="textblock"><dl class="reflist">
-<dt>Member <a class="el" href="classoboe_1_1_audio_stream.html#acb8edbc17ff79993a8ed996d216fe6f3">oboe::AudioStream::getTimestamp</a>  (clockid_t, int64_t *, int64_t *)</dt>
-<dd><a class="anchor" id="_deprecated000001"></a>since 1.0, use <a class="el" href="classoboe_1_1_audio_stream.html#a49254e6b1b19cb6d0ca6c63058029771">AudioStream::getTimestamp(clockid_t clockId)</a> instead, which returns <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>  </dd>
-<dt>Member <a class="el" href="classoboe_1_1_audio_stream_base.html#a8878a90949badbb5486cc2e022a57086">oboe::AudioStreamBase::getFramesPerCallback</a>  () const</dt>
-<dd><a class="anchor" id="_deprecated000002"></a>use <code>getFramesPerDataCallback</code> instead.  </dd>
-<dt>Member <a class="el" href="classoboe_1_1_audio_stream_builder.html#a86b94cfa47729bef2e04dce1a9086074">oboe::AudioStreamBuilder::openStream</a>  (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> **stream)</dt>
-<dd><a class="anchor" id="_deprecated000004"></a>Use <a class="el" href="classoboe_1_1_audio_stream_builder.html#a44b68216c48f8fb08a9e63178e0b0eeb">openStream(std::shared_ptr&lt;oboe::AudioStream&gt; &amp;stream)</a> instead.  </dd>
-<dt>Member <a class="el" href="classoboe_1_1_audio_stream_builder.html#a3f397821f61eabaeedaf31064c859a54">oboe::AudioStreamBuilder::setFramesPerCallback</a>  (int framesPerCallback)</dt>
-<dd><a class="anchor" id="_deprecated000003"></a>use <code>setFramesPerDataCallback</code> instead.  </dd>
-<dt>Class <a class="el" href="classoboe_1_1_audio_stream_callback.html">oboe::AudioStreamCallback</a>  </dt>
-<dd><a class="anchor" id="_deprecated000005"></a>Use <code><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a></code> and <code><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a></code> instead </dd>
-</dl>
-</div></div><!-- PageDoc -->
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/dir_768f6301d9838e45d679001914ab2803.html b/docs/reference/dir_768f6301d9838e45d679001914ab2803.html
deleted file mode 100644
index 4e1ebc5..0000000
--- a/docs/reference/dir_768f6301d9838e45d679001914ab2803.html
+++ /dev/null
@@ -1,82 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: include/oboe Directory Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="dir_d44c64559bbebec7f509842c48db8b23.html">include</a></li><li class="navelem"><a class="el" href="dir_768f6301d9838e45d679001914ab2803.html">oboe</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe Directory Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/dir_d44c64559bbebec7f509842c48db8b23.html b/docs/reference/dir_d44c64559bbebec7f509842c48db8b23.html
deleted file mode 100644
index 4620fd8..0000000
--- a/docs/reference/dir_d44c64559bbebec7f509842c48db8b23.html
+++ /dev/null
@@ -1,86 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: include Directory Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="dir_d44c64559bbebec7f509842c48db8b23.html">include</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">include Directory Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="subdirs"></a>
-Directories</h2></td></tr>
-</table>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/doc.png b/docs/reference/doc.png
deleted file mode 100644
index 17edabf..0000000
--- a/docs/reference/doc.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/doxygen.css b/docs/reference/doxygen.css
deleted file mode 100644
index e251592..0000000
--- a/docs/reference/doxygen.css
+++ /dev/null
@@ -1,1764 +0,0 @@
-/* The standard CSS for doxygen 1.8.15 */
-
-body, table, div, p, dl {
-	font: 400 14px/22px Roboto,sans-serif;
-}
-
-p.reference, p.definition {
-	font: 400 14px/22px Roboto,sans-serif;
-}
-
-/* @group Heading Levels */
-
-h1.groupheader {
-	font-size: 150%;
-}
-
-.title {
-	font: 400 14px/28px Roboto,sans-serif;
-	font-size: 150%;
-	font-weight: bold;
-	margin: 10px 2px;
-}
-
-h2.groupheader {
-	border-bottom: 1px solid #879ECB;
-	color: #354C7B;
-	font-size: 150%;
-	font-weight: normal;
-	margin-top: 1.75em;
-	padding-top: 8px;
-	padding-bottom: 4px;
-	width: 100%;
-}
-
-h3.groupheader {
-	font-size: 100%;
-}
-
-h1, h2, h3, h4, h5, h6 {
-	-webkit-transition: text-shadow 0.5s linear;
-	-moz-transition: text-shadow 0.5s linear;
-	-ms-transition: text-shadow 0.5s linear;
-	-o-transition: text-shadow 0.5s linear;
-	transition: text-shadow 0.5s linear;
-	margin-right: 15px;
-}
-
-h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow {
-	text-shadow: 0 0 15px cyan;
-}
-
-dt {
-	font-weight: bold;
-}
-
-div.multicol {
-	-moz-column-gap: 1em;
-	-webkit-column-gap: 1em;
-	-moz-column-count: 3;
-	-webkit-column-count: 3;
-}
-
-p.startli, p.startdd {
-	margin-top: 2px;
-}
-
-p.starttd {
-	margin-top: 0px;
-}
-
-p.endli {
-	margin-bottom: 0px;
-}
-
-p.enddd {
-	margin-bottom: 4px;
-}
-
-p.endtd {
-	margin-bottom: 2px;
-}
-
-p.interli {
-}
-
-p.interdd {
-}
-
-p.intertd {
-}
-
-/* @end */
-
-caption {
-	font-weight: bold;
-}
-
-span.legend {
-        font-size: 70%;
-        text-align: center;
-}
-
-h3.version {
-        font-size: 90%;
-        text-align: center;
-}
-
-div.qindex, div.navtab{
-	background-color: #EBEFF6;
-	border: 1px solid #A3B4D7;
-	text-align: center;
-}
-
-div.qindex, div.navpath {
-	width: 100%;
-	line-height: 140%;
-}
-
-div.navtab {
-	margin-right: 15px;
-}
-
-/* @group Link Styling */
-
-a {
-	color: #3D578C;
-	font-weight: normal;
-	text-decoration: none;
-}
-
-.contents a:visited {
-	color: #4665A2;
-}
-
-a:hover {
-	text-decoration: underline;
-}
-
-a.qindex {
-	font-weight: bold;
-}
-
-a.qindexHL {
-	font-weight: bold;
-	background-color: #9CAFD4;
-	color: #FFFFFF;
-	border: 1px double #869DCA;
-}
-
-.contents a.qindexHL:visited {
-        color: #FFFFFF;
-}
-
-a.el {
-	font-weight: bold;
-}
-
-a.elRef {
-}
-
-a.code, a.code:visited, a.line, a.line:visited {
-	color: #4665A2; 
-}
-
-a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
-	color: #4665A2; 
-}
-
-/* @end */
-
-dl.el {
-	margin-left: -1cm;
-}
-
-ul {
-  overflow: hidden; /*Fixed: list item bullets overlap floating elements*/
-}
-
-#side-nav ul {
-  overflow: visible; /* reset ul rule for scroll bar in GENERATE_TREEVIEW window */
-}
-
-#main-nav ul {
-  overflow: visible; /* reset ul rule for the navigation bar drop down lists */
-}
-
-.fragment {
-  text-align: left;
-  direction: ltr;
-  overflow-x: auto; /*Fixed: fragment lines overlap floating elements*/
-  overflow-y: hidden;
-}
-
-pre.fragment {
-        border: 1px solid #C4CFE5;
-        background-color: #FBFCFD;
-        padding: 4px 6px;
-        margin: 4px 8px 4px 2px;
-        overflow: auto;
-        word-wrap: break-word;
-        font-size:  9pt;
-        line-height: 125%;
-        font-family: monospace, fixed;
-        font-size: 105%;
-}
-
-div.fragment {
-  padding: 0 0 1px 0; /*Fixed: last line underline overlap border*/
-  margin: 4px 8px 4px 2px;
-	background-color: #FBFCFD;
-	border: 1px solid #C4CFE5;
-}
-
-div.line {
-	font-family: monospace, fixed;
-        font-size: 13px;
-	min-height: 13px;
-	line-height: 1.0;
-	text-wrap: unrestricted;
-	white-space: -moz-pre-wrap; /* Moz */
-	white-space: -pre-wrap;     /* Opera 4-6 */
-	white-space: -o-pre-wrap;   /* Opera 7 */
-	white-space: pre-wrap;      /* CSS3  */
-	word-wrap: break-word;      /* IE 5.5+ */
-	text-indent: -53px;
-	padding-left: 53px;
-	padding-bottom: 0px;
-	margin: 0px;
-	-webkit-transition-property: background-color, box-shadow;
-	-webkit-transition-duration: 0.5s;
-	-moz-transition-property: background-color, box-shadow;
-	-moz-transition-duration: 0.5s;
-	-ms-transition-property: background-color, box-shadow;
-	-ms-transition-duration: 0.5s;
-	-o-transition-property: background-color, box-shadow;
-	-o-transition-duration: 0.5s;
-	transition-property: background-color, box-shadow;
-	transition-duration: 0.5s;
-}
-
-div.line:after {
-    content:"\000A";
-    white-space: pre;
-}
-
-div.line.glow {
-	background-color: cyan;
-	box-shadow: 0 0 10px cyan;
-}
-
-
-span.lineno {
-	padding-right: 4px;
-	text-align: right;
-	border-right: 2px solid #0F0;
-	background-color: #E8E8E8;
-        white-space: pre;
-}
-span.lineno a {
-	background-color: #D8D8D8;
-}
-
-span.lineno a:hover {
-	background-color: #C8C8C8;
-}
-
-.lineno {
-	-webkit-touch-callout: none;
-	-webkit-user-select: none;
-	-khtml-user-select: none;
-	-moz-user-select: none;
-	-ms-user-select: none;
-	user-select: none;
-}
-
-div.ah, span.ah {
-	background-color: black;
-	font-weight: bold;
-	color: #FFFFFF;
-	margin-bottom: 3px;
-	margin-top: 3px;
-	padding: 0.2em;
-	border: solid thin #333;
-	border-radius: 0.5em;
-	-webkit-border-radius: .5em;
-	-moz-border-radius: .5em;
-	box-shadow: 2px 2px 3px #999;
-	-webkit-box-shadow: 2px 2px 3px #999;
-	-moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
-	background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));
-	background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000 110%);
-}
-
-div.classindex ul {
-        list-style: none;
-        padding-left: 0;
-}
-
-div.classindex span.ai {
-        display: inline-block;
-}
-
-div.groupHeader {
-	margin-left: 16px;
-	margin-top: 12px;
-	font-weight: bold;
-}
-
-div.groupText {
-	margin-left: 16px;
-	font-style: italic;
-}
-
-body {
-	background-color: white;
-	color: black;
-        margin: 0;
-}
-
-div.contents {
-	margin-top: 10px;
-	margin-left: 12px;
-	margin-right: 8px;
-}
-
-td.indexkey {
-	background-color: #EBEFF6;
-	font-weight: bold;
-	border: 1px solid #C4CFE5;
-	margin: 2px 0px 2px 0;
-	padding: 2px 10px;
-        white-space: nowrap;
-        vertical-align: top;
-}
-
-td.indexvalue {
-	background-color: #EBEFF6;
-	border: 1px solid #C4CFE5;
-	padding: 2px 10px;
-	margin: 2px 0px;
-}
-
-tr.memlist {
-	background-color: #EEF1F7;
-}
-
-p.formulaDsp {
-	text-align: center;
-}
-
-img.formulaDsp {
-	
-}
-
-img.formulaInl, img.inline {
-	vertical-align: middle;
-}
-
-div.center {
-	text-align: center;
-        margin-top: 0px;
-        margin-bottom: 0px;
-        padding: 0px;
-}
-
-div.center img {
-	border: 0px;
-}
-
-address.footer {
-	text-align: right;
-	padding-right: 12px;
-}
-
-img.footer {
-	border: 0px;
-	vertical-align: middle;
-}
-
-/* @group Code Colorization */
-
-span.keyword {
-	color: #008000
-}
-
-span.keywordtype {
-	color: #604020
-}
-
-span.keywordflow {
-	color: #e08000
-}
-
-span.comment {
-	color: #800000
-}
-
-span.preprocessor {
-	color: #806020
-}
-
-span.stringliteral {
-	color: #002080
-}
-
-span.charliteral {
-	color: #008080
-}
-
-span.vhdldigit { 
-	color: #ff00ff 
-}
-
-span.vhdlchar { 
-	color: #000000 
-}
-
-span.vhdlkeyword { 
-	color: #700070 
-}
-
-span.vhdllogic { 
-	color: #ff0000 
-}
-
-blockquote {
-        background-color: #F7F8FB;
-        border-left: 2px solid #9CAFD4;
-        margin: 0 24px 0 4px;
-        padding: 0 12px 0 16px;
-}
-
-blockquote.DocNodeRTL {
-   border-left: 0;
-   border-right: 2px solid #9CAFD4;
-   margin: 0 4px 0 24px;
-   padding: 0 16px 0 12px;
-}
-
-/* @end */
-
-/*
-.search {
-	color: #003399;
-	font-weight: bold;
-}
-
-form.search {
-	margin-bottom: 0px;
-	margin-top: 0px;
-}
-
-input.search {
-	font-size: 75%;
-	color: #000080;
-	font-weight: normal;
-	background-color: #e8eef2;
-}
-*/
-
-td.tiny {
-	font-size: 75%;
-}
-
-.dirtab {
-	padding: 4px;
-	border-collapse: collapse;
-	border: 1px solid #A3B4D7;
-}
-
-th.dirtab {
-	background: #EBEFF6;
-	font-weight: bold;
-}
-
-hr {
-	height: 0px;
-	border: none;
-	border-top: 1px solid #4A6AAA;
-}
-
-hr.footer {
-	height: 1px;
-}
-
-/* @group Member Descriptions */
-
-table.memberdecls {
-	border-spacing: 0px;
-	padding: 0px;
-}
-
-.memberdecls td, .fieldtable tr {
-	-webkit-transition-property: background-color, box-shadow;
-	-webkit-transition-duration: 0.5s;
-	-moz-transition-property: background-color, box-shadow;
-	-moz-transition-duration: 0.5s;
-	-ms-transition-property: background-color, box-shadow;
-	-ms-transition-duration: 0.5s;
-	-o-transition-property: background-color, box-shadow;
-	-o-transition-duration: 0.5s;
-	transition-property: background-color, box-shadow;
-	transition-duration: 0.5s;
-}
-
-.memberdecls td.glow, .fieldtable tr.glow {
-	background-color: cyan;
-	box-shadow: 0 0 15px cyan;
-}
-
-.mdescLeft, .mdescRight,
-.memItemLeft, .memItemRight,
-.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
-	background-color: #F9FAFC;
-	border: none;
-	margin: 4px;
-	padding: 1px 0 0 8px;
-}
-
-.mdescLeft, .mdescRight {
-	padding: 0px 8px 4px 8px;
-	color: #555;
-}
-
-.memSeparator {
-        border-bottom: 1px solid #DEE4F0;
-        line-height: 1px;
-        margin: 0px;
-        padding: 0px;
-}
-
-.memItemLeft, .memTemplItemLeft {
-        white-space: nowrap;
-}
-
-.memItemRight {
-	width: 100%;
-}
-
-.memTemplParams {
-	color: #4665A2;
-        white-space: nowrap;
-	font-size: 80%;
-}
-
-/* @end */
-
-/* @group Member Details */
-
-/* Styles for detailed member documentation */
-
-.memtitle {
-	padding: 8px;
-	border-top: 1px solid #A8B8D9;
-	border-left: 1px solid #A8B8D9;
-	border-right: 1px solid #A8B8D9;
-	border-top-right-radius: 4px;
-	border-top-left-radius: 4px;
-	margin-bottom: -1px;
-	background-image: url('nav_f.png');
-	background-repeat: repeat-x;
-	background-color: #E2E8F2;
-	line-height: 1.25;
-	font-weight: 300;
-	float:left;
-}
-
-.permalink
-{
-        font-size: 65%;
-        display: inline-block;
-        vertical-align: middle;
-}
-
-.memtemplate {
-	font-size: 80%;
-	color: #4665A2;
-	font-weight: normal;
-	margin-left: 9px;
-}
-
-.memnav {
-	background-color: #EBEFF6;
-	border: 1px solid #A3B4D7;
-	text-align: center;
-	margin: 2px;
-	margin-right: 15px;
-	padding: 2px;
-}
-
-.mempage {
-	width: 100%;
-}
-
-.memitem {
-	padding: 0;
-	margin-bottom: 10px;
-	margin-right: 5px;
-        -webkit-transition: box-shadow 0.5s linear;
-        -moz-transition: box-shadow 0.5s linear;
-        -ms-transition: box-shadow 0.5s linear;
-        -o-transition: box-shadow 0.5s linear;
-        transition: box-shadow 0.5s linear;
-        display: table !important;
-        width: 100%;
-}
-
-.memitem.glow {
-         box-shadow: 0 0 15px cyan;
-}
-
-.memname {
-        font-weight: 400;
-        margin-left: 6px;
-}
-
-.memname td {
-	vertical-align: bottom;
-}
-
-.memproto, dl.reflist dt {
-        border-top: 1px solid #A8B8D9;
-        border-left: 1px solid #A8B8D9;
-        border-right: 1px solid #A8B8D9;
-        padding: 6px 0px 6px 0px;
-        color: #253555;
-        font-weight: bold;
-        text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
-        background-color: #DFE5F1;
-        /* opera specific markup */
-        box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
-        border-top-right-radius: 4px;
-        /* firefox specific markup */
-        -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
-        -moz-border-radius-topright: 4px;
-        /* webkit specific markup */
-        -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
-        -webkit-border-top-right-radius: 4px;
-
-}
-
-.overload {
-        font-family: "courier new",courier,monospace;
-	font-size: 65%;
-}
-
-.memdoc, dl.reflist dd {
-        border-bottom: 1px solid #A8B8D9;      
-        border-left: 1px solid #A8B8D9;      
-        border-right: 1px solid #A8B8D9; 
-        padding: 6px 10px 2px 10px;
-        background-color: #FBFCFD;
-        border-top-width: 0;
-        background-image:url('nav_g.png');
-        background-repeat:repeat-x;
-        background-color: #FFFFFF;
-        /* opera specific markup */
-        border-bottom-left-radius: 4px;
-        border-bottom-right-radius: 4px;
-        box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
-        /* firefox specific markup */
-        -moz-border-radius-bottomleft: 4px;
-        -moz-border-radius-bottomright: 4px;
-        -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
-        /* webkit specific markup */
-        -webkit-border-bottom-left-radius: 4px;
-        -webkit-border-bottom-right-radius: 4px;
-        -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
-}
-
-dl.reflist dt {
-        padding: 5px;
-}
-
-dl.reflist dd {
-        margin: 0px 0px 10px 0px;
-        padding: 5px;
-}
-
-.paramkey {
-	text-align: right;
-}
-
-.paramtype {
-	white-space: nowrap;
-}
-
-.paramname {
-	color: #602020;
-	white-space: nowrap;
-}
-.paramname em {
-	font-style: normal;
-}
-.paramname code {
-        line-height: 14px;
-}
-
-.params, .retval, .exception, .tparams {
-        margin-left: 0px;
-        padding-left: 0px;
-}       
-
-.params .paramname, .retval .paramname, .tparams .paramname {
-        font-weight: bold;
-        vertical-align: top;
-}
-        
-.params .paramtype, .tparams .paramtype {
-        font-style: italic;
-        vertical-align: top;
-}       
-        
-.params .paramdir, .tparams .paramdir {
-        font-family: "courier new",courier,monospace;
-        vertical-align: top;
-}
-
-table.mlabels {
-	border-spacing: 0px;
-}
-
-td.mlabels-left {
-	width: 100%;
-	padding: 0px;
-}
-
-td.mlabels-right {
-	vertical-align: bottom;
-	padding: 0px;
-	white-space: nowrap;
-}
-
-span.mlabels {
-        margin-left: 8px;
-}
-
-span.mlabel {
-        background-color: #728DC1;
-        border-top:1px solid #5373B4;
-        border-left:1px solid #5373B4;
-        border-right:1px solid #C4CFE5;
-        border-bottom:1px solid #C4CFE5;
-	text-shadow: none;
-	color: white;
-	margin-right: 4px;
-	padding: 2px 3px;
-	border-radius: 3px;
-	font-size: 7pt;
-	white-space: nowrap;
-	vertical-align: middle;
-}
-
-
-
-/* @end */
-
-/* these are for tree view inside a (index) page */
-
-div.directory {
-        margin: 10px 0px;
-        border-top: 1px solid #9CAFD4;
-        border-bottom: 1px solid #9CAFD4;
-        width: 100%;
-}
-
-.directory table {
-        border-collapse:collapse;
-}
-
-.directory td {
-        margin: 0px;
-        padding: 0px;
-	vertical-align: top;
-}
-
-.directory td.entry {
-        white-space: nowrap;
-        padding-right: 6px;
-	padding-top: 3px;
-}
-
-.directory td.entry a {
-        outline:none;
-}
-
-.directory td.entry a img {
-        border: none;
-}
-
-.directory td.desc {
-        width: 100%;
-        padding-left: 6px;
-	padding-right: 6px;
-	padding-top: 3px;
-	border-left: 1px solid rgba(0,0,0,0.05);
-}
-
-.directory tr.even {
-	padding-left: 6px;
-	background-color: #F7F8FB;
-}
-
-.directory img {
-	vertical-align: -30%;
-}
-
-.directory .levels {
-        white-space: nowrap;
-        width: 100%;
-        text-align: right;
-        font-size: 9pt;
-}
-
-.directory .levels span {
-        cursor: pointer;
-        padding-left: 2px;
-        padding-right: 2px;
-	color: #3D578C;
-}
-
-.arrow {
-    color: #9CAFD4;
-    -webkit-user-select: none;
-    -khtml-user-select: none;
-    -moz-user-select: none;
-    -ms-user-select: none;
-    user-select: none;
-    cursor: pointer;
-    font-size: 80%;
-    display: inline-block;
-    width: 16px;
-    height: 22px;
-}
-
-.icon {
-    font-family: Arial, Helvetica;
-    font-weight: bold;
-    font-size: 12px;
-    height: 14px;
-    width: 16px;
-    display: inline-block;
-    background-color: #728DC1;
-    color: white;
-    text-align: center;
-    border-radius: 4px;
-    margin-left: 2px;
-    margin-right: 2px;
-}
-
-.icona {
-    width: 24px;
-    height: 22px;
-    display: inline-block;
-}
-
-.iconfopen {
-    width: 24px;
-    height: 18px;
-    margin-bottom: 4px;
-    background-image:url('folderopen.png');
-    background-position: 0px -4px;
-    background-repeat: repeat-y;
-    vertical-align:top;
-    display: inline-block;
-}
-
-.iconfclosed {
-    width: 24px;
-    height: 18px;
-    margin-bottom: 4px;
-    background-image:url('folderclosed.png');
-    background-position: 0px -4px;
-    background-repeat: repeat-y;
-    vertical-align:top;
-    display: inline-block;
-}
-
-.icondoc {
-    width: 24px;
-    height: 18px;
-    margin-bottom: 4px;
-    background-image:url('doc.png');
-    background-position: 0px -4px;
-    background-repeat: repeat-y;
-    vertical-align:top;
-    display: inline-block;
-}
-
-table.directory {
-    font: 400 14px Roboto,sans-serif;
-}
-
-/* @end */
-
-div.dynheader {
-        margin-top: 8px;
-	-webkit-touch-callout: none;
-	-webkit-user-select: none;
-	-khtml-user-select: none;
-	-moz-user-select: none;
-	-ms-user-select: none;
-	user-select: none;
-}
-
-address {
-	font-style: normal;
-	color: #2A3D61;
-}
-
-table.doxtable caption {
-	caption-side: top;
-}
-
-table.doxtable {
-	border-collapse:collapse;
-        margin-top: 4px;
-        margin-bottom: 4px;
-}
-
-table.doxtable td, table.doxtable th {
-	border: 1px solid #2D4068;
-	padding: 3px 7px 2px;
-}
-
-table.doxtable th {
-	background-color: #374F7F;
-	color: #FFFFFF;
-	font-size: 110%;
-	padding-bottom: 4px;
-	padding-top: 5px;
-}
-
-table.fieldtable {
-        /*width: 100%;*/
-        margin-bottom: 10px;
-        border: 1px solid #A8B8D9;
-        border-spacing: 0px;
-        -moz-border-radius: 4px;
-        -webkit-border-radius: 4px;
-        border-radius: 4px;
-        -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
-        -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
-        box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
-}
-
-.fieldtable td, .fieldtable th {
-        padding: 3px 7px 2px;
-}
-
-.fieldtable td.fieldtype, .fieldtable td.fieldname {
-        white-space: nowrap;
-        border-right: 1px solid #A8B8D9;
-        border-bottom: 1px solid #A8B8D9;
-        vertical-align: top;
-}
-
-.fieldtable td.fieldname {
-        padding-top: 3px;
-}
-
-.fieldtable td.fielddoc {
-        border-bottom: 1px solid #A8B8D9;
-        /*width: 100%;*/
-}
-
-.fieldtable td.fielddoc p:first-child {
-        margin-top: 0px;
-}       
-        
-.fieldtable td.fielddoc p:last-child {
-        margin-bottom: 2px;
-}
-
-.fieldtable tr:last-child td {
-        border-bottom: none;
-}
-
-.fieldtable th {
-        background-image:url('nav_f.png');
-        background-repeat:repeat-x;
-        background-color: #E2E8F2;
-        font-size: 90%;
-        color: #253555;
-        padding-bottom: 4px;
-        padding-top: 5px;
-        text-align:left;
-        font-weight: 400;
-        -moz-border-radius-topleft: 4px;
-        -moz-border-radius-topright: 4px;
-        -webkit-border-top-left-radius: 4px;
-        -webkit-border-top-right-radius: 4px;
-        border-top-left-radius: 4px;
-        border-top-right-radius: 4px;
-        border-bottom: 1px solid #A8B8D9;
-}
-
-
-.tabsearch {
-	top: 0px;
-	left: 10px;
-	height: 36px;
-	background-image: url('tab_b.png');
-	z-index: 101;
-	overflow: hidden;
-	font-size: 13px;
-}
-
-.navpath ul
-{
-	font-size: 11px;
-	background-image:url('tab_b.png');
-	background-repeat:repeat-x;
-	background-position: 0 -5px;
-	height:30px;
-	line-height:30px;
-	color:#8AA0CC;
-	border:solid 1px #C2CDE4;
-	overflow:hidden;
-	margin:0px;
-	padding:0px;
-}
-
-.navpath li
-{
-	list-style-type:none;
-	float:left;
-	padding-left:10px;
-	padding-right:15px;
-	background-image:url('bc_s.png');
-	background-repeat:no-repeat;
-	background-position:right;
-	color:#364D7C;
-}
-
-.navpath li.navelem a
-{
-	height:32px;
-	display:block;
-	text-decoration: none;
-	outline: none;
-	color: #283A5D;
-	font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif;
-	text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
-	text-decoration: none;        
-}
-
-.navpath li.navelem a:hover
-{
-	color:#6884BD;
-}
-
-.navpath li.footer
-{
-        list-style-type:none;
-        float:right;
-        padding-left:10px;
-        padding-right:15px;
-        background-image:none;
-        background-repeat:no-repeat;
-        background-position:right;
-        color:#364D7C;
-        font-size: 8pt;
-}
-
-
-div.summary
-{
-	float: right;
-	font-size: 8pt;
-	padding-right: 5px;
-	width: 50%;
-	text-align: right;
-}       
-
-div.summary a
-{
-	white-space: nowrap;
-}
-
-table.classindex
-{
-        margin: 10px;
-        white-space: nowrap;
-        margin-left: 3%;
-        margin-right: 3%;
-        width: 94%;
-        border: 0;
-        border-spacing: 0; 
-        padding: 0;
-}
-
-div.ingroups
-{
-	font-size: 8pt;
-	width: 50%;
-	text-align: left;
-}
-
-div.ingroups a
-{
-	white-space: nowrap;
-}
-
-div.header
-{
-        background-image:url('nav_h.png');
-        background-repeat:repeat-x;
-	background-color: #F9FAFC;
-	margin:  0px;
-	border-bottom: 1px solid #C4CFE5;
-}
-
-div.headertitle
-{
-	padding: 5px 5px 5px 10px;
-}
-
-.PageDocRTL-title div.headertitle {
-  text-align: right;
-  direction: rtl;
-}
-
-dl {
-        padding: 0 0 0 0;
-}
-
-/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug, dl.examples */
-dl.section {
-	margin-left: 0px;
-	padding-left: 0px;
-}
-
-dl.section.DocNodeRTL {
-  margin-right: 0px;
-  padding-right: 0px;
-}
-
-dl.note {
-  margin-left: -7px;
-  padding-left: 3px;
-  border-left: 4px solid;
-  border-color: #D0C000;
-}
-
-dl.note.DocNodeRTL {
-  margin-left: 0;
-  padding-left: 0;
-  border-left: 0;
-  margin-right: -7px;
-  padding-right: 3px;
-  border-right: 4px solid;
-  border-color: #D0C000;
-}
-
-dl.warning, dl.attention {
-  margin-left: -7px;
-  padding-left: 3px;
-  border-left: 4px solid;
-  border-color: #FF0000;
-}
-
-dl.warning.DocNodeRTL, dl.attention.DocNodeRTL {
-  margin-left: 0;
-  padding-left: 0;
-  border-left: 0;
-  margin-right: -7px;
-  padding-right: 3px;
-  border-right: 4px solid;
-  border-color: #FF0000;
-}
-
-dl.pre, dl.post, dl.invariant {
-  margin-left: -7px;
-  padding-left: 3px;
-  border-left: 4px solid;
-  border-color: #00D000;
-}
-
-dl.pre.DocNodeRTL, dl.post.DocNodeRTL, dl.invariant.DocNodeRTL {
-  margin-left: 0;
-  padding-left: 0;
-  border-left: 0;
-  margin-right: -7px;
-  padding-right: 3px;
-  border-right: 4px solid;
-  border-color: #00D000;
-}
-
-dl.deprecated {
-  margin-left: -7px;
-  padding-left: 3px;
-  border-left: 4px solid;
-  border-color: #505050;
-}
-
-dl.deprecated.DocNodeRTL {
-  margin-left: 0;
-  padding-left: 0;
-  border-left: 0;
-  margin-right: -7px;
-  padding-right: 3px;
-  border-right: 4px solid;
-  border-color: #505050;
-}
-
-dl.todo {
-  margin-left: -7px;
-  padding-left: 3px;
-  border-left: 4px solid;
-  border-color: #00C0E0;
-}
-
-dl.todo.DocNodeRTL {
-  margin-left: 0;
-  padding-left: 0;
-  border-left: 0;
-  margin-right: -7px;
-  padding-right: 3px;
-  border-right: 4px solid;
-  border-color: #00C0E0;
-}
-
-dl.test {
-  margin-left: -7px;
-  padding-left: 3px;
-  border-left: 4px solid;
-  border-color: #3030E0;
-}
-
-dl.test.DocNodeRTL {
-  margin-left: 0;
-  padding-left: 0;
-  border-left: 0;
-  margin-right: -7px;
-  padding-right: 3px;
-  border-right: 4px solid;
-  border-color: #3030E0;
-}
-
-dl.bug {
-  margin-left: -7px;
-  padding-left: 3px;
-  border-left: 4px solid;
-  border-color: #C08050;
-}
-
-dl.bug.DocNodeRTL {
-  margin-left: 0;
-  padding-left: 0;
-  border-left: 0;
-  margin-right: -7px;
-  padding-right: 3px;
-  border-right: 4px solid;
-  border-color: #C08050;
-}
-
-dl.section dd {
-	margin-bottom: 6px;
-}
-
-
-#projectlogo
-{
-	text-align: center;
-	vertical-align: bottom;
-	border-collapse: separate;
-}
- 
-#projectlogo img
-{ 
-	border: 0px none;
-}
- 
-#projectalign
-{
-        vertical-align: middle;
-}
-
-#projectname
-{
-	font: 300% Tahoma, Arial,sans-serif;
-	margin: 0px;
-	padding: 2px 0px;
-}
-    
-#projectbrief
-{
-	font: 120% Tahoma, Arial,sans-serif;
-	margin: 0px;
-	padding: 0px;
-}
-
-#projectnumber
-{
-	font: 50% Tahoma, Arial,sans-serif;
-	margin: 0px;
-	padding: 0px;
-}
-
-#titlearea
-{
-	padding: 0px;
-	margin: 0px;
-	width: 100%;
-	border-bottom: 1px solid #5373B4;
-}
-
-.image
-{
-        text-align: center;
-}
-
-.dotgraph
-{
-        text-align: center;
-}
-
-.mscgraph
-{
-        text-align: center;
-}
-
-.plantumlgraph
-{
-        text-align: center;
-}
-
-.diagraph
-{
-        text-align: center;
-}
-
-.caption
-{
-	font-weight: bold;
-}
-
-div.zoom
-{
-	border: 1px solid #90A5CE;
-}
-
-dl.citelist {
-        margin-bottom:50px;
-}
-
-dl.citelist dt {
-        color:#334975;
-        float:left;
-        font-weight:bold;
-        margin-right:10px;
-        padding:5px;
-}
-
-dl.citelist dd {
-        margin:2px 0;
-        padding:5px 0;
-}
-
-div.toc {
-        padding: 14px 25px;
-        background-color: #F4F6FA;
-        border: 1px solid #D8DFEE;
-        border-radius: 7px 7px 7px 7px;
-        float: right;
-        height: auto;
-        margin: 0 8px 10px 10px;
-        width: 200px;
-}
-
-.PageDocRTL-title div.toc {
-  float: left !important;
-  text-align: right;
-}
-
-div.toc li {
-        background: url("bdwn.png") no-repeat scroll 0 5px transparent;
-        font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif;
-        margin-top: 5px;
-        padding-left: 10px;
-        padding-top: 2px;
-}
-
-.PageDocRTL-title div.toc li {
-  background-position-x: right !important;
-  padding-left: 0 !important;
-  padding-right: 10px;
-}
-
-div.toc h3 {
-        font: bold 12px/1.2 Arial,FreeSans,sans-serif;
-	color: #4665A2;
-        border-bottom: 0 none;
-        margin: 0;
-}
-
-div.toc ul {
-        list-style: none outside none;
-        border: medium none;
-        padding: 0px;
-}       
-
-div.toc li.level1 {
-        margin-left: 0px;
-}
-
-div.toc li.level2 {
-        margin-left: 15px;
-}
-
-div.toc li.level3 {
-        margin-left: 30px;
-}
-
-div.toc li.level4 {
-        margin-left: 45px;
-}
-
-.PageDocRTL-title div.toc li.level1 {
-  margin-left: 0 !important;
-  margin-right: 0;
-}
-
-.PageDocRTL-title div.toc li.level2 {
-  margin-left: 0 !important;
-  margin-right: 15px;
-}
-
-.PageDocRTL-title div.toc li.level3 {
-  margin-left: 0 !important;
-  margin-right: 30px;
-}
-
-.PageDocRTL-title div.toc li.level4 {
-  margin-left: 0 !important;
-  margin-right: 45px;
-}
-
-.inherit_header {
-        font-weight: bold;
-        color: gray;
-        cursor: pointer;
-	-webkit-touch-callout: none;
-	-webkit-user-select: none;
-	-khtml-user-select: none;
-	-moz-user-select: none;
-	-ms-user-select: none;
-	user-select: none;
-}
-
-.inherit_header td {
-        padding: 6px 0px 2px 5px;
-}
-
-.inherit {
-        display: none;
-}
-
-tr.heading h2 {
-        margin-top: 12px;
-        margin-bottom: 4px;
-}
-
-/* tooltip related style info */
-
-.ttc {
-        position: absolute;
-        display: none;
-}
-
-#powerTip {
-	cursor: default;
-	white-space: nowrap;
-	background-color: white;
-	border: 1px solid gray;
-	border-radius: 4px 4px 4px 4px;
-	box-shadow: 1px 1px 7px gray;
-	display: none;
-	font-size: smaller;
-	max-width: 80%;
-	opacity: 0.9;
-	padding: 1ex 1em 1em;
-	position: absolute;
-	z-index: 2147483647;
-}
-
-#powerTip div.ttdoc {
-        color: grey;
-	font-style: italic;
-}
-
-#powerTip div.ttname a {
-        font-weight: bold;
-}
-
-#powerTip div.ttname {
-        font-weight: bold;
-}
-
-#powerTip div.ttdeci {
-        color: #006318;
-}
-
-#powerTip div {
-        margin: 0px;
-        padding: 0px;
-        font: 12px/16px Roboto,sans-serif;
-}
-
-#powerTip:before, #powerTip:after {
-	content: "";
-	position: absolute;
-	margin: 0px;
-}
-
-#powerTip.n:after,  #powerTip.n:before,
-#powerTip.s:after,  #powerTip.s:before,
-#powerTip.w:after,  #powerTip.w:before,
-#powerTip.e:after,  #powerTip.e:before,
-#powerTip.ne:after, #powerTip.ne:before,
-#powerTip.se:after, #powerTip.se:before,
-#powerTip.nw:after, #powerTip.nw:before,
-#powerTip.sw:after, #powerTip.sw:before {
-	border: solid transparent;
-	content: " ";
-	height: 0;
-	width: 0;
-	position: absolute;
-}
-
-#powerTip.n:after,  #powerTip.s:after,
-#powerTip.w:after,  #powerTip.e:after,
-#powerTip.nw:after, #powerTip.ne:after,
-#powerTip.sw:after, #powerTip.se:after {
-	border-color: rgba(255, 255, 255, 0);
-}
-
-#powerTip.n:before,  #powerTip.s:before,
-#powerTip.w:before,  #powerTip.e:before,
-#powerTip.nw:before, #powerTip.ne:before,
-#powerTip.sw:before, #powerTip.se:before {
-	border-color: rgba(128, 128, 128, 0);
-}
-
-#powerTip.n:after,  #powerTip.n:before,
-#powerTip.ne:after, #powerTip.ne:before,
-#powerTip.nw:after, #powerTip.nw:before {
-	top: 100%;
-}
-
-#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after {
-	border-top-color: #FFFFFF;
-	border-width: 10px;
-	margin: 0px -10px;
-}
-#powerTip.n:before {
-	border-top-color: #808080;
-	border-width: 11px;
-	margin: 0px -11px;
-}
-#powerTip.n:after, #powerTip.n:before {
-	left: 50%;
-}
-
-#powerTip.nw:after, #powerTip.nw:before {
-	right: 14px;
-}
-
-#powerTip.ne:after, #powerTip.ne:before {
-	left: 14px;
-}
-
-#powerTip.s:after,  #powerTip.s:before,
-#powerTip.se:after, #powerTip.se:before,
-#powerTip.sw:after, #powerTip.sw:before {
-	bottom: 100%;
-}
-
-#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after {
-	border-bottom-color: #FFFFFF;
-	border-width: 10px;
-	margin: 0px -10px;
-}
-
-#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before {
-	border-bottom-color: #808080;
-	border-width: 11px;
-	margin: 0px -11px;
-}
-
-#powerTip.s:after, #powerTip.s:before {
-	left: 50%;
-}
-
-#powerTip.sw:after, #powerTip.sw:before {
-	right: 14px;
-}
-
-#powerTip.se:after, #powerTip.se:before {
-	left: 14px;
-}
-
-#powerTip.e:after, #powerTip.e:before {
-	left: 100%;
-}
-#powerTip.e:after {
-	border-left-color: #FFFFFF;
-	border-width: 10px;
-	top: 50%;
-	margin-top: -10px;
-}
-#powerTip.e:before {
-	border-left-color: #808080;
-	border-width: 11px;
-	top: 50%;
-	margin-top: -11px;
-}
-
-#powerTip.w:after, #powerTip.w:before {
-	right: 100%;
-}
-#powerTip.w:after {
-	border-right-color: #FFFFFF;
-	border-width: 10px;
-	top: 50%;
-	margin-top: -10px;
-}
-#powerTip.w:before {
-	border-right-color: #808080;
-	border-width: 11px;
-	top: 50%;
-	margin-top: -11px;
-}
-
-@media print
-{
-  #top { display: none; }
-  #side-nav { display: none; }
-  #nav-path { display: none; }
-  body { overflow:visible; }
-  h1, h2, h3, h4, h5, h6 { page-break-after: avoid; }
-  .summary { display: none; }
-  .memitem { page-break-inside: avoid; }
-  #doc-content
-  {
-    margin-left:0 !important;
-    height:auto !important;
-    width:auto !important;
-    overflow:inherit;
-    display:inline;
-  }
-}
-
-/* @group Markdown */
-
-/*
-table.markdownTable {
-	border-collapse:collapse;
-        margin-top: 4px;
-        margin-bottom: 4px;
-}
-
-table.markdownTable td, table.markdownTable th {
-	border: 1px solid #2D4068;
-	padding: 3px 7px 2px;
-}
-
-table.markdownTableHead tr {
-}
-
-table.markdownTableBodyLeft td, table.markdownTable th {
-	border: 1px solid #2D4068;
-	padding: 3px 7px 2px;
-}
-
-th.markdownTableHeadLeft th.markdownTableHeadRight th.markdownTableHeadCenter th.markdownTableHeadNone {
-	background-color: #374F7F;
-	color: #FFFFFF;
-	font-size: 110%;
-	padding-bottom: 4px;
-	padding-top: 5px;
-}
-
-th.markdownTableHeadLeft {
-	text-align: left
-}
-
-th.markdownTableHeadRight {
-	text-align: right
-}
-
-th.markdownTableHeadCenter {
-	text-align: center
-}
-*/
-
-table.markdownTable {
-	border-collapse:collapse;
-        margin-top: 4px;
-        margin-bottom: 4px;
-}
-
-table.markdownTable td, table.markdownTable th {
-	border: 1px solid #2D4068;
-	padding: 3px 7px 2px;
-}
-
-table.markdownTable tr {
-}
-
-th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone {
-	background-color: #374F7F;
-	color: #FFFFFF;
-	font-size: 110%;
-	padding-bottom: 4px;
-	padding-top: 5px;
-}
-
-th.markdownTableHeadLeft, td.markdownTableBodyLeft {
-	text-align: left
-}
-
-th.markdownTableHeadRight, td.markdownTableBodyRight {
-	text-align: right
-}
-
-th.markdownTableHeadCenter, td.markdownTableBodyCenter {
-	text-align: center
-}
-
-.DocNodeRTL {
-  text-align: right;
-  direction: rtl;
-}
-
-.DocNodeLTR {
-  text-align: left;
-  direction: ltr;
-}
-
-table.DocNodeRTL {
-   width: auto;
-   margin-right: 0;
-   margin-left: auto;
-}
-
-table.DocNodeLTR {
-   width: auto;
-   margin-right: auto;
-   margin-left: 0;
-}
-
-tt, code, kbd, samp
-{
-  display: inline-block;
-  direction:ltr; 
-}
-/* @end */
-
-u {
-	text-decoration: underline;
-}
-
diff --git a/docs/reference/doxygen.png b/docs/reference/doxygen.png
deleted file mode 100644
index 3ff17d8..0000000
--- a/docs/reference/doxygen.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/dynsections.js b/docs/reference/dynsections.js
deleted file mode 100644
index ea0a7b3..0000000
--- a/docs/reference/dynsections.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- @licstart  The following is the entire license notice for the
- JavaScript code in this file.
-
- Copyright (C) 1997-2017 by Dimitri van Heesch
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
- @licend  The above is the entire license notice
- for the JavaScript code in this file
- */
-function toggleVisibility(linkObj)
-{
- var base = $(linkObj).attr('id');
- var summary = $('#'+base+'-summary');
- var content = $('#'+base+'-content');
- var trigger = $('#'+base+'-trigger');
- var src=$(trigger).attr('src');
- if (content.is(':visible')===true) {
-   content.hide();
-   summary.show();
-   $(linkObj).addClass('closed').removeClass('opened');
-   $(trigger).attr('src',src.substring(0,src.length-8)+'closed.png');
- } else {
-   content.show();
-   summary.hide();
-   $(linkObj).removeClass('closed').addClass('opened');
-   $(trigger).attr('src',src.substring(0,src.length-10)+'open.png');
- }
- return false;
-}
-
-function updateStripes()
-{
-  $('table.directory tr').
-       removeClass('even').filter(':visible:even').addClass('even');
-}
-
-function toggleLevel(level)
-{
-  $('table.directory tr').each(function() {
-    var l = this.id.split('_').length-1;
-    var i = $('#img'+this.id.substring(3));
-    var a = $('#arr'+this.id.substring(3));
-    if (l<level+1) {
-      i.removeClass('iconfopen iconfclosed').addClass('iconfopen');
-      a.html('&#9660;');
-      $(this).show();
-    } else if (l==level+1) {
-      i.removeClass('iconfclosed iconfopen').addClass('iconfclosed');
-      a.html('&#9658;');
-      $(this).show();
-    } else {
-      $(this).hide();
-    }
-  });
-  updateStripes();
-}
-
-function toggleFolder(id)
-{
-  // the clicked row
-  var currentRow = $('#row_'+id);
-
-  // all rows after the clicked row
-  var rows = currentRow.nextAll("tr");
-
-  var re = new RegExp('^row_'+id+'\\d+_$', "i"); //only one sub
-
-  // only match elements AFTER this one (can't hide elements before)
-  var childRows = rows.filter(function() { return this.id.match(re); });
-
-  // first row is visible we are HIDING
-  if (childRows.filter(':first').is(':visible')===true) {
-    // replace down arrow by right arrow for current row
-    var currentRowSpans = currentRow.find("span");
-    currentRowSpans.filter(".iconfopen").removeClass("iconfopen").addClass("iconfclosed");
-    currentRowSpans.filter(".arrow").html('&#9658;');
-    rows.filter("[id^=row_"+id+"]").hide(); // hide all children
-  } else { // we are SHOWING
-    // replace right arrow by down arrow for current row
-    var currentRowSpans = currentRow.find("span");
-    currentRowSpans.filter(".iconfclosed").removeClass("iconfclosed").addClass("iconfopen");
-    currentRowSpans.filter(".arrow").html('&#9660;');
-    // replace down arrows by right arrows for child rows
-    var childRowsSpans = childRows.find("span");
-    childRowsSpans.filter(".iconfopen").removeClass("iconfopen").addClass("iconfclosed");
-    childRowsSpans.filter(".arrow").html('&#9658;');
-    childRows.show(); //show all children
-  }
-  updateStripes();
-}
-
-
-function toggleInherit(id)
-{
-  var rows = $('tr.inherit.'+id);
-  var img = $('tr.inherit_header.'+id+' img');
-  var src = $(img).attr('src');
-  if (rows.filter(':first').is(':visible')===true) {
-    rows.css('display','none');
-    $(img).attr('src',src.substring(0,src.length-8)+'closed.png');
-  } else {
-    rows.css('display','table-row'); // using show() causes jump in firefox
-    $(img).attr('src',src.substring(0,src.length-10)+'open.png');
-  }
-}
-/* @license-end */
diff --git a/docs/reference/files.html b/docs/reference/files.html
deleted file mode 100644
index 820f043..0000000
--- a/docs/reference/files.html
+++ /dev/null
@@ -1,95 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: File List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="header">
-  <div class="headertitle">
-<div class="title">File List</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="textblock">Here is a list of all documented files with brief descriptions:</div><div class="directory">
-<div class="levels">[detail level <span onclick="javascript:toggleLevel(1);">1</span><span onclick="javascript:toggleLevel(2);">2</span><span onclick="javascript:toggleLevel(3);">3</span>]</div><table class="directory">
-<tr id="row_0_" class="even"><td class="entry"><span style="width:0px;display:inline-block;">&#160;</span><span id="arr_0_" class="arrow" onclick="toggleFolder('0_')">&#9660;</span><span id="img_0_" class="iconfopen" onclick="toggleFolder('0_')">&#160;</span><a class="el" href="dir_d44c64559bbebec7f509842c48db8b23.html" target="_self">include</a></td><td class="desc"></td></tr>
-<tr id="row_0_0_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><span id="arr_0_0_" class="arrow" onclick="toggleFolder('0_0_')">&#9660;</span><span id="img_0_0_" class="iconfopen" onclick="toggleFolder('0_0_')">&#160;</span><a class="el" href="dir_768f6301d9838e45d679001914ab2803.html" target="_self">oboe</a></td><td class="desc"></td></tr>
-<tr id="row_0_0_0_" class="even"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><a href="_audio_stream_8h_source.html"><span class="icondoc"></span></a><b>AudioStream.h</b></td><td class="desc"></td></tr>
-<tr id="row_0_0_1_"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><a href="_audio_stream_base_8h_source.html"><span class="icondoc"></span></a><b>AudioStreamBase.h</b></td><td class="desc"></td></tr>
-<tr id="row_0_0_2_" class="even"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><a href="_audio_stream_builder_8h_source.html"><span class="icondoc"></span></a><b>AudioStreamBuilder.h</b></td><td class="desc"></td></tr>
-<tr id="row_0_0_3_"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><a href="_audio_stream_callback_8h_source.html"><span class="icondoc"></span></a><b>AudioStreamCallback.h</b></td><td class="desc"></td></tr>
-<tr id="row_0_0_4_" class="even"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><a href="_definitions_8h_source.html"><span class="icondoc"></span></a><b>Definitions.h</b></td><td class="desc"></td></tr>
-<tr id="row_0_0_5_"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><a href="_latency_tuner_8h_source.html"><span class="icondoc"></span></a><b>LatencyTuner.h</b></td><td class="desc"></td></tr>
-<tr id="row_0_0_6_" class="even"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><a href="_oboe_8h_source.html"><span class="icondoc"></span></a><b>Oboe.h</b></td><td class="desc"></td></tr>
-<tr id="row_0_0_7_"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><a href="_result_with_value_8h_source.html"><span class="icondoc"></span></a><b>ResultWithValue.h</b></td><td class="desc"></td></tr>
-<tr id="row_0_0_8_" class="even"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><a href="_stabilized_callback_8h_source.html"><span class="icondoc"></span></a><b>StabilizedCallback.h</b></td><td class="desc"></td></tr>
-<tr id="row_0_0_9_"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><a href="_utilities_8h_source.html"><span class="icondoc"></span></a><b>Utilities.h</b></td><td class="desc"></td></tr>
-<tr id="row_0_0_10_" class="even"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><a href="_version_8h_source.html"><span class="icondoc"></span></a><b>Version.h</b></td><td class="desc"></td></tr>
-</table>
-</div><!-- directory -->
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/folderclosed.png b/docs/reference/folderclosed.png
deleted file mode 100644
index bb8ab35..0000000
--- a/docs/reference/folderclosed.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/folderopen.png b/docs/reference/folderopen.png
deleted file mode 100644
index d6c7f67..0000000
--- a/docs/reference/folderopen.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/functions.html b/docs/reference/functions.html
deleted file mode 100644
index 2debcc1..0000000
--- a/docs/reference/functions.html
+++ /dev/null
@@ -1,554 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Class Members</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="contents">
-<div class="textblock">Here is a list of all documented class members with links to the class documentation for each member:</div>
-
-<h3><a id="index_a"></a>- a -</h3><ul>
-<li>AudioStream()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a8ebb587a07bf62c864fd62c63b241fd4">oboe::AudioStream</a>
-</li>
-<li>AudioStreamBase()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#aa6b103e1b0f808bbc4949d56f0829f98">oboe::AudioStreamBase</a>
-</li>
-</ul>
-
-
-<h3><a id="index_c"></a>- c -</h3><ul>
-<li>calculateLatencyMillis()
-: <a class="el" href="classoboe_1_1_audio_stream.html#ae023cb001f3261d064f423101798d6be">oboe::AudioStream</a>
-</li>
-<li>ChannelCount
-: <a class="el" href="classoboe_1_1_default_stream_values.html#ad5dce538d5963c81bf58350ab730962d">oboe::DefaultStreamValues</a>
-</li>
-<li>close()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a9c8ea30e30e513766d5e996c370eb8d8">oboe::AudioStream</a>
-</li>
-<li>createBasedOnSign()
-: <a class="el" href="classoboe_1_1_result_with_value.html#a2304c6120e2aad8f2189383a98c7b0a7">oboe::ResultWithValue&lt; T &gt;</a>
-</li>
-</ul>
-
-
-<h3><a id="index_e"></a>- e -</h3><ul>
-<li>error()
-: <a class="el" href="classoboe_1_1_result_with_value.html#adfc76ae6db81535c2e82b856975eed41">oboe::ResultWithValue&lt; T &gt;</a>
-</li>
-</ul>
-
-
-<h3><a id="index_f"></a>- f -</h3><ul>
-<li>fireDataCallback()
-: <a class="el" href="classoboe_1_1_audio_stream.html#ab7a8cfe5d6039386bc5850fd5ee9bd62">oboe::AudioStream</a>
-</li>
-<li>flush()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a32c25c0333eab3d65ce02275ad4acb3d">oboe::AudioStream</a>
-</li>
-<li>FramesPerBurst
-: <a class="el" href="classoboe_1_1_default_stream_values.html#ab5ea5576699cebc56193f5c297d3e300">oboe::DefaultStreamValues</a>
-</li>
-</ul>
-
-
-<h3><a id="index_g"></a>- g -</h3><ul>
-<li>getAudioApi()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a2b7a3cee7444114843dbdd1fc705f6bb">oboe::AudioStream</a>
-, <a class="el" href="classoboe_1_1_audio_stream_builder.html#ac9d41811c297fd28bc61833f640bb8d0">oboe::AudioStreamBuilder</a>
-</li>
-<li>getAvailableFrames()
-: <a class="el" href="classoboe_1_1_audio_stream.html#afa35ee4b8629fbffe26b9be7c7ed55d2">oboe::AudioStream</a>
-</li>
-<li>getBufferCapacityInFrames()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ab1531253e64aaebe9e9eddbafb9098fc">oboe::AudioStreamBase</a>
-</li>
-<li>getBufferSizeInFrames()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#af5217ab05bfde0d7637024b599302d0b">oboe::AudioStreamBase</a>
-</li>
-<li>getBytesPerFrame()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a5c01907a59d5f89a5e4b819fe66b08bc">oboe::AudioStream</a>
-</li>
-<li>getBytesPerSample()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a44dda61e6e948e49b68f87172f084d62">oboe::AudioStream</a>
-</li>
-<li>getChannelCount()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a87e6bf37d6a2a5e983b8ca8d29aea575">oboe::AudioStreamBase</a>
-</li>
-<li>getContentType()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ab12e2d068fa87e0553b01a400d96eb82">oboe::AudioStreamBase</a>
-</li>
-<li>getDataCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a9fb2f34ae62dbda2c10e8513b754fa0c">oboe::AudioStreamBase</a>
-</li>
-<li>getDeviceId()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a093057d625bc896864b959974c265f21">oboe::AudioStreamBase</a>
-</li>
-<li>getDirection()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a6f86f2233a04c5a0b056f0c1c261f1b1">oboe::AudioStreamBase</a>
-</li>
-<li>getErrorCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a1328fb9288166ff325995ce1ea1867f0">oboe::AudioStreamBase</a>
-</li>
-<li>getFormat()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ab1e640461d7bf9d596decb913da7ac86">oboe::AudioStreamBase</a>
-</li>
-<li>getFramesPerBurst()
-: <a class="el" href="classoboe_1_1_audio_stream.html#ac160acb656515814fa6fdd157c131a0a">oboe::AudioStream</a>
-</li>
-<li>getFramesPerCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a8878a90949badbb5486cc2e022a57086">oboe::AudioStreamBase</a>
-</li>
-<li>getFramesPerDataCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#abc3ee2815568b425d15a40e132aa8e38">oboe::AudioStreamBase</a>
-</li>
-<li>getFramesRead()
-: <a class="el" href="classoboe_1_1_audio_stream.html#aeebfc59abd978cd6dff07c16cfe266df">oboe::AudioStream</a>
-</li>
-<li>getFramesWritten()
-: <a class="el" href="classoboe_1_1_audio_stream.html#ab43dd4074e1de57bac1c3fd111430341">oboe::AudioStream</a>
-</li>
-<li>getInputPreset()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a5c773b93b8aa38191c7199cab023428a">oboe::AudioStreamBase</a>
-</li>
-<li>getLastErrorCallbackResult()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a8fe8afdf164a1fe835c514f709743d75">oboe::AudioStream</a>
-</li>
-<li>getPerformanceMode()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a2ddb935de0e24dd7ae8e2cfbecac9fdc">oboe::AudioStreamBase</a>
-</li>
-<li>getSampleRate()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ae9d32f3e09174bad69e74f147ee33087">oboe::AudioStreamBase</a>
-</li>
-<li>getSampleRateConversionQuality()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a1de8d6982d411a0cf50a32efba0ca3f2">oboe::AudioStreamBase</a>
-</li>
-<li>getSessionId()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#aa3c502ce09bbad7690a2dd6acaf8892e">oboe::AudioStreamBase</a>
-</li>
-<li>getSharingMode()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a1fb033fc963f971bd1aa8f6707e49b41">oboe::AudioStreamBase</a>
-</li>
-<li>getState()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a9d37cc6513823c685ae892626ff83ea8">oboe::AudioStream</a>
-</li>
-<li>getTimestamp()
-: <a class="el" href="classoboe_1_1_audio_stream.html#acb8edbc17ff79993a8ed996d216fe6f3">oboe::AudioStream</a>
-</li>
-<li>getUnderlyingStream()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a5458d7130415eb4defe3dbc11d479e2f">oboe::AudioStream</a>
-</li>
-<li>getUsage()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a0bcfb2f8bd11c92b541fd910da9af397">oboe::AudioStreamBase</a>
-</li>
-<li>getXRunCount()
-: <a class="el" href="classoboe_1_1_audio_stream.html#ad1a1d3bbf3b348ed92b7ed18ce9cc261">oboe::AudioStream</a>
-</li>
-</ul>
-
-
-<h3><a id="index_i"></a>- i -</h3><ul>
-<li>isAAudioRecommended()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a622732bbe5c6577356d749f7dc2108df">oboe::AudioStreamBuilder</a>
-</li>
-<li>isAAudioSupported()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a18e7b5f7554a4c2ca763e35e8117d699">oboe::AudioStreamBuilder</a>
-</li>
-<li>isAtMaximumBufferSize()
-: <a class="el" href="classoboe_1_1_latency_tuner.html#a45c013fd6787ad09d328385d6314c4d4">oboe::LatencyTuner</a>
-</li>
-<li>isChannelConversionAllowed()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#aa4ec3aa76e69350fbce6f00786211495">oboe::AudioStreamBase</a>
-</li>
-<li>isDataCallbackEnabled()
-: <a class="el" href="classoboe_1_1_audio_stream.html#add85011ba825f74931deeb92c5edf831">oboe::AudioStream</a>
-</li>
-<li>isDataCallbackSpecified()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a9a54d38b985a2eb12c6972104dc0ce73">oboe::AudioStreamBase</a>
-</li>
-<li>isErrorCallbackSpecified()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#aef579f6d1f779c89d051f0963f2976b3">oboe::AudioStreamBase</a>
-</li>
-<li>isFormatConversionAllowed()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ace3625a7332bf02a86818fdf63fcccb4">oboe::AudioStreamBase</a>
-</li>
-<li>isValidConfig()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a5d5e07e98921d0193a5c0ccbe06f68c2">oboe::AudioStreamBase</a>
-</li>
-<li>isXRunCountSupported()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a43d8a098440cde28f4ee8bedd6d107c4">oboe::AudioStream</a>
-</li>
-</ul>
-
-
-<h3><a id="index_l"></a>- l -</h3><ul>
-<li>LatencyTuner()
-: <a class="el" href="classoboe_1_1_latency_tuner.html#a0263b9a55825c0a403653b2b508073ea">oboe::LatencyTuner</a>
-</li>
-<li>launchStopThread()
-: <a class="el" href="classoboe_1_1_audio_stream.html#aa5f4801cca6877eeaa4735b93933269d">oboe::AudioStream</a>
-</li>
-</ul>
-
-
-<h3><a id="index_m"></a>- m -</h3><ul>
-<li>Major
-: <a class="el" href="structoboe_1_1_version.html#a270f2e92582d5187be339eeda8e2b276">oboe::Version</a>
-</li>
-<li>mBufferCapacityInFrames
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6">oboe::AudioStreamBase</a>
-</li>
-<li>mBufferSizeInFrames
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a3b65595d26d1eae1b8ce9925a5b98f6a">oboe::AudioStreamBase</a>
-</li>
-<li>mChannelCount
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">oboe::AudioStreamBase</a>
-</li>
-<li>mContentType
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b">oboe::AudioStreamBase</a>
-</li>
-<li>mDataCallback
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">oboe::AudioStreamBase</a>
-</li>
-<li>mDeviceId
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8">oboe::AudioStreamBase</a>
-</li>
-<li>mDirection
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880">oboe::AudioStreamBase</a>
-</li>
-<li>mErrorCallback
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">oboe::AudioStreamBase</a>
-</li>
-<li>mFormat
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">oboe::AudioStreamBase</a>
-</li>
-<li>mFramesPerBurst
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a54061319ed348329a29d883a5de2482e">oboe::AudioStreamBase</a>
-</li>
-<li>mFramesPerCallback
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899">oboe::AudioStreamBase</a>
-</li>
-<li>mFramesRead
-: <a class="el" href="classoboe_1_1_audio_stream.html#a07e82f9b9e2e4800f23ae9a7193c3b58">oboe::AudioStream</a>
-</li>
-<li>mFramesWritten
-: <a class="el" href="classoboe_1_1_audio_stream.html#a88a63317b7c58815bac074976b00aa23">oboe::AudioStream</a>
-</li>
-<li>Minor
-: <a class="el" href="structoboe_1_1_version.html#ae460bb95e3a9099696205a35fffb5469">oboe::Version</a>
-</li>
-<li>mInputPreset
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589">oboe::AudioStreamBase</a>
-</li>
-<li>mPerformanceMode
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765">oboe::AudioStreamBase</a>
-</li>
-<li>mSampleRate
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea">oboe::AudioStreamBase</a>
-</li>
-<li>mSessionId
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737">oboe::AudioStreamBase</a>
-</li>
-<li>mSharingMode
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473">oboe::AudioStreamBase</a>
-</li>
-<li>mUsage
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c">oboe::AudioStreamBase</a>
-</li>
-</ul>
-
-
-<h3><a id="index_n"></a>- n -</h3><ul>
-<li>Number
-: <a class="el" href="structoboe_1_1_version.html#ac579661e79bcee45dc676d4647891de0">oboe::Version</a>
-</li>
-</ul>
-
-
-<h3><a id="index_o"></a>- o -</h3><ul>
-<li>onAudioReady()
-: <a class="el" href="classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d">oboe::AudioStreamDataCallback</a>
-, <a class="el" href="classoboe_1_1_stabilized_callback.html#ad447e12ebf732cf151655c1fbaf58a49">oboe::StabilizedCallback</a>
-</li>
-<li>onDefaultCallback()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a0ea79e60f5a3d29fc5a1a116aba11dfe">oboe::AudioStream</a>
-</li>
-<li>onError()
-: <a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">oboe::AudioStreamErrorCallback</a>
-</li>
-<li>onErrorAfterClose()
-: <a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe">oboe::AudioStreamErrorCallback</a>
-, <a class="el" href="classoboe_1_1_stabilized_callback.html#af7521da42c4b08a71e6102994f6f41f4">oboe::StabilizedCallback</a>
-</li>
-<li>onErrorBeforeClose()
-: <a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0">oboe::AudioStreamErrorCallback</a>
-, <a class="el" href="classoboe_1_1_stabilized_callback.html#a7ec0e9fca3181962ab78716bcda83e10">oboe::StabilizedCallback</a>
-</li>
-<li>open()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a686c6ce8a29051c858fd1de386805dc6">oboe::AudioStream</a>
-</li>
-<li>openManagedStream()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a7ab172a9be4fca2489aa5cbcc48c20ff">oboe::AudioStreamBuilder</a>
-</li>
-<li>openStream()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a86b94cfa47729bef2e04dce1a9086074">oboe::AudioStreamBuilder</a>
-</li>
-<li>operator !()
-: <a class="el" href="classoboe_1_1_result_with_value.html#a6fb3c61c5716a045ba48dc5a5dfc8169">oboe::ResultWithValue&lt; T &gt;</a>
-</li>
-<li>operator bool()
-: <a class="el" href="classoboe_1_1_result_with_value.html#ae32b1953b777af7d1d0c94862ca39986">oboe::ResultWithValue&lt; T &gt;</a>
-</li>
-<li>operator Result()
-: <a class="el" href="classoboe_1_1_result_with_value.html#af62107817c0bc76047e6b655a78504ba">oboe::ResultWithValue&lt; T &gt;</a>
-</li>
-<li>operator=()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#aa9c987a59555d7a60b9f7a63f4afc7fc">oboe::AudioStreamBase</a>
-</li>
-</ul>
-
-
-<h3><a id="index_p"></a>- p -</h3><ul>
-<li>Patch
-: <a class="el" href="structoboe_1_1_version.html#a690110f2b3e887892da8f29ab5c057b2">oboe::Version</a>
-</li>
-<li>pause()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a04f29836748a8e5842aef2be200022ad">oboe::AudioStream</a>
-</li>
-</ul>
-
-
-<h3><a id="index_r"></a>- r -</h3><ul>
-<li>read()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a8089f0a0cb68d4039cf33e6584129978">oboe::AudioStream</a>
-</li>
-<li>requestFlush()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a6bd5d633ff999e4da1faf3cd949aa602">oboe::AudioStream</a>
-</li>
-<li>requestPause()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a7f18bb3cc5490fd7fbc1f6da63c730f6">oboe::AudioStream</a>
-</li>
-<li>requestReset()
-: <a class="el" href="classoboe_1_1_latency_tuner.html#a6c0142e08dc65eda8f758b4794450867">oboe::LatencyTuner</a>
-</li>
-<li>requestStart()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a3c484e314dee8dfed1d419f487b5d601">oboe::AudioStream</a>
-</li>
-<li>requestStop()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a820e634f741e6b5efdcef8104cecb919">oboe::AudioStream</a>
-</li>
-<li>ResultWithValue()
-: <a class="el" href="classoboe_1_1_result_with_value.html#a600309367db58d71f0ec16e90f7ebea5">oboe::ResultWithValue&lt; T &gt;</a>
-</li>
-</ul>
-
-
-<h3><a id="index_s"></a>- s -</h3><ul>
-<li>SampleRate
-: <a class="el" href="classoboe_1_1_default_stream_values.html#a46a5d9a653f2153f618cadcab764e1b1">oboe::DefaultStreamValues</a>
-</li>
-<li>setAudioApi()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a38c6d6c5e718df1e3ac69daaac47c391">oboe::AudioStreamBuilder</a>
-</li>
-<li>setBufferCapacityInFrames()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#abaff480867af51ca0899bfa6fd7cc3ef">oboe::AudioStreamBuilder</a>
-</li>
-<li>setBufferSizeIncrement()
-: <a class="el" href="classoboe_1_1_latency_tuner.html#a2684b30205126c8acd2f75d01cce05db">oboe::LatencyTuner</a>
-</li>
-<li>setBufferSizeInFrames()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a06e3f9e133b3a75515e7793939d1cd03">oboe::AudioStream</a>
-</li>
-<li>setCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a698cefa9af73bc97c020c004821fccbd">oboe::AudioStreamBuilder</a>
-</li>
-<li>setChannelConversionAllowed()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#ad50f5d20cdf420d982bf499790cd3563">oboe::AudioStreamBuilder</a>
-</li>
-<li>setChannelCount()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a075d10291e1f998d90c2f73ef767b5a7">oboe::AudioStreamBuilder</a>
-</li>
-<li>setContentType()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a6a17bafc217c2b624179fbbf77fe4468">oboe::AudioStreamBuilder</a>
-</li>
-<li>setDataCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#acad307720e0f370267b4e2f9a626ae70">oboe::AudioStreamBuilder</a>
-</li>
-<li>setDataCallbackEnabled()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a0faa6d3a6fd4f367e6f80d5a29e6dcba">oboe::AudioStream</a>
-</li>
-<li>setDeviceId()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#af36ddcd00686a9e1de661bdac0685a8e">oboe::AudioStreamBuilder</a>
-</li>
-<li>setDirection()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#ab3fbd47b06197619c26393637e26354c">oboe::AudioStreamBuilder</a>
-</li>
-<li>setErrorCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#aacb66f530bfc6f545911b5e169774567">oboe::AudioStreamBuilder</a>
-</li>
-<li>setFormat()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#aa2e1d2d73cd6c2eb9f349bf2fe5f6515">oboe::AudioStreamBuilder</a>
-</li>
-<li>setFormatConversionAllowed()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a7ec5f427cd6fe55cb1ce536ff0cbb4d2">oboe::AudioStreamBuilder</a>
-</li>
-<li>setFramesPerCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a3f397821f61eabaeedaf31064c859a54">oboe::AudioStreamBuilder</a>
-</li>
-<li>setFramesPerDataCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#afb8e95e80df7edd1af27af490438785e">oboe::AudioStreamBuilder</a>
-</li>
-<li>setInputPreset()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a144a3d095fd668210282f1a91f23e1f0">oboe::AudioStreamBuilder</a>
-</li>
-<li>setMinimumBufferSize()
-: <a class="el" href="classoboe_1_1_latency_tuner.html#adc96aa53b18a051b6ccdacb838139bf8">oboe::LatencyTuner</a>
-</li>
-<li>setPerformanceMode()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a6cd1d65612e844e59da71a68ea0ab3ee">oboe::AudioStreamBuilder</a>
-</li>
-<li>setSampleRate()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a30ef3d5f51d56a9f980dc09600ed139d">oboe::AudioStreamBuilder</a>
-</li>
-<li>setSampleRateConversionQuality()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#af7d24a9ec975d430732151e5ee0d1027">oboe::AudioStreamBuilder</a>
-</li>
-<li>setSessionId()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a54c1651bdbe089d0d714af499e8a5f1d">oboe::AudioStreamBuilder</a>
-</li>
-<li>setSharingMode()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a3e991742acbbfb6fe5ebcf592c478654">oboe::AudioStreamBuilder</a>
-</li>
-<li>setUsage()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a593255a2f5eb972665775cfc5bc58f6a">oboe::AudioStreamBuilder</a>
-</li>
-<li>setWorkaroundsEnabled()
-: <a class="el" href="classoboe_1_1_oboe_globals.html#af2b8af764c5a5e6fc007b7725117303b">oboe::OboeGlobals</a>
-</li>
-<li>start()
-: <a class="el" href="classoboe_1_1_audio_stream.html#af04f03eb6b64b564f1c4401688987d21">oboe::AudioStream</a>
-</li>
-<li>stop()
-: <a class="el" href="classoboe_1_1_audio_stream.html#aec093859d42f0470c884edd1e976d9f3">oboe::AudioStream</a>
-</li>
-</ul>
-
-
-<h3><a id="index_t"></a>- t -</h3><ul>
-<li>Text
-: <a class="el" href="structoboe_1_1_version.html#a2c86e578b827fbca5f40c460a7754503">oboe::Version</a>
-</li>
-<li>tune()
-: <a class="el" href="classoboe_1_1_latency_tuner.html#ad2be756965e6a9af3114008eda892174">oboe::LatencyTuner</a>
-</li>
-</ul>
-
-
-<h3><a id="index_u"></a>- u -</h3><ul>
-<li>updateFramesRead()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a462358ddab709c79d1a7968d6d55b727">oboe::AudioStream</a>
-</li>
-<li>updateFramesWritten()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a64ad978c5f70ced17ef5a96605496515">oboe::AudioStream</a>
-</li>
-<li>usesAAudio()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a15cdaaaa4c1e8da322d6da33334c8147">oboe::AudioStream</a>
-</li>
-</ul>
-
-
-<h3><a id="index_v"></a>- v -</h3><ul>
-<li>value()
-: <a class="el" href="classoboe_1_1_result_with_value.html#a45f5c99a2c9f8fbaca502276f7ebb434">oboe::ResultWithValue&lt; T &gt;</a>
-</li>
-</ul>
-
-
-<h3><a id="index_w"></a>- w -</h3><ul>
-<li>waitForAvailableFrames()
-: <a class="el" href="classoboe_1_1_audio_stream.html#afddb0962863ccf9ec6672a042fe15941">oboe::AudioStream</a>
-</li>
-<li>waitForStateChange()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a0c865a5501f369d959c39d8ab8b46a07">oboe::AudioStream</a>
-</li>
-<li>waitForStateTransition()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a8adbacd6a55a94a532916ab037fba1d6">oboe::AudioStream</a>
-</li>
-<li>wasErrorCallbackCalled()
-: <a class="el" href="classoboe_1_1_audio_stream.html#aa48da7bf28026b7cccee73e6b054af28">oboe::AudioStream</a>
-</li>
-<li>willUseAAudio()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#aa07ea100fcb107d9f7913f206c2214f4">oboe::AudioStreamBuilder</a>
-</li>
-<li>write()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a3612c05ed6b01a213dde67d913c07e11">oboe::AudioStream</a>
-</li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/functions_func.html b/docs/reference/functions_func.html
deleted file mode 100644
index 06fd3c1..0000000
--- a/docs/reference/functions_func.html
+++ /dev/null
@@ -1,465 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Class Members - Functions</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="contents">
-&#160;
-
-<h3><a id="index_a"></a>- a -</h3><ul>
-<li>AudioStream()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a8ebb587a07bf62c864fd62c63b241fd4">oboe::AudioStream</a>
-</li>
-<li>AudioStreamBase()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#aa6b103e1b0f808bbc4949d56f0829f98">oboe::AudioStreamBase</a>
-</li>
-</ul>
-
-
-<h3><a id="index_c"></a>- c -</h3><ul>
-<li>calculateLatencyMillis()
-: <a class="el" href="classoboe_1_1_audio_stream.html#ae023cb001f3261d064f423101798d6be">oboe::AudioStream</a>
-</li>
-<li>close()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a9c8ea30e30e513766d5e996c370eb8d8">oboe::AudioStream</a>
-</li>
-<li>createBasedOnSign()
-: <a class="el" href="classoboe_1_1_result_with_value.html#a2304c6120e2aad8f2189383a98c7b0a7">oboe::ResultWithValue&lt; T &gt;</a>
-</li>
-</ul>
-
-
-<h3><a id="index_e"></a>- e -</h3><ul>
-<li>error()
-: <a class="el" href="classoboe_1_1_result_with_value.html#adfc76ae6db81535c2e82b856975eed41">oboe::ResultWithValue&lt; T &gt;</a>
-</li>
-</ul>
-
-
-<h3><a id="index_f"></a>- f -</h3><ul>
-<li>fireDataCallback()
-: <a class="el" href="classoboe_1_1_audio_stream.html#ab7a8cfe5d6039386bc5850fd5ee9bd62">oboe::AudioStream</a>
-</li>
-<li>flush()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a32c25c0333eab3d65ce02275ad4acb3d">oboe::AudioStream</a>
-</li>
-</ul>
-
-
-<h3><a id="index_g"></a>- g -</h3><ul>
-<li>getAudioApi()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a2b7a3cee7444114843dbdd1fc705f6bb">oboe::AudioStream</a>
-, <a class="el" href="classoboe_1_1_audio_stream_builder.html#ac9d41811c297fd28bc61833f640bb8d0">oboe::AudioStreamBuilder</a>
-</li>
-<li>getAvailableFrames()
-: <a class="el" href="classoboe_1_1_audio_stream.html#afa35ee4b8629fbffe26b9be7c7ed55d2">oboe::AudioStream</a>
-</li>
-<li>getBufferCapacityInFrames()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ab1531253e64aaebe9e9eddbafb9098fc">oboe::AudioStreamBase</a>
-</li>
-<li>getBufferSizeInFrames()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#af5217ab05bfde0d7637024b599302d0b">oboe::AudioStreamBase</a>
-</li>
-<li>getBytesPerFrame()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a5c01907a59d5f89a5e4b819fe66b08bc">oboe::AudioStream</a>
-</li>
-<li>getBytesPerSample()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a44dda61e6e948e49b68f87172f084d62">oboe::AudioStream</a>
-</li>
-<li>getChannelCount()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a87e6bf37d6a2a5e983b8ca8d29aea575">oboe::AudioStreamBase</a>
-</li>
-<li>getContentType()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ab12e2d068fa87e0553b01a400d96eb82">oboe::AudioStreamBase</a>
-</li>
-<li>getDataCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a9fb2f34ae62dbda2c10e8513b754fa0c">oboe::AudioStreamBase</a>
-</li>
-<li>getDeviceId()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a093057d625bc896864b959974c265f21">oboe::AudioStreamBase</a>
-</li>
-<li>getDirection()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a6f86f2233a04c5a0b056f0c1c261f1b1">oboe::AudioStreamBase</a>
-</li>
-<li>getErrorCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a1328fb9288166ff325995ce1ea1867f0">oboe::AudioStreamBase</a>
-</li>
-<li>getFormat()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ab1e640461d7bf9d596decb913da7ac86">oboe::AudioStreamBase</a>
-</li>
-<li>getFramesPerBurst()
-: <a class="el" href="classoboe_1_1_audio_stream.html#ac160acb656515814fa6fdd157c131a0a">oboe::AudioStream</a>
-</li>
-<li>getFramesPerCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a8878a90949badbb5486cc2e022a57086">oboe::AudioStreamBase</a>
-</li>
-<li>getFramesPerDataCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#abc3ee2815568b425d15a40e132aa8e38">oboe::AudioStreamBase</a>
-</li>
-<li>getFramesRead()
-: <a class="el" href="classoboe_1_1_audio_stream.html#aeebfc59abd978cd6dff07c16cfe266df">oboe::AudioStream</a>
-</li>
-<li>getFramesWritten()
-: <a class="el" href="classoboe_1_1_audio_stream.html#ab43dd4074e1de57bac1c3fd111430341">oboe::AudioStream</a>
-</li>
-<li>getInputPreset()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a5c773b93b8aa38191c7199cab023428a">oboe::AudioStreamBase</a>
-</li>
-<li>getLastErrorCallbackResult()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a8fe8afdf164a1fe835c514f709743d75">oboe::AudioStream</a>
-</li>
-<li>getPerformanceMode()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a2ddb935de0e24dd7ae8e2cfbecac9fdc">oboe::AudioStreamBase</a>
-</li>
-<li>getSampleRate()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ae9d32f3e09174bad69e74f147ee33087">oboe::AudioStreamBase</a>
-</li>
-<li>getSampleRateConversionQuality()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a1de8d6982d411a0cf50a32efba0ca3f2">oboe::AudioStreamBase</a>
-</li>
-<li>getSessionId()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#aa3c502ce09bbad7690a2dd6acaf8892e">oboe::AudioStreamBase</a>
-</li>
-<li>getSharingMode()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a1fb033fc963f971bd1aa8f6707e49b41">oboe::AudioStreamBase</a>
-</li>
-<li>getState()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a9d37cc6513823c685ae892626ff83ea8">oboe::AudioStream</a>
-</li>
-<li>getTimestamp()
-: <a class="el" href="classoboe_1_1_audio_stream.html#acb8edbc17ff79993a8ed996d216fe6f3">oboe::AudioStream</a>
-</li>
-<li>getUnderlyingStream()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a5458d7130415eb4defe3dbc11d479e2f">oboe::AudioStream</a>
-</li>
-<li>getUsage()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a0bcfb2f8bd11c92b541fd910da9af397">oboe::AudioStreamBase</a>
-</li>
-<li>getXRunCount()
-: <a class="el" href="classoboe_1_1_audio_stream.html#ad1a1d3bbf3b348ed92b7ed18ce9cc261">oboe::AudioStream</a>
-</li>
-</ul>
-
-
-<h3><a id="index_i"></a>- i -</h3><ul>
-<li>isAAudioRecommended()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a622732bbe5c6577356d749f7dc2108df">oboe::AudioStreamBuilder</a>
-</li>
-<li>isAAudioSupported()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a18e7b5f7554a4c2ca763e35e8117d699">oboe::AudioStreamBuilder</a>
-</li>
-<li>isAtMaximumBufferSize()
-: <a class="el" href="classoboe_1_1_latency_tuner.html#a45c013fd6787ad09d328385d6314c4d4">oboe::LatencyTuner</a>
-</li>
-<li>isChannelConversionAllowed()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#aa4ec3aa76e69350fbce6f00786211495">oboe::AudioStreamBase</a>
-</li>
-<li>isDataCallbackEnabled()
-: <a class="el" href="classoboe_1_1_audio_stream.html#add85011ba825f74931deeb92c5edf831">oboe::AudioStream</a>
-</li>
-<li>isDataCallbackSpecified()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a9a54d38b985a2eb12c6972104dc0ce73">oboe::AudioStreamBase</a>
-</li>
-<li>isErrorCallbackSpecified()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#aef579f6d1f779c89d051f0963f2976b3">oboe::AudioStreamBase</a>
-</li>
-<li>isFormatConversionAllowed()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ace3625a7332bf02a86818fdf63fcccb4">oboe::AudioStreamBase</a>
-</li>
-<li>isValidConfig()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a5d5e07e98921d0193a5c0ccbe06f68c2">oboe::AudioStreamBase</a>
-</li>
-<li>isXRunCountSupported()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a43d8a098440cde28f4ee8bedd6d107c4">oboe::AudioStream</a>
-</li>
-</ul>
-
-
-<h3><a id="index_l"></a>- l -</h3><ul>
-<li>LatencyTuner()
-: <a class="el" href="classoboe_1_1_latency_tuner.html#a0263b9a55825c0a403653b2b508073ea">oboe::LatencyTuner</a>
-</li>
-<li>launchStopThread()
-: <a class="el" href="classoboe_1_1_audio_stream.html#aa5f4801cca6877eeaa4735b93933269d">oboe::AudioStream</a>
-</li>
-</ul>
-
-
-<h3><a id="index_o"></a>- o -</h3><ul>
-<li>onAudioReady()
-: <a class="el" href="classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d">oboe::AudioStreamDataCallback</a>
-, <a class="el" href="classoboe_1_1_stabilized_callback.html#ad447e12ebf732cf151655c1fbaf58a49">oboe::StabilizedCallback</a>
-</li>
-<li>onDefaultCallback()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a0ea79e60f5a3d29fc5a1a116aba11dfe">oboe::AudioStream</a>
-</li>
-<li>onError()
-: <a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3">oboe::AudioStreamErrorCallback</a>
-</li>
-<li>onErrorAfterClose()
-: <a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe">oboe::AudioStreamErrorCallback</a>
-, <a class="el" href="classoboe_1_1_stabilized_callback.html#af7521da42c4b08a71e6102994f6f41f4">oboe::StabilizedCallback</a>
-</li>
-<li>onErrorBeforeClose()
-: <a class="el" href="classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0">oboe::AudioStreamErrorCallback</a>
-, <a class="el" href="classoboe_1_1_stabilized_callback.html#a7ec0e9fca3181962ab78716bcda83e10">oboe::StabilizedCallback</a>
-</li>
-<li>open()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a686c6ce8a29051c858fd1de386805dc6">oboe::AudioStream</a>
-</li>
-<li>openManagedStream()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a7ab172a9be4fca2489aa5cbcc48c20ff">oboe::AudioStreamBuilder</a>
-</li>
-<li>openStream()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a86b94cfa47729bef2e04dce1a9086074">oboe::AudioStreamBuilder</a>
-</li>
-<li>operator !()
-: <a class="el" href="classoboe_1_1_result_with_value.html#a6fb3c61c5716a045ba48dc5a5dfc8169">oboe::ResultWithValue&lt; T &gt;</a>
-</li>
-<li>operator bool()
-: <a class="el" href="classoboe_1_1_result_with_value.html#ae32b1953b777af7d1d0c94862ca39986">oboe::ResultWithValue&lt; T &gt;</a>
-</li>
-<li>operator Result()
-: <a class="el" href="classoboe_1_1_result_with_value.html#af62107817c0bc76047e6b655a78504ba">oboe::ResultWithValue&lt; T &gt;</a>
-</li>
-<li>operator=()
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#aa9c987a59555d7a60b9f7a63f4afc7fc">oboe::AudioStreamBase</a>
-</li>
-</ul>
-
-
-<h3><a id="index_p"></a>- p -</h3><ul>
-<li>pause()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a04f29836748a8e5842aef2be200022ad">oboe::AudioStream</a>
-</li>
-</ul>
-
-
-<h3><a id="index_r"></a>- r -</h3><ul>
-<li>read()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a8089f0a0cb68d4039cf33e6584129978">oboe::AudioStream</a>
-</li>
-<li>requestFlush()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a6bd5d633ff999e4da1faf3cd949aa602">oboe::AudioStream</a>
-</li>
-<li>requestPause()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a7f18bb3cc5490fd7fbc1f6da63c730f6">oboe::AudioStream</a>
-</li>
-<li>requestReset()
-: <a class="el" href="classoboe_1_1_latency_tuner.html#a6c0142e08dc65eda8f758b4794450867">oboe::LatencyTuner</a>
-</li>
-<li>requestStart()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a3c484e314dee8dfed1d419f487b5d601">oboe::AudioStream</a>
-</li>
-<li>requestStop()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a820e634f741e6b5efdcef8104cecb919">oboe::AudioStream</a>
-</li>
-<li>ResultWithValue()
-: <a class="el" href="classoboe_1_1_result_with_value.html#a600309367db58d71f0ec16e90f7ebea5">oboe::ResultWithValue&lt; T &gt;</a>
-</li>
-</ul>
-
-
-<h3><a id="index_s"></a>- s -</h3><ul>
-<li>setAudioApi()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a38c6d6c5e718df1e3ac69daaac47c391">oboe::AudioStreamBuilder</a>
-</li>
-<li>setBufferCapacityInFrames()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#abaff480867af51ca0899bfa6fd7cc3ef">oboe::AudioStreamBuilder</a>
-</li>
-<li>setBufferSizeIncrement()
-: <a class="el" href="classoboe_1_1_latency_tuner.html#a2684b30205126c8acd2f75d01cce05db">oboe::LatencyTuner</a>
-</li>
-<li>setBufferSizeInFrames()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a06e3f9e133b3a75515e7793939d1cd03">oboe::AudioStream</a>
-</li>
-<li>setCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a698cefa9af73bc97c020c004821fccbd">oboe::AudioStreamBuilder</a>
-</li>
-<li>setChannelConversionAllowed()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#ad50f5d20cdf420d982bf499790cd3563">oboe::AudioStreamBuilder</a>
-</li>
-<li>setChannelCount()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a075d10291e1f998d90c2f73ef767b5a7">oboe::AudioStreamBuilder</a>
-</li>
-<li>setContentType()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a6a17bafc217c2b624179fbbf77fe4468">oboe::AudioStreamBuilder</a>
-</li>
-<li>setDataCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#acad307720e0f370267b4e2f9a626ae70">oboe::AudioStreamBuilder</a>
-</li>
-<li>setDataCallbackEnabled()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a0faa6d3a6fd4f367e6f80d5a29e6dcba">oboe::AudioStream</a>
-</li>
-<li>setDeviceId()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#af36ddcd00686a9e1de661bdac0685a8e">oboe::AudioStreamBuilder</a>
-</li>
-<li>setDirection()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#ab3fbd47b06197619c26393637e26354c">oboe::AudioStreamBuilder</a>
-</li>
-<li>setErrorCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#aacb66f530bfc6f545911b5e169774567">oboe::AudioStreamBuilder</a>
-</li>
-<li>setFormat()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#aa2e1d2d73cd6c2eb9f349bf2fe5f6515">oboe::AudioStreamBuilder</a>
-</li>
-<li>setFormatConversionAllowed()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a7ec5f427cd6fe55cb1ce536ff0cbb4d2">oboe::AudioStreamBuilder</a>
-</li>
-<li>setFramesPerCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a3f397821f61eabaeedaf31064c859a54">oboe::AudioStreamBuilder</a>
-</li>
-<li>setFramesPerDataCallback()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#afb8e95e80df7edd1af27af490438785e">oboe::AudioStreamBuilder</a>
-</li>
-<li>setInputPreset()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a144a3d095fd668210282f1a91f23e1f0">oboe::AudioStreamBuilder</a>
-</li>
-<li>setMinimumBufferSize()
-: <a class="el" href="classoboe_1_1_latency_tuner.html#adc96aa53b18a051b6ccdacb838139bf8">oboe::LatencyTuner</a>
-</li>
-<li>setPerformanceMode()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a6cd1d65612e844e59da71a68ea0ab3ee">oboe::AudioStreamBuilder</a>
-</li>
-<li>setSampleRate()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a30ef3d5f51d56a9f980dc09600ed139d">oboe::AudioStreamBuilder</a>
-</li>
-<li>setSampleRateConversionQuality()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#af7d24a9ec975d430732151e5ee0d1027">oboe::AudioStreamBuilder</a>
-</li>
-<li>setSessionId()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a54c1651bdbe089d0d714af499e8a5f1d">oboe::AudioStreamBuilder</a>
-</li>
-<li>setSharingMode()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a3e991742acbbfb6fe5ebcf592c478654">oboe::AudioStreamBuilder</a>
-</li>
-<li>setUsage()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#a593255a2f5eb972665775cfc5bc58f6a">oboe::AudioStreamBuilder</a>
-</li>
-<li>setWorkaroundsEnabled()
-: <a class="el" href="classoboe_1_1_oboe_globals.html#af2b8af764c5a5e6fc007b7725117303b">oboe::OboeGlobals</a>
-</li>
-<li>start()
-: <a class="el" href="classoboe_1_1_audio_stream.html#af04f03eb6b64b564f1c4401688987d21">oboe::AudioStream</a>
-</li>
-<li>stop()
-: <a class="el" href="classoboe_1_1_audio_stream.html#aec093859d42f0470c884edd1e976d9f3">oboe::AudioStream</a>
-</li>
-</ul>
-
-
-<h3><a id="index_t"></a>- t -</h3><ul>
-<li>tune()
-: <a class="el" href="classoboe_1_1_latency_tuner.html#ad2be756965e6a9af3114008eda892174">oboe::LatencyTuner</a>
-</li>
-</ul>
-
-
-<h3><a id="index_u"></a>- u -</h3><ul>
-<li>updateFramesRead()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a462358ddab709c79d1a7968d6d55b727">oboe::AudioStream</a>
-</li>
-<li>updateFramesWritten()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a64ad978c5f70ced17ef5a96605496515">oboe::AudioStream</a>
-</li>
-<li>usesAAudio()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a15cdaaaa4c1e8da322d6da33334c8147">oboe::AudioStream</a>
-</li>
-</ul>
-
-
-<h3><a id="index_v"></a>- v -</h3><ul>
-<li>value()
-: <a class="el" href="classoboe_1_1_result_with_value.html#a45f5c99a2c9f8fbaca502276f7ebb434">oboe::ResultWithValue&lt; T &gt;</a>
-</li>
-</ul>
-
-
-<h3><a id="index_w"></a>- w -</h3><ul>
-<li>waitForAvailableFrames()
-: <a class="el" href="classoboe_1_1_audio_stream.html#afddb0962863ccf9ec6672a042fe15941">oboe::AudioStream</a>
-</li>
-<li>waitForStateChange()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a0c865a5501f369d959c39d8ab8b46a07">oboe::AudioStream</a>
-</li>
-<li>waitForStateTransition()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a8adbacd6a55a94a532916ab037fba1d6">oboe::AudioStream</a>
-</li>
-<li>wasErrorCallbackCalled()
-: <a class="el" href="classoboe_1_1_audio_stream.html#aa48da7bf28026b7cccee73e6b054af28">oboe::AudioStream</a>
-</li>
-<li>willUseAAudio()
-: <a class="el" href="classoboe_1_1_audio_stream_builder.html#aa07ea100fcb107d9f7913f206c2214f4">oboe::AudioStreamBuilder</a>
-</li>
-<li>write()
-: <a class="el" href="classoboe_1_1_audio_stream.html#a3612c05ed6b01a213dde67d913c07e11">oboe::AudioStream</a>
-</li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/functions_vars.html b/docs/reference/functions_vars.html
deleted file mode 100644
index 22e4c29..0000000
--- a/docs/reference/functions_vars.html
+++ /dev/null
@@ -1,157 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Class Members - Variables</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="contents">
-&#160;<ul>
-<li>ChannelCount
-: <a class="el" href="classoboe_1_1_default_stream_values.html#ad5dce538d5963c81bf58350ab730962d">oboe::DefaultStreamValues</a>
-</li>
-<li>FramesPerBurst
-: <a class="el" href="classoboe_1_1_default_stream_values.html#ab5ea5576699cebc56193f5c297d3e300">oboe::DefaultStreamValues</a>
-</li>
-<li>Major
-: <a class="el" href="structoboe_1_1_version.html#a270f2e92582d5187be339eeda8e2b276">oboe::Version</a>
-</li>
-<li>mBufferCapacityInFrames
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6">oboe::AudioStreamBase</a>
-</li>
-<li>mBufferSizeInFrames
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a3b65595d26d1eae1b8ce9925a5b98f6a">oboe::AudioStreamBase</a>
-</li>
-<li>mChannelCount
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206">oboe::AudioStreamBase</a>
-</li>
-<li>mContentType
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b">oboe::AudioStreamBase</a>
-</li>
-<li>mDataCallback
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f">oboe::AudioStreamBase</a>
-</li>
-<li>mDeviceId
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8">oboe::AudioStreamBase</a>
-</li>
-<li>mDirection
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880">oboe::AudioStreamBase</a>
-</li>
-<li>mErrorCallback
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b">oboe::AudioStreamBase</a>
-</li>
-<li>mFormat
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09">oboe::AudioStreamBase</a>
-</li>
-<li>mFramesPerBurst
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a54061319ed348329a29d883a5de2482e">oboe::AudioStreamBase</a>
-</li>
-<li>mFramesPerCallback
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899">oboe::AudioStreamBase</a>
-</li>
-<li>mFramesRead
-: <a class="el" href="classoboe_1_1_audio_stream.html#a07e82f9b9e2e4800f23ae9a7193c3b58">oboe::AudioStream</a>
-</li>
-<li>mFramesWritten
-: <a class="el" href="classoboe_1_1_audio_stream.html#a88a63317b7c58815bac074976b00aa23">oboe::AudioStream</a>
-</li>
-<li>Minor
-: <a class="el" href="structoboe_1_1_version.html#ae460bb95e3a9099696205a35fffb5469">oboe::Version</a>
-</li>
-<li>mInputPreset
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589">oboe::AudioStreamBase</a>
-</li>
-<li>mPerformanceMode
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765">oboe::AudioStreamBase</a>
-</li>
-<li>mSampleRate
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea">oboe::AudioStreamBase</a>
-</li>
-<li>mSessionId
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737">oboe::AudioStreamBase</a>
-</li>
-<li>mSharingMode
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473">oboe::AudioStreamBase</a>
-</li>
-<li>mUsage
-: <a class="el" href="classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c">oboe::AudioStreamBase</a>
-</li>
-<li>Number
-: <a class="el" href="structoboe_1_1_version.html#ac579661e79bcee45dc676d4647891de0">oboe::Version</a>
-</li>
-<li>Patch
-: <a class="el" href="structoboe_1_1_version.html#a690110f2b3e887892da8f29ab5c057b2">oboe::Version</a>
-</li>
-<li>SampleRate
-: <a class="el" href="classoboe_1_1_default_stream_values.html#a46a5d9a653f2153f618cadcab764e1b1">oboe::DefaultStreamValues</a>
-</li>
-<li>Text
-: <a class="el" href="structoboe_1_1_version.html#a2c86e578b827fbca5f40c460a7754503">oboe::Version</a>
-</li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/hierarchy.html b/docs/reference/hierarchy.html
deleted file mode 100644
index d7d985c..0000000
--- a/docs/reference/hierarchy.html
+++ /dev/null
@@ -1,97 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Class Hierarchy</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="header">
-  <div class="headertitle">
-<div class="title">Class Hierarchy</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="textblock">This inheritance list is sorted roughly, but not completely, alphabetically:</div><div class="directory">
-<div class="levels">[detail level <span onclick="javascript:toggleLevel(1);">1</span><span onclick="javascript:toggleLevel(2);">2</span><span onclick="javascript:toggleLevel(3);">3</span>]</div><table class="directory">
-<tr id="row_0_" class="even"><td class="entry"><span style="width:0px;display:inline-block;">&#160;</span><span id="arr_0_" class="arrow" onclick="toggleFolder('0_')">&#9660;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_audio_stream_base.html" target="_self">oboe::AudioStreamBase</a></td><td class="desc"></td></tr>
-<tr id="row_0_0_"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_audio_stream.html" target="_self">oboe::AudioStream</a></td><td class="desc"></td></tr>
-<tr id="row_0_1_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_audio_stream_builder.html" target="_self">oboe::AudioStreamBuilder</a></td><td class="desc"></td></tr>
-<tr id="row_1_"><td class="entry"><span style="width:0px;display:inline-block;">&#160;</span><span id="arr_1_" class="arrow" onclick="toggleFolder('1_')">&#9660;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_audio_stream_data_callback.html" target="_self">oboe::AudioStreamDataCallback</a></td><td class="desc"></td></tr>
-<tr id="row_1_0_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><span id="arr_1_0_" class="arrow" onclick="toggleFolder('1_0_')">&#9660;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_audio_stream_callback.html" target="_self">oboe::AudioStreamCallback</a></td><td class="desc"></td></tr>
-<tr id="row_1_0_0_"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_stabilized_callback.html" target="_self">oboe::StabilizedCallback</a></td><td class="desc"></td></tr>
-<tr id="row_2_" class="even"><td class="entry"><span style="width:0px;display:inline-block;">&#160;</span><span id="arr_2_" class="arrow" onclick="toggleFolder('2_')">&#9660;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_audio_stream_error_callback.html" target="_self">oboe::AudioStreamErrorCallback</a></td><td class="desc"></td></tr>
-<tr id="row_2_0_"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_audio_stream_callback.html" target="_self">oboe::AudioStreamCallback</a></td><td class="desc"></td></tr>
-<tr id="row_3_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_default_stream_values.html" target="_self">oboe::DefaultStreamValues</a></td><td class="desc"></td></tr>
-<tr id="row_4_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structoboe_1_1_frame_timestamp.html" target="_self">oboe::FrameTimestamp</a></td><td class="desc"></td></tr>
-<tr id="row_5_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_latency_tuner.html" target="_self">oboe::LatencyTuner</a></td><td class="desc"></td></tr>
-<tr id="row_6_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_oboe_globals.html" target="_self">oboe::OboeGlobals</a></td><td class="desc"></td></tr>
-<tr id="row_7_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classoboe_1_1_result_with_value.html" target="_self">oboe::ResultWithValue&lt; T &gt;</a></td><td class="desc"></td></tr>
-<tr id="row_8_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structoboe_1_1_stream_deleter_functor.html" target="_self">oboe::StreamDeleterFunctor</a></td><td class="desc"></td></tr>
-<tr id="row_9_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structoboe_1_1_version.html" target="_self">oboe::Version</a></td><td class="desc"></td></tr>
-</table>
-</div><!-- directory -->
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/index.html b/docs/reference/index.html
deleted file mode 100644
index 9c83aee..0000000
--- a/docs/reference/index.html
+++ /dev/null
@@ -1,80 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: API reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="PageDoc"><div class="header">
-  <div class="headertitle">
-<div class="title">API reference </div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="textblock"><p>All documentation is found in the <a href="namespaceoboe.html">oboe namespace section</a> </p>
-</div></div><!-- PageDoc -->
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/jquery.js b/docs/reference/jquery.js
deleted file mode 100644
index 1ee895c..0000000
--- a/docs/reference/jquery.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.7.2
- * http://jquery.com/
- *
- * Copyright 2011, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- * Copyright 2011, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- *
- * Date: Wed Mar 21 12:46:34 2012 -0700
- */
-(function(bd,L){var av=bd.document,bu=bd.navigator,bm=bd.location;var b=(function(){var bF=function(b0,b1){return new bF.fn.init(b0,b1,bD)},bU=bd.jQuery,bH=bd.$,bD,bY=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,bM=/\S/,bI=/^\s+/,bE=/\s+$/,bA=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,bN=/^[\],:{}\s]*$/,bW=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,bP=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,bJ=/(?:^|:|,)(?:\s*\[)+/g,by=/(webkit)[ \/]([\w.]+)/,bR=/(opera)(?:.*version)?[ \/]([\w.]+)/,bQ=/(msie) ([\w.]+)/,bS=/(mozilla)(?:.*? rv:([\w.]+))?/,bB=/-([a-z]|[0-9])/ig,bZ=/^-ms-/,bT=function(b0,b1){return(b1+"").toUpperCase()},bX=bu.userAgent,bV,bC,e,bL=Object.prototype.toString,bG=Object.prototype.hasOwnProperty,bz=Array.prototype.push,bK=Array.prototype.slice,bO=String.prototype.trim,bv=Array.prototype.indexOf,bx={};bF.fn=bF.prototype={constructor:bF,init:function(b0,b4,b3){var b2,b5,b1,b6;if(!b0){return this}if(b0.nodeType){this.context=this[0]=b0;this.length=1;return this}if(b0==="body"&&!b4&&av.body){this.context=av;this[0]=av.body;this.selector=b0;this.length=1;return this}if(typeof b0==="string"){if(b0.charAt(0)==="<"&&b0.charAt(b0.length-1)===">"&&b0.length>=3){b2=[null,b0,null]}else{b2=bY.exec(b0)}if(b2&&(b2[1]||!b4)){if(b2[1]){b4=b4 instanceof bF?b4[0]:b4;b6=(b4?b4.ownerDocument||b4:av);b1=bA.exec(b0);if(b1){if(bF.isPlainObject(b4)){b0=[av.createElement(b1[1])];bF.fn.attr.call(b0,b4,true)}else{b0=[b6.createElement(b1[1])]}}else{b1=bF.buildFragment([b2[1]],[b6]);b0=(b1.cacheable?bF.clone(b1.fragment):b1.fragment).childNodes}return bF.merge(this,b0)}else{b5=av.getElementById(b2[2]);if(b5&&b5.parentNode){if(b5.id!==b2[2]){return b3.find(b0)}this.length=1;this[0]=b5}this.context=av;this.selector=b0;return this}}else{if(!b4||b4.jquery){return(b4||b3).find(b0)}else{return this.constructor(b4).find(b0)}}}else{if(bF.isFunction(b0)){return b3.ready(b0)}}if(b0.selector!==L){this.selector=b0.selector;this.context=b0.context}return bF.makeArray(b0,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return bK.call(this,0)},get:function(b0){return b0==null?this.toArray():(b0<0?this[this.length+b0]:this[b0])},pushStack:function(b1,b3,b0){var b2=this.constructor();if(bF.isArray(b1)){bz.apply(b2,b1)}else{bF.merge(b2,b1)}b2.prevObject=this;b2.context=this.context;if(b3==="find"){b2.selector=this.selector+(this.selector?" ":"")+b0}else{if(b3){b2.selector=this.selector+"."+b3+"("+b0+")"}}return b2},each:function(b1,b0){return bF.each(this,b1,b0)},ready:function(b0){bF.bindReady();bC.add(b0);return this},eq:function(b0){b0=+b0;return b0===-1?this.slice(b0):this.slice(b0,b0+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(bK.apply(this,arguments),"slice",bK.call(arguments).join(","))},map:function(b0){return this.pushStack(bF.map(this,function(b2,b1){return b0.call(b2,b1,b2)}))},end:function(){return this.prevObject||this.constructor(null)},push:bz,sort:[].sort,splice:[].splice};bF.fn.init.prototype=bF.fn;bF.extend=bF.fn.extend=function(){var b9,b2,b0,b1,b6,b7,b5=arguments[0]||{},b4=1,b3=arguments.length,b8=false;if(typeof b5==="boolean"){b8=b5;b5=arguments[1]||{};b4=2}if(typeof b5!=="object"&&!bF.isFunction(b5)){b5={}}if(b3===b4){b5=this;--b4}for(;b4<b3;b4++){if((b9=arguments[b4])!=null){for(b2 in b9){b0=b5[b2];b1=b9[b2];if(b5===b1){continue}if(b8&&b1&&(bF.isPlainObject(b1)||(b6=bF.isArray(b1)))){if(b6){b6=false;b7=b0&&bF.isArray(b0)?b0:[]}else{b7=b0&&bF.isPlainObject(b0)?b0:{}}b5[b2]=bF.extend(b8,b7,b1)}else{if(b1!==L){b5[b2]=b1}}}}}return b5};bF.extend({noConflict:function(b0){if(bd.$===bF){bd.$=bH}if(b0&&bd.jQuery===bF){bd.jQuery=bU}return bF},isReady:false,readyWait:1,holdReady:function(b0){if(b0){bF.readyWait++}else{bF.ready(true)}},ready:function(b0){if((b0===true&&!--bF.readyWait)||(b0!==true&&!bF.isReady)){if(!av.body){return setTimeout(bF.ready,1)}bF.isReady=true;if(b0!==true&&--bF.readyWait>0){return}bC.fireWith(av,[bF]);if(bF.fn.trigger){bF(av).trigger("ready").off("ready")}}},bindReady:function(){if(bC){return}bC=bF.Callbacks("once memory");if(av.readyState==="complete"){return setTimeout(bF.ready,1)}if(av.addEventListener){av.addEventListener("DOMContentLoaded",e,false);bd.addEventListener("load",bF.ready,false)}else{if(av.attachEvent){av.attachEvent("onreadystatechange",e);bd.attachEvent("onload",bF.ready);var b0=false;try{b0=bd.frameElement==null}catch(b1){}if(av.documentElement.doScroll&&b0){bw()}}}},isFunction:function(b0){return bF.type(b0)==="function"},isArray:Array.isArray||function(b0){return bF.type(b0)==="array"},isWindow:function(b0){return b0!=null&&b0==b0.window},isNumeric:function(b0){return !isNaN(parseFloat(b0))&&isFinite(b0)},type:function(b0){return b0==null?String(b0):bx[bL.call(b0)]||"object"},isPlainObject:function(b2){if(!b2||bF.type(b2)!=="object"||b2.nodeType||bF.isWindow(b2)){return false}try{if(b2.constructor&&!bG.call(b2,"constructor")&&!bG.call(b2.constructor.prototype,"isPrototypeOf")){return false}}catch(b1){return false}var b0;for(b0 in b2){}return b0===L||bG.call(b2,b0)},isEmptyObject:function(b1){for(var b0 in b1){return false}return true},error:function(b0){throw new Error(b0)},parseJSON:function(b0){if(typeof b0!=="string"||!b0){return null}b0=bF.trim(b0);if(bd.JSON&&bd.JSON.parse){return bd.JSON.parse(b0)}if(bN.test(b0.replace(bW,"@").replace(bP,"]").replace(bJ,""))){return(new Function("return "+b0))()}bF.error("Invalid JSON: "+b0)},parseXML:function(b2){if(typeof b2!=="string"||!b2){return null}var b0,b1;try{if(bd.DOMParser){b1=new DOMParser();b0=b1.parseFromString(b2,"text/xml")}else{b0=new ActiveXObject("Microsoft.XMLDOM");b0.async="false";b0.loadXML(b2)}}catch(b3){b0=L}if(!b0||!b0.documentElement||b0.getElementsByTagName("parsererror").length){bF.error("Invalid XML: "+b2)}return b0},noop:function(){},globalEval:function(b0){if(b0&&bM.test(b0)){(bd.execScript||function(b1){bd["eval"].call(bd,b1)})(b0)}},camelCase:function(b0){return b0.replace(bZ,"ms-").replace(bB,bT)},nodeName:function(b1,b0){return b1.nodeName&&b1.nodeName.toUpperCase()===b0.toUpperCase()},each:function(b3,b6,b2){var b1,b4=0,b5=b3.length,b0=b5===L||bF.isFunction(b3);if(b2){if(b0){for(b1 in b3){if(b6.apply(b3[b1],b2)===false){break}}}else{for(;b4<b5;){if(b6.apply(b3[b4++],b2)===false){break}}}}else{if(b0){for(b1 in b3){if(b6.call(b3[b1],b1,b3[b1])===false){break}}}else{for(;b4<b5;){if(b6.call(b3[b4],b4,b3[b4++])===false){break}}}}return b3},trim:bO?function(b0){return b0==null?"":bO.call(b0)}:function(b0){return b0==null?"":b0.toString().replace(bI,"").replace(bE,"")},makeArray:function(b3,b1){var b0=b1||[];if(b3!=null){var b2=bF.type(b3);if(b3.length==null||b2==="string"||b2==="function"||b2==="regexp"||bF.isWindow(b3)){bz.call(b0,b3)}else{bF.merge(b0,b3)}}return b0},inArray:function(b2,b3,b1){var b0;if(b3){if(bv){return bv.call(b3,b2,b1)}b0=b3.length;b1=b1?b1<0?Math.max(0,b0+b1):b1:0;for(;b1<b0;b1++){if(b1 in b3&&b3[b1]===b2){return b1}}}return -1},merge:function(b4,b2){var b3=b4.length,b1=0;if(typeof b2.length==="number"){for(var b0=b2.length;b1<b0;b1++){b4[b3++]=b2[b1]}}else{while(b2[b1]!==L){b4[b3++]=b2[b1++]}}b4.length=b3;return b4},grep:function(b1,b6,b0){var b2=[],b5;b0=!!b0;for(var b3=0,b4=b1.length;b3<b4;b3++){b5=!!b6(b1[b3],b3);if(b0!==b5){b2.push(b1[b3])}}return b2},map:function(b0,b7,b8){var b5,b6,b4=[],b2=0,b1=b0.length,b3=b0 instanceof bF||b1!==L&&typeof b1==="number"&&((b1>0&&b0[0]&&b0[b1-1])||b1===0||bF.isArray(b0));if(b3){for(;b2<b1;b2++){b5=b7(b0[b2],b2,b8);if(b5!=null){b4[b4.length]=b5}}}else{for(b6 in b0){b5=b7(b0[b6],b6,b8);if(b5!=null){b4[b4.length]=b5}}}return b4.concat.apply([],b4)},guid:1,proxy:function(b4,b3){if(typeof b3==="string"){var b2=b4[b3];b3=b4;b4=b2}if(!bF.isFunction(b4)){return L}var b0=bK.call(arguments,2),b1=function(){return b4.apply(b3,b0.concat(bK.call(arguments)))};b1.guid=b4.guid=b4.guid||b1.guid||bF.guid++;return b1},access:function(b0,b6,b9,b7,b4,ca,b8){var b2,b5=b9==null,b3=0,b1=b0.length;if(b9&&typeof b9==="object"){for(b3 in b9){bF.access(b0,b6,b3,b9[b3],1,ca,b7)}b4=1}else{if(b7!==L){b2=b8===L&&bF.isFunction(b7);if(b5){if(b2){b2=b6;b6=function(cc,cb,cd){return b2.call(bF(cc),cd)}}else{b6.call(b0,b7);b6=null}}if(b6){for(;b3<b1;b3++){b6(b0[b3],b9,b2?b7.call(b0[b3],b3,b6(b0[b3],b9)):b7,b8)}}b4=1}}return b4?b0:b5?b6.call(b0):b1?b6(b0[0],b9):ca},now:function(){return(new Date()).getTime()},uaMatch:function(b1){b1=b1.toLowerCase();var b0=by.exec(b1)||bR.exec(b1)||bQ.exec(b1)||b1.indexOf("compatible")<0&&bS.exec(b1)||[];return{browser:b0[1]||"",version:b0[2]||"0"}},sub:function(){function b0(b3,b4){return new b0.fn.init(b3,b4)}bF.extend(true,b0,this);b0.superclass=this;b0.fn=b0.prototype=this();b0.fn.constructor=b0;b0.sub=this.sub;b0.fn.init=function b2(b3,b4){if(b4&&b4 instanceof bF&&!(b4 instanceof b0)){b4=b0(b4)}return bF.fn.init.call(this,b3,b4,b1)};b0.fn.init.prototype=b0.fn;var b1=b0(av);return b0},browser:{}});bF.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(b1,b0){bx["[object "+b0+"]"]=b0.toLowerCase()});bV=bF.uaMatch(bX);if(bV.browser){bF.browser[bV.browser]=true;bF.browser.version=bV.version}if(bF.browser.webkit){bF.browser.safari=true}if(bM.test("\xA0")){bI=/^[\s\xA0]+/;bE=/[\s\xA0]+$/}bD=bF(av);if(av.addEventListener){e=function(){av.removeEventListener("DOMContentLoaded",e,false);bF.ready()}}else{if(av.attachEvent){e=function(){if(av.readyState==="complete"){av.detachEvent("onreadystatechange",e);bF.ready()}}}}function bw(){if(bF.isReady){return}try{av.documentElement.doScroll("left")}catch(b0){setTimeout(bw,1);return}bF.ready()}return bF})();var a3={};function X(e){var bv=a3[e]={},bw,bx;e=e.split(/\s+/);for(bw=0,bx=e.length;bw<bx;bw++){bv[e[bw]]=true}return bv}b.Callbacks=function(bx){bx=bx?(a3[bx]||X(bx)):{};var bC=[],bD=[],by,e,bz,bw,bA,bB,bF=function(bG){var bH,bK,bJ,bI,bL;for(bH=0,bK=bG.length;bH<bK;bH++){bJ=bG[bH];bI=b.type(bJ);if(bI==="array"){bF(bJ)}else{if(bI==="function"){if(!bx.unique||!bE.has(bJ)){bC.push(bJ)}}}}},bv=function(bH,bG){bG=bG||[];by=!bx.memory||[bH,bG];e=true;bz=true;bB=bw||0;bw=0;bA=bC.length;for(;bC&&bB<bA;bB++){if(bC[bB].apply(bH,bG)===false&&bx.stopOnFalse){by=true;break}}bz=false;if(bC){if(!bx.once){if(bD&&bD.length){by=bD.shift();bE.fireWith(by[0],by[1])}}else{if(by===true){bE.disable()}else{bC=[]}}}},bE={add:function(){if(bC){var bG=bC.length;bF(arguments);if(bz){bA=bC.length}else{if(by&&by!==true){bw=bG;bv(by[0],by[1])}}}return this},remove:function(){if(bC){var bG=arguments,bI=0,bJ=bG.length;for(;bI<bJ;bI++){for(var bH=0;bH<bC.length;bH++){if(bG[bI]===bC[bH]){if(bz){if(bH<=bA){bA--;if(bH<=bB){bB--}}}bC.splice(bH--,1);if(bx.unique){break}}}}}return this},has:function(bH){if(bC){var bG=0,bI=bC.length;for(;bG<bI;bG++){if(bH===bC[bG]){return true}}}return false},empty:function(){bC=[];return this},disable:function(){bC=bD=by=L;return this},disabled:function(){return !bC},lock:function(){bD=L;if(!by||by===true){bE.disable()}return this},locked:function(){return !bD},fireWith:function(bH,bG){if(bD){if(bz){if(!bx.once){bD.push([bH,bG])}}else{if(!(bx.once&&by)){bv(bH,bG)}}}return this},fire:function(){bE.fireWith(this,arguments);return this},fired:function(){return !!e}};return bE};var aK=[].slice;b.extend({Deferred:function(by){var bx=b.Callbacks("once memory"),bw=b.Callbacks("once memory"),bv=b.Callbacks("memory"),e="pending",bA={resolve:bx,reject:bw,notify:bv},bC={done:bx.add,fail:bw.add,progress:bv.add,state:function(){return e},isResolved:bx.fired,isRejected:bw.fired,then:function(bE,bD,bF){bB.done(bE).fail(bD).progress(bF);return this},always:function(){bB.done.apply(bB,arguments).fail.apply(bB,arguments);return this},pipe:function(bF,bE,bD){return b.Deferred(function(bG){b.each({done:[bF,"resolve"],fail:[bE,"reject"],progress:[bD,"notify"]},function(bI,bL){var bH=bL[0],bK=bL[1],bJ;if(b.isFunction(bH)){bB[bI](function(){bJ=bH.apply(this,arguments);if(bJ&&b.isFunction(bJ.promise)){bJ.promise().then(bG.resolve,bG.reject,bG.notify)}else{bG[bK+"With"](this===bB?bG:this,[bJ])}})}else{bB[bI](bG[bK])}})}).promise()},promise:function(bE){if(bE==null){bE=bC}else{for(var bD in bC){bE[bD]=bC[bD]}}return bE}},bB=bC.promise({}),bz;for(bz in bA){bB[bz]=bA[bz].fire;bB[bz+"With"]=bA[bz].fireWith}bB.done(function(){e="resolved"},bw.disable,bv.lock).fail(function(){e="rejected"},bx.disable,bv.lock);if(by){by.call(bB,bB)}return bB},when:function(bA){var bx=aK.call(arguments,0),bv=0,e=bx.length,bB=new Array(e),bw=e,by=e,bC=e<=1&&bA&&b.isFunction(bA.promise)?bA:b.Deferred(),bE=bC.promise();function bD(bF){return function(bG){bx[bF]=arguments.length>1?aK.call(arguments,0):bG;if(!(--bw)){bC.resolveWith(bC,bx)}}}function bz(bF){return function(bG){bB[bF]=arguments.length>1?aK.call(arguments,0):bG;bC.notifyWith(bE,bB)}}if(e>1){for(;bv<e;bv++){if(bx[bv]&&bx[bv].promise&&b.isFunction(bx[bv].promise)){bx[bv].promise().then(bD(bv),bC.reject,bz(bv))}else{--bw}}if(!bw){bC.resolveWith(bC,bx)}}else{if(bC!==bA){bC.resolveWith(bC,e?[bA]:[])}}return bE}});b.support=(function(){var bI,bH,bE,bF,bx,bD,bC,bz,bJ,bA,by,bw,bv=av.createElement("div"),bG=av.documentElement;bv.setAttribute("className","t");bv.innerHTML="   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";bH=bv.getElementsByTagName("*");bE=bv.getElementsByTagName("a")[0];if(!bH||!bH.length||!bE){return{}}bF=av.createElement("select");bx=bF.appendChild(av.createElement("option"));bD=bv.getElementsByTagName("input")[0];bI={leadingWhitespace:(bv.firstChild.nodeType===3),tbody:!bv.getElementsByTagName("tbody").length,htmlSerialize:!!bv.getElementsByTagName("link").length,style:/top/.test(bE.getAttribute("style")),hrefNormalized:(bE.getAttribute("href")==="/a"),opacity:/^0.55/.test(bE.style.opacity),cssFloat:!!bE.style.cssFloat,checkOn:(bD.value==="on"),optSelected:bx.selected,getSetAttribute:bv.className!=="t",enctype:!!av.createElement("form").enctype,html5Clone:av.createElement("nav").cloneNode(true).outerHTML!=="<:nav></:nav>",submitBubbles:true,changeBubbles:true,focusinBubbles:false,deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true,pixelMargin:true};b.boxModel=bI.boxModel=(av.compatMode==="CSS1Compat");bD.checked=true;bI.noCloneChecked=bD.cloneNode(true).checked;bF.disabled=true;bI.optDisabled=!bx.disabled;try{delete bv.test}catch(bB){bI.deleteExpando=false}if(!bv.addEventListener&&bv.attachEvent&&bv.fireEvent){bv.attachEvent("onclick",function(){bI.noCloneEvent=false});bv.cloneNode(true).fireEvent("onclick")}bD=av.createElement("input");bD.value="t";bD.setAttribute("type","radio");bI.radioValue=bD.value==="t";bD.setAttribute("checked","checked");bD.setAttribute("name","t");bv.appendChild(bD);bC=av.createDocumentFragment();bC.appendChild(bv.lastChild);bI.checkClone=bC.cloneNode(true).cloneNode(true).lastChild.checked;bI.appendChecked=bD.checked;bC.removeChild(bD);bC.appendChild(bv);if(bv.attachEvent){for(by in {submit:1,change:1,focusin:1}){bA="on"+by;bw=(bA in bv);if(!bw){bv.setAttribute(bA,"return;");bw=(typeof bv[bA]==="function")}bI[by+"Bubbles"]=bw}}bC.removeChild(bv);bC=bF=bx=bv=bD=null;b(function(){var bM,bV,bW,bU,bO,bP,bR,bL,bK,bQ,bN,e,bT,bS=av.getElementsByTagName("body")[0];if(!bS){return}bL=1;bT="padding:0;margin:0;border:";bN="position:absolute;top:0;left:0;width:1px;height:1px;";e=bT+"0;visibility:hidden;";bK="style='"+bN+bT+"5px solid #000;";bQ="<div "+bK+"display:block;'><div style='"+bT+"0;display:block;overflow:hidden;'></div></div><table "+bK+"' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";bM=av.createElement("div");bM.style.cssText=e+"width:0;height:0;position:static;top:0;margin-top:"+bL+"px";bS.insertBefore(bM,bS.firstChild);bv=av.createElement("div");bM.appendChild(bv);bv.innerHTML="<table><tr><td style='"+bT+"0;display:none'></td><td>t</td></tr></table>";bz=bv.getElementsByTagName("td");bw=(bz[0].offsetHeight===0);bz[0].style.display="";bz[1].style.display="none";bI.reliableHiddenOffsets=bw&&(bz[0].offsetHeight===0);if(bd.getComputedStyle){bv.innerHTML="";bR=av.createElement("div");bR.style.width="0";bR.style.marginRight="0";bv.style.width="2px";bv.appendChild(bR);bI.reliableMarginRight=(parseInt((bd.getComputedStyle(bR,null)||{marginRight:0}).marginRight,10)||0)===0}if(typeof bv.style.zoom!=="undefined"){bv.innerHTML="";bv.style.width=bv.style.padding="1px";bv.style.border=0;bv.style.overflow="hidden";bv.style.display="inline";bv.style.zoom=1;bI.inlineBlockNeedsLayout=(bv.offsetWidth===3);bv.style.display="block";bv.style.overflow="visible";bv.innerHTML="<div style='width:5px;'></div>";bI.shrinkWrapBlocks=(bv.offsetWidth!==3)}bv.style.cssText=bN+e;bv.innerHTML=bQ;bV=bv.firstChild;bW=bV.firstChild;bO=bV.nextSibling.firstChild.firstChild;bP={doesNotAddBorder:(bW.offsetTop!==5),doesAddBorderForTableAndCells:(bO.offsetTop===5)};bW.style.position="fixed";bW.style.top="20px";bP.fixedPosition=(bW.offsetTop===20||bW.offsetTop===15);bW.style.position=bW.style.top="";bV.style.overflow="hidden";bV.style.position="relative";bP.subtractsBorderForOverflowNotVisible=(bW.offsetTop===-5);bP.doesNotIncludeMarginInBodyOffset=(bS.offsetTop!==bL);if(bd.getComputedStyle){bv.style.marginTop="1%";bI.pixelMargin=(bd.getComputedStyle(bv,null)||{marginTop:0}).marginTop!=="1%"}if(typeof bM.style.zoom!=="undefined"){bM.style.zoom=1}bS.removeChild(bM);bR=bv=bM=null;b.extend(bI,bP)});return bI})();var aT=/^(?:\{.*\}|\[.*\])$/,aA=/([A-Z])/g;b.extend({cache:{},uuid:0,expando:"jQuery"+(b.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},hasData:function(e){e=e.nodeType?b.cache[e[b.expando]]:e[b.expando];return !!e&&!S(e)},data:function(bx,bv,bz,by){if(!b.acceptData(bx)){return}var bG,bA,bD,bE=b.expando,bC=typeof bv==="string",bF=bx.nodeType,e=bF?b.cache:bx,bw=bF?bx[bE]:bx[bE]&&bE,bB=bv==="events";if((!bw||!e[bw]||(!bB&&!by&&!e[bw].data))&&bC&&bz===L){return}if(!bw){if(bF){bx[bE]=bw=++b.uuid}else{bw=bE}}if(!e[bw]){e[bw]={};if(!bF){e[bw].toJSON=b.noop}}if(typeof bv==="object"||typeof bv==="function"){if(by){e[bw]=b.extend(e[bw],bv)}else{e[bw].data=b.extend(e[bw].data,bv)}}bG=bA=e[bw];if(!by){if(!bA.data){bA.data={}}bA=bA.data}if(bz!==L){bA[b.camelCase(bv)]=bz}if(bB&&!bA[bv]){return bG.events}if(bC){bD=bA[bv];if(bD==null){bD=bA[b.camelCase(bv)]}}else{bD=bA}return bD},removeData:function(bx,bv,by){if(!b.acceptData(bx)){return}var bB,bA,bz,bC=b.expando,bD=bx.nodeType,e=bD?b.cache:bx,bw=bD?bx[bC]:bC;if(!e[bw]){return}if(bv){bB=by?e[bw]:e[bw].data;if(bB){if(!b.isArray(bv)){if(bv in bB){bv=[bv]}else{bv=b.camelCase(bv);if(bv in bB){bv=[bv]}else{bv=bv.split(" ")}}}for(bA=0,bz=bv.length;bA<bz;bA++){delete bB[bv[bA]]}if(!(by?S:b.isEmptyObject)(bB)){return}}}if(!by){delete e[bw].data;if(!S(e[bw])){return}}if(b.support.deleteExpando||!e.setInterval){delete e[bw]}else{e[bw]=null}if(bD){if(b.support.deleteExpando){delete bx[bC]}else{if(bx.removeAttribute){bx.removeAttribute(bC)}else{bx[bC]=null}}}},_data:function(bv,e,bw){return b.data(bv,e,bw,true)},acceptData:function(bv){if(bv.nodeName){var e=b.noData[bv.nodeName.toLowerCase()];if(e){return !(e===true||bv.getAttribute("classid")!==e)}}return true}});b.fn.extend({data:function(bD,bC){var by,bv,bB,e,bx,bw=this[0],bA=0,bz=null;if(bD===L){if(this.length){bz=b.data(bw);if(bw.nodeType===1&&!b._data(bw,"parsedAttrs")){bB=bw.attributes;for(bx=bB.length;bA<bx;bA++){e=bB[bA].name;if(e.indexOf("data-")===0){e=b.camelCase(e.substring(5));a6(bw,e,bz[e])}}b._data(bw,"parsedAttrs",true)}}return bz}if(typeof bD==="object"){return this.each(function(){b.data(this,bD)})}by=bD.split(".",2);by[1]=by[1]?"."+by[1]:"";bv=by[1]+"!";return b.access(this,function(bE){if(bE===L){bz=this.triggerHandler("getData"+bv,[by[0]]);if(bz===L&&bw){bz=b.data(bw,bD);bz=a6(bw,bD,bz)}return bz===L&&by[1]?this.data(by[0]):bz}by[1]=bE;this.each(function(){var bF=b(this);bF.triggerHandler("setData"+bv,by);b.data(this,bD,bE);bF.triggerHandler("changeData"+bv,by)})},null,bC,arguments.length>1,null,false)},removeData:function(e){return this.each(function(){b.removeData(this,e)})}});function a6(bx,bw,by){if(by===L&&bx.nodeType===1){var bv="data-"+bw.replace(aA,"-$1").toLowerCase();by=bx.getAttribute(bv);if(typeof by==="string"){try{by=by==="true"?true:by==="false"?false:by==="null"?null:b.isNumeric(by)?+by:aT.test(by)?b.parseJSON(by):by}catch(bz){}b.data(bx,bw,by)}else{by=L}}return by}function S(bv){for(var e in bv){if(e==="data"&&b.isEmptyObject(bv[e])){continue}if(e!=="toJSON"){return false}}return true}function bj(by,bx,bA){var bw=bx+"defer",bv=bx+"queue",e=bx+"mark",bz=b._data(by,bw);if(bz&&(bA==="queue"||!b._data(by,bv))&&(bA==="mark"||!b._data(by,e))){setTimeout(function(){if(!b._data(by,bv)&&!b._data(by,e)){b.removeData(by,bw,true);bz.fire()}},0)}}b.extend({_mark:function(bv,e){if(bv){e=(e||"fx")+"mark";b._data(bv,e,(b._data(bv,e)||0)+1)}},_unmark:function(by,bx,bv){if(by!==true){bv=bx;bx=by;by=false}if(bx){bv=bv||"fx";var e=bv+"mark",bw=by?0:((b._data(bx,e)||1)-1);if(bw){b._data(bx,e,bw)}else{b.removeData(bx,e,true);bj(bx,bv,"mark")}}},queue:function(bv,e,bx){var bw;if(bv){e=(e||"fx")+"queue";bw=b._data(bv,e);if(bx){if(!bw||b.isArray(bx)){bw=b._data(bv,e,b.makeArray(bx))}else{bw.push(bx)}}return bw||[]}},dequeue:function(by,bx){bx=bx||"fx";var bv=b.queue(by,bx),bw=bv.shift(),e={};if(bw==="inprogress"){bw=bv.shift()}if(bw){if(bx==="fx"){bv.unshift("inprogress")}b._data(by,bx+".run",e);bw.call(by,function(){b.dequeue(by,bx)},e)}if(!bv.length){b.removeData(by,bx+"queue "+bx+".run",true);bj(by,bx,"queue")}}});b.fn.extend({queue:function(e,bv){var bw=2;if(typeof e!=="string"){bv=e;e="fx";bw--}if(arguments.length<bw){return b.queue(this[0],e)}return bv===L?this:this.each(function(){var bx=b.queue(this,e,bv);if(e==="fx"&&bx[0]!=="inprogress"){b.dequeue(this,e)}})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(bv,e){bv=b.fx?b.fx.speeds[bv]||bv:bv;e=e||"fx";return this.queue(e,function(bx,bw){var by=setTimeout(bx,bv);bw.stop=function(){clearTimeout(by)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(bD,bw){if(typeof bD!=="string"){bw=bD;bD=L}bD=bD||"fx";var e=b.Deferred(),bv=this,by=bv.length,bB=1,bz=bD+"defer",bA=bD+"queue",bC=bD+"mark",bx;function bE(){if(!(--bB)){e.resolveWith(bv,[bv])}}while(by--){if((bx=b.data(bv[by],bz,L,true)||(b.data(bv[by],bA,L,true)||b.data(bv[by],bC,L,true))&&b.data(bv[by],bz,b.Callbacks("once memory"),true))){bB++;bx.add(bE)}}bE();return e.promise(bw)}});var aQ=/[\n\t\r]/g,ag=/\s+/,aV=/\r/g,g=/^(?:button|input)$/i,C=/^(?:button|input|object|select|textarea)$/i,l=/^a(?:rea)?$/i,ao=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,E=b.support.getSetAttribute,bf,aZ,aG;b.fn.extend({attr:function(e,bv){return b.access(this,b.attr,e,bv,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,bv){return b.access(this,b.prop,e,bv,arguments.length>1)},removeProp:function(e){e=b.propFix[e]||e;return this.each(function(){try{this[e]=L;delete this[e]}catch(bv){}})},addClass:function(by){var bA,bw,bv,bx,bz,bB,e;if(b.isFunction(by)){return this.each(function(bC){b(this).addClass(by.call(this,bC,this.className))})}if(by&&typeof by==="string"){bA=by.split(ag);for(bw=0,bv=this.length;bw<bv;bw++){bx=this[bw];if(bx.nodeType===1){if(!bx.className&&bA.length===1){bx.className=by}else{bz=" "+bx.className+" ";for(bB=0,e=bA.length;bB<e;bB++){if(!~bz.indexOf(" "+bA[bB]+" ")){bz+=bA[bB]+" "}}bx.className=b.trim(bz)}}}}return this},removeClass:function(bz){var bA,bw,bv,by,bx,bB,e;if(b.isFunction(bz)){return this.each(function(bC){b(this).removeClass(bz.call(this,bC,this.className))})}if((bz&&typeof bz==="string")||bz===L){bA=(bz||"").split(ag);for(bw=0,bv=this.length;bw<bv;bw++){by=this[bw];if(by.nodeType===1&&by.className){if(bz){bx=(" "+by.className+" ").replace(aQ," ");for(bB=0,e=bA.length;bB<e;bB++){bx=bx.replace(" "+bA[bB]+" "," ")}by.className=b.trim(bx)}else{by.className=""}}}}return this},toggleClass:function(bx,bv){var bw=typeof bx,e=typeof bv==="boolean";if(b.isFunction(bx)){return this.each(function(by){b(this).toggleClass(bx.call(this,by,this.className,bv),bv)})}return this.each(function(){if(bw==="string"){var bA,bz=0,by=b(this),bB=bv,bC=bx.split(ag);while((bA=bC[bz++])){bB=e?bB:!by.hasClass(bA);by[bB?"addClass":"removeClass"](bA)}}else{if(bw==="undefined"||bw==="boolean"){if(this.className){b._data(this,"__className__",this.className)}this.className=this.className||bx===false?"":b._data(this,"__className__")||""}}})},hasClass:function(e){var bx=" "+e+" ",bw=0,bv=this.length;for(;bw<bv;bw++){if(this[bw].nodeType===1&&(" "+this[bw].className+" ").replace(aQ," ").indexOf(bx)>-1){return true}}return false},val:function(bx){var e,bv,by,bw=this[0];if(!arguments.length){if(bw){e=b.valHooks[bw.type]||b.valHooks[bw.nodeName.toLowerCase()];if(e&&"get" in e&&(bv=e.get(bw,"value"))!==L){return bv}bv=bw.value;return typeof bv==="string"?bv.replace(aV,""):bv==null?"":bv}return}by=b.isFunction(bx);return this.each(function(bA){var bz=b(this),bB;if(this.nodeType!==1){return}if(by){bB=bx.call(this,bA,bz.val())}else{bB=bx}if(bB==null){bB=""}else{if(typeof bB==="number"){bB+=""}else{if(b.isArray(bB)){bB=b.map(bB,function(bC){return bC==null?"":bC+""})}}}e=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()];if(!e||!("set" in e)||e.set(this,bB,"value")===L){this.value=bB}})}});b.extend({valHooks:{option:{get:function(e){var bv=e.attributes.value;return !bv||bv.specified?e.value:e.text}},select:{get:function(e){var bA,bv,bz,bx,by=e.selectedIndex,bB=[],bC=e.options,bw=e.type==="select-one";if(by<0){return null}bv=bw?by:0;bz=bw?by+1:bC.length;for(;bv<bz;bv++){bx=bC[bv];if(bx.selected&&(b.support.optDisabled?!bx.disabled:bx.getAttribute("disabled")===null)&&(!bx.parentNode.disabled||!b.nodeName(bx.parentNode,"optgroup"))){bA=b(bx).val();if(bw){return bA}bB.push(bA)}}if(bw&&!bB.length&&bC.length){return b(bC[by]).val()}return bB},set:function(bv,bw){var e=b.makeArray(bw);b(bv).find("option").each(function(){this.selected=b.inArray(b(this).val(),e)>=0});if(!e.length){bv.selectedIndex=-1}return e}}},attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(bA,bx,bB,bz){var bw,e,by,bv=bA.nodeType;if(!bA||bv===3||bv===8||bv===2){return}if(bz&&bx in b.attrFn){return b(bA)[bx](bB)}if(typeof bA.getAttribute==="undefined"){return b.prop(bA,bx,bB)}by=bv!==1||!b.isXMLDoc(bA);if(by){bx=bx.toLowerCase();e=b.attrHooks[bx]||(ao.test(bx)?aZ:bf)}if(bB!==L){if(bB===null){b.removeAttr(bA,bx);return}else{if(e&&"set" in e&&by&&(bw=e.set(bA,bB,bx))!==L){return bw}else{bA.setAttribute(bx,""+bB);return bB}}}else{if(e&&"get" in e&&by&&(bw=e.get(bA,bx))!==null){return bw}else{bw=bA.getAttribute(bx);return bw===null?L:bw}}},removeAttr:function(by,bA){var bz,bB,bw,e,bv,bx=0;if(bA&&by.nodeType===1){bB=bA.toLowerCase().split(ag);e=bB.length;for(;bx<e;bx++){bw=bB[bx];if(bw){bz=b.propFix[bw]||bw;bv=ao.test(bw);if(!bv){b.attr(by,bw,"")}by.removeAttribute(E?bw:bz);if(bv&&bz in by){by[bz]=false}}}}},attrHooks:{type:{set:function(e,bv){if(g.test(e.nodeName)&&e.parentNode){b.error("type property can't be changed")}else{if(!b.support.radioValue&&bv==="radio"&&b.nodeName(e,"input")){var bw=e.value;e.setAttribute("type",bv);if(bw){e.value=bw}return bv}}}},value:{get:function(bv,e){if(bf&&b.nodeName(bv,"button")){return bf.get(bv,e)}return e in bv?bv.value:null},set:function(bv,bw,e){if(bf&&b.nodeName(bv,"button")){return bf.set(bv,bw,e)}bv.value=bw}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(bz,bx,bA){var bw,e,by,bv=bz.nodeType;if(!bz||bv===3||bv===8||bv===2){return}by=bv!==1||!b.isXMLDoc(bz);if(by){bx=b.propFix[bx]||bx;e=b.propHooks[bx]}if(bA!==L){if(e&&"set" in e&&(bw=e.set(bz,bA,bx))!==L){return bw}else{return(bz[bx]=bA)}}else{if(e&&"get" in e&&(bw=e.get(bz,bx))!==null){return bw}else{return bz[bx]}}},propHooks:{tabIndex:{get:function(bv){var e=bv.getAttributeNode("tabindex");return e&&e.specified?parseInt(e.value,10):C.test(bv.nodeName)||l.test(bv.nodeName)&&bv.href?0:L}}}});b.attrHooks.tabindex=b.propHooks.tabIndex;aZ={get:function(bv,e){var bx,bw=b.prop(bv,e);return bw===true||typeof bw!=="boolean"&&(bx=bv.getAttributeNode(e))&&bx.nodeValue!==false?e.toLowerCase():L},set:function(bv,bx,e){var bw;if(bx===false){b.removeAttr(bv,e)}else{bw=b.propFix[e]||e;if(bw in bv){bv[bw]=true}bv.setAttribute(e,e.toLowerCase())}return e}};if(!E){aG={name:true,id:true,coords:true};bf=b.valHooks.button={get:function(bw,bv){var e;e=bw.getAttributeNode(bv);return e&&(aG[bv]?e.nodeValue!=="":e.specified)?e.nodeValue:L},set:function(bw,bx,bv){var e=bw.getAttributeNode(bv);if(!e){e=av.createAttribute(bv);bw.setAttributeNode(e)}return(e.nodeValue=bx+"")}};b.attrHooks.tabindex.set=bf.set;b.each(["width","height"],function(bv,e){b.attrHooks[e]=b.extend(b.attrHooks[e],{set:function(bw,bx){if(bx===""){bw.setAttribute(e,"auto");return bx}}})});b.attrHooks.contenteditable={get:bf.get,set:function(bv,bw,e){if(bw===""){bw="false"}bf.set(bv,bw,e)}}}if(!b.support.hrefNormalized){b.each(["href","src","width","height"],function(bv,e){b.attrHooks[e]=b.extend(b.attrHooks[e],{get:function(bx){var bw=bx.getAttribute(e,2);return bw===null?L:bw}})})}if(!b.support.style){b.attrHooks.style={get:function(e){return e.style.cssText.toLowerCase()||L},set:function(e,bv){return(e.style.cssText=""+bv)}}}if(!b.support.optSelected){b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(bv){var e=bv.parentNode;if(e){e.selectedIndex;if(e.parentNode){e.parentNode.selectedIndex}}return null}})}if(!b.support.enctype){b.propFix.enctype="encoding"}if(!b.support.checkOn){b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return e.getAttribute("value")===null?"on":e.value}}})}b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,bv){if(b.isArray(bv)){return(e.checked=b.inArray(b(e).val(),bv)>=0)}}})});var be=/^(?:textarea|input|select)$/i,n=/^([^\.]*)?(?:\.(.+))?$/,J=/(?:^|\s)hover(\.\S+)?\b/,aP=/^key/,bg=/^(?:mouse|contextmenu)|click/,T=/^(?:focusinfocus|focusoutblur)$/,U=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,Y=function(e){var bv=U.exec(e);if(bv){bv[1]=(bv[1]||"").toLowerCase();bv[3]=bv[3]&&new RegExp("(?:^|\\s)"+bv[3]+"(?:\\s|$)")}return bv},j=function(bw,e){var bv=bw.attributes||{};return((!e[1]||bw.nodeName.toLowerCase()===e[1])&&(!e[2]||(bv.id||{}).value===e[2])&&(!e[3]||e[3].test((bv["class"]||{}).value)))},bt=function(e){return b.event.special.hover?e:e.replace(J,"mouseenter$1 mouseleave$1")};b.event={add:function(bx,bC,bJ,bA,by){var bD,bB,bK,bI,bH,bF,e,bG,bv,bz,bw,bE;if(bx.nodeType===3||bx.nodeType===8||!bC||!bJ||!(bD=b._data(bx))){return}if(bJ.handler){bv=bJ;bJ=bv.handler;by=bv.selector}if(!bJ.guid){bJ.guid=b.guid++}bK=bD.events;if(!bK){bD.events=bK={}}bB=bD.handle;if(!bB){bD.handle=bB=function(bL){return typeof b!=="undefined"&&(!bL||b.event.triggered!==bL.type)?b.event.dispatch.apply(bB.elem,arguments):L};bB.elem=bx}bC=b.trim(bt(bC)).split(" ");for(bI=0;bI<bC.length;bI++){bH=n.exec(bC[bI])||[];bF=bH[1];e=(bH[2]||"").split(".").sort();bE=b.event.special[bF]||{};bF=(by?bE.delegateType:bE.bindType)||bF;bE=b.event.special[bF]||{};bG=b.extend({type:bF,origType:bH[1],data:bA,handler:bJ,guid:bJ.guid,selector:by,quick:by&&Y(by),namespace:e.join(".")},bv);bw=bK[bF];if(!bw){bw=bK[bF]=[];bw.delegateCount=0;if(!bE.setup||bE.setup.call(bx,bA,e,bB)===false){if(bx.addEventListener){bx.addEventListener(bF,bB,false)}else{if(bx.attachEvent){bx.attachEvent("on"+bF,bB)}}}}if(bE.add){bE.add.call(bx,bG);if(!bG.handler.guid){bG.handler.guid=bJ.guid}}if(by){bw.splice(bw.delegateCount++,0,bG)}else{bw.push(bG)}b.event.global[bF]=true}bx=null},global:{},remove:function(bJ,bE,bv,bH,bB){var bI=b.hasData(bJ)&&b._data(bJ),bF,bx,bz,bL,bC,bA,bG,bw,by,bK,bD,e;if(!bI||!(bw=bI.events)){return}bE=b.trim(bt(bE||"")).split(" ");for(bF=0;bF<bE.length;bF++){bx=n.exec(bE[bF])||[];bz=bL=bx[1];bC=bx[2];if(!bz){for(bz in bw){b.event.remove(bJ,bz+bE[bF],bv,bH,true)}continue}by=b.event.special[bz]||{};bz=(bH?by.delegateType:by.bindType)||bz;bD=bw[bz]||[];bA=bD.length;bC=bC?new RegExp("(^|\\.)"+bC.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(bG=0;bG<bD.length;bG++){e=bD[bG];if((bB||bL===e.origType)&&(!bv||bv.guid===e.guid)&&(!bC||bC.test(e.namespace))&&(!bH||bH===e.selector||bH==="**"&&e.selector)){bD.splice(bG--,1);if(e.selector){bD.delegateCount--}if(by.remove){by.remove.call(bJ,e)}}}if(bD.length===0&&bA!==bD.length){if(!by.teardown||by.teardown.call(bJ,bC)===false){b.removeEvent(bJ,bz,bI.handle)}delete bw[bz]}}if(b.isEmptyObject(bw)){bK=bI.handle;if(bK){bK.elem=null}b.removeData(bJ,["events","handle"],true)}},customEvent:{getData:true,setData:true,changeData:true},trigger:function(bv,bD,bA,bJ){if(bA&&(bA.nodeType===3||bA.nodeType===8)){return}var bG=bv.type||bv,bx=[],e,bw,bC,bH,bz,by,bF,bE,bB,bI;if(T.test(bG+b.event.triggered)){return}if(bG.indexOf("!")>=0){bG=bG.slice(0,-1);bw=true}if(bG.indexOf(".")>=0){bx=bG.split(".");bG=bx.shift();bx.sort()}if((!bA||b.event.customEvent[bG])&&!b.event.global[bG]){return}bv=typeof bv==="object"?bv[b.expando]?bv:new b.Event(bG,bv):new b.Event(bG);bv.type=bG;bv.isTrigger=true;bv.exclusive=bw;bv.namespace=bx.join(".");bv.namespace_re=bv.namespace?new RegExp("(^|\\.)"+bx.join("\\.(?:.*\\.)?")+"(\\.|$)"):null;by=bG.indexOf(":")<0?"on"+bG:"";if(!bA){e=b.cache;for(bC in e){if(e[bC].events&&e[bC].events[bG]){b.event.trigger(bv,bD,e[bC].handle.elem,true)}}return}bv.result=L;if(!bv.target){bv.target=bA}bD=bD!=null?b.makeArray(bD):[];bD.unshift(bv);bF=b.event.special[bG]||{};if(bF.trigger&&bF.trigger.apply(bA,bD)===false){return}bB=[[bA,bF.bindType||bG]];if(!bJ&&!bF.noBubble&&!b.isWindow(bA)){bI=bF.delegateType||bG;bH=T.test(bI+bG)?bA:bA.parentNode;bz=null;for(;bH;bH=bH.parentNode){bB.push([bH,bI]);bz=bH}if(bz&&bz===bA.ownerDocument){bB.push([bz.defaultView||bz.parentWindow||bd,bI])}}for(bC=0;bC<bB.length&&!bv.isPropagationStopped();bC++){bH=bB[bC][0];bv.type=bB[bC][1];bE=(b._data(bH,"events")||{})[bv.type]&&b._data(bH,"handle");if(bE){bE.apply(bH,bD)}bE=by&&bH[by];if(bE&&b.acceptData(bH)&&bE.apply(bH,bD)===false){bv.preventDefault()}}bv.type=bG;if(!bJ&&!bv.isDefaultPrevented()){if((!bF._default||bF._default.apply(bA.ownerDocument,bD)===false)&&!(bG==="click"&&b.nodeName(bA,"a"))&&b.acceptData(bA)){if(by&&bA[bG]&&((bG!=="focus"&&bG!=="blur")||bv.target.offsetWidth!==0)&&!b.isWindow(bA)){bz=bA[by];if(bz){bA[by]=null}b.event.triggered=bG;bA[bG]();b.event.triggered=L;if(bz){bA[by]=bz}}}}return bv.result},dispatch:function(bH){bH=b.event.fix(bH||bd.event);var bD=((b._data(this,"events")||{})[bH.type]||[]),bC=bD.delegateCount,bx=[].slice.call(arguments,0),bE=!bH.exclusive&&!bH.namespace,bz=b.event.special[bH.type]||{},bv=[],bJ,bG,by,bA,bK,bI,bB,bw,e,bF,bL;bx[0]=bH;bH.delegateTarget=this;if(bz.preDispatch&&bz.preDispatch.call(this,bH)===false){return}if(bC&&!(bH.button&&bH.type==="click")){bA=b(this);bA.context=this.ownerDocument||this;for(by=bH.target;by!=this;by=by.parentNode||this){if(by.disabled!==true){bI={};bw=[];bA[0]=by;for(bJ=0;bJ<bC;bJ++){e=bD[bJ];bF=e.selector;if(bI[bF]===L){bI[bF]=(e.quick?j(by,e.quick):bA.is(bF))}if(bI[bF]){bw.push(e)}}if(bw.length){bv.push({elem:by,matches:bw})}}}}if(bD.length>bC){bv.push({elem:this,matches:bD.slice(bC)})}for(bJ=0;bJ<bv.length&&!bH.isPropagationStopped();bJ++){bB=bv[bJ];bH.currentTarget=bB.elem;for(bG=0;bG<bB.matches.length&&!bH.isImmediatePropagationStopped();bG++){e=bB.matches[bG];if(bE||(!bH.namespace&&!e.namespace)||bH.namespace_re&&bH.namespace_re.test(e.namespace)){bH.data=e.data;bH.handleObj=e;bK=((b.event.special[e.origType]||{}).handle||e.handler).apply(bB.elem,bx);if(bK!==L){bH.result=bK;if(bK===false){bH.preventDefault();bH.stopPropagation()}}}}}if(bz.postDispatch){bz.postDispatch.call(this,bH)}return bH.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(bv,e){if(bv.which==null){bv.which=e.charCode!=null?e.charCode:e.keyCode}return bv}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(bx,bw){var by,bz,e,bv=bw.button,bA=bw.fromElement;if(bx.pageX==null&&bw.clientX!=null){by=bx.target.ownerDocument||av;bz=by.documentElement;e=by.body;bx.pageX=bw.clientX+(bz&&bz.scrollLeft||e&&e.scrollLeft||0)-(bz&&bz.clientLeft||e&&e.clientLeft||0);bx.pageY=bw.clientY+(bz&&bz.scrollTop||e&&e.scrollTop||0)-(bz&&bz.clientTop||e&&e.clientTop||0)}if(!bx.relatedTarget&&bA){bx.relatedTarget=bA===bx.target?bw.toElement:bA}if(!bx.which&&bv!==L){bx.which=(bv&1?1:(bv&2?3:(bv&4?2:0)))}return bx}},fix:function(bw){if(bw[b.expando]){return bw}var bv,bz,e=bw,bx=b.event.fixHooks[bw.type]||{},by=bx.props?this.props.concat(bx.props):this.props;bw=b.Event(e);for(bv=by.length;bv;){bz=by[--bv];bw[bz]=e[bz]}if(!bw.target){bw.target=e.srcElement||av}if(bw.target.nodeType===3){bw.target=bw.target.parentNode}if(bw.metaKey===L){bw.metaKey=bw.ctrlKey}return bx.filter?bx.filter(bw,e):bw},special:{ready:{setup:b.bindReady},load:{noBubble:true},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(bw,bv,e){if(b.isWindow(this)){this.onbeforeunload=e}},teardown:function(bv,e){if(this.onbeforeunload===e){this.onbeforeunload=null}}}},simulate:function(bw,by,bx,bv){var bz=b.extend(new b.Event(),bx,{type:bw,isSimulated:true,originalEvent:{}});if(bv){b.event.trigger(bz,null,by)}else{b.event.dispatch.call(by,bz)}if(bz.isDefaultPrevented()){bx.preventDefault()}}};b.event.handle=b.event.dispatch;b.removeEvent=av.removeEventListener?function(bv,e,bw){if(bv.removeEventListener){bv.removeEventListener(e,bw,false)}}:function(bv,e,bw){if(bv.detachEvent){bv.detachEvent("on"+e,bw)}};b.Event=function(bv,e){if(!(this instanceof b.Event)){return new b.Event(bv,e)}if(bv&&bv.type){this.originalEvent=bv;this.type=bv.type;this.isDefaultPrevented=(bv.defaultPrevented||bv.returnValue===false||bv.getPreventDefault&&bv.getPreventDefault())?i:bl}else{this.type=bv}if(e){b.extend(this,e)}this.timeStamp=bv&&bv.timeStamp||b.now();this[b.expando]=true};function bl(){return false}function i(){return true}b.Event.prototype={preventDefault:function(){this.isDefaultPrevented=i;var bv=this.originalEvent;if(!bv){return}if(bv.preventDefault){bv.preventDefault()}else{bv.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=i;var bv=this.originalEvent;if(!bv){return}if(bv.stopPropagation){bv.stopPropagation()}bv.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=i;this.stopPropagation()},isDefaultPrevented:bl,isPropagationStopped:bl,isImmediatePropagationStopped:bl};b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(bv,e){b.event.special[bv]={delegateType:e,bindType:e,handle:function(bz){var bB=this,bA=bz.relatedTarget,by=bz.handleObj,bw=by.selector,bx;if(!bA||(bA!==bB&&!b.contains(bB,bA))){bz.type=by.origType;bx=by.handler.apply(this,arguments);bz.type=e}return bx}}});if(!b.support.submitBubbles){b.event.special.submit={setup:function(){if(b.nodeName(this,"form")){return false}b.event.add(this,"click._submit keypress._submit",function(bx){var bw=bx.target,bv=b.nodeName(bw,"input")||b.nodeName(bw,"button")?bw.form:L;if(bv&&!bv._submit_attached){b.event.add(bv,"submit._submit",function(e){e._submit_bubble=true});bv._submit_attached=true}})},postDispatch:function(e){if(e._submit_bubble){delete e._submit_bubble;if(this.parentNode&&!e.isTrigger){b.event.simulate("submit",this.parentNode,e,true)}}},teardown:function(){if(b.nodeName(this,"form")){return false}b.event.remove(this,"._submit")}}}if(!b.support.changeBubbles){b.event.special.change={setup:function(){if(be.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio"){b.event.add(this,"propertychange._change",function(e){if(e.originalEvent.propertyName==="checked"){this._just_changed=true}});b.event.add(this,"click._change",function(e){if(this._just_changed&&!e.isTrigger){this._just_changed=false;b.event.simulate("change",this,e,true)}})}return false}b.event.add(this,"beforeactivate._change",function(bw){var bv=bw.target;if(be.test(bv.nodeName)&&!bv._change_attached){b.event.add(bv,"change._change",function(e){if(this.parentNode&&!e.isSimulated&&!e.isTrigger){b.event.simulate("change",this.parentNode,e,true)}});bv._change_attached=true}})},handle:function(bv){var e=bv.target;if(this!==e||bv.isSimulated||bv.isTrigger||(e.type!=="radio"&&e.type!=="checkbox")){return bv.handleObj.handler.apply(this,arguments)}},teardown:function(){b.event.remove(this,"._change");return be.test(this.nodeName)}}}if(!b.support.focusinBubbles){b.each({focus:"focusin",blur:"focusout"},function(bx,e){var bv=0,bw=function(by){b.event.simulate(e,by.target,b.event.fix(by),true)};b.event.special[e]={setup:function(){if(bv++===0){av.addEventListener(bx,bw,true)}},teardown:function(){if(--bv===0){av.removeEventListener(bx,bw,true)}}}})}b.fn.extend({on:function(bw,e,bz,by,bv){var bA,bx;if(typeof bw==="object"){if(typeof e!=="string"){bz=bz||e;e=L}for(bx in bw){this.on(bx,e,bz,bw[bx],bv)}return this}if(bz==null&&by==null){by=e;bz=e=L}else{if(by==null){if(typeof e==="string"){by=bz;bz=L}else{by=bz;bz=e;e=L}}}if(by===false){by=bl}else{if(!by){return this}}if(bv===1){bA=by;by=function(bB){b().off(bB);return bA.apply(this,arguments)};by.guid=bA.guid||(bA.guid=b.guid++)}return this.each(function(){b.event.add(this,bw,by,bz,e)})},one:function(bv,e,bx,bw){return this.on(bv,e,bx,bw,1)},off:function(bw,e,by){if(bw&&bw.preventDefault&&bw.handleObj){var bv=bw.handleObj;b(bw.delegateTarget).off(bv.namespace?bv.origType+"."+bv.namespace:bv.origType,bv.selector,bv.handler);return this}if(typeof bw==="object"){for(var bx in bw){this.off(bx,e,bw[bx])}return this}if(e===false||typeof e==="function"){by=e;e=L}if(by===false){by=bl}return this.each(function(){b.event.remove(this,bw,by,e)})},bind:function(e,bw,bv){return this.on(e,null,bw,bv)},unbind:function(e,bv){return this.off(e,null,bv)},live:function(e,bw,bv){b(this.context).on(e,this.selector,bw,bv);return this},die:function(e,bv){b(this.context).off(e,this.selector||"**",bv);return this},delegate:function(e,bv,bx,bw){return this.on(bv,e,bx,bw)},undelegate:function(e,bv,bw){return arguments.length==1?this.off(e,"**"):this.off(bv,e,bw)},trigger:function(e,bv){return this.each(function(){b.event.trigger(e,bv,this)})},triggerHandler:function(e,bv){if(this[0]){return b.event.trigger(e,bv,this[0],true)}},toggle:function(bx){var bv=arguments,e=bx.guid||b.guid++,bw=0,by=function(bz){var bA=(b._data(this,"lastToggle"+bx.guid)||0)%bw;b._data(this,"lastToggle"+bx.guid,bA+1);bz.preventDefault();return bv[bA].apply(this,arguments)||false};by.guid=e;while(bw<bv.length){bv[bw++].guid=e}return this.click(by)},hover:function(e,bv){return this.mouseenter(e).mouseleave(bv||e)}});b.each(("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu").split(" "),function(bv,e){b.fn[e]=function(bx,bw){if(bw==null){bw=bx;bx=null}return arguments.length>0?this.on(e,null,bx,bw):this.trigger(e)};if(b.attrFn){b.attrFn[e]=true}if(aP.test(e)){b.event.fixHooks[e]=b.event.keyHooks}if(bg.test(e)){b.event.fixHooks[e]=b.event.mouseHooks}});
-/*!
- * Sizzle CSS Selector Engine
- *  Copyright 2011, The Dojo Foundation
- *  Released under the MIT, BSD, and GPL Licenses.
- *  More information: http://sizzlejs.com/
- */
-(function(){var bH=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,bC="sizcache"+(Math.random()+"").replace(".",""),bI=0,bL=Object.prototype.toString,bB=false,bA=true,bK=/\\/g,bO=/\r\n/g,bQ=/\W/;[0,0].sort(function(){bA=false;return 0});var by=function(bV,e,bY,bZ){bY=bY||[];e=e||av;var b1=e;if(e.nodeType!==1&&e.nodeType!==9){return[]}if(!bV||typeof bV!=="string"){return bY}var bS,b3,b6,bR,b2,b5,b4,bX,bU=true,bT=by.isXML(e),bW=[],b0=bV;do{bH.exec("");bS=bH.exec(b0);if(bS){b0=bS[3];bW.push(bS[1]);if(bS[2]){bR=bS[3];break}}}while(bS);if(bW.length>1&&bD.exec(bV)){if(bW.length===2&&bE.relative[bW[0]]){b3=bM(bW[0]+bW[1],e,bZ)}else{b3=bE.relative[bW[0]]?[e]:by(bW.shift(),e);while(bW.length){bV=bW.shift();if(bE.relative[bV]){bV+=bW.shift()}b3=bM(bV,b3,bZ)}}}else{if(!bZ&&bW.length>1&&e.nodeType===9&&!bT&&bE.match.ID.test(bW[0])&&!bE.match.ID.test(bW[bW.length-1])){b2=by.find(bW.shift(),e,bT);e=b2.expr?by.filter(b2.expr,b2.set)[0]:b2.set[0]}if(e){b2=bZ?{expr:bW.pop(),set:bF(bZ)}:by.find(bW.pop(),bW.length===1&&(bW[0]==="~"||bW[0]==="+")&&e.parentNode?e.parentNode:e,bT);b3=b2.expr?by.filter(b2.expr,b2.set):b2.set;if(bW.length>0){b6=bF(b3)}else{bU=false}while(bW.length){b5=bW.pop();b4=b5;if(!bE.relative[b5]){b5=""}else{b4=bW.pop()}if(b4==null){b4=e}bE.relative[b5](b6,b4,bT)}}else{b6=bW=[]}}if(!b6){b6=b3}if(!b6){by.error(b5||bV)}if(bL.call(b6)==="[object Array]"){if(!bU){bY.push.apply(bY,b6)}else{if(e&&e.nodeType===1){for(bX=0;b6[bX]!=null;bX++){if(b6[bX]&&(b6[bX]===true||b6[bX].nodeType===1&&by.contains(e,b6[bX]))){bY.push(b3[bX])}}}else{for(bX=0;b6[bX]!=null;bX++){if(b6[bX]&&b6[bX].nodeType===1){bY.push(b3[bX])}}}}}else{bF(b6,bY)}if(bR){by(bR,b1,bY,bZ);by.uniqueSort(bY)}return bY};by.uniqueSort=function(bR){if(bJ){bB=bA;bR.sort(bJ);if(bB){for(var e=1;e<bR.length;e++){if(bR[e]===bR[e-1]){bR.splice(e--,1)}}}}return bR};by.matches=function(e,bR){return by(e,null,null,bR)};by.matchesSelector=function(e,bR){return by(bR,null,null,[e]).length>0};by.find=function(bX,e,bY){var bW,bS,bU,bT,bV,bR;if(!bX){return[]}for(bS=0,bU=bE.order.length;bS<bU;bS++){bV=bE.order[bS];if((bT=bE.leftMatch[bV].exec(bX))){bR=bT[1];bT.splice(1,1);if(bR.substr(bR.length-1)!=="\\"){bT[1]=(bT[1]||"").replace(bK,"");bW=bE.find[bV](bT,e,bY);if(bW!=null){bX=bX.replace(bE.match[bV],"");break}}}}if(!bW){bW=typeof e.getElementsByTagName!=="undefined"?e.getElementsByTagName("*"):[]}return{set:bW,expr:bX}};by.filter=function(b1,b0,b4,bU){var bW,e,bZ,b6,b3,bR,bT,bV,b2,bS=b1,b5=[],bY=b0,bX=b0&&b0[0]&&by.isXML(b0[0]);while(b1&&b0.length){for(bZ in bE.filter){if((bW=bE.leftMatch[bZ].exec(b1))!=null&&bW[2]){bR=bE.filter[bZ];bT=bW[1];e=false;bW.splice(1,1);if(bT.substr(bT.length-1)==="\\"){continue}if(bY===b5){b5=[]}if(bE.preFilter[bZ]){bW=bE.preFilter[bZ](bW,bY,b4,b5,bU,bX);if(!bW){e=b6=true}else{if(bW===true){continue}}}if(bW){for(bV=0;(b3=bY[bV])!=null;bV++){if(b3){b6=bR(b3,bW,bV,bY);b2=bU^b6;if(b4&&b6!=null){if(b2){e=true}else{bY[bV]=false}}else{if(b2){b5.push(b3);e=true}}}}}if(b6!==L){if(!b4){bY=b5}b1=b1.replace(bE.match[bZ],"");if(!e){return[]}break}}}if(b1===bS){if(e==null){by.error(b1)}else{break}}bS=b1}return bY};by.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)};var bw=by.getText=function(bU){var bS,bT,e=bU.nodeType,bR="";if(e){if(e===1||e===9||e===11){if(typeof bU.textContent==="string"){return bU.textContent}else{if(typeof bU.innerText==="string"){return bU.innerText.replace(bO,"")}else{for(bU=bU.firstChild;bU;bU=bU.nextSibling){bR+=bw(bU)}}}}else{if(e===3||e===4){return bU.nodeValue}}}else{for(bS=0;(bT=bU[bS]);bS++){if(bT.nodeType!==8){bR+=bw(bT)}}}return bR};var bE=by.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(e){return e.getAttribute("href")},type:function(e){return e.getAttribute("type")}},relative:{"+":function(bW,bR){var bT=typeof bR==="string",bV=bT&&!bQ.test(bR),bX=bT&&!bV;if(bV){bR=bR.toLowerCase()}for(var bS=0,e=bW.length,bU;bS<e;bS++){if((bU=bW[bS])){while((bU=bU.previousSibling)&&bU.nodeType!==1){}bW[bS]=bX||bU&&bU.nodeName.toLowerCase()===bR?bU||false:bU===bR}}if(bX){by.filter(bR,bW,true)}},">":function(bW,bR){var bV,bU=typeof bR==="string",bS=0,e=bW.length;if(bU&&!bQ.test(bR)){bR=bR.toLowerCase();for(;bS<e;bS++){bV=bW[bS];if(bV){var bT=bV.parentNode;bW[bS]=bT.nodeName.toLowerCase()===bR?bT:false}}}else{for(;bS<e;bS++){bV=bW[bS];if(bV){bW[bS]=bU?bV.parentNode:bV.parentNode===bR}}if(bU){by.filter(bR,bW,true)}}},"":function(bT,bR,bV){var bU,bS=bI++,e=bN;if(typeof bR==="string"&&!bQ.test(bR)){bR=bR.toLowerCase();bU=bR;e=bv}e("parentNode",bR,bS,bT,bU,bV)},"~":function(bT,bR,bV){var bU,bS=bI++,e=bN;if(typeof bR==="string"&&!bQ.test(bR)){bR=bR.toLowerCase();bU=bR;e=bv}e("previousSibling",bR,bS,bT,bU,bV)}},find:{ID:function(bR,bS,bT){if(typeof bS.getElementById!=="undefined"&&!bT){var e=bS.getElementById(bR[1]);return e&&e.parentNode?[e]:[]}},NAME:function(bS,bV){if(typeof bV.getElementsByName!=="undefined"){var bR=[],bU=bV.getElementsByName(bS[1]);for(var bT=0,e=bU.length;bT<e;bT++){if(bU[bT].getAttribute("name")===bS[1]){bR.push(bU[bT])}}return bR.length===0?null:bR}},TAG:function(e,bR){if(typeof bR.getElementsByTagName!=="undefined"){return bR.getElementsByTagName(e[1])}}},preFilter:{CLASS:function(bT,bR,bS,e,bW,bX){bT=" "+bT[1].replace(bK,"")+" ";if(bX){return bT}for(var bU=0,bV;(bV=bR[bU])!=null;bU++){if(bV){if(bW^(bV.className&&(" "+bV.className+" ").replace(/[\t\n\r]/g," ").indexOf(bT)>=0)){if(!bS){e.push(bV)}}else{if(bS){bR[bU]=false}}}}return false},ID:function(e){return e[1].replace(bK,"")},TAG:function(bR,e){return bR[1].replace(bK,"").toLowerCase()},CHILD:function(e){if(e[1]==="nth"){if(!e[2]){by.error(e[0])}e[2]=e[2].replace(/^\+|\s*/g,"");var bR=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(e[2]==="even"&&"2n"||e[2]==="odd"&&"2n+1"||!/\D/.test(e[2])&&"0n+"+e[2]||e[2]);e[2]=(bR[1]+(bR[2]||1))-0;e[3]=bR[3]-0}else{if(e[2]){by.error(e[0])}}e[0]=bI++;return e},ATTR:function(bU,bR,bS,e,bV,bW){var bT=bU[1]=bU[1].replace(bK,"");if(!bW&&bE.attrMap[bT]){bU[1]=bE.attrMap[bT]}bU[4]=(bU[4]||bU[5]||"").replace(bK,"");if(bU[2]==="~="){bU[4]=" "+bU[4]+" "}return bU},PSEUDO:function(bU,bR,bS,e,bV){if(bU[1]==="not"){if((bH.exec(bU[3])||"").length>1||/^\w/.test(bU[3])){bU[3]=by(bU[3],null,null,bR)}else{var bT=by.filter(bU[3],bR,bS,true^bV);if(!bS){e.push.apply(e,bT)}return false}}else{if(bE.match.POS.test(bU[0])||bE.match.CHILD.test(bU[0])){return true}}return bU},POS:function(e){e.unshift(true);return e}},filters:{enabled:function(e){return e.disabled===false&&e.type!=="hidden"},disabled:function(e){return e.disabled===true},checked:function(e){return e.checked===true},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},parent:function(e){return !!e.firstChild},empty:function(e){return !e.firstChild},has:function(bS,bR,e){return !!by(e[3],bS).length},header:function(e){return(/h\d/i).test(e.nodeName)},text:function(bS){var e=bS.getAttribute("type"),bR=bS.type;return bS.nodeName.toLowerCase()==="input"&&"text"===bR&&(e===bR||e===null)},radio:function(e){return e.nodeName.toLowerCase()==="input"&&"radio"===e.type},checkbox:function(e){return e.nodeName.toLowerCase()==="input"&&"checkbox"===e.type},file:function(e){return e.nodeName.toLowerCase()==="input"&&"file"===e.type},password:function(e){return e.nodeName.toLowerCase()==="input"&&"password"===e.type},submit:function(bR){var e=bR.nodeName.toLowerCase();return(e==="input"||e==="button")&&"submit"===bR.type},image:function(e){return e.nodeName.toLowerCase()==="input"&&"image"===e.type},reset:function(bR){var e=bR.nodeName.toLowerCase();return(e==="input"||e==="button")&&"reset"===bR.type},button:function(bR){var e=bR.nodeName.toLowerCase();return e==="input"&&"button"===bR.type||e==="button"},input:function(e){return(/input|select|textarea|button/i).test(e.nodeName)},focus:function(e){return e===e.ownerDocument.activeElement}},setFilters:{first:function(bR,e){return e===0},last:function(bS,bR,e,bT){return bR===bT.length-1},even:function(bR,e){return e%2===0},odd:function(bR,e){return e%2===1},lt:function(bS,bR,e){return bR<e[3]-0},gt:function(bS,bR,e){return bR>e[3]-0},nth:function(bS,bR,e){return e[3]-0===bR},eq:function(bS,bR,e){return e[3]-0===bR}},filter:{PSEUDO:function(bS,bX,bW,bY){var e=bX[1],bR=bE.filters[e];if(bR){return bR(bS,bW,bX,bY)}else{if(e==="contains"){return(bS.textContent||bS.innerText||bw([bS])||"").indexOf(bX[3])>=0}else{if(e==="not"){var bT=bX[3];for(var bV=0,bU=bT.length;bV<bU;bV++){if(bT[bV]===bS){return false}}return true}else{by.error(e)}}}},CHILD:function(bS,bU){var bT,b0,bW,bZ,e,bV,bY,bX=bU[1],bR=bS;switch(bX){case"only":case"first":while((bR=bR.previousSibling)){if(bR.nodeType===1){return false}}if(bX==="first"){return true}bR=bS;case"last":while((bR=bR.nextSibling)){if(bR.nodeType===1){return false}}return true;case"nth":bT=bU[2];b0=bU[3];if(bT===1&&b0===0){return true}bW=bU[0];bZ=bS.parentNode;if(bZ&&(bZ[bC]!==bW||!bS.nodeIndex)){bV=0;for(bR=bZ.firstChild;bR;bR=bR.nextSibling){if(bR.nodeType===1){bR.nodeIndex=++bV}}bZ[bC]=bW}bY=bS.nodeIndex-b0;if(bT===0){return bY===0}else{return(bY%bT===0&&bY/bT>=0)}}},ID:function(bR,e){return bR.nodeType===1&&bR.getAttribute("id")===e},TAG:function(bR,e){return(e==="*"&&bR.nodeType===1)||!!bR.nodeName&&bR.nodeName.toLowerCase()===e},CLASS:function(bR,e){return(" "+(bR.className||bR.getAttribute("class"))+" ").indexOf(e)>-1},ATTR:function(bV,bT){var bS=bT[1],e=by.attr?by.attr(bV,bS):bE.attrHandle[bS]?bE.attrHandle[bS](bV):bV[bS]!=null?bV[bS]:bV.getAttribute(bS),bW=e+"",bU=bT[2],bR=bT[4];return e==null?bU==="!=":!bU&&by.attr?e!=null:bU==="="?bW===bR:bU==="*="?bW.indexOf(bR)>=0:bU==="~="?(" "+bW+" ").indexOf(bR)>=0:!bR?bW&&e!==false:bU==="!="?bW!==bR:bU==="^="?bW.indexOf(bR)===0:bU==="$="?bW.substr(bW.length-bR.length)===bR:bU==="|="?bW===bR||bW.substr(0,bR.length+1)===bR+"-":false},POS:function(bU,bR,bS,bV){var e=bR[2],bT=bE.setFilters[e];if(bT){return bT(bU,bS,bR,bV)}}}};var bD=bE.match.POS,bx=function(bR,e){return"\\"+(e-0+1)};for(var bz in bE.match){bE.match[bz]=new RegExp(bE.match[bz].source+(/(?![^\[]*\])(?![^\(]*\))/.source));bE.leftMatch[bz]=new RegExp(/(^(?:.|\r|\n)*?)/.source+bE.match[bz].source.replace(/\\(\d+)/g,bx))}bE.match.globalPOS=bD;var bF=function(bR,e){bR=Array.prototype.slice.call(bR,0);if(e){e.push.apply(e,bR);return e}return bR};try{Array.prototype.slice.call(av.documentElement.childNodes,0)[0].nodeType}catch(bP){bF=function(bU,bT){var bS=0,bR=bT||[];if(bL.call(bU)==="[object Array]"){Array.prototype.push.apply(bR,bU)}else{if(typeof bU.length==="number"){for(var e=bU.length;bS<e;bS++){bR.push(bU[bS])}}else{for(;bU[bS];bS++){bR.push(bU[bS])}}}return bR}}var bJ,bG;if(av.documentElement.compareDocumentPosition){bJ=function(bR,e){if(bR===e){bB=true;return 0}if(!bR.compareDocumentPosition||!e.compareDocumentPosition){return bR.compareDocumentPosition?-1:1}return bR.compareDocumentPosition(e)&4?-1:1}}else{bJ=function(bY,bX){if(bY===bX){bB=true;return 0}else{if(bY.sourceIndex&&bX.sourceIndex){return bY.sourceIndex-bX.sourceIndex}}var bV,bR,bS=[],e=[],bU=bY.parentNode,bW=bX.parentNode,bZ=bU;if(bU===bW){return bG(bY,bX)}else{if(!bU){return -1}else{if(!bW){return 1}}}while(bZ){bS.unshift(bZ);bZ=bZ.parentNode}bZ=bW;while(bZ){e.unshift(bZ);bZ=bZ.parentNode}bV=bS.length;bR=e.length;for(var bT=0;bT<bV&&bT<bR;bT++){if(bS[bT]!==e[bT]){return bG(bS[bT],e[bT])}}return bT===bV?bG(bY,e[bT],-1):bG(bS[bT],bX,1)};bG=function(bR,e,bS){if(bR===e){return bS}var bT=bR.nextSibling;while(bT){if(bT===e){return -1}bT=bT.nextSibling}return 1}}(function(){var bR=av.createElement("div"),bS="script"+(new Date()).getTime(),e=av.documentElement;bR.innerHTML="<a name='"+bS+"'/>";e.insertBefore(bR,e.firstChild);if(av.getElementById(bS)){bE.find.ID=function(bU,bV,bW){if(typeof bV.getElementById!=="undefined"&&!bW){var bT=bV.getElementById(bU[1]);return bT?bT.id===bU[1]||typeof bT.getAttributeNode!=="undefined"&&bT.getAttributeNode("id").nodeValue===bU[1]?[bT]:L:[]}};bE.filter.ID=function(bV,bT){var bU=typeof bV.getAttributeNode!=="undefined"&&bV.getAttributeNode("id");return bV.nodeType===1&&bU&&bU.nodeValue===bT}}e.removeChild(bR);e=bR=null})();(function(){var e=av.createElement("div");e.appendChild(av.createComment(""));if(e.getElementsByTagName("*").length>0){bE.find.TAG=function(bR,bV){var bU=bV.getElementsByTagName(bR[1]);if(bR[1]==="*"){var bT=[];for(var bS=0;bU[bS];bS++){if(bU[bS].nodeType===1){bT.push(bU[bS])}}bU=bT}return bU}}e.innerHTML="<a href='#'></a>";if(e.firstChild&&typeof e.firstChild.getAttribute!=="undefined"&&e.firstChild.getAttribute("href")!=="#"){bE.attrHandle.href=function(bR){return bR.getAttribute("href",2)}}e=null})();if(av.querySelectorAll){(function(){var e=by,bT=av.createElement("div"),bS="__sizzle__";bT.innerHTML="<p class='TEST'></p>";if(bT.querySelectorAll&&bT.querySelectorAll(".TEST").length===0){return}by=function(b4,bV,bZ,b3){bV=bV||av;if(!b3&&!by.isXML(bV)){var b2=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b4);if(b2&&(bV.nodeType===1||bV.nodeType===9)){if(b2[1]){return bF(bV.getElementsByTagName(b4),bZ)}else{if(b2[2]&&bE.find.CLASS&&bV.getElementsByClassName){return bF(bV.getElementsByClassName(b2[2]),bZ)}}}if(bV.nodeType===9){if(b4==="body"&&bV.body){return bF([bV.body],bZ)}else{if(b2&&b2[3]){var bY=bV.getElementById(b2[3]);if(bY&&bY.parentNode){if(bY.id===b2[3]){return bF([bY],bZ)}}else{return bF([],bZ)}}}try{return bF(bV.querySelectorAll(b4),bZ)}catch(b0){}}else{if(bV.nodeType===1&&bV.nodeName.toLowerCase()!=="object"){var bW=bV,bX=bV.getAttribute("id"),bU=bX||bS,b6=bV.parentNode,b5=/^\s*[+~]/.test(b4);if(!bX){bV.setAttribute("id",bU)}else{bU=bU.replace(/'/g,"\\$&")}if(b5&&b6){bV=bV.parentNode}try{if(!b5||b6){return bF(bV.querySelectorAll("[id='"+bU+"'] "+b4),bZ)}}catch(b1){}finally{if(!bX){bW.removeAttribute("id")}}}}}return e(b4,bV,bZ,b3)};for(var bR in e){by[bR]=e[bR]}bT=null})()}(function(){var e=av.documentElement,bS=e.matchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.msMatchesSelector;if(bS){var bU=!bS.call(av.createElement("div"),"div"),bR=false;try{bS.call(av.documentElement,"[test!='']:sizzle")}catch(bT){bR=true}by.matchesSelector=function(bW,bY){bY=bY.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!by.isXML(bW)){try{if(bR||!bE.match.PSEUDO.test(bY)&&!/!=/.test(bY)){var bV=bS.call(bW,bY);if(bV||!bU||bW.document&&bW.document.nodeType!==11){return bV}}}catch(bX){}}return by(bY,null,null,[bW]).length>0}}})();(function(){var e=av.createElement("div");e.innerHTML="<div class='test e'></div><div class='test'></div>";if(!e.getElementsByClassName||e.getElementsByClassName("e").length===0){return}e.lastChild.className="e";if(e.getElementsByClassName("e").length===1){return}bE.order.splice(1,0,"CLASS");bE.find.CLASS=function(bR,bS,bT){if(typeof bS.getElementsByClassName!=="undefined"&&!bT){return bS.getElementsByClassName(bR[1])}};e=null})();function bv(bR,bW,bV,bZ,bX,bY){for(var bT=0,bS=bZ.length;bT<bS;bT++){var e=bZ[bT];if(e){var bU=false;e=e[bR];while(e){if(e[bC]===bV){bU=bZ[e.sizset];break}if(e.nodeType===1&&!bY){e[bC]=bV;e.sizset=bT}if(e.nodeName.toLowerCase()===bW){bU=e;break}e=e[bR]}bZ[bT]=bU}}}function bN(bR,bW,bV,bZ,bX,bY){for(var bT=0,bS=bZ.length;bT<bS;bT++){var e=bZ[bT];if(e){var bU=false;e=e[bR];while(e){if(e[bC]===bV){bU=bZ[e.sizset];break}if(e.nodeType===1){if(!bY){e[bC]=bV;e.sizset=bT}if(typeof bW!=="string"){if(e===bW){bU=true;break}}else{if(by.filter(bW,[e]).length>0){bU=e;break}}}e=e[bR]}bZ[bT]=bU}}}if(av.documentElement.contains){by.contains=function(bR,e){return bR!==e&&(bR.contains?bR.contains(e):true)}}else{if(av.documentElement.compareDocumentPosition){by.contains=function(bR,e){return !!(bR.compareDocumentPosition(e)&16)}}else{by.contains=function(){return false}}}by.isXML=function(e){var bR=(e?e.ownerDocument||e:0).documentElement;return bR?bR.nodeName!=="HTML":false};var bM=function(bS,e,bW){var bV,bX=[],bU="",bY=e.nodeType?[e]:e;while((bV=bE.match.PSEUDO.exec(bS))){bU+=bV[0];bS=bS.replace(bE.match.PSEUDO,"")}bS=bE.relative[bS]?bS+"*":bS;for(var bT=0,bR=bY.length;bT<bR;bT++){by(bS,bY[bT],bX,bW)}return by.filter(bU,bX)};by.attr=b.attr;by.selectors.attrMap={};b.find=by;b.expr=by.selectors;b.expr[":"]=b.expr.filters;b.unique=by.uniqueSort;b.text=by.getText;b.isXMLDoc=by.isXML;b.contains=by.contains})();var ab=/Until$/,aq=/^(?:parents|prevUntil|prevAll)/,bb=/,/,bp=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,H=b.expr.match.globalPOS,ay={children:true,contents:true,next:true,prev:true};b.fn.extend({find:function(e){var bw=this,by,bv;if(typeof e!=="string"){return b(e).filter(function(){for(by=0,bv=bw.length;by<bv;by++){if(b.contains(bw[by],this)){return true}}})}var bx=this.pushStack("","find",e),bA,bB,bz;for(by=0,bv=this.length;by<bv;by++){bA=bx.length;b.find(e,this[by],bx);if(by>0){for(bB=bA;bB<bx.length;bB++){for(bz=0;bz<bA;bz++){if(bx[bz]===bx[bB]){bx.splice(bB--,1);break}}}}}return bx},has:function(bv){var e=b(bv);return this.filter(function(){for(var bx=0,bw=e.length;bx<bw;bx++){if(b.contains(this,e[bx])){return true}}})},not:function(e){return this.pushStack(aH(this,e,false),"not",e)},filter:function(e){return this.pushStack(aH(this,e,true),"filter",e)},is:function(e){return !!e&&(typeof e==="string"?H.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(by,bx){var bv=[],bw,e,bz=this[0];if(b.isArray(by)){var bB=1;while(bz&&bz.ownerDocument&&bz!==bx){for(bw=0;bw<by.length;bw++){if(b(bz).is(by[bw])){bv.push({selector:by[bw],elem:bz,level:bB})}}bz=bz.parentNode;bB++}return bv}var bA=H.test(by)||typeof by!=="string"?b(by,bx||this.context):0;for(bw=0,e=this.length;bw<e;bw++){bz=this[bw];while(bz){if(bA?bA.index(bz)>-1:b.find.matchesSelector(bz,by)){bv.push(bz);break}else{bz=bz.parentNode;if(!bz||!bz.ownerDocument||bz===bx||bz.nodeType===11){break}}}}bv=bv.length>1?b.unique(bv):bv;return this.pushStack(bv,"closest",by)},index:function(e){if(!e){return(this[0]&&this[0].parentNode)?this.prevAll().length:-1}if(typeof e==="string"){return b.inArray(this[0],b(e))}return b.inArray(e.jquery?e[0]:e,this)},add:function(e,bv){var bx=typeof e==="string"?b(e,bv):b.makeArray(e&&e.nodeType?[e]:e),bw=b.merge(this.get(),bx);return this.pushStack(B(bx[0])||B(bw[0])?bw:b.unique(bw))},andSelf:function(){return this.add(this.prevObject)}});function B(e){return !e||!e.parentNode||e.parentNode.nodeType===11}b.each({parent:function(bv){var e=bv.parentNode;return e&&e.nodeType!==11?e:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(bv,e,bw){return b.dir(bv,"parentNode",bw)},next:function(e){return b.nth(e,2,"nextSibling")},prev:function(e){return b.nth(e,2,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(bv,e,bw){return b.dir(bv,"nextSibling",bw)},prevUntil:function(bv,e,bw){return b.dir(bv,"previousSibling",bw)},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.makeArray(e.childNodes)}},function(e,bv){b.fn[e]=function(by,bw){var bx=b.map(this,bv,by);if(!ab.test(e)){bw=by}if(bw&&typeof bw==="string"){bx=b.filter(bw,bx)}bx=this.length>1&&!ay[e]?b.unique(bx):bx;if((this.length>1||bb.test(bw))&&aq.test(e)){bx=bx.reverse()}return this.pushStack(bx,e,P.call(arguments).join(","))}});b.extend({filter:function(bw,e,bv){if(bv){bw=":not("+bw+")"}return e.length===1?b.find.matchesSelector(e[0],bw)?[e[0]]:[]:b.find.matches(bw,e)},dir:function(bw,bv,by){var e=[],bx=bw[bv];while(bx&&bx.nodeType!==9&&(by===L||bx.nodeType!==1||!b(bx).is(by))){if(bx.nodeType===1){e.push(bx)}bx=bx[bv]}return e},nth:function(by,e,bw,bx){e=e||1;var bv=0;for(;by;by=by[bw]){if(by.nodeType===1&&++bv===e){break}}return by},sibling:function(bw,bv){var e=[];for(;bw;bw=bw.nextSibling){if(bw.nodeType===1&&bw!==bv){e.push(bw)}}return e}});function aH(bx,bw,e){bw=bw||0;if(b.isFunction(bw)){return b.grep(bx,function(bz,by){var bA=!!bw.call(bz,by,bz);return bA===e})}else{if(bw.nodeType){return b.grep(bx,function(bz,by){return(bz===bw)===e})}else{if(typeof bw==="string"){var bv=b.grep(bx,function(by){return by.nodeType===1});if(bp.test(bw)){return b.filter(bw,bv,!e)}else{bw=b.filter(bw,bv)}}}}return b.grep(bx,function(bz,by){return(b.inArray(bz,bw)>=0)===e})}function a(e){var bw=aS.split("|"),bv=e.createDocumentFragment();if(bv.createElement){while(bw.length){bv.createElement(bw.pop())}}return bv}var aS="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ah=/ jQuery\d+="(?:\d+|null)"/g,ar=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,d=/<([\w:]+)/,v=/<tbody/i,W=/<|&#?\w+;/,ae=/<(?:script|style)/i,O=/<(?:script|object|embed|option|style)/i,ai=new RegExp("<(?:"+aS+")[\\s/>]","i"),o=/checked\s*(?:[^=]|=\s*.checked.)/i,bn=/\/(java|ecma)script/i,aO=/^\s*<!(?:\[CDATA\[|\-\-)/,ax={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},ac=a(av);ax.optgroup=ax.option;ax.tbody=ax.tfoot=ax.colgroup=ax.caption=ax.thead;ax.th=ax.td;if(!b.support.htmlSerialize){ax._default=[1,"div<div>","</div>"]}b.fn.extend({text:function(e){return b.access(this,function(bv){return bv===L?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||av).createTextNode(bv))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e)){return this.each(function(bw){b(this).wrapAll(e.call(this,bw))})}if(this[0]){var bv=b(e,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){bv.insertBefore(this[0])}bv.map(function(){var bw=this;while(bw.firstChild&&bw.firstChild.nodeType===1){bw=bw.firstChild}return bw}).append(this)}return this},wrapInner:function(e){if(b.isFunction(e)){return this.each(function(bv){b(this).wrapInner(e.call(this,bv))})}return this.each(function(){var bv=b(this),bw=bv.contents();if(bw.length){bw.wrapAll(e)}else{bv.append(e)}})},wrap:function(e){var bv=b.isFunction(e);return this.each(function(bw){b(this).wrapAll(bv?e.call(this,bw):e)})},unwrap:function(){return this.parent().each(function(){if(!b.nodeName(this,"body")){b(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.appendChild(e)}})},prepend:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.insertBefore(e,this.firstChild)}})},before:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bv){this.parentNode.insertBefore(bv,this)})}else{if(arguments.length){var e=b.clean(arguments);e.push.apply(e,this.toArray());return this.pushStack(e,"before",arguments)}}},after:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bv){this.parentNode.insertBefore(bv,this.nextSibling)})}else{if(arguments.length){var e=this.pushStack(this,"after",arguments);e.push.apply(e,b.clean(arguments));return e}}},remove:function(e,bx){for(var bv=0,bw;(bw=this[bv])!=null;bv++){if(!e||b.filter(e,[bw]).length){if(!bx&&bw.nodeType===1){b.cleanData(bw.getElementsByTagName("*"));b.cleanData([bw])}if(bw.parentNode){bw.parentNode.removeChild(bw)}}}return this},empty:function(){for(var e=0,bv;(bv=this[e])!=null;e++){if(bv.nodeType===1){b.cleanData(bv.getElementsByTagName("*"))}while(bv.firstChild){bv.removeChild(bv.firstChild)}}return this},clone:function(bv,e){bv=bv==null?false:bv;e=e==null?bv:e;return this.map(function(){return b.clone(this,bv,e)})},html:function(e){return b.access(this,function(by){var bx=this[0]||{},bw=0,bv=this.length;if(by===L){return bx.nodeType===1?bx.innerHTML.replace(ah,""):null}if(typeof by==="string"&&!ae.test(by)&&(b.support.leadingWhitespace||!ar.test(by))&&!ax[(d.exec(by)||["",""])[1].toLowerCase()]){by=by.replace(R,"<$1></$2>");try{for(;bw<bv;bw++){bx=this[bw]||{};if(bx.nodeType===1){b.cleanData(bx.getElementsByTagName("*"));bx.innerHTML=by}}bx=0}catch(bz){}}if(bx){this.empty().append(by)}},null,e,arguments.length)},replaceWith:function(e){if(this[0]&&this[0].parentNode){if(b.isFunction(e)){return this.each(function(bx){var bw=b(this),bv=bw.html();bw.replaceWith(e.call(this,bx,bv))})}if(typeof e!=="string"){e=b(e).detach()}return this.each(function(){var bw=this.nextSibling,bv=this.parentNode;b(this).remove();if(bw){b(bw).before(e)}else{b(bv).append(e)}})}else{return this.length?this.pushStack(b(b.isFunction(e)?e():e),"replaceWith",e):this}},detach:function(e){return this.remove(e,true)},domManip:function(bB,bF,bE){var bx,by,bA,bD,bC=bB[0],bv=[];if(!b.support.checkClone&&arguments.length===3&&typeof bC==="string"&&o.test(bC)){return this.each(function(){b(this).domManip(bB,bF,bE,true)})}if(b.isFunction(bC)){return this.each(function(bH){var bG=b(this);bB[0]=bC.call(this,bH,bF?bG.html():L);bG.domManip(bB,bF,bE)})}if(this[0]){bD=bC&&bC.parentNode;if(b.support.parentNode&&bD&&bD.nodeType===11&&bD.childNodes.length===this.length){bx={fragment:bD}}else{bx=b.buildFragment(bB,this,bv)}bA=bx.fragment;if(bA.childNodes.length===1){by=bA=bA.firstChild}else{by=bA.firstChild}if(by){bF=bF&&b.nodeName(by,"tr");for(var bw=0,e=this.length,bz=e-1;bw<e;bw++){bE.call(bF?bc(this[bw],by):this[bw],bx.cacheable||(e>1&&bw<bz)?b.clone(bA,true,true):bA)}}if(bv.length){b.each(bv,function(bG,bH){if(bH.src){b.ajax({type:"GET",global:false,url:bH.src,async:false,dataType:"script"})}else{b.globalEval((bH.text||bH.textContent||bH.innerHTML||"").replace(aO,"/*$0*/"))}if(bH.parentNode){bH.parentNode.removeChild(bH)}})}}return this}});function bc(e,bv){return b.nodeName(e,"table")?(e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody"))):e}function s(bB,bv){if(bv.nodeType!==1||!b.hasData(bB)){return}var by,bx,e,bA=b._data(bB),bz=b._data(bv,bA),bw=bA.events;if(bw){delete bz.handle;bz.events={};for(by in bw){for(bx=0,e=bw[by].length;bx<e;bx++){b.event.add(bv,by,bw[by][bx])}}}if(bz.data){bz.data=b.extend({},bz.data)}}function aj(bv,e){var bw;if(e.nodeType!==1){return}if(e.clearAttributes){e.clearAttributes()}if(e.mergeAttributes){e.mergeAttributes(bv)}bw=e.nodeName.toLowerCase();if(bw==="object"){e.outerHTML=bv.outerHTML}else{if(bw==="input"&&(bv.type==="checkbox"||bv.type==="radio")){if(bv.checked){e.defaultChecked=e.checked=bv.checked}if(e.value!==bv.value){e.value=bv.value}}else{if(bw==="option"){e.selected=bv.defaultSelected}else{if(bw==="input"||bw==="textarea"){e.defaultValue=bv.defaultValue}else{if(bw==="script"&&e.text!==bv.text){e.text=bv.text}}}}}e.removeAttribute(b.expando);e.removeAttribute("_submit_attached");e.removeAttribute("_change_attached")}b.buildFragment=function(bz,bx,bv){var by,e,bw,bA,bB=bz[0];if(bx&&bx[0]){bA=bx[0].ownerDocument||bx[0]}if(!bA.createDocumentFragment){bA=av}if(bz.length===1&&typeof bB==="string"&&bB.length<512&&bA===av&&bB.charAt(0)==="<"&&!O.test(bB)&&(b.support.checkClone||!o.test(bB))&&(b.support.html5Clone||!ai.test(bB))){e=true;bw=b.fragments[bB];if(bw&&bw!==1){by=bw}}if(!by){by=bA.createDocumentFragment();b.clean(bz,bA,by,bv)}if(e){b.fragments[bB]=bw?by:1}return{fragment:by,cacheable:e}};b.fragments={};b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,bv){b.fn[e]=function(bw){var bz=[],bC=b(bw),bB=this.length===1&&this[0].parentNode;if(bB&&bB.nodeType===11&&bB.childNodes.length===1&&bC.length===1){bC[bv](this[0]);return this}else{for(var bA=0,bx=bC.length;bA<bx;bA++){var by=(bA>0?this.clone(true):this).get();b(bC[bA])[bv](by);bz=bz.concat(by)}return this.pushStack(bz,e,bC.selector)}}});function bh(e){if(typeof e.getElementsByTagName!=="undefined"){return e.getElementsByTagName("*")}else{if(typeof e.querySelectorAll!=="undefined"){return e.querySelectorAll("*")}else{return[]}}}function az(e){if(e.type==="checkbox"||e.type==="radio"){e.defaultChecked=e.checked}}function D(e){var bv=(e.nodeName||"").toLowerCase();if(bv==="input"){az(e)}else{if(bv!=="script"&&typeof e.getElementsByTagName!=="undefined"){b.grep(e.getElementsByTagName("input"),az)}}}function am(e){var bv=av.createElement("div");ac.appendChild(bv);bv.innerHTML=e.outerHTML;return bv.firstChild}b.extend({clone:function(by,bA,bw){var e,bv,bx,bz=b.support.html5Clone||b.isXMLDoc(by)||!ai.test("<"+by.nodeName+">")?by.cloneNode(true):am(by);if((!b.support.noCloneEvent||!b.support.noCloneChecked)&&(by.nodeType===1||by.nodeType===11)&&!b.isXMLDoc(by)){aj(by,bz);e=bh(by);bv=bh(bz);for(bx=0;e[bx];++bx){if(bv[bx]){aj(e[bx],bv[bx])}}}if(bA){s(by,bz);if(bw){e=bh(by);bv=bh(bz);for(bx=0;e[bx];++bx){s(e[bx],bv[bx])}}}e=bv=null;return bz},clean:function(bI,bw,bv,bx){var bA,bH,bD,bJ=[];bw=bw||av;if(typeof bw.createElement==="undefined"){bw=bw.ownerDocument||bw[0]&&bw[0].ownerDocument||av}for(var bE=0,bG;(bG=bI[bE])!=null;bE++){if(typeof bG==="number"){bG+=""}if(!bG){continue}if(typeof bG==="string"){if(!W.test(bG)){bG=bw.createTextNode(bG)}else{bG=bG.replace(R,"<$1></$2>");var bN=(d.exec(bG)||["",""])[1].toLowerCase(),bz=ax[bN]||ax._default,bK=bz[0],bB=bw.createElement("div"),bL=ac.childNodes,bM;if(bw===av){ac.appendChild(bB)}else{a(bw).appendChild(bB)}bB.innerHTML=bz[1]+bG+bz[2];while(bK--){bB=bB.lastChild}if(!b.support.tbody){var by=v.test(bG),e=bN==="table"&&!by?bB.firstChild&&bB.firstChild.childNodes:bz[1]==="<table>"&&!by?bB.childNodes:[];for(bD=e.length-1;bD>=0;--bD){if(b.nodeName(e[bD],"tbody")&&!e[bD].childNodes.length){e[bD].parentNode.removeChild(e[bD])}}}if(!b.support.leadingWhitespace&&ar.test(bG)){bB.insertBefore(bw.createTextNode(ar.exec(bG)[0]),bB.firstChild)}bG=bB.childNodes;if(bB){bB.parentNode.removeChild(bB);if(bL.length>0){bM=bL[bL.length-1];if(bM&&bM.parentNode){bM.parentNode.removeChild(bM)}}}}}var bF;if(!b.support.appendChecked){if(bG[0]&&typeof(bF=bG.length)==="number"){for(bD=0;bD<bF;bD++){D(bG[bD])}}else{D(bG)}}if(bG.nodeType){bJ.push(bG)}else{bJ=b.merge(bJ,bG)}}if(bv){bA=function(bO){return !bO.type||bn.test(bO.type)};for(bE=0;bJ[bE];bE++){bH=bJ[bE];if(bx&&b.nodeName(bH,"script")&&(!bH.type||bn.test(bH.type))){bx.push(bH.parentNode?bH.parentNode.removeChild(bH):bH)}else{if(bH.nodeType===1){var bC=b.grep(bH.getElementsByTagName("script"),bA);bJ.splice.apply(bJ,[bE+1,0].concat(bC))}bv.appendChild(bH)}}}return bJ},cleanData:function(bv){var by,bw,e=b.cache,bB=b.event.special,bA=b.support.deleteExpando;for(var bz=0,bx;(bx=bv[bz])!=null;bz++){if(bx.nodeName&&b.noData[bx.nodeName.toLowerCase()]){continue}bw=bx[b.expando];if(bw){by=e[bw];if(by&&by.events){for(var bC in by.events){if(bB[bC]){b.event.remove(bx,bC)}else{b.removeEvent(bx,bC,by.handle)}}if(by.handle){by.handle.elem=null}}if(bA){delete bx[b.expando]}else{if(bx.removeAttribute){bx.removeAttribute(b.expando)}}delete e[bw]}}}});var al=/alpha\([^)]*\)/i,au=/opacity=([^)]*)/,y=/([A-Z]|^ms)/g,bo=/^[\-+]?(?:\d*\.)?\d+$/i,a1=/^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,I=/^([\-+])=([\-+.\de]+)/,aE=/^margin/,a9={position:"absolute",visibility:"hidden",display:"block"},G=["Top","Right","Bottom","Left"],Z,aJ,aY;b.fn.css=function(e,bv){return b.access(this,function(bx,bw,by){return by!==L?b.style(bx,bw,by):b.css(bx,bw)},e,bv,arguments.length>1)};b.extend({cssHooks:{opacity:{get:function(bw,bv){if(bv){var e=Z(bw,"opacity");return e===""?"1":e}else{return bw.style.opacity}}}},cssNumber:{fillOpacity:true,fontWeight:true,lineHeight:true,opacity:true,orphans:true,widows:true,zIndex:true,zoom:true},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(bx,bw,bD,by){if(!bx||bx.nodeType===3||bx.nodeType===8||!bx.style){return}var bB,bC,bz=b.camelCase(bw),bv=bx.style,bE=b.cssHooks[bz];bw=b.cssProps[bz]||bz;if(bD!==L){bC=typeof bD;if(bC==="string"&&(bB=I.exec(bD))){bD=(+(bB[1]+1)*+bB[2])+parseFloat(b.css(bx,bw));bC="number"}if(bD==null||bC==="number"&&isNaN(bD)){return}if(bC==="number"&&!b.cssNumber[bz]){bD+="px"}if(!bE||!("set" in bE)||(bD=bE.set(bx,bD))!==L){try{bv[bw]=bD}catch(bA){}}}else{if(bE&&"get" in bE&&(bB=bE.get(bx,false,by))!==L){return bB}return bv[bw]}},css:function(by,bx,bv){var bw,e;bx=b.camelCase(bx);e=b.cssHooks[bx];bx=b.cssProps[bx]||bx;if(bx==="cssFloat"){bx="float"}if(e&&"get" in e&&(bw=e.get(by,true,bv))!==L){return bw}else{if(Z){return Z(by,bx)}}},swap:function(by,bx,bz){var e={},bw,bv;for(bv in bx){e[bv]=by.style[bv];by.style[bv]=bx[bv]}bw=bz.call(by);for(bv in bx){by.style[bv]=e[bv]}return bw}});b.curCSS=b.css;if(av.defaultView&&av.defaultView.getComputedStyle){aJ=function(bA,bw){var bv,bz,e,by,bx=bA.style;bw=bw.replace(y,"-$1").toLowerCase();if((bz=bA.ownerDocument.defaultView)&&(e=bz.getComputedStyle(bA,null))){bv=e.getPropertyValue(bw);if(bv===""&&!b.contains(bA.ownerDocument.documentElement,bA)){bv=b.style(bA,bw)}}if(!b.support.pixelMargin&&e&&aE.test(bw)&&a1.test(bv)){by=bx.width;bx.width=bv;bv=e.width;bx.width=by}return bv}}if(av.documentElement.currentStyle){aY=function(bz,bw){var bA,e,by,bv=bz.currentStyle&&bz.currentStyle[bw],bx=bz.style;if(bv==null&&bx&&(by=bx[bw])){bv=by}if(a1.test(bv)){bA=bx.left;e=bz.runtimeStyle&&bz.runtimeStyle.left;if(e){bz.runtimeStyle.left=bz.currentStyle.left}bx.left=bw==="fontSize"?"1em":bv;bv=bx.pixelLeft+"px";bx.left=bA;if(e){bz.runtimeStyle.left=e}}return bv===""?"auto":bv}}Z=aJ||aY;function af(by,bw,bv){var bz=bw==="width"?by.offsetWidth:by.offsetHeight,bx=bw==="width"?1:0,e=4;if(bz>0){if(bv!=="border"){for(;bx<e;bx+=2){if(!bv){bz-=parseFloat(b.css(by,"padding"+G[bx]))||0}if(bv==="margin"){bz+=parseFloat(b.css(by,bv+G[bx]))||0}else{bz-=parseFloat(b.css(by,"border"+G[bx]+"Width"))||0}}}return bz+"px"}bz=Z(by,bw);if(bz<0||bz==null){bz=by.style[bw]}if(a1.test(bz)){return bz}bz=parseFloat(bz)||0;if(bv){for(;bx<e;bx+=2){bz+=parseFloat(b.css(by,"padding"+G[bx]))||0;if(bv!=="padding"){bz+=parseFloat(b.css(by,"border"+G[bx]+"Width"))||0}if(bv==="margin"){bz+=parseFloat(b.css(by,bv+G[bx]))||0}}}return bz+"px"}b.each(["height","width"],function(bv,e){b.cssHooks[e]={get:function(by,bx,bw){if(bx){if(by.offsetWidth!==0){return af(by,e,bw)}else{return b.swap(by,a9,function(){return af(by,e,bw)})}}},set:function(bw,bx){return bo.test(bx)?bx+"px":bx}}});if(!b.support.opacity){b.cssHooks.opacity={get:function(bv,e){return au.test((e&&bv.currentStyle?bv.currentStyle.filter:bv.style.filter)||"")?(parseFloat(RegExp.$1)/100)+"":e?"1":""},set:function(by,bz){var bx=by.style,bv=by.currentStyle,e=b.isNumeric(bz)?"alpha(opacity="+bz*100+")":"",bw=bv&&bv.filter||bx.filter||"";bx.zoom=1;if(bz>=1&&b.trim(bw.replace(al,""))===""){bx.removeAttribute("filter");if(bv&&!bv.filter){return}}bx.filter=al.test(bw)?bw.replace(al,e):bw+" "+e}}}b(function(){if(!b.support.reliableMarginRight){b.cssHooks.marginRight={get:function(bv,e){return b.swap(bv,{display:"inline-block"},function(){if(e){return Z(bv,"margin-right")}else{return bv.style.marginRight}})}}}});if(b.expr&&b.expr.filters){b.expr.filters.hidden=function(bw){var bv=bw.offsetWidth,e=bw.offsetHeight;return(bv===0&&e===0)||(!b.support.reliableHiddenOffsets&&((bw.style&&bw.style.display)||b.css(bw,"display"))==="none")};b.expr.filters.visible=function(e){return !b.expr.filters.hidden(e)}}b.each({margin:"",padding:"",border:"Width"},function(e,bv){b.cssHooks[e+bv]={expand:function(by){var bx,bz=typeof by==="string"?by.split(" "):[by],bw={};for(bx=0;bx<4;bx++){bw[e+G[bx]+bv]=bz[bx]||bz[bx-2]||bz[0]}return bw}}});var k=/%20/g,ap=/\[\]$/,bs=/\r?\n/g,bq=/#.*$/,aD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,a0=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,aN=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,aR=/^(?:GET|HEAD)$/,c=/^\/\//,M=/\?/,a7=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,p=/^(?:select|textarea)/i,h=/\s+/,br=/([?&])_=[^&]*/,K=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,z=b.fn.load,aa={},q={},aF,r,aW=["*/"]+["*"];try{aF=bm.href}catch(aw){aF=av.createElement("a");aF.href="";aF=aF.href}r=K.exec(aF.toLowerCase())||[];function f(e){return function(by,bA){if(typeof by!=="string"){bA=by;by="*"}if(b.isFunction(bA)){var bx=by.toLowerCase().split(h),bw=0,bz=bx.length,bv,bB,bC;for(;bw<bz;bw++){bv=bx[bw];bC=/^\+/.test(bv);if(bC){bv=bv.substr(1)||"*"}bB=e[bv]=e[bv]||[];bB[bC?"unshift":"push"](bA)}}}}function aX(bv,bE,bz,bD,bB,bx){bB=bB||bE.dataTypes[0];bx=bx||{};bx[bB]=true;var bA=bv[bB],bw=0,e=bA?bA.length:0,by=(bv===aa),bC;for(;bw<e&&(by||!bC);bw++){bC=bA[bw](bE,bz,bD);if(typeof bC==="string"){if(!by||bx[bC]){bC=L}else{bE.dataTypes.unshift(bC);bC=aX(bv,bE,bz,bD,bC,bx)}}}if((by||!bC)&&!bx["*"]){bC=aX(bv,bE,bz,bD,"*",bx)}return bC}function an(bw,bx){var bv,e,by=b.ajaxSettings.flatOptions||{};for(bv in bx){if(bx[bv]!==L){(by[bv]?bw:(e||(e={})))[bv]=bx[bv]}}if(e){b.extend(true,bw,e)}}b.fn.extend({load:function(bw,bz,bA){if(typeof bw!=="string"&&z){return z.apply(this,arguments)}else{if(!this.length){return this}}var by=bw.indexOf(" ");if(by>=0){var e=bw.slice(by,bw.length);bw=bw.slice(0,by)}var bx="GET";if(bz){if(b.isFunction(bz)){bA=bz;bz=L}else{if(typeof bz==="object"){bz=b.param(bz,b.ajaxSettings.traditional);bx="POST"}}}var bv=this;b.ajax({url:bw,type:bx,dataType:"html",data:bz,complete:function(bC,bB,bD){bD=bC.responseText;if(bC.isResolved()){bC.done(function(bE){bD=bE});bv.html(e?b("<div>").append(bD.replace(a7,"")).find(e):bD)}if(bA){bv.each(bA,[bD,bB,bC])}}});return this},serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?b.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||p.test(this.nodeName)||a0.test(this.type))}).map(function(e,bv){var bw=b(this).val();return bw==null?null:b.isArray(bw)?b.map(bw,function(by,bx){return{name:bv.name,value:by.replace(bs,"\r\n")}}):{name:bv.name,value:bw.replace(bs,"\r\n")}}).get()}});b.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,bv){b.fn[bv]=function(bw){return this.on(bv,bw)}});b.each(["get","post"],function(e,bv){b[bv]=function(bw,by,bz,bx){if(b.isFunction(by)){bx=bx||bz;bz=by;by=L}return b.ajax({type:bv,url:bw,data:by,success:bz,dataType:bx})}});b.extend({getScript:function(e,bv){return b.get(e,L,bv,"script")},getJSON:function(e,bv,bw){return b.get(e,bv,bw,"json")},ajaxSetup:function(bv,e){if(e){an(bv,b.ajaxSettings)}else{e=bv;bv=b.ajaxSettings}an(bv,e);return bv},ajaxSettings:{url:aF,isLocal:aN.test(r[1]),global:true,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:true,async:true,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":aW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":bd.String,"text html":true,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{context:true,url:true}},ajaxPrefilter:f(aa),ajaxTransport:f(q),ajax:function(bz,bx){if(typeof bz==="object"){bx=bz;bz=L}bx=bx||{};var bD=b.ajaxSetup({},bx),bS=bD.context||bD,bG=bS!==bD&&(bS.nodeType||bS instanceof b)?b(bS):b.event,bR=b.Deferred(),bN=b.Callbacks("once memory"),bB=bD.statusCode||{},bC,bH={},bO={},bQ,by,bL,bE,bI,bA=0,bw,bK,bJ={readyState:0,setRequestHeader:function(bT,bU){if(!bA){var e=bT.toLowerCase();bT=bO[e]=bO[e]||bT;bH[bT]=bU}return this},getAllResponseHeaders:function(){return bA===2?bQ:null},getResponseHeader:function(bT){var e;if(bA===2){if(!by){by={};while((e=aD.exec(bQ))){by[e[1].toLowerCase()]=e[2]}}e=by[bT.toLowerCase()]}return e===L?null:e},overrideMimeType:function(e){if(!bA){bD.mimeType=e}return this},abort:function(e){e=e||"abort";if(bL){bL.abort(e)}bF(0,e);return this}};function bF(bZ,bU,b0,bW){if(bA===2){return}bA=2;if(bE){clearTimeout(bE)}bL=L;bQ=bW||"";bJ.readyState=bZ>0?4:0;var bT,b4,b3,bX=bU,bY=b0?bk(bD,bJ,b0):L,bV,b2;if(bZ>=200&&bZ<300||bZ===304){if(bD.ifModified){if((bV=bJ.getResponseHeader("Last-Modified"))){b.lastModified[bC]=bV}if((b2=bJ.getResponseHeader("Etag"))){b.etag[bC]=b2}}if(bZ===304){bX="notmodified";bT=true}else{try{b4=F(bD,bY);bX="success";bT=true}catch(b1){bX="parsererror";b3=b1}}}else{b3=bX;if(!bX||bZ){bX="error";if(bZ<0){bZ=0}}}bJ.status=bZ;bJ.statusText=""+(bU||bX);if(bT){bR.resolveWith(bS,[b4,bX,bJ])}else{bR.rejectWith(bS,[bJ,bX,b3])}bJ.statusCode(bB);bB=L;if(bw){bG.trigger("ajax"+(bT?"Success":"Error"),[bJ,bD,bT?b4:b3])}bN.fireWith(bS,[bJ,bX]);if(bw){bG.trigger("ajaxComplete",[bJ,bD]);if(!(--b.active)){b.event.trigger("ajaxStop")}}}bR.promise(bJ);bJ.success=bJ.done;bJ.error=bJ.fail;bJ.complete=bN.add;bJ.statusCode=function(bT){if(bT){var e;if(bA<2){for(e in bT){bB[e]=[bB[e],bT[e]]}}else{e=bT[bJ.status];bJ.then(e,e)}}return this};bD.url=((bz||bD.url)+"").replace(bq,"").replace(c,r[1]+"//");bD.dataTypes=b.trim(bD.dataType||"*").toLowerCase().split(h);if(bD.crossDomain==null){bI=K.exec(bD.url.toLowerCase());bD.crossDomain=!!(bI&&(bI[1]!=r[1]||bI[2]!=r[2]||(bI[3]||(bI[1]==="http:"?80:443))!=(r[3]||(r[1]==="http:"?80:443))))}if(bD.data&&bD.processData&&typeof bD.data!=="string"){bD.data=b.param(bD.data,bD.traditional)}aX(aa,bD,bx,bJ);if(bA===2){return false}bw=bD.global;bD.type=bD.type.toUpperCase();bD.hasContent=!aR.test(bD.type);if(bw&&b.active++===0){b.event.trigger("ajaxStart")}if(!bD.hasContent){if(bD.data){bD.url+=(M.test(bD.url)?"&":"?")+bD.data;delete bD.data}bC=bD.url;if(bD.cache===false){var bv=b.now(),bP=bD.url.replace(br,"$1_="+bv);bD.url=bP+((bP===bD.url)?(M.test(bD.url)?"&":"?")+"_="+bv:"")}}if(bD.data&&bD.hasContent&&bD.contentType!==false||bx.contentType){bJ.setRequestHeader("Content-Type",bD.contentType)}if(bD.ifModified){bC=bC||bD.url;if(b.lastModified[bC]){bJ.setRequestHeader("If-Modified-Since",b.lastModified[bC])}if(b.etag[bC]){bJ.setRequestHeader("If-None-Match",b.etag[bC])}}bJ.setRequestHeader("Accept",bD.dataTypes[0]&&bD.accepts[bD.dataTypes[0]]?bD.accepts[bD.dataTypes[0]]+(bD.dataTypes[0]!=="*"?", "+aW+"; q=0.01":""):bD.accepts["*"]);for(bK in bD.headers){bJ.setRequestHeader(bK,bD.headers[bK])}if(bD.beforeSend&&(bD.beforeSend.call(bS,bJ,bD)===false||bA===2)){bJ.abort();return false}for(bK in {success:1,error:1,complete:1}){bJ[bK](bD[bK])}bL=aX(q,bD,bx,bJ);if(!bL){bF(-1,"No Transport")}else{bJ.readyState=1;if(bw){bG.trigger("ajaxSend",[bJ,bD])}if(bD.async&&bD.timeout>0){bE=setTimeout(function(){bJ.abort("timeout")},bD.timeout)}try{bA=1;bL.send(bH,bF)}catch(bM){if(bA<2){bF(-1,bM)}else{throw bM}}}return bJ},param:function(e,bw){var bv=[],by=function(bz,bA){bA=b.isFunction(bA)?bA():bA;bv[bv.length]=encodeURIComponent(bz)+"="+encodeURIComponent(bA)};if(bw===L){bw=b.ajaxSettings.traditional}if(b.isArray(e)||(e.jquery&&!b.isPlainObject(e))){b.each(e,function(){by(this.name,this.value)})}else{for(var bx in e){u(bx,e[bx],bw,by)}}return bv.join("&").replace(k,"+")}});function u(bw,by,bv,bx){if(b.isArray(by)){b.each(by,function(bA,bz){if(bv||ap.test(bw)){bx(bw,bz)}else{u(bw+"["+(typeof bz==="object"?bA:"")+"]",bz,bv,bx)}})}else{if(!bv&&b.type(by)==="object"){for(var e in by){u(bw+"["+e+"]",by[e],bv,bx)}}else{bx(bw,by)}}}b.extend({active:0,lastModified:{},etag:{}});function bk(bD,bC,bz){var bv=bD.contents,bB=bD.dataTypes,bw=bD.responseFields,by,bA,bx,e;for(bA in bw){if(bA in bz){bC[bw[bA]]=bz[bA]}}while(bB[0]==="*"){bB.shift();if(by===L){by=bD.mimeType||bC.getResponseHeader("content-type")}}if(by){for(bA in bv){if(bv[bA]&&bv[bA].test(by)){bB.unshift(bA);break}}}if(bB[0] in bz){bx=bB[0]}else{for(bA in bz){if(!bB[0]||bD.converters[bA+" "+bB[0]]){bx=bA;break}if(!e){e=bA}}bx=bx||e}if(bx){if(bx!==bB[0]){bB.unshift(bx)}return bz[bx]}}function F(bH,bz){if(bH.dataFilter){bz=bH.dataFilter(bz,bH.dataType)}var bD=bH.dataTypes,bG={},bA,bE,bw=bD.length,bB,bC=bD[0],bx,by,bF,bv,e;for(bA=1;bA<bw;bA++){if(bA===1){for(bE in bH.converters){if(typeof bE==="string"){bG[bE.toLowerCase()]=bH.converters[bE]}}}bx=bC;bC=bD[bA];if(bC==="*"){bC=bx}else{if(bx!=="*"&&bx!==bC){by=bx+" "+bC;bF=bG[by]||bG["* "+bC];if(!bF){e=L;for(bv in bG){bB=bv.split(" ");if(bB[0]===bx||bB[0]==="*"){e=bG[bB[1]+" "+bC];if(e){bv=bG[bv];if(bv===true){bF=e}else{if(e===true){bF=bv}}break}}}}if(!(bF||e)){b.error("No conversion from "+by.replace(" "," to "))}if(bF!==true){bz=bF?bF(bz):e(bv(bz))}}}}return bz}var aC=b.now(),t=/(\=)\?(&|$)|\?\?/i;b.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return b.expando+"_"+(aC++)}});b.ajaxPrefilter("json jsonp",function(bD,bA,bC){var bx=(typeof bD.data==="string")&&/^application\/x\-www\-form\-urlencoded/.test(bD.contentType);if(bD.dataTypes[0]==="jsonp"||bD.jsonp!==false&&(t.test(bD.url)||bx&&t.test(bD.data))){var bB,bw=bD.jsonpCallback=b.isFunction(bD.jsonpCallback)?bD.jsonpCallback():bD.jsonpCallback,bz=bd[bw],e=bD.url,by=bD.data,bv="$1"+bw+"$2";if(bD.jsonp!==false){e=e.replace(t,bv);if(bD.url===e){if(bx){by=by.replace(t,bv)}if(bD.data===by){e+=(/\?/.test(e)?"&":"?")+bD.jsonp+"="+bw}}}bD.url=e;bD.data=by;bd[bw]=function(bE){bB=[bE]};bC.always(function(){bd[bw]=bz;if(bB&&b.isFunction(bz)){bd[bw](bB[0])}});bD.converters["script json"]=function(){if(!bB){b.error(bw+" was not called")}return bB[0]};bD.dataTypes[0]="json";return"script"}});b.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){b.globalEval(e);return e}}});b.ajaxPrefilter("script",function(e){if(e.cache===L){e.cache=false}if(e.crossDomain){e.type="GET";e.global=false}});b.ajaxTransport("script",function(bw){if(bw.crossDomain){var e,bv=av.head||av.getElementsByTagName("head")[0]||av.documentElement;return{send:function(bx,by){e=av.createElement("script");e.async="async";if(bw.scriptCharset){e.charset=bw.scriptCharset}e.src=bw.url;e.onload=e.onreadystatechange=function(bA,bz){if(bz||!e.readyState||/loaded|complete/.test(e.readyState)){e.onload=e.onreadystatechange=null;if(bv&&e.parentNode){bv.removeChild(e)}e=L;if(!bz){by(200,"success")}}};bv.insertBefore(e,bv.firstChild)},abort:function(){if(e){e.onload(0,1)}}}}});var A=bd.ActiveXObject?function(){for(var e in N){N[e](0,1)}}:false,x=0,N;function aM(){try{return new bd.XMLHttpRequest()}catch(bv){}}function ak(){try{return new bd.ActiveXObject("Microsoft.XMLHTTP")}catch(bv){}}b.ajaxSettings.xhr=bd.ActiveXObject?function(){return !this.isLocal&&aM()||ak()}:aM;(function(e){b.extend(b.support,{ajax:!!e,cors:!!e&&("withCredentials" in e)})})(b.ajaxSettings.xhr());if(b.support.ajax){b.ajaxTransport(function(e){if(!e.crossDomain||b.support.cors){var bv;return{send:function(bB,bw){var bA=e.xhr(),bz,by;if(e.username){bA.open(e.type,e.url,e.async,e.username,e.password)}else{bA.open(e.type,e.url,e.async)}if(e.xhrFields){for(by in e.xhrFields){bA[by]=e.xhrFields[by]}}if(e.mimeType&&bA.overrideMimeType){bA.overrideMimeType(e.mimeType)}if(!e.crossDomain&&!bB["X-Requested-With"]){bB["X-Requested-With"]="XMLHttpRequest"}try{for(by in bB){bA.setRequestHeader(by,bB[by])}}catch(bx){}bA.send((e.hasContent&&e.data)||null);bv=function(bK,bE){var bF,bD,bC,bI,bH;try{if(bv&&(bE||bA.readyState===4)){bv=L;if(bz){bA.onreadystatechange=b.noop;if(A){delete N[bz]}}if(bE){if(bA.readyState!==4){bA.abort()}}else{bF=bA.status;bC=bA.getAllResponseHeaders();bI={};bH=bA.responseXML;if(bH&&bH.documentElement){bI.xml=bH}try{bI.text=bA.responseText}catch(bK){}try{bD=bA.statusText}catch(bJ){bD=""}if(!bF&&e.isLocal&&!e.crossDomain){bF=bI.text?200:404}else{if(bF===1223){bF=204}}}}}catch(bG){if(!bE){bw(-1,bG)}}if(bI){bw(bF,bD,bI,bC)}};if(!e.async||bA.readyState===4){bv()}else{bz=++x;if(A){if(!N){N={};b(bd).unload(A)}N[bz]=bv}bA.onreadystatechange=bv}},abort:function(){if(bv){bv(0,1)}}}}})}var Q={},ba,m,aB=/^(?:toggle|show|hide)$/,aU=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,a4,aI=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],a5;b.fn.extend({show:function(bx,bA,bz){var bw,by;if(bx||bx===0){return this.animate(a2("show",3),bx,bA,bz)}else{for(var bv=0,e=this.length;bv<e;bv++){bw=this[bv];if(bw.style){by=bw.style.display;if(!b._data(bw,"olddisplay")&&by==="none"){by=bw.style.display=""}if((by===""&&b.css(bw,"display")==="none")||!b.contains(bw.ownerDocument.documentElement,bw)){b._data(bw,"olddisplay",w(bw.nodeName))}}}for(bv=0;bv<e;bv++){bw=this[bv];if(bw.style){by=bw.style.display;if(by===""||by==="none"){bw.style.display=b._data(bw,"olddisplay")||""}}}return this}},hide:function(bx,bA,bz){if(bx||bx===0){return this.animate(a2("hide",3),bx,bA,bz)}else{var bw,by,bv=0,e=this.length;for(;bv<e;bv++){bw=this[bv];if(bw.style){by=b.css(bw,"display");if(by!=="none"&&!b._data(bw,"olddisplay")){b._data(bw,"olddisplay",by)}}}for(bv=0;bv<e;bv++){if(this[bv].style){this[bv].style.display="none"}}return this}},_toggle:b.fn.toggle,toggle:function(bw,bv,bx){var e=typeof bw==="boolean";if(b.isFunction(bw)&&b.isFunction(bv)){this._toggle.apply(this,arguments)}else{if(bw==null||e){this.each(function(){var by=e?bw:b(this).is(":hidden");b(this)[by?"show":"hide"]()})}else{this.animate(a2("toggle",3),bw,bv,bx)}}return this},fadeTo:function(e,bx,bw,bv){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:bx},e,bw,bv)},animate:function(bz,bw,by,bx){var e=b.speed(bw,by,bx);if(b.isEmptyObject(bz)){return this.each(e.complete,[false])}bz=b.extend({},bz);function bv(){if(e.queue===false){b._mark(this)}var bE=b.extend({},e),bL=this.nodeType===1,bJ=bL&&b(this).is(":hidden"),bB,bG,bD,bK,bN,bF,bI,bC,bH,bM,bA;bE.animatedProperties={};for(bD in bz){bB=b.camelCase(bD);if(bD!==bB){bz[bB]=bz[bD];delete bz[bD]}if((bN=b.cssHooks[bB])&&"expand" in bN){bF=bN.expand(bz[bB]);delete bz[bB];for(bD in bF){if(!(bD in bz)){bz[bD]=bF[bD]}}}}for(bB in bz){bG=bz[bB];if(b.isArray(bG)){bE.animatedProperties[bB]=bG[1];bG=bz[bB]=bG[0]}else{bE.animatedProperties[bB]=bE.specialEasing&&bE.specialEasing[bB]||bE.easing||"swing"}if(bG==="hide"&&bJ||bG==="show"&&!bJ){return bE.complete.call(this)}if(bL&&(bB==="height"||bB==="width")){bE.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(b.css(this,"display")==="inline"&&b.css(this,"float")==="none"){if(!b.support.inlineBlockNeedsLayout||w(this.nodeName)==="inline"){this.style.display="inline-block"}else{this.style.zoom=1}}}}if(bE.overflow!=null){this.style.overflow="hidden"}for(bD in bz){bK=new b.fx(this,bE,bD);bG=bz[bD];if(aB.test(bG)){bA=b._data(this,"toggle"+bD)||(bG==="toggle"?bJ?"show":"hide":0);if(bA){b._data(this,"toggle"+bD,bA==="show"?"hide":"show");bK[bA]()}else{bK[bG]()}}else{bI=aU.exec(bG);bC=bK.cur();if(bI){bH=parseFloat(bI[2]);bM=bI[3]||(b.cssNumber[bD]?"":"px");if(bM!=="px"){b.style(this,bD,(bH||1)+bM);bC=((bH||1)/bK.cur())*bC;b.style(this,bD,bC+bM)}if(bI[1]){bH=((bI[1]==="-="?-1:1)*bH)+bC}bK.custom(bC,bH,bM)}else{bK.custom(bC,bG,"")}}}return true}return e.queue===false?this.each(bv):this.queue(e.queue,bv)},stop:function(bw,bv,e){if(typeof bw!=="string"){e=bv;bv=bw;bw=L}if(bv&&bw!==false){this.queue(bw||"fx",[])}return this.each(function(){var bx,by=false,bA=b.timers,bz=b._data(this);if(!e){b._unmark(true,this)}function bB(bE,bF,bD){var bC=bF[bD];b.removeData(bE,bD,true);bC.stop(e)}if(bw==null){for(bx in bz){if(bz[bx]&&bz[bx].stop&&bx.indexOf(".run")===bx.length-4){bB(this,bz,bx)}}}else{if(bz[bx=bw+".run"]&&bz[bx].stop){bB(this,bz,bx)}}for(bx=bA.length;bx--;){if(bA[bx].elem===this&&(bw==null||bA[bx].queue===bw)){if(e){bA[bx](true)}else{bA[bx].saveState()}by=true;bA.splice(bx,1)}}if(!(e&&by)){b.dequeue(this,bw)}})}});function bi(){setTimeout(at,0);return(a5=b.now())}function at(){a5=L}function a2(bv,e){var bw={};b.each(aI.concat.apply([],aI.slice(0,e)),function(){bw[this]=bv});return bw}b.each({slideDown:a2("show",1),slideUp:a2("hide",1),slideToggle:a2("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,bv){b.fn[e]=function(bw,by,bx){return this.animate(bv,bw,by,bx)}});b.extend({speed:function(bw,bx,bv){var e=bw&&typeof bw==="object"?b.extend({},bw):{complete:bv||!bv&&bx||b.isFunction(bw)&&bw,duration:bw,easing:bv&&bx||bx&&!b.isFunction(bx)&&bx};e.duration=b.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in b.fx.speeds?b.fx.speeds[e.duration]:b.fx.speeds._default;if(e.queue==null||e.queue===true){e.queue="fx"}e.old=e.complete;e.complete=function(by){if(b.isFunction(e.old)){e.old.call(this)}if(e.queue){b.dequeue(this,e.queue)}else{if(by!==false){b._unmark(this)}}};return e},easing:{linear:function(e){return e},swing:function(e){return(-Math.cos(e*Math.PI)/2)+0.5}},timers:[],fx:function(bv,e,bw){this.options=e;this.elem=bv;this.prop=bw;e.orig=e.orig||{}}});b.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(b.fx.step[this.prop]||b.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var e,bv=b.css(this.elem,this.prop);return isNaN(e=parseFloat(bv))?!bv||bv==="auto"?0:bv:e},custom:function(bz,by,bx){var e=this,bw=b.fx;this.startTime=a5||bi();this.end=by;this.now=this.start=bz;this.pos=this.state=0;this.unit=bx||this.unit||(b.cssNumber[this.prop]?"":"px");function bv(bA){return e.step(bA)}bv.queue=this.options.queue;bv.elem=this.elem;bv.saveState=function(){if(b._data(e.elem,"fxshow"+e.prop)===L){if(e.options.hide){b._data(e.elem,"fxshow"+e.prop,e.start)}else{if(e.options.show){b._data(e.elem,"fxshow"+e.prop,e.end)}}}};if(bv()&&b.timers.push(bv)&&!a4){a4=setInterval(bw.tick,bw.interval)}},show:function(){var e=b._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=e||b.style(this.elem,this.prop);this.options.show=true;if(e!==L){this.custom(this.cur(),e)}else{this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur())}b(this.elem).show()},hide:function(){this.options.orig[this.prop]=b._data(this.elem,"fxshow"+this.prop)||b.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(by){var bA,bB,bv,bx=a5||bi(),e=true,bz=this.elem,bw=this.options;if(by||bx>=bw.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();bw.animatedProperties[this.prop]=true;for(bA in bw.animatedProperties){if(bw.animatedProperties[bA]!==true){e=false}}if(e){if(bw.overflow!=null&&!b.support.shrinkWrapBlocks){b.each(["","X","Y"],function(bC,bD){bz.style["overflow"+bD]=bw.overflow[bC]})}if(bw.hide){b(bz).hide()}if(bw.hide||bw.show){for(bA in bw.animatedProperties){b.style(bz,bA,bw.orig[bA]);b.removeData(bz,"fxshow"+bA,true);b.removeData(bz,"toggle"+bA,true)}}bv=bw.complete;if(bv){bw.complete=false;bv.call(bz)}}return false}else{if(bw.duration==Infinity){this.now=bx}else{bB=bx-this.startTime;this.state=bB/bw.duration;this.pos=b.easing[bw.animatedProperties[this.prop]](this.state,bB,0,1,bw.duration);this.now=this.start+((this.end-this.start)*this.pos)}this.update()}return true}};b.extend(b.fx,{tick:function(){var bw,bv=b.timers,e=0;for(;e<bv.length;e++){bw=bv[e];if(!bw()&&bv[e]===bw){bv.splice(e--,1)}}if(!bv.length){b.fx.stop()}},interval:13,stop:function(){clearInterval(a4);a4=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(e){b.style(e.elem,"opacity",e.now)},_default:function(e){if(e.elem.style&&e.elem.style[e.prop]!=null){e.elem.style[e.prop]=e.now+e.unit}else{e.elem[e.prop]=e.now}}}});b.each(aI.concat.apply([],aI),function(e,bv){if(bv.indexOf("margin")){b.fx.step[bv]=function(bw){b.style(bw.elem,bv,Math.max(0,bw.now)+bw.unit)}}});if(b.expr&&b.expr.filters){b.expr.filters.animated=function(e){return b.grep(b.timers,function(bv){return e===bv.elem}).length}}function w(bx){if(!Q[bx]){var e=av.body,bv=b("<"+bx+">").appendTo(e),bw=bv.css("display");bv.remove();if(bw==="none"||bw===""){if(!ba){ba=av.createElement("iframe");ba.frameBorder=ba.width=ba.height=0}e.appendChild(ba);if(!m||!ba.createElement){m=(ba.contentWindow||ba.contentDocument).document;m.write((b.support.boxModel?"<!doctype html>":"")+"<html><body>");m.close()}bv=m.createElement(bx);m.body.appendChild(bv);bw=b.css(bv,"display");e.removeChild(ba)}Q[bx]=bw}return Q[bx]}var a8,V=/^t(?:able|d|h)$/i,ad=/^(?:body|html)$/i;if("getBoundingClientRect" in av.documentElement){a8=function(by,bH,bw,bB){try{bB=by.getBoundingClientRect()}catch(bF){}if(!bB||!b.contains(bw,by)){return bB?{top:bB.top,left:bB.left}:{top:0,left:0}}var bC=bH.body,bD=aL(bH),bA=bw.clientTop||bC.clientTop||0,bE=bw.clientLeft||bC.clientLeft||0,bv=bD.pageYOffset||b.support.boxModel&&bw.scrollTop||bC.scrollTop,bz=bD.pageXOffset||b.support.boxModel&&bw.scrollLeft||bC.scrollLeft,bG=bB.top+bv-bA,bx=bB.left+bz-bE;return{top:bG,left:bx}}}else{a8=function(bz,bE,bx){var bC,bw=bz.offsetParent,bv=bz,bA=bE.body,bB=bE.defaultView,e=bB?bB.getComputedStyle(bz,null):bz.currentStyle,bD=bz.offsetTop,by=bz.offsetLeft;while((bz=bz.parentNode)&&bz!==bA&&bz!==bx){if(b.support.fixedPosition&&e.position==="fixed"){break}bC=bB?bB.getComputedStyle(bz,null):bz.currentStyle;bD-=bz.scrollTop;by-=bz.scrollLeft;if(bz===bw){bD+=bz.offsetTop;by+=bz.offsetLeft;if(b.support.doesNotAddBorder&&!(b.support.doesAddBorderForTableAndCells&&V.test(bz.nodeName))){bD+=parseFloat(bC.borderTopWidth)||0;by+=parseFloat(bC.borderLeftWidth)||0}bv=bw;bw=bz.offsetParent}if(b.support.subtractsBorderForOverflowNotVisible&&bC.overflow!=="visible"){bD+=parseFloat(bC.borderTopWidth)||0;by+=parseFloat(bC.borderLeftWidth)||0}e=bC}if(e.position==="relative"||e.position==="static"){bD+=bA.offsetTop;by+=bA.offsetLeft}if(b.support.fixedPosition&&e.position==="fixed"){bD+=Math.max(bx.scrollTop,bA.scrollTop);by+=Math.max(bx.scrollLeft,bA.scrollLeft)}return{top:bD,left:by}}}b.fn.offset=function(e){if(arguments.length){return e===L?this:this.each(function(bx){b.offset.setOffset(this,e,bx)})}var bv=this[0],bw=bv&&bv.ownerDocument;if(!bw){return null}if(bv===bw.body){return b.offset.bodyOffset(bv)}return a8(bv,bw,bw.documentElement)};b.offset={bodyOffset:function(e){var bw=e.offsetTop,bv=e.offsetLeft;if(b.support.doesNotIncludeMarginInBodyOffset){bw+=parseFloat(b.css(e,"marginTop"))||0;bv+=parseFloat(b.css(e,"marginLeft"))||0}return{top:bw,left:bv}},setOffset:function(bx,bG,bA){var bB=b.css(bx,"position");if(bB==="static"){bx.style.position="relative"}var bz=b(bx),bv=bz.offset(),e=b.css(bx,"top"),bE=b.css(bx,"left"),bF=(bB==="absolute"||bB==="fixed")&&b.inArray("auto",[e,bE])>-1,bD={},bC={},bw,by;if(bF){bC=bz.position();bw=bC.top;by=bC.left}else{bw=parseFloat(e)||0;by=parseFloat(bE)||0}if(b.isFunction(bG)){bG=bG.call(bx,bA,bv)}if(bG.top!=null){bD.top=(bG.top-bv.top)+bw}if(bG.left!=null){bD.left=(bG.left-bv.left)+by}if("using" in bG){bG.using.call(bx,bD)}else{bz.css(bD)}}};b.fn.extend({position:function(){if(!this[0]){return null}var bw=this[0],bv=this.offsetParent(),bx=this.offset(),e=ad.test(bv[0].nodeName)?{top:0,left:0}:bv.offset();bx.top-=parseFloat(b.css(bw,"marginTop"))||0;bx.left-=parseFloat(b.css(bw,"marginLeft"))||0;e.top+=parseFloat(b.css(bv[0],"borderTopWidth"))||0;e.left+=parseFloat(b.css(bv[0],"borderLeftWidth"))||0;return{top:bx.top-e.top,left:bx.left-e.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||av.body;while(e&&(!ad.test(e.nodeName)&&b.css(e,"position")==="static")){e=e.offsetParent}return e})}});b.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(bw,bv){var e=/Y/.test(bv);b.fn[bw]=function(bx){return b.access(this,function(by,bB,bA){var bz=aL(by);if(bA===L){return bz?(bv in bz)?bz[bv]:b.support.boxModel&&bz.document.documentElement[bB]||bz.document.body[bB]:by[bB]}if(bz){bz.scrollTo(!e?bA:b(bz).scrollLeft(),e?bA:b(bz).scrollTop())}else{by[bB]=bA}},bw,bx,arguments.length,null)}});function aL(e){return b.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:false}b.each({Height:"height",Width:"width"},function(bw,bx){var bv="client"+bw,e="scroll"+bw,by="offset"+bw;b.fn["inner"+bw]=function(){var bz=this[0];return bz?bz.style?parseFloat(b.css(bz,bx,"padding")):this[bx]():null};b.fn["outer"+bw]=function(bA){var bz=this[0];return bz?bz.style?parseFloat(b.css(bz,bx,bA?"margin":"border")):this[bx]():null};b.fn[bx]=function(bz){return b.access(this,function(bC,bB,bD){var bF,bE,bG,bA;if(b.isWindow(bC)){bF=bC.document;bE=bF.documentElement[bv];return b.support.boxModel&&bE||bF.body&&bF.body[bv]||bE}if(bC.nodeType===9){bF=bC.documentElement;if(bF[bv]>=bF[e]){return bF[bv]}return Math.max(bC.body[e],bF[e],bC.body[by],bF[by])}if(bD===L){bG=b.css(bC,bB);bA=parseFloat(bG);return b.isNumeric(bA)?bA:bG}b(bC).css(bB,bD)},bx,bz,arguments.length,null)}});bd.jQuery=bd.$=b;if(typeof define==="function"&&define.amd&&define.amd.jQuery){define("jquery",[],function(){return b})}})(window);/*!
- * jQuery UI 1.8.18
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI
- */
-(function(a,d){a.ui=a.ui||{};if(a.ui.version){return}a.extend(a.ui,{version:"1.8.18",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(e,f){return typeof e==="number"?this.each(function(){var g=this;setTimeout(function(){a(g).focus();if(f){f.call(g)}},e)}):this._focus.apply(this,arguments)},scrollParent:function(){var e;if((a.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){e=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(a.curCSS(this,"position",1))&&(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}else{e=this.parents().filter(function(){return(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!e.length?a(document):e},zIndex:function(h){if(h!==d){return this.css("zIndex",h)}if(this.length){var f=a(this[0]),e,g;while(f.length&&f[0]!==document){e=f.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){g=parseInt(f.css("zIndex"),10);if(!isNaN(g)&&g!==0){return g}}f=f.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});a.each(["Width","Height"],function(g,e){var f=e==="Width"?["Left","Right"]:["Top","Bottom"],h=e.toLowerCase(),k={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};function j(m,l,i,n){a.each(f,function(){l-=parseFloat(a.curCSS(m,"padding"+this,true))||0;if(i){l-=parseFloat(a.curCSS(m,"border"+this+"Width",true))||0}if(n){l-=parseFloat(a.curCSS(m,"margin"+this,true))||0}});return l}a.fn["inner"+e]=function(i){if(i===d){return k["inner"+e].call(this)}return this.each(function(){a(this).css(h,j(this,i)+"px")})};a.fn["outer"+e]=function(i,l){if(typeof i!=="number"){return k["outer"+e].call(this,i)}return this.each(function(){a(this).css(h,j(this,i,true,l)+"px")})}});function c(g,e){var j=g.nodeName.toLowerCase();if("area"===j){var i=g.parentNode,h=i.name,f;if(!g.href||!h||i.nodeName.toLowerCase()!=="map"){return false}f=a("img[usemap=#"+h+"]")[0];return !!f&&b(f)}return(/input|select|textarea|button|object/.test(j)?!g.disabled:"a"==j?g.href||e:e)&&b(g)}function b(e){return !a(e).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.extend(a.expr[":"],{data:function(g,f,e){return !!a.data(g,e[3])},focusable:function(e){return c(e,!isNaN(a.attr(e,"tabindex")))},tabbable:function(g){var e=a.attr(g,"tabindex"),f=isNaN(e);return(f||e>=0)&&c(g,!f)}});a(function(){var e=document.body,f=e.appendChild(f=document.createElement("div"));f.offsetHeight;a.extend(f.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});a.support.minHeight=f.offsetHeight===100;a.support.selectstart="onselectstart" in f;e.removeChild(f).style.display="none"});a.extend(a.ui,{plugin:{add:function(f,g,j){var h=a.ui[f].prototype;for(var e in j){h.plugins[e]=h.plugins[e]||[];h.plugins[e].push([g,j[e]])}},call:function(e,g,f){var j=e.plugins[g];if(!j||!e.element[0].parentNode){return}for(var h=0;h<j.length;h++){if(e.options[j[h][0]]){j[h][1].apply(e.element,f)}}}},contains:function(f,e){return document.compareDocumentPosition?f.compareDocumentPosition(e)&16:f!==e&&f.contains(e)},hasScroll:function(h,f){if(a(h).css("overflow")==="hidden"){return false}var e=(f&&f==="left")?"scrollLeft":"scrollTop",g=false;if(h[e]>0){return true}h[e]=1;g=(h[e]>0);h[e]=0;return g},isOverAxis:function(f,e,g){return(f>e)&&(f<(e+g))},isOver:function(j,f,i,h,e,g){return a.ui.isOverAxis(j,i,e)&&a.ui.isOverAxis(f,h,g)}})})(jQuery);/*!
- * jQuery UI Widget 1.8.18
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Widget
- */
-(function(b,d){if(b.cleanData){var c=b.cleanData;b.cleanData=function(f){for(var g=0,h;(h=f[g])!=null;g++){try{b(h).triggerHandler("remove")}catch(j){}}c(f)}}else{var a=b.fn.remove;b.fn.remove=function(e,f){return this.each(function(){if(!f){if(!e||b.filter(e,[this]).length){b("*",this).add([this]).each(function(){try{b(this).triggerHandler("remove")}catch(g){}})}}return a.call(b(this),e,f)})}}b.widget=function(f,h,e){var g=f.split(".")[0],j;f=f.split(".")[1];j=g+"-"+f;if(!e){e=h;h=b.Widget}b.expr[":"][j]=function(k){return !!b.data(k,f)};b[g]=b[g]||{};b[g][f]=function(k,l){if(arguments.length){this._createWidget(k,l)}};var i=new h();i.options=b.extend(true,{},i.options);b[g][f].prototype=b.extend(true,i,{namespace:g,widgetName:f,widgetEventPrefix:b[g][f].prototype.widgetEventPrefix||f,widgetBaseClass:j},e);b.widget.bridge(f,b[g][f])};b.widget.bridge=function(f,e){b.fn[f]=function(i){var g=typeof i==="string",h=Array.prototype.slice.call(arguments,1),j=this;i=!g&&h.length?b.extend.apply(null,[true,i].concat(h)):i;if(g&&i.charAt(0)==="_"){return j}if(g){this.each(function(){var k=b.data(this,f),l=k&&b.isFunction(k[i])?k[i].apply(k,h):k;if(l!==k&&l!==d){j=l;return false}})}else{this.each(function(){var k=b.data(this,f);if(k){k.option(i||{})._init()}else{b.data(this,f,new e(i,this))}})}return j}};b.Widget=function(e,f){if(arguments.length){this._createWidget(e,f)}};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(f,g){b.data(g,this.widgetName,this);this.element=b(g);this.options=b.extend(true,{},this.options,this._getCreateOptions(),f);var e=this;this.element.bind("remove."+this.widgetName,function(){e.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(f,g){var e=f;if(arguments.length===0){return b.extend({},this.options)}if(typeof f==="string"){if(g===d){return this.options[f]}e={};e[f]=g}this._setOptions(e);return this},_setOptions:function(f){var e=this;b.each(f,function(g,h){e._setOption(g,h)});return this},_setOption:function(e,f){this.options[e]=f;if(e==="disabled"){this.widget()[f?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",f)}return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(e,f,g){var j,i,h=this.options[e];g=g||{};f=b.Event(f);f.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase();f.target=this.element[0];i=f.originalEvent;if(i){for(j in i){if(!(j in f)){f[j]=i[j]}}}this.element.trigger(f,g);return !(b.isFunction(h)&&h.call(this.element[0],f,g)===false||f.isDefaultPrevented())}}})(jQuery);/*!
- * jQuery UI Mouse 1.8.18
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Mouse
- *
- * Depends:
- *	jquery.ui.widget.js
- */
-(function(b,c){var a=false;b(document).mouseup(function(d){a=false});b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var d=this;this.element.bind("mousedown."+this.widgetName,function(e){return d._mouseDown(e)}).bind("click."+this.widgetName,function(e){if(true===b.data(e.target,d.widgetName+".preventClickEvent")){b.removeData(e.target,d.widgetName+".preventClickEvent");e.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(f){if(a){return}(this._mouseStarted&&this._mouseUp(f));this._mouseDownEvent=f;var e=this,g=(f.which==1),d=(typeof this.options.cancel=="string"&&f.target.nodeName?b(f.target).closest(this.options.cancel).length:false);if(!g||d||!this._mouseCapture(f)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){e.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(f)&&this._mouseDelayMet(f)){this._mouseStarted=(this._mouseStart(f)!==false);if(!this._mouseStarted){f.preventDefault();return true}}if(true===b.data(f.target,this.widgetName+".preventClickEvent")){b.removeData(f.target,this.widgetName+".preventClickEvent")}this._mouseMoveDelegate=function(h){return e._mouseMove(h)};this._mouseUpDelegate=function(h){return e._mouseUp(h)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);f.preventDefault();a=true;return true},_mouseMove:function(d){if(b.browser.msie&&!(document.documentMode>=9)&&!d.button){return this._mouseUp(d)}if(this._mouseStarted){this._mouseDrag(d);return d.preventDefault()}if(this._mouseDistanceMet(d)&&this._mouseDelayMet(d)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,d)!==false);(this._mouseStarted?this._mouseDrag(d):this._mouseUp(d))}return !this._mouseStarted},_mouseUp:function(d){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;if(d.target==this._mouseDownEvent.target){b.data(d.target,this.widgetName+".preventClickEvent",true)}this._mouseStop(d)}return false},_mouseDistanceMet:function(d){return(Math.max(Math.abs(this._mouseDownEvent.pageX-d.pageX),Math.abs(this._mouseDownEvent.pageY-d.pageY))>=this.options.distance)},_mouseDelayMet:function(d){return this.mouseDelayMet},_mouseStart:function(d){},_mouseDrag:function(d){},_mouseStop:function(d){},_mouseCapture:function(d){return true}})})(jQuery);(function(c,d){c.widget("ui.resizable",c.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000},_create:function(){var f=this,k=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(k.aspectRatio),aspectRatio:k.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:k.helper||k.ghost||k.animate?k.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){this.element.wrap(c('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=k.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var l=this.handles.split(",");this.handles={};for(var g=0;g<l.length;g++){var j=c.trim(l[g]),e="ui-resizable-"+j;var h=c('<div class="ui-resizable-handle '+e+'"></div>');if(/sw|se|ne|nw/.test(j)){h.css({zIndex:++k.zIndex})}if("se"==j){h.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[j]=".ui-resizable-"+j;this.element.append(h)}}this._renderAxis=function(q){q=q||this.element;for(var n in this.handles){if(this.handles[n].constructor==String){this.handles[n]=c(this.handles[n],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var o=c(this.handles[n],this.element),p=0;p=/sw|ne|nw|se|n|s/.test(n)?o.outerHeight():o.outerWidth();var m=["padding",/ne|nw|n/.test(n)?"Top":/se|sw|s/.test(n)?"Bottom":/^e$/.test(n)?"Right":"Left"].join("");q.css(m,p);this._proportionallyResize()}if(!c(this.handles[n]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!f.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}f.axis=i&&i[1]?i[1]:"se"}});if(k.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){if(k.disabled){return}c(this).removeClass("ui-resizable-autohide");f._handles.show()},function(){if(k.disabled){return}if(!f.resizing){c(this).addClass("ui-resizable-autohide");f._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var e=function(g){c(g).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){e(this.element);var f=this.element;f.after(this.originalElement.css({position:f.css("position"),width:f.outerWidth(),height:f.outerHeight(),top:f.css("top"),left:f.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);e(this.originalElement);return this},_mouseCapture:function(f){var g=false;for(var e in this.handles){if(c(this.handles[e])[0]==f.target){g=true}}return !this.options.disabled&&g},_mouseStart:function(g){var j=this.options,f=this.element.position(),e=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(e.is(".ui-draggable")||(/absolute/).test(e.css("position"))){e.css({position:"absolute",top:f.top,left:f.left})}this._renderProxy();var k=b(this.helper.css("left")),h=b(this.helper.css("top"));if(j.containment){k+=c(j.containment).scrollLeft()||0;h+=c(j.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:k,top:h};this.size=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalSize=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalPosition={left:k,top:h};this.sizeDiff={width:e.outerWidth()-e.width(),height:e.outerHeight()-e.height()};this.originalMousePosition={left:g.pageX,top:g.pageY};this.aspectRatio=(typeof j.aspectRatio=="number")?j.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var i=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",i=="auto"?this.axis+"-resize":i);e.addClass("ui-resizable-resizing");this._propagate("start",g);return true},_mouseDrag:function(e){var h=this.helper,g=this.options,m={},q=this,j=this.originalMousePosition,n=this.axis;var r=(e.pageX-j.left)||0,p=(e.pageY-j.top)||0;var i=this._change[n];if(!i){return false}var l=i.apply(this,[e,r,p]),k=c.browser.msie&&c.browser.version<7,f=this.sizeDiff;this._updateVirtualBoundaries(e.shiftKey);if(this._aspectRatio||e.shiftKey){l=this._updateRatio(l,e)}l=this._respectSize(l,e);this._propagate("resize",e);h.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(l);this._trigger("resize",e,this.ui());return false},_mouseStop:function(h){this.resizing=false;var i=this.options,m=this;if(this._helper){var g=this._proportionallyResizeElements,e=g.length&&(/textarea/i).test(g[0].nodeName),f=e&&c.ui.hasScroll(g[0],"left")?0:m.sizeDiff.height,k=e?0:m.sizeDiff.width;var n={width:(m.helper.width()-k),height:(m.helper.height()-f)},j=(parseInt(m.element.css("left"),10)+(m.position.left-m.originalPosition.left))||null,l=(parseInt(m.element.css("top"),10)+(m.position.top-m.originalPosition.top))||null;if(!i.animate){this.element.css(c.extend(n,{top:l,left:j}))}m.helper.height(m.size.height);m.helper.width(m.size.width);if(this._helper&&!i.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",h);if(this._helper){this.helper.remove()}return false},_updateVirtualBoundaries:function(g){var j=this.options,i,h,f,k,e;e={minWidth:a(j.minWidth)?j.minWidth:0,maxWidth:a(j.maxWidth)?j.maxWidth:Infinity,minHeight:a(j.minHeight)?j.minHeight:0,maxHeight:a(j.maxHeight)?j.maxHeight:Infinity};if(this._aspectRatio||g){i=e.minHeight*this.aspectRatio;f=e.minWidth/this.aspectRatio;h=e.maxHeight*this.aspectRatio;k=e.maxWidth/this.aspectRatio;if(i>e.minWidth){e.minWidth=i}if(f>e.minHeight){e.minHeight=f}if(h<e.maxWidth){e.maxWidth=h}if(k<e.maxHeight){e.maxHeight=k}}this._vBoundaries=e},_updateCache:function(e){var f=this.options;this.offset=this.helper.offset();if(a(e.left)){this.position.left=e.left}if(a(e.top)){this.position.top=e.top}if(a(e.height)){this.size.height=e.height}if(a(e.width)){this.size.width=e.width}},_updateRatio:function(h,g){var i=this.options,j=this.position,f=this.size,e=this.axis;if(a(h.height)){h.width=(h.height*this.aspectRatio)}else{if(a(h.width)){h.height=(h.width/this.aspectRatio)}}if(e=="sw"){h.left=j.left+(f.width-h.width);h.top=null}if(e=="nw"){h.top=j.top+(f.height-h.height);h.left=j.left+(f.width-h.width)}return h},_respectSize:function(l,g){var j=this.helper,i=this._vBoundaries,r=this._aspectRatio||g.shiftKey,q=this.axis,t=a(l.width)&&i.maxWidth&&(i.maxWidth<l.width),m=a(l.height)&&i.maxHeight&&(i.maxHeight<l.height),h=a(l.width)&&i.minWidth&&(i.minWidth>l.width),s=a(l.height)&&i.minHeight&&(i.minHeight>l.height);if(h){l.width=i.minWidth}if(s){l.height=i.minHeight}if(t){l.width=i.maxWidth}if(m){l.height=i.maxHeight}var f=this.originalPosition.left+this.originalSize.width,p=this.position.top+this.size.height;var k=/sw|nw|w/.test(q),e=/nw|ne|n/.test(q);if(h&&k){l.left=f-i.minWidth}if(t&&k){l.left=f-i.maxWidth}if(s&&e){l.top=p-i.minHeight}if(m&&e){l.top=p-i.maxHeight}var n=!l.width&&!l.height;if(n&&!l.left&&l.top){l.top=null}else{if(n&&!l.top&&l.left){l.left=null}}return l},_proportionallyResize:function(){var k=this.options;if(!this._proportionallyResizeElements.length){return}var g=this.helper||this.element;for(var f=0;f<this._proportionallyResizeElements.length;f++){var h=this._proportionallyResizeElements[f];if(!this.borderDif){var e=[h.css("borderTopWidth"),h.css("borderRightWidth"),h.css("borderBottomWidth"),h.css("borderLeftWidth")],j=[h.css("paddingTop"),h.css("paddingRight"),h.css("paddingBottom"),h.css("paddingLeft")];this.borderDif=c.map(e,function(l,n){var m=parseInt(l,10)||0,o=parseInt(j[n],10)||0;return m+o})}if(c.browser.msie&&!(!(c(g).is(":hidden")||c(g).parents(":hidden").length))){continue}h.css({height:(g.height()-this.borderDif[0]-this.borderDif[2])||0,width:(g.width()-this.borderDif[1]-this.borderDif[3])||0})}},_renderProxy:function(){var f=this.element,i=this.options;this.elementOffset=f.offset();if(this._helper){this.helper=this.helper||c('<div style="overflow:hidden;"></div>');var e=c.browser.msie&&c.browser.version<7,g=(e?1:0),h=(e?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+h,height:this.element.outerHeight()+h,position:"absolute",left:this.elementOffset.left-g+"px",top:this.elementOffset.top-g+"px",zIndex:++i.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(g,f,e){return{width:this.originalSize.width+f}},w:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{left:i.left+f,width:g.width-f}},n:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{top:i.top+e,height:g.height-e}},s:function(g,f,e){return{height:this.originalSize.height+e}},se:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},sw:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[g,f,e]))},ne:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},nw:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[g,f,e]))}},_propagate:function(f,e){c.ui.plugin.call(this,f,[e,this.ui()]);(f!="resize"&&this._trigger(f,e,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});c.extend(c.ui.resizable,{version:"1.8.18"});c.ui.plugin.add("resizable","alsoResize",{start:function(f,g){var e=c(this).data("resizable"),i=e.options;var h=function(j){c(j).each(function(){var k=c(this);k.data("resizable-alsoresize",{width:parseInt(k.width(),10),height:parseInt(k.height(),10),left:parseInt(k.css("left"),10),top:parseInt(k.css("top"),10)})})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.parentNode){if(i.alsoResize.length){i.alsoResize=i.alsoResize[0];h(i.alsoResize)}else{c.each(i.alsoResize,function(j){h(j)})}}else{h(i.alsoResize)}},resize:function(g,i){var f=c(this).data("resizable"),j=f.options,h=f.originalSize,l=f.originalPosition;var k={height:(f.size.height-h.height)||0,width:(f.size.width-h.width)||0,top:(f.position.top-l.top)||0,left:(f.position.left-l.left)||0},e=function(m,n){c(m).each(function(){var q=c(this),r=c(this).data("resizable-alsoresize"),p={},o=n&&n.length?n:q.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];c.each(o,function(s,u){var t=(r[u]||0)+(k[u]||0);if(t&&t>=0){p[u]=t||null}});q.css(p)})};if(typeof(j.alsoResize)=="object"&&!j.alsoResize.nodeType){c.each(j.alsoResize,function(m,n){e(m,n)})}else{e(j.alsoResize)}},stop:function(e,f){c(this).removeData("resizable-alsoresize")}});c.ui.plugin.add("resizable","animate",{stop:function(i,n){var p=c(this).data("resizable"),j=p.options;var h=p._proportionallyResizeElements,e=h.length&&(/textarea/i).test(h[0].nodeName),f=e&&c.ui.hasScroll(h[0],"left")?0:p.sizeDiff.height,l=e?0:p.sizeDiff.width;var g={width:(p.size.width-l),height:(p.size.height-f)},k=(parseInt(p.element.css("left"),10)+(p.position.left-p.originalPosition.left))||null,m=(parseInt(p.element.css("top"),10)+(p.position.top-p.originalPosition.top))||null;p.element.animate(c.extend(g,m&&k?{top:m,left:k}:{}),{duration:j.animateDuration,easing:j.animateEasing,step:function(){var o={width:parseInt(p.element.css("width"),10),height:parseInt(p.element.css("height"),10),top:parseInt(p.element.css("top"),10),left:parseInt(p.element.css("left"),10)};if(h&&h.length){c(h[0]).css({width:o.width,height:o.height})}p._updateCache(o);p._propagate("resize",i)}})}});c.ui.plugin.add("resizable","containment",{start:function(f,r){var t=c(this).data("resizable"),j=t.options,l=t.element;var g=j.containment,k=(g instanceof c)?g.get(0):(/parent/.test(g))?l.parent().get(0):g;if(!k){return}t.containerElement=c(k);if(/document/.test(g)||g==document){t.containerOffset={left:0,top:0};t.containerPosition={left:0,top:0};t.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var n=c(k),i=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){i[p]=b(n.css("padding"+o))});t.containerOffset=n.offset();t.containerPosition=n.position();t.containerSize={height:(n.innerHeight()-i[3]),width:(n.innerWidth()-i[1])};var q=t.containerOffset,e=t.containerSize.height,m=t.containerSize.width,h=(c.ui.hasScroll(k,"left")?k.scrollWidth:m),s=(c.ui.hasScroll(k)?k.scrollHeight:e);t.parentData={element:k,left:q.left,top:q.top,width:h,height:s}}},resize:function(g,q){var t=c(this).data("resizable"),i=t.options,f=t.containerSize,p=t.containerOffset,m=t.size,n=t.position,r=t._aspectRatio||g.shiftKey,e={top:0,left:0},h=t.containerElement;if(h[0]!=document&&(/static/).test(h.css("position"))){e=p}if(n.left<(t._helper?p.left:0)){t.size.width=t.size.width+(t._helper?(t.position.left-p.left):(t.position.left-e.left));if(r){t.size.height=t.size.width/i.aspectRatio}t.position.left=i.helper?p.left:0}if(n.top<(t._helper?p.top:0)){t.size.height=t.size.height+(t._helper?(t.position.top-p.top):t.position.top);if(r){t.size.width=t.size.height*i.aspectRatio}t.position.top=t._helper?p.top:0}t.offset.left=t.parentData.left+t.position.left;t.offset.top=t.parentData.top+t.position.top;var l=Math.abs((t._helper?t.offset.left-e.left:(t.offset.left-e.left))+t.sizeDiff.width),s=Math.abs((t._helper?t.offset.top-e.top:(t.offset.top-p.top))+t.sizeDiff.height);var k=t.containerElement.get(0)==t.element.parent().get(0),j=/relative|absolute/.test(t.containerElement.css("position"));if(k&&j){l-=t.parentData.left}if(l+t.size.width>=t.parentData.width){t.size.width=t.parentData.width-l;if(r){t.size.height=t.size.width/t.aspectRatio}}if(s+t.size.height>=t.parentData.height){t.size.height=t.parentData.height-s;if(r){t.size.width=t.size.height*t.aspectRatio}}},stop:function(f,n){var q=c(this).data("resizable"),g=q.options,l=q.position,m=q.containerOffset,e=q.containerPosition,i=q.containerElement;var j=c(q.helper),r=j.offset(),p=j.outerWidth()-q.sizeDiff.width,k=j.outerHeight()-q.sizeDiff.height;if(q._helper&&!g.animate&&(/relative/).test(i.css("position"))){c(this).css({left:r.left-e.left-m.left,width:p,height:k})}if(q._helper&&!g.animate&&(/static/).test(i.css("position"))){c(this).css({left:r.left-e.left-m.left,width:p,height:k})}}});c.ui.plugin.add("resizable","ghost",{start:function(g,h){var e=c(this).data("resizable"),i=e.options,f=e.size;e.ghost=e.originalElement.clone();e.ghost.css({opacity:0.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof i.ghost=="string"?i.ghost:"");e.ghost.appendTo(e.helper)},resize:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost){e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})}},stop:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost&&e.helper){e.helper.get(0).removeChild(e.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(e,m){var p=c(this).data("resizable"),h=p.options,k=p.size,i=p.originalSize,j=p.originalPosition,n=p.axis,l=h._aspectRatio||e.shiftKey;h.grid=typeof h.grid=="number"?[h.grid,h.grid]:h.grid;var g=Math.round((k.width-i.width)/(h.grid[0]||1))*(h.grid[0]||1),f=Math.round((k.height-i.height)/(h.grid[1]||1))*(h.grid[1]||1);if(/^(se|s|e)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f}else{if(/^(ne)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f;p.position.top=j.top-f}else{if(/^(sw)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f;p.position.left=j.left-g}else{p.size.width=i.width+g;p.size.height=i.height+f;p.position.top=j.top-f;p.position.left=j.left-g}}}}});var b=function(e){return parseInt(e,10)||0};var a=function(e){return !isNaN(parseInt(e,10))}})(jQuery);/*!
- * jQuery hashchange event - v1.3 - 7/21/2010
- * http://benalman.com/projects/jquery-hashchange-plugin/
- * 
- * Copyright (c) 2010 "Cowboy" Ben Alman
- * Dual licensed under the MIT and GPL licenses.
- * http://benalman.com/about/license/
- */
-(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){r||l(a());n()}).attr("src",r||"javascript:0").insertAfter("body")[0].contentWindow;h.onpropertychange=function(){try{if(event.propertyName==="title"){q.document.title=h.title}}catch(s){}}}};j.stop=k;o=function(){return a(q.location.href)};l=function(v,s){var u=q.document,t=$.fn[c].domain;if(v!==s){u.title=h.title;u.open();t&&u.write('<script>document.domain="'+t+'"<\/script>');u.close();q.location.hash=v}}})();return j})()})(jQuery,this);(function(c){var a=c.scrollTo=function(f,e,d){c(window).scrollTo(f,e,d)};a.defaults={axis:"xy",duration:parseFloat(c.fn.jquery)>=1.3?0:1};a.window=function(d){return c(window)._scrollable()};c.fn._scrollable=function(){return this.map(function(){var e=this,d=!e.nodeName||c.inArray(e.nodeName.toLowerCase(),["iframe","#document","html","body"])!=-1;if(!d){return e}var f=(e.contentWindow||e).document||e.ownerDocument||e;return c.browser.safari||f.compatMode=="BackCompat"?f.body:f.documentElement})};c.fn.scrollTo=function(f,e,d){if(typeof e=="object"){d=e;e=0}if(typeof d=="function"){d={onAfter:d}}if(f=="max"){f=9000000000}d=c.extend({},a.defaults,d);e=e||d.speed||d.duration;d.queue=d.queue&&d.axis.length>1;if(d.queue){e/=2}d.offset=b(d.offset);d.over=b(d.over);return this._scrollable().each(function(){var l=this,j=c(l),k=f,i,g={},m=j.is("html,body");switch(typeof k){case"number":case"string":if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(k)){k=b(k);break}k=c(k,this);case"object":if(k.is||k.style){i=(k=c(k)).offset()}}c.each(d.axis.split(""),function(q,r){var s=r=="x"?"Left":"Top",u=s.toLowerCase(),p="scroll"+s,o=l[p],n=a.max(l,r);if(i){g[p]=i[u]+(m?0:o-j.offset()[u]);if(d.margin){g[p]-=parseInt(k.css("margin"+s))||0;g[p]-=parseInt(k.css("border"+s+"Width"))||0}g[p]+=d.offset[u]||0;if(d.over[u]){g[p]+=k[r=="x"?"width":"height"]()*d.over[u]}}else{var t=k[u];g[p]=t.slice&&t.slice(-1)=="%"?parseFloat(t)/100*n:t}if(/^\d+$/.test(g[p])){g[p]=g[p]<=0?0:Math.min(g[p],n)}if(!q&&d.queue){if(o!=g[p]){h(d.onAfterFirst)}delete g[p]}});h(d.onAfter);function h(n){j.animate(g,e,d.easing,n&&function(){n.call(this,f,d)})}}).end()};a.max=function(j,i){var h=i=="x"?"Width":"Height",e="scroll"+h;if(!c(j).is("html,body")){return j[e]-c(j)[h.toLowerCase()]()}var g="client"+h,f=j.ownerDocument.documentElement,d=j.ownerDocument.body;return Math.max(f[e],d[e])-Math.min(f[g],d[g])};function b(d){return typeof d=="object"?d:{top:d,left:d}}})(jQuery);/*!
- PowerTip - v1.2.0 - 2013-04-03
- http://stevenbenner.github.com/jquery-powertip/
- Copyright (c) 2013 Steven Benner (http://stevenbenner.com/).
- Released under MIT license.
- https://raw.github.com/stevenbenner/jquery-powertip/master/LICENSE.txt
-*/
-(function(a){if(typeof define==="function"&&define.amd){define(["jquery"],a)}else{a(jQuery)}}(function(k){var A=k(document),s=k(window),w=k("body");var n="displayController",e="hasActiveHover",d="forcedOpen",u="hasMouseMove",f="mouseOnToPopup",g="originalTitle",y="powertip",o="powertipjq",l="powertiptarget",E=180/Math.PI;var c={isTipOpen:false,isFixedTipOpen:false,isClosing:false,tipOpenImminent:false,activeHover:null,currentX:0,currentY:0,previousX:0,previousY:0,desyncTimeout:null,mouseTrackingActive:false,delayInProgress:false,windowWidth:0,windowHeight:0,scrollTop:0,scrollLeft:0};var p={none:0,top:1,bottom:2,left:4,right:8};k.fn.powerTip=function(F,N){if(!this.length){return this}if(k.type(F)==="string"&&k.powerTip[F]){return k.powerTip[F].call(this,this,N)}var O=k.extend({},k.fn.powerTip.defaults,F),G=new x(O);h();this.each(function M(){var R=k(this),Q=R.data(y),P=R.data(o),T=R.data(l),S;if(R.data(n)){k.powerTip.destroy(R)}S=R.attr("title");if(!Q&&!T&&!P&&S){R.data(y,S);R.data(g,S);R.removeAttr("title")}R.data(n,new t(R,O,G))});if(!O.manual){this.on({"mouseenter.powertip":function J(P){k.powerTip.show(this,P)},"mouseleave.powertip":function L(){k.powerTip.hide(this)},"focus.powertip":function K(){k.powerTip.show(this)},"blur.powertip":function H(){k.powerTip.hide(this,true)},"keydown.powertip":function I(P){if(P.keyCode===27){k.powerTip.hide(this,true)}}})}return this};k.fn.powerTip.defaults={fadeInTime:200,fadeOutTime:100,followMouse:false,popupId:"powerTip",intentSensitivity:7,intentPollInterval:100,closeDelay:100,placement:"n",smartPlacement:false,offset:10,mouseOnToPopup:false,manual:false};k.fn.powerTip.smartPlacementLists={n:["n","ne","nw","s"],e:["e","ne","se","w","nw","sw","n","s","e"],s:["s","se","sw","n"],w:["w","nw","sw","e","ne","se","n","s","w"],nw:["nw","w","sw","n","s","se","nw"],ne:["ne","e","se","n","s","sw","ne"],sw:["sw","w","nw","s","n","ne","sw"],se:["se","e","ne","s","n","nw","se"],"nw-alt":["nw-alt","n","ne-alt","sw-alt","s","se-alt","w","e"],"ne-alt":["ne-alt","n","nw-alt","se-alt","s","sw-alt","e","w"],"sw-alt":["sw-alt","s","se-alt","nw-alt","n","ne-alt","w","e"],"se-alt":["se-alt","s","sw-alt","ne-alt","n","nw-alt","e","w"]};k.powerTip={show:function z(F,G){if(G){i(G);c.previousX=G.pageX;c.previousY=G.pageY;k(F).data(n).show()}else{k(F).first().data(n).show(true,true)}return F},reposition:function r(F){k(F).first().data(n).resetPosition();return F},hide:function D(G,F){if(G){k(G).first().data(n).hide(F)}else{if(c.activeHover){c.activeHover.data(n).hide(true)}}return G},destroy:function C(G){k(G).off(".powertip").each(function F(){var I=k(this),H=[g,n,e,d];if(I.data(g)){I.attr("title",I.data(g));H.push(y)}I.removeData(H)});return G}};k.powerTip.showTip=k.powerTip.show;k.powerTip.closeTip=k.powerTip.hide;function b(){var F=this;F.top="auto";F.left="auto";F.right="auto";F.bottom="auto";F.set=function(H,G){if(k.isNumeric(G)){F[H]=Math.round(G)}}}function t(K,N,F){var J=null;function L(P,Q){M();if(!K.data(e)){if(!P){c.tipOpenImminent=true;J=setTimeout(function O(){J=null;I()},N.intentPollInterval)}else{if(Q){K.data(d,true)}F.showTip(K)}}}function G(P){M();c.tipOpenImminent=false;if(K.data(e)){K.data(d,false);if(!P){c.delayInProgress=true;J=setTimeout(function O(){J=null;F.hideTip(K);c.delayInProgress=false},N.closeDelay)}else{F.hideTip(K)}}}function I(){var Q=Math.abs(c.previousX-c.currentX),O=Math.abs(c.previousY-c.currentY),P=Q+O;if(P<N.intentSensitivity){F.showTip(K)}else{c.previousX=c.currentX;c.previousY=c.currentY;L()}}function M(){J=clearTimeout(J);c.delayInProgress=false}function H(){F.resetPosition(K)}this.show=L;this.hide=G;this.cancel=M;this.resetPosition=H}function j(){function G(M,L,J,O,P){var K=L.split("-")[0],N=new b(),I;if(q(M)){I=H(M,K)}else{I=F(M,K)}switch(L){case"n":N.set("left",I.left-(J/2));N.set("bottom",c.windowHeight-I.top+P);break;case"e":N.set("left",I.left+P);N.set("top",I.top-(O/2));break;case"s":N.set("left",I.left-(J/2));N.set("top",I.top+P);break;case"w":N.set("top",I.top-(O/2));N.set("right",c.windowWidth-I.left+P);break;case"nw":N.set("bottom",c.windowHeight-I.top+P);N.set("right",c.windowWidth-I.left-20);break;case"nw-alt":N.set("left",I.left);N.set("bottom",c.windowHeight-I.top+P);break;case"ne":N.set("left",I.left-20);N.set("bottom",c.windowHeight-I.top+P);break;case"ne-alt":N.set("bottom",c.windowHeight-I.top+P);N.set("right",c.windowWidth-I.left);break;case"sw":N.set("top",I.top+P);N.set("right",c.windowWidth-I.left-20);break;case"sw-alt":N.set("left",I.left);N.set("top",I.top+P);break;case"se":N.set("left",I.left-20);N.set("top",I.top+P);break;case"se-alt":N.set("top",I.top+P);N.set("right",c.windowWidth-I.left);break}return N}function F(K,J){var O=K.offset(),N=K.outerWidth(),I=K.outerHeight(),M,L;switch(J){case"n":M=O.left+N/2;L=O.top;break;case"e":M=O.left+N;L=O.top+I/2;break;case"s":M=O.left+N/2;L=O.top+I;break;case"w":M=O.left;L=O.top+I/2;break;case"nw":M=O.left;L=O.top;break;case"ne":M=O.left+N;L=O.top;break;case"sw":M=O.left;L=O.top+I;break;case"se":M=O.left+N;L=O.top+I;break}return{top:L,left:M}}function H(O,K){var S=O.closest("svg")[0],N=O[0],W=S.createSVGPoint(),L=N.getBBox(),V=N.getScreenCTM(),M=L.width/2,Q=L.height/2,P=[],I=["nw","n","ne","e","se","s","sw","w"],U,X,R,T;function J(){P.push(W.matrixTransform(V))}W.x=L.x;W.y=L.y;J();W.x+=M;J();W.x+=M;J();W.y+=Q;J();W.y+=Q;J();W.x-=M;J();W.x-=M;J();W.y-=Q;J();if(P[0].y!==P[1].y||P[0].x!==P[7].x){X=Math.atan2(V.b,V.a)*E;R=Math.ceil(((X%360)-22.5)/45);if(R<1){R+=8}while(R--){I.push(I.shift())}}for(T=0;T<P.length;T++){if(I[T]===K){U=P[T];break}}return{top:U.y+c.scrollTop,left:U.x+c.scrollLeft}}this.compute=G}function x(Q){var P=new j(),O=k("#"+Q.popupId);if(O.length===0){O=k("<div/>",{id:Q.popupId});if(w.length===0){w=k("body")}w.append(O)}if(Q.followMouse){if(!O.data(u)){A.on("mousemove",M);s.on("scroll",M);O.data(u,true)}}if(Q.mouseOnToPopup){O.on({mouseenter:function L(){if(O.data(f)){if(c.activeHover){c.activeHover.data(n).cancel()}}},mouseleave:function N(){if(c.activeHover){c.activeHover.data(n).hide()}}})}function I(S){S.data(e,true);O.queue(function R(T){H(S);T()})}function H(S){var U;if(!S.data(e)){return}if(c.isTipOpen){if(!c.isClosing){K(c.activeHover)}O.delay(100).queue(function R(V){H(S);V()});return}S.trigger("powerTipPreRender");U=B(S);if(U){O.empty().append(U)}else{return}S.trigger("powerTipRender");c.activeHover=S;c.isTipOpen=true;O.data(f,Q.mouseOnToPopup);if(!Q.followMouse){G(S);c.isFixedTipOpen=true}else{M()}O.fadeIn(Q.fadeInTime,function T(){if(!c.desyncTimeout){c.desyncTimeout=setInterval(J,500)}S.trigger("powerTipOpen")})}function K(R){c.isClosing=true;c.activeHover=null;c.isTipOpen=false;c.desyncTimeout=clearInterval(c.desyncTimeout);R.data(e,false);R.data(d,false);O.fadeOut(Q.fadeOutTime,function S(){var T=new b();c.isClosing=false;c.isFixedTipOpen=false;O.removeClass();T.set("top",c.currentY+Q.offset);T.set("left",c.currentX+Q.offset);O.css(T);R.trigger("powerTipClose")})}function M(){if(!c.isFixedTipOpen&&(c.isTipOpen||(c.tipOpenImminent&&O.data(u)))){var R=O.outerWidth(),V=O.outerHeight(),U=new b(),S,T;U.set("top",c.currentY+Q.offset);U.set("left",c.currentX+Q.offset);S=m(U,R,V);if(S!==p.none){T=a(S);if(T===1){if(S===p.right){U.set("left",c.windowWidth-R)}else{if(S===p.bottom){U.set("top",c.scrollTop+c.windowHeight-V)}}}else{U.set("left",c.currentX-R-Q.offset);U.set("top",c.currentY-V-Q.offset)}}O.css(U)}}function G(S){var R,T;if(Q.smartPlacement){R=k.fn.powerTip.smartPlacementLists[Q.placement];k.each(R,function(U,W){var V=m(F(S,W),O.outerWidth(),O.outerHeight());T=W;if(V===p.none){return false}})}else{F(S,Q.placement);T=Q.placement}O.addClass(T)}function F(U,T){var R=0,S,W,V=new b();V.set("top",0);V.set("left",0);O.css(V);do{S=O.outerWidth();W=O.outerHeight();V=P.compute(U,T,S,W,Q.offset);O.css(V)}while(++R<=5&&(S!==O.outerWidth()||W!==O.outerHeight()));return V}function J(){var R=false;if(c.isTipOpen&&!c.isClosing&&!c.delayInProgress){if(c.activeHover.data(e)===false||c.activeHover.is(":disabled")){R=true}else{if(!v(c.activeHover)&&!c.activeHover.is(":focus")&&!c.activeHover.data(d)){if(O.data(f)){if(!v(O)){R=true}}else{R=true}}}if(R){K(c.activeHover)}}}this.showTip=I;this.hideTip=K;this.resetPosition=G}function q(F){return window.SVGElement&&F[0] instanceof SVGElement}function h(){if(!c.mouseTrackingActive){c.mouseTrackingActive=true;k(function H(){c.scrollLeft=s.scrollLeft();c.scrollTop=s.scrollTop();c.windowWidth=s.width();c.windowHeight=s.height()});A.on("mousemove",i);s.on({resize:function G(){c.windowWidth=s.width();c.windowHeight=s.height()},scroll:function F(){var I=s.scrollLeft(),J=s.scrollTop();if(I!==c.scrollLeft){c.currentX+=I-c.scrollLeft;c.scrollLeft=I}if(J!==c.scrollTop){c.currentY+=J-c.scrollTop;c.scrollTop=J}}})}}function i(F){c.currentX=F.pageX;c.currentY=F.pageY}function v(F){var H=F.offset(),J=F[0].getBoundingClientRect(),I=J.right-J.left,G=J.bottom-J.top;return c.currentX>=H.left&&c.currentX<=H.left+I&&c.currentY>=H.top&&c.currentY<=H.top+G}function B(I){var G=I.data(y),F=I.data(o),K=I.data(l),H,J;if(G){if(k.isFunction(G)){G=G.call(I[0])}J=G}else{if(F){if(k.isFunction(F)){F=F.call(I[0])}if(F.length>0){J=F.clone(true,true)}}else{if(K){H=k("#"+K);if(H.length>0){J=H.html()}}}}return J}function m(M,L,K){var G=c.scrollTop,J=c.scrollLeft,I=G+c.windowHeight,F=J+c.windowWidth,H=p.none;if(M.top<G||Math.abs(M.bottom-c.windowHeight)-K<G){H|=p.top}if(M.top+K>I||Math.abs(M.bottom-c.windowHeight)>I){H|=p.bottom}if(M.left<J||M.right+L>F){H|=p.left}if(M.left+L>F||M.right<J){H|=p.right}return H}function a(G){var F=0;while(G){G&=G-1;F++}return F}}));/*!
- * jQuery UI Touch Punch 0.2.3
- *
- * Copyright 2011–2014, Dave Furfero
- * Dual licensed under the MIT or GPL Version 2 licenses.
- *
- * Depends:
- *  jquery.ui.widget.js
- *  jquery.ui.mouse.js
- */
-(function(b){b.support.touch="ontouchend" in document;if(!b.support.touch){return}var d=b.ui.mouse.prototype,f=d._mouseInit,c=d._mouseDestroy,a;function e(h,i){if(h.originalEvent.touches.length>1){return}h.preventDefault();var j=h.originalEvent.changedTouches[0],g=document.createEvent("MouseEvents");g.initMouseEvent(i,true,true,window,1,j.screenX,j.screenY,j.clientX,j.clientY,false,false,false,false,0,null);h.target.dispatchEvent(g)}d._touchStart=function(h){var g=this;if(a||!g._mouseCapture(h.originalEvent.changedTouches[0])){return}a=true;g._touchMoved=false;e(h,"mouseover");e(h,"mousemove");e(h,"mousedown")};d._touchMove=function(g){if(!a){return}this._touchMoved=true;e(g,"mousemove")};d._touchEnd=function(g){if(!a){return}e(g,"mouseup");e(g,"mouseout");if(!this._touchMoved){e(g,"click")}a=false};d._mouseInit=function(){var g=this;g.element.bind({touchstart:b.proxy(g,"_touchStart"),touchmove:b.proxy(g,"_touchMove"),touchend:b.proxy(g,"_touchEnd")});f.call(g)};d._mouseDestroy=function(){var g=this;g.element.unbind({touchstart:b.proxy(g,"_touchStart"),touchmove:b.proxy(g,"_touchMove"),touchend:b.proxy(g,"_touchEnd")});c.call(g)}})(jQuery);/*!
- * SmartMenus jQuery Plugin - v1.0.0 - January 27, 2016
- * http://www.smartmenus.org/
- *
- * Copyright Vasil Dinkov, Vadikom Web Ltd.
- * http://vadikom.com
- *
- * Licensed MIT
- */
-(function(a){if(typeof define==="function"&&define.amd){define(["jquery"],a)}else{if(typeof module==="object"&&typeof module.exports==="object"){module.exports=a(require("jquery"))}else{a(jQuery)}}}(function(a){var b=[],e=!!window.createPopup,f=false,d="ontouchstart" in window,h=false,g=window.requestAnimationFrame||function(l){return setTimeout(l,1000/60)},c=window.cancelAnimationFrame||function(l){clearTimeout(l)};function k(m){var n=".smartmenus_mouse";if(!h&&!m){var o=true,l=null;a(document).bind(i([["mousemove",function(s){var t={x:s.pageX,y:s.pageY,timeStamp:new Date().getTime()};if(l){var q=Math.abs(l.x-t.x),p=Math.abs(l.y-t.y);if((q>0||p>0)&&q<=2&&p<=2&&t.timeStamp-l.timeStamp<=300){f=true;if(o){var r=a(s.target).closest("a");if(r.is("a")){a.each(b,function(){if(a.contains(this.$root[0],r[0])){this.itemEnter({currentTarget:r[0]});return false}})}o=false}}}l=t}],[d?"touchstart":"pointerover pointermove pointerout MSPointerOver MSPointerMove MSPointerOut",function(p){if(j(p.originalEvent)){f=false}}]],n));h=true}else{if(h&&m){a(document).unbind(n);h=false}}}function j(l){return !/^(4|mouse)$/.test(l.pointerType)}function i(l,n){if(!n){n=""}var m={};a.each(l,function(o,p){m[p[0].split(" ").join(n+" ")+n]=p[1]});return m}a.SmartMenus=function(m,l){this.$root=a(m);this.opts=l;this.rootId="";this.accessIdPrefix="";this.$subArrow=null;this.activatedItems=[];this.visibleSubMenus=[];this.showTimeout=0;this.hideTimeout=0;this.scrollTimeout=0;this.clickActivated=false;this.focusActivated=false;this.zIndexInc=0;this.idInc=0;this.$firstLink=null;this.$firstSub=null;this.disabled=false;this.$disableOverlay=null;this.$touchScrollingSub=null;this.cssTransforms3d="perspective" in m.style||"webkitPerspective" in m.style;this.wasCollapsible=false;this.init()};a.extend(a.SmartMenus,{hideAll:function(){a.each(b,function(){this.menuHideAll()})},destroy:function(){while(b.length){b[0].destroy()}k(true)},prototype:{init:function(n){var l=this;if(!n){b.push(this);this.rootId=(new Date().getTime()+Math.random()+"").replace(/\D/g,"");this.accessIdPrefix="sm-"+this.rootId+"-";if(this.$root.hasClass("sm-rtl")){this.opts.rightToLeftSubMenus=true}var r=".smartmenus";this.$root.data("smartmenus",this).attr("data-smartmenus-id",this.rootId).dataSM("level",1).bind(i([["mouseover focusin",a.proxy(this.rootOver,this)],["mouseout focusout",a.proxy(this.rootOut,this)],["keydown",a.proxy(this.rootKeyDown,this)]],r)).delegate("a",i([["mouseenter",a.proxy(this.itemEnter,this)],["mouseleave",a.proxy(this.itemLeave,this)],["mousedown",a.proxy(this.itemDown,this)],["focus",a.proxy(this.itemFocus,this)],["blur",a.proxy(this.itemBlur,this)],["click",a.proxy(this.itemClick,this)]],r));r+=this.rootId;if(this.opts.hideOnClick){a(document).bind(i([["touchstart",a.proxy(this.docTouchStart,this)],["touchmove",a.proxy(this.docTouchMove,this)],["touchend",a.proxy(this.docTouchEnd,this)],["click",a.proxy(this.docClick,this)]],r))}a(window).bind(i([["resize orientationchange",a.proxy(this.winResize,this)]],r));if(this.opts.subIndicators){this.$subArrow=a("<span/>").addClass("sub-arrow");if(this.opts.subIndicatorsText){this.$subArrow.html(this.opts.subIndicatorsText)}}k()}this.$firstSub=this.$root.find("ul").each(function(){l.menuInit(a(this))}).eq(0);this.$firstLink=this.$root.find("a").eq(0);if(this.opts.markCurrentItem){var p=/(index|default)\.[^#\?\/]*/i,m=/#.*/,q=window.location.href.replace(p,""),o=q.replace(m,"");this.$root.find("a").each(function(){var s=this.href.replace(p,""),t=a(this);if(s==q||s==o){t.addClass("current");if(l.opts.markCurrentTree){t.parentsUntil("[data-smartmenus-id]","ul").each(function(){a(this).dataSM("parent-a").addClass("current")})}}})}this.wasCollapsible=this.isCollapsible()},destroy:function(m){if(!m){var n=".smartmenus";this.$root.removeData("smartmenus").removeAttr("data-smartmenus-id").removeDataSM("level").unbind(n).undelegate(n);n+=this.rootId;a(document).unbind(n);a(window).unbind(n);if(this.opts.subIndicators){this.$subArrow=null}}this.menuHideAll();var l=this;this.$root.find("ul").each(function(){var o=a(this);if(o.dataSM("scroll-arrows")){o.dataSM("scroll-arrows").remove()}if(o.dataSM("shown-before")){if(l.opts.subMenusMinWidth||l.opts.subMenusMaxWidth){o.css({width:"",minWidth:"",maxWidth:""}).removeClass("sm-nowrap")}if(o.dataSM("scroll-arrows")){o.dataSM("scroll-arrows").remove()}o.css({zIndex:"",top:"",left:"",marginLeft:"",marginTop:"",display:""})}if((o.attr("id")||"").indexOf(l.accessIdPrefix)==0){o.removeAttr("id")}}).removeDataSM("in-mega").removeDataSM("shown-before").removeDataSM("ie-shim").removeDataSM("scroll-arrows").removeDataSM("parent-a").removeDataSM("level").removeDataSM("beforefirstshowfired").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeAttr("aria-expanded");this.$root.find("a.has-submenu").each(function(){var o=a(this);if(o.attr("id").indexOf(l.accessIdPrefix)==0){o.removeAttr("id")}}).removeClass("has-submenu").removeDataSM("sub").removeAttr("aria-haspopup").removeAttr("aria-controls").removeAttr("aria-expanded").closest("li").removeDataSM("sub");if(this.opts.subIndicators){this.$root.find("span.sub-arrow").remove()}if(this.opts.markCurrentItem){this.$root.find("a.current").removeClass("current")}if(!m){this.$root=null;this.$firstLink=null;this.$firstSub=null;if(this.$disableOverlay){this.$disableOverlay.remove();this.$disableOverlay=null}b.splice(a.inArray(this,b),1)}},disable:function(l){if(!this.disabled){this.menuHideAll();if(!l&&!this.opts.isPopup&&this.$root.is(":visible")){var m=this.$root.offset();this.$disableOverlay=a('<div class="sm-jquery-disable-overlay"/>').css({position:"absolute",top:m.top,left:m.left,width:this.$root.outerWidth(),height:this.$root.outerHeight(),zIndex:this.getStartZIndex(true),opacity:0}).appendTo(document.body)}this.disabled=true}},docClick:function(l){if(this.$touchScrollingSub){this.$touchScrollingSub=null;return}if(this.visibleSubMenus.length&&!a.contains(this.$root[0],l.target)||a(l.target).is("a")){this.menuHideAll()}},docTouchEnd:function(m){if(!this.lastTouch){return}if(this.visibleSubMenus.length&&(this.lastTouch.x2===undefined||this.lastTouch.x1==this.lastTouch.x2)&&(this.lastTouch.y2===undefined||this.lastTouch.y1==this.lastTouch.y2)&&(!this.lastTouch.target||!a.contains(this.$root[0],this.lastTouch.target))){if(this.hideTimeout){clearTimeout(this.hideTimeout);this.hideTimeout=0}var l=this;this.hideTimeout=setTimeout(function(){l.menuHideAll()},350)}this.lastTouch=null},docTouchMove:function(m){if(!this.lastTouch){return}var l=m.originalEvent.touches[0];this.lastTouch.x2=l.pageX;this.lastTouch.y2=l.pageY},docTouchStart:function(m){var l=m.originalEvent.touches[0];this.lastTouch={x1:l.pageX,y1:l.pageY,target:l.target}},enable:function(){if(this.disabled){if(this.$disableOverlay){this.$disableOverlay.remove();this.$disableOverlay=null}this.disabled=false}},getClosestMenu:function(m){var l=a(m).closest("ul");while(l.dataSM("in-mega")){l=l.parent().closest("ul")}return l[0]||null},getHeight:function(l){return this.getOffset(l,true)},getOffset:function(n,l){var m;if(n.css("display")=="none"){m={position:n[0].style.position,visibility:n[0].style.visibility};n.css({position:"absolute",visibility:"hidden"}).show()}var o=n[0].getBoundingClientRect&&n[0].getBoundingClientRect(),p=o&&(l?o.height||o.bottom-o.top:o.width||o.right-o.left);if(!p&&p!==0){p=l?n[0].offsetHeight:n[0].offsetWidth}if(m){n.hide().css(m)}return p},getStartZIndex:function(l){var m=parseInt(this[l?"$root":"$firstSub"].css("z-index"));if(!l&&isNaN(m)){m=parseInt(this.$root.css("z-index"))}return !isNaN(m)?m:1},getTouchPoint:function(l){return l.touches&&l.touches[0]||l.changedTouches&&l.changedTouches[0]||l},getViewport:function(l){var m=l?"Height":"Width",o=document.documentElement["client"+m],n=window["inner"+m];if(n){o=Math.min(o,n)}return o},getViewportHeight:function(){return this.getViewport(true)},getViewportWidth:function(){return this.getViewport()},getWidth:function(l){return this.getOffset(l)},handleEvents:function(){return !this.disabled&&this.isCSSOn()},handleItemEvents:function(l){return this.handleEvents()&&!this.isLinkInMegaMenu(l)},isCollapsible:function(){return this.$firstSub.css("position")=="static"},isCSSOn:function(){return this.$firstLink.css("display")=="block"},isFixed:function(){var l=this.$root.css("position")=="fixed";if(!l){this.$root.parentsUntil("body").each(function(){if(a(this).css("position")=="fixed"){l=true;return false}})}return l},isLinkInMegaMenu:function(l){return a(this.getClosestMenu(l[0])).hasClass("mega-menu")},isTouchMode:function(){return !f||this.opts.noMouseOver||this.isCollapsible()},itemActivate:function(p,l){var n=p.closest("ul"),q=n.dataSM("level");if(q>1&&(!this.activatedItems[q-2]||this.activatedItems[q-2][0]!=n.dataSM("parent-a")[0])){var m=this;a(n.parentsUntil("[data-smartmenus-id]","ul").get().reverse()).add(n).each(function(){m.itemActivate(a(this).dataSM("parent-a"))})}if(!this.isCollapsible()||l){this.menuHideSubMenus(!this.activatedItems[q-1]||this.activatedItems[q-1][0]!=p[0]?q-1:q)}this.activatedItems[q-1]=p;if(this.$root.triggerHandler("activate.smapi",p[0])===false){return}var o=p.dataSM("sub");if(o&&(this.isTouchMode()||(!this.opts.showOnClick||this.clickActivated))){this.menuShow(o)}},itemBlur:function(m){var l=a(m.currentTarget);if(!this.handleItemEvents(l)){return}this.$root.triggerHandler("blur.smapi",l[0])},itemClick:function(o){var n=a(o.currentTarget);if(!this.handleItemEvents(n)){return}if(this.$touchScrollingSub&&this.$touchScrollingSub[0]==n.closest("ul")[0]){this.$touchScrollingSub=null;o.stopPropagation();return false}if(this.$root.triggerHandler("click.smapi",n[0])===false){return false}var p=a(o.target).is("span.sub-arrow"),m=n.dataSM("sub"),l=m?m.dataSM("level")==2:false;if(m&&!m.is(":visible")){if(this.opts.showOnClick&&l){this.clickActivated=true}this.itemActivate(n);if(m.is(":visible")){this.focusActivated=true;return false}}else{if(this.isCollapsible()&&p){this.itemActivate(n);this.menuHide(m);return false}}if(this.opts.showOnClick&&l||n.hasClass("disabled")||this.$root.triggerHandler("select.smapi",n[0])===false){return false}},itemDown:function(m){var l=a(m.currentTarget);if(!this.handleItemEvents(l)){return}l.dataSM("mousedown",true)},itemEnter:function(n){var m=a(n.currentTarget);if(!this.handleItemEvents(m)){return}if(!this.isTouchMode()){if(this.showTimeout){clearTimeout(this.showTimeout);this.showTimeout=0}var l=this;this.showTimeout=setTimeout(function(){l.itemActivate(m)},this.opts.showOnClick&&m.closest("ul").dataSM("level")==1?1:this.opts.showTimeout)}this.$root.triggerHandler("mouseenter.smapi",m[0])},itemFocus:function(m){var l=a(m.currentTarget);if(!this.handleItemEvents(l)){return}if(this.focusActivated&&(!this.isTouchMode()||!l.dataSM("mousedown"))&&(!this.activatedItems.length||this.activatedItems[this.activatedItems.length-1][0]!=l[0])){this.itemActivate(l,true)}this.$root.triggerHandler("focus.smapi",l[0])},itemLeave:function(m){var l=a(m.currentTarget);if(!this.handleItemEvents(l)){return}if(!this.isTouchMode()){l[0].blur();if(this.showTimeout){clearTimeout(this.showTimeout);this.showTimeout=0}}l.removeDataSM("mousedown");this.$root.triggerHandler("mouseleave.smapi",l[0])},menuHide:function(m){if(this.$root.triggerHandler("beforehide.smapi",m[0])===false){return}m.stop(true,true);if(m.css("display")!="none"){var l=function(){m.css("z-index","")};if(this.isCollapsible()){if(this.opts.collapsibleHideFunction){this.opts.collapsibleHideFunction.call(this,m,l)}else{m.hide(this.opts.collapsibleHideDuration,l)}}else{if(this.opts.hideFunction){this.opts.hideFunction.call(this,m,l)}else{m.hide(this.opts.hideDuration,l)}}if(m.dataSM("ie-shim")){m.dataSM("ie-shim").remove().css({"-webkit-transform":"",transform:""})}if(m.dataSM("scroll")){this.menuScrollStop(m);m.css({"touch-action":"","-ms-touch-action":"","-webkit-transform":"",transform:""}).unbind(".smartmenus_scroll").removeDataSM("scroll").dataSM("scroll-arrows").hide()}m.dataSM("parent-a").removeClass("highlighted").attr("aria-expanded","false");m.attr({"aria-expanded":"false","aria-hidden":"true"});var n=m.dataSM("level");this.activatedItems.splice(n-1,1);this.visibleSubMenus.splice(a.inArray(m,this.visibleSubMenus),1);this.$root.triggerHandler("hide.smapi",m[0])}},menuHideAll:function(){if(this.showTimeout){clearTimeout(this.showTimeout);this.showTimeout=0}var m=this.opts.isPopup?1:0;for(var l=this.visibleSubMenus.length-1;l>=m;l--){this.menuHide(this.visibleSubMenus[l])}if(this.opts.isPopup){this.$root.stop(true,true);if(this.$root.is(":visible")){if(this.opts.hideFunction){this.opts.hideFunction.call(this,this.$root)}else{this.$root.hide(this.opts.hideDuration)}if(this.$root.dataSM("ie-shim")){this.$root.dataSM("ie-shim").remove()}}}this.activatedItems=[];this.visibleSubMenus=[];this.clickActivated=false;this.focusActivated=false;this.zIndexInc=0;this.$root.triggerHandler("hideAll.smapi")},menuHideSubMenus:function(n){for(var l=this.activatedItems.length-1;l>=n;l--){var m=this.activatedItems[l].dataSM("sub");if(m){this.menuHide(m)}}},menuIframeShim:function(l){if(e&&this.opts.overlapControlsInIE&&!l.dataSM("ie-shim")){l.dataSM("ie-shim",a("<iframe/>").attr({src:"javascript:0",tabindex:-9}).css({position:"absolute",top:"auto",left:"0",opacity:0,border:"0"}))}},menuInit:function(l){if(!l.dataSM("in-mega")){if(l.hasClass("mega-menu")){l.find("ul").dataSM("in-mega",true)}var q=2,m=l[0];while((m=m.parentNode.parentNode)!=this.$root[0]){q++}var n=l.prevAll("a").eq(-1);if(!n.length){n=l.prevAll().find("a").eq(-1)}n.addClass("has-submenu").dataSM("sub",l);l.dataSM("parent-a",n).dataSM("level",q).parent().dataSM("sub",l);var o=n.attr("id")||this.accessIdPrefix+(++this.idInc),p=l.attr("id")||this.accessIdPrefix+(++this.idInc);n.attr({id:o,"aria-haspopup":"true","aria-controls":p,"aria-expanded":"false"});l.attr({id:p,role:"group","aria-hidden":"true","aria-labelledby":o,"aria-expanded":"false"});if(this.opts.subIndicators){n[this.opts.subIndicatorsPos](this.$subArrow.clone())}}},menuPosition:function(K){var r=K.dataSM("parent-a"),D=r.closest("li"),E=D.parent(),l=K.dataSM("level"),t=this.getWidth(K),J=this.getHeight(K),u=r.offset(),o=u.left,m=u.top,q=this.getWidth(r),F=this.getHeight(r),H=a(window),v=H.scrollLeft(),s=H.scrollTop(),z=this.getViewportWidth(),L=this.getViewportHeight(),w=E.parent().is("[data-sm-horizontal-sub]")||l==2&&!E.hasClass("sm-vertical"),B=this.opts.rightToLeftSubMenus&&!D.is("[data-sm-reverse]")||!this.opts.rightToLeftSubMenus&&D.is("[data-sm-reverse]"),p=l==2?this.opts.mainMenuSubOffsetX:this.opts.subMenusSubOffsetX,n=l==2?this.opts.mainMenuSubOffsetY:this.opts.subMenusSubOffsetY,C,A;if(w){C=B?q-t-p:p;A=this.opts.bottomToTopSubMenus?-J-n:F+n}else{C=B?p-t:q-p;A=this.opts.bottomToTopSubMenus?F-n-J:n}if(this.opts.keepInViewport){var N=o+C,M=m+A;if(B&&N<v){C=w?v-N+C:q-p}else{if(!B&&N+t>v+z){C=w?v+z-t-N+C:p-t}}if(!w){if(J<L&&M+J>s+L){A+=s+L-J-M}else{if(J>=L||M<s){A+=s-M}}}if(w&&(M+J>s+L+0.49||M<s)||!w&&J>L+0.49){var G=this;if(!K.dataSM("scroll-arrows")){K.dataSM("scroll-arrows",a([a('<span class="scroll-up"><span class="scroll-up-arrow"></span></span>')[0],a('<span class="scroll-down"><span class="scroll-down-arrow"></span></span>')[0]]).bind({mouseenter:function(){K.dataSM("scroll").up=a(this).hasClass("scroll-up");G.menuScroll(K)},mouseleave:function(x){G.menuScrollStop(K);G.menuScrollOut(K,x)},"mousewheel DOMMouseScroll":function(x){x.preventDefault()}}).insertAfter(K))}var I=".smartmenus_scroll";K.dataSM("scroll",{y:this.cssTransforms3d?0:A-F,step:1,itemH:F,subH:J,arrowDownH:this.getHeight(K.dataSM("scroll-arrows").eq(1))}).bind(i([["mouseover",function(x){G.menuScrollOver(K,x)}],["mouseout",function(x){G.menuScrollOut(K,x)}],["mousewheel DOMMouseScroll",function(x){G.menuScrollMousewheel(K,x)}]],I)).dataSM("scroll-arrows").css({top:"auto",left:"0",marginLeft:C+(parseInt(K.css("border-left-width"))||0),width:t-(parseInt(K.css("border-left-width"))||0)-(parseInt(K.css("border-right-width"))||0),zIndex:K.css("z-index")}).eq(w&&this.opts.bottomToTopSubMenus?0:1).show();if(this.isFixed()){K.css({"touch-action":"none","-ms-touch-action":"none"}).bind(i([[d?"touchstart touchmove touchend":"pointerdown pointermove pointerup MSPointerDown MSPointerMove MSPointerUp",function(x){G.menuScrollTouch(K,x)}]],I))}}}K.css({top:"auto",left:"0",marginLeft:C,marginTop:A-F});this.menuIframeShim(K);if(K.dataSM("ie-shim")){K.dataSM("ie-shim").css({zIndex:K.css("z-index"),width:t,height:J,marginLeft:C,marginTop:A-F})}},menuScroll:function(r,m,n){var p=r.dataSM("scroll"),q=r.dataSM("scroll-arrows"),o=p.up?p.upEnd:p.downEnd,s;if(!m&&p.momentum){p.momentum*=0.92;s=p.momentum;if(s<0.5){this.menuScrollStop(r);return}}else{s=n||(m||!this.opts.scrollAccelerate?this.opts.scrollStep:Math.floor(p.step))}var l=r.dataSM("level");if(this.activatedItems[l-1]&&this.activatedItems[l-1].dataSM("sub")&&this.activatedItems[l-1].dataSM("sub").is(":visible")){this.menuHideSubMenus(l-1)}p.y=p.up&&o<=p.y||!p.up&&o>=p.y?p.y:(Math.abs(o-p.y)>s?p.y+(p.up?s:-s):o);r.add(r.dataSM("ie-shim")).css(this.cssTransforms3d?{"-webkit-transform":"translate3d(0, "+p.y+"px, 0)",transform:"translate3d(0, "+p.y+"px, 0)"}:{marginTop:p.y});if(f&&(p.up&&p.y>p.downEnd||!p.up&&p.y<p.upEnd)){q.eq(p.up?1:0).show()}if(p.y==o){if(f){q.eq(p.up?0:1).hide()}this.menuScrollStop(r)}else{if(!m){if(this.opts.scrollAccelerate&&p.step<this.opts.scrollStep){p.step+=0.2}var t=this;this.scrollTimeout=g(function(){t.menuScroll(r)})}}},menuScrollMousewheel:function(m,n){if(this.getClosestMenu(n.target)==m[0]){n=n.originalEvent;var l=(n.wheelDelta||-n.detail)>0;if(m.dataSM("scroll-arrows").eq(l?0:1).is(":visible")){m.dataSM("scroll").up=l;this.menuScroll(m,true)}}n.preventDefault()},menuScrollOut:function(l,m){if(f){if(!/^scroll-(up|down)/.test((m.relatedTarget||"").className)&&(l[0]!=m.relatedTarget&&!a.contains(l[0],m.relatedTarget)||this.getClosestMenu(m.relatedTarget)!=l[0])){l.dataSM("scroll-arrows").css("visibility","hidden")}}},menuScrollOver:function(n,o){if(f){if(!/^scroll-(up|down)/.test(o.target.className)&&this.getClosestMenu(o.target)==n[0]){this.menuScrollRefreshData(n);var m=n.dataSM("scroll"),l=a(window).scrollTop()-n.dataSM("parent-a").offset().top-m.itemH;n.dataSM("scroll-arrows").eq(0).css("margin-top",l).end().eq(1).css("margin-top",l+this.getViewportHeight()-m.arrowDownH).end().css("visibility","visible")}}},menuScrollRefreshData:function(n){var m=n.dataSM("scroll"),l=a(window).scrollTop()-n.dataSM("parent-a").offset().top-m.itemH;if(this.cssTransforms3d){l=-(parseFloat(n.css("margin-top"))-l)}a.extend(m,{upEnd:l,downEnd:l+this.getViewportHeight()-m.subH})},menuScrollStop:function(l){if(this.scrollTimeout){c(this.scrollTimeout);this.scrollTimeout=0;l.dataSM("scroll").step=1;return true}},menuScrollTouch:function(p,q){q=q.originalEvent;if(j(q)){var m=this.getTouchPoint(q);if(this.getClosestMenu(m.target)==p[0]){var o=p.dataSM("scroll");if(/(start|down)$/i.test(q.type)){if(this.menuScrollStop(p)){q.preventDefault();this.$touchScrollingSub=p}else{this.$touchScrollingSub=null}this.menuScrollRefreshData(p);a.extend(o,{touchStartY:m.pageY,touchStartTime:q.timeStamp})}else{if(/move$/i.test(q.type)){var n=o.touchY!==undefined?o.touchY:o.touchStartY;if(n!==undefined&&n!=m.pageY){this.$touchScrollingSub=p;var l=n<m.pageY;if(o.up!==undefined&&o.up!=l){a.extend(o,{touchStartY:m.pageY,touchStartTime:q.timeStamp})}a.extend(o,{up:l,touchY:m.pageY});this.menuScroll(p,true,Math.abs(m.pageY-n))}q.preventDefault()}else{if(o.touchY!==undefined){if(o.momentum=Math.pow(Math.abs(m.pageY-o.touchStartY)/(q.timeStamp-o.touchStartTime),2)*15){this.menuScrollStop(p);this.menuScroll(p);q.preventDefault()}delete o.touchY}}}}}},menuShow:function(n){if(!n.dataSM("beforefirstshowfired")){n.dataSM("beforefirstshowfired",true);if(this.$root.triggerHandler("beforefirstshow.smapi",n[0])===false){return}}if(this.$root.triggerHandler("beforeshow.smapi",n[0])===false){return}n.dataSM("shown-before",true).stop(true,true);if(!n.is(":visible")){var m=n.dataSM("parent-a");if(this.opts.keepHighlighted||this.isCollapsible()){m.addClass("highlighted")}if(this.isCollapsible()){n.removeClass("sm-nowrap").css({zIndex:"",width:"auto",minWidth:"",maxWidth:"",top:"",left:"",marginLeft:"",marginTop:""})}else{n.css("z-index",this.zIndexInc=(this.zIndexInc||this.getStartZIndex())+1);if(this.opts.subMenusMinWidth||this.opts.subMenusMaxWidth){n.css({width:"auto",minWidth:"",maxWidth:""}).addClass("sm-nowrap");if(this.opts.subMenusMinWidth){n.css("min-width",this.opts.subMenusMinWidth)}if(this.opts.subMenusMaxWidth){var o=this.getWidth(n);n.css("max-width",this.opts.subMenusMaxWidth);if(o>this.getWidth(n)){n.removeClass("sm-nowrap").css("width",this.opts.subMenusMaxWidth)}}}this.menuPosition(n);if(n.dataSM("ie-shim")){n.dataSM("ie-shim").insertBefore(n)}}var l=function(){n.css("overflow","")};if(this.isCollapsible()){if(this.opts.collapsibleShowFunction){this.opts.collapsibleShowFunction.call(this,n,l)}else{n.show(this.opts.collapsibleShowDuration,l)}}else{if(this.opts.showFunction){this.opts.showFunction.call(this,n,l)}else{n.show(this.opts.showDuration,l)}}m.attr("aria-expanded","true");n.attr({"aria-expanded":"true","aria-hidden":"false"});this.visibleSubMenus.push(n);this.$root.triggerHandler("show.smapi",n[0])}},popupHide:function(l){if(this.hideTimeout){clearTimeout(this.hideTimeout);this.hideTimeout=0}var m=this;this.hideTimeout=setTimeout(function(){m.menuHideAll()},l?1:this.opts.hideTimeout)},popupShow:function(o,n){if(!this.opts.isPopup){alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.');return}if(this.hideTimeout){clearTimeout(this.hideTimeout);this.hideTimeout=0}this.$root.dataSM("shown-before",true).stop(true,true);if(!this.$root.is(":visible")){this.$root.css({left:o,top:n});this.menuIframeShim(this.$root);if(this.$root.dataSM("ie-shim")){this.$root.dataSM("ie-shim").css({zIndex:this.$root.css("z-index"),width:this.getWidth(this.$root),height:this.getHeight(this.$root),left:o,top:n}).insertBefore(this.$root)}var m=this,l=function(){m.$root.css("overflow","")};if(this.opts.showFunction){this.opts.showFunction.call(this,this.$root,l)}else{this.$root.show(this.opts.showDuration,l)}this.visibleSubMenus[0]=this.$root}},refresh:function(){this.destroy(true);this.init(true)},rootKeyDown:function(o){if(!this.handleEvents()){return}switch(o.keyCode){case 27:var m=this.activatedItems[0];if(m){this.menuHideAll();m[0].focus();var n=m.dataSM("sub");if(n){this.menuHide(n)}}break;case 32:var l=a(o.target);if(l.is("a")&&this.handleItemEvents(l)){var n=l.dataSM("sub");if(n&&!n.is(":visible")){this.itemClick({currentTarget:o.target});o.preventDefault()}}break}},rootOut:function(m){if(!this.handleEvents()||this.isTouchMode()||m.target==this.$root[0]){return}if(this.hideTimeout){clearTimeout(this.hideTimeout);this.hideTimeout=0}if(!this.opts.showOnClick||!this.opts.hideOnClick){var l=this;this.hideTimeout=setTimeout(function(){l.menuHideAll()},this.opts.hideTimeout)}},rootOver:function(l){if(!this.handleEvents()||this.isTouchMode()||l.target==this.$root[0]){return}if(this.hideTimeout){clearTimeout(this.hideTimeout);this.hideTimeout=0}},winResize:function(m){if(!this.handleEvents()){if(this.$disableOverlay){var n=this.$root.offset();this.$disableOverlay.css({top:n.top,left:n.left,width:this.$root.outerWidth(),height:this.$root.outerHeight()})}return}if(!("onorientationchange" in window)||m.type=="orientationchange"){var l=this.isCollapsible();if(!(this.wasCollapsible&&l)){if(this.activatedItems.length){this.activatedItems[this.activatedItems.length-1][0].blur()}this.menuHideAll()}this.wasCollapsible=l}}}});a.fn.dataSM=function(l,m){if(m){return this.data(l+"_smartmenus",m)}return this.data(l+"_smartmenus")};a.fn.removeDataSM=function(l){return this.removeData(l+"_smartmenus")};a.fn.smartmenus=function(m){if(typeof m=="string"){var l=arguments,o=m;Array.prototype.shift.call(l);return this.each(function(){var p=a(this).data("smartmenus");if(p&&p[o]){p[o].apply(p,l)}})}var n=a.extend({},a.fn.smartmenus.defaults,m);return this.each(function(){new a.SmartMenus(this,n)})};a.fn.smartmenus.defaults={isPopup:false,mainMenuSubOffsetX:0,mainMenuSubOffsetY:0,subMenusSubOffsetX:0,subMenusSubOffsetY:0,subMenusMinWidth:"10em",subMenusMaxWidth:"20em",subIndicators:true,subIndicatorsPos:"prepend",subIndicatorsText:"+",scrollStep:30,scrollAccelerate:true,showTimeout:250,hideTimeout:500,showDuration:0,showFunction:null,hideDuration:0,hideFunction:function(m,l){m.fadeOut(200,l)},collapsibleShowDuration:0,collapsibleShowFunction:function(m,l){m.slideDown(200,l)},collapsibleHideDuration:0,collapsibleHideFunction:function(m,l){m.slideUp(200,l)},showOnClick:false,hideOnClick:true,noMouseOver:false,keepInViewport:true,keepHighlighted:true,markCurrentItem:false,markCurrentTree:true,rightToLeftSubMenus:false,bottomToTopSubMenus:false,overlapControlsInIE:true};return a}));
\ No newline at end of file
diff --git a/docs/reference/menu.js b/docs/reference/menu.js
deleted file mode 100644
index 433c15b..0000000
--- a/docs/reference/menu.js
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- @licstart  The following is the entire license notice for the
- JavaScript code in this file.
-
- Copyright (C) 1997-2017 by Dimitri van Heesch
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
- @licend  The above is the entire license notice
- for the JavaScript code in this file
- */
-function initMenu(relPath,searchEnabled,serverSide,searchPage,search) {
-  function makeTree(data,relPath) {
-    var result='';
-    if ('children' in data) {
-      result+='<ul>';
-      for (var i in data.children) {
-        result+='<li><a href="'+relPath+data.children[i].url+'">'+
-                                data.children[i].text+'</a>'+
-                                makeTree(data.children[i],relPath)+'</li>';
-      }
-      result+='</ul>';
-    }
-    return result;
-  }
-
-  $('#main-nav').append(makeTree(menudata,relPath));
-  $('#main-nav').children(':first').addClass('sm sm-dox').attr('id','main-menu');
-  if (searchEnabled) {
-    if (serverSide) {
-      $('#main-menu').append('<li style="float:right"><div id="MSearchBox" class="MSearchBoxInactive"><div class="left"><form id="FSearchBox" action="'+relPath+searchPage+'" method="get"><img id="MSearchSelect" src="'+relPath+'search/mag.png" alt=""/><input type="text" id="MSearchField" name="query" value="'+search+'" size="20" accesskey="S" onfocus="searchBox.OnSearchFieldFocus(true)" onblur="searchBox.OnSearchFieldFocus(false)"></form></div><div class="right"></div></div></li>');
-    } else {
-      $('#main-menu').append('<li style="float:right"><div id="MSearchBox" class="MSearchBoxInactive"><span class="left"><img id="MSearchSelect" src="'+relPath+'search/mag_sel.png" onmouseover="return searchBox.OnSearchSelectShow()" onmouseout="return searchBox.OnSearchSelectHide()" alt=""/><input type="text" id="MSearchField" value="'+search+'" accesskey="S" onfocus="searchBox.OnSearchFieldFocus(true)" onblur="searchBox.OnSearchFieldFocus(false)" onkeyup="searchBox.OnSearchFieldChange(event)"/></span><span class="right"><a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="'+relPath+'search/close.png" alt=""/></a></span></div></li>');
-    }
-  }
-  $('#main-menu').smartmenus();
-}
-/* @license-end */
diff --git a/docs/reference/menudata.js b/docs/reference/menudata.js
deleted file mode 100644
index be2e16a..0000000
--- a/docs/reference/menudata.js
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-@ @licstart  The following is the entire license notice for the
-JavaScript code in this file.
-
-Copyright (C) 1997-2017 by Dimitri van Heesch
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-@licend  The above is the entire license notice
-for the JavaScript code in this file
-*/
-var menudata={children:[
-{text:"Main Page",url:"index.html"},
-{text:"Related Pages",url:"pages.html"},
-{text:"Namespaces",url:"namespaces.html",children:[
-{text:"Namespace List",url:"namespaces.html"},
-{text:"Namespace Members",url:"namespacemembers.html",children:[
-{text:"All",url:"namespacemembers.html",children:[
-{text:"a",url:"namespacemembers.html#index_a"},
-{text:"c",url:"namespacemembers.html#index_c"},
-{text:"d",url:"namespacemembers.html#index_d"},
-{text:"g",url:"namespacemembers.html#index_g"},
-{text:"i",url:"namespacemembers.html#index_i"},
-{text:"k",url:"namespacemembers.html#index_k"},
-{text:"m",url:"namespacemembers.html#index_m"},
-{text:"n",url:"namespacemembers.html#index_n"},
-{text:"o",url:"namespacemembers.html#index_o"},
-{text:"p",url:"namespacemembers.html#index_p"},
-{text:"r",url:"namespacemembers.html#index_r"},
-{text:"s",url:"namespacemembers.html#index_s"},
-{text:"u",url:"namespacemembers.html#index_u"},
-{text:"v",url:"namespacemembers.html#index_v"}]},
-{text:"Functions",url:"namespacemembers_func.html"},
-{text:"Variables",url:"namespacemembers_vars.html"},
-{text:"Enumerations",url:"namespacemembers_enum.html"},
-{text:"Enumerator",url:"namespacemembers_eval.html"}]}]},
-{text:"Classes",url:"annotated.html",children:[
-{text:"Class List",url:"annotated.html"},
-{text:"Class Index",url:"classes.html"},
-{text:"Class Hierarchy",url:"hierarchy.html"},
-{text:"Class Members",url:"functions.html",children:[
-{text:"All",url:"functions.html",children:[
-{text:"a",url:"functions.html#index_a"},
-{text:"c",url:"functions.html#index_c"},
-{text:"e",url:"functions.html#index_e"},
-{text:"f",url:"functions.html#index_f"},
-{text:"g",url:"functions.html#index_g"},
-{text:"i",url:"functions.html#index_i"},
-{text:"l",url:"functions.html#index_l"},
-{text:"m",url:"functions.html#index_m"},
-{text:"n",url:"functions.html#index_n"},
-{text:"o",url:"functions.html#index_o"},
-{text:"p",url:"functions.html#index_p"},
-{text:"r",url:"functions.html#index_r"},
-{text:"s",url:"functions.html#index_s"},
-{text:"t",url:"functions.html#index_t"},
-{text:"u",url:"functions.html#index_u"},
-{text:"v",url:"functions.html#index_v"},
-{text:"w",url:"functions.html#index_w"}]},
-{text:"Functions",url:"functions_func.html",children:[
-{text:"a",url:"functions_func.html#index_a"},
-{text:"c",url:"functions_func.html#index_c"},
-{text:"e",url:"functions_func.html#index_e"},
-{text:"f",url:"functions_func.html#index_f"},
-{text:"g",url:"functions_func.html#index_g"},
-{text:"i",url:"functions_func.html#index_i"},
-{text:"l",url:"functions_func.html#index_l"},
-{text:"o",url:"functions_func.html#index_o"},
-{text:"p",url:"functions_func.html#index_p"},
-{text:"r",url:"functions_func.html#index_r"},
-{text:"s",url:"functions_func.html#index_s"},
-{text:"t",url:"functions_func.html#index_t"},
-{text:"u",url:"functions_func.html#index_u"},
-{text:"v",url:"functions_func.html#index_v"},
-{text:"w",url:"functions_func.html#index_w"}]},
-{text:"Variables",url:"functions_vars.html"}]}]},
-{text:"Files",url:"files.html",children:[
-{text:"File List",url:"files.html"}]}]}
diff --git a/docs/reference/namespacemembers.html b/docs/reference/namespacemembers.html
deleted file mode 100644
index 9f20db9..0000000
--- a/docs/reference/namespacemembers.html
+++ /dev/null
@@ -1,259 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Namespace Members</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="contents">
-<div class="textblock">Here is a list of all documented namespace members with links to the namespaces they belong to:</div>
-
-<h3><a id="index_a"></a>- a -</h3><ul>
-<li>Allocate
-: <a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa8485ca716c8cd4aafee372fd7028c123">oboe</a>
-</li>
-<li>AudioApi
-: <a class="el" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">oboe</a>
-</li>
-<li>AudioFormat
-: <a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">oboe</a>
-</li>
-</ul>
-
-
-<h3><a id="index_c"></a>- c -</h3><ul>
-<li>Camcorder
-: <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a6e8ef178769235d18b44fe2bb5ab33fe">oboe</a>
-</li>
-<li>ChannelCount
-: <a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029">oboe</a>
-</li>
-<li>ContentType
-: <a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">oboe</a>
-</li>
-<li>convertFloatToPcm16()
-: <a class="el" href="namespaceoboe.html#adbda063116feb9fa98a31ee820170060">oboe</a>
-</li>
-<li>convertFormatToSizeInBytes()
-: <a class="el" href="namespaceoboe.html#ac67383a3df0f6e7a51f8415ffd9fdaca">oboe</a>
-</li>
-<li>convertPcm16ToFloat()
-: <a class="el" href="namespaceoboe.html#ad17bee42828d13f2ef62a889e175c643">oboe</a>
-</li>
-<li>convertToText()
-: <a class="el" href="namespaceoboe.html#af65aaea3c5d82eee6906664d61c094b3">oboe</a>
-</li>
-</ul>
-
-
-<h3><a id="index_d"></a>- d -</h3><ul>
-<li>DataCallbackResult
-: <a class="el" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">oboe</a>
-</li>
-<li>Direction
-: <a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">oboe</a>
-</li>
-</ul>
-
-
-<h3><a id="index_g"></a>- g -</h3><ul>
-<li>Generic
-: <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a0ba6f369e7f8a700c14afe2992290544">oboe</a>
-</li>
-<li>getPropertyInteger()
-: <a class="el" href="namespaceoboe.html#a4284cffcf4d852ca4f357429303d7af5">oboe</a>
-</li>
-<li>getPropertyString()
-: <a class="el" href="namespaceoboe.html#a1ff1f1323d722494dac353a6b4d1bd5b">oboe</a>
-</li>
-<li>getSdkVersion()
-: <a class="el" href="namespaceoboe.html#a54528938e9fccab7ad8947ccf0e409db">oboe</a>
-</li>
-</ul>
-
-
-<h3><a id="index_i"></a>- i -</h3><ul>
-<li>InputPreset
-: <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">oboe</a>
-</li>
-</ul>
-
-
-<h3><a id="index_k"></a>- k -</h3><ul>
-<li>kDefaultTimeoutNanos
-: <a class="el" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">oboe</a>
-</li>
-<li>kMillisPerSecond
-: <a class="el" href="namespaceoboe.html#ad1bb9f5626cec20d3a052a8721959873">oboe</a>
-</li>
-<li>kNanosPerMicrosecond
-: <a class="el" href="namespaceoboe.html#aedef0759ae3622b6f0324799bcbdebf0">oboe</a>
-</li>
-<li>kNanosPerMillisecond
-: <a class="el" href="namespaceoboe.html#a831e887150474c087170679eaca8672b">oboe</a>
-</li>
-<li>kNanosPerSecond
-: <a class="el" href="namespaceoboe.html#a5948466b593c4eab65f7025846a39f51">oboe</a>
-</li>
-<li>kUnspecified
-: <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">oboe</a>
-</li>
-</ul>
-
-
-<h3><a id="index_m"></a>- m -</h3><ul>
-<li>Mono
-: <a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a8be103218645e121b51078620f452c79">oboe</a>
-</li>
-<li>Movie
-: <a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba8b3b366178c2b7b1688bca6cd33758b1">oboe</a>
-</li>
-<li>Music
-: <a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604bac156fcc7b29059305cef26f3904d4517">oboe</a>
-</li>
-</ul>
-
-
-<h3><a id="index_n"></a>- n -</h3><ul>
-<li>None
-: <a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa58c518b26e83ea48393a76f6c9ecb51f">oboe</a>
-</li>
-</ul>
-
-
-<h3><a id="index_o"></a>- o -</h3><ul>
-<li>operator&lt;&lt;()
-: <a class="el" href="namespaceoboe.html#aa403103686222502d1cfc47bafc10aeb">oboe</a>
-</li>
-</ul>
-
-
-<h3><a id="index_p"></a>- p -</h3><ul>
-<li>PerformanceMode
-: <a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">oboe</a>
-</li>
-</ul>
-
-
-<h3><a id="index_r"></a>- r -</h3><ul>
-<li>Result
-: <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe</a>
-</li>
-</ul>
-
-
-<h3><a id="index_s"></a>- s -</h3><ul>
-<li>SampleRateConversionQuality
-: <a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">oboe</a>
-</li>
-<li>SessionId
-: <a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">oboe</a>
-</li>
-<li>SharingMode
-: <a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">oboe</a>
-</li>
-<li>Sonification
-: <a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba0885eef555037e94a7cf39fe683c2799">oboe</a>
-</li>
-<li>Speech
-: <a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba3dc48a4b4619aa4edd1da7b937b4dcd1">oboe</a>
-</li>
-<li>Stereo
-: <a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a534e646333ca7568317b171ea96b89ba">oboe</a>
-</li>
-<li>StreamState
-: <a class="el" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">oboe</a>
-</li>
-</ul>
-
-
-<h3><a id="index_u"></a>- u -</h3><ul>
-<li>Unprocessed
-: <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06acad9424158aefae0af7975901b11d85f">oboe</a>
-</li>
-<li>Unspecified
-: <a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a946257a568f77c12df4fc4c49125da76">oboe</a>
-</li>
-<li>Usage
-: <a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">oboe</a>
-</li>
-</ul>
-
-
-<h3><a id="index_v"></a>- v -</h3><ul>
-<li>VoiceCommunication
-: <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a1862e72c9730c448fbec6f61a5d8234d">oboe</a>
-</li>
-<li>VoicePerformance
-: <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06ad19edec0a23e435c774bf3bbcf1d999c">oboe</a>
-</li>
-<li>VoiceRecognition
-: <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06af6e440b4e9edf49afe18aa4be77be6fc">oboe</a>
-</li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/namespacemembers_enum.html b/docs/reference/namespacemembers_enum.html
deleted file mode 100644
index 5e2c920..0000000
--- a/docs/reference/namespacemembers_enum.html
+++ /dev/null
@@ -1,118 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Namespace Members</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="contents">
-&#160;<ul>
-<li>AudioApi
-: <a class="el" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">oboe</a>
-</li>
-<li>AudioFormat
-: <a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">oboe</a>
-</li>
-<li>ChannelCount
-: <a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029">oboe</a>
-</li>
-<li>ContentType
-: <a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">oboe</a>
-</li>
-<li>DataCallbackResult
-: <a class="el" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">oboe</a>
-</li>
-<li>Direction
-: <a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">oboe</a>
-</li>
-<li>InputPreset
-: <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">oboe</a>
-</li>
-<li>PerformanceMode
-: <a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">oboe</a>
-</li>
-<li>Result
-: <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe</a>
-</li>
-<li>SampleRateConversionQuality
-: <a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">oboe</a>
-</li>
-<li>SessionId
-: <a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">oboe</a>
-</li>
-<li>SharingMode
-: <a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">oboe</a>
-</li>
-<li>StreamState
-: <a class="el" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">oboe</a>
-</li>
-<li>Usage
-: <a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">oboe</a>
-</li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/namespacemembers_eval.html b/docs/reference/namespacemembers_eval.html
deleted file mode 100644
index 004d6ca..0000000
--- a/docs/reference/namespacemembers_eval.html
+++ /dev/null
@@ -1,121 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Namespace Members</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="contents">
-&#160;<ul>
-<li>Allocate
-: <a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa8485ca716c8cd4aafee372fd7028c123">oboe</a>
-</li>
-<li>Camcorder
-: <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a6e8ef178769235d18b44fe2bb5ab33fe">oboe</a>
-</li>
-<li>Generic
-: <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a0ba6f369e7f8a700c14afe2992290544">oboe</a>
-</li>
-<li>Mono
-: <a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a8be103218645e121b51078620f452c79">oboe</a>
-</li>
-<li>Movie
-: <a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba8b3b366178c2b7b1688bca6cd33758b1">oboe</a>
-</li>
-<li>Music
-: <a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604bac156fcc7b29059305cef26f3904d4517">oboe</a>
-</li>
-<li>None
-: <a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa58c518b26e83ea48393a76f6c9ecb51f">oboe</a>
-</li>
-<li>Sonification
-: <a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba0885eef555037e94a7cf39fe683c2799">oboe</a>
-</li>
-<li>Speech
-: <a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba3dc48a4b4619aa4edd1da7b937b4dcd1">oboe</a>
-</li>
-<li>Stereo
-: <a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a534e646333ca7568317b171ea96b89ba">oboe</a>
-</li>
-<li>Unprocessed
-: <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06acad9424158aefae0af7975901b11d85f">oboe</a>
-</li>
-<li>Unspecified
-: <a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a946257a568f77c12df4fc4c49125da76">oboe</a>
-</li>
-<li>VoiceCommunication
-: <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a1862e72c9730c448fbec6f61a5d8234d">oboe</a>
-</li>
-<li>VoicePerformance
-: <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06ad19edec0a23e435c774bf3bbcf1d999c">oboe</a>
-</li>
-<li>VoiceRecognition
-: <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06af6e440b4e9edf49afe18aa4be77be6fc">oboe</a>
-</li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/namespacemembers_func.html b/docs/reference/namespacemembers_func.html
deleted file mode 100644
index ab074f0..0000000
--- a/docs/reference/namespacemembers_func.html
+++ /dev/null
@@ -1,100 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Namespace Members</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="contents">
-&#160;<ul>
-<li>convertFloatToPcm16()
-: <a class="el" href="namespaceoboe.html#adbda063116feb9fa98a31ee820170060">oboe</a>
-</li>
-<li>convertFormatToSizeInBytes()
-: <a class="el" href="namespaceoboe.html#ac67383a3df0f6e7a51f8415ffd9fdaca">oboe</a>
-</li>
-<li>convertPcm16ToFloat()
-: <a class="el" href="namespaceoboe.html#ad17bee42828d13f2ef62a889e175c643">oboe</a>
-</li>
-<li>convertToText()
-: <a class="el" href="namespaceoboe.html#af65aaea3c5d82eee6906664d61c094b3">oboe</a>
-</li>
-<li>getPropertyInteger()
-: <a class="el" href="namespaceoboe.html#a4284cffcf4d852ca4f357429303d7af5">oboe</a>
-</li>
-<li>getPropertyString()
-: <a class="el" href="namespaceoboe.html#a1ff1f1323d722494dac353a6b4d1bd5b">oboe</a>
-</li>
-<li>getSdkVersion()
-: <a class="el" href="namespaceoboe.html#a54528938e9fccab7ad8947ccf0e409db">oboe</a>
-</li>
-<li>operator&lt;&lt;()
-: <a class="el" href="namespaceoboe.html#aa403103686222502d1cfc47bafc10aeb">oboe</a>
-</li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/namespacemembers_vars.html b/docs/reference/namespacemembers_vars.html
deleted file mode 100644
index 745e0d6..0000000
--- a/docs/reference/namespacemembers_vars.html
+++ /dev/null
@@ -1,94 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Namespace Members</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="contents">
-&#160;<ul>
-<li>kDefaultTimeoutNanos
-: <a class="el" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">oboe</a>
-</li>
-<li>kMillisPerSecond
-: <a class="el" href="namespaceoboe.html#ad1bb9f5626cec20d3a052a8721959873">oboe</a>
-</li>
-<li>kNanosPerMicrosecond
-: <a class="el" href="namespaceoboe.html#aedef0759ae3622b6f0324799bcbdebf0">oboe</a>
-</li>
-<li>kNanosPerMillisecond
-: <a class="el" href="namespaceoboe.html#a831e887150474c087170679eaca8672b">oboe</a>
-</li>
-<li>kNanosPerSecond
-: <a class="el" href="namespaceoboe.html#a5948466b593c4eab65f7025846a39f51">oboe</a>
-</li>
-<li>kUnspecified
-: <a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">oboe</a>
-</li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/namespaceoboe.html b/docs/reference/namespaceoboe.html
deleted file mode 100644
index a337dd7..0000000
--- a/docs/reference/namespaceoboe.html
+++ /dev/null
@@ -1,1079 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe Namespace Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="#nested-classes">Classes</a> &#124;
-<a href="#typedef-members">Typedefs</a> &#124;
-<a href="#enum-members">Enumerations</a> &#124;
-<a href="#func-members">Functions</a> &#124;
-<a href="#var-members">Variables</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe Namespace Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="nested-classes"></a>
-Classes</h2></td></tr>
-<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">class &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a></td></tr>
-<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">class &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_base.html">AudioStreamBase</a></td></tr>
-<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">class &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_builder.html">AudioStreamBuilder</a></td></tr>
-<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">class &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_callback.html">AudioStreamCallback</a></td></tr>
-<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">class &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_data_callback.html">AudioStreamDataCallback</a></td></tr>
-<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">class &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_audio_stream_error_callback.html">AudioStreamErrorCallback</a></td></tr>
-<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">class &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_default_stream_values.html">DefaultStreamValues</a></td></tr>
-<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">struct &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structoboe_1_1_frame_timestamp.html">FrameTimestamp</a></td></tr>
-<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">class &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_latency_tuner.html">LatencyTuner</a></td></tr>
-<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">class &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_oboe_globals.html">OboeGlobals</a></td></tr>
-<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">class &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a></td></tr>
-<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">class &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classoboe_1_1_stabilized_callback.html">StabilizedCallback</a></td></tr>
-<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">struct &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structoboe_1_1_stream_deleter_functor.html">StreamDeleterFunctor</a></td></tr>
-<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">struct &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structoboe_1_1_version.html">Version</a></td></tr>
-<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table><table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="typedef-members"></a>
-Typedefs</h2></td></tr>
-<tr class="memitem:a2b3b25550ebb0c6f792d0d5b870359cd"><td class="memItemLeft" align="right" valign="top"><a id="a2b3b25550ebb0c6f792d0d5b870359cd"></a>
-using&#160;</td><td class="memItemRight" valign="bottom"><b>ManagedStream</b> = std::unique_ptr&lt; <a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a>, <a class="el" href="structoboe_1_1_stream_deleter_functor.html">StreamDeleterFunctor</a> &gt;</td></tr>
-<tr class="separator:a2b3b25550ebb0c6f792d0d5b870359cd"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table><table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="enum-members"></a>
-Enumerations</h2></td></tr>
-<tr class="memitem:a89fa2ce046723764618c29db737917f6"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">StreamState</a> : int32_t { <br />
-&#160;&#160;<b>Uninitialized</b> = 0, 
-<b>Unknown</b> = 1, 
-<b>Open</b> = 2, 
-<b>Starting</b> = 3, 
-<br />
-&#160;&#160;<b>Started</b> = 4, 
-<b>Pausing</b> = 5, 
-<b>Paused</b> = 6, 
-<b>Flushing</b> = 7, 
-<br />
-&#160;&#160;<b>Flushed</b> = 8, 
-<b>Stopping</b> = 9, 
-<b>Stopped</b> = 10, 
-<b>Closing</b> = 11, 
-<br />
-&#160;&#160;<b>Closed</b> = 12, 
-<b>Disconnected</b> = 13
-<br />
- }</td></tr>
-<tr class="separator:a89fa2ce046723764618c29db737917f6"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:af2147500089212955498a08ef2edb5ae"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">Direction</a> : int32_t { <a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54">Direction::Output</a> = 0, 
-<a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5aea324118a6721dd6b8a9b9f4e327df2bf5">Direction::Input</a> = 1
- }</td></tr>
-<tr class="separator:af2147500089212955498a08ef2edb5ae"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a92afc593e856571aacbfd02e57075df6"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a> : int32_t { <a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6a4bbb8f967da6d1a610596d7257179c2b">AudioFormat::Invalid</a> = -1, 
-<a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a6fcdc090caeade09d0efd6253932b6f5">Unspecified</a> = 0, 
-<a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6abcd774f891b5f9df7099f3ea75dadf8d">AudioFormat::I16</a> = 1, 
-<a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6a22ae0e2b89e5e3d477f988cc36d3272b">AudioFormat::Float</a> = 2
- }</td></tr>
-<tr class="separator:a92afc593e856571aacbfd02e57075df6"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:af85fc9910a287df6c5df0ed396bb75cd"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">DataCallbackResult</a> : int32_t { <b>Continue</b> = 0, 
-<b>Stop</b> = 1
- }</td></tr>
-<tr class="separator:af85fc9910a287df6c5df0ed396bb75cd"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a486512e787b609c80ba4436f23929af1"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">Result</a> : int32_t { <br />
-&#160;&#160;<b>OK</b> = 0, 
-<b>ErrorBase</b> = -900, 
-<b>ErrorDisconnected</b> = -899, 
-<b>ErrorIllegalArgument</b> = -898, 
-<br />
-&#160;&#160;<b>ErrorInternal</b> = -896, 
-<b>ErrorInvalidState</b> = -895, 
-<b>ErrorInvalidHandle</b> = -892, 
-<b>ErrorUnimplemented</b> = -890, 
-<br />
-&#160;&#160;<b>ErrorUnavailable</b> = -889, 
-<b>ErrorNoFreeHandles</b> = -888, 
-<b>ErrorNoMemory</b> = -887, 
-<b>ErrorNull</b> = -886, 
-<br />
-&#160;&#160;<b>ErrorTimeout</b> = -885, 
-<b>ErrorWouldBlock</b> = -884, 
-<b>ErrorInvalidFormat</b> = -883, 
-<b>ErrorOutOfRange</b> = -882, 
-<br />
-&#160;&#160;<b>ErrorNoService</b> = -881, 
-<b>ErrorInvalidRate</b> = -880, 
-<b>Reserved1</b>, 
-<b>Reserved2</b>, 
-<br />
-&#160;&#160;<b>Reserved3</b>, 
-<b>Reserved4</b>, 
-<b>Reserved5</b>, 
-<b>Reserved6</b>, 
-<br />
-&#160;&#160;<b>Reserved7</b>, 
-<b>Reserved8</b>, 
-<b>Reserved9</b>, 
-<b>Reserved10</b>, 
-<br />
-&#160;&#160;<b>ErrorClosed</b>
-<br />
- }</td></tr>
-<tr class="separator:a486512e787b609c80ba4436f23929af1"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a8330247b25429953a08354f41834d520"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">SharingMode</a> : int32_t { <a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520a2ef50b4c466304dc6ac77bac8a779971">SharingMode::Exclusive</a> = 0, 
-<a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca">SharingMode::Shared</a> = 1
- }</td></tr>
-<tr class="separator:a8330247b25429953a08354f41834d520"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a1068781f3920654b1bfd7ed136468184"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">PerformanceMode</a> : int32_t { <a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa6adf97f83acf6453d4a6a4b1070f3754">None</a> = 10, 
-<a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184abbad080463ed11f9d77797c04aa1e5b1">PerformanceMode::PowerSaving</a> = 11, 
-<a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184a611907b5ab1865515c35357efa41a9b9">PerformanceMode::LowLatency</a> = 12
- }</td></tr>
-<tr class="separator:a1068781f3920654b1bfd7ed136468184"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a92972414867c81d5974cb2ed7abefbf6"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">AudioApi</a> : int32_t { <a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a6fcdc090caeade09d0efd6253932b6f5">Unspecified</a> = kUnspecified, 
-<a class="el" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a24e758ea9c1e842ef71cc8ff8b63fa9b">AudioApi::OpenSLES</a>, 
-<a class="el" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a99780b1e8d754eb42abed0ca5253e55b">AudioApi::AAudio</a>
- }</td></tr>
-<tr class="separator:a92972414867c81d5974cb2ed7abefbf6"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a82f3720eba7654aceb7282be36f9ff1d"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">SampleRateConversionQuality</a> : int32_t { <br />
-&#160;&#160;<a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa6adf97f83acf6453d4a6a4b1070f3754">None</a>, 
-<a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1da90fd7fdf6f41406a75e5265b9583bb4e">SampleRateConversionQuality::Fastest</a>, 
-<b>Low</b>, 
-<b>Medium</b>, 
-<br />
-&#160;&#160;<b>High</b>, 
-<a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1da68ef004de6166492c1d668eb8efe09bd">SampleRateConversionQuality::Best</a>
-<br />
- }</td></tr>
-<tr class="separator:a82f3720eba7654aceb7282be36f9ff1d"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a104ee8396c173fefac429759ea3c21a0"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">Usage</a> : int32_t { <br />
-&#160;&#160;<a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74">Usage::Media</a> = 1, 
-<a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a5bad8854288c956062ec1d4d7c14fed6">VoiceCommunication</a> = 2, 
-<a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a404f62633744bf4da0c6a27a2b78ce74">Usage::VoiceCommunicationSignalling</a> = 3, 
-<a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a46c4c4d980dfe025ae5b35aa0011dde4">Usage::Alarm</a> = 4, 
-<br />
-&#160;&#160;<a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a96d008db67fc0b5551a926842bbb6a71">Usage::Notification</a> = 5, 
-<a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a4e7a4b08274d472394b740a20d3bbdaf">Usage::NotificationRingtone</a> = 6, 
-<a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a089240b5380dbd12f1eac0ec258a3b2f">Usage::NotificationEvent</a> = 10, 
-<a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a639ffd54516c1a84a288a363c9469df8">Usage::AssistanceAccessibility</a> = 11, 
-<br />
-&#160;&#160;<a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0ade058a1314f9a8504593259ff4f21a1e">Usage::AssistanceNavigationGuidance</a> = 12, 
-<a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a1ce57a0572748beebfc0c664ca1077e7">Usage::AssistanceSonification</a> = 13, 
-<a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a63d72051e901c069f8aa1b32aa0c43bb">Usage::Game</a> = 14, 
-<a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a9b1363da9503dbd4142c0274a88e8d4b">Usage::Assistant</a> = 16
-<br />
- }</td></tr>
-<tr class="separator:a104ee8396c173fefac429759ea3c21a0"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a2a3cec6f021c1a324df60273710c604b"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">ContentType</a> : int32_t { <a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba3dc48a4b4619aa4edd1da7b937b4dcd1">Speech</a> = 1, 
-<a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604bac156fcc7b29059305cef26f3904d4517">Music</a> = 2, 
-<a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba8b3b366178c2b7b1688bca6cd33758b1">Movie</a> = 3, 
-<a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba0885eef555037e94a7cf39fe683c2799">Sonification</a> = 4
- }</td></tr>
-<tr class="separator:a2a3cec6f021c1a324df60273710c604b"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a4477ed232b02e2694d9309baf55a8f06"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">InputPreset</a> : int32_t { <br />
-&#160;&#160;<a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a0ba6f369e7f8a700c14afe2992290544">Generic</a> = 1, 
-<a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a6e8ef178769235d18b44fe2bb5ab33fe">Camcorder</a> = 5, 
-<a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06af6e440b4e9edf49afe18aa4be77be6fc">VoiceRecognition</a> = 6, 
-<a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a1862e72c9730c448fbec6f61a5d8234d">VoiceCommunication</a> = 7, 
-<br />
-&#160;&#160;<a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a5bad8854288c956062ec1d4d7c14fed6">VoiceCommunication</a> = 2, 
-<a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06acad9424158aefae0af7975901b11d85f">Unprocessed</a> = 9, 
-<a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06ad19edec0a23e435c774bf3bbcf1d999c">VoicePerformance</a> = 10
-<br />
- }</td></tr>
-<tr class="separator:a4477ed232b02e2694d9309baf55a8f06"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5752250c10e96179e3618d7f72937eaf"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">SessionId</a> { <a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa58c518b26e83ea48393a76f6c9ecb51f">None</a> = -1, 
-<a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa6adf97f83acf6453d4a6a4b1070f3754">None</a> = 10, 
-<a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa6adf97f83acf6453d4a6a4b1070f3754">None</a>, 
-<a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa8485ca716c8cd4aafee372fd7028c123">Allocate</a> = 0
- }</td></tr>
-<tr class="separator:a5752250c10e96179e3618d7f72937eaf"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a522e6806948369987639a0d1df03c029"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029">ChannelCount</a> : int32_t { <br />
-&#160;&#160;<a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a946257a568f77c12df4fc4c49125da76">Unspecified</a> = kUnspecified, 
-<a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a6fcdc090caeade09d0efd6253932b6f5">Unspecified</a> = 0, 
-<a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a6fcdc090caeade09d0efd6253932b6f5">Unspecified</a> = kUnspecified, 
-<a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a8be103218645e121b51078620f452c79">Mono</a> = 1, 
-<br />
-&#160;&#160;<a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029a534e646333ca7568317b171ea96b89ba">Stereo</a> = 2
-<br />
- }</td></tr>
-<tr class="separator:a522e6806948369987639a0d1df03c029"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table><table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="func-members"></a>
-Functions</h2></td></tr>
-<tr class="memitem:aa403103686222502d1cfc47bafc10aeb"><td class="memTemplParams" colspan="2">template&lt;typename T &gt; </td></tr>
-<tr class="memitem:aa403103686222502d1cfc47bafc10aeb"><td class="memTemplItemLeft" align="right" valign="top">std::ostream &amp;&#160;</td><td class="memTemplItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#aa403103686222502d1cfc47bafc10aeb">operator&lt;&lt;</a> (std::ostream &amp;strm, const <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt; T &gt; &amp;result)</td></tr>
-<tr class="separator:aa403103686222502d1cfc47bafc10aeb"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:adbda063116feb9fa98a31ee820170060"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#adbda063116feb9fa98a31ee820170060">convertFloatToPcm16</a> (const float *source, int16_t *destination, int32_t numSamples)</td></tr>
-<tr class="separator:adbda063116feb9fa98a31ee820170060"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ad17bee42828d13f2ef62a889e175c643"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#ad17bee42828d13f2ef62a889e175c643">convertPcm16ToFloat</a> (const int16_t *source, float *destination, int32_t numSamples)</td></tr>
-<tr class="separator:ad17bee42828d13f2ef62a889e175c643"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ac67383a3df0f6e7a51f8415ffd9fdaca"><td class="memItemLeft" align="right" valign="top">int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#ac67383a3df0f6e7a51f8415ffd9fdaca">convertFormatToSizeInBytes</a> (<a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a> format)</td></tr>
-<tr class="separator:ac67383a3df0f6e7a51f8415ffd9fdaca"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:af65aaea3c5d82eee6906664d61c094b3"><td class="memTemplParams" colspan="2">template&lt;typename FromType &gt; </td></tr>
-<tr class="memitem:af65aaea3c5d82eee6906664d61c094b3"><td class="memTemplItemLeft" align="right" valign="top">const char *&#160;</td><td class="memTemplItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#af65aaea3c5d82eee6906664d61c094b3">convertToText</a> (FromType input)</td></tr>
-<tr class="separator:af65aaea3c5d82eee6906664d61c094b3"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a1ff1f1323d722494dac353a6b4d1bd5b"><td class="memItemLeft" align="right" valign="top">std::string&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a1ff1f1323d722494dac353a6b4d1bd5b">getPropertyString</a> (const char *name)</td></tr>
-<tr class="separator:a1ff1f1323d722494dac353a6b4d1bd5b"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a4284cffcf4d852ca4f357429303d7af5"><td class="memItemLeft" align="right" valign="top">int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a4284cffcf4d852ca4f357429303d7af5">getPropertyInteger</a> (const char *name, int defaultValue)</td></tr>
-<tr class="separator:a4284cffcf4d852ca4f357429303d7af5"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a54528938e9fccab7ad8947ccf0e409db"><td class="memItemLeft" align="right" valign="top">int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a54528938e9fccab7ad8947ccf0e409db">getSdkVersion</a> ()</td></tr>
-<tr class="separator:a54528938e9fccab7ad8947ccf0e409db"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a78417a797f5306478c8a37cee53fd12a"><td class="memItemLeft" align="right" valign="top"><a id="a78417a797f5306478c8a37cee53fd12a"></a>
-const char *&#160;</td><td class="memItemRight" valign="bottom"><b>getVersionText</b> ()</td></tr>
-<tr class="separator:a78417a797f5306478c8a37cee53fd12a"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table><table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="var-members"></a>
-Variables</h2></td></tr>
-<tr class="memitem:aab8f5f081a8b2147e16ec920347c1b5c"><td class="memItemLeft" align="right" valign="top">constexpr int64_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c">kDefaultTimeoutNanos</a> = (2000 * <a class="el" href="namespaceoboe.html#a831e887150474c087170679eaca8672b">kNanosPerMillisecond</a>)</td></tr>
-<tr class="separator:aab8f5f081a8b2147e16ec920347c1b5c"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ab0772052200184e514082eaa89be7905"><td class="memItemLeft" align="right" valign="top">constexpr int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#ab0772052200184e514082eaa89be7905">kUnspecified</a> = 0</td></tr>
-<tr class="separator:ab0772052200184e514082eaa89be7905"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:aedef0759ae3622b6f0324799bcbdebf0"><td class="memItemLeft" align="right" valign="top">constexpr int64_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#aedef0759ae3622b6f0324799bcbdebf0">kNanosPerMicrosecond</a> = 1000</td></tr>
-<tr class="separator:aedef0759ae3622b6f0324799bcbdebf0"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a831e887150474c087170679eaca8672b"><td class="memItemLeft" align="right" valign="top">constexpr int64_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a831e887150474c087170679eaca8672b">kNanosPerMillisecond</a> = <a class="el" href="namespaceoboe.html#aedef0759ae3622b6f0324799bcbdebf0">kNanosPerMicrosecond</a> * 1000</td></tr>
-<tr class="separator:a831e887150474c087170679eaca8672b"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ad1bb9f5626cec20d3a052a8721959873"><td class="memItemLeft" align="right" valign="top">constexpr int64_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#ad1bb9f5626cec20d3a052a8721959873">kMillisPerSecond</a> = 1000</td></tr>
-<tr class="separator:ad1bb9f5626cec20d3a052a8721959873"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5948466b593c4eab65f7025846a39f51"><td class="memItemLeft" align="right" valign="top">constexpr int64_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespaceoboe.html#a5948466b593c4eab65f7025846a39f51">kNanosPerSecond</a> = <a class="el" href="namespaceoboe.html#a831e887150474c087170679eaca8672b">kNanosPerMillisecond</a> * <a class="el" href="namespaceoboe.html#ad1bb9f5626cec20d3a052a8721959873">kMillisPerSecond</a></td></tr>
-<tr class="separator:a5948466b593c4eab65f7025846a39f51"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
-<div class="textblock"><p>WARNING - UNDER CONSTRUCTION - THIS API WILL CHANGE. </p>
-</div><h2 class="groupheader">Enumeration Type Documentation</h2>
-<a id="a92972414867c81d5974cb2ed7abefbf6"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a92972414867c81d5974cb2ed7abefbf6">&#9670;&nbsp;</a></span>AudioApi</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">enum <a class="el" href="namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6">oboe::AudioApi</a> : int32_t</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">strong</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The underlying audio API used by the audio stream. </p>
-<table class="fieldtable">
-<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="a522e6806948369987639a0d1df03c029a6fcdc090caeade09d0efd6253932b6f5"></a>Unspecified&#160;</td><td class="fielddoc"><p>Try to use AAudio. If not available then use OpenSL ES. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a92972414867c81d5974cb2ed7abefbf6a24e758ea9c1e842ef71cc8ff8b63fa9b"></a>OpenSLES&#160;</td><td class="fielddoc"><p>Use OpenSL ES. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a92972414867c81d5974cb2ed7abefbf6a99780b1e8d754eb42abed0ca5253e55b"></a>AAudio&#160;</td><td class="fielddoc"><p>Try to use AAudio. Fail if unavailable. </p>
-</td></tr>
-</table>
-
-</div>
-</div>
-<a id="a92afc593e856571aacbfd02e57075df6"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a92afc593e856571aacbfd02e57075df6">&#9670;&nbsp;</a></span>AudioFormat</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">enum <a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">oboe::AudioFormat</a> : int32_t</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">strong</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The format of audio samples. </p>
-<table class="fieldtable">
-<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="a92afc593e856571aacbfd02e57075df6a4bbb8f967da6d1a610596d7257179c2b"></a>Invalid&#160;</td><td class="fielddoc"><p>Invalid format. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a522e6806948369987639a0d1df03c029a6fcdc090caeade09d0efd6253932b6f5"></a>Unspecified&#160;</td><td class="fielddoc"><p>Unspecified format. Format will be decided by Oboe. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a92afc593e856571aacbfd02e57075df6abcd774f891b5f9df7099f3ea75dadf8d"></a>I16&#160;</td><td class="fielddoc"><p>Signed 16-bit integers. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a92afc593e856571aacbfd02e57075df6a22ae0e2b89e5e3d477f988cc36d3272b"></a>Float&#160;</td><td class="fielddoc"><p>Single precision floating points. </p>
-</td></tr>
-</table>
-
-</div>
-</div>
-<a id="a522e6806948369987639a0d1df03c029"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a522e6806948369987639a0d1df03c029">&#9670;&nbsp;</a></span>ChannelCount</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">enum <a class="el" href="namespaceoboe.html#a522e6806948369987639a0d1df03c029">oboe::ChannelCount</a> : int32_t</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>The channel count of the audio stream. The underlying type is <code>int32_t</code>. Use of this enum is convenient to avoid "magic" numbers when specifying the channel count.</p>
-<p>For example, you can write <code>builder.setChannelCount(ChannelCount::Stereo)</code> rather than <code>builder.setChannelCount(2)</code> </p>
-<table class="fieldtable">
-<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="a522e6806948369987639a0d1df03c029a946257a568f77c12df4fc4c49125da76"></a>Unspecified&#160;</td><td class="fielddoc"><p>Audio channel count definition, use Mono or Stereo </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a522e6806948369987639a0d1df03c029a6fcdc090caeade09d0efd6253932b6f5"></a>Unspecified&#160;</td><td class="fielddoc"><p>Unspecified format. Format will be decided by Oboe. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a522e6806948369987639a0d1df03c029a6fcdc090caeade09d0efd6253932b6f5"></a>Unspecified&#160;</td><td class="fielddoc"><p>Try to use AAudio. If not available then use OpenSL ES. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a522e6806948369987639a0d1df03c029a8be103218645e121b51078620f452c79"></a>Mono&#160;</td><td class="fielddoc"><p>Use this for mono audio </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a522e6806948369987639a0d1df03c029a534e646333ca7568317b171ea96b89ba"></a>Stereo&#160;</td><td class="fielddoc"><p>Use this for stereo audio. </p>
-</td></tr>
-</table>
-
-</div>
-</div>
-<a id="a2a3cec6f021c1a324df60273710c604b"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a2a3cec6f021c1a324df60273710c604b">&#9670;&nbsp;</a></span>ContentType</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">enum <a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b">oboe::ContentType</a> : int32_t</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>The ContentType attribute describes <em>what</em> you are playing. It expresses the general category of the content. This information is optional. But in case it is known (for instance <a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba8b3b366178c2b7b1688bca6cd33758b1">Movie</a> for a movie streaming service or <a class="el" href="namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba3dc48a4b4619aa4edd1da7b937b4dcd1">Speech</a> for an audio book application) this information might be used by the audio framework to enforce audio focus.</p>
-<p>Note that these match the equivalent values in AudioAttributes in the Android Java API.</p>
-<p>This attribute only has an effect on Android API 28+. </p>
-<table class="fieldtable">
-<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="a2a3cec6f021c1a324df60273710c604ba3dc48a4b4619aa4edd1da7b937b4dcd1"></a>Speech&#160;</td><td class="fielddoc"><p>Use this for spoken voice, audio books, etcetera. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a2a3cec6f021c1a324df60273710c604bac156fcc7b29059305cef26f3904d4517"></a>Music&#160;</td><td class="fielddoc"><p>Use this for pre-recorded or live music. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a2a3cec6f021c1a324df60273710c604ba8b3b366178c2b7b1688bca6cd33758b1"></a>Movie&#160;</td><td class="fielddoc"><p>Use this for a movie or video soundtrack. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a2a3cec6f021c1a324df60273710c604ba0885eef555037e94a7cf39fe683c2799"></a>Sonification&#160;</td><td class="fielddoc"><p>Use this for sound is designed to accompany a user action, such as a click or beep sound made when the user presses a button. </p>
-</td></tr>
-</table>
-
-</div>
-</div>
-<a id="af85fc9910a287df6c5df0ed396bb75cd"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#af85fc9910a287df6c5df0ed396bb75cd">&#9670;&nbsp;</a></span>DataCallbackResult</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">enum <a class="el" href="namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd">oboe::DataCallbackResult</a> : int32_t</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">strong</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The result of an audio callback. </p>
-
-</div>
-</div>
-<a id="af2147500089212955498a08ef2edb5ae"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#af2147500089212955498a08ef2edb5ae">&#9670;&nbsp;</a></span>Direction</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">enum <a class="el" href="namespaceoboe.html#af2147500089212955498a08ef2edb5ae">oboe::Direction</a> : int32_t</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">strong</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The direction of the stream. </p>
-<table class="fieldtable">
-<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54"></a>Output&#160;</td><td class="fielddoc"><p>Used for playback. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="af2147500089212955498a08ef2edb5aea324118a6721dd6b8a9b9f4e327df2bf5"></a>Input&#160;</td><td class="fielddoc"><p>Used for recording. </p>
-</td></tr>
-</table>
-
-</div>
-</div>
-<a id="a4477ed232b02e2694d9309baf55a8f06"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a4477ed232b02e2694d9309baf55a8f06">&#9670;&nbsp;</a></span>InputPreset</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">enum <a class="el" href="namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06">oboe::InputPreset</a> : int32_t</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>Defines the audio source. An audio source defines both a default physical source of audio signal, and a recording configuration.</p>
-<p>Note that these match the equivalent values in MediaRecorder.AudioSource in the Android Java API.</p>
-<p>This attribute only has an effect on Android API 28+. </p>
-<table class="fieldtable">
-<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="a4477ed232b02e2694d9309baf55a8f06a0ba6f369e7f8a700c14afe2992290544"></a>Generic&#160;</td><td class="fielddoc"><p>Use this preset when other presets do not apply. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a4477ed232b02e2694d9309baf55a8f06a6e8ef178769235d18b44fe2bb5ab33fe"></a>Camcorder&#160;</td><td class="fielddoc"><p>Use this preset when recording video. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a4477ed232b02e2694d9309baf55a8f06af6e440b4e9edf49afe18aa4be77be6fc"></a>VoiceRecognition&#160;</td><td class="fielddoc"><p>Use this preset when doing speech recognition. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a4477ed232b02e2694d9309baf55a8f06a1862e72c9730c448fbec6f61a5d8234d"></a>VoiceCommunication&#160;</td><td class="fielddoc"><p>Use this preset when doing telephony or voice messaging. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a4477ed232b02e2694d9309baf55a8f06a5bad8854288c956062ec1d4d7c14fed6"></a>VoiceCommunication&#160;</td><td class="fielddoc"><p>Use this for voice over IP, telephony, etcetera. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a4477ed232b02e2694d9309baf55a8f06acad9424158aefae0af7975901b11d85f"></a>Unprocessed&#160;</td><td class="fielddoc"><p>Use this preset to obtain an input with no effects. Note that this input will not have automatic gain control so the recorded volume may be very low. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a4477ed232b02e2694d9309baf55a8f06ad19edec0a23e435c774bf3bbcf1d999c"></a>VoicePerformance&#160;</td><td class="fielddoc"><p>Use this preset for capturing audio meant to be processed in real time and played back for live performance (e.g karaoke). The capture path will minimize latency and coupling with playback path. </p>
-</td></tr>
-</table>
-
-</div>
-</div>
-<a id="a1068781f3920654b1bfd7ed136468184"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a1068781f3920654b1bfd7ed136468184">&#9670;&nbsp;</a></span>PerformanceMode</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">enum <a class="el" href="namespaceoboe.html#a1068781f3920654b1bfd7ed136468184">oboe::PerformanceMode</a> : int32_t</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">strong</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The performance mode of the audio stream. </p>
-<table class="fieldtable">
-<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="a5752250c10e96179e3618d7f72937eafa6adf97f83acf6453d4a6a4b1070f3754"></a>None&#160;</td><td class="fielddoc"><p>No particular performance needs. Default. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a1068781f3920654b1bfd7ed136468184abbad080463ed11f9d77797c04aa1e5b1"></a>PowerSaving&#160;</td><td class="fielddoc"><p>Extending battery life is most important. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a1068781f3920654b1bfd7ed136468184a611907b5ab1865515c35357efa41a9b9"></a>LowLatency&#160;</td><td class="fielddoc"><p>Reducing latency is most important. </p>
-</td></tr>
-</table>
-
-</div>
-</div>
-<a id="a486512e787b609c80ba4436f23929af1"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a486512e787b609c80ba4436f23929af1">&#9670;&nbsp;</a></span>Result</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">enum <a class="el" href="namespaceoboe.html#a486512e787b609c80ba4436f23929af1">oboe::Result</a> : int32_t</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">strong</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The result of an operation. All except the <code>OK</code> result indicates that an error occurred. The <code>Result</code> can be converted into a human readable string using <code>convertToText</code>. </p>
-
-</div>
-</div>
-<a id="a82f3720eba7654aceb7282be36f9ff1d"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a82f3720eba7654aceb7282be36f9ff1d">&#9670;&nbsp;</a></span>SampleRateConversionQuality</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">enum <a class="el" href="namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d">oboe::SampleRateConversionQuality</a> : int32_t</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">strong</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Specifies the quality of the sample rate conversion performed by Oboe. Higher quality will require more CPU load. Higher quality conversion will probably be implemented using a sinc based resampler. </p>
-<table class="fieldtable">
-<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="a5752250c10e96179e3618d7f72937eafa6adf97f83acf6453d4a6a4b1070f3754"></a>None&#160;</td><td class="fielddoc"><p>No conversion by Oboe. Underlying APIs may still do conversion. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a82f3720eba7654aceb7282be36f9ff1da90fd7fdf6f41406a75e5265b9583bb4e"></a>Fastest&#160;</td><td class="fielddoc"><p>Fastest conversion but may not sound great. This may be implemented using bilinear interpolation. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a82f3720eba7654aceb7282be36f9ff1da68ef004de6166492c1d668eb8efe09bd"></a>Best&#160;</td><td class="fielddoc"><p>Highest quality conversion, which may be expensive in terms of CPU. </p>
-</td></tr>
-</table>
-
-</div>
-</div>
-<a id="a5752250c10e96179e3618d7f72937eaf"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a5752250c10e96179e3618d7f72937eaf">&#9670;&nbsp;</a></span>SessionId</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">enum <a class="el" href="namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf">oboe::SessionId</a></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>This attribute can be used to allocate a session ID to the audio stream.</p>
-<p>This attribute only has an effect on Android API 28+. </p>
-<table class="fieldtable">
-<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="a5752250c10e96179e3618d7f72937eafa58c518b26e83ea48393a76f6c9ecb51f"></a>None&#160;</td><td class="fielddoc"><p>Do not allocate a session ID. Effects cannot be used with this stream. Default. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a5752250c10e96179e3618d7f72937eafa6adf97f83acf6453d4a6a4b1070f3754"></a>None&#160;</td><td class="fielddoc"><p>No particular performance needs. Default. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a5752250c10e96179e3618d7f72937eafa6adf97f83acf6453d4a6a4b1070f3754"></a>None&#160;</td><td class="fielddoc"><p>No conversion by Oboe. Underlying APIs may still do conversion. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a5752250c10e96179e3618d7f72937eafa8485ca716c8cd4aafee372fd7028c123"></a>Allocate&#160;</td><td class="fielddoc"><p>Allocate a session ID that can be used to attach and control effects using the Java AudioEffects API. Note that the use of this flag may result in higher latency.</p>
-<p>Note that this matches the value of AudioManager.AUDIO_SESSION_ID_GENERATE. </p>
-</td></tr>
-</table>
-
-</div>
-</div>
-<a id="a8330247b25429953a08354f41834d520"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a8330247b25429953a08354f41834d520">&#9670;&nbsp;</a></span>SharingMode</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">enum <a class="el" href="namespaceoboe.html#a8330247b25429953a08354f41834d520">oboe::SharingMode</a> : int32_t</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">strong</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The sharing mode of the audio stream. </p>
-<table class="fieldtable">
-<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="a8330247b25429953a08354f41834d520a2ef50b4c466304dc6ac77bac8a779971"></a>Exclusive&#160;</td><td class="fielddoc"><p>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.</p>
-<p>If you do not need the lowest possible latency then we recommend using Shared, which is the default. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca"></a>Shared&#160;</td><td class="fielddoc"><p>Multiple applications can share the same device. The data from output streams will be mixed by the audio service. The data for input streams will be distributed by the audio service.</p>
-<p>This will have higher latency than the EXCLUSIVE mode. </p>
-</td></tr>
-</table>
-
-</div>
-</div>
-<a id="a89fa2ce046723764618c29db737917f6"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a89fa2ce046723764618c29db737917f6">&#9670;&nbsp;</a></span>StreamState</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">enum <a class="el" href="namespaceoboe.html#a89fa2ce046723764618c29db737917f6">oboe::StreamState</a> : int32_t</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">strong</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The state of the audio stream. </p>
-
-</div>
-</div>
-<a id="a104ee8396c173fefac429759ea3c21a0"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a104ee8396c173fefac429759ea3c21a0">&#9670;&nbsp;</a></span>Usage</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">enum <a class="el" href="namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0">oboe::Usage</a> : int32_t</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">strong</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>The Usage attribute expresses <em>why</em> you are playing a sound, what is this sound used for. This information is used by certain platforms or routing policies to make more refined volume or routing decisions.</p>
-<p>Note that these match the equivalent values in AudioAttributes in the Android Java API.</p>
-<p>This attribute only has an effect on Android API 28+. </p>
-<table class="fieldtable">
-<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74"></a>Media&#160;</td><td class="fielddoc"><p>Use this for streaming media, music performance, video, podcasts, etcetera. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a4477ed232b02e2694d9309baf55a8f06a5bad8854288c956062ec1d4d7c14fed6"></a>VoiceCommunication&#160;</td><td class="fielddoc"><p>Use this for voice over IP, telephony, etcetera. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a104ee8396c173fefac429759ea3c21a0a404f62633744bf4da0c6a27a2b78ce74"></a>VoiceCommunicationSignalling&#160;</td><td class="fielddoc"><p>Use this for sounds associated with telephony such as busy tones, DTMF, etcetera. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a104ee8396c173fefac429759ea3c21a0a46c4c4d980dfe025ae5b35aa0011dde4"></a>Alarm&#160;</td><td class="fielddoc"><p>Use this to demand the users attention. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a104ee8396c173fefac429759ea3c21a0a96d008db67fc0b5551a926842bbb6a71"></a>Notification&#160;</td><td class="fielddoc"><p>Use this for notifying the user when a message has arrived or some other background event has occured. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a104ee8396c173fefac429759ea3c21a0a4e7a4b08274d472394b740a20d3bbdaf"></a>NotificationRingtone&#160;</td><td class="fielddoc"><p>Use this when the phone rings. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a104ee8396c173fefac429759ea3c21a0a089240b5380dbd12f1eac0ec258a3b2f"></a>NotificationEvent&#160;</td><td class="fielddoc"><p>Use this to attract the users attention when, for example, the battery is low. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a104ee8396c173fefac429759ea3c21a0a639ffd54516c1a84a288a363c9469df8"></a>AssistanceAccessibility&#160;</td><td class="fielddoc"><p>Use this for screen readers, etcetera. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a104ee8396c173fefac429759ea3c21a0ade058a1314f9a8504593259ff4f21a1e"></a>AssistanceNavigationGuidance&#160;</td><td class="fielddoc"><p>Use this for driving or navigation directions. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a104ee8396c173fefac429759ea3c21a0a1ce57a0572748beebfc0c664ca1077e7"></a>AssistanceSonification&#160;</td><td class="fielddoc"><p>Use this for user interface sounds, beeps, etcetera. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a104ee8396c173fefac429759ea3c21a0a63d72051e901c069f8aa1b32aa0c43bb"></a>Game&#160;</td><td class="fielddoc"><p>Use this for game audio and sound effects. </p>
-</td></tr>
-<tr><td class="fieldname"><a id="a104ee8396c173fefac429759ea3c21a0a9b1363da9503dbd4142c0274a88e8d4b"></a>Assistant&#160;</td><td class="fielddoc"><p>Use this for audio responses to user queries, audio instructions or help utterances. </p>
-</td></tr>
-</table>
-
-</div>
-</div>
-<h2 class="groupheader">Function Documentation</h2>
-<a id="adbda063116feb9fa98a31ee820170060"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#adbda063116feb9fa98a31ee820170060">&#9670;&nbsp;</a></span>convertFloatToPcm16()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">void oboe::convertFloatToPcm16 </td>
-          <td>(</td>
-          <td class="paramtype">const float *&#160;</td>
-          <td class="paramname"><em>source</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int16_t *&#160;</td>
-          <td class="paramname"><em>destination</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int32_t&#160;</td>
-          <td class="paramname"><em>numSamples</em>&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>Convert an array of floats to an array of 16-bit integers.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">source</td><td>the input array. </td></tr>
-    <tr><td class="paramname">destination</td><td>the output array. </td></tr>
-    <tr><td class="paramname">numSamples</td><td>the number of values to convert. </td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<a id="ac67383a3df0f6e7a51f8415ffd9fdaca"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ac67383a3df0f6e7a51f8415ffd9fdaca">&#9670;&nbsp;</a></span>convertFormatToSizeInBytes()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">int32_t oboe::convertFormatToSizeInBytes </td>
-          <td>(</td>
-          <td class="paramtype"><a class="el" href="namespaceoboe.html#a92afc593e856571aacbfd02e57075df6">AudioFormat</a>&#160;</td>
-          <td class="paramname"><em>format</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<dl class="section return"><dt>Returns</dt><dd>the size of a sample of the given format in bytes or 0 if format is invalid </dd></dl>
-
-</div>
-</div>
-<a id="ad17bee42828d13f2ef62a889e175c643"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ad17bee42828d13f2ef62a889e175c643">&#9670;&nbsp;</a></span>convertPcm16ToFloat()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">void oboe::convertPcm16ToFloat </td>
-          <td>(</td>
-          <td class="paramtype">const int16_t *&#160;</td>
-          <td class="paramname"><em>source</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">float *&#160;</td>
-          <td class="paramname"><em>destination</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int32_t&#160;</td>
-          <td class="paramname"><em>numSamples</em>&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>Convert an array of 16-bit integers to an array of floats.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">source</td><td>the input array. </td></tr>
-    <tr><td class="paramname">destination</td><td>the output array. </td></tr>
-    <tr><td class="paramname">numSamples</td><td>the number of values to convert. </td></tr>
-  </table>
-  </dd>
-</dl>
-
-</div>
-</div>
-<a id="af65aaea3c5d82eee6906664d61c094b3"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#af65aaea3c5d82eee6906664d61c094b3">&#9670;&nbsp;</a></span>convertToText()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<div class="memtemplate">
-template&lt;typename FromType &gt; </div>
-      <table class="memname">
-        <tr>
-          <td class="memname">const char* oboe::convertToText </td>
-          <td>(</td>
-          <td class="paramtype">FromType&#160;</td>
-          <td class="paramname"><em>input</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>The text is the ASCII symbol corresponding to the supplied Oboe enum value, or an English message saying the value is unrecognized. This is intended for developers to use when debugging. It is not for displaying to users.</p>
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">input</td><td>object to convert from. </td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section see"><dt>See also</dt><dd>common/Utilities.cpp for concrete implementations </dd></dl>
-<dl class="section return"><dt>Returns</dt><dd>text representation of an Oboe enum value. There is no need to call free on this. </dd></dl>
-
-</div>
-</div>
-<a id="a4284cffcf4d852ca4f357429303d7af5"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a4284cffcf4d852ca4f357429303d7af5">&#9670;&nbsp;</a></span>getPropertyInteger()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">int oboe::getPropertyInteger </td>
-          <td>(</td>
-          <td class="paramtype">const char *&#160;</td>
-          <td class="paramname"><em>name</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>defaultValue</em>&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">name</td><td></td></tr>
-    <tr><td class="paramname">defaultValue</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>integer value associated with a property or the default value </dd></dl>
-
-</div>
-</div>
-<a id="a1ff1f1323d722494dac353a6b4d1bd5b"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a1ff1f1323d722494dac353a6b4d1bd5b">&#9670;&nbsp;</a></span>getPropertyString()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">std::string oboe::getPropertyString </td>
-          <td>(</td>
-          <td class="paramtype">const char *&#160;</td>
-          <td class="paramname"><em>name</em></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<dl class="params"><dt>Parameters</dt><dd>
-  <table class="params">
-    <tr><td class="paramname">name</td><td></td></tr>
-  </table>
-  </dd>
-</dl>
-<dl class="section return"><dt>Returns</dt><dd>the value of a named system property in a string or empty string </dd></dl>
-
-</div>
-</div>
-<a id="a54528938e9fccab7ad8947ccf0e409db"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a54528938e9fccab7ad8947ccf0e409db">&#9670;&nbsp;</a></span>getSdkVersion()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">int oboe::getSdkVersion </td>
-          <td>(</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>Return the version of the SDK that is currently running.</p>
-<p>For example, on Android, this would return 27 for Oreo 8.1. If the version number cannot be determined then this will return -1.</p>
-<dl class="section return"><dt>Returns</dt><dd>version number or -1 </dd></dl>
-
-</div>
-</div>
-<a id="aa403103686222502d1cfc47bafc10aeb"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aa403103686222502d1cfc47bafc10aeb">&#9670;&nbsp;</a></span>operator&lt;&lt;()</h2>
-
-<div class="memitem">
-<div class="memproto">
-<div class="memtemplate">
-template&lt;typename T &gt; </div>
-      <table class="memname">
-        <tr>
-          <td class="memname">std::ostream&amp; oboe::operator&lt;&lt; </td>
-          <td>(</td>
-          <td class="paramtype">std::ostream &amp;&#160;</td>
-          <td class="paramname"><em>strm</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">const <a class="el" href="classoboe_1_1_result_with_value.html">ResultWithValue</a>&lt; T &gt; &amp;&#160;</td>
-          <td class="paramname"><em>result</em>&#160;</td>
-        </tr>
-        <tr>
-          <td></td>
-          <td>)</td>
-          <td></td><td></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>If the result is <code>OK</code> then return the value, otherwise return a human-readable error message. </p>
-
-</div>
-</div>
-<h2 class="groupheader">Variable Documentation</h2>
-<a id="aab8f5f081a8b2147e16ec920347c1b5c"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aab8f5f081a8b2147e16ec920347c1b5c">&#9670;&nbsp;</a></span>kDefaultTimeoutNanos</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">constexpr int64_t oboe::kDefaultTimeoutNanos = (2000 * <a class="el" href="namespaceoboe.html#a831e887150474c087170679eaca8672b">kNanosPerMillisecond</a>)</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>The default number of nanoseconds to wait for when performing state change operations on the stream, such as <code>start</code> and <code>stop</code>.</p>
-<dl class="section see"><dt>See also</dt><dd><a class="el" href="classoboe_1_1_audio_stream.html#af04f03eb6b64b564f1c4401688987d21">oboe::AudioStream::start</a> </dd></dl>
-
-</div>
-</div>
-<a id="ad1bb9f5626cec20d3a052a8721959873"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ad1bb9f5626cec20d3a052a8721959873">&#9670;&nbsp;</a></span>kMillisPerSecond</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">constexpr int64_t oboe::kMillisPerSecond = 1000</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>The number of milliseconds in a second. 1,000. </p>
-
-</div>
-</div>
-<a id="aedef0759ae3622b6f0324799bcbdebf0"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#aedef0759ae3622b6f0324799bcbdebf0">&#9670;&nbsp;</a></span>kNanosPerMicrosecond</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">constexpr int64_t oboe::kNanosPerMicrosecond = 1000</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>The number of nanoseconds in a microsecond. 1,000. </p>
-
-</div>
-</div>
-<a id="a831e887150474c087170679eaca8672b"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a831e887150474c087170679eaca8672b">&#9670;&nbsp;</a></span>kNanosPerMillisecond</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">constexpr int64_t oboe::kNanosPerMillisecond = <a class="el" href="namespaceoboe.html#aedef0759ae3622b6f0324799bcbdebf0">kNanosPerMicrosecond</a> * 1000</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>The number of nanoseconds in a millisecond. 1,000,000. </p>
-
-</div>
-</div>
-<a id="a5948466b593c4eab65f7025846a39f51"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a5948466b593c4eab65f7025846a39f51">&#9670;&nbsp;</a></span>kNanosPerSecond</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">constexpr int64_t oboe::kNanosPerSecond = <a class="el" href="namespaceoboe.html#a831e887150474c087170679eaca8672b">kNanosPerMillisecond</a> * <a class="el" href="namespaceoboe.html#ad1bb9f5626cec20d3a052a8721959873">kMillisPerSecond</a></td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>The number of nanoseconds in a second. 1,000,000,000. </p>
-
-</div>
-</div>
-<a id="ab0772052200184e514082eaa89be7905"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ab0772052200184e514082eaa89be7905">&#9670;&nbsp;</a></span>kUnspecified</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">constexpr int32_t oboe::kUnspecified = 0</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-<p>Represents any attribute, property or value which hasn't been specified. </p>
-
-</div>
-</div>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/namespaces.html b/docs/reference/namespaces.html
deleted file mode 100644
index 860d475..0000000
--- a/docs/reference/namespaces.html
+++ /dev/null
@@ -1,83 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Namespace List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="header">
-  <div class="headertitle">
-<div class="title">Namespace List</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="textblock">Here is a list of all documented namespaces with brief descriptions:</div><div class="directory">
-<table class="directory">
-<tr id="row_0_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">N</span></span><a class="el" href="namespaceoboe.html" target="_self">oboe</a></td><td class="desc"></td></tr>
-</table>
-</div><!-- directory -->
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/nav_f.png b/docs/reference/nav_f.png
deleted file mode 100644
index 72a58a5..0000000
--- a/docs/reference/nav_f.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/nav_g.png b/docs/reference/nav_g.png
deleted file mode 100644
index 2093a23..0000000
--- a/docs/reference/nav_g.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/nav_h.png b/docs/reference/nav_h.png
deleted file mode 100644
index 33389b1..0000000
--- a/docs/reference/nav_h.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/open.png b/docs/reference/open.png
deleted file mode 100644
index 30f75c7..0000000
--- a/docs/reference/open.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/pages.html b/docs/reference/pages.html
deleted file mode 100644
index a0c44c4..0000000
--- a/docs/reference/pages.html
+++ /dev/null
@@ -1,83 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Related Pages</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-</div><!-- top -->
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div class="header">
-  <div class="headertitle">
-<div class="title">Related Pages</div>  </div>
-</div><!--header-->
-<div class="contents">
-<div class="textblock">Here is a list of all related documentation pages:</div><div class="directory">
-<table class="directory">
-<tr id="row_0_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="deprecated.html" target="_self">Deprecated List</a></td><td class="desc"></td></tr>
-</table>
-</div><!-- directory -->
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/search/all_0.html b/docs/reference/search/all_0.html
deleted file mode 100644
index 5330204..0000000
--- a/docs/reference/search/all_0.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_0.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_0.js b/docs/reference/search/all_0.js
deleted file mode 100644
index 8347df5..0000000
--- a/docs/reference/search/all_0.js
+++ /dev/null
@@ -1,19 +0,0 @@
-var searchData=
-[
-  ['aaudio',['AAudio',['../namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a99780b1e8d754eb42abed0ca5253e55b',1,'oboe']]],
-  ['alarm',['Alarm',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a46c4c4d980dfe025ae5b35aa0011dde4',1,'oboe']]],
-  ['allocate',['Allocate',['../namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa8485ca716c8cd4aafee372fd7028c123',1,'oboe']]],
-  ['assistanceaccessibility',['AssistanceAccessibility',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a639ffd54516c1a84a288a363c9469df8',1,'oboe']]],
-  ['assistancenavigationguidance',['AssistanceNavigationGuidance',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0ade058a1314f9a8504593259ff4f21a1e',1,'oboe']]],
-  ['assistancesonification',['AssistanceSonification',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a1ce57a0572748beebfc0c664ca1077e7',1,'oboe']]],
-  ['assistant',['Assistant',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a9b1363da9503dbd4142c0274a88e8d4b',1,'oboe']]],
-  ['audioapi',['AudioApi',['../namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6',1,'oboe']]],
-  ['audioformat',['AudioFormat',['../namespaceoboe.html#a92afc593e856571aacbfd02e57075df6',1,'oboe']]],
-  ['audiostream',['AudioStream',['../classoboe_1_1_audio_stream.html',1,'oboe::AudioStream'],['../classoboe_1_1_audio_stream.html#a8ebb587a07bf62c864fd62c63b241fd4',1,'oboe::AudioStream::AudioStream()']]],
-  ['audiostreambase',['AudioStreamBase',['../classoboe_1_1_audio_stream_base.html',1,'oboe::AudioStreamBase'],['../classoboe_1_1_audio_stream_base.html#aa6b103e1b0f808bbc4949d56f0829f98',1,'oboe::AudioStreamBase::AudioStreamBase()']]],
-  ['audiostreambuilder',['AudioStreamBuilder',['../classoboe_1_1_audio_stream_builder.html',1,'oboe']]],
-  ['audiostreamcallback',['AudioStreamCallback',['../classoboe_1_1_audio_stream_callback.html',1,'oboe']]],
-  ['audiostreamdatacallback',['AudioStreamDataCallback',['../classoboe_1_1_audio_stream_data_callback.html',1,'oboe']]],
-  ['audiostreamerrorcallback',['AudioStreamErrorCallback',['../classoboe_1_1_audio_stream_error_callback.html',1,'oboe']]],
-  ['api_20reference',['API reference',['../index.html',1,'']]]
-];
diff --git a/docs/reference/search/all_1.html b/docs/reference/search/all_1.html
deleted file mode 100644
index 2f46793..0000000
--- a/docs/reference/search/all_1.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_1.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_1.js b/docs/reference/search/all_1.js
deleted file mode 100644
index b71b1ef..0000000
--- a/docs/reference/search/all_1.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['best',['Best',['../namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1da68ef004de6166492c1d668eb8efe09bd',1,'oboe']]]
-];
diff --git a/docs/reference/search/all_10.html b/docs/reference/search/all_10.html
deleted file mode 100644
index 170dc09..0000000
--- a/docs/reference/search/all_10.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_10.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_10.js b/docs/reference/search/all_10.js
deleted file mode 100644
index 3365c35..0000000
--- a/docs/reference/search/all_10.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var searchData=
-[
-  ['text',['Text',['../structoboe_1_1_version.html#a2c86e578b827fbca5f40c460a7754503',1,'oboe::Version']]],
-  ['tune',['tune',['../classoboe_1_1_latency_tuner.html#ad2be756965e6a9af3114008eda892174',1,'oboe::LatencyTuner']]]
-];
diff --git a/docs/reference/search/all_11.html b/docs/reference/search/all_11.html
deleted file mode 100644
index 10fcd09..0000000
--- a/docs/reference/search/all_11.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_11.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_11.js b/docs/reference/search/all_11.js
deleted file mode 100644
index 7baa0a3..0000000
--- a/docs/reference/search/all_11.js
+++ /dev/null
@@ -1,9 +0,0 @@
-var searchData=
-[
-  ['unprocessed',['Unprocessed',['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06acad9424158aefae0af7975901b11d85f',1,'oboe']]],
-  ['unspecified',['Unspecified',['../namespaceoboe.html#a522e6806948369987639a0d1df03c029a946257a568f77c12df4fc4c49125da76',1,'oboe::Unspecified()'],['../namespaceoboe.html#a522e6806948369987639a0d1df03c029a6fcdc090caeade09d0efd6253932b6f5',1,'oboe::Unspecified()'],['../namespaceoboe.html#a522e6806948369987639a0d1df03c029a6fcdc090caeade09d0efd6253932b6f5',1,'oboe::Unspecified()']]],
-  ['updateframesread',['updateFramesRead',['../classoboe_1_1_audio_stream.html#a462358ddab709c79d1a7968d6d55b727',1,'oboe::AudioStream']]],
-  ['updateframeswritten',['updateFramesWritten',['../classoboe_1_1_audio_stream.html#a64ad978c5f70ced17ef5a96605496515',1,'oboe::AudioStream']]],
-  ['usage',['Usage',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0',1,'oboe']]],
-  ['usesaaudio',['usesAAudio',['../classoboe_1_1_audio_stream.html#a15cdaaaa4c1e8da322d6da33334c8147',1,'oboe::AudioStream']]]
-];
diff --git a/docs/reference/search/all_12.html b/docs/reference/search/all_12.html
deleted file mode 100644
index 0876adf..0000000
--- a/docs/reference/search/all_12.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_12.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_12.js b/docs/reference/search/all_12.js
deleted file mode 100644
index 4015beb..0000000
--- a/docs/reference/search/all_12.js
+++ /dev/null
@@ -1,9 +0,0 @@
-var searchData=
-[
-  ['value',['value',['../classoboe_1_1_result_with_value.html#a45f5c99a2c9f8fbaca502276f7ebb434',1,'oboe::ResultWithValue']]],
-  ['version',['Version',['../structoboe_1_1_version.html',1,'oboe']]],
-  ['voicecommunication',['VoiceCommunication',['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a1862e72c9730c448fbec6f61a5d8234d',1,'oboe::VoiceCommunication()'],['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a5bad8854288c956062ec1d4d7c14fed6',1,'oboe::VoiceCommunication()']]],
-  ['voicecommunicationsignalling',['VoiceCommunicationSignalling',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a404f62633744bf4da0c6a27a2b78ce74',1,'oboe']]],
-  ['voiceperformance',['VoicePerformance',['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06ad19edec0a23e435c774bf3bbcf1d999c',1,'oboe']]],
-  ['voicerecognition',['VoiceRecognition',['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06af6e440b4e9edf49afe18aa4be77be6fc',1,'oboe']]]
-];
diff --git a/docs/reference/search/all_13.html b/docs/reference/search/all_13.html
deleted file mode 100644
index dc6c049..0000000
--- a/docs/reference/search/all_13.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_13.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_13.js b/docs/reference/search/all_13.js
deleted file mode 100644
index 059114d..0000000
--- a/docs/reference/search/all_13.js
+++ /dev/null
@@ -1,9 +0,0 @@
-var searchData=
-[
-  ['waitforavailableframes',['waitForAvailableFrames',['../classoboe_1_1_audio_stream.html#afddb0962863ccf9ec6672a042fe15941',1,'oboe::AudioStream']]],
-  ['waitforstatechange',['waitForStateChange',['../classoboe_1_1_audio_stream.html#a0c865a5501f369d959c39d8ab8b46a07',1,'oboe::AudioStream']]],
-  ['waitforstatetransition',['waitForStateTransition',['../classoboe_1_1_audio_stream.html#a8adbacd6a55a94a532916ab037fba1d6',1,'oboe::AudioStream']]],
-  ['waserrorcallbackcalled',['wasErrorCallbackCalled',['../classoboe_1_1_audio_stream.html#aa48da7bf28026b7cccee73e6b054af28',1,'oboe::AudioStream']]],
-  ['willuseaaudio',['willUseAAudio',['../classoboe_1_1_audio_stream_builder.html#aa07ea100fcb107d9f7913f206c2214f4',1,'oboe::AudioStreamBuilder']]],
-  ['write',['write',['../classoboe_1_1_audio_stream.html#a3612c05ed6b01a213dde67d913c07e11',1,'oboe::AudioStream']]]
-];
diff --git a/docs/reference/search/all_2.html b/docs/reference/search/all_2.html
deleted file mode 100644
index 4c33d85..0000000
--- a/docs/reference/search/all_2.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_2.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_2.js b/docs/reference/search/all_2.js
deleted file mode 100644
index 9af0893..0000000
--- a/docs/reference/search/all_2.js
+++ /dev/null
@@ -1,13 +0,0 @@
-var searchData=
-[
-  ['calculatelatencymillis',['calculateLatencyMillis',['../classoboe_1_1_audio_stream.html#ae023cb001f3261d064f423101798d6be',1,'oboe::AudioStream']]],
-  ['camcorder',['Camcorder',['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a6e8ef178769235d18b44fe2bb5ab33fe',1,'oboe']]],
-  ['channelcount',['ChannelCount',['../classoboe_1_1_default_stream_values.html#ad5dce538d5963c81bf58350ab730962d',1,'oboe::DefaultStreamValues::ChannelCount()'],['../namespaceoboe.html#a522e6806948369987639a0d1df03c029',1,'oboe::ChannelCount()']]],
-  ['close',['close',['../classoboe_1_1_audio_stream.html#a9c8ea30e30e513766d5e996c370eb8d8',1,'oboe::AudioStream']]],
-  ['contenttype',['ContentType',['../namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b',1,'oboe']]],
-  ['convertfloattopcm16',['convertFloatToPcm16',['../namespaceoboe.html#adbda063116feb9fa98a31ee820170060',1,'oboe']]],
-  ['convertformattosizeinbytes',['convertFormatToSizeInBytes',['../namespaceoboe.html#ac67383a3df0f6e7a51f8415ffd9fdaca',1,'oboe']]],
-  ['convertpcm16tofloat',['convertPcm16ToFloat',['../namespaceoboe.html#ad17bee42828d13f2ef62a889e175c643',1,'oboe']]],
-  ['converttotext',['convertToText',['../namespaceoboe.html#af65aaea3c5d82eee6906664d61c094b3',1,'oboe']]],
-  ['createbasedonsign',['createBasedOnSign',['../classoboe_1_1_result_with_value.html#a2304c6120e2aad8f2189383a98c7b0a7',1,'oboe::ResultWithValue']]]
-];
diff --git a/docs/reference/search/all_3.html b/docs/reference/search/all_3.html
deleted file mode 100644
index b634070..0000000
--- a/docs/reference/search/all_3.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_3.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_3.js b/docs/reference/search/all_3.js
deleted file mode 100644
index 355d37d..0000000
--- a/docs/reference/search/all_3.js
+++ /dev/null
@@ -1,7 +0,0 @@
-var searchData=
-[
-  ['datacallbackresult',['DataCallbackResult',['../namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd',1,'oboe']]],
-  ['defaultstreamvalues',['DefaultStreamValues',['../classoboe_1_1_default_stream_values.html',1,'oboe']]],
-  ['deprecated_20list',['Deprecated List',['../deprecated.html',1,'']]],
-  ['direction',['Direction',['../namespaceoboe.html#af2147500089212955498a08ef2edb5ae',1,'oboe']]]
-];
diff --git a/docs/reference/search/all_4.html b/docs/reference/search/all_4.html
deleted file mode 100644
index dd062ae..0000000
--- a/docs/reference/search/all_4.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_4.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_4.js b/docs/reference/search/all_4.js
deleted file mode 100644
index a10f813..0000000
--- a/docs/reference/search/all_4.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var searchData=
-[
-  ['error',['error',['../classoboe_1_1_result_with_value.html#adfc76ae6db81535c2e82b856975eed41',1,'oboe::ResultWithValue']]],
-  ['exclusive',['Exclusive',['../namespaceoboe.html#a8330247b25429953a08354f41834d520a2ef50b4c466304dc6ac77bac8a779971',1,'oboe']]]
-];
diff --git a/docs/reference/search/all_5.html b/docs/reference/search/all_5.html
deleted file mode 100644
index f0780fd..0000000
--- a/docs/reference/search/all_5.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_5.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_5.js b/docs/reference/search/all_5.js
deleted file mode 100644
index 5e78f64..0000000
--- a/docs/reference/search/all_5.js
+++ /dev/null
@@ -1,9 +0,0 @@
-var searchData=
-[
-  ['fastest',['Fastest',['../namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1da90fd7fdf6f41406a75e5265b9583bb4e',1,'oboe']]],
-  ['firedatacallback',['fireDataCallback',['../classoboe_1_1_audio_stream.html#ab7a8cfe5d6039386bc5850fd5ee9bd62',1,'oboe::AudioStream']]],
-  ['float',['Float',['../namespaceoboe.html#a92afc593e856571aacbfd02e57075df6a22ae0e2b89e5e3d477f988cc36d3272b',1,'oboe']]],
-  ['flush',['flush',['../classoboe_1_1_audio_stream.html#a32c25c0333eab3d65ce02275ad4acb3d',1,'oboe::AudioStream']]],
-  ['framesperburst',['FramesPerBurst',['../classoboe_1_1_default_stream_values.html#ab5ea5576699cebc56193f5c297d3e300',1,'oboe::DefaultStreamValues']]],
-  ['frametimestamp',['FrameTimestamp',['../structoboe_1_1_frame_timestamp.html',1,'oboe']]]
-];
diff --git a/docs/reference/search/all_6.html b/docs/reference/search/all_6.html
deleted file mode 100644
index 39b0f55..0000000
--- a/docs/reference/search/all_6.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_6.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_6.js b/docs/reference/search/all_6.js
deleted file mode 100644
index ce9595c..0000000
--- a/docs/reference/search/all_6.js
+++ /dev/null
@@ -1,38 +0,0 @@
-var searchData=
-[
-  ['game',['Game',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a63d72051e901c069f8aa1b32aa0c43bb',1,'oboe']]],
-  ['generic',['Generic',['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a0ba6f369e7f8a700c14afe2992290544',1,'oboe']]],
-  ['getaudioapi',['getAudioApi',['../classoboe_1_1_audio_stream.html#a2b7a3cee7444114843dbdd1fc705f6bb',1,'oboe::AudioStream::getAudioApi()'],['../classoboe_1_1_audio_stream_builder.html#ac9d41811c297fd28bc61833f640bb8d0',1,'oboe::AudioStreamBuilder::getAudioApi()']]],
-  ['getavailableframes',['getAvailableFrames',['../classoboe_1_1_audio_stream.html#afa35ee4b8629fbffe26b9be7c7ed55d2',1,'oboe::AudioStream']]],
-  ['getbuffercapacityinframes',['getBufferCapacityInFrames',['../classoboe_1_1_audio_stream_base.html#ab1531253e64aaebe9e9eddbafb9098fc',1,'oboe::AudioStreamBase']]],
-  ['getbuffersizeinframes',['getBufferSizeInFrames',['../classoboe_1_1_audio_stream_base.html#af5217ab05bfde0d7637024b599302d0b',1,'oboe::AudioStreamBase']]],
-  ['getbytesperframe',['getBytesPerFrame',['../classoboe_1_1_audio_stream.html#a5c01907a59d5f89a5e4b819fe66b08bc',1,'oboe::AudioStream']]],
-  ['getbytespersample',['getBytesPerSample',['../classoboe_1_1_audio_stream.html#a44dda61e6e948e49b68f87172f084d62',1,'oboe::AudioStream']]],
-  ['getchannelcount',['getChannelCount',['../classoboe_1_1_audio_stream_base.html#a87e6bf37d6a2a5e983b8ca8d29aea575',1,'oboe::AudioStreamBase']]],
-  ['getcontenttype',['getContentType',['../classoboe_1_1_audio_stream_base.html#ab12e2d068fa87e0553b01a400d96eb82',1,'oboe::AudioStreamBase']]],
-  ['getdatacallback',['getDataCallback',['../classoboe_1_1_audio_stream_base.html#a9fb2f34ae62dbda2c10e8513b754fa0c',1,'oboe::AudioStreamBase']]],
-  ['getdeviceid',['getDeviceId',['../classoboe_1_1_audio_stream_base.html#a093057d625bc896864b959974c265f21',1,'oboe::AudioStreamBase']]],
-  ['getdirection',['getDirection',['../classoboe_1_1_audio_stream_base.html#a6f86f2233a04c5a0b056f0c1c261f1b1',1,'oboe::AudioStreamBase']]],
-  ['geterrorcallback',['getErrorCallback',['../classoboe_1_1_audio_stream_base.html#a1328fb9288166ff325995ce1ea1867f0',1,'oboe::AudioStreamBase']]],
-  ['getformat',['getFormat',['../classoboe_1_1_audio_stream_base.html#ab1e640461d7bf9d596decb913da7ac86',1,'oboe::AudioStreamBase']]],
-  ['getframesperburst',['getFramesPerBurst',['../classoboe_1_1_audio_stream.html#ac160acb656515814fa6fdd157c131a0a',1,'oboe::AudioStream']]],
-  ['getframespercallback',['getFramesPerCallback',['../classoboe_1_1_audio_stream_base.html#a8878a90949badbb5486cc2e022a57086',1,'oboe::AudioStreamBase']]],
-  ['getframesperdatacallback',['getFramesPerDataCallback',['../classoboe_1_1_audio_stream_base.html#abc3ee2815568b425d15a40e132aa8e38',1,'oboe::AudioStreamBase']]],
-  ['getframesread',['getFramesRead',['../classoboe_1_1_audio_stream.html#aeebfc59abd978cd6dff07c16cfe266df',1,'oboe::AudioStream']]],
-  ['getframeswritten',['getFramesWritten',['../classoboe_1_1_audio_stream.html#ab43dd4074e1de57bac1c3fd111430341',1,'oboe::AudioStream']]],
-  ['getinputpreset',['getInputPreset',['../classoboe_1_1_audio_stream_base.html#a5c773b93b8aa38191c7199cab023428a',1,'oboe::AudioStreamBase']]],
-  ['getlasterrorcallbackresult',['getLastErrorCallbackResult',['../classoboe_1_1_audio_stream.html#a8fe8afdf164a1fe835c514f709743d75',1,'oboe::AudioStream']]],
-  ['getperformancemode',['getPerformanceMode',['../classoboe_1_1_audio_stream_base.html#a2ddb935de0e24dd7ae8e2cfbecac9fdc',1,'oboe::AudioStreamBase']]],
-  ['getpropertyinteger',['getPropertyInteger',['../namespaceoboe.html#a4284cffcf4d852ca4f357429303d7af5',1,'oboe']]],
-  ['getpropertystring',['getPropertyString',['../namespaceoboe.html#a1ff1f1323d722494dac353a6b4d1bd5b',1,'oboe']]],
-  ['getsamplerate',['getSampleRate',['../classoboe_1_1_audio_stream_base.html#ae9d32f3e09174bad69e74f147ee33087',1,'oboe::AudioStreamBase']]],
-  ['getsamplerateconversionquality',['getSampleRateConversionQuality',['../classoboe_1_1_audio_stream_base.html#a1de8d6982d411a0cf50a32efba0ca3f2',1,'oboe::AudioStreamBase']]],
-  ['getsdkversion',['getSdkVersion',['../namespaceoboe.html#a54528938e9fccab7ad8947ccf0e409db',1,'oboe']]],
-  ['getsessionid',['getSessionId',['../classoboe_1_1_audio_stream_base.html#aa3c502ce09bbad7690a2dd6acaf8892e',1,'oboe::AudioStreamBase']]],
-  ['getsharingmode',['getSharingMode',['../classoboe_1_1_audio_stream_base.html#a1fb033fc963f971bd1aa8f6707e49b41',1,'oboe::AudioStreamBase']]],
-  ['getstate',['getState',['../classoboe_1_1_audio_stream.html#a9d37cc6513823c685ae892626ff83ea8',1,'oboe::AudioStream']]],
-  ['gettimestamp',['getTimestamp',['../classoboe_1_1_audio_stream.html#acb8edbc17ff79993a8ed996d216fe6f3',1,'oboe::AudioStream::getTimestamp(clockid_t, int64_t *, int64_t *)'],['../classoboe_1_1_audio_stream.html#a49254e6b1b19cb6d0ca6c63058029771',1,'oboe::AudioStream::getTimestamp(clockid_t)']]],
-  ['getunderlyingstream',['getUnderlyingStream',['../classoboe_1_1_audio_stream.html#a5458d7130415eb4defe3dbc11d479e2f',1,'oboe::AudioStream']]],
-  ['getusage',['getUsage',['../classoboe_1_1_audio_stream_base.html#a0bcfb2f8bd11c92b541fd910da9af397',1,'oboe::AudioStreamBase']]],
-  ['getxruncount',['getXRunCount',['../classoboe_1_1_audio_stream.html#ad1a1d3bbf3b348ed92b7ed18ce9cc261',1,'oboe::AudioStream']]]
-];
diff --git a/docs/reference/search/all_7.html b/docs/reference/search/all_7.html
deleted file mode 100644
index 9cd0196..0000000
--- a/docs/reference/search/all_7.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_7.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_7.js b/docs/reference/search/all_7.js
deleted file mode 100644
index f8e2e06..0000000
--- a/docs/reference/search/all_7.js
+++ /dev/null
@@ -1,17 +0,0 @@
-var searchData=
-[
-  ['i16',['I16',['../namespaceoboe.html#a92afc593e856571aacbfd02e57075df6abcd774f891b5f9df7099f3ea75dadf8d',1,'oboe']]],
-  ['input',['Input',['../namespaceoboe.html#af2147500089212955498a08ef2edb5aea324118a6721dd6b8a9b9f4e327df2bf5',1,'oboe']]],
-  ['inputpreset',['InputPreset',['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06',1,'oboe']]],
-  ['invalid',['Invalid',['../namespaceoboe.html#a92afc593e856571aacbfd02e57075df6a4bbb8f967da6d1a610596d7257179c2b',1,'oboe']]],
-  ['isaaudiorecommended',['isAAudioRecommended',['../classoboe_1_1_audio_stream_builder.html#a622732bbe5c6577356d749f7dc2108df',1,'oboe::AudioStreamBuilder']]],
-  ['isaaudiosupported',['isAAudioSupported',['../classoboe_1_1_audio_stream_builder.html#a18e7b5f7554a4c2ca763e35e8117d699',1,'oboe::AudioStreamBuilder']]],
-  ['isatmaximumbuffersize',['isAtMaximumBufferSize',['../classoboe_1_1_latency_tuner.html#a45c013fd6787ad09d328385d6314c4d4',1,'oboe::LatencyTuner']]],
-  ['ischannelconversionallowed',['isChannelConversionAllowed',['../classoboe_1_1_audio_stream_base.html#aa4ec3aa76e69350fbce6f00786211495',1,'oboe::AudioStreamBase']]],
-  ['isdatacallbackenabled',['isDataCallbackEnabled',['../classoboe_1_1_audio_stream.html#add85011ba825f74931deeb92c5edf831',1,'oboe::AudioStream']]],
-  ['isdatacallbackspecified',['isDataCallbackSpecified',['../classoboe_1_1_audio_stream_base.html#a9a54d38b985a2eb12c6972104dc0ce73',1,'oboe::AudioStreamBase']]],
-  ['iserrorcallbackspecified',['isErrorCallbackSpecified',['../classoboe_1_1_audio_stream_base.html#aef579f6d1f779c89d051f0963f2976b3',1,'oboe::AudioStreamBase']]],
-  ['isformatconversionallowed',['isFormatConversionAllowed',['../classoboe_1_1_audio_stream_base.html#ace3625a7332bf02a86818fdf63fcccb4',1,'oboe::AudioStreamBase']]],
-  ['isvalidconfig',['isValidConfig',['../classoboe_1_1_audio_stream_base.html#a5d5e07e98921d0193a5c0ccbe06f68c2',1,'oboe::AudioStreamBase']]],
-  ['isxruncountsupported',['isXRunCountSupported',['../classoboe_1_1_audio_stream.html#a43d8a098440cde28f4ee8bedd6d107c4',1,'oboe::AudioStream']]]
-];
diff --git a/docs/reference/search/all_8.html b/docs/reference/search/all_8.html
deleted file mode 100644
index 1e8fb9c..0000000
--- a/docs/reference/search/all_8.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_8.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_8.js b/docs/reference/search/all_8.js
deleted file mode 100644
index de55599..0000000
--- a/docs/reference/search/all_8.js
+++ /dev/null
@@ -1,9 +0,0 @@
-var searchData=
-[
-  ['kdefaulttimeoutnanos',['kDefaultTimeoutNanos',['../namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c',1,'oboe']]],
-  ['kmillispersecond',['kMillisPerSecond',['../namespaceoboe.html#ad1bb9f5626cec20d3a052a8721959873',1,'oboe']]],
-  ['knanospermicrosecond',['kNanosPerMicrosecond',['../namespaceoboe.html#aedef0759ae3622b6f0324799bcbdebf0',1,'oboe']]],
-  ['knanospermillisecond',['kNanosPerMillisecond',['../namespaceoboe.html#a831e887150474c087170679eaca8672b',1,'oboe']]],
-  ['knanospersecond',['kNanosPerSecond',['../namespaceoboe.html#a5948466b593c4eab65f7025846a39f51',1,'oboe']]],
-  ['kunspecified',['kUnspecified',['../namespaceoboe.html#ab0772052200184e514082eaa89be7905',1,'oboe']]]
-];
diff --git a/docs/reference/search/all_9.html b/docs/reference/search/all_9.html
deleted file mode 100644
index 27df366..0000000
--- a/docs/reference/search/all_9.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_9.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_9.js b/docs/reference/search/all_9.js
deleted file mode 100644
index 1516973..0000000
--- a/docs/reference/search/all_9.js
+++ /dev/null
@@ -1,6 +0,0 @@
-var searchData=
-[
-  ['latencytuner',['LatencyTuner',['../classoboe_1_1_latency_tuner.html',1,'oboe::LatencyTuner'],['../classoboe_1_1_latency_tuner.html#a0263b9a55825c0a403653b2b508073ea',1,'oboe::LatencyTuner::LatencyTuner(AudioStream &amp;stream)'],['../classoboe_1_1_latency_tuner.html#ab437bd10605af9e5733d043f8adc0b43',1,'oboe::LatencyTuner::LatencyTuner(AudioStream &amp;stream, int32_t maximumBufferSize)']]],
-  ['launchstopthread',['launchStopThread',['../classoboe_1_1_audio_stream.html#aa5f4801cca6877eeaa4735b93933269d',1,'oboe::AudioStream']]],
-  ['lowlatency',['LowLatency',['../namespaceoboe.html#a1068781f3920654b1bfd7ed136468184a611907b5ab1865515c35357efa41a9b9',1,'oboe']]]
-];
diff --git a/docs/reference/search/all_a.html b/docs/reference/search/all_a.html
deleted file mode 100644
index 63f9254..0000000
--- a/docs/reference/search/all_a.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_a.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_a.js b/docs/reference/search/all_a.js
deleted file mode 100644
index 30be357..0000000
--- a/docs/reference/search/all_a.js
+++ /dev/null
@@ -1,28 +0,0 @@
-var searchData=
-[
-  ['major',['Major',['../structoboe_1_1_version.html#a270f2e92582d5187be339eeda8e2b276',1,'oboe::Version']]],
-  ['mbuffercapacityinframes',['mBufferCapacityInFrames',['../classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6',1,'oboe::AudioStreamBase']]],
-  ['mbuffersizeinframes',['mBufferSizeInFrames',['../classoboe_1_1_audio_stream_base.html#a3b65595d26d1eae1b8ce9925a5b98f6a',1,'oboe::AudioStreamBase']]],
-  ['mchannelcount',['mChannelCount',['../classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206',1,'oboe::AudioStreamBase']]],
-  ['mcontenttype',['mContentType',['../classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b',1,'oboe::AudioStreamBase']]],
-  ['mdatacallback',['mDataCallback',['../classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f',1,'oboe::AudioStreamBase']]],
-  ['mdeviceid',['mDeviceId',['../classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8',1,'oboe::AudioStreamBase']]],
-  ['mdirection',['mDirection',['../classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880',1,'oboe::AudioStreamBase']]],
-  ['media',['Media',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74',1,'oboe']]],
-  ['merrorcallback',['mErrorCallback',['../classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b',1,'oboe::AudioStreamBase']]],
-  ['mformat',['mFormat',['../classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09',1,'oboe::AudioStreamBase']]],
-  ['mframesperburst',['mFramesPerBurst',['../classoboe_1_1_audio_stream_base.html#a54061319ed348329a29d883a5de2482e',1,'oboe::AudioStreamBase']]],
-  ['mframespercallback',['mFramesPerCallback',['../classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899',1,'oboe::AudioStreamBase']]],
-  ['mframesread',['mFramesRead',['../classoboe_1_1_audio_stream.html#a07e82f9b9e2e4800f23ae9a7193c3b58',1,'oboe::AudioStream']]],
-  ['mframeswritten',['mFramesWritten',['../classoboe_1_1_audio_stream.html#a88a63317b7c58815bac074976b00aa23',1,'oboe::AudioStream']]],
-  ['minor',['Minor',['../structoboe_1_1_version.html#ae460bb95e3a9099696205a35fffb5469',1,'oboe::Version']]],
-  ['minputpreset',['mInputPreset',['../classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589',1,'oboe::AudioStreamBase']]],
-  ['mono',['Mono',['../namespaceoboe.html#a522e6806948369987639a0d1df03c029a8be103218645e121b51078620f452c79',1,'oboe']]],
-  ['movie',['Movie',['../namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba8b3b366178c2b7b1688bca6cd33758b1',1,'oboe']]],
-  ['mperformancemode',['mPerformanceMode',['../classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765',1,'oboe::AudioStreamBase']]],
-  ['msamplerate',['mSampleRate',['../classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea',1,'oboe::AudioStreamBase']]],
-  ['msessionid',['mSessionId',['../classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737',1,'oboe::AudioStreamBase']]],
-  ['msharingmode',['mSharingMode',['../classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473',1,'oboe::AudioStreamBase']]],
-  ['musage',['mUsage',['../classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c',1,'oboe::AudioStreamBase']]],
-  ['music',['Music',['../namespaceoboe.html#a2a3cec6f021c1a324df60273710c604bac156fcc7b29059305cef26f3904d4517',1,'oboe']]]
-];
diff --git a/docs/reference/search/all_b.html b/docs/reference/search/all_b.html
deleted file mode 100644
index 44ae3e4..0000000
--- a/docs/reference/search/all_b.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_b.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_b.js b/docs/reference/search/all_b.js
deleted file mode 100644
index 930747d..0000000
--- a/docs/reference/search/all_b.js
+++ /dev/null
@@ -1,8 +0,0 @@
-var searchData=
-[
-  ['none',['None',['../namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa58c518b26e83ea48393a76f6c9ecb51f',1,'oboe::None()'],['../namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa6adf97f83acf6453d4a6a4b1070f3754',1,'oboe::None()'],['../namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa6adf97f83acf6453d4a6a4b1070f3754',1,'oboe::None()']]],
-  ['notification',['Notification',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a96d008db67fc0b5551a926842bbb6a71',1,'oboe']]],
-  ['notificationevent',['NotificationEvent',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a089240b5380dbd12f1eac0ec258a3b2f',1,'oboe']]],
-  ['notificationringtone',['NotificationRingtone',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a4e7a4b08274d472394b740a20d3bbdaf',1,'oboe']]],
-  ['number',['Number',['../structoboe_1_1_version.html#ac579661e79bcee45dc676d4647891de0',1,'oboe::Version']]]
-];
diff --git a/docs/reference/search/all_c.html b/docs/reference/search/all_c.html
deleted file mode 100644
index 3de1586..0000000
--- a/docs/reference/search/all_c.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_c.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_c.js b/docs/reference/search/all_c.js
deleted file mode 100644
index dcdc687..0000000
--- a/docs/reference/search/all_c.js
+++ /dev/null
@@ -1,20 +0,0 @@
-var searchData=
-[
-  ['oboe',['oboe',['../namespaceoboe.html',1,'']]],
-  ['oboeglobals',['OboeGlobals',['../classoboe_1_1_oboe_globals.html',1,'oboe']]],
-  ['onaudioready',['onAudioReady',['../classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d',1,'oboe::AudioStreamDataCallback::onAudioReady()'],['../classoboe_1_1_stabilized_callback.html#ad447e12ebf732cf151655c1fbaf58a49',1,'oboe::StabilizedCallback::onAudioReady()']]],
-  ['ondefaultcallback',['onDefaultCallback',['../classoboe_1_1_audio_stream.html#a0ea79e60f5a3d29fc5a1a116aba11dfe',1,'oboe::AudioStream']]],
-  ['onerror',['onError',['../classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3',1,'oboe::AudioStreamErrorCallback']]],
-  ['onerrorafterclose',['onErrorAfterClose',['../classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe',1,'oboe::AudioStreamErrorCallback::onErrorAfterClose()'],['../classoboe_1_1_stabilized_callback.html#af7521da42c4b08a71e6102994f6f41f4',1,'oboe::StabilizedCallback::onErrorAfterClose()']]],
-  ['onerrorbeforeclose',['onErrorBeforeClose',['../classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0',1,'oboe::AudioStreamErrorCallback::onErrorBeforeClose()'],['../classoboe_1_1_stabilized_callback.html#a7ec0e9fca3181962ab78716bcda83e10',1,'oboe::StabilizedCallback::onErrorBeforeClose()']]],
-  ['open',['open',['../classoboe_1_1_audio_stream.html#a686c6ce8a29051c858fd1de386805dc6',1,'oboe::AudioStream']]],
-  ['openmanagedstream',['openManagedStream',['../classoboe_1_1_audio_stream_builder.html#a7ab172a9be4fca2489aa5cbcc48c20ff',1,'oboe::AudioStreamBuilder']]],
-  ['opensles',['OpenSLES',['../namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a24e758ea9c1e842ef71cc8ff8b63fa9b',1,'oboe']]],
-  ['openstream',['openStream',['../classoboe_1_1_audio_stream_builder.html#a86b94cfa47729bef2e04dce1a9086074',1,'oboe::AudioStreamBuilder::openStream(AudioStream **stream)'],['../classoboe_1_1_audio_stream_builder.html#a44b68216c48f8fb08a9e63178e0b0eeb',1,'oboe::AudioStreamBuilder::openStream(std::shared_ptr&lt; oboe::AudioStream &gt; &amp;stream)']]],
-  ['operator_20_21',['operator !',['../classoboe_1_1_result_with_value.html#a6fb3c61c5716a045ba48dc5a5dfc8169',1,'oboe::ResultWithValue']]],
-  ['operator_20bool',['operator bool',['../classoboe_1_1_result_with_value.html#ae32b1953b777af7d1d0c94862ca39986',1,'oboe::ResultWithValue']]],
-  ['operator_20result',['operator Result',['../classoboe_1_1_result_with_value.html#af62107817c0bc76047e6b655a78504ba',1,'oboe::ResultWithValue']]],
-  ['operator_3c_3c',['operator&lt;&lt;',['../namespaceoboe.html#aa403103686222502d1cfc47bafc10aeb',1,'oboe']]],
-  ['operator_3d',['operator=',['../classoboe_1_1_audio_stream_base.html#aa9c987a59555d7a60b9f7a63f4afc7fc',1,'oboe::AudioStreamBase']]],
-  ['output',['Output',['../namespaceoboe.html#af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54',1,'oboe']]]
-];
diff --git a/docs/reference/search/all_d.html b/docs/reference/search/all_d.html
deleted file mode 100644
index a2d5bd7..0000000
--- a/docs/reference/search/all_d.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_d.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_d.js b/docs/reference/search/all_d.js
deleted file mode 100644
index ac1a01a..0000000
--- a/docs/reference/search/all_d.js
+++ /dev/null
@@ -1,7 +0,0 @@
-var searchData=
-[
-  ['patch',['Patch',['../structoboe_1_1_version.html#a690110f2b3e887892da8f29ab5c057b2',1,'oboe::Version']]],
-  ['pause',['pause',['../classoboe_1_1_audio_stream.html#a04f29836748a8e5842aef2be200022ad',1,'oboe::AudioStream']]],
-  ['performancemode',['PerformanceMode',['../namespaceoboe.html#a1068781f3920654b1bfd7ed136468184',1,'oboe']]],
-  ['powersaving',['PowerSaving',['../namespaceoboe.html#a1068781f3920654b1bfd7ed136468184abbad080463ed11f9d77797c04aa1e5b1',1,'oboe']]]
-];
diff --git a/docs/reference/search/all_e.html b/docs/reference/search/all_e.html
deleted file mode 100644
index f9a056d..0000000
--- a/docs/reference/search/all_e.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_e.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_e.js b/docs/reference/search/all_e.js
deleted file mode 100644
index 3c91dff..0000000
--- a/docs/reference/search/all_e.js
+++ /dev/null
@@ -1,11 +0,0 @@
-var searchData=
-[
-  ['read',['read',['../classoboe_1_1_audio_stream.html#a8089f0a0cb68d4039cf33e6584129978',1,'oboe::AudioStream']]],
-  ['requestflush',['requestFlush',['../classoboe_1_1_audio_stream.html#a6bd5d633ff999e4da1faf3cd949aa602',1,'oboe::AudioStream']]],
-  ['requestpause',['requestPause',['../classoboe_1_1_audio_stream.html#a7f18bb3cc5490fd7fbc1f6da63c730f6',1,'oboe::AudioStream']]],
-  ['requestreset',['requestReset',['../classoboe_1_1_latency_tuner.html#a6c0142e08dc65eda8f758b4794450867',1,'oboe::LatencyTuner']]],
-  ['requeststart',['requestStart',['../classoboe_1_1_audio_stream.html#a3c484e314dee8dfed1d419f487b5d601',1,'oboe::AudioStream']]],
-  ['requeststop',['requestStop',['../classoboe_1_1_audio_stream.html#a820e634f741e6b5efdcef8104cecb919',1,'oboe::AudioStream']]],
-  ['result',['Result',['../namespaceoboe.html#a486512e787b609c80ba4436f23929af1',1,'oboe']]],
-  ['resultwithvalue',['ResultWithValue',['../classoboe_1_1_result_with_value.html',1,'oboe::ResultWithValue&lt; T &gt;'],['../classoboe_1_1_result_with_value.html#aae75caa0d16a9e23a012f77fb50c5927',1,'oboe::ResultWithValue::ResultWithValue(oboe::Result error)'],['../classoboe_1_1_result_with_value.html#a600309367db58d71f0ec16e90f7ebea5',1,'oboe::ResultWithValue::ResultWithValue(T value)']]]
-];
diff --git a/docs/reference/search/all_f.html b/docs/reference/search/all_f.html
deleted file mode 100644
index f6997fa..0000000
--- a/docs/reference/search/all_f.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="all_f.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/all_f.js b/docs/reference/search/all_f.js
deleted file mode 100644
index fd423fd..0000000
--- a/docs/reference/search/all_f.js
+++ /dev/null
@@ -1,42 +0,0 @@
-var searchData=
-[
-  ['samplerate',['SampleRate',['../classoboe_1_1_default_stream_values.html#a46a5d9a653f2153f618cadcab764e1b1',1,'oboe::DefaultStreamValues']]],
-  ['samplerateconversionquality',['SampleRateConversionQuality',['../namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d',1,'oboe']]],
-  ['sessionid',['SessionId',['../namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf',1,'oboe']]],
-  ['setaudioapi',['setAudioApi',['../classoboe_1_1_audio_stream_builder.html#a38c6d6c5e718df1e3ac69daaac47c391',1,'oboe::AudioStreamBuilder']]],
-  ['setbuffercapacityinframes',['setBufferCapacityInFrames',['../classoboe_1_1_audio_stream_builder.html#abaff480867af51ca0899bfa6fd7cc3ef',1,'oboe::AudioStreamBuilder']]],
-  ['setbuffersizeincrement',['setBufferSizeIncrement',['../classoboe_1_1_latency_tuner.html#a2684b30205126c8acd2f75d01cce05db',1,'oboe::LatencyTuner']]],
-  ['setbuffersizeinframes',['setBufferSizeInFrames',['../classoboe_1_1_audio_stream.html#a06e3f9e133b3a75515e7793939d1cd03',1,'oboe::AudioStream']]],
-  ['setcallback',['setCallback',['../classoboe_1_1_audio_stream_builder.html#a698cefa9af73bc97c020c004821fccbd',1,'oboe::AudioStreamBuilder']]],
-  ['setchannelconversionallowed',['setChannelConversionAllowed',['../classoboe_1_1_audio_stream_builder.html#ad50f5d20cdf420d982bf499790cd3563',1,'oboe::AudioStreamBuilder']]],
-  ['setchannelcount',['setChannelCount',['../classoboe_1_1_audio_stream_builder.html#a075d10291e1f998d90c2f73ef767b5a7',1,'oboe::AudioStreamBuilder']]],
-  ['setcontenttype',['setContentType',['../classoboe_1_1_audio_stream_builder.html#a6a17bafc217c2b624179fbbf77fe4468',1,'oboe::AudioStreamBuilder']]],
-  ['setdatacallback',['setDataCallback',['../classoboe_1_1_audio_stream_builder.html#acad307720e0f370267b4e2f9a626ae70',1,'oboe::AudioStreamBuilder']]],
-  ['setdatacallbackenabled',['setDataCallbackEnabled',['../classoboe_1_1_audio_stream.html#a0faa6d3a6fd4f367e6f80d5a29e6dcba',1,'oboe::AudioStream']]],
-  ['setdeviceid',['setDeviceId',['../classoboe_1_1_audio_stream_builder.html#af36ddcd00686a9e1de661bdac0685a8e',1,'oboe::AudioStreamBuilder']]],
-  ['setdirection',['setDirection',['../classoboe_1_1_audio_stream_builder.html#ab3fbd47b06197619c26393637e26354c',1,'oboe::AudioStreamBuilder']]],
-  ['seterrorcallback',['setErrorCallback',['../classoboe_1_1_audio_stream_builder.html#aacb66f530bfc6f545911b5e169774567',1,'oboe::AudioStreamBuilder']]],
-  ['setformat',['setFormat',['../classoboe_1_1_audio_stream_builder.html#aa2e1d2d73cd6c2eb9f349bf2fe5f6515',1,'oboe::AudioStreamBuilder']]],
-  ['setformatconversionallowed',['setFormatConversionAllowed',['../classoboe_1_1_audio_stream_builder.html#a7ec5f427cd6fe55cb1ce536ff0cbb4d2',1,'oboe::AudioStreamBuilder']]],
-  ['setframespercallback',['setFramesPerCallback',['../classoboe_1_1_audio_stream_builder.html#a3f397821f61eabaeedaf31064c859a54',1,'oboe::AudioStreamBuilder']]],
-  ['setframesperdatacallback',['setFramesPerDataCallback',['../classoboe_1_1_audio_stream_builder.html#afb8e95e80df7edd1af27af490438785e',1,'oboe::AudioStreamBuilder']]],
-  ['setinputpreset',['setInputPreset',['../classoboe_1_1_audio_stream_builder.html#a144a3d095fd668210282f1a91f23e1f0',1,'oboe::AudioStreamBuilder']]],
-  ['setminimumbuffersize',['setMinimumBufferSize',['../classoboe_1_1_latency_tuner.html#adc96aa53b18a051b6ccdacb838139bf8',1,'oboe::LatencyTuner']]],
-  ['setperformancemode',['setPerformanceMode',['../classoboe_1_1_audio_stream_builder.html#a6cd1d65612e844e59da71a68ea0ab3ee',1,'oboe::AudioStreamBuilder']]],
-  ['setsamplerate',['setSampleRate',['../classoboe_1_1_audio_stream_builder.html#a30ef3d5f51d56a9f980dc09600ed139d',1,'oboe::AudioStreamBuilder']]],
-  ['setsamplerateconversionquality',['setSampleRateConversionQuality',['../classoboe_1_1_audio_stream_builder.html#af7d24a9ec975d430732151e5ee0d1027',1,'oboe::AudioStreamBuilder']]],
-  ['setsessionid',['setSessionId',['../classoboe_1_1_audio_stream_builder.html#a54c1651bdbe089d0d714af499e8a5f1d',1,'oboe::AudioStreamBuilder']]],
-  ['setsharingmode',['setSharingMode',['../classoboe_1_1_audio_stream_builder.html#a3e991742acbbfb6fe5ebcf592c478654',1,'oboe::AudioStreamBuilder']]],
-  ['setusage',['setUsage',['../classoboe_1_1_audio_stream_builder.html#a593255a2f5eb972665775cfc5bc58f6a',1,'oboe::AudioStreamBuilder']]],
-  ['setworkaroundsenabled',['setWorkaroundsEnabled',['../classoboe_1_1_oboe_globals.html#af2b8af764c5a5e6fc007b7725117303b',1,'oboe::OboeGlobals']]],
-  ['shared',['Shared',['../namespaceoboe.html#a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca',1,'oboe']]],
-  ['sharingmode',['SharingMode',['../namespaceoboe.html#a8330247b25429953a08354f41834d520',1,'oboe']]],
-  ['sonification',['Sonification',['../namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba0885eef555037e94a7cf39fe683c2799',1,'oboe']]],
-  ['speech',['Speech',['../namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba3dc48a4b4619aa4edd1da7b937b4dcd1',1,'oboe']]],
-  ['stabilizedcallback',['StabilizedCallback',['../classoboe_1_1_stabilized_callback.html',1,'oboe']]],
-  ['start',['start',['../classoboe_1_1_audio_stream.html#af04f03eb6b64b564f1c4401688987d21',1,'oboe::AudioStream']]],
-  ['stereo',['Stereo',['../namespaceoboe.html#a522e6806948369987639a0d1df03c029a534e646333ca7568317b171ea96b89ba',1,'oboe']]],
-  ['stop',['stop',['../classoboe_1_1_audio_stream.html#aec093859d42f0470c884edd1e976d9f3',1,'oboe::AudioStream']]],
-  ['streamdeleterfunctor',['StreamDeleterFunctor',['../structoboe_1_1_stream_deleter_functor.html',1,'oboe']]],
-  ['streamstate',['StreamState',['../namespaceoboe.html#a89fa2ce046723764618c29db737917f6',1,'oboe']]]
-];
diff --git a/docs/reference/search/classes_0.html b/docs/reference/search/classes_0.html
deleted file mode 100644
index b3c6ec6..0000000
--- a/docs/reference/search/classes_0.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="classes_0.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/classes_0.js b/docs/reference/search/classes_0.js
deleted file mode 100644
index 2a04f01..0000000
--- a/docs/reference/search/classes_0.js
+++ /dev/null
@@ -1,9 +0,0 @@
-var searchData=
-[
-  ['audiostream',['AudioStream',['../classoboe_1_1_audio_stream.html',1,'oboe']]],
-  ['audiostreambase',['AudioStreamBase',['../classoboe_1_1_audio_stream_base.html',1,'oboe']]],
-  ['audiostreambuilder',['AudioStreamBuilder',['../classoboe_1_1_audio_stream_builder.html',1,'oboe']]],
-  ['audiostreamcallback',['AudioStreamCallback',['../classoboe_1_1_audio_stream_callback.html',1,'oboe']]],
-  ['audiostreamdatacallback',['AudioStreamDataCallback',['../classoboe_1_1_audio_stream_data_callback.html',1,'oboe']]],
-  ['audiostreamerrorcallback',['AudioStreamErrorCallback',['../classoboe_1_1_audio_stream_error_callback.html',1,'oboe']]]
-];
diff --git a/docs/reference/search/classes_1.html b/docs/reference/search/classes_1.html
deleted file mode 100644
index b744c4d..0000000
--- a/docs/reference/search/classes_1.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="classes_1.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/classes_1.js b/docs/reference/search/classes_1.js
deleted file mode 100644
index 16ce552..0000000
--- a/docs/reference/search/classes_1.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['defaultstreamvalues',['DefaultStreamValues',['../classoboe_1_1_default_stream_values.html',1,'oboe']]]
-];
diff --git a/docs/reference/search/classes_2.html b/docs/reference/search/classes_2.html
deleted file mode 100644
index 7878acb..0000000
--- a/docs/reference/search/classes_2.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="classes_2.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/classes_2.js b/docs/reference/search/classes_2.js
deleted file mode 100644
index 7398be3..0000000
--- a/docs/reference/search/classes_2.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['frametimestamp',['FrameTimestamp',['../structoboe_1_1_frame_timestamp.html',1,'oboe']]]
-];
diff --git a/docs/reference/search/classes_3.html b/docs/reference/search/classes_3.html
deleted file mode 100644
index c231d86..0000000
--- a/docs/reference/search/classes_3.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="classes_3.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/classes_3.js b/docs/reference/search/classes_3.js
deleted file mode 100644
index 70a7846..0000000
--- a/docs/reference/search/classes_3.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['latencytuner',['LatencyTuner',['../classoboe_1_1_latency_tuner.html',1,'oboe']]]
-];
diff --git a/docs/reference/search/classes_4.html b/docs/reference/search/classes_4.html
deleted file mode 100644
index 86dd438..0000000
--- a/docs/reference/search/classes_4.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="classes_4.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/classes_4.js b/docs/reference/search/classes_4.js
deleted file mode 100644
index d1e1d90..0000000
--- a/docs/reference/search/classes_4.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['oboeglobals',['OboeGlobals',['../classoboe_1_1_oboe_globals.html',1,'oboe']]]
-];
diff --git a/docs/reference/search/classes_5.html b/docs/reference/search/classes_5.html
deleted file mode 100644
index 7aaef4d..0000000
--- a/docs/reference/search/classes_5.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="classes_5.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/classes_5.js b/docs/reference/search/classes_5.js
deleted file mode 100644
index 991f31b..0000000
--- a/docs/reference/search/classes_5.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['resultwithvalue',['ResultWithValue',['../classoboe_1_1_result_with_value.html',1,'oboe']]]
-];
diff --git a/docs/reference/search/classes_6.html b/docs/reference/search/classes_6.html
deleted file mode 100644
index aad7834..0000000
--- a/docs/reference/search/classes_6.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="classes_6.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/classes_6.js b/docs/reference/search/classes_6.js
deleted file mode 100644
index 6a6692b..0000000
--- a/docs/reference/search/classes_6.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var searchData=
-[
-  ['stabilizedcallback',['StabilizedCallback',['../classoboe_1_1_stabilized_callback.html',1,'oboe']]],
-  ['streamdeleterfunctor',['StreamDeleterFunctor',['../structoboe_1_1_stream_deleter_functor.html',1,'oboe']]]
-];
diff --git a/docs/reference/search/classes_7.html b/docs/reference/search/classes_7.html
deleted file mode 100644
index 794e394..0000000
--- a/docs/reference/search/classes_7.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="classes_7.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/classes_7.js b/docs/reference/search/classes_7.js
deleted file mode 100644
index 8578da8..0000000
--- a/docs/reference/search/classes_7.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['version',['Version',['../structoboe_1_1_version.html',1,'oboe']]]
-];
diff --git a/docs/reference/search/close.png b/docs/reference/search/close.png
deleted file mode 100644
index 9342d3d..0000000
--- a/docs/reference/search/close.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/search/enums_0.html b/docs/reference/search/enums_0.html
deleted file mode 100644
index 7040a9c..0000000
--- a/docs/reference/search/enums_0.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enums_0.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enums_0.js b/docs/reference/search/enums_0.js
deleted file mode 100644
index b7984e3..0000000
--- a/docs/reference/search/enums_0.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var searchData=
-[
-  ['audioapi',['AudioApi',['../namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6',1,'oboe']]],
-  ['audioformat',['AudioFormat',['../namespaceoboe.html#a92afc593e856571aacbfd02e57075df6',1,'oboe']]]
-];
diff --git a/docs/reference/search/enums_1.html b/docs/reference/search/enums_1.html
deleted file mode 100644
index 0c65c0e..0000000
--- a/docs/reference/search/enums_1.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enums_1.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enums_1.js b/docs/reference/search/enums_1.js
deleted file mode 100644
index 7c86062..0000000
--- a/docs/reference/search/enums_1.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var searchData=
-[
-  ['channelcount',['ChannelCount',['../namespaceoboe.html#a522e6806948369987639a0d1df03c029',1,'oboe']]],
-  ['contenttype',['ContentType',['../namespaceoboe.html#a2a3cec6f021c1a324df60273710c604b',1,'oboe']]]
-];
diff --git a/docs/reference/search/enums_2.html b/docs/reference/search/enums_2.html
deleted file mode 100644
index 4250446..0000000
--- a/docs/reference/search/enums_2.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enums_2.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enums_2.js b/docs/reference/search/enums_2.js
deleted file mode 100644
index f3cd977..0000000
--- a/docs/reference/search/enums_2.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var searchData=
-[
-  ['datacallbackresult',['DataCallbackResult',['../namespaceoboe.html#af85fc9910a287df6c5df0ed396bb75cd',1,'oboe']]],
-  ['direction',['Direction',['../namespaceoboe.html#af2147500089212955498a08ef2edb5ae',1,'oboe']]]
-];
diff --git a/docs/reference/search/enums_3.html b/docs/reference/search/enums_3.html
deleted file mode 100644
index b118cca..0000000
--- a/docs/reference/search/enums_3.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enums_3.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enums_3.js b/docs/reference/search/enums_3.js
deleted file mode 100644
index 9637ff4..0000000
--- a/docs/reference/search/enums_3.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['inputpreset',['InputPreset',['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06',1,'oboe']]]
-];
diff --git a/docs/reference/search/enums_4.html b/docs/reference/search/enums_4.html
deleted file mode 100644
index 2795d4b..0000000
--- a/docs/reference/search/enums_4.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enums_4.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enums_4.js b/docs/reference/search/enums_4.js
deleted file mode 100644
index da0c72e..0000000
--- a/docs/reference/search/enums_4.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['performancemode',['PerformanceMode',['../namespaceoboe.html#a1068781f3920654b1bfd7ed136468184',1,'oboe']]]
-];
diff --git a/docs/reference/search/enums_5.html b/docs/reference/search/enums_5.html
deleted file mode 100644
index ab40bbd..0000000
--- a/docs/reference/search/enums_5.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enums_5.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enums_5.js b/docs/reference/search/enums_5.js
deleted file mode 100644
index 1451740..0000000
--- a/docs/reference/search/enums_5.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['result',['Result',['../namespaceoboe.html#a486512e787b609c80ba4436f23929af1',1,'oboe']]]
-];
diff --git a/docs/reference/search/enums_6.html b/docs/reference/search/enums_6.html
deleted file mode 100644
index f32ac36..0000000
--- a/docs/reference/search/enums_6.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enums_6.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enums_6.js b/docs/reference/search/enums_6.js
deleted file mode 100644
index 37af444..0000000
--- a/docs/reference/search/enums_6.js
+++ /dev/null
@@ -1,7 +0,0 @@
-var searchData=
-[
-  ['samplerateconversionquality',['SampleRateConversionQuality',['../namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1d',1,'oboe']]],
-  ['sessionid',['SessionId',['../namespaceoboe.html#a5752250c10e96179e3618d7f72937eaf',1,'oboe']]],
-  ['sharingmode',['SharingMode',['../namespaceoboe.html#a8330247b25429953a08354f41834d520',1,'oboe']]],
-  ['streamstate',['StreamState',['../namespaceoboe.html#a89fa2ce046723764618c29db737917f6',1,'oboe']]]
-];
diff --git a/docs/reference/search/enums_7.html b/docs/reference/search/enums_7.html
deleted file mode 100644
index 7a25d59..0000000
--- a/docs/reference/search/enums_7.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enums_7.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enums_7.js b/docs/reference/search/enums_7.js
deleted file mode 100644
index f48919d..0000000
--- a/docs/reference/search/enums_7.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['usage',['Usage',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0',1,'oboe']]]
-];
diff --git a/docs/reference/search/enumvalues_0.html b/docs/reference/search/enumvalues_0.html
deleted file mode 100644
index 78895c7..0000000
--- a/docs/reference/search/enumvalues_0.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_0.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_0.js b/docs/reference/search/enumvalues_0.js
deleted file mode 100644
index ae6ce98..0000000
--- a/docs/reference/search/enumvalues_0.js
+++ /dev/null
@@ -1,10 +0,0 @@
-var searchData=
-[
-  ['aaudio',['AAudio',['../namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a99780b1e8d754eb42abed0ca5253e55b',1,'oboe']]],
-  ['alarm',['Alarm',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a46c4c4d980dfe025ae5b35aa0011dde4',1,'oboe']]],
-  ['allocate',['Allocate',['../namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa8485ca716c8cd4aafee372fd7028c123',1,'oboe']]],
-  ['assistanceaccessibility',['AssistanceAccessibility',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a639ffd54516c1a84a288a363c9469df8',1,'oboe']]],
-  ['assistancenavigationguidance',['AssistanceNavigationGuidance',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0ade058a1314f9a8504593259ff4f21a1e',1,'oboe']]],
-  ['assistancesonification',['AssistanceSonification',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a1ce57a0572748beebfc0c664ca1077e7',1,'oboe']]],
-  ['assistant',['Assistant',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a9b1363da9503dbd4142c0274a88e8d4b',1,'oboe']]]
-];
diff --git a/docs/reference/search/enumvalues_1.html b/docs/reference/search/enumvalues_1.html
deleted file mode 100644
index 9b02a4b..0000000
--- a/docs/reference/search/enumvalues_1.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_1.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_1.js b/docs/reference/search/enumvalues_1.js
deleted file mode 100644
index b71b1ef..0000000
--- a/docs/reference/search/enumvalues_1.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['best',['Best',['../namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1da68ef004de6166492c1d668eb8efe09bd',1,'oboe']]]
-];
diff --git a/docs/reference/search/enumvalues_2.html b/docs/reference/search/enumvalues_2.html
deleted file mode 100644
index 2482854..0000000
--- a/docs/reference/search/enumvalues_2.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_2.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_2.js b/docs/reference/search/enumvalues_2.js
deleted file mode 100644
index 95d7223..0000000
--- a/docs/reference/search/enumvalues_2.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['camcorder',['Camcorder',['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a6e8ef178769235d18b44fe2bb5ab33fe',1,'oboe']]]
-];
diff --git a/docs/reference/search/enumvalues_3.html b/docs/reference/search/enumvalues_3.html
deleted file mode 100644
index e6124b9..0000000
--- a/docs/reference/search/enumvalues_3.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_3.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_3.js b/docs/reference/search/enumvalues_3.js
deleted file mode 100644
index b328e30..0000000
--- a/docs/reference/search/enumvalues_3.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['exclusive',['Exclusive',['../namespaceoboe.html#a8330247b25429953a08354f41834d520a2ef50b4c466304dc6ac77bac8a779971',1,'oboe']]]
-];
diff --git a/docs/reference/search/enumvalues_4.html b/docs/reference/search/enumvalues_4.html
deleted file mode 100644
index 8d234cf..0000000
--- a/docs/reference/search/enumvalues_4.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_4.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_4.js b/docs/reference/search/enumvalues_4.js
deleted file mode 100644
index 092f182..0000000
--- a/docs/reference/search/enumvalues_4.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var searchData=
-[
-  ['fastest',['Fastest',['../namespaceoboe.html#a82f3720eba7654aceb7282be36f9ff1da90fd7fdf6f41406a75e5265b9583bb4e',1,'oboe']]],
-  ['float',['Float',['../namespaceoboe.html#a92afc593e856571aacbfd02e57075df6a22ae0e2b89e5e3d477f988cc36d3272b',1,'oboe']]]
-];
diff --git a/docs/reference/search/enumvalues_5.html b/docs/reference/search/enumvalues_5.html
deleted file mode 100644
index d16ee24..0000000
--- a/docs/reference/search/enumvalues_5.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_5.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_5.js b/docs/reference/search/enumvalues_5.js
deleted file mode 100644
index 1a458e6..0000000
--- a/docs/reference/search/enumvalues_5.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var searchData=
-[
-  ['game',['Game',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a63d72051e901c069f8aa1b32aa0c43bb',1,'oboe']]],
-  ['generic',['Generic',['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a0ba6f369e7f8a700c14afe2992290544',1,'oboe']]]
-];
diff --git a/docs/reference/search/enumvalues_6.html b/docs/reference/search/enumvalues_6.html
deleted file mode 100644
index c39f086..0000000
--- a/docs/reference/search/enumvalues_6.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_6.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_6.js b/docs/reference/search/enumvalues_6.js
deleted file mode 100644
index 6152673..0000000
--- a/docs/reference/search/enumvalues_6.js
+++ /dev/null
@@ -1,6 +0,0 @@
-var searchData=
-[
-  ['i16',['I16',['../namespaceoboe.html#a92afc593e856571aacbfd02e57075df6abcd774f891b5f9df7099f3ea75dadf8d',1,'oboe']]],
-  ['input',['Input',['../namespaceoboe.html#af2147500089212955498a08ef2edb5aea324118a6721dd6b8a9b9f4e327df2bf5',1,'oboe']]],
-  ['invalid',['Invalid',['../namespaceoboe.html#a92afc593e856571aacbfd02e57075df6a4bbb8f967da6d1a610596d7257179c2b',1,'oboe']]]
-];
diff --git a/docs/reference/search/enumvalues_7.html b/docs/reference/search/enumvalues_7.html
deleted file mode 100644
index f75419f..0000000
--- a/docs/reference/search/enumvalues_7.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_7.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_7.js b/docs/reference/search/enumvalues_7.js
deleted file mode 100644
index 5a5e75e..0000000
--- a/docs/reference/search/enumvalues_7.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['lowlatency',['LowLatency',['../namespaceoboe.html#a1068781f3920654b1bfd7ed136468184a611907b5ab1865515c35357efa41a9b9',1,'oboe']]]
-];
diff --git a/docs/reference/search/enumvalues_8.html b/docs/reference/search/enumvalues_8.html
deleted file mode 100644
index 96b5b73..0000000
--- a/docs/reference/search/enumvalues_8.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_8.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_8.js b/docs/reference/search/enumvalues_8.js
deleted file mode 100644
index d608830..0000000
--- a/docs/reference/search/enumvalues_8.js
+++ /dev/null
@@ -1,7 +0,0 @@
-var searchData=
-[
-  ['media',['Media',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a3b563524fdb17b4a86590470d40bef74',1,'oboe']]],
-  ['mono',['Mono',['../namespaceoboe.html#a522e6806948369987639a0d1df03c029a8be103218645e121b51078620f452c79',1,'oboe']]],
-  ['movie',['Movie',['../namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba8b3b366178c2b7b1688bca6cd33758b1',1,'oboe']]],
-  ['music',['Music',['../namespaceoboe.html#a2a3cec6f021c1a324df60273710c604bac156fcc7b29059305cef26f3904d4517',1,'oboe']]]
-];
diff --git a/docs/reference/search/enumvalues_9.html b/docs/reference/search/enumvalues_9.html
deleted file mode 100644
index 2e532f4..0000000
--- a/docs/reference/search/enumvalues_9.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_9.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_9.js b/docs/reference/search/enumvalues_9.js
deleted file mode 100644
index 676a565..0000000
--- a/docs/reference/search/enumvalues_9.js
+++ /dev/null
@@ -1,7 +0,0 @@
-var searchData=
-[
-  ['none',['None',['../namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa58c518b26e83ea48393a76f6c9ecb51f',1,'oboe::None()'],['../namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa6adf97f83acf6453d4a6a4b1070f3754',1,'oboe::None()'],['../namespaceoboe.html#a5752250c10e96179e3618d7f72937eafa6adf97f83acf6453d4a6a4b1070f3754',1,'oboe::None()']]],
-  ['notification',['Notification',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a96d008db67fc0b5551a926842bbb6a71',1,'oboe']]],
-  ['notificationevent',['NotificationEvent',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a089240b5380dbd12f1eac0ec258a3b2f',1,'oboe']]],
-  ['notificationringtone',['NotificationRingtone',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a4e7a4b08274d472394b740a20d3bbdaf',1,'oboe']]]
-];
diff --git a/docs/reference/search/enumvalues_a.html b/docs/reference/search/enumvalues_a.html
deleted file mode 100644
index 8486158..0000000
--- a/docs/reference/search/enumvalues_a.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_a.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_a.js b/docs/reference/search/enumvalues_a.js
deleted file mode 100644
index 5ee70a9..0000000
--- a/docs/reference/search/enumvalues_a.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var searchData=
-[
-  ['opensles',['OpenSLES',['../namespaceoboe.html#a92972414867c81d5974cb2ed7abefbf6a24e758ea9c1e842ef71cc8ff8b63fa9b',1,'oboe']]],
-  ['output',['Output',['../namespaceoboe.html#af2147500089212955498a08ef2edb5aea29c2c02a361c9d7028472e5d92cd4a54',1,'oboe']]]
-];
diff --git a/docs/reference/search/enumvalues_b.html b/docs/reference/search/enumvalues_b.html
deleted file mode 100644
index 3ac456a..0000000
--- a/docs/reference/search/enumvalues_b.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_b.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_b.js b/docs/reference/search/enumvalues_b.js
deleted file mode 100644
index b39686f..0000000
--- a/docs/reference/search/enumvalues_b.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['powersaving',['PowerSaving',['../namespaceoboe.html#a1068781f3920654b1bfd7ed136468184abbad080463ed11f9d77797c04aa1e5b1',1,'oboe']]]
-];
diff --git a/docs/reference/search/enumvalues_c.html b/docs/reference/search/enumvalues_c.html
deleted file mode 100644
index 0f79745..0000000
--- a/docs/reference/search/enumvalues_c.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_c.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_c.js b/docs/reference/search/enumvalues_c.js
deleted file mode 100644
index d63160d..0000000
--- a/docs/reference/search/enumvalues_c.js
+++ /dev/null
@@ -1,7 +0,0 @@
-var searchData=
-[
-  ['shared',['Shared',['../namespaceoboe.html#a8330247b25429953a08354f41834d520aa6156ea9d66fef24e87e841fbabf7cca',1,'oboe']]],
-  ['sonification',['Sonification',['../namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba0885eef555037e94a7cf39fe683c2799',1,'oboe']]],
-  ['speech',['Speech',['../namespaceoboe.html#a2a3cec6f021c1a324df60273710c604ba3dc48a4b4619aa4edd1da7b937b4dcd1',1,'oboe']]],
-  ['stereo',['Stereo',['../namespaceoboe.html#a522e6806948369987639a0d1df03c029a534e646333ca7568317b171ea96b89ba',1,'oboe']]]
-];
diff --git a/docs/reference/search/enumvalues_d.html b/docs/reference/search/enumvalues_d.html
deleted file mode 100644
index ea3e08f..0000000
--- a/docs/reference/search/enumvalues_d.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_d.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_d.js b/docs/reference/search/enumvalues_d.js
deleted file mode 100644
index 256a82b..0000000
--- a/docs/reference/search/enumvalues_d.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var searchData=
-[
-  ['unprocessed',['Unprocessed',['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06acad9424158aefae0af7975901b11d85f',1,'oboe']]],
-  ['unspecified',['Unspecified',['../namespaceoboe.html#a522e6806948369987639a0d1df03c029a946257a568f77c12df4fc4c49125da76',1,'oboe::Unspecified()'],['../namespaceoboe.html#a522e6806948369987639a0d1df03c029a6fcdc090caeade09d0efd6253932b6f5',1,'oboe::Unspecified()'],['../namespaceoboe.html#a522e6806948369987639a0d1df03c029a6fcdc090caeade09d0efd6253932b6f5',1,'oboe::Unspecified()']]]
-];
diff --git a/docs/reference/search/enumvalues_e.html b/docs/reference/search/enumvalues_e.html
deleted file mode 100644
index fcadce6..0000000
--- a/docs/reference/search/enumvalues_e.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="enumvalues_e.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/enumvalues_e.js b/docs/reference/search/enumvalues_e.js
deleted file mode 100644
index 4225514..0000000
--- a/docs/reference/search/enumvalues_e.js
+++ /dev/null
@@ -1,7 +0,0 @@
-var searchData=
-[
-  ['voicecommunication',['VoiceCommunication',['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a1862e72c9730c448fbec6f61a5d8234d',1,'oboe::VoiceCommunication()'],['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06a5bad8854288c956062ec1d4d7c14fed6',1,'oboe::VoiceCommunication()']]],
-  ['voicecommunicationsignalling',['VoiceCommunicationSignalling',['../namespaceoboe.html#a104ee8396c173fefac429759ea3c21a0a404f62633744bf4da0c6a27a2b78ce74',1,'oboe']]],
-  ['voiceperformance',['VoicePerformance',['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06ad19edec0a23e435c774bf3bbcf1d999c',1,'oboe']]],
-  ['voicerecognition',['VoiceRecognition',['../namespaceoboe.html#a4477ed232b02e2694d9309baf55a8f06af6e440b4e9edf49afe18aa4be77be6fc',1,'oboe']]]
-];
diff --git a/docs/reference/search/functions_0.html b/docs/reference/search/functions_0.html
deleted file mode 100644
index bc73761..0000000
--- a/docs/reference/search/functions_0.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_0.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_0.js b/docs/reference/search/functions_0.js
deleted file mode 100644
index ac56f9d..0000000
--- a/docs/reference/search/functions_0.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var searchData=
-[
-  ['audiostream',['AudioStream',['../classoboe_1_1_audio_stream.html#a8ebb587a07bf62c864fd62c63b241fd4',1,'oboe::AudioStream']]],
-  ['audiostreambase',['AudioStreamBase',['../classoboe_1_1_audio_stream_base.html#aa6b103e1b0f808bbc4949d56f0829f98',1,'oboe::AudioStreamBase']]]
-];
diff --git a/docs/reference/search/functions_1.html b/docs/reference/search/functions_1.html
deleted file mode 100644
index bfcf880..0000000
--- a/docs/reference/search/functions_1.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_1.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_1.js b/docs/reference/search/functions_1.js
deleted file mode 100644
index 0e05de0..0000000
--- a/docs/reference/search/functions_1.js
+++ /dev/null
@@ -1,10 +0,0 @@
-var searchData=
-[
-  ['calculatelatencymillis',['calculateLatencyMillis',['../classoboe_1_1_audio_stream.html#ae023cb001f3261d064f423101798d6be',1,'oboe::AudioStream']]],
-  ['close',['close',['../classoboe_1_1_audio_stream.html#a9c8ea30e30e513766d5e996c370eb8d8',1,'oboe::AudioStream']]],
-  ['convertfloattopcm16',['convertFloatToPcm16',['../namespaceoboe.html#adbda063116feb9fa98a31ee820170060',1,'oboe']]],
-  ['convertformattosizeinbytes',['convertFormatToSizeInBytes',['../namespaceoboe.html#ac67383a3df0f6e7a51f8415ffd9fdaca',1,'oboe']]],
-  ['convertpcm16tofloat',['convertPcm16ToFloat',['../namespaceoboe.html#ad17bee42828d13f2ef62a889e175c643',1,'oboe']]],
-  ['converttotext',['convertToText',['../namespaceoboe.html#af65aaea3c5d82eee6906664d61c094b3',1,'oboe']]],
-  ['createbasedonsign',['createBasedOnSign',['../classoboe_1_1_result_with_value.html#a2304c6120e2aad8f2189383a98c7b0a7',1,'oboe::ResultWithValue']]]
-];
diff --git a/docs/reference/search/functions_2.html b/docs/reference/search/functions_2.html
deleted file mode 100644
index 2b44474..0000000
--- a/docs/reference/search/functions_2.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_2.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_2.js b/docs/reference/search/functions_2.js
deleted file mode 100644
index 6ae5fc1..0000000
--- a/docs/reference/search/functions_2.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['error',['error',['../classoboe_1_1_result_with_value.html#adfc76ae6db81535c2e82b856975eed41',1,'oboe::ResultWithValue']]]
-];
diff --git a/docs/reference/search/functions_3.html b/docs/reference/search/functions_3.html
deleted file mode 100644
index 3dca367..0000000
--- a/docs/reference/search/functions_3.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_3.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_3.js b/docs/reference/search/functions_3.js
deleted file mode 100644
index 03977c3..0000000
--- a/docs/reference/search/functions_3.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var searchData=
-[
-  ['firedatacallback',['fireDataCallback',['../classoboe_1_1_audio_stream.html#ab7a8cfe5d6039386bc5850fd5ee9bd62',1,'oboe::AudioStream']]],
-  ['flush',['flush',['../classoboe_1_1_audio_stream.html#a32c25c0333eab3d65ce02275ad4acb3d',1,'oboe::AudioStream']]]
-];
diff --git a/docs/reference/search/functions_4.html b/docs/reference/search/functions_4.html
deleted file mode 100644
index e713f28..0000000
--- a/docs/reference/search/functions_4.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_4.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_4.js b/docs/reference/search/functions_4.js
deleted file mode 100644
index eb44bb5..0000000
--- a/docs/reference/search/functions_4.js
+++ /dev/null
@@ -1,36 +0,0 @@
-var searchData=
-[
-  ['getaudioapi',['getAudioApi',['../classoboe_1_1_audio_stream.html#a2b7a3cee7444114843dbdd1fc705f6bb',1,'oboe::AudioStream::getAudioApi()'],['../classoboe_1_1_audio_stream_builder.html#ac9d41811c297fd28bc61833f640bb8d0',1,'oboe::AudioStreamBuilder::getAudioApi()']]],
-  ['getavailableframes',['getAvailableFrames',['../classoboe_1_1_audio_stream.html#afa35ee4b8629fbffe26b9be7c7ed55d2',1,'oboe::AudioStream']]],
-  ['getbuffercapacityinframes',['getBufferCapacityInFrames',['../classoboe_1_1_audio_stream_base.html#ab1531253e64aaebe9e9eddbafb9098fc',1,'oboe::AudioStreamBase']]],
-  ['getbuffersizeinframes',['getBufferSizeInFrames',['../classoboe_1_1_audio_stream_base.html#af5217ab05bfde0d7637024b599302d0b',1,'oboe::AudioStreamBase']]],
-  ['getbytesperframe',['getBytesPerFrame',['../classoboe_1_1_audio_stream.html#a5c01907a59d5f89a5e4b819fe66b08bc',1,'oboe::AudioStream']]],
-  ['getbytespersample',['getBytesPerSample',['../classoboe_1_1_audio_stream.html#a44dda61e6e948e49b68f87172f084d62',1,'oboe::AudioStream']]],
-  ['getchannelcount',['getChannelCount',['../classoboe_1_1_audio_stream_base.html#a87e6bf37d6a2a5e983b8ca8d29aea575',1,'oboe::AudioStreamBase']]],
-  ['getcontenttype',['getContentType',['../classoboe_1_1_audio_stream_base.html#ab12e2d068fa87e0553b01a400d96eb82',1,'oboe::AudioStreamBase']]],
-  ['getdatacallback',['getDataCallback',['../classoboe_1_1_audio_stream_base.html#a9fb2f34ae62dbda2c10e8513b754fa0c',1,'oboe::AudioStreamBase']]],
-  ['getdeviceid',['getDeviceId',['../classoboe_1_1_audio_stream_base.html#a093057d625bc896864b959974c265f21',1,'oboe::AudioStreamBase']]],
-  ['getdirection',['getDirection',['../classoboe_1_1_audio_stream_base.html#a6f86f2233a04c5a0b056f0c1c261f1b1',1,'oboe::AudioStreamBase']]],
-  ['geterrorcallback',['getErrorCallback',['../classoboe_1_1_audio_stream_base.html#a1328fb9288166ff325995ce1ea1867f0',1,'oboe::AudioStreamBase']]],
-  ['getformat',['getFormat',['../classoboe_1_1_audio_stream_base.html#ab1e640461d7bf9d596decb913da7ac86',1,'oboe::AudioStreamBase']]],
-  ['getframesperburst',['getFramesPerBurst',['../classoboe_1_1_audio_stream.html#ac160acb656515814fa6fdd157c131a0a',1,'oboe::AudioStream']]],
-  ['getframespercallback',['getFramesPerCallback',['../classoboe_1_1_audio_stream_base.html#a8878a90949badbb5486cc2e022a57086',1,'oboe::AudioStreamBase']]],
-  ['getframesperdatacallback',['getFramesPerDataCallback',['../classoboe_1_1_audio_stream_base.html#abc3ee2815568b425d15a40e132aa8e38',1,'oboe::AudioStreamBase']]],
-  ['getframesread',['getFramesRead',['../classoboe_1_1_audio_stream.html#aeebfc59abd978cd6dff07c16cfe266df',1,'oboe::AudioStream']]],
-  ['getframeswritten',['getFramesWritten',['../classoboe_1_1_audio_stream.html#ab43dd4074e1de57bac1c3fd111430341',1,'oboe::AudioStream']]],
-  ['getinputpreset',['getInputPreset',['../classoboe_1_1_audio_stream_base.html#a5c773b93b8aa38191c7199cab023428a',1,'oboe::AudioStreamBase']]],
-  ['getlasterrorcallbackresult',['getLastErrorCallbackResult',['../classoboe_1_1_audio_stream.html#a8fe8afdf164a1fe835c514f709743d75',1,'oboe::AudioStream']]],
-  ['getperformancemode',['getPerformanceMode',['../classoboe_1_1_audio_stream_base.html#a2ddb935de0e24dd7ae8e2cfbecac9fdc',1,'oboe::AudioStreamBase']]],
-  ['getpropertyinteger',['getPropertyInteger',['../namespaceoboe.html#a4284cffcf4d852ca4f357429303d7af5',1,'oboe']]],
-  ['getpropertystring',['getPropertyString',['../namespaceoboe.html#a1ff1f1323d722494dac353a6b4d1bd5b',1,'oboe']]],
-  ['getsamplerate',['getSampleRate',['../classoboe_1_1_audio_stream_base.html#ae9d32f3e09174bad69e74f147ee33087',1,'oboe::AudioStreamBase']]],
-  ['getsamplerateconversionquality',['getSampleRateConversionQuality',['../classoboe_1_1_audio_stream_base.html#a1de8d6982d411a0cf50a32efba0ca3f2',1,'oboe::AudioStreamBase']]],
-  ['getsdkversion',['getSdkVersion',['../namespaceoboe.html#a54528938e9fccab7ad8947ccf0e409db',1,'oboe']]],
-  ['getsessionid',['getSessionId',['../classoboe_1_1_audio_stream_base.html#aa3c502ce09bbad7690a2dd6acaf8892e',1,'oboe::AudioStreamBase']]],
-  ['getsharingmode',['getSharingMode',['../classoboe_1_1_audio_stream_base.html#a1fb033fc963f971bd1aa8f6707e49b41',1,'oboe::AudioStreamBase']]],
-  ['getstate',['getState',['../classoboe_1_1_audio_stream.html#a9d37cc6513823c685ae892626ff83ea8',1,'oboe::AudioStream']]],
-  ['gettimestamp',['getTimestamp',['../classoboe_1_1_audio_stream.html#acb8edbc17ff79993a8ed996d216fe6f3',1,'oboe::AudioStream::getTimestamp(clockid_t, int64_t *, int64_t *)'],['../classoboe_1_1_audio_stream.html#a49254e6b1b19cb6d0ca6c63058029771',1,'oboe::AudioStream::getTimestamp(clockid_t)']]],
-  ['getunderlyingstream',['getUnderlyingStream',['../classoboe_1_1_audio_stream.html#a5458d7130415eb4defe3dbc11d479e2f',1,'oboe::AudioStream']]],
-  ['getusage',['getUsage',['../classoboe_1_1_audio_stream_base.html#a0bcfb2f8bd11c92b541fd910da9af397',1,'oboe::AudioStreamBase']]],
-  ['getxruncount',['getXRunCount',['../classoboe_1_1_audio_stream.html#ad1a1d3bbf3b348ed92b7ed18ce9cc261',1,'oboe::AudioStream']]]
-];
diff --git a/docs/reference/search/functions_5.html b/docs/reference/search/functions_5.html
deleted file mode 100644
index cfe6b17..0000000
--- a/docs/reference/search/functions_5.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_5.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_5.js b/docs/reference/search/functions_5.js
deleted file mode 100644
index 3d03906..0000000
--- a/docs/reference/search/functions_5.js
+++ /dev/null
@@ -1,13 +0,0 @@
-var searchData=
-[
-  ['isaaudiorecommended',['isAAudioRecommended',['../classoboe_1_1_audio_stream_builder.html#a622732bbe5c6577356d749f7dc2108df',1,'oboe::AudioStreamBuilder']]],
-  ['isaaudiosupported',['isAAudioSupported',['../classoboe_1_1_audio_stream_builder.html#a18e7b5f7554a4c2ca763e35e8117d699',1,'oboe::AudioStreamBuilder']]],
-  ['isatmaximumbuffersize',['isAtMaximumBufferSize',['../classoboe_1_1_latency_tuner.html#a45c013fd6787ad09d328385d6314c4d4',1,'oboe::LatencyTuner']]],
-  ['ischannelconversionallowed',['isChannelConversionAllowed',['../classoboe_1_1_audio_stream_base.html#aa4ec3aa76e69350fbce6f00786211495',1,'oboe::AudioStreamBase']]],
-  ['isdatacallbackenabled',['isDataCallbackEnabled',['../classoboe_1_1_audio_stream.html#add85011ba825f74931deeb92c5edf831',1,'oboe::AudioStream']]],
-  ['isdatacallbackspecified',['isDataCallbackSpecified',['../classoboe_1_1_audio_stream_base.html#a9a54d38b985a2eb12c6972104dc0ce73',1,'oboe::AudioStreamBase']]],
-  ['iserrorcallbackspecified',['isErrorCallbackSpecified',['../classoboe_1_1_audio_stream_base.html#aef579f6d1f779c89d051f0963f2976b3',1,'oboe::AudioStreamBase']]],
-  ['isformatconversionallowed',['isFormatConversionAllowed',['../classoboe_1_1_audio_stream_base.html#ace3625a7332bf02a86818fdf63fcccb4',1,'oboe::AudioStreamBase']]],
-  ['isvalidconfig',['isValidConfig',['../classoboe_1_1_audio_stream_base.html#a5d5e07e98921d0193a5c0ccbe06f68c2',1,'oboe::AudioStreamBase']]],
-  ['isxruncountsupported',['isXRunCountSupported',['../classoboe_1_1_audio_stream.html#a43d8a098440cde28f4ee8bedd6d107c4',1,'oboe::AudioStream']]]
-];
diff --git a/docs/reference/search/functions_6.html b/docs/reference/search/functions_6.html
deleted file mode 100644
index a78ec13..0000000
--- a/docs/reference/search/functions_6.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_6.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_6.js b/docs/reference/search/functions_6.js
deleted file mode 100644
index f7da369..0000000
--- a/docs/reference/search/functions_6.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var searchData=
-[
-  ['latencytuner',['LatencyTuner',['../classoboe_1_1_latency_tuner.html#a0263b9a55825c0a403653b2b508073ea',1,'oboe::LatencyTuner::LatencyTuner(AudioStream &amp;stream)'],['../classoboe_1_1_latency_tuner.html#ab437bd10605af9e5733d043f8adc0b43',1,'oboe::LatencyTuner::LatencyTuner(AudioStream &amp;stream, int32_t maximumBufferSize)']]],
-  ['launchstopthread',['launchStopThread',['../classoboe_1_1_audio_stream.html#aa5f4801cca6877eeaa4735b93933269d',1,'oboe::AudioStream']]]
-];
diff --git a/docs/reference/search/functions_7.html b/docs/reference/search/functions_7.html
deleted file mode 100644
index 7842361..0000000
--- a/docs/reference/search/functions_7.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_7.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_7.js b/docs/reference/search/functions_7.js
deleted file mode 100644
index d06a926..0000000
--- a/docs/reference/search/functions_7.js
+++ /dev/null
@@ -1,16 +0,0 @@
-var searchData=
-[
-  ['onaudioready',['onAudioReady',['../classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d',1,'oboe::AudioStreamDataCallback::onAudioReady()'],['../classoboe_1_1_stabilized_callback.html#ad447e12ebf732cf151655c1fbaf58a49',1,'oboe::StabilizedCallback::onAudioReady()']]],
-  ['ondefaultcallback',['onDefaultCallback',['../classoboe_1_1_audio_stream.html#a0ea79e60f5a3d29fc5a1a116aba11dfe',1,'oboe::AudioStream']]],
-  ['onerror',['onError',['../classoboe_1_1_audio_stream_error_callback.html#a5ad4b8936746ecbb2160a9389b117fc3',1,'oboe::AudioStreamErrorCallback']]],
-  ['onerrorafterclose',['onErrorAfterClose',['../classoboe_1_1_audio_stream_error_callback.html#a76bd3ef3e00396e10c21812003654cfe',1,'oboe::AudioStreamErrorCallback::onErrorAfterClose()'],['../classoboe_1_1_stabilized_callback.html#af7521da42c4b08a71e6102994f6f41f4',1,'oboe::StabilizedCallback::onErrorAfterClose()']]],
-  ['onerrorbeforeclose',['onErrorBeforeClose',['../classoboe_1_1_audio_stream_error_callback.html#a4eb1e4916b71d8231e97b19898bc9bf0',1,'oboe::AudioStreamErrorCallback::onErrorBeforeClose()'],['../classoboe_1_1_stabilized_callback.html#a7ec0e9fca3181962ab78716bcda83e10',1,'oboe::StabilizedCallback::onErrorBeforeClose()']]],
-  ['open',['open',['../classoboe_1_1_audio_stream.html#a686c6ce8a29051c858fd1de386805dc6',1,'oboe::AudioStream']]],
-  ['openmanagedstream',['openManagedStream',['../classoboe_1_1_audio_stream_builder.html#a7ab172a9be4fca2489aa5cbcc48c20ff',1,'oboe::AudioStreamBuilder']]],
-  ['openstream',['openStream',['../classoboe_1_1_audio_stream_builder.html#a86b94cfa47729bef2e04dce1a9086074',1,'oboe::AudioStreamBuilder::openStream(AudioStream **stream)'],['../classoboe_1_1_audio_stream_builder.html#a44b68216c48f8fb08a9e63178e0b0eeb',1,'oboe::AudioStreamBuilder::openStream(std::shared_ptr&lt; oboe::AudioStream &gt; &amp;stream)']]],
-  ['operator_20_21',['operator !',['../classoboe_1_1_result_with_value.html#a6fb3c61c5716a045ba48dc5a5dfc8169',1,'oboe::ResultWithValue']]],
-  ['operator_20bool',['operator bool',['../classoboe_1_1_result_with_value.html#ae32b1953b777af7d1d0c94862ca39986',1,'oboe::ResultWithValue']]],
-  ['operator_20result',['operator Result',['../classoboe_1_1_result_with_value.html#af62107817c0bc76047e6b655a78504ba',1,'oboe::ResultWithValue']]],
-  ['operator_3c_3c',['operator&lt;&lt;',['../namespaceoboe.html#aa403103686222502d1cfc47bafc10aeb',1,'oboe']]],
-  ['operator_3d',['operator=',['../classoboe_1_1_audio_stream_base.html#aa9c987a59555d7a60b9f7a63f4afc7fc',1,'oboe::AudioStreamBase']]]
-];
diff --git a/docs/reference/search/functions_8.html b/docs/reference/search/functions_8.html
deleted file mode 100644
index 48feafe..0000000
--- a/docs/reference/search/functions_8.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_8.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_8.js b/docs/reference/search/functions_8.js
deleted file mode 100644
index 6d3c638..0000000
--- a/docs/reference/search/functions_8.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['pause',['pause',['../classoboe_1_1_audio_stream.html#a04f29836748a8e5842aef2be200022ad',1,'oboe::AudioStream']]]
-];
diff --git a/docs/reference/search/functions_9.html b/docs/reference/search/functions_9.html
deleted file mode 100644
index 0f05a8b..0000000
--- a/docs/reference/search/functions_9.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_9.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_9.js b/docs/reference/search/functions_9.js
deleted file mode 100644
index eec0888..0000000
--- a/docs/reference/search/functions_9.js
+++ /dev/null
@@ -1,10 +0,0 @@
-var searchData=
-[
-  ['read',['read',['../classoboe_1_1_audio_stream.html#a8089f0a0cb68d4039cf33e6584129978',1,'oboe::AudioStream']]],
-  ['requestflush',['requestFlush',['../classoboe_1_1_audio_stream.html#a6bd5d633ff999e4da1faf3cd949aa602',1,'oboe::AudioStream']]],
-  ['requestpause',['requestPause',['../classoboe_1_1_audio_stream.html#a7f18bb3cc5490fd7fbc1f6da63c730f6',1,'oboe::AudioStream']]],
-  ['requestreset',['requestReset',['../classoboe_1_1_latency_tuner.html#a6c0142e08dc65eda8f758b4794450867',1,'oboe::LatencyTuner']]],
-  ['requeststart',['requestStart',['../classoboe_1_1_audio_stream.html#a3c484e314dee8dfed1d419f487b5d601',1,'oboe::AudioStream']]],
-  ['requeststop',['requestStop',['../classoboe_1_1_audio_stream.html#a820e634f741e6b5efdcef8104cecb919',1,'oboe::AudioStream']]],
-  ['resultwithvalue',['ResultWithValue',['../classoboe_1_1_result_with_value.html#aae75caa0d16a9e23a012f77fb50c5927',1,'oboe::ResultWithValue::ResultWithValue(oboe::Result error)'],['../classoboe_1_1_result_with_value.html#a600309367db58d71f0ec16e90f7ebea5',1,'oboe::ResultWithValue::ResultWithValue(T value)']]]
-];
diff --git a/docs/reference/search/functions_a.html b/docs/reference/search/functions_a.html
deleted file mode 100644
index 03faad2..0000000
--- a/docs/reference/search/functions_a.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_a.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_a.js b/docs/reference/search/functions_a.js
deleted file mode 100644
index ed9e410..0000000
--- a/docs/reference/search/functions_a.js
+++ /dev/null
@@ -1,31 +0,0 @@
-var searchData=
-[
-  ['setaudioapi',['setAudioApi',['../classoboe_1_1_audio_stream_builder.html#a38c6d6c5e718df1e3ac69daaac47c391',1,'oboe::AudioStreamBuilder']]],
-  ['setbuffercapacityinframes',['setBufferCapacityInFrames',['../classoboe_1_1_audio_stream_builder.html#abaff480867af51ca0899bfa6fd7cc3ef',1,'oboe::AudioStreamBuilder']]],
-  ['setbuffersizeincrement',['setBufferSizeIncrement',['../classoboe_1_1_latency_tuner.html#a2684b30205126c8acd2f75d01cce05db',1,'oboe::LatencyTuner']]],
-  ['setbuffersizeinframes',['setBufferSizeInFrames',['../classoboe_1_1_audio_stream.html#a06e3f9e133b3a75515e7793939d1cd03',1,'oboe::AudioStream']]],
-  ['setcallback',['setCallback',['../classoboe_1_1_audio_stream_builder.html#a698cefa9af73bc97c020c004821fccbd',1,'oboe::AudioStreamBuilder']]],
-  ['setchannelconversionallowed',['setChannelConversionAllowed',['../classoboe_1_1_audio_stream_builder.html#ad50f5d20cdf420d982bf499790cd3563',1,'oboe::AudioStreamBuilder']]],
-  ['setchannelcount',['setChannelCount',['../classoboe_1_1_audio_stream_builder.html#a075d10291e1f998d90c2f73ef767b5a7',1,'oboe::AudioStreamBuilder']]],
-  ['setcontenttype',['setContentType',['../classoboe_1_1_audio_stream_builder.html#a6a17bafc217c2b624179fbbf77fe4468',1,'oboe::AudioStreamBuilder']]],
-  ['setdatacallback',['setDataCallback',['../classoboe_1_1_audio_stream_builder.html#acad307720e0f370267b4e2f9a626ae70',1,'oboe::AudioStreamBuilder']]],
-  ['setdatacallbackenabled',['setDataCallbackEnabled',['../classoboe_1_1_audio_stream.html#a0faa6d3a6fd4f367e6f80d5a29e6dcba',1,'oboe::AudioStream']]],
-  ['setdeviceid',['setDeviceId',['../classoboe_1_1_audio_stream_builder.html#af36ddcd00686a9e1de661bdac0685a8e',1,'oboe::AudioStreamBuilder']]],
-  ['setdirection',['setDirection',['../classoboe_1_1_audio_stream_builder.html#ab3fbd47b06197619c26393637e26354c',1,'oboe::AudioStreamBuilder']]],
-  ['seterrorcallback',['setErrorCallback',['../classoboe_1_1_audio_stream_builder.html#aacb66f530bfc6f545911b5e169774567',1,'oboe::AudioStreamBuilder']]],
-  ['setformat',['setFormat',['../classoboe_1_1_audio_stream_builder.html#aa2e1d2d73cd6c2eb9f349bf2fe5f6515',1,'oboe::AudioStreamBuilder']]],
-  ['setformatconversionallowed',['setFormatConversionAllowed',['../classoboe_1_1_audio_stream_builder.html#a7ec5f427cd6fe55cb1ce536ff0cbb4d2',1,'oboe::AudioStreamBuilder']]],
-  ['setframespercallback',['setFramesPerCallback',['../classoboe_1_1_audio_stream_builder.html#a3f397821f61eabaeedaf31064c859a54',1,'oboe::AudioStreamBuilder']]],
-  ['setframesperdatacallback',['setFramesPerDataCallback',['../classoboe_1_1_audio_stream_builder.html#afb8e95e80df7edd1af27af490438785e',1,'oboe::AudioStreamBuilder']]],
-  ['setinputpreset',['setInputPreset',['../classoboe_1_1_audio_stream_builder.html#a144a3d095fd668210282f1a91f23e1f0',1,'oboe::AudioStreamBuilder']]],
-  ['setminimumbuffersize',['setMinimumBufferSize',['../classoboe_1_1_latency_tuner.html#adc96aa53b18a051b6ccdacb838139bf8',1,'oboe::LatencyTuner']]],
-  ['setperformancemode',['setPerformanceMode',['../classoboe_1_1_audio_stream_builder.html#a6cd1d65612e844e59da71a68ea0ab3ee',1,'oboe::AudioStreamBuilder']]],
-  ['setsamplerate',['setSampleRate',['../classoboe_1_1_audio_stream_builder.html#a30ef3d5f51d56a9f980dc09600ed139d',1,'oboe::AudioStreamBuilder']]],
-  ['setsamplerateconversionquality',['setSampleRateConversionQuality',['../classoboe_1_1_audio_stream_builder.html#af7d24a9ec975d430732151e5ee0d1027',1,'oboe::AudioStreamBuilder']]],
-  ['setsessionid',['setSessionId',['../classoboe_1_1_audio_stream_builder.html#a54c1651bdbe089d0d714af499e8a5f1d',1,'oboe::AudioStreamBuilder']]],
-  ['setsharingmode',['setSharingMode',['../classoboe_1_1_audio_stream_builder.html#a3e991742acbbfb6fe5ebcf592c478654',1,'oboe::AudioStreamBuilder']]],
-  ['setusage',['setUsage',['../classoboe_1_1_audio_stream_builder.html#a593255a2f5eb972665775cfc5bc58f6a',1,'oboe::AudioStreamBuilder']]],
-  ['setworkaroundsenabled',['setWorkaroundsEnabled',['../classoboe_1_1_oboe_globals.html#af2b8af764c5a5e6fc007b7725117303b',1,'oboe::OboeGlobals']]],
-  ['start',['start',['../classoboe_1_1_audio_stream.html#af04f03eb6b64b564f1c4401688987d21',1,'oboe::AudioStream']]],
-  ['stop',['stop',['../classoboe_1_1_audio_stream.html#aec093859d42f0470c884edd1e976d9f3',1,'oboe::AudioStream']]]
-];
diff --git a/docs/reference/search/functions_b.html b/docs/reference/search/functions_b.html
deleted file mode 100644
index c690013..0000000
--- a/docs/reference/search/functions_b.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_b.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_b.js b/docs/reference/search/functions_b.js
deleted file mode 100644
index 40c62d8..0000000
--- a/docs/reference/search/functions_b.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['tune',['tune',['../classoboe_1_1_latency_tuner.html#ad2be756965e6a9af3114008eda892174',1,'oboe::LatencyTuner']]]
-];
diff --git a/docs/reference/search/functions_c.html b/docs/reference/search/functions_c.html
deleted file mode 100644
index 3b2976a..0000000
--- a/docs/reference/search/functions_c.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_c.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_c.js b/docs/reference/search/functions_c.js
deleted file mode 100644
index dc14aca..0000000
--- a/docs/reference/search/functions_c.js
+++ /dev/null
@@ -1,6 +0,0 @@
-var searchData=
-[
-  ['updateframesread',['updateFramesRead',['../classoboe_1_1_audio_stream.html#a462358ddab709c79d1a7968d6d55b727',1,'oboe::AudioStream']]],
-  ['updateframeswritten',['updateFramesWritten',['../classoboe_1_1_audio_stream.html#a64ad978c5f70ced17ef5a96605496515',1,'oboe::AudioStream']]],
-  ['usesaaudio',['usesAAudio',['../classoboe_1_1_audio_stream.html#a15cdaaaa4c1e8da322d6da33334c8147',1,'oboe::AudioStream']]]
-];
diff --git a/docs/reference/search/functions_d.html b/docs/reference/search/functions_d.html
deleted file mode 100644
index 0c54246..0000000
--- a/docs/reference/search/functions_d.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_d.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_d.js b/docs/reference/search/functions_d.js
deleted file mode 100644
index dc4094a..0000000
--- a/docs/reference/search/functions_d.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['value',['value',['../classoboe_1_1_result_with_value.html#a45f5c99a2c9f8fbaca502276f7ebb434',1,'oboe::ResultWithValue']]]
-];
diff --git a/docs/reference/search/functions_e.html b/docs/reference/search/functions_e.html
deleted file mode 100644
index c1bd870..0000000
--- a/docs/reference/search/functions_e.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="functions_e.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/functions_e.js b/docs/reference/search/functions_e.js
deleted file mode 100644
index 059114d..0000000
--- a/docs/reference/search/functions_e.js
+++ /dev/null
@@ -1,9 +0,0 @@
-var searchData=
-[
-  ['waitforavailableframes',['waitForAvailableFrames',['../classoboe_1_1_audio_stream.html#afddb0962863ccf9ec6672a042fe15941',1,'oboe::AudioStream']]],
-  ['waitforstatechange',['waitForStateChange',['../classoboe_1_1_audio_stream.html#a0c865a5501f369d959c39d8ab8b46a07',1,'oboe::AudioStream']]],
-  ['waitforstatetransition',['waitForStateTransition',['../classoboe_1_1_audio_stream.html#a8adbacd6a55a94a532916ab037fba1d6',1,'oboe::AudioStream']]],
-  ['waserrorcallbackcalled',['wasErrorCallbackCalled',['../classoboe_1_1_audio_stream.html#aa48da7bf28026b7cccee73e6b054af28',1,'oboe::AudioStream']]],
-  ['willuseaaudio',['willUseAAudio',['../classoboe_1_1_audio_stream_builder.html#aa07ea100fcb107d9f7913f206c2214f4',1,'oboe::AudioStreamBuilder']]],
-  ['write',['write',['../classoboe_1_1_audio_stream.html#a3612c05ed6b01a213dde67d913c07e11',1,'oboe::AudioStream']]]
-];
diff --git a/docs/reference/search/mag_sel.png b/docs/reference/search/mag_sel.png
deleted file mode 100644
index 39c0ed5..0000000
--- a/docs/reference/search/mag_sel.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/search/namespaces_0.html b/docs/reference/search/namespaces_0.html
deleted file mode 100644
index c534537..0000000
--- a/docs/reference/search/namespaces_0.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="namespaces_0.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/namespaces_0.js b/docs/reference/search/namespaces_0.js
deleted file mode 100644
index 9e061ed..0000000
--- a/docs/reference/search/namespaces_0.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['oboe',['oboe',['../namespaceoboe.html',1,'']]]
-];
diff --git a/docs/reference/search/nomatches.html b/docs/reference/search/nomatches.html
deleted file mode 100644
index 4377320..0000000
--- a/docs/reference/search/nomatches.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="NoMatches">No Matches</div>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/pages_0.html b/docs/reference/search/pages_0.html
deleted file mode 100644
index 3d06b05..0000000
--- a/docs/reference/search/pages_0.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="pages_0.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/pages_0.js b/docs/reference/search/pages_0.js
deleted file mode 100644
index 6f1bc35..0000000
--- a/docs/reference/search/pages_0.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['api_20reference',['API reference',['../index.html',1,'']]]
-];
diff --git a/docs/reference/search/pages_1.html b/docs/reference/search/pages_1.html
deleted file mode 100644
index 06f1e40..0000000
--- a/docs/reference/search/pages_1.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="pages_1.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/pages_1.js b/docs/reference/search/pages_1.js
deleted file mode 100644
index 038da54..0000000
--- a/docs/reference/search/pages_1.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['deprecated_20list',['Deprecated List',['../deprecated.html',1,'']]]
-];
diff --git a/docs/reference/search/search.css b/docs/reference/search/search.css
deleted file mode 100644
index 3cf9df9..0000000
--- a/docs/reference/search/search.css
+++ /dev/null
@@ -1,271 +0,0 @@
-/*---------------- Search Box */
-
-#FSearchBox {
-    float: left;
-}
-
-#MSearchBox {
-    white-space : nowrap;
-    float: none;
-    margin-top: 8px;
-    right: 0px;
-    width: 170px;
-    height: 24px;
-    z-index: 102;
-}
-
-#MSearchBox .left
-{
-    display:block;
-    position:absolute;
-    left:10px;
-    width:20px;
-    height:19px;
-    background:url('search_l.png') no-repeat;
-    background-position:right;
-}
-
-#MSearchSelect {
-    display:block;
-    position:absolute;
-    width:20px;
-    height:19px;
-}
-
-.left #MSearchSelect {
-    left:4px;
-}
-
-.right #MSearchSelect {
-    right:5px;
-}
-
-#MSearchField {
-    display:block;
-    position:absolute;
-    height:19px;
-    background:url('search_m.png') repeat-x;
-    border:none;
-    width:115px;
-    margin-left:20px;
-    padding-left:4px;
-    color: #909090;
-    outline: none;
-    font: 9pt Arial, Verdana, sans-serif;
-    -webkit-border-radius: 0px;
-}
-
-#FSearchBox #MSearchField {
-    margin-left:15px;
-}
-
-#MSearchBox .right {
-    display:block;
-    position:absolute;
-    right:10px;
-    top:8px;
-    width:20px;
-    height:19px;
-    background:url('search_r.png') no-repeat;
-    background-position:left;
-}
-
-#MSearchClose {
-    display: none;
-    position: absolute;
-    top: 4px;
-    background : none;
-    border: none;
-    margin: 0px 4px 0px 0px;
-    padding: 0px 0px;
-    outline: none;
-}
-
-.left #MSearchClose {
-    left: 6px;
-}
-
-.right #MSearchClose {
-    right: 2px;
-}
-
-.MSearchBoxActive #MSearchField {
-    color: #000000;
-}
-
-/*---------------- Search filter selection */
-
-#MSearchSelectWindow {
-    display: none;
-    position: absolute;
-    left: 0; top: 0;
-    border: 1px solid #90A5CE;
-    background-color: #F9FAFC;
-    z-index: 10001;
-    padding-top: 4px;
-    padding-bottom: 4px;
-    -moz-border-radius: 4px;
-    -webkit-border-top-left-radius: 4px;
-    -webkit-border-top-right-radius: 4px;
-    -webkit-border-bottom-left-radius: 4px;
-    -webkit-border-bottom-right-radius: 4px;
-    -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
-}
-
-.SelectItem {
-    font: 8pt Arial, Verdana, sans-serif;
-    padding-left:  2px;
-    padding-right: 12px;
-    border: 0px;
-}
-
-span.SelectionMark {
-    margin-right: 4px;
-    font-family: monospace;
-    outline-style: none;
-    text-decoration: none;
-}
-
-a.SelectItem {
-    display: block;
-    outline-style: none;
-    color: #000000; 
-    text-decoration: none;
-    padding-left:   6px;
-    padding-right: 12px;
-}
-
-a.SelectItem:focus,
-a.SelectItem:active {
-    color: #000000; 
-    outline-style: none;
-    text-decoration: none;
-}
-
-a.SelectItem:hover {
-    color: #FFFFFF;
-    background-color: #3D578C;
-    outline-style: none;
-    text-decoration: none;
-    cursor: pointer;
-    display: block;
-}
-
-/*---------------- Search results window */
-
-iframe#MSearchResults {
-    width: 60ex;
-    height: 15em;
-}
-
-#MSearchResultsWindow {
-    display: none;
-    position: absolute;
-    left: 0; top: 0;
-    border: 1px solid #000;
-    background-color: #EEF1F7;
-    z-index:10000;
-}
-
-/* ----------------------------------- */
-
-
-#SRIndex {
-    clear:both; 
-    padding-bottom: 15px;
-}
-
-.SREntry {
-    font-size: 10pt;
-    padding-left: 1ex;
-}
-
-.SRPage .SREntry {
-    font-size: 8pt;
-    padding: 1px 5px;
-}
-
-body.SRPage {
-    margin: 5px 2px;
-}
-
-.SRChildren {
-    padding-left: 3ex; padding-bottom: .5em 
-}
-
-.SRPage .SRChildren {
-    display: none;
-}
-
-.SRSymbol {
-    font-weight: bold; 
-    color: #425E97;
-    font-family: Arial, Verdana, sans-serif;
-    text-decoration: none;
-    outline: none;
-}
-
-a.SRScope {
-    display: block;
-    color: #425E97; 
-    font-family: Arial, Verdana, sans-serif;
-    text-decoration: none;
-    outline: none;
-}
-
-a.SRSymbol:focus, a.SRSymbol:active,
-a.SRScope:focus, a.SRScope:active {
-    text-decoration: underline;
-}
-
-span.SRScope {
-    padding-left: 4px;
-}
-
-.SRPage .SRStatus {
-    padding: 2px 5px;
-    font-size: 8pt;
-    font-style: italic;
-}
-
-.SRResult {
-    display: none;
-}
-
-DIV.searchresults {
-    margin-left: 10px;
-    margin-right: 10px;
-}
-
-/*---------------- External search page results */
-
-.searchresult {
-    background-color: #F0F3F8;
-}
-
-.pages b {
-   color: white;
-   padding: 5px 5px 3px 5px;
-   background-image: url("../tab_a.png");
-   background-repeat: repeat-x;
-   text-shadow: 0 1px 1px #000000;
-}
-
-.pages {
-    line-height: 17px;
-    margin-left: 4px;
-    text-decoration: none;
-}
-
-.hl {
-    font-weight: bold;
-}
-
-#searchresults {
-    margin-bottom: 20px;
-}
-
-.searchpages {
-    margin-top: 10px;
-}
-
diff --git a/docs/reference/search/search.js b/docs/reference/search/search.js
deleted file mode 100644
index a554ab9..0000000
--- a/docs/reference/search/search.js
+++ /dev/null
@@ -1,814 +0,0 @@
-/*
- @licstart  The following is the entire license notice for the
- JavaScript code in this file.
-
- Copyright (C) 1997-2017 by Dimitri van Heesch
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
- @licend  The above is the entire license notice
- for the JavaScript code in this file
- */
-function convertToId(search)
-{
-  var result = '';
-  for (i=0;i<search.length;i++)
-  {
-    var c = search.charAt(i);
-    var cn = c.charCodeAt(0);
-    if (c.match(/[a-z0-9\u0080-\uFFFF]/))
-    {
-      result+=c;
-    }
-    else if (cn<16)
-    {
-      result+="_0"+cn.toString(16);
-    }
-    else
-    {
-      result+="_"+cn.toString(16);
-    }
-  }
-  return result;
-}
-
-function getXPos(item)
-{
-  var x = 0;
-  if (item.offsetWidth)
-  {
-    while (item && item!=document.body)
-    {
-      x   += item.offsetLeft;
-      item = item.offsetParent;
-    }
-  }
-  return x;
-}
-
-function getYPos(item)
-{
-  var y = 0;
-  if (item.offsetWidth)
-  {
-     while (item && item!=document.body)
-     {
-       y   += item.offsetTop;
-       item = item.offsetParent;
-     }
-  }
-  return y;
-}
-
-/* A class handling everything associated with the search panel.
-
-   Parameters:
-   name - The name of the global variable that will be
-          storing this instance.  Is needed to be able to set timeouts.
-   resultPath - path to use for external files
-*/
-function SearchBox(name, resultsPath, inFrame, label)
-{
-  if (!name || !resultsPath) {  alert("Missing parameters to SearchBox."); }
-
-  // ---------- Instance variables
-  this.name                  = name;
-  this.resultsPath           = resultsPath;
-  this.keyTimeout            = 0;
-  this.keyTimeoutLength      = 500;
-  this.closeSelectionTimeout = 300;
-  this.lastSearchValue       = "";
-  this.lastResultsPage       = "";
-  this.hideTimeout           = 0;
-  this.searchIndex           = 0;
-  this.searchActive          = false;
-  this.insideFrame           = inFrame;
-  this.searchLabel           = label;
-
-  // ----------- DOM Elements
-
-  this.DOMSearchField = function()
-  {  return document.getElementById("MSearchField");  }
-
-  this.DOMSearchSelect = function()
-  {  return document.getElementById("MSearchSelect");  }
-
-  this.DOMSearchSelectWindow = function()
-  {  return document.getElementById("MSearchSelectWindow");  }
-
-  this.DOMPopupSearchResults = function()
-  {  return document.getElementById("MSearchResults");  }
-
-  this.DOMPopupSearchResultsWindow = function()
-  {  return document.getElementById("MSearchResultsWindow");  }
-
-  this.DOMSearchClose = function()
-  {  return document.getElementById("MSearchClose"); }
-
-  this.DOMSearchBox = function()
-  {  return document.getElementById("MSearchBox");  }
-
-  // ------------ Event Handlers
-
-  // Called when focus is added or removed from the search field.
-  this.OnSearchFieldFocus = function(isActive)
-  {
-    this.Activate(isActive);
-  }
-
-  this.OnSearchSelectShow = function()
-  {
-    var searchSelectWindow = this.DOMSearchSelectWindow();
-    var searchField        = this.DOMSearchSelect();
-
-    if (this.insideFrame)
-    {
-      var left = getXPos(searchField);
-      var top  = getYPos(searchField);
-      left += searchField.offsetWidth + 6;
-      top += searchField.offsetHeight;
-
-      // show search selection popup
-      searchSelectWindow.style.display='block';
-      left -= searchSelectWindow.offsetWidth;
-      searchSelectWindow.style.left =  left + 'px';
-      searchSelectWindow.style.top  =  top  + 'px';
-    }
-    else
-    {
-      var left = getXPos(searchField);
-      var top  = getYPos(searchField);
-      top += searchField.offsetHeight;
-
-      // show search selection popup
-      searchSelectWindow.style.display='block';
-      searchSelectWindow.style.left =  left + 'px';
-      searchSelectWindow.style.top  =  top  + 'px';
-    }
-
-    // stop selection hide timer
-    if (this.hideTimeout)
-    {
-      clearTimeout(this.hideTimeout);
-      this.hideTimeout=0;
-    }
-    return false; // to avoid "image drag" default event
-  }
-
-  this.OnSearchSelectHide = function()
-  {
-    this.hideTimeout = setTimeout(this.name +".CloseSelectionWindow()",
-                                  this.closeSelectionTimeout);
-  }
-
-  // Called when the content of the search field is changed.
-  this.OnSearchFieldChange = function(evt)
-  {
-    if (this.keyTimeout) // kill running timer
-    {
-      clearTimeout(this.keyTimeout);
-      this.keyTimeout = 0;
-    }
-
-    var e  = (evt) ? evt : window.event; // for IE
-    if (e.keyCode==40 || e.keyCode==13)
-    {
-      if (e.shiftKey==1)
-      {
-        this.OnSearchSelectShow();
-        var win=this.DOMSearchSelectWindow();
-        for (i=0;i<win.childNodes.length;i++)
-        {
-          var child = win.childNodes[i]; // get span within a
-          if (child.className=='SelectItem')
-          {
-            child.focus();
-            return;
-          }
-        }
-        return;
-      }
-      else if (window.frames.MSearchResults.searchResults)
-      {
-        var elem = window.frames.MSearchResults.searchResults.NavNext(0);
-        if (elem) elem.focus();
-      }
-    }
-    else if (e.keyCode==27) // Escape out of the search field
-    {
-      this.DOMSearchField().blur();
-      this.DOMPopupSearchResultsWindow().style.display = 'none';
-      this.DOMSearchClose().style.display = 'none';
-      this.lastSearchValue = '';
-      this.Activate(false);
-      return;
-    }
-
-    // strip whitespaces
-    var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
-
-    if (searchValue != this.lastSearchValue) // search value has changed
-    {
-      if (searchValue != "") // non-empty search
-      {
-        // set timer for search update
-        this.keyTimeout = setTimeout(this.name + '.Search()',
-                                     this.keyTimeoutLength);
-      }
-      else // empty search field
-      {
-        this.DOMPopupSearchResultsWindow().style.display = 'none';
-        this.DOMSearchClose().style.display = 'none';
-        this.lastSearchValue = '';
-      }
-    }
-  }
-
-  this.SelectItemCount = function(id)
-  {
-    var count=0;
-    var win=this.DOMSearchSelectWindow();
-    for (i=0;i<win.childNodes.length;i++)
-    {
-      var child = win.childNodes[i]; // get span within a
-      if (child.className=='SelectItem')
-      {
-        count++;
-      }
-    }
-    return count;
-  }
-
-  this.SelectItemSet = function(id)
-  {
-    var i,j=0;
-    var win=this.DOMSearchSelectWindow();
-    for (i=0;i<win.childNodes.length;i++)
-    {
-      var child = win.childNodes[i]; // get span within a
-      if (child.className=='SelectItem')
-      {
-        var node = child.firstChild;
-        if (j==id)
-        {
-          node.innerHTML='&#8226;';
-        }
-        else
-        {
-          node.innerHTML='&#160;';
-        }
-        j++;
-      }
-    }
-  }
-
-  // Called when an search filter selection is made.
-  // set item with index id as the active item
-  this.OnSelectItem = function(id)
-  {
-    this.searchIndex = id;
-    this.SelectItemSet(id);
-    var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
-    if (searchValue!="" && this.searchActive) // something was found -> do a search
-    {
-      this.Search();
-    }
-  }
-
-  this.OnSearchSelectKey = function(evt)
-  {
-    var e = (evt) ? evt : window.event; // for IE
-    if (e.keyCode==40 && this.searchIndex<this.SelectItemCount()) // Down
-    {
-      this.searchIndex++;
-      this.OnSelectItem(this.searchIndex);
-    }
-    else if (e.keyCode==38 && this.searchIndex>0) // Up
-    {
-      this.searchIndex--;
-      this.OnSelectItem(this.searchIndex);
-    }
-    else if (e.keyCode==13 || e.keyCode==27)
-    {
-      this.OnSelectItem(this.searchIndex);
-      this.CloseSelectionWindow();
-      this.DOMSearchField().focus();
-    }
-    return false;
-  }
-
-  // --------- Actions
-
-  // Closes the results window.
-  this.CloseResultsWindow = function()
-  {
-    this.DOMPopupSearchResultsWindow().style.display = 'none';
-    this.DOMSearchClose().style.display = 'none';
-    this.Activate(false);
-  }
-
-  this.CloseSelectionWindow = function()
-  {
-    this.DOMSearchSelectWindow().style.display = 'none';
-  }
-
-  // Performs a search.
-  this.Search = function()
-  {
-    this.keyTimeout = 0;
-
-    // strip leading whitespace
-    var searchValue = this.DOMSearchField().value.replace(/^ +/, "");
-
-    var code = searchValue.toLowerCase().charCodeAt(0);
-    var idxChar = searchValue.substr(0, 1).toLowerCase();
-    if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair
-    {
-      idxChar = searchValue.substr(0, 2);
-    }
-
-    var resultsPage;
-    var resultsPageWithSearch;
-    var hasResultsPage;
-
-    var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar);
-    if (idx!=-1)
-    {
-       var hexCode=idx.toString(16);
-       resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html';
-       resultsPageWithSearch = resultsPage+'?'+escape(searchValue);
-       hasResultsPage = true;
-    }
-    else // nothing available for this search term
-    {
-       resultsPage = this.resultsPath + '/nomatches.html';
-       resultsPageWithSearch = resultsPage;
-       hasResultsPage = false;
-    }
-
-    window.frames.MSearchResults.location = resultsPageWithSearch;
-    var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow();
-
-    if (domPopupSearchResultsWindow.style.display!='block')
-    {
-       var domSearchBox = this.DOMSearchBox();
-       this.DOMSearchClose().style.display = 'inline';
-       if (this.insideFrame)
-       {
-         var domPopupSearchResults = this.DOMPopupSearchResults();
-         domPopupSearchResultsWindow.style.position = 'relative';
-         domPopupSearchResultsWindow.style.display  = 'block';
-         var width = document.body.clientWidth - 8; // the -8 is for IE :-(
-         domPopupSearchResultsWindow.style.width    = width + 'px';
-         domPopupSearchResults.style.width          = width + 'px';
-       }
-       else
-       {
-         var domPopupSearchResults = this.DOMPopupSearchResults();
-         var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth;
-         var top  = getYPos(domSearchBox) + 20;  // domSearchBox.offsetHeight + 1;
-         domPopupSearchResultsWindow.style.display = 'block';
-         left -= domPopupSearchResults.offsetWidth;
-         domPopupSearchResultsWindow.style.top     = top  + 'px';
-         domPopupSearchResultsWindow.style.left    = left + 'px';
-       }
-    }
-
-    this.lastSearchValue = searchValue;
-    this.lastResultsPage = resultsPage;
-  }
-
-  // -------- Activation Functions
-
-  // Activates or deactivates the search panel, resetting things to
-  // their default values if necessary.
-  this.Activate = function(isActive)
-  {
-    if (isActive || // open it
-        this.DOMPopupSearchResultsWindow().style.display == 'block'
-       )
-    {
-      this.DOMSearchBox().className = 'MSearchBoxActive';
-
-      var searchField = this.DOMSearchField();
-
-      if (searchField.value == this.searchLabel) // clear "Search" term upon entry
-      {
-        searchField.value = '';
-        this.searchActive = true;
-      }
-    }
-    else if (!isActive) // directly remove the panel
-    {
-      this.DOMSearchBox().className = 'MSearchBoxInactive';
-      this.DOMSearchField().value   = this.searchLabel;
-      this.searchActive             = false;
-      this.lastSearchValue          = ''
-      this.lastResultsPage          = '';
-    }
-  }
-}
-
-// -----------------------------------------------------------------------
-
-// The class that handles everything on the search results page.
-function SearchResults(name)
-{
-    // The number of matches from the last run of <Search()>.
-    this.lastMatchCount = 0;
-    this.lastKey = 0;
-    this.repeatOn = false;
-
-    // Toggles the visibility of the passed element ID.
-    this.FindChildElement = function(id)
-    {
-      var parentElement = document.getElementById(id);
-      var element = parentElement.firstChild;
-
-      while (element && element!=parentElement)
-      {
-        if (element.nodeName == 'DIV' && element.className == 'SRChildren')
-        {
-          return element;
-        }
-
-        if (element.nodeName == 'DIV' && element.hasChildNodes())
-        {
-           element = element.firstChild;
-        }
-        else if (element.nextSibling)
-        {
-           element = element.nextSibling;
-        }
-        else
-        {
-          do
-          {
-            element = element.parentNode;
-          }
-          while (element && element!=parentElement && !element.nextSibling);
-
-          if (element && element!=parentElement)
-          {
-            element = element.nextSibling;
-          }
-        }
-      }
-    }
-
-    this.Toggle = function(id)
-    {
-      var element = this.FindChildElement(id);
-      if (element)
-      {
-        if (element.style.display == 'block')
-        {
-          element.style.display = 'none';
-        }
-        else
-        {
-          element.style.display = 'block';
-        }
-      }
-    }
-
-    // Searches for the passed string.  If there is no parameter,
-    // it takes it from the URL query.
-    //
-    // Always returns true, since other documents may try to call it
-    // and that may or may not be possible.
-    this.Search = function(search)
-    {
-      if (!search) // get search word from URL
-      {
-        search = window.location.search;
-        search = search.substring(1);  // Remove the leading '?'
-        search = unescape(search);
-      }
-
-      search = search.replace(/^ +/, ""); // strip leading spaces
-      search = search.replace(/ +$/, ""); // strip trailing spaces
-      search = search.toLowerCase();
-      search = convertToId(search);
-
-      var resultRows = document.getElementsByTagName("div");
-      var matches = 0;
-
-      var i = 0;
-      while (i < resultRows.length)
-      {
-        var row = resultRows.item(i);
-        if (row.className == "SRResult")
-        {
-          var rowMatchName = row.id.toLowerCase();
-          rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_'
-
-          if (search.length<=rowMatchName.length &&
-             rowMatchName.substr(0, search.length)==search)
-          {
-            row.style.display = 'block';
-            matches++;
-          }
-          else
-          {
-            row.style.display = 'none';
-          }
-        }
-        i++;
-      }
-      document.getElementById("Searching").style.display='none';
-      if (matches == 0) // no results
-      {
-        document.getElementById("NoMatches").style.display='block';
-      }
-      else // at least one result
-      {
-        document.getElementById("NoMatches").style.display='none';
-      }
-      this.lastMatchCount = matches;
-      return true;
-    }
-
-    // return the first item with index index or higher that is visible
-    this.NavNext = function(index)
-    {
-      var focusItem;
-      while (1)
-      {
-        var focusName = 'Item'+index;
-        focusItem = document.getElementById(focusName);
-        if (focusItem && focusItem.parentNode.parentNode.style.display=='block')
-        {
-          break;
-        }
-        else if (!focusItem) // last element
-        {
-          break;
-        }
-        focusItem=null;
-        index++;
-      }
-      return focusItem;
-    }
-
-    this.NavPrev = function(index)
-    {
-      var focusItem;
-      while (1)
-      {
-        var focusName = 'Item'+index;
-        focusItem = document.getElementById(focusName);
-        if (focusItem && focusItem.parentNode.parentNode.style.display=='block')
-        {
-          break;
-        }
-        else if (!focusItem) // last element
-        {
-          break;
-        }
-        focusItem=null;
-        index--;
-      }
-      return focusItem;
-    }
-
-    this.ProcessKeys = function(e)
-    {
-      if (e.type == "keydown")
-      {
-        this.repeatOn = false;
-        this.lastKey = e.keyCode;
-      }
-      else if (e.type == "keypress")
-      {
-        if (!this.repeatOn)
-        {
-          if (this.lastKey) this.repeatOn = true;
-          return false; // ignore first keypress after keydown
-        }
-      }
-      else if (e.type == "keyup")
-      {
-        this.lastKey = 0;
-        this.repeatOn = false;
-      }
-      return this.lastKey!=0;
-    }
-
-    this.Nav = function(evt,itemIndex)
-    {
-      var e  = (evt) ? evt : window.event; // for IE
-      if (e.keyCode==13) return true;
-      if (!this.ProcessKeys(e)) return false;
-
-      if (this.lastKey==38) // Up
-      {
-        var newIndex = itemIndex-1;
-        var focusItem = this.NavPrev(newIndex);
-        if (focusItem)
-        {
-          var child = this.FindChildElement(focusItem.parentNode.parentNode.id);
-          if (child && child.style.display == 'block') // children visible
-          {
-            var n=0;
-            var tmpElem;
-            while (1) // search for last child
-            {
-              tmpElem = document.getElementById('Item'+newIndex+'_c'+n);
-              if (tmpElem)
-              {
-                focusItem = tmpElem;
-              }
-              else // found it!
-              {
-                break;
-              }
-              n++;
-            }
-          }
-        }
-        if (focusItem)
-        {
-          focusItem.focus();
-        }
-        else // return focus to search field
-        {
-           parent.document.getElementById("MSearchField").focus();
-        }
-      }
-      else if (this.lastKey==40) // Down
-      {
-        var newIndex = itemIndex+1;
-        var focusItem;
-        var item = document.getElementById('Item'+itemIndex);
-        var elem = this.FindChildElement(item.parentNode.parentNode.id);
-        if (elem && elem.style.display == 'block') // children visible
-        {
-          focusItem = document.getElementById('Item'+itemIndex+'_c0');
-        }
-        if (!focusItem) focusItem = this.NavNext(newIndex);
-        if (focusItem)  focusItem.focus();
-      }
-      else if (this.lastKey==39) // Right
-      {
-        var item = document.getElementById('Item'+itemIndex);
-        var elem = this.FindChildElement(item.parentNode.parentNode.id);
-        if (elem) elem.style.display = 'block';
-      }
-      else if (this.lastKey==37) // Left
-      {
-        var item = document.getElementById('Item'+itemIndex);
-        var elem = this.FindChildElement(item.parentNode.parentNode.id);
-        if (elem) elem.style.display = 'none';
-      }
-      else if (this.lastKey==27) // Escape
-      {
-        parent.searchBox.CloseResultsWindow();
-        parent.document.getElementById("MSearchField").focus();
-      }
-      else if (this.lastKey==13) // Enter
-      {
-        return true;
-      }
-      return false;
-    }
-
-    this.NavChild = function(evt,itemIndex,childIndex)
-    {
-      var e  = (evt) ? evt : window.event; // for IE
-      if (e.keyCode==13) return true;
-      if (!this.ProcessKeys(e)) return false;
-
-      if (this.lastKey==38) // Up
-      {
-        if (childIndex>0)
-        {
-          var newIndex = childIndex-1;
-          document.getElementById('Item'+itemIndex+'_c'+newIndex).focus();
-        }
-        else // already at first child, jump to parent
-        {
-          document.getElementById('Item'+itemIndex).focus();
-        }
-      }
-      else if (this.lastKey==40) // Down
-      {
-        var newIndex = childIndex+1;
-        var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex);
-        if (!elem) // last child, jump to parent next parent
-        {
-          elem = this.NavNext(itemIndex+1);
-        }
-        if (elem)
-        {
-          elem.focus();
-        }
-      }
-      else if (this.lastKey==27) // Escape
-      {
-        parent.searchBox.CloseResultsWindow();
-        parent.document.getElementById("MSearchField").focus();
-      }
-      else if (this.lastKey==13) // Enter
-      {
-        return true;
-      }
-      return false;
-    }
-}
-
-function setKeyActions(elem,action)
-{
-  elem.setAttribute('onkeydown',action);
-  elem.setAttribute('onkeypress',action);
-  elem.setAttribute('onkeyup',action);
-}
-
-function setClassAttr(elem,attr)
-{
-  elem.setAttribute('class',attr);
-  elem.setAttribute('className',attr);
-}
-
-function createResults()
-{
-  var results = document.getElementById("SRResults");
-  for (var e=0; e<searchData.length; e++)
-  {
-    var id = searchData[e][0];
-    var srResult = document.createElement('div');
-    srResult.setAttribute('id','SR_'+id);
-    setClassAttr(srResult,'SRResult');
-    var srEntry = document.createElement('div');
-    setClassAttr(srEntry,'SREntry');
-    var srLink = document.createElement('a');
-    srLink.setAttribute('id','Item'+e);
-    setKeyActions(srLink,'return searchResults.Nav(event,'+e+')');
-    setClassAttr(srLink,'SRSymbol');
-    srLink.innerHTML = searchData[e][1][0];
-    srEntry.appendChild(srLink);
-    if (searchData[e][1].length==2) // single result
-    {
-      srLink.setAttribute('href',searchData[e][1][1][0]);
-      if (searchData[e][1][1][1])
-      {
-       srLink.setAttribute('target','_parent');
-      }
-      var srScope = document.createElement('span');
-      setClassAttr(srScope,'SRScope');
-      srScope.innerHTML = searchData[e][1][1][2];
-      srEntry.appendChild(srScope);
-    }
-    else // multiple results
-    {
-      srLink.setAttribute('href','javascript:searchResults.Toggle("SR_'+id+'")');
-      var srChildren = document.createElement('div');
-      setClassAttr(srChildren,'SRChildren');
-      for (var c=0; c<searchData[e][1].length-1; c++)
-      {
-        var srChild = document.createElement('a');
-        srChild.setAttribute('id','Item'+e+'_c'+c);
-        setKeyActions(srChild,'return searchResults.NavChild(event,'+e+','+c+')');
-        setClassAttr(srChild,'SRScope');
-        srChild.setAttribute('href',searchData[e][1][c+1][0]);
-        if (searchData[e][1][c+1][1])
-        {
-         srChild.setAttribute('target','_parent');
-        }
-        srChild.innerHTML = searchData[e][1][c+1][2];
-        srChildren.appendChild(srChild);
-      }
-      srEntry.appendChild(srChildren);
-    }
-    srResult.appendChild(srEntry);
-    results.appendChild(srResult);
-  }
-}
-
-function init_search()
-{
-  var results = document.getElementById("MSearchSelectWindow");
-  for (var key in indexSectionLabels)
-  {
-    var link = document.createElement('a');
-    link.setAttribute('class','SelectItem');
-    link.setAttribute('onclick','searchBox.OnSelectItem('+key+')');
-    link.href='javascript:void(0)';
-    link.innerHTML='<span class="SelectionMark">&#160;</span>'+indexSectionLabels[key];
-    results.appendChild(link);
-  }
-  searchBox.OnSelectItem(0);
-}
-/* @license-end */
diff --git a/docs/reference/search/search_l.png b/docs/reference/search/search_l.png
deleted file mode 100644
index fd5f7da..0000000
--- a/docs/reference/search/search_l.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/search/search_m.png b/docs/reference/search/search_m.png
deleted file mode 100644
index b429a16..0000000
--- a/docs/reference/search/search_m.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/search/search_r.png b/docs/reference/search/search_r.png
deleted file mode 100644
index 1af5d21..0000000
--- a/docs/reference/search/search_r.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/search/searchdata.js b/docs/reference/search/searchdata.js
deleted file mode 100644
index cee1bb6..0000000
--- a/docs/reference/search/searchdata.js
+++ /dev/null
@@ -1,36 +0,0 @@
-var indexSectionsWithContent =
-{
-  0: "abcdefgiklmnoprstuvw",
-  1: "adflorsv",
-  2: "o",
-  3: "acefgiloprstuvw",
-  4: "cfkmnpst",
-  5: "acdiprsu",
-  6: "abcefgilmnopsuv",
-  7: "ad"
-};
-
-var indexSectionNames =
-{
-  0: "all",
-  1: "classes",
-  2: "namespaces",
-  3: "functions",
-  4: "variables",
-  5: "enums",
-  6: "enumvalues",
-  7: "pages"
-};
-
-var indexSectionLabels =
-{
-  0: "All",
-  1: "Classes",
-  2: "Namespaces",
-  3: "Functions",
-  4: "Variables",
-  5: "Enumerations",
-  6: "Enumerator",
-  7: "Pages"
-};
-
diff --git a/docs/reference/search/variables_0.html b/docs/reference/search/variables_0.html
deleted file mode 100644
index 12104bc..0000000
--- a/docs/reference/search/variables_0.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="variables_0.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/variables_0.js b/docs/reference/search/variables_0.js
deleted file mode 100644
index 7da4b4c..0000000
--- a/docs/reference/search/variables_0.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['channelcount',['ChannelCount',['../classoboe_1_1_default_stream_values.html#ad5dce538d5963c81bf58350ab730962d',1,'oboe::DefaultStreamValues']]]
-];
diff --git a/docs/reference/search/variables_1.html b/docs/reference/search/variables_1.html
deleted file mode 100644
index b784017..0000000
--- a/docs/reference/search/variables_1.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="variables_1.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/variables_1.js b/docs/reference/search/variables_1.js
deleted file mode 100644
index d2d8e0d..0000000
--- a/docs/reference/search/variables_1.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['framesperburst',['FramesPerBurst',['../classoboe_1_1_default_stream_values.html#ab5ea5576699cebc56193f5c297d3e300',1,'oboe::DefaultStreamValues']]]
-];
diff --git a/docs/reference/search/variables_2.html b/docs/reference/search/variables_2.html
deleted file mode 100644
index 0cb98d3..0000000
--- a/docs/reference/search/variables_2.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="variables_2.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/variables_2.js b/docs/reference/search/variables_2.js
deleted file mode 100644
index de55599..0000000
--- a/docs/reference/search/variables_2.js
+++ /dev/null
@@ -1,9 +0,0 @@
-var searchData=
-[
-  ['kdefaulttimeoutnanos',['kDefaultTimeoutNanos',['../namespaceoboe.html#aab8f5f081a8b2147e16ec920347c1b5c',1,'oboe']]],
-  ['kmillispersecond',['kMillisPerSecond',['../namespaceoboe.html#ad1bb9f5626cec20d3a052a8721959873',1,'oboe']]],
-  ['knanospermicrosecond',['kNanosPerMicrosecond',['../namespaceoboe.html#aedef0759ae3622b6f0324799bcbdebf0',1,'oboe']]],
-  ['knanospermillisecond',['kNanosPerMillisecond',['../namespaceoboe.html#a831e887150474c087170679eaca8672b',1,'oboe']]],
-  ['knanospersecond',['kNanosPerSecond',['../namespaceoboe.html#a5948466b593c4eab65f7025846a39f51',1,'oboe']]],
-  ['kunspecified',['kUnspecified',['../namespaceoboe.html#ab0772052200184e514082eaa89be7905',1,'oboe']]]
-];
diff --git a/docs/reference/search/variables_3.html b/docs/reference/search/variables_3.html
deleted file mode 100644
index 1e83bf5..0000000
--- a/docs/reference/search/variables_3.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="variables_3.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/variables_3.js b/docs/reference/search/variables_3.js
deleted file mode 100644
index 1f4218c..0000000
--- a/docs/reference/search/variables_3.js
+++ /dev/null
@@ -1,24 +0,0 @@
-var searchData=
-[
-  ['major',['Major',['../structoboe_1_1_version.html#a270f2e92582d5187be339eeda8e2b276',1,'oboe::Version']]],
-  ['mbuffercapacityinframes',['mBufferCapacityInFrames',['../classoboe_1_1_audio_stream_base.html#ac81d4719b350f8138aad1af38f0873b6',1,'oboe::AudioStreamBase']]],
-  ['mbuffersizeinframes',['mBufferSizeInFrames',['../classoboe_1_1_audio_stream_base.html#a3b65595d26d1eae1b8ce9925a5b98f6a',1,'oboe::AudioStreamBase']]],
-  ['mchannelcount',['mChannelCount',['../classoboe_1_1_audio_stream_base.html#a5ff460bac9d14dfeac4eeddfcbb6e206',1,'oboe::AudioStreamBase']]],
-  ['mcontenttype',['mContentType',['../classoboe_1_1_audio_stream_base.html#a5f8f0e5add381b841856de80ea4cdb2b',1,'oboe::AudioStreamBase']]],
-  ['mdatacallback',['mDataCallback',['../classoboe_1_1_audio_stream_base.html#a6d8493f66a945cb426506c70f0358e5f',1,'oboe::AudioStreamBase']]],
-  ['mdeviceid',['mDeviceId',['../classoboe_1_1_audio_stream_base.html#a23dafa12fb1a6242b088ebd5a52798c8',1,'oboe::AudioStreamBase']]],
-  ['mdirection',['mDirection',['../classoboe_1_1_audio_stream_base.html#a26e9294721561d3b16bcaeec5faf4880',1,'oboe::AudioStreamBase']]],
-  ['merrorcallback',['mErrorCallback',['../classoboe_1_1_audio_stream_base.html#adc0c8cc54adb6d3350c62b8a74b9c57b',1,'oboe::AudioStreamBase']]],
-  ['mformat',['mFormat',['../classoboe_1_1_audio_stream_base.html#a7869f04836c2c2bdc10c7309ad4b8e09',1,'oboe::AudioStreamBase']]],
-  ['mframesperburst',['mFramesPerBurst',['../classoboe_1_1_audio_stream_base.html#a54061319ed348329a29d883a5de2482e',1,'oboe::AudioStreamBase']]],
-  ['mframespercallback',['mFramesPerCallback',['../classoboe_1_1_audio_stream_base.html#a3962eb94420ad0ecea70029236001899',1,'oboe::AudioStreamBase']]],
-  ['mframesread',['mFramesRead',['../classoboe_1_1_audio_stream.html#a07e82f9b9e2e4800f23ae9a7193c3b58',1,'oboe::AudioStream']]],
-  ['mframeswritten',['mFramesWritten',['../classoboe_1_1_audio_stream.html#a88a63317b7c58815bac074976b00aa23',1,'oboe::AudioStream']]],
-  ['minor',['Minor',['../structoboe_1_1_version.html#ae460bb95e3a9099696205a35fffb5469',1,'oboe::Version']]],
-  ['minputpreset',['mInputPreset',['../classoboe_1_1_audio_stream_base.html#a1e5d4f5b30c4cc36f81ffd858cc00589',1,'oboe::AudioStreamBase']]],
-  ['mperformancemode',['mPerformanceMode',['../classoboe_1_1_audio_stream_base.html#ab99671c2d0552557e75dc7b4afe91765',1,'oboe::AudioStreamBase']]],
-  ['msamplerate',['mSampleRate',['../classoboe_1_1_audio_stream_base.html#a998885bb6c4f37e145f4626ad4177dea',1,'oboe::AudioStreamBase']]],
-  ['msessionid',['mSessionId',['../classoboe_1_1_audio_stream_base.html#abe1c1e9cada1ced9b5c1504ac9b07737',1,'oboe::AudioStreamBase']]],
-  ['msharingmode',['mSharingMode',['../classoboe_1_1_audio_stream_base.html#ae9187492b679c97a0963e264954be473',1,'oboe::AudioStreamBase']]],
-  ['musage',['mUsage',['../classoboe_1_1_audio_stream_base.html#a5b518e82f39c9fcbd7050fd66adb253c',1,'oboe::AudioStreamBase']]]
-];
diff --git a/docs/reference/search/variables_4.html b/docs/reference/search/variables_4.html
deleted file mode 100644
index 39883bd..0000000
--- a/docs/reference/search/variables_4.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="variables_4.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/variables_4.js b/docs/reference/search/variables_4.js
deleted file mode 100644
index 12f3084..0000000
--- a/docs/reference/search/variables_4.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['number',['Number',['../structoboe_1_1_version.html#ac579661e79bcee45dc676d4647891de0',1,'oboe::Version']]]
-];
diff --git a/docs/reference/search/variables_5.html b/docs/reference/search/variables_5.html
deleted file mode 100644
index f25879c..0000000
--- a/docs/reference/search/variables_5.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="variables_5.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/variables_5.js b/docs/reference/search/variables_5.js
deleted file mode 100644
index 5bf0388..0000000
--- a/docs/reference/search/variables_5.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['patch',['Patch',['../structoboe_1_1_version.html#a690110f2b3e887892da8f29ab5c057b2',1,'oboe::Version']]]
-];
diff --git a/docs/reference/search/variables_6.html b/docs/reference/search/variables_6.html
deleted file mode 100644
index 0fcd6c2..0000000
--- a/docs/reference/search/variables_6.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="variables_6.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/variables_6.js b/docs/reference/search/variables_6.js
deleted file mode 100644
index 5e6f721..0000000
--- a/docs/reference/search/variables_6.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['samplerate',['SampleRate',['../classoboe_1_1_default_stream_values.html#a46a5d9a653f2153f618cadcab764e1b1',1,'oboe::DefaultStreamValues']]]
-];
diff --git a/docs/reference/search/variables_7.html b/docs/reference/search/variables_7.html
deleted file mode 100644
index ad2fa37..0000000
--- a/docs/reference/search/variables_7.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html><head><title></title>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<link rel="stylesheet" type="text/css" href="search.css"/>
-<script type="text/javascript" src="variables_7.js"></script>
-<script type="text/javascript" src="search.js"></script>
-</head>
-<body class="SRPage">
-<div id="SRIndex">
-<div class="SRStatus" id="Loading">Loading...</div>
-<div id="SRResults"></div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-createResults();
-/* @license-end */
---></script>
-<div class="SRStatus" id="Searching">Searching...</div>
-<div class="SRStatus" id="NoMatches">No Matches</div>
-<script type="text/javascript"><!--
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-document.getElementById("Loading").style.display="none";
-document.getElementById("NoMatches").style.display="none";
-var searchResults = new SearchResults("searchResults");
-searchResults.Search();
-/* @license-end */
---></script>
-</div>
-</body>
-</html>
diff --git a/docs/reference/search/variables_7.js b/docs/reference/search/variables_7.js
deleted file mode 100644
index 9df80e8..0000000
--- a/docs/reference/search/variables_7.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var searchData=
-[
-  ['text',['Text',['../structoboe_1_1_version.html#a2c86e578b827fbca5f40c460a7754503',1,'oboe::Version']]]
-];
diff --git a/docs/reference/splitbar.png b/docs/reference/splitbar.png
deleted file mode 100644
index fe895f2..0000000
--- a/docs/reference/splitbar.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/structoboe_1_1_frame_timestamp-members.html b/docs/reference/structoboe_1_1_frame_timestamp-members.html
deleted file mode 100644
index 65258b7..0000000
--- a/docs/reference/structoboe_1_1_frame_timestamp-members.html
+++ /dev/null
@@ -1,87 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Member List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="structoboe_1_1_frame_timestamp.html">FrameTimestamp</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe::FrameTimestamp Member List</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p>This is the complete list of members for <a class="el" href="structoboe_1_1_frame_timestamp.html">oboe::FrameTimestamp</a>, including all inherited members.</p>
-<table class="directory">
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>position</b> (defined in <a class="el" href="structoboe_1_1_frame_timestamp.html">oboe::FrameTimestamp</a>)</td><td class="entry"><a class="el" href="structoboe_1_1_frame_timestamp.html">oboe::FrameTimestamp</a></td><td class="entry"></td></tr>
-  <tr bgcolor="#f0f0f0"><td class="entry"><b>timestamp</b> (defined in <a class="el" href="structoboe_1_1_frame_timestamp.html">oboe::FrameTimestamp</a>)</td><td class="entry"><a class="el" href="structoboe_1_1_frame_timestamp.html">oboe::FrameTimestamp</a></td><td class="entry"></td></tr>
-</table></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/structoboe_1_1_frame_timestamp.html b/docs/reference/structoboe_1_1_frame_timestamp.html
deleted file mode 100644
index fd8e1f4..0000000
--- a/docs/reference/structoboe_1_1_frame_timestamp.html
+++ /dev/null
@@ -1,102 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe::FrameTimestamp Struct Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="structoboe_1_1_frame_timestamp.html">FrameTimestamp</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="#pub-attribs">Public Attributes</a> &#124;
-<a href="structoboe_1_1_frame_timestamp-members.html">List of all members</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe::FrameTimestamp Struct Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p><code>#include &lt;<a class="el" href="_definitions_8h_source.html">Definitions.h</a>&gt;</code></p>
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-attribs"></a>
-Public Attributes</h2></td></tr>
-<tr class="memitem:ae8b0baab150dc8359a51f1d4020821df"><td class="memItemLeft" align="right" valign="top"><a id="ae8b0baab150dc8359a51f1d4020821df"></a>
-int64_t&#160;</td><td class="memItemRight" valign="bottom"><b>position</b></td></tr>
-<tr class="separator:ae8b0baab150dc8359a51f1d4020821df"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a5ed8520f3d07594c3cb0c0ea63f7fbe5"><td class="memItemLeft" align="right" valign="top"><a id="a5ed8520f3d07594c3cb0c0ea63f7fbe5"></a>
-int64_t&#160;</td><td class="memItemRight" valign="bottom"><b>timestamp</b></td></tr>
-<tr class="separator:a5ed8520f3d07594c3cb0c0ea63f7fbe5"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
-<div class="textblock"><p>The time at which the frame at <code>position</code> was presented </p>
-</div><hr/>The documentation for this struct was generated from the following file:<ul>
-<li>include/oboe/<a class="el" href="_definitions_8h_source.html">Definitions.h</a></li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/structoboe_1_1_stream_deleter_functor-members.html b/docs/reference/structoboe_1_1_stream_deleter_functor-members.html
deleted file mode 100644
index dec5ee1..0000000
--- a/docs/reference/structoboe_1_1_stream_deleter_functor-members.html
+++ /dev/null
@@ -1,86 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Member List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="structoboe_1_1_stream_deleter_functor.html">StreamDeleterFunctor</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe::StreamDeleterFunctor Member List</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p>This is the complete list of members for <a class="el" href="structoboe_1_1_stream_deleter_functor.html">oboe::StreamDeleterFunctor</a>, including all inherited members.</p>
-<table class="directory">
-  <tr bgcolor="#f0f0f0" class="even"><td class="entry"><b>operator()</b>(AudioStream *audioStream) (defined in <a class="el" href="structoboe_1_1_stream_deleter_functor.html">oboe::StreamDeleterFunctor</a>)</td><td class="entry"><a class="el" href="structoboe_1_1_stream_deleter_functor.html">oboe::StreamDeleterFunctor</a></td><td class="entry"><span class="mlabel">inline</span></td></tr>
-</table></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/structoboe_1_1_stream_deleter_functor.html b/docs/reference/structoboe_1_1_stream_deleter_functor.html
deleted file mode 100644
index 1fa0714..0000000
--- a/docs/reference/structoboe_1_1_stream_deleter_functor.html
+++ /dev/null
@@ -1,99 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe::StreamDeleterFunctor Struct Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="structoboe_1_1_stream_deleter_functor.html">StreamDeleterFunctor</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="#pub-methods">Public Member Functions</a> &#124;
-<a href="structoboe_1_1_stream_deleter_functor-members.html">List of all members</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe::StreamDeleterFunctor Struct Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p><code>#include &lt;<a class="el" href="_audio_stream_8h_source.html">AudioStream.h</a>&gt;</code></p>
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-methods"></a>
-Public Member Functions</h2></td></tr>
-<tr class="memitem:aa63f56f03cbdc07e52159c99c7a005be"><td class="memItemLeft" align="right" valign="top"><a id="aa63f56f03cbdc07e52159c99c7a005be"></a>
-void&#160;</td><td class="memItemRight" valign="bottom"><b>operator()</b> (<a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> *audioStream)</td></tr>
-<tr class="separator:aa63f56f03cbdc07e52159c99c7a005be"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
-<div class="textblock"><p>This struct is a stateless functor which closes an <a class="el" href="classoboe_1_1_audio_stream.html">AudioStream</a> prior to its deletion. This means it can be used to safely delete a smart pointer referring to an open stream. </p>
-</div><hr/>The documentation for this struct was generated from the following file:<ul>
-<li>include/oboe/<a class="el" href="_audio_stream_8h_source.html">AudioStream.h</a></li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/structoboe_1_1_version-members.html b/docs/reference/structoboe_1_1_version-members.html
deleted file mode 100644
index fd09739..0000000
--- a/docs/reference/structoboe_1_1_version-members.html
+++ /dev/null
@@ -1,90 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: Member List</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="structoboe_1_1_version.html">Version</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="headertitle">
-<div class="title">oboe::Version Member List</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p>This is the complete list of members for <a class="el" href="structoboe_1_1_version.html">oboe::Version</a>, including all inherited members.</p>
-<table class="directory">
-  <tr class="even"><td class="entry"><a class="el" href="structoboe_1_1_version.html#a270f2e92582d5187be339eeda8e2b276">Major</a></td><td class="entry"><a class="el" href="structoboe_1_1_version.html">oboe::Version</a></td><td class="entry"><span class="mlabel">static</span></td></tr>
-  <tr><td class="entry"><a class="el" href="structoboe_1_1_version.html#ae460bb95e3a9099696205a35fffb5469">Minor</a></td><td class="entry"><a class="el" href="structoboe_1_1_version.html">oboe::Version</a></td><td class="entry"><span class="mlabel">static</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="structoboe_1_1_version.html#ac579661e79bcee45dc676d4647891de0">Number</a></td><td class="entry"><a class="el" href="structoboe_1_1_version.html">oboe::Version</a></td><td class="entry"><span class="mlabel">static</span></td></tr>
-  <tr><td class="entry"><a class="el" href="structoboe_1_1_version.html#a690110f2b3e887892da8f29ab5c057b2">Patch</a></td><td class="entry"><a class="el" href="structoboe_1_1_version.html">oboe::Version</a></td><td class="entry"><span class="mlabel">static</span></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="structoboe_1_1_version.html#a2c86e578b827fbca5f40c460a7754503">Text</a></td><td class="entry"><a class="el" href="structoboe_1_1_version.html">oboe::Version</a></td><td class="entry"><span class="mlabel">static</span></td></tr>
-</table></div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/structoboe_1_1_version.html b/docs/reference/structoboe_1_1_version.html
deleted file mode 100644
index fe7af0b..0000000
--- a/docs/reference/structoboe_1_1_version.html
+++ /dev/null
@@ -1,222 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen 1.8.15"/>
-<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Oboe: oboe::Version Struct Reference</title>
-<link href="tabs.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<link href="search/search.css" rel="stylesheet" type="text/css"/>
-<script type="text/javascript" src="search/searchdata.js"></script>
-<script type="text/javascript" src="search/search.js"></script>
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="titlearea">
-<table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
-  <td id="projectalign" style="padding-left: 0.5em;">
-   <div id="projectname">Oboe
-   &#160;<span id="projectnumber">1.5</span>
-   </div>
-   <div id="projectbrief">A library for creating real-time audio apps on Android</div>
-  </td>
- </tr>
- </tbody>
-</table>
-</div>
-<!-- end header part -->
-<!-- Generated by Doxygen 1.8.15 -->
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-var searchBox = new SearchBox("searchBox", "search",false,'Search');
-/* @license-end */
-</script>
-<script type="text/javascript" src="menudata.js"></script>
-<script type="text/javascript" src="menu.js"></script>
-<script type="text/javascript">
-/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
-$(function() {
-  initMenu('',true,false,'search.php','Search');
-  $(document).ready(function() { init_search(); });
-});
-/* @license-end */</script>
-<div id="main-nav"></div>
-<!-- window showing the filter options -->
-<div id="MSearchSelectWindow"
-     onmouseover="return searchBox.OnSearchSelectShow()"
-     onmouseout="return searchBox.OnSearchSelectHide()"
-     onkeydown="return searchBox.OnSearchSelectKey(event)">
-</div>
-
-<!-- iframe showing the search results (closed by default) -->
-<div id="MSearchResultsWindow">
-<iframe src="javascript:void(0)" frameborder="0" 
-        name="MSearchResults" id="MSearchResults">
-</iframe>
-</div>
-
-<div id="nav-path" class="navpath">
-  <ul>
-<li class="navelem"><a class="el" href="namespaceoboe.html">oboe</a></li><li class="navelem"><a class="el" href="structoboe_1_1_version.html">Version</a></li>  </ul>
-</div>
-</div><!-- top -->
-<div class="header">
-  <div class="summary">
-<a href="#pub-static-attribs">Static Public Attributes</a> &#124;
-<a href="structoboe_1_1_version-members.html">List of all members</a>  </div>
-  <div class="headertitle">
-<div class="title">oboe::Version Struct Reference</div>  </div>
-</div><!--header-->
-<div class="contents">
-
-<p><code>#include &lt;<a class="el" href="_version_8h_source.html">Version.h</a>&gt;</code></p>
-<table class="memberdecls">
-<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-static-attribs"></a>
-Static Public Attributes</h2></td></tr>
-<tr class="memitem:a270f2e92582d5187be339eeda8e2b276"><td class="memItemLeft" align="right" valign="top">static constexpr uint8_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structoboe_1_1_version.html#a270f2e92582d5187be339eeda8e2b276">Major</a> = OBOE_VERSION_MAJOR</td></tr>
-<tr class="separator:a270f2e92582d5187be339eeda8e2b276"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ae460bb95e3a9099696205a35fffb5469"><td class="memItemLeft" align="right" valign="top">static constexpr uint8_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structoboe_1_1_version.html#ae460bb95e3a9099696205a35fffb5469">Minor</a> = OBOE_VERSION_MINOR</td></tr>
-<tr class="separator:ae460bb95e3a9099696205a35fffb5469"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a690110f2b3e887892da8f29ab5c057b2"><td class="memItemLeft" align="right" valign="top">static constexpr uint16_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structoboe_1_1_version.html#a690110f2b3e887892da8f29ab5c057b2">Patch</a> = OBOE_VERSION_PATCH</td></tr>
-<tr class="separator:a690110f2b3e887892da8f29ab5c057b2"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:a2c86e578b827fbca5f40c460a7754503"><td class="memItemLeft" align="right" valign="top">static constexpr const char *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structoboe_1_1_version.html#a2c86e578b827fbca5f40c460a7754503">Text</a> = OBOE_VERSION_TEXT</td></tr>
-<tr class="separator:a2c86e578b827fbca5f40c460a7754503"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ac579661e79bcee45dc676d4647891de0"><td class="memItemLeft" align="right" valign="top">static constexpr uint32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structoboe_1_1_version.html#ac579661e79bcee45dc676d4647891de0">Number</a> = OBOE_VERSION_NUMBER</td></tr>
-<tr class="separator:ac579661e79bcee45dc676d4647891de0"><td class="memSeparator" colspan="2">&#160;</td></tr>
-</table>
-<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
-<div class="textblock"><p>Oboe versioning object </p>
-</div><h2 class="groupheader">Member Data Documentation</h2>
-<a id="a270f2e92582d5187be339eeda8e2b276"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a270f2e92582d5187be339eeda8e2b276">&#9670;&nbsp;</a></span>Major</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">constexpr uint8_t oboe::Version::Major = OBOE_VERSION_MAJOR</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">static</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>This is incremented when we make breaking API changes. Based loosely on <a href="https://semver.org/">https://semver.org/</a>. </p>
-
-</div>
-</div>
-<a id="ae460bb95e3a9099696205a35fffb5469"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ae460bb95e3a9099696205a35fffb5469">&#9670;&nbsp;</a></span>Minor</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">constexpr uint8_t oboe::Version::Minor = OBOE_VERSION_MINOR</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">static</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>This is incremented when we add backwards compatible functionality. Or set to zero when MAJOR is incremented. </p>
-
-</div>
-</div>
-<a id="ac579661e79bcee45dc676d4647891de0"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ac579661e79bcee45dc676d4647891de0">&#9670;&nbsp;</a></span>Number</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">constexpr uint32_t oboe::Version::Number = OBOE_VERSION_NUMBER</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">static</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>Integer representation of the current Oboe library version. This will always increase when the version number changes so can be compared using integer comparison. </p>
-
-</div>
-</div>
-<a id="a690110f2b3e887892da8f29ab5c057b2"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a690110f2b3e887892da8f29ab5c057b2">&#9670;&nbsp;</a></span>Patch</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">constexpr uint16_t oboe::Version::Patch = OBOE_VERSION_PATCH</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">static</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p>This is incremented when we make backwards compatible bug fixes. Or set to zero when MINOR is incremented. </p>
-
-</div>
-</div>
-<a id="a2c86e578b827fbca5f40c460a7754503"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#a2c86e578b827fbca5f40c460a7754503">&#9670;&nbsp;</a></span>Text</h2>
-
-<div class="memitem">
-<div class="memproto">
-<table class="mlabels">
-  <tr>
-  <td class="mlabels-left">
-      <table class="memname">
-        <tr>
-          <td class="memname">constexpr const char* oboe::Version::Text = OBOE_VERSION_TEXT</td>
-        </tr>
-      </table>
-  </td>
-  <td class="mlabels-right">
-<span class="mlabels"><span class="mlabel">static</span></span>  </td>
-  </tr>
-</table>
-</div><div class="memdoc">
-<p><a class="el" href="structoboe_1_1_version.html">Version</a> string in the form MAJOR.MINOR.PATCH. </p>
-
-</div>
-</div>
-<hr/>The documentation for this struct was generated from the following file:<ul>
-<li>include/oboe/<a class="el" href="_version_8h_source.html">Version.h</a></li>
-</ul>
-</div><!-- contents -->
-<!-- start footer part -->
-<hr class="footer"/><address class="footer"><small>
-Generated by &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> 1.8.15
-</small></address>
-</body>
-</html>
diff --git a/docs/reference/sync_off.png b/docs/reference/sync_off.png
deleted file mode 100644
index 3b443fc..0000000
--- a/docs/reference/sync_off.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/sync_on.png b/docs/reference/sync_on.png
deleted file mode 100644
index e08320f..0000000
--- a/docs/reference/sync_on.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/tab_a.png b/docs/reference/tab_a.png
deleted file mode 100644
index 3b725c4..0000000
--- a/docs/reference/tab_a.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/tab_b.png b/docs/reference/tab_b.png
deleted file mode 100644
index e2b4a86..0000000
--- a/docs/reference/tab_b.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/tab_h.png b/docs/reference/tab_h.png
deleted file mode 100644
index fd5cb70..0000000
--- a/docs/reference/tab_h.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/tab_s.png b/docs/reference/tab_s.png
deleted file mode 100644
index ab478c9..0000000
--- a/docs/reference/tab_s.png
+++ /dev/null
Binary files differ
diff --git a/docs/reference/tabs.css b/docs/reference/tabs.css
deleted file mode 100644
index 8ea7d54..0000000
--- a/docs/reference/tabs.css
+++ /dev/null
@@ -1 +0,0 @@
-.sm{position:relative;z-index:9999}.sm,.sm ul,.sm li{display:block;list-style:none;margin:0;padding:0;line-height:normal;direction:ltr;text-align:left;-webkit-tap-highlight-color:rgba(0,0,0,0)}.sm-rtl,.sm-rtl ul,.sm-rtl li{direction:rtl;text-align:right}.sm>li>h1,.sm>li>h2,.sm>li>h3,.sm>li>h4,.sm>li>h5,.sm>li>h6{margin:0;padding:0}.sm ul{display:none}.sm li,.sm a{position:relative}.sm a{display:block}.sm a.disabled{cursor:not-allowed}.sm:after{content:"\00a0";display:block;height:0;font:0/0 serif;clear:both;visibility:hidden;overflow:hidden}.sm,.sm *,.sm *:before,.sm *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sm-dox{background-image:url("tab_b.png")}.sm-dox a,.sm-dox a:focus,.sm-dox a:hover,.sm-dox a:active{padding:0 12px;padding-right:43px;font-family:"Lucida Grande","Geneva","Helvetica",Arial,sans-serif;font-size:13px;font-weight:bold;line-height:36px;text-decoration:none;text-shadow:0 1px 1px rgba(255,255,255,0.9);color:#283a5d;outline:0}.sm-dox a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox a.current{color:#d23600}.sm-dox a.disabled{color:#bbb}.sm-dox a span.sub-arrow{position:absolute;top:50%;margin-top:-14px;left:auto;right:3px;width:28px;height:28px;overflow:hidden;font:bold 12px/28px monospace !important;text-align:center;text-shadow:none;background:rgba(255,255,255,0.5);-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox a.highlighted span.sub-arrow:before{display:block;content:'-'}.sm-dox>li:first-child>a,.sm-dox>li:first-child>:not(ul) a{-moz-border-radius:5px 5px 0 0;-webkit-border-radius:5px;border-radius:5px 5px 0 0}.sm-dox>li:last-child>a,.sm-dox>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul{-moz-border-radius:0 0 5px 5px;-webkit-border-radius:0;border-radius:0 0 5px 5px}.sm-dox>li:last-child>a.highlighted,.sm-dox>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox ul{background:rgba(162,162,162,0.1)}.sm-dox ul a,.sm-dox ul a:focus,.sm-dox ul a:hover,.sm-dox ul a:active{font-size:12px;border-left:8px solid transparent;line-height:36px;text-shadow:none;background-color:white;background-image:none}.sm-dox ul a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox ul ul a,.sm-dox ul ul a:hover,.sm-dox ul ul a:focus,.sm-dox ul ul a:active{border-left:16px solid transparent}.sm-dox ul ul ul a,.sm-dox ul ul ul a:hover,.sm-dox ul ul ul a:focus,.sm-dox ul ul ul a:active{border-left:24px solid transparent}.sm-dox ul ul ul ul a,.sm-dox ul ul ul ul a:hover,.sm-dox ul ul ul ul a:focus,.sm-dox ul ul ul ul a:active{border-left:32px solid transparent}.sm-dox ul ul ul ul ul a,.sm-dox ul ul ul ul ul a:hover,.sm-dox ul ul ul ul ul a:focus,.sm-dox ul ul ul ul ul a:active{border-left:40px solid transparent}@media(min-width:768px){.sm-dox ul{position:absolute;width:12em}.sm-dox li{float:left}.sm-dox.sm-rtl li{float:right}.sm-dox ul li,.sm-dox.sm-rtl ul li,.sm-dox.sm-vertical li{float:none}.sm-dox a{white-space:nowrap}.sm-dox ul a,.sm-dox.sm-vertical a{white-space:normal}.sm-dox .sm-nowrap>li>a,.sm-dox .sm-nowrap>li>:not(ul) a{white-space:nowrap}.sm-dox{padding:0 10px;background-image:url("tab_b.png");line-height:36px}.sm-dox a span.sub-arrow{top:50%;margin-top:-2px;right:12px;width:0;height:0;border-width:4px;border-style:solid dashed dashed dashed;border-color:#283a5d transparent transparent transparent;background:transparent;-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted{padding:0 12px;background-image:url("tab_s.png");background-repeat:no-repeat;background-position:right;-moz-border-radius:0 !important;-webkit-border-radius:0;border-radius:0 !important}.sm-dox a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox a:hover span.sub-arrow{border-color:white transparent transparent transparent}.sm-dox a.has-submenu{padding-right:24px}.sm-dox li{border-top:0}.sm-dox>li>ul:before,.sm-dox>li>ul:after{content:'';position:absolute;top:-18px;left:30px;width:0;height:0;overflow:hidden;border-width:9px;border-style:dashed dashed solid dashed;border-color:transparent transparent #bbb transparent}.sm-dox>li>ul:after{top:-16px;left:31px;border-width:8px;border-color:transparent transparent #fff transparent}.sm-dox ul{border:1px solid #bbb;padding:5px 0;background:#fff;-moz-border-radius:5px !important;-webkit-border-radius:5px;border-radius:5px !important;-moz-box-shadow:0 5px 9px rgba(0,0,0,0.2);-webkit-box-shadow:0 5px 9px rgba(0,0,0,0.2);box-shadow:0 5px 9px rgba(0,0,0,0.2)}.sm-dox ul a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-color:transparent transparent transparent #555;border-style:dashed dashed dashed solid}.sm-dox ul a,.sm-dox ul a:hover,.sm-dox ul a:focus,.sm-dox ul a:active,.sm-dox ul a.highlighted{color:#555;background-image:none;border:0 !important;color:#555;background-image:none}.sm-dox ul a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox ul a:hover span.sub-arrow{border-color:transparent transparent transparent white}.sm-dox span.scroll-up,.sm-dox span.scroll-down{position:absolute;display:none;visibility:hidden;overflow:hidden;background:#fff;height:36px}.sm-dox span.scroll-up:hover,.sm-dox span.scroll-down:hover{background:#eee}.sm-dox span.scroll-up:hover span.scroll-up-arrow,.sm-dox span.scroll-up:hover span.scroll-down-arrow{border-color:transparent transparent #d23600 transparent}.sm-dox span.scroll-down:hover span.scroll-down-arrow{border-color:#d23600 transparent transparent transparent}.sm-dox span.scroll-up-arrow,.sm-dox span.scroll-down-arrow{position:absolute;top:0;left:50%;margin-left:-6px;width:0;height:0;overflow:hidden;border-width:6px;border-style:dashed dashed solid dashed;border-color:transparent transparent #555 transparent}.sm-dox span.scroll-down-arrow{top:8px;border-style:solid dashed dashed dashed;border-color:#555 transparent transparent transparent}.sm-dox.sm-rtl a.has-submenu{padding-right:12px;padding-left:24px}.sm-dox.sm-rtl a span.sub-arrow{right:auto;left:12px}.sm-dox.sm-rtl.sm-vertical a.has-submenu{padding:10px 20px}.sm-dox.sm-rtl.sm-vertical a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-rtl>li>ul:before{left:auto;right:30px}.sm-dox.sm-rtl>li>ul:after{left:auto;right:31px}.sm-dox.sm-rtl ul a.has-submenu{padding:10px 20px !important}.sm-dox.sm-rtl ul a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-vertical{padding:10px 0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox.sm-vertical a{padding:10px 20px}.sm-dox.sm-vertical a:hover,.sm-dox.sm-vertical a:focus,.sm-dox.sm-vertical a:active,.sm-dox.sm-vertical a.highlighted{background:#fff}.sm-dox.sm-vertical a.disabled{background-image:url("tab_b.png")}.sm-dox.sm-vertical a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-style:dashed dashed dashed solid;border-color:transparent transparent transparent #555}.sm-dox.sm-vertical>li>ul:before,.sm-dox.sm-vertical>li>ul:after{display:none}.sm-dox.sm-vertical ul a{padding:10px 20px}.sm-dox.sm-vertical ul a:hover,.sm-dox.sm-vertical ul a:focus,.sm-dox.sm-vertical ul a:active,.sm-dox.sm-vertical ul a.highlighted{background:#eee}.sm-dox.sm-vertical ul a.disabled{background:#fff}}
\ No newline at end of file
diff --git a/include/oboe/AudioStream.h b/include/oboe/AudioStream.h
index c862de6..cbec76e 100644
--- a/include/oboe/AudioStream.h
+++ b/include/oboe/AudioStream.h
@@ -130,7 +130,7 @@
      *
      * @return state or a negative error.
      */
-    virtual StreamState getState() const = 0;
+    virtual StreamState getState() = 0;
 
     /**
      * Wait until the stream's current state no longer matches the input state.
@@ -191,7 +191,7 @@
      * @return a result which is either Result::OK with the xRun count as the value, or a
      * Result::Error* code
      */
-    virtual ResultWithValue<int32_t> getXRunCount() const {
+    virtual ResultWithValue<int32_t> getXRunCount() {
         return ResultWithValue<int32_t>(Result::ErrorUnimplemented);
     }
 
@@ -205,7 +205,9 @@
      *
      * @return burst size
      */
-    virtual int32_t getFramesPerBurst() = 0;
+    int32_t getFramesPerBurst() const {
+        return mFramesPerBurst;
+    }
 
     /**
      * Get the number of bytes in each audio frame. This is calculated using the channel count
@@ -260,6 +262,10 @@
      * The latency of an OUTPUT stream is generally higher than the INPUT latency
      * because an app generally tries to keep the OUTPUT buffer full and the INPUT buffer empty.
      *
+     * Note that due to issues in Android before R, we recommend NOT calling
+     * this method from a data callback. See this tech note for more details.
+     * https://github.com/google/oboe/blob/main/docs/notes/rlsbuffer.md
+     *
      * @return a ResultWithValue which has a result of Result::OK and a value containing the latency
      * in milliseconds, or a result of Result::Error*.
      */
@@ -278,6 +284,10 @@
      * The time is based on the implementation's best effort, using whatever knowledge is available
      * to the system, but cannot account for any delay unknown to the implementation.
      *
+     * Note that due to issues in Android before R, we recommend NOT calling
+     * this method from a data callback. See this tech note for more details.
+     * https://github.com/google/oboe/blob/main/docs/notes/rlsbuffer.md
+     *
      * @deprecated since 1.0, use AudioStream::getTimestamp(clockid_t clockId) instead, which
      * returns ResultWithValue
      * @param clockId the type of clock to use e.g. CLOCK_MONOTONIC
@@ -301,6 +311,11 @@
      * The time is based on the implementation's best effort, using whatever knowledge is available
      * to the system, but cannot account for any delay unknown to the implementation.
      *
+     * Note that due to issues in Android before R, we recommend NOT calling
+     * this method from a data callback. See this tech note for more details.
+     * https://github.com/google/oboe/blob/main/docs/notes/rlsbuffer.md
+     *
+     * See 
      * @param clockId the type of clock to use e.g. CLOCK_MONOTONIC
      * @return a FrameTimestamp containing the position and time at which a particular audio frame
      * entered or left the audio processing pipeline, or an error if the operation failed.
@@ -373,11 +388,6 @@
     }
 
     /**
-     * Launch a thread that will stop the stream.
-     */
-    void launchStopThread();
-
-    /**
      * Update mFramesWritten.
      * For internal use only.
      */
@@ -425,7 +435,12 @@
      * This can be used with an EXCLUSIVE MMAP input stream to avoid reading data too close to
      * the DSP write position, which may cause glitches.
      *
-     * @param numFrames minimum frames available
+     * Starting with Oboe 1.7.1, the numFrames will be clipped internally against the
+     * BufferCapacity minus BurstSize. This is to prevent trying to wait for more frames
+     * than could possibly be available. In this case, the return value may be less than numFrames.
+     * Note that there may still be glitching if numFrames is too high.
+     *
+     * @param numFrames requested minimum frames available
      * @param timeoutNanoseconds
      * @return number of frames available, ErrorTimeout
      */
@@ -439,6 +454,29 @@
         return mErrorCallbackResult;
     }
 
+
+    int32_t getDelayBeforeCloseMillis() const {
+        return mDelayBeforeCloseMillis;
+    }
+
+    /**
+     * Set the time to sleep before closing the internal stream.
+     *
+     * Sometimes a callback can occur shortly after a stream has been stopped and
+     * even after a close! If the stream has been closed then the callback
+     * might access memory that has been freed, which could cause a crash.
+     * This seems to be more likely in Android P or earlier.
+     * But it can also occur in later versions. By sleeping, we give time for
+     * the callback threads to finish.
+     *
+     * Note that this only has an effect when OboeGlobals::areWorkaroundsEnabled() is true.
+     *
+     * @param delayBeforeCloseMillis time to sleep before close.
+     */
+    void setDelayBeforeCloseMillis(int32_t delayBeforeCloseMillis) {
+        mDelayBeforeCloseMillis = delayBeforeCloseMillis;
+    }
+
 protected:
 
     /**
@@ -500,6 +538,21 @@
         mDataCallbackEnabled = enabled;
     }
 
+    /**
+     * This should only be called as a stream is being opened.
+     * Otherwise we might override setDelayBeforeCloseMillis().
+     */
+    void calculateDefaultDelayBeforeCloseMillis();
+
+    /**
+     * Try to avoid a race condition when closing.
+     */
+    void sleepBeforeClose() {
+        if (mDelayBeforeCloseMillis > 0) {
+            usleep(mDelayBeforeCloseMillis * 1000);
+        }
+    }
+
     /*
      * Set a weak_ptr to this stream from the shared_ptr so that we can
      * later use a shared_ptr in the error callback.
@@ -537,6 +590,17 @@
 
     oboe::Result         mErrorCallbackResult = oboe::Result::OK;
 
+    /**
+     * Number of frames which will be copied to/from the audio device in a single read/write
+     * operation
+     */
+    int32_t              mFramesPerBurst = kUnspecified;
+
+    // Time to sleep in order to prevent a race condition with a callback after a close().
+    // Two milliseconds may be enough but 10 msec is even safer.
+    static constexpr int kMinDelayBeforeCloseMillis = 10;
+    int32_t              mDelayBeforeCloseMillis = kMinDelayBeforeCloseMillis;
+
 private:
 
     // Log the scheduler if it changes.
@@ -545,7 +609,6 @@
 
     std::atomic<bool>    mDataCallbackEnabled{false};
     std::atomic<bool>    mErrorCallbackCalled{false};
-
 };
 
 /**
diff --git a/include/oboe/AudioStreamBase.h b/include/oboe/AudioStreamBase.h
index d431767..e17d539 100644
--- a/include/oboe/AudioStreamBase.h
+++ b/include/oboe/AudioStreamBase.h
@@ -18,6 +18,7 @@
 #define OBOE_STREAM_BASE_H_
 
 #include <memory>
+#include <string>
 #include "oboe/AudioStreamCallback.h"
 #include "oboe/Definitions.h"
 
@@ -177,12 +178,21 @@
         return mSampleRateConversionQuality;
     }
 
+    /**
+     * @return the stream's channel mask.
+     */
+    ChannelMask getChannelMask() const {
+        return mChannelMask;
+    }
+
 protected:
     /** The callback which will be fired when new data is ready to be read/written. **/
     AudioStreamDataCallback        *mDataCallback = nullptr;
+    std::shared_ptr<AudioStreamDataCallback> mSharedDataCallback;
 
     /** The callback which will be fired when an error or a disconnect occurs. **/
     AudioStreamErrorCallback       *mErrorCallback = nullptr;
+    std::shared_ptr<AudioStreamErrorCallback> mSharedErrorCallback;
 
     /** Number of audio frames which will be requested in each callback */
     int32_t                         mFramesPerCallback = kUnspecified;
@@ -196,11 +206,8 @@
     int32_t                         mBufferCapacityInFrames = kUnspecified;
     /** Stream buffer size specified as a number of audio frames */
     int32_t                         mBufferSizeInFrames = kUnspecified;
-    /**
-     * Number of frames which will be copied to/from the audio device in a single read/write
-     * operation
-     */
-    int32_t                         mFramesPerBurst = kUnspecified;
+    /** Stream channel mask. Only active on Android 32+ */
+    ChannelMask                     mChannelMask = ChannelMask::Unspecified;
 
     /** Stream sharing mode */
     SharingMode                     mSharingMode = SharingMode::Shared;
@@ -222,6 +229,11 @@
     /** Stream session ID allocation strategy. Only active on Android 28+ */
     SessionId                       mSessionId = SessionId::None;
 
+    /** Control the name of the package creating the stream. Only active on Android 31+ */
+    std::string                     mPackageName;
+    /** Control the attribution tag of the context creating the stream. Only active on Android 31+ */
+    std::string                     mAttributionTag;
+
     // Control whether Oboe can convert channel counts to achieve optimal results.
     bool                            mChannelConversionAllowed = false;
     // Control whether Oboe can convert data formats to achieve optimal results.
@@ -235,6 +247,8 @@
             case AudioFormat::Unspecified:
             case AudioFormat::I16:
             case AudioFormat::Float:
+            case AudioFormat::I24:
+            case AudioFormat::I32:
                 break;
 
             default:
diff --git a/include/oboe/AudioStreamBuilder.h b/include/oboe/AudioStreamBuilder.h
index bd12585..5c7ac4b 100644
--- a/include/oboe/AudioStreamBuilder.h
+++ b/include/oboe/AudioStreamBuilder.h
@@ -19,6 +19,7 @@
 
 #include "oboe/Definitions.h"
 #include "oboe/AudioStreamBase.h"
+#include "oboe/Utilities.h"
 #include "ResultWithValue.h"
 
 namespace oboe {
@@ -42,13 +43,37 @@
      *
      * Default is kUnspecified. If the value is unspecified then
      * the application should query for the actual value after the stream is opened.
+     *
+     * As the channel count here may be different from the corresponding channel count of
+     * provided channel mask used in setChannelMask(). The last called will be respected
+     * if this function and setChannelMask() are called.
      */
     AudioStreamBuilder *setChannelCount(int channelCount) {
         mChannelCount = channelCount;
+        mChannelMask = ChannelMask::Unspecified;
         return this;
     }
 
     /**
+     * Request a specific channel mask.
+     *
+     * Default is kUnspecified. If the value is unspecified then the application
+     * should query for the actual value after the stream is opened.
+     *
+     * As the corresponding channel count of provided channel mask here may be different
+     * from the channel count used in setChannelCount(). The last called will be respected
+     * if this function and setChannelCount() are called.
+     *
+     * As the setChannelMask API is available on Android 32+, this call will only take effects
+     * on Android 32+.
+     */
+     AudioStreamBuilder *setChannelMask(ChannelMask channelMask) {
+         mChannelMask = channelMask;
+         mChannelCount = getChannelCountFromChannelMask(channelMask);
+         return this;
+     }
+
+    /**
      * Request the direction for a stream. The default is Direction::Output.
      *
      * @param direction Direction::Output or Direction::Input
@@ -92,6 +117,14 @@
      * the callbacks. But if your application is, for example, doing FFTs or other block
      * oriented operations, then call this function to get the sizes you need.
      *
+     * Calling setFramesPerDataCallback() does not guarantee anything about timing.
+     * This just collects the data into a the number of frames that your app requires.
+     * We encourage leaving this unspecified in most cases.
+     *
+     * If this number is larger than the burst size, some bursts will not receive a callback.
+     * If this number is smaller than the burst size, there may be multiple callbacks in a single
+     * burst.
+     *
      * @param framesPerCallback
      * @return pointer to the builder so calls can be chained
      */
@@ -295,11 +328,14 @@
      * In most cases, the primary device will be the appropriate device to use, and the
      * deviceId can be left kUnspecified.
      *
-     * On Android, for example, the ID could be obtained from the Java AudioManager.
-     * AudioManager.getDevices() returns an array of AudioDeviceInfo[], which contains
-     * a getId() method (as well as other type information), that should be passed
-     * to this method.
+     * The ID could be obtained from the Java AudioManager.
+     * AudioManager.getDevices() returns an array of AudioDeviceInfo,
+     * which contains a getId() method. That ID can be passed to this function.
      *
+     * It is possible that you may not get the device that you requested.
+     * So if it is important to you, you should call
+     * stream->getDeviceId() after the stream is opened to
+     * verify the actual ID.
      *
      * Note that when using OpenSL ES, this will be ignored and the created
      * stream will have deviceId kUnspecified.
@@ -318,11 +354,31 @@
      * <strong>Important: See AudioStreamCallback for restrictions on what may be called
      * from the callback methods.</strong>
      *
-     * @param dataCallback
+     * We pass a shared_ptr so that the sharedDataCallback object cannot be deleted
+     * before the stream is deleted.
+     *
+     * @param sharedDataCallback
      * @return pointer to the builder so calls can be chained
      */
-    AudioStreamBuilder *setDataCallback(oboe::AudioStreamDataCallback *dataCallback) {
+    AudioStreamBuilder *setDataCallback(std::shared_ptr<AudioStreamDataCallback> sharedDataCallback) {
+        // Use this raw pointer in the rest of the code to retain backwards compatibility.
+        mDataCallback = sharedDataCallback.get();
+        // Hold a shared_ptr to protect the raw pointer for the lifetime of the stream.
+        mSharedDataCallback = sharedDataCallback;
+        return this;
+    }
+
+    /**
+    * Pass a raw pointer to a data callback. This is not recommended because the dataCallback
+    * object might get deleted by the app while it is being used.
+    *
+    * @deprecated Call setDataCallback(std::shared_ptr<AudioStreamDataCallback>) instead.
+    * @param dataCallback
+    * @return pointer to the builder so calls can be chained
+    */
+    AudioStreamBuilder *setDataCallback(AudioStreamDataCallback *dataCallback) {
         mDataCallback = dataCallback;
+        mSharedDataCallback = nullptr;
         return this;
     }
 
@@ -338,11 +394,32 @@
      * <strong>When an error callback occurs, the associated stream must be stopped and closed
      * in a separate thread.</strong>
      *
-     * @param errorCallback
+     * We pass a shared_ptr so that the errorCallback object cannot be deleted before the stream is deleted.
+     * If the stream was created using a shared_ptr then the stream cannot be deleted before the
+     * error callback has finished running.
+     *
+     * @param sharedErrorCallback
      * @return pointer to the builder so calls can be chained
      */
-    AudioStreamBuilder *setErrorCallback(oboe::AudioStreamErrorCallback *errorCallback) {
+    AudioStreamBuilder *setErrorCallback(std::shared_ptr<AudioStreamErrorCallback> sharedErrorCallback) {
+        // Use this raw pointer in the rest of the code to retain backwards compatibility.
+        mErrorCallback = sharedErrorCallback.get();
+        // Hold a shared_ptr to protect the raw pointer for the lifetime of the stream.
+        mSharedErrorCallback = sharedErrorCallback;
+        return this;
+    }
+
+    /**
+    * Pass a raw pointer to an error callback. This is not recommended because the errorCallback
+    * object might get deleted by the app while it is being used.
+    *
+    * @deprecated Call setErrorCallback(std::shared_ptr<AudioStreamErrorCallback>) instead.
+    * @param errorCallback
+    * @return pointer to the builder so calls can be chained
+    */
+    AudioStreamBuilder *setErrorCallback(AudioStreamErrorCallback *errorCallback) {
         mErrorCallback = errorCallback;
+        mSharedErrorCallback = nullptr;
         return this;
     }
 
@@ -354,18 +431,8 @@
      * <strong>Important: See AudioStreamCallback for restrictions on what may be called
      * from the callback methods.</strong>
      *
-     * When an error callback occurs, the associated stream will be stopped and closed in a separate thread.
-     *
-     * A note on why the streamCallback parameter is a raw pointer rather than a smart pointer:
-     *
-     * The caller should retain ownership of the object streamCallback points to. At first glance weak_ptr may seem like
-     * a good candidate for streamCallback as this implies temporary ownership. However, a weak_ptr can only be created
-     * from a shared_ptr. A shared_ptr incurs some performance overhead. The callback object is likely to be accessed
-     * every few milliseconds when the stream requires new data so this overhead is something we want to avoid.
-     *
-     * This leaves a raw pointer as the logical type choice. The only caveat being that the caller must not destroy
-     * the callback before the stream has been closed.
-     *
+     * @deprecated Call setDataCallback(std::shared_ptr<AudioStreamDataCallback>) and
+     *     setErrorCallback(std::shared_ptr<AudioStreamErrorCallback>) instead.
      * @param streamCallback
      * @return pointer to the builder so calls can be chained
      */
@@ -383,7 +450,7 @@
      * On some devices, mono streams might be broken, so a stereo stream might be opened
      * and converted to mono.
      *
-     * Default is true.
+     * Default is false.
      */
     AudioStreamBuilder *setChannelConversionAllowed(bool allowed) {
         mChannelConversionAllowed = allowed;
@@ -391,11 +458,11 @@
     }
 
     /**
-     * If true then  Oboe might convert data formats to achieve optimal results.
+     * If true then Oboe might convert data formats to achieve optimal results.
      * On some versions of Android, for example, a float stream could not get a
      * low latency data path. So an I16 stream might be opened and converted to float.
      *
-     * Default is true.
+     * Default is false.
      */
     AudioStreamBuilder *setFormatConversionAllowed(bool allowed) {
         mFormatConversionAllowed = allowed;
@@ -419,6 +486,43 @@
     }
 
     /**
+    * Declare the name of the package creating the stream.
+    *
+    * This is usually {@code Context#getPackageName()}.
+    *
+    * The default, if you do not call this function, is a random package in the calling uid.
+    * The vast majority of apps have only one package per calling UID.
+    * If an invalid package name is set, input streams may not be given permission to
+    * record when started.
+    *
+    * The package name is usually the applicationId in your app's build.gradle file.
+    *
+    * Available since API level 31.
+    *
+    * @param packageName packageName of the calling app.
+    */
+    AudioStreamBuilder *setPackageName(std::string packageName) {
+        mPackageName = packageName;
+        return this;
+    }
+
+    /**
+    * Declare the attribution tag of the context creating the stream.
+    *
+    * This is usually {@code Context#getAttributionTag()}.
+    *
+    * The default, if you do not call this function, is null.
+    *
+    * Available since API level 31.
+    *
+    * @param attributionTag attributionTag of the calling context.
+    */
+    AudioStreamBuilder *setAttributionTag(std::string attributionTag) {
+        mAttributionTag = attributionTag;
+        return this;
+    }
+
+    /**
      * @return true if AAudio will be used based on the current settings.
      */
     bool willUseAAudio() const {
diff --git a/include/oboe/AudioStreamCallback.h b/include/oboe/AudioStreamCallback.h
index 915c3d7..17d28ba 100644
--- a/include/oboe/AudioStreamCallback.h
+++ b/include/oboe/AudioStreamCallback.h
@@ -92,6 +92,10 @@
  * being alerted when a stream has an error or is disconnected
  * using `onError*` methods.
  *
+ * Note: This callback is only fired when an AudioStreamCallback is set.
+ * If you use AudioStream::write() you have to evaluate the return codes of
+ * AudioStream::write() to notice errors in the stream.
+ *
  * It is used with AudioStreamBuilder::setErrorCallback().
  */
 class AudioStreamErrorCallback {
diff --git a/include/oboe/Definitions.h b/include/oboe/Definitions.h
index 8063a83..be65c84 100644
--- a/include/oboe/Definitions.h
+++ b/include/oboe/Definitions.h
@@ -17,7 +17,6 @@
 #ifndef OBOE_DEFINITIONS_H
 #define OBOE_DEFINITIONS_H
 
-
 #include <cstdint>
 #include <type_traits>
 
@@ -108,9 +107,36 @@
         I16 = 1, // AAUDIO_FORMAT_PCM_I16,
 
         /**
-         * Single precision floating points.
+         * Single precision floating point.
+         *
+         * This is the recommended format for most applications.
+         * But note that the use of Float may prevent the opening of
+         * a low-latency input path on OpenSL ES or Legacy AAudio streams.
          */
         Float = 2, // AAUDIO_FORMAT_PCM_FLOAT,
+
+        /**
+         * Signed 24-bit integers, packed into 3 bytes.
+         *
+         * Note that the use of this format does not guarantee that
+         * the full precision will be provided.  The underlying device may
+         * be using I16 format.
+         *
+         * Added in API 31 (S).
+         */
+        I24 = 3, // AAUDIO_FORMAT_PCM_I24_PACKED
+
+        /**
+         * Signed 32-bit integers.
+         *
+         * Note that the use of this format does not guarantee that
+         * the full precision will be provided.  The underlying device may
+         * be using I16 format.
+         *
+         * Added in API 31 (S).
+         */
+        I32 = 4, // AAUDIO_FORMAT_PCM_I32
+
     };
 
     /**
@@ -158,7 +184,7 @@
         Reserved8,
         Reserved9,
         Reserved10,
-        ErrorClosed,
+        ErrorClosed = -869,
     };
 
     /**
@@ -218,11 +244,14 @@
 
         /**
          * Use OpenSL ES.
+         * Note that OpenSL ES is deprecated in Android 13, API 30 and above.
          */
         OpenSLES,
 
         /**
          * Try to use AAudio. Fail if unavailable.
+         * AAudio was first supported in Android 8, API 26 and above.
+         * It is only recommended for API 27 and above.
          */
         AAudio
     };
@@ -242,8 +271,17 @@
          * This may be implemented using bilinear interpolation.
          */
         Fastest,
+        /**
+         * Low quality conversion with 8 taps.
+         */
         Low,
+        /**
+         * Medium quality conversion with 16 taps.
+         */
         Medium,
+        /**
+         * High quality conversion with 32 taps.
+         */
         High,
         /**
          * Highest quality conversion, which may be expensive in terms of CPU.
@@ -457,6 +495,160 @@
     };
 
     /**
+     * The channel mask of the audio stream. The underlying type is `uint32_t`.
+     * Use of this enum is convenient.
+     *
+     * ChannelMask::Unspecified means this is not specified.
+     * The rest of the enums are channel position masks.
+     * Use the combinations of the channel position masks defined below instead of
+     * using those values directly.
+     */
+    enum class ChannelMask : uint32_t { // aaudio_channel_mask_t
+        Unspecified = kUnspecified,
+        FrontLeft = 1 << 0,
+        FrontRight = 1 << 1,
+        FrontCenter = 1 << 2,
+        LowFrequency = 1 << 3,
+        BackLeft = 1 << 4,
+        BackRight = 1 << 5,
+        FrontLeftOfCenter = 1 << 6,
+        FrontRightOfCenter = 1 << 7,
+        BackCenter = 1 << 8,
+        SideLeft = 1 << 9,
+        SideRight = 1 << 10,
+        TopCenter = 1 << 11,
+        TopFrontLeft = 1 << 12,
+        TopFrontCenter = 1 << 13,
+        TopFrontRight = 1 << 14,
+        TopBackLeft = 1 << 15,
+        TopBackCenter = 1 << 16,
+        TopBackRight = 1 << 17,
+        TopSideLeft = 1 << 18,
+        TopSideRight = 1 << 19,
+        BottomFrontLeft = 1 << 20,
+        BottomFrontCenter = 1 << 21,
+        BottomFrontRight = 1 << 22,
+        LowFrequency2 = 1 << 23,
+        FrontWideLeft = 1 << 24,
+        FrontWideRight = 1 << 25,
+
+        Mono = FrontLeft,
+
+        Stereo = FrontLeft |
+                 FrontRight,
+
+        CM2Point1 = FrontLeft |
+                    FrontRight |
+                    LowFrequency,
+
+        Tri = FrontLeft |
+              FrontRight |
+              FrontCenter,
+
+        TriBack = FrontLeft |
+                  FrontRight |
+                  BackCenter,
+
+        CM3Point1 = FrontLeft |
+                    FrontRight |
+                    FrontCenter |
+                    LowFrequency,
+
+        CM2Point0Point2 = FrontLeft |
+                          FrontRight |
+                          TopSideLeft |
+                          TopSideRight,
+
+        CM2Point1Point2 = CM2Point0Point2 |
+                          LowFrequency,
+
+        CM3Point0Point2 = FrontLeft |
+                          FrontRight |
+                          FrontCenter |
+                          TopSideLeft |
+                          TopSideRight,
+
+        CM3Point1Point2 = CM3Point0Point2 |
+                          LowFrequency,
+
+        Quad = FrontLeft |
+               FrontRight |
+               BackLeft |
+               BackRight,
+
+        QuadSide = FrontLeft |
+                   FrontRight |
+                   SideLeft |
+                   SideRight,
+
+        Surround = FrontLeft |
+                   FrontRight |
+                   FrontCenter |
+                   BackCenter,
+
+        Penta = Quad |
+                FrontCenter,
+
+        // aka 5Point1Back
+        CM5Point1 = FrontLeft |
+                    FrontRight |
+                    FrontCenter |
+                    LowFrequency |
+                    BackLeft |
+                    BackRight,
+
+        CM5Point1Side = FrontLeft |
+                        FrontRight |
+                        FrontCenter |
+                        LowFrequency |
+                        SideLeft |
+                        SideRight,
+
+        CM6Point1 = FrontLeft |
+                    FrontRight |
+                    FrontCenter |
+                    LowFrequency |
+                    BackLeft |
+                    BackRight |
+                    BackCenter,
+
+        CM7Point1 = CM5Point1 |
+                    SideLeft |
+                    SideRight,
+
+        CM5Point1Point2 = CM5Point1 |
+                          TopSideLeft |
+                          TopSideRight,
+
+        CM5Point1Point4 = CM5Point1 |
+                          TopFrontLeft |
+                          TopFrontRight |
+                          TopBackLeft |
+                          TopBackRight,
+
+        CM7Point1Point2 = CM7Point1 |
+                          TopSideLeft |
+                          TopSideRight,
+
+        CM7Point1Point4 = CM7Point1 |
+                          TopFrontLeft |
+                          TopFrontRight |
+                          TopBackLeft |
+                          TopBackRight,
+
+        CM9Point1Point4 = CM7Point1Point4 |
+                          FrontWideLeft |
+                          FrontWideRight,
+
+        CM9Point1Point6 = CM9Point1Point4 |
+                          TopSideLeft |
+                          TopSideRight,
+
+        FrontBack = FrontCenter |
+                    BackCenter,
+    };
+
+    /**
      * On API 16 to 26 OpenSL ES will be used. When using OpenSL ES the optimal values for sampleRate and
      * framesPerBurst are not known by the native code.
      * On API 17+ these values should be obtained from the AudioManager using this code:
diff --git a/src/fifo/FifoBuffer.h b/include/oboe/FifoBuffer.h
similarity index 63%
rename from src/fifo/FifoBuffer.h
rename to include/oboe/FifoBuffer.h
index 6cced2d..68c1f05 100644
--- a/src/fifo/FifoBuffer.h
+++ b/include/oboe/FifoBuffer.h
@@ -22,14 +22,30 @@
 
 #include "oboe/Definitions.h"
 
-#include "FifoControllerBase.h"
+#include "oboe/FifoControllerBase.h"
 
 namespace oboe {
 
 class FifoBuffer {
 public:
+	/**
+	 * Construct a `FifoBuffer`.
+	 *
+	 * @param bytesPerFrame amount of bytes for one frame
+	 * @param capacityInFrames the capacity of frames in fifo
+	 */
     FifoBuffer(uint32_t bytesPerFrame, uint32_t capacityInFrames);
 
+	/**
+	 * Construct a `FifoBuffer`.
+	 * To be used if the storage allocation is done outside of FifoBuffer.
+	 *
+	 * @param bytesPerFrame amount of bytes for one frame
+	 * @param capacityInFrames capacity of frames in fifo
+	 * @param readCounterAddress address of read counter
+	 * @param writeCounterAddress address of write counter
+	 * @param dataStorageAddress address of storage
+	 */
     FifoBuffer(uint32_t   bytesPerFrame,
                uint32_t   capacityInFrames,
                std::atomic<uint64_t>   *readCounterAddress,
@@ -38,18 +54,36 @@
 
     ~FifoBuffer();
 
+	/**
+	 * Convert a number of frames in bytes.
+	 *
+	 * @return number of bytes
+	 */
     int32_t convertFramesToBytes(int32_t frames);
 
     /**
      * Read framesToRead or, if not enough, then read as many as are available.
+     *
      * @param destination
      * @param framesToRead number of frames requested
      * @return number of frames actually read
      */
     int32_t read(void *destination, int32_t framesToRead);
 
+	/**
+	 * Write framesToWrite or, if too enough, then write as many as the fifo are not empty.
+	 *
+	 * @param destination
+	 * @param framesToWrite number of frames requested
+	 * @return number of frames actually write
+	 */
     int32_t write(const void *source, int32_t framesToWrite);
 
+	/**
+	 * Get the buffer capacity in frames.
+	 *
+	 * @return number of frames
+	 */
     uint32_t getBufferCapacityInFrames() const;
 
     /**
@@ -62,25 +96,56 @@
      */
     int32_t readNow(void *destination, int32_t numFrames);
 
+	/**
+	 * Get the number of frames in the fifo.
+	 *
+	 * @return number of frames actually in the buffer
+	 */
     uint32_t getFullFramesAvailable() {
         return mFifo->getFullFramesAvailable();
     }
 
+	/**
+	 * Get the amount of bytes per frame.
+	 *
+	 * @return number of bytes per frame
+	 */
     uint32_t getBytesPerFrame() const {
         return mBytesPerFrame;
     }
 
+	/**
+	 * Get the position of read counter.
+	 *
+	 * @return position of read counter
+	 */
     uint64_t getReadCounter() const {
         return mFifo->getReadCounter();
     }
 
+	/**
+	 * Set the position of read counter.
+	 *
+	 * @param n position of read counter
+	 */
     void setReadCounter(uint64_t n) {
         mFifo->setReadCounter(n);
     }
 
+	/**
+	 * Get the position of write counter.
+	 *
+	 * @return position of write counter
+	 */
     uint64_t getWriteCounter() {
         return mFifo->getWriteCounter();
     }
+
+    /**
+	 * Set the position of write counter.
+	 *
+	 * @param n position of write counter
+	 */
     void setWriteCounter(uint64_t n) {
         mFifo->setWriteCounter(n);
     }
diff --git a/src/fifo/FifoControllerBase.h b/include/oboe/FifoControllerBase.h
similarity index 74%
rename from src/fifo/FifoControllerBase.h
rename to include/oboe/FifoControllerBase.h
index a4c2b41..6c12b75 100644
--- a/src/fifo/FifoControllerBase.h
+++ b/include/oboe/FifoControllerBase.h
@@ -34,9 +34,11 @@
 class FifoControllerBase {
 
 public:
-    /**
-     * @param totalFrames capacity of the circular buffer in frames.
-     */
+   /**
+	 * Construct a `FifoControllerBase`.
+	 *
+	 * @param totalFrames capacity of the circular buffer in frames
+	 */
     FifoControllerBase(uint32_t totalFrames);
 
     virtual ~FifoControllerBase() = default;
@@ -45,35 +47,53 @@
      * The frames available to read will be calculated from the read and write counters.
      * The result will be clipped to the capacity of the buffer.
      * If the buffer has underflowed then this will return zero.
+     *
      * @return number of valid frames available to read.
      */
     uint32_t getFullFramesAvailable() const;
 
-    /**
+	/**
      * The index in a circular buffer of the next frame to read.
+     *
+     * @return read index position
      */
     uint32_t getReadIndex() const;
 
-    /**
-     * @param numFrames number of frames to advance the read index
-     */
+   /**
+	* Advance read index from a number of frames.
+	* Equivalent of incrementReadCounter(numFrames).
+	*
+	* @param numFrames number of frames to advance the read index
+	*/
     void advanceReadIndex(uint32_t numFrames);
 
-    /**
-     * @return maximum number of frames that can be written without exceeding the threshold.
-     */
+	/**
+	 * Get the number of frame that are not written yet.
+	 *
+	 * @return maximum number of frames that can be written without exceeding the threshold
+	 */
     uint32_t getEmptyFramesAvailable() const;
 
     /**
-     * The index in a circular buffer of the next frame to write.
-     */
+	 * The index in a circular buffer of the next frame to write.
+	 *
+	 * @return index of the next frame to write
+	 */
     uint32_t getWriteIndex() const;
 
-    /**
+	/**
+     * Advance write index from a number of frames.
+     * Equivalent of incrementWriteCounter(numFrames).
+     *
      * @param numFrames number of frames to advance the write index
      */
     void advanceWriteIndex(uint32_t numFrames);
 
+	/**
+	 * Get the frame capacity of the fifo.
+	 *
+	 * @return frame capacity
+	 */
     uint32_t getFrameCapacity() const { return mTotalFrames; }
 
     virtual uint64_t getReadCounter() const = 0;
diff --git a/include/oboe/Oboe.h b/include/oboe/Oboe.h
index c3a0bca..ea595af 100644
--- a/include/oboe/Oboe.h
+++ b/include/oboe/Oboe.h
@@ -33,5 +33,7 @@
 #include "oboe/Utilities.h"
 #include "oboe/Version.h"
 #include "oboe/StabilizedCallback.h"
+#include "oboe/FifoBuffer.h"
+#include "oboe/OboeExtensions.h"
 
 #endif //OBOE_OBOE_H
diff --git a/include/oboe/OboeExtensions.h b/include/oboe/OboeExtensions.h
new file mode 100644
index 0000000..3722e77
--- /dev/null
+++ b/include/oboe/OboeExtensions.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2022 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 OBOE_EXTENSIONS_
+#define OBOE_EXTENSIONS_
+
+#include <stdint.h>
+
+#include "oboe/Definitions.h"
+#include "oboe/AudioStream.h"
+
+namespace oboe {
+
+/**
+ * The definitions below are only for testing.
+ * They are not recommended for use in an application.
+ * They may change or be removed at any time.
+ */
+class OboeExtensions {
+public:
+
+    /**
+    * @returns true if the device supports AAudio MMAP
+    */
+    static bool isMMapSupported();
+
+    /**
+    * @returns true if the AAudio MMAP data path can be selected
+    */
+    static bool isMMapEnabled();
+
+    /**
+     * Controls whether the AAudio MMAP data path can be selected when opening a stream.
+     * It has no effect after the stream has been opened.
+     * It only affects the application that calls it. Other apps are not affected.
+     *
+     * @param enabled
+     * @return 0 or a negative error code
+     */
+    static int32_t setMMapEnabled(bool enabled);
+
+    /**
+     * @param oboeStream
+     * @return true if the AAudio MMAP data path is used on the stream
+     */
+    static bool isMMapUsed(oboe::AudioStream *oboeStream);
+};
+
+} // namespace oboe
+
+#endif // OBOE_LATENCY_TUNER_
diff --git a/include/oboe/StabilizedCallback.h b/include/oboe/StabilizedCallback.h
index 3f1a689..244fdb7 100644
--- a/include/oboe/StabilizedCallback.h
+++ b/include/oboe/StabilizedCallback.h
@@ -60,7 +60,7 @@
 #if defined(__i386__) || defined(__x86_64__)
 #define cpu_relax() asm volatile("rep; nop" ::: "memory");
 
-#elif defined(__arm__) || defined(__mips__)
+#elif defined(__arm__) || defined(__mips__) || defined(__riscv)
     #define cpu_relax() asm volatile("":::"memory")
 
 #elif defined(__aarch64__)
diff --git a/include/oboe/Utilities.h b/include/oboe/Utilities.h
index 2c27088..a5e9170 100644
--- a/include/oboe/Utilities.h
+++ b/include/oboe/Utilities.h
@@ -82,6 +82,8 @@
  */
 int getSdkVersion();
 
+int getChannelCountFromChannelMask(ChannelMask channelMask);
+
 } // namespace oboe
 
 #endif //OBOE_UTILITIES_H
diff --git a/include/oboe/Version.h b/include/oboe/Version.h
index 1fd1805..6bcc045 100644
--- a/include/oboe/Version.h
+++ b/include/oboe/Version.h
@@ -34,7 +34,7 @@
 #define OBOE_VERSION_MAJOR 1
 
 // Type: 8-bit unsigned int. Min value: 0 Max value: 255. See below for description.
-#define OBOE_VERSION_MINOR 5
+#define OBOE_VERSION_MINOR 7
 
 // Type: 16-bit unsigned int. Min value: 0 Max value: 65535. See below for description.
 #define OBOE_VERSION_PATCH 1
diff --git a/prefab/oboe-VERSION.pom b/prefab/oboe-VERSION.pom
index b1a1f10..5ede97a 100644
--- a/prefab/oboe-VERSION.pom
+++ b/prefab/oboe-VERSION.pom
@@ -11,7 +11,7 @@
   <licenses>
     <license>
       <name>The Oboe License</name>
-      <url>https://github.com/google/oboe/blob/master/LICENSE</url>
+      <url>https://github.com/google/oboe/blob/main/LICENSE</url>
       <distribution>repo</distribution>
     </license>
   </licenses>
diff --git a/prefab/oboe-VERSION/AndroidManifest.xml b/prefab/oboe-VERSION/AndroidManifest.xml
index 6a7fbd1..ab1574b 100644
--- a/prefab/oboe-VERSION/AndroidManifest.xml
+++ b/prefab/oboe-VERSION/AndroidManifest.xml
@@ -1,3 +1,3 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.google.oboe" android:versionCode="1" android:versionName="1.0">
-	<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="29"/>
-</manifest>
\ No newline at end of file
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.google.oboe">
+	<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33"/>
+</manifest>
diff --git a/samples/LiveEffect/README.md b/samples/LiveEffect/README.md
index c24292b..e705fd2 100644
--- a/samples/LiveEffect/README.md
+++ b/samples/LiveEffect/README.md
@@ -21,6 +21,16 @@
 onBothStreamsReady() method in "src/main/cpp/FullDuplexPass.h"
 
 ### Caveats
-When first time starting audio devices, the stream may not be stable.
-The symptom is the strange callback pattern. This sample waits half a second
-for audio system to stablize. It is an estimate, it would vary on different platforms.
+OpenES SL does not allow setting the recording or playback device.
+
+Synchronizing input and output streams for full-duplex operation is tricky.  
+
+Input and output have different startup times. The input side may have to charge up the microphone circuit.
+Also the initial timing for the output callback may be bursty as it fills the buffer up.
+So when the output stream makes its first callback, the input buffer may be overflowing or empty or partially full.
+
+In order to get into sync we go through a few phases.
+
+* In Phase 1 we always drain the input buffer as much as possible, more than the output callback asks for. When we have done this for a while, we move to phase 2.
+* In Phase 2 we optionally skip reading the input once to allow it to fill up with one burst. This makes it less likely to underflow on future reads.
+* In Phase 3 we should be in a stable situation where the output is nearly full and the input is nearly empty.  You should be able to run for hours like this with no glitches.
diff --git a/samples/LiveEffect/build.gradle b/samples/LiveEffect/build.gradle
index 99397fe..f336d2e 100644
--- a/samples/LiveEffect/build.gradle
+++ b/samples/LiveEffect/build.gradle
@@ -1,12 +1,12 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 28
+    compileSdkVersion 33
 
     defaultConfig {
         applicationId 'com.google.oboe.samples.liveeffect'
-        minSdkVersion 16
-        targetSdkVersion 28
+        minSdkVersion 21
+        targetSdkVersion 33
         versionCode 1
         versionName '1.0'
         ndk {
@@ -32,7 +32,7 @@
 }
 
 dependencies {
-    implementation 'androidx.appcompat:appcompat:1.0.0-rc02'
+    implementation 'androidx.appcompat:appcompat:1.6.0-rc01'
     implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
     implementation project(':audio-device')
 }
diff --git a/samples/LiveEffect/src/main/AndroidManifest.xml b/samples/LiveEffect/src/main/AndroidManifest.xml
index a668edb..a43a6d7 100644
--- a/samples/LiveEffect/src/main/AndroidManifest.xml
+++ b/samples/LiveEffect/src/main/AndroidManifest.xml
@@ -16,7 +16,8 @@
       <activity
           android:name="com.google.oboe.samples.liveEffect.MainActivity"
           android:label="@string/app_name"
-          android:screenOrientation="portrait">
+          android:screenOrientation="portrait"
+          android:exported="true">
         <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
diff --git a/samples/LiveEffect/src/main/cpp/LiveEffectEngine.cpp b/samples/LiveEffect/src/main/cpp/LiveEffectEngine.cpp
index 8c873f8..e02e009 100644
--- a/samples/LiveEffect/src/main/cpp/LiveEffectEngine.cpp
+++ b/samples/LiveEffect/src/main/cpp/LiveEffectEngine.cpp
@@ -31,14 +31,12 @@
     mPlaybackDeviceId = deviceId;
 }
 
-bool LiveEffectEngine::isAAudioSupported() {
-    oboe::AudioStreamBuilder builder;
-    return builder.isAAudioSupported();
+bool LiveEffectEngine::isAAudioRecommended() {
+    return oboe::AudioStreamBuilder::isAAudioRecommended();
 }
 
 bool LiveEffectEngine::setAudioApi(oboe::AudioApi api) {
     if (mIsEffectOn) return false;
-
     mAudioApi = api;
     return true;
 }
@@ -86,6 +84,7 @@
     setupPlaybackStreamParameters(&outBuilder);
     oboe::Result result = outBuilder.openStream(mPlayStream);
     if (result != oboe::Result::OK) {
+        LOGE("Failed to open output stream. Error %s", oboe::convertToText(result));
         mSampleRate = oboe::kUnspecified;
         return result;
     } else {
@@ -97,6 +96,7 @@
     setupRecordingStreamParameters(&inBuilder, mSampleRate);
     result = inBuilder.openStream(mRecordingStream);
     if (result != oboe::Result::OK) {
+        LOGE("Failed to open input stream. Error %s", oboe::convertToText(result));
         closeStream(mPlayStream);
         return result;
     }
@@ -155,6 +155,7 @@
     // mode.
     builder->setAudioApi(mAudioApi)
         ->setFormat(mFormat)
+        ->setFormatConversionAllowed(true)
         ->setSharingMode(oboe::SharingMode::Exclusive)
         ->setPerformanceMode(oboe::PerformanceMode::LowLatency);
     return builder;
diff --git a/samples/LiveEffect/src/main/cpp/LiveEffectEngine.h b/samples/LiveEffect/src/main/cpp/LiveEffectEngine.h
index c12cbdb..962b16f 100644
--- a/samples/LiveEffect/src/main/cpp/LiveEffectEngine.h
+++ b/samples/LiveEffect/src/main/cpp/LiveEffectEngine.h
@@ -49,7 +49,7 @@
     void onErrorAfterClose(oboe::AudioStream *oboeStream, oboe::Result error) override;
 
     bool setAudioApi(oboe::AudioApi);
-    bool isAAudioSupported(void);
+    bool isAAudioRecommended(void);
 
 private:
     FullDuplexPass    mFullDuplexPass;
diff --git a/samples/LiveEffect/src/main/cpp/jni_bridge.cpp b/samples/LiveEffect/src/main/cpp/jni_bridge.cpp
index eb70e6d..ad9172e 100644
--- a/samples/LiveEffect/src/main/cpp/jni_bridge.cpp
+++ b/samples/LiveEffect/src/main/cpp/jni_bridge.cpp
@@ -112,7 +112,7 @@
 }
 
 JNIEXPORT jboolean JNICALL
-Java_com_google_oboe_samples_liveEffect_LiveEffectEngine_isAAudioSupported(
+Java_com_google_oboe_samples_liveEffect_LiveEffectEngine_isAAudioRecommended(
     JNIEnv *env, jclass type) {
     if (engine == nullptr) {
         LOGE(
@@ -120,7 +120,7 @@
             "before calling this method");
         return JNI_FALSE;
     }
-    return engine->isAAudioSupported() ? JNI_TRUE : JNI_FALSE;
+    return engine->isAAudioRecommended() ? JNI_TRUE : JNI_FALSE;
 }
 
 JNIEXPORT void JNICALL
diff --git a/samples/LiveEffect/src/main/java/com/google/oboe/samples/liveEffect/LiveEffectEngine.java b/samples/LiveEffect/src/main/java/com/google/oboe/samples/liveEffect/LiveEffectEngine.java
index fe2cbb3..7775de4 100644
--- a/samples/LiveEffect/src/main/java/com/google/oboe/samples/liveEffect/LiveEffectEngine.java
+++ b/samples/LiveEffect/src/main/java/com/google/oboe/samples/liveEffect/LiveEffectEngine.java
@@ -30,7 +30,7 @@
 
     // Native methods
     static native boolean create();
-    static native boolean isAAudioSupported();
+    static native boolean isAAudioRecommended();
     static native boolean setAPI(int apiType);
     static native boolean setEffectOn(boolean isEffectOn);
     static native void setRecordingDeviceId(int deviceId);
diff --git a/samples/LiveEffect/src/main/java/com/google/oboe/samples/liveEffect/MainActivity.java b/samples/LiveEffect/src/main/java/com/google/oboe/samples/liveEffect/MainActivity.java
index fad59b1..5d877b7 100644
--- a/samples/LiveEffect/src/main/java/com/google/oboe/samples/liveEffect/MainActivity.java
+++ b/samples/LiveEffect/src/main/java/com/google/oboe/samples/liveEffect/MainActivity.java
@@ -54,7 +54,7 @@
     private boolean isPlaying = false;
 
     private int apiSelection = OBOE_API_AAUDIO;
-    private boolean aaudioSupported = true;
+    private boolean mAAudioRecommended = true;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -109,6 +109,7 @@
             public void onClick(View v) {
                 if (((RadioButton)v).isChecked()) {
                     apiSelection = OBOE_API_AAUDIO;
+                    setSpinnersEnabled(true);
                 }
             }
         });
@@ -117,6 +118,7 @@
             public void onClick(View v) {
                 if (((RadioButton)v).isChecked()) {
                     apiSelection = OBOE_API_OPENSL_ES;
+                    setSpinnersEnabled(false);
                 }
             }
         });
@@ -125,12 +127,12 @@
     }
 
     private void EnableAudioApiUI(boolean enable) {
-        if(apiSelection == OBOE_API_AAUDIO && !aaudioSupported)
+        if(apiSelection == OBOE_API_AAUDIO && !mAAudioRecommended)
         {
             apiSelection = OBOE_API_OPENSL_ES;
         }
         findViewById(R.id.slesButton).setEnabled(enable);
-        if(!aaudioSupported) {
+        if(!mAAudioRecommended) {
             findViewById(R.id.aaudioButton).setEnabled(false);
         } else {
             findViewById(R.id.aaudioButton).setEnabled(enable);
@@ -138,6 +140,7 @@
 
         ((RadioGroup)findViewById(R.id.apiSelectionGroup))
           .check(apiSelection == OBOE_API_AAUDIO ? R.id.aaudioButton : R.id.slesButton);
+        setSpinnersEnabled(enable);
     }
 
     @Override
@@ -150,7 +153,7 @@
     protected void onResume() {
         super.onResume();
         LiveEffectEngine.create();
-        aaudioSupported = LiveEffectEngine.isAAudioSupported();
+        mAAudioRecommended = LiveEffectEngine.isAAudioRecommended();
         EnableAudioApiUI(true);
         LiveEffectEngine.setAPI(apiSelection);
     }
@@ -180,7 +183,6 @@
 
         boolean success = LiveEffectEngine.setEffectOn(true);
         if (success) {
-            setSpinnersEnabled(false);
             statusText.setText(R.string.status_playing);
             toggleEffectButton.setText(R.string.stop_effect);
             isPlaying = true;
@@ -197,11 +199,16 @@
         resetStatusView();
         toggleEffectButton.setText(R.string.start_effect);
         isPlaying = false;
-        setSpinnersEnabled(true);
         EnableAudioApiUI(true);
     }
 
     private void setSpinnersEnabled(boolean isEnabled){
+        if (((RadioButton)findViewById(R.id.slesButton)).isChecked())
+        {
+            isEnabled = false;
+            playbackDeviceSpinner.setSelection(0);
+            recordingDeviceSpinner.setSelection(0);
+        }
         recordingDeviceSpinner.setEnabled(isEnabled);
         playbackDeviceSpinner.setEnabled(isEnabled);
     }
diff --git a/samples/LiveEffect/src/main/res/drawable/balance_seekbar.xml b/samples/LiveEffect/src/main/res/drawable/balance_seekbar.xml
index 127181e..fd1b3fa 100644
--- a/samples/LiveEffect/src/main/res/drawable/balance_seekbar.xml
+++ b/samples/LiveEffect/src/main/res/drawable/balance_seekbar.xml
@@ -14,4 +14,4 @@
             </shape>
         </clip>
     </item>
-</layer-list>
\ No newline at end of file
+</layer-list>
diff --git a/samples/LiveEffect/src/main/res/layout-v21/activity_main.xml b/samples/LiveEffect/src/main/res/layout-v21/activity_main.xml
index 6d2bfa8..150bbe8 100644
--- a/samples/LiveEffect/src/main/res/layout-v21/activity_main.xml
+++ b/samples/LiveEffect/src/main/res/layout-v21/activity_main.xml
@@ -22,6 +22,40 @@
     tools:context="com.google.oboe.samples.liveEffect.MainActivity"
     tools:layout_editor_absoluteY="81dp">
 
+    <RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/apiSelectionGroup"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/activity_horizontal_margin"
+        android:layout_marginLeft="@dimen/activity_horizontal_margin"
+        android:layout_marginTop="@dimen/activity_vertical_margin"
+        android:orientation="horizontal"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent">
+
+        <TextView
+            android:id="@+id/apiTextView"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/apiSelection" />
+
+        <RadioButton
+            android:id="@+id/aaudioButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="16dp"
+            android:layout_marginLeft="16dp"
+            android:text="@string/aaudio" />
+
+        <RadioButton
+            android:id="@+id/slesButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="16dp"
+            android:layout_marginLeft="16dp"
+            android:text="@string/sles" />
+    </RadioGroup>
+
     <TextView
         android:id="@+id/recDeviceLabel"
         android:layout_width="wrap_content"
@@ -31,7 +65,7 @@
         android:layout_marginTop="@dimen/activity_vertical_margin"
         android:text="@string/recording_device"
         app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
+        app:layout_constraintTop_toBottomOf="@+id/apiSelectionGroup"/>
 
     <com.google.oboe.samples.audio_device.AudioDeviceSpinner
         android:id="@+id/recording_devices_spinner"
@@ -64,41 +98,6 @@
         app:layout_constraintLeft_toLeftOf="parent"
         app:layout_constraintTop_toBottomOf="@+id/playDeviceLabel" />
 
-    <RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/apiSelectionGroup"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/activity_horizontal_margin"
-        android:layout_marginLeft="@dimen/activity_horizontal_margin"
-        android:layout_marginTop="@dimen/activity_vertical_margin"
-        android:orientation="horizontal"
-        app:layout_constraintTop_toBottomOf="@+id/playback_devices_spinner"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent">
-
-        <TextView
-            android:id="@+id/apiTextView"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/apiSelection" />
-
-        <RadioButton
-            android:id="@+id/aaudioButton"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="16dp"
-            android:layout_marginLeft="16dp"
-            android:text="@string/aaudio" />
-
-        <RadioButton
-            android:id="@+id/slesButton"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="16dp"
-            android:layout_marginLeft="16dp"
-            android:text="@string/sles" />
-    </RadioGroup>
-
     <Button
         android:id="@+id/button_toggle_effect"
         android:layout_width="wrap_content"
@@ -110,7 +109,7 @@
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintHorizontal_bias="0.53"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/apiSelectionGroup" />
+        app:layout_constraintTop_toBottomOf="@+id/playback_devices_spinner" />
 
     <TextView
         android:id="@+id/status_view_text"
diff --git a/samples/LiveEffect/src/main/res/layout/activity_main.xml b/samples/LiveEffect/src/main/res/layout/activity_main.xml
index 3d4c88f..0d63782 100644
--- a/samples/LiveEffect/src/main/res/layout/activity_main.xml
+++ b/samples/LiveEffect/src/main/res/layout/activity_main.xml
@@ -22,6 +22,40 @@
     tools:context="com.google.oboe.samples.liveEffect.MainActivity"
     tools:layout_editor_absoluteY="81dp">
 
+    <RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/apiSelectionGroup"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/activity_horizontal_margin"
+        android:layout_marginLeft="@dimen/activity_horizontal_margin"
+        android:layout_marginTop="@dimen/activity_vertical_margin"
+        android:orientation="horizontal"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent">
+
+        <TextView
+            android:id="@+id/apiTextView"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/apiSelection" />
+
+        <RadioButton
+            android:id="@+id/aaudioButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="16dp"
+            android:layout_marginLeft="16dp"
+            android:text="@string/aaudio" />
+
+        <RadioButton
+            android:id="@+id/slesButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="16dp"
+            android:layout_marginLeft="16dp"
+            android:text="@string/sles" />
+    </RadioGroup>
+
     <TextView
         android:id="@+id/recDeviceLabel"
         android:layout_width="wrap_content"
@@ -31,7 +65,7 @@
         android:layout_marginTop="@dimen/activity_vertical_margin"
         android:text="@string/recording_device"
         app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
+        app:layout_constraintTop_toBottomOf="@+id/apiSelectionGroup"/>
 
     <com.google.oboe.samples.audio_device.AudioDeviceSpinner
         android:id="@+id/recording_devices_spinner"
@@ -64,41 +98,6 @@
         app:layout_constraintLeft_toLeftOf="parent"
         app:layout_constraintTop_toBottomOf="@+id/playDeviceLabel" />
 
-    <RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/apiSelectionGroup"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/activity_horizontal_margin"
-        android:layout_marginLeft="@dimen/activity_horizontal_margin"
-        android:layout_marginTop="@dimen/activity_vertical_margin"
-        android:orientation="horizontal"
-        app:layout_constraintTop_toBottomOf="@+id/playback_devices_spinner"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent">
-
-        <TextView
-            android:id="@+id/apiTextView"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/apiSelection" />
-
-        <RadioButton
-            android:id="@+id/aaudioButton"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="16dp"
-            android:layout_marginLeft="16dp"
-            android:text="@string/aaudio" />
-
-        <RadioButton
-            android:id="@+id/slesButton"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="16dp"
-            android:layout_marginLeft="16dp"
-            android:text="@string/sles" />
-    </RadioGroup>
-
     <Button
         android:id="@+id/button_toggle_effect"
         android:layout_width="wrap_content"
@@ -108,8 +107,7 @@
         android:textAllCaps="false"
         android:text="@string/start_effect"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/apiSelectionGroup" />
+        app:layout_constraintTop_toBottomOf="@+id/playback_devices_spinner" />
 
     <TextView
         android:id="@+id/status_view_text"
diff --git a/samples/LiveEffect/src/main/res/values/colors.xml b/samples/LiveEffect/src/main/res/values/colors.xml
index 87b8786..4334e33 100644
--- a/samples/LiveEffect/src/main/res/values/colors.xml
+++ b/samples/LiveEffect/src/main/res/values/colors.xml
@@ -1,3 +1,3 @@
 <resources>
     <color name="colorBlue">#4444CC</color>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/samples/MegaDrone/README.md b/samples/MegaDrone/README.md
index 5865fdb..a3b4034 100644
--- a/samples/MegaDrone/README.md
+++ b/samples/MegaDrone/README.md
@@ -30,7 +30,7 @@
 |1 - Mono|16-bit int|
 |2 - Stereo|16-bit int|
 |1 - Mono|Float|
-|1 - Stereo|Float|
+|2 - Stereo|Float|
 
 The signal chain for mono streams is: 
 
@@ -44,4 +44,4 @@
  
 Screenshots
 -----------
-![megadrone-screenshot](megadrone-screenshot.png)
\ No newline at end of file
+![megadrone-screenshot](megadrone-screenshot.png)
diff --git a/samples/MegaDrone/build.gradle b/samples/MegaDrone/build.gradle
index 3bb2539..93c372c 100644
--- a/samples/MegaDrone/build.gradle
+++ b/samples/MegaDrone/build.gradle
@@ -1,17 +1,17 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 28
+    compileSdkVersion 33
     defaultConfig {
         applicationId "com.google.oboe.samples.megadrone"
-        minSdkVersion 16
-        targetSdkVersion 28
+        minSdkVersion 21
+        targetSdkVersion 33
         versionCode 1
         versionName "1.0"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         externalNativeBuild {
             cmake {
-                cppFlags "-std=c++14"
+                cppFlags "-std=c++17"
                 abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
             }
         }
@@ -42,6 +42,6 @@
 
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
-    implementation 'androidx.appcompat:appcompat:1.0.0-rc02'
+    implementation 'androidx.appcompat:appcompat:1.6.0-rc01'
     implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
 }
diff --git a/samples/MegaDrone/src/main/AndroidManifest.xml b/samples/MegaDrone/src/main/AndroidManifest.xml
index 3a229f8..d47eefe 100644
--- a/samples/MegaDrone/src/main/AndroidManifest.xml
+++ b/samples/MegaDrone/src/main/AndroidManifest.xml
@@ -10,7 +10,8 @@
         android:supportsRtl="true"
         android:theme="@style/AppTheme">
         <activity android:name="com.google.oboe.samples.megadrone.MainActivity"
-            android:screenOrientation="portrait">
+            android:screenOrientation="portrait"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
diff --git a/samples/MegaDrone/src/main/cpp/MegaDroneEngine.cpp b/samples/MegaDrone/src/main/cpp/MegaDroneEngine.cpp
index ee4de17..df3309e 100644
--- a/samples/MegaDrone/src/main/cpp/MegaDroneEngine.cpp
+++ b/samples/MegaDrone/src/main/cpp/MegaDroneEngine.cpp
@@ -56,19 +56,19 @@
     return builder.setSharingMode(oboe::SharingMode::Exclusive)
             ->setPerformanceMode(oboe::PerformanceMode::LowLatency)
             ->setFormat(oboe::AudioFormat::Float)
-            ->setDataCallback(mDataCallback.get())
-            ->setErrorCallback(mErrorCallback.get())
+            ->setDataCallback(mDataCallback)
+            ->setErrorCallback(mErrorCallback)
             ->openStream(mStream);
 }
 
 // Create the callback and set its thread affinity to the supplied CPU core IDs
 void MegaDroneEngine::createCallback(std::vector<int> cpuIds){
 
-    mDataCallback = std::make_unique<DefaultDataCallback>();
+    mDataCallback = std::make_shared<DefaultDataCallback>();
 
     // Create the error callback, we supply ourselves as the parent so that we can restart the stream
     // when it's disconnected
-    mErrorCallback = std::make_unique<DefaultErrorCallback>(*this);
+    mErrorCallback = std::make_shared<DefaultErrorCallback>(*this);
 
     // Bind the audio callback to specific CPU cores as this can help avoid underruns caused by
     // core migrations
@@ -76,17 +76,41 @@
     mDataCallback->setThreadAffinityEnabled(true);
 }
 
-bool MegaDroneEngine::start(){
+bool MegaDroneEngine::start() {
+    // It is possible for a stream's device to become disconnected during stream open or between
+    // stream open and stream start.
+    // If the stream fails to start, close the old stream and try again.
+    bool didStart = false;
+    int tryCount = 0;
+    do {
+        if (tryCount > 0) {
+            usleep(20 * 1000); // Sleep between tries to give the system time to settle.
+        }
+        didStart = attemptStart();
+    } while (!didStart && tryCount++ < 3);
+    if (!didStart) {
+        LOGE("Failed at starting the stream");
+    }
+    return didStart;
+}
+
+bool MegaDroneEngine::attemptStart() {
     auto result = createPlaybackStream();
-    if (result == Result::OK){
+
+    if (result == Result::OK) {
         // Create our synthesizer audio source using the properties of the stream
         mAudioSource = std::make_shared<Synth>(mStream->getSampleRate(), mStream->getChannelCount());
         mDataCallback->reset();
         mDataCallback->setSource(std::dynamic_pointer_cast<IRenderableAudio>(mAudioSource));
-        mStream->start();
-        return true;
+        result = mStream->start();
+        if (result == Result::OK) {
+            return true;
+        } else {
+            LOGW("Failed attempt at starting the playback stream. Error: %s", convertToText(result));
+            return false;
+        }
     } else {
-        LOGE("Failed to create the playback stream. Error: %s", convertToText(result));
+        LOGW("Failed attempt at creating the playback stream. Error: %s", convertToText(result));
         return false;
     }
 }
diff --git a/samples/MegaDrone/src/main/cpp/MegaDroneEngine.h b/samples/MegaDrone/src/main/cpp/MegaDroneEngine.h
index d0b84a4..1720522 100644
--- a/samples/MegaDrone/src/main/cpp/MegaDroneEngine.h
+++ b/samples/MegaDrone/src/main/cpp/MegaDroneEngine.h
@@ -47,9 +47,10 @@
 private:
     std::shared_ptr<AudioStream> mStream;
     std::shared_ptr<TappableAudioSource> mAudioSource;
-    std::unique_ptr<DefaultDataCallback> mDataCallback;
-    std::unique_ptr<DefaultErrorCallback> mErrorCallback;
+    std::shared_ptr<DefaultDataCallback> mDataCallback;
+    std::shared_ptr<DefaultErrorCallback> mErrorCallback;
 
+    bool attemptStart();
     oboe::Result createPlaybackStream();
     void createCallback(std::vector<int> cpuIds);
 };
diff --git a/samples/README.md b/samples/README.md
index 6439623..bfee3de 100644
--- a/samples/README.md
+++ b/samples/README.md
@@ -2,11 +2,15 @@
 ==============
 These samples demonstrate how to use the Oboe library:
 
-1. [hello-oboe](hello-oboe): creates an output (playback) stream and plays a
-sine wave when you tap the screen
-1. [RhythmGame](RhythmGame): A simple rhythm game where you copy the clap patterns you hear by tapping on the screen
-1. [MegaDrone](MegaDrone): A one hundred oscillator synthesizer, demonstrates low latency and CPU performance
-1. [LiveEffect](LiveEffect): loops audio from input stream to output stream to demonstrate duplex capability
+1. [MinimalOboe](minimaloboe): Just create an Oboe stream and play white noise. Restart stream when disconnected. (Kotlin/Compose)
+1. [hello-oboe](hello-oboe): Creates an output (playback) stream and plays a
+sine wave when you tap the screen. (Java)
+1. [RhythmGame](RhythmGame): A simple rhythm game where you copy the clap patterns you hear by tapping on the screen.
+There is an associated codelab to follow along with. (Java)
+1. [MegaDrone](MegaDrone): A one hundred oscillator synthesizer, demonstrates low latency and CPU performance. (Java)
+1. [DrumThumper](drumthumper): A drum pad that plays sounds from loaded WAV files. (Java)
+1. [LiveEffect](LiveEffect): Loops audio from input stream to output stream to demonstrate duplex capability. (Java)
+1. [SoundBoard](SoundBoard): A 30 note dynamic synthesizer, demonstating combining signals. (Kotlin)
 
 Pre-requisites
 -------------
diff --git a/samples/RhythmGame/CMakeLists.txt b/samples/RhythmGame/CMakeLists.txt
index b404e68..7197c92 100644
--- a/samples/RhythmGame/CMakeLists.txt
+++ b/samples/RhythmGame/CMakeLists.txt
@@ -75,4 +75,4 @@
 # Enable optimization flags: if having problems with source level debugging,
 # disable -Ofast ( and debug ), re-enable after done debugging.
 target_compile_options(native-lib
-    PRIVATE -std=c++14 -Wall -Werror "$<$<CONFIG:RELEASE>:-Ofast>")
+    PRIVATE -std=c++17 -Wall -Werror "$<$<CONFIG:RELEASE>:-Ofast>")
diff --git a/samples/RhythmGame/README.md b/samples/RhythmGame/README.md
index 794588a..add81cc 100644
--- a/samples/RhythmGame/README.md
+++ b/samples/RhythmGame/README.md
@@ -3,7 +3,7 @@
 
 This sample demonstrates how to build a simple musical game. The objective of the game is to clap in time to a song by copying what you hear. You do this by listening to the clap sounds, then tapping on the screen to copy those claps.
 
-For a step-by-step guide on how this game works and how to build it check out this codelab: [Build a Musical Game using Oboe](https://codelabs.developers.google.com/codelabs/musicalgame-using-oboe/index.html). 
+For a step-by-step guide on how this game works and how to build it check out this codelab: [Build a Musical Game using Oboe](https://developer.android.com/codelabs/musicalgame-using-oboe). 
 
 
 Screenshots
@@ -31,9 +31,9 @@
 
 ![Game architecture](images/2-architecture.png "Game architecture")
 
-Oboe provides the [`AudioStream`](https://github.com/google/oboe/blob/master/include/oboe/AudioStream.h) class and associated objects to allow the sample to output audio data to the audio device. All other objects are provided by the sample.
+Oboe provides the [`AudioStream`](https://github.com/google/oboe/blob/main/include/oboe/AudioStream.h) class and associated objects to allow the sample to output audio data to the audio device. All other objects are provided by the sample.
 
-Each time the `AudioStream` needs more audio data it calls [`AudioDataCallback::onAudioReady`](https://github.com/google/oboe/blob/master/include/oboe/AudioStreamCallback.h). This passes a container array named `audioData` to the `Game` object which must then fill the array with `numFrames` of audio frames.
+Each time the `AudioStream` needs more audio data it calls [`AudioDataCallback::onAudioReady`](https://github.com/google/oboe/blob/main/include/oboe/AudioStreamCallback.h). This passes a container array named `audioData` to the `Game` object which must then fill the array with `numFrames` of audio frames.
 
 
 ![onAudioReady signature](images/3-audioData.png "onAudioReady signature")
@@ -41,8 +41,8 @@
 ### Latency optimizations
 The sample uses the following optimizations to obtain a low latency audio stream:
 
-- Performance mode set to [Low Latency](https://github.com/google/oboe/blob/master/FullGuide.md#setting-performance-mode)
-- Sharing mode set to [Exclusive](https://github.com/google/oboe/blob/master/FullGuide.md#sharing-mode)
+- Performance mode set to [Low Latency](https://github.com/google/oboe/blob/main/FullGuide.md#setting-performance-mode)
+- Sharing mode set to [Exclusive](https://github.com/google/oboe/blob/main/FullGuide.md#sharing-mode)
 - Buffer size set to twice the number of frames in a burst (double buffering)
 
 ### Audio rendering
diff --git a/samples/RhythmGame/build.gradle b/samples/RhythmGame/build.gradle
index 7511796..88681f4 100644
--- a/samples/RhythmGame/build.gradle
+++ b/samples/RhythmGame/build.gradle
@@ -1,16 +1,16 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 28
+    compileSdkVersion 33
     defaultConfig {
         applicationId "com.google.oboe.samples.rhythmgame"
-        targetSdkVersion 28
+        targetSdkVersion 33
         versionCode 1
         versionName "1.0"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         externalNativeBuild {
             cmake {
-                cppFlags "-std=c++14"
+                cppFlags "-std=c++17"
                 abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
             }
         }
@@ -26,11 +26,6 @@
             path "CMakeLists.txt"
         }
     }
-    sourceSets {
-        main {
-            jniLibs.srcDirs = ['libs']
-        }
-    }
     flavorDimensions "extractorLibrary"
     productFlavors {
         ndkExtractor {
@@ -61,12 +56,13 @@
                     arguments "-DUSE_FFMPEG=1"
                 }
             }
-        }*/
+        }
+        */
     }
 }
 
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
-    implementation 'androidx.appcompat:appcompat:1.0.0-rc02'
+    implementation 'androidx.appcompat:appcompat:1.6.0-rc01'
     implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
 }
diff --git a/samples/RhythmGame/src/main/AndroidManifest.xml b/samples/RhythmGame/src/main/AndroidManifest.xml
index c998cef..4798cc2 100644
--- a/samples/RhythmGame/src/main/AndroidManifest.xml
+++ b/samples/RhythmGame/src/main/AndroidManifest.xml
@@ -10,7 +10,8 @@
         android:supportsRtl="true"
         android:theme="@style/AppTheme">
         <activity android:name=".MainActivity"
-            android:screenOrientation="portrait">
+            android:screenOrientation="portrait"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
diff --git a/samples/RhythmGame/src/main/cpp/Game.cpp b/samples/RhythmGame/src/main/cpp/Game.cpp
index 1f50df4..199f4cc 100644
--- a/samples/RhythmGame/src/main/cpp/Game.cpp
+++ b/samples/RhythmGame/src/main/cpp/Game.cpp
@@ -115,10 +115,7 @@
 
 DataCallbackResult Game::onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numFrames) {
 
-    // If our audio stream is expecting 16-bit samples we need to render our floats into a separate
-    // buffer then convert them into 16-bit ints
-    bool is16Bit = (oboeStream->getFormat() == AudioFormat::I16);
-    float *outputBuffer = (is16Bit) ? mConversionBuffer.get() : static_cast<float *>(audioData);
+    auto *outputBuffer = static_cast<float *>(audioData);
 
     int64_t nextClapEventMs;
 
@@ -136,20 +133,24 @@
         mCurrentFrame++;
     }
 
-    if (is16Bit){
-        oboe::convertFloatToPcm16(outputBuffer,
-                                  static_cast<int16_t*>(audioData),
-                                  numFrames * oboeStream->getChannelCount());
-    }
-
     mLastUpdateTime = nowUptimeMillis();
 
     return DataCallbackResult::Continue;
 }
 
-void Game::onErrorAfterClose(AudioStream *oboeStream, Result error){
-    LOGE("The audio stream was closed, please restart the game. Error: %s", convertToText(error));
-};
+void Game::onErrorAfterClose(AudioStream *audioStream, Result error) {
+    if (error == Result::ErrorDisconnected){
+        mGameState = GameState::Loading;
+        mAudioStream.reset();
+        mMixer.removeAllTracks();
+        mCurrentFrame = 0;
+        mSongPositionMs = 0;
+        mLastUpdateTime = 0;
+        start();
+    } else {
+        LOGE("Stream error: %s", convertToText(error));
+    }
+}
 
 /**
  * Get the result of a tap
@@ -175,30 +176,22 @@
 
     // Create an audio stream
     AudioStreamBuilder builder;
-    builder.setDataCallback(this);
-    builder.setErrorCallback(this);
+    builder.setFormat(AudioFormat::Float);
+    builder.setFormatConversionAllowed(true);
     builder.setPerformanceMode(PerformanceMode::LowLatency);
     builder.setSharingMode(SharingMode::Exclusive);
-
+    builder.setSampleRate(48000);
+    builder.setSampleRateConversionQuality(
+            SampleRateConversionQuality::Medium);
+    builder.setChannelCount(2);
+    builder.setDataCallback(this);
+    builder.setErrorCallback(this);
     Result result = builder.openStream(mAudioStream);
     if (result != Result::OK){
         LOGE("Failed to open stream. Error: %s", convertToText(result));
         return false;
     }
 
-    if (mAudioStream->getFormat() == AudioFormat::I16){
-        mConversionBuffer = std::make_unique<float[]>(
-                (size_t)mAudioStream->getBufferCapacityInFrames() *
-                mAudioStream->getChannelCount());
-    }
-
-    // Reduce stream latency by setting the buffer size to a multiple of the burst size
-    auto setBufferSizeResult = mAudioStream->setBufferSizeInFrames(
-            mAudioStream->getFramesPerBurst() * kBufferSizeInBursts);
-    if (setBufferSizeResult != Result::OK){
-        LOGW("Failed to set buffer size. Error: %s", convertToText(setBufferSizeResult.error()));
-    }
-
     mMixer.setChannelCount(mAudioStream->getChannelCount());
 
     return true;
diff --git a/samples/RhythmGame/src/main/cpp/Game.h b/samples/RhythmGame/src/main/cpp/Game.h
index cfe1c15..d9cb2ef 100644
--- a/samples/RhythmGame/src/main/cpp/Game.h
+++ b/samples/RhythmGame/src/main/cpp/Game.h
@@ -40,7 +40,7 @@
     FailedToLoad
 };
 
-class Game : public AudioStreamCallback {
+class Game : public AudioStreamDataCallback, AudioStreamErrorCallback {
 public:
     explicit Game(AAssetManager&);
     void start();
@@ -51,11 +51,11 @@
     void tick();
     void tap(int64_t eventTimeAsUptime);
 
-    // Inherited from oboe::AudioStreamDataCallback
+    // Inherited from oboe::AudioStreamDataCallback.
     DataCallbackResult
     onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numFrames) override;
 
-    // Inherited from oboe::AudioStreamErrorCallback
+    // Inherited from oboe::AudioStreamErrorCallback.
     void onErrorAfterClose(AudioStream *oboeStream, Result error) override;
 
 private:
@@ -64,7 +64,6 @@
     std::unique_ptr<Player> mClap;
     std::unique_ptr<Player> mBackingTrack;
     Mixer mMixer;
-    std::unique_ptr<float[]> mConversionBuffer { nullptr }; // For float->int16 conversion
 
     LockFreeQueue<int64_t, kMaxQueueItems> mClapEvents;
     std::atomic<int64_t> mCurrentFrame { 0 };
diff --git a/samples/RhythmGame/src/main/cpp/GameConstants.h b/samples/RhythmGame/src/main/cpp/GameConstants.h
index 51a2274..2881592 100644
--- a/samples/RhythmGame/src/main/cpp/GameConstants.h
+++ b/samples/RhythmGame/src/main/cpp/GameConstants.h
@@ -57,4 +57,4 @@
     int32_t sampleRate;
 };
 
-#endif //SAMPLES_GAMECONSTANTS_H
\ No newline at end of file
+#endif //SAMPLES_GAMECONSTANTS_H
diff --git a/samples/RhythmGame/src/main/cpp/audio/AAssetDataSource.cpp b/samples/RhythmGame/src/main/cpp/audio/AAssetDataSource.cpp
index c5f3ff4..1c69787 100644
--- a/samples/RhythmGame/src/main/cpp/audio/AAssetDataSource.cpp
+++ b/samples/RhythmGame/src/main/cpp/audio/AAssetDataSource.cpp
@@ -83,4 +83,4 @@
     return new AAssetDataSource(std::move(outputBuffer),
             numSamples,
             targetProperties);
-}
\ No newline at end of file
+}
diff --git a/samples/RhythmGame/src/main/cpp/audio/FFMpegExtractor.cpp b/samples/RhythmGame/src/main/cpp/audio/FFMpegExtractor.cpp
index e4bda6c..97d212f 100644
--- a/samples/RhythmGame/src/main/cpp/audio/FFMpegExtractor.cpp
+++ b/samples/RhythmGame/src/main/cpp/audio/FFMpegExtractor.cpp
@@ -121,6 +121,8 @@
         uint8_t *targetData,
         AudioProperties targetProperties) {
 
+    LOGI("Decoder: FFMpeg");
+
     int returnValue = -1; // -1 indicates error
 
     // Create a buffer for FFmpeg to use for decoding (freed in the custom deleter below)
@@ -254,8 +256,7 @@
             if (result == AVERROR(EAGAIN)) {
                 // The codec needs more data before it can decode
                 LOGI("avcodec_receive_frame returned EAGAIN");
-                avPacket.size = 0;
-                avPacket.data = nullptr;
+                av_packet_unref(&avPacket);
                 continue;
             } else if (result != 0) {
                 LOGE("avcodec_receive_frame error: %s", av_err2str(result));
@@ -289,8 +290,7 @@
             bytesWritten += bytesToWrite;
             av_freep(&buffer1);
 
-            avPacket.size = 0;
-            avPacket.data = nullptr;
+            av_packet_unref(&avPacket);
         }
     }
 
diff --git a/samples/RhythmGame/src/main/cpp/audio/Player.cpp b/samples/RhythmGame/src/main/cpp/audio/Player.cpp
index c193e93..e73a9c3 100644
--- a/samples/RhythmGame/src/main/cpp/audio/Player.cpp
+++ b/samples/RhythmGame/src/main/cpp/audio/Player.cpp
@@ -56,4 +56,4 @@
     for (int i = 0; i < numSamples; ++i) {
         start[i] = 0;
     }
-}
\ No newline at end of file
+}
diff --git a/samples/RhythmGame/src/main/cpp/utils/UtilityFunctions.cpp b/samples/RhythmGame/src/main/cpp/utils/UtilityFunctions.cpp
index 2168a46..431f607 100644
--- a/samples/RhythmGame/src/main/cpp/utils/UtilityFunctions.cpp
+++ b/samples/RhythmGame/src/main/cpp/utils/UtilityFunctions.cpp
@@ -37,4 +37,4 @@
             SetGLScreenColor(kTapLateColor);
             break;
     }
-}
\ No newline at end of file
+}
diff --git a/samples/RhythmGame/src/main/java/com/google/oboe/samples/rhythmgame/MainActivity.java b/samples/RhythmGame/src/main/java/com/google/oboe/samples/rhythmgame/MainActivity.java
index dd85059..8c69c16 100644
--- a/samples/RhythmGame/src/main/java/com/google/oboe/samples/rhythmgame/MainActivity.java
+++ b/samples/RhythmGame/src/main/java/com/google/oboe/samples/rhythmgame/MainActivity.java
@@ -29,6 +29,12 @@
 
     // Used to load the 'native-lib' library on application startup.
     static {
+        if (BuildConfig.FLAVOR == "ffmpegExtractor"){
+            System.loadLibrary("avutil");
+            System.loadLibrary("swresample");
+            System.loadLibrary("avcodec");
+            System.loadLibrary("avformat");
+        }
         System.loadLibrary("native-lib");
     }
 
diff --git a/samples/RhythmGame/src/main/res/layout/activity_main.xml b/samples/RhythmGame/src/main/res/layout/activity_main.xml
index 4c002e3..dafd7af 100644
--- a/samples/RhythmGame/src/main/res/layout/activity_main.xml
+++ b/samples/RhythmGame/src/main/res/layout/activity_main.xml
@@ -21,4 +21,20 @@
         app:layout_constraintTop_toTopOf="parent"
         android:layout_height="match_parent" />
 
+    <TextView
+        android:id="@+id/instructionsBlock"
+        android:layout_width="294dp"
+        android:layout_height="159dp"
+        android:layout_marginStart="16dp"
+        android:layout_marginTop="16dp"
+        android:clickable="false"
+        android:ems="10"
+        android:focusable="false"
+        android:gravity="start|top"
+        android:inputType="textMultiLine"
+        android:text="See https://github.com/google/oboe/blob/main/samples/RhythmGame/README.md for instructions. There is a link to a codelab to follow along with."
+        android:textColor="#FFFFFF"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/samples/RhythmGame/test/CMakeLists.txt b/samples/RhythmGame/test/CMakeLists.txt
index b6314e3..5460d5a 100644
--- a/samples/RhythmGame/test/CMakeLists.txt
+++ b/samples/RhythmGame/test/CMakeLists.txt
@@ -9,4 +9,4 @@
 
 # Build our test binary
 add_executable (testRhythmGame testLockFreeQueue.cpp)
-target_link_libraries(testRhythmGame  gtest)
\ No newline at end of file
+target_link_libraries(testRhythmGame  gtest)
diff --git a/samples/RhythmGame/test/run_tests.sh b/samples/RhythmGame/test/run_tests.sh
index 0b7180c..cb888d9 100755
--- a/samples/RhythmGame/test/run_tests.sh
+++ b/samples/RhythmGame/test/run_tests.sh
@@ -79,7 +79,7 @@
 	-DANDROID_ABI=${ABI} \
 	-DANDROID_PLATFORM=${PLATFORM} \
   	-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-	-DCMAKE_CXX_FLAGS=-std=c++14 \
+	-DCMAKE_CXX_FLAGS=-std=c++17 \
 	-DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake \
 	-DCMAKE_VERBOSE_MAKEFILE=1"
 
@@ -107,4 +107,4 @@
 adb push ${BUILD_DIR}/${TEST_BINARY_FILENAME} ${REMOTE_DIR}
 
 echo "Running test binary"
-adb shell ${REMOTE_DIR}/${TEST_BINARY_FILENAME}
\ No newline at end of file
+adb shell ${REMOTE_DIR}/${TEST_BINARY_FILENAME}
diff --git a/samples/SoundBoard/README.md b/samples/SoundBoard/README.md
new file mode 100644
index 0000000..9c4090b
--- /dev/null
+++ b/samples/SoundBoard/README.md
@@ -0,0 +1,47 @@
+Soundboard
+==========
+Do you want to just jam with some digital tunes? Now you can!
+
+This sample demonstrates how to obtain the lowest latency and optimal computational throughput by:
+
+1) Leaving Oboe to choose the best default stream properties for the current device
+2) Setting performance mode to LowLatency
+3) Setting sharing mode to Exclusive
+4) Setting the buffer size to 2 bursts
+5) Using the `-Ofast` compiler optimization flag, even when building the `Debug` variant
+7) Using a `StabilizedCallback` which aims to spend a fixed percentage of the callback time to avoid CPU frequency scaling ([video explanation](https://www.youtube.com/watch?v=C0BPXZIvG-Q&feature=youtu.be&t=1158))
+
+The [following article explaining how to debug CPU performance problems](https://medium.com/@donturner/debugging-audio-glitches-on-android-ed10782f9c64) may also be useful when looking at this code.
+
+Implementation details
+---
+The stream properties are left to Oboe as such the app must output audio data in a format which matches that of the stream. 
+
+Four different formats are supported: 
+
+|Channel count|Format|
+|-------------|------|
+|1 - Mono|16-bit int|
+|2 - Stereo|16-bit int|
+|1 - Mono|Float|
+|2 - Stereo|Float|
+
+The signal chain for mono streams is: 
+
+    SynthSound->Mixer
+
+For stereo chains a mono to stereo converter is added to the end of the chain: 
+
+    SynthSound->Mixer->MonoToStereo
+ 
+The compiler optimization flag `-Ofast` can be found in [CMakeLists.txt](CMakeLists.txt). 
+
+Each SynthSound is a series of 5 Oscillators, creating a pleasant sounding note when combined.
+
+There are 30 notes, corresponding to G3 to C6, moving left to right, top to bottom.
+
+In order to determine whether a note should be played, MusicTileView demonstrates how to keep track of where each finger is.
+
+Images
+-----------
+![soundboard_image](soundboard_image.png)
diff --git a/samples/SoundBoard/build.gradle b/samples/SoundBoard/build.gradle
new file mode 100644
index 0000000..81cb605
--- /dev/null
+++ b/samples/SoundBoard/build.gradle
@@ -0,0 +1,50 @@
+apply plugin: 'com.android.application'
+
+android {
+    compileSdkVersion 33
+    defaultConfig {
+        applicationId "com.google.oboe.samples.soundboard"
+        minSdkVersion 21
+        targetSdkVersion 33
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+        externalNativeBuild {
+            cmake {
+                cppFlags "-std=c++17"
+                abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
+            }
+        }
+    }
+    signingConfigs {
+        release {
+            storeFile new File("${System.properties['user.home']}/.android/debug.keystore")
+            storePassword 'android'
+            storeType "jks"
+            keyAlias 'androiddebugkey'
+            keyPassword 'android'
+        }
+    }
+    buildTypes {
+        release {
+            signingConfig signingConfigs.release
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+            debuggable false
+        }
+        debug {
+         debuggable true
+        }
+    }
+    externalNativeBuild {
+        cmake {
+            path "src/main/cpp/CMakeLists.txt"
+        }
+    }
+}
+
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    implementation 'androidx.appcompat:appcompat:1.6.0-rc01'
+    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+}
diff --git a/samples/SoundBoard/proguard-rules.pro b/samples/SoundBoard/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/samples/SoundBoard/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/samples/SoundBoard/soundboard_image.png b/samples/SoundBoard/soundboard_image.png
new file mode 100644
index 0000000..d3bc21b
--- /dev/null
+++ b/samples/SoundBoard/soundboard_image.png
Binary files differ
diff --git a/samples/SoundBoard/src/main/AndroidManifest.xml b/samples/SoundBoard/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ed62039
--- /dev/null
+++ b/samples/SoundBoard/src/main/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.oboe.samples.soundboard">
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+        <activity android:name="com.google.oboe.samples.soundboard.MainActivity"
+            android:screenOrientation="portrait"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/samples/SoundBoard/src/main/cpp/CMakeLists.txt b/samples/SoundBoard/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000..cf5ef3c
--- /dev/null
+++ b/samples/SoundBoard/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.4.1)
+
+
+### INCLUDE OBOE LIBRARY ###
+
+# Set the path to the Oboe library directory
+set (OBOE_DIR ../../../../..)
+
+# Add the Oboe library as a subproject. Since Oboe is an out-of-tree source library we must also
+# specify a binary directory
+add_subdirectory(${OBOE_DIR} ./oboe-bin)
+
+# Include the Oboe headers
+include_directories(${OBOE_DIR}/include ${OBOE_DIR}/samples/shared ${OBOE_DIR}/samples/debug-utils)
+
+
+### END OBOE INCLUDE SECTION ###
+
+add_library( soundboard SHARED
+        native-lib.cpp
+        SoundBoardEngine.cpp
+        )
+
+target_link_libraries( soundboard log oboe )
+
+# Enable optimization flags: if having problems with source level debugging,
+# disable -Ofast ( and debug ), re-enable it after done debugging.
+target_compile_options(soundboard PRIVATE -Wall -Werror -Ofast)
diff --git a/samples/SoundBoard/src/main/cpp/SoundBoardEngine.cpp b/samples/SoundBoard/src/main/cpp/SoundBoardEngine.cpp
new file mode 100644
index 0000000..defb6dc
--- /dev/null
+++ b/samples/SoundBoard/src/main/cpp/SoundBoardEngine.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2018 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 <memory>
+#include "SoundBoardEngine.h"
+
+/**
+ * Main audio engine for the SoundBoard sample. It is responsible for:
+ *
+ * - Creating the callback object which will be supplied when constructing the audio stream
+ * - Creating the playback stream, including setting the callback object
+ * - Creating `Synth` which will render the audio inside the callback
+ * - Starting the playback stream
+ * - Restarting the playback stream when `restart()` is called by the callback object
+ *
+ * @param numSignals
+ */
+SoundBoardEngine::SoundBoardEngine(int32_t numSignals) {
+    createCallback(numSignals);
+}
+
+SoundBoardEngine::~SoundBoardEngine() {
+    if (mStream) {
+        LOGE("SoundBoardEngine destructor was called without calling stop()."
+             "Please call stop() to ensure stream resources are not leaked.");
+        stop();
+    }
+}
+
+void SoundBoardEngine::noteOff(int32_t noteIndex) {
+    mSynth->noteOff(noteIndex);
+}
+
+void SoundBoardEngine::noteOn(int32_t noteIndex) {
+    mSynth->noteOn(noteIndex);
+}
+
+void SoundBoardEngine::tap(bool isDown) {
+    mSynth->tap(isDown);
+}
+
+void SoundBoardEngine::restart() {
+    stop();
+    start();
+}
+// Create the playback stream
+oboe::Result SoundBoardEngine::createPlaybackStream() {
+    oboe::AudioStreamBuilder builder;
+    return builder.setSharingMode(oboe::SharingMode::Exclusive)
+            ->setPerformanceMode(oboe::PerformanceMode::LowLatency)
+            ->setFormat(oboe::AudioFormat::Float)
+            ->setDataCallback(mDataCallback)
+            ->setErrorCallback(mErrorCallback)
+            ->openStream(mStream);
+}
+
+// Create the callback and set its thread affinity to the supplied CPU core IDs
+void SoundBoardEngine::createCallback(int32_t numSignals){
+
+    mDataCallback = std::make_shared<DefaultDataCallback>();
+
+    // Create the error callback, we supply ourselves as the parent so that we can restart the stream
+    // when it's disconnected
+    mErrorCallback = std::make_shared<DefaultErrorCallback>(*this);
+
+    mNumSignals = numSignals;
+}
+
+bool SoundBoardEngine::start() {
+    // It is possible for a stream's device to become disconnected during stream open or between
+    // stream open and stream start.
+    // If the stream fails to start, close the old stream and try again.
+    bool didStart = false;
+    int tryCount = 0;
+    do {
+        if (tryCount > 0) {
+            usleep(20 * 1000); // Sleep between tries to give the system time to settle.
+        }
+        didStart = attemptStart();
+    } while (!didStart && tryCount++ < 3);
+    if (!didStart) {
+        LOGE("Failed at starting the stream");
+    }
+    return didStart;
+}
+
+bool SoundBoardEngine::attemptStart() {
+    auto result = createPlaybackStream();
+
+    if (result == Result::OK) {
+        // Create our synthesizer audio source using the properties of the stream
+        mSynth = Synth::create(mStream->getSampleRate(), mStream->getChannelCount(), mNumSignals);
+        mDataCallback->reset();
+        mDataCallback->setSource(std::dynamic_pointer_cast<IRenderableAudio>(mSynth));
+        result = mStream->start();
+        if (result == Result::OK) {
+            return true;
+        } else {
+            LOGW("Failed attempt at starting the playback stream. Error: %s", convertToText(result));
+            return false;
+        }
+    } else {
+        LOGW("Failed attempt at creating the playback stream. Error: %s", convertToText(result));
+        return false;
+    }
+}
+
+bool SoundBoardEngine::stop() {
+    if(mStream && mStream->getState() != oboe::StreamState::Closed) {
+        mStream->stop();
+        mStream->close();
+    }
+    mStream.reset();
+    return true;
+}
+
diff --git a/samples/SoundBoard/src/main/cpp/SoundBoardEngine.h b/samples/SoundBoard/src/main/cpp/SoundBoardEngine.h
new file mode 100644
index 0000000..033f839
--- /dev/null
+++ b/samples/SoundBoard/src/main/cpp/SoundBoardEngine.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018 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 SOUNDBOARD_ENGINE_H
+#define SOUNDBOARD_ENGINE_H
+
+
+#include <oboe/Oboe.h>
+#include <vector>
+
+#include "Synth.h"
+#include <DefaultDataCallback.h>
+#include <TappableAudioSource.h>
+#include <IRestartable.h>
+#include <DefaultErrorCallback.h>
+
+using namespace oboe;
+
+class SoundBoardEngine : public IRestartable {
+
+public:
+    SoundBoardEngine(int32_t numSignals);
+
+    virtual ~SoundBoardEngine();
+
+    void noteOff(int32_t noteIndex);
+
+    void noteOn(int32_t noteIndex);
+
+    void tap(bool isDown);
+
+    // from IRestartable
+    virtual void restart() override;
+
+    bool start();
+    bool stop();
+
+private:
+    int32_t mNumSignals;
+
+    std::shared_ptr<AudioStream> mStream;
+    std::shared_ptr<Synth> mSynth;
+    std::shared_ptr<DefaultDataCallback> mDataCallback;
+    std::shared_ptr<DefaultErrorCallback> mErrorCallback;
+
+    bool attemptStart();
+    oboe::Result createPlaybackStream();
+    void createCallback(int32_t numSignals);
+};
+
+
+#endif //SOUNDBOARD_ENGINE_H
diff --git a/samples/SoundBoard/src/main/cpp/Synth.h b/samples/SoundBoard/src/main/cpp/Synth.h
new file mode 100644
index 0000000..47aa2fa
--- /dev/null
+++ b/samples/SoundBoard/src/main/cpp/Synth.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018 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 SOUNDBOARD_SYNTH_H
+#define SOUNDBOARD_SYNTH_H
+
+#include <array>
+#include <TappableAudioSource.h>
+
+#include <SynthSound.h>
+#include <Mixer.h>
+#include <MonoToStereo.h>
+
+constexpr float kOscBaseFrequency = 196.00; // Start at G3
+constexpr float kOscFrequencyMultiplier = 1.05946309436;
+constexpr float kOscBaseAmplitude = 0.20;
+constexpr float kOscAmplitudeMultiplier = 0.96;
+
+class Synth : public IRenderableAudio, public ITappable {
+public:
+    static ::std::shared_ptr<Synth> create(const int32_t sampleRate, const int32_t channelCount, const int32_t numSignals) {
+        return ::std::make_shared<Synth>(sampleRate, channelCount, numSignals);
+    }
+
+    Synth(const int32_t sampleRate, const int32_t channelCount, const int32_t numSignals) {
+        float curFrequency = kOscBaseFrequency;
+        float curAmplitude = kOscBaseAmplitude;
+        for (int i = 0; i < numSignals; ++i) {
+            mOscs[i].setSampleRate(sampleRate);
+            mOscs[i].setFrequency(curFrequency);
+            curFrequency *= kOscFrequencyMultiplier;
+            mOscs[i].setAmplitude(curAmplitude);
+            curAmplitude *= kOscAmplitudeMultiplier;
+            mMixer.addTrack(&mOscs[i]);
+        }
+
+        if (channelCount == oboe::ChannelCount::Stereo) {
+            mOutputStage =  &mConverter;
+        } else {
+            mOutputStage = &mMixer;
+        }
+    }
+
+    void noteOff(int32_t noteIndex) {
+        mOscs[noteIndex].noteOff();
+    }
+
+    void noteOn(int32_t noteIndex) {
+        mOscs[noteIndex].noteOn();
+    }
+
+    void tap(bool isOn) override {
+        for (int i = 0; i < mNumSignals; i++) {
+            if (isOn) {
+                mOscs[i].noteOn();
+            } else {
+                mOscs[i].noteOff();
+            }
+        }
+    };
+
+    // From IRenderableAudio
+    void renderAudio(float *audioData, int32_t numFrames) override {
+        mOutputStage->renderAudio(audioData, numFrames);
+    };
+
+    virtual ~Synth() {
+    }
+private:
+    // Rendering objects
+    int32_t mNumSignals;
+    std::array<SynthSound, kMaxTracks> mOscs;
+    Mixer mMixer;
+    MonoToStereo mConverter = MonoToStereo(&mMixer);
+    IRenderableAudio *mOutputStage; // This will point to either the mixer or converter, so it needs to be raw
+};
+
+
+#endif //SOUNDBOARD_SYNTH_H
diff --git a/samples/SoundBoard/src/main/cpp/native-lib.cpp b/samples/SoundBoard/src/main/cpp/native-lib.cpp
new file mode 100644
index 0000000..dcd0464
--- /dev/null
+++ b/samples/SoundBoard/src/main/cpp/native-lib.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018 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 <jni.h>
+#include <string>
+#include <vector>
+
+#include "SoundBoardEngine.h"
+
+extern "C" {
+/**
+ * Start the audio engine
+ *
+ * @param env
+ * @param instance
+ * @param jCpuIds - CPU core IDs which the audio process should affine to
+ * @return a pointer to the audio engine. This should be passed to other methods
+ */
+JNIEXPORT jlong JNICALL
+Java_com_google_oboe_samples_soundboard_MainActivity_startEngine(JNIEnv *env, jobject /*unused*/,
+         jint jNumSignals) {
+    LOGD("numSignals : %d", static_cast<int>(jNumSignals));
+    SoundBoardEngine  *engine = new SoundBoardEngine(jNumSignals);
+
+    if (!engine->start()) {
+        LOGE("Failed to start SoundBoard Engine");
+        delete engine;
+        engine = nullptr;
+    } else  {
+        LOGD("Engine Started");
+    }
+    return reinterpret_cast<jlong>(engine);
+}
+
+JNIEXPORT void JNICALL
+Java_com_google_oboe_samples_soundboard_MainActivity_stopEngine(JNIEnv *env, jobject instance,
+        jlong jEngineHandle) {
+    auto engine = reinterpret_cast<SoundBoardEngine*>(jEngineHandle);
+    if (engine) {
+        engine->stop();
+        delete engine;
+    } else {
+        LOGD("Engine invalid, call startEngine() to create");
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_google_oboe_samples_soundboard_MainActivity_native_1setDefaultStreamValues(JNIEnv *env,
+                                                                            jclass type,
+                                                                            jint sampleRate,
+                                                                            jint framesPerBurst) {
+    oboe::DefaultStreamValues::SampleRate = (int32_t) sampleRate;
+    oboe::DefaultStreamValues::FramesPerBurst = (int32_t) framesPerBurst;
+}
+
+JNIEXPORT void JNICALL
+Java_com_google_oboe_samples_soundboard_NoteListener_noteOff(JNIEnv *env, jobject thiz,
+                                                         jlong engine_handle, jint noteIndex) {
+    auto *engine = reinterpret_cast<SoundBoardEngine*>(engine_handle);
+    if (engine) {
+        engine->noteOff(noteIndex);
+    } else {
+        LOGE("Engine handle is invalid, call createEngine() to create a new one");
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_google_oboe_samples_soundboard_NoteListener_noteOn(JNIEnv *env, jobject thiz,
+                                                         jlong engine_handle, jint noteIndex) {
+    auto *engine = reinterpret_cast<SoundBoardEngine*>(engine_handle);
+    if (engine) {
+        engine->noteOn(noteIndex);
+    } else {
+        LOGE("Engine handle is invalid, call createEngine() to create a new one");
+    }
+}
+
+} // extern "C"
diff --git a/samples/SoundBoard/src/main/ic_launcher-playstore.png b/samples/SoundBoard/src/main/ic_launcher-playstore.png
new file mode 100644
index 0000000..a47702f
--- /dev/null
+++ b/samples/SoundBoard/src/main/ic_launcher-playstore.png
Binary files differ
diff --git a/samples/SoundBoard/src/main/java/com/google/oboe/samples/soundboard/MainActivity.java b/samples/SoundBoard/src/main/java/com/google/oboe/samples/soundboard/MainActivity.java
new file mode 100644
index 0000000..bceb007
--- /dev/null
+++ b/samples/SoundBoard/src/main/java/com/google/oboe/samples/soundboard/MainActivity.java
@@ -0,0 +1,111 @@
+package com.google.oboe.samples.soundboard;
+
+/*
+ * Copyright 2021 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.
+ */
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Rect;
+import android.media.AudioManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+
+import java.util.ArrayList;
+
+import static java.lang.Math.min;
+
+public class MainActivity extends AppCompatActivity {
+
+    private final String TAG = MainActivity.class.toString();
+    private final int NUM_ROWS = 6;
+    private final int NUM_COLUMNS = 5;
+    private static long mEngineHandle = 0;
+
+    private native long startEngine(int numSignals);
+    private native void stopEngine(long engineHandle);
+
+    private static native void native_setDefaultStreamValues(int sampleRate, int framesPerBurst);
+
+    // Used to load the 'native-lib' library on application startup.
+    static {
+        System.loadLibrary("soundboard");
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+    }
+
+    @Override
+    protected void onResume(){
+        setDefaultStreamValues(this);
+        mEngineHandle = startEngine(NUM_ROWS * NUM_COLUMNS);
+        createMusicTiles(this);
+        super.onResume();
+    }
+
+    @Override
+    protected void onPause(){
+        stopEngine(mEngineHandle);
+        super.onPause();
+    }
+
+    static void setDefaultStreamValues(Context context) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
+            AudioManager myAudioMgr = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+            String sampleRateStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
+            int defaultSampleRate = Integer.parseInt(sampleRateStr);
+            String framesPerBurstStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
+            int defaultFramesPerBurst = Integer.parseInt(framesPerBurstStr);
+
+            native_setDefaultStreamValues(defaultSampleRate, defaultFramesPerBurst);
+        }
+    }
+
+    void createMusicTiles(Context context) {
+        DisplayMetrics displayMetrics = new DisplayMetrics();
+        ((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+        int height = displayMetrics.heightPixels;
+        int width = displayMetrics.widthPixels;
+
+        // 5 by 6 tiles
+        final int numRows = NUM_ROWS;
+        final int numColumns = NUM_COLUMNS;
+        final int tileLength = min(height / (numRows), width / (numColumns));
+        final int xStartLocation = (width - tileLength * numColumns) / 2;
+        // Height isn't a perfect measurement so shift the location slightly up from the "center"
+        final int yStartLocation = (height - tileLength * numRows) / 2 / 2;
+
+        ArrayList<Rect> rectangles = new ArrayList<Rect>();
+        for (int i = 0; i < numRows; i++) {
+            for (int j = 0; j < numColumns; j++) {
+                Rect rectangle = new Rect(xStartLocation + j * tileLength,
+                        yStartLocation + i * tileLength,
+                        xStartLocation + j * tileLength + tileLength,
+                        yStartLocation + i * tileLength + tileLength);
+                rectangles.add(rectangle);
+            }
+        }
+        
+        setContentView(new MusicTileView(this, rectangles, new NoteListener(mEngineHandle)));
+    }
+}
+
+
diff --git a/samples/SoundBoard/src/main/java/com/google/oboe/samples/soundboard/MusicTileView.java b/samples/SoundBoard/src/main/java/com/google/oboe/samples/soundboard/MusicTileView.java
new file mode 100644
index 0000000..5355067
--- /dev/null
+++ b/samples/SoundBoard/src/main/java/com/google/oboe/samples/soundboard/MusicTileView.java
@@ -0,0 +1,169 @@
+package com.google.oboe.samples.soundboard;
+
+/*
+ * Copyright 2021 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.
+ */
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.util.SparseArray;
+import android.view.MotionEvent;
+import android.view.View;
+
+import java.util.ArrayList;
+
+public class MusicTileView extends View {
+    private ArrayList<Rect> mRectangles;
+    private boolean[] mIsPressedPerRectangle;
+    private Paint mPaint;
+    private SparseArray<PointF> mLocationsOfFingers;
+    private TileListener mTileListener;
+
+    public interface TileListener {
+        public void onTileOn(int index);
+        public void onTileOff(int index);
+    }
+
+    public MusicTileView(Context context, ArrayList<Rect> rectangles, TileListener tileListener) {
+        super(context);
+
+        mRectangles = rectangles;
+        mIsPressedPerRectangle = new boolean[rectangles.size()];
+        mPaint = new Paint();
+        mLocationsOfFingers = new SparseArray<PointF>();
+
+        mTileListener = tileListener;
+    }
+
+    private int getIndexFromLocation(PointF pointF) {
+        for (int i = 0; i < mRectangles.size(); i++) {
+            if (pointF.x > mRectangles.get(i).left &&
+                    pointF.x < mRectangles.get(i).right &&
+                    pointF.y > mRectangles.get(i).top &&
+                    pointF.y < mRectangles.get(i).bottom) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        for (int i = 0; i < mRectangles.size(); i++) {
+            mPaint.setStyle(Paint.Style.FILL);
+            if (mIsPressedPerRectangle[i]) {
+                mPaint.setColor(Color.rgb(128, 0, 0));
+            } else {
+                mPaint.setColor(Color.BLACK);
+            }
+            canvas.drawRect(mRectangles.get(i), mPaint);
+
+            // border
+            mPaint.setStyle(Paint.Style.STROKE);
+            mPaint.setStrokeWidth(10);
+            mPaint.setColor(Color.WHITE);
+            canvas.drawRect(mRectangles.get(i), mPaint);
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        int pointerIndex = event.getActionIndex();
+        int pointerId = event.getPointerId(pointerIndex);
+        int maskedAction = event.getActionMasked();
+
+        boolean didImageChange = false;
+        switch (maskedAction) {
+            // Move each point from it's current point to the new point.
+            case MotionEvent.ACTION_MOVE: {
+                // Create an array to check for finger changes as multiple fingers may be on the
+                // same tile. This two-pass algorithm records the overall difference before changing
+                // the actual tiles.
+                int[] notesChangedBy = new int[mRectangles.size()];
+                for (int size = event.getPointerCount(), i = 0; i < size; i++) {
+                    PointF point = mLocationsOfFingers.get(event.getPointerId(i));
+                    if (point != null) {
+                        int prevIndex = getIndexFromLocation(point);
+                        point.x = event.getX(i);
+                        point.y = event.getY(i);
+                        int newIndex = getIndexFromLocation(point);
+
+                        if (newIndex != prevIndex) {
+                            if (prevIndex != -1) {
+                                notesChangedBy[prevIndex]--;
+                            }
+                            if (newIndex != -1) {
+                                notesChangedBy[newIndex]++;
+                            }
+                        }
+                    }
+                }
+
+                // Now go through the rectangles to see if they have changed
+                for (int i = 0; i < mRectangles.size(); i++) {
+                    if (notesChangedBy[i] > 0) {
+                        mIsPressedPerRectangle[i] = true;
+                        mTileListener.onTileOn(i);
+                        didImageChange = true;
+                    } else if (notesChangedBy[i] < 0) {
+                        mIsPressedPerRectangle[i] = false;
+                        mTileListener.onTileOff(i);
+                        didImageChange = true;
+                    }
+                }
+                break;
+            }
+            // Add a new point when a location is pressed
+            case MotionEvent.ACTION_DOWN:
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                PointF f = new PointF();
+                f.x = event.getX(pointerIndex);
+                f.y = event.getY(pointerIndex);
+                mLocationsOfFingers.put(pointerId, f);
+                int curIndex = getIndexFromLocation(f);
+                if (curIndex != -1) {
+                    mIsPressedPerRectangle[curIndex] = true;
+                    mTileListener.onTileOn(curIndex);
+                    didImageChange = true;
+                }
+                break;
+            }
+            // Remove a point when a location lifted or when there is an error
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_POINTER_UP:
+            case MotionEvent.ACTION_CANCEL: {
+                int curIndex = getIndexFromLocation(mLocationsOfFingers.get(event.getPointerId(pointerIndex)));
+                if (curIndex != -1) {
+                    mIsPressedPerRectangle[curIndex] = false;
+                    mTileListener.onTileOff(curIndex);
+                    didImageChange = true;
+                }
+                mLocationsOfFingers.remove(pointerId);
+                break;
+            }
+        }
+
+        // Calling invalidate() will force onDraw() to be called
+        if (didImageChange) {
+            invalidate();
+        }
+
+        return true;
+    }
+}
diff --git a/samples/SoundBoard/src/main/java/com/google/oboe/samples/soundboard/NoteListener.java b/samples/SoundBoard/src/main/java/com/google/oboe/samples/soundboard/NoteListener.java
new file mode 100644
index 0000000..e734ea3
--- /dev/null
+++ b/samples/SoundBoard/src/main/java/com/google/oboe/samples/soundboard/NoteListener.java
@@ -0,0 +1,36 @@
+package com.google.oboe.samples.soundboard;
+
+/*
+ * Copyright 2021 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.
+ */
+
+public class NoteListener implements MusicTileView.TileListener {
+    private native void noteOn(long engineHandle, int noteIndex);
+    private native void noteOff(long engineHandle, int noteIndex);
+
+    long mEngineHandle;
+
+    public NoteListener(long engineHandle) {
+        mEngineHandle = engineHandle;
+    }
+
+    public void onTileOn(int index) {
+        noteOn(mEngineHandle, index);
+    }
+
+    public void onTileOff(int index) {
+        noteOff(mEngineHandle, index);
+    }
+}
diff --git a/samples/SoundBoard/src/main/res/drawable-v24/ic_launcher_foreground.xml b/samples/SoundBoard/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..1f6bb29
--- /dev/null
+++ b/samples/SoundBoard/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillType="evenOdd"
+        android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
+        android:strokeWidth="1"
+        android:strokeColor="#00000000">
+        <aapt:attr name="android:fillColor">
+            <gradient
+                android:endX="78.5885"
+                android:endY="90.9159"
+                android:startX="48.7653"
+                android:startY="61.0927"
+                android:type="linear">
+                <item
+                    android:color="#44000000"
+                    android:offset="0.0" />
+                <item
+                    android:color="#00000000"
+                    android:offset="1.0" />
+            </gradient>
+        </aapt:attr>
+    </path>
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillType="nonZero"
+        android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
+        android:strokeWidth="1"
+        android:strokeColor="#00000000" />
+</vector>
diff --git a/samples/SoundBoard/src/main/res/drawable/ic_launcher_background.xml b/samples/SoundBoard/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..ca3826a
--- /dev/null
+++ b/samples/SoundBoard/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector
+    android:height="108dp"
+    android:width="108dp"
+    android:viewportHeight="108"
+    android:viewportWidth="108"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#3DDC84"
+          android:pathData="M0,0h108v108h-108z"/>
+    <path android:fillColor="#00000000" android:pathData="M9,0L9,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,0L19,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M29,0L29,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M39,0L39,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M49,0L49,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M59,0L59,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M69,0L69,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M79,0L79,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M89,0L89,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M99,0L99,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,9L108,9"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,19L108,19"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,29L108,29"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,39L108,39"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,49L108,49"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,59L108,59"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,69L108,69"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,79L108,79"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,89L108,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,99L108,99"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,29L89,29"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,39L89,39"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,49L89,49"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,59L89,59"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,69L89,69"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,79L89,79"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M29,19L29,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M39,19L39,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M49,19L49,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M59,19L59,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M69,19L69,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M79,19L79,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+</vector>
diff --git a/samples/SoundBoard/src/main/res/layout/activity_main.xml b/samples/SoundBoard/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..faae9c9
--- /dev/null
+++ b/samples/SoundBoard/src/main/res/layout/activity_main.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".MainActivity">
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/samples/SoundBoard/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/samples/SoundBoard/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..c4a603d
--- /dev/null
+++ b/samples/SoundBoard/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background"/>
+    <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/samples/SoundBoard/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/samples/SoundBoard/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..c4a603d
--- /dev/null
+++ b/samples/SoundBoard/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background"/>
+    <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/samples/SoundBoard/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/samples/SoundBoard/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..5e0f2e4
--- /dev/null
+++ b/samples/SoundBoard/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/samples/SoundBoard/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/samples/SoundBoard/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..d9bbb99
--- /dev/null
+++ b/samples/SoundBoard/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/samples/SoundBoard/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/samples/SoundBoard/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..2372dd0
--- /dev/null
+++ b/samples/SoundBoard/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/samples/SoundBoard/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/samples/SoundBoard/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..d31f26c
--- /dev/null
+++ b/samples/SoundBoard/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/samples/SoundBoard/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/samples/SoundBoard/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..121cda6
--- /dev/null
+++ b/samples/SoundBoard/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/samples/SoundBoard/src/main/res/values/colors.xml b/samples/SoundBoard/src/main/res/values/colors.xml
new file mode 100644
index 0000000..5783a67
--- /dev/null
+++ b/samples/SoundBoard/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="colorPrimary">#800000</color>
+    <color name="colorPrimaryDark">#300000</color>
+    <color name="colorAccent">#D81B60</color>
+</resources>
diff --git a/samples/SoundBoard/src/main/res/values/strings.xml b/samples/SoundBoard/src/main/res/values/strings.xml
new file mode 100644
index 0000000..14a570e
--- /dev/null
+++ b/samples/SoundBoard/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">soundboard</string>
+</resources>
diff --git a/samples/SoundBoard/src/main/res/values/styles.xml b/samples/SoundBoard/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/samples/SoundBoard/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+</resources>
diff --git a/samples/audio-device/build.gradle b/samples/audio-device/build.gradle
index dcd1144..4f52c4e 100644
--- a/samples/audio-device/build.gradle
+++ b/samples/audio-device/build.gradle
@@ -1,12 +1,10 @@
 apply plugin: 'com.android.library'
 
 android {
-    compileSdkVersion 28
+    compileSdkVersion 33
     defaultConfig {
-        minSdkVersion 16
-        targetSdkVersion 28
-        versionCode 1
-        versionName "1.0"
+        minSdkVersion 21
+        targetSdkVersion 33
     }
     buildTypes {
         release {
diff --git a/samples/build.gradle b/samples/build.gradle
index 9570cc6..6b8dbbf 100644
--- a/samples/build.gradle
+++ b/samples/build.gradle
@@ -17,19 +17,20 @@
 
 // Top-level build file where you can add configuration options common to all sub-projects/modules.
 
-
-
 buildscript {
-    ext.kotlin_version = '1.3.50'
+    ext {
+        compose_version = '1.2.0'
+        kotlin_version = '1.7.0'
+    }
 
     repositories {
         google()
-        jcenter()
+        mavenCentral()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:4.0.1'
+        classpath 'com.android.tools.build:gradle:7.2.2'
         // NOTE: Do not place your application dependencies here; they belong
-        // in the individual module build.gradle files
+        // in the individual module build.gradle files.
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
     }
 }
@@ -37,6 +38,6 @@
 allprojects {
     repositories {
         google()
-        jcenter()
+        mavenCentral()
     }
 }
diff --git a/samples/drumthumper/build.gradle b/samples/drumthumper/build.gradle
index 6778cbb..17a1199 100644
--- a/samples/drumthumper/build.gradle
+++ b/samples/drumthumper/build.gradle
@@ -1,21 +1,21 @@
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
+plugins {
+    id 'com.android.application'
+    id 'org.jetbrains.kotlin.android'
+}
 android {
-    compileSdkVersion 29
-    buildToolsVersion "29.0.3"
+    compileSdkVersion 33
 
     defaultConfig {
         // Usually the applicationId follows the same scheme as the application package name,
         // however, this sample will be published on the Google Play Store which will not allow an
         // applicationId starting with "com.google" as this is reserved for official Google
-        // products. The current owner of Oboe sample apps on Google Play is Phil Burk, who
-        // publishes using the application Id prefix of "com.plausiblesoftware".
+        // products. The current owner of the DrumThumper sample apps on Google Play is Paul McLean,
+        // who publishes using the application Id prefix of "com.plausiblesoftware".
         applicationId "com.plausiblesoftware.drumthumper"
-        minSdkVersion 26
-        targetSdkVersion 29
-        versionCode 1
-        versionName "1.0"
+        minSdkVersion 23
+        targetSdkVersion 33
+        versionCode 2
+        versionName "1.01"
 
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
@@ -36,7 +36,12 @@
 
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
-    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
-    implementation 'androidx.appcompat:appcompat:1.2.0'
-    implementation 'androidx.core:core-ktx:1.3.1'
+    implementation "androidx.core:core-ktx:$kotlin_version"
+    implementation 'androidx.appcompat:appcompat:1.6.0-rc01'
+    def lifecycle_version = "2.5.1"
+    implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
+    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
+    implementation project(path: ':iolib')
+    implementation project(path: ':parselib')
 }
+
diff --git a/samples/drumthumper/src/main/AndroidManifest.xml b/samples/drumthumper/src/main/AndroidManifest.xml
index bd28d07..ea4c376 100644
--- a/samples/drumthumper/src/main/AndroidManifest.xml
+++ b/samples/drumthumper/src/main/AndroidManifest.xml
@@ -9,7 +9,8 @@
         android:roundIcon="@mipmap/ic_launcher_round"
         android:supportsRtl="true"
         android:theme="@style/AppTheme">
-        <activity android:name="com.plausiblesoftware.drumthumper.DrumThumperActivity">
+        <activity android:name="com.plausiblesoftware.drumthumper.DrumThumperActivity"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
diff --git a/samples/drumthumper/src/main/cpp/CMakeLists.txt b/samples/drumthumper/src/main/cpp/CMakeLists.txt
index 758f74d..9d2250a 100644
--- a/samples/drumthumper/src/main/cpp/CMakeLists.txt
+++ b/samples/drumthumper/src/main/cpp/CMakeLists.txt
@@ -70,4 +70,4 @@
 
         # Links the target library to the log library
         # included in the NDK.
-        log)
\ No newline at end of file
+        log)
diff --git a/samples/drumthumper/src/main/cpp/DrumPlayerJNI.cpp b/samples/drumthumper/src/main/cpp/DrumPlayerJNI.cpp
index b1dcf41..651dc61 100644
--- a/samples/drumthumper/src/main/cpp/DrumPlayerJNI.cpp
+++ b/samples/drumthumper/src/main/cpp/DrumPlayerJNI.cpp
@@ -114,6 +114,13 @@
 }
 
 /**
+ * Native (JNI) implementation of DrumPlayer.trigger()
+ */
+JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_stopTrigger(JNIEnv* env, jobject, jint index) {
+    sDTPlayer.triggerUp(index);
+}
+
+/**
  * Native (JNI) implementation of DrumPlayer.getOutputReset()
  */
 JNIEXPORT jboolean JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_getOutputReset(JNIEnv*, jobject) {
diff --git a/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumPlayer.kt b/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumPlayer.kt
index 8adb9af..3b3a56b 100644
--- a/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumPlayer.kt
+++ b/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumPlayer.kt
@@ -26,7 +26,7 @@
                                         // Stereo Playback, set to 1 for Mono playback
                                         // This IS NOT the channel format of the source samples
                                         // (which must be mono).
-        val NUM_SAMPLE_CHANNELS: Int = 1;   // All WAV resource must be mono
+        val NUM_SAMPLE_CHANNELS: Int = 1   // All WAV resource must be mono
 
         // Sample Buffer IDs
         val BASSDRUM: Int = 0
@@ -109,6 +109,7 @@
     private external fun unloadWavAssetsNative()
 
     external fun trigger(drumIndex: Int)
+    external fun stopTrigger(drumIndex: Int)
 
     external fun setPan(index: Int, pan: Float)
     external fun getPan(index: Int): Float
diff --git a/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumThumperActivity.kt b/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumThumperActivity.kt
index b80b7e6..1ec4905 100644
--- a/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumThumperActivity.kt
+++ b/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumThumperActivity.kt
@@ -48,7 +48,7 @@
 
     private var mDeviceListener: DeviceListener = DeviceListener()
 
-    private var mMixControlsShowing = false;
+    private var mMixControlsShowing = false
 
     init {
         // Load the library containing the a native code including the JNI  functions
@@ -84,7 +84,7 @@
         }
 
         private fun resetOutput() {
-            Log.i(TAG, "resetOutput() time:" + LocalDateTime.now() + " native reset:" + mDrumPlayer.getOutputReset());
+            Log.i(TAG, "resetOutput() time:" + LocalDateTime.now() + " native reset:" + mDrumPlayer.getOutputReset())
             if (mDrumPlayer.getOutputReset()) {
                 // the (native) stream has been reset by the onErrorAfterClose() callback
                 mDrumPlayer.clearOutputReset()
@@ -107,8 +107,8 @@
     //
     // UI Helpers
     //
-    val GAIN_FACTOR = 100.0f;
-    val MAX_PAN_POSITION = 200.0f;
+    val GAIN_FACTOR = 100.0f
+    val MAX_PAN_POSITION = 200.0f
     val HALF_PAN_POSITION = MAX_PAN_POSITION / 2.0f
 
     private fun gainPosToGainVal(pos: Int) : Float {
@@ -131,8 +131,8 @@
     }
 
     private fun showMixControls(show : Boolean) {
-        mMixControlsShowing = show;
-        val showFlag = if (mMixControlsShowing) View.VISIBLE else View.GONE;
+        mMixControlsShowing = show
+        val showFlag = if (mMixControlsShowing) View.VISIBLE else View.GONE
         findViewById<LinearLayout>(R.id.kickMixControls).setVisibility(showFlag)
         findViewById<LinearLayout>(R.id.snareMixControls).setVisibility(showFlag)
         findViewById<LinearLayout>(R.id.hihatOpenMixControls).setVisibility(showFlag)
@@ -223,7 +223,7 @@
         connectMixSliders(R.id.crashPan, R.id.crashGain, DrumPlayer.CRASHCYMBAL)
 
         findViewById<Button>(R.id.mixCtrlBtn).setOnClickListener(this)
-        showMixControls(false);
+        showMixControls(false)
     }
 
     override fun onStop() {
@@ -248,8 +248,18 @@
             R.id.snarePad -> mDrumPlayer.trigger(DrumPlayer.SNAREDRUM)
             R.id.midTomPad -> mDrumPlayer.trigger(DrumPlayer.MIDTOM)
             R.id.lowTomPad -> mDrumPlayer.trigger(DrumPlayer.LOWTOM)
-            R.id.hihatOpenPad -> mDrumPlayer.trigger(DrumPlayer.HIHATOPEN)
-            R.id.hihatClosedPad -> mDrumPlayer.trigger(DrumPlayer.HIHATCLOSED)
+            R.id.hihatOpenPad -> {
+                mDrumPlayer.trigger(DrumPlayer.HIHATOPEN)
+                // For a real drum set, hi-hat can play either the open or the closed sound at any
+                // given time.
+                mDrumPlayer.stopTrigger(DrumPlayer.HIHATCLOSED)
+            }
+            R.id.hihatClosedPad -> {
+                mDrumPlayer.trigger(DrumPlayer.HIHATCLOSED)
+                // For a real drum set, hi-hat can play either the open or the closed sound at any
+                // given time.
+                mDrumPlayer.stopTrigger(DrumPlayer.HIHATOPEN)
+            }
             R.id.ridePad -> mDrumPlayer.trigger(DrumPlayer.RIDECYMBAL)
             R.id.crashPad -> mDrumPlayer.trigger(DrumPlayer.CRASHCYMBAL)
         }
diff --git a/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/TriggerPad.kt b/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/TriggerPad.kt
index c6166eb..98b1b5e 100644
--- a/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/TriggerPad.kt
+++ b/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/TriggerPad.kt
@@ -170,12 +170,12 @@
     override fun onTouchEvent(event: MotionEvent): Boolean {
         if (event.actionMasked == MotionEvent.ACTION_DOWN ||
                 event.actionMasked == MotionEvent.ACTION_POINTER_DOWN) {
-            mIsDown = true;
+            mIsDown = true
             triggerDown()
             invalidate()
             return true
         } else if (event.actionMasked == MotionEvent.ACTION_UP) {
-            mIsDown = false;
+            mIsDown = false
             triggerUp()
             invalidate()
             return true
diff --git a/samples/gradle/wrapper/gradle-wrapper.properties b/samples/gradle/wrapper/gradle-wrapper.properties
index bbba345..efcdb87 100644
--- a/samples/gradle/wrapper/gradle-wrapper.properties
+++ b/samples/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Fri Jun 26 17:35:21 PDT 2020
+#Wed Mar 03 18:52:06 GMT 2021
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
diff --git a/samples/hello-oboe/README.md b/samples/hello-oboe/README.md
index bd33aee..517a0a5 100644
--- a/samples/hello-oboe/README.md
+++ b/samples/hello-oboe/README.md
@@ -16,4 +16,4 @@
 
 Screenshots
 -----------
-![hello-oboe-screenshot](hello-oboe-screenshot.png)
\ No newline at end of file
+![hello-oboe-screenshot](hello-oboe-screenshot.png)
diff --git a/samples/hello-oboe/build.gradle b/samples/hello-oboe/build.gradle
index c457761..29b6fc2 100644
--- a/samples/hello-oboe/build.gradle
+++ b/samples/hello-oboe/build.gradle
@@ -1,17 +1,17 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 28
+    compileSdkVersion 33
 
     defaultConfig {
         applicationId 'com.google.oboe.samples.hellooboe'
-        minSdkVersion 16
-        targetSdkVersion 28
+        minSdkVersion 21
+        targetSdkVersion 33
         versionCode 1
         versionName '1.0'
         externalNativeBuild {
             cmake {
-                cppFlags "-std=c++14"
+                cppFlags "-std=c++17"
                 arguments '-DANDROID_STL=c++_static'
                 // armeabi and mips are deprecated in NDK r16 so we don't want to build for them
                 abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
@@ -35,6 +35,6 @@
 dependencies {
     implementation fileTree(include: ['*.jar'], dir: 'libs')
     implementation project(':audio-device')
-    implementation 'androidx.appcompat:appcompat:1.0.0-rc02'
+    implementation 'androidx.appcompat:appcompat:1.6.0-rc01'
     implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
 }
diff --git a/samples/hello-oboe/src/main/AndroidManifest.xml b/samples/hello-oboe/src/main/AndroidManifest.xml
index eb283fb..593873e 100644
--- a/samples/hello-oboe/src/main/AndroidManifest.xml
+++ b/samples/hello-oboe/src/main/AndroidManifest.xml
@@ -14,7 +14,8 @@
       <activity
           android:name="com.google.oboe.samples.hellooboe.MainActivity"
           android:label="@string/app_name"
-          android:screenOrientation="portrait">
+          android:screenOrientation="portrait"
+          android:exported="true">
         <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
diff --git a/samples/hello-oboe/src/main/cpp/HelloOboeEngine.cpp b/samples/hello-oboe/src/main/cpp/HelloOboeEngine.cpp
index 1fa06ea..c27d5a4 100644
--- a/samples/hello-oboe/src/main/cpp/HelloOboeEngine.cpp
+++ b/samples/hello-oboe/src/main/cpp/HelloOboeEngine.cpp
@@ -35,8 +35,8 @@
  *
  */
 HelloOboeEngine::HelloOboeEngine()
-        : mLatencyCallback(std::make_unique<LatencyTuningCallback>()),
-        mErrorCallback(std::make_unique<DefaultErrorCallback>(*this)) {
+        : mLatencyCallback(std::make_shared<LatencyTuningCallback>()),
+        mErrorCallback(std::make_shared<DefaultErrorCallback>(*this)) {
 }
 
 double HelloOboeEngine::getCurrentOutputLatencyMillis() {
@@ -45,30 +45,13 @@
     std::lock_guard<std::mutex> lock(mLock);
     if (!mStream) return -1.0;
 
-    // Get the time that a known audio frame was presented for playing
-    auto result = mStream->getTimestamp(CLOCK_MONOTONIC);
-    double outputLatencyMillis = -1;
-    const int64_t kNanosPerMillisecond = 1000000;
-    if (result == oboe::Result::OK) {
-        oboe::FrameTimestamp playedFrame = result.value();
-        // Get the write index for the next audio frame
-        int64_t writeIndex = mStream->getFramesWritten();
-        // Calculate the number of frames between our known frame and the write index
-        int64_t frameIndexDelta = writeIndex - playedFrame.position;
-        // Calculate the time which the next frame will be presented
-        int64_t frameTimeDelta = (frameIndexDelta * oboe::kNanosPerSecond) /  (mStream->getSampleRate());
-        int64_t nextFramePresentationTime = playedFrame.timestamp + frameTimeDelta;
-        // Assume that the next frame will be written at the current time
-        using namespace std::chrono;
-        int64_t nextFrameWriteTime =
-                duration_cast<nanoseconds>(steady_clock::now().time_since_epoch()).count();
-        // Calculate the latency
-        outputLatencyMillis = static_cast<double>(nextFramePresentationTime - nextFrameWriteTime)
-                         / kNanosPerMillisecond;
+    oboe::ResultWithValue<double> latencyResult = mStream->calculateLatencyMillis();
+    if (latencyResult) {
+        return latencyResult.value();
     } else {
-        LOGE("Error calculating latency: %s", oboe::convertToText(result.error()));
+        LOGE("Error calculating latency: %s", oboe::convertToText(latencyResult.error()));
+        return -1.0;
     }
-    return outputLatencyMillis;
 }
 
 void HelloOboeEngine::setBufferSizeInBursts(int32_t numBursts) {
@@ -85,43 +68,36 @@
     }
 }
 
-void HelloOboeEngine::setAudioApi(oboe::AudioApi audioApi) {
-    mAudioApi = audioApi;
-    reopenStream();
-}
-
-void HelloOboeEngine::setChannelCount(int channelCount) {
-    mChannelCount = channelCount;
-    reopenStream();
-}
-
-void HelloOboeEngine::setDeviceId(int32_t deviceId) {
-    mDeviceId = deviceId;
-    if (reopenStream() != oboe::Result::OK) {
-        LOGW("Open stream failed, forcing deviceId to Unspecified");
-        mDeviceId = oboe::Unspecified;
-    }
-}
-
 bool HelloOboeEngine::isLatencyDetectionSupported() {
     return mIsLatencyDetectionSupported;
 }
 
-void HelloOboeEngine::tap(bool isDown) {
-    mAudioSource->tap(isDown);
+bool HelloOboeEngine::isAAudioRecommended() {
+    return oboe::AudioStreamBuilder::isAAudioRecommended();
 }
 
-oboe::Result HelloOboeEngine::createPlaybackStream() {
+void HelloOboeEngine::tap(bool isDown) {
+    if (mAudioSource) {
+        mAudioSource->tap(isDown);
+    }
+}
+
+oboe::Result HelloOboeEngine::openPlaybackStream() {
     oboe::AudioStreamBuilder builder;
-    return builder.setSharingMode(oboe::SharingMode::Exclusive)
+    oboe::Result result = builder.setSharingMode(oboe::SharingMode::Exclusive)
         ->setPerformanceMode(oboe::PerformanceMode::LowLatency)
         ->setFormat(oboe::AudioFormat::Float)
-        ->setDataCallback(mLatencyCallback.get())
-        ->setErrorCallback(mErrorCallback.get())
+        ->setFormatConversionAllowed(true)
+        ->setDataCallback(mLatencyCallback)
+        ->setErrorCallback(mErrorCallback)
         ->setAudioApi(mAudioApi)
         ->setChannelCount(mChannelCount)
         ->setDeviceId(mDeviceId)
         ->openStream(mStream);
+    if (result == oboe::Result::OK) {
+        mChannelCount = mStream->getChannelCount();
+    }
+    return result;
 }
 
 void HelloOboeEngine::restart() {
@@ -130,40 +106,70 @@
     start();
 }
 
+oboe::Result HelloOboeEngine::start(oboe::AudioApi audioApi, int deviceId, int channelCount) {
+    mAudioApi = audioApi;
+    mDeviceId = deviceId;
+    mChannelCount = channelCount;
+    return start();
+}
+
 oboe::Result HelloOboeEngine::start() {
     std::lock_guard<std::mutex> lock(mLock);
-
-    auto result = createPlaybackStream();
-    if (result == oboe::Result::OK){
-        mAudioSource =  std::make_shared<SoundGenerator>(mStream->getSampleRate(),
-                mStream->getChannelCount());
-        mLatencyCallback->setSource(std::dynamic_pointer_cast<IRenderableAudio>(mAudioSource));
-        mStream->start();
-        mIsLatencyDetectionSupported = (mStream->getTimestamp((CLOCK_MONOTONIC)) !=
-                                        oboe::Result::ErrorUnimplemented);
-
-        LOGD("Stream opened: AudioAPI = %d, channelCount = %d, deviceID = %d",
-                mStream->getAudioApi(),
-                mStream->getChannelCount(),
-                mStream->getDeviceId());
-    } else {
-        LOGE("Error creating playback stream. Error: %s", oboe::convertToText(result));
+    oboe::Result result = oboe::Result::OK;
+    // It is possible for a stream's device to become disconnected during the open or between
+    // the Open and the Start.
+    // So if it fails to start, close the old stream and try again.
+    int tryCount = 0;
+    do {
+        if (tryCount > 0) {
+            usleep(20 * 1000); // Sleep between tries to give the system time to settle.
+        }
         mIsLatencyDetectionSupported = false;
+        result = openPlaybackStream();
+        if (result == oboe::Result::OK) {
+            mAudioSource = std::make_shared<SoundGenerator>(mStream->getSampleRate(),
+                                                            mStream->getChannelCount());
+            mLatencyCallback->setSource(
+                    std::dynamic_pointer_cast<IRenderableAudio>(mAudioSource));
+
+            LOGD("Stream opened: AudioAPI = %d, channelCount = %d, deviceID = %d",
+                 mStream->getAudioApi(),
+                 mStream->getChannelCount(),
+                 mStream->getDeviceId());
+
+            result = mStream->requestStart();
+            if (result != oboe::Result::OK) {
+                LOGE("Error starting playback stream. Error: %s", oboe::convertToText(result));
+                mStream->close();
+                mStream.reset();
+            } else {
+                mIsLatencyDetectionSupported = (mStream->getTimestamp((CLOCK_MONOTONIC)) !=
+                                                oboe::Result::ErrorUnimplemented);
+            }
+        } else {
+            LOGE("Error creating playback stream. Error: %s", oboe::convertToText(result));
+        }
+    } while (result != oboe::Result::OK && tryCount++ < 3);
+    return result;
+}
+
+oboe::Result HelloOboeEngine::stop() {
+    oboe::Result result = oboe::Result::OK;
+    // Stop, close and delete in case not already closed.
+    std::lock_guard<std::mutex> lock(mLock);
+    if (mStream) {
+        result = mStream->stop();
+        mStream->close();
+        mStream.reset();
     }
     return result;
 }
 
-void HelloOboeEngine::stop() {
-    // Stop, close and delete in case not already closed.
-    std::lock_guard<std::mutex> lock(mLock);
-    if (mStream) {
-        mStream->stop();
-        mStream->close();
-        mStream.reset();
-    }
-}
-
 oboe::Result HelloOboeEngine::reopenStream() {
-    stop();
-    return start();
+    if (mStream) {
+        stop();
+        return start();
+    } else {
+        return oboe::Result::OK;
+    }
 }
diff --git a/samples/hello-oboe/src/main/cpp/HelloOboeEngine.h b/samples/hello-oboe/src/main/cpp/HelloOboeEngine.h
index 29231ee..ea535b1 100644
--- a/samples/hello-oboe/src/main/cpp/HelloOboeEngine.h
+++ b/samples/hello-oboe/src/main/cpp/HelloOboeEngine.h
@@ -37,34 +37,22 @@
 
     /**
      * Open and start a stream.
+     * @param deviceId the audio device id, can be obtained through an {@link AudioDeviceInfo} object
+     * using Java/JNI.
      * @return error or OK
      */
+    oboe::Result start(oboe::AudioApi audioApi, int deviceId, int channelCount);
+    /* Start using current settings. */
     oboe::Result start();
 
     /**
      * Stop and close the stream.
      */
-    void stop();
+    oboe::Result stop();
 
     // From IRestartable
     void restart() override;
 
-    // These methods reset the underlying stream with new properties
-
-    /**
-     * Set the audio device which should be used for playback. Can be set to oboe::kUnspecified if
-     * you want to use the default playback device (which is usually the built-in speaker if
-     * no other audio devices, such as headphones, are attached).
-     *
-     * @param deviceId the audio device id, can be obtained through an {@link AudioDeviceInfo} object
-     * using Java/JNI.
-    */
-    void setDeviceId(int32_t deviceId);
-
-    void setChannelCount(int channelCount);
-
-    void setAudioApi(oboe::AudioApi audioApi);
-
     void setBufferSizeInBursts(int32_t numBursts);
 
     /**
@@ -86,13 +74,15 @@
 
     bool isLatencyDetectionSupported();
 
+    bool isAAudioRecommended();
+
 private:
     oboe::Result reopenStream();
-    oboe::Result createPlaybackStream();
+    oboe::Result openPlaybackStream();
 
     std::shared_ptr<oboe::AudioStream> mStream;
-    std::unique_ptr<LatencyTuningCallback> mLatencyCallback;
-    std::unique_ptr<DefaultErrorCallback> mErrorCallback;
+    std::shared_ptr<LatencyTuningCallback> mLatencyCallback;
+    std::shared_ptr<DefaultErrorCallback> mErrorCallback;
     std::shared_ptr<SoundGenerator> mAudioSource;
     bool mIsLatencyDetectionSupported = false;
 
diff --git a/samples/hello-oboe/src/main/cpp/jni_bridge.cpp b/samples/hello-oboe/src/main/cpp/jni_bridge.cpp
index 0efaff0..8d049c5 100644
--- a/samples/hello-oboe/src/main/cpp/jni_bridge.cpp
+++ b/samples/hello-oboe/src/main/cpp/jni_bridge.cpp
@@ -20,153 +20,68 @@
 #include "logging_macros.h"
 
 extern "C" {
+/* We only need one HelloOboeEngine and it is needed for the entire time.
+ * So just allocate one statically. */
+static HelloOboeEngine sEngine;
 
-/**
- * Creates the audio engine
- *
- * @return a pointer to the audio engine. This should be passed to other methods
- */
-JNIEXPORT jlong JNICALL
-Java_com_google_oboe_samples_hellooboe_PlaybackEngine_native_1createEngine(
+JNIEXPORT jint JNICALL
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_startEngine(
         JNIEnv *env,
-        jclass /*unused*/) {
-    // We use std::nothrow so `new` returns a nullptr if the engine creation fails
-    HelloOboeEngine *engine = new(std::nothrow) HelloOboeEngine();
-    if (engine == nullptr) {
-        LOGE("Could not instantiate HelloOboeEngine");
-        return 0;
-    }
-    auto result = engine->start();
-    if (result != oboe::Result::OK) {
-        LOGE("Opening and starting stream failed. Returned %d", result);
-        engine->stop();
-        delete engine;
-        return 0;
-    }
-    return reinterpret_cast<jlong>(engine);
+        jclass,
+        int audioApi, int deviceId, int channelCount) {
+    return static_cast<jint>(sEngine.start((oboe::AudioApi)audioApi, deviceId, channelCount));
+}
+
+JNIEXPORT jint JNICALL
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_stopEngine(
+        JNIEnv *env,
+        jclass) {
+    return static_cast<jint>(sEngine.stop());
 }
 
 JNIEXPORT void JNICALL
-Java_com_google_oboe_samples_hellooboe_PlaybackEngine_native_1deleteEngine(
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_setToneOn(
         JNIEnv *env,
         jclass,
-        jlong engineHandle) {
-
-    HelloOboeEngine *engine = reinterpret_cast<HelloOboeEngine *>(engineHandle);
-    engine->stop();
-    delete engine;
-}
-
-JNIEXPORT void JNICALL
-Java_com_google_oboe_samples_hellooboe_PlaybackEngine_native_1setToneOn(
-        JNIEnv *env,
-        jclass,
-        jlong engineHandle,
         jboolean isToneOn) {
 
-    HelloOboeEngine *engine = reinterpret_cast<HelloOboeEngine *>(engineHandle);
-    if (engine == nullptr) {
-        LOGE("Engine handle is invalid, call createHandle() to create a new one");
-        return;
-    }
-    engine->tap(isToneOn);
+    sEngine.tap(isToneOn);
 }
 
-JNIEXPORT void JNICALL
-Java_com_google_oboe_samples_hellooboe_PlaybackEngine_native_1setAudioApi(
-        JNIEnv *env,
-        jclass type,
-        jlong engineHandle,
-        jint audioApi) {
-
-    HelloOboeEngine *engine = reinterpret_cast<HelloOboeEngine*>(engineHandle);
-    if (engine == nullptr) {
-        LOGE("Engine handle is invalid, call createHandle() to create a new one");
-        return;
-    }
-
-    oboe::AudioApi api = static_cast<oboe::AudioApi>(audioApi);
-    engine->setAudioApi(api);
-}
 
 JNIEXPORT void JNICALL
-Java_com_google_oboe_samples_hellooboe_PlaybackEngine_native_1setAudioDeviceId(
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_setBufferSizeInBursts(
         JNIEnv *env,
         jclass,
-        jlong engineHandle,
-        jint deviceId) {
-
-    HelloOboeEngine *engine = reinterpret_cast<HelloOboeEngine*>(engineHandle);
-    if (engine == nullptr) {
-        LOGE("Engine handle is invalid, call createHandle() to create a new one");
-        return;
-    }
-    engine->setDeviceId(deviceId);
-}
-
-JNIEXPORT void JNICALL
-Java_com_google_oboe_samples_hellooboe_PlaybackEngine_native_1setChannelCount(
-        JNIEnv *env,
-        jclass type,
-        jlong engineHandle,
-        jint channelCount) {
-
-    HelloOboeEngine *engine = reinterpret_cast<HelloOboeEngine*>(engineHandle);
-    if (engine == nullptr) {
-        LOGE("Engine handle is invalid, call createHandle() to create a new one");
-        return;
-    }
-    engine->setChannelCount(channelCount);
-}
-
-JNIEXPORT void JNICALL
-Java_com_google_oboe_samples_hellooboe_PlaybackEngine_native_1setBufferSizeInBursts(
-        JNIEnv *env,
-        jclass,
-        jlong engineHandle,
         jint bufferSizeInBursts) {
-
-    HelloOboeEngine *engine = reinterpret_cast<HelloOboeEngine*>(engineHandle);
-    if (engine == nullptr) {
-        LOGE("Engine handle is invalid, call createHandle() to create a new one");
-        return;
-    }
-    engine->setBufferSizeInBursts(bufferSizeInBursts);
+    sEngine.setBufferSizeInBursts(bufferSizeInBursts);
 }
 
-
 JNIEXPORT jdouble JNICALL
-Java_com_google_oboe_samples_hellooboe_PlaybackEngine_native_1getCurrentOutputLatencyMillis(
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_getCurrentOutputLatencyMillis(
         JNIEnv *env,
-        jclass,
-        jlong engineHandle) {
-
-    HelloOboeEngine *engine = reinterpret_cast<HelloOboeEngine*>(engineHandle);
-    if (engine == nullptr) {
-        LOGE("Engine is null, you must call createEngine before calling this method");
-        return static_cast<jdouble>(-1.0);
-    }
-    return static_cast<jdouble>(engine->getCurrentOutputLatencyMillis());
+        jclass) {
+    return static_cast<jdouble>(sEngine.getCurrentOutputLatencyMillis());
 }
 
 JNIEXPORT jboolean JNICALL
-Java_com_google_oboe_samples_hellooboe_PlaybackEngine_native_1isLatencyDetectionSupported(
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_isLatencyDetectionSupported(
         JNIEnv *env,
-        jclass type,
-        jlong engineHandle) {
+        jclass) {
+    return (sEngine.isLatencyDetectionSupported() ? JNI_TRUE : JNI_FALSE);
+}
 
-    HelloOboeEngine *engine = reinterpret_cast<HelloOboeEngine*>(engineHandle);
-    if (engine == nullptr) {
-        LOGE("Engine is null, you must call createEngine before calling this method");
-        return JNI_FALSE;
-    }
-    return (engine->isLatencyDetectionSupported() ? JNI_TRUE : JNI_FALSE);
+JNIEXPORT jboolean JNICALL
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_isAAudioRecommended(
+        JNIEnv *env,
+        jclass) {
+    return (sEngine.isAAudioRecommended() ? JNI_TRUE : JNI_FALSE);
 }
 
 JNIEXPORT void JNICALL
-Java_com_google_oboe_samples_hellooboe_PlaybackEngine_native_1setDefaultStreamValues(
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_setDefaultStreamValues(
         JNIEnv *env,
-        jclass type,
+        jclass,
         jint sampleRate,
         jint framesPerBurst) {
     oboe::DefaultStreamValues::SampleRate = (int32_t) sampleRate;
diff --git a/samples/hello-oboe/src/main/java/com/google/oboe/samples/hellooboe/BackgroundRunner.java b/samples/hello-oboe/src/main/java/com/google/oboe/samples/hellooboe/BackgroundRunner.java
new file mode 100644
index 0000000..29e1530
--- /dev/null
+++ b/samples/hello-oboe/src/main/java/com/google/oboe/samples/hellooboe/BackgroundRunner.java
@@ -0,0 +1,56 @@
+package com.google.oboe.samples.hellooboe;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+
+/** Run Audio function in a background thread.
+ * This will avoid ANRs that can occur if the AudioServer or HAL crashes
+ * and takes a long time to recover.
+ *
+ * This thread will run for the lifetime of the app so only make one BackgroundRunner
+ * and reuse it.
+ */
+public abstract class BackgroundRunner {
+    private Handler mHandler;
+    private HandlerThread mThread = new HandlerThread("BackgroundRunner");
+
+    public BackgroundRunner() {
+        mThread.start();
+        mHandler = new Handler(mThread.getLooper()) {
+            public void handleMessage(Message message) {
+                super.handleMessage(message);
+                handleMessageInBackground(message);
+            }
+        };
+    }
+
+    /**
+     * @param message
+     * @return true if the message was successfully queued
+     */
+    public boolean sendMessage(Message message) {
+        return mHandler.sendMessage(message);
+    }
+
+    /**
+     * @param what command code for background operation
+     * @param arg1 optional argument
+     * @return true if the message was successfully queued
+     */
+    public boolean sendMessage(int what, int arg1) {
+        Message message = mHandler.obtainMessage();
+        message.what = what;
+        message.arg1 = arg1;
+        return sendMessage(message);
+    }
+
+    public boolean sendMessage(int what) {
+        return sendMessage(what, 0);
+    }
+
+    /**
+     * Implement this in your app.
+     */
+    abstract void handleMessageInBackground(Message message);
+}
diff --git a/samples/hello-oboe/src/main/java/com/google/oboe/samples/hellooboe/MainActivity.java b/samples/hello-oboe/src/main/java/com/google/oboe/samples/hellooboe/MainActivity.java
index 0060ecb..526d1c8 100644
--- a/samples/hello-oboe/src/main/java/com/google/oboe/samples/hellooboe/MainActivity.java
+++ b/samples/hello-oboe/src/main/java/com/google/oboe/samples/hellooboe/MainActivity.java
@@ -17,11 +17,16 @@
 package com.google.oboe.samples.hellooboe;
 
 import android.app.Activity;
+import android.content.Context;
+import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 import android.os.Build;
 import android.os.Bundle;
-import androidx.core.view.MotionEventCompat;
 
+import androidx.annotation.RequiresApi;
+
+import android.os.Message;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.AdapterView;
@@ -29,6 +34,7 @@
 import android.widget.SimpleAdapter;
 import android.widget.Spinner;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import com.google.oboe.samples.audio_device.AudioDeviceListEntry;
 import com.google.oboe.samples.audio_device.AudioDeviceSpinner;
@@ -37,18 +43,19 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.Timer;
 import java.util.TimerTask;
 
 public class MainActivity extends Activity {
-
-    private static final String TAG = MainActivity.class.getName();
+    private static final String TAG = "HelloOboe";
     private static final long UPDATE_LATENCY_EVERY_MILLIS = 1000;
     private static final Integer[] CHANNEL_COUNT_OPTIONS = {1, 2, 3, 4, 5, 6, 7, 8};
     // Default to Stereo (OPTIONS is zero-based array so index 1 = 2 channels)
     private static final int CHANNEL_COUNT_DEFAULT_OPTION_INDEX = 1;
     private static final int[] BUFFER_SIZE_OPTIONS = {0, 1, 2, 4, 8};
     private static final String[] AUDIO_API_OPTIONS = {"Unspecified", "OpenSL ES", "AAudio"};
+    private static final int OBOE_API_OPENSL_ES = 1;
     // Default all other spinners to the first option on the list
     private static final int SPINNER_DEFAULT_OPTION_INDEX = 0;
 
@@ -58,6 +65,68 @@
     private Spinner mBufferSizeSpinner;
     private TextView mLatencyText;
     private Timer mLatencyUpdater;
+    private boolean mScoStarted = false;
+
+    /** Commands for background thread. */
+    private static final int WHAT_START = 100;
+    private static final int WHAT_STOP = 101;
+    private static final int WHAT_SET_DEVICE_ID = 102;
+    private static final int WHAT_SET_AUDIO_API = 103;
+    private static final int WHAT_SET_CHANNEL_COUNT = 104;
+    private BackgroundRunner mRunner = new MyBackgroundRunner();
+
+    private class MyBackgroundRunner extends BackgroundRunner {
+        // These are initialized to zero by Java.
+        // Zero matches the oboe::Unspecified value.
+        int audioApi;
+        int deviceId;
+        int channelCount;
+
+        @Override
+            /* Execute this in a background thread to avoid ANRs. */
+        void handleMessageInBackground(Message message) {
+            int what = message.what;
+            int arg1 = message.arg1;
+            Log.i(MainActivity.TAG, "got background message, what = " + what + ", arg1 = " + arg1);
+            int result = 0;
+            boolean restart = false;
+            switch (what) {
+                case WHAT_START:
+                    result = PlaybackEngine.startEngine(audioApi, deviceId, channelCount);
+                    break;
+                case WHAT_STOP:
+                    result = PlaybackEngine.stopEngine();
+                    break;
+                case WHAT_SET_AUDIO_API:
+                    if (audioApi != arg1) {
+                        audioApi = arg1;
+                        restart = true;
+                    }
+                    break;
+                case WHAT_SET_DEVICE_ID:
+                    if (deviceId != arg1) {
+                        deviceId = arg1;
+                        restart = true;
+                    }
+                    break;
+                case WHAT_SET_CHANNEL_COUNT:
+                    if (channelCount != arg1) {
+                        channelCount = arg1;
+                        restart = true;
+                    }
+                    break;
+            }
+            if (restart) {
+                int result1 = PlaybackEngine.stopEngine();
+                int result2 = PlaybackEngine.startEngine(audioApi, deviceId, channelCount);
+                result = (result2 != 0) ? result2 : result1;
+            }
+            if (result != 0) {
+                Log.e(TAG, "audio error " + result);
+                showToast("Error in audio =" + result);
+            }
+        }
+    }
 
     /*
      * Hook to user control to start / stop audio playback:
@@ -67,8 +136,7 @@
      */
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        int action = MotionEventCompat.getActionMasked(event);
-        switch (action) {
+        switch (event.getAction()) {
             case (MotionEvent.ACTION_DOWN):
                 PlaybackEngine.setToneOn(true);
                 break;
@@ -88,8 +156,8 @@
         setupPlaybackDeviceSpinner();
         setupChannelCountSpinner();
         setupBufferSizeSpinner();
-
     }
+
     /*
     * Creating engine in onResume() and destroying in onPause() so the stream retains exclusive
     * mode only while in focus. This allows other apps to reclaim exclusive stream mode.
@@ -97,38 +165,54 @@
     @Override
     protected void onResume() {
         super.onResume();
-        PlaybackEngine.create(this);
+        PlaybackEngine.setDefaultStreamValues(this);
         setupLatencyUpdater();
+
         // Return the spinner states to their default value
         mChannelCountSpinner.setSelection(CHANNEL_COUNT_DEFAULT_OPTION_INDEX);
         mPlaybackDeviceSpinner.setSelection(SPINNER_DEFAULT_OPTION_INDEX);
         mBufferSizeSpinner.setSelection(SPINNER_DEFAULT_OPTION_INDEX);
-        mAudioApiSpinner.setSelection(SPINNER_DEFAULT_OPTION_INDEX);
+        if (PlaybackEngine.isAAudioRecommended()) {
+            mAudioApiSpinner.setSelection(SPINNER_DEFAULT_OPTION_INDEX);
+        } else {
+            mAudioApiSpinner.setSelection(OBOE_API_OPENSL_ES);
+            mAudioApiSpinner.setEnabled(false);
+        }
+
+        startAudioAsync();
     }
 
     @Override
     protected void onPause() {
-       if (mLatencyUpdater != null) mLatencyUpdater.cancel();
-       PlaybackEngine.delete();
-       super.onPause();
+        if (mLatencyUpdater != null) mLatencyUpdater.cancel();
+        stopAudioAsync();
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+            clearCommunicationDevice();
+        } else {
+            if (mScoStarted) {
+                stopBluetoothSco();
+                mScoStarted = false;
+            }
+        }
+        super.onPause();
     }
 
     private void setupChannelCountSpinner() {
         mChannelCountSpinner = findViewById(R.id.channelCountSpinner);
 
-        ArrayAdapter<Integer> channelCountAdapter = new ArrayAdapter<Integer>(this, R.layout.channel_counts_spinner, CHANNEL_COUNT_OPTIONS);
+        ArrayAdapter<Integer> channelCountAdapter = new ArrayAdapter<>(this, R.layout.channel_counts_spinner, CHANNEL_COUNT_OPTIONS);
         mChannelCountSpinner.setAdapter(channelCountAdapter);
         mChannelCountSpinner.setSelection(CHANNEL_COUNT_DEFAULT_OPTION_INDEX);
 
         mChannelCountSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
             @Override
             public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
-                PlaybackEngine.setChannelCount(CHANNEL_COUNT_OPTIONS[mChannelCountSpinner.getSelectedItemPosition()]);
+                setChannelCountAsync(CHANNEL_COUNT_OPTIONS[mChannelCountSpinner.getSelectedItemPosition()]);
             }
 
             @Override
             public void onNothingSelected(AdapterView<?> adapterView) {
-
             }
         });
     }
@@ -151,7 +235,6 @@
 
             @Override
             public void onNothingSelected(AdapterView<?> adapterView) {
-
             }
         });
     }
@@ -164,14 +247,33 @@
             mPlaybackDeviceSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                 @Override
                 public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
-                    PlaybackEngine.setAudioDeviceId(getPlaybackDeviceId());
+                    // To use Bluetooth SCO, setCommunicationDevice() or startBluetoothSco() must
+                    // be called. The AudioManager.startBluetoothSco() is deprecated in Android T.
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+                        if (isScoDevice(getPlaybackDeviceId())){
+                            setCommunicationDevice(getPlaybackDeviceId());
+                        } else {
+                            clearCommunicationDevice();
+                        }
+                    } else {
+                        // Start Bluetooth SCO if needed.
+                        if (isScoDevice(getPlaybackDeviceId()) && !mScoStarted) {
+                            startBluetoothSco();
+                            mScoStarted = true;
+                        } else if (!isScoDevice(getPlaybackDeviceId()) && mScoStarted) {
+                            stopBluetoothSco();
+                            mScoStarted = false;
+                        }
+                    }
+                    setAudioDeviceIdAsync(getPlaybackDeviceId());
                 }
 
                 @Override
                 public void onNothingSelected(AdapterView<?> adapterView) {
-
                 }
             });
+        } else {
+            mPlaybackDeviceSpinner.setEnabled(false);
         }
     }
 
@@ -188,12 +290,17 @@
         mAudioApiSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
             @Override
             public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
-                PlaybackEngine.setAudioApi(i);
+                setAudioApiAsync(i);
+                if (i == OBOE_API_OPENSL_ES) {
+                    mPlaybackDeviceSpinner.setSelection(SPINNER_DEFAULT_OPTION_INDEX);
+                    mPlaybackDeviceSpinner.setEnabled(false);
+                } else {
+                    mPlaybackDeviceSpinner.setEnabled(true);
+                }
             }
 
             @Override
             public void onNothingSelected(AdapterView<?> adapterView) {
-
             }
         });
     }
@@ -212,7 +319,7 @@
         // parseInt will throw a NumberFormatException if the string doesn't contain a valid integer
         // representation. We don't need to worry about this because the values are derived from
         // the BUFFER_SIZE_OPTIONS int array.
-        return Integer.parseInt(selectedOption.get(valueKey));
+        return Integer.parseInt(Objects.requireNonNull(selectedOption.get(valueKey)));
     }
 
     private void setupLatencyUpdater() {
@@ -232,12 +339,7 @@
                     latencyStr = getString(R.string.only_supported_on_api_26);
                 }
 
-                runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        mLatencyText.setText(getString(R.string.latency, latencyStr));
-                    }
-                });
+                runOnUiThread(() -> mLatencyText.setText(getString(R.string.latency, latencyStr)));
             }
         };
         mLatencyUpdater = new Timer();
@@ -281,4 +383,74 @@
         }
         return audioApiOptions;
     }
+
+    protected void showToast(final String message) {
+        runOnUiThread(() -> Toast.makeText(MainActivity.this,
+                message,
+                Toast.LENGTH_SHORT).show());
+    }
+
+    @RequiresApi(api = Build.VERSION_CODES.S)
+    private void setCommunicationDevice(int deviceId) {
+        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        final AudioDeviceInfo[] devices;
+        devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+        for (AudioDeviceInfo device : devices) {
+            if (device.getId() == deviceId) {
+                audioManager.setCommunicationDevice(device);
+                return;
+            }
+        }
+    }
+
+    @RequiresApi(api = Build.VERSION_CODES.S)
+    private void clearCommunicationDevice() {
+        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        audioManager.clearCommunicationDevice();
+    }
+
+    @RequiresApi(api = Build.VERSION_CODES.M)
+    private boolean isScoDevice(int deviceId) {
+        if (deviceId == 0) return false; // Unspecified
+        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        final AudioDeviceInfo[] devices;
+        devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+        for (AudioDeviceInfo device : devices) {
+            if (device.getId() == deviceId) {
+                return device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO;
+            }
+        }
+        return false;
+    }
+
+    private void startBluetoothSco() {
+        AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        myAudioMgr.startBluetoothSco();
+    }
+
+    private void stopBluetoothSco() {
+        AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        myAudioMgr.stopBluetoothSco();
+    }
+
+
+    void startAudioAsync() {
+        mRunner.sendMessage(WHAT_START);
+    }
+
+    void stopAudioAsync() {
+        mRunner.sendMessage(WHAT_STOP);
+    }
+
+    void setAudioApiAsync(int audioApi){
+        mRunner.sendMessage(WHAT_SET_AUDIO_API, audioApi);
+    }
+
+    void setAudioDeviceIdAsync(int deviceId){
+        mRunner.sendMessage(WHAT_SET_DEVICE_ID, deviceId);
+    }
+
+    void setChannelCountAsync(int channelCount) {
+        mRunner.sendMessage(WHAT_SET_CHANNEL_COUNT, channelCount);
+    }
 }
diff --git a/samples/hello-oboe/src/main/java/com/google/oboe/samples/hellooboe/PlaybackEngine.java b/samples/hello-oboe/src/main/java/com/google/oboe/samples/hellooboe/PlaybackEngine.java
index 84bfeee..d5efba4 100644
--- a/samples/hello-oboe/src/main/java/com/google/oboe/samples/hellooboe/PlaybackEngine.java
+++ b/samples/hello-oboe/src/main/java/com/google/oboe/samples/hellooboe/PlaybackEngine.java
@@ -20,24 +20,12 @@
 import android.os.Build;
 
 public class PlaybackEngine {
-
-    static long mEngineHandle = 0;
-
     // Load native library
     static {
         System.loadLibrary("hello-oboe");
     }
 
-    static boolean create(Context context){
-
-        if (mEngineHandle == 0){
-            setDefaultStreamValues(context);
-            mEngineHandle = native_createEngine();
-        }
-        return (mEngineHandle != 0);
-    }
-
-    private static void setDefaultStreamValues(Context context) {
+    static void setDefaultStreamValues(Context context) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
             AudioManager myAudioMgr = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
             String sampleRateStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
@@ -45,55 +33,20 @@
             String framesPerBurstStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
             int defaultFramesPerBurst = Integer.parseInt(framesPerBurstStr);
 
-            native_setDefaultStreamValues(defaultSampleRate, defaultFramesPerBurst);
+            setDefaultStreamValues(defaultSampleRate, defaultFramesPerBurst);
         }
     }
 
-    static void delete(){
-        if (mEngineHandle != 0){
-            native_deleteEngine(mEngineHandle);
-        }
-        mEngineHandle = 0;
-    }
 
-    static void setToneOn(boolean isToneOn){
-        if (mEngineHandle != 0) native_setToneOn(mEngineHandle, isToneOn);
-    }
+    // Native methods that require audioserver calls and might take several seconds.
+    static native int startEngine(int audioApi, int deviceId, int channelCount);
+    static native int stopEngine();
 
-    static void setAudioApi(int audioApi){
-        if (mEngineHandle != 0) native_setAudioApi(mEngineHandle, audioApi);
-    }
-
-    static void setAudioDeviceId(int deviceId){
-        if (mEngineHandle != 0) native_setAudioDeviceId(mEngineHandle, deviceId);
-    }
-
-    static void setChannelCount(int channelCount) {
-        if (mEngineHandle != 0) native_setChannelCount(mEngineHandle, channelCount);
-    }
-
-    static void setBufferSizeInBursts(int bufferSizeInBursts){
-        if (mEngineHandle != 0) native_setBufferSizeInBursts(mEngineHandle, bufferSizeInBursts);
-    }
-
-    static double getCurrentOutputLatencyMillis(){
-        if (mEngineHandle == 0) return 0;
-        return native_getCurrentOutputLatencyMillis(mEngineHandle);
-    }
-
-    static boolean isLatencyDetectionSupported() {
-        return mEngineHandle != 0 && native_isLatencyDetectionSupported(mEngineHandle);
-    }
-
-    // Native methods
-    private static native long native_createEngine();
-    private static native void native_deleteEngine(long engineHandle);
-    private static native void native_setToneOn(long engineHandle, boolean isToneOn);
-    private static native void native_setAudioApi(long engineHandle, int audioApi);
-    private static native void native_setAudioDeviceId(long engineHandle, int deviceId);
-    private static native void native_setChannelCount(long mEngineHandle, int channelCount);
-    private static native void native_setBufferSizeInBursts(long engineHandle, int bufferSizeInBursts);
-    private static native double native_getCurrentOutputLatencyMillis(long engineHandle);
-    private static native boolean native_isLatencyDetectionSupported(long engineHandle);
-    private static native void native_setDefaultStreamValues(int sampleRate, int framesPerBurst);
+    // Native methods that only talk to the native client code.
+    static native void setToneOn(boolean isToneOn);
+    static native void setBufferSizeInBursts(int bufferSizeInBursts);
+    static native double getCurrentOutputLatencyMillis();
+    static native boolean isLatencyDetectionSupported();
+    static native boolean isAAudioRecommended();
+    static native void setDefaultStreamValues(int sampleRate, int framesPerBurst);
 }
diff --git a/samples/iolib/build.gradle b/samples/iolib/build.gradle
index b7b9159..d0571a9 100644
--- a/samples/iolib/build.gradle
+++ b/samples/iolib/build.gradle
@@ -1,15 +1,11 @@
 apply plugin: 'com.android.library'
 
 android {
-    compileSdkVersion 29
-    buildToolsVersion "29.0.1"
-
+    compileSdkVersion 33
 
     defaultConfig {
-        minSdkVersion 26
-        targetSdkVersion 29
-        versionCode 1
-        versionName "1.0"
+        minSdkVersion 21
+        targetSdkVersion 33
 
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         consumerProguardFiles 'consumer-rules.pro'
diff --git a/samples/iolib/src/main/cpp/player/SampleBuffer.cpp b/samples/iolib/src/main/cpp/player/SampleBuffer.cpp
index 039a24c..2ab065d 100644
--- a/samples/iolib/src/main/cpp/player/SampleBuffer.cpp
+++ b/samples/iolib/src/main/cpp/player/SampleBuffer.cpp
@@ -21,7 +21,7 @@
 
 #include "wav/WavStreamReader.h"
 
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
 
 namespace iolib {
 
diff --git a/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp b/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp
index f873d56..aa133be 100644
--- a/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp
+++ b/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp
@@ -48,7 +48,8 @@
         __android_log_print(ANDROID_LOG_ERROR, TAG, "  streamState::Disconnected");
     }
 
-    memset(audioData, 0, numFrames * mChannelCount * sizeof(float));
+    memset(audioData, 0, static_cast<size_t>(numFrames) * static_cast<size_t>(mChannelCount)
+            * sizeof(float));
 
     // OneShotSampleSource* sources = mSampleSources.get();
     for(int32_t index = 0; index < mNumSampleBuffers; index++) {
diff --git a/samples/minimaloboe/.gitignore b/samples/minimaloboe/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/samples/minimaloboe/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/samples/minimaloboe/README.md b/samples/minimaloboe/README.md
new file mode 100644
index 0000000..4d080ed
--- /dev/null
+++ b/samples/minimaloboe/README.md
@@ -0,0 +1,16 @@
+# Minimal Oboe
+
+## Overview
+
+This app is a very simple demonstration of turning on audio from buttons.
+It uses a low-latency Oboe stream.
+
+## Implementation
+
+The app is written using Kotlin and Jetpack Compose.
+
+The app state is maintained by subclassing DefaultLifecycleObserver.
+Oboe is called through an external native function.
+
+This app uses shared_ptr for passing callbacks to Oboe.
+When the stream is disconnected, it starts a new stream.
diff --git a/samples/minimaloboe/build.gradle b/samples/minimaloboe/build.gradle
new file mode 100644
index 0000000..bf03f78
--- /dev/null
+++ b/samples/minimaloboe/build.gradle
@@ -0,0 +1,76 @@
+plugins {
+    id 'com.android.application'
+    id 'org.jetbrains.kotlin.android'
+}
+
+android {
+    compileSdk 33
+
+    defaultConfig {
+        applicationId "com.example.minimaloboe"
+        minSdk 21
+        targetSdk 32
+        versionCode 1
+        versionName "1.0"
+
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+        vectorDrawables {
+            useSupportLibrary true
+        }
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+    kotlinOptions {
+        jvmTarget = '1.8'
+    }
+    buildFeatures {
+        compose true
+    }
+    composeOptions {
+        kotlinCompilerExtensionVersion compose_version
+    }
+
+    externalNativeBuild {
+        cmake {
+            path 'src/main/cpp/CMakeLists.txt'
+        }
+    }
+    packagingOptions {
+        resources {
+            excludes += '/META-INF/{AL2.0,LGPL2.1}'
+        }
+    }
+}
+
+dependencies {
+    implementation "androidx.core:core-ktx:$kotlin_version"
+    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
+    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
+    implementation "androidx.activity:activity-ktx:1.6.0"
+    def lifecycle_version = "2.6.0-alpha02"
+    implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
+    implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
+    implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"
+    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
+    implementation "androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version"
+    implementation "androidx.compose.ui:ui:$compose_version"
+    implementation "androidx.compose.material:material:$compose_version"
+    implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
+    implementation 'androidx.activity:activity-compose:1.3.1'
+    implementation 'androidx.appcompat:appcompat:1.6.0-rc01'
+    testImplementation 'junit:junit:4.13.2'
+    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+    androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
+    debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
+    debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
+}
diff --git a/samples/minimaloboe/proguard-rules.pro b/samples/minimaloboe/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/samples/minimaloboe/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/samples/minimaloboe/src/main/AndroidManifest.xml b/samples/minimaloboe/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..25d9e02
--- /dev/null
+++ b/samples/minimaloboe/src/main/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.minimaloboe">
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/Theme.Samples">
+        <activity
+            android:name=".MainActivity"
+            android:exported="true"
+            android:label="@string/app_name"
+            android:theme="@style/Theme.Samples">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/samples/minimaloboe/src/main/cpp/CMakeLists.txt b/samples/minimaloboe/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000..045ff5c
--- /dev/null
+++ b/samples/minimaloboe/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,52 @@
+#
+# Copyright 2022 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.
+#
+
+cmake_minimum_required(VERSION 3.4.1)
+
+# Set the path to the Oboe library directory
+set (OBOE_DIR ../../../../../)
+#message("OBOE_DIR = " + ${OBOE_DIR})
+
+add_subdirectory(${OBOE_DIR} ./oboe-bin)
+
+# include folders
+include_directories(
+        ${OBOE_DIR}/include
+        ${CMAKE_CURRENT_LIST_DIR}
+)
+
+# App specific sources
+set (APP_SOURCES
+        SimpleNoiseMaker.cpp
+        MinimalOboeJNI.cpp
+        )
+
+# Build the minimaloboe (native) library
+add_library(minimaloboe SHARED
+        ${APP_SOURCES}
+        )
+
+# Enable optimization flags: if having problems with source level debugging,
+# disable -Ofast ( and debug ), re-enable after done debugging.
+target_compile_options(minimaloboe PRIVATE -Wall -Werror "$<$<CONFIG:RELEASE>:-Ofast>")
+
+target_link_libraries( # Specifies the target library.
+        minimaloboe
+        oboe
+
+        # Links the target library to the log library
+        # included in the NDK.
+        log)
diff --git a/samples/minimaloboe/src/main/cpp/MinimalOboeJNI.cpp b/samples/minimaloboe/src/main/cpp/MinimalOboeJNI.cpp
new file mode 100644
index 0000000..295c9ef
--- /dev/null
+++ b/samples/minimaloboe/src/main/cpp/MinimalOboeJNI.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2022 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 <jni.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+static const char *TAG = "MinimalOboeJNI";
+
+#include <android/log.h>
+
+#include <SimpleNoiseMaker.h>
+
+// JNI functions are "C" calling convention
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+using namespace oboe;
+
+// Use a static object so we don't have to worry about it getting deleted at the wrong time.
+static SimpleNoiseMaker sPlayer;
+
+/**
+ * Native (JNI) implementation of AudioPlayer.startAudiostreamNative()
+ */
+JNIEXPORT jint JNICALL Java_com_example_minimaloboe_AudioPlayer_startAudioStreamNative(
+        JNIEnv * /* env */, jobject) {
+    __android_log_print(ANDROID_LOG_INFO, TAG, "%s", __func__);
+    Result result = sPlayer.open();
+    if (result == Result::OK) {
+        result = sPlayer.start();
+    }
+    return (jint) result;
+}
+
+/**
+ * Native (JNI) implementation of AudioPlayer.stopAudioStreamNative()
+ */
+JNIEXPORT jint JNICALL Java_com_example_minimaloboe_AudioPlayer_stopAudioStreamNative(
+        JNIEnv * /* env */, jobject) {
+    __android_log_print(ANDROID_LOG_INFO, TAG, "%s", __func__);
+    // We need to close() even if the stop() fails because we need to delete the resources.
+    Result result1 = sPlayer.stop();
+    Result result2 = sPlayer.close();
+    // Return first failure code.
+    return (jint) ((result1 != Result::OK) ? result1 : result2);
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/samples/minimaloboe/src/main/cpp/SimpleNoiseMaker.cpp b/samples/minimaloboe/src/main/cpp/SimpleNoiseMaker.cpp
new file mode 100644
index 0000000..4058391
--- /dev/null
+++ b/samples/minimaloboe/src/main/cpp/SimpleNoiseMaker.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2022 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 <stdlib.h>
+
+static const char *TAG = "SimpleNoiseMaker";
+
+#include <android/log.h>
+
+#include <SimpleNoiseMaker.h>
+
+using namespace oboe;
+
+oboe::Result SimpleNoiseMaker::open() {
+    // Use shared_ptr to prevent use of a deleted callback.
+    mDataCallback = std::make_shared<MyDataCallback>();
+    mErrorCallback = std::make_shared<MyErrorCallback>(this);
+
+    AudioStreamBuilder builder;
+    oboe::Result result = builder.setSharingMode(oboe::SharingMode::Exclusive)
+            ->setPerformanceMode(oboe::PerformanceMode::LowLatency)
+            ->setFormat(oboe::AudioFormat::Float)
+            ->setChannelCount(kChannelCount)
+            ->setDataCallback(mDataCallback)
+            ->setErrorCallback(mErrorCallback)
+                    // Open using a shared_ptr.
+            ->openStream(mStream);
+    return result;
+}
+
+oboe::Result SimpleNoiseMaker::start() {
+    return mStream->requestStart();
+}
+
+oboe::Result SimpleNoiseMaker::stop() {
+    return mStream->requestStop();
+}
+
+oboe::Result SimpleNoiseMaker::close() {
+    return mStream->close();
+}
+
+/**
+ * This callback method will be called from a high priority audio thread.
+ * It should only do math and not do any blocking operations like
+ * reading or writing files, memory allocation, or networking.
+ * @param audioStream
+ * @param audioData pointer to an array of samples to be filled
+ * @param numFrames number of frames needed
+ * @return
+ */
+DataCallbackResult SimpleNoiseMaker::MyDataCallback::onAudioReady(
+        AudioStream *audioStream,
+        void *audioData,
+        int32_t numFrames) {
+    // We requested float when we built the stream.
+    float *output = (float *) audioData;
+    // Fill buffer with random numbers to create "white noise".
+    int numSamples = numFrames * kChannelCount;
+    for (int i = 0; i < numSamples; i++) {
+        // drand48() returns a random number between 0.0 and 1.0.
+        // Center and scale it to a reasonable value.
+        *output++ = (float) ((drand48() - 0.5) * 0.6);
+    }
+    return oboe::DataCallbackResult::Continue;
+}
+
+void SimpleNoiseMaker::MyErrorCallback::onErrorAfterClose(oboe::AudioStream *oboeStream,
+                                                          oboe::Result error) {
+    __android_log_print(ANDROID_LOG_INFO, TAG,
+                        "%s() - error = %s",
+                        __func__,
+                        oboe::convertToText(error)
+    );
+    // Try to open and start a new stream after a disconnect.
+    if (mParent->open() == Result::OK) {
+        mParent->start();
+    }
+}
diff --git a/samples/minimaloboe/src/main/cpp/SimpleNoiseMaker.h b/samples/minimaloboe/src/main/cpp/SimpleNoiseMaker.h
new file mode 100644
index 0000000..6376c0b
--- /dev/null
+++ b/samples/minimaloboe/src/main/cpp/SimpleNoiseMaker.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2022 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 SIMPLE_NOISE_MAKER_H
+#define SIMPLE_NOISE_MAKER_H
+
+#include "oboe/Oboe.h"
+
+/**
+ * Play white noise using Oboe.
+ */
+class SimpleNoiseMaker {
+public:
+
+    /**
+     * Open an Oboe stream.
+     * @return OK or negative error code.
+     */
+    oboe::Result open();
+
+    oboe::Result start();
+
+    oboe::Result stop();
+
+    oboe::Result close();
+
+private:
+
+    class MyDataCallback : public oboe::AudioStreamDataCallback {
+    public:
+        oboe::DataCallbackResult onAudioReady(
+                oboe::AudioStream *audioStream,
+                void *audioData,
+                int32_t numFrames) override;
+
+    };
+
+    class MyErrorCallback : public oboe::AudioStreamErrorCallback {
+    public:
+        MyErrorCallback(SimpleNoiseMaker *parent) : mParent(parent) {}
+
+        virtual ~MyErrorCallback() {
+        }
+
+        void onErrorAfterClose(oboe::AudioStream *oboeStream, oboe::Result error) override;
+
+    private:
+        SimpleNoiseMaker *mParent;
+    };
+
+    std::shared_ptr<oboe::AudioStream> mStream;
+    std::shared_ptr<MyDataCallback> mDataCallback;
+    std::shared_ptr<MyErrorCallback> mErrorCallback;
+
+    static constexpr int kChannelCount = 2;
+};
+
+#endif //SIMPLE_NOISE_MAKER_H
diff --git a/samples/minimaloboe/src/main/java/com/example/minimaloboe/AudioPlayer.kt b/samples/minimaloboe/src/main/java/com/example/minimaloboe/AudioPlayer.kt
new file mode 100644
index 0000000..4871d74
--- /dev/null
+++ b/samples/minimaloboe/src/main/java/com/example/minimaloboe/AudioPlayer.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2022 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.
+ */
+
+package com.example.minimaloboe
+
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.plus
+import kotlin.coroutines.CoroutineContext
+
+object AudioPlayer : DefaultLifecycleObserver {
+
+    // Create a coroutine scope which we can launch coroutines from. This way, if our
+    // player is ever destroyed (for example, if it was no longer a singleton and had multiple
+    // instances) any jobs would also be cancelled.
+    private val coroutineScope = CoroutineScope(Dispatchers.Default) + Job()
+
+    private var _playerState = MutableStateFlow<PlayerState>(PlayerState.NoResultYet)
+    val playerState = _playerState.asStateFlow()
+
+    init {
+        // Load the library containing the native code including the JNI functions.
+        System.loadLibrary("minimaloboe")
+    }
+
+    fun setPlaybackEnabled(isEnabled: Boolean) {
+        // Start (and stop) Oboe from a coroutine in case it blocks for too long.
+        // If the AudioServer has died it may take several seconds to recover.
+        // That can cause an ANR if we are starting audio from the main UI thread.
+        coroutineScope.launch {
+
+            val result = if (isEnabled) {
+                startAudioStreamNative()
+            } else {
+                stopAudioStreamNative()
+            }
+
+            val newUiState = if (result == 0) {
+                if (isEnabled){
+                    PlayerState.Started
+                } else {
+                    PlayerState.Stopped
+                }
+            } else {
+                PlayerState.Unknown(result)
+            }
+
+            _playerState.update { newUiState }
+        }
+    }
+
+    override fun onStop(owner: LifecycleOwner) {
+        super.onStop(owner)
+        setPlaybackEnabled(false)
+    }
+
+    private external fun startAudioStreamNative(): Int
+    private external fun stopAudioStreamNative(): Int
+}
+
+sealed interface PlayerState {
+    object NoResultYet : PlayerState
+    object Started : PlayerState
+    object Stopped : PlayerState
+    data class Unknown(val resultCode: Int) : PlayerState
+}
diff --git a/samples/minimaloboe/src/main/java/com/example/minimaloboe/MainActivity.kt b/samples/minimaloboe/src/main/java/com/example/minimaloboe/MainActivity.kt
new file mode 100644
index 0000000..edb2901
--- /dev/null
+++ b/samples/minimaloboe/src/main/java/com/example/minimaloboe/MainActivity.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2022 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.
+ */
+
+package com.example.minimaloboe
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material.Button
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Surface
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.ProcessLifecycleOwner
+import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.example.minimaloboe.ui.theme.SamplesTheme
+
+class MainActivity : ComponentActivity() {
+
+    @OptIn(ExperimentalLifecycleComposeApi::class)
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        // Let our AudioPlayer observe lifecycle events for the application so when it goes into the
+        // background we can stop audio playback.
+        ProcessLifecycleOwner.get().lifecycle.addObserver(AudioPlayer)
+
+        setContent {
+            SamplesTheme {
+                // A surface container using the 'background' color from the theme
+                Surface(
+                    modifier = Modifier.fillMaxSize(),
+                    color = MaterialTheme.colors.background
+                ) {
+                    MainControls()
+                }
+            }
+        }
+    }
+}
+
+@ExperimentalLifecycleComposeApi
+@Composable
+fun MainControls() {
+    val playerState by AudioPlayer.playerState.collectAsStateWithLifecycle()
+    MainControls(playerState, AudioPlayer::setPlaybackEnabled)
+}
+
+@ExperimentalLifecycleComposeApi
+@Composable
+fun MainControls(playerState: PlayerState, setPlaybackEnabled: (Boolean) -> Unit) {
+
+    Column {
+
+        val isPlaying = playerState is PlayerState.Started
+
+        Text(text = "Minimal Oboe!")
+
+        Row {
+            Button(
+                onClick = { setPlaybackEnabled(true) },
+                enabled = !isPlaying
+            ) {
+                Text(text = "Start Audio")
+            }
+            Button(
+                onClick = { setPlaybackEnabled(false) },
+                enabled = isPlaying
+            ) {
+                Text(text = "Stop Audio")
+            }
+        }
+
+        // Create a status message for displaying the current playback state.
+        val uiStatusMessage = "Current status: " +
+                when (playerState) {
+                    PlayerState.NoResultYet -> "No result yet"
+                    PlayerState.Started -> "Started"
+                    PlayerState.Stopped -> "Stopped"
+                    is PlayerState.Unknown -> {
+                        "Unknown. Result = " + playerState.resultCode
+                    }
+                }
+
+        Text(uiStatusMessage)
+    }
+}
+
+@OptIn(ExperimentalLifecycleComposeApi::class)
+@Preview(showBackground = true)
+@Composable
+fun DefaultPreview() {
+    SamplesTheme {
+        MainControls(PlayerState.Started) { }
+    }
+}
diff --git a/samples/minimaloboe/src/main/java/com/example/minimaloboe/ui/theme/Color.kt b/samples/minimaloboe/src/main/java/com/example/minimaloboe/ui/theme/Color.kt
new file mode 100644
index 0000000..c4f8298
--- /dev/null
+++ b/samples/minimaloboe/src/main/java/com/example/minimaloboe/ui/theme/Color.kt
@@ -0,0 +1,8 @@
+package com.example.minimaloboe.ui.theme
+
+import androidx.compose.ui.graphics.Color
+
+val Purple200 = Color(0xFFBB86FC)
+val Purple500 = Color(0xFF6200EE)
+val Purple700 = Color(0xFF3700B3)
+val Teal200 = Color(0xFF03DAC5)
diff --git a/samples/minimaloboe/src/main/java/com/example/minimaloboe/ui/theme/Shape.kt b/samples/minimaloboe/src/main/java/com/example/minimaloboe/ui/theme/Shape.kt
new file mode 100644
index 0000000..ca2815d
--- /dev/null
+++ b/samples/minimaloboe/src/main/java/com/example/minimaloboe/ui/theme/Shape.kt
@@ -0,0 +1,11 @@
+package com.example.minimaloboe.ui.theme
+
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Shapes
+import androidx.compose.ui.unit.dp
+
+val Shapes = Shapes(
+    small = RoundedCornerShape(4.dp),
+    medium = RoundedCornerShape(4.dp),
+    large = RoundedCornerShape(0.dp)
+)
diff --git a/samples/minimaloboe/src/main/java/com/example/minimaloboe/ui/theme/Theme.kt b/samples/minimaloboe/src/main/java/com/example/minimaloboe/ui/theme/Theme.kt
new file mode 100644
index 0000000..28c66a0
--- /dev/null
+++ b/samples/minimaloboe/src/main/java/com/example/minimaloboe/ui/theme/Theme.kt
@@ -0,0 +1,44 @@
+package com.example.minimaloboe.ui.theme
+
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.darkColors
+import androidx.compose.material.lightColors
+import androidx.compose.runtime.Composable
+
+private val DarkColorPalette = darkColors(
+    primary = Purple200,
+    primaryVariant = Purple700,
+    secondary = Teal200
+)
+
+private val LightColorPalette = lightColors(
+    primary = Purple500,
+    primaryVariant = Purple700,
+    secondary = Teal200
+
+    /* Other default colors to override
+    background = Color.White,
+    surface = Color.White,
+    onPrimary = Color.White,
+    onSecondary = Color.Black,
+    onBackground = Color.Black,
+    onSurface = Color.Black,
+    */
+)
+
+@Composable
+fun SamplesTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
+    val colors = if (darkTheme) {
+        DarkColorPalette
+    } else {
+        LightColorPalette
+    }
+
+    MaterialTheme(
+        colors = colors,
+        typography = Typography,
+        shapes = Shapes,
+        content = content
+    )
+}
diff --git a/samples/minimaloboe/src/main/java/com/example/minimaloboe/ui/theme/Type.kt b/samples/minimaloboe/src/main/java/com/example/minimaloboe/ui/theme/Type.kt
new file mode 100644
index 0000000..b391730
--- /dev/null
+++ b/samples/minimaloboe/src/main/java/com/example/minimaloboe/ui/theme/Type.kt
@@ -0,0 +1,21 @@
+package com.example.minimaloboe.ui.theme
+
+import androidx.compose.material.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+
+// Set of Material typography styles to start with
+val Typography = Typography(
+    body1 = TextStyle(
+        fontFamily = FontFamily.Default,
+        fontWeight = FontWeight.Normal,
+        fontSize = 24.sp
+    ),
+    button = TextStyle(
+        fontFamily = FontFamily.Default,
+        fontWeight = FontWeight.W500,
+        fontSize = 20.sp
+    )
+)
diff --git a/samples/minimaloboe/src/main/res/drawable-v24/ic_launcher_foreground.xml b/samples/minimaloboe/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+        <aapt:attr name="android:fillColor">
+            <gradient
+                android:endX="85.84757"
+                android:endY="92.4963"
+                android:startX="42.9492"
+                android:startY="49.59793"
+                android:type="linear">
+                <item
+                    android:color="#44000000"
+                    android:offset="0.0" />
+                <item
+                    android:color="#00000000"
+                    android:offset="1.0" />
+            </gradient>
+        </aapt:attr>
+    </path>
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillType="nonZero"
+        android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+        android:strokeWidth="1"
+        android:strokeColor="#00000000" />
+</vector>
\ No newline at end of file
diff --git a/samples/minimaloboe/src/main/res/drawable/ic_launcher_background.xml b/samples/minimaloboe/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillColor="#3DDC84"
+        android:pathData="M0,0h108v108h-108z" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M9,0L9,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,0L19,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,0L29,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,0L39,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,0L49,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,0L59,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,0L69,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,0L79,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M89,0L89,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M99,0L99,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,9L108,9"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,19L108,19"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,29L108,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,39L108,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,49L108,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,59L108,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,69L108,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,79L108,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,89L108,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,99L108,99"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,29L89,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,39L89,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,49L89,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,59L89,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,69L89,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,79L89,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,19L29,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,19L39,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,19L49,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,19L59,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,19L69,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,19L79,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/samples/minimaloboe/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/samples/minimaloboe/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/samples/minimaloboe/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/samples/minimaloboe/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/samples/minimaloboe/src/main/res/mipmap-hdpi/ic_launcher.webp b/samples/minimaloboe/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/mipmap-hdpi/ic_launcher.webp
Binary files differ
diff --git a/samples/minimaloboe/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/samples/minimaloboe/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Binary files differ
diff --git a/samples/minimaloboe/src/main/res/mipmap-mdpi/ic_launcher.webp b/samples/minimaloboe/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/mipmap-mdpi/ic_launcher.webp
Binary files differ
diff --git a/samples/minimaloboe/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/samples/minimaloboe/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Binary files differ
diff --git a/samples/minimaloboe/src/main/res/mipmap-xhdpi/ic_launcher.webp b/samples/minimaloboe/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/mipmap-xhdpi/ic_launcher.webp
Binary files differ
diff --git a/samples/minimaloboe/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/samples/minimaloboe/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/samples/minimaloboe/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/samples/minimaloboe/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/mipmap-xxhdpi/ic_launcher.webp
Binary files differ
diff --git a/samples/minimaloboe/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/samples/minimaloboe/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/samples/minimaloboe/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/samples/minimaloboe/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Binary files differ
diff --git a/samples/minimaloboe/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/samples/minimaloboe/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/samples/minimaloboe/src/main/res/values/colors.xml b/samples/minimaloboe/src/main/res/values/colors.xml
new file mode 100644
index 0000000..ca1931b
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="purple_200">#FFBB86FC</color>
+    <color name="purple_500">#FF6200EE</color>
+    <color name="purple_700">#FF3700B3</color>
+    <color name="teal_200">#FF03DAC5</color>
+    <color name="teal_700">#FF018786</color>
+    <color name="black">#FF000000</color>
+    <color name="white">#FFFFFFFF</color>
+</resources>
diff --git a/samples/minimaloboe/src/main/res/values/strings.xml b/samples/minimaloboe/src/main/res/values/strings.xml
new file mode 100644
index 0000000..ebfbbf5
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">MinimalOboe</string>
+</resources>
diff --git a/samples/minimaloboe/src/main/res/values/themes.xml b/samples/minimaloboe/src/main/res/values/themes.xml
new file mode 100644
index 0000000..0cbbe65
--- /dev/null
+++ b/samples/minimaloboe/src/main/res/values/themes.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <style name="Theme.Samples" parent="android:Theme.Material.Light.NoActionBar">
+        <item name="android:statusBarColor">@color/purple_700</item>
+    </style>
+</resources>
diff --git a/samples/parselib/build.gradle b/samples/parselib/build.gradle
index beaf792..58b2190 100644
--- a/samples/parselib/build.gradle
+++ b/samples/parselib/build.gradle
@@ -1,15 +1,11 @@
 apply plugin: 'com.android.library'
 
 android {
-    compileSdkVersion 29
-    buildToolsVersion "29.0.1"
-
+    compileSdkVersion 33
 
     defaultConfig {
-        minSdkVersion 16
-        targetSdkVersion 29
-        versionCode 1
-        versionName "1.0"
+        minSdkVersion 21
+        targetSdkVersion 33
 
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
diff --git a/samples/parselib/src/main/cpp/wav/WavStreamReader.cpp b/samples/parselib/src/main/cpp/wav/WavStreamReader.cpp
index 98927b5..968c8a9 100644
--- a/samples/parselib/src/main/cpp/wav/WavStreamReader.cpp
+++ b/samples/parselib/src/main/cpp/wav/WavStreamReader.cpp
@@ -28,18 +28,18 @@
 

 static const char *TAG = "WavStreamReader";

 

+static constexpr int kConversionBufferFrames = 16;

+

 namespace parselib {

 

 WavStreamReader::WavStreamReader(InputStream *stream) {

     mStream = stream;

 

-    mWavChunk = 0;

-    mFmtChunk = 0;

-    mDataChunk = 0;

+    mWavChunk = nullptr;

+    mFmtChunk = nullptr;

+    mDataChunk = nullptr;

 

     mAudioDataStartPos = -1;

-

-    mChunkMap = new std::map<RiffID, WavChunkHeader *>();

 }

 

 int WavStreamReader::getSampleEncoding() {

@@ -78,26 +78,26 @@
 //        __android_log_print(ANDROID_LOG_INFO, TAG, "[%c%c%c%c]",

 //                            tagStr[0], tagStr[1], tagStr[2], tagStr[3]);

 

-        WavChunkHeader *chunk = 0;

+        std::shared_ptr<WavChunkHeader> chunk = nullptr;

         if (tag == WavRIFFChunkHeader::RIFFID_RIFF) {

-            chunk = mWavChunk = new WavRIFFChunkHeader(tag);

+            chunk = mWavChunk = std::make_shared<WavRIFFChunkHeader>(WavRIFFChunkHeader(tag));

             mWavChunk->read(mStream);

         } else if (tag == WavFmtChunkHeader::RIFFID_FMT) {

-            chunk = mFmtChunk = new WavFmtChunkHeader(tag);

+            chunk = mFmtChunk = std::make_shared<WavFmtChunkHeader>(WavFmtChunkHeader(tag));

             mFmtChunk->read(mStream);

         } else if (tag == WavChunkHeader::RIFFID_DATA) {

-            chunk = mDataChunk = new WavChunkHeader(tag);

+            chunk = mDataChunk = std::make_shared<WavChunkHeader>(WavChunkHeader(tag));

             mDataChunk->read(mStream);

             // We are now positioned at the start of the audio data.

             mAudioDataStartPos = mStream->getPos();

             mStream->advance(mDataChunk->mChunkSize);

         } else {

-            chunk = new WavChunkHeader(tag);

+            chunk = std::make_shared<WavChunkHeader>(WavChunkHeader(tag));

             chunk->read(mStream);

             mStream->advance(chunk->mChunkSize); // skip the body

         }

 

-        (*mChunkMap)[tag] = chunk;

+        mChunkMap[tag] = chunk;

     }

 

     if (mDataChunk != 0) {

@@ -112,48 +112,206 @@
     }

 }

 

+/**

+ * Read and convert samples in PCM8 format to float

+ */

+int WavStreamReader::getDataFloat_PCM8(float *buff, int numFrames) {

+    int numChannels = mFmtChunk->mNumChannels;

+

+    int buffOffset = 0;

+    int totalFramesRead = 0;

+

+    static constexpr int kSampleSize = sizeof(u_int8_t);

+    static constexpr float kSampleFullScale = (float)0x80;

+    static constexpr float kInverseScale = 1.0f / kSampleFullScale;

+

+    u_int8_t readBuff[kConversionBufferFrames * numChannels];

+    int framesLeft = numFrames;

+    while (framesLeft > 0) {

+        int framesThisRead = std::min(framesLeft, kConversionBufferFrames);

+        //__android_log_print(ANDROID_LOG_INFO, TAG, "read(%d)", framesThisRead);

+        int numFramesRead =

+                mStream->read(readBuff, framesThisRead *  kSampleSize * numChannels) /

+                (kSampleSize * numChannels);

+        totalFramesRead += numFramesRead;

+

+        // Convert & Scale

+        for (int offset = 0; offset < numFramesRead * numChannels; offset++) {

+            // PCM8 is unsigned, so we need to make it signed before scaling/converting

+            buff[buffOffset++] = ((float) readBuff[offset] - kSampleFullScale)

+                    * kInverseScale;

+        }

+

+        if (numFramesRead < framesThisRead) {

+            break; // none left

+        }

+

+        framesLeft -= framesThisRead;

+    }

+

+    return totalFramesRead;

+}

+

+/**

+ * Read and convert samples in PCM16 format to float

+ */

+int WavStreamReader::getDataFloat_PCM16(float *buff, int numFrames) {

+    int numChannels = mFmtChunk->mNumChannels;

+

+    int buffOffset = 0;

+    int totalFramesRead = 0;

+

+    static constexpr int kSampleSize = sizeof(int16_t);

+    static constexpr float kSampleFullScale = (float) 0x8000;

+    static constexpr float kInverseScale = 1.0f / kSampleFullScale;

+

+    int16_t readBuff[kConversionBufferFrames * numChannels];

+    int framesLeft = numFrames;

+    while (framesLeft > 0) {

+        int framesThisRead = std::min(framesLeft, kConversionBufferFrames);

+        //__android_log_print(ANDROID_LOG_INFO, TAG, "read(%d)", framesThisRead);

+        int numFramesRead =

+                mStream->read(readBuff, framesThisRead * kSampleSize * numChannels) /

+                (kSampleSize * numChannels);

+        totalFramesRead += numFramesRead;

+

+        // Convert & Scale

+        for (int offset = 0; offset < numFramesRead * numChannels; offset++) {

+            buff[buffOffset++] = (float) readBuff[offset] * kInverseScale;

+        }

+

+        if (numFramesRead < framesThisRead) {

+            break; // none left

+        }

+

+        framesLeft -= framesThisRead;

+    }

+

+    return totalFramesRead;

+}

+

+/**

+ * Read and convert samples in PCM24 format to float

+ */

+int WavStreamReader::getDataFloat_PCM24(float *buff, int numFrames) {

+    int numChannels = mFmtChunk->mNumChannels;

+    int numSamples = numFrames * numChannels;

+

+    static constexpr float kSampleFullScale = (float) 0x80000000;

+    static constexpr float kInverseScale = 1.0f / kSampleFullScale;

+

+    uint8_t buffer[3];

+    for(int sampleIndex = 0; sampleIndex < numSamples; sampleIndex++) {

+        if (mStream->read(buffer, 3) < 3) {

+            break; // no more data

+        }

+        int32_t sample = (buffer[0] << 8) | (buffer[1] << 16) | (buffer[2] << 24);

+        buff[sampleIndex] = (float)sample * kInverseScale;

+    }

+

+    return numFrames;

+}

+

+/**

+ * Read and convert samples in Float32 format to float

+ */

+int WavStreamReader::getDataFloat_Float32(float *buff, int numFrames) {

+    // Turns out that WAV Float32 is just Android floats

+    int numChannels = mFmtChunk->mNumChannels;

+

+    return mStream->read(buff, numFrames * sizeof(float) * numChannels) /

+           (sizeof(float) * numChannels);

+}

+

+/**

+ * Read and convert samples in PCM32 format to float

+ */

+int WavStreamReader::getDataFloat_PCM32(float *buff, int numFrames) {

+    int numChannels = mFmtChunk->mNumChannels;

+

+    int buffOffset = 0;

+    int totalFramesRead = 0;

+

+    static constexpr int kSampleSize = sizeof(int32_t);

+    static constexpr float kSampleFullScale = (float) 0x80000000;

+    static constexpr float kInverseScale = 1.0f / kSampleFullScale;

+

+    int32_t readBuff[kConversionBufferFrames * numChannels];

+    int framesLeft = numFrames;

+    while (framesLeft > 0) {

+        int framesThisRead = std::min(framesLeft, kConversionBufferFrames);

+        //__android_log_print(ANDROID_LOG_INFO, TAG, "read(%d)", framesThisRead);

+        int numFramesRead =

+                mStream->read(readBuff, framesThisRead *  kSampleSize* numChannels) /

+                    (kSampleSize * numChannels);

+        totalFramesRead += numFramesRead;

+

+        // convert & Scale

+        for (int offset = 0; offset < numFramesRead * numChannels; offset++) {

+            buff[buffOffset++] = (float) readBuff[offset] * kInverseScale;

+        }

+

+        if (numFramesRead < framesThisRead) {

+            break; // none left

+        }

+

+        framesLeft -= framesThisRead;

+    }

+

+    return totalFramesRead;

+}

+

 int WavStreamReader::getDataFloat(float *buff, int numFrames) {

     // __android_log_print(ANDROID_LOG_INFO, TAG, "getData(%d)", numFrames);

 

-    if (mDataChunk == 0 || mFmtChunk == 0) {

-        return 0;

+    if (mDataChunk == nullptr || mFmtChunk == nullptr) {

+        return ERR_INVALID_STATE;

     }

 

-    int totalFramesRead = 0;

+    int numFramesRead = 0;

+    switch (mFmtChunk->mSampleSize) {

+        case 8:

+            numFramesRead = getDataFloat_PCM8(buff, numFrames);

+            break;

 

-    int numChans = mFmtChunk->mNumChannels;

-    int buffOffset = 0;

+        case 16:

+            numFramesRead = getDataFloat_PCM16(buff, numFrames);

+            break;

 

-    // TODO - Manage other input formats

-    if (mFmtChunk->mSampleSize == 16) {

-        short *readBuff = new short[128 * numChans];

-        int framesLeft = numFrames;

-        while (framesLeft > 0) {

-            int framesThisRead = std::min(framesLeft, 128);

-            //__android_log_print(ANDROID_LOG_INFO, TAG, "read(%d)", framesThisRead);

-            int numFramesRead =

-                    mStream->read(readBuff, framesThisRead * sizeof(short) * numChans) /

-                    (sizeof(short) * numChans);

-            totalFramesRead += numFramesRead;

-

-            // convert

-            for (int offset = 0; offset < numFramesRead * numChans; offset++) {

-                buff[buffOffset++] = (float) readBuff[offset] / (float) 0x7FFF;

+        case 24:

+            if (mFmtChunk->mEncodingId == WavFmtChunkHeader::ENCODING_PCM) {

+                numFramesRead = getDataFloat_PCM24(buff, numFrames);

+            } else {

+                __android_log_print(ANDROID_LOG_INFO, TAG, "invalid encoding:%d mSampleSize:%d",

+                                    mFmtChunk->mEncodingId, mFmtChunk->mSampleSize);

             }

+            break;

 

-            if (numFramesRead < framesThisRead) {

-                break; // none left

+        case 32:

+            if (mFmtChunk->mEncodingId == WavFmtChunkHeader::ENCODING_PCM) {

+                numFramesRead = getDataFloat_PCM32(buff, numFrames);

+            } else if (mFmtChunk->mEncodingId == WavFmtChunkHeader::ENCODING_IEEE_FLOAT) {

+                numFramesRead = getDataFloat_Float32(buff, numFrames);

+            } else {

+                __android_log_print(ANDROID_LOG_INFO, TAG, "invalid encoding:%d mSampleSize:%d",

+                                    mFmtChunk->mEncodingId, mFmtChunk->mSampleSize);

             }

+            break;

 

-            framesLeft -= framesThisRead;

-        }

-        delete[] readBuff;

-

-        // __android_log_print(ANDROID_LOG_INFO, TAG, "  returns:%d", totalFramesRead);

-        return totalFramesRead;

+        default:

+            __android_log_print(ANDROID_LOG_INFO, TAG, "invalid encoding:%d mSampleSize:%d",

+                    mFmtChunk->mEncodingId, mFmtChunk->mSampleSize);

+            return ERR_INVALID_FORMAT;

     }

 

-    return 0;

+    // Zero out any unread frames

+    if (numFramesRead < numFrames) {

+        int numChannels = getNumChannels();

+        memset(buff + (numFramesRead * numChannels), 0,

+                (numFrames - numFramesRead) * sizeof(buff[0]) * numChannels);

+    }

+

+    return numFramesRead;

 }

 

 } // namespace parselib

diff --git a/samples/parselib/src/main/cpp/wav/WavStreamReader.h b/samples/parselib/src/main/cpp/wav/WavStreamReader.h
index 9a0ab98..1f7ee12 100644
--- a/samples/parselib/src/main/cpp/wav/WavStreamReader.h
+++ b/samples/parselib/src/main/cpp/wav/WavStreamReader.h
@@ -52,6 +52,9 @@
     // Data access

     void positionToAudio();

 

+    static constexpr int ERR_INVALID_FORMAT    = -1;

+    static constexpr int ERR_INVALID_STATE    = -2;

+

     int getDataFloat(float *buff, int numFrames);

 

     // int getData16(short *buff, int numFramees);

@@ -59,13 +62,26 @@
 protected:

     InputStream *mStream;

 

-    WavRIFFChunkHeader *mWavChunk;

-    WavFmtChunkHeader *mFmtChunk;

-    WavChunkHeader *mDataChunk;

+    std::shared_ptr<WavRIFFChunkHeader> mWavChunk;

+    std::shared_ptr<WavFmtChunkHeader> mFmtChunk;

+    std::shared_ptr<WavChunkHeader> mDataChunk;

 

     long mAudioDataStartPos;

 

-    std::map<RiffID, WavChunkHeader *> *mChunkMap;

+    std::map<RiffID, std::shared_ptr<WavChunkHeader>> mChunkMap;

+

+private:

+    /*

+     * Individual Format Readers/Converters

+     */

+    int getDataFloat_PCM8(float *buff, int numFrames);

+

+    int getDataFloat_PCM16(float *buff, int numFrames);

+

+    int getDataFloat_PCM24(float *buff, int numFrames);

+

+    int getDataFloat_Float32(float *buff, int numFrames);

+    int getDataFloat_PCM32(float *buff, int numFrames);

 };

 

 } // namespace parselib

diff --git a/samples/settings.gradle b/samples/settings.gradle
index 21b8f54..ddec58e 100644
--- a/samples/settings.gradle
+++ b/samples/settings.gradle
@@ -20,6 +20,8 @@
 include ':RhythmGame'
 include ':MegaDrone'
 include ':LiveEffect'
+include ':SoundBoard'
 include ':drumthumper'
 include ':parselib'
 include ':iolib'
+include ':minimaloboe'
diff --git a/samples/shared/DefaultDataCallback.h b/samples/shared/DefaultDataCallback.h
index e7f858e..212d976 100644
--- a/samples/shared/DefaultDataCallback.h
+++ b/samples/shared/DefaultDataCallback.h
@@ -17,7 +17,6 @@
 #ifndef SAMPLES_DEFAULT_DATA_CALLBACK_H
 #define SAMPLES_DEFAULT_DATA_CALLBACK_H
 
-
 #include <vector>
 #include <oboe/AudioStreamCallback.h>
 #include <logging_macros.h>
diff --git a/samples/shared/Mixer.h b/samples/shared/Mixer.h
index 56926d8..c91766e 100644
--- a/samples/shared/Mixer.h
+++ b/samples/shared/Mixer.h
@@ -52,6 +52,13 @@
 
     void setChannelCount(int32_t channelCount){ mChannelCount = channelCount; }
 
+    void removeAllTracks(){
+        for (int i = 0; i < mNextFreeTrackIndex; i++){
+            mTracks[i] = nullptr;
+        }
+        mNextFreeTrackIndex = 0;
+    }
+
 private:
     float mixingBuffer[kBufferSize];
     std::array<IRenderableAudio*, kMaxTracks> mTracks;
diff --git a/samples/shared/Oscillator.h b/samples/shared/Oscillator.h
index 4847274..75281b1 100644
--- a/samples/shared/Oscillator.h
+++ b/samples/shared/Oscillator.h
@@ -61,7 +61,7 @@
             for (int i = 0; i < numFrames; ++i) {
 
                 // Sine wave (sinf)
-                //data[i*kChannelCount] = sinf(mPhase) * mAmplitude;
+                //audioData[i] = sinf(mPhase) * mAmplitude;
 
                 // Square wave
                 if (mPhase <= kPi){
diff --git a/samples/shared/SynthSound.h b/samples/shared/SynthSound.h
new file mode 100644
index 0000000..43fc551
--- /dev/null
+++ b/samples/shared/SynthSound.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2018 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 SHARED_SYNTH_SOUND_H
+#define SHARED_SYNTH_SOUND_H
+#include <cstdint>
+#include <atomic>
+#include <math.h>
+#include <memory>
+#include "IRenderableAudio.h"
+constexpr float kDefaultFrequency = 440.0;
+constexpr int32_t kDefaultSampleRate = 48000;
+constexpr float kPi = M_PI;
+constexpr float kTwoPi = kPi * 2;
+constexpr int32_t kNumSineWaves = 5;
+constexpr float kSustainMultiplier = 0.99999;
+constexpr float kReleaseMultiplier = 0.999;
+// Stop playing music below this cutoff
+constexpr float kMasterAmplitudeCutOff = 0.01;
+
+class SynthSound : public IRenderableAudio {
+
+public:
+    SynthSound() {
+
+    }
+
+    ~SynthSound() {
+
+    };
+
+    void noteOn() {
+        mTrigger = true; // start a note envelope
+        mAmplitudeScaler = kSustainMultiplier;
+    }
+
+    void noteOff() {
+        mAmplitudeScaler = kReleaseMultiplier;
+    }
+
+    void setSampleRate(int32_t sampleRate) {
+        mSampleRate = sampleRate;
+        updatePhaseIncrement();
+    };
+    void setFrequency(float frequency) {
+        mFrequency = frequency;
+        updatePhaseIncrement();
+    };
+    // Amplitudes from https://epubs.siam.org/doi/pdf/10.1137/S00361445003822
+    inline void setAmplitude(float amplitude) {
+        mAmplitudes[0] = amplitude * .2f;
+        mAmplitudes[1] = amplitude;
+        mAmplitudes[2] = amplitude * .1f;
+        mAmplitudes[3] = amplitude * .02f;
+        mAmplitudes[4] = amplitude * .15f;
+    };
+    // From IRenderableAudio
+    void renderAudio(float *audioData, int32_t numFrames) override {
+        for (int i = 0; i < numFrames; ++i) {
+            if (mTrigger.exchange(false)) {
+                mMasterAmplitude = 1.0;
+                mPhase = 0.0f;
+            } else {
+                mMasterAmplitude *= mAmplitudeScaler;
+            }
+
+            audioData[i] = 0;
+            if (mMasterAmplitude < kMasterAmplitudeCutOff) {
+                continue;
+            }
+            for (int j = 0; j < kNumSineWaves; ++j) {
+                audioData[i] += sinf(mPhase * (j + 1)) * mAmplitudes[j] * mMasterAmplitude;
+            }
+            mPhase += mPhaseIncrement;
+            if (mPhase > kTwoPi) {
+                mPhase -=  kTwoPi;
+            }
+        }
+    };
+
+private:
+    std::atomic<bool> mTrigger;
+    float mMasterAmplitude = 0.0f;
+    std::atomic<float> mAmplitudeScaler;
+    std::array<std::atomic<float>, kNumSineWaves> mAmplitudes;
+    float mPhase = 0.0f;
+    std::atomic<float> mPhaseIncrement;
+    std::atomic<float> mFrequency { kDefaultFrequency };
+    std::atomic<int32_t> mSampleRate { kDefaultSampleRate };
+    void updatePhaseIncrement(){
+        // Note how there is a division here. If this file is changed so that updatePhaseIncrement
+        // is called more frequently, please cache 1/mSampleRate. This allows this operation to not
+        // need divisions.
+        mPhaseIncrement = kTwoPi * mFrequency / static_cast<float>(mSampleRate);
+    };
+};
+#endif //SHARED_SYNTH_SOUND_H
diff --git a/samples/shared/TappableAudioSource.h b/samples/shared/TappableAudioSource.h
index fde3917..27cbf10 100644
--- a/samples/shared/TappableAudioSource.h
+++ b/samples/shared/TappableAudioSource.h
@@ -35,4 +35,4 @@
     int32_t mChannelCount;
 };
 
-#endif //SAMPLES_RENDERABLE_TAP_H
\ No newline at end of file
+#endif //SAMPLES_RENDERABLE_TAP_H
diff --git a/src/aaudio/AAudioExtensions.h b/src/aaudio/AAudioExtensions.h
index 51a37ae..b3653c0 100644
--- a/src/aaudio/AAudioExtensions.h
+++ b/src/aaudio/AAudioExtensions.h
@@ -129,9 +129,16 @@
             return 0;
         }
 
+        AAudioLoader *libLoader = AAudioLoader::getInstance();
+        int openResult = libLoader->open();
+        if (openResult != 0) {
+            LOGD("%s() could not open " LIB_AAUDIO_NAME, __func__);
+            return AAUDIO_ERROR_UNAVAILABLE;
+        }
+
         void *libHandle = AAudioLoader::getInstance()->getLibHandle();
         if (libHandle == nullptr) {
-            LOGI("%s() could not find " LIB_AAUDIO_NAME, __func__);
+            LOGE("%s() could not find " LIB_AAUDIO_NAME, __func__);
             return AAUDIO_ERROR_UNAVAILABLE;
         }
 
diff --git a/src/aaudio/AAudioLoader.cpp b/src/aaudio/AAudioLoader.cpp
index ec97a26..82595fd 100644
--- a/src/aaudio/AAudioLoader.cpp
+++ b/src/aaudio/AAudioLoader.cpp
@@ -83,6 +83,15 @@
         builder_setSessionId   = load_V_PBI("AAudioStreamBuilder_setSessionId");
     }
 
+    if (getSdkVersion() >= __ANDROID_API_S__){
+        builder_setPackageName       = load_V_PBCPH("AAudioStreamBuilder_setPackageName");
+        builder_setAttributionTag    = load_V_PBCPH("AAudioStreamBuilder_setAttributionTag");
+    }
+
+    if (getSdkVersion() >= __ANDROID_API_S_V2__) {
+        builder_setChannelMask = load_V_PBU("AAudioStreamBuilder_setChannelMask");
+    }
+
     builder_delete             = load_I_PB("AAudioStreamBuilder_delete");
 
 
@@ -133,6 +142,10 @@
         stream_getInputPreset  = load_I_PS("AAudioStream_getInputPreset");
         stream_getSessionId    = load_I_PS("AAudioStream_getSessionId");
     }
+
+    if (getSdkVersion() >= __ANDROID_API_S_V2__) {
+        stream_getChannelMask = load_U_PS("AAudioStream_getChannelMask");
+    }
     return 0;
 }
 
@@ -160,6 +173,12 @@
     return reinterpret_cast<signature_V_PBI>(proc);
 }
 
+AAudioLoader::signature_V_PBCPH AAudioLoader::load_V_PBCPH(const char *functionName) {
+    void *proc = dlsym(mLibHandle, functionName);
+    AAudioLoader_check(proc, functionName);
+    return reinterpret_cast<signature_V_PBCPH>(proc);
+}
+
 AAudioLoader::signature_V_PBPDPV AAudioLoader::load_V_PBPDPV(const char *functionName) {
     void *proc = dlsym(mLibHandle, functionName);
     AAudioLoader_check(proc, functionName);
@@ -238,10 +257,26 @@
     return reinterpret_cast<signature_I_PSKPLPL>(proc);
 }
 
+AAudioLoader::signature_V_PBU AAudioLoader::load_V_PBU(const char *functionName) {
+    void *proc = dlsym(mLibHandle, functionName);
+    AAudioLoader_check(proc, functionName);
+    return reinterpret_cast<signature_V_PBU>(proc);
+}
+
+AAudioLoader::signature_U_PS AAudioLoader::load_U_PS(const char *functionName) {
+    void *proc = dlsym(mLibHandle, functionName);
+    AAudioLoader_check(proc, functionName);
+    return reinterpret_cast<signature_U_PS>(proc);
+}
+
 // Ensure that all AAudio primitive data types are int32_t
 #define ASSERT_INT32(type) static_assert(std::is_same<int32_t, type>::value, \
 #type" must be int32_t")
 
+// Ensure that all AAudio primitive data types are uint32_t
+#define ASSERT_UINT32(type) static_assert(std::is_same<uint32_t, type>::value, \
+#type" must be uint32_t")
+
 #define ERRMSG "Oboe constants must match AAudio constants."
 
 // These asserts help verify that the Oboe definitions match the equivalent AAudio definitions.
@@ -350,6 +385,66 @@
 
 #endif // __NDK_MAJOR__ >= 17
 
+// The aaudio channel masks were added in NDK 24,
+// which is the first version to support Android SC_V2 (API 32).
+#if __NDK_MAJOR__ >= 24
+
+    ASSERT_UINT32(aaudio_channel_mask_t);
+
+    static_assert((uint32_t)ChannelMask::FrontLeft == AAUDIO_CHANNEL_FRONT_LEFT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::FrontRight == AAUDIO_CHANNEL_FRONT_RIGHT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::FrontCenter == AAUDIO_CHANNEL_FRONT_CENTER, ERRMSG);
+    static_assert((uint32_t)ChannelMask::LowFrequency == AAUDIO_CHANNEL_LOW_FREQUENCY, ERRMSG);
+    static_assert((uint32_t)ChannelMask::BackLeft == AAUDIO_CHANNEL_BACK_LEFT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::BackRight == AAUDIO_CHANNEL_BACK_RIGHT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::FrontLeftOfCenter == AAUDIO_CHANNEL_FRONT_LEFT_OF_CENTER, ERRMSG);
+    static_assert((uint32_t)ChannelMask::FrontRightOfCenter == AAUDIO_CHANNEL_FRONT_RIGHT_OF_CENTER, ERRMSG);
+    static_assert((uint32_t)ChannelMask::BackCenter == AAUDIO_CHANNEL_BACK_CENTER, ERRMSG);
+    static_assert((uint32_t)ChannelMask::SideLeft == AAUDIO_CHANNEL_SIDE_LEFT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::SideRight == AAUDIO_CHANNEL_SIDE_RIGHT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::TopCenter == AAUDIO_CHANNEL_TOP_CENTER, ERRMSG);
+    static_assert((uint32_t)ChannelMask::TopFrontLeft == AAUDIO_CHANNEL_TOP_FRONT_LEFT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::TopFrontCenter == AAUDIO_CHANNEL_TOP_FRONT_CENTER, ERRMSG);
+    static_assert((uint32_t)ChannelMask::TopFrontRight == AAUDIO_CHANNEL_TOP_FRONT_RIGHT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::TopBackLeft == AAUDIO_CHANNEL_TOP_BACK_LEFT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::TopBackCenter == AAUDIO_CHANNEL_TOP_BACK_CENTER, ERRMSG);
+    static_assert((uint32_t)ChannelMask::TopBackRight == AAUDIO_CHANNEL_TOP_BACK_RIGHT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::TopSideLeft == AAUDIO_CHANNEL_TOP_SIDE_LEFT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::TopSideRight == AAUDIO_CHANNEL_TOP_SIDE_RIGHT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::BottomFrontLeft == AAUDIO_CHANNEL_BOTTOM_FRONT_LEFT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::BottomFrontCenter == AAUDIO_CHANNEL_BOTTOM_FRONT_CENTER, ERRMSG);
+    static_assert((uint32_t)ChannelMask::BottomFrontRight == AAUDIO_CHANNEL_BOTTOM_FRONT_RIGHT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::LowFrequency2 == AAUDIO_CHANNEL_LOW_FREQUENCY_2, ERRMSG);
+    static_assert((uint32_t)ChannelMask::FrontWideLeft == AAUDIO_CHANNEL_FRONT_WIDE_LEFT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::FrontWideRight == AAUDIO_CHANNEL_FRONT_WIDE_RIGHT, ERRMSG);
+    static_assert((uint32_t)ChannelMask::Mono == AAUDIO_CHANNEL_MONO, ERRMSG);
+    static_assert((uint32_t)ChannelMask::Stereo == AAUDIO_CHANNEL_STEREO, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM2Point1 == AAUDIO_CHANNEL_2POINT1, ERRMSG);
+    static_assert((uint32_t)ChannelMask::Tri == AAUDIO_CHANNEL_TRI, ERRMSG);
+    static_assert((uint32_t)ChannelMask::TriBack == AAUDIO_CHANNEL_TRI_BACK, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM3Point1 == AAUDIO_CHANNEL_3POINT1, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM2Point0Point2 == AAUDIO_CHANNEL_2POINT0POINT2, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM2Point1Point2 == AAUDIO_CHANNEL_2POINT1POINT2, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM3Point0Point2 == AAUDIO_CHANNEL_3POINT0POINT2, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM3Point1Point2 == AAUDIO_CHANNEL_3POINT1POINT2, ERRMSG);
+    static_assert((uint32_t)ChannelMask::Quad == AAUDIO_CHANNEL_QUAD, ERRMSG);
+    static_assert((uint32_t)ChannelMask::QuadSide == AAUDIO_CHANNEL_QUAD_SIDE, ERRMSG);
+    static_assert((uint32_t)ChannelMask::Surround == AAUDIO_CHANNEL_SURROUND, ERRMSG);
+    static_assert((uint32_t)ChannelMask::Penta == AAUDIO_CHANNEL_PENTA, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM5Point1 == AAUDIO_CHANNEL_5POINT1, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM5Point1Side == AAUDIO_CHANNEL_5POINT1_SIDE, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM6Point1 == AAUDIO_CHANNEL_6POINT1, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM7Point1 == AAUDIO_CHANNEL_7POINT1, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM5Point1Point2 == AAUDIO_CHANNEL_5POINT1POINT2, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM5Point1Point4 == AAUDIO_CHANNEL_5POINT1POINT4, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM7Point1Point2 == AAUDIO_CHANNEL_7POINT1POINT2, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM7Point1Point4 == AAUDIO_CHANNEL_7POINT1POINT4, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM9Point1Point4 == AAUDIO_CHANNEL_9POINT1POINT4, ERRMSG);
+    static_assert((uint32_t)ChannelMask::CM9Point1Point6 == AAUDIO_CHANNEL_9POINT1POINT6, ERRMSG);
+    static_assert((uint32_t)ChannelMask::FrontBack == AAUDIO_CHANNEL_FRONT_BACK, ERRMSG);
+
+#endif
+
 #endif // AAUDIO_AAUDIO_H
 
 } // namespace oboe
diff --git a/src/aaudio/AAudioLoader.h b/src/aaudio/AAudioLoader.h
index faadd05..ea00a47 100644
--- a/src/aaudio/AAudioLoader.h
+++ b/src/aaudio/AAudioLoader.h
@@ -66,6 +66,19 @@
 #define __NDK_MAJOR__ 0
 #endif
 
+#if __NDK_MAJOR__ < 24
+// Defined in SC_V2
+typedef uint32_t aaudio_channel_mask_t;
+#endif
+
+#ifndef __ANDROID_API_S__
+#define __ANDROID_API_S__ 31
+#endif
+
+#ifndef __ANDROID_API_S_V2__
+#define __ANDROID_API_S_V2__ 32
+#endif
+
 namespace oboe {
 
 /**
@@ -86,6 +99,7 @@
     // P = Pointer to following data type
     // C = Const prefix
     // H = cHar
+    // U = uint32_t
     typedef int32_t  (*signature_I_PPB)(AAudioStreamBuilder **builder);
 
     typedef const char * (*signature_CPH_I)(int32_t);
@@ -97,6 +111,11 @@
     // AAudioStreamBuilder_setSampleRate()
     typedef void    (*signature_V_PBI)(AAudioStreamBuilder *, int32_t);
 
+    // AAudioStreamBuilder_setChannelMask()
+    typedef void    (*signature_V_PBU)(AAudioStreamBuilder *, uint32_t);
+
+    typedef void    (*signature_V_PBCPH)(AAudioStreamBuilder *, const char *);
+
     typedef int32_t (*signature_I_PS)(AAudioStream *);  // AAudioStream_getSampleRate()
     typedef int64_t (*signature_L_PS)(AAudioStream *);  // AAudioStream_getFramesRead()
     // AAudioStream_setBufferSizeInFrames()
@@ -124,6 +143,8 @@
 
     typedef bool    (*signature_B_PS)(AAudioStream *);
 
+    typedef uint32_t (*signature_U_PS)(AAudioStream *);
+
     static AAudioLoader* getInstance(); // singleton
 
     /**
@@ -153,12 +174,16 @@
     signature_V_PBI builder_setPerformanceMode = nullptr;
     signature_V_PBI builder_setSampleRate = nullptr;
     signature_V_PBI builder_setSharingMode = nullptr;
+    signature_V_PBU builder_setChannelMask = nullptr;
 
     signature_V_PBI builder_setUsage = nullptr;
     signature_V_PBI builder_setContentType = nullptr;
     signature_V_PBI builder_setInputPreset = nullptr;
     signature_V_PBI builder_setSessionId = nullptr;
 
+    signature_V_PBCPH builder_setPackageName = nullptr;
+    signature_V_PBCPH builder_setAttributionTag = nullptr;
+
     signature_V_PBPDPV  builder_setDataCallback = nullptr;
     signature_V_PBPEPV  builder_setErrorCallback = nullptr;
 
@@ -203,6 +228,8 @@
     signature_I_PS   stream_getInputPreset = nullptr;
     signature_I_PS   stream_getSessionId = nullptr;
 
+    signature_U_PS   stream_getChannelMask = nullptr;
+
   private:
     AAudioLoader() {}
     ~AAudioLoader();
@@ -211,6 +238,7 @@
     signature_I_PPB     load_I_PPB(const char *name);
     signature_CPH_I     load_CPH_I(const char *name);
     signature_V_PBI     load_V_PBI(const char *name);
+    signature_V_PBCPH   load_V_PBCPH(const char *name);
     signature_V_PBPDPV  load_V_PBPDPV(const char *name);
     signature_V_PBPEPV  load_V_PBPEPV(const char *name);
     signature_I_PB      load_I_PB(const char *name);
@@ -224,6 +252,8 @@
     signature_I_PSCPVIL load_I_PSCPVIL(const char *name);
     signature_I_PSTPTL  load_I_PSTPTL(const char *name);
     signature_I_PSKPLPL load_I_PSKPLPL(const char *name);
+    signature_V_PBU     load_V_PBU(const char *name);
+    signature_U_PS      load_U_PS(const char *name);
 
     void *mLibHandle = nullptr;
 };
diff --git a/src/aaudio/AudioStreamAAudio.cpp b/src/aaudio/AudioStreamAAudio.cpp
index bc535ae..abc8694 100644
--- a/src/aaudio/AudioStreamAAudio.cpp
+++ b/src/aaudio/AudioStreamAAudio.cpp
@@ -62,7 +62,7 @@
 // It calls app error callbacks from a static function in case the stream gets deleted.
 static void oboe_aaudio_error_thread_proc(AudioStreamAAudio *oboeStream,
                                           Result error) {
-    LOGD("%s() - entering >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", __func__);
+    LOGD("%s(,%d) - entering >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", __func__, error);
     AudioStreamErrorCallback *errorCallback = oboeStream->getErrorCallback();
     if (errorCallback == nullptr) return; // should be impossible
     bool isErrorHandled = errorCallback->onError(oboeStream, error);
@@ -205,7 +205,18 @@
     }
     mLibLoader->builder_setBufferCapacityInFrames(aaudioBuilder, capacity);
 
-    mLibLoader->builder_setChannelCount(aaudioBuilder, mChannelCount);
+    // Channel mask was added in SC_V2. Given the corresponding channel count of selected channel
+    // mask may be different from selected channel count, the last set value will be respected.
+    // If channel count is set after channel mask, the previously set channel mask will be cleared.
+    // If channel mask is set after channel count, the channel count will be automatically
+    // calculated from selected channel mask. In that case, only set channel mask when the API
+    // is available and the channel mask is specified.
+    if (mLibLoader->builder_setChannelMask != nullptr && mChannelMask != ChannelMask::Unspecified) {
+        mLibLoader->builder_setChannelMask(aaudioBuilder,
+                                           static_cast<aaudio_channel_mask_t>(mChannelMask));
+    } else {
+        mLibLoader->builder_setChannelCount(aaudioBuilder, mChannelCount);
+    }
     mLibLoader->builder_setDeviceId(aaudioBuilder, mDeviceId);
     mLibLoader->builder_setDirection(aaudioBuilder, static_cast<aaudio_direction_t>(mDirection));
     mLibLoader->builder_setFormat(aaudioBuilder, static_cast<aaudio_format_t>(mFormat));
@@ -241,7 +252,16 @@
                                          static_cast<aaudio_session_id_t>(mSessionId));
     }
 
-    // TODO get more parameters from the builder?
+    // These were added in S so we have to check for the function pointer.
+    if (mLibLoader->builder_setPackageName != nullptr && !mPackageName.empty()) {
+        mLibLoader->builder_setPackageName(aaudioBuilder,
+                                           mPackageName.c_str());
+    }
+
+    if (mLibLoader->builder_setAttributionTag != nullptr && !mAttributionTag.empty()) {
+        mLibLoader->builder_setAttributionTag(aaudioBuilder,
+                                           mAttributionTag.c_str());
+    }
 
     if (isDataCallbackSpecified()) {
         mLibLoader->builder_setDataCallback(aaudioBuilder, oboe_aaudio_data_callback_proc, this);
@@ -282,6 +302,7 @@
             mLibLoader->stream_getPerformanceMode(mAAudioStream));
     mBufferCapacityInFrames = mLibLoader->stream_getBufferCapacity(mAAudioStream);
     mBufferSizeInFrames = mLibLoader->stream_getBufferSize(mAAudioStream);
+    mFramesPerBurst = mLibLoader->stream_getFramesPerBurst(mAAudioStream);
 
     // These were added in P so we have to check for the function pointer.
     if (mLibLoader->stream_getUsage != nullptr) {
@@ -299,10 +320,16 @@
         mSessionId = SessionId::None;
     }
 
+    if (mLibLoader->stream_getChannelMask != nullptr) {
+        mChannelMask = static_cast<ChannelMask>(mLibLoader->stream_getChannelMask(mAAudioStream));
+    }
+
     LOGD("AudioStreamAAudio.open() format=%d, sampleRate=%d, capacity = %d",
             static_cast<int>(mFormat), static_cast<int>(mSampleRate),
             static_cast<int>(mBufferCapacityInFrames));
 
+    calculateDefaultDelayBeforeCloseMillis();
+
 error2:
     mLibLoader->builder_delete(aaudioBuilder);
     LOGD("AudioStreamAAudio.open: AAudioStream_Open() returned %s",
@@ -318,19 +345,19 @@
 
     AudioStream::close();
 
-    // This will delete the AAudio stream object so we need to null out the pointer.
-    AAudioStream *stream = mAAudioStream.exchange(nullptr);
+    AAudioStream *stream = nullptr;
+    {
+        // Wait for any methods using mAAudioStream to finish.
+        std::unique_lock<std::shared_mutex> lock2(mAAudioStreamLock);
+        // Closing will delete *mAAudioStream so we need to null out the pointer atomically.
+        stream = mAAudioStream.exchange(nullptr);
+    }
     if (stream != nullptr) {
         if (OboeGlobals::areWorkaroundsEnabled()) {
             // Make sure we are really stopped. Do it under mLock
             // so another thread cannot call requestStart() right before the close.
             requestStop_l(stream);
-            // Sometimes a callback can occur shortly after a stream has been stopped and
-            // even after a close! If the stream has been closed then the callback
-            // can access memory that has been freed. That causes a crash.
-            // This seems to be more likely in Android P or earlier.
-            // But it can also occur in later versions.
-            usleep(kDelayBeforeCloseMillis * 1000);
+            sleepBeforeClose();
         }
         return static_cast<Result>(mLibLoader->stream_close(stream));
     } else {
@@ -338,7 +365,22 @@
     }
 }
 
-DataCallbackResult AudioStreamAAudio::callOnAudioReady(AAudioStream *stream,
+static void oboe_stop_thread_proc(AudioStream *oboeStream) {
+    if (oboeStream != nullptr) {
+        oboeStream->requestStop();
+    }
+}
+
+void AudioStreamAAudio::launchStopThread() {
+    // Prevent multiple stop threads from being launched.
+    if (mStopThreadAllowed.exchange(false)) {
+        // Stop this stream on a separate thread
+        std::thread t(oboe_stop_thread_proc, this);
+        t.detach();
+    }
+}
+
+DataCallbackResult AudioStreamAAudio::callOnAudioReady(AAudioStream * /*stream*/,
                                                                  void *audioData,
                                                                  int32_t numFrames) {
     DataCallbackResult result = fireDataCallback(audioData, numFrames);
@@ -351,16 +393,12 @@
             LOGE("Oboe callback returned unexpected value = %d", result);
         }
 
-        if (getSdkVersion() <= __ANDROID_API_P__) {
+        // Returning Stop caused various problems before S. See #1230
+        if (OboeGlobals::areWorkaroundsEnabled() && getSdkVersion() <= __ANDROID_API_R__) {
             launchStopThread();
-            if (isMMapUsed()) {
-                return DataCallbackResult::Stop;
-            } else {
-                // Legacy stream <= API_P cannot be restarted after returning Stop.
-                return DataCallbackResult::Continue;
-            }
+            return DataCallbackResult::Continue;
         } else {
-            return DataCallbackResult::Stop; // OK >= API_Q
+            return DataCallbackResult::Stop; // OK >= API_S
         }
     }
 }
@@ -380,6 +418,7 @@
         if (isDataCallbackSpecified()) {
             setDataCallbackEnabled(true);
         }
+        mStopThreadAllowed = true;
         return static_cast<Result>(mLibLoader->stream_requestStart(stream));
     } else {
         return Result::ErrorClosed;
@@ -445,6 +484,7 @@
 ResultWithValue<int32_t>   AudioStreamAAudio::write(const void *buffer,
                                      int32_t numFrames,
                                      int64_t timeoutNanoseconds) {
+    std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
         int32_t result = mLibLoader->stream_write(mAAudioStream, buffer,
@@ -458,6 +498,7 @@
 ResultWithValue<int32_t>   AudioStreamAAudio::read(void *buffer,
                                  int32_t numFrames,
                                  int64_t timeoutNanoseconds) {
+    std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
         int32_t result = mLibLoader->stream_read(mAAudioStream, buffer,
@@ -541,29 +582,27 @@
 }
 
 ResultWithValue<int32_t> AudioStreamAAudio::setBufferSizeInFrames(int32_t requestedFrames) {
+    int32_t adjustedFrames = requestedFrames;
+    if (adjustedFrames > mBufferCapacityInFrames) {
+        adjustedFrames = mBufferCapacityInFrames;
+    }
+    // This calls getBufferSize() so avoid recursive lock.
+    adjustedFrames = QuirksManager::getInstance().clipBufferSize(*this, adjustedFrames);
 
+    std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
     AAudioStream *stream = mAAudioStream.load();
-
     if (stream != nullptr) {
-        int32_t adjustedFrames = requestedFrames;
-        if (adjustedFrames > mBufferCapacityInFrames) {
-            adjustedFrames = mBufferCapacityInFrames;
-        }
-        adjustedFrames = QuirksManager::getInstance().clipBufferSize(*this, adjustedFrames);
-
         int32_t newBufferSize = mLibLoader->stream_setBufferSize(mAAudioStream, adjustedFrames);
-
         // Cache the result if it's valid
         if (newBufferSize > 0) mBufferSizeInFrames = newBufferSize;
-
         return ResultWithValue<int32_t>::createBasedOnSign(newBufferSize);
-
     } else {
         return ResultWithValue<int32_t>(Result::ErrorClosed);
     }
 }
 
-StreamState AudioStreamAAudio::getState() const {
+StreamState AudioStreamAAudio::getState() {
+    std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
         aaudio_stream_state_t aaudioState = mLibLoader->stream_getState(stream);
@@ -580,6 +619,7 @@
 }
 
 int32_t AudioStreamAAudio::getBufferSizeInFrames() {
+    std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
         mBufferSizeInFrames = mLibLoader->stream_getBufferSize(stream);
@@ -587,29 +627,34 @@
     return mBufferSizeInFrames;
 }
 
-int32_t AudioStreamAAudio::getFramesPerBurst() {
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream != nullptr) {
-        mFramesPerBurst = mLibLoader->stream_getFramesPerBurst(stream);
-    }
-    return mFramesPerBurst;
-}
-
 void AudioStreamAAudio::updateFramesRead() {
+    std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
     AAudioStream *stream = mAAudioStream.load();
+// Set to 1 for debugging race condition #1180 with mAAudioStream.
+// See also DEBUG_CLOSE_RACE in OboeTester.
+// This was left in the code so that we could test the fix again easily in the future.
+// We could not trigger the race condition without adding these get calls and the sleeps.
+#define DEBUG_CLOSE_RACE 0
+#if DEBUG_CLOSE_RACE
+    // This is used when testing race conditions with close().
+    // See DEBUG_CLOSE_RACE in OboeTester
+    AudioClock::sleepForNanos(400 * kNanosPerMillisecond);
+#endif // DEBUG_CLOSE_RACE
     if (stream != nullptr) {
         mFramesRead = mLibLoader->stream_getFramesRead(stream);
     }
 }
 
 void AudioStreamAAudio::updateFramesWritten() {
+    std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
         mFramesWritten = mLibLoader->stream_getFramesWritten(stream);
     }
 }
 
-ResultWithValue<int32_t> AudioStreamAAudio::getXRunCount() const {
+ResultWithValue<int32_t> AudioStreamAAudio::getXRunCount() {
+    std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
         return ResultWithValue<int32_t>::createBasedOnSign(mLibLoader->stream_getXRunCount(stream));
@@ -621,11 +666,12 @@
 Result AudioStreamAAudio::getTimestamp(clockid_t clockId,
                                    int64_t *framePosition,
                                    int64_t *timeNanoseconds) {
+    if (getState() != StreamState::Started) {
+        return Result::ErrorInvalidState;
+    }
+    std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
-        if (getState() != StreamState::Started) {
-            return Result::ErrorInvalidState;
-        }
         return static_cast<Result>(mLibLoader->stream_getTimestamp(stream, clockId,
                                                framePosition, timeNanoseconds));
     } else {
@@ -634,11 +680,6 @@
 }
 
 ResultWithValue<double> AudioStreamAAudio::calculateLatencyMillis() {
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream == nullptr) {
-        return ResultWithValue<double>(Result::ErrorClosed);
-    }
-
     // Get the time that a known audio frame was presented.
     int64_t hardwareFrameIndex;
     int64_t hardwareFrameHardwareTime;
@@ -676,6 +717,7 @@
 }
 
 bool AudioStreamAAudio::isMMapUsed() {
+    std::shared_lock<std::shared_mutex> lock(mAAudioStreamLock);
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
         return AAudioExtensions::getInstance().isMMapUsed(stream);
diff --git a/src/aaudio/AudioStreamAAudio.h b/src/aaudio/AudioStreamAAudio.h
index 83f4b2f..9846423 100644
--- a/src/aaudio/AudioStreamAAudio.h
+++ b/src/aaudio/AudioStreamAAudio.h
@@ -18,6 +18,7 @@
 #define OBOE_STREAM_AAUDIO_H_
 
 #include <atomic>
+#include <shared_mutex>
 #include <mutex>
 #include <thread>
 
@@ -67,8 +68,7 @@
 
     ResultWithValue<int32_t> setBufferSizeInFrames(int32_t requestedFrames) override;
     int32_t getBufferSizeInFrames() override;
-    int32_t getFramesPerBurst() override;
-    ResultWithValue<int32_t> getXRunCount() const override;
+    ResultWithValue<int32_t> getXRunCount()  override;
     bool isXRunCountSupported() const override { return true; }
 
     ResultWithValue<double> calculateLatencyMillis() override;
@@ -81,7 +81,7 @@
                                        int64_t *framePosition,
                                        int64_t *timeNanoseconds) override;
 
-    StreamState getState() const override;
+    StreamState getState() override;
 
     AudioApi getAudioApi() const override {
         return AudioApi::AAudio;
@@ -91,7 +91,7 @@
                                                    void *audioData,
                                                    int32_t numFrames);
 
-    bool                 isMMapUsed();
+    bool isMMapUsed();
 
 protected:
     static void internalErrorCallback(
@@ -112,14 +112,24 @@
     // Must call under mLock. And stream must NOT be nullptr.
     Result requestStop_l(AAudioStream *stream);
 
-    // Time to sleep in order to prevent a race condition with a callback after a close().
-    // Two milliseconds may be enough but 10 msec is even safer.
-    static constexpr int kDelayBeforeCloseMillis = 10;
+    /**
+     * Launch a thread that will stop the stream.
+     */
+    void launchStopThread();
+
+public:
+    int32_t getMDelayBeforeCloseMillis() const;
+
+    void setDelayBeforeCloseMillis(int32_t mDelayBeforeCloseMillis);
+
+private:
 
     std::atomic<bool>    mCallbackThreadEnabled;
+    std::atomic<bool>    mStopThreadAllowed{false};
 
     // pointer to the underlying 'C' AAudio stream, valid if open, null if closed
     std::atomic<AAudioStream *> mAAudioStream{nullptr};
+    std::shared_mutex           mAAudioStreamLock; // to protect mAAudioStream while closing
 
     static AAudioLoader *mLibLoader;
 
diff --git a/src/common/AudioStream.cpp b/src/common/AudioStream.cpp
index 8a9cd45..7f9ed4d 100644
--- a/src/common/AudioStream.cpp
+++ b/src/common/AudioStream.cpp
@@ -55,7 +55,7 @@
 DataCallbackResult AudioStream::fireDataCallback(void *audioData, int32_t numFrames) {
     if (!isDataCallbackEnabled()) {
         LOGW("AudioStream::%s() called with data callback disabled!", __func__);
-        return DataCallbackResult::Stop; // We should not be getting called any more.
+        return DataCallbackResult::Stop; // Should not be getting called
     }
 
     DataCallbackResult result;
@@ -166,6 +166,14 @@
     if (numFrames == 0) return Result::OK;
     if (numFrames < 0) return Result::ErrorOutOfRange;
 
+    // Make sure we don't try to wait for more frames than the buffer can hold.
+    // Subtract framesPerBurst because this is often called from a callback
+    // and we don't want to be sleeping if the buffer is close to overflowing.
+    const int32_t maxAvailableFrames = getBufferCapacityInFrames() - getFramesPerBurst();
+    numFrames = std::min(numFrames, maxAvailableFrames);
+    // The capacity should never be less than one burst. But clip to zero just in case.
+    numFrames = std::max(0, numFrames);
+
     int64_t framesAvailable = 0;
     int64_t burstInNanos = getFramesPerBurst() * kNanosPerSecond / getSampleRate();
     bool ready = false;
@@ -196,16 +204,13 @@
     }
 }
 
-static void oboe_stop_thread_proc(AudioStream *oboeStream) {
-    if (oboeStream != nullptr) {
-        oboeStream->requestStop();
-    }
-}
-
-void AudioStream::launchStopThread() {
-    // Stop this stream on a separate thread
-    std::thread t(oboe_stop_thread_proc, this);
-    t.detach();
+void AudioStream::calculateDefaultDelayBeforeCloseMillis() {
+    // Calculate delay time before close based on burst duration.
+    // Start with a burst duration then add 1 msec as a safety margin.
+    mDelayBeforeCloseMillis = std::max(kMinDelayBeforeCloseMillis,
+                                       1 + ((mFramesPerBurst * 1000) / getSampleRate()));
+    LOGD("calculateDefaultDelayBeforeCloseMillis() default = %d",
+         static_cast<int>(mDelayBeforeCloseMillis));
 }
 
 } // namespace oboe
diff --git a/src/common/AudioStreamBuilder.cpp b/src/common/AudioStreamBuilder.cpp
index b9f04b8..5dbe38c 100644
--- a/src/common/AudioStreamBuilder.cpp
+++ b/src/common/AudioStreamBuilder.cpp
@@ -91,6 +91,7 @@
 Result AudioStreamBuilder::openStream(AudioStream **streamPP) {
     auto result = isValidConfig();
     if (result != Result::OK) {
+        LOGW("%s() invalid config %d", __func__, result);
         return result;
     }
 
@@ -202,24 +203,16 @@
 
 Result AudioStreamBuilder::openManagedStream(oboe::ManagedStream &stream) {
     stream.reset();
-    auto result = isValidConfig();
-    if (result != Result::OK) {
-        return result;
-    }
     AudioStream *streamptr;
-    result = openStream(&streamptr);
+    auto result = openStream(&streamptr);
     stream.reset(streamptr);
     return result;
 }
 
 Result AudioStreamBuilder::openStream(std::shared_ptr<AudioStream> &sharedStream) {
     sharedStream.reset();
-    auto result = isValidConfig();
-    if (result != Result::OK) {
-        return result;
-    }
     AudioStream *streamptr;
-    result = openStream(&streamptr);
+    auto result = openStream(&streamptr);
     if (result == Result::OK) {
         sharedStream.reset(streamptr);
         // Save a weak_ptr in the stream for use with callbacks.
diff --git a/src/common/DataConversionFlowGraph.cpp b/src/common/DataConversionFlowGraph.cpp
index 2829e6f..374fffd 100644
--- a/src/common/DataConversionFlowGraph.cpp
+++ b/src/common/DataConversionFlowGraph.cpp
@@ -20,17 +20,20 @@
 #include "DataConversionFlowGraph.h"
 #include "SourceFloatCaller.h"
 #include "SourceI16Caller.h"
+#include "SourceI24Caller.h"
+#include "SourceI32Caller.h"
 
-#include <flowgraph/ClipToRange.h>
 #include <flowgraph/MonoToMultiConverter.h>
 #include <flowgraph/MultiToMonoConverter.h>
 #include <flowgraph/RampLinear.h>
 #include <flowgraph/SinkFloat.h>
 #include <flowgraph/SinkI16.h>
 #include <flowgraph/SinkI24.h>
+#include <flowgraph/SinkI32.h>
 #include <flowgraph/SourceFloat.h>
 #include <flowgraph/SourceI16.h>
 #include <flowgraph/SourceI24.h>
+#include <flowgraph/SourceI32.h>
 #include <flowgraph/SampleRateConverter.h>
 
 using namespace oboe;
@@ -116,6 +119,14 @@
                 mSourceCaller = std::make_unique<SourceI16Caller>(sourceChannelCount,
                                                                   actualSourceFramesPerCallback);
                 break;
+            case AudioFormat::I24:
+                mSourceCaller = std::make_unique<SourceI24Caller>(sourceChannelCount,
+                                                                  actualSourceFramesPerCallback);
+                break;
+            case AudioFormat::I32:
+                mSourceCaller = std::make_unique<SourceI32Caller>(sourceChannelCount,
+                                                                  actualSourceFramesPerCallback);
+                break;
             default:
                 LOGE("%s() Unsupported source caller format = %d", __func__, sourceFormat);
                 return Result::ErrorIllegalArgument;
@@ -132,6 +143,12 @@
             case AudioFormat::I16:
                 mSource = std::make_unique<SourceI16>(sourceChannelCount);
                 break;
+            case AudioFormat::I24:
+                mSource = std::make_unique<SourceI24>(sourceChannelCount);
+                break;
+            case AudioFormat::I32:
+                mSource = std::make_unique<SourceI32>(sourceChannelCount);
+                break;
             default:
                 LOGE("%s() Unsupported source format = %d", __func__, sourceFormat);
                 return Result::ErrorIllegalArgument;
@@ -202,6 +219,12 @@
         case AudioFormat::I16:
             mSink = std::make_unique<SinkI16>(sinkChannelCount);
             break;
+        case AudioFormat::I24:
+            mSink = std::make_unique<SinkI24>(sinkChannelCount);
+            break;
+        case AudioFormat::I32:
+            mSink = std::make_unique<SinkI32>(sinkChannelCount);
+            break;
         default:
             LOGE("%s() Unsupported sink format = %d", __func__, sinkFormat);
             return Result::ErrorIllegalArgument;;
diff --git a/src/common/FilterAudioStream.cpp b/src/common/FilterAudioStream.cpp
index 975b03d..5d4e693 100644
--- a/src/common/FilterAudioStream.cpp
+++ b/src/common/FilterAudioStream.cpp
@@ -48,7 +48,7 @@
     AudioStream *sourceStream =  isOutput ? this : mChildStream.get();
     AudioStream *sinkStream =  isOutput ? mChildStream.get() : this;
 
-    mRateScaler = ((double) sourceStream->getSampleRate()) / sinkStream->getSampleRate();
+    mRateScaler = ((double) getSampleRate()) / mChildStream->getSampleRate();
 
     return mFlowGraph->configure(sourceStream, sinkStream);
 }
diff --git a/src/common/FilterAudioStream.h b/src/common/FilterAudioStream.h
index 5428db5..2f50e3e 100644
--- a/src/common/FilterAudioStream.h
+++ b/src/common/FilterAudioStream.h
@@ -56,6 +56,8 @@
         mBufferCapacityInFrames = mChildStream->getBufferCapacityInFrames();
         mPerformanceMode = mChildStream->getPerformanceMode();
         mInputPreset = mChildStream->getInputPreset();
+        mFramesPerBurst = mChildStream->getFramesPerBurst();
+        mDeviceId = mChildStream->getDeviceId();
     }
 
     virtual ~FilterAudioStream() = default;
@@ -113,7 +115,7 @@
             int32_t numFrames,
             int64_t timeoutNanoseconds) override;
 
-    StreamState getState() const override {
+    StreamState getState() override {
         return mChildStream->getState();
     }
 
@@ -128,10 +130,6 @@
         return mChildStream->isXRunCountSupported();
     }
 
-    int32_t getFramesPerBurst() override {
-        return mChildStream->getFramesPerBurst();
-    }
-
     AudioApi getAudioApi() const override {
         return mChildStream->getAudioApi();
     }
@@ -159,7 +157,7 @@
         return mBufferSizeInFrames;
     }
 
-    ResultWithValue<int32_t> getXRunCount() const override {
+    ResultWithValue<int32_t> getXRunCount() override {
         return mChildStream->getXRunCount();
     }
 
@@ -184,20 +182,20 @@
             void *audioData,
             int32_t numFrames) override;
 
-    bool onError(AudioStream * audioStream, Result error) override {
+    bool onError(AudioStream * /*audioStream*/, Result error) override {
         if (mErrorCallback != nullptr) {
             return mErrorCallback->onError(this, error);
         }
         return false;
     }
 
-    void onErrorBeforeClose(AudioStream *oboeStream, Result error) override {
+    void onErrorBeforeClose(AudioStream * /*oboeStream*/, Result error) override {
         if (mErrorCallback != nullptr) {
             mErrorCallback->onErrorBeforeClose(this, error);
         }
     }
 
-    void onErrorAfterClose(AudioStream *oboeStream, Result error) override {
+    void onErrorAfterClose(AudioStream * /*oboeStream*/, Result error) override {
         // Close this parent stream because the callback will only close the child.
         AudioStream::close();
         if (mErrorCallback != nullptr) {
diff --git a/src/common/OboeExtensions.cpp b/src/common/OboeExtensions.cpp
new file mode 100644
index 0000000..57731e8
--- /dev/null
+++ b/src/common/OboeExtensions.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 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 "oboe/OboeExtensions.h"
+#include "aaudio/AAudioExtensions.h"
+
+using namespace oboe;
+
+bool OboeExtensions::isMMapSupported(){
+    return AAudioExtensions::getInstance().isMMapSupported();
+}
+
+bool OboeExtensions::isMMapEnabled(){
+    return AAudioExtensions::getInstance().isMMapEnabled();
+}
+
+int32_t OboeExtensions::setMMapEnabled(bool enabled){
+    return AAudioExtensions::getInstance().setMMapEnabled(enabled);
+}
+
+bool OboeExtensions::isMMapUsed(oboe::AudioStream *oboeStream){
+    return AAudioExtensions::getInstance().isMMapUsed(oboeStream);
+}
diff --git a/src/common/QuirksManager.cpp b/src/common/QuirksManager.cpp
index 5d35c71..16425fb 100644
--- a/src/common/QuirksManager.cpp
+++ b/src/common/QuirksManager.cpp
@@ -62,33 +62,44 @@
             && builder.getChannelCount() <= kChannelCountStereo;
 }
 
-class SamsungDeviceQuirks : public  QuirksManager::DeviceQuirks {
-public:
-    SamsungDeviceQuirks() {
-        std::string arch = getPropertyString("ro.arch");
-        isExynos = (arch.rfind("exynos", 0) == 0); // starts with?
+bool QuirksManager::DeviceQuirks::shouldConvertFloatToI16ForOutputStreams() {
+    std::string productManufacturer = getPropertyString("ro.product.manufacturer");
+    if (getSdkVersion() < __ANDROID_API_L__) {
+        return true;
+    } else if ((productManufacturer == "vivo") && (getSdkVersion() < __ANDROID_API_M__)) {
+        return true;
+    }
+    return false;
+}
 
+/**
+ * This is for Samsung Exynos quirks. Samsung Mobile uses Qualcomm chips so
+ * the QualcommDeviceQuirks would apply.
+ */
+class SamsungExynosDeviceQuirks : public  QuirksManager::DeviceQuirks {
+public:
+    SamsungExynosDeviceQuirks() {
         std::string chipname = getPropertyString("ro.hardware.chipname");
         isExynos9810 = (chipname == "exynos9810");
         isExynos990 = (chipname == "exynos990");
+        isExynos850 = (chipname == "exynos850");
 
         mBuildChangelist = getPropertyInteger("ro.build.changelist", 0);
     }
 
-    virtual ~SamsungDeviceQuirks() = default;
+    virtual ~SamsungExynosDeviceQuirks() = default;
 
     int32_t getExclusiveBottomMarginInBursts() const override {
-        // TODO Make this conditional on build version when MMAP timing improves.
-        return isExynos ? kBottomMarginExynos : kBottomMarginOther;
+        return kBottomMargin;
     }
 
     int32_t getExclusiveTopMarginInBursts() const override {
         return kTopMargin;
     }
 
-    // See Oboe issue #824 for more information.
+    // See Oboe issues #824 and #1247 for more information.
     bool isMonoMMapActuallyStereo() const override {
-        return isExynos9810; // TODO We can make this version specific if it gets fixed.
+        return isExynos9810 || isExynos850; // TODO We can make this version specific if it gets fixed.
     }
 
     bool isAAudioMMapPossible(const AudioStreamBuilder &builder) const override {
@@ -102,29 +113,83 @@
         // This detects b/159066712 , S20 LSI has corrupt low latency audio recording
         // and turns off MMAP.
         // See also https://github.com/google/oboe/issues/892
-        bool mRecordingCorrupted = isInput
+        bool isRecordingCorrupted = isInput
             && isExynos990
             && mBuildChangelist < 19350896;
-        return !mRecordingCorrupted;
+
+        // Certain S9+ builds record silence when using MMAP and not using the VoiceCommunication
+        // preset.
+        // See https://github.com/google/oboe/issues/1110
+        bool wouldRecordSilence = isInput
+            && isExynos9810
+            && mBuildChangelist <= 18847185
+            && (builder.getInputPreset() != InputPreset::VoiceCommunication);
+
+        if (wouldRecordSilence){
+            LOGI("QuirksManager::%s() Requested stream configuration would result in silence on "
+                 "this device. Switching off MMAP.", __func__);
+        }
+
+        return !isRecordingCorrupted && !wouldRecordSilence;
     }
 
 private:
     // Stay farther away from DSP position on Exynos devices.
-    static constexpr int32_t kBottomMarginExynos = 2;
-    static constexpr int32_t kBottomMarginOther = 1;
+    static constexpr int32_t kBottomMargin = 2;
     static constexpr int32_t kTopMargin = 1;
-    bool isExynos = false;
     bool isExynos9810 = false;
     bool isExynos990 = false;
+    bool isExynos850 = false;
     int mBuildChangelist = 0;
 };
 
+class QualcommDeviceQuirks : public  QuirksManager::DeviceQuirks {
+public:
+    QualcommDeviceQuirks() {
+        std::string modelName = getPropertyString("ro.soc.model");
+        isSM8150 = (modelName == "SDM8150");
+    }
+
+    virtual ~QualcommDeviceQuirks() = default;
+
+    int32_t getExclusiveBottomMarginInBursts() const override {
+        return kBottomMargin;
+    }
+
+    bool isMMapSafe(const AudioStreamBuilder &builder) override {
+        // See https://github.com/google/oboe/issues/1121#issuecomment-897957749
+        bool isMMapBroken = false;
+        if (isSM8150 && (getSdkVersion() <= __ANDROID_API_P__)) {
+            LOGI("QuirksManager::%s() MMAP not actually supported on this chip."
+                 " Switching off MMAP.", __func__);
+            isMMapBroken = true;
+        }
+
+        return !isMMapBroken;
+    }
+
+private:
+    bool isSM8150 = false;
+    static constexpr int32_t kBottomMargin = 1;
+};
+
 QuirksManager::QuirksManager() {
-    std::string manufacturer = getPropertyString("ro.product.manufacturer");
-    if (manufacturer == "samsung") {
-        mDeviceQuirks = std::make_unique<SamsungDeviceQuirks>();
-    } else {
-        mDeviceQuirks = std::make_unique<DeviceQuirks>();
+    std::string productManufacturer = getPropertyString("ro.product.manufacturer");
+    if (productManufacturer == "samsung") {
+        std::string arch = getPropertyString("ro.arch");
+        bool isExynos = (arch.rfind("exynos", 0) == 0); // starts with?
+        if (isExynos) {
+            mDeviceQuirks = std::make_unique<SamsungExynosDeviceQuirks>();
+        }
+    }
+    if (!mDeviceQuirks) {
+        std::string socManufacturer = getPropertyString("ro.soc.manufacturer");
+        if (socManufacturer == "Qualcomm") {
+            // This may include Samsung Mobile devices.
+            mDeviceQuirks = std::make_unique<QualcommDeviceQuirks>();
+        } else {
+            mDeviceQuirks = std::make_unique<DeviceQuirks>();
+        }
     }
 }
 
@@ -158,7 +223,8 @@
         conversionNeeded = true;
     }
 
-    // If a SAMPLE RATE is specified for low latency then let the native code choose an optimal rate.
+    // If a SAMPLE RATE is specified for low latency, let the native code choose an optimal rate.
+    // This isn't really a workaround. It is an Oboe feature that is convenient to place here.
     // TODO There may be a problem if the devices supports low latency
     //      at a higher rate than the default.
     if (builder.getSampleRate() != oboe::Unspecified
@@ -171,7 +237,8 @@
 
     // Data Format
     // OpenSL ES and AAudio before P do not support FAST path for FLOAT capture.
-    if (isFloat
+    if (OboeGlobals::areWorkaroundsEnabled()
+            && isFloat
             && isInput
             && builder.isFormatConversionAllowed()
             && isLowLatency
@@ -182,6 +249,21 @@
         LOGI("QuirksManager::%s() forcing internal format to I16 for low latency", __func__);
     }
 
+    // Add quirk for float output when needed.
+    if (OboeGlobals::areWorkaroundsEnabled()
+            && isFloat
+            && !isInput
+            && builder.isFormatConversionAllowed()
+            && mDeviceQuirks->shouldConvertFloatToI16ForOutputStreams()
+            ) {
+        childBuilder.setFormat(AudioFormat::I16);
+        conversionNeeded = true;
+        LOGI("QuirksManager::%s() float was requested but not supported on pre-L devices "
+             "and some devices like Vivo devices may have issues on L devices, "
+             "creating an underlying I16 stream and using format conversion to provide a float "
+             "stream", __func__);
+    }
+
     // Channel Count conversions
     if (OboeGlobals::areWorkaroundsEnabled()
             && builder.isChannelConversionAllowed()
diff --git a/src/common/QuirksManager.h b/src/common/QuirksManager.h
index aeca270..c24e974 100644
--- a/src/common/QuirksManager.h
+++ b/src/common/QuirksManager.h
@@ -106,6 +106,9 @@
             return true;
         }
 
+        // On some devices, Float does not work so it should be converted to I16.
+        static bool shouldConvertFloatToI16ForOutputStreams();
+
         static constexpr int32_t kDefaultBottomMarginInBursts = 0;
         static constexpr int32_t kDefaultTopMarginInBursts = 0;
 
diff --git a/src/common/SourceI16Caller.h b/src/common/SourceI16Caller.h
index 22c1b9a..02a57c2 100644
--- a/src/common/SourceI16Caller.h
+++ b/src/common/SourceI16Caller.h
@@ -32,7 +32,8 @@
 public:
     SourceI16Caller(int32_t channelCount, int32_t framesPerCallback)
     : AudioSourceCaller(channelCount, framesPerCallback, sizeof(int16_t)) {
-        mConversionBuffer = std::make_unique<int16_t[]>(channelCount * output.getFramesPerBuffer());
+        mConversionBuffer = std::make_unique<int16_t[]>(static_cast<size_t>(channelCount)
+                * static_cast<size_t>(output.getFramesPerBuffer()));
     }
 
     int32_t onProcess(int32_t numFrames) override;
diff --git a/src/common/SourceI24Caller.cpp b/src/common/SourceI24Caller.cpp
new file mode 100644
index 0000000..2e44c3d
--- /dev/null
+++ b/src/common/SourceI24Caller.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 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 <algorithm>
+#include <unistd.h>
+#include "flowgraph/FlowGraphNode.h"
+#include "SourceI24Caller.h"
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+#include <audio_utils/primitives.h>
+#endif
+
+using namespace oboe;
+using namespace flowgraph;
+
+int32_t SourceI24Caller::onProcess(int32_t numFrames) {
+    int32_t numBytes = mStream->getBytesPerFrame() * numFrames;
+    int32_t bytesRead = mBlockReader.read((uint8_t *) mConversionBuffer.get(), numBytes);
+    int32_t framesRead = bytesRead / mStream->getBytesPerFrame();
+
+    float *floatData = output.getBuffer();
+    const uint8_t *byteData = mConversionBuffer.get();
+    int32_t numSamples = framesRead * output.getSamplesPerFrame();
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+    memcpy_to_float_from_p24(floatData, byteData, numSamples);
+#else
+    static const float scale = 1. / (float)(1UL << 31);
+    for (int i = 0; i < numSamples; i++) {
+        // Assemble the data assuming Little Endian format.
+        int32_t pad = byteData[2];
+        pad <<= 8;
+        pad |= byteData[1];
+        pad <<= 8;
+        pad |= byteData[0];
+        pad <<= 8; // Shift to 32 bit data so the sign is correct.
+        byteData += kBytesPerI24Packed;
+        *floatData++ = pad * scale; // scale to range -1.0 to 1.0
+    }
+#endif
+
+    return framesRead;
+}
diff --git a/src/common/SourceI24Caller.h b/src/common/SourceI24Caller.h
new file mode 100644
index 0000000..3b5eab7
--- /dev/null
+++ b/src/common/SourceI24Caller.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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 OBOE_SOURCE_I24_CALLER_H
+#define OBOE_SOURCE_I24_CALLER_H
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "flowgraph/FlowGraphNode.h"
+#include "AudioSourceCaller.h"
+#include "FixedBlockReader.h"
+
+namespace oboe {
+
+/**
+ * AudioSource that uses callback to get more data.
+ */
+class SourceI24Caller : public AudioSourceCaller {
+public:
+    SourceI24Caller(int32_t channelCount, int32_t framesPerCallback)
+    : AudioSourceCaller(channelCount, framesPerCallback, kBytesPerI24Packed) {
+        mConversionBuffer = std::make_unique<uint8_t[]>(static_cast<size_t>(kBytesPerI24Packed)
+                * static_cast<size_t>(channelCount)
+                * static_cast<size_t>(output.getFramesPerBuffer()));
+    }
+
+    int32_t onProcess(int32_t numFrames) override;
+
+    const char *getName() override {
+        return "SourceI24Caller";
+    }
+
+private:
+    std::unique_ptr<uint8_t[]>  mConversionBuffer;
+    static constexpr int kBytesPerI24Packed = 3;
+};
+
+}
+#endif //OBOE_SOURCE_I16_CALLER_H
diff --git a/src/common/SourceI32Caller.cpp b/src/common/SourceI32Caller.cpp
new file mode 100644
index 0000000..188bd47
--- /dev/null
+++ b/src/common/SourceI32Caller.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 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 <algorithm>
+#include <unistd.h>
+#include "flowgraph/FlowGraphNode.h"
+#include "SourceI32Caller.h"
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+#include <audio_utils/primitives.h>
+#endif
+
+using namespace oboe;
+using namespace flowgraph;
+
+int32_t SourceI32Caller::onProcess(int32_t numFrames) {
+    int32_t numBytes = mStream->getBytesPerFrame() * numFrames;
+    int32_t bytesRead = mBlockReader.read((uint8_t *) mConversionBuffer.get(), numBytes);
+    int32_t framesRead = bytesRead / mStream->getBytesPerFrame();
+
+    float *floatData = output.getBuffer();
+    const int32_t *intData = mConversionBuffer.get();
+    int32_t numSamples = framesRead * output.getSamplesPerFrame();
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+    memcpy_to_float_from_i32(floatData, shortData, numSamples);
+#else
+    for (int i = 0; i < numSamples; i++) {
+        *floatData++ = *intData++ * kScale;
+    }
+#endif
+
+    return framesRead;
+}
diff --git a/src/common/SourceI32Caller.h b/src/common/SourceI32Caller.h
new file mode 100644
index 0000000..18c3343
--- /dev/null
+++ b/src/common/SourceI32Caller.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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 OBOE_SOURCE_I32_CALLER_H
+#define OBOE_SOURCE_I32_CALLER_H
+
+#include <memory.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "flowgraph/FlowGraphNode.h"
+#include "AudioSourceCaller.h"
+#include "FixedBlockReader.h"
+
+namespace oboe {
+
+/**
+ * AudioSource that uses callback to get more data.
+ */
+class SourceI32Caller : public AudioSourceCaller {
+public:
+    SourceI32Caller(int32_t channelCount, int32_t framesPerCallback)
+    : AudioSourceCaller(channelCount, framesPerCallback, sizeof(int32_t)) {
+        mConversionBuffer = std::make_unique<int32_t[]>(static_cast<size_t>(channelCount)
+                * static_cast<size_t>(output.getFramesPerBuffer()));
+    }
+
+    int32_t onProcess(int32_t numFrames) override;
+
+    const char *getName() override {
+        return "SourceI32Caller";
+    }
+
+private:
+    std::unique_ptr<int32_t[]>  mConversionBuffer;
+    static constexpr float kScale = 1.0 / (1UL << 31);
+};
+
+}
+#endif //OBOE_SOURCE_I32_CALLER_H
diff --git a/src/common/StabilizedCallback.cpp b/src/common/StabilizedCallback.cpp
index 692db89..a2ac549 100644
--- a/src/common/StabilizedCallback.cpp
+++ b/src/common/StabilizedCallback.cpp
@@ -109,4 +109,4 @@
         mOpsPerNano = kFilterCoefficient * measuredOpsPerNano + (1.0 - kFilterCoefficient) * mOpsPerNano;
         opsPerStep = (int) (mOpsPerNano * kLoadGenerationStepSizeNanos);
     }
-}
\ No newline at end of file
+}
diff --git a/src/common/Trace.cpp b/src/common/Trace.cpp
index 5ed445b..f08f36d 100644
--- a/src/common/Trace.cpp
+++ b/src/common/Trace.cpp
@@ -72,4 +72,4 @@
             mIsTracingSupported = true;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/common/Trace.h b/src/common/Trace.h
index c7965f9..dad6c00 100644
--- a/src/common/Trace.h
+++ b/src/common/Trace.h
@@ -28,4 +28,4 @@
     static bool mIsTracingSupported;
 };
 
-#endif //OBOE_TRACE_H
\ No newline at end of file
+#endif //OBOE_TRACE_H
diff --git a/src/common/Utilities.cpp b/src/common/Utilities.cpp
index d38874b..22296e6 100644
--- a/src/common/Utilities.cpp
+++ b/src/common/Utilities.cpp
@@ -60,6 +60,12 @@
         case AudioFormat::Float:
             size = sizeof(float);
             break;
+        case AudioFormat::I24:
+            size = 3; // packed 24-bit data
+            break;
+        case AudioFormat::I32:
+            size = sizeof(int32_t);
+            break;
         default:
             break;
     }
@@ -98,6 +104,8 @@
         case AudioFormat::Unspecified:  return "Unspecified";
         case AudioFormat::I16:          return "I16";
         case AudioFormat::Float:        return "Float";
+        case AudioFormat::I24:          return "I24";
+        case AudioFormat::I32:          return "I32";
         default:                        return "Unrecognized format";
     }
 }
@@ -302,4 +310,8 @@
     return sCachedSdkVersion;
 }
 
+int getChannelCountFromChannelMask(ChannelMask channelMask) {
+    return __builtin_popcount(static_cast<uint32_t>(channelMask));
+}
+
 }// namespace oboe
diff --git a/src/fifo/FifoBuffer.cpp b/src/fifo/FifoBuffer.cpp
index d8314bb..c33315d 100644
--- a/src/fifo/FifoBuffer.cpp
+++ b/src/fifo/FifoBuffer.cpp
@@ -18,10 +18,10 @@
 #include <memory.h>
 #include <stdint.h>
 
-#include "fifo/FifoControllerBase.h"
+#include "oboe/FifoControllerBase.h"
 #include "fifo/FifoController.h"
 #include "fifo/FifoControllerIndirect.h"
-#include "fifo/FifoBuffer.h"
+#include "oboe/FifoBuffer.h"
 
 namespace oboe {
 
diff --git a/src/fifo/FifoController.cpp b/src/fifo/FifoController.cpp
index b2168d1..aa0d5b7 100644
--- a/src/fifo/FifoController.cpp
+++ b/src/fifo/FifoController.cpp
@@ -16,7 +16,6 @@
 
 #include <stdint.h>
 
-#include "FifoControllerBase.h"
 #include "FifoController.h"
 
 namespace oboe {
diff --git a/src/fifo/FifoController.h b/src/fifo/FifoController.h
index d3e413e..b3e2d07 100644
--- a/src/fifo/FifoController.h
+++ b/src/fifo/FifoController.h
@@ -20,7 +20,7 @@
 #include <atomic>
 #include <stdint.h>
 
-#include "FifoControllerBase.h"
+#include "oboe/FifoControllerBase.h"
 
 namespace oboe {
 
diff --git a/src/fifo/FifoControllerBase.cpp b/src/fifo/FifoControllerBase.cpp
index d341947..dc65b87 100644
--- a/src/fifo/FifoControllerBase.cpp
+++ b/src/fifo/FifoControllerBase.cpp
@@ -18,7 +18,7 @@
 #include <cassert>
 #include <stdint.h>
 
-#include "FifoControllerBase.h"
+#include "oboe/FifoControllerBase.h"
 
 namespace oboe {
 
diff --git a/src/fifo/FifoControllerIndirect.h b/src/fifo/FifoControllerIndirect.h
index 32f7881..c25c607 100644
--- a/src/fifo/FifoControllerIndirect.h
+++ b/src/fifo/FifoControllerIndirect.h
@@ -20,7 +20,7 @@
 #include <atomic>
 #include <stdint.h>
 
-#include "FifoControllerBase.h"
+#include "oboe/FifoControllerBase.h"
 
 namespace oboe {
 
diff --git a/src/flowgraph/ChannelCountConverter.cpp b/src/flowgraph/ChannelCountConverter.cpp
index b56f8b2..dc80427 100644
--- a/src/flowgraph/ChannelCountConverter.cpp
+++ b/src/flowgraph/ChannelCountConverter.cpp
@@ -27,7 +27,7 @@
         , output(*this, outputChannelCount) {
 }
 
-ChannelCountConverter::~ChannelCountConverter() { }
+ChannelCountConverter::~ChannelCountConverter() = default;
 
 int32_t ChannelCountConverter::onProcess(int32_t numFrames) {
     const float *inputBuffer = input.getBuffer();
diff --git a/src/flowgraph/ChannelCountConverter.h b/src/flowgraph/ChannelCountConverter.h
index f688d44..858f4d4 100644
--- a/src/flowgraph/ChannelCountConverter.h
+++ b/src/flowgraph/ChannelCountConverter.h
@@ -22,8 +22,7 @@
 
 #include "FlowGraphNode.h"
 
-namespace FLOWGRAPH_OUTER_NAMESPACE {
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
 
 /**
  * Change the number of number of channels without mixing.
@@ -48,7 +47,6 @@
         FlowGraphPortFloatOutput output;
     };
 
-} /* namespace flowgraph */
-} /* namespace FLOWGRAPH_OUTER_NAMESPACE */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
 
 #endif //FLOWGRAPH_CHANNEL_COUNT_CONVERTER_H
diff --git a/src/flowgraph/ClipToRange.h b/src/flowgraph/ClipToRange.h
index 4dc82f6..2fddeee 100644
--- a/src/flowgraph/ClipToRange.h
+++ b/src/flowgraph/ClipToRange.h
@@ -23,8 +23,7 @@
 
 #include "FlowGraphNode.h"
 
-namespace FLOWGRAPH_OUTER_NAMESPACE {
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
 
 // This is 3 dB, (10^(3/20)), to match the maximum headroom in AudioTrack for float data.
 // It is designed to allow occasional transient peaks.
@@ -64,7 +63,6 @@
     float mMaximum = kDefaultMaxHeadroom;
 };
 
-} /* namespace flowgraph */
-} /* namespace FLOWGRAPH_OUTER_NAMESPACE */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
 
 #endif //FLOWGRAPH_CLIP_TO_RANGE_H
diff --git a/src/flowgraph/FlowGraphNode.cpp b/src/flowgraph/FlowGraphNode.cpp
index 9a62d7d..012abe7 100644
--- a/src/flowgraph/FlowGraphNode.cpp
+++ b/src/flowgraph/FlowGraphNode.cpp
@@ -68,7 +68,7 @@
         : FlowGraphPort(parent, samplesPerFrame)
         , mFramesPerBuffer(framesPerBuffer)
         , mBuffer(nullptr) {
-    size_t numFloats = static_cast<size_t>(framesPerBuffer * getSamplesPerFrame());
+    size_t numFloats = static_cast<size_t>(framesPerBuffer) * getSamplesPerFrame();
     mBuffer = std::make_unique<float[]>(numFloats);
 }
 
diff --git a/src/flowgraph/FlowGraphNode.h b/src/flowgraph/FlowGraphNode.h
index acbee56..2884c08 100644
--- a/src/flowgraph/FlowGraphNode.h
+++ b/src/flowgraph/FlowGraphNode.h
@@ -38,23 +38,26 @@
 // TODO Review use of raw pointers for connect(). Maybe use smart pointers but need to avoid
 //      run-time deallocation in audio thread.
 
-// Set this to 1 if using it inside the Android framework.
-// This code is kept here so that it can be moved easily between Oboe and AAudio.
+// Set flags FLOWGRAPH_ANDROID_INTERNAL and FLOWGRAPH_OUTER_NAMESPACE based on whether compiler
+// flag __ANDROID_NDK__ is defined. __ANDROID_NDK__ should be defined in oboe and not aaudio.
+
 #ifndef FLOWGRAPH_ANDROID_INTERNAL
+#ifdef __ANDROID_NDK__
 #define FLOWGRAPH_ANDROID_INTERNAL 0
-#endif
+#else
+#define FLOWGRAPH_ANDROID_INTERNAL 1
+#endif // __ANDROID_NDK__
+#endif // FLOWGRAPH_ANDROID_INTERNAL
 
-// Set this to a name that will prevent AAudio from calling into Oboe.
-// AAudio and Oboe both use a version of this flowgraph package.
-// There was a problem in the unit tests where AAudio would call a constructor
-// in AAudio and then call a destructor in Oboe! That caused memory corruption.
-// For more details, see Issue #930.
 #ifndef FLOWGRAPH_OUTER_NAMESPACE
+#ifdef __ANDROID_NDK__
 #define FLOWGRAPH_OUTER_NAMESPACE oboe
-#endif
+#else
+#define FLOWGRAPH_OUTER_NAMESPACE aaudio
+#endif // __ANDROID_NDK__
+#endif // FLOWGRAPH_OUTER_NAMESPACE
 
-namespace FLOWGRAPH_OUTER_NAMESPACE {
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
 
 // Default block size that can be overridden when the FlowGraphPortFloat is created.
 // If it is too small then we will have too much overhead from switching between nodes.
@@ -70,7 +73,7 @@
  */
 class FlowGraphNode {
 public:
-    FlowGraphNode() {}
+    FlowGraphNode() = default;
     virtual ~FlowGraphNode() = default;
 
     /**
@@ -108,7 +111,7 @@
     virtual void reset();
 
     void addInputPort(FlowGraphPort &port) {
-        mInputPorts.push_back(port);
+        mInputPorts.emplace_back(port);
     }
 
     bool isDataPulledAutomatically() const {
@@ -164,7 +167,7 @@
             : mContainingNode(parent)
             , mSamplesPerFrame(samplesPerFrame) {
     }
-    
+
     virtual ~FlowGraphPort() = default;
 
     // Ports are often declared public. So let's make them non-copyable.
@@ -403,7 +406,7 @@
     FlowGraphPortFloatInput input;
 
     /**
-     * Dummy processor. The work happens in the read() method.
+     * Do nothing. The work happens in the read() method.
      *
      * @param numFrames
      * @return number of frames actually processed
@@ -442,7 +445,6 @@
     FlowGraphPortFloatOutput output;
 };
 
-} /* namespace flowgraph */
-} /* namespace FLOWGRAPH_OUTER_NAMESPACE */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
 
 #endif /* FLOWGRAPH_FLOW_GRAPH_NODE_H */
diff --git a/src/flowgraph/FlowgraphUtilities.h b/src/flowgraph/FlowgraphUtilities.h
new file mode 100644
index 0000000..5e90588
--- /dev/null
+++ b/src/flowgraph/FlowgraphUtilities.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2020 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 FLOWGRAPH_UTILITIES_H
+#define FLOWGRAPH_UTILITIES_H
+
+#include <unistd.h>
+
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
+
+class FlowgraphUtilities {
+public:
+// This was copied from audio_utils/primitives.h
+/**
+ * Convert a single-precision floating point value to a Q0.31 integer value.
+ * Rounds to nearest, ties away from 0.
+ *
+ * Values outside the range [-1.0, 1.0) are properly clamped to -2147483648 and 2147483647,
+ * including -Inf and +Inf. NaN values are considered undefined, and behavior may change
+ * depending on hardware and future implementation of this function.
+ */
+static int32_t clamp32FromFloat(float f)
+{
+    static const float scale = (float)(1UL << 31);
+    static const float limpos = 1.;
+    static const float limneg = -1.;
+
+    if (f <= limneg) {
+        return INT32_MIN;
+    } else if (f >= limpos) {
+        return INT32_MAX;
+    }
+    f *= scale;
+    /* integer conversion is through truncation (though int to float is not).
+     * ensure that we round to nearest, ties away from 0.
+     */
+    return f > 0 ? f + 0.5 : f - 0.5;
+}
+
+};
+
+#endif // FLOWGRAPH_UTILITIES_H
diff --git a/src/flowgraph/Limiter.cpp b/src/flowgraph/Limiter.cpp
new file mode 100644
index 0000000..def905a
--- /dev/null
+++ b/src/flowgraph/Limiter.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2022 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 <algorithm>
+#include <math.h>
+#include <unistd.h>
+#include "FlowGraphNode.h"
+#include "Limiter.h"
+
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
+
+Limiter::Limiter(int32_t channelCount)
+        : FlowGraphFilter(channelCount) {
+}
+
+int32_t Limiter::onProcess(int32_t numFrames) {
+    const float *inputBuffer = input.getBuffer();
+    float *outputBuffer = output.getBuffer();
+
+    int32_t numSamples = numFrames * output.getSamplesPerFrame();
+
+    // Cache the last valid output to reduce memory read/write
+    float lastValidOutput = mLastValidOutput;
+
+    for (int32_t i = 0; i < numSamples; i++) {
+        // Use the previous output if the input is NaN
+        if (!isnan(*inputBuffer)) {
+            lastValidOutput = processFloat(*inputBuffer);
+        }
+        inputBuffer++;
+        *outputBuffer++ = lastValidOutput;
+    }
+    mLastValidOutput = lastValidOutput;
+
+    return numFrames;
+}
+
+float Limiter::processFloat(float in)
+{
+    float in_abs = fabsf(in);
+    if (in_abs <= 1) {
+        return in;
+    }
+    float out;
+    if (in_abs < kXWhenYis3Decibels) {
+        out = (kPolynomialSplineA * in_abs + kPolynomialSplineB) * in_abs + kPolynomialSplineC;
+    } else {
+        out = M_SQRT2;
+    }
+    if (in < 0) {
+        out = -out;
+    }
+    return out;
+}
diff --git a/src/flowgraph/Limiter.h b/src/flowgraph/Limiter.h
new file mode 100644
index 0000000..393a7bf
--- /dev/null
+++ b/src/flowgraph/Limiter.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2022 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 FLOWGRAPH_LIMITER_H
+#define FLOWGRAPH_LIMITER_H
+
+#include <atomic>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "FlowGraphNode.h"
+
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
+
+class Limiter : public FlowGraphFilter {
+public:
+    explicit Limiter(int32_t channelCount);
+
+    int32_t onProcess(int32_t numFrames) override;
+
+    const char *getName() override {
+        return "Limiter";
+    }
+
+private:
+    // These numbers are based on a polynomial spline for a quadratic solution Ax^2 + Bx + C
+    // The range is up to 3 dB, (10^(3/20)), to match AudioTrack for float data.
+    static constexpr float kPolynomialSplineA = -0.6035533905; // -(1+sqrt(2))/4
+    static constexpr float kPolynomialSplineB = 2.2071067811; // (3+sqrt(2))/2
+    static constexpr float kPolynomialSplineC = -0.6035533905; // -(1+sqrt(2))/4
+    static constexpr float kXWhenYis3Decibels = 1.8284271247; // -1+2sqrt(2)
+
+    /**
+     * Process an input based on the following:
+     * If between -1 and 1, return the input value.
+     * If above kXWhenYis3Decibels, return sqrt(2).
+     * If below -kXWhenYis3Decibels, return -sqrt(2).
+     * If between 1 and kXWhenYis3Decibels, use a quadratic spline (Ax^2 + Bx + C).
+     * If between -kXWhenYis3Decibels and -1, use the absolute value for the spline and flip it.
+     * The derivative of the spline is 1 at 1 and 0 at kXWhenYis3Decibels.
+     * This way, the graph is both continuous and differentiable.
+     */
+    float processFloat(float in);
+
+    // Use the previous valid output for NaN inputs
+    float mLastValidOutput = 0.0f;
+};
+
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
+
+#endif //FLOWGRAPH_LIMITER_H
diff --git a/src/flowgraph/ManyToMultiConverter.h b/src/flowgraph/ManyToMultiConverter.h
index c60e070..50644cf 100644
--- a/src/flowgraph/ManyToMultiConverter.h
+++ b/src/flowgraph/ManyToMultiConverter.h
@@ -23,8 +23,7 @@
 
 #include "FlowGraphNode.h"
 
-namespace FLOWGRAPH_OUTER_NAMESPACE {
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
 
 /**
  * Combine multiple mono inputs into one interleaved multi-channel output.
@@ -37,7 +36,7 @@
 
     int32_t onProcess(int numFrames) override;
 
-    void setEnabled(bool enabled) {}
+    void setEnabled(bool /*enabled*/) {}
 
     std::vector<std::unique_ptr<flowgraph::FlowGraphPortFloatInput>> inputs;
     flowgraph::FlowGraphPortFloatOutput output;
@@ -49,7 +48,6 @@
 private:
 };
 
-} /* namespace flowgraph */
-} /* namespace FLOWGRAPH_OUTER_NAMESPACE */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
 
 #endif //FLOWGRAPH_MANY_TO_MULTI_CONVERTER_H
diff --git a/src/flowgraph/MonoBlend.cpp b/src/flowgraph/MonoBlend.cpp
new file mode 100644
index 0000000..4fd75e1
--- /dev/null
+++ b/src/flowgraph/MonoBlend.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021 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 <unistd.h>
+
+#include "MonoBlend.h"
+
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
+
+MonoBlend::MonoBlend(int32_t channelCount)
+        : FlowGraphFilter(channelCount)
+        , mInvChannelCount(1. / channelCount)
+{
+}
+
+int32_t MonoBlend::onProcess(int32_t numFrames) {
+    int32_t channelCount = output.getSamplesPerFrame();
+    const float *inputBuffer = input.getBuffer();
+    float *outputBuffer = output.getBuffer();
+
+    for (size_t i = 0; i < numFrames; ++i) {
+        float accum = 0;
+        for (size_t j = 0; j < channelCount; ++j) {
+            accum += *inputBuffer++;
+        }
+        accum *= mInvChannelCount;
+        for (size_t j = 0; j < channelCount; ++j) {
+            *outputBuffer++ = accum;
+        }
+    }
+
+    return numFrames;
+}
diff --git a/src/flowgraph/MonoBlend.h b/src/flowgraph/MonoBlend.h
new file mode 100644
index 0000000..f8d44ff
--- /dev/null
+++ b/src/flowgraph/MonoBlend.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2021 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 FLOWGRAPH_MONO_BLEND_H
+#define FLOWGRAPH_MONO_BLEND_H
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "FlowGraphNode.h"
+
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
+
+/**
+ * Combine data between multiple channels so each channel is an average
+ * of all channels.
+ */
+class MonoBlend : public FlowGraphFilter {
+public:
+    explicit MonoBlend(int32_t channelCount);
+
+    virtual ~MonoBlend() = default;
+
+    int32_t onProcess(int32_t numFrames) override;
+
+    const char *getName() override {
+        return "MonoBlend";
+    }
+private:
+    const float mInvChannelCount;
+};
+
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
+
+#endif //FLOWGRAPH_MONO_BLEND
diff --git a/src/flowgraph/MonoToMultiConverter.cpp b/src/flowgraph/MonoToMultiConverter.cpp
index bb471a0..33eed52 100644
--- a/src/flowgraph/MonoToMultiConverter.cpp
+++ b/src/flowgraph/MonoToMultiConverter.cpp
@@ -25,8 +25,6 @@
         , output(*this, outputChannelCount) {
 }
 
-MonoToMultiConverter::~MonoToMultiConverter() { }
-
 int32_t MonoToMultiConverter::onProcess(int32_t numFrames) {
     const float *inputBuffer = input.getBuffer();
     float *outputBuffer = output.getBuffer();
diff --git a/src/flowgraph/MonoToMultiConverter.h b/src/flowgraph/MonoToMultiConverter.h
index 9216f1a..762edb0 100644
--- a/src/flowgraph/MonoToMultiConverter.h
+++ b/src/flowgraph/MonoToMultiConverter.h
@@ -22,8 +22,7 @@
 
 #include "FlowGraphNode.h"
 
-namespace FLOWGRAPH_OUTER_NAMESPACE {
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
 
 /**
  * Convert a monophonic stream to a multi-channel interleaved stream
@@ -33,7 +32,7 @@
 public:
     explicit MonoToMultiConverter(int32_t outputChannelCount);
 
-    virtual ~MonoToMultiConverter();
+    virtual ~MonoToMultiConverter() = default;
 
     int32_t onProcess(int32_t numFrames) override;
 
@@ -45,7 +44,6 @@
     FlowGraphPortFloatOutput output;
 };
 
-} /* namespace flowgraph */
-} /* namespace FLOWGRAPH_OUTER_NAMESPACE */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
 
 #endif //FLOWGRAPH_MONO_TO_MULTI_CONVERTER_H
diff --git a/src/flowgraph/MultiToManyConverter.cpp b/src/flowgraph/MultiToManyConverter.cpp
new file mode 100644
index 0000000..5cdf594
--- /dev/null
+++ b/src/flowgraph/MultiToManyConverter.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021 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 <unistd.h>
+#include "FlowGraphNode.h"
+#include "MultiToManyConverter.h"
+
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
+
+MultiToManyConverter::MultiToManyConverter(int32_t channelCount)
+        : outputs(channelCount)
+        , input(*this, channelCount) {
+    for (int i = 0; i < channelCount; i++) {
+        outputs[i] = std::make_unique<FlowGraphPortFloatOutput>(*this, 1);
+    }
+}
+
+MultiToManyConverter::~MultiToManyConverter() = default;
+
+int32_t MultiToManyConverter::onProcess(int32_t numFrames) {
+    int32_t channelCount = input.getSamplesPerFrame();
+
+    for (int ch = 0; ch < channelCount; ch++) {
+        const float *inputBuffer = input.getBuffer() + ch;
+        float *outputBuffer = outputs[ch]->getBuffer();
+
+        for (int i = 0; i < numFrames; i++) {
+            *outputBuffer++ = *inputBuffer;
+            inputBuffer += channelCount;
+        }
+    }
+
+    return numFrames;
+}
diff --git a/src/flowgraph/MultiToManyConverter.h b/src/flowgraph/MultiToManyConverter.h
new file mode 100644
index 0000000..0b222ac
--- /dev/null
+++ b/src/flowgraph/MultiToManyConverter.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 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 FLOWGRAPH_MULTI_TO_MANY_CONVERTER_H
+#define FLOWGRAPH_MULTI_TO_MANY_CONVERTER_H
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "FlowGraphNode.h"
+
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
+
+/**
+ * Convert a multi-channel interleaved stream to multiple mono-channel
+ * outputs
+ */
+    class MultiToManyConverter : public FlowGraphNode {
+    public:
+        explicit MultiToManyConverter(int32_t channelCount);
+
+        virtual ~MultiToManyConverter();
+
+        int32_t onProcess(int32_t numFrames) override;
+
+        const char *getName() override {
+            return "MultiToManyConverter";
+        }
+
+        std::vector<std::unique_ptr<flowgraph::FlowGraphPortFloatOutput>> outputs;
+        flowgraph::FlowGraphPortFloatInput input;
+    };
+
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
+
+#endif //FLOWGRAPH_MULTI_TO_MANY_CONVERTER_H
diff --git a/src/flowgraph/MultiToMonoConverter.cpp b/src/flowgraph/MultiToMonoConverter.cpp
index 8e895bf..467f95e 100644
--- a/src/flowgraph/MultiToMonoConverter.cpp
+++ b/src/flowgraph/MultiToMonoConverter.cpp
@@ -25,7 +25,7 @@
         , output(*this, 1) {
 }
 
-MultiToMonoConverter::~MultiToMonoConverter() { }
+MultiToMonoConverter::~MultiToMonoConverter() = default;
 
 int32_t MultiToMonoConverter::onProcess(int32_t numFrames) {
     const float *inputBuffer = input.getBuffer();
diff --git a/src/flowgraph/MultiToMonoConverter.h b/src/flowgraph/MultiToMonoConverter.h
index 9cb6911..bf5b7b6 100644
--- a/src/flowgraph/MultiToMonoConverter.h
+++ b/src/flowgraph/MultiToMonoConverter.h
@@ -22,8 +22,7 @@
 
 #include "FlowGraphNode.h"
 
-namespace FLOWGRAPH_OUTER_NAMESPACE {
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
 
 /**
  * Convert a multi-channel interleaved stream to a monophonic stream
@@ -45,7 +44,6 @@
         FlowGraphPortFloatOutput output;
     };
 
-} /* namespace flowgraph */
-} /* namespace FLOWGRAPH_OUTER_NAMESPACE */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
 
 #endif //FLOWGRAPH_MULTI_TO_MONO_CONVERTER_H
diff --git a/src/flowgraph/RampLinear.cpp b/src/flowgraph/RampLinear.cpp
index 33b2712..80ac72a 100644
--- a/src/flowgraph/RampLinear.cpp
+++ b/src/flowgraph/RampLinear.cpp
@@ -32,6 +32,10 @@
 
 void RampLinear::setTarget(float target) {
     mTarget.store(target);
+    // If the ramp has not been used then start immediately at this level.
+    if (mLastCallCount == kInitialCallCount) {
+        forceCurrent(target);
+    }
 }
 
 float RampLinear::interpolateCurrent() {
diff --git a/src/flowgraph/RampLinear.h b/src/flowgraph/RampLinear.h
index 8d4c546..3839d6e 100644
--- a/src/flowgraph/RampLinear.h
+++ b/src/flowgraph/RampLinear.h
@@ -23,8 +23,7 @@
 
 #include "FlowGraphNode.h"
 
-namespace FLOWGRAPH_OUTER_NAMESPACE {
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
 
 /**
  * When the target is modified then the output will ramp smoothly
@@ -92,7 +91,6 @@
     float               mLevelTo         = 0.0f;
 };
 
-} /* namespace flowgraph */
-} /* namespace FLOWGRAPH_OUTER_NAMESPACE */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
 
 #endif //FLOWGRAPH_RAMP_LINEAR_H
diff --git a/src/flowgraph/SampleRateConverter.cpp b/src/flowgraph/SampleRateConverter.cpp
index b1ae4bd..a15fcb8 100644
--- a/src/flowgraph/SampleRateConverter.cpp
+++ b/src/flowgraph/SampleRateConverter.cpp
@@ -17,9 +17,10 @@
 #include "SampleRateConverter.h"
 
 using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
 
-SampleRateConverter::SampleRateConverter(int32_t channelCount, MultiChannelResampler &resampler)
+SampleRateConverter::SampleRateConverter(int32_t channelCount,
+                                         MultiChannelResampler &resampler)
         : FlowGraphFilter(channelCount)
         , mResampler(resampler) {
     setDataPulledAutomatically(false);
diff --git a/src/flowgraph/SampleRateConverter.h b/src/flowgraph/SampleRateConverter.h
index 534df49..f883e6c 100644
--- a/src/flowgraph/SampleRateConverter.h
+++ b/src/flowgraph/SampleRateConverter.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_SAMPLE_RATE_CONVERTER_H
-#define OBOE_SAMPLE_RATE_CONVERTER_H
+#ifndef FLOWGRAPH_SAMPLE_RATE_CONVERTER_H
+#define FLOWGRAPH_SAMPLE_RATE_CONVERTER_H
 
 #include <unistd.h>
 #include <sys/types.h>
@@ -23,12 +23,12 @@
 #include "FlowGraphNode.h"
 #include "resampler/MultiChannelResampler.h"
 
-namespace FLOWGRAPH_OUTER_NAMESPACE {
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
 
 class SampleRateConverter : public FlowGraphFilter {
 public:
-    explicit SampleRateConverter(int32_t channelCount, resampler::MultiChannelResampler &mResampler);
+    explicit SampleRateConverter(int32_t channelCount,
+                                 resampler::MultiChannelResampler &mResampler);
 
     virtual ~SampleRateConverter() = default;
 
@@ -58,7 +58,6 @@
 
 };
 
-} /* namespace flowgraph */
-} /* namespace FLOWGRAPH_OUTER_NAMESPACE */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
 
-#endif //OBOE_SAMPLE_RATE_CONVERTER_H
+#endif //FLOWGRAPH_SAMPLE_RATE_CONVERTER_H
diff --git a/src/flowgraph/SinkFloat.cpp b/src/flowgraph/SinkFloat.cpp
index e0ac6e9..940a66b 100644
--- a/src/flowgraph/SinkFloat.cpp
+++ b/src/flowgraph/SinkFloat.cpp
@@ -26,15 +26,13 @@
 }
 
 int32_t SinkFloat::read(void *data, int32_t numFrames) {
-    // printf("SinkFloat::read(,,%d)\n", numFrames);
     float *floatData = (float *) data;
-    int32_t channelCount = input.getSamplesPerFrame();
+    const int32_t channelCount = input.getSamplesPerFrame();
 
     int32_t framesLeft = numFrames;
     while (framesLeft > 0) {
         // Run the graph and pull data through the input port.
         int32_t framesPulled = pullData(framesLeft);
-        // printf("SinkFloat::read: framesLeft = %d, framesPulled = %d\n", framesLeft, framesPulled);
         if (framesPulled <= 0) {
             break;
         }
@@ -44,6 +42,5 @@
         floatData += numSamples;
         framesLeft -= framesPulled;
     }
-    // printf("SinkFloat returning %d\n", numFrames - framesLeft);
     return numFrames - framesLeft;
 }
diff --git a/src/flowgraph/SinkFloat.h b/src/flowgraph/SinkFloat.h
index 98d2182..3be3f5d 100644
--- a/src/flowgraph/SinkFloat.h
+++ b/src/flowgraph/SinkFloat.h
@@ -23,8 +23,7 @@
 
 #include "FlowGraphNode.h"
 
-namespace FLOWGRAPH_OUTER_NAMESPACE {
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
 
 /**
  * AudioSink that lets you read data as 32-bit floats.
@@ -32,6 +31,7 @@
 class SinkFloat : public FlowGraphSink {
 public:
     explicit SinkFloat(int32_t channelCount);
+    ~SinkFloat() override = default;
 
     int32_t read(void *data, int32_t numFrames) override;
 
@@ -40,7 +40,6 @@
     }
 };
 
-} /* namespace flowgraph */
-} /* namespace FLOWGRAPH_OUTER_NAMESPACE */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
 
 #endif //FLOWGRAPH_SINK_FLOAT_H
diff --git a/src/flowgraph/SinkI16.h b/src/flowgraph/SinkI16.h
index e65ffae..bf124f5 100644
--- a/src/flowgraph/SinkI16.h
+++ b/src/flowgraph/SinkI16.h
@@ -22,8 +22,7 @@
 
 #include "FlowGraphNode.h"
 
-namespace FLOWGRAPH_OUTER_NAMESPACE {
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
 
 /**
  * AudioSink that lets you read data as 16-bit signed integers.
@@ -39,7 +38,6 @@
     }
 };
 
-} /* namespace flowgraph */
-} /* namespace FLOWGRAPH_OUTER_NAMESPACE */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
 
 #endif //FLOWGRAPH_SINK_I16_H
diff --git a/src/flowgraph/SinkI24.h b/src/flowgraph/SinkI24.h
index 116a579..6b4135e 100644
--- a/src/flowgraph/SinkI24.h
+++ b/src/flowgraph/SinkI24.h
@@ -22,8 +22,7 @@
 
 #include "FlowGraphNode.h"
 
-namespace FLOWGRAPH_OUTER_NAMESPACE {
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
 
 /**
  * AudioSink that lets you read data as packed 24-bit signed integers.
@@ -40,7 +39,6 @@
     }
 };
 
-} /* namespace flowgraph */
-} /* namespace FLOWGRAPH_OUTER_NAMESPACE */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
 
 #endif //FLOWGRAPH_SINK_I24_H
diff --git a/src/flowgraph/SinkI32.cpp b/src/flowgraph/SinkI32.cpp
new file mode 100644
index 0000000..b14b3d2
--- /dev/null
+++ b/src/flowgraph/SinkI32.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2020 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 "FlowGraphNode.h"
+#include "FlowgraphUtilities.h"
+#include "SinkI32.h"
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+#include <audio_utils/primitives.h>
+#endif
+
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
+
+SinkI32::SinkI32(int32_t channelCount)
+        : FlowGraphSink(channelCount) {}
+
+int32_t SinkI32::read(void *data, int32_t numFrames) {
+    int32_t *intData = (int32_t *) data;
+    const int32_t channelCount = input.getSamplesPerFrame();
+
+    int32_t framesLeft = numFrames;
+    while (framesLeft > 0) {
+        // Run the graph and pull data through the input port.
+        int32_t framesRead = pullData(framesLeft);
+        if (framesRead <= 0) {
+            break;
+        }
+        const float *signal = input.getBuffer();
+        int32_t numSamples = framesRead * channelCount;
+#if FLOWGRAPH_ANDROID_INTERNAL
+        memcpy_to_i32_from_float(intData, signal, numSamples);
+        intData += numSamples;
+        signal += numSamples;
+#else
+        for (int i = 0; i < numSamples; i++) {
+            *intData++ = FlowgraphUtilities::clamp32FromFloat(*signal++);
+        }
+#endif
+        framesLeft -= framesRead;
+    }
+    return numFrames - framesLeft;
+}
diff --git a/src/flowgraph/SinkI32.h b/src/flowgraph/SinkI32.h
new file mode 100644
index 0000000..35507ea
--- /dev/null
+++ b/src/flowgraph/SinkI32.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2020 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 FLOWGRAPH_SINK_I32_H
+#define FLOWGRAPH_SINK_I32_H
+
+#include <stdint.h>
+
+#include "FlowGraphNode.h"
+
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
+
+class SinkI32 : public FlowGraphSink {
+public:
+    explicit SinkI32(int32_t channelCount);
+    ~SinkI32() override = default;
+
+    int32_t read(void *data, int32_t numFrames) override;
+
+    const char *getName() override {
+        return "SinkI32";
+    }
+};
+
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
+
+#endif //FLOWGRAPH_SINK_I32_H
diff --git a/src/flowgraph/SourceFloat.cpp b/src/flowgraph/SourceFloat.cpp
index 3161ec1..a0c8827 100644
--- a/src/flowgraph/SourceFloat.cpp
+++ b/src/flowgraph/SourceFloat.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include "common/OboeDebug.h"
 #include <algorithm>
 #include <unistd.h>
 #include "FlowGraphNode.h"
@@ -28,11 +27,11 @@
 
 int32_t SourceFloat::onProcess(int32_t numFrames) {
     float *outputBuffer = output.getBuffer();
-    int32_t channelCount = output.getSamplesPerFrame();
+    const int32_t channelCount = output.getSamplesPerFrame();
 
-    int32_t framesLeft = mSizeInFrames - mFrameIndex;
-    int32_t framesToProcess = std::min(numFrames, framesLeft);
-    int32_t numSamples = framesToProcess * channelCount;
+    const int32_t framesLeft = mSizeInFrames - mFrameIndex;
+    const int32_t framesToProcess = std::min(numFrames, framesLeft);
+    const int32_t numSamples = framesToProcess * channelCount;
 
     const float *floatBase = (float *) mData;
     const float *floatData = &floatBase[mFrameIndex * channelCount];
diff --git a/src/flowgraph/SourceFloat.h b/src/flowgraph/SourceFloat.h
index d191c4c..78053e5 100644
--- a/src/flowgraph/SourceFloat.h
+++ b/src/flowgraph/SourceFloat.h
@@ -22,8 +22,7 @@
 
 #include "FlowGraphNode.h"
 
-namespace FLOWGRAPH_OUTER_NAMESPACE {
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
 
 /**
  * AudioSource that reads a block of pre-defined float data.
@@ -31,6 +30,7 @@
 class SourceFloat : public FlowGraphSourceBuffered {
 public:
     explicit SourceFloat(int32_t channelCount);
+    ~SourceFloat() override = default;
 
     int32_t onProcess(int32_t numFrames) override;
 
@@ -39,7 +39,6 @@
     }
 };
 
-} /* namespace flowgraph */
-} /* namespace FLOWGRAPH_OUTER_NAMESPACE */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
 
 #endif //FLOWGRAPH_SOURCE_FLOAT_H
diff --git a/src/flowgraph/SourceI16.cpp b/src/flowgraph/SourceI16.cpp
index 16cd2b3..58c3b1e 100644
--- a/src/flowgraph/SourceI16.cpp
+++ b/src/flowgraph/SourceI16.cpp
@@ -51,4 +51,4 @@
 
     mFrameIndex += framesToProcess;
     return framesToProcess;
-}
\ No newline at end of file
+}
diff --git a/src/flowgraph/SourceI16.h b/src/flowgraph/SourceI16.h
index 3e04c5e..923890c 100644
--- a/src/flowgraph/SourceI16.h
+++ b/src/flowgraph/SourceI16.h
@@ -22,8 +22,7 @@
 
 #include "FlowGraphNode.h"
 
-namespace FLOWGRAPH_OUTER_NAMESPACE {
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
 /**
  * AudioSource that reads a block of pre-defined 16-bit integer data.
  */
@@ -38,7 +37,6 @@
     }
 };
 
-} /* namespace flowgraph */
-} /* namespace FLOWGRAPH_OUTER_NAMESPACE */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
 
 #endif //FLOWGRAPH_SOURCE_I16_H
diff --git a/src/flowgraph/SourceI24.cpp b/src/flowgraph/SourceI24.cpp
index 321f732..cd4b7d9 100644
--- a/src/flowgraph/SourceI24.cpp
+++ b/src/flowgraph/SourceI24.cpp
@@ -17,13 +17,13 @@
 #include <algorithm>
 #include <unistd.h>
 
+#include "FlowGraphNode.h"
+#include "SourceI24.h"
+
 #if FLOWGRAPH_ANDROID_INTERNAL
 #include <audio_utils/primitives.h>
 #endif
 
-#include "FlowGraphNode.h"
-#include "SourceI24.h"
-
 using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
 
 constexpr int kBytesPerI24Packed = 3;
@@ -62,4 +62,4 @@
 
     mFrameIndex += framesToProcess;
     return framesToProcess;
-}
\ No newline at end of file
+}
diff --git a/src/flowgraph/SourceI24.h b/src/flowgraph/SourceI24.h
index 69044d5..fb66d4a 100644
--- a/src/flowgraph/SourceI24.h
+++ b/src/flowgraph/SourceI24.h
@@ -22,8 +22,7 @@
 
 #include "FlowGraphNode.h"
 
-namespace FLOWGRAPH_OUTER_NAMESPACE {
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
 
 /**
  * AudioSource that reads a block of pre-defined 24-bit packed integer data.
@@ -39,7 +38,6 @@
     }
 };
 
-} /* namespace flowgraph */
-} /* namespace FLOWGRAPH_OUTER_NAMESPACE */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
 
 #endif //FLOWGRAPH_SOURCE_I24_H
diff --git a/src/flowgraph/SourceI32.cpp b/src/flowgraph/SourceI32.cpp
new file mode 100644
index 0000000..b1c8f75
--- /dev/null
+++ b/src/flowgraph/SourceI32.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020 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 <algorithm>
+#include <unistd.h>
+
+#include "FlowGraphNode.h"
+#include "SourceI32.h"
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+#include <audio_utils/primitives.h>
+#endif
+
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
+
+SourceI32::SourceI32(int32_t channelCount)
+        : FlowGraphSourceBuffered(channelCount) {
+}
+
+int32_t SourceI32::onProcess(int32_t numFrames) {
+    float *floatData = output.getBuffer();
+    const int32_t channelCount = output.getSamplesPerFrame();
+
+    const int32_t framesLeft = mSizeInFrames - mFrameIndex;
+    const int32_t framesToProcess = std::min(numFrames, framesLeft);
+    const int32_t numSamples = framesToProcess * channelCount;
+
+    const int32_t *intBase = static_cast<const int32_t *>(mData);
+    const int32_t *intData = &intBase[mFrameIndex * channelCount];
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+    memcpy_to_float_from_i32(floatData, intData, numSamples);
+#else
+    for (int i = 0; i < numSamples; i++) {
+        *floatData++ = *intData++ * kScale;
+    }
+#endif
+
+    mFrameIndex += framesToProcess;
+    return framesToProcess;
+}
diff --git a/src/flowgraph/SourceI32.h b/src/flowgraph/SourceI32.h
new file mode 100644
index 0000000..7109469
--- /dev/null
+++ b/src/flowgraph/SourceI32.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018 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 FLOWGRAPH_SOURCE_I32_H
+#define FLOWGRAPH_SOURCE_I32_H
+
+#include <stdint.h>
+
+#include "FlowGraphNode.h"
+
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
+
+class SourceI32 : public FlowGraphSourceBuffered {
+public:
+    explicit SourceI32(int32_t channelCount);
+    ~SourceI32() override = default;
+
+    int32_t onProcess(int32_t numFrames) override;
+
+    const char *getName() override {
+        return "SourceI32";
+    }
+private:
+    static constexpr float kScale = 1.0 / (1UL << 31);
+};
+
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
+
+#endif //FLOWGRAPH_SOURCE_I32_H
diff --git a/src/flowgraph/resampler/HyperbolicCosineWindow.h b/src/flowgraph/resampler/HyperbolicCosineWindow.h
index f6479ae..76ec0e7 100644
--- a/src/flowgraph/resampler/HyperbolicCosineWindow.h
+++ b/src/flowgraph/resampler/HyperbolicCosineWindow.h
@@ -19,7 +19,9 @@
 
 #include <math.h>
 
-namespace resampler {
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
 
 /**
  * Calculate a HyperbolicCosineWindow window centered at 0.
@@ -64,5 +66,6 @@
     double mInverseCoshAlpha = 1.0;
 };
 
-} // namespace resampler
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
+
 #endif //RESAMPLER_HYPERBOLIC_COSINE_WINDOW_H
diff --git a/src/flowgraph/resampler/IntegerRatio.cpp b/src/flowgraph/resampler/IntegerRatio.cpp
index 4bd75b3..39e9b24 100644
--- a/src/flowgraph/resampler/IntegerRatio.cpp
+++ b/src/flowgraph/resampler/IntegerRatio.cpp
@@ -16,7 +16,7 @@
 
 #include "IntegerRatio.h"
 
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
 
 // Enough primes to cover the common sample rates.
 static const int kPrimes[] = {
diff --git a/src/flowgraph/resampler/IntegerRatio.h b/src/flowgraph/resampler/IntegerRatio.h
index fb390f1..a6b524c 100644
--- a/src/flowgraph/resampler/IntegerRatio.h
+++ b/src/flowgraph/resampler/IntegerRatio.h
@@ -14,12 +14,14 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_INTEGER_RATIO_H
-#define OBOE_INTEGER_RATIO_H
+#ifndef RESAMPLER_INTEGER_RATIO_H
+#define RESAMPLER_INTEGER_RATIO_H
 
 #include <sys/types.h>
 
-namespace resampler {
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
 
 /**
  * Represent the ratio of two integers.
@@ -47,6 +49,6 @@
     int32_t mDenominator;
 };
 
-}
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
 
-#endif //OBOE_INTEGER_RATIO_H
+#endif //RESAMPLER_INTEGER_RATIO_H
diff --git a/src/flowgraph/resampler/KaiserWindow.h b/src/flowgraph/resampler/KaiserWindow.h
index 73dbc41..f99f9b4 100644
--- a/src/flowgraph/resampler/KaiserWindow.h
+++ b/src/flowgraph/resampler/KaiserWindow.h
@@ -19,7 +19,9 @@
 
 #include <math.h>
 
-namespace resampler {
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
 
 /**
  * Calculate a Kaiser window centered at 0.
@@ -83,5 +85,6 @@
     double mInverseBesselBeta = 1.0;
 };
 
-} // namespace resampler
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
+
 #endif //RESAMPLER_KAISER_WINDOW_H
diff --git a/src/flowgraph/resampler/LinearResampler.cpp b/src/flowgraph/resampler/LinearResampler.cpp
index a7748c1..cb4932a 100644
--- a/src/flowgraph/resampler/LinearResampler.cpp
+++ b/src/flowgraph/resampler/LinearResampler.cpp
@@ -16,7 +16,7 @@
 
 #include "LinearResampler.h"
 
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
 
 LinearResampler::LinearResampler(const MultiChannelResampler::Builder &builder)
         : MultiChannelResampler(builder) {
diff --git a/src/flowgraph/resampler/LinearResampler.h b/src/flowgraph/resampler/LinearResampler.h
index 5dcc881..5434379 100644
--- a/src/flowgraph/resampler/LinearResampler.h
+++ b/src/flowgraph/resampler/LinearResampler.h
@@ -14,22 +14,24 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_LINEAR_RESAMPLER_H
-#define OBOE_LINEAR_RESAMPLER_H
+#ifndef RESAMPLER_LINEAR_RESAMPLER_H
+#define RESAMPLER_LINEAR_RESAMPLER_H
 
 #include <memory>
 #include <sys/types.h>
 #include <unistd.h>
-#include "MultiChannelResampler.h"
 
-namespace resampler {
+#include "MultiChannelResampler.h"
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
 
 /**
  * Simple resampler that uses bi-linear interpolation.
  */
 class LinearResampler : public MultiChannelResampler {
 public:
-    LinearResampler(const MultiChannelResampler::Builder &builder);
+    explicit LinearResampler(const MultiChannelResampler::Builder &builder);
 
     void writeFrame(const float *frame) override;
 
@@ -40,5 +42,6 @@
     std::unique_ptr<float[]> mCurrentFrame;
 };
 
-} // namespace resampler
-#endif //OBOE_LINEAR_RESAMPLER_H
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
+
+#endif //RESAMPLER_LINEAR_RESAMPLER_H
diff --git a/src/flowgraph/resampler/MultiChannelResampler.cpp b/src/flowgraph/resampler/MultiChannelResampler.cpp
index d630520..a3ce58c 100644
--- a/src/flowgraph/resampler/MultiChannelResampler.cpp
+++ b/src/flowgraph/resampler/MultiChannelResampler.cpp
@@ -25,11 +25,12 @@
 #include "SincResampler.h"
 #include "SincResamplerStereo.h"
 
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
 
 MultiChannelResampler::MultiChannelResampler(const MultiChannelResampler::Builder &builder)
         : mNumTaps(builder.getNumTaps())
-        , mX(builder.getChannelCount() * builder.getNumTaps() * 2)
+        , mX(static_cast<size_t>(builder.getChannelCount())
+                * static_cast<size_t>(builder.getNumTaps()) * 2)
         , mSingleFrame(builder.getChannelCount())
         , mChannelCount(builder.getChannelCount())
         {
@@ -39,7 +40,7 @@
     ratio.reduce();
     mNumerator = ratio.getNumerator();
     mDenominator = ratio.getDenominator();
-    mIntegerPhase = mDenominator;
+    mIntegerPhase = mDenominator; // so we start with a write needed
 }
 
 // static factory method
@@ -110,7 +111,7 @@
     if (--mCursor < 0) {
         mCursor = getNumTaps() - 1;
     }
-    float *dest = &mX[mCursor * getChannelCount()];
+    float *dest = &mX[static_cast<size_t>(mCursor) * static_cast<size_t>(getChannelCount())];
     int offset = getNumTaps() * getChannelCount();
     for (int channel = 0; channel < getChannelCount(); channel++) {
         // Write twice so we avoid having to wrap when reading.
@@ -130,7 +131,7 @@
                                               int32_t numRows,
                                               double phaseIncrement,
                                               float normalizedCutoff) {
-    mCoefficients.resize(getNumTaps() * numRows);
+    mCoefficients.resize(static_cast<size_t>(getNumTaps()) * static_cast<size_t>(numRows));
     int coefficientIndex = 0;
     double phase = 0.0; // ranges from 0.0 to 1.0, fraction between samples
     // Stretch the sinc function for low pass filtering.
@@ -150,7 +151,7 @@
 #if MCR_USE_KAISER
             float window = mKaiserWindow(tapPhase * numTapsHalfInverse);
 #else
-            float window = mCoshWindow(tapPhase * numTapsHalfInverse);
+            float window = mCoshWindow(static_cast<double>(tapPhase) * numTapsHalfInverse);
 #endif
             float coefficient = sinc(radians * cutoffScaler) * window;
             mCoefficients.at(coefficientIndex++) = coefficient;
diff --git a/src/flowgraph/resampler/MultiChannelResampler.h b/src/flowgraph/resampler/MultiChannelResampler.h
index 8b23d81..717f3fd 100644
--- a/src/flowgraph/resampler/MultiChannelResampler.h
+++ b/src/flowgraph/resampler/MultiChannelResampler.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_MULTICHANNEL_RESAMPLER_H
-#define OBOE_MULTICHANNEL_RESAMPLER_H
+#ifndef RESAMPLER_MULTICHANNEL_RESAMPLER_H
+#define RESAMPLER_MULTICHANNEL_RESAMPLER_H
 
 #include <memory>
 #include <vector>
@@ -34,7 +34,9 @@
 #include "HyperbolicCosineWindow.h"
 #endif
 
-namespace resampler {
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
 
 class MultiChannelResampler {
 
@@ -267,5 +269,6 @@
     const int              mChannelCount;
 };
 
-}
-#endif //OBOE_MULTICHANNEL_RESAMPLER_H
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
+
+#endif //RESAMPLER_MULTICHANNEL_RESAMPLER_H
diff --git a/src/flowgraph/resampler/PolyphaseResampler.cpp b/src/flowgraph/resampler/PolyphaseResampler.cpp
index 163cf7c..e47ee8e 100644
--- a/src/flowgraph/resampler/PolyphaseResampler.cpp
+++ b/src/flowgraph/resampler/PolyphaseResampler.cpp
@@ -19,7 +19,7 @@
 #include "IntegerRatio.h"
 #include "PolyphaseResampler.h"
 
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
 
 PolyphaseResampler::PolyphaseResampler(const MultiChannelResampler::Builder &builder)
         : MultiChannelResampler(builder)
@@ -40,13 +40,11 @@
     // Clear accumulator for mixing.
     std::fill(mSingleFrame.begin(), mSingleFrame.end(), 0.0);
 
-//    printf("PolyphaseResampler: mCoefficientCursor = %4d\n", mCoefficientCursor);
     // Multiply input times windowed sinc function.
     float *coefficients = &mCoefficients[mCoefficientCursor];
-    float *xFrame = &mX[mCursor * getChannelCount()];
+    float *xFrame = &mX[static_cast<size_t>(mCursor) * static_cast<size_t>(getChannelCount())];
     for (int i = 0; i < mNumTaps; i++) {
         float coefficient = *coefficients++;
-//        printf("PolyphaseResampler: coeff = %10.6f, xFrame[0] = %10.6f\n", coefficient, xFrame[0]);
         for (int channel = 0; channel < getChannelCount(); channel++) {
             mSingleFrame[channel] += *xFrame++ * coefficient;
         }
diff --git a/src/flowgraph/resampler/PolyphaseResampler.h b/src/flowgraph/resampler/PolyphaseResampler.h
index 52671cd..3642fce 100644
--- a/src/flowgraph/resampler/PolyphaseResampler.h
+++ b/src/flowgraph/resampler/PolyphaseResampler.h
@@ -14,16 +14,18 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_POLYPHASE_RESAMPLER_H
-#define OBOE_POLYPHASE_RESAMPLER_H
+#ifndef RESAMPLER_POLYPHASE_RESAMPLER_H
+#define RESAMPLER_POLYPHASE_RESAMPLER_H
 
 #include <memory>
 #include <vector>
 #include <sys/types.h>
 #include <unistd.h>
-#include "MultiChannelResampler.h"
 
-namespace resampler {
+#include "MultiChannelResampler.h"
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
 /**
  * Resampler that is optimized for a reduced ratio of sample rates.
  * All of the coefficients for each possible phase value are pre-calculated.
@@ -46,6 +48,6 @@
 
 };
 
-}
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
 
-#endif //OBOE_POLYPHASE_RESAMPLER_H
+#endif //RESAMPLER_POLYPHASE_RESAMPLER_H
diff --git a/src/flowgraph/resampler/PolyphaseResamplerMono.cpp b/src/flowgraph/resampler/PolyphaseResamplerMono.cpp
index c0e29b7..fdaf13e 100644
--- a/src/flowgraph/resampler/PolyphaseResamplerMono.cpp
+++ b/src/flowgraph/resampler/PolyphaseResamplerMono.cpp
@@ -17,7 +17,7 @@
 #include <cassert>
 #include "PolyphaseResamplerMono.h"
 
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
 
 #define MONO  1
 
diff --git a/src/flowgraph/resampler/PolyphaseResamplerMono.h b/src/flowgraph/resampler/PolyphaseResamplerMono.h
index d97b513..fe020b5 100644
--- a/src/flowgraph/resampler/PolyphaseResamplerMono.h
+++ b/src/flowgraph/resampler/PolyphaseResamplerMono.h
@@ -14,14 +14,16 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_POLYPHASE_RESAMPLER_MONO_H
-#define OBOE_POLYPHASE_RESAMPLER_MONO_H
+#ifndef RESAMPLER_POLYPHASE_RESAMPLER_MONO_H
+#define RESAMPLER_POLYPHASE_RESAMPLER_MONO_H
 
 #include <sys/types.h>
 #include <unistd.h>
-#include "PolyphaseResampler.h"
 
-namespace resampler {
+#include "PolyphaseResampler.h"
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
 
 class PolyphaseResamplerMono : public PolyphaseResampler {
 public:
@@ -34,6 +36,6 @@
     void readFrame(float *frame) override;
 };
 
-}
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
 
-#endif //OBOE_POLYPHASE_RESAMPLER_MONO_H
+#endif //RESAMPLER_POLYPHASE_RESAMPLER_MONO_H
diff --git a/src/flowgraph/resampler/PolyphaseResamplerStereo.cpp b/src/flowgraph/resampler/PolyphaseResamplerStereo.cpp
index e4bef74..b381851 100644
--- a/src/flowgraph/resampler/PolyphaseResamplerStereo.cpp
+++ b/src/flowgraph/resampler/PolyphaseResamplerStereo.cpp
@@ -17,7 +17,7 @@
 #include <cassert>
 #include "PolyphaseResamplerStereo.h"
 
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
 
 #define STEREO  2
 
diff --git a/src/flowgraph/resampler/PolyphaseResamplerStereo.h b/src/flowgraph/resampler/PolyphaseResamplerStereo.h
index 3dfd4e2..ee4caba 100644
--- a/src/flowgraph/resampler/PolyphaseResamplerStereo.h
+++ b/src/flowgraph/resampler/PolyphaseResamplerStereo.h
@@ -14,14 +14,16 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_POLYPHASE_RESAMPLER_STEREO_H
-#define OBOE_POLYPHASE_RESAMPLER_STEREO_H
+#ifndef RESAMPLER_POLYPHASE_RESAMPLER_STEREO_H
+#define RESAMPLER_POLYPHASE_RESAMPLER_STEREO_H
 
 #include <sys/types.h>
 #include <unistd.h>
-#include "PolyphaseResampler.h"
 
-namespace resampler {
+#include "PolyphaseResampler.h"
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
 
 class PolyphaseResamplerStereo : public PolyphaseResampler {
 public:
@@ -34,6 +36,6 @@
     void readFrame(float *frame) override;
 };
 
-}
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
 
-#endif //OBOE_POLYPHASE_RESAMPLER_STEREO_H
+#endif //RESAMPLER_POLYPHASE_RESAMPLER_STEREO_H
diff --git a/src/flowgraph/resampler/README.md b/src/flowgraph/resampler/README.md
index eaea99f..356f06c 100644
--- a/src/flowgraph/resampler/README.md
+++ b/src/flowgraph/resampler/README.md
@@ -14,6 +14,7 @@
 
 1. Copy the "resampler" folder to a folder in your project that is in the include path.
 2. Add all of the \*.cpp files in the resampler folder to your project IDE or Makefile.
+3. In ResamplerDefinitions.h, define RESAMPLER_OUTER_NAMESPACE with your own project name. Alternatively, use -DRESAMPLER_OUTER_NAMESPACE=mynamespace when compiling to avoid modifying the resampler code.
 
 ## Creating a Resampler
 
@@ -39,8 +40,8 @@
 
 For example, suppose you are converting from 44100 Hz to 48000 Hz and using an input buffer with 960 frames. If you calculate the number of output frames you get:
 
-    960 * 48000 * 44100 = 1044.897959...
-    
+    960.0 * 48000 / 44100 = 1044.897959...
+
 You cannot generate a fractional number of frames. So the resampler will sometimes generate 1044 frames and sometimes 1045 frames. On average it will generate 1044.897959 frames. The resampler stores the fraction internally and keeps track of when to consume or generate a frame.
 
 You can either use a fixed number of input frames or a fixed number of output frames. The other frame count will vary.
@@ -53,7 +54,7 @@
 
     float *outputBuffer;     // multi-channel buffer to be filled
     int    numOutputFrames;  // number of frames of output
-    
+
 The resampler has a method isWriteNeeded() that tells you whether to write to or read from the resampler.
 
     int outputFramesLeft = numOutputFrames;
@@ -98,4 +99,3 @@
 When you are done, you should delete the Resampler to avoid a memory leak.
 
     delete resampler;
-    
diff --git a/src/flowgraph/resampler/ResamplerDefinitions.h b/src/flowgraph/resampler/ResamplerDefinitions.h
new file mode 100644
index 0000000..c6791ec
--- /dev/null
+++ b/src/flowgraph/resampler/ResamplerDefinitions.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2022 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.
+ */
+
+// Set flag RESAMPLER_OUTER_NAMESPACE based on whether compiler flag
+// __ANDROID_NDK__ is defined. __ANDROID_NDK__ should be defined in oboe
+// but not in android.
+
+#ifndef RESAMPLER_OUTER_NAMESPACE
+#ifdef __ANDROID_NDK__
+#define RESAMPLER_OUTER_NAMESPACE oboe
+#else
+#define RESAMPLER_OUTER_NAMESPACE aaudio
+#endif // __ANDROID_NDK__
+#endif // RESAMPLER_OUTER_NAMESPACE
diff --git a/src/flowgraph/resampler/SincResampler.cpp b/src/flowgraph/resampler/SincResampler.cpp
index 3758210..a14ee47 100644
--- a/src/flowgraph/resampler/SincResampler.cpp
+++ b/src/flowgraph/resampler/SincResampler.cpp
@@ -18,16 +18,16 @@
 #include <math.h>
 #include "SincResampler.h"
 
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
 
 SincResampler::SincResampler(const MultiChannelResampler::Builder &builder)
         : MultiChannelResampler(builder)
         , mSingleFrame2(builder.getChannelCount()) {
     assert((getNumTaps() % 4) == 0); // Required for loop unrolling.
-    mNumRows = kMaxCoefficients / getNumTaps(); // no guard row needed
-//    printf("SincResampler: numRows = %d\n", mNumRows);
-    mPhaseScaler = (double) mNumRows / mDenominator;
-    double phaseIncrement = 1.0 / mNumRows;
+    mNumRows = kMaxCoefficients / getNumTaps(); // includes guard row
+    const int32_t numRowsNoGuard = mNumRows - 1;
+    mPhaseScaler = (double) numRowsNoGuard / mDenominator;
+    const double phaseIncrement = 1.0 / numRowsNoGuard;
     generateCoefficients(builder.getInputRate(),
                          builder.getOutputRate(),
                          mNumRows,
@@ -41,37 +41,31 @@
     std::fill(mSingleFrame2.begin(), mSingleFrame2.end(), 0.0);
 
     // Determine indices into coefficients table.
-    double tablePhase = getIntegerPhase() * mPhaseScaler;
-    int index1 = static_cast<int>(floor(tablePhase));
-    if (index1 >= mNumRows) { // no guard row needed because we wrap the indices
-        tablePhase -= mNumRows;
-        index1 -= mNumRows;
-    }
+    const double tablePhase = getIntegerPhase() * mPhaseScaler;
+    const int indexLow = static_cast<int>(floor(tablePhase));
+    const int indexHigh = indexLow + 1; // OK because using a guard row.
+    assert (indexHigh < mNumRows);
+    float *coefficientsLow = &mCoefficients[static_cast<size_t>(indexLow)
+                                            * static_cast<size_t>(getNumTaps())];
+    float *coefficientsHigh = &mCoefficients[static_cast<size_t>(indexHigh)
+                                             * static_cast<size_t>(getNumTaps())];
 
-    int index2 = index1 + 1;
-    if (index2 >= mNumRows) { // no guard row needed because we wrap the indices
-        index2 -= mNumRows;
-    }
-
-    float *coefficients1 = &mCoefficients[index1 * getNumTaps()];
-    float *coefficients2 = &mCoefficients[index2 * getNumTaps()];
-
-    float *xFrame = &mX[mCursor * getChannelCount()];
-    for (int i = 0; i < mNumTaps; i++) {
-        float coefficient1 = *coefficients1++;
-        float coefficient2 = *coefficients2++;
+    float *xFrame = &mX[static_cast<size_t>(mCursor) * static_cast<size_t>(getChannelCount())];
+    for (int tap = 0; tap < mNumTaps; tap++) {
+        const float coefficientLow = *coefficientsLow++;
+        const float coefficientHigh = *coefficientsHigh++;
         for (int channel = 0; channel < getChannelCount(); channel++) {
-            float sample = *xFrame++;
-            mSingleFrame[channel] +=  sample * coefficient1;
-            mSingleFrame2[channel] += sample * coefficient2;
+            const float sample = *xFrame++;
+            mSingleFrame[channel] += sample * coefficientLow;
+            mSingleFrame2[channel] += sample * coefficientHigh;
         }
     }
 
     // Interpolate and copy to output.
-    float fraction = tablePhase - index1;
+    const float fraction = tablePhase - indexLow;
     for (int channel = 0; channel < getChannelCount(); channel++) {
-        float low = mSingleFrame[channel];
-        float high = mSingleFrame2[channel];
+        const float low = mSingleFrame[channel];
+        const float high = mSingleFrame2[channel];
         frame[channel] = low + (fraction * (high - low));
     }
 }
diff --git a/src/flowgraph/resampler/SincResampler.h b/src/flowgraph/resampler/SincResampler.h
index 6ab61c9..05ff092 100644
--- a/src/flowgraph/resampler/SincResampler.h
+++ b/src/flowgraph/resampler/SincResampler.h
@@ -14,15 +14,17 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_SINC_RESAMPLER_H
-#define OBOE_SINC_RESAMPLER_H
+#ifndef RESAMPLER_SINC_RESAMPLER_H
+#define RESAMPLER_SINC_RESAMPLER_H
 
 #include <memory>
 #include <sys/types.h>
 #include <unistd.h>
-#include "MultiChannelResampler.h"
 
-namespace resampler {
+#include "MultiChannelResampler.h"
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
 
 /**
  * Resampler that can interpolate between coefficients.
@@ -43,5 +45,6 @@
     double             mPhaseScaler = 1.0;
 };
 
-}
-#endif //OBOE_SINC_RESAMPLER_H
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
+
+#endif //RESAMPLER_SINC_RESAMPLER_H
diff --git a/src/flowgraph/resampler/SincResamplerStereo.cpp b/src/flowgraph/resampler/SincResamplerStereo.cpp
index ce00302..d459abf 100644
--- a/src/flowgraph/resampler/SincResamplerStereo.cpp
+++ b/src/flowgraph/resampler/SincResamplerStereo.cpp
@@ -19,7 +19,7 @@
 
 #include "SincResamplerStereo.h"
 
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
 
 #define STEREO  2
 
@@ -54,13 +54,12 @@
     // Determine indices into coefficients table.
     double tablePhase = getIntegerPhase() * mPhaseScaler;
     int index1 = static_cast<int>(floor(tablePhase));
-    float *coefficients1 = &mCoefficients[index1 * getNumTaps()];
+    float *coefficients1 = &mCoefficients[static_cast<size_t>(index1)
+            * static_cast<size_t>(getNumTaps())];
     int index2 = (index1 + 1);
-    if (index2 >= mNumRows) { // no guard row needed because we wrap the indices
-        index2 = 0;
-    }
-    float *coefficients2 = &mCoefficients[index2 * getNumTaps()];
-    float *xFrame = &mX[mCursor * getChannelCount()];
+    float *coefficients2 = &mCoefficients[static_cast<size_t>(index2)
+            * static_cast<size_t>(getNumTaps())];
+    float *xFrame = &mX[static_cast<size_t>(mCursor) * static_cast<size_t>(getChannelCount())];
     for (int i = 0; i < mNumTaps; i++) {
         float coefficient1 = *coefficients1++;
         float coefficient2 = *coefficients2++;
diff --git a/src/flowgraph/resampler/SincResamplerStereo.h b/src/flowgraph/resampler/SincResamplerStereo.h
index 7d66c26..d5576d1 100644
--- a/src/flowgraph/resampler/SincResamplerStereo.h
+++ b/src/flowgraph/resampler/SincResamplerStereo.h
@@ -14,14 +14,16 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_SINC_RESAMPLER_STEREO_H
-#define OBOE_SINC_RESAMPLER_STEREO_H
+#ifndef RESAMPLER_SINC_RESAMPLER_STEREO_H
+#define RESAMPLER_SINC_RESAMPLER_STEREO_H
 
 #include <sys/types.h>
 #include <unistd.h>
-#include "SincResampler.h"
 
-namespace resampler {
+#include "SincResampler.h"
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
 
 class SincResamplerStereo : public SincResampler {
 public:
@@ -35,5 +37,6 @@
 
 };
 
-}
-#endif //OBOE_SINC_RESAMPLER_STEREO_H
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
+
+#endif //RESAMPLER_SINC_RESAMPLER_STEREO_H
diff --git a/src/opensles/AudioInputStreamOpenSLES.cpp b/src/opensles/AudioInputStreamOpenSLES.cpp
index b07b0cc..65298c4 100644
--- a/src/opensles/AudioInputStreamOpenSLES.cpp
+++ b/src/opensles/AudioInputStreamOpenSLES.cpp
@@ -19,6 +19,7 @@
 #include <SLES/OpenSLES.h>
 #include <SLES/OpenSLES_Android.h>
 
+#include "common/OboeDebug.h"
 #include "oboe/AudioStreamBuilder.h"
 #include "AudioInputStreamOpenSLES.h"
 #include "AudioStreamOpenSLES.h"
@@ -98,9 +99,10 @@
     SLuint32 bitsPerSample = static_cast<SLuint32>(getBytesPerSample() * kBitsPerByte);
 
     // configure audio sink
+    mBufferQueueLength = calculateOptimalBufferQueueLength();
     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
             SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,    // locatorType
-            static_cast<SLuint32>(kBufferQueueLength)};   // numBuffers
+            static_cast<SLuint32>(mBufferQueueLength)};   // numBuffers
 
     // Define the audio data format.
     SLDataFormat_PCM format_pcm = {
@@ -194,27 +196,16 @@
         goto error;
     }
 
-    result = AudioStreamOpenSLES::registerBufferQueueCallback();
+    result = finishCommonOpen(configItf);
     if (SL_RESULT_SUCCESS != result) {
         goto error;
     }
 
-    result = updateStreamParameters(configItf);
-    if (SL_RESULT_SUCCESS != result) {
-        goto error;
-    }
-
-    oboeResult = configureBufferSizes(mSampleRate);
-    if (Result::OK != oboeResult) {
-        goto error;
-    }
-
-    allocateFifo();
-
     setState(StreamState::Open);
     return Result::OK;
 
 error:
+    close(); // Clean up various OpenSL objects and prevent resource leaks.
     return Result::ErrorInternal; // TODO convert error from SLES to OBOE
 }
 
@@ -225,7 +216,10 @@
     if (getState() == StreamState::Closed){
         result = Result::ErrorClosed;
     } else {
-        requestStop_l();
+        (void) requestStop_l();
+        if (OboeGlobals::areWorkaroundsEnabled()) {
+            sleepBeforeClose();
+        }
         // invalidate any interfaces
         mRecordInterface = nullptr;
         result = AudioStreamOpenSLES::close_l();
@@ -238,7 +232,7 @@
     Result result = Result::OK;
 
     if (mRecordInterface == nullptr) {
-        LOGE("AudioInputStreamOpenSLES::%s() mRecordInterface is null", __func__);
+        LOGW("AudioInputStreamOpenSLES::%s() mRecordInterface is null", __func__);
         return Result::ErrorInvalidState;
     }
     SLresult slResult = (*mRecordInterface)->SetRecordState(mRecordInterface, newState);
@@ -270,12 +264,16 @@
     setDataCallbackEnabled(true);
 
     setState(StreamState::Starting);
-    Result result = setRecordState_l(SL_RECORDSTATE_RECORDING);
-    if (result == Result::OK) {
-        setState(StreamState::Started);
+
+    if (getBufferDepth(mSimpleBufferQueueInterface) == 0) {
         // Enqueue the first buffer to start the streaming.
         // This does not call the callback function.
         enqueueCallbackBuffer(mSimpleBufferQueueInterface);
+    }
+
+    Result result = setRecordState_l(SL_RECORDSTATE_RECORDING);
+    if (result == Result::OK) {
+        setState(StreamState::Started);
     } else {
         setState(initialState);
     }
@@ -308,6 +306,7 @@
         case StreamState::Stopping:
         case StreamState::Stopped:
             return Result::OK;
+        case StreamState::Uninitialized:
         case StreamState::Closed:
             return Result::ErrorClosed;
         default:
diff --git a/src/opensles/AudioOutputStreamOpenSLES.cpp b/src/opensles/AudioOutputStreamOpenSLES.cpp
index 5791b5e..6d480d2 100644
--- a/src/opensles/AudioOutputStreamOpenSLES.cpp
+++ b/src/opensles/AudioOutputStreamOpenSLES.cpp
@@ -20,6 +20,7 @@
 #include <SLES/OpenSLES_Android.h>
 #include <common/AudioClock.h>
 
+#include "common/OboeDebug.h"
 #include "oboe/AudioStreamBuilder.h"
 #include "AudioOutputStreamOpenSLES.h"
 #include "AudioStreamOpenSLES.h"
@@ -140,9 +141,10 @@
     SLuint32 bitsPerSample = static_cast<SLuint32>(getBytesPerSample() * kBitsPerByte);
 
     // configure audio source
+    mBufferQueueLength = calculateOptimalBufferQueueLength();
     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
             SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,    // locatorType
-            static_cast<SLuint32>(kBufferQueueLength)};   // numBuffers
+            static_cast<SLuint32>(mBufferQueueLength)};   // numBuffers
 
     // Define the audio data format.
     SLDataFormat_PCM format_pcm = {
@@ -213,27 +215,16 @@
         goto error;
     }
 
-    result = AudioStreamOpenSLES::registerBufferQueueCallback();
+    result = finishCommonOpen(configItf);
     if (SL_RESULT_SUCCESS != result) {
         goto error;
     }
 
-    result = updateStreamParameters(configItf);
-    if (SL_RESULT_SUCCESS != result) {
-        goto error;
-    }
-
-    oboeResult = configureBufferSizes(mSampleRate);
-    if (Result::OK != oboeResult) {
-        goto error;
-    }
-
-    allocateFifo();
-
     setState(StreamState::Open);
     return Result::OK;
 
 error:
+    close();  // Clean up various OpenSL objects and prevent resource leaks.
     return Result::ErrorInternal; // TODO convert error from SLES to OBOE
 }
 
@@ -249,7 +240,10 @@
     if (getState() == StreamState::Closed){
         result = Result::ErrorClosed;
     } else {
-        requestPause_l();
+        (void) requestPause_l();
+        if (OboeGlobals::areWorkaroundsEnabled()) {
+            sleepBeforeClose();
+        }
         // invalidate any interfaces
         mPlayInterface = nullptr;
         result = AudioStreamOpenSLES::close_l();
@@ -297,15 +291,26 @@
     setDataCallbackEnabled(true);
 
     setState(StreamState::Starting);
+
+    if (getBufferDepth(mSimpleBufferQueueInterface) == 0) {
+        // Enqueue the first buffer if needed to start the streaming.
+        // We may need to stop the current stream.
+        bool shouldStopStream = processBufferCallback(mSimpleBufferQueueInterface);
+        if (shouldStopStream) {
+            LOGD("Stopping the current stream.");
+            if (requestStop_l() != Result::OK) {
+                LOGW("Failed to flush the stream. Error %s", convertToText(flush()));
+            }
+            setState(initialState);
+            mLock.unlock();
+            return Result::ErrorClosed;
+        }
+    }
+
     Result result = setPlayState_l(SL_PLAYSTATE_PLAYING);
     if (result == Result::OK) {
         setState(StreamState::Started);
         mLock.unlock();
-        if (getBufferDepth(mSimpleBufferQueueInterface) == 0) {
-            // Enqueue the first buffer if needed to start the streaming.
-            // This might call requestStop() so try to avoid a recursive lock.
-            processBufferCallback(mSimpleBufferQueueInterface);
-        }
     } else {
         setState(initialState);
         mLock.unlock();
@@ -326,6 +331,7 @@
         case StreamState::Pausing:
         case StreamState::Paused:
             return Result::OK;
+        case StreamState::Uninitialized:
         case StreamState::Closed:
             return Result::ErrorClosed;
         default:
@@ -375,14 +381,19 @@
 }
 
 Result AudioOutputStreamOpenSLES::requestStop() {
-    LOGD("AudioOutputStreamOpenSLES(): %s() called", __func__);
     std::lock_guard<std::mutex> lock(mLock);
+    return requestStop_l();
+}
+
+Result AudioOutputStreamOpenSLES::requestStop_l() {
+    LOGD("AudioOutputStreamOpenSLES(): %s() called", __func__);
 
     StreamState initialState = getState();
     switch (initialState) {
         case StreamState::Stopping:
         case StreamState::Stopped:
             return Result::OK;
+        case StreamState::Uninitialized:
         case StreamState::Closed:
             return Result::ErrorClosed;
         default:
diff --git a/src/opensles/AudioOutputStreamOpenSLES.h b/src/opensles/AudioOutputStreamOpenSLES.h
index ed11eb9..fc57fd3 100644
--- a/src/opensles/AudioOutputStreamOpenSLES.h
+++ b/src/opensles/AudioOutputStreamOpenSLES.h
@@ -61,6 +61,8 @@
 
     Result requestFlush_l();
 
+    Result requestStop_l();
+
     /**
      * Set OpenSL ES PLAYSTATE.
      *
diff --git a/src/opensles/AudioStreamBuffered.cpp b/src/opensles/AudioStreamBuffered.cpp
index 298c1eb..9737b72 100644
--- a/src/opensles/AudioStreamBuffered.cpp
+++ b/src/opensles/AudioStreamBuffered.cpp
@@ -18,6 +18,7 @@
 
 #include "oboe/Oboe.h"
 
+#include "common/OboeDebug.h"
 #include "opensles/AudioStreamBuffered.h"
 #include "common/AudioClock.h"
 
@@ -54,9 +55,10 @@
                 capacityFrames = numBursts * getFramesPerBurst();
             }
         }
-        // TODO consider using std::make_unique if we require c++14
-        mFifoBuffer.reset(new FifoBuffer(getBytesPerFrame(), capacityFrames));
+
+        mFifoBuffer = std::make_unique<FifoBuffer>(getBytesPerFrame(), capacityFrames);
         mBufferCapacityInFrames = capacityFrames;
+        mBufferSizeInFrames = mBufferCapacityInFrames;
     }
 }
 
@@ -280,4 +282,4 @@
     return (!isDataCallbackSpecified());
 }
 
-} // namespace oboe
\ No newline at end of file
+} // namespace oboe
diff --git a/src/opensles/AudioStreamBuffered.h b/src/opensles/AudioStreamBuffered.h
index d7e8885..3080ce6 100644
--- a/src/opensles/AudioStreamBuffered.h
+++ b/src/opensles/AudioStreamBuffered.h
@@ -22,7 +22,7 @@
 #include "common/OboeDebug.h"
 #include "oboe/AudioStream.h"
 #include "oboe/AudioStreamCallback.h"
-#include "fifo/FifoBuffer.h"
+#include "oboe/FifoBuffer.h"
 
 namespace oboe {
 
@@ -49,7 +49,7 @@
 
     int32_t getBufferCapacityInFrames() const override;
 
-    ResultWithValue<int32_t> getXRunCount() const override {
+    ResultWithValue<int32_t> getXRunCount() override {
         return ResultWithValue<int32_t>(mXRunCount);
     }
 
diff --git a/src/opensles/AudioStreamOpenSLES.cpp b/src/opensles/AudioStreamOpenSLES.cpp
index 2b69935..62692a4 100644
--- a/src/opensles/AudioStreamOpenSLES.cpp
+++ b/src/opensles/AudioStreamOpenSLES.cpp
@@ -16,7 +16,6 @@
 #include <cassert>
 #include <android/log.h>
 
-
 #include <SLES/OpenSLES.h>
 #include <SLES/OpenSLES_Android.h>
 #include <oboe/AudioStream.h>
@@ -71,6 +70,13 @@
 
     LOGI("AudioStreamOpenSLES::open() chans=%d, rate=%d", mChannelCount, mSampleRate);
 
+    // OpenSL ES only supports I16 and Float
+    if (mFormat != AudioFormat::I16 && mFormat != AudioFormat::Float) {
+        LOGW("%s() Android's OpenSL ES implementation only supports I16 and Float. Format: %d",
+             __func__, mFormat);
+        return Result::ErrorInvalidFormat;
+    }
+
     SLresult result = EngineOpenSLES::getInstance().open();
     if (SL_RESULT_SUCCESS != result) {
         return Result::ErrorInternal;
@@ -78,6 +84,7 @@
 
     Result oboeResult = AudioStreamBuffered::open();
     if (oboeResult != Result::OK) {
+        EngineOpenSLES::getInstance().close();
         return oboeResult;
     }
     // Convert to defaults if UNSPECIFIED
@@ -87,41 +94,102 @@
     if (mChannelCount == kUnspecified) {
         mChannelCount = DefaultStreamValues::ChannelCount;
     }
+    if (mContentType == kUnspecified) {
+        mContentType = ContentType::Music;
+    }
+    if (static_cast<const int32_t>(mUsage) == kUnspecified) {
+        mUsage = Usage::Media;
+    }
 
     mSharingMode = SharingMode::Shared;
 
     return Result::OK;
 }
 
+
+SLresult AudioStreamOpenSLES::finishCommonOpen(SLAndroidConfigurationItf configItf) {
+    SLresult result = registerBufferQueueCallback();
+    if (SL_RESULT_SUCCESS != result) {
+        return result;
+    }
+
+    result = updateStreamParameters(configItf);
+    if (SL_RESULT_SUCCESS != result) {
+        return result;
+    }
+
+    Result oboeResult = configureBufferSizes(mSampleRate);
+    if (Result::OK != oboeResult) {
+        return (SLresult) oboeResult;
+    }
+
+    allocateFifo();
+
+    calculateDefaultDelayBeforeCloseMillis();
+
+    return SL_RESULT_SUCCESS;
+}
+
+static int32_t roundUpDivideByN(int32_t x, int32_t n) {
+    return (x + n - 1) / n;
+}
+
+int32_t AudioStreamOpenSLES::calculateOptimalBufferQueueLength() {
+    int32_t queueLength = kBufferQueueLengthDefault;
+    int32_t likelyFramesPerBurst = estimateNativeFramesPerBurst();
+    int32_t minCapacity = mBufferCapacityInFrames; // specified by app or zero
+    // The buffer capacity needs to be at least twice the size of the requested callbackSize
+    // so that we can have double buffering.
+    minCapacity = std::max(minCapacity, kDoubleBufferCount * mFramesPerCallback);
+    if (minCapacity > 0) {
+        int32_t queueLengthFromCapacity = roundUpDivideByN(minCapacity, likelyFramesPerBurst);
+        queueLength = std::max(queueLength, queueLengthFromCapacity);
+    }
+    queueLength = std::min(queueLength, kBufferQueueLengthMax); // clip to max
+    // TODO Investigate the effect of queueLength on latency for normal streams. (not low latency)
+    return queueLength;
+}
+
+/**
+ * The best information we have is if DefaultStreamValues::FramesPerBurst
+ * was set by the app based on AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER.
+ * Without that we just have to guess.
+ * @return
+ */
+int32_t AudioStreamOpenSLES::estimateNativeFramesPerBurst() {
+    int32_t framesPerBurst = DefaultStreamValues::FramesPerBurst;
+    LOGD("AudioStreamOpenSLES:%s() DefaultStreamValues::FramesPerBurst = %d",
+            __func__, DefaultStreamValues::FramesPerBurst);
+    framesPerBurst = std::max(framesPerBurst, 16);
+    // Calculate the size of a fixed duration high latency buffer based on sample rate.
+    // Estimate sample based on default options in order of priority.
+    int32_t sampleRate = 48000;
+    sampleRate = (DefaultStreamValues::SampleRate > 0)
+            ? DefaultStreamValues::SampleRate : sampleRate;
+    sampleRate = (mSampleRate > 0) ? mSampleRate : sampleRate;
+    int32_t framesPerHighLatencyBuffer =
+            (kHighLatencyBufferSizeMillis * sampleRate) / kMillisPerSecond;
+    // For high latency streams, use a larger buffer size.
+    // Performance Mode support was added in N_MR1 (7.1)
+    if (getSdkVersion() >= __ANDROID_API_N_MR1__
+            && mPerformanceMode != PerformanceMode::LowLatency
+            && framesPerBurst < framesPerHighLatencyBuffer) {
+        // Find a multiple of framesPerBurst >= framesPerHighLatencyBuffer.
+        int32_t numBursts = roundUpDivideByN(framesPerHighLatencyBuffer, framesPerBurst);
+        framesPerBurst *= numBursts;
+        LOGD("AudioStreamOpenSLES:%s() NOT low latency, numBursts = %d, mSampleRate = %d, set framesPerBurst = %d",
+             __func__, numBursts, mSampleRate, framesPerBurst);
+    }
+    return framesPerBurst;
+}
+
 Result AudioStreamOpenSLES::configureBufferSizes(int32_t sampleRate) {
     LOGD("AudioStreamOpenSLES:%s(%d) initial mFramesPerBurst = %d, mFramesPerCallback = %d",
-            __func__, sampleRate, mFramesPerBurst, mFramesPerCallback);
-    // Decide frames per burst based on hints from caller.
-    if (mFramesPerCallback != kUnspecified) {
-        // Requested framesPerCallback must be honored.
-        mFramesPerBurst = mFramesPerCallback;
-    } else {
-        mFramesPerBurst = DefaultStreamValues::FramesPerBurst;
-
-        // Calculate the size of a fixed duration high latency buffer based on sample rate.
-        int32_t framesPerHighLatencyBuffer =
-                (kHighLatencyBufferSizeMillis * sampleRate) / kMillisPerSecond;
-
-        // For high latency streams, use a larger buffer size.
-        // Performance Mode support was added in N_MR1 (7.1)
-        if (getSdkVersion() >= __ANDROID_API_N_MR1__
-            && mPerformanceMode != PerformanceMode::LowLatency
-            && mFramesPerBurst < framesPerHighLatencyBuffer) {
-            // Find a multiple of framesPerBurst >= framesPerHighLatencyBuffer.
-            int32_t numBursts = (framesPerHighLatencyBuffer + mFramesPerBurst - 1) / mFramesPerBurst;
-            mFramesPerBurst *= numBursts;
-            LOGD("AudioStreamOpenSLES:%s() NOT low latency, set mFramesPerBurst = %d",
-                 __func__, mFramesPerBurst);
-        }
-        mFramesPerCallback = mFramesPerBurst;
-    }
+            __func__, mSampleRate, mFramesPerBurst, mFramesPerCallback);
+    mFramesPerBurst = estimateNativeFramesPerBurst();
+    mFramesPerCallback = (mFramesPerCallback > 0) ? mFramesPerCallback : mFramesPerBurst;
     LOGD("AudioStreamOpenSLES:%s(%d) final mFramesPerBurst = %d, mFramesPerCallback = %d",
-         __func__, sampleRate, mFramesPerBurst, mFramesPerCallback);
+         __func__, mSampleRate, mFramesPerBurst, mFramesPerCallback);
 
     mBytesPerCallback = mFramesPerCallback * getBytesPerFrame();
     if (mBytesPerCallback <= 0) {
@@ -130,10 +198,12 @@
         return Result::ErrorInvalidFormat; // causing bytesPerFrame == 0
     }
 
-    mCallbackBuffer = std::make_unique<uint8_t[]>(mBytesPerCallback);
+    for (int i = 0; i < mBufferQueueLength; ++i) {
+        mCallbackBuffer[i] = std::make_unique<uint8_t[]>(mBytesPerCallback);
+    }
 
     if (!usingFIFO()) {
-        mBufferCapacityInFrames = mFramesPerBurst * kBufferQueueLength;
+        mBufferCapacityInFrames = mFramesPerBurst * mBufferQueueLength;
         // Check for overflow.
         if (mBufferCapacityInFrames <= 0) {
             mBufferCapacityInFrames = 0;
@@ -292,7 +362,10 @@
 }
 
 SLresult AudioStreamOpenSLES::enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq) {
-    return (*bq)->Enqueue(bq, mCallbackBuffer.get(), mBytesPerCallback);
+    SLresult result = (*bq)->Enqueue(
+            bq, mCallbackBuffer[mCallbackBufferIndex].get(), mBytesPerCallback);
+    mCallbackBufferIndex = (mCallbackBufferIndex + 1) % mBufferQueueLength;
+    return result;
 }
 
 int32_t AudioStreamOpenSLES::getBufferDepth(SLAndroidSimpleBufferQueueItf bq) {
@@ -301,16 +374,17 @@
     return (result == SL_RESULT_SUCCESS) ? queueState.count : -1;
 }
 
-void AudioStreamOpenSLES::processBufferCallback(SLAndroidSimpleBufferQueueItf bq) {
-    bool stopStream = false;
+bool AudioStreamOpenSLES::processBufferCallback(SLAndroidSimpleBufferQueueItf bq) {
+    bool shouldStopStream = false;
     // Ask the app callback to process the buffer.
-    DataCallbackResult result = fireDataCallback(mCallbackBuffer.get(), mFramesPerCallback);
+    DataCallbackResult result =
+            fireDataCallback(mCallbackBuffer[mCallbackBufferIndex].get(), mFramesPerCallback);
     if (result == DataCallbackResult::Continue) {
         // Pass the buffer to OpenSLES.
         SLresult enqueueResult = enqueueCallbackBuffer(bq);
         if (enqueueResult != SL_RESULT_SUCCESS) {
             LOGE("%s() returned %d", __func__, enqueueResult);
-            stopStream = true;
+            shouldStopStream = true;
         }
         // Update Oboe client position with frames handled by the callback.
         if (getDirection() == Direction::Input) {
@@ -320,19 +394,24 @@
         }
     } else if (result == DataCallbackResult::Stop) {
         LOGD("Oboe callback returned Stop");
-        stopStream = true;
+        shouldStopStream = true;
     } else {
         LOGW("Oboe callback returned unexpected value = %d", result);
-        stopStream = true;
+        shouldStopStream = true;
     }
-    if (stopStream) {
-        requestStop();
+    if (shouldStopStream) {
+        mCallbackBufferIndex = 0;
     }
+    return shouldStopStream;
 }
 
 // This callback handler is called every time a buffer has been processed by OpenSL ES.
 static void bqCallbackGlue(SLAndroidSimpleBufferQueueItf bq, void *context) {
-    (reinterpret_cast<AudioStreamOpenSLES *>(context))->processBufferCallback(bq);
+    bool shouldStopStream = (reinterpret_cast<AudioStreamOpenSLES *>(context))
+            ->processBufferCallback(bq);
+    if (shouldStopStream) {
+        (reinterpret_cast<AudioStreamOpenSLES *>(context))->requestStop();
+    }
 }
 
 SLresult AudioStreamOpenSLES::registerBufferQueueCallback() {
@@ -354,10 +433,6 @@
     return result;
 }
 
-int32_t AudioStreamOpenSLES::getFramesPerBurst() {
-    return mFramesPerBurst;
-}
-
 int64_t AudioStreamOpenSLES::getFramesProcessedByServer() {
     updateServiceFrameCounter();
     int64_t millis64 = mPositionMillis.get();
diff --git a/src/opensles/AudioStreamOpenSLES.h b/src/opensles/AudioStreamOpenSLES.h
index 10a730b..0164b83 100644
--- a/src/opensles/AudioStreamOpenSLES.h
+++ b/src/opensles/AudioStreamOpenSLES.h
@@ -30,7 +30,8 @@
 namespace oboe {
 
 constexpr int kBitsPerByte = 8;
-constexpr int kBufferQueueLength = 2; // double buffered for callbacks
+constexpr int kBufferQueueLengthDefault = 2; // double buffered for callbacks
+constexpr int kBufferQueueLengthMax = 8; // AudioFlinger won't use more than 8
 
 /**
  * INTERNAL USE ONLY
@@ -56,10 +57,7 @@
      *
      * @return state or a negative error.
      */
-    StreamState getState() const override { return mState.load(); }
-
-    int32_t getFramesPerBurst() override;
-
+    StreamState getState() override { return mState.load(); }
 
     AudioApi getAudioApi() const override {
         return AudioApi::OpenSLES;
@@ -70,8 +68,10 @@
      * Called by by OpenSL ES framework.
      *
      * This is public, but don't call it directly.
+     *
+     * @return whether the current stream should be stopped.
      */
-    void processBufferCallback(SLAndroidSimpleBufferQueueItf bq);
+    bool processBufferCallback(SLAndroidSimpleBufferQueueItf bq);
 
     Result waitForStateChange(StreamState currentState,
                               StreamState *nextState,
@@ -79,6 +79,14 @@
 
 protected:
 
+    /**
+     * Finish setting up the stream. Common for INPUT and OUTPUT.
+     *
+     * @param configItf
+     * @return SL_RESULT_SUCCESS if OK.
+     */
+    SLresult finishCommonOpen(SLAndroidConfigurationItf configItf);
+
     // This must be called under mLock.
     Result close_l();
 
@@ -89,21 +97,18 @@
 
     static SLuint32 getDefaultByteOrder();
 
-    SLresult registerBufferQueueCallback();
-
     int32_t getBufferDepth(SLAndroidSimpleBufferQueueItf bq);
 
+    int32_t calculateOptimalBufferQueueLength();
+    int32_t estimateNativeFramesPerBurst();
+
     SLresult enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq);
 
     SLresult configurePerformanceMode(SLAndroidConfigurationItf configItf);
 
-    SLresult updateStreamParameters(SLAndroidConfigurationItf configItf);
-
     PerformanceMode convertPerformanceMode(SLuint32 openslMode) const;
     SLuint32 convertPerformanceMode(PerformanceMode oboeMode) const;
 
-    Result configureBufferSizes(int32_t sampleRate);
-
     void logUnsupportedAttributes();
 
     /**
@@ -119,12 +124,21 @@
     // OpenSLES stuff
     SLObjectItf                   mObjectInterface = nullptr;
     SLAndroidSimpleBufferQueueItf mSimpleBufferQueueInterface = nullptr;
+    int                           mBufferQueueLength = 0;
 
     int32_t                       mBytesPerCallback = oboe::kUnspecified;
     MonotonicCounter              mPositionMillis; // for tracking OpenSL ES service position
 
 private:
-    std::unique_ptr<uint8_t[]>    mCallbackBuffer;
+
+    constexpr static int kDoubleBufferCount = 2;
+
+    SLresult registerBufferQueueCallback();
+    SLresult updateStreamParameters(SLAndroidConfigurationItf configItf);
+    Result configureBufferSizes(int32_t sampleRate);
+
+    std::unique_ptr<uint8_t[]>    mCallbackBuffer[kBufferQueueLengthMax];
+    int                           mCallbackBufferIndex = 0;
     std::atomic<StreamState>      mState{StreamState::Uninitialized};
 
 };
diff --git a/src/opensles/EngineOpenSLES.cpp b/src/opensles/EngineOpenSLES.cpp
index d82219e..e1007d1 100644
--- a/src/opensles/EngineOpenSLES.cpp
+++ b/src/opensles/EngineOpenSLES.cpp
@@ -14,12 +14,47 @@
  * limitations under the License.
  */
 
+#include <dlfcn.h>
 #include "common/OboeDebug.h"
 #include "EngineOpenSLES.h"
 #include "OpenSLESUtilities.h"
 
 using namespace oboe;
 
+// OpenSL ES is deprecated in SDK 30.
+// So we use custom dynamic linking to access the library.
+#define LIB_OPENSLES_NAME "libOpenSLES.so"
+typedef SLresult  (*prototype_slCreateEngine)(
+        SLObjectItf             *pEngine,
+        SLuint32                numOptions,
+        const SLEngineOption    *pEngineOptions,
+        SLuint32                numInterfaces,
+        const SLInterfaceID     *pInterfaceIds,
+        const SLboolean         *pInterfaceRequired
+);
+static prototype_slCreateEngine gFunction_slCreateEngine = nullptr;
+static void *gLibOpenSlesLibraryHandle = nullptr;
+
+// Load the OpenSL ES library and the one primary entry point.
+// @return true if linked OK
+static bool linkOpenSLES() {
+    if (gLibOpenSlesLibraryHandle == nullptr && gFunction_slCreateEngine == nullptr) {
+        // Use RTLD_NOW to avoid the unpredictable behavior that RTLD_LAZY can cause.
+        // Also resolving all the links now will prevent a run-time penalty later.
+        gLibOpenSlesLibraryHandle = dlopen(LIB_OPENSLES_NAME, RTLD_NOW);
+        if (gLibOpenSlesLibraryHandle == nullptr) {
+            LOGE("linkOpenSLES() could not find " LIB_OPENSLES_NAME);
+        } else {
+            gFunction_slCreateEngine = (prototype_slCreateEngine) dlsym(
+                    gLibOpenSlesLibraryHandle,
+                    "slCreateEngine");
+            LOGD("linkOpenSLES(): dlsym(%s) returned %p", "slCreateEngine",
+                 gFunction_slCreateEngine);
+        }
+    }
+    return gFunction_slCreateEngine != nullptr;
+}
+
 EngineOpenSLES &EngineOpenSLES::getInstance() {
     static EngineOpenSLES sInstance;
     return sInstance;
@@ -30,9 +65,14 @@
 
     SLresult result = SL_RESULT_SUCCESS;
     if (mOpenCount++ == 0) {
+        // load the library and link to it
+        if (!linkOpenSLES()) {
+            result = SL_RESULT_FEATURE_UNSUPPORTED;
+            goto error;
+        };
 
         // create engine
-        result = slCreateEngine(&mEngineObject, 0, NULL, 0, NULL, NULL);
+        result = (*gFunction_slCreateEngine)(&mEngineObject, 0, NULL, 0, NULL, NULL);
         if (SL_RESULT_SUCCESS != result) {
             LOGE("EngineOpenSLES - slCreateEngine() result:%s", getSLErrStr(result));
             goto error;
diff --git a/src/opensles/OpenSLESUtilities.cpp b/src/opensles/OpenSLESUtilities.cpp
index 4be23b3..6d25e79 100644
--- a/src/opensles/OpenSLESUtilities.cpp
+++ b/src/opensles/OpenSLESUtilities.cpp
@@ -83,6 +83,8 @@
             return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
         case AudioFormat::Float:
             return SL_ANDROID_PCM_REPRESENTATION_FLOAT;
+        case AudioFormat::I24:
+        case AudioFormat::I32:
         case AudioFormat::Invalid:
         case AudioFormat::Unspecified:
         default:
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 1e8b459..ddbff2d 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -7,7 +7,7 @@
 # This may work on Linux.
 # set(ANDROID_NDK $ENV{HOME}/Android/sdk/ndk-bundle)
 
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++14")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++17")
 
 # Include GoogleTest library
 set(GOOGLETEST_ROOT ${ANDROID_NDK}/sources/third_party/googletest)
@@ -25,15 +25,19 @@
 
 # Build the test binary
 add_executable(
-        testOboe
-        testAAudio.cpp
-        testUtilities.cpp
-        testFlowgraph.cpp
-        testStreamClosedMethods.cpp
-        testStreamWaitState.cpp
-        testXRunBehaviour.cpp
-        testStreamOpen.cpp
-        testStreamStates.cpp
+		testOboe
+		testAAudio.cpp
+		testFlowgraph.cpp
+		testResampler.cpp
+		testReturnStop.cpp
+		testStreamClosedMethods.cpp
+		testStreamFramesProcessed.cpp
+		testStreamOpen.cpp
+		testStreamStates.cpp
+		testStreamStop.cpp
+		testStreamWaitState.cpp
+		testXRunBehaviour.cpp
+		testUtilities.cpp
         )
 
 target_link_libraries(testOboe gtest oboe)
diff --git a/tests/README.md b/tests/README.md
index 107e287..c836568 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -9,9 +9,10 @@
 
 ## Prerequisites/caveats
 
-You must have compiled and executed one of the Oboe examples or OboeTester. That ensures that the NDK and cmake is installed.
-
-You must define `ANDROID_NDK` as an environment variable and make sure `cmake` is on your path.
+1. Java JDK installed.
+2. On Mac, you must agree to the XCode license. The script will prompt you.
+3. You must have compiled and executed one of the Oboe examples or OboeTester. That ensures that the NDK and cmake is installed.
+4. You must define `ANDROID_NDK` as an environment variable and make sure `cmake` is on your path.
 
 To test this on Mac or Linux enter:
 
diff --git a/tests/UnitTestRunner/app/build.gradle b/tests/UnitTestRunner/app/build.gradle
index e44a5ec..8547843 100644
--- a/tests/UnitTestRunner/app/build.gradle
+++ b/tests/UnitTestRunner/app/build.gradle
@@ -1,11 +1,11 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 28
+    compileSdkVersion 33
     defaultConfig {
         applicationId "com.google.oboe.tests.unittestrunner"
-        minSdkVersion 16
-        targetSdkVersion 28
+        minSdkVersion 21
+        targetSdkVersion 33
         versionCode 1
         versionName "1.0"
     }
@@ -15,10 +15,15 @@
             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
         }
     }
+    externalNativeBuild {
+        cmake {
+            path file('../../CMakeLists.txt')
+        }
+    }
 }
 
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
-    implementation 'androidx.appcompat:appcompat:1.0.0-rc02'
+    implementation 'androidx.appcompat:appcompat:1.1.0'
     implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
 }
diff --git a/tests/UnitTestRunner/app/src/main/.gitignore b/tests/UnitTestRunner/app/src/main/.gitignore
new file mode 100644
index 0000000..95dab48
--- /dev/null
+++ b/tests/UnitTestRunner/app/src/main/.gitignore
@@ -0,0 +1,2 @@
+/assets
+/jniLibs
diff --git a/tests/UnitTestRunner/app/src/main/AndroidManifest.xml b/tests/UnitTestRunner/app/src/main/AndroidManifest.xml
index 252be00..aad3df6 100644
--- a/tests/UnitTestRunner/app/src/main/AndroidManifest.xml
+++ b/tests/UnitTestRunner/app/src/main/AndroidManifest.xml
@@ -10,7 +10,7 @@
         android:roundIcon="@mipmap/ic_launcher_round"
         android:supportsRtl="true"
         android:theme="@style/AppTheme">
-        <activity android:name=".MainActivity" android:screenOrientation="landscape">
+        <activity android:name=".MainActivity" android:exported="true" android:screenOrientation="landscape">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
@@ -19,4 +19,4 @@
         </activity>
     </application>
 
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/tests/UnitTestRunner/app/src/main/assets/.gitignore b/tests/UnitTestRunner/app/src/main/assets/.gitignore
deleted file mode 100644
index 241e560..0000000
--- a/tests/UnitTestRunner/app/src/main/assets/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-
diff --git a/tests/UnitTestRunner/app/src/main/java/com/google/oboe/tests/unittestrunner/MainActivity.java b/tests/UnitTestRunner/app/src/main/java/com/google/oboe/tests/unittestrunner/MainActivity.java
index 802faaf..7541474 100644
--- a/tests/UnitTestRunner/app/src/main/java/com/google/oboe/tests/unittestrunner/MainActivity.java
+++ b/tests/UnitTestRunner/app/src/main/java/com/google/oboe/tests/unittestrunner/MainActivity.java
@@ -9,10 +9,8 @@
 import android.content.res.AssetManager;
 import android.os.Build;
 import android.os.Bundle;
-import android.text.method.ScrollingMovementMethod;
 import android.util.Log;
-import android.view.View;
-import android.widget.Button;
+import android.view.WindowManager;
 import android.widget.ScrollView;
 import android.widget.TextView;
 import android.widget.Toast;
@@ -28,7 +26,7 @@
 public class MainActivity extends AppCompatActivity {
 
     private final String TAG = MainActivity.class.getName();
-    private static final String TEST_BINARY_FILEANAME = "testOboe";
+    private static final String TEST_BINARY_FILENAME = "testOboe.so";
     private static final int APP_PERMISSION_REQUEST = 0;
 
     private TextView outputText;
@@ -38,6 +36,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
 
         outputText = findViewById(R.id.output_view_text);
         scrollView = findViewById(R.id.scroll_view);
@@ -48,27 +47,76 @@
         if (!isRecordPermissionGranted()){
             requestPermissions();
         } else {
-
+            Log.d(TAG, "Got RECORD_AUDIO permission");
             Thread commandThread = new Thread(new UnitTestCommand());
             commandThread.start();
         }
     }
 
     private String executeBinary() {
+        StringBuilder output = new StringBuilder();
 
+        try {
+            String executablePath;
+            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
+                executablePath = getApplicationInfo().nativeLibraryDir + "/" + TEST_BINARY_FILENAME;
+            } else {
+                executablePath = getExecutablePathFromAssets();
+            }
+
+            Log.d(TAG, "Attempting to execute " + executablePath);
+
+            Process process = Runtime.getRuntime().exec(executablePath);
+
+            BufferedReader stdInput = new BufferedReader(new
+                    InputStreamReader(process.getInputStream()));
+
+            BufferedReader stdError = new BufferedReader(new
+                    InputStreamReader(process.getErrorStream()));
+
+            // read the output from the command
+            String s;
+            while ((s = stdInput.readLine()) != null) {
+                Log.d(TAG, s);
+                output.append(s).append("\n");
+            }
+
+            // read any errors from the attempted command
+            while ((s = stdError.readLine()) != null) {
+                Log.e(TAG, "ERROR: " + s);
+                output.append("ERROR: ").append(s).append("\n");
+            }
+
+            process.waitFor();
+            Log.d(TAG, "Finished executing binary");
+        } catch (IOException e){
+            Log.e(TAG, "Could not execute binary ", e);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Interrupted", e);
+        }
+
+        return output.toString();
+    }
+
+    // Legacy method to get asset path.
+    // This will not work on more recent Android releases.
+    private String getExecutablePathFromAssets() {
         AssetManager assetManager = getAssets();
 
-        StringBuffer output = new StringBuffer();
-        String abi = Build.CPU_ABI;
+        String abi = Build.SUPPORTED_ABIS[0];
+        String extraStringForDebugBuilds = "-hwasan";
+        if (abi.endsWith(extraStringForDebugBuilds)) {
+            abi = abi.substring(0, abi.length() - extraStringForDebugBuilds.length());
+        }
         String filesDir = getFilesDir().getPath();
-        String testBinaryPath = abi + "/" + TEST_BINARY_FILEANAME;
+        String testBinaryPath = abi + "/" + TEST_BINARY_FILENAME;
 
         try {
             InputStream inStream = assetManager.open(testBinaryPath);
             Log.d(TAG, "Opened " + testBinaryPath);
 
             // Copy this file to an executable location
-            File outFile = new File(filesDir, TEST_BINARY_FILEANAME);
+            File outFile = new File(filesDir, TEST_BINARY_FILENAME);
 
             OutputStream outStream = new FileOutputStream(outFile);
 
@@ -82,42 +130,17 @@
             outStream.close();
             Log.d(TAG, "Copied " + testBinaryPath + " to " + filesDir);
 
-            String executablePath =  filesDir + "/" + TEST_BINARY_FILEANAME;
-            Log.d(TAG, "Attempting to execute " + executablePath);
-
-            new File(executablePath).setExecutable(true, false);
+            String executablePath = filesDir + "/" + TEST_BINARY_FILENAME;
             Log.d(TAG, "Setting execute permission on " + executablePath);
-
-            Process process = Runtime.getRuntime().exec(executablePath);
-
-            BufferedReader stdInput = new BufferedReader(new
-                    InputStreamReader(process.getInputStream()));
-
-            BufferedReader stdError = new BufferedReader(new
-                    InputStreamReader(process.getErrorStream()));
-
-            // read the output from the command
-            String s = null;
-            while ((s = stdInput.readLine()) != null) {
-                Log.d(TAG, s);
-                output.append(s + "\n");
+            boolean success = new File(executablePath).setExecutable(true, false);
+            if (!success) {
+                Log.d(TAG, "Could not set execute permission on " + executablePath);
             }
-
-            // read any errors from the attempted command
-            while ((s = stdError.readLine()) != null) {
-                Log.e(TAG, "ERROR: " + s);
-                output.append("ERROR: " + s + "\n");
-            }
-
-            process.waitFor();
-            Log.d(TAG, "Finished executing binary");
-        } catch (IOException e){
-            Log.e(TAG, "Could not execute binary ", e);
-        } catch (InterruptedException e) {
-            Log.e(TAG, "Interrupted", e);
+            return executablePath;
+        } catch (IOException e) {
+            e.printStackTrace();
         }
-
-        return output.toString();
+        return "";
     }
 
     private boolean isRecordPermissionGranted() {
@@ -163,19 +186,11 @@
         public void run() {
             final String output = executeBinary();
 
-            runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    outputText.setText(output);
+            runOnUiThread(() -> {
+                outputText.setText(output);
 
-                    // Scroll to the bottom so we can see the test result
-                    scrollView.postDelayed(new Runnable() {
-                        @Override
-                        public void run() {
-                            scrollView.scrollTo(0, outputText.getBottom());
-                        }
-                    }, 100);
-                }
+                // Scroll to the bottom so we can see the test result
+                scrollView.postDelayed(() -> scrollView.scrollTo(0, outputText.getBottom()), 100);
             });
         }
     }
diff --git a/tests/UnitTestRunner/app/src/main/res/layout/activity_main.xml b/tests/UnitTestRunner/app/src/main/res/layout/activity_main.xml
index bc8099f..dcc70d7 100644
--- a/tests/UnitTestRunner/app/src/main/res/layout/activity_main.xml
+++ b/tests/UnitTestRunner/app/src/main/res/layout/activity_main.xml
@@ -28,4 +28,4 @@
              />
     </ScrollView>
 
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/tests/UnitTestRunner/build.gradle b/tests/UnitTestRunner/build.gradle
index 234724f..98a6f28 100644
--- a/tests/UnitTestRunner/build.gradle
+++ b/tests/UnitTestRunner/build.gradle
@@ -1,24 +1,26 @@
 // Top-level build file where you can add configuration options common to all sub-projects/modules.
 
 buildscript {
-    
     repositories {
-        google()
-        jcenter()
+        mavenCentral()
+        maven {
+            url 'https://maven.google.com/'
+            name 'Google'
+        }
     }
-    dependencies {
-        classpath 'com.android.tools.build:gradle:3.3.0-alpha10'
-        
 
-        // NOTE: Do not place your application dependencies here; they belong
-        // in the individual module build.gradle files
+    dependencies {
+        classpath 'com.android.tools.build:gradle:7.2.1'
     }
 }
 
 allprojects {
     repositories {
-        google()
-        jcenter()
+        mavenCentral()
+        maven {
+            url 'https://maven.google.com/'
+            name 'Google'
+        }
     }
 }
 
diff --git a/tests/UnitTestRunner/gradle/wrapper/gradle-wrapper.properties b/tests/UnitTestRunner/gradle/wrapper/gradle-wrapper.properties
index 59b9957..1f10e87 100644
--- a/tests/UnitTestRunner/gradle/wrapper/gradle-wrapper.properties
+++ b/tests/UnitTestRunner/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index a56e023..d20b3bc 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -50,7 +50,8 @@
 TEST_BINARY_FILENAME=testOboe
 TEST_RUNNER_DIR=UnitTestRunner
 TEST_RUNNER_PACKAGE_NAME=com.google.oboe.tests.unittestrunner
-TEST_RUNNER_ASSET_DIR=${TEST_RUNNER_DIR}/app/src/main/assets
+TEST_RUNNER_JNILIBS_DIR=${TEST_RUNNER_DIR}/app/src/main/jniLibs
+TEST_RUNNER_ASSETS_DIR=${TEST_RUNNER_DIR}/app/src/main/assets
 
 # Check prerequisites
 if [ -z "$ANDROID_NDK" ]; then
@@ -68,7 +69,7 @@
 ABI=$(adb shell getprop ro.product.cpu.abi | tr -d '\n\r')
 
 if [ -z "$ABI" ]; then
-    echo "No device ABI was set. Please ensure a device or emulator is running"
+    echo "No device ABI was set. Please ensure a device or emulator is running. You may need to unplug extra devices."
     exit 1
 fi  
 
@@ -83,6 +84,11 @@
 	exit 1
 fi
 
+mkdir -p ${BUILD_DIR} 
+
+echo "Cleaning up previous build because swapping phones may result in stale binaries"
+rm -r ${BUILD_DIR}
+
 # Configure the build
 echo "Building tests for ${ABI} using ${PLATFORM}"
 
@@ -91,13 +97,11 @@
 	-DANDROID_ABI=${ABI} \
 	-DANDROID_PLATFORM=${PLATFORM} \
   	-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-	-DCMAKE_CXX_FLAGS=-std=c++14 \
+	-DCMAKE_CXX_FLAGS=-std=c++17 \
 	-DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake \
 	-DCMAKE_VERBOSE_MAKEFILE=1"
 
-mkdir -p ${BUILD_DIR} 
-
-cmake ${CMAKE_ARGS}	
+cmake ${CMAKE_ARGS}
   
 # Perform the build
 pushd ${BUILD_DIR}
@@ -112,22 +116,43 @@
 	
 popd
 
-# Copy the binary into the unit test runner app
-mkdir ${TEST_RUNNER_ASSET_DIR}/${ABI}
-DESTINATION_DIR=${TEST_RUNNER_ASSET_DIR}/${ABI}/${TEST_BINARY_FILENAME}
+# Copy the binary into the jniLibs and assets folders of the unit test runner app
+# The assets folder does not work after Android R for security reasons
+# The jniLibs folder doesn't seem to work before Android O
+# Thus, copy into both
+mkdir ${TEST_RUNNER_JNILIBS_DIR}
+mkdir ${TEST_RUNNER_JNILIBS_DIR}/${ABI}
+DESTINATION_DIR=${TEST_RUNNER_JNILIBS_DIR}/${ABI}/${TEST_BINARY_FILENAME}
 echo "Copying binary to ${DESTINATION_DIR}"
-cp ${BUILD_DIR}/${TEST_BINARY_FILENAME} ${DESTINATION_DIR}
+cp ${BUILD_DIR}/${TEST_BINARY_FILENAME} ${DESTINATION_DIR}.so
+mkdir ${TEST_RUNNER_ASSETS_DIR}
+mkdir ${TEST_RUNNER_ASSETS_DIR}/${ABI}
+DESTINATION_DIR=${TEST_RUNNER_ASSETS_DIR}/${ABI}/${TEST_BINARY_FILENAME}
+echo "Copying binary to ${DESTINATION_DIR}"
+cp ${BUILD_DIR}/${TEST_BINARY_FILENAME} ${DESTINATION_DIR}.so
 
 # Build and install the unit test runner app
 pushd ${TEST_RUNNER_DIR}
     echo "Building test runner app" 
 	./gradlew assembleDebug
+	if [ $? -ne 0 ]; then
+		echo "Building test app FAILED"
+		exit 1
+	fi
+	
 	echo "Installing to device"
 	./gradlew installDebug
+	if [ $? -ne 0 ]; then
+		echo "Installing tests FAILED"
+		exit 1
+	fi
 popd
 
+echo "Clear logcat from before the test."
+adb logcat -c
 echo "Starting app - Check your device for test results"
 adb shell am start ${TEST_RUNNER_PACKAGE_NAME}/.MainActivity 
 
 sleep 1
-adb logcat --pid=`adb shell pidof -s ${TEST_RUNNER_PACKAGE_NAME}`
+echo "Logging test logs and Oboe logs. Run adb logcat for complete logs."
+adb logcat ${TEST_RUNNER_PACKAGE_NAME}.MainActivity:V OboeAudio:V *:S
diff --git a/tests/testAAudio.cpp b/tests/testAAudio.cpp
index 32be442..c8de776 100644
--- a/tests/testAAudio.cpp
+++ b/tests/testAAudio.cpp
@@ -1,4 +1,4 @@
-#include <oboe/Oboe.h>/*
+/*
  * Copyright 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/testFlowgraph.cpp b/tests/testFlowgraph.cpp
index b9a7009..2b341c3 100644
--- a/tests/testFlowgraph.cpp
+++ b/tests/testFlowgraph.cpp
@@ -20,19 +20,18 @@
 
 #include "stdio.h"
 
-#include <iostream>
-
 #include <gtest/gtest.h>
 #include <oboe/Oboe.h>
 
 #include "flowgraph/ClipToRange.h"
+#include "flowgraph/Limiter.h"
 #include "flowgraph/MonoToMultiConverter.h"
 #include "flowgraph/SourceFloat.h"
 #include "flowgraph/RampLinear.h"
-#include "flowgraph/SampleRateConverter.h"
 #include "flowgraph/SinkFloat.h"
 #include "flowgraph/SinkI16.h"
 #include "flowgraph/SinkI24.h"
+#include "flowgraph/SinkI32.h"
 #include "flowgraph/SourceI16.h"
 #include "flowgraph/SourceI24.h"
 
@@ -80,31 +79,40 @@
 }
 
 TEST(test_flowgraph, module_ramp_linear) {
+    constexpr int singleNumOutput = 1;
     constexpr int rampSize = 5;
     constexpr int numOutput = 100;
     constexpr float value = 1.0f;
-    constexpr float target = 100.0f;
+    constexpr float initialTarget = 10.0f;
+    constexpr float finalTarget = 100.0f;
+    constexpr float tolerance = 0.0001f; // arbitrary
     float output[numOutput] = {};
     RampLinear rampLinear{1};
     SinkFloat sinkFloat{1};
 
     rampLinear.input.setValue(value);
     rampLinear.setLengthInFrames(rampSize);
-    rampLinear.setTarget(target);
-    rampLinear.forceCurrent(0.0f);
-
     rampLinear.output.connect(&sinkFloat.input);
 
+    // Check that the values go to the initial target instantly.
+    rampLinear.setTarget(initialTarget);
+    int32_t singleNumRead = sinkFloat.read(output, singleNumOutput);
+    ASSERT_EQ(singleNumRead, singleNumOutput);
+    EXPECT_NEAR(value * initialTarget, output[0], tolerance);
+
+    // Now set target and check that the linear ramp works as expected.
+    rampLinear.setTarget(finalTarget);
     int32_t numRead = sinkFloat.read(output, numOutput);
+    const float incrementSize = (finalTarget - initialTarget) / rampSize;
     ASSERT_EQ(numOutput, numRead);
-    constexpr float tolerance = 0.0001f; // arbitrary
+
     int i = 0;
     for (; i < rampSize; i++) {
-        float expected = i * value * target / rampSize;
+        float expected = value * (initialTarget + i * incrementSize);
         EXPECT_NEAR(expected, output[i], tolerance);
     }
     for (; i < numOutput; i++) {
-        float expected = value * target;
+        float expected = value * finalTarget;
         EXPECT_NEAR(expected, output[i], tolerance);
     }
 }
@@ -160,3 +168,102 @@
     }
 }
 
+TEST(test_flowgraph, module_sinki32) {
+    static constexpr int kNumSamples = 8;
+    static const float input[] = {
+        1.0f, 0.5f, -0.25f, -1.0f,
+        0.0f, 53.9f, -87.2f, -1.02f};
+    static const int32_t expected[] = {
+        INT32_MAX, 1 << 30, INT32_MIN / 4, INT32_MIN,
+        0, INT32_MAX, INT32_MIN, INT32_MIN};
+    int32_t output[kNumSamples + 10]; // larger than input
+
+    SourceFloat sourceFloat{1};
+    SinkI32 sinkI32{1};
+
+    sourceFloat.setData(input, kNumSamples);
+    sourceFloat.output.connect(&sinkI32.input);
+
+    int numOutputFrames = sizeof(output) / sizeof(int32_t);
+    int32_t numRead = sinkI32.read(output, numOutputFrames);
+    ASSERT_EQ(kNumSamples, numRead);
+    for (int i = 0; i < numRead; i++) {
+        EXPECT_EQ(expected[i], output[i]) << ", i = " << i;
+    }
+}
+
+TEST(test_flowgraph, module_limiter) {
+    constexpr int kNumSamples = 101;
+    constexpr float kLastSample = 3.0f;
+    constexpr float kFirstSample = -kLastSample;
+    constexpr float kDeltaBetweenSamples = (kLastSample - kFirstSample) / (kNumSamples - 1);
+    constexpr float kTolerance = 0.00001f;
+
+    float input[kNumSamples];
+    float output[kNumSamples];
+    SourceFloat sourceFloat{1};
+    Limiter limiter{1};
+    SinkFloat sinkFloat{1};
+
+    for (int i = 0; i < kNumSamples; i++) {
+        input[i] = kFirstSample + i * kDeltaBetweenSamples;
+    }
+
+    const int numInputFrames = std::size(input);
+    sourceFloat.setData(input, numInputFrames);
+
+    sourceFloat.output.connect(&limiter.input);
+    limiter.output.connect(&sinkFloat.input);
+
+    const int numOutputFrames = std::size(output);
+    int32_t numRead = sinkFloat.read(output, numOutputFrames);
+    ASSERT_EQ(numInputFrames, numRead);
+
+    for (int i = 0; i < numRead; i++) {
+        // limiter must be symmetric wrt 0.
+        EXPECT_NEAR(output[i], -output[kNumSamples - i - 1], kTolerance);
+        if (i > 0) {
+            EXPECT_GE(output[i], output[i - 1]); // limiter must be monotonic
+        }
+        if (input[i] == 0.f) {
+            EXPECT_EQ(0.f, output[i]);
+        } else if (input[i] > 0.0f) {
+            EXPECT_GE(output[i], 0.0f);
+            EXPECT_LE(output[i], M_SQRT2); // limiter actually limits
+            EXPECT_LE(output[i], input[i]); // a limiter, gain <= 1
+        } else {
+            EXPECT_LE(output[i], 0.0f);
+            EXPECT_GE(output[i], -M_SQRT2); // limiter actually limits
+            EXPECT_GE(output[i], input[i]); // a limiter, gain <= 1
+        }
+        if (-1.f <= input[i] && input[i] <= 1.f) {
+            EXPECT_EQ(input[i], output[i]);
+        }
+    }
+}
+
+TEST(test_flowgraph, module_limiter_nan) {
+    constexpr int kArbitraryOutputSize = 100;
+    constexpr float kFloatNan = NAN;
+    static const float input[] = {kFloatNan, 0.5f, kFloatNan, kFloatNan, -10.0f, kFloatNan};
+    static const float expected[] = {0.0f, 0.5f, 0.5f, 0.5f, -M_SQRT2, -M_SQRT2};
+    constexpr float tolerance = 0.00001f;
+    float output[kArbitraryOutputSize];
+    SourceFloat sourceFloat{1};
+    Limiter limiter{1};
+    SinkFloat sinkFloat{1};
+
+    const int numInputFrames = std::size(input);
+    sourceFloat.setData(input, numInputFrames);
+
+    sourceFloat.output.connect(&limiter.input);
+    limiter.output.connect(&sinkFloat.input);
+
+    const int numOutputFrames = std::size(output);
+    int32_t numRead = sinkFloat.read(output, numOutputFrames);
+    ASSERT_EQ(numInputFrames, numRead);
+
+    for (int i = 0; i < numRead; i++) {
+        EXPECT_NEAR(expected[i], output[i], tolerance);
+    }
+}
diff --git a/tests/testResampler.cpp b/tests/testResampler.cpp
new file mode 100644
index 0000000..de06941
--- /dev/null
+++ b/tests/testResampler.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2022 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.
+ */
+
+/*
+ * Test FlowGraph
+ */
+
+#include "math.h"
+#include "stdio.h"
+
+#include <gtest/gtest.h>
+#include <oboe/Oboe.h>
+
+#include "flowgraph/resampler/MultiChannelResampler.h"
+
+using namespace oboe::resampler;
+
+// Measure zero crossings.
+static int32_t countZeroCrossingsWithHysteresis(float *input, int32_t numSamples) {
+    const float kHysteresisLevel = 0.25f;
+    int zeroCrossingCount = 0;
+    int state = 0; // can be -1, 0, +1
+    for (int i = 0; i < numSamples; i++) {
+        if (input[i] >= kHysteresisLevel) {
+            if (state < 0) {
+                zeroCrossingCount++;
+            }
+            state = 1;
+        } else if (input[i] <= -kHysteresisLevel) {
+            if (state > 0) {
+                zeroCrossingCount++;
+            }
+            state = -1;
+        }
+    }
+    return zeroCrossingCount;
+}
+
+static constexpr int kChannelCount = 1;
+
+/**
+ * Convert a sine wave and then look for glitches.
+ * Glitches have a high value in the second derivative.
+ */
+static void checkResampler(int32_t sourceRate, int32_t sinkRate,
+        MultiChannelResampler::Quality quality) {
+    const int kNumOutputSamples = 10000;
+    const double framesPerCycle = 81.379; // target output period
+
+    int numInputSamples = kNumOutputSamples * sourceRate / sinkRate;
+
+    std::unique_ptr<float[]>  inputBuffer = std::make_unique<float[]>(numInputSamples);
+    std::unique_ptr<float[]>  outputBuffer = std::make_unique<float[]>(kNumOutputSamples);
+
+    // Generate a sine wave for input.
+    const double kPhaseIncrement = 2.0 * sinkRate / (framesPerCycle * sourceRate);
+    double phase = 0.0;
+    for (int i = 0; i < numInputSamples; i++) {
+        inputBuffer[i] = sin(phase * M_PI);
+        phase += kPhaseIncrement;
+        while (phase > 1.0) {
+            phase -= 2.0;
+        }
+    }
+    int sourceZeroCrossingCount = countZeroCrossingsWithHysteresis(inputBuffer.get(), numInputSamples);
+
+    // Use a MultiChannelResampler to convert from the sourceRate to the sinkRate.
+    std::unique_ptr<MultiChannelResampler>  mcResampler;
+    mcResampler.reset(MultiChannelResampler::make(kChannelCount,
+                                                 sourceRate,
+                                                 sinkRate,
+                                                 quality));
+    int inputFramesLeft = numInputSamples;
+    int numRead = 0;
+    float *input = inputBuffer.get(); // for iteration
+    float *output = outputBuffer.get();
+    while (inputFramesLeft > 0) {
+        if (mcResampler->isWriteNeeded()) {
+            mcResampler->writeNextFrame(input);
+            input++;
+            inputFramesLeft--;
+        } else {
+            mcResampler->readNextFrame(output);
+            output++;
+            numRead++;
+        }
+    }
+
+    ASSERT_LE(numRead, kNumOutputSamples);
+    // Some frames are lost priming the FIR filter.
+    const int kMaxAlgorithmicFrameLoss = 16;
+    EXPECT_GT(numRead, kNumOutputSamples - kMaxAlgorithmicFrameLoss);
+
+    int sinkZeroCrossingCount = countZeroCrossingsWithHysteresis(outputBuffer.get(), numRead);
+    // Some cycles may get chopped off at the end.
+    const int kMaxZeroCrossingDelta = 3;
+    EXPECT_LE(abs(sourceZeroCrossingCount - sinkZeroCrossingCount), kMaxZeroCrossingDelta);
+
+    // Detect glitches by looking for spikes in the second derivative.
+    output = outputBuffer.get();
+    float previousValue = output[0];
+    float previousSlope = output[1] - output[0];
+    for (int i = 0; i < numRead; i++) {
+        float slope = output[i] - previousValue;
+        float slopeDelta = fabs(slope - previousSlope);
+        // Skip a few samples because there are often some steep slope changes at the beginning.
+        if (i > 10) {
+            EXPECT_LT(slopeDelta, 0.1);
+        }
+        previousValue = output[i];
+        previousSlope = slope;
+    }
+
+#if 0
+    // Save to disk for inspection.
+    FILE *fp = fopen( "/sdcard/Download/src_float_out.raw" , "wb" );
+    fwrite(outputBuffer.get(), sizeof(float), numRead, fp );
+    fclose(fp);
+#endif
+}
+
+
+TEST(test_resampler, resampler_scan_all) {
+    // TODO Add 64000, 88200, 96000 when they work. Failing now.
+    const int rates[] = {8000, 11025, 22050, 32000, 44100, 48000};
+    const MultiChannelResampler::Quality qualities[] =
+    {
+        MultiChannelResampler::Quality::Fastest,
+        MultiChannelResampler::Quality::Low,
+        MultiChannelResampler::Quality::Medium,
+        MultiChannelResampler::Quality::High,
+        MultiChannelResampler::Quality::Best
+    };
+    for (int srcRate : rates) {
+        for (int destRate : rates) {
+            for (auto quality : qualities) {
+                if (srcRate != destRate) {
+                    checkResampler(srcRate, destRate, quality);
+                }
+            }
+        }
+    }
+}
+
+TEST(test_resampler, resampler_8000_11025_best) {
+    checkResampler(8000, 11025, MultiChannelResampler::Quality::Best);
+}
+TEST(test_resampler, resampler_8000_48000_best) {
+    checkResampler(8000, 48000, MultiChannelResampler::Quality::Best);
+}
+
+TEST(test_resampler, resampler_8000_44100_best) {
+    checkResampler(8000, 44100, MultiChannelResampler::Quality::Best);
+}
+
+TEST(test_resampler, resampler_11025_24000_best) {
+    checkResampler(11025, 24000, MultiChannelResampler::Quality::Best);
+}
+
+TEST(test_resampler, resampler_11025_48000_fastest) {
+    checkResampler(11025, 48000, MultiChannelResampler::Quality::Fastest);
+}
+TEST(test_resampler, resampler_11025_48000_low) {
+    checkResampler(11025, 48000, MultiChannelResampler::Quality::Low);
+}
+TEST(test_resampler, resampler_11025_48000_medium) {
+    checkResampler(11025, 48000, MultiChannelResampler::Quality::Medium);
+}
+TEST(test_resampler, resampler_11025_48000_high) {
+    checkResampler(11025, 48000, MultiChannelResampler::Quality::High);
+}
+
+TEST(test_resampler, resampler_11025_48000_best) {
+    checkResampler(11025, 48000, MultiChannelResampler::Quality::Best);
+}
+
+TEST(test_resampler, resampler_11025_44100_best) {
+    checkResampler(11025, 44100, MultiChannelResampler::Quality::Best);
+}
+
+// TODO This fails because the output is very low.
+//TEST(test_resampler, resampler_11025_88200_best) {
+//    checkResampler(11025, 88200, MultiChannelResampler::Quality::Best);
+//}
+
+TEST(test_resampler, resampler_16000_48000_best) {
+    checkResampler(16000, 48000, MultiChannelResampler::Quality::Best);
+}
+
+TEST(test_resampler, resampler_44100_48000_low) {
+    checkResampler(44100, 48000, MultiChannelResampler::Quality::Low);
+}
+TEST(test_resampler, resampler_44100_48000_best) {
+    checkResampler(44100, 48000, MultiChannelResampler::Quality::Best);
+}
+
+// Look for glitches when downsampling.
+TEST(test_resampler, resampler_48000_11025_best) {
+    checkResampler(48000, 11025, MultiChannelResampler::Quality::Best);
+}
+TEST(test_resampler, resampler_48000_44100_best) {
+    checkResampler(48000, 44100, MultiChannelResampler::Quality::Best);
+}
+TEST(test_resampler, resampler_44100_11025_best) {
+    checkResampler(44100, 11025, MultiChannelResampler::Quality::Best);
+}
diff --git a/tests/testReturnStop.cpp b/tests/testReturnStop.cpp
new file mode 100644
index 0000000..6708894
--- /dev/null
+++ b/tests/testReturnStop.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2021 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 <atomic>
+#include <tuple>
+
+#include <gtest/gtest.h>
+#include <oboe/Oboe.h>
+
+
+// Test returning DataCallbackResult::Stop from a callback.
+using namespace oboe;
+
+static constexpr int kTimeoutInNanos = 500 * kNanosPerMillisecond;
+
+class ReturnStopCallback : public AudioStreamDataCallback {
+public:
+    DataCallbackResult onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numFrames) override {
+        return (++callbackCount < kMaxCallbacks) ? DataCallbackResult::Continue : DataCallbackResult::Stop;
+    }
+
+    void reset() {
+        callbackCount = 0;
+    }
+
+    int getMaxCallbacks() const { return kMaxCallbacks; }
+
+    std::atomic<int> callbackCount{0};
+    
+private:
+    // I get strange linker errors with GTest if I try to reference this directly.
+    static constexpr int kMaxCallbacks = 40;
+};
+
+using StreamReturnStopParams = std::tuple<Direction, AudioApi, PerformanceMode, bool>;
+
+class StreamReturnStop : public ::testing::Test,
+                         public ::testing::WithParamInterface<StreamReturnStopParams> {
+
+protected:
+    void TearDown() override;
+
+    AudioStreamBuilder mBuilder;
+    AudioStream *mStream = nullptr;
+};
+
+void StreamReturnStop::TearDown() {
+    if (mStream != nullptr) {
+        mStream->close();
+        mStream = nullptr;
+    }
+}
+
+TEST_P(StreamReturnStop, VerifyStreamReturnStop) {
+    const Direction direction = std::get<0>(GetParam());
+    const AudioApi audioApi = std::get<1>(GetParam());
+    const PerformanceMode performanceMode = std::get<2>(GetParam());
+    const bool useRequestStart = std::get<3>(GetParam());
+
+    ReturnStopCallback *callback = new ReturnStopCallback();
+    mBuilder.setDirection(direction)
+            ->setFormat(AudioFormat::I16)
+            ->setPerformanceMode(performanceMode)
+            ->setDataCallback(callback);
+    if (mBuilder.isAAudioRecommended()) {
+        mBuilder.setAudioApi(audioApi);
+    }
+    mStream = nullptr;
+    Result r = mBuilder.openStream(&mStream);
+    ASSERT_EQ(r, Result::OK) << "Failed to open stream. " << convertToText(r);
+
+    // Start and stop several times.
+    for (int i = 0; i < 3; i++) {
+        callback->reset();
+        // Oboe has two ways to start a stream.
+        if (useRequestStart) {
+            r = mStream->requestStart();
+        } else {
+            r = mStream->start();
+        }
+        ASSERT_EQ(r, Result::OK) << "Failed to start stream. " << convertToText(r);
+    
+        // Wait for callbacks to complete.
+        const int kMaxCallbackPeriodMillis = 500;
+        const int kPollPeriodMillis = 20;
+        int timeout = 2 * callback->getMaxCallbacks() * kMaxCallbackPeriodMillis / kPollPeriodMillis;
+        do {
+            usleep(kPollPeriodMillis * 1000);
+        } while (callback->callbackCount < callback->getMaxCallbacks() && timeout-- > 0);
+        EXPECT_GT(timeout, 0) << "timed out waiting for enough callbacks";
+        
+        StreamState next = StreamState::Unknown;
+        r = mStream->waitForStateChange(StreamState::Started, &next, kTimeoutInNanos);
+        EXPECT_EQ(r, Result::OK) << "waitForStateChange(Started) timed out. " << convertToText(r);
+        r = mStream->waitForStateChange(StreamState::Stopping, &next, kTimeoutInNanos);
+        EXPECT_EQ(r, Result::OK) << "waitForStateChange(Stopping) timed out. " << convertToText(r);
+        EXPECT_EQ(next, StreamState::Stopped) << "Stream not in state Stopped, was " << convertToText(next);
+        
+        EXPECT_EQ(callback->callbackCount, callback->getMaxCallbacks()) << "Too many callbacks = " << callback->callbackCount;
+
+        const int kOboeStartStopSleepMSec = 10;
+        usleep(kOboeStartStopSleepMSec * 1000); // avoid race condition in emulator
+    }
+
+    ASSERT_EQ(Result::OK, mStream->close());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        StreamReturnStopTest,
+        StreamReturnStop,
+        ::testing::Values(
+                // Last boolean is true if requestStart() should be called instead of start().
+                StreamReturnStopParams({Direction::Output, AudioApi::AAudio, PerformanceMode::LowLatency, true}),
+                StreamReturnStopParams({Direction::Output, AudioApi::AAudio, PerformanceMode::LowLatency, false}),
+                StreamReturnStopParams({Direction::Output, AudioApi::AAudio, PerformanceMode::None, true}),
+                StreamReturnStopParams({Direction::Output, AudioApi::AAudio, PerformanceMode::None, false}),
+                StreamReturnStopParams({Direction::Output, AudioApi::OpenSLES, PerformanceMode::LowLatency, true}),
+                StreamReturnStopParams({Direction::Output, AudioApi::OpenSLES, PerformanceMode::LowLatency, false}),
+                StreamReturnStopParams({Direction::Input, AudioApi::AAudio, PerformanceMode::LowLatency, true}),
+                StreamReturnStopParams({Direction::Input, AudioApi::AAudio, PerformanceMode::LowLatency, false})
+                )
+        );
diff --git a/tests/testStreamClosedMethods.cpp b/tests/testStreamClosedMethods.cpp
index cbb2191..a75e8ae 100644
--- a/tests/testStreamClosedMethods.cpp
+++ b/tests/testStreamClosedMethods.cpp
@@ -50,6 +50,43 @@
         return (s == StreamState::Closed);
     }
 
+    static int64_t getNanoseconds() {
+        struct timespec time;
+        int result = clock_gettime(CLOCK_MONOTONIC, &time);
+        if (result < 0) {
+            return result;
+        }
+        return (time.tv_sec * (int64_t)1e9) + time.tv_nsec;
+    }
+
+    int32_t mElapsedTimeMillis = 0; // used for passing back a value from a test function.
+	// ASSERT_* requires a void return type.
+    void measureCloseTime(int32_t delayMillis) {
+        ASSERT_TRUE(openStream());
+        mStream->setDelayBeforeCloseMillis(delayMillis);
+        ASSERT_EQ(delayMillis, mStream->getDelayBeforeCloseMillis());
+        // Measure time it takes to close.
+        int64_t startTimeMillis = getNanoseconds() / 1e6;
+        ASSERT_TRUE(closeStream());
+        int64_t stopTimeMillis = getNanoseconds() / 1e6;
+        int32_t elapsedTimeMillis = (int32_t)(stopTimeMillis - startTimeMillis);
+        ASSERT_GE(elapsedTimeMillis, delayMillis);
+        mElapsedTimeMillis = elapsedTimeMillis;
+    }
+
+    void testDelayBeforeClose() {
+        const int32_t delayMillis = 100;
+        measureCloseTime(0);
+        int32_t elapsedTimeMillis1 = mElapsedTimeMillis;
+        // Do it again with a longer sleep using setDelayBeforeCloseMillis.
+        // The increase in elapsed time should match the added delay.
+        measureCloseTime(delayMillis);
+        int32_t elapsedTimeMillis2 = mElapsedTimeMillis;
+        int32_t extraElapsedTime = elapsedTimeMillis2 - elapsedTimeMillis1;
+        // Expect the additional elapsed time to be close to the added delay.
+        ASSERT_LE(abs(extraElapsedTime - delayMillis), delayMillis / 5);
+    }
+
     AudioStreamBuilder mBuilder;
     AudioStream       *mStream = nullptr;
 
@@ -211,11 +248,12 @@
     mBuilder.setFormat(AudioFormat::I16);
     mBuilder.setChannelCount(1);
     ASSERT_TRUE(openStream());
+    ASSERT_EQ(mStream->setBufferSizeInFrames(mStream->getBufferCapacityInFrames()), Result::OK);
     mStream->start();
 
     int16_t buffer[4] = { 1, 2, 3, 4 };
     Result r = mStream->write(&buffer, 4, 0);
-    if (r != Result::OK){
+    if (r != Result::OK) {
         FAIL() << "Could not write to audio stream";
     }
 
@@ -226,7 +264,6 @@
     ASSERT_EQ(mStream->getFramesWritten(), f);
 }
 
-// TODO: Reading a positive value doesn't work on OpenSL ES in this test - why?
 TEST_F(StreamClosedReturnValues, GetFramesReadReturnsLastKnownValue) {
 
     mBuilder.setDirection(Direction::Input);
@@ -236,14 +273,12 @@
     ASSERT_TRUE(openStream());
     mStream->start();
 
-/*
     int16_t buffer[192];
-    auto r = mStream->read(&buffer, 192, 0);
+    auto r = mStream->read(&buffer, 192, 1000 * kNanosPerMillisecond);
     ASSERT_EQ(r.value(), 192);
-*/
 
     auto f = mStream->getFramesRead();
-//    ASSERT_EQ(f, 192);
+    ASSERT_EQ(f, 192);
 
     ASSERT_TRUE(closeStream());
     ASSERT_EQ(mStream->getFramesRead(), f);
@@ -301,7 +336,7 @@
     ASSERT_TRUE(openAndCloseStream());
     StreamState next;
     Result r = mStream->waitForStateChange(StreamState::Open, &next, 0);
-    ASSERT_EQ(r, Result::ErrorClosed) << convertToText(r);
+    EXPECT_TRUE(r == Result::OK || r == Result::ErrorClosed) << convertToText(r);
 }
 
 TEST_F(StreamClosedReturnValues, SetBufferSizeInFramesReturnsClosed){
@@ -317,7 +352,7 @@
 
     if (mStream->getAudioApi() == AudioApi::AAudio){
         auto r = mStream->calculateLatencyMillis();
-        ASSERT_EQ(r.error(), Result::ErrorClosed);
+        ASSERT_EQ(r.error(), Result::ErrorInvalidState);
     }
 }
 
@@ -338,3 +373,29 @@
     auto r = mStream->write(buffer, 1, 0);
     ASSERT_EQ(r.error(), Result::ErrorClosed);
 }
+
+TEST_F(StreamClosedReturnValues, DelayBeforeCloseInput){
+    if (AudioStreamBuilder::isAAudioRecommended()) {
+        mBuilder.setDirection(Direction::Input);
+        testDelayBeforeClose();
+    }
+}
+
+TEST_F(StreamClosedReturnValues, DelayBeforeCloseOutput){
+    if (AudioStreamBuilder::isAAudioRecommended()) {
+        mBuilder.setDirection(Direction::Output);
+        testDelayBeforeClose();
+    }
+}
+
+TEST_F(StreamClosedReturnValues, DelayBeforeCloseInputOpenSL){
+    mBuilder.setAudioApi(AudioApi::OpenSLES);
+    mBuilder.setDirection(Direction::Input);
+    testDelayBeforeClose();
+}
+
+TEST_F(StreamClosedReturnValues, DelayBeforeCloseOutputOpenSL){
+    mBuilder.setAudioApi(AudioApi::OpenSLES);
+    mBuilder.setDirection(Direction::Output);
+    testDelayBeforeClose();
+}
diff --git a/tests/testStreamFramesProcessed.cpp b/tests/testStreamFramesProcessed.cpp
new file mode 100644
index 0000000..daa9c3d
--- /dev/null
+++ b/tests/testStreamFramesProcessed.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2021 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 <gtest/gtest.h>
+#include <oboe/Oboe.h>
+
+#include <tuple>
+
+using namespace oboe;
+
+class FramesProcessedCallback : public AudioStreamDataCallback {
+public:
+    DataCallbackResult onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numFrames) override {
+        return DataCallbackResult::Continue;
+    }
+};
+
+using StreamFramesProcessedParams = std::tuple<Direction, int32_t>;
+
+class StreamFramesProcessed : public ::testing::Test,
+                              public ::testing::WithParamInterface<StreamFramesProcessedParams> {
+
+protected:
+    void TearDown() override;
+
+    static constexpr int PROCESS_TIME_SECONDS = 5;
+
+    AudioStreamBuilder mBuilder;
+    AudioStream *mStream = nullptr;
+};
+
+void StreamFramesProcessed::TearDown() {
+    if (mStream != nullptr) {
+        mStream->close();
+        mStream = nullptr;
+    }
+}
+
+TEST_P(StreamFramesProcessed, VerifyFramesProcessed) {
+    const Direction direction = std::get<0>(GetParam());
+    const int32_t sampleRate = std::get<1>(GetParam());
+
+    AudioStreamDataCallback *callback = new FramesProcessedCallback();
+    mBuilder.setDirection(direction)
+            ->setFormat(AudioFormat::I16)
+            ->setSampleRate(sampleRate)
+            ->setSampleRateConversionQuality(SampleRateConversionQuality::Medium)
+            ->setPerformanceMode(PerformanceMode::LowLatency)
+            ->setSharingMode(SharingMode::Exclusive)
+            ->setDataCallback(callback);
+    mStream = nullptr;
+    Result r = mBuilder.openStream(&mStream);
+    ASSERT_EQ(r, Result::OK) << "Failed to open stream." << convertToText(r);
+
+    r = mStream->start();
+    ASSERT_EQ(r, Result::OK) << "Failed to start stream." << convertToText(r);
+    sleep(PROCESS_TIME_SECONDS);
+
+    // The frames written should be close to sampleRate * PROCESS_TIME_SECONDS
+    const int kDeltaFramesWindowInFrames = 30000;
+    const int64_t framesWritten = mStream->getFramesWritten();
+    const int64_t framesRead = mStream->getFramesRead();
+    EXPECT_NEAR(framesWritten, sampleRate * PROCESS_TIME_SECONDS, kDeltaFramesWindowInFrames);
+    EXPECT_NEAR(framesRead, sampleRate * PROCESS_TIME_SECONDS, kDeltaFramesWindowInFrames);
+}
+
+INSTANTIATE_TEST_CASE_P(
+        StreamFramesProcessedTest,
+        StreamFramesProcessed,
+        ::testing::Values(
+                StreamFramesProcessedParams({Direction::Output, 8000}),
+                StreamFramesProcessedParams({Direction::Output, 44100}),
+                StreamFramesProcessedParams({Direction::Output, 96000}),
+                StreamFramesProcessedParams({Direction::Input, 8000}),
+                StreamFramesProcessedParams({Direction::Input, 44100}),
+                StreamFramesProcessedParams({Direction::Input, 96000})
+                )
+        );
diff --git a/tests/testStreamOpen.cpp b/tests/testStreamOpen.cpp
index bdbfa50..9d01c07 100644
--- a/tests/testStreamOpen.cpp
+++ b/tests/testStreamOpen.cpp
@@ -1,4 +1,4 @@
-#include <oboe/Oboe.h>/*
+/*
  * Copyright 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,6 +18,10 @@
 #include <oboe/Oboe.h>
 #include <android/api-level.h>
 
+#ifndef __ANDROID_API_S__
+#define __ANDROID_API_S__ 31
+#endif
+
 using namespace oboe;
 
 class CallbackSizeMonitor : public AudioStreamCallback {
@@ -38,6 +42,7 @@
 protected:
 
     bool openStream() {
+        EXPECT_EQ(mStream, nullptr);
         Result r = mBuilder.openStream(&mStream);
         EXPECT_EQ(r, Result::OK) << "Failed to open stream " << convertToText(r);
         EXPECT_EQ(0, openCount) << "Should start with a fresh object every time.";
@@ -46,17 +51,24 @@
     }
 
     bool closeStream() {
-        Result r = mStream->close();
-        EXPECT_EQ(r, Result::OK) << "Failed to close stream. " << convertToText(r);
-        usleep(500 * 1000); // give previous stream time to settle
-        return (r == Result::OK);
+        if (mStream != nullptr){
+          Result r = mStream->close();
+          EXPECT_EQ(r, Result::OK) << "Failed to close stream. " << convertToText(r);
+          usleep(500 * 1000); // give previous stream time to settle
+          mStream = nullptr;
+          return (r == Result::OK);
+        } else {
+          return true;
+        }
     }
 
     void checkSampleRateConversionAdvancing(Direction direction) {
         CallbackSizeMonitor callback;
 
         mBuilder.setDirection(direction);
-        mBuilder.setAudioApi(AudioApi::AAudio);
+        if (mBuilder.isAAudioRecommended()) {
+            mBuilder.setAudioApi(AudioApi::AAudio);
+        }
         mBuilder.setCallback(&callback);
         mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
         mBuilder.setSampleRate(44100);
@@ -88,7 +100,10 @@
 
 };
 
-TEST_F(StreamOpen, ForOpenSLESDefaultSampleRateIsUsed){
+class StreamOpenOutput : public StreamOpen {};
+class StreamOpenInput : public StreamOpen {};
+
+TEST_F(StreamOpenOutput, ForOpenSLESDefaultSampleRateIsUsed){
 
     DefaultStreamValues::SampleRate = 44100;
     DefaultStreamValues::FramesPerBurst = 192;
@@ -98,18 +113,21 @@
     ASSERT_TRUE(closeStream());
 }
 
-TEST_F(StreamOpen, ForOpenSLESDefaultFramesPerBurstIsUsed){
+TEST_F(StreamOpenOutput, ForOpenSLESDefaultFramesPerBurstIsUsed){
 
     DefaultStreamValues::SampleRate = 48000;
     DefaultStreamValues::FramesPerBurst = 128; // used for low latency
     mBuilder.setAudioApi(AudioApi::OpenSLES);
     mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
     ASSERT_TRUE(openStream());
-    ASSERT_EQ(mStream->getFramesPerBurst(), 128);
+    // Some devices like emulators may not support Low Latency
+    if (mStream->getPerformanceMode() == PerformanceMode::LowLatency) {
+        ASSERT_EQ(mStream->getFramesPerBurst(), 128);
+    }
     ASSERT_TRUE(closeStream());
 }
 
-TEST_F(StreamOpen, ForOpenSLESDefaultChannelCountIsUsed){
+TEST_F(StreamOpenOutput, ForOpenSLESDefaultChannelCountIsUsed){
 
     DefaultStreamValues::ChannelCount = 1;
     mBuilder.setAudioApi(AudioApi::OpenSLES);
@@ -118,18 +136,18 @@
     ASSERT_TRUE(closeStream());
 }
 
-TEST_F(StreamOpen, OutputForOpenSLESPerformanceModeShouldBeNone){
+TEST_F(StreamOpenOutput, OutputForOpenSLESPerformanceModeShouldBeNone){
     // We will not get a LowLatency stream if we request 16000 Hz.
     mBuilder.setSampleRate(16000);
     mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
     mBuilder.setDirection(Direction::Output);
     mBuilder.setAudioApi(AudioApi::OpenSLES);
-	ASSERT_TRUE(openStream());
+	  ASSERT_TRUE(openStream());
     ASSERT_EQ((int)mStream->getPerformanceMode(), (int)PerformanceMode::None);
     ASSERT_TRUE(closeStream());
 }
 
-TEST_F(StreamOpen, InputForOpenSLESPerformanceModeShouldBeNone){
+TEST_F(StreamOpenInput, InputForOpenSLESPerformanceModeShouldBeNone){
     // We will not get a LowLatency stream if we request 16000 Hz.
     mBuilder.setSampleRate(16000);
     mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
@@ -140,7 +158,7 @@
     ASSERT_TRUE(closeStream());
 }
 
-TEST_F(StreamOpen, ForOpenSlesIllegalFormatRejectedOutput) {
+TEST_F(StreamOpenOutput, ForOpenSlesIllegalFormatRejectedOutput) {
     mBuilder.setAudioApi(AudioApi::OpenSLES);
     mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
     mBuilder.setFormat(static_cast<AudioFormat>(666));
@@ -151,7 +169,7 @@
     }
 }
 
-TEST_F(StreamOpen, ForOpenSlesIllegalFormatRejectedInput) {
+TEST_F(StreamOpenInput, ForOpenSlesIllegalFormatRejectedInput) {
     mBuilder.setAudioApi(AudioApi::OpenSLES);
     mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
     mBuilder.setDirection(Direction::Input);
@@ -164,7 +182,7 @@
 }
 
 // Make sure the callback is called with the requested FramesPerCallback
-TEST_F(StreamOpen, OpenSLESFramesPerCallback) {
+TEST_F(StreamOpenOutput, OpenSLESFramesPerCallback) {
     const int kRequestedFramesPerCallback = 417;
     CallbackSizeMonitor callback;
 
@@ -187,7 +205,6 @@
     ASSERT_TRUE(closeStream());
 }
 
-/* TODO - This is hanging!
 // Make sure the LowLatency callback has the requested FramesPerCallback.
 TEST_F(StreamOpen, AAudioFramesPerCallbackLowLatency) {
     const int kRequestedFramesPerCallback = 192;
@@ -209,9 +226,7 @@
     ASSERT_EQ(mStream->requestStop(), Result::OK);
     ASSERT_TRUE(closeStream());
 }
-*/
 
-/* TODO - This is hanging!
 // Make sure the regular callback has the requested FramesPerCallback.
 TEST_F(StreamOpen, AAudioFramesPerCallbackNone) {
     const int kRequestedFramesPerCallback = 1024;
@@ -223,7 +238,6 @@
     mBuilder.setPerformanceMode(PerformanceMode::None);
     ASSERT_TRUE(openStream());
     ASSERT_EQ(kRequestedFramesPerCallback, mStream->getFramesPerCallback());
-    ASSERT_EQ(mStream->setBufferSizeInFrames(mStream->getBufferCapacityInFrames()), Result::OK);
     ASSERT_EQ(mStream->requestStart(), Result::OK);
     int timeout = 20;
     while (callback.framesPerCallback == 0 && timeout > 0) {
@@ -234,9 +248,8 @@
     ASSERT_EQ(mStream->requestStop(), Result::OK);
     ASSERT_TRUE(closeStream());
 }
-*/
 
-TEST_F(StreamOpen, RecordingFormatUnspecifiedReturnsI16BeforeMarshmallow){
+TEST_F(StreamOpenInput, RecordingFormatUnspecifiedReturnsI16BeforeMarshmallow){
 
     if (getSdkVersion() < __ANDROID_API_M__){
         mBuilder.setDirection(Direction::Input);
@@ -247,7 +260,7 @@
     }
 }
 
-TEST_F(StreamOpen, RecordingFormatUnspecifiedReturnsFloatOnMarshmallowAndLater){
+TEST_F(StreamOpenInput, RecordingFormatUnspecifiedReturnsFloatOnMarshmallowAndLater){
 
     if (getSdkVersion() >= __ANDROID_API_M__){
         mBuilder.setDirection(Direction::Input);
@@ -258,7 +271,7 @@
     }
 }
 
-TEST_F(StreamOpen, RecordingFormatFloatReturnsErrorBeforeMarshmallow){
+TEST_F(StreamOpenInput, RecordingFormatFloatReturnsErrorBeforeMarshmallow){
 
     if (getSdkVersion() < __ANDROID_API_M__){
         mBuilder.setDirection(Direction::Input);
@@ -269,7 +282,7 @@
     }
 }
 
-TEST_F(StreamOpen, RecordingFormatFloatReturnsFloatOnMarshmallowAndLater){
+TEST_F(StreamOpenInput, RecordingFormatFloatReturnsFloatOnMarshmallowAndLater){
 
     if (getSdkVersion() >= __ANDROID_API_M__){
         mBuilder.setDirection(Direction::Input);
@@ -280,7 +293,7 @@
     }
 }
 
-TEST_F(StreamOpen, RecordingFormatI16ReturnsI16){
+TEST_F(StreamOpenInput, RecordingFormatI16ReturnsI16){
 
     mBuilder.setDirection(Direction::Input);
     mBuilder.setFormat(AudioFormat::I16);
@@ -289,7 +302,7 @@
     ASSERT_TRUE(closeStream());
 }
 
-TEST_F(StreamOpen, PlaybackFormatUnspecifiedReturnsI16BeforeLollipop){
+TEST_F(StreamOpenOutput, PlaybackFormatUnspecifiedReturnsI16BeforeLollipop){
 
     if (getSdkVersion() < __ANDROID_API_L__){
         mBuilder.setDirection(Direction::Output);
@@ -300,7 +313,7 @@
     }
 }
 
-TEST_F(StreamOpen, PlaybackFormatUnspecifiedReturnsFloatOnLollipopAndLater){
+TEST_F(StreamOpenOutput, PlaybackFormatUnspecifiedReturnsFloatOnLollipopAndLater){
 
     if (getSdkVersion() >= __ANDROID_API_L__){
         mBuilder.setDirection(Direction::Output);
@@ -311,7 +324,7 @@
     }
 }
 
-TEST_F(StreamOpen, PlaybackFormatFloatReturnsErrorBeforeLollipop){
+TEST_F(StreamOpenOutput, PlaybackFormatFloatReturnsErrorBeforeLollipop){
 
     if (getSdkVersion() < __ANDROID_API_L__){
         mBuilder.setDirection(Direction::Output);
@@ -322,7 +335,16 @@
     }
 }
 
-TEST_F(StreamOpen, PlaybackFormatFloatReturnsFloatOnLollipopAndLater){
+TEST_F(StreamOpenOutput, PlaybackFormatFloatReturnsFloatWithFormatConversionAllowed){
+    mBuilder.setDirection(Direction::Output);
+    mBuilder.setFormat(AudioFormat::Float);
+    mBuilder.setFormatConversionAllowed(true);
+    ASSERT_TRUE(openStream());
+    ASSERT_EQ(mStream->getFormat(), AudioFormat::Float);
+    ASSERT_TRUE(closeStream());
+}
+
+TEST_F(StreamOpenOutput, PlaybackFormatFloatReturnsFloatOnLollipopAndLater){
 
     if (getSdkVersion() >= __ANDROID_API_L__){
         mBuilder.setDirection(Direction::Output);
@@ -333,7 +355,7 @@
     }
 }
 
-TEST_F(StreamOpen, PlaybackFormatI16ReturnsI16) {
+TEST_F(StreamOpenOutput, PlaybackFormatI16ReturnsI16) {
     mBuilder.setDirection(Direction::Output);
     mBuilder.setFormat(AudioFormat::I16);
     ASSERT_TRUE(openStream());
@@ -341,7 +363,7 @@
     ASSERT_TRUE(closeStream());
 }
 
-TEST_F(StreamOpen, OpenCloseLowLatencyStream){
+TEST_F(StreamOpenOutput, OpenCloseLowLatencyStream){
     mBuilder.setDirection(Direction::Output);
     mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
     float *buf = new float[100];
@@ -350,7 +372,7 @@
     ASSERT_TRUE(closeStream());
 }
 
-TEST_F(StreamOpen, LowLatencyStreamHasSmallBufferSize){
+TEST_F(StreamOpenOutput, LowLatencyStreamHasSmallBufferSize){
 
     if (mBuilder.isAAudioRecommended()) {
         mBuilder.setDirection(Direction::Output);
@@ -364,11 +386,77 @@
 }
 
 // See if sample rate conversion by Oboe is calling the callback.
-TEST_F(StreamOpen, AAudioOutputSampleRate44100) {
+TEST_F(StreamOpenOutput, AAudioOutputSampleRate44100) {
     checkSampleRateConversionAdvancing(Direction::Output);
 }
 
 // See if sample rate conversion by Oboe is calling the callback.
-TEST_F(StreamOpen, AAudioInputSampleRate44100) {
+TEST_F(StreamOpenInput, AAudioInputSampleRate44100) {
     checkSampleRateConversionAdvancing(Direction::Input);
 }
+
+TEST_F(StreamOpenOutput, AAudioOutputSetPackageName){
+    if (getSdkVersion() >= __ANDROID_API_S__){
+        mBuilder.setAudioApi(AudioApi::AAudio);
+        mBuilder.setPackageName("com.google.oboe.tests.unittestrunner");
+        ASSERT_TRUE(openStream());
+        ASSERT_EQ(mStream->requestStart(), Result::OK);
+        ASSERT_TRUE(closeStream());
+    }
+}
+
+TEST_F(StreamOpenInput, AAudioInputSetPackageName){
+    if (getSdkVersion() >= __ANDROID_API_S__){
+        mBuilder.setDirection(Direction::Input);
+        mBuilder.setAudioApi(AudioApi::AAudio);
+        mBuilder.setPackageName("com.google.oboe.tests.unittestrunner");
+        ASSERT_TRUE(openStream());
+        ASSERT_EQ(mStream->requestStart(), Result::OK);
+        ASSERT_TRUE(closeStream());
+    }
+}
+
+TEST_F(StreamOpenOutput, AAudioOutputSetAttributionTag){
+    if (getSdkVersion() >= __ANDROID_API_S__){
+        mBuilder.setAudioApi(AudioApi::AAudio);
+        mBuilder.setAttributionTag("TestSetOutputAttributionTag");
+        ASSERT_TRUE(openStream());
+        ASSERT_EQ(mStream->requestStart(), Result::OK);
+        ASSERT_TRUE(closeStream());
+    }
+}
+
+TEST_F(StreamOpenInput, AAudioInputSetAttributionTag){
+    if (getSdkVersion() >= __ANDROID_API_S__){
+        mBuilder.setDirection(Direction::Input);
+        mBuilder.setAudioApi(AudioApi::AAudio);
+        mBuilder.setAttributionTag("TestSetInputAttributionTag");
+        ASSERT_TRUE(openStream());
+        ASSERT_EQ(mStream->requestStart(), Result::OK);
+        ASSERT_TRUE(closeStream());
+    }
+}
+
+TEST_F(StreamOpenOutput, OutputForOpenSLESPerformanceModeNoneGetBufferSizeInFrames){
+    mBuilder.setPerformanceMode(PerformanceMode::None);
+    mBuilder.setAudioApi(AudioApi::OpenSLES);
+    ASSERT_TRUE(openStream());
+    EXPECT_GT(mStream->getBufferSizeInFrames(), 0);
+    ASSERT_TRUE(closeStream());
+}
+
+TEST_F(StreamOpenOutput, OboeExtensions){
+    if (OboeExtensions::isMMapSupported()) {
+        ASSERT_EQ(OboeExtensions::setMMapEnabled(true), 0);
+        ASSERT_TRUE(OboeExtensions::isMMapEnabled());
+
+        ASSERT_EQ(OboeExtensions::setMMapEnabled(false), 0);
+        ASSERT_FALSE(OboeExtensions::isMMapEnabled());
+        ASSERT_TRUE(openStream());
+        EXPECT_FALSE(OboeExtensions::isMMapUsed(mStream));
+        ASSERT_TRUE(closeStream());
+
+        ASSERT_EQ(OboeExtensions::setMMapEnabled(true), 0);
+        ASSERT_TRUE(OboeExtensions::isMMapEnabled());
+    }
+}
diff --git a/tests/testStreamStop.cpp b/tests/testStreamStop.cpp
new file mode 100644
index 0000000..ca7e365
--- /dev/null
+++ b/tests/testStreamStop.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2022 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 <thread>
+
+#include <gtest/gtest.h>
+
+#include <oboe/Oboe.h>
+
+using namespace oboe;
+
+using TestStreamStopParams = std::tuple<Direction, AudioApi, PerformanceMode>;
+
+class TestStreamStop : public ::testing::Test,
+                         public ::testing::WithParamInterface<TestStreamStopParams> {
+
+protected:
+
+    void SetUp(){
+        mBuilder.setPerformanceMode(PerformanceMode::None);
+        mBuilder.setDirection(Direction::Output);
+    }
+
+    bool openStream(Direction direction, AudioApi audioApi, PerformanceMode perfMode) {
+        mBuilder.setDirection(direction);
+        if (mBuilder.isAAudioRecommended()) {
+            mBuilder.setAudioApi(audioApi);
+        }
+        mBuilder.setPerformanceMode(perfMode);
+        mBuilder.setChannelCount(1);
+        mBuilder.setFormat(AudioFormat::I16);
+        Result r = mBuilder.openStream(&mStream);
+        EXPECT_EQ(r, Result::OK) << "Failed to open stream " << convertToText(r);
+        if (r != Result::OK)
+            return false;
+
+        Direction d = mStream->getDirection();
+        EXPECT_EQ(d, direction) << convertToText(mStream->getDirection());
+        return (d == direction);
+    }
+
+    bool openStream(AudioStreamBuilder &builder) {
+        Result r = builder.openStream(&mStream);
+        EXPECT_EQ(r, Result::OK) << "Failed to open stream " << convertToText(r);
+        return (r == Result::OK);
+    }
+
+    void stopWhileUsingLargeBuffer() {
+        StreamState next = StreamState::Unknown;
+        auto r = mStream->requestStart();
+        EXPECT_EQ(r, Result::OK);
+        r = mStream->waitForStateChange(StreamState::Starting, &next, kTimeoutInNanos);
+        EXPECT_EQ(r, Result::OK);
+        EXPECT_EQ(next, StreamState::Started) << "next = " << convertToText(next);
+
+        AudioStream *str = mStream;
+
+        int16_t buffer[kFramesToWrite] = {};
+
+        std::thread stopper([str] {
+            int64_t estimatedCompletionTimeUs = kMicroSecondsPerSecond * kFramesToWrite / str->getSampleRate();
+            usleep(estimatedCompletionTimeUs / 2); // Stop halfway during the read/write
+            EXPECT_EQ(str->close(), Result::OK);
+        });
+
+        if (mBuilder.getDirection() == Direction::Output) {
+            r = mStream->write(&buffer, kFramesToWrite, kTimeoutInNanos);
+        } else {
+            r = mStream->read(&buffer, kFramesToWrite, kTimeoutInNanos);
+        }
+        if (r != Result::OK) {
+            FAIL() << "Could not read/write to audio stream: " << static_cast<int>(r);
+        }
+
+        stopper.join();
+        r = mStream->waitForStateChange(StreamState::Started, &next,
+                                        1000 * kNanosPerMillisecond);
+        if ((r != Result::ErrorClosed) && (r != Result::OK)) {
+            FAIL() << "Wrong closed result type: " << static_cast<int>(r);
+        }
+    }
+
+    AudioStreamBuilder mBuilder;
+    AudioStream *mStream = nullptr;
+    static constexpr int kTimeoutInNanos = 1000 * kNanosPerMillisecond;
+    static constexpr int64_t kMicroSecondsPerSecond = 1000000;
+    static constexpr int kFramesToWrite = 10000;
+
+};
+
+TEST_P(TestStreamStop, VerifyTestStreamStop) {
+    const Direction direction = std::get<0>(GetParam());
+    const AudioApi audioApi = std::get<1>(GetParam());
+    const PerformanceMode performanceMode = std::get<2>(GetParam());
+
+    ASSERT_TRUE(openStream(direction, audioApi, performanceMode));
+    stopWhileUsingLargeBuffer();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        TestStreamStopTest,
+        TestStreamStop,
+        ::testing::Values(
+                TestStreamStopParams({Direction::Output, AudioApi::AAudio, PerformanceMode::LowLatency}),
+                TestStreamStopParams({Direction::Output, AudioApi::AAudio, PerformanceMode::None}),
+                TestStreamStopParams({Direction::Output, AudioApi::AAudio, PerformanceMode::PowerSaving}),
+                TestStreamStopParams({Direction::Output, AudioApi::OpenSLES, PerformanceMode::LowLatency}),
+                TestStreamStopParams({Direction::Output, AudioApi::OpenSLES, PerformanceMode::None}),
+                TestStreamStopParams({Direction::Output, AudioApi::OpenSLES, PerformanceMode::PowerSaving}),
+                TestStreamStopParams({Direction::Input, AudioApi::AAudio, PerformanceMode::LowLatency}),
+                TestStreamStopParams({Direction::Input, AudioApi::AAudio, PerformanceMode::None}),
+                TestStreamStopParams({Direction::Input, AudioApi::AAudio, PerformanceMode::PowerSaving}),
+                TestStreamStopParams({Direction::Input, AudioApi::OpenSLES, PerformanceMode::LowLatency}),
+                TestStreamStopParams({Direction::Input, AudioApi::OpenSLES, PerformanceMode::None}),
+                TestStreamStopParams({Direction::Input, AudioApi::OpenSLES, PerformanceMode::PowerSaving})
+        )
+);
diff --git a/tests/testUtilities.cpp b/tests/testUtilities.cpp
index 6b101be..c1d3334 100644
--- a/tests/testUtilities.cpp
+++ b/tests/testUtilities.cpp
@@ -37,4 +37,4 @@
 TEST_F(UtilityFunctions, ConvertsFloatToSizeOf4Bytes){
     int32_t sizeInBytes = oboe::convertFormatToSizeInBytes(AudioFormat::Float);
     ASSERT_EQ(sizeInBytes, 4);
-}
\ No newline at end of file
+}
diff --git a/tests/testXRunBehaviour.cpp b/tests/testXRunBehaviour.cpp
index ccb597f..c28946d 100644
--- a/tests/testXRunBehaviour.cpp
+++ b/tests/testXRunBehaviour.cpp
@@ -78,4 +78,4 @@
         ASSERT_TRUE(mStream->isXRunCountSupported());
     }
     ASSERT_TRUE(closeStream());
-}
\ No newline at end of file
+}