From 72247fd19a844716e540b06dbc435fbf9a21e783 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 01/45] Revert "AAudio now used on API 27 rather than 26" This reverts commit 2426893468e0551c62a0825d4c1051c27cd16107. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e267af924..dcf8803da 100755 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Oboe is a C++ library which makes it easy to build high-performance audio apps o ## Features - Compatible with API 16 onwards - runs on 99% of Android devices -- Chooses the audio API (OpenSL ES on API 16+ or AAudio on API 27+) which will give the best audio performance on the target Android device +- Chooses the audio API (OpenSL ES on API 16+ or AAudio on API 26+) which will give the best audio performance on the target Android device - Automatic latency tuning - Modern C++ allowing you to write clean, elegant code From e20675261ed774b58b38de5de6a951185e91d0db Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 02/45] Revert "Do not use AAudio unless running on Android 8.1 or higher" This reverts commit 64f63e225101820d6d60bef073611f7838241f99. --- src/aaudio/AudioStreamAAudio.cpp | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/aaudio/AudioStreamAAudio.cpp b/src/aaudio/AudioStreamAAudio.cpp index 452f8407e..a256ef1c4 100644 --- a/src/aaudio/AudioStreamAAudio.cpp +++ b/src/aaudio/AudioStreamAAudio.cpp @@ -16,16 +16,12 @@ #include #include -#include #include "aaudio/AAudioLoader.h" #include "aaudio/AudioStreamAAudio.h" #include "common/OboeDebug.h" #include "oboe/Utilities.h" -#ifdef __ANDROID__ -#include -#endif using namespace oboe; @@ -93,22 +89,7 @@ AudioStreamAAudio::~AudioStreamAAudio() delete[] mShortCallbackBuffer; } -static bool isRunningOnAndroid8_1OrHigher() { -#ifdef __ANDROID__ - char sdk[PROP_VALUE_MAX] = {0}; - if (__system_property_get("ro.build.version.sdk", sdk) != 0) { - return atoi(sdk) >= 27; // SDK Level 27 is Android Oreo 8.1 - } -#endif - return false; -} - bool AudioStreamAAudio::isSupported() { - if (!isRunningOnAndroid8_1OrHigher()) { - // See https://github.com/google/oboe/issues/40, - // AAudio is not stable enough on Android 8.0. - return false; - } mLibLoader = AAudioLoader::getInstance(); int openResult = mLibLoader->open(); return openResult == 0; @@ -399,4 +380,4 @@ Result AudioStreamAAudio::getTimestamp(clockid_t clockId, } } -} // namespace oboe +} // namespace oboe \ No newline at end of file From f3f8102fe0d41a62467a9572710431c0403314c0 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 03/45] Revert "Adding unit tests and testing script" This reverts commit 6b93baddf07b6d817d7ff97945bdf6b303c9f539. --- tests/CMakeLists.txt | 10 ---- tests/run_tests.sh | 110 ---------------------------------------- tests/testUtilities.cpp | 43 ---------------- 3 files changed, 163 deletions(-) delete mode 100644 tests/CMakeLists.txt delete mode 100755 tests/run_tests.sh delete mode 100644 tests/testUtilities.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt deleted file mode 100644 index 303bf1a56..000000000 --- a/tests/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -cmake_minimum_required(VERSION 3.4.1) - -set(GOOGLETEST_ROOT ${ANDROID_NDK}/sources/third_party/googletest/googletest) -add_library(gtest STATIC ${GOOGLETEST_ROOT}/src/gtest_main.cc ${GOOGLETEST_ROOT}/src/gtest-all.cc) -target_include_directories(gtest PRIVATE ${GOOGLETEST_ROOT}) -target_include_directories(gtest PUBLIC ${GOOGLETEST_ROOT}/include) - -include_directories(../include) -add_executable(testOboe testUtilities.cpp ../src/common/Utilities.cpp) -target_link_libraries(testOboe gtest) \ No newline at end of file diff --git a/tests/run_tests.sh b/tests/run_tests.sh deleted file mode 100755 index c4a8a81e7..000000000 --- a/tests/run_tests.sh +++ /dev/null @@ -1,110 +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. - -################################################ -# Script to build and run the Oboe tests on an attached Android device or emulator -# -# Prerequisites: -# - CMake on PATH -# - ANDROID_NDK environment variable is set to your Android NDK location -# e.g. /Library/Android/sdk/ndk-bundle -# - Android device or emulator attached and accessible via adb -# -# Instructions: -# Run this script from within the oboe/tests directory. A directory 'build' will be -# created containing the test binary. This binary will then be copied to the device/emulator -# and executed. -# -# The initial run may take some time as GTest is built, subsequent runs should be much, much -# faster. -# -# If you want to perform a clean build just delete the 'build' folder and re-run this script -# -################################################ - -#!/bin/bash - -# Directories, paths and filenames -BUILD_DIR=build -CMAKE=cmake -TEST_BINARY_FILENAME=testOboe -REMOTE_DIR=/data/local/tmp/oboe - -# Check prerequisites -if [ -z "$ANDROID_NDK" ]; then - echo "Please set ANDROID_NDK to the Android NDK folder" - exit 1 -fi - -if [ ! $(type -P ${CMAKE}) ]; then - echo "${CMAKE} was not found on your path. You can install it using Android Studio using Tools->Android->SDK Manager->SDK Tools." - exit 1 -fi - -# Get the device ABI -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" - exit 1 -fi - -echo "Device/emulator architecture is $ABI" - -if [ ${ABI} == "arm64-v8a" ] || [ ${ABI} == "x86_64" ]; then - PLATFORM=android-21 -elif [ ${ABI} == "armeabi-v7a" ] || [ ${ABI} == "x86" ]; then - PLATFORM=android-16 -else - echo "Unrecognised ABI: ${ABI}. Supported ABIs are: arm64-v8a, armeabi-v7a, x86_64, x86. If you feel ${ABI} should be supported please file an issue on github.com/google/oboe" - exit 1 -fi - -# Configure the build -echo "Building tests for ${ABI} using ${PLATFORM}" - -CMAKE_ARGS="-H. \ - -B${BUILD_DIR} \ - -DANDROID_ABI=${ABI} \ - -DANDROID_PLATFORM=${PLATFORM} \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DCMAKE_CXX_FLAGS=-std=c++11 \ - -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake \ - -DCMAKE_VERBOSE_MAKEFILE=1" - -mkdir -p ${BUILD_DIR} - -cmake ${CMAKE_ARGS} - -# Perform the build -pushd ${BUILD_DIR} - make -j5 - - if [ $? -eq 0 ]; then - echo "Tests built successfully" - else - echo "Building tests FAILED" - exit 1 - fi - -popd - - -# Push the test binary to the device and run it -echo "Pushing test binary to device/emulator" -adb shell mkdir -p ${REMOTE_DIR} -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 diff --git a/tests/testUtilities.cpp b/tests/testUtilities.cpp deleted file mode 100644 index 99451453f..000000000 --- a/tests/testUtilities.cpp +++ /dev/null @@ -1,43 +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. - */ - -#include -#include -#include - -/** - * Tests needing to be written: - * - * - oboe::convertFormatToSizeInBytes() - */ - -using namespace oboe; - -class UtilityFunctions : public ::testing::Test { - - - -}; - -TEST_F(UtilityFunctions, Converts16BitIntegerToSizeOf2Bytes){ - int32_t sizeInBytes = oboe::convertFormatToSizeInBytes(AudioFormat::I16); - ASSERT_EQ(sizeInBytes, 2); -} - -TEST_F(UtilityFunctions, ConvertsFloatToSizeOf4Bytes){ - int32_t sizeInBytes = oboe::convertFormatToSizeInBytes(AudioFormat::Float); - ASSERT_EQ(sizeInBytes, 4); -} \ No newline at end of file From 097f3e9d51e6120aa8201eaca2cb2fa8908581cd Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 04/45] Revert "Version bump from 0.9 to 0.10" This reverts commit 62a37e31ff7ab4209bc132e929b110936ac070d9. --- include/oboe/Version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/oboe/Version.h b/include/oboe/Version.h index 46143d5f5..c143ebc0a 100644 --- a/include/oboe/Version.h +++ b/include/oboe/Version.h @@ -32,7 +32,7 @@ #define OBOE_VERSION_MAJOR 0 // Type: 8-bit unsigned int. Min value: 0 Max value: 255. See below for description. -#define OBOE_VERSION_MINOR 10 +#define OBOE_VERSION_MINOR 9 // Type: 16-bit unsigned int. Min value: 0 Max value: 65535. See below for description. #define OBOE_VERSION_PATCH 0 From ad337b9ea6094a12ce91ac8b5bff89542a1f431c Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 05/45] Revert "More concise return strings for convertToText methods" This reverts commit 58fc3ccf3ebe60b0f74b2e576d347944c0088a81. --- src/common/Utilities.cpp | 122 +++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 55 deletions(-) diff --git a/src/common/Utilities.cpp b/src/common/Utilities.cpp index 04dc42678..a830734e5 100644 --- a/src/common/Utilities.cpp +++ b/src/common/Utilities.cpp @@ -19,6 +19,9 @@ #include "oboe/Definitions.h" #include "oboe/Utilities.h" +// TODO: Return the int value as well as the name +#define OBOE_CASE_ENUM(name) case name: return #name + namespace oboe { constexpr float kScaleI16ToFloat = (1.0f / 32768.0f); @@ -61,93 +64,100 @@ int32_t convertFormatToSizeInBytes(AudioFormat format) { template<> const char *convertToText(Result returnCode) { switch (returnCode) { - case Result::OK: return "OK"; - case Result::ErrorDisconnected: return "ErrorDisconnected"; - case Result::ErrorIllegalArgument: return "ErrorIllegalArgument"; - case Result::ErrorInternal: return "ErrorInternal"; - case Result::ErrorInvalidState: return "ErrorInvalidState"; - case Result::ErrorInvalidHandle: return "ErrorInvalidHandle"; - case Result::ErrorUnimplemented: return "ErrorUnimplemented"; - case Result::ErrorUnavailable: return "ErrorUnavailable"; - case Result::ErrorNoFreeHandles: return "ErrorNoFreeHandles"; - case Result::ErrorNoMemory: return "ErrorNoMemory"; - case Result::ErrorNull: return "ErrorNull"; - case Result::ErrorTimeout: return "ErrorTimeout"; - case Result::ErrorWouldBlock: return "ErrorWouldBlock"; - case Result::ErrorInvalidFormat: return "ErrorInvalidFormat"; - case Result::ErrorOutOfRange: return "ErrorOutOfRange"; - case Result::ErrorNoService: return "ErrorNoService"; - case Result::ErrorInvalidRate: return "ErrorInvalidRate"; - default: return "Unrecognized result"; + OBOE_CASE_ENUM(Result::OK); + OBOE_CASE_ENUM(Result::ErrorDisconnected); + OBOE_CASE_ENUM(Result::ErrorIllegalArgument); + OBOE_CASE_ENUM(Result::ErrorInternal); + OBOE_CASE_ENUM(Result::ErrorInvalidState); + OBOE_CASE_ENUM(Result::ErrorInvalidHandle); + OBOE_CASE_ENUM(Result::ErrorUnimplemented); + OBOE_CASE_ENUM(Result::ErrorUnavailable); + OBOE_CASE_ENUM(Result::ErrorNoFreeHandles); + OBOE_CASE_ENUM(Result::ErrorNoMemory); + OBOE_CASE_ENUM(Result::ErrorNull); + OBOE_CASE_ENUM(Result::ErrorTimeout); + OBOE_CASE_ENUM(Result::ErrorWouldBlock); + OBOE_CASE_ENUM(Result::ErrorInvalidFormat); + OBOE_CASE_ENUM(Result::ErrorOutOfRange); + OBOE_CASE_ENUM(Result::ErrorNoService); + OBOE_CASE_ENUM(Result::ErrorInvalidRate); + default: + return "Unrecognized result"; } } template<> const char *convertToText(AudioFormat format) { switch (format) { - case AudioFormat::Invalid: return "Invalid"; - case AudioFormat::Unspecified: return "Unspecified"; - case AudioFormat::I16: return "I16"; - case AudioFormat::Float: return "Float"; - default: return "Unrecognized format"; + OBOE_CASE_ENUM(AudioFormat::Invalid); + OBOE_CASE_ENUM(AudioFormat::Unspecified); + OBOE_CASE_ENUM(AudioFormat::I16); + OBOE_CASE_ENUM(AudioFormat::Float); + default: + return "Unrecognized format"; } } template<> const char *convertToText(PerformanceMode mode) { switch (mode) { - case PerformanceMode::LowLatency: return "LowLatency"; - case PerformanceMode::None: return "None"; - case PerformanceMode::PowerSaving: return "PowerSaving"; - default: return "Unrecognized performance mode"; + OBOE_CASE_ENUM(PerformanceMode::LowLatency); + OBOE_CASE_ENUM(PerformanceMode::None); + OBOE_CASE_ENUM(PerformanceMode::PowerSaving); + default: + return "Unrecognized performance mode"; } } template<> const char *convertToText(SharingMode mode) { switch (mode) { - case SharingMode::Exclusive: return "Exclusive"; - case SharingMode::Shared: return "Shared"; - default: return "Unrecognized sharing mode"; + OBOE_CASE_ENUM(SharingMode::Exclusive); + OBOE_CASE_ENUM(SharingMode::Shared); + default: + return "Unrecognized sharing mode"; } } template<> const char *convertToText(DataCallbackResult result) { switch (result) { - case DataCallbackResult::Continue: return "Continue"; - case DataCallbackResult::Stop: return "Stop"; - default: return "Unrecognized data callback result"; + OBOE_CASE_ENUM(DataCallbackResult::Continue); + OBOE_CASE_ENUM(DataCallbackResult::Stop); + default: + return "Unrecognized data callback result"; } } template<> const char *convertToText(Direction direction) { switch (direction) { - case Direction::Input: return "Input"; - case Direction::Output: return "Output"; - default: return "Unrecognized direction"; + OBOE_CASE_ENUM(Direction::Input); + OBOE_CASE_ENUM(Direction::Output); + default: + return "Unrecognized direction"; } } template<> const char *convertToText(StreamState state) { switch (state) { - case StreamState::Closed: return "Closed"; - case StreamState::Closing: return "Closing"; - case StreamState::Disconnected: return "Disconnected"; - case StreamState::Flushed: return "Flushed"; - case StreamState::Flushing: return "Flushing"; - case StreamState::Open: return "Open"; - case StreamState::Paused: return "Paused"; - case StreamState::Pausing: return "Pausing"; - case StreamState::Started: return "Started"; - case StreamState::Starting: return "Starting"; - case StreamState::Stopped: return "Stopped"; - case StreamState::Stopping: return "Stopping"; - case StreamState::Uninitialized: return "Uninitialized"; - case StreamState::Unknown: return "Unknown"; - default: return "Unrecognized stream state"; + OBOE_CASE_ENUM(StreamState::Closed); + OBOE_CASE_ENUM(StreamState::Closing); + OBOE_CASE_ENUM(StreamState::Disconnected); + OBOE_CASE_ENUM(StreamState::Flushed); + OBOE_CASE_ENUM(StreamState::Flushing); + OBOE_CASE_ENUM(StreamState::Open); + OBOE_CASE_ENUM(StreamState::Paused); + OBOE_CASE_ENUM(StreamState::Pausing); + OBOE_CASE_ENUM(StreamState::Started); + OBOE_CASE_ENUM(StreamState::Starting); + OBOE_CASE_ENUM(StreamState::Stopped); + OBOE_CASE_ENUM(StreamState::Stopping); + OBOE_CASE_ENUM(StreamState::Uninitialized); + OBOE_CASE_ENUM(StreamState::Unknown); + default: + return "Unrecognized stream state"; } } @@ -155,10 +165,12 @@ template<> const char *convertToText(AudioApi audioApi) { switch (audioApi) { - case AudioApi::Unspecified: return "Unspecified"; - case AudioApi::OpenSLES: return "OpenSLES"; - case AudioApi::AAudio: return "AAudio"; - default: return "Unrecognised audio API"; + OBOE_CASE_ENUM(AudioApi::Unspecified); + OBOE_CASE_ENUM(AudioApi::OpenSLES); + OBOE_CASE_ENUM(AudioApi::AAudio); + default: + return "Unrecognised audio API"; + } } From 70bfc12e797ea0385417fbe4b4d4613da56984f6 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 06/45] Revert "Adding convertToText for AudioApi" This reverts commit 4109c15d2ba9b15729e22c87529d6700682aa469. --- include/oboe/AudioStream.h | 9 +++++---- src/common/Utilities.cpp | 14 +------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/include/oboe/AudioStream.h b/include/oboe/AudioStream.h index 90b98a8dc..98fc15761 100644 --- a/include/oboe/AudioStream.h +++ b/include/oboe/AudioStream.h @@ -79,8 +79,8 @@ class AudioStream : public AudioStreamBase { virtual StreamState getState() = 0; /** - * 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 + * Wait until the current state no longer matches the input state. + * The current state is passed to avoid race conditions caused by the state * changing between calls. * * Note that generally applications do not need to call this. It is considered @@ -95,12 +95,13 @@ class AudioStream : public AudioStreamBase { * } * * - * @param inputState The state we want to avoid. + * @param stream A handle provided by OboeStreamBuilder_openStream() + * @param currentState The state we want to avoid. * @param nextState Pointer to a variable that will be set to the new state. * @param timeoutNanoseconds The maximum time to wait in nanoseconds. * @return Result::OK or a Result::Error. */ - virtual Result waitForStateChange(StreamState inputState, + virtual Result waitForStateChange(StreamState currentState, StreamState *nextState, int64_t timeoutNanoseconds) = 0; diff --git a/src/common/Utilities.cpp b/src/common/Utilities.cpp index a830734e5..a72fdb87a 100644 --- a/src/common/Utilities.cpp +++ b/src/common/Utilities.cpp @@ -161,17 +161,5 @@ const char *convertToText(StreamState state) { } } -template<> -const char *convertToText(AudioApi audioApi) { - - switch (audioApi) { - OBOE_CASE_ENUM(AudioApi::Unspecified); - OBOE_CASE_ENUM(AudioApi::OpenSLES); - OBOE_CASE_ENUM(AudioApi::AAudio); - default: - return "Unrecognised audio API"; - - } -} -}// namespace oboe \ No newline at end of file +} // namespace oboe \ No newline at end of file From 9c2e8bfbd3482fe1716f9750aed0ecf4ade6e2f3 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 07/45] Revert "Rename ApiIndex to AudioApi, move into Definitions.h" This reverts commit 360c8aab4497f42b5e8c969a1110619b00d44336. --- include/oboe/AudioStreamBuilder.h | 24 +++++++++++++++++++++--- include/oboe/Definitions.h | 18 ------------------ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/include/oboe/AudioStreamBuilder.h b/include/oboe/AudioStreamBuilder.h index 34c38b8f2..920f8af4d 100644 --- a/include/oboe/AudioStreamBuilder.h +++ b/include/oboe/AudioStreamBuilder.h @@ -32,6 +32,24 @@ class AudioStreamBuilder : public AudioStreamBase { AudioStreamBuilder() : AudioStreamBase() {} + enum class AudioApi { + /** + * Try to use AAudio. If not available then use OpenSL ES. + */ + Unspecified, + + /** + * Use OpenSL ES. + */ + OpenSLES, + + /** + * Try to use AAudio. Fail if unavailable. + */ + AAudio + }; + + /** * Request a specific number of channels. * @@ -113,7 +131,7 @@ class AudioStreamBuilder : public AudioStreamBase { return this; } - AudioApi getAudioApi() const { return mAudioApi; } + AudioApi getApiIndex() const { return mAudioApi; } /** * Normally you would leave this unspecified, and Oboe will chose the best API @@ -121,8 +139,8 @@ class AudioStreamBuilder : public AudioStreamBase { * @param Must be AudioApi::Unspecified, AudioApi::OpenSLES or AudioApi::AAudio. * @return pointer to the builder so calls can be chained */ - AudioStreamBuilder *setAudioApi(AudioApi audioApi) { - mAudioApi = audioApi; + AudioStreamBuilder *setApiIndex(AudioApi apiIndex) { + mAudioApi = apiIndex; return this; } diff --git a/include/oboe/Definitions.h b/include/oboe/Definitions.h index 4b02b3c30..0cc6bea02 100644 --- a/include/oboe/Definitions.h +++ b/include/oboe/Definitions.h @@ -125,24 +125,6 @@ namespace oboe { // Reducing latency is most important. LowLatency = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY }; - - enum class AudioApi : int32_t { - /** - * Try to use AAudio. If not available then use OpenSL ES. - */ - Unspecified = kUnspecified, - - /** - * Use OpenSL ES. - */ - OpenSLES, - - /** - * Try to use AAudio. Fail if unavailable. - */ - AAudio - }; - } // namespace oboe #endif // OBOE_DEFINITIONS_H From 9b73d071c2bad58d2a34d2760bf098374fdde933 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 08/45] Revert "Initialize mStreamCallback to nullptr. Fixes #44." This reverts commit 4e7965d193333ec1e12c7ec8a54f938545ca8434. --- include/oboe/AudioStreamBase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/oboe/AudioStreamBase.h b/include/oboe/AudioStreamBase.h index be2d892fd..b55cfcb81 100644 --- a/include/oboe/AudioStreamBase.h +++ b/include/oboe/AudioStreamBase.h @@ -95,7 +95,7 @@ class AudioStreamBase { } protected: - AudioStreamCallback *mStreamCallback = nullptr; + AudioStreamCallback *mStreamCallback; int32_t mFramesPerCallback = kUnspecified; int32_t mChannelCount = kUnspecified; int32_t mSampleRate = kUnspecified; From acc427113a3be336272b539a5f5c49570248548d Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 09/45] Revert "Add convertToText(StreamState). Fixes #38" This reverts commit 1415d4be7520721cc5ca76291e72e606eb15d010. --- include/oboe/Definitions.h | 1 - src/common/Utilities.cpp | 23 ----------------------- 2 files changed, 24 deletions(-) diff --git a/include/oboe/Definitions.h b/include/oboe/Definitions.h index 0cc6bea02..7ec73c0cb 100644 --- a/include/oboe/Definitions.h +++ b/include/oboe/Definitions.h @@ -45,7 +45,6 @@ namespace oboe { enum class StreamState : aaudio_stream_state_t { Uninitialized = AAUDIO_STREAM_STATE_UNINITIALIZED, - Unknown = AAUDIO_STREAM_STATE_UNKNOWN, Open = AAUDIO_STREAM_STATE_OPEN, Starting = AAUDIO_STREAM_STATE_STARTING, Started = AAUDIO_STREAM_STATE_STARTED, diff --git a/src/common/Utilities.cpp b/src/common/Utilities.cpp index a72fdb87a..5df58ea86 100644 --- a/src/common/Utilities.cpp +++ b/src/common/Utilities.cpp @@ -139,27 +139,4 @@ const char *convertToText(Direction direction) { } } -template<> -const char *convertToText(StreamState state) { - switch (state) { - OBOE_CASE_ENUM(StreamState::Closed); - OBOE_CASE_ENUM(StreamState::Closing); - OBOE_CASE_ENUM(StreamState::Disconnected); - OBOE_CASE_ENUM(StreamState::Flushed); - OBOE_CASE_ENUM(StreamState::Flushing); - OBOE_CASE_ENUM(StreamState::Open); - OBOE_CASE_ENUM(StreamState::Paused); - OBOE_CASE_ENUM(StreamState::Pausing); - OBOE_CASE_ENUM(StreamState::Started); - OBOE_CASE_ENUM(StreamState::Starting); - OBOE_CASE_ENUM(StreamState::Stopped); - OBOE_CASE_ENUM(StreamState::Stopping); - OBOE_CASE_ENUM(StreamState::Uninitialized); - OBOE_CASE_ENUM(StreamState::Unknown); - default: - return "Unrecognized stream state"; - } -} - - } // namespace oboe \ No newline at end of file From c7188a89f1558fd381aa5f5ad0213f9571a15927 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 10/45] Revert "Move float scaling value into constant. Fixes #21" This reverts commit f6586af334dc3c44f03def42c38f52c266117657. --- src/common/Utilities.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/common/Utilities.cpp b/src/common/Utilities.cpp index 5df58ea86..6bc89cde4 100644 --- a/src/common/Utilities.cpp +++ b/src/common/Utilities.cpp @@ -24,8 +24,6 @@ namespace oboe { -constexpr float kScaleI16ToFloat = (1.0f / 32768.0f); - void convertFloatToPcm16(const float *source, int16_t *destination, int32_t numSamples) { for (int i = 0; i < numSamples; i++) { float fval = source[i]; @@ -42,7 +40,7 @@ void convertFloatToPcm16(const float *source, int16_t *destination, int32_t numS void convertPcm16ToFloat(const int16_t *source, float *destination, int32_t numSamples) { for (int i = 0; i < numSamples; i++) { - destination[i] = source[i] * kScaleI16ToFloat; + destination[i] = source[i] * (1.0f / 32768.0f); } } From adee4264f0925102a9709c1dc753af044c6cd5f8 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 11/45] Revert "Add disconnected state" This reverts commit 3082e8379756e847bb435017760393abbd43b13d. --- include/oboe/Definitions.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/oboe/Definitions.h b/include/oboe/Definitions.h index 7ec73c0cb..341677be4 100644 --- a/include/oboe/Definitions.h +++ b/include/oboe/Definitions.h @@ -56,7 +56,6 @@ namespace oboe { Stopped = AAUDIO_STREAM_STATE_STOPPED, Closing = AAUDIO_STREAM_STATE_CLOSING, Closed = AAUDIO_STREAM_STATE_CLOSED, - Disconnected = AAUDIO_STREAM_STATE_DISCONNECTED, }; enum class Direction : aaudio_direction_t { From 5d2e272ccf5c52efc605c4d7396f5dd8034228e1 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 12/45] Revert "Input streams are live" This reverts commit 25d9ef91db81e6d6f174fc9c69b6c8e0700f978c. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index dcf8803da..fb1232e58 100755 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ Oboe is a C++ library which makes it easy to build high-performance audio apps on Android. It was created primarily to allow developers to target a simplified API that works across multiple API levels back to API level 16 (Jelly Bean). +**Note:** This version (0.9) of Oboe only supports playback (output) streams. Support for recording (input) streams is in active development. + [Get started with Oboe here](GettingStarted.md). ## Features From 14fdd2f6019e2ad3caee4f1229ccc699b9c8b2f6 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 13/45] Revert "Oboe works with NDK r15" This reverts commit 7785ef95c2325ce558b9af6cfa4e718d06144211. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb1232e58..36f63c5ed 100755 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Oboe is a C++ library which makes it easy to build high-performance audio apps o - Modern C++ allowing you to write clean, elegant code ## Requirements -To build Oboe you will need the [Android NDK](https://developer.android.com/ndk/index.html) r15 or above +To build Oboe you will need the [Android NDK](https://developer.android.com/ndk/index.html) r16 or above ## Documentation - [Getting Started Guide](GettingStarted.md) From bf35a7e4bbc4e0b1052527aea53d34231651df97 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 14/45] Revert "Change Version from class to struct" This reverts commit c4295d74243941b4d5073bce3f6795e5975f53ec. --- include/oboe/Version.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/oboe/Version.h b/include/oboe/Version.h index c143ebc0a..ce468ebdf 100644 --- a/include/oboe/Version.h +++ b/include/oboe/Version.h @@ -51,7 +51,9 @@ namespace oboe { -struct Version { +class Version { + +public: /** * This is incremented when we make breaking API changes. Based loosely on https://semver.org/. */ From d48e5f27a56ef167aad6b0d1b1f38abd919df6fb Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 15/45] Revert "Use #defines for version numbers" This reverts commit edc14ea380907d7e678846add7b902328a990847. --- CMakeLists.txt | 1 + include/oboe/Version.h | 68 +++++++++++------------------------------- src/common/Version.cpp | 39 ++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 50 deletions(-) create mode 100644 src/common/Version.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b82a0fda..d67372f0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,7 @@ set (oboe_sources src/common/AudioStream.cpp src/common/AudioStreamBuilder.cpp src/common/Utilities.cpp + src/common/Version.cpp src/fifo/FifoBuffer.cpp src/fifo/FifoController.cpp src/fifo/FifoControllerBase.cpp diff --git a/include/oboe/Version.h b/include/oboe/Version.h index ce468ebdf..dbfd95680 100644 --- a/include/oboe/Version.h +++ b/include/oboe/Version.h @@ -17,70 +17,38 @@ #ifndef OBOE_VERSIONINFO_H #define OBOE_VERSIONINFO_H -/** - * A note on use of preprocessor defines: - * - * This is one of the few times when it's suitable to use preprocessor defines rather than constexpr - * Why? Because C++11 requires a lot of boilerplate code to convert integers into compile-time - * string literals. The preprocessor, despite it's lack of type checking, is more suited to the task - * - * See: https://stackoverflow.com/questions/6713420/c-convert-integer-to-string-at-compile-time/26824971#26824971 - * - */ - -// Type: 8-bit unsigned int. Min value: 0 Max value: 255. See below for description. -#define OBOE_VERSION_MAJOR 0 - -// Type: 8-bit unsigned int. Min value: 0 Max value: 255. See below for description. -#define OBOE_VERSION_MINOR 9 - -// Type: 16-bit unsigned int. Min value: 0 Max value: 65535. See below for description. -#define OBOE_VERSION_PATCH 0 - -#define OBOE_STRINGIFY(x) #x -#define OBOE_TOSTRING(x) OBOE_STRINGIFY(x) - -// Type: String literal. See below for description. -#define OBOE_VERSION_TEXT \ - OBOE_TOSTRING(OBOE_VERSION_MAJOR) "." \ - OBOE_TOSTRING(OBOE_VERSION_MINOR) "." \ - OBOE_TOSTRING(OBOE_VERSION_PATCH) - -// Type: 32-bit unsigned int. See below for description. -#define OBOE_VERSION_NUMBER ((OBOE_VERSION_MAJOR << 24) | (OBOE_VERSION_MINOR << 16) | OBOE_VERSION_PATCH) - namespace oboe { class Version { public: - /** - * This is incremented when we make breaking API changes. Based loosely on https://semver.org/. - */ - static constexpr uint8_t Major = OBOE_VERSION_MAJOR; + // This is incremented when we make breaking API changes. Based loosely on https://semver.org/ + static constexpr uint8_t MajorNumber = 0; - /** - * This is incremented when we add backwards compatible functionality. Or set to zero when MAJOR is - * incremented. - */ - static constexpr uint8_t Minor = OBOE_VERSION_MINOR; + // This is incremented when we add backwards compatible functionality. Or set to zero when kVersionMajor is + // incremented + static constexpr uint8_t MinorNumber = 9; - /** - * This is incremented when we make backwards compatible bug fixes. Or set to zero when MINOR is - * incremented. - */ - static constexpr uint16_t Patch = OBOE_VERSION_PATCH; + // This is incremented when we make backwards compatible bug fixes. Or set to zero when kVersionMinor is + // incremented + static constexpr uint16_t SubMinorNumber = 0; /** - * Version string in the form MAJOR.MINOR.PATCH. + * Provides a text representation of the current Oboe library version in the form: + * + * MAJOR.MINOR.SUBMINOR + * + * @return A string containing the current Oboe library version */ - static constexpr const char * Text = OBOE_VERSION_TEXT; + static const char * toString(); /** - * Integer representation of the current Oboe library version. This will always increase when the + * Provides an integer representation of the current Oboe library version. This will always increase when the * version number changes so can be compared using integer comparison. + * + * @return an integer representing the current Oboe library version. */ - static constexpr uint32_t Number = OBOE_VERSION_NUMBER; + static uint32_t toInt(); }; } // namespace oboe diff --git a/src/common/Version.cpp b/src/common/Version.cpp new file mode 100644 index 000000000..e5074985e --- /dev/null +++ b/src/common/Version.cpp @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#include +#include "oboe/Version.h" + +namespace oboe { + +// Max digits in 32-bit unsigned int = 10, plus two periods, plus null terminator = 13 +constexpr int kMaxVersionStringLength = 13; + +const char * Version::toString() { + + static char text[kMaxVersionStringLength]; + snprintf(text, kMaxVersionStringLength, "%d.%d.%d", + MajorNumber, + MinorNumber, + SubMinorNumber); + return text; +} + +uint32_t Version::toInt(){ + return MajorNumber << 24 | MinorNumber << 16 | SubMinorNumber; +} + +} // namespace oboe \ No newline at end of file From 517f612b639b57c63a136d23374f9323f754e49a Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 16/45] Revert "Adding version information" This reverts commit 63634d9dd38252a3e20029b3e0cb4b6ba9757863. --- CMakeLists.txt | 1 - include/oboe/Oboe.h | 1 - include/oboe/Version.h | 55 ------------------------------------------ src/common/Version.cpp | 39 ------------------------------ 4 files changed, 96 deletions(-) delete mode 100644 include/oboe/Version.h delete mode 100644 src/common/Version.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d67372f0f..1b82a0fda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,6 @@ set (oboe_sources src/common/AudioStream.cpp src/common/AudioStreamBuilder.cpp src/common/Utilities.cpp - src/common/Version.cpp src/fifo/FifoBuffer.cpp src/fifo/FifoController.cpp src/fifo/FifoControllerBase.cpp diff --git a/include/oboe/Oboe.h b/include/oboe/Oboe.h index 1fd8a59ee..34733e008 100644 --- a/include/oboe/Oboe.h +++ b/include/oboe/Oboe.h @@ -23,6 +23,5 @@ #include "oboe/AudioStreamBase.h" #include "oboe/AudioStreamBuilder.h" #include "oboe/Utilities.h" -#include "oboe/Version.h" #endif //OBOE_OBOE_H diff --git a/include/oboe/Version.h b/include/oboe/Version.h deleted file mode 100644 index dbfd95680..000000000 --- a/include/oboe/Version.h +++ /dev/null @@ -1,55 +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. - */ - -#ifndef OBOE_VERSIONINFO_H -#define OBOE_VERSIONINFO_H - -namespace oboe { - -class Version { - -public: - // This is incremented when we make breaking API changes. Based loosely on https://semver.org/ - static constexpr uint8_t MajorNumber = 0; - - // This is incremented when we add backwards compatible functionality. Or set to zero when kVersionMajor is - // incremented - static constexpr uint8_t MinorNumber = 9; - - // This is incremented when we make backwards compatible bug fixes. Or set to zero when kVersionMinor is - // incremented - static constexpr uint16_t SubMinorNumber = 0; - - /** - * Provides a text representation of the current Oboe library version in the form: - * - * MAJOR.MINOR.SUBMINOR - * - * @return A string containing the current Oboe library version - */ - static const char * toString(); - - /** - * Provides an integer representation of the current Oboe library version. This will always increase when the - * version number changes so can be compared using integer comparison. - * - * @return an integer representing the current Oboe library version. - */ - static uint32_t toInt(); -}; - -} // namespace oboe -#endif //OBOE_VERSIONINFO_H diff --git a/src/common/Version.cpp b/src/common/Version.cpp deleted file mode 100644 index e5074985e..000000000 --- a/src/common/Version.cpp +++ /dev/null @@ -1,39 +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. - */ - -#include -#include "oboe/Version.h" - -namespace oboe { - -// Max digits in 32-bit unsigned int = 10, plus two periods, plus null terminator = 13 -constexpr int kMaxVersionStringLength = 13; - -const char * Version::toString() { - - static char text[kMaxVersionStringLength]; - snprintf(text, kMaxVersionStringLength, "%d.%d.%d", - MajorNumber, - MinorNumber, - SubMinorNumber); - return text; -} - -uint32_t Version::toInt(){ - return MajorNumber << 24 | MinorNumber << 16 | SubMinorNumber; -} - -} // namespace oboe \ No newline at end of file From f0bf6aa7f7258c2e5040219445ee35598c6ea22e Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 17/45] Revert "Update the CMakeLists.txt complete example" This reverts commit 960725d56233414e9ef29efd9198a26629cf1eac. --- GettingStarted.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/GettingStarted.md b/GettingStarted.md index 43b23a195..1e532d997 100644 --- a/GettingStarted.md +++ b/GettingStarted.md @@ -36,19 +36,17 @@ Here's a complete example `CMakeLists.txt` file: cmake_minimum_required(VERSION 3.4.1) - # Build our own native library - add_library (native-lib SHARED src/main/cpp/native-lib.cpp ) - - # Specify the libraries which our native library is dependent on, including Oboe - target_link_libraries (native-lib log oboe) - # Build the Oboe library set (OBOE_DIR ../../../oboe) add_subdirectory (${OBOE_DIR} ./oboe) - - # Make the Oboe public headers available to our app include_directories (${OBOE_DIR}/include) + # Build our own native library + add_library (native-lib SHARED src/main/cpp/native-lib.cpp ) + + # Specify the libraries which our native library is dependent on + target_link_libraries (native-lib log oboe) + Verify that your project builds correctly. If you have any issues building please [report them here](issues/new). # Using Oboe From 7d578c42a45cd4a8d575089733453c908c7af1d3 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 18/45] Revert "oboe: make chanCountToChanMask non-virtual" This reverts commit c7a2b008e4e490be01bc6ed46c75400077a2fc52. --- src/opensles/AudioInputStreamOpenSLES.h | 3 +-- src/opensles/AudioOutputStreamOpenSLES.h | 2 +- src/opensles/AudioStreamOpenSLES.h | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/opensles/AudioInputStreamOpenSLES.h b/src/opensles/AudioInputStreamOpenSLES.h index 89c03d07d..9fb79f576 100644 --- a/src/opensles/AudioInputStreamOpenSLES.h +++ b/src/opensles/AudioInputStreamOpenSLES.h @@ -49,8 +49,7 @@ class AudioInputStreamOpenSLES : public AudioStreamOpenSLES { StreamState *nextState, int64_t timeoutNanoseconds) override; - int chanCountToChanMask(int chanCount); - + int chanCountToChanMask(int chanCount) override; private: Result setRecordState(SLuint32 newState); diff --git a/src/opensles/AudioOutputStreamOpenSLES.h b/src/opensles/AudioOutputStreamOpenSLES.h index f8b83de9f..9e73f2ae3 100644 --- a/src/opensles/AudioOutputStreamOpenSLES.h +++ b/src/opensles/AudioOutputStreamOpenSLES.h @@ -48,7 +48,7 @@ class AudioOutputStreamOpenSLES : public AudioStreamOpenSLES { StreamState *nextState, int64_t timeoutNanoseconds) override; - int chanCountToChanMask(int chanCount); + int chanCountToChanMask(int chanCount) override; private: diff --git a/src/opensles/AudioStreamOpenSLES.h b/src/opensles/AudioStreamOpenSLES.h index 7056e57b4..da4a9adeb 100644 --- a/src/opensles/AudioStreamOpenSLES.h +++ b/src/opensles/AudioStreamOpenSLES.h @@ -57,6 +57,8 @@ class AudioStreamOpenSLES : public AudioStreamBuffered { int32_t getFramesPerBurst() override; + virtual int chanCountToChanMask(int chanCount) = 0; + /** * Process next OpenSL ES buffer. * Called by by OpenSL ES framework. From 7f05126d329e628dbc3b7b09665f1fc66925384b Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 19/45] Revert "oboe: address review comments, better singleton" This reverts commit 6d8e3e1e7a2571a4d386121769465391a2b3b5f7. --- CMakeLists.txt | 6 +---- src/opensles/AudioInputStreamOpenSLES.cpp | 8 +++---- src/opensles/AudioOutputStreamOpenSLES.cpp | 28 +++++++++++----------- src/opensles/AudioStreamOpenSLES.cpp | 8 +++---- src/opensles/AudioStreamOpenSLES.h | 10 +++++--- src/opensles/EngineOpenSLES.cpp | 4 ++-- src/opensles/EngineOpenSLES.h | 11 ++------- src/opensles/OpenSLESUtilities.cpp | 8 +++---- src/opensles/OutputMixerOpenSLES.cpp | 8 +++---- src/opensles/OutputMixerOpenSLES.h | 11 ++------- 10 files changed, 42 insertions(+), 60 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b82a0fda..1a4bfadbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,13 +11,9 @@ set (oboe_sources src/fifo/FifoController.cpp src/fifo/FifoControllerBase.cpp src/fifo/FifoControllerIndirect.cpp - src/opensles/AudioInputStreamOpenSLES.cpp - src/opensles/AudioOutputStreamOpenSLES.cpp src/opensles/AudioStreamBuffered.cpp src/opensles/AudioStreamOpenSLES.cpp - src/opensles/EngineOpenSLES.cpp src/opensles/OpenSLESUtilities.cpp - src/opensles/OutputMixerOpenSLES.cpp ) add_library(oboe STATIC ${oboe_sources}) @@ -29,4 +25,4 @@ target_compile_options(oboe PRIVATE -std=c++11 PRIVATE -Wall PRIVATE "$<$:-Werror>") # Only include -Werror when building debug config -target_link_libraries(oboe PRIVATE log OpenSLES) +target_link_libraries(oboe PRIVATE log OpenSLES) \ No newline at end of file diff --git a/src/opensles/AudioInputStreamOpenSLES.cpp b/src/opensles/AudioInputStreamOpenSLES.cpp index 3ff10e64f..23e1c66b3 100644 --- a/src/opensles/AudioInputStreamOpenSLES.cpp +++ b/src/opensles/AudioInputStreamOpenSLES.cpp @@ -59,7 +59,7 @@ Result AudioInputStreamOpenSLES::open() { Result oboeResult = AudioStreamOpenSLES::open(); if (Result::OK != oboeResult) return oboeResult; - SLuint32 bitsPerSample = getBytesPerSample() * kBitsPerByte; + SLuint32 bitsPerSample = getBytesPerSample() * OBOE_BITS_PER_BYTE; // configure audio sink SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { @@ -100,7 +100,7 @@ Result AudioInputStreamOpenSLES::open() { NULL }; SLDataSource audioSrc = {&loc_dev, NULL }; - SLresult result = EngineOpenSLES::getInstance().createAudioRecorder(&mObjectInterface, + SLresult result = EngineOpenSLES::getInstance()->createAudioRecorder(&mObjectInterface, &audioSrc, &audioSink); if (SL_RESULT_SUCCESS != result) { @@ -130,17 +130,17 @@ Result AudioInputStreamOpenSLES::open() { result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_RECORD, &mRecordInterface); if (SL_RESULT_SUCCESS != result) { - LOGE("GetInterface RECORD result:%s", getSLErrStr(result)); + LOGE("get recorder interface result:%s", getSLErrStr(result)); goto error; } result = AudioStreamOpenSLES::registerBufferQueueCallback(); if (SL_RESULT_SUCCESS != result) { + LOGE("get bufferqueue interface:%p result:%s", mSimpleBufferQueueInterface, getSLErrStr(result)); goto error; } return Result::OK; - error: return Result::ErrorInternal; // TODO convert error from SLES to OBOE } diff --git a/src/opensles/AudioOutputStreamOpenSLES.cpp b/src/opensles/AudioOutputStreamOpenSLES.cpp index 21297661e..b31d62735 100644 --- a/src/opensles/AudioOutputStreamOpenSLES.cpp +++ b/src/opensles/AudioOutputStreamOpenSLES.cpp @@ -35,16 +35,15 @@ AudioOutputStreamOpenSLES::~AudioOutputStreamOpenSLES() { } // These will wind up in -constexpr int SL_ANDROID_SPEAKER_STEREO = (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT); +#define SL_ANDROID_SPEAKER_QUAD (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT \ + | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT) -constexpr int SL_ANDROID_SPEAKER_QUAD = (SL_ANDROID_SPEAKER_STEREO - | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT); +#define SL_ANDROID_SPEAKER_5DOT1 (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT \ + | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY| SL_SPEAKER_BACK_LEFT \ + | SL_SPEAKER_BACK_RIGHT) -constexpr int SL_ANDROID_SPEAKER_5DOT1 = (SL_ANDROID_SPEAKER_QUAD - | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY); - -constexpr int SL_ANDROID_SPEAKER_7DOT1 = (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT - | SL_SPEAKER_SIDE_RIGHT); +#define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT \ + |SL_SPEAKER_SIDE_RIGHT) int AudioOutputStreamOpenSLES::chanCountToChanMask(int chanCount) { int channelMask = 0; @@ -55,7 +54,7 @@ int AudioOutputStreamOpenSLES::chanCountToChanMask(int chanCount) { break; case 2: - channelMask = SL_ANDROID_SPEAKER_STEREO; + channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; break; case 4: // Quad @@ -77,13 +76,13 @@ Result AudioOutputStreamOpenSLES::open() { Result oboeResult = AudioStreamOpenSLES::open(); if (Result::OK != oboeResult) return oboeResult; - SLresult result = OutputMixerOpenSL::getInstance().open(); + SLresult result = OutputMixerOpenSL::getInstance()->open(); if (SL_RESULT_SUCCESS != result) { AudioStreamOpenSLES::close(); return Result::ErrorInternal; } - SLuint32 bitsPerSample = getBytesPerSample() * kBitsPerByte; + SLuint32 bitsPerSample = getBytesPerSample() * OBOE_BITS_PER_BYTE; // configure audio source SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { @@ -117,7 +116,7 @@ Result AudioOutputStreamOpenSLES::open() { audioSrc.pFormat = &format_pcm_ex; } - result = OutputMixerOpenSL::getInstance().createAudioPlayer(&mObjectInterface, + result = OutputMixerOpenSL::getInstance()->createAudioPlayer(&mObjectInterface, &audioSrc); if (SL_RESULT_SUCCESS != result) { LOGE("createAudioPlayer() result:%s", getSLErrStr(result)); @@ -132,12 +131,13 @@ Result AudioOutputStreamOpenSLES::open() { result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_PLAY, &mPlayInterface); if (SL_RESULT_SUCCESS != result) { - LOGE("GetInterface PLAY result:%s", getSLErrStr(result)); + LOGE("get player interface result:%s", getSLErrStr(result)); goto error; } result = AudioStreamOpenSLES::registerBufferQueueCallback(); if (SL_RESULT_SUCCESS != result) { + LOGE("get bufferqueue interface:%p result:%s", mSimpleBufferQueueInterface, getSLErrStr(result)); goto error; } @@ -150,7 +150,7 @@ Result AudioOutputStreamOpenSLES::close() { requestPause(); // invalidate any interfaces mPlayInterface = NULL; - OutputMixerOpenSL::getInstance().close(); + OutputMixerOpenSL::getInstance()->close(); return AudioStreamOpenSLES::close(); } diff --git a/src/opensles/AudioStreamOpenSLES.cpp b/src/opensles/AudioStreamOpenSLES.cpp index 3830eeb7c..0a674af48 100644 --- a/src/opensles/AudioStreamOpenSLES.cpp +++ b/src/opensles/AudioStreamOpenSLES.cpp @@ -65,7 +65,7 @@ Result AudioStreamOpenSLES::open() { return Result::ErrorInvalidFormat; } - SLresult result = EngineOpenSLES::getInstance().open(); + SLresult result = EngineOpenSLES::getInstance()->open(); if (SL_RESULT_SUCCESS != result) { return Result::ErrorInternal; } @@ -119,7 +119,7 @@ Result AudioStreamOpenSLES::close() { } mSimpleBufferQueueInterface = NULL; - EngineOpenSLES::getInstance().close(); + EngineOpenSLES::getInstance()->close(); return Result::OK; } @@ -149,9 +149,7 @@ SLresult AudioStreamOpenSLES::registerBufferQueueCallback() { SLresult result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &mSimpleBufferQueueInterface); if (SL_RESULT_SUCCESS != result) { - LOGE("get buffer queue interface:%p result:%s", - mSimpleBufferQueueInterface, - getSLErrStr(result)); + LOGE("get bufferqueue interface:%p result:%s", mSimpleBufferQueueInterface, getSLErrStr(result)); } else { // Register the BufferQueue callback result = (*mSimpleBufferQueueInterface)->RegisterCallback(mSimpleBufferQueueInterface, diff --git a/src/opensles/AudioStreamOpenSLES.h b/src/opensles/AudioStreamOpenSLES.h index da4a9adeb..1688c1e34 100644 --- a/src/opensles/AudioStreamOpenSLES.h +++ b/src/opensles/AudioStreamOpenSLES.h @@ -26,7 +26,10 @@ namespace oboe { -constexpr int kBitsPerByte = 8; +#define OBOE_BITS_PER_BYTE 8 // common value TODO modernize + + + /** * INTERNAL USE ONLY @@ -48,6 +51,7 @@ class AudioStreamOpenSLES : public AudioStreamBuffered { virtual Result open() override; virtual Result close() override; + /** * Query the current state, eg. OBOE_STREAM_STATE_PAUSING * @@ -57,6 +61,8 @@ class AudioStreamOpenSLES : public AudioStreamBuffered { int32_t getFramesPerBurst() override; + static SLuint32 getDefaultByteOrder(); + virtual int chanCountToChanMask(int chanCount) = 0; /** @@ -69,8 +75,6 @@ class AudioStreamOpenSLES : public AudioStreamBuffered { protected: - static SLuint32 getDefaultByteOrder(); - SLresult registerBufferQueueCallback(); SLresult enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq); diff --git a/src/opensles/EngineOpenSLES.cpp b/src/opensles/EngineOpenSLES.cpp index 8df3fed91..cf87ecc87 100644 --- a/src/opensles/EngineOpenSLES.cpp +++ b/src/opensles/EngineOpenSLES.cpp @@ -20,9 +20,9 @@ using namespace oboe; -EngineOpenSLES &EngineOpenSLES::getInstance() { +EngineOpenSLES *EngineOpenSLES::getInstance() { static EngineOpenSLES sInstance; - return sInstance; + return &sInstance; } SLresult EngineOpenSLES::open() { diff --git a/src/opensles/EngineOpenSLES.h b/src/opensles/EngineOpenSLES.h index 7658c955a..20564f95f 100644 --- a/src/opensles/EngineOpenSLES.h +++ b/src/opensles/EngineOpenSLES.h @@ -30,7 +30,7 @@ namespace oboe { */ class EngineOpenSLES { public: - static EngineOpenSLES &getInstance(); + static EngineOpenSLES *getInstance(); SLresult open(); @@ -46,15 +46,8 @@ class EngineOpenSLES { SLDataSink *audioSink); private: - // Make this a safe Singleton - EngineOpenSLES()= default; - ~EngineOpenSLES()= default; - EngineOpenSLES(const EngineOpenSLES&)= delete; - EngineOpenSLES& operator=(const EngineOpenSLES&)= delete; - std::mutex mLock; - int32_t mOpenCount = 0; - + std::atomic mOpenCount{0}; SLObjectItf mEngineObject = 0; SLEngineItf mEngineInterface; }; diff --git a/src/opensles/OpenSLESUtilities.cpp b/src/opensles/OpenSLESUtilities.cpp index 45f1c1880..c764af382 100644 --- a/src/opensles/OpenSLESUtilities.cpp +++ b/src/opensles/OpenSLESUtilities.cpp @@ -61,15 +61,13 @@ SLAndroidDataFormat_PCM_EX OpenSLES_createExtendedFormat( SLuint32 OpenSLES_ConvertFormatToRepresentation(AudioFormat format) { switch(format) { + case AudioFormat::Invalid: + case AudioFormat::Unspecified: + return 0; case AudioFormat::I16: return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT; case AudioFormat::Float: return SL_ANDROID_PCM_REPRESENTATION_FLOAT; - case AudioFormat::Invalid: - case AudioFormat::Unspecified: - default: - return 0; } } - } // namespace oboe \ No newline at end of file diff --git a/src/opensles/OutputMixerOpenSLES.cpp b/src/opensles/OutputMixerOpenSLES.cpp index 901e9a75e..db36ec175 100644 --- a/src/opensles/OutputMixerOpenSLES.cpp +++ b/src/opensles/OutputMixerOpenSLES.cpp @@ -22,9 +22,9 @@ using namespace oboe; -OutputMixerOpenSL &OutputMixerOpenSL::getInstance() { +OutputMixerOpenSL *OutputMixerOpenSL::getInstance() { static OutputMixerOpenSL sInstance; - return sInstance; + return &sInstance; } SLresult OutputMixerOpenSL::open() { @@ -33,7 +33,7 @@ SLresult OutputMixerOpenSL::open() { SLresult result = SL_RESULT_SUCCESS; if (mOpenCount++ == 0) { // get the output mixer - result = EngineOpenSLES::getInstance().createOutputMix(&mOutputMixObject); + result = EngineOpenSLES::getInstance()->createOutputMix(&mOutputMixObject); if (SL_RESULT_SUCCESS != result) { LOGE("OutputMixerOpenSL() - createOutputMix() result:%s", getSLErrStr(result)); goto error; @@ -70,5 +70,5 @@ SLresult OutputMixerOpenSL::createAudioPlayer(SLObjectItf *objectItf, SLDataSource *audioSource) { SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, mOutputMixObject}; SLDataSink audioSink = {&loc_outmix, NULL}; - return EngineOpenSLES::getInstance().createAudioPlayer(objectItf, audioSource, &audioSink); + return EngineOpenSLES::getInstance()->createAudioPlayer(objectItf, audioSource, &audioSink); } diff --git a/src/opensles/OutputMixerOpenSLES.h b/src/opensles/OutputMixerOpenSLES.h index 1fc77e512..5a414df0b 100644 --- a/src/opensles/OutputMixerOpenSLES.h +++ b/src/opensles/OutputMixerOpenSLES.h @@ -31,7 +31,7 @@ namespace oboe { class OutputMixerOpenSL { public: - static OutputMixerOpenSL &getInstance(); + static OutputMixerOpenSL *getInstance(); SLresult open(); @@ -41,15 +41,8 @@ class OutputMixerOpenSL { SLDataSource *audioSource); private: - // Make this a safe Singleton - OutputMixerOpenSL()= default; - ~OutputMixerOpenSL()= default; - OutputMixerOpenSL(const OutputMixerOpenSL&)= delete; - OutputMixerOpenSL& operator=(const OutputMixerOpenSL&)= delete; - std::mutex mLock; - int32_t mOpenCount = 0; - + std::atomic mOpenCount{0}; SLObjectItf mOutputMixObject = 0; }; From 2dd7bfc0a0d305e37bef84afb52279d285d3a6d3 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 20/45] Revert "oboe: OPenSL ES opens moved into stream open" This reverts commit de932b1b59061d95198029d97be5e1872eab1966. --- src/opensles/AudioInputStreamOpenSLES.cpp | 2 +- src/opensles/AudioOutputStreamOpenSLES.cpp | 11 +++-------- src/opensles/AudioStreamOpenSLES.cpp | 11 ++++------- src/opensles/AudioStreamOpenSLES.h | 4 ++-- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/opensles/AudioInputStreamOpenSLES.cpp b/src/opensles/AudioInputStreamOpenSLES.cpp index 23e1c66b3..3d82b5e87 100644 --- a/src/opensles/AudioInputStreamOpenSLES.cpp +++ b/src/opensles/AudioInputStreamOpenSLES.cpp @@ -37,7 +37,7 @@ AudioInputStreamOpenSLES::~AudioInputStreamOpenSLES() { #define SL_ANDROID_UNKNOWN_CHANNELMASK 0 int AudioInputStreamOpenSLES::chanCountToChanMask(int channelCount) { - // from internal sles_channel_in_mask_from_count(chanCount); + // stolen from sles_channel_in_mask_from_count(chanCount); switch (channelCount) { case 1: return SL_SPEAKER_FRONT_LEFT; diff --git a/src/opensles/AudioOutputStreamOpenSLES.cpp b/src/opensles/AudioOutputStreamOpenSLES.cpp index b31d62735..76d8bc4a1 100644 --- a/src/opensles/AudioOutputStreamOpenSLES.cpp +++ b/src/opensles/AudioOutputStreamOpenSLES.cpp @@ -29,9 +29,11 @@ using namespace oboe; AudioOutputStreamOpenSLES::AudioOutputStreamOpenSLES(const AudioStreamBuilder &builder) : AudioStreamOpenSLES(builder) { + OutputMixerOpenSL::getInstance()->open(); } AudioOutputStreamOpenSLES::~AudioOutputStreamOpenSLES() { + OutputMixerOpenSL::getInstance()->close(); } // These will wind up in @@ -76,12 +78,6 @@ Result AudioOutputStreamOpenSLES::open() { Result oboeResult = AudioStreamOpenSLES::open(); if (Result::OK != oboeResult) return oboeResult; - SLresult result = OutputMixerOpenSL::getInstance()->open(); - if (SL_RESULT_SUCCESS != result) { - AudioStreamOpenSLES::close(); - return Result::ErrorInternal; - } - SLuint32 bitsPerSample = getBytesPerSample() * OBOE_BITS_PER_BYTE; // configure audio source @@ -116,7 +112,7 @@ Result AudioOutputStreamOpenSLES::open() { audioSrc.pFormat = &format_pcm_ex; } - result = OutputMixerOpenSL::getInstance()->createAudioPlayer(&mObjectInterface, + SLresult result = OutputMixerOpenSL::getInstance()->createAudioPlayer(&mObjectInterface, &audioSrc); if (SL_RESULT_SUCCESS != result) { LOGE("createAudioPlayer() result:%s", getSLErrStr(result)); @@ -150,7 +146,6 @@ Result AudioOutputStreamOpenSLES::close() { requestPause(); // invalidate any interfaces mPlayInterface = NULL; - OutputMixerOpenSL::getInstance()->close(); return AudioStreamOpenSLES::close(); } diff --git a/src/opensles/AudioStreamOpenSLES.cpp b/src/opensles/AudioStreamOpenSLES.cpp index 0a674af48..115e4983b 100644 --- a/src/opensles/AudioStreamOpenSLES.cpp +++ b/src/opensles/AudioStreamOpenSLES.cpp @@ -35,14 +35,18 @@ using namespace oboe; + + AudioStreamOpenSLES::AudioStreamOpenSLES(const AudioStreamBuilder &builder) : AudioStreamBuffered(builder) { mSimpleBufferQueueInterface = NULL; mFramesPerBurst = builder.getDefaultFramesPerBurst(); + EngineOpenSLES::getInstance()->open(); LOGD("AudioStreamOpenSLES(): after OpenSLContext()"); } AudioStreamOpenSLES::~AudioStreamOpenSLES() { + EngineOpenSLES::getInstance()->close(); delete[] mCallbackBuffer; } @@ -65,11 +69,6 @@ Result AudioStreamOpenSLES::open() { return Result::ErrorInvalidFormat; } - SLresult result = EngineOpenSLES::getInstance()->open(); - if (SL_RESULT_SUCCESS != result) { - return Result::ErrorInternal; - } - // If audio format is unspecified then choose a suitable default. // API 21+: FLOAT // API <21: INT16 @@ -101,7 +100,6 @@ Result AudioStreamOpenSLES::open() { } mBytesPerCallback = mFramesPerCallback * getBytesPerFrame(); - delete[] mCallbackBuffer; // to prevent memory leaks mCallbackBuffer = new uint8_t[mBytesPerCallback]; LOGD("AudioStreamOpenSLES(): mFramesPerCallback = %d", mFramesPerCallback); LOGD("AudioStreamOpenSLES(): mBytesPerCallback = %d", mBytesPerCallback); @@ -119,7 +117,6 @@ Result AudioStreamOpenSLES::close() { } mSimpleBufferQueueInterface = NULL; - EngineOpenSLES::getInstance()->close(); return Result::OK; } diff --git a/src/opensles/AudioStreamOpenSLES.h b/src/opensles/AudioStreamOpenSLES.h index 1688c1e34..6895b731e 100644 --- a/src/opensles/AudioStreamOpenSLES.h +++ b/src/opensles/AudioStreamOpenSLES.h @@ -91,8 +91,8 @@ class AudioStreamOpenSLES : public AudioStreamBuffered { SLObjectItf mObjectInterface = nullptr; SLAndroidSimpleBufferQueueItf mSimpleBufferQueueInterface = nullptr; - uint8_t *mCallbackBuffer = nullptr; - int32_t mBytesPerCallback = oboe::kUnspecified; + uint8_t *mCallbackBuffer; + int32_t mBytesPerCallback; int32_t mFramesPerBurst = 0; int32_t mBurstsPerBuffer = 2; // Double buffered StreamState mState = StreamState::Uninitialized; From 0282806c9eccac0a2020df760acdbc5ed9f58f40 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 21/45] Revert "oboe: cleanup OpenSL ES input" This reverts commit eedc0984b27dbebf024724191b76e89ba924cd08. --- src/opensles/AudioInputStreamOpenSLES.cpp | 2 +- src/opensles/AudioInputStreamOpenSLES.h | 4 - src/opensles/AudioOutputStreamOpenSLES.cpp | 7 +- src/opensles/AudioOutputStreamOpenSLES.h | 3 - src/opensles/AudioStreamOpenSLES.cpp | 154 ++++++++++++++++++++- src/opensles/AudioStreamOpenSLES.h | 54 +++++++- src/opensles/EngineOpenSLES.cpp | 102 -------------- src/opensles/EngineOpenSLES.h | 58 -------- src/opensles/OutputMixerOpenSLES.cpp | 74 ---------- src/opensles/OutputMixerOpenSLES.h | 51 ------- 10 files changed, 203 insertions(+), 306 deletions(-) delete mode 100644 src/opensles/EngineOpenSLES.cpp delete mode 100644 src/opensles/EngineOpenSLES.h delete mode 100644 src/opensles/OutputMixerOpenSLES.cpp delete mode 100644 src/opensles/OutputMixerOpenSLES.h diff --git a/src/opensles/AudioInputStreamOpenSLES.cpp b/src/opensles/AudioInputStreamOpenSLES.cpp index 3d82b5e87..5c9ecd78f 100644 --- a/src/opensles/AudioInputStreamOpenSLES.cpp +++ b/src/opensles/AudioInputStreamOpenSLES.cpp @@ -100,7 +100,7 @@ Result AudioInputStreamOpenSLES::open() { NULL }; SLDataSource audioSrc = {&loc_dev, NULL }; - SLresult result = EngineOpenSLES::getInstance()->createAudioRecorder(&mObjectInterface, + SLresult result = OpenSLEngine::getInstance()->createAudioRecorder(&mObjectInterface, &audioSrc, &audioSink); if (SL_RESULT_SUCCESS != result) { diff --git a/src/opensles/AudioInputStreamOpenSLES.h b/src/opensles/AudioInputStreamOpenSLES.h index 9fb79f576..83f608cff 100644 --- a/src/opensles/AudioInputStreamOpenSLES.h +++ b/src/opensles/AudioInputStreamOpenSLES.h @@ -26,10 +26,6 @@ namespace oboe { -/** - * INTERNAL USE ONLY - */ - class AudioInputStreamOpenSLES : public AudioStreamOpenSLES { public: AudioInputStreamOpenSLES(); diff --git a/src/opensles/AudioOutputStreamOpenSLES.cpp b/src/opensles/AudioOutputStreamOpenSLES.cpp index 76d8bc4a1..d963ed421 100644 --- a/src/opensles/AudioOutputStreamOpenSLES.cpp +++ b/src/opensles/AudioOutputStreamOpenSLES.cpp @@ -23,17 +23,16 @@ #include "AudioOutputStreamOpenSLES.h" #include "AudioStreamOpenSLES.h" #include "OpenSLESUtilities.h" -#include "OutputMixerOpenSLES.h" using namespace oboe; AudioOutputStreamOpenSLES::AudioOutputStreamOpenSLES(const AudioStreamBuilder &builder) : AudioStreamOpenSLES(builder) { - OutputMixerOpenSL::getInstance()->open(); + OpenSLOutputMixer::getInstance()->open(); } AudioOutputStreamOpenSLES::~AudioOutputStreamOpenSLES() { - OutputMixerOpenSL::getInstance()->close(); + OpenSLOutputMixer::getInstance()->close(); } // These will wind up in @@ -112,7 +111,7 @@ Result AudioOutputStreamOpenSLES::open() { audioSrc.pFormat = &format_pcm_ex; } - SLresult result = OutputMixerOpenSL::getInstance()->createAudioPlayer(&mObjectInterface, + SLresult result = OpenSLOutputMixer::getInstance()->createAudioPlayer(&mObjectInterface, &audioSrc); if (SL_RESULT_SUCCESS != result) { LOGE("createAudioPlayer() result:%s", getSLErrStr(result)); diff --git a/src/opensles/AudioOutputStreamOpenSLES.h b/src/opensles/AudioOutputStreamOpenSLES.h index 9e73f2ae3..c5c6de926 100644 --- a/src/opensles/AudioOutputStreamOpenSLES.h +++ b/src/opensles/AudioOutputStreamOpenSLES.h @@ -26,9 +26,6 @@ namespace oboe { -/** - * INTERNAL USE ONLY - */ class AudioOutputStreamOpenSLES : public AudioStreamOpenSLES { public: AudioOutputStreamOpenSLES(); diff --git a/src/opensles/AudioStreamOpenSLES.cpp b/src/opensles/AudioStreamOpenSLES.cpp index 115e4983b..d6a7b2a74 100644 --- a/src/opensles/AudioStreamOpenSLES.cpp +++ b/src/opensles/AudioStreamOpenSLES.cpp @@ -36,17 +36,167 @@ using namespace oboe; +OpenSLEngine *OpenSLEngine::getInstance() { + // TODO mutex + if (sInstance == nullptr) { + sInstance = new OpenSLEngine(); + } + return sInstance; +} + +SLresult OpenSLEngine::open() { + SLresult result = SL_RESULT_SUCCESS; + if (sOpenCount > 0) { + ++sOpenCount; + return SL_RESULT_SUCCESS; + } + + // create engine + result = slCreateEngine(&sEngineObject, 0, NULL, 0, NULL, NULL); + if (SL_RESULT_SUCCESS != result) { + LOGE("OpenSLEngine() - slCreateEngine() result:%s", getSLErrStr(result)); + return result; + } + + // realize the engine + result = (*sEngineObject)->Realize(sEngineObject, SL_BOOLEAN_FALSE); + if (SL_RESULT_SUCCESS != result) { + LOGE("OpenSLEngine() - Realize() engine result:%s", getSLErrStr(result)); + goto error; + } + + // get the engine interface, which is needed in order to create other objects + result = (*sEngineObject)->GetInterface(sEngineObject, SL_IID_ENGINE, &sEngineEngine); + if (SL_RESULT_SUCCESS != result) { + LOGE("OpenSLEngine() - GetInterface() engine result:%s", getSLErrStr(result)); + goto error; + } + + ++sOpenCount; + return result; + + error: + close(); + return result; +} + +void OpenSLEngine::close() { +// __android_log_print(ANDROID_LOG_INFO, TAG, "CloseSLEngine()"); + --sOpenCount; + if (sOpenCount > 0) { + return; + } + + if (sEngineObject != NULL) { + (*sEngineObject)->Destroy(sEngineObject); + sEngineObject = NULL; + sEngineEngine = NULL; + } +} + +SLresult OpenSLEngine::createOutputMix(SLObjectItf *objectItf) { + return (*sEngineEngine)->CreateOutputMix(sEngineEngine, objectItf, 0, 0, 0); +} + +SLresult OpenSLEngine::createAudioPlayer(SLObjectItf *objectItf, + SLDataSource *audioSource, + SLDataSink *audioSink) { + + const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE}; + const SLboolean reqs[] = {SL_BOOLEAN_TRUE}; + + // The Player + return (*sEngineEngine)->CreateAudioPlayer(sEngineEngine, objectItf, audioSource, + audioSink, + sizeof(ids) / sizeof(ids[0]), ids, reqs); +} + +SLresult OpenSLEngine::createAudioRecorder(SLObjectItf *objectItf, + SLDataSource *audioSource, + SLDataSink *audioSink) { + + const SLInterfaceID ids[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + SL_IID_ANDROIDCONFIGURATION }; + const SLboolean reqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; + + // The Player + return (*sEngineEngine)->CreateAudioRecorder(sEngineEngine, objectItf, audioSource, + audioSink, + sizeof(ids) / sizeof(ids[0]), ids, reqs); +} + +OpenSLEngine *OpenSLEngine::sInstance = nullptr; + +OpenSLOutputMixer *OpenSLOutputMixer::getInstance() { + // TODO mutex + if (sInstance == nullptr) { + sInstance = new OpenSLOutputMixer(); + } + return sInstance; +} + +SLresult OpenSLOutputMixer::open() { + SLresult result = SL_RESULT_SUCCESS; + if (sOpenCount > 0) { + ++sOpenCount; + return SL_RESULT_SUCCESS; + } + + // get the output mixer + result = OpenSLEngine::getInstance()->createOutputMix(&sOutputMixObject); + if (SL_RESULT_SUCCESS != result) { + LOGE("OpenSLOutputMixer() - createOutputMix() result:%s", getSLErrStr(result)); + goto error; + } + + // realize the output mix + result = (*sOutputMixObject)->Realize(sOutputMixObject, SL_BOOLEAN_FALSE); + if (SL_RESULT_SUCCESS != result) { + LOGE("OpenSLOutputMixer() - Realize() sOutputMixObject result:%s", getSLErrStr(result)); + goto error; + } + + ++sOpenCount; + return result; + + error: + close(); + return result; +} + +void OpenSLOutputMixer::close() { +// __android_log_print(ANDROID_LOG_INFO, TAG, "CloseSLEngine()"); + --sOpenCount; + if (sOpenCount > 0) { + return; + } + // destroy output mix object, and invalidate all associated interfaces + if (sOutputMixObject != NULL) { + (*sOutputMixObject)->Destroy(sOutputMixObject); + sOutputMixObject = NULL; + } +} + +SLresult OpenSLOutputMixer::createAudioPlayer(SLObjectItf *objectItf, + SLDataSource *audioSource) { + SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, sOutputMixObject}; + SLDataSink audioSink = {&loc_outmix, NULL}; + return OpenSLEngine::getInstance()->createAudioPlayer(objectItf, audioSource, &audioSink); +} + +OpenSLOutputMixer *OpenSLOutputMixer::sInstance = nullptr; + AudioStreamOpenSLES::AudioStreamOpenSLES(const AudioStreamBuilder &builder) : AudioStreamBuffered(builder) { mSimpleBufferQueueInterface = NULL; mFramesPerBurst = builder.getDefaultFramesPerBurst(); - EngineOpenSLES::getInstance()->open(); + OpenSLEngine::getInstance()->open(); LOGD("AudioStreamOpenSLES(): after OpenSLContext()"); } AudioStreamOpenSLES::~AudioStreamOpenSLES() { - EngineOpenSLES::getInstance()->close(); + OpenSLEngine::getInstance()->close(); delete[] mCallbackBuffer; } diff --git a/src/opensles/AudioStreamOpenSLES.h b/src/opensles/AudioStreamOpenSLES.h index 6895b731e..9a8fa95ab 100644 --- a/src/opensles/AudioStreamOpenSLES.h +++ b/src/opensles/AudioStreamOpenSLES.h @@ -14,32 +14,72 @@ * limitations under the License. */ -#ifndef OBOE_AUDIO_STREAM_OPENSL_ES_H_ -#define OBOE_AUDIO_STREAM_OPENSL_ES_H_ +#ifndef AUDIO_STREAM_OPENSL_ES_H_ +#define AUDIO_STREAM_OPENSL_ES_H_ #include #include #include "oboe/Oboe.h" #include "AudioStreamBuffered.h" -#include "EngineOpenSLES.h" namespace oboe { #define OBOE_BITS_PER_BYTE 8 // common value TODO modernize +class OpenSLEngine { +public: + static OpenSLEngine *getInstance(); + + SLresult open(); + + void close(); + + SLresult createOutputMix(SLObjectItf *objectItf); + + SLresult createAudioPlayer(SLObjectItf *objectItf, + SLDataSource *audioSource, + SLDataSink *audioSink); + SLresult createAudioRecorder(SLObjectItf *objectItf, + SLDataSource *audioSource, + SLDataSink *audioSink); + +private: + static OpenSLEngine *sInstance; + +// engine interfaces + int32_t sOpenCount = 0; + SLObjectItf sEngineObject = 0; + SLEngineItf sEngineEngine; +}; +class OpenSLOutputMixer { +public: + static OpenSLOutputMixer *getInstance(); + + SLresult open(); + + void close(); + + SLresult createAudioPlayer(SLObjectItf *objectItf, + SLDataSource *audioSource); +private: + static OpenSLOutputMixer *sInstance; + +// engine interfaces + int32_t sOpenCount = 0; +// output mix interfaces + SLObjectItf sOutputMixObject = 0; +}; /** - * INTERNAL USE ONLY - * * A stream that wraps OpenSL ES. * * Do not instantiate this class directly. * Use an OboeStreamBuilder to create one. */ - +// class AudioStreamOpenSLES : public AudioStreamBuffered { public: @@ -100,4 +140,4 @@ class AudioStreamOpenSLES : public AudioStreamBuffered { } // namespace oboe -#endif // OBOE_AUDIO_STREAM_OPENSL_ES_H_ +#endif // AUDIO_STREAM_OPENSL_ES_H_ diff --git a/src/opensles/EngineOpenSLES.cpp b/src/opensles/EngineOpenSLES.cpp deleted file mode 100644 index cf87ecc87..000000000 --- a/src/opensles/EngineOpenSLES.cpp +++ /dev/null @@ -1,102 +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. - */ - -#include "common/OboeDebug.h" -#include "EngineOpenSLES.h" -#include "OpenSLESUtilities.h" - -using namespace oboe; - -EngineOpenSLES *EngineOpenSLES::getInstance() { - static EngineOpenSLES sInstance; - return &sInstance; -} - -SLresult EngineOpenSLES::open() { - std::lock_guard lock(mLock); - - SLresult result = SL_RESULT_SUCCESS; - if (mOpenCount++ == 0) { - - // create engine - result = slCreateEngine(&mEngineObject, 0, NULL, 0, NULL, NULL); - if (SL_RESULT_SUCCESS != result) { - LOGE("EngineOpenSLES - slCreateEngine() result:%s", getSLErrStr(result)); - goto error; - } - - // realize the engine - result = (*mEngineObject)->Realize(mEngineObject, SL_BOOLEAN_FALSE); - if (SL_RESULT_SUCCESS != result) { - LOGE("EngineOpenSLES - Realize() engine result:%s", getSLErrStr(result)); - goto error; - } - - // get the engine interface, which is needed in order to create other objects - result = (*mEngineObject)->GetInterface(mEngineObject, SL_IID_ENGINE, &mEngineInterface); - if (SL_RESULT_SUCCESS != result) { - LOGE("EngineOpenSLES - GetInterface() engine result:%s", getSLErrStr(result)); - goto error; - } - } - - return result; - -error: - close(); - return result; -} - -void EngineOpenSLES::close() { - std::lock_guard lock(mLock); - if (--mOpenCount == 0) { - if (mEngineObject != NULL) { - (*mEngineObject)->Destroy(mEngineObject); - mEngineObject = NULL; - mEngineInterface = NULL; - } - } -} - -SLresult EngineOpenSLES::createOutputMix(SLObjectItf *objectItf) { - return (*mEngineInterface)->CreateOutputMix(mEngineInterface, objectItf, 0, 0, 0); -} - -SLresult EngineOpenSLES::createAudioPlayer(SLObjectItf *objectItf, - SLDataSource *audioSource, - SLDataSink *audioSink) { - - const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE}; - const SLboolean reqs[] = {SL_BOOLEAN_TRUE}; - - return (*mEngineInterface)->CreateAudioPlayer(mEngineInterface, objectItf, audioSource, - audioSink, - sizeof(ids) / sizeof(ids[0]), ids, reqs); -} - -SLresult EngineOpenSLES::createAudioRecorder(SLObjectItf *objectItf, - SLDataSource *audioSource, - SLDataSink *audioSink) { - - const SLInterfaceID ids[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - SL_IID_ANDROIDCONFIGURATION }; - const SLboolean reqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; - - return (*mEngineInterface)->CreateAudioRecorder(mEngineInterface, objectItf, audioSource, - audioSink, - sizeof(ids) / sizeof(ids[0]), ids, reqs); -} - diff --git a/src/opensles/EngineOpenSLES.h b/src/opensles/EngineOpenSLES.h deleted file mode 100644 index 20564f95f..000000000 --- a/src/opensles/EngineOpenSLES.h +++ /dev/null @@ -1,58 +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. - */ - -#ifndef OBOE_ENGINE_OPENSLES_H -#define OBOE_ENGINE_OPENSLES_H - -#include -#include - -#include -#include - -namespace oboe { - -/** - * INTERNAL USE ONLY - */ -class EngineOpenSLES { -public: - static EngineOpenSLES *getInstance(); - - SLresult open(); - - void close(); - - SLresult createOutputMix(SLObjectItf *objectItf); - - SLresult createAudioPlayer(SLObjectItf *objectItf, - SLDataSource *audioSource, - SLDataSink *audioSink); - SLresult createAudioRecorder(SLObjectItf *objectItf, - SLDataSource *audioSource, - SLDataSink *audioSink); - -private: - std::mutex mLock; - std::atomic mOpenCount{0}; - SLObjectItf mEngineObject = 0; - SLEngineItf mEngineInterface; -}; - -} // namespace oboe - - -#endif //OBOE_ENGINE_OPENSLES_H diff --git a/src/opensles/OutputMixerOpenSLES.cpp b/src/opensles/OutputMixerOpenSLES.cpp deleted file mode 100644 index db36ec175..000000000 --- a/src/opensles/OutputMixerOpenSLES.cpp +++ /dev/null @@ -1,74 +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. - */ - - -#include "common/OboeDebug.h" -#include "EngineOpenSLES.h" -#include "OpenSLESUtilities.h" -#include "OutputMixerOpenSLES.h" - -using namespace oboe; - -OutputMixerOpenSL *OutputMixerOpenSL::getInstance() { - static OutputMixerOpenSL sInstance; - return &sInstance; -} - -SLresult OutputMixerOpenSL::open() { - std::lock_guard lock(mLock); - - SLresult result = SL_RESULT_SUCCESS; - if (mOpenCount++ == 0) { - // get the output mixer - result = EngineOpenSLES::getInstance()->createOutputMix(&mOutputMixObject); - if (SL_RESULT_SUCCESS != result) { - LOGE("OutputMixerOpenSL() - createOutputMix() result:%s", getSLErrStr(result)); - goto error; - } - - // realize the output mix - result = (*mOutputMixObject)->Realize(mOutputMixObject, SL_BOOLEAN_FALSE); - if (SL_RESULT_SUCCESS != result) { - LOGE("OutputMixerOpenSL() - Realize() mOutputMixObject result:%s", getSLErrStr(result)); - goto error; - } - } - - return result; - -error: - close(); - return result; -} - -void OutputMixerOpenSL::close() { - std::lock_guard lock(mLock); - - if (--mOpenCount == 0) { - // destroy output mix object, and invalidate all associated interfaces - if (mOutputMixObject != NULL) { - (*mOutputMixObject)->Destroy(mOutputMixObject); - mOutputMixObject = NULL; - } - } -} - -SLresult OutputMixerOpenSL::createAudioPlayer(SLObjectItf *objectItf, - SLDataSource *audioSource) { - SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, mOutputMixObject}; - SLDataSink audioSink = {&loc_outmix, NULL}; - return EngineOpenSLES::getInstance()->createAudioPlayer(objectItf, audioSource, &audioSink); -} diff --git a/src/opensles/OutputMixerOpenSLES.h b/src/opensles/OutputMixerOpenSLES.h deleted file mode 100644 index 5a414df0b..000000000 --- a/src/opensles/OutputMixerOpenSLES.h +++ /dev/null @@ -1,51 +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. - */ - -#ifndef OBOE_OUTPUT_MIXER_OPENSLES_H -#define OBOE_OUTPUT_MIXER_OPENSLES_H - -#include -#include - -#include -#include - -namespace oboe { - -/** - * INTERNAL USE ONLY - */ - -class OutputMixerOpenSL { -public: - static OutputMixerOpenSL *getInstance(); - - SLresult open(); - - void close(); - - SLresult createAudioPlayer(SLObjectItf *objectItf, - SLDataSource *audioSource); - -private: - std::mutex mLock; - std::atomic mOpenCount{0}; - SLObjectItf mOutputMixObject = 0; -}; - -} // namespace oboe - -#endif //OBOE_OUTPUT_MIXER_OPENSLES_H From fca82b566cb85e9d497a6206029c5264e2750411 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 22/45] Revert "oboe: implement input stream" This reverts commit 05a98c703b4bb9ce23bfe5eb02e588630f95a843. --- src/opensles/AudioInputStreamOpenSLES.cpp | 175 ++------------------- src/opensles/AudioInputStreamOpenSLES.h | 4 - src/opensles/AudioOutputStreamOpenSLES.cpp | 53 +++++-- src/opensles/AudioOutputStreamOpenSLES.h | 4 +- src/opensles/AudioStreamOpenSLES.cpp | 76 ++------- src/opensles/AudioStreamOpenSLES.h | 27 +--- 6 files changed, 72 insertions(+), 267 deletions(-) diff --git a/src/opensles/AudioInputStreamOpenSLES.cpp b/src/opensles/AudioInputStreamOpenSLES.cpp index 5c9ecd78f..694e97006 100644 --- a/src/opensles/AudioInputStreamOpenSLES.cpp +++ b/src/opensles/AudioInputStreamOpenSLES.cpp @@ -14,15 +14,9 @@ * limitations under the License. */ -#include - -#include -#include - #include "oboe/AudioStreamBuilder.h" #include "AudioInputStreamOpenSLES.h" #include "AudioStreamOpenSLES.h" -#include "OpenSLESUtilities.h" using namespace oboe; @@ -33,187 +27,44 @@ AudioInputStreamOpenSLES::AudioInputStreamOpenSLES(const AudioStreamBuilder &bui AudioInputStreamOpenSLES::~AudioInputStreamOpenSLES() { } -#define AUDIO_CHANNEL_COUNT_MAX 30u -#define SL_ANDROID_UNKNOWN_CHANNELMASK 0 - -int AudioInputStreamOpenSLES::chanCountToChanMask(int channelCount) { - // stolen from sles_channel_in_mask_from_count(chanCount); - switch (channelCount) { - case 1: - return SL_SPEAKER_FRONT_LEFT; - case 2: - return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - default: { - if (channelCount > AUDIO_CHANNEL_COUNT_MAX) { - return SL_ANDROID_UNKNOWN_CHANNELMASK; - } else { - SLuint32 bitfield = (1 << channelCount) - 1; - return SL_ANDROID_MAKE_INDEXED_CHANNEL_MASK(bitfield); - } - } - } + +int AudioInputStreamOpenSLES::chanCountToChanMask(int chanCount) { + return 0; // TODO } + Result AudioInputStreamOpenSLES::open() { - Result oboeResult = AudioStreamOpenSLES::open(); - if (Result::OK != oboeResult) return oboeResult; - - SLuint32 bitsPerSample = getBytesPerSample() * OBOE_BITS_PER_BYTE; - - // configure audio sink - SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { - SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // locatorType - static_cast(mBurstsPerBuffer)}; // numBuffers - - // Define the audio data format. - SLDataFormat_PCM format_pcm = { - SL_DATAFORMAT_PCM, // formatType - (SLuint32) mChannelCount, // numChannels - (SLuint32) (mSampleRate * kMillisPerSecond), // milliSamplesPerSec - bitsPerSample, // bitsPerSample - bitsPerSample, // containerSize; - (SLuint32) chanCountToChanMask(mChannelCount), // channelMask - getDefaultByteOrder(), - }; - - SLDataSink audioSink = {&loc_bufq, &format_pcm}; - - /** - * API 21 (Lollipop) introduced support for floating-point data representation and an extended - * data format type: SLAndroidDataFormat_PCM_EX. If running on API 21+ use this newer format - * type, creating it from our original format. - */ - SLAndroidDataFormat_PCM_EX format_pcm_ex; - if (__ANDROID_API__ >= __ANDROID_API_L__) { - SLuint32 representation = OpenSLES_ConvertFormatToRepresentation(getFormat()); - // Fill in the format structure. - format_pcm_ex = OpenSLES_createExtendedFormat(format_pcm, representation); - // Use in place of the previous format. - audioSink.pFormat = &format_pcm_ex; - } - - // configure audio source - SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, - SL_IODEVICE_AUDIOINPUT, - SL_DEFAULTDEVICEID_AUDIOINPUT, - NULL }; - SLDataSource audioSrc = {&loc_dev, NULL }; - - SLresult result = OpenSLEngine::getInstance()->createAudioRecorder(&mObjectInterface, - &audioSrc, - &audioSink); - if (SL_RESULT_SUCCESS != result) { - LOGE("createAudioRecorder() result:%s", getSLErrStr(result)); - goto error; - } - - // Configure the voice recognition preset, which has no - // signal processing, for lower latency. - SLAndroidConfigurationItf inputConfig; - result = (*mObjectInterface)->GetInterface(mObjectInterface, - SL_IID_ANDROIDCONFIGURATION, - &inputConfig); - if (SL_RESULT_SUCCESS == result) { - SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION; - (*inputConfig)->SetConfiguration(inputConfig, - SL_ANDROID_KEY_RECORDING_PRESET, - &presetValue, - sizeof(SLuint32)); - } - - result = (*mObjectInterface)->Realize(mObjectInterface, SL_BOOLEAN_FALSE); - if (SL_RESULT_SUCCESS != result) { - LOGE("Realize recorder object result:%s", getSLErrStr(result)); - goto error; - } - - result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_RECORD, &mRecordInterface); - if (SL_RESULT_SUCCESS != result) { - LOGE("get recorder interface result:%s", getSLErrStr(result)); - goto error; - } - - result = AudioStreamOpenSLES::registerBufferQueueCallback(); - if (SL_RESULT_SUCCESS != result) { - LOGE("get bufferqueue interface:%p result:%s", mSimpleBufferQueueInterface, getSLErrStr(result)); - goto error; - } - - return Result::OK; -error: - return Result::ErrorInternal; // TODO convert error from SLES to OBOE + return Result::ErrorUnimplemented; // TODO } Result AudioInputStreamOpenSLES::close() { - requestStop(); - mRecordInterface = NULL; - return AudioStreamOpenSLES::close(); -} -Result AudioInputStreamOpenSLES::setRecordState(SLuint32 newState) { - Result result = Result::OK; - LOGD("AudioInputStreamOpenSLES::setRecordState(%d)", newState); - if (mRecordInterface == NULL) { - return Result::ErrorInvalidState; - } - SLresult slResult = (*mRecordInterface)->SetRecordState(mRecordInterface, newState); - if(SL_RESULT_SUCCESS != slResult) { - LOGD("AudioInputStreamOpenSLES::setPlayState() returned %s", getSLErrStr(slResult)); - result = Result::ErrorInvalidState; // TODO review - } else { - setState(StreamState::Pausing); - } - return result; + return AudioStreamOpenSLES::close(); } Result AudioInputStreamOpenSLES::requestStart() { - LOGD("AudioInputStreamOpenSLES::requestStart()"); - Result result = setRecordState(SL_RECORDSTATE_RECORDING); - if(result != Result::OK) { - result = Result::ErrorInvalidState; // TODO review - } else { - // Enqueue the first buffer so that we have data ready in the callback. - enqueueCallbackBuffer(mSimpleBufferQueueInterface); - setState(StreamState::Starting); - } - return result; + return Result::ErrorUnimplemented; // TODO } Result AudioInputStreamOpenSLES::requestPause() { - LOGD("AudioInputStreamOpenSLES::requestStop()"); - Result result = setRecordState(SL_RECORDSTATE_PAUSED); - if(result != Result::OK) { - result = Result::ErrorInvalidState; // TODO review - } else { - setState(StreamState::Pausing); - } - return result; + return Result::ErrorUnimplemented; // TODO } Result AudioInputStreamOpenSLES::requestFlush() { return Result::ErrorUnimplemented; // TODO } -Result AudioInputStreamOpenSLES::requestStop() { - LOGD("AudioInputStreamOpenSLES::requestStop()"); - Result result = setRecordState(SL_RECORDSTATE_STOPPED); - if(result != Result::OK) { - result = Result::ErrorInvalidState; // TODO review - } else { - setState(StreamState::Stopping); - } - return result; +Result AudioInputStreamOpenSLES::requestStop() +{ + return Result::ErrorUnimplemented; // TODO } Result AudioInputStreamOpenSLES::waitForStateChange(StreamState currentState, StreamState *nextState, - int64_t timeoutNanoseconds) { - LOGD("AudioInputStreamOpenSLES::waitForStateChange()"); - if (mRecordInterface == NULL) { - return Result::ErrorInvalidState; - } + int64_t timeoutNanoseconds) +{ return Result::ErrorUnimplemented; // TODO } diff --git a/src/opensles/AudioInputStreamOpenSLES.h b/src/opensles/AudioInputStreamOpenSLES.h index 83f608cff..5bcc1febd 100644 --- a/src/opensles/AudioInputStreamOpenSLES.h +++ b/src/opensles/AudioInputStreamOpenSLES.h @@ -46,11 +46,7 @@ class AudioInputStreamOpenSLES : public AudioStreamOpenSLES { int64_t timeoutNanoseconds) override; int chanCountToChanMask(int chanCount) override; -private: - Result setRecordState(SLuint32 newState); - - SLRecordItf mRecordInterface; }; } // namespace oboe diff --git a/src/opensles/AudioOutputStreamOpenSLES.cpp b/src/opensles/AudioOutputStreamOpenSLES.cpp index d963ed421..7dad9672d 100644 --- a/src/opensles/AudioOutputStreamOpenSLES.cpp +++ b/src/opensles/AudioOutputStreamOpenSLES.cpp @@ -26,6 +26,8 @@ using namespace oboe; +#define OBOE_BITS_PER_BYTE 8 // common value + AudioOutputStreamOpenSLES::AudioOutputStreamOpenSLES(const AudioStreamBuilder &builder) : AudioStreamOpenSLES(builder) { OpenSLOutputMixer::getInstance()->open(); @@ -73,7 +75,13 @@ int AudioOutputStreamOpenSLES::chanCountToChanMask(int chanCount) { return channelMask; } +// this callback handler is called every time a buffer finishes playing +static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { + ((AudioStreamOpenSLES *) context)->enqueueBuffer(); +} + Result AudioOutputStreamOpenSLES::open() { + Result oboeResult = AudioStreamOpenSLES::open(); if (Result::OK != oboeResult) return oboeResult; @@ -102,37 +110,45 @@ Result AudioOutputStreamOpenSLES::open() { * data format type: SLAndroidDataFormat_PCM_EX. If running on API 21+ use this newer format * type, creating it from our original format. */ - SLAndroidDataFormat_PCM_EX format_pcm_ex; if (__ANDROID_API__ >= __ANDROID_API_L__) { SLuint32 representation = OpenSLES_ConvertFormatToRepresentation(getFormat()); - // Fill in the format structure. - format_pcm_ex = OpenSLES_createExtendedFormat(format_pcm, representation); - // Use in place of the previous format. + SLAndroidDataFormat_PCM_EX format_pcm_ex = OpenSLES_createExtendedFormat(format_pcm, + representation); + // Overwrite the previous format. audioSrc.pFormat = &format_pcm_ex; } - SLresult result = OpenSLOutputMixer::getInstance()->createAudioPlayer(&mObjectInterface, + SLresult result = OpenSLOutputMixer::getInstance()->createAudioPlayer(&bqPlayerObject_, &audioSrc); if (SL_RESULT_SUCCESS != result) { LOGE("createAudioPlayer() result:%s", getSLErrStr(result)); goto error; } - result = (*mObjectInterface)->Realize(mObjectInterface, SL_BOOLEAN_FALSE); + result = (*bqPlayerObject_)->Realize(bqPlayerObject_, SL_BOOLEAN_FALSE); if (SL_RESULT_SUCCESS != result) { LOGE("Realize player object result:%s", getSLErrStr(result)); goto error; } - result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_PLAY, &mPlayInterface); + result = (*bqPlayerObject_)->GetInterface(bqPlayerObject_, SL_IID_PLAY, &bqPlayerPlay_); if (SL_RESULT_SUCCESS != result) { LOGE("get player interface result:%s", getSLErrStr(result)); goto error; } - result = AudioStreamOpenSLES::registerBufferQueueCallback(); + // The BufferQueue + result = (*bqPlayerObject_)->GetInterface(bqPlayerObject_, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bq_); + if (SL_RESULT_SUCCESS != result) { + LOGE("get bufferqueue interface:%p result:%s", bq_, getSLErrStr(result)); + goto error; + } + + // The register BufferQueue callback + result = (*bq_)->RegisterCallback(bq_, bqPlayerCallback, this); if (SL_RESULT_SUCCESS != result) { - LOGE("get bufferqueue interface:%p result:%s", mSimpleBufferQueueInterface, getSLErrStr(result)); + LOGE("register callback result:%s", getSLErrStr(result)); goto error; } @@ -143,18 +159,23 @@ Result AudioOutputStreamOpenSLES::open() { Result AudioOutputStreamOpenSLES::close() { requestPause(); - // invalidate any interfaces - mPlayInterface = NULL; + if (bqPlayerObject_ != NULL) { + (*bqPlayerObject_)->Destroy(bqPlayerObject_); + bqPlayerObject_ = NULL; + + // invalidate any interfaces + bqPlayerPlay_ = NULL; + } return AudioStreamOpenSLES::close(); } Result AudioOutputStreamOpenSLES::setPlayState(SLuint32 newState) { Result result = Result::OK; LOGD("AudioOutputStreamOpenSLES(): setPlayState()"); - if (mPlayInterface == NULL) { + if (bqPlayerPlay_ == NULL) { return Result::ErrorInvalidState; } - SLresult slResult = (*mPlayInterface)->SetPlayState(mPlayInterface, newState); + SLresult slResult = (*bqPlayerPlay_)->SetPlayState(bqPlayerPlay_, newState); if(SL_RESULT_SUCCESS != slResult) { LOGD("AudioOutputStreamOpenSLES(): setPlayState() returned %s", getSLErrStr(slResult)); result = Result::ErrorInvalidState; // TODO review @@ -170,7 +191,7 @@ Result AudioOutputStreamOpenSLES::requestStart() { if(result != Result::OK) { result = Result::ErrorInvalidState; // TODO review } else { - processBufferCallback(mSimpleBufferQueueInterface); + enqueueBuffer(); setState(StreamState::Starting); } return result; @@ -189,7 +210,7 @@ Result AudioOutputStreamOpenSLES::requestPause() { Result AudioOutputStreamOpenSLES::requestFlush() { LOGD("AudioOutputStreamOpenSLES(): requestFlush()"); - if (mPlayInterface == NULL) { + if (bqPlayerPlay_ == NULL) { return Result::ErrorInvalidState; } return Result::ErrorUnimplemented; // TODO @@ -210,7 +231,7 @@ Result AudioOutputStreamOpenSLES::waitForStateChange(StreamState currentState, StreamState *nextState, int64_t timeoutNanoseconds) { LOGD("AudioOutputStreamOpenSLES::waitForStateChange()"); - if (mPlayInterface == NULL) { + if (bqPlayerPlay_ == NULL) { return Result::ErrorInvalidState; } return Result::ErrorUnimplemented; // TODO diff --git a/src/opensles/AudioOutputStreamOpenSLES.h b/src/opensles/AudioOutputStreamOpenSLES.h index c5c6de926..964b09252 100644 --- a/src/opensles/AudioOutputStreamOpenSLES.h +++ b/src/opensles/AudioOutputStreamOpenSLES.h @@ -57,8 +57,8 @@ class AudioOutputStreamOpenSLES : public AudioStreamOpenSLES { */ Result setPlayState(SLuint32 newState); - SLPlayItf mPlayInterface = nullptr; - + SLObjectItf bqPlayerObject_ = nullptr; + SLPlayItf bqPlayerPlay_ = nullptr; }; } // namespace oboe diff --git a/src/opensles/AudioStreamOpenSLES.cpp b/src/opensles/AudioStreamOpenSLES.cpp index d6a7b2a74..fd08605cd 100644 --- a/src/opensles/AudioStreamOpenSLES.cpp +++ b/src/opensles/AudioStreamOpenSLES.cpp @@ -103,26 +103,12 @@ SLresult OpenSLEngine::createAudioPlayer(SLObjectItf *objectItf, SLDataSink *audioSink) { const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE}; - const SLboolean reqs[] = {SL_BOOLEAN_TRUE}; + const SLboolean req[] = {SL_BOOLEAN_TRUE}; // The Player return (*sEngineEngine)->CreateAudioPlayer(sEngineEngine, objectItf, audioSource, audioSink, - sizeof(ids) / sizeof(ids[0]), ids, reqs); -} - -SLresult OpenSLEngine::createAudioRecorder(SLObjectItf *objectItf, - SLDataSource *audioSource, - SLDataSink *audioSink) { - - const SLInterfaceID ids[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - SL_IID_ANDROIDCONFIGURATION }; - const SLboolean reqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; - - // The Player - return (*sEngineEngine)->CreateAudioRecorder(sEngineEngine, objectItf, audioSource, - audioSink, - sizeof(ids) / sizeof(ids[0]), ids, reqs); + sizeof(ids) / sizeof(ids[0]), ids, req); } OpenSLEngine *OpenSLEngine::sInstance = nullptr; @@ -186,10 +172,21 @@ SLresult OpenSLOutputMixer::createAudioPlayer(SLObjectItf *objectItf, OpenSLOutputMixer *OpenSLOutputMixer::sInstance = nullptr; +SLresult AudioStreamOpenSLES::enqueueBuffer() { + // Ask the callback to fill the output buffer with data. + Result result = fireCallback(mCallbackBuffer, mFramesPerCallback); + if (result != Result::OK) { + LOGE("Oboe callback returned %d", result); + return SL_RESULT_INTERNAL_ERROR; + } else { + // Pass the data to OpenSLES. + return (*bq_)->Enqueue(bq_, mCallbackBuffer, mBytesPerCallback); + } +} AudioStreamOpenSLES::AudioStreamOpenSLES(const AudioStreamBuilder &builder) : AudioStreamBuffered(builder) { - mSimpleBufferQueueInterface = NULL; + bq_ = NULL; mFramesPerBurst = builder.getDefaultFramesPerBurst(); OpenSLEngine::getInstance()->open(); LOGD("AudioStreamOpenSLES(): after OpenSLContext()"); @@ -261,53 +258,10 @@ Result AudioStreamOpenSLES::open() { } Result AudioStreamOpenSLES::close() { - if (mObjectInterface != NULL) { - (*mObjectInterface)->Destroy(mObjectInterface); - mObjectInterface = NULL; - - } - mSimpleBufferQueueInterface = NULL; + bq_ = NULL; return Result::OK; } -SLresult AudioStreamOpenSLES::enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq) { - return (*bq)->Enqueue(bq, mCallbackBuffer, mBytesPerCallback); -} - -SLresult AudioStreamOpenSLES::processBufferCallback(SLAndroidSimpleBufferQueueItf bq) { - // Ask the callback to fill the output buffer with data. - Result result = fireCallback(mCallbackBuffer, mFramesPerCallback); - if (result != Result::OK) { - LOGE("Oboe callback returned %d", result); - return SL_RESULT_INTERNAL_ERROR; - } else { - // Pass the data to OpenSLES. - return enqueueCallbackBuffer(bq); - } -} - -// this callback handler is called every time a buffer needs processing -static void bqCallbackGlue(SLAndroidSimpleBufferQueueItf bq, void *context) { - ((AudioStreamOpenSLES *) context)->processBufferCallback(bq); -} - -SLresult AudioStreamOpenSLES::registerBufferQueueCallback() { - // The BufferQueue - SLresult result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &mSimpleBufferQueueInterface); - if (SL_RESULT_SUCCESS != result) { - LOGE("get bufferqueue interface:%p result:%s", mSimpleBufferQueueInterface, getSLErrStr(result)); - } else { - // Register the BufferQueue callback - result = (*mSimpleBufferQueueInterface)->RegisterCallback(mSimpleBufferQueueInterface, - bqCallbackGlue, this); - if (SL_RESULT_SUCCESS != result) { - LOGE("RegisterCallback result:%s", getSLErrStr(result)); - } - } - return result; -} - int32_t AudioStreamOpenSLES::getFramesPerBurst() { return mFramesPerBurst; } diff --git a/src/opensles/AudioStreamOpenSLES.h b/src/opensles/AudioStreamOpenSLES.h index 9a8fa95ab..653048c5b 100644 --- a/src/opensles/AudioStreamOpenSLES.h +++ b/src/opensles/AudioStreamOpenSLES.h @@ -25,8 +25,6 @@ namespace oboe { -#define OBOE_BITS_PER_BYTE 8 // common value TODO modernize - class OpenSLEngine { public: static OpenSLEngine *getInstance(); @@ -40,9 +38,6 @@ class OpenSLEngine { SLresult createAudioPlayer(SLObjectItf *objectItf, SLDataSource *audioSource, SLDataSink *audioSink); - SLresult createAudioRecorder(SLObjectItf *objectItf, - SLDataSource *audioSource, - SLDataSink *audioSink); private: static OpenSLEngine *sInstance; @@ -91,6 +86,8 @@ class AudioStreamOpenSLES : public AudioStreamBuffered { virtual Result open() override; virtual Result close() override; + // public, but don't call directly (called by the OSLES callback) + SLresult enqueueBuffer(); /** * Query the current state, eg. OBOE_STREAM_STATE_PAUSING @@ -105,20 +102,7 @@ class AudioStreamOpenSLES : public AudioStreamBuffered { virtual int chanCountToChanMask(int chanCount) = 0; - /** - * Process next OpenSL ES buffer. - * Called by by OpenSL ES framework. - * - * This is public, but don't call it directly. - */ - SLresult processBufferCallback(SLAndroidSimpleBufferQueueItf bq); - protected: - - SLresult registerBufferQueueCallback(); - - SLresult enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq); - /** * Internal use only. * Use this instead of directly setting the internal state variable. @@ -127,15 +111,14 @@ class AudioStreamOpenSLES : public AudioStreamBuffered { mState = state; } - // OpenSLES stuff - SLObjectItf mObjectInterface = nullptr; - SLAndroidSimpleBufferQueueItf mSimpleBufferQueueInterface = nullptr; - uint8_t *mCallbackBuffer; int32_t mBytesPerCallback; int32_t mFramesPerBurst = 0; int32_t mBurstsPerBuffer = 2; // Double buffered StreamState mState = StreamState::Uninitialized; + + // OpenSLES stuff + SLAndroidSimpleBufferQueueItf bq_ = nullptr; }; } // namespace oboe From 1fcc25ea7f92046ff0bfacf4d94d93a4c1d0d9b8 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 23/45] Revert "oboe: move OpenSL ES output code to its own class" This reverts commit 41e1a5feb69cf5181550fac13f776f86e48926aa. --- src/opensles/AudioInputStreamOpenSLES.cpp | 42 ---- src/opensles/AudioInputStreamOpenSLES.h | 15 -- src/opensles/AudioOutputStreamOpenSLES.cpp | 209 ----------------- src/opensles/AudioOutputStreamOpenSLES.h | 26 --- src/opensles/AudioStreamOpenSLES.cpp | 255 ++++++++++++++++++++- src/opensles/AudioStreamOpenSLES.h | 31 ++- src/opensles/OpenSLESUtilities.cpp | 38 --- src/opensles/OpenSLESUtilities.h | 6 - 8 files changed, 274 insertions(+), 348 deletions(-) diff --git a/src/opensles/AudioInputStreamOpenSLES.cpp b/src/opensles/AudioInputStreamOpenSLES.cpp index 694e97006..688844530 100644 --- a/src/opensles/AudioInputStreamOpenSLES.cpp +++ b/src/opensles/AudioInputStreamOpenSLES.cpp @@ -26,45 +26,3 @@ AudioInputStreamOpenSLES::AudioInputStreamOpenSLES(const AudioStreamBuilder &bui AudioInputStreamOpenSLES::~AudioInputStreamOpenSLES() { } - - -int AudioInputStreamOpenSLES::chanCountToChanMask(int chanCount) { - return 0; // TODO -} - - -Result AudioInputStreamOpenSLES::open() { - - return Result::ErrorUnimplemented; // TODO -} - -Result AudioInputStreamOpenSLES::close() { - - return AudioStreamOpenSLES::close(); -} - -Result AudioInputStreamOpenSLES::requestStart() -{ - return Result::ErrorUnimplemented; // TODO -} - - -Result AudioInputStreamOpenSLES::requestPause() { - return Result::ErrorUnimplemented; // TODO -} - -Result AudioInputStreamOpenSLES::requestFlush() { - return Result::ErrorUnimplemented; // TODO -} - -Result AudioInputStreamOpenSLES::requestStop() -{ - return Result::ErrorUnimplemented; // TODO -} - -Result AudioInputStreamOpenSLES::waitForStateChange(StreamState currentState, - StreamState *nextState, - int64_t timeoutNanoseconds) -{ - return Result::ErrorUnimplemented; // TODO -} diff --git a/src/opensles/AudioInputStreamOpenSLES.h b/src/opensles/AudioInputStreamOpenSLES.h index 5bcc1febd..3e8b0ff70 100644 --- a/src/opensles/AudioInputStreamOpenSLES.h +++ b/src/opensles/AudioInputStreamOpenSLES.h @@ -32,21 +32,6 @@ class AudioInputStreamOpenSLES : public AudioStreamOpenSLES { explicit AudioInputStreamOpenSLES(const AudioStreamBuilder &builder); virtual ~AudioInputStreamOpenSLES(); - - Result open() override; - Result close() override; - - Result requestStart() override; - Result requestPause() override; - Result requestFlush() override; - Result requestStop() override; - - Result waitForStateChange(StreamState currentState, - StreamState *nextState, - int64_t timeoutNanoseconds) override; - - int chanCountToChanMask(int chanCount) override; - }; } // namespace oboe diff --git a/src/opensles/AudioOutputStreamOpenSLES.cpp b/src/opensles/AudioOutputStreamOpenSLES.cpp index 7dad9672d..5be7b5448 100644 --- a/src/opensles/AudioOutputStreamOpenSLES.cpp +++ b/src/opensles/AudioOutputStreamOpenSLES.cpp @@ -14,225 +14,16 @@ * limitations under the License. */ -#include - -#include -#include - #include "oboe/AudioStreamBuilder.h" #include "AudioOutputStreamOpenSLES.h" #include "AudioStreamOpenSLES.h" -#include "OpenSLESUtilities.h" using namespace oboe; -#define OBOE_BITS_PER_BYTE 8 // common value AudioOutputStreamOpenSLES::AudioOutputStreamOpenSLES(const AudioStreamBuilder &builder) : AudioStreamOpenSLES(builder) { - OpenSLOutputMixer::getInstance()->open(); } AudioOutputStreamOpenSLES::~AudioOutputStreamOpenSLES() { - OpenSLOutputMixer::getInstance()->close(); -} - -// These will wind up in -#define SL_ANDROID_SPEAKER_QUAD (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT \ - | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT) - -#define SL_ANDROID_SPEAKER_5DOT1 (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT \ - | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY| SL_SPEAKER_BACK_LEFT \ - | SL_SPEAKER_BACK_RIGHT) - -#define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT \ - |SL_SPEAKER_SIDE_RIGHT) - -int AudioOutputStreamOpenSLES::chanCountToChanMask(int chanCount) { - int channelMask = 0; - - switch (chanCount) { - case 1: - channelMask = SL_SPEAKER_FRONT_CENTER; - break; - - case 2: - channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - break; - - case 4: // Quad - channelMask = SL_ANDROID_SPEAKER_QUAD; - break; - - case 6: // 5.1 - channelMask = SL_ANDROID_SPEAKER_5DOT1; - break; - - case 8: // 7.1 - channelMask = SL_ANDROID_SPEAKER_7DOT1; - break; - } - return channelMask; -} - -// this callback handler is called every time a buffer finishes playing -static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { - ((AudioStreamOpenSLES *) context)->enqueueBuffer(); -} - -Result AudioOutputStreamOpenSLES::open() { - - Result oboeResult = AudioStreamOpenSLES::open(); - if (Result::OK != oboeResult) return oboeResult; - - SLuint32 bitsPerSample = getBytesPerSample() * OBOE_BITS_PER_BYTE; - - // configure audio source - SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { - SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // locatorType - static_cast(mBurstsPerBuffer)}; // numBuffers - - // Define the audio data format. - SLDataFormat_PCM format_pcm = { - SL_DATAFORMAT_PCM, // formatType - (SLuint32) mChannelCount, // numChannels - (SLuint32) (mSampleRate * kMillisPerSecond), // milliSamplesPerSec - bitsPerSample, // bitsPerSample - bitsPerSample, // containerSize; - (SLuint32) chanCountToChanMask(mChannelCount), // channelMask - getDefaultByteOrder(), - }; - - SLDataSource audioSrc = {&loc_bufq, &format_pcm}; - - /** - * API 21 (Lollipop) introduced support for floating-point data representation and an extended - * data format type: SLAndroidDataFormat_PCM_EX. If running on API 21+ use this newer format - * type, creating it from our original format. - */ - if (__ANDROID_API__ >= __ANDROID_API_L__) { - SLuint32 representation = OpenSLES_ConvertFormatToRepresentation(getFormat()); - SLAndroidDataFormat_PCM_EX format_pcm_ex = OpenSLES_createExtendedFormat(format_pcm, - representation); - // Overwrite the previous format. - audioSrc.pFormat = &format_pcm_ex; - } - - SLresult result = OpenSLOutputMixer::getInstance()->createAudioPlayer(&bqPlayerObject_, - &audioSrc); - if (SL_RESULT_SUCCESS != result) { - LOGE("createAudioPlayer() result:%s", getSLErrStr(result)); - goto error; - } - - result = (*bqPlayerObject_)->Realize(bqPlayerObject_, SL_BOOLEAN_FALSE); - if (SL_RESULT_SUCCESS != result) { - LOGE("Realize player object result:%s", getSLErrStr(result)); - goto error; - } - - result = (*bqPlayerObject_)->GetInterface(bqPlayerObject_, SL_IID_PLAY, &bqPlayerPlay_); - if (SL_RESULT_SUCCESS != result) { - LOGE("get player interface result:%s", getSLErrStr(result)); - goto error; - } - - // The BufferQueue - result = (*bqPlayerObject_)->GetInterface(bqPlayerObject_, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bq_); - if (SL_RESULT_SUCCESS != result) { - LOGE("get bufferqueue interface:%p result:%s", bq_, getSLErrStr(result)); - goto error; - } - - // The register BufferQueue callback - result = (*bq_)->RegisterCallback(bq_, bqPlayerCallback, this); - if (SL_RESULT_SUCCESS != result) { - LOGE("register callback result:%s", getSLErrStr(result)); - goto error; - } - - return Result::OK; -error: - return Result::ErrorInternal; // TODO convert error from SLES to OBOE -} - -Result AudioOutputStreamOpenSLES::close() { - requestPause(); - if (bqPlayerObject_ != NULL) { - (*bqPlayerObject_)->Destroy(bqPlayerObject_); - bqPlayerObject_ = NULL; - - // invalidate any interfaces - bqPlayerPlay_ = NULL; - } - return AudioStreamOpenSLES::close(); -} - -Result AudioOutputStreamOpenSLES::setPlayState(SLuint32 newState) { - Result result = Result::OK; - LOGD("AudioOutputStreamOpenSLES(): setPlayState()"); - if (bqPlayerPlay_ == NULL) { - return Result::ErrorInvalidState; - } - SLresult slResult = (*bqPlayerPlay_)->SetPlayState(bqPlayerPlay_, newState); - if(SL_RESULT_SUCCESS != slResult) { - LOGD("AudioOutputStreamOpenSLES(): setPlayState() returned %s", getSLErrStr(slResult)); - result = Result::ErrorInvalidState; // TODO review - } else { - setState(StreamState::Pausing); - } - return result; -} - -Result AudioOutputStreamOpenSLES::requestStart() { - LOGD("AudioOutputStreamOpenSLES(): requestStart()"); - Result result = setPlayState(SL_PLAYSTATE_PLAYING); - if(result != Result::OK) { - result = Result::ErrorInvalidState; // TODO review - } else { - enqueueBuffer(); - setState(StreamState::Starting); - } - return result; -} - -Result AudioOutputStreamOpenSLES::requestPause() { - LOGD("AudioOutputStreamOpenSLES(): requestPause()"); - Result result = setPlayState(SL_PLAYSTATE_PAUSED); - if(result != Result::OK) { - result = Result::ErrorInvalidState; // TODO review - } else { - setState(StreamState::Pausing); - } - return result; -} - -Result AudioOutputStreamOpenSLES::requestFlush() { - LOGD("AudioOutputStreamOpenSLES(): requestFlush()"); - if (bqPlayerPlay_ == NULL) { - return Result::ErrorInvalidState; - } - return Result::ErrorUnimplemented; // TODO -} - -Result AudioOutputStreamOpenSLES::requestStop() { - LOGD("AudioOutputStreamOpenSLES(): requestStop()"); - Result result = setPlayState(SL_PLAYSTATE_STOPPED); - if(result != Result::OK) { - result = Result::ErrorInvalidState; // TODO review - } else { - setState(StreamState::Stopping); - } - return result; -} - -Result AudioOutputStreamOpenSLES::waitForStateChange(StreamState currentState, - StreamState *nextState, - int64_t timeoutNanoseconds) { - LOGD("AudioOutputStreamOpenSLES::waitForStateChange()"); - if (bqPlayerPlay_ == NULL) { - return Result::ErrorInvalidState; - } - return Result::ErrorUnimplemented; // TODO } diff --git a/src/opensles/AudioOutputStreamOpenSLES.h b/src/opensles/AudioOutputStreamOpenSLES.h index 964b09252..75e87886c 100644 --- a/src/opensles/AudioOutputStreamOpenSLES.h +++ b/src/opensles/AudioOutputStreamOpenSLES.h @@ -32,33 +32,7 @@ class AudioOutputStreamOpenSLES : public AudioStreamOpenSLES { explicit AudioOutputStreamOpenSLES(const AudioStreamBuilder &builder); virtual ~AudioOutputStreamOpenSLES(); - - Result open() override; - Result close() override; - - Result requestStart() override; - Result requestPause() override; - Result requestFlush() override; - Result requestStop() override; - - Result waitForStateChange(StreamState currentState, - StreamState *nextState, - int64_t timeoutNanoseconds) override; - - int chanCountToChanMask(int chanCount) override; - private: - - /** - * Set OpenSL ES PLAYSTATE. - * - * @param newState SL_PLAYSTATE_PAUSED, SL_PLAYSTATE_PLAYING, SL_PLAYSTATE_STOPPED - * @return - */ - Result setPlayState(SLuint32 newState); - - SLObjectItf bqPlayerObject_ = nullptr; - SLPlayItf bqPlayerPlay_ = nullptr; }; } // namespace oboe diff --git a/src/opensles/AudioStreamOpenSLES.cpp b/src/opensles/AudioStreamOpenSLES.cpp index fd08605cd..c1935a0ea 100644 --- a/src/opensles/AudioStreamOpenSLES.cpp +++ b/src/opensles/AudioStreamOpenSLES.cpp @@ -33,8 +33,76 @@ #define DEFAULT_SAMPLE_RATE 48000 // very common rate for mobile audio and video #define DEFAULT_CHANNEL_COUNT 2 // stereo +#define OBOE_BITS_PER_BYTE 8 // common value + using namespace oboe; +/* + * OSLES Helpers + */ +static const char *errStrings[] = { + "SL_RESULT_SUCCESS", // 0 + "SL_RESULT_PRECONDITIONS_VIOLATE", // 1 + "SL_RESULT_PARAMETER_INVALID", // 2 + "SL_RESULT_MEMORY_FAILURE", // 3 + "SL_RESULT_RESOURCE_ERROR", // 4 + "SL_RESULT_RESOURCE_LOST", // 5 + "SL_RESULT_IO_ERROR", // 6 + "SL_RESULT_BUFFER_INSUFFICIENT", // 7 + "SL_RESULT_CONTENT_CORRUPTED", // 8 + "SL_RESULT_CONTENT_UNSUPPORTED", // 9 + "SL_RESULT_CONTENT_NOT_FOUND", // 10 + "SL_RESULT_PERMISSION_DENIED", // 11 + "SL_RESULT_FEATURE_UNSUPPORTED", // 12 + "SL_RESULT_INTERNAL_ERROR", // 13 + "SL_RESULT_UNKNOWN_ERROR", // 14 + "SL_RESULT_OPERATION_ABORTED", // 15 + "SL_RESULT_CONTROL_LOST" // 16 +}; + +const char *getSLErrStr(SLresult code) { + return errStrings[code]; +} + +// These will wind up in +#define SL_ANDROID_SPEAKER_QUAD (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT \ + | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT) + +#define SL_ANDROID_SPEAKER_5DOT1 (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT \ + | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY| SL_SPEAKER_BACK_LEFT \ + | SL_SPEAKER_BACK_RIGHT) + +#define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT \ + |SL_SPEAKER_SIDE_RIGHT) + +int chanCountToChanMask(int chanCount) { + int channelMask = 0; + + switch (chanCount) { + case 1: + channelMask = SL_SPEAKER_FRONT_CENTER; + break; + + case 2: + channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; + break; + + case 4: // Quad + channelMask = SL_ANDROID_SPEAKER_QUAD; + break; + + case 6: // 5.1 + channelMask = SL_ANDROID_SPEAKER_5DOT1; + break; + + case 8: // 7.1 + channelMask = SL_ANDROID_SPEAKER_7DOT1; + break; + } + return channelMask; +} + +static const char *TAG = "AAudioStreamOpenSLES"; OpenSLEngine *OpenSLEngine::getInstance() { // TODO mutex @@ -172,6 +240,11 @@ SLresult OpenSLOutputMixer::createAudioPlayer(SLObjectItf *objectItf, OpenSLOutputMixer *OpenSLOutputMixer::sInstance = nullptr; +// this callback handler is called every time a buffer finishes playing +static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { + ((AudioStreamOpenSLES *) context)->enqueueBuffer(); +} + SLresult AudioStreamOpenSLES::enqueueBuffer() { // Ask the callback to fill the output buffer with data. Result result = fireCallback(mCallbackBuffer, mFramesPerCallback); @@ -184,31 +257,65 @@ SLresult AudioStreamOpenSLES::enqueueBuffer() { } } + +static void CloseSLEngine() { + OpenSLOutputMixer::getInstance()->close(); + OpenSLEngine::getInstance()->close(); +} + +static SLresult OpenSLContext() { + SLresult result = OpenSLEngine::getInstance()->open(); + if (SL_RESULT_SUCCESS == result) { + // get the output mixer + result = OpenSLOutputMixer::getInstance()->open(); + if (SL_RESULT_SUCCESS != result) { + CloseSLEngine(); + } + } + return result; +} + AudioStreamOpenSLES::AudioStreamOpenSLES(const AudioStreamBuilder &builder) : AudioStreamBuffered(builder) { + bqPlayerObject_ = NULL; bq_ = NULL; + bqPlayerPlay_ = NULL; mFramesPerBurst = builder.getDefaultFramesPerBurst(); - OpenSLEngine::getInstance()->open(); + OpenSLContext(); LOGD("AudioStreamOpenSLES(): after OpenSLContext()"); } AudioStreamOpenSLES::~AudioStreamOpenSLES() { - OpenSLEngine::getInstance()->close(); + CloseSLEngine(); delete[] mCallbackBuffer; } +static SLuint32 ConvertFormatToRepresentation(AudioFormat format) { + switch(format) { + case AudioFormat::Invalid: + case AudioFormat::Unspecified: + return 0; + case AudioFormat::I16: + return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT; + case AudioFormat::Float: + return SL_ANDROID_PCM_REPRESENTATION_FLOAT; + } +} + static bool s_isLittleEndian() { static uint32_t value = 1; return *((uint8_t *) &value) == 1; // Does address point to LSB? } -SLuint32 AudioStreamOpenSLES::getDefaultByteOrder() { +static SLuint32 s_getDefaultByteOrder() { return s_isLittleEndian() ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; } Result AudioStreamOpenSLES::open() { - LOGI("AudioStreamOpenSLES::open(chans:%d, rate:%d)", + SLresult result; + + __android_log_print(ANDROID_LOG_INFO, TAG, "AudioPlayerOpenSLES::Open(chans:%d, rate:%d)", mChannelCount, mSampleRate); if (__ANDROID_API__ < __ANDROID_API_L__ && mFormat == AudioFormat::Float){ @@ -251,6 +358,62 @@ Result AudioStreamOpenSLES::open() { LOGD("AudioStreamOpenSLES(): mFramesPerCallback = %d", mFramesPerCallback); LOGD("AudioStreamOpenSLES(): mBytesPerCallback = %d", mBytesPerCallback); + SLuint32 bitsPerSample = getBytesPerSample() * OBOE_BITS_PER_BYTE; + + // configure audio source + SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { + SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // locatorType + static_cast(mBurstsPerBuffer)}; // numBuffers + + // Define the audio data format. + SLDataFormat_PCM format_pcm = { + SL_DATAFORMAT_PCM, // formatType + (SLuint32) mChannelCount, // numChannels + (SLuint32) (mSampleRate * kMillisPerSecond), // milliSamplesPerSec + bitsPerSample, // bitsPerSample + bitsPerSample, // containerSize; + (SLuint32) chanCountToChanMask(mChannelCount), // channelMask + s_getDefaultByteOrder(), + }; + + SLDataSource audioSrc = {&loc_bufq, &format_pcm}; + + /** + * API 21 (Lollipop) introduced support for floating-point data representation and an extended + * data format type: SLAndroidDataFormat_PCM_EX. If running on API 21+ use this newer format + * type, creating it from our original format. + */ + if (__ANDROID_API__ >= __ANDROID_API_L__) { + SLuint32 representation = ConvertFormatToRepresentation(getFormat()); + SLAndroidDataFormat_PCM_EX format_pcm_ex = OpenSLES_createExtendedFormat(format_pcm, + representation); + // Overwrite the previous format. + audioSrc.pFormat = &format_pcm_ex; + } + + result = OpenSLOutputMixer::getInstance()->createAudioPlayer(&bqPlayerObject_, &audioSrc); + LOGD("CreateAudioPlayer() result:%s", getSLErrStr(result)); + assert(SL_RESULT_SUCCESS == result); + + result = (*bqPlayerObject_)->Realize(bqPlayerObject_, SL_BOOLEAN_FALSE); + LOGD("Realize player object result:%s", getSLErrStr(result)); + assert(SL_RESULT_SUCCESS == result); + + result = (*bqPlayerObject_)->GetInterface(bqPlayerObject_, SL_IID_PLAY, &bqPlayerPlay_); + LOGD("get player interface result:%s", getSLErrStr(result)); + assert(SL_RESULT_SUCCESS == result); + + // The BufferQueue + result = (*bqPlayerObject_)->GetInterface(bqPlayerObject_, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bq_); + LOGD("get bufferqueue interface:%p result:%s", bq_, getSLErrStr(result)); + assert(SL_RESULT_SUCCESS == result); + + // The register BufferQueue callback + result = (*bq_)->RegisterCallback(bq_, bqPlayerCallback, this); + LOGD("register callback result:%s", getSLErrStr(result)); + assert(SL_RESULT_SUCCESS == result); + mSharingMode = SharingMode::Shared; mBufferCapacityInFrames = mFramesPerBurst * mBurstsPerBuffer; @@ -258,10 +421,92 @@ Result AudioStreamOpenSLES::open() { } Result AudioStreamOpenSLES::close() { - bq_ = NULL; +// __android_log_write(ANDROID_LOG_INFO, TAG, "AudioStreamOpenSLES()"); + // TODO make sure callback is no longer being called + if (bqPlayerObject_ != NULL) { + (*bqPlayerObject_)->Destroy(bqPlayerObject_); + bqPlayerObject_ = NULL; + + // invalidate any interfaces + bqPlayerPlay_ = NULL; + bq_ = NULL; + } return Result::OK; } +Result AudioStreamOpenSLES::setPlayState(SLuint32 newState) +{ + Result result = Result::OK; + LOGD("AudioStreamOpenSLES(): setPlayState()"); + if (bqPlayerPlay_ == NULL) { + return Result::ErrorInvalidState; + } + SLresult slResult = (*bqPlayerPlay_)->SetPlayState(bqPlayerPlay_, newState); + if(SL_RESULT_SUCCESS != slResult) { + LOGD("AudioStreamOpenSLES(): setPlayState() returned %s", getSLErrStr(slResult)); + result = Result::ErrorInvalidState; // TODO review + } else { + setState(StreamState::Pausing); + } + return result; +} + +Result AudioStreamOpenSLES::requestStart() +{ + LOGD("AudioStreamOpenSLES(): requestStart()"); + Result result = setPlayState(SL_PLAYSTATE_PLAYING); + if(result != Result::OK) { + result = Result::ErrorInvalidState; // TODO review + } else { + enqueueBuffer(); + setState(StreamState::Starting); + } + return result; +} + + +Result AudioStreamOpenSLES::requestPause() { + LOGD("AudioStreamOpenSLES(): requestPause()"); + Result result = setPlayState(SL_PLAYSTATE_PAUSED); + if(result != Result::OK) { + result = Result::ErrorInvalidState; // TODO review + } else { + setState(StreamState::Pausing); + } + return result; +} + +Result AudioStreamOpenSLES::requestFlush() { + LOGD("AudioStreamOpenSLES(): requestFlush()"); + if (bqPlayerPlay_ == NULL) { + return Result::ErrorInvalidState; + } + return Result::ErrorUnimplemented; // TODO +} + +Result AudioStreamOpenSLES::requestStop() +{ + LOGD("AudioStreamOpenSLES(): requestStop()"); + Result result = setPlayState(SL_PLAYSTATE_STOPPED); + if(result != Result::OK) { + result = Result::ErrorInvalidState; // TODO review + } else { + setState(StreamState::Stopping); + } + return result; +} + +Result AudioStreamOpenSLES::waitForStateChange(StreamState currentState, + StreamState *nextState, + int64_t timeoutNanoseconds) +{ + LOGD("AudioStreamOpenSLES(): waitForStateChange()"); + if (bqPlayerPlay_ == NULL) { + return Result::ErrorInvalidState; + } + return Result::ErrorUnimplemented; // TODO +} + int32_t AudioStreamOpenSLES::getFramesPerBurst() { return mFramesPerBurst; } diff --git a/src/opensles/AudioStreamOpenSLES.h b/src/opensles/AudioStreamOpenSLES.h index 653048c5b..a41d240a1 100644 --- a/src/opensles/AudioStreamOpenSLES.h +++ b/src/opensles/AudioStreamOpenSLES.h @@ -83,12 +83,21 @@ class AudioStreamOpenSLES : public AudioStreamBuffered { virtual ~AudioStreamOpenSLES(); - virtual Result open() override; - virtual Result close() override; + Result open() override; + Result close() override; + + Result requestStart() override; + Result requestPause() override; + Result requestFlush() override; + Result requestStop() override; // public, but don't call directly (called by the OSLES callback) SLresult enqueueBuffer(); + Result waitForStateChange(StreamState currentState, + StreamState *nextState, + int64_t timeoutNanoseconds) override; + /** * Query the current state, eg. OBOE_STREAM_STATE_PAUSING * @@ -98,11 +107,9 @@ class AudioStreamOpenSLES : public AudioStreamBuffered { int32_t getFramesPerBurst() override; - static SLuint32 getDefaultByteOrder(); - - virtual int chanCountToChanMask(int chanCount) = 0; - protected: +private: + /** * Internal use only. * Use this instead of directly setting the internal state variable. @@ -111,6 +118,14 @@ class AudioStreamOpenSLES : public AudioStreamBuffered { mState = state; } + /** + * Set OpenSL ES state. + * + * @param newState SL_PLAYSTATE_PAUSED, SL_PLAYSTATE_PLAYING, SL_PLAYSTATE_STOPPED + * @return + */ + Result setPlayState(SLuint32 newState); + uint8_t *mCallbackBuffer; int32_t mBytesPerCallback; int32_t mFramesPerBurst = 0; @@ -118,7 +133,9 @@ class AudioStreamOpenSLES : public AudioStreamBuffered { StreamState mState = StreamState::Uninitialized; // OpenSLES stuff - SLAndroidSimpleBufferQueueItf bq_ = nullptr; + SLObjectItf bqPlayerObject_; + SLPlayItf bqPlayerPlay_; + SLAndroidSimpleBufferQueueItf bq_; }; } // namespace oboe diff --git a/src/opensles/OpenSLESUtilities.cpp b/src/opensles/OpenSLESUtilities.cpp index c764af382..0636bda32 100644 --- a/src/opensles/OpenSLESUtilities.cpp +++ b/src/opensles/OpenSLESUtilities.cpp @@ -18,33 +18,6 @@ namespace oboe { -/* - * OSLES Helpers - */ -static const char *errStrings[] = { - "SL_RESULT_SUCCESS", // 0 - "SL_RESULT_PRECONDITIONS_VIOLATE", // 1 - "SL_RESULT_PARAMETER_INVALID", // 2 - "SL_RESULT_MEMORY_FAILURE", // 3 - "SL_RESULT_RESOURCE_ERROR", // 4 - "SL_RESULT_RESOURCE_LOST", // 5 - "SL_RESULT_IO_ERROR", // 6 - "SL_RESULT_BUFFER_INSUFFICIENT", // 7 - "SL_RESULT_CONTENT_CORRUPTED", // 8 - "SL_RESULT_CONTENT_UNSUPPORTED", // 9 - "SL_RESULT_CONTENT_NOT_FOUND", // 10 - "SL_RESULT_PERMISSION_DENIED", // 11 - "SL_RESULT_FEATURE_UNSUPPORTED", // 12 - "SL_RESULT_INTERNAL_ERROR", // 13 - "SL_RESULT_UNKNOWN_ERROR", // 14 - "SL_RESULT_OPERATION_ABORTED", // 15 - "SL_RESULT_CONTROL_LOST" // 16 -}; - -const char *getSLErrStr(SLresult code) { - return errStrings[code]; -} - SLAndroidDataFormat_PCM_EX OpenSLES_createExtendedFormat( SLDataFormat_PCM format, SLuint32 representation) { SLAndroidDataFormat_PCM_EX format_pcm_ex; @@ -59,15 +32,4 @@ SLAndroidDataFormat_PCM_EX OpenSLES_createExtendedFormat( return format_pcm_ex; } -SLuint32 OpenSLES_ConvertFormatToRepresentation(AudioFormat format) { - switch(format) { - case AudioFormat::Invalid: - case AudioFormat::Unspecified: - return 0; - case AudioFormat::I16: - return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT; - case AudioFormat::Float: - return SL_ANDROID_PCM_REPRESENTATION_FLOAT; - } -} } // namespace oboe \ No newline at end of file diff --git a/src/opensles/OpenSLESUtilities.h b/src/opensles/OpenSLESUtilities.h index 20f5498e5..a0b73af4b 100644 --- a/src/opensles/OpenSLESUtilities.h +++ b/src/opensles/OpenSLESUtilities.h @@ -18,12 +18,9 @@ #define OBOE_OPENSLES_OPENSLESUTILITIES_H #include -#include "oboe/Oboe.h" namespace oboe { -const char *getSLErrStr(SLresult code); - /** * Creates an extended PCM format from the supplied format and data representation. This method * should only be called on Android devices with API level 21+. API 21 introduced the @@ -37,9 +34,6 @@ const char *getSLErrStr(SLresult code); SLAndroidDataFormat_PCM_EX OpenSLES_createExtendedFormat(SLDataFormat_PCM format, SLuint32 representation); - -SLuint32 OpenSLES_ConvertFormatToRepresentation(AudioFormat format); - } // namespace oboe #endif //OBOE_OPENSLES_OPENSLESUTILITIES_H From 48fac9050a3f0345dd51e808b9215161c79de65b Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 24/45] Revert "oboe: OpenSL ES refactor engine" This reverts commit 9e99ba5cc8e55a02467a3e41c0afb057c163b4c8. --- src/common/AudioStreamBuilder.cpp | 8 +- src/opensles/AudioInputStreamOpenSLES.cpp | 28 ---- src/opensles/AudioInputStreamOpenSLES.h | 39 ----- src/opensles/AudioOutputStreamOpenSLES.cpp | 29 ---- src/opensles/AudioOutputStreamOpenSLES.h | 40 ----- src/opensles/AudioStreamOpenSLES.cpp | 167 +++++++-------------- src/opensles/AudioStreamOpenSLES.h | 43 ------ 7 files changed, 54 insertions(+), 300 deletions(-) delete mode 100644 src/opensles/AudioInputStreamOpenSLES.cpp delete mode 100644 src/opensles/AudioInputStreamOpenSLES.h delete mode 100644 src/opensles/AudioOutputStreamOpenSLES.cpp delete mode 100644 src/opensles/AudioOutputStreamOpenSLES.h diff --git a/src/common/AudioStreamBuilder.cpp b/src/common/AudioStreamBuilder.cpp index a3582e889..6d92391b1 100644 --- a/src/common/AudioStreamBuilder.cpp +++ b/src/common/AudioStreamBuilder.cpp @@ -20,8 +20,6 @@ #include "OboeDebug.h" #include "oboe/Oboe.h" #include "oboe/AudioStreamBuilder.h" -#include "opensles/AudioInputStreamOpenSLES.h" -#include "opensles/AudioOutputStreamOpenSLES.h" #include "opensles/AudioStreamOpenSLES.h" namespace oboe { @@ -43,11 +41,7 @@ AudioStream *AudioStreamBuilder::build() { } // fall into using older existing API case AudioApi::OpenSLES: - if (getDirection() == oboe::Direction::Output) { - stream = new AudioOutputStreamOpenSLES(*this); - } else if (getDirection() == oboe::Direction::Input) { - stream = new AudioInputStreamOpenSLES(*this); - } + stream = new AudioStreamOpenSLES(*this); break; } return stream; diff --git a/src/opensles/AudioInputStreamOpenSLES.cpp b/src/opensles/AudioInputStreamOpenSLES.cpp deleted file mode 100644 index 688844530..000000000 --- a/src/opensles/AudioInputStreamOpenSLES.cpp +++ /dev/null @@ -1,28 +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. - */ - -#include "oboe/AudioStreamBuilder.h" -#include "AudioInputStreamOpenSLES.h" -#include "AudioStreamOpenSLES.h" - -using namespace oboe; - -AudioInputStreamOpenSLES::AudioInputStreamOpenSLES(const AudioStreamBuilder &builder) - : AudioStreamOpenSLES(builder) { -} - -AudioInputStreamOpenSLES::~AudioInputStreamOpenSLES() { -} diff --git a/src/opensles/AudioInputStreamOpenSLES.h b/src/opensles/AudioInputStreamOpenSLES.h deleted file mode 100644 index 3e8b0ff70..000000000 --- a/src/opensles/AudioInputStreamOpenSLES.h +++ /dev/null @@ -1,39 +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. - */ - -#ifndef AUDIO_INPUT_STREAM_OPENSL_ES_H_ -#define AUDIO_INPUT_STREAM_OPENSL_ES_H_ - - -#include -#include - -#include "oboe/Oboe.h" -#include "AudioStreamOpenSLES.h" - -namespace oboe { - -class AudioInputStreamOpenSLES : public AudioStreamOpenSLES { -public: - AudioInputStreamOpenSLES(); - explicit AudioInputStreamOpenSLES(const AudioStreamBuilder &builder); - - virtual ~AudioInputStreamOpenSLES(); -}; - -} // namespace oboe - -#endif //AUDIO_INPUT_STREAM_OPENSL_ES_H_ diff --git a/src/opensles/AudioOutputStreamOpenSLES.cpp b/src/opensles/AudioOutputStreamOpenSLES.cpp deleted file mode 100644 index 5be7b5448..000000000 --- a/src/opensles/AudioOutputStreamOpenSLES.cpp +++ /dev/null @@ -1,29 +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. - */ - -#include "oboe/AudioStreamBuilder.h" -#include "AudioOutputStreamOpenSLES.h" -#include "AudioStreamOpenSLES.h" - -using namespace oboe; - - -AudioOutputStreamOpenSLES::AudioOutputStreamOpenSLES(const AudioStreamBuilder &builder) - : AudioStreamOpenSLES(builder) { -} - -AudioOutputStreamOpenSLES::~AudioOutputStreamOpenSLES() { -} diff --git a/src/opensles/AudioOutputStreamOpenSLES.h b/src/opensles/AudioOutputStreamOpenSLES.h deleted file mode 100644 index 75e87886c..000000000 --- a/src/opensles/AudioOutputStreamOpenSLES.h +++ /dev/null @@ -1,40 +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. - */ - -#ifndef AUDIO_OUTPUT_STREAM_OPENSL_ES_H_ -#define AUDIO_OUTPUT_STREAM_OPENSL_ES_H_ - - -#include -#include - -#include "oboe/Oboe.h" -#include "AudioStreamOpenSLES.h" - -namespace oboe { - -class AudioOutputStreamOpenSLES : public AudioStreamOpenSLES { -public: - AudioOutputStreamOpenSLES(); - explicit AudioOutputStreamOpenSLES(const AudioStreamBuilder &builder); - - virtual ~AudioOutputStreamOpenSLES(); -private: -}; - -} // namespace oboe - -#endif //AUDIO_OUTPUT_STREAM_OPENSL_ES_H_ diff --git a/src/opensles/AudioStreamOpenSLES.cpp b/src/opensles/AudioStreamOpenSLES.cpp index c1935a0ea..dfb9f8493 100644 --- a/src/opensles/AudioStreamOpenSLES.cpp +++ b/src/opensles/AudioStreamOpenSLES.cpp @@ -35,7 +35,7 @@ #define OBOE_BITS_PER_BYTE 8 // common value -using namespace oboe; +namespace oboe { /* * OSLES Helpers @@ -104,15 +104,34 @@ int chanCountToChanMask(int chanCount) { static const char *TAG = "AAudioStreamOpenSLES"; -OpenSLEngine *OpenSLEngine::getInstance() { - // TODO mutex - if (sInstance == nullptr) { - sInstance = new OpenSLEngine(); +// engine interfaces +static int32_t sOpenCount = 0; +static SLObjectItf sEngineObject = 0; +static SLEngineItf sEngineEngine; + +// output mix interfaces +static SLObjectItf sOutputMixObject = 0; + +static void CloseSLEngine(); + +SLresult AudioStreamOpenSLES::enqueueBuffer() { + // Ask the callback to fill the output buffer with data. + Result result = fireCallback(mCallbackBuffer, mFramesPerCallback); + if (result != Result::OK) { + LOGE("Oboe callback returned %d", result); + return SL_RESULT_INTERNAL_ERROR; + } else { + // Pass the data to OpenSLES. + return (*bq_)->Enqueue(bq_, mCallbackBuffer, mBytesPerCallback); } - return sInstance; } -SLresult OpenSLEngine::open() { +// this callback handler is called every time a buffer finishes playing +static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { + ((AudioStreamOpenSLES *) context)->enqueueBuffer(); +} + +static SLresult OpenSLEngine() { SLresult result = SL_RESULT_SUCCESS; if (sOpenCount > 0) { ++sOpenCount; @@ -140,85 +159,29 @@ SLresult OpenSLEngine::open() { goto error; } - ++sOpenCount; - return result; - - error: - close(); - return result; -} - -void OpenSLEngine::close() { -// __android_log_print(ANDROID_LOG_INFO, TAG, "CloseSLEngine()"); - --sOpenCount; - if (sOpenCount > 0) { - return; - } - - if (sEngineObject != NULL) { - (*sEngineObject)->Destroy(sEngineObject); - sEngineObject = NULL; - sEngineEngine = NULL; - } -} - -SLresult OpenSLEngine::createOutputMix(SLObjectItf *objectItf) { - return (*sEngineEngine)->CreateOutputMix(sEngineEngine, objectItf, 0, 0, 0); -} - -SLresult OpenSLEngine::createAudioPlayer(SLObjectItf *objectItf, - SLDataSource *audioSource, - SLDataSink *audioSink) { - - const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE}; - const SLboolean req[] = {SL_BOOLEAN_TRUE}; - - // The Player - return (*sEngineEngine)->CreateAudioPlayer(sEngineEngine, objectItf, audioSource, - audioSink, - sizeof(ids) / sizeof(ids[0]), ids, req); -} - -OpenSLEngine *OpenSLEngine::sInstance = nullptr; - -OpenSLOutputMixer *OpenSLOutputMixer::getInstance() { - // TODO mutex - if (sInstance == nullptr) { - sInstance = new OpenSLOutputMixer(); - } - return sInstance; -} - -SLresult OpenSLOutputMixer::open() { - SLresult result = SL_RESULT_SUCCESS; - if (sOpenCount > 0) { - ++sOpenCount; - return SL_RESULT_SUCCESS; - } - // get the output mixer - result = OpenSLEngine::getInstance()->createOutputMix(&sOutputMixObject); + result = (*sEngineEngine)->CreateOutputMix(sEngineEngine, &sOutputMixObject, 0, 0, 0); if (SL_RESULT_SUCCESS != result) { - LOGE("OpenSLOutputMixer() - createOutputMix() result:%s", getSLErrStr(result)); + LOGE("OpenSLEngine() - CreateOutputMix() result:%s", getSLErrStr(result)); goto error; } // realize the output mix result = (*sOutputMixObject)->Realize(sOutputMixObject, SL_BOOLEAN_FALSE); if (SL_RESULT_SUCCESS != result) { - LOGE("OpenSLOutputMixer() - Realize() sOutputMixObject result:%s", getSLErrStr(result)); + LOGE("OpenSLEngine() - Realize() sOutputMixObject result:%s", getSLErrStr(result)); goto error; } ++sOpenCount; return result; - error: - close(); +error: + CloseSLEngine(); return result; } -void OpenSLOutputMixer::close() { +static void CloseSLEngine() { // __android_log_print(ANDROID_LOG_INFO, TAG, "CloseSLEngine()"); --sOpenCount; if (sOpenCount > 0) { @@ -229,50 +192,12 @@ void OpenSLOutputMixer::close() { (*sOutputMixObject)->Destroy(sOutputMixObject); sOutputMixObject = NULL; } -} - -SLresult OpenSLOutputMixer::createAudioPlayer(SLObjectItf *objectItf, - SLDataSource *audioSource) { - SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, sOutputMixObject}; - SLDataSink audioSink = {&loc_outmix, NULL}; - return OpenSLEngine::getInstance()->createAudioPlayer(objectItf, audioSource, &audioSink); -} - -OpenSLOutputMixer *OpenSLOutputMixer::sInstance = nullptr; - -// this callback handler is called every time a buffer finishes playing -static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { - ((AudioStreamOpenSLES *) context)->enqueueBuffer(); -} - -SLresult AudioStreamOpenSLES::enqueueBuffer() { - // Ask the callback to fill the output buffer with data. - Result result = fireCallback(mCallbackBuffer, mFramesPerCallback); - if (result != Result::OK) { - LOGE("Oboe callback returned %d", result); - return SL_RESULT_INTERNAL_ERROR; - } else { - // Pass the data to OpenSLES. - return (*bq_)->Enqueue(bq_, mCallbackBuffer, mBytesPerCallback); - } -} - - -static void CloseSLEngine() { - OpenSLOutputMixer::getInstance()->close(); - OpenSLEngine::getInstance()->close(); -} -static SLresult OpenSLContext() { - SLresult result = OpenSLEngine::getInstance()->open(); - if (SL_RESULT_SUCCESS == result) { - // get the output mixer - result = OpenSLOutputMixer::getInstance()->open(); - if (SL_RESULT_SUCCESS != result) { - CloseSLEngine(); - } + if (sEngineObject != NULL) { + (*sEngineObject)->Destroy(sEngineObject); + sEngineObject = NULL; + sEngineEngine = NULL; } - return result; } AudioStreamOpenSLES::AudioStreamOpenSLES(const AudioStreamBuilder &builder) @@ -281,8 +206,8 @@ AudioStreamOpenSLES::AudioStreamOpenSLES(const AudioStreamBuilder &builder) bq_ = NULL; bqPlayerPlay_ = NULL; mFramesPerBurst = builder.getDefaultFramesPerBurst(); - OpenSLContext(); - LOGD("AudioStreamOpenSLES(): after OpenSLContext()"); + OpenSLEngine(); + LOGD("AudioStreamOpenSLES(): after OpenSLEngine()"); } AudioStreamOpenSLES::~AudioStreamOpenSLES() { @@ -365,6 +290,8 @@ Result AudioStreamOpenSLES::open() { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // locatorType static_cast(mBurstsPerBuffer)}; // numBuffers + // SLuint32 chanMask = SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT; + // Define the audio data format. SLDataFormat_PCM format_pcm = { SL_DATAFORMAT_PCM, // formatType @@ -391,7 +318,17 @@ Result AudioStreamOpenSLES::open() { audioSrc.pFormat = &format_pcm_ex; } - result = OpenSLOutputMixer::getInstance()->createAudioPlayer(&bqPlayerObject_, &audioSrc); + // configure audio sink + SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, sOutputMixObject}; + SLDataSink audioSnk = {&loc_outmix, NULL}; + + const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE}; + const SLboolean req[] = {SL_BOOLEAN_TRUE}; + + // The Player + result = (*sEngineEngine)->CreateAudioPlayer(sEngineEngine, &bqPlayerObject_, &audioSrc, + &audioSnk, + sizeof(ids) / sizeof(ids[0]), ids, req); LOGD("CreateAudioPlayer() result:%s", getSLErrStr(result)); assert(SL_RESULT_SUCCESS == result); @@ -510,3 +447,5 @@ Result AudioStreamOpenSLES::waitForStateChange(StreamState currentState, int32_t AudioStreamOpenSLES::getFramesPerBurst() { return mFramesPerBurst; } + +} // namespace oboe diff --git a/src/opensles/AudioStreamOpenSLES.h b/src/opensles/AudioStreamOpenSLES.h index a41d240a1..41ec329bd 100644 --- a/src/opensles/AudioStreamOpenSLES.h +++ b/src/opensles/AudioStreamOpenSLES.h @@ -25,49 +25,6 @@ namespace oboe { -class OpenSLEngine { -public: - static OpenSLEngine *getInstance(); - - SLresult open(); - - void close(); - - SLresult createOutputMix(SLObjectItf *objectItf); - - SLresult createAudioPlayer(SLObjectItf *objectItf, - SLDataSource *audioSource, - SLDataSink *audioSink); - -private: - static OpenSLEngine *sInstance; - -// engine interfaces - int32_t sOpenCount = 0; - SLObjectItf sEngineObject = 0; - SLEngineItf sEngineEngine; -}; - -class OpenSLOutputMixer { -public: - static OpenSLOutputMixer *getInstance(); - - SLresult open(); - - void close(); - - SLresult createAudioPlayer(SLObjectItf *objectItf, - SLDataSource *audioSource); - -private: - static OpenSLOutputMixer *sInstance; - -// engine interfaces - int32_t sOpenCount = 0; -// output mix interfaces - SLObjectItf sOutputMixObject = 0; -}; - /** * A stream that wraps OpenSL ES. * From 5d69fc057414ef8d6adbea19f719d8dacb172c84 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 25/45] Revert "New diagrams for sharing modes" This reverts commit a625de281ef3014b26fcbf294eff160aeb9b615c. --- FullGuide.md | 12 ++++-------- oboe-sharing-mode-exclusive.jpg | Bin 10674 -> 0 bytes oboe-sharing-mode-shared.jpg | Bin 15818 -> 0 bytes oboe-sharing-modes.png | Bin 0 -> 29614 bytes 4 files changed, 4 insertions(+), 8 deletions(-) delete mode 100644 oboe-sharing-mode-exclusive.jpg delete mode 100644 oboe-sharing-mode-shared.jpg create mode 100644 oboe-sharing-modes.png diff --git a/FullGuide.md b/FullGuide.md index 014c903e5..0e84fa937 100644 --- a/FullGuide.md +++ b/FullGuide.md @@ -26,16 +26,12 @@ The audio device attached to a stream determines whether the stream is for input ### Sharing mode -A stream has a sharing mode: - -* `SharingMode::Exclusive` (available on API 26+) means the stream has exclusive access to an endpoint on its audio device; the endpoint cannot be used by any other audio stream. If the exclusive endpoint is already in use, it might not be possible for the stream to obtain access to it. Exclusive streams provide the lowest possible latency by bypassing the mixer stage, but they are also more likely to get disconnected. You should close exclusive streams as soon as you no longer need them, so that other apps can access that endpoint. Not all audio devices provide exclusive endpoints. System sounds and sounds from other apps can still be heard when an exclusive stream is in use as they use a different endpoint. - -![Oboe exclusive sharing mode diagram](oboe-sharing-mode-exclusive.jpg) +![Oboe sharing diagram](oboe-sharing-modes.png) -* `SharingMode::Shared` allows Oboe to mix audio. Oboe mixes all the shared streams assigned to the same endpoint on the audio device. - -![Oboe exclusive sharing mode diagram](oboe-sharing-mode-shared.jpg) +A stream has a sharing mode: +* `SharingMode::Exclusive` (available on API 26+) means the stream has exclusive access to an endpoint on its audio device; the endpoint cannot be used by any other audio stream. If the exclusive endpoint is already in use, it might not be possible for the stream to obtain access to it. Exclusive streams provide the lowest possible latency by bypassing the mixer stage, but they are also more likely to get disconnected. You should close exclusive streams as soon as you no longer need them, so that other apps can access the device. Not all audio devices provide exclusive endpoints. +* `SharingMode::Shared` allows Oboe to mix audio. Oboe mixes all the shared streams assigned to the same device. You can explicitly request the sharing mode when you create a stream, although you are not guaranteed to receive that mode. By default, the sharing mode is `Shared`. diff --git a/oboe-sharing-mode-exclusive.jpg b/oboe-sharing-mode-exclusive.jpg deleted file mode 100644 index 0d23481b8995b7f0a1cd6e34ee550dc19754d847..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10674 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 diff --git a/oboe-sharing-mode-shared.jpg b/oboe-sharing-mode-shared.jpg deleted file mode 100644 index 5233689c96072f64dcf92bd9c6908d72cd21f33d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15818 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 a%fD!^E9&dtIIdo<`&SD57rGBceg9vjuPplj diff --git a/oboe-sharing-modes.png b/oboe-sharing-modes.png new file mode 100644 index 0000000000000000000000000000000000000000..53103b8dfeefd37b3a1650a451d5328808d8c868 GIT binary patch literal 29614 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 literal 0 HcmV?d00001 From 880012bcac544a08d718c3466c41eb07c9205b7a Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 26/45] Revert "Minor text reordering to make it easier to diff" This reverts commit 9642e1e817d113c6afa1f54597bf6a26fbf63454. --- FullGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FullGuide.md b/FullGuide.md index 0e84fa937..1d7655e25 100644 --- a/FullGuide.md +++ b/FullGuide.md @@ -30,8 +30,8 @@ The audio device attached to a stream determines whether the stream is for input A stream has a sharing mode: -* `SharingMode::Exclusive` (available on API 26+) means the stream has exclusive access to an endpoint on its audio device; the endpoint cannot be used by any other audio stream. If the exclusive endpoint is already in use, it might not be possible for the stream to obtain access to it. Exclusive streams provide the lowest possible latency by bypassing the mixer stage, but they are also more likely to get disconnected. You should close exclusive streams as soon as you no longer need them, so that other apps can access the device. Not all audio devices provide exclusive endpoints. * `SharingMode::Shared` allows Oboe to mix audio. Oboe mixes all the shared streams assigned to the same device. +* `SharingMode::Exclusive` (available on API 26+) means the stream has exclusive access to an endpoint on its audio device; the endpoint cannot be used by any other audio stream. If the exclusive endpoint is already in use, it might not be possible for the stream to obtain access to it. Exclusive streams provide the lowest possible latency by bypassing the mixer stage, but they are also more likely to get disconnected. You should close exclusive streams as soon as you no longer need them, so that other apps can access the device. Not all audio devices provide exclusive endpoints. You can explicitly request the sharing mode when you create a stream, although you are not guaranteed to receive that mode. By default, the sharing mode is `Shared`. From 179c2ea55c275cc1a53048afdd167005ee1f1f73 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 27/45] Revert "Updated text and added diagram on sharing modes" This reverts commit 86d371624d51a7c00cade2a7543ea6ea5c1830f9. --- FullGuide.md | 7 +++---- oboe-sharing-modes.png | Bin 29614 -> 0 bytes 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 oboe-sharing-modes.png diff --git a/FullGuide.md b/FullGuide.md index 1d7655e25..6e220682c 100644 --- a/FullGuide.md +++ b/FullGuide.md @@ -26,14 +26,13 @@ The audio device attached to a stream determines whether the stream is for input ### Sharing mode -![Oboe sharing diagram](oboe-sharing-modes.png) - A stream has a sharing mode: +* `SharingMode::Exclusive` (available on API 26+) means the stream has exclusive access to its audio device; the device cannot be used by any other audio stream. If the audio device is already in use, it might not be possible for the stream to have exclusive access. Exclusive streams provide the lowest possible latency, but they are also more likely to get disconnected. You should close exclusive streams as soon as you no longer need them, so that other apps can access the device. * `SharingMode::Shared` allows Oboe to mix audio. Oboe mixes all the shared streams assigned to the same device. -* `SharingMode::Exclusive` (available on API 26+) means the stream has exclusive access to an endpoint on its audio device; the endpoint cannot be used by any other audio stream. If the exclusive endpoint is already in use, it might not be possible for the stream to obtain access to it. Exclusive streams provide the lowest possible latency by bypassing the mixer stage, but they are also more likely to get disconnected. You should close exclusive streams as soon as you no longer need them, so that other apps can access the device. Not all audio devices provide exclusive endpoints. -You can explicitly request the sharing mode when you create a stream, although you are not guaranteed to receive that mode. By default, the sharing mode is `Shared`. +You can explicitly request the sharing mode when you create a stream, although you are not guaranteed to receive that mode. By default, +the sharing mode is `Shared`. ### Audio format diff --git a/oboe-sharing-modes.png b/oboe-sharing-modes.png deleted file mode 100644 index 53103b8dfeefd37b3a1650a451d5328808d8c868..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29614 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 From 62013d8035e90fcae040fcecfc9333598a22107e Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 28/45] Revert "Clearer instructions for adding Oboe to a project" This reverts commit 39c4005660c08014a9a48d372cb805e51304ff3e. --- GettingStarted.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/GettingStarted.md b/GettingStarted.md index 1e532d997..012e9a60a 100644 --- a/GettingStarted.md +++ b/GettingStarted.md @@ -1,21 +1,18 @@ # Getting Started The easiest way to start using Oboe is to build it from source by adding a few steps to an existing Android Studio project. -## Adding Oboe to your project - -### 1. Clone the github repository +## Building Oboe Start by cloning the Oboe repository: git clone https://github.com/google/oboe **Make a note of the path which you cloned oboe into - you will need it shortly** -### 2. Update CMakeLists.txt -Open your app's `CMakeLists.txt`. This can be found under `External Build Files` in the Android project view. +Open your app's `CMakeLists.txt`, this can be found under `External Build Files` in the Android project view. ![CMakeLists.txt location in Android Studio](cmakelists-location-in-as.png "CMakeLists.txt location in Android Studio") -Now add the following commands to the end of `CMakeLists.txt`. **Remember to update `**PATH TO OBOE**` with your local Oboe path from the previous step**: +Now add the following build steps to `CMakeLists.txt`, **update `**PATH TO OBOE**` with your local Oboe path from the previous step**: # Set the path to the Oboe directory. set (OBOE_DIR ***PATH TO OBOE***) @@ -27,8 +24,7 @@ Now add the following commands to the end of `CMakeLists.txt`. **Remember to upd include_directories (${OBOE_DIR}/include) -In the same file find the [`target_link_libraries`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html) command. -Add `oboe` to the list of libraries which your app's library depends on. For example: +In the same file *after* your own library definition (by default it is named `native-lib`) add the dependencies for the Oboe library: target_link_libraries(native-lib oboe) From aba9533ba6d7952b7c9ad472a3e9a81ffc57309b Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 29/45] Revert "Oboe can be added to an existing project using CMake add_subdirectory" This reverts commit 193241d2520a6fb09fe8aafe5ca0dff9124c9770. --- CMakeLists.txt | 28 ++++++++++++++++++---------- GettingStarted.md | 34 +++++++++++++++------------------- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a4bfadbf..529427f0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,25 @@ cmake_minimum_required(VERSION 3.4.1) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++14") + +# Specify directories which the compiler should look for headers +include_directories( + include + src +) + set (oboe_sources + include/oboe/LatencyTuner.h + include/oboe/Definitions.h + include/oboe/AudioStream.h + include/oboe/AudioStreamBase.h + include/oboe/AudioStreamBuilder.h + include/oboe/AudioStreamCallback.h + include/oboe/Utilities.h src/aaudio/AAudioLoader.cpp src/aaudio/AudioStreamAAudio.cpp + src/common/AudioClock.h + src/common/OboeDebug.h src/common/LatencyTuner.cpp src/common/AudioStream.cpp src/common/AudioStreamBuilder.cpp @@ -16,13 +33,4 @@ set (oboe_sources src/opensles/OpenSLESUtilities.cpp ) -add_library(oboe STATIC ${oboe_sources}) - -# Specify directories which the compiler should look for headers -target_include_directories(oboe PRIVATE src include) - -target_compile_options(oboe PRIVATE -std=c++11 - PRIVATE -Wall - PRIVATE "$<$:-Werror>") # Only include -Werror when building debug config - -target_link_libraries(oboe PRIVATE log OpenSLES) \ No newline at end of file +add_library(oboe STATIC ${oboe_sources}) \ No newline at end of file diff --git a/GettingStarted.md b/GettingStarted.md index 012e9a60a..e9cf932f6 100644 --- a/GettingStarted.md +++ b/GettingStarted.md @@ -6,42 +6,38 @@ Start by cloning the Oboe repository: git clone https://github.com/google/oboe -**Make a note of the path which you cloned oboe into - you will need it shortly** - Open your app's `CMakeLists.txt`, this can be found under `External Build Files` in the Android project view. ![CMakeLists.txt location in Android Studio](cmakelists-location-in-as.png "CMakeLists.txt location in Android Studio") -Now add the following build steps to `CMakeLists.txt`, **update `**PATH TO OBOE**` with your local Oboe path from the previous step**: - - # Set the path to the Oboe directory. - set (OBOE_DIR ***PATH TO OBOE***) - - # Add the Oboe library as a subdirectory in your project. - add_subdirectory (${OBOE_DIR} ./oboe) - - # Specify the path to the Oboe header files. - include_directories (${OBOE_DIR}/include) +Now add the following build steps to `CMakeLists.txt`, making sure you update `/local/path/to/oboe` with your local Oboe repository directory: + # Build the Oboe library + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++11") + set (OBOE_DIR /local/path/to/oboe) + file (GLOB_RECURSE OBOE_SOURCES ${OBOE_DIR}/src/*) + include_directories(${OBOE_DIR}/include ${OBOE_DIR}/src) + add_library(oboe STATIC ${OBOE_SOURCES}) -In the same file *after* your own library definition (by default it is named `native-lib`) add the dependencies for the Oboe library: +In the same file *after* your own library definition (by default it is named `native-lib`) add the dependencies for the Oboe and OpenSLES libraries: - target_link_libraries(native-lib oboe) + target_link_libraries(native-lib log oboe OpenSLES) Here's a complete example `CMakeLists.txt` file: cmake_minimum_required(VERSION 3.4.1) # Build the Oboe library - set (OBOE_DIR ../../../oboe) - add_subdirectory (${OBOE_DIR} ./oboe) - include_directories (${OBOE_DIR}/include) + set (OBOE_DIR /Users/donturner/Code/workspace-android/oboe) + file (GLOB_RECURSE OBOE_SOURCES ${OBOE_DIR}/src/*) + include_directories(${OBOE_DIR}/include ${OBOE_DIR}/src) + add_library(oboe STATIC ${OBOE_SOURCES}) # Build our own native library - add_library (native-lib SHARED src/main/cpp/native-lib.cpp ) + add_library( native-lib SHARED src/main/cpp/native-lib.cpp ) # Specify the libraries which our native library is dependent on - target_link_libraries (native-lib log oboe) + target_link_libraries( native-lib log oboe OpenSLES ) Verify that your project builds correctly. If you have any issues building please [report them here](issues/new). From f3e8b289f45fae249cf6ddcc2fa3d87a60f415e6 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 30/45] Revert "Changing std::make_unique to std::unique_ptr to avoid dependency on C++14" This reverts commit a00668b3507329ac9b3ef08d986c22a783c24b35. --- GettingStarted.md | 2 +- src/opensles/AudioStreamBuffered.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GettingStarted.md b/GettingStarted.md index e9cf932f6..7636d61f6 100644 --- a/GettingStarted.md +++ b/GettingStarted.md @@ -13,7 +13,7 @@ Open your app's `CMakeLists.txt`, this can be found under `External Build Files` Now add the following build steps to `CMakeLists.txt`, making sure you update `/local/path/to/oboe` with your local Oboe repository directory: # Build the Oboe library - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++11") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++14") set (OBOE_DIR /local/path/to/oboe) file (GLOB_RECURSE OBOE_SOURCES ${OBOE_DIR}/src/*) include_directories(${OBOE_DIR}/include ${OBOE_DIR}/src) diff --git a/src/opensles/AudioStreamBuffered.cpp b/src/opensles/AudioStreamBuffered.cpp index ceb4c850c..f852d9c2f 100644 --- a/src/opensles/AudioStreamBuffered.cpp +++ b/src/opensles/AudioStreamBuffered.cpp @@ -44,7 +44,7 @@ Result AudioStreamBuffered::open() { // TODO: Fix memory leak here mFifoBuffer = new FifoBuffer(getBytesPerFrame(), 1024); // TODO size? // Create a callback that reads from the FIFO - mInternalCallback = std::unique_ptr(new AudioStreamBufferedCallback(this)); + mInternalCallback = std::make_unique(this); mStreamCallback = mInternalCallback.get(); LOGD("AudioStreamBuffered(): mStreamCallback = %p", mStreamCallback); } From 05a54f59213e485bcfcb558dabd3ff6e01493e82 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 31/45] Revert "Add TODO for convertToText method to return int value in string" This reverts commit ccf84cf1c00c2b41d4f5dbf5316afc0ee19fd368. --- src/common/Utilities.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/Utilities.cpp b/src/common/Utilities.cpp index 6bc89cde4..66336a23b 100644 --- a/src/common/Utilities.cpp +++ b/src/common/Utilities.cpp @@ -19,7 +19,6 @@ #include "oboe/Definitions.h" #include "oboe/Utilities.h" -// TODO: Return the int value as well as the name #define OBOE_CASE_ENUM(name) case name: return #name namespace oboe { From 82df4d7de6349d7bf32757294ad7b7e9d0995343 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 32/45] Revert "Adding template method convertToText" This reverts commit 3d6f1b743eb06d01d8416c4e18154c67f884e447. --- FullGuide.md | 8 +++- GettingStarted.md | 7 ++-- include/oboe/Definitions.h | 13 ------ include/oboe/Utilities.h | 59 +++++++++++++++++++++++++--- src/common/Utilities.cpp | 18 +++------ src/opensles/AudioStreamBuffered.cpp | 1 - 6 files changed, 69 insertions(+), 37 deletions(-) diff --git a/FullGuide.md b/FullGuide.md index 6e220682c..1654abac9 100644 --- a/FullGuide.md +++ b/FullGuide.md @@ -99,7 +99,7 @@ To be safe, check the state of the audio stream after you create it, as explaine __android_log_print(ANDROID_LOG_ERROR, "AudioEngine", "Error opening stream %s", - convertToText(result)); + convertResultToText(result)); } @@ -404,8 +404,14 @@ Calls that return stream settings, like `AudioStream::getSampleRate()` and `Audi These calls are also thread safe: * `convertToText()` +* `convertAudioFormatToText()` +* `convertPerformanceModeToText()` +* `convertSharingModeToText()` +* `convertDataCallbackResultToText()` +* `convertDirectionToText()` * `AudioStream::get*()` except for `getTimestamp()` + Note: When a stream uses a callback function, it's safe to read/write from the callback thread while also closing the stream from the thread in which it is running. diff --git a/GettingStarted.md b/GettingStarted.md index 7636d61f6..a66e6e811 100644 --- a/GettingStarted.md +++ b/GettingStarted.md @@ -13,7 +13,6 @@ Open your app's `CMakeLists.txt`, this can be found under `External Build Files` Now add the following build steps to `CMakeLists.txt`, making sure you update `/local/path/to/oboe` with your local Oboe repository directory: # Build the Oboe library - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++14") set (OBOE_DIR /local/path/to/oboe) file (GLOB_RECURSE OBOE_SOURCES ${OBOE_DIR}/src/*) include_directories(${OBOE_DIR}/include ${OBOE_DIR}/src) @@ -80,10 +79,10 @@ Open the stream: oboe::AudioStream *stream; oboe::Result result = builder.openStream(&stream); -Check the result to make sure the stream was opened successfully. Oboe has a convenience method for converting its types into human-readable strings called `oboe::convertToText`: +Check the result to make sure the stream was opened successfully. Oboe has many convenience methods for converting its types into human-readable strings, they all start with `oboe::convert`: if (result != Result::OK){ - LOGE("Failed to create stream. Error: %s", oboe::convertToText(result)); + LOGE("Failed to create stream. Error: %s", oboe::convertResultToText(result)); } Note that this sample code uses the [logging macros from here](https://github.com/googlesamples/android-audio-high-performance/blob/master/debug-utils/logging_macros.h). @@ -91,7 +90,7 @@ Note that this sample code uses the [logging macros from here](https://github.co Check the properties of the created stream. The **format** is one property which you should check. The default is `float` on API 21+ and `int16_t` on API 20 or lower. This will dictate the `audioData` type in the `AudioStreamCallback::onAudioReady` callback. oboe::AudioFormat format = stream->getFormat(); - LOGI("AudioStream format is %s", oboe::convertToText(format)); + LOGI("AudioStream format is %s", oboe::convertAudioFormatToText(format)); Now start the stream. diff --git a/include/oboe/Definitions.h b/include/oboe/Definitions.h index 341677be4..52fe7b815 100644 --- a/include/oboe/Definitions.h +++ b/include/oboe/Definitions.h @@ -18,21 +18,8 @@ #define OBOE_DEFINITIONS_H #include -#include #include -// Ensure that all AAudio primitive data types are int32_t -#define ASSERT_INT32(type) static_assert(std::is_same::value, \ -#type" must be int32_t") - -ASSERT_INT32(aaudio_stream_state_t); -ASSERT_INT32(aaudio_direction_t); -ASSERT_INT32(aaudio_format_t); -ASSERT_INT32(aaudio_data_callback_result_t); -ASSERT_INT32(aaudio_result_t); -ASSERT_INT32(aaudio_sharing_mode_t); -ASSERT_INT32(aaudio_performance_mode_t); - namespace oboe { constexpr int32_t kUnspecified = 0; diff --git a/include/oboe/Utilities.h b/include/oboe/Utilities.h index 4f2b1399d..14f77dd74 100644 --- a/include/oboe/Utilities.h +++ b/include/oboe/Utilities.h @@ -32,17 +32,64 @@ void convertPcm16ToFloat(const int16_t *source, float *destination, int32_t numS int32_t convertFormatToSizeInBytes(AudioFormat format); /** - * The text is the ASCII symbol corresponding to the supplied Oboe enum value, - * or an English message saying the value is unrecognized. + * The text is the ASCII symbol corresponding to the returnCode, + * or an English message saying the returnCode is unrecognized. * This is intended for developers to use when debugging. * It is not for displaying to users. * - * @param enum value @see common/Utilities.cpp for concrete implementations - * @return text representation of an Oboe enum value. + * @return pointer to a text representation of an Oboe result code. */ -template -const char * convertToText(FromType); +const char * convertResultToText(Result returnCode); +/** + * The text is the ASCII symbol corresponding to the audio format, + * or an English message saying the audio format is unrecognized. + * This is intended for developers to use when debugging. + * It is not for displaying to users. + * + * @return pointer to a text representation of an Oboe audio format. + */ +const char * convertAudioFormatToText(AudioFormat format); + +/** + * The text is the ASCII symbol corresponding to the performance mode, + * or an English message saying the performance is unrecognized. + * This is intended for developers to use when debugging. + * It is not for displaying to users. + * + * @return pointer to a text representation of an Oboe performance mode. + */ +const char * convertPerformanceModeToText(PerformanceMode mode); + +/** + * The text is the ASCII symbol corresponding to the sharing mode, + * or an English message saying the sharing mode is unrecognized. + * This is intended for developers to use when debugging. + * It is not for displaying to users. + * + * @return pointer to a text representation of an Oboe sharing mode. + */ +const char * convertSharingModeToText(SharingMode mode); + +/** + * The text is the ASCII symbol corresponding to the data callback result, + * or an English message saying the data callback result is unrecognized. + * This is intended for developers to use when debugging. + * It is not for displaying to users. + * + * @return pointer to a text representation of an Oboe data callback result. + */ +const char * convertDataCallbackResultToText(DataCallbackResult result); + +/** + * The text is the ASCII symbol corresponding to the stream direction, + * or an English message saying the stream direction is unrecognized. + * This is intended for developers to use when debugging. + * It is not for displaying to users. + * + * @return pointer to a text representation of an Oboe stream direction. + */ +const char * convertDirectionToText(Direction direction); } // namespace oboe diff --git a/src/common/Utilities.cpp b/src/common/Utilities.cpp index 66336a23b..aae03c3e0 100644 --- a/src/common/Utilities.cpp +++ b/src/common/Utilities.cpp @@ -58,8 +58,7 @@ int32_t convertFormatToSizeInBytes(AudioFormat format) { return size; } -template<> -const char *convertToText(Result returnCode) { +const char *convertResultToText(Result returnCode) { switch (returnCode) { OBOE_CASE_ENUM(Result::OK); OBOE_CASE_ENUM(Result::ErrorDisconnected); @@ -83,8 +82,7 @@ const char *convertToText(Result returnCode) { } } -template<> -const char *convertToText(AudioFormat format) { +const char *convertAudioFormatToText(AudioFormat format) { switch (format) { OBOE_CASE_ENUM(AudioFormat::Invalid); OBOE_CASE_ENUM(AudioFormat::Unspecified); @@ -95,8 +93,7 @@ const char *convertToText(AudioFormat format) { } } -template<> -const char *convertToText(PerformanceMode mode) { +const char *convertPerformanceModeToText(PerformanceMode mode) { switch (mode) { OBOE_CASE_ENUM(PerformanceMode::LowLatency); OBOE_CASE_ENUM(PerformanceMode::None); @@ -106,8 +103,7 @@ const char *convertToText(PerformanceMode mode) { } } -template<> -const char *convertToText(SharingMode mode) { +const char *convertSharingModeToText(SharingMode mode) { switch (mode) { OBOE_CASE_ENUM(SharingMode::Exclusive); OBOE_CASE_ENUM(SharingMode::Shared); @@ -116,8 +112,7 @@ const char *convertToText(SharingMode mode) { } } -template<> -const char *convertToText(DataCallbackResult result) { +const char *convertDataCallbackResultToText(DataCallbackResult result) { switch (result) { OBOE_CASE_ENUM(DataCallbackResult::Continue); OBOE_CASE_ENUM(DataCallbackResult::Stop); @@ -126,8 +121,7 @@ const char *convertToText(DataCallbackResult result) { } } -template<> -const char *convertToText(Direction direction) { +const char *convertDirectionToText(Direction direction) { switch (direction) { OBOE_CASE_ENUM(Direction::Input); OBOE_CASE_ENUM(Direction::Output); diff --git a/src/opensles/AudioStreamBuffered.cpp b/src/opensles/AudioStreamBuffered.cpp index f852d9c2f..40c56ccdc 100644 --- a/src/opensles/AudioStreamBuffered.cpp +++ b/src/opensles/AudioStreamBuffered.cpp @@ -41,7 +41,6 @@ Result AudioStreamBuffered::open() { // callback that reads data from the FIFO. if (getCallback() == nullptr) { LOGD("AudioStreamBuffered(): new FifoBuffer"); - // TODO: Fix memory leak here mFifoBuffer = new FifoBuffer(getBytesPerFrame(), 1024); // TODO size? // Create a callback that reads from the FIFO mInternalCallback = std::make_unique(this); From caf9fb373fed6c734bb71062e445bbf2b138e9c6 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 33/45] Revert "Revert to using raw pointer for setCallback" This reverts commit f3e7fd31608a5f31d33d3ea71df868f8ec338562. --- CMakeLists.txt | 2 +- include/oboe/AudioStream.h | 2 ++ include/oboe/AudioStreamBase.h | 4 ++-- include/oboe/AudioStreamBuilder.h | 17 ++++------------- src/opensles/AudioStreamBuffered.cpp | 9 ++++----- src/opensles/AudioStreamBuffered.h | 1 - 6 files changed, 13 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 529427f0f..767d0164b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.4.1) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++14") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++11") # Specify directories which the compiler should look for headers include_directories( diff --git a/include/oboe/AudioStream.h b/include/oboe/AudioStream.h index 98fc15761..94b3a5173 100644 --- a/include/oboe/AudioStream.h +++ b/include/oboe/AudioStream.h @@ -144,6 +144,8 @@ class AudioStream : public AudioStreamBase { bool isPlaying(); + std::shared_ptr getCallback() const { return mStreamCallback; } + int32_t getBytesPerFrame() const { return mChannelCount * getBytesPerSample(); } int32_t getBytesPerSample() const; diff --git a/include/oboe/AudioStreamBase.h b/include/oboe/AudioStreamBase.h index b55cfcb81..10d90217a 100644 --- a/include/oboe/AudioStreamBase.h +++ b/include/oboe/AudioStreamBase.h @@ -90,12 +90,12 @@ class AudioStreamBase { int32_t getDeviceId() const { return mDeviceId; } - AudioStreamCallback* getCallback() const { + std::shared_ptr getCallback() const { return mStreamCallback; } protected: - AudioStreamCallback *mStreamCallback; + std::shared_ptr mStreamCallback; int32_t mFramesPerCallback = kUnspecified; int32_t mChannelCount = kUnspecified; int32_t mSampleRate = kUnspecified; diff --git a/include/oboe/AudioStreamBuilder.h b/include/oboe/AudioStreamBuilder.h index 920f8af4d..4c81064ec 100644 --- a/include/oboe/AudioStreamBuilder.h +++ b/include/oboe/AudioStreamBuilder.h @@ -196,22 +196,13 @@ class AudioStreamBuilder : public AudioStreamBase { /** * Specifies an object to handle data or error related callbacks from the underlying API. * - * 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. + * When an error callback occurs, the associated stream will be stopped + * and closed in a separate thread. * * @param streamCallback - * @return pointer to the builder so calls can be chained + * @return */ - AudioStreamBuilder *setCallback(AudioStreamCallback *streamCallback) { + AudioStreamBuilder *setCallback(std::shared_ptr streamCallback) { mStreamCallback = streamCallback; return this; } diff --git a/src/opensles/AudioStreamBuffered.cpp b/src/opensles/AudioStreamBuffered.cpp index 40c56ccdc..b90901f59 100644 --- a/src/opensles/AudioStreamBuffered.cpp +++ b/src/opensles/AudioStreamBuffered.cpp @@ -26,7 +26,7 @@ namespace oboe { */ AudioStreamBuffered::AudioStreamBuffered(const AudioStreamBuilder &builder) : AudioStream(builder) - , mFifoBuffer(nullptr) + , mFifoBuffer(NULL) { } @@ -39,13 +39,12 @@ Result AudioStreamBuffered::open() { // If the caller does not provide a callback use our own internal // callback that reads data from the FIFO. - if (getCallback() == nullptr) { + if (getCallback() == NULL) { LOGD("AudioStreamBuffered(): new FifoBuffer"); mFifoBuffer = new FifoBuffer(getBytesPerFrame(), 1024); // TODO size? // Create a callback that reads from the FIFO - mInternalCallback = std::make_unique(this); - mStreamCallback = mInternalCallback.get(); - LOGD("AudioStreamBuffered(): mStreamCallback = %p", mStreamCallback); + mStreamCallback = std::make_shared(this); + LOGD("AudioStreamBuffered(): mStreamCallback = %p", mStreamCallback.get()); } return Result::OK; } diff --git a/src/opensles/AudioStreamBuffered.h b/src/opensles/AudioStreamBuffered.h index c4c291448..eba16eb34 100644 --- a/src/opensles/AudioStreamBuffered.h +++ b/src/opensles/AudioStreamBuffered.h @@ -70,7 +70,6 @@ class AudioStreamBuffered : public AudioStream { private: FifoBuffer *mFifoBuffer; - std::unique_ptr mInternalCallback; }; } // namespace oboe From 85a2cd10166660419690ee345e6aa5babfb1a7e8 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 34/45] Revert "member vairable alignment" This reverts commit ac5893d0f9d415a43c996f265e9b8e0ab90b7a0d. --- include/oboe/LatencyTuner.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/oboe/LatencyTuner.h b/include/oboe/LatencyTuner.h index 7b879ba57..19c33109e 100644 --- a/include/oboe/LatencyTuner.h +++ b/include/oboe/LatencyTuner.h @@ -83,7 +83,7 @@ class LatencyTuner { // arbitrary number of calls to wait before bumping up the latency static constexpr int32_t kIdleCount = 8; - AudioStream &mStream; + AudioStream &mStream; State mState = State::Idle; int32_t mPreviousXRuns = 0; int32_t mIdleCountDown = 0; From 91ea9a86d4446a5acf247270a74a46e8aa72202e Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 35/45] Revert "Minor edits to address comments" This reverts commit 1d81d97e721843b586b7e1d8b183ef4ec0268254. --- include/oboe/Definitions.h | 1 - src/common/Utilities.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/include/oboe/Definitions.h b/include/oboe/Definitions.h index 52fe7b815..ce67c3b9a 100644 --- a/include/oboe/Definitions.h +++ b/include/oboe/Definitions.h @@ -24,7 +24,6 @@ namespace oboe { constexpr int32_t kUnspecified = 0; - // TODO: Investigate using std::chrono constexpr int64_t kNanosPerMicrosecond = 1000; constexpr int64_t kNanosPerMillisecond = kNanosPerMicrosecond * 1000; constexpr int64_t kMillisPerSecond = 1000; diff --git a/src/common/Utilities.cpp b/src/common/Utilities.cpp index aae03c3e0..e48e32a2c 100644 --- a/src/common/Utilities.cpp +++ b/src/common/Utilities.cpp @@ -61,6 +61,7 @@ int32_t convertFormatToSizeInBytes(AudioFormat format) { const char *convertResultToText(Result returnCode) { switch (returnCode) { OBOE_CASE_ENUM(Result::OK); + OBOE_CASE_ENUM(Result::ErrorBase); OBOE_CASE_ENUM(Result::ErrorDisconnected); OBOE_CASE_ENUM(Result::ErrorIllegalArgument); OBOE_CASE_ENUM(Result::ErrorInternal); From 021d18e07d7cd2e632e5ef84918563e25c956bd9 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 36/45] Revert "Rename Stream to AudioStream" This reverts commit dab3a24ddcfc949d199204c16ececd3c2ff96bee. --- CMakeLists.txt | 18 ++--- FullGuide.md | 52 ++++++------- GettingStarted.md | 16 ++-- build_all_android.sh | 4 +- include/oboe/LatencyTuner.h | 6 +- include/oboe/Oboe.h | 6 +- include/oboe/{AudioStream.h => Stream.h} | 14 ++-- .../oboe/{AudioStreamBase.h => StreamBase.h} | 16 ++-- .../{AudioStreamBuilder.h => StreamBuilder.h} | 34 ++++----- ...AudioStreamCallback.h => StreamCallback.h} | 12 +-- ...AudioStreamAAudio.cpp => StreamAAudio.cpp} | 74 +++++++++---------- .../{AudioStreamAAudio.h => StreamAAudio.h} | 16 ++-- src/common/LatencyTuner.cpp | 2 +- src/common/{AudioStream.cpp => Stream.cpp} | 30 ++++---- ...dioStreamBuilder.cpp => StreamBuilder.cpp} | 26 +++---- ...oStreamBuffered.cpp => StreamBuffered.cpp} | 30 ++++---- ...AudioStreamBuffered.h => StreamBuffered.h} | 18 ++--- ...oStreamOpenSLES.cpp => StreamOpenSLES.cpp} | 56 +++++++------- ...AudioStreamOpenSLES.h => StreamOpenSLES.h} | 10 +-- 19 files changed, 220 insertions(+), 220 deletions(-) rename include/oboe/{AudioStream.h => Stream.h} (95%) rename include/oboe/{AudioStreamBase.h => StreamBase.h} (89%) rename include/oboe/{AudioStreamBuilder.h => StreamBuilder.h} (87%) rename include/oboe/{AudioStreamCallback.h => StreamCallback.h} (87%) rename src/aaudio/{AudioStreamAAudio.cpp => StreamAAudio.cpp} (84%) rename src/aaudio/{AudioStreamAAudio.h => StreamAAudio.h} (90%) rename src/common/{AudioStream.cpp => Stream.cpp} (82%) rename src/common/{AudioStreamBuilder.cpp => StreamBuilder.cpp} (67%) rename src/opensles/{AudioStreamBuffered.cpp => StreamBuffered.cpp} (75%) rename src/opensles/{AudioStreamBuffered.h => StreamBuffered.h} (80%) rename src/opensles/{AudioStreamOpenSLES.cpp => StreamOpenSLES.cpp} (90%) rename src/opensles/{AudioStreamOpenSLES.h => StreamOpenSLES.h} (92%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 767d0164b..fcce7b09c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,25 +11,25 @@ include_directories( set (oboe_sources include/oboe/LatencyTuner.h include/oboe/Definitions.h - include/oboe/AudioStream.h - include/oboe/AudioStreamBase.h - include/oboe/AudioStreamBuilder.h - include/oboe/AudioStreamCallback.h + include/oboe/Stream.h + include/oboe/StreamBase.h + include/oboe/StreamBuilder.h + include/oboe/StreamCallback.h include/oboe/Utilities.h src/aaudio/AAudioLoader.cpp - src/aaudio/AudioStreamAAudio.cpp + src/aaudio/StreamAAudio.cpp src/common/AudioClock.h src/common/OboeDebug.h src/common/LatencyTuner.cpp - src/common/AudioStream.cpp - src/common/AudioStreamBuilder.cpp + src/common/Stream.cpp + src/common/StreamBuilder.cpp src/common/Utilities.cpp src/fifo/FifoBuffer.cpp src/fifo/FifoController.cpp src/fifo/FifoControllerBase.cpp src/fifo/FifoControllerIndirect.cpp - src/opensles/AudioStreamBuffered.cpp - src/opensles/AudioStreamOpenSLES.cpp + src/opensles/StreamBuffered.cpp + src/opensles/StreamOpenSLES.cpp src/opensles/OpenSLESUtilities.cpp ) diff --git a/FullGuide.md b/FullGuide.md index 1654abac9..fba36e439 100644 --- a/FullGuide.md +++ b/FullGuide.md @@ -3,7 +3,7 @@ Oboe is a C++ library which makes it easy to build high-performance audio apps o ## Audio streams -Oboe moves audio data between your app and the audio inputs and outputs on your Android device. Your app passes data in and out by reading from and writing to *audio streams*, represented by the class `AudioStream`. The read/write calls can be blocking or non-blocking. +Oboe moves audio data between your app and the audio inputs and outputs on your Android device. Your app passes data in and out by reading from and writing to *audio streams*, represented by the class `Stream`. The read/write calls can be blocking or non-blocking. A stream is defined by the following: @@ -59,11 +59,11 @@ Oboe might perform sample conversion on its own. For example, if an app is writi ## Creating an audio stream -The Oboe library follows a [builder design pattern](https://en.wikipedia.org/wiki/Builder_pattern) and provides the class `AudioStreamBuilder`. +The Oboe library follows a [builder design pattern](https://en.wikipedia.org/wiki/Builder_pattern) and provides the class `StreamBuilder`. - 1. Set the audio stream configuration using an AudioStreamBuilder. Use the builder functions that correspond to the stream parameters. These optional set functions are available: + 1. Set the audio stream configuration using an StreamBuilder. Use the builder functions that correspond to the stream parameters. These optional set functions are available: - AudioStreamBuilder streamBuilder; + StreamBuilder streamBuilder; streamBuilder.setDeviceId(deviceId); streamBuilder.setDirection(direction); @@ -81,7 +81,7 @@ whether Oboe will use AAudio or OpenSL ES as the audio engine for you app. Oboe will automatically select the best implementation available on your device. If you want to specifically select AAudio or OpenSL, set the APIIndex yourself. After a stream has been opened, you can verify that the API you specified was -chosen by calling `AudioStreamBuilder::getAPIIndex()`. The allowable indexes are +chosen by calling `StreamBuilder::getAPIIndex()`. The allowable indexes are `AAudio` and `OpenSLES`. If you do not specify the deviceId, the default is the primary output device. @@ -92,7 +92,7 @@ it to `kUnspecified`. To be safe, check the state of the audio stream after you create it, as explained in step 3, below. - 2. After you've configured the AudioStreamBuilder, call `openStream()` to open the stream: + 2. After you've configured the StreamBuilder, call `openStream()` to open the stream: Result result = streamBuilder.openStream(&stream_); if (result != OK){ @@ -113,7 +113,7 @@ To be safe, check the state of the audio stream after you create it, as explaine builder setting: -| AudioStreamBuilder set methods | AudioStream get methods | +| StreamBuilder set methods | Stream get methods | | :------------------------ | :----------------- | | `setDeviceId()` | `getDeviceId()` | | `setDirection()` | `getDirection()` | @@ -166,7 +166,7 @@ Though it's not shown, you can call `close()` from any state Oboe doesn't provide callbacks to alert you to state changes. One special function, -`AudioStream::waitForStateChange()` can be used to wait for a state change. +`Stream::waitForStateChange()` can be used to wait for a state change. The function does not detect a state change on its own, and does not wait for a specific state. It waits until the current state @@ -194,16 +194,16 @@ stream. You can use this same technique after calling request start, stop, or flush, using the corresponding transient state as the inputState. Do not call -`waitForStateChange()` after calling `AudioStream::close()` since the stream +`waitForStateChange()` after calling `Stream::close()` since the stream will be deleted as soon as it closes. And do not call `close()` while `waitForStateChange()` is running in another thread. ### Reading and writing to an audio stream After the stream is started you can read or write to it using the methods -`AudioStream::read(buffer, numFrames, timeoutNanos)` +`Stream::read(buffer, numFrames, timeoutNanos)` and -`AudioStream::write(buffer, numFrames, timeoutNanos)`. +`Stream::write(buffer, numFrames, timeoutNanos)`. For a blocking read or write that transfers the specified number of frames, set timeoutNanos greater than zero. For a non-blocking call, set timeoutNanos to zero. In this case the result is the actual number of frames transferred. @@ -248,7 +248,7 @@ An audio stream can become disconnected at any time if one of these events happe When a stream is disconnected, it has the state "Disconnected" and any attempts to execute write() or other functions return `OBOE_ERROR_DISCONNECTED`. 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 `AudioStreamCallback` and implements the `onError(stream, error)` +which extends `StreamCallback` and implements the `onError(stream, error)` method. Register your class using `builder.setCallback(yourCallbackClass)`. The `onError()` method should check the state of the stream as shown in the following @@ -258,7 +258,7 @@ stream it might have different characteristics than the original stream (for example framesPerBurst): ``` -void PlayAudioEngine::onError(AudioStream *audioStream, Result error) { +void PlayAudioEngine::onError(Stream *audioStream, Result error) { if (error == Result::ErrorDisconnected) { // Handle stream restart on a separate thread std::function restartStream = std::bind(&PlayAudioEngine::restartStream, this); @@ -268,7 +268,7 @@ void PlayAudioEngine::onError(AudioStream *audioStream, Result error) { } ``` -You can also implement two other callback methods in the class `AudioStreamCallback`: +You can also implement two other callback methods in the class `StreamCallback`: * `onAudioReady()` is used for a high-priority callback * `onExit()` is called when the callback thread exits. @@ -285,13 +285,13 @@ For applications that require low latency, an audio stream can use an asynchrono The callback runs in a high-priority thread that has better performance. Your code can access the callback mechanism by implementing the virtual class -`AudioStreamCallback`. The stream periodically executes `onAudioReady()` (the +`StreamCallback`. The stream periodically executes `onAudioReady()` (the callback function) to acquire the data for its next burst. - class AudioEngine : AudioStreamCallback { + class AudioEngine : StreamCallback { public: DataCallbackResult AudioEngine::onAudioReady( - AudioStream *oboeStream, + Stream *oboeStream, void *audioData, int32_t numFrames){ oscillator_->render(static_cast(audioData), numFrames); @@ -322,11 +322,11 @@ The callback does a non-blocking read from the input stream placing the data int (Note that Oboe version 1 does not support input streams, so this example cannot run.) - class AudioEngine : AudioStreamCallback { + class AudioEngine : StreamCallback { public: oboe_data_callback_result_t AudioEngine::onAudioReady( - AudioStream *oboeStream, + Stream *oboeStream, void *audioData, int32_t numFrames){ Result result = @@ -347,12 +347,12 @@ The callback does a non-blocking read from the input stream placing the data int streamBuilder.setCallback(this); } - void setRecordingStream(AudioStream *stream) { + void setRecordingStream(Stream *stream) { recordingStream = stream; } private: - AudioStream *recordingStream; + Stream *recordingStream; } @@ -360,7 +360,7 @@ Note that in this example it is assumed the input and output streams have the sa ### Setting performance mode -Every AudioStream has a *performance mode* which has a large effect on your app's behavior. There are three modes: +Every Stream has a *performance mode* which has a large effect on your app's behavior. There are three modes: * `PerformanceMode::None` is the default mode. It uses a basic stream that balances latency and power savings. * `PerformanceMode::LowLatency` uses smaller buffers and an optimized data path for reduced latency. @@ -382,12 +382,12 @@ In the current version of Oboe, in order to achieve the lowest possible latency MyOboeStreamCallback myCallback; // Create a stream builder -AudioStreamBuilder builder; +StreamBuilder builder; builder.setCallback(myCallback); builder.setPerformanceMode(PerformanceMode::LowLatency); // Use it to create the stream -AudioStream *stream; +Stream *stream; builder.openStream(&stream); ``` @@ -399,7 +399,7 @@ This is because Oboe avoids using mutexes, which can cause thread preemption and To be safe, don't call `waitForStateChange()` or read or write to the same stream from two different threads. Similarly, don't close a stream in one thread while reading or writing to it in another thread. -Calls that return stream settings, like `AudioStream::getSampleRate()` and `AudioStream::getChannelCount()`, are thread safe. +Calls that return stream settings, like `Stream::getSampleRate()` and `Stream::getChannelCount()`, are thread safe. These calls are also thread safe: @@ -409,7 +409,7 @@ These calls are also thread safe: * `convertSharingModeToText()` * `convertDataCallbackResultToText()` * `convertDirectionToText()` -* `AudioStream::get*()` except for `getTimestamp()` +* `Stream::get*()` except for `getTimestamp()` Note: When a stream uses a callback function, it's safe to read/write from the callback thread while also closing the stream diff --git a/GettingStarted.md b/GettingStarted.md index a66e6e811..df87ae672 100644 --- a/GettingStarted.md +++ b/GettingStarted.md @@ -48,9 +48,9 @@ Include the Oboe header: #include -Streams are built using an `AudioStreamBuilder`. Create one like this: +Streams are built using an `StreamBuilder`. Create one like this: - oboe::AudioStreamBuilder builder; + oboe::StreamBuilder builder; Use the builder's set methods to set properties on the stream (you can read more about these properties in the [full guide](FullGuide.md)): @@ -58,12 +58,12 @@ Use the builder's set methods to set properties on the stream (you can read more builder.setPerformanceMode(oboe::PerformanceMode::LowLatency); builder.setSharingMode(oboe::SharingMode::Exclusive); -Define an `AudioStreamCallback` class to receive callbacks whenever the stream requires new data. +Define an `StreamCallback` class to receive callbacks whenever the stream requires new data. - class MyCallback : public oboe::AudioStreamCallback { + class MyCallback : public oboe::StreamCallback { public: oboe::Result - onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames){ + onAudioReady(oboe::Stream *audioStream, void *audioData, int32_t numFrames){ generateSineWave(static_cast(audioData), numFrames); return oboe::DataCallbackResult::Continue; } @@ -76,7 +76,7 @@ Supply this callback class to the builder: Open the stream: - oboe::AudioStream *stream; + oboe::Stream *stream; oboe::Result result = builder.openStream(&stream); Check the result to make sure the stream was opened successfully. Oboe has many convenience methods for converting its types into human-readable strings, they all start with `oboe::convert`: @@ -87,10 +87,10 @@ Check the result to make sure the stream was opened successfully. Oboe has many Note that this sample code uses the [logging macros from here](https://github.com/googlesamples/android-audio-high-performance/blob/master/debug-utils/logging_macros.h). -Check the properties of the created stream. The **format** is one property which you should check. The default is `float` on API 21+ and `int16_t` on API 20 or lower. This will dictate the `audioData` type in the `AudioStreamCallback::onAudioReady` callback. +Check the properties of the created stream. The **format** is one property which you should check. The default is `float` on API 21+ and `int16_t` on API 20 or lower. This will dictate the `audioData` type in the `StreamCallback::onAudioReady` callback. oboe::AudioFormat format = stream->getFormat(); - LOGI("AudioStream format is %s", oboe::convertAudioFormatToText(format)); + LOGI("Stream format is %s", oboe::convertAudioFormatToText(format)); Now start the stream. diff --git a/build_all_android.sh b/build_all_android.sh index edbe6b7ae..4c7e886f2 100755 --- a/build_all_android.sh +++ b/build_all_android.sh @@ -121,8 +121,8 @@ build_oboe x86_64 21 printf "%s\r\n" "example: |" >> ${CDEP_MANIFEST_FILE} printf "%s\r\n" " #include " >> ${CDEP_MANIFEST_FILE} printf "%s\r\n" " void openStream() {" >> ${CDEP_MANIFEST_FILE} -printf "%s\r\n" " AudioStreamBuilder builder;" >> ${CDEP_MANIFEST_FILE} -printf "%s\r\n" " AudioStream *stream;" >> ${CDEP_MANIFEST_FILE} +printf "%s\r\n" " StreamBuilder builder;" >> ${CDEP_MANIFEST_FILE} +printf "%s\r\n" " Stream *stream;" >> ${CDEP_MANIFEST_FILE} printf "%s\r\n" " builder.openStream(&stream);" >> ${CDEP_MANIFEST_FILE} printf "%s\r\n" " }" >> ${CDEP_MANIFEST_FILE} diff --git a/include/oboe/LatencyTuner.h b/include/oboe/LatencyTuner.h index 19c33109e..e398bd9f8 100644 --- a/include/oboe/LatencyTuner.h +++ b/include/oboe/LatencyTuner.h @@ -20,7 +20,7 @@ #include #include #include "oboe/Definitions.h" -#include "oboe/AudioStream.h" +#include "oboe/Stream.h" namespace oboe { @@ -41,7 +41,7 @@ namespace oboe { */ class LatencyTuner { public: - explicit LatencyTuner(AudioStream &stream); + explicit LatencyTuner(Stream &stream); /** * Adjust the bufferSizeInFrames to optimize latency. @@ -83,7 +83,7 @@ class LatencyTuner { // arbitrary number of calls to wait before bumping up the latency static constexpr int32_t kIdleCount = 8; - AudioStream &mStream; + Stream &mStream; State mState = State::Idle; int32_t mPreviousXRuns = 0; int32_t mIdleCountDown = 0; diff --git a/include/oboe/Oboe.h b/include/oboe/Oboe.h index 34733e008..6faaef7d2 100644 --- a/include/oboe/Oboe.h +++ b/include/oboe/Oboe.h @@ -19,9 +19,9 @@ #include "oboe/Definitions.h" #include "oboe/LatencyTuner.h" -#include "oboe/AudioStream.h" -#include "oboe/AudioStreamBase.h" -#include "oboe/AudioStreamBuilder.h" +#include "oboe/Stream.h" +#include "oboe/StreamBase.h" +#include "oboe/StreamBuilder.h" #include "oboe/Utilities.h" #endif //OBOE_OBOE_H diff --git a/include/oboe/AudioStream.h b/include/oboe/Stream.h similarity index 95% rename from include/oboe/AudioStream.h rename to include/oboe/Stream.h index 94b3a5173..a974185e2 100644 --- a/include/oboe/AudioStream.h +++ b/include/oboe/Stream.h @@ -20,8 +20,8 @@ #include #include #include "oboe/Definitions.h" -#include "oboe/AudioStreamBuilder.h" -#include "oboe/AudioStreamBase.h" +#include "oboe/StreamBuilder.h" +#include "oboe/StreamBase.h" /** WARNING - UNDER CONSTRUCTION - THIS API WILL CHANGE. */ @@ -32,13 +32,13 @@ constexpr int64_t kDefaultTimeoutNanos = (2000 * kNanosPerMillisecond); /** * Base class for Oboe C++ audio stream. */ -class AudioStream : public AudioStreamBase { +class Stream : public StreamBase { public: - AudioStream() {} - explicit AudioStream(const AudioStreamBuilder &builder); + Stream() {} + explicit Stream(const StreamBuilder &builder); - virtual ~AudioStream() = default; + virtual ~Stream() = default; /** * Open a stream based on the current settings. @@ -144,7 +144,7 @@ class AudioStream : public AudioStreamBase { bool isPlaying(); - std::shared_ptr getCallback() const { return mStreamCallback; } + std::shared_ptr getCallback() const { return mStreamCallback; } int32_t getBytesPerFrame() const { return mChannelCount * getBytesPerSample(); } diff --git a/include/oboe/AudioStreamBase.h b/include/oboe/StreamBase.h similarity index 89% rename from include/oboe/AudioStreamBase.h rename to include/oboe/StreamBase.h index 10d90217a..e4c46b468 100644 --- a/include/oboe/AudioStreamBase.h +++ b/include/oboe/StreamBase.h @@ -18,7 +18,7 @@ #define OBOE_STREAM_BASE_H_ #include -#include "oboe/AudioStreamCallback.h" +#include "oboe/StreamCallback.h" #include "oboe/Definitions.h" namespace oboe { @@ -31,17 +31,17 @@ namespace oboe { * OboeStream will generally return the actual final value, but getFramesPerCallback() * can be unspecified even for a stream. */ -class AudioStreamBase { +class StreamBase { public: - AudioStreamBase() {} + StreamBase() {} - virtual ~AudioStreamBase() = default; + virtual ~StreamBase() = default; // This class only contains primitives so we can use default constructor and copy methods. - AudioStreamBase(const AudioStreamBase&) = default; + StreamBase(const StreamBase&) = default; - AudioStreamBase& operator=(const AudioStreamBase&) = default; + StreamBase& operator=(const StreamBase&) = default; /** * @return number of channels, for example 2 for stereo @@ -90,12 +90,12 @@ class AudioStreamBase { int32_t getDeviceId() const { return mDeviceId; } - std::shared_ptr getCallback() const { + std::shared_ptr getCallback() const { return mStreamCallback; } protected: - std::shared_ptr mStreamCallback; + std::shared_ptr mStreamCallback; int32_t mFramesPerCallback = kUnspecified; int32_t mChannelCount = kUnspecified; int32_t mSampleRate = kUnspecified; diff --git a/include/oboe/AudioStreamBuilder.h b/include/oboe/StreamBuilder.h similarity index 87% rename from include/oboe/AudioStreamBuilder.h rename to include/oboe/StreamBuilder.h index 4c81064ec..93a8b6902 100644 --- a/include/oboe/AudioStreamBuilder.h +++ b/include/oboe/StreamBuilder.h @@ -18,7 +18,7 @@ #define OBOE_STREAM_BUILDER_H_ #include "oboe/Definitions.h" -#include "oboe/AudioStreamBase.h" +#include "oboe/StreamBase.h" namespace oboe { @@ -27,10 +27,10 @@ constexpr int32_t kDefaultFramesPerBurst = 192; // arbitrary value, 4 msec at 48 /** * Factory class for an audio Stream. */ -class AudioStreamBuilder : public AudioStreamBase { +class StreamBuilder : public StreamBase { public: - AudioStreamBuilder() : AudioStreamBase() {} + StreamBuilder() : StreamBase() {} enum class AudioApi { /** @@ -56,7 +56,7 @@ class AudioStreamBuilder : public AudioStreamBase { * Default is kUnspecified. If the value is unspecified then * the application should query for the actual value after the stream is opened. */ - AudioStreamBuilder *setChannelCount(int channelCount) { + StreamBuilder *setChannelCount(int channelCount) { mChannelCount = channelCount; return this; } @@ -66,7 +66,7 @@ class AudioStreamBuilder : public AudioStreamBase { * * @param direction Direction::Output or Direction::Input */ - AudioStreamBuilder *setDirection(Direction direction) { + StreamBuilder *setDirection(Direction direction) { mDirection = direction; return this; } @@ -82,7 +82,7 @@ class AudioStreamBuilder : public AudioStreamBase { * But it is traditionally called "sample rate". Se we use that term. * */ - AudioStreamBuilder *setSampleRate(int32_t sampleRate) { + StreamBuilder *setSampleRate(int32_t sampleRate) { mSampleRate = sampleRate; return this; } @@ -101,7 +101,7 @@ class AudioStreamBuilder : public AudioStreamBase { * @param framesPerCallback * @return */ - AudioStreamBuilder *setFramesPerCallback(int framesPerCallback) { + StreamBuilder *setFramesPerCallback(int framesPerCallback) { mFramesPerCallback = framesPerCallback; return this; } @@ -112,7 +112,7 @@ class AudioStreamBuilder : public AudioStreamBase { * Default is Format::Unspecified. If the value is unspecified then * the application should query for the actual value after the stream is opened. */ - AudioStreamBuilder *setFormat(AudioFormat format) { + StreamBuilder *setFormat(AudioFormat format) { mFormat = format; return this; } @@ -126,7 +126,7 @@ class AudioStreamBuilder : public AudioStreamBase { * @param frames the desired buffer capacity in frames or kUnspecified * @return pointer to the builder so calls can be chained */ - AudioStreamBuilder *setBufferCapacityInFrames(int32_t bufferCapacityInFrames) { + StreamBuilder *setBufferCapacityInFrames(int32_t bufferCapacityInFrames) { mBufferCapacityInFrames = bufferCapacityInFrames; return this; } @@ -139,7 +139,7 @@ class AudioStreamBuilder : public AudioStreamBase { * @param Must be AudioApi::Unspecified, AudioApi::OpenSLES or AudioApi::AAudio. * @return pointer to the builder so calls can be chained */ - AudioStreamBuilder *setApiIndex(AudioApi apiIndex) { + StreamBuilder *setApiIndex(AudioApi apiIndex) { mAudioApi = apiIndex; return this; } @@ -161,7 +161,7 @@ class AudioStreamBuilder : public AudioStreamBase { * @param sharingMode SharingMode::Shared or SharingMode::Exclusive * @return pointer to the builder so calls can be chained */ - AudioStreamBuilder *setSharingMode(SharingMode sharingMode) { + StreamBuilder *setSharingMode(SharingMode sharingMode) { mSharingMode = sharingMode; return this; } @@ -174,7 +174,7 @@ class AudioStreamBuilder : public AudioStreamBase { * @param performanceMode for example, PerformanceMode::LowLatency * @return pointer to the builder so calls can be chained */ - AudioStreamBuilder *setPerformanceMode(PerformanceMode performanceMode) { + StreamBuilder *setPerformanceMode(PerformanceMode performanceMode) { mPerformanceMode = performanceMode; return this; } @@ -188,7 +188,7 @@ class AudioStreamBuilder : public AudioStreamBase { * @param deviceId device identifier or kUnspecified * @return pointer to the builder so calls can be chained */ - AudioStreamBuilder *setDeviceId(int32_t deviceId) { + StreamBuilder *setDeviceId(int32_t deviceId) { mDeviceId = deviceId; return this; } @@ -202,7 +202,7 @@ class AudioStreamBuilder : public AudioStreamBase { * @param streamCallback * @return */ - AudioStreamBuilder *setCallback(std::shared_ptr streamCallback) { + StreamBuilder *setCallback(std::shared_ptr streamCallback) { mStreamCallback = streamCallback; return this; } @@ -225,7 +225,7 @@ class AudioStreamBuilder : public AudioStreamBase { * @param defaultFramesPerBurst * @return pointer to the builder so calls can be chained */ - AudioStreamBuilder *setDefaultFramesPerBurst(int32_t defaultFramesPerBurst) { + StreamBuilder *setDefaultFramesPerBurst(int32_t defaultFramesPerBurst) { mDefaultFramesPerBurst = defaultFramesPerBurst; return this; } @@ -240,7 +240,7 @@ class AudioStreamBuilder : public AudioStreamBase { * @param stream pointer to a variable to receive the stream address * @return OBOE_OK if successful or a negative error code */ - Result openStream(AudioStream **stream); + Result openStream(Stream **stream); protected: @@ -251,7 +251,7 @@ class AudioStreamBuilder : public AudioStreamBase { * * @return pointer to an AudioStream object. */ - oboe::AudioStream *build(); + oboe::Stream *build(); AudioApi mAudioApi = AudioApi::Unspecified; diff --git a/include/oboe/AudioStreamCallback.h b/include/oboe/StreamCallback.h similarity index 87% rename from include/oboe/AudioStreamCallback.h rename to include/oboe/StreamCallback.h index 9a5db1763..cdbb16613 100644 --- a/include/oboe/AudioStreamCallback.h +++ b/include/oboe/StreamCallback.h @@ -21,11 +21,11 @@ namespace oboe { -class AudioStream; +class Stream; -class AudioStreamCallback { +class StreamCallback { public: - virtual ~AudioStreamCallback() = default; + virtual ~StreamCallback() = default; /** * A buffer is ready for processing. @@ -36,7 +36,7 @@ class AudioStreamCallback { * @return DataCallbackResult::Continue or DataCallbackResult::Stop */ virtual DataCallbackResult onAudioReady( - AudioStream *oboeStream, + Stream *oboeStream, void *audioData, int32_t numFrames) = 0; @@ -48,7 +48,7 @@ class AudioStreamCallback { * @param oboeStream pointer to the associated stream * @param error */ - virtual void onErrorBeforeClose(AudioStream *oboeStream, Result error) {} + virtual void onErrorBeforeClose(Stream *oboeStream, Result error) {} /** * This will be called when an error occurs on a stream or when the stream is disconnected. @@ -60,7 +60,7 @@ class AudioStreamCallback { * @param oboeStream pointer to the associated stream * @param error */ - virtual void onErrorAfterClose(AudioStream *oboeStream, Result error) {} + virtual void onErrorAfterClose(Stream *oboeStream, Result error) {} }; diff --git a/src/aaudio/AudioStreamAAudio.cpp b/src/aaudio/StreamAAudio.cpp similarity index 84% rename from src/aaudio/AudioStreamAAudio.cpp rename to src/aaudio/StreamAAudio.cpp index a256ef1c4..7689d333b 100644 --- a/src/aaudio/AudioStreamAAudio.cpp +++ b/src/aaudio/StreamAAudio.cpp @@ -18,14 +18,14 @@ #include #include "aaudio/AAudioLoader.h" -#include "aaudio/AudioStreamAAudio.h" +#include "aaudio/StreamAAudio.h" #include "common/OboeDebug.h" #include "oboe/Utilities.h" using namespace oboe; -AAudioLoader *AudioStreamAAudio::mLibLoader = nullptr; +AAudioLoader *StreamAAudio::mLibLoader = nullptr; // 'C' wrapper for the data callback method @@ -35,7 +35,7 @@ static aaudio_data_callback_result_t oboe_aaudio_data_callback_proc( void *audioData, int32_t numFrames) { - AudioStreamAAudio *oboeStream = (AudioStreamAAudio *)userData; + StreamAAudio *oboeStream = (StreamAAudio *)userData; if (oboeStream != NULL) { return static_cast( oboeStream->callOnAudioReady(stream, audioData, numFrames)); @@ -44,7 +44,7 @@ static aaudio_data_callback_result_t oboe_aaudio_data_callback_proc( } } -static void oboe_aaudio_error_thread_proc(AudioStreamAAudio *oboeStream, +static void oboe_aaudio_error_thread_proc(StreamAAudio *oboeStream, AAudioStream *stream, Result error) { if (oboeStream != NULL) { @@ -58,7 +58,7 @@ static void oboe_aaudio_error_callback_proc( void *userData, aaudio_result_t error) { - AudioStreamAAudio *oboeStream = (AudioStreamAAudio *)userData; + StreamAAudio *oboeStream = (StreamAAudio *)userData; if (oboeStream != NULL) { // Handle error on a separate thread std::thread t(oboe_aaudio_error_thread_proc, oboeStream, stream, static_cast(error)); @@ -72,50 +72,50 @@ namespace oboe { /* * Create a stream that uses Oboe Audio API. */ -AudioStreamAAudio::AudioStreamAAudio(const AudioStreamBuilder &builder) - : AudioStream(builder) +StreamAAudio::StreamAAudio(const StreamBuilder &builder) + : Stream(builder) , mFloatCallbackBuffer(nullptr) , mShortCallbackBuffer(nullptr) , mAAudioStream(nullptr) { mCallbackThreadEnabled.store(false); - LOGD("AudioStreamAAudio() call isSupported()"); + LOGD("StreamAAudio() call isSupported()"); isSupported(); } -AudioStreamAAudio::~AudioStreamAAudio() +StreamAAudio::~StreamAAudio() { delete[] mFloatCallbackBuffer; delete[] mShortCallbackBuffer; } -bool AudioStreamAAudio::isSupported() { +bool StreamAAudio::isSupported() { mLibLoader = AAudioLoader::getInstance(); int openResult = mLibLoader->open(); return openResult == 0; } -Result AudioStreamAAudio::open() { +Result StreamAAudio::open() { Result result = Result::OK; if (mAAudioStream != nullptr) { return Result::ErrorInvalidState; } - result = AudioStream::open(); + result = Stream::open(); if (result != Result::OK) { return result; } - LOGD("AudioStreamAAudio(): AAudio_createStreamBuilder()"); + LOGD("StreamAAudio(): AAudio_createStreamBuilder()"); AAudioStreamBuilder *aaudioBuilder; result = static_cast(mLibLoader->createStreamBuilder(&aaudioBuilder)); if (result != Result::OK) { return result; } - LOGD("AudioStreamAAudio.open() try with deviceId = %d", (int) mDeviceId); + LOGD("StreamAAudio.open() try with deviceId = %d", (int) mDeviceId); mLibLoader->builder_setBufferCapacityInFrames(aaudioBuilder, mBufferCapacityInFrames); mLibLoader->builder_setChannelCount(aaudioBuilder, mChannelCount); mLibLoader->builder_setDeviceId(aaudioBuilder, mDeviceId); @@ -157,20 +157,20 @@ Result AudioStreamAAudio::open() { mLibLoader->stream_getPerformanceMode(mAAudioStream)); mBufferCapacityInFrames = mLibLoader->stream_getBufferCapacity(mAAudioStream); - LOGD("AudioStreamAAudio.open() app format = %d", (int) mFormat); - LOGD("AudioStreamAAudio.open() native format = %d", (int) mNativeFormat); - LOGD("AudioStreamAAudio.open() sample rate = %d", (int) mSampleRate); - LOGD("AudioStreamAAudio.open() capacity = %d", (int) mBufferCapacityInFrames); + LOGD("StreamAAudio.open() app format = %d", (int) mFormat); + LOGD("StreamAAudio.open() native format = %d", (int) mNativeFormat); + LOGD("StreamAAudio.open() sample rate = %d", (int) mSampleRate); + LOGD("StreamAAudio.open() capacity = %d", (int) mBufferCapacityInFrames); error2: mLibLoader->builder_delete(aaudioBuilder); - LOGD("AudioStreamAAudio.open: AAudioStream_Open() returned %s, mAAudioStream = %p", + LOGD("StreamAAudio.open: AAudioStream_Open() returned %s, mAAudioStream = %p", mLibLoader->convertResultToText(static_cast(result)), mAAudioStream.load()); return result; } -Result AudioStreamAAudio::close() +Result StreamAAudio::close() { // The main reason we have this mutex if to prevent a collision between a call // by the application to stop a stream at the same time that an onError callback @@ -186,7 +186,7 @@ Result AudioStreamAAudio::close() return result; } -DataCallbackResult AudioStreamAAudio::callOnAudioReady(AAudioStream *stream, +DataCallbackResult StreamAAudio::callOnAudioReady(AAudioStream *stream, void *audioData, int32_t numFrames) { return mStreamCallback->onAudioReady( @@ -195,7 +195,7 @@ DataCallbackResult AudioStreamAAudio::callOnAudioReady(AAudioStream *stream, numFrames); } -void AudioStreamAAudio::onErrorInThread(AAudioStream *stream, Result error) { +void StreamAAudio::onErrorInThread(AAudioStream *stream, Result error) { LOGD("onErrorInThread() - entering ==================================="); assert(stream == mAAudioStream.load()); requestStop(); @@ -209,7 +209,7 @@ void AudioStreamAAudio::onErrorInThread(AAudioStream *stream, Result error) { LOGD("onErrorInThread() - exiting ==================================="); } -Result AudioStreamAAudio::convertApplicationDataToNative(int32_t numFrames) { +Result StreamAAudio::convertApplicationDataToNative(int32_t numFrames) { Result result = Result::ErrorUnimplemented; int32_t numSamples = numFrames * getChannelCount(); if (mFormat == AudioFormat::Float) { @@ -226,7 +226,7 @@ Result AudioStreamAAudio::convertApplicationDataToNative(int32_t numFrames) { return result; } -Result AudioStreamAAudio::requestStart() +Result StreamAAudio::requestStart() { std::lock_guard lock(mLock); AAudioStream *stream = mAAudioStream.load(); @@ -237,7 +237,7 @@ Result AudioStreamAAudio::requestStart() } } -Result AudioStreamAAudio::requestPause() +Result StreamAAudio::requestPause() { std::lock_guard lock(mLock); AAudioStream *stream = mAAudioStream.load(); @@ -248,7 +248,7 @@ Result AudioStreamAAudio::requestPause() } } -Result AudioStreamAAudio::requestFlush() { +Result StreamAAudio::requestFlush() { std::lock_guard lock(mLock); AAudioStream *stream = mAAudioStream.load(); if (stream != nullptr) { @@ -258,7 +258,7 @@ Result AudioStreamAAudio::requestFlush() { } } -Result AudioStreamAAudio::requestStop() +Result StreamAAudio::requestStop() { std::lock_guard lock(mLock); AAudioStream *stream = mAAudioStream.load(); @@ -270,7 +270,7 @@ Result AudioStreamAAudio::requestStop() } // TODO: Update to return tuple of Result and framesWritten (avoids cast) -int32_t AudioStreamAAudio::write(const void *buffer, +int32_t StreamAAudio::write(const void *buffer, int32_t numFrames, int64_t timeoutNanoseconds) { @@ -282,7 +282,7 @@ int32_t AudioStreamAAudio::write(const void *buffer, } } -Result AudioStreamAAudio::waitForStateChange(StreamState currentState, +Result StreamAAudio::waitForStateChange(StreamState currentState, StreamState *nextState, int64_t timeoutNanoseconds) { @@ -302,7 +302,7 @@ Result AudioStreamAAudio::waitForStateChange(StreamState currentState, } } -Result AudioStreamAAudio::setBufferSizeInFrames(int32_t requestedFrames) +Result StreamAAudio::setBufferSizeInFrames(int32_t requestedFrames) { if (requestedFrames > mBufferCapacityInFrames) { requestedFrames = mBufferCapacityInFrames; @@ -310,7 +310,7 @@ Result AudioStreamAAudio::setBufferSizeInFrames(int32_t requestedFrames) return static_cast(mLibLoader->stream_setBufferSize(mAAudioStream, requestedFrames)); } -StreamState AudioStreamAAudio::getState() +StreamState StreamAAudio::getState() { AAudioStream *stream = mAAudioStream.load(); if (stream != nullptr) { @@ -320,7 +320,7 @@ StreamState AudioStreamAAudio::getState() } } -int32_t AudioStreamAAudio::getBufferSizeInFrames() const { +int32_t StreamAAudio::getBufferSizeInFrames() const { AAudioStream *stream = mAAudioStream.load(); if (stream != nullptr) { return mLibLoader->stream_getBufferSize(stream); @@ -329,7 +329,7 @@ int32_t AudioStreamAAudio::getBufferSizeInFrames() const { } } -int32_t AudioStreamAAudio::getFramesPerBurst() +int32_t StreamAAudio::getFramesPerBurst() { AAudioStream *stream = mAAudioStream.load(); if (stream != nullptr) { @@ -339,7 +339,7 @@ int32_t AudioStreamAAudio::getFramesPerBurst() } } -int64_t AudioStreamAAudio::getFramesRead() +int64_t StreamAAudio::getFramesRead() { AAudioStream *stream = mAAudioStream.load(); if (stream != nullptr) { @@ -348,7 +348,7 @@ int64_t AudioStreamAAudio::getFramesRead() return static_cast(Result::ErrorNull); } } -int64_t AudioStreamAAudio::getFramesWritten() +int64_t StreamAAudio::getFramesWritten() { AAudioStream *stream = mAAudioStream.load(); if (stream != nullptr) { @@ -358,7 +358,7 @@ int64_t AudioStreamAAudio::getFramesWritten() } } -int32_t AudioStreamAAudio::getXRunCount() +int32_t StreamAAudio::getXRunCount() { AAudioStream *stream = mAAudioStream.load(); if (stream != nullptr) { @@ -368,7 +368,7 @@ int32_t AudioStreamAAudio::getXRunCount() } } -Result AudioStreamAAudio::getTimestamp(clockid_t clockId, +Result StreamAAudio::getTimestamp(clockid_t clockId, int64_t *framePosition, int64_t *timeNanoseconds) { AAudioStream *stream = mAAudioStream.load(); diff --git a/src/aaudio/AudioStreamAAudio.h b/src/aaudio/StreamAAudio.h similarity index 90% rename from src/aaudio/AudioStreamAAudio.h rename to src/aaudio/StreamAAudio.h index 9c5c40658..36dbeaaa3 100644 --- a/src/aaudio/AudioStreamAAudio.h +++ b/src/aaudio/StreamAAudio.h @@ -23,8 +23,8 @@ #include "aaudio/AAudio.h" -#include "oboe/AudioStreamBuilder.h" -#include "oboe/AudioStream.h" +#include "oboe/StreamBuilder.h" +#include "oboe/Stream.h" #include "oboe/Definitions.h" namespace oboe { @@ -37,12 +37,12 @@ class AAudioLoader; * Do not create this class directly. * Use an OboeStreamBuilder to create one. */ -class AudioStreamAAudio : public AudioStream { +class StreamAAudio : public Stream { public: - AudioStreamAAudio(); - explicit AudioStreamAAudio(const AudioStreamBuilder &builder); + StreamAAudio(); + explicit StreamAAudio(const StreamBuilder &builder); - ~AudioStreamAAudio(); + ~StreamAAudio(); /** * @@ -50,8 +50,8 @@ class AudioStreamAAudio : public AudioStream { */ static bool isSupported(); - // These functions override methods in AudioStream. - // See AudioStream for documentation. + // These functions override methods in Stream. + // See Stream for documentation. Result open() override; Result close() override; diff --git a/src/common/LatencyTuner.cpp b/src/common/LatencyTuner.cpp index b28ef667c..b6247d9b0 100644 --- a/src/common/LatencyTuner.cpp +++ b/src/common/LatencyTuner.cpp @@ -18,7 +18,7 @@ using namespace oboe; -LatencyTuner::LatencyTuner(AudioStream &stream) +LatencyTuner::LatencyTuner(Stream &stream) : mStream(stream) { reset(); } diff --git a/src/common/AudioStream.cpp b/src/common/Stream.cpp similarity index 82% rename from src/common/AudioStream.cpp rename to src/common/Stream.cpp index 9ece16682..26e593505 100644 --- a/src/common/AudioStream.cpp +++ b/src/common/Stream.cpp @@ -16,36 +16,36 @@ #include #include -#include +#include #include "OboeDebug.h" #include namespace oboe { /* - * AudioStream + * Stream */ -AudioStream::AudioStream(const AudioStreamBuilder &builder) - : AudioStreamBase(builder) { +Stream::Stream(const StreamBuilder &builder) + : StreamBase(builder) { } -Result AudioStream::open() { +Result Stream::open() { // TODO validate parameters or let underlyng API validate them? return Result::OK; } -Result AudioStream::fireCallback(void *audioData, int32_t numFrames) +Result Stream::fireCallback(void *audioData, int32_t numFrames) { int scheduler = sched_getscheduler(0) & ~SCHED_RESET_ON_FORK; // for current thread if (scheduler != mPreviousScheduler) { - LOGD("AudioStream::fireCallback() scheduler = %s", + LOGD("Stream::fireCallback() scheduler = %s", ((scheduler == SCHED_FIFO) ? "SCHED_FIFO" : ((scheduler == SCHED_OTHER) ? "SCHED_OTHER" : ((scheduler == SCHED_RR) ? "SCHED_RR" : "UNKNOWN"))) ); mPreviousScheduler = scheduler; } - if (mStreamCallback == nullptr) { + if (mStreamCallback == NULL) { return Result::ErrorNull; } else { /** @@ -62,7 +62,7 @@ Result AudioStream::fireCallback(void *audioData, int32_t numFrames) } } -Result AudioStream::waitForStateTransition(StreamState startingState, +Result Stream::waitForStateTransition(StreamState startingState, StreamState endingState, int64_t timeoutNanoseconds) { @@ -81,7 +81,7 @@ Result AudioStream::waitForStateTransition(StreamState startingState, } } -Result AudioStream::start(int64_t timeoutNanoseconds) +Result Stream::start(int64_t timeoutNanoseconds) { Result result = requestStart(); if (result != Result::OK) return result; @@ -89,7 +89,7 @@ Result AudioStream::start(int64_t timeoutNanoseconds) StreamState::Started, timeoutNanoseconds); } -Result AudioStream::pause(int64_t timeoutNanoseconds) +Result Stream::pause(int64_t timeoutNanoseconds) { Result result = requestPause(); if (result != Result::OK) return result; @@ -97,7 +97,7 @@ Result AudioStream::pause(int64_t timeoutNanoseconds) StreamState::Paused, timeoutNanoseconds); } -Result AudioStream::flush(int64_t timeoutNanoseconds) +Result Stream::flush(int64_t timeoutNanoseconds) { Result result = requestFlush(); if (result != Result::OK) return result; @@ -105,7 +105,7 @@ Result AudioStream::flush(int64_t timeoutNanoseconds) StreamState::Flushed, timeoutNanoseconds); } -Result AudioStream::stop(int64_t timeoutNanoseconds) +Result Stream::stop(int64_t timeoutNanoseconds) { Result result = requestStop(); if (result != Result::OK) return result; @@ -113,12 +113,12 @@ Result AudioStream::stop(int64_t timeoutNanoseconds) StreamState::Stopped, timeoutNanoseconds); } -bool AudioStream::isPlaying() { +bool Stream::isPlaying() { StreamState state = getState(); return state == StreamState::Starting || state == StreamState::Started; } -int32_t AudioStream::getBytesPerSample() const { +int32_t Stream::getBytesPerSample() const { return convertFormatToSizeInBytes(mFormat); } diff --git a/src/common/AudioStreamBuilder.cpp b/src/common/StreamBuilder.cpp similarity index 67% rename from src/common/AudioStreamBuilder.cpp rename to src/common/StreamBuilder.cpp index 6d92391b1..f3da91536 100644 --- a/src/common/AudioStreamBuilder.cpp +++ b/src/common/StreamBuilder.cpp @@ -16,43 +16,43 @@ #include -#include "aaudio/AudioStreamAAudio.h" +#include "aaudio/StreamAAudio.h" #include "OboeDebug.h" #include "oboe/Oboe.h" -#include "oboe/AudioStreamBuilder.h" -#include "opensles/AudioStreamOpenSLES.h" +#include "oboe/StreamBuilder.h" +#include "opensles/StreamOpenSLES.h" namespace oboe { -bool AudioStreamBuilder::isAAudioSupported() { - return AudioStreamAAudio::isSupported(); +bool StreamBuilder::isAAudioSupported() { + return StreamAAudio::isSupported(); } -AudioStream *AudioStreamBuilder::build() { - LOGD("AudioStreamBuilder.build(): mAudioApi %d, mChannelCount = %d, mFramesPerCallback = %d", +Stream *StreamBuilder::build() { + LOGD("StreamBuilder.build(): mAudioApi %d, mChannelCount = %d, mFramesPerCallback = %d", mAudioApi, mChannelCount, mFramesPerCallback); - AudioStream *stream = nullptr; + Stream *stream = nullptr; switch(mAudioApi) { case AudioApi::Unspecified: case AudioApi::AAudio: - if (AudioStreamAAudio::isSupported()) { - stream = new AudioStreamAAudio(*this); + if (StreamAAudio::isSupported()) { + stream = new StreamAAudio(*this); break; } // fall into using older existing API case AudioApi::OpenSLES: - stream = new AudioStreamOpenSLES(*this); + stream = new StreamOpenSLES(*this); break; } return stream; } -Result AudioStreamBuilder::openStream(AudioStream **streamPP) { +Result StreamBuilder::openStream(Stream **streamPP) { if (streamPP == nullptr) { return Result::ErrorNull; } *streamPP = nullptr; - AudioStream *streamP = build(); + Stream *streamP = build(); if (streamP == nullptr) { return Result::ErrorNull; } diff --git a/src/opensles/AudioStreamBuffered.cpp b/src/opensles/StreamBuffered.cpp similarity index 75% rename from src/opensles/AudioStreamBuffered.cpp rename to src/opensles/StreamBuffered.cpp index b90901f59..5b4af19cf 100644 --- a/src/opensles/AudioStreamBuffered.cpp +++ b/src/opensles/StreamBuffered.cpp @@ -16,23 +16,23 @@ #include "oboe/Oboe.h" -#include "opensles/AudioStreamBuffered.h" +#include "opensles/StreamBuffered.h" #include "common/AudioClock.h" namespace oboe { /* - * AudioStream with a FifoBuffer + * Stream with a FifoBuffer */ -AudioStreamBuffered::AudioStreamBuffered(const AudioStreamBuilder &builder) - : AudioStream(builder) +StreamBuffered::StreamBuffered(const StreamBuilder &builder) + : Stream(builder) , mFifoBuffer(NULL) { } -Result AudioStreamBuffered::open() { +Result StreamBuffered::open() { - Result result = AudioStream::open(); + Result result = Stream::open(); if (result != Result::OK) { return result; } @@ -40,17 +40,17 @@ Result AudioStreamBuffered::open() { // If the caller does not provide a callback use our own internal // callback that reads data from the FIFO. if (getCallback() == NULL) { - LOGD("AudioStreamBuffered(): new FifoBuffer"); + LOGD("StreamBuffered(): new FifoBuffer"); mFifoBuffer = new FifoBuffer(getBytesPerFrame(), 1024); // TODO size? // Create a callback that reads from the FIFO mStreamCallback = std::make_shared(this); - LOGD("AudioStreamBuffered(): mStreamCallback = %p", mStreamCallback.get()); + LOGD("StreamBuffered(): mStreamCallback = %p", mStreamCallback.get()); } return Result::OK; } // TODO: This method should return a tuple of Result,int32_t where the 2nd return param is the frames written -int32_t AudioStreamBuffered::write(const void *buffer, +int32_t StreamBuffered::write(const void *buffer, int32_t numFrames, int64_t timeoutNanoseconds) { @@ -59,7 +59,7 @@ int32_t AudioStreamBuffered::write(const void *buffer, int32_t framesLeft = numFrames; while(framesLeft > 0 && result >= 0) { result = mFifoBuffer->write(source, numFrames); - LOGD("AudioStreamBuffered::writeNow(): wrote %d/%d frames", result, numFrames); + LOGD("StreamBuffered::writeNow(): wrote %d/%d frames", result, numFrames); if (result > 0) { source += mFifoBuffer->convertFramesToBytes(result); incrementFramesWritten(result); @@ -74,7 +74,7 @@ int32_t AudioStreamBuffered::write(const void *buffer, return result; } -Result AudioStreamBuffered::setBufferSizeInFrames(int32_t requestedFrames) +Result StreamBuffered::setBufferSizeInFrames(int32_t requestedFrames) { if (mFifoBuffer != nullptr) { if (requestedFrames > mFifoBuffer->getBufferCapacityInFrames()) { @@ -88,19 +88,19 @@ Result AudioStreamBuffered::setBufferSizeInFrames(int32_t requestedFrames) } -int32_t AudioStreamBuffered::getBufferSizeInFrames() const { +int32_t StreamBuffered::getBufferSizeInFrames() const { if (mFifoBuffer != nullptr) { return mFifoBuffer->getThresholdFrames(); } else { - return AudioStream::getBufferSizeInFrames(); + return Stream::getBufferSizeInFrames(); } } -int32_t AudioStreamBuffered::getBufferCapacityInFrames() const { +int32_t StreamBuffered::getBufferCapacityInFrames() const { if (mFifoBuffer != nullptr) { return mFifoBuffer->getBufferCapacityInFrames(); // Maybe set mBufferCapacity in constructor } else { - return AudioStream::getBufferCapacityInFrames(); + return Stream::getBufferCapacityInFrames(); } } diff --git a/src/opensles/AudioStreamBuffered.h b/src/opensles/StreamBuffered.h similarity index 80% rename from src/opensles/AudioStreamBuffered.h rename to src/opensles/StreamBuffered.h index eba16eb34..577a639f2 100644 --- a/src/opensles/AudioStreamBuffered.h +++ b/src/opensles/StreamBuffered.h @@ -18,18 +18,18 @@ #define OBOE_STREAM_BUFFERED_H #include "common/OboeDebug.h" -#include "oboe/AudioStream.h" -#include "oboe/AudioStreamCallback.h" +#include "oboe/Stream.h" +#include "oboe/StreamCallback.h" #include "fifo/FifoBuffer.h" namespace oboe { // A stream that contains a FIFO buffer. -class AudioStreamBuffered : public AudioStream { +class StreamBuffered : public Stream { public: - AudioStreamBuffered(); - explicit AudioStreamBuffered(const AudioStreamBuilder &builder); + StreamBuffered(); + explicit StreamBuffered(const StreamBuilder &builder); Result open() override; @@ -45,16 +45,16 @@ class AudioStreamBuffered : public AudioStream { protected: - class AudioStreamBufferedCallback : public AudioStreamCallback { + class AudioStreamBufferedCallback : public StreamCallback { public: - AudioStreamBufferedCallback(AudioStreamBuffered *bufferedStream) + AudioStreamBufferedCallback(StreamBuffered *bufferedStream) : mBufferedStream(bufferedStream) { } virtual ~AudioStreamBufferedCallback() {} virtual DataCallbackResult onAudioReady( - AudioStream *audioStream, + Stream *audioStream, void *audioData, int numFrames) { int32_t framesRead = mBufferedStream->mFifoBuffer->readNow(audioData, numFrames); @@ -64,7 +64,7 @@ class AudioStreamBuffered : public AudioStream { virtual void onExit(Result reason) {} private: - AudioStreamBuffered *mBufferedStream; + StreamBuffered *mBufferedStream; }; private: diff --git a/src/opensles/AudioStreamOpenSLES.cpp b/src/opensles/StreamOpenSLES.cpp similarity index 90% rename from src/opensles/AudioStreamOpenSLES.cpp rename to src/opensles/StreamOpenSLES.cpp index dfb9f8493..75a954d48 100644 --- a/src/opensles/AudioStreamOpenSLES.cpp +++ b/src/opensles/StreamOpenSLES.cpp @@ -21,8 +21,8 @@ #include #include "common/OboeDebug.h" -#include "oboe/AudioStreamBuilder.h" -#include "AudioStreamOpenSLES.h" +#include "oboe/StreamBuilder.h" +#include "StreamOpenSLES.h" #include "OpenSLESUtilities.h" #ifndef NULL @@ -114,7 +114,7 @@ static SLObjectItf sOutputMixObject = 0; static void CloseSLEngine(); -SLresult AudioStreamOpenSLES::enqueueBuffer() { +SLresult StreamOpenSLES::enqueueBuffer() { // Ask the callback to fill the output buffer with data. Result result = fireCallback(mCallbackBuffer, mFramesPerCallback); if (result != Result::OK) { @@ -128,7 +128,7 @@ SLresult AudioStreamOpenSLES::enqueueBuffer() { // this callback handler is called every time a buffer finishes playing static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { - ((AudioStreamOpenSLES *) context)->enqueueBuffer(); + ((StreamOpenSLES *) context)->enqueueBuffer(); } static SLresult OpenSLEngine() { @@ -200,17 +200,17 @@ static void CloseSLEngine() { } } -AudioStreamOpenSLES::AudioStreamOpenSLES(const AudioStreamBuilder &builder) - : AudioStreamBuffered(builder) { +StreamOpenSLES::StreamOpenSLES(const StreamBuilder &builder) + : StreamBuffered(builder) { bqPlayerObject_ = NULL; bq_ = NULL; bqPlayerPlay_ = NULL; mFramesPerBurst = builder.getDefaultFramesPerBurst(); OpenSLEngine(); - LOGD("AudioStreamOpenSLES(): after OpenSLEngine()"); + LOGD("StreamOpenSLES(): after OpenSLEngine()"); } -AudioStreamOpenSLES::~AudioStreamOpenSLES() { +StreamOpenSLES::~StreamOpenSLES() { CloseSLEngine(); delete[] mCallbackBuffer; } @@ -236,7 +236,7 @@ static SLuint32 s_getDefaultByteOrder() { return s_isLittleEndian() ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; } -Result AudioStreamOpenSLES::open() { +Result StreamOpenSLES::open() { SLresult result; @@ -256,7 +256,7 @@ Result AudioStreamOpenSLES::open() { AudioFormat::I16 : AudioFormat::Float; } - Result oboeResult = AudioStreamBuffered::open(); + Result oboeResult = StreamBuffered::open(); if (oboeResult != Result::OK) { return oboeResult; } @@ -280,8 +280,8 @@ Result AudioStreamOpenSLES::open() { mBytesPerCallback = mFramesPerCallback * getBytesPerFrame(); mCallbackBuffer = new uint8_t[mBytesPerCallback]; - LOGD("AudioStreamOpenSLES(): mFramesPerCallback = %d", mFramesPerCallback); - LOGD("AudioStreamOpenSLES(): mBytesPerCallback = %d", mBytesPerCallback); + LOGD("StreamOpenSLES(): mFramesPerCallback = %d", mFramesPerCallback); + LOGD("StreamOpenSLES(): mBytesPerCallback = %d", mBytesPerCallback); SLuint32 bitsPerSample = getBytesPerSample() * OBOE_BITS_PER_BYTE; @@ -357,8 +357,8 @@ Result AudioStreamOpenSLES::open() { return Result::OK; } -Result AudioStreamOpenSLES::close() { -// __android_log_write(ANDROID_LOG_INFO, TAG, "AudioStreamOpenSLES()"); +Result StreamOpenSLES::close() { +// __android_log_write(ANDROID_LOG_INFO, TAG, "StreamOpenSLES()"); // TODO make sure callback is no longer being called if (bqPlayerObject_ != NULL) { (*bqPlayerObject_)->Destroy(bqPlayerObject_); @@ -371,16 +371,16 @@ Result AudioStreamOpenSLES::close() { return Result::OK; } -Result AudioStreamOpenSLES::setPlayState(SLuint32 newState) +Result StreamOpenSLES::setPlayState(SLuint32 newState) { Result result = Result::OK; - LOGD("AudioStreamOpenSLES(): setPlayState()"); + LOGD("StreamOpenSLES(): setPlayState()"); if (bqPlayerPlay_ == NULL) { return Result::ErrorInvalidState; } SLresult slResult = (*bqPlayerPlay_)->SetPlayState(bqPlayerPlay_, newState); if(SL_RESULT_SUCCESS != slResult) { - LOGD("AudioStreamOpenSLES(): setPlayState() returned %s", getSLErrStr(slResult)); + LOGD("StreamOpenSLES(): setPlayState() returned %s", getSLErrStr(slResult)); result = Result::ErrorInvalidState; // TODO review } else { setState(StreamState::Pausing); @@ -388,9 +388,9 @@ Result AudioStreamOpenSLES::setPlayState(SLuint32 newState) return result; } -Result AudioStreamOpenSLES::requestStart() +Result StreamOpenSLES::requestStart() { - LOGD("AudioStreamOpenSLES(): requestStart()"); + LOGD("StreamOpenSLES(): requestStart()"); Result result = setPlayState(SL_PLAYSTATE_PLAYING); if(result != Result::OK) { result = Result::ErrorInvalidState; // TODO review @@ -402,8 +402,8 @@ Result AudioStreamOpenSLES::requestStart() } -Result AudioStreamOpenSLES::requestPause() { - LOGD("AudioStreamOpenSLES(): requestPause()"); +Result StreamOpenSLES::requestPause() { + LOGD("StreamOpenSLES(): requestPause()"); Result result = setPlayState(SL_PLAYSTATE_PAUSED); if(result != Result::OK) { result = Result::ErrorInvalidState; // TODO review @@ -413,17 +413,17 @@ Result AudioStreamOpenSLES::requestPause() { return result; } -Result AudioStreamOpenSLES::requestFlush() { - LOGD("AudioStreamOpenSLES(): requestFlush()"); +Result StreamOpenSLES::requestFlush() { + LOGD("StreamOpenSLES(): requestFlush()"); if (bqPlayerPlay_ == NULL) { return Result::ErrorInvalidState; } return Result::ErrorUnimplemented; // TODO } -Result AudioStreamOpenSLES::requestStop() +Result StreamOpenSLES::requestStop() { - LOGD("AudioStreamOpenSLES(): requestStop()"); + LOGD("StreamOpenSLES(): requestStop()"); Result result = setPlayState(SL_PLAYSTATE_STOPPED); if(result != Result::OK) { result = Result::ErrorInvalidState; // TODO review @@ -433,18 +433,18 @@ Result AudioStreamOpenSLES::requestStop() return result; } -Result AudioStreamOpenSLES::waitForStateChange(StreamState currentState, +Result StreamOpenSLES::waitForStateChange(StreamState currentState, StreamState *nextState, int64_t timeoutNanoseconds) { - LOGD("AudioStreamOpenSLES(): waitForStateChange()"); + LOGD("StreamOpenSLES(): waitForStateChange()"); if (bqPlayerPlay_ == NULL) { return Result::ErrorInvalidState; } return Result::ErrorUnimplemented; // TODO } -int32_t AudioStreamOpenSLES::getFramesPerBurst() { +int32_t StreamOpenSLES::getFramesPerBurst() { return mFramesPerBurst; } diff --git a/src/opensles/AudioStreamOpenSLES.h b/src/opensles/StreamOpenSLES.h similarity index 92% rename from src/opensles/AudioStreamOpenSLES.h rename to src/opensles/StreamOpenSLES.h index 41ec329bd..2621dcf64 100644 --- a/src/opensles/AudioStreamOpenSLES.h +++ b/src/opensles/StreamOpenSLES.h @@ -21,7 +21,7 @@ #include #include "oboe/Oboe.h" -#include "AudioStreamBuffered.h" +#include "StreamBuffered.h" namespace oboe { @@ -32,13 +32,13 @@ namespace oboe { * Use an OboeStreamBuilder to create one. */ // -class AudioStreamOpenSLES : public AudioStreamBuffered { +class StreamOpenSLES : public StreamBuffered { public: - AudioStreamOpenSLES(); - explicit AudioStreamOpenSLES(const AudioStreamBuilder &builder); + StreamOpenSLES(); + explicit StreamOpenSLES(const StreamBuilder &builder); - virtual ~AudioStreamOpenSLES(); + virtual ~StreamOpenSLES(); Result open() override; Result close() override; From 2ef3ed8afb14725869964222ceb6bbb8870d4b0d Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 37/45] Revert "Use std::shared_ptr for callback object" This reverts commit e783d69f05db5fb8a02ed2ce795dcce57ccae370. --- include/oboe/Stream.h | 2 +- include/oboe/StreamBase.h | 25 ++++++++++++------------- include/oboe/StreamBuilder.h | 18 +++++++++--------- src/opensles/StreamBuffered.cpp | 10 ++++++++-- src/opensles/StreamBuffered.h | 2 ++ 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/include/oboe/Stream.h b/include/oboe/Stream.h index a974185e2..6e5f79bf3 100644 --- a/include/oboe/Stream.h +++ b/include/oboe/Stream.h @@ -144,7 +144,7 @@ class Stream : public StreamBase { bool isPlaying(); - std::shared_ptr getCallback() const { return mStreamCallback; } + StreamCallback *getCallback() const { return mStreamCallback; } int32_t getBytesPerFrame() const { return mChannelCount * getBytesPerSample(); } diff --git a/include/oboe/StreamBase.h b/include/oboe/StreamBase.h index e4c46b468..1ae131da1 100644 --- a/include/oboe/StreamBase.h +++ b/include/oboe/StreamBase.h @@ -17,7 +17,6 @@ #ifndef OBOE_STREAM_BASE_H_ #define OBOE_STREAM_BASE_H_ -#include #include "oboe/StreamCallback.h" #include "oboe/Definitions.h" @@ -90,22 +89,22 @@ class StreamBase { int32_t getDeviceId() const { return mDeviceId; } - std::shared_ptr getCallback() const { + StreamCallback *getCallback() const { return mStreamCallback; } protected: - std::shared_ptr mStreamCallback; - int32_t mFramesPerCallback = kUnspecified; - int32_t mChannelCount = kUnspecified; - int32_t mSampleRate = kUnspecified; - int32_t mDeviceId = kUnspecified; - int32_t mBufferCapacityInFrames = kUnspecified; - - SharingMode mSharingMode = SharingMode::Shared; - AudioFormat mFormat = AudioFormat::Unspecified; - Direction mDirection = Direction::Output; - PerformanceMode mPerformanceMode = PerformanceMode::None; + StreamCallback *mStreamCallback = NULL; + int32_t mFramesPerCallback = kUnspecified; + int32_t mChannelCount = kUnspecified; + int32_t mSampleRate = kUnspecified; + int32_t mDeviceId = kUnspecified; + int32_t mBufferCapacityInFrames = kUnspecified; + + SharingMode mSharingMode = SharingMode::Shared; + AudioFormat mFormat = AudioFormat::Unspecified; + Direction mDirection = Direction::Output; + PerformanceMode mPerformanceMode = PerformanceMode::None; }; } // namespace oboe diff --git a/include/oboe/StreamBuilder.h b/include/oboe/StreamBuilder.h index 93a8b6902..f46e702e4 100644 --- a/include/oboe/StreamBuilder.h +++ b/include/oboe/StreamBuilder.h @@ -53,7 +53,7 @@ class StreamBuilder : public StreamBase { /** * Request a specific number of channels. * - * Default is kUnspecified. If the value is unspecified then + * Default is OBOE_UNSPECIFIED. If the value is unspecified then * the application should query for the actual value after the stream is opened. */ StreamBuilder *setChannelCount(int channelCount) { @@ -62,7 +62,7 @@ class StreamBuilder : public StreamBase { } /** - * Request the direction for a stream. The default is Direction::Output. + * Request the direction for a stream. The default is OBOE_DIRECTION_OUTPUT. * * @param direction Direction::Output or Direction::Input */ @@ -74,7 +74,7 @@ class StreamBuilder : public StreamBase { /** * Request a specific sample rate in Hz. * - * Default is kUnspecified. If the value is unspecified then + * Default is OBOE_UNSPECIFIED. If the value is unspecified then * the application should query for the actual value after the stream is opened. * * Technically, this should be called the "frame rate" or "frames per second", @@ -121,9 +121,9 @@ class StreamBuilder : public StreamBase { * Set the requested maximum buffer capacity in frames. * The final stream capacity may differ, but will probably be at least this big. * - * Default is kUnspecified. + * Default is OBOE_UNSPECIFIED. * - * @param frames the desired buffer capacity in frames or kUnspecified + * @param frames the desired buffer capacity in frames or OBOE_UNSPECIFIED * @return pointer to the builder so calls can be chained */ StreamBuilder *setBufferCapacityInFrames(int32_t bufferCapacityInFrames) { @@ -136,7 +136,7 @@ class StreamBuilder : public StreamBase { /** * Normally you would leave this unspecified, and Oboe will chose the best API * for the device at runtime. - * @param Must be AudioApi::Unspecified, AudioApi::OpenSLES or AudioApi::AAudio. + * @param Must be API_UNSPECIFIED, API_OPENSL_ES or API_AAUDIO. * @return pointer to the builder so calls can be chained */ StreamBuilder *setApiIndex(AudioApi apiIndex) { @@ -171,7 +171,7 @@ class StreamBuilder : public StreamBase { * This will determine the latency, the power consumption, and the level of * protection from glitches. * - * @param performanceMode for example, PerformanceMode::LowLatency + * @param performanceMode for example, OBOE_PERFORMANCE_MODE_LOW_LATENCY * @return pointer to the builder so calls can be chained */ StreamBuilder *setPerformanceMode(PerformanceMode performanceMode) { @@ -185,7 +185,7 @@ class StreamBuilder : public StreamBase { * * By default, the primary device will be used. * - * @param deviceId device identifier or kUnspecified + * @param deviceId device identifier or OBOE_DEVICE_UNSPECIFIED * @return pointer to the builder so calls can be chained */ StreamBuilder *setDeviceId(int32_t deviceId) { @@ -202,7 +202,7 @@ class StreamBuilder : public StreamBase { * @param streamCallback * @return */ - StreamBuilder *setCallback(std::shared_ptr streamCallback) { + StreamBuilder *setCallback(StreamCallback *streamCallback) { mStreamCallback = streamCallback; return this; } diff --git a/src/opensles/StreamBuffered.cpp b/src/opensles/StreamBuffered.cpp index 5b4af19cf..670827b9a 100644 --- a/src/opensles/StreamBuffered.cpp +++ b/src/opensles/StreamBuffered.cpp @@ -27,6 +27,7 @@ namespace oboe { StreamBuffered::StreamBuffered(const StreamBuilder &builder) : Stream(builder) , mFifoBuffer(NULL) + , mInternalCallback(NULL) { } @@ -43,12 +44,17 @@ Result StreamBuffered::open() { LOGD("StreamBuffered(): new FifoBuffer"); mFifoBuffer = new FifoBuffer(getBytesPerFrame(), 1024); // TODO size? // Create a callback that reads from the FIFO - mStreamCallback = std::make_shared(this); - LOGD("StreamBuffered(): mStreamCallback = %p", mStreamCallback.get()); + mInternalCallback = new AudioStreamBufferedCallback(this); + mStreamCallback = mInternalCallback; + LOGD("StreamBuffered(): mInternalCallback = %p", mInternalCallback); } return Result::OK; } +StreamBuffered::~StreamBuffered() { + delete mInternalCallback; +} + // TODO: This method should return a tuple of Result,int32_t where the 2nd return param is the frames written int32_t StreamBuffered::write(const void *buffer, int32_t numFrames, diff --git a/src/opensles/StreamBuffered.h b/src/opensles/StreamBuffered.h index 577a639f2..e76304824 100644 --- a/src/opensles/StreamBuffered.h +++ b/src/opensles/StreamBuffered.h @@ -30,6 +30,7 @@ class StreamBuffered : public Stream { StreamBuffered(); explicit StreamBuffered(const StreamBuilder &builder); + virtual ~StreamBuffered(); Result open() override; @@ -70,6 +71,7 @@ class StreamBuffered : public Stream { private: FifoBuffer *mFifoBuffer; + AudioStreamBufferedCallback *mInternalCallback; }; } // namespace oboe From 7fcc0b87e8252662d8f95c47731d5c91be1d227f Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 38/45] Revert "Add default case to convert methods" This reverts commit 8de38ccd6b1a185cb98c8451015ee56db26c933d. --- src/common/Utilities.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/common/Utilities.cpp b/src/common/Utilities.cpp index e48e32a2c..ed51044bb 100644 --- a/src/common/Utilities.cpp +++ b/src/common/Utilities.cpp @@ -78,8 +78,6 @@ const char *convertResultToText(Result returnCode) { OBOE_CASE_ENUM(Result::ErrorOutOfRange); OBOE_CASE_ENUM(Result::ErrorNoService); OBOE_CASE_ENUM(Result::ErrorInvalidRate); - default: - return "Unrecognized result"; } } @@ -89,8 +87,6 @@ const char *convertAudioFormatToText(AudioFormat format) { OBOE_CASE_ENUM(AudioFormat::Unspecified); OBOE_CASE_ENUM(AudioFormat::I16); OBOE_CASE_ENUM(AudioFormat::Float); - default: - return "Unrecognized format"; } } @@ -99,8 +95,6 @@ const char *convertPerformanceModeToText(PerformanceMode mode) { OBOE_CASE_ENUM(PerformanceMode::LowLatency); OBOE_CASE_ENUM(PerformanceMode::None); OBOE_CASE_ENUM(PerformanceMode::PowerSaving); - default: - return "Unrecognized performance mode"; } } @@ -108,8 +102,6 @@ const char *convertSharingModeToText(SharingMode mode) { switch (mode) { OBOE_CASE_ENUM(SharingMode::Exclusive); OBOE_CASE_ENUM(SharingMode::Shared); - default: - return "Unrecognized sharing mode"; } } @@ -117,8 +109,6 @@ const char *convertDataCallbackResultToText(DataCallbackResult result) { switch (result) { OBOE_CASE_ENUM(DataCallbackResult::Continue); OBOE_CASE_ENUM(DataCallbackResult::Stop); - default: - return "Unrecognized data callback result"; } } @@ -126,8 +116,6 @@ const char *convertDirectionToText(Direction direction) { switch (direction) { OBOE_CASE_ENUM(Direction::Input); OBOE_CASE_ENUM(Direction::Output); - default: - return "Unrecognized direction"; } } From b0417cd8c52e74c18ee2f10237b523cf1d35ae3c Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 39/45] Revert "More documentation fixes" This reverts commit 2657e7c1c51ac21f6756c71a60d2b06bacb27cd1. --- GettingStarted.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GettingStarted.md b/GettingStarted.md index df87ae672..c29f9f521 100644 --- a/GettingStarted.md +++ b/GettingStarted.md @@ -79,7 +79,7 @@ Open the stream: oboe::Stream *stream; oboe::Result result = builder.openStream(&stream); -Check the result to make sure the stream was opened successfully. Oboe has many convenience methods for converting its types into human-readable strings, they all start with `oboe::convert`: +Check the result to make sure the stream was opened successfully. Oboe has many convenience methods for converting its types into human-readable strings, they all start with `Oboe_convert`: if (result != Result::OK){ LOGE("Failed to create stream. Error: %s", oboe::convertResultToText(result)); From 4658ddeb05863d9a8c74cfcff81cd92f584d4213 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Mon, 12 Feb 2018 14:08:19 +0000 Subject: [PATCH 40/45] Revert "Documentation tidy up" This reverts commit 7c85211557baa1fe2c2e1353ce24de74b4d39fc7. --- CMakeLists.txt | 5 +++ FullGuide.md | 68 ++++++++++++++++++------------------- GettingStarted.md | 28 +++++++-------- include/oboe/LatencyTuner.h | 2 +- include/oboe/Stream.h | 16 +++++---- src/fifo/FifoBuffer.h | 6 ++-- 6 files changed, 66 insertions(+), 59 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fcce7b09c..2461fa088 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,12 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++11") include_directories( include src + /Users/donturner/Library/Android/sdk/ndk-bundle/sysroot/usr/include + /Users/donturner/Library/Android/sdk/ndk-bundle/sysroot/usr/include/arm-linux-androideabi/ ) +#file(GLOB_RECURSE oboe_sources src/*) + set (oboe_sources include/oboe/LatencyTuner.h include/oboe/Definitions.h @@ -33,4 +37,5 @@ set (oboe_sources src/opensles/OpenSLESUtilities.cpp ) + add_library(oboe STATIC ${oboe_sources}) \ No newline at end of file diff --git a/FullGuide.md b/FullGuide.md index fba36e439..89d966810 100644 --- a/FullGuide.md +++ b/FullGuide.md @@ -28,11 +28,11 @@ The audio device attached to a stream determines whether the stream is for input A stream has a sharing mode: -* `SharingMode::Exclusive` (available on API 26+) means the stream has exclusive access to its audio device; the device cannot be used by any other audio stream. If the audio device is already in use, it might not be possible for the stream to have exclusive access. Exclusive streams provide the lowest possible latency, but they are also more likely to get disconnected. You should close exclusive streams as soon as you no longer need them, so that other apps can access the device. -* `SharingMode::Shared` allows Oboe to mix audio. Oboe mixes all the shared streams assigned to the same device. +* `OBOE_SHARING_MODE_EXCLUSIVE` (available on API 26+) means the stream has exclusive access to its audio device; the device cannot be used by any other audio stream. If the audio device is already in use, it might not be possible for the stream to have exclusive access. Exclusive streams provide the lowest possible latency, but they are also more likely to get disconnected. You should close exclusive streams as soon as you no longer need them, so that other apps can access the device. +* `OBOE_SHARING_MODE_SHARED` allows Oboe to mix audio. Oboe mixes all the shared streams assigned to the same device. You can explicitly request the sharing mode when you create a stream, although you are not guaranteed to receive that mode. By default, -the sharing mode is `Shared`. +the sharing mode is `SHARED`. ### Audio format @@ -44,16 +44,16 @@ The data passed through a stream has the usual digital audio attributes, which y Oboe permits these sample formats: -| AudioFormat | C data type | Notes | +| oboe_format_t | C data type | Notes | | :------------ | :---------- | :---- | -| I16 | int16_t | common 16-bit samples, [Q0.15 format](https://source.android.com/devices/audio/data_formats#androidFormats) | -| Float | float | -1.0 to +1.0 | +| OBOE_FORMAT_PCM_I16 | int16_t | common 16-bit samples, [Q0.15 format](https://source.android.com/devices/audio/data_formats#androidFormats) | +| OBOE_FORMAT_PCM_FLOAT | float | -1.0 to +1.0 | Oboe might perform sample conversion on its own. For example, if an app is writing FLOAT data but the HAL uses PCM_I16, Oboe might convert the samples automatically. Conversion can happen in either direction. If your app processes audio input, it is wise to verify the input format and be prepared to convert data if necessary, as in this example: - AudioFormat dataFormat = stream->getDataFormat(); + oboe_format_t dataFormat = stream->getDataFormat(); //... later - if (dataFormat == AudioFormat::I16) { + if (dataFormat == OBOE_FORMAT_PCM_I16) { convertFloatToPcm16(...) } @@ -88,7 +88,7 @@ If you do not specify the deviceId, the default is the primary output device. If you do not specify the stream direction, the default is an output stream. For all other parameters, you can explicitly set a value, or let the system assign the optimal value by not specifying the parameter at all or setting -it to `kUnspecified`. +it to `OBOE_UNSPECIFIED`. To be safe, check the state of the audio stream after you create it, as explained in step 3, below. @@ -99,7 +99,7 @@ To be safe, check the state of the audio stream after you create it, as explaine __android_log_print(ANDROID_LOG_ERROR, "AudioEngine", "Error opening stream %s", - convertResultToText(result)); + OboeConvert_ResultToText(result)); } @@ -178,9 +178,9 @@ Since you can't wait for the Paused state, use `waitForStateChange()` to wait fo other than Pausing*. Here's how that's done: ``` -StreamState inputState = StreamState::Pausing; -StreamState nextState = StreamState::Uninitialized; -int64_t timeoutNanos = 100 * kNanosPerMillisecond; +StreamState inputState = OBOE_STREAM_STATE_PAUSING; +StreamState nextState = OBOE_STREAM_STATE_UNINITIALIZED; +int64_t timeoutNanos = 100 * OBOE_NANOS_PER_MILLISECOND; result = stream->requestPause(); result = stream->waitForStateChange(inputState, &nextState, timeoutNanos); ``` @@ -259,12 +259,12 @@ original stream (for example framesPerBurst): ``` void PlayAudioEngine::onError(Stream *audioStream, Result error) { - if (error == Result::ErrorDisconnected) { + if (error == OBOE_ERROR_DISCONNECTED) { // Handle stream restart on a separate thread std::function restartStream = std::bind(&PlayAudioEngine::restartStream, this); mStreamRestartThread = new std::thread(restartStream); } - // See Definitions.h for other Result::Error* codes + // See OboeDefinitions.h for other OBOE_ERROR_* codes } ``` @@ -290,12 +290,12 @@ callback function) to acquire the data for its next burst. class AudioEngine : StreamCallback { public: - DataCallbackResult AudioEngine::onAudioReady( + oboe_data_callback_result_t AudioEngine::onAudioReady( Stream *oboeStream, void *audioData, int32_t numFrames){ oscillator_->render(static_cast(audioData), numFrames); - return DataCallbackResult::Continue; + return OBOE_CALLBACK_RESULT_CONTINUE; } bool AudioEngine::start() { @@ -333,13 +333,13 @@ The callback does a non-blocking read from the input stream placing the data int stream2.read(audioData, numFrames, timeout); if (result == numFrames) - return DataCallbackResult::Continue; + return OBOE_CALLBACK_RESULT_CONTINUE; if (result >= 0) { memset(static_cast(audioData) + result * samplesPerFrame, 0, sizeof(sample_type) * (numFrames - result) * samplesPerFrame); - return DataCallbackResult::Continue; + return OBOE_CALLBACK_RESULT_CONTINUE; } - return DataCallbackResult::Stop; + return OBOE_CALLBACK_RESULT_STOP; } bool AudioEngine::start() { @@ -362,20 +362,20 @@ Note that in this example it is assumed the input and output streams have the sa Every Stream has a *performance mode* which has a large effect on your app's behavior. There are three modes: -* `PerformanceMode::None` is the default mode. It uses a basic stream that balances latency and power savings. -* `PerformanceMode::LowLatency` uses smaller buffers and an optimized data path for reduced latency. -* `PerformanceMode::PowerSaving` uses larger internal buffers and a data path that trades off latency for lower power. +* `OBOE_PERFORMANCE_MODE_NONE` is the default mode. It uses a basic stream that balances latency and power savings. +* `OBOE_PERFORMANCE_MODE_LOW_LATENCY` uses smaller buffers and an optimized data path for reduced latency. +* `OBOE_PERFORMANCE_MODE_POWER_SAVING` uses larger internal buffers and a data path that trades off latency for lower power. You can select the performance mode by calling `setPerformanceMode()`, and discover the current mode by calling `getPerformanceMode()`. -If low latency is more important than power savings in your application, use `PerformanceMode::LowLatency`. +If low latency is more important than power savings in your application, use `OBOE_PERFORMANCE_MODE_LOW_LATENCY`. This is useful for apps that are very interactive, such as games or keyboard synthesizers. -If saving power is more important than low latency in your application, use `PerformanceMode::PowerSaving`. +If saving power is more important than low latency in your application, use `OBOE_PERFORMANCE_MODE_POWER_SAVING`. This is typical for apps that play back previously generated music, such as streaming audio or MIDI file players. -In the current version of Oboe, in order to achieve the lowest possible latency you must use the `PerformanceMode::LowLatency` performance mode along with a high-priority callback. Follow this example: +In the current version of Oboe, in order to achieve the lowest possible latency you must use the `OBOE_PERFORMANCE_MODE_LOW_LATENCY` performance mode along with a high-priority callback. Follow this example: ``` // Create a callback object @@ -384,7 +384,7 @@ MyOboeStreamCallback myCallback; // Create a stream builder StreamBuilder builder; builder.setCallback(myCallback); -builder.setPerformanceMode(PerformanceMode::LowLatency); +builder.setPerformanceMode(OBOE_PERFORMANCE_MODE_LOW_LATENCY); // Use it to create the stream Stream *stream; @@ -403,12 +403,12 @@ Calls that return stream settings, like `Stream::getSampleRate()` and `Stream::g These calls are also thread safe: -* `convertToText()` -* `convertAudioFormatToText()` -* `convertPerformanceModeToText()` -* `convertSharingModeToText()` -* `convertDataCallbackResultToText()` -* `convertDirectionToText()` +* `Oboe_convertToText()` +* `Oboe_convertAudioFormatToText()` +* `Oboe_convertPerformanceModeToText()` +* `Oboe_convertSharingModeToText()` +* `Oboe_convertDataCallbackResultToText()` +* `Oboe_convertDirectionToText()` * `Stream::get*()` except for `getTimestamp()` @@ -424,7 +424,7 @@ A small demo app is available on our [GitHub page](https://github.com/googlesamp ## Known Issues -The following methods are defined, but will return `Result::ErrorUnimplemented`: +The following methods are defined, but will return `OBOE_ERROR_UNIMPLEMENTED`: * `setBufferSizeInFrames()` * `getBufferSizeInFrames()` diff --git a/GettingStarted.md b/GettingStarted.md index c29f9f521..b1274f1db 100644 --- a/GettingStarted.md +++ b/GettingStarted.md @@ -50,22 +50,22 @@ Include the Oboe header: Streams are built using an `StreamBuilder`. Create one like this: - oboe::StreamBuilder builder; + StreamBuilder builder; Use the builder's set methods to set properties on the stream (you can read more about these properties in the [full guide](FullGuide.md)): - builder.setDirection(oboe::Direction::Output); - builder.setPerformanceMode(oboe::PerformanceMode::LowLatency); - builder.setSharingMode(oboe::SharingMode::Exclusive); + builder.setDirection(OBOE_DIRECTION_OUTPUT); + builder.setPerformanceMode(OBOE_PERFORMANCE_MODE_LOW_LATENCY); + builder.setSharingMode(OBOE_SHARING_MODE_EXCLUSIVE); Define an `StreamCallback` class to receive callbacks whenever the stream requires new data. - class MyCallback : public oboe::StreamCallback { + class MyCallback : public StreamCallback { public: - oboe::Result - onAudioReady(oboe::Stream *audioStream, void *audioData, int32_t numFrames){ + oboe_data_callback_result_t + onAudioReady(Stream *audioStream, void *audioData, int32_t numFrames){ generateSineWave(static_cast(audioData), numFrames); - return oboe::DataCallbackResult::Continue; + return OBOE_CALLBACK_RESULT_CONTINUE; } }; @@ -76,21 +76,21 @@ Supply this callback class to the builder: Open the stream: - oboe::Stream *stream; - oboe::Result result = builder.openStream(&stream); + Stream *stream; + Result result = builder.openStream(&stream); Check the result to make sure the stream was opened successfully. Oboe has many convenience methods for converting its types into human-readable strings, they all start with `Oboe_convert`: - if (result != Result::OK){ - LOGE("Failed to create stream. Error: %s", oboe::convertResultToText(result)); + if (result != OK){ + LOGE("Failed to create stream. Error: %s", Oboe_convertResultToText(result)); } Note that this sample code uses the [logging macros from here](https://github.com/googlesamples/android-audio-high-performance/blob/master/debug-utils/logging_macros.h). Check the properties of the created stream. The **format** is one property which you should check. The default is `float` on API 21+ and `int16_t` on API 20 or lower. This will dictate the `audioData` type in the `StreamCallback::onAudioReady` callback. - oboe::AudioFormat format = stream->getFormat(); - LOGI("Stream format is %s", oboe::convertAudioFormatToText(format)); + oboe_audio_format_t format = stream->getFormat(); + LOGI("Stream format is %s", Oboe_convertAudioFormatToText(format)); Now start the stream. diff --git a/include/oboe/LatencyTuner.h b/include/oboe/LatencyTuner.h index e398bd9f8..0cab7ec41 100644 --- a/include/oboe/LatencyTuner.h +++ b/include/oboe/LatencyTuner.h @@ -49,7 +49,7 @@ class LatencyTuner { * * Latency tuning is only supported for AAudio. * - * @return OK or negative error, ErrorUnimplemented for OpenSL ES + * @return OBOE_OK or negative error, OBOE_ERROR_UNIMPLEMENTED for OpenSL ES */ Result tune(); diff --git a/include/oboe/Stream.h b/include/oboe/Stream.h index 6e5f79bf3..4ed66bd24 100644 --- a/include/oboe/Stream.h +++ b/include/oboe/Stream.h @@ -72,7 +72,7 @@ class Stream : public StreamBase { virtual Result requestStop() = 0; /** - * Query the current state, eg. StreamState::Pausing + * Query the current state, eg. OBOE_STREAM_STATE_PAUSING * * @return state or a negative error. */ @@ -87,9 +87,9 @@ class Stream : public StreamBase { * an advanced technique. * *

-     * int64_t timeoutNanos = 500 * kNanosPerMillisecond; // arbitrary 1/2 second
+     * int64_t timeoutNanos = 500 * OBOE_NANOS_PER_MILLISECOND; // arbitrary 1/2 second
      * StreamState currentState = stream->getState(stream);
-     * while (currentState >= 0 && currentState != StreamState::Paused) {
+     * while (currentState >= 0 && currentState != OBOE_STREAM_STATE_PAUSED) {
      *     currentState = stream->waitForStateChange(
      *                                   stream, currentState, timeoutNanos);
      * }
@@ -99,12 +99,14 @@ class Stream : public StreamBase {
      * @param currentState The state we want to avoid.
      * @param nextState Pointer to a variable that will be set to the new state.
      * @param timeoutNanoseconds The maximum time to wait in nanoseconds.
-     * @return Result::OK or a Result::Error.
+     * @return OBOE_OK or a negative error.
      */
     virtual Result waitForStateChange(StreamState currentState,
                                           StreamState *nextState,
                                           int64_t timeoutNanoseconds) = 0;
 
+
+
     /**
     * This can be used to adjust the latency of the buffer by changing
     * the threshold where blocking will occur.
@@ -114,7 +116,7 @@ class Stream : public StreamBase {
     * This cannot be set higher than getBufferCapacity().
     *
     * @param requestedFrames requested number of frames that can be filled without blocking
-    * @return resulting buffer size in frames or a Result::Error
+    * @return resulting buffer size in frames or a negative error
     */
     virtual Result setBufferSizeInFrames(int32_t requestedFrames) {
         return Result::ErrorUnimplemented;
@@ -203,9 +205,9 @@ class Stream : public StreamBase {
 
     /**
      * Wait for a transition from one state to another.
-     * @return OK if the endingState was observed, or ErrorUnexpectedState
+     * @return OBOE_OK if the endingState was observed, or OBOE_ERROR_UNEXPECTED_STATE
      *   if any state that was not the startingState or endingState was observed
-     *   or ErrorTimeout.
+     *   or OBOE_ERROR_TIMEOUT.
      */
     virtual Result waitForStateTransition(StreamState startingState,
                                               StreamState endingState,
diff --git a/src/fifo/FifoBuffer.h b/src/fifo/FifoBuffer.h
index e94e53a8e..e23bdd71d 100644
--- a/src/fifo/FifoBuffer.h
+++ b/src/fifo/FifoBuffer.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_FIFOPROCESSOR_H
-#define OBOE_FIFOPROCESSOR_H
+#ifndef NATIVEOBOE_FIFOPROCESSOR_H
+#define NATIVEOBOE_FIFOPROCESSOR_H
 
 #include 
 #include 
@@ -94,4 +94,4 @@ class FifoBuffer {
 
 } // namespace oboe
 
-#endif //OBOE_FIFOPROCESSOR_H
+#endif //NATIVEOBOE_FIFOPROCESSOR_H

From dd615c4d0f8968d753b68d52aef5e669fd17f8e4 Mon Sep 17 00:00:00 2001
From: Don Turner 
Date: Mon, 12 Feb 2018 14:08:19 +0000
Subject: [PATCH 41/45] Revert "Use oboe namespace"

This reverts commit f7b9295cb502621417d84013c96cce0d49097ff5.
---
 CMakeLists.txt                                |  33 +--
 FullGuide.md                                  |  66 ++---
 GettingStarted.md                             |  18 +-
 build_all_android.sh                          |   4 +-
 include/oboe/Definitions.h                    | 114 --------
 include/oboe/Oboe.h                           |  12 +-
 include/oboe/OboeDefinitions.h                | 130 +++++++++
 .../{LatencyTuner.h => OboeLatencyTuner.h}    |  41 ++-
 include/oboe/{Stream.h => OboeStream.h}       |  91 ++++---
 .../oboe/{StreamBase.h => OboeStreamBase.h}   |  58 ++--
 .../{StreamBuilder.h => OboeStreamBuilder.h}  |  75 +++---
 ...{StreamCallback.h => OboeStreamCallback.h} |  28 +-
 include/oboe/{Utilities.h => OboeUtilities.h} |  31 +--
 src/aaudio/AAudioLoader.cpp                   |   4 -
 src/aaudio/AAudioLoader.h                     |   6 +-
 ...{StreamAAudio.cpp => OboeStreamAAudio.cpp} | 247 ++++++++----------
 .../{StreamAAudio.h => OboeStreamAAudio.h}    |  61 ++---
 src/aaudio/build.gradle                       |   3 +
 src/common/AudioClock.h                       |  18 +-
 src/common/OboeDebug.h                        |   6 +-
 ...{LatencyTuner.cpp => OboeLatencyTuner.cpp} |  47 ++--
 src/common/OboeStream.cpp                     | 117 +++++++++
 ...treamBuilder.cpp => OboeStreamBuilder.cpp} |  44 ++--
 src/common/OboeUtilities.cpp                  | 127 +++++++++
 src/common/Stream.cpp                         | 125 ---------
 src/common/Utilities.cpp                      | 122 ---------
 src/fifo/FifoBuffer.cpp                       |   6 +-
 src/fifo/FifoBuffer.h                         |   6 +-
 src/fifo/FifoController.cpp                   |   5 -
 src/fifo/FifoController.h                     |   3 -
 src/fifo/FifoControllerBase.cpp               |   4 -
 src/fifo/FifoControllerBase.h                 |   4 +-
 src/fifo/FifoControllerIndirect.cpp           |   4 -
 src/fifo/FifoControllerIndirect.h             |   4 -
 ...eamBuffered.cpp => OboeStreamBuffered.cpp} |  53 ++--
 ...{StreamBuffered.h => OboeStreamBuffered.h} |  45 ++--
 ...eamOpenSLES.cpp => OboeStreamOpenSLES.cpp} | 144 +++++-----
 ...{StreamOpenSLES.h => OboeStreamOpenSLES.h} |  37 ++-
 src/opensles/OpenSLESUtilities.cpp            |   4 -
 src/opensles/OpenSLESUtilities.h              |   4 -
 40 files changed, 910 insertions(+), 1041 deletions(-)
 delete mode 100644 include/oboe/Definitions.h
 create mode 100644 include/oboe/OboeDefinitions.h
 rename include/oboe/{LatencyTuner.h => OboeLatencyTuner.h} (81%)
 rename include/oboe/{Stream.h => OboeStream.h} (71%)
 rename include/oboe/{StreamBase.h => OboeStreamBase.h} (60%)
 rename include/oboe/{StreamBuilder.h => OboeStreamBuilder.h} (77%)
 rename include/oboe/{StreamCallback.h => OboeStreamCallback.h} (74%)
 rename include/oboe/{Utilities.h => OboeUtilities.h} (76%)
 rename src/aaudio/{StreamAAudio.cpp => OboeStreamAAudio.cpp} (53%)
 rename src/aaudio/{StreamAAudio.h => OboeStreamAAudio.h} (58%)
 create mode 100644 src/aaudio/build.gradle
 rename src/common/{LatencyTuner.cpp => OboeLatencyTuner.cpp} (63%)
 create mode 100644 src/common/OboeStream.cpp
 rename src/common/{StreamBuilder.cpp => OboeStreamBuilder.cpp} (54%)
 create mode 100644 src/common/OboeUtilities.cpp
 delete mode 100644 src/common/Stream.cpp
 delete mode 100644 src/common/Utilities.cpp
 rename src/opensles/{StreamBuffered.cpp => OboeStreamBuffered.cpp} (64%)
 rename src/opensles/{StreamBuffered.h => OboeStreamBuffered.h} (57%)
 rename src/opensles/{StreamOpenSLES.cpp => OboeStreamOpenSLES.cpp} (76%)
 rename src/opensles/{StreamOpenSLES.h => OboeStreamOpenSLES.h} (70%)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2461fa088..89e684ec8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,37 +5,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++11")
 # Specify directories which the compiler should look for headers
 include_directories(
   include
-  src
-  /Users/donturner/Library/Android/sdk/ndk-bundle/sysroot/usr/include
-  /Users/donturner/Library/Android/sdk/ndk-bundle/sysroot/usr/include/arm-linux-androideabi/
-)
-
-#file(GLOB_RECURSE oboe_sources src/*)
-
-set (oboe_sources
-        include/oboe/LatencyTuner.h
-        include/oboe/Definitions.h
-        include/oboe/Stream.h
-        include/oboe/StreamBase.h
-        include/oboe/StreamBuilder.h
-        include/oboe/StreamCallback.h
-        include/oboe/Utilities.h
-        src/aaudio/AAudioLoader.cpp
-        src/aaudio/StreamAAudio.cpp
-        src/common/AudioClock.h
-        src/common/OboeDebug.h
-        src/common/LatencyTuner.cpp
-        src/common/Stream.cpp
-        src/common/StreamBuilder.cpp
-        src/common/Utilities.cpp
-        src/fifo/FifoBuffer.cpp
-        src/fifo/FifoController.cpp
-        src/fifo/FifoControllerBase.cpp
-        src/fifo/FifoControllerIndirect.cpp
-        src/opensles/StreamBuffered.cpp
-        src/opensles/StreamOpenSLES.cpp
-        src/opensles/OpenSLESUtilities.cpp
-        )
+  src)
 
+file(GLOB_RECURSE oboe_sources src/*)
 
 add_library(oboe STATIC ${oboe_sources})
\ No newline at end of file
diff --git a/FullGuide.md b/FullGuide.md
index 89d966810..7466502c4 100644
--- a/FullGuide.md
+++ b/FullGuide.md
@@ -3,7 +3,7 @@ Oboe is a C++ library which makes it easy to build high-performance audio apps o
 
 ## Audio streams
 
-Oboe moves audio data between your app and the audio inputs and outputs on your Android device. Your app passes data in and out by reading from and writing to *audio streams*, represented by the class `Stream`. The read/write calls can be blocking or non-blocking.
+Oboe moves audio data between your app and the audio inputs and outputs on your Android device. Your app passes data in and out by reading from and writing to *audio streams*, represented by the class `OboeStream`. The read/write calls can be blocking or non-blocking.
 
 A stream is defined by the following:
 
@@ -59,11 +59,11 @@ Oboe might perform sample conversion on its own. For example, if an app is writi
 
 ## Creating an audio stream
 
-The Oboe library follows a [builder design pattern](https://en.wikipedia.org/wiki/Builder_pattern) and provides the class `StreamBuilder`.
+The Oboe library follows a [builder design pattern](https://en.wikipedia.org/wiki/Builder_pattern) and provides the class `OboeStreamBuilder`.
 
-  1. Set the audio stream configuration using an StreamBuilder. Use the builder functions that correspond to the stream parameters. These optional set functions are available:
+  1. Set the audio stream configuration using an OboeStreamBuilder. Use the builder functions that correspond to the stream parameters. These optional set functions are available:
 
-    StreamBuilder streamBuilder;
+    OboeStreamBuilder streamBuilder;
 
     streamBuilder.setDeviceId(deviceId);
     streamBuilder.setDirection(direction);
@@ -81,8 +81,8 @@ whether Oboe will use AAudio or OpenSL ES as the audio engine for you app. Oboe
 will automatically select the best implementation available on your device. If
 you want to specifically select AAudio or OpenSL, set the APIIndex yourself.
 After a stream has been opened, you can verify that the API you specified was
-chosen by calling `StreamBuilder::getAPIIndex()`. The allowable indexes are
-`AAudio` and `OpenSLES`.
+chosen by calling `OboeStreamBuilder::getAPIIndex()`. The allowable indexes are
+`API_AAUDIO` and `API_OPENSL_ES`.
 
 If you do not specify the deviceId, the default is the primary output device.
 If you do not specify the stream direction, the default is an output stream.
@@ -92,10 +92,10 @@ it to `OBOE_UNSPECIFIED`.
 
 To be safe, check the state of the audio stream after you create it, as explained in step 3, below.
 
-  2. After you've configured the StreamBuilder, call `openStream()` to open the stream:
+  2. After you've configured the OboeStreamBuilder, call `openStream()` to open the stream:
 
-    Result result = streamBuilder.openStream(&stream_);
-    if (result != OK){
+    oboe_result_t result = streamBuilder.openStream(&stream_);
+    if (result != OBOE_OK){
         __android_log_print(ANDROID_LOG_ERROR,
                             "AudioEngine",
                             "Error opening stream %s",
@@ -139,7 +139,7 @@ Data only flows through a stream when the stream is in the Started state. To
 move a stream between states, use one of the functions that request a state
 transition:
 
-    Result result;
+    oboe_result_t result;
     result = stream->requestStart();
     result = stream->requestStop();
     result = stream->requestPause();
@@ -166,7 +166,7 @@ Though it's not shown, you can call `close()` from any state
 
 Oboe doesn't provide callbacks to alert you to state changes. One special
 function,
-`Stream::waitForStateChange()` can be used to wait for a state change.
+`OboeStream::waitForStateChange()` can be used to wait for a state change.
 
 The function does not detect a state change on its own, and does not wait for a
 specific state. It waits until the current state
@@ -178,8 +178,8 @@ Since you can't wait for the Paused state, use `waitForStateChange()` to wait fo
 other than Pausing*. Here's how that's done:
 
 ```
-StreamState inputState = OBOE_STREAM_STATE_PAUSING;
-StreamState nextState = OBOE_STREAM_STATE_UNINITIALIZED;
+oboe_stream_state_t inputState = OBOE_STREAM_STATE_PAUSING;
+oboe_stream_state_t nextState = OBOE_STREAM_STATE_UNINITIALIZED;
 int64_t timeoutNanos = 100 * OBOE_NANOS_PER_MILLISECOND;
 result = stream->requestPause();
 result = stream->waitForStateChange(inputState, &nextState, timeoutNanos);
@@ -194,16 +194,16 @@ stream.
 
 You can use this same technique after calling request start, stop, or flush,
 using the corresponding transient state as the inputState. Do not call
-`waitForStateChange()` after calling `Stream::close()` since the stream
+`waitForStateChange()` after calling `OboeStream::close()` since the stream
 will be deleted as soon as it closes. And do not call `close()`
 while `waitForStateChange()` is running in another thread.
 
 ### Reading and writing to an audio stream
 
 After the stream is started you can read or write to it using the methods
-`Stream::read(buffer, numFrames, timeoutNanos)`
+`OboeStream::read(buffer, numFrames, timeoutNanos)`
 and
-`Stream::write(buffer, numFrames, timeoutNanos)`.
+`OboeStream::write(buffer, numFrames, timeoutNanos)`.
 
 
 For a blocking read or write that transfers the specified number of frames, set timeoutNanos greater than zero. For a non-blocking call, set timeoutNanos to zero. In this case the result is the actual number of frames transferred.
@@ -214,7 +214,7 @@ frames was read. If not, the buffer might contain unknown data that could cause
 audio glitch. You can pad the buffer with zeros to create a
 silent dropout:
 
-    Result result =
+    oboe_result_t result =
         stream.read(audioData, numFrames, timeout);
     if (result < 0) {
       // Error!
@@ -248,7 +248,7 @@ An audio stream can become disconnected at any time if one of these events happe
 When a stream is disconnected, it has the state "Disconnected" and any attempts to execute write() or other functions return `OBOE_ERROR_DISCONNECTED`.  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 `StreamCallback` and implements the `onError(stream, error)`
+which extends `OboeStreamCallback` and implements the `onError(stream, error)`
 method. Register your class using `builder.setCallback(yourCallbackClass)`.
 
 The `onError()` method should check the state of the stream as shown in the following
@@ -258,7 +258,7 @@ stream it might have different characteristics than the
 original stream (for example framesPerBurst):
 
 ```
-void PlayAudioEngine::onError(Stream *audioStream, Result error) {
+void PlayAudioEngine::onError(OboeStream *audioStream, oboe_result_t error) {
     if (error == OBOE_ERROR_DISCONNECTED) {
         // Handle stream restart on a separate thread
         std::function restartStream = std::bind(&PlayAudioEngine::restartStream, this);
@@ -268,7 +268,7 @@ void PlayAudioEngine::onError(Stream *audioStream, Result error) {
 }
 ```
 
-You can also implement two other callback methods in the class `StreamCallback`:
+You can also implement two other callback methods in the class `OboeStreamCallback`:
 
 * `onAudioReady()` is used for a high-priority callback
 * `onExit()` is called when the callback thread exits.
@@ -285,13 +285,13 @@ For applications that require low latency, an audio stream can use an asynchrono
 The callback runs in a high-priority thread that has better performance.
 
 Your code can access the callback mechanism by implementing the virtual class
-`StreamCallback`. The stream periodically executes `onAudioReady()` (the
+`OboeStreamCallback`. The stream periodically executes `onAudioReady()` (the
 callback function) to acquire the data for its next burst.
 
-    class AudioEngine : StreamCallback {
+    class AudioEngine : OboeStreamCallback {
     public:
         oboe_data_callback_result_t AudioEngine::onAudioReady(
-                Stream *oboeStream,
+                OboeStream *oboeStream,
                 void *audioData,
                 int32_t numFrames){
             oscillator_->render(static_cast(audioData), numFrames);
@@ -322,14 +322,14 @@ The callback does a non-blocking read from the input stream placing the data int
 
 (Note that Oboe version 1 does not support input streams, so this example cannot run.)
 
-    class AudioEngine : StreamCallback {
+    class AudioEngine : OboeStreamCallback {
     public:
 
         oboe_data_callback_result_t AudioEngine::onAudioReady(
-                Stream *oboeStream,
+                OboeStream *oboeStream,
                 void *audioData,
                 int32_t numFrames){
-                Result result =
+                oboe_result_t result =
                   stream2.read(audioData, numFrames, timeout);
 
                 if (result == numFrames)
@@ -347,12 +347,12 @@ The callback does a non-blocking read from the input stream placing the data int
             streamBuilder.setCallback(this);
         }
 
-        void setRecordingStream(Stream *stream) {
+        void setRecordingStream(OboeStream *stream) {
           recordingStream = stream;
         }
 
     private:
-        Stream *recordingStream;
+        OboeStream *recordingStream;
     }
 
 
@@ -360,7 +360,7 @@ Note that in this example it is assumed the input and output streams have the sa
 
 ### Setting performance mode
 
-Every Stream has a *performance mode* which has a large effect on your app's behavior. There are three modes:
+Every OboeStream has a *performance mode* which has a large effect on your app's behavior. There are three modes:
 
 * `OBOE_PERFORMANCE_MODE_NONE` is the default mode. It uses a basic stream that balances latency and power savings.
 * `OBOE_PERFORMANCE_MODE_LOW_LATENCY` uses smaller buffers and an optimized data path for reduced latency.
@@ -382,12 +382,12 @@ In the current version of Oboe, in order to achieve the lowest possible latency
 MyOboeStreamCallback myCallback;
 
 // Create a stream builder
-StreamBuilder builder;
+OboeStreamBuilder builder;
 builder.setCallback(myCallback);
 builder.setPerformanceMode(OBOE_PERFORMANCE_MODE_LOW_LATENCY);
 
 // Use it to create the stream
-Stream *stream;
+OboeStream *stream;
 builder.openStream(&stream);
 ```
 
@@ -399,7 +399,7 @@ This is because Oboe avoids using mutexes, which can cause thread preemption and
 
 To be safe, don't call `waitForStateChange()` or read or write to the same stream from two different threads. Similarly, don't close a stream in one thread while reading or writing to it in another thread.
 
-Calls that return stream settings, like `Stream::getSampleRate()` and `Stream::getChannelCount()`, are thread safe.
+Calls that return stream settings, like `OboeStream::getSampleRate()` and `OboeStream::getChannelCount()`, are thread safe.
 
 These calls are also thread safe:
 
@@ -409,7 +409,7 @@ These calls are also thread safe:
 * `Oboe_convertSharingModeToText()`
 * `Oboe_convertDataCallbackResultToText()`
 * `Oboe_convertDirectionToText()`
-* `Stream::get*()` except for `getTimestamp()`
+* `OboeStream::get*()` except for `getTimestamp()`
 
 
 Note: When a stream uses a callback function, it's safe to read/write from the callback thread while also closing the stream
diff --git a/GettingStarted.md b/GettingStarted.md
index b1274f1db..c28e0a443 100644
--- a/GettingStarted.md
+++ b/GettingStarted.md
@@ -48,9 +48,9 @@ Include the Oboe header:
 
     #include 
 
-Streams are built using an `StreamBuilder`. Create one like this:
+Streams are built using an `OboeStreamBuilder`. Create one like this:
 
-    StreamBuilder builder;
+    OboeStreamBuilder builder;
 
 Use the builder's set methods to set properties on the stream (you can read more about these properties in the [full guide](FullGuide.md)):
 
@@ -58,12 +58,12 @@ Use the builder's set methods to set properties on the stream (you can read more
     builder.setPerformanceMode(OBOE_PERFORMANCE_MODE_LOW_LATENCY);
     builder.setSharingMode(OBOE_SHARING_MODE_EXCLUSIVE);
 
-Define an `StreamCallback` class to receive callbacks whenever the stream requires new data.
+Define an `OboeStreamCallback` class to receive callbacks whenever the stream requires new data.
 
-    class MyCallback : public StreamCallback {
+    class MyCallback : public OboeStreamCallback {
     public:
         oboe_data_callback_result_t
-        onAudioReady(Stream *audioStream, void *audioData, int32_t numFrames){
+        onAudioReady(OboeStream *audioStream, void *audioData, int32_t numFrames){
             generateSineWave(static_cast(audioData), numFrames);
             return OBOE_CALLBACK_RESULT_CONTINUE;
         }
@@ -76,18 +76,18 @@ Supply this callback class to the builder:
 
 Open the stream:
 
-    Stream *stream;
-    Result result = builder.openStream(&stream);
+    OboeStream *stream;
+    oboe_result_t result = builder.openStream(&stream);
 
 Check the result to make sure the stream was opened successfully. Oboe has many convenience methods for converting its types into human-readable strings, they all start with `Oboe_convert`:
 
-    if (result != OK){
+    if (result != OBOE_OK){
         LOGE("Failed to create stream. Error: %s", Oboe_convertResultToText(result));
     }
 
 Note that this sample code uses the [logging macros from here](https://github.com/googlesamples/android-audio-high-performance/blob/master/debug-utils/logging_macros.h).
 
-Check the properties of the created stream. The **format** is one property which you should check. The default is `float` on API 21+ and `int16_t` on API 20 or lower. This will dictate the `audioData` type in the `StreamCallback::onAudioReady` callback.
+Check the properties of the created stream. The **format** is one property which you should check. The default is `float` on API 21+ and `int16_t` on API 20 or lower. This will dictate the `audioData` type in the `OboeStreamCallback::onAudioReady` callback.
 
     oboe_audio_format_t format = stream->getFormat();
     LOGI("Stream format is %s", Oboe_convertAudioFormatToText(format));
diff --git a/build_all_android.sh b/build_all_android.sh
index 4c7e886f2..056769325 100755
--- a/build_all_android.sh
+++ b/build_all_android.sh
@@ -121,8 +121,8 @@ build_oboe x86_64 21
 printf "%s\r\n" "example: |" >> ${CDEP_MANIFEST_FILE}
 printf "%s\r\n" "  #include " >> ${CDEP_MANIFEST_FILE}
 printf "%s\r\n" "  void openStream() {" >> ${CDEP_MANIFEST_FILE}
-printf "%s\r\n" "    StreamBuilder builder;" >> ${CDEP_MANIFEST_FILE}
-printf "%s\r\n" "    Stream *stream;" >> ${CDEP_MANIFEST_FILE}
+printf "%s\r\n" "    OboeStreamBuilder builder;" >> ${CDEP_MANIFEST_FILE}
+printf "%s\r\n" "    OboeStream *stream;" >> ${CDEP_MANIFEST_FILE}
 printf "%s\r\n" "    builder.openStream(&stream);" >> ${CDEP_MANIFEST_FILE}
 printf "%s\r\n" "  }" >> ${CDEP_MANIFEST_FILE}
 
diff --git a/include/oboe/Definitions.h b/include/oboe/Definitions.h
deleted file mode 100644
index ce67c3b9a..000000000
--- a/include/oboe/Definitions.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef OBOE_DEFINITIONS_H
-#define OBOE_DEFINITIONS_H
-
-#include 
-#include 
-
-namespace oboe {
-
-    constexpr int32_t kUnspecified = 0;
-
-    constexpr int64_t kNanosPerMicrosecond =    1000;
-    constexpr int64_t kNanosPerMillisecond =    kNanosPerMicrosecond * 1000;
-    constexpr int64_t kMillisPerSecond =        1000;
-    constexpr int64_t kNanosPerSecond =         kNanosPerMillisecond * kMillisPerSecond;
-
-    enum class StreamState : aaudio_stream_state_t {
-        Uninitialized = AAUDIO_STREAM_STATE_UNINITIALIZED,
-        Open = AAUDIO_STREAM_STATE_OPEN,
-        Starting = AAUDIO_STREAM_STATE_STARTING,
-        Started = AAUDIO_STREAM_STATE_STARTED,
-        Pausing = AAUDIO_STREAM_STATE_PAUSING,
-        Paused = AAUDIO_STREAM_STATE_PAUSED,
-        Flushing = AAUDIO_STREAM_STATE_FLUSHING,
-        Flushed = AAUDIO_STREAM_STATE_FLUSHED,
-        Stopping = AAUDIO_STREAM_STATE_STOPPING,
-        Stopped = AAUDIO_STREAM_STATE_STOPPED,
-        Closing = AAUDIO_STREAM_STATE_CLOSING,
-        Closed = AAUDIO_STREAM_STATE_CLOSED,
-    };
-
-    enum class Direction : aaudio_direction_t {
-        Output = AAUDIO_DIRECTION_OUTPUT,
-        Input = AAUDIO_DIRECTION_INPUT,
-    };
-
-    enum class AudioFormat : aaudio_format_t {
-        Invalid = AAUDIO_FORMAT_INVALID,
-        Unspecified = AAUDIO_FORMAT_UNSPECIFIED,
-        I16 = AAUDIO_FORMAT_PCM_I16,
-        Float = AAUDIO_FORMAT_PCM_FLOAT,
-    };
-
-    enum class DataCallbackResult : aaudio_data_callback_result_t {
-        Continue = AAUDIO_CALLBACK_RESULT_CONTINUE,
-        Stop = AAUDIO_CALLBACK_RESULT_STOP,
-    };
-
-    enum class Result : aaudio_result_t {
-        OK,
-        ErrorBase = AAUDIO_ERROR_BASE,
-        ErrorDisconnected = AAUDIO_ERROR_DISCONNECTED,
-        ErrorIllegalArgument = AAUDIO_ERROR_ILLEGAL_ARGUMENT,
-        ErrorInternal = AAUDIO_ERROR_INTERNAL,
-        ErrorInvalidState = AAUDIO_ERROR_INVALID_STATE,
-        ErrorInvalidHandle = AAUDIO_ERROR_INVALID_HANDLE,
-        ErrorUnimplemented = AAUDIO_ERROR_UNIMPLEMENTED,
-        ErrorUnavailable = AAUDIO_ERROR_UNAVAILABLE,
-        ErrorNoFreeHandles = AAUDIO_ERROR_NO_FREE_HANDLES,
-        ErrorNoMemory = AAUDIO_ERROR_NO_MEMORY,
-        ErrorNull = AAUDIO_ERROR_NULL,
-        ErrorTimeout = AAUDIO_ERROR_TIMEOUT,
-        ErrorWouldBlock = AAUDIO_ERROR_WOULD_BLOCK,
-        ErrorInvalidFormat = AAUDIO_ERROR_INVALID_FORMAT,
-        ErrorOutOfRange = AAUDIO_ERROR_OUT_OF_RANGE,
-        ErrorNoService = AAUDIO_ERROR_NO_SERVICE,
-        ErrorInvalidRate = AAUDIO_ERROR_INVALID_RATE,
-    };
-
-    enum class SharingMode : aaudio_sharing_mode_t {
-
-        /**
-         * 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.
-         */
-        Exclusive = AAUDIO_SHARING_MODE_EXCLUSIVE,
-
-        /**
-         * Multiple applications will be mixed by the AAudio Server.
-         * This will have higher latency than the EXCLUSIVE mode.
-         */
-        Shared = AAUDIO_SHARING_MODE_SHARED,
-    };
-
-    enum class PerformanceMode : aaudio_performance_mode_t {
-
-        // No particular performance needs. Default.
-        None = AAUDIO_PERFORMANCE_MODE_NONE,
-
-        // Extending battery life is most important.
-        PowerSaving = AAUDIO_PERFORMANCE_MODE_POWER_SAVING,
-
-        // Reducing latency is most important.
-        LowLatency = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
-    };
-} // namespace oboe
-
-#endif // OBOE_DEFINITIONS_H
diff --git a/include/oboe/Oboe.h b/include/oboe/Oboe.h
index 6faaef7d2..eab021ca8 100644
--- a/include/oboe/Oboe.h
+++ b/include/oboe/Oboe.h
@@ -17,11 +17,11 @@
 #ifndef OBOE_OBOE_H
 #define OBOE_OBOE_H
 
-#include "oboe/Definitions.h"
-#include "oboe/LatencyTuner.h"
-#include "oboe/Stream.h"
-#include "oboe/StreamBase.h"
-#include "oboe/StreamBuilder.h"
-#include "oboe/Utilities.h"
+#include "oboe/OboeDefinitions.h"
+#include "oboe/OboeLatencyTuner.h"
+#include "oboe/OboeStream.h"
+#include "oboe/OboeStreamBase.h"
+#include "oboe/OboeStreamBuilder.h"
+#include "oboe/OboeUtilities.h"
 
 #endif //OBOE_OBOE_H
diff --git a/include/oboe/OboeDefinitions.h b/include/oboe/OboeDefinitions.h
new file mode 100644
index 000000000..6c7a8f194
--- /dev/null
+++ b/include/oboe/OboeDefinitions.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OBOE_OBOE_DEFINITIONS_H
+#define OBOE_OBOE_DEFINITIONS_H
+
+#include 
+#include 
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef aaudio_result_t  oboe_result_t;
+
+/**
+ * This is used to represent a value that has not been specified.
+ * For example, an application could use OBOE_UNSPECIFIED to indicate
+ * that it did not not care what the specific value of a parameter was
+ * and would accept whatever it was given.
+ */
+#define OBOE_UNSPECIFIED           0
+#define OBOE_NANOS_PER_MICROSECOND ((int64_t)1000)
+#define OBOE_NANOS_PER_MILLISECOND (OBOE_NANOS_PER_MICROSECOND * 1000)
+#define OBOE_MILLIS_PER_SECOND     1000
+#define OBOE_NANOS_PER_SECOND      (OBOE_NANOS_PER_MILLISECOND * OBOE_MILLIS_PER_SECOND)
+
+#define oboe_direction_t aaudio_direction_t
+#define OBOE_DIRECTION_OUTPUT AAUDIO_DIRECTION_OUTPUT
+#define OBOE_DIRECTION_INPUT AAUDIO_DIRECTION_INPUT
+
+#define oboe_audio_format_t aaudio_format_t
+#define OBOE_AUDIO_FORMAT_INVALID     AAUDIO_FORMAT_INVALID
+#define OBOE_AUDIO_FORMAT_UNSPECIFIED AAUDIO_FORMAT_UNSPECIFIED
+#define OBOE_AUDIO_FORMAT_PCM_I16     AAUDIO_FORMAT_PCM_I16
+#define OBOE_AUDIO_FORMAT_PCM_FLOAT   AAUDIO_FORMAT_PCM_FLOAT
+
+#define oboe_data_callback_result_t   aaudio_data_callback_result_t
+#define OBOE_CALLBACK_RESULT_CONTINUE AAUDIO_CALLBACK_RESULT_CONTINUE
+#define OBOE_CALLBACK_RESULT_STOP     AAUDIO_CALLBACK_RESULT_STOP
+
+enum {
+    OBOE_OK,
+    OBOE_ERROR_BASE = AAUDIO_ERROR_BASE,
+    OBOE_ERROR_DISCONNECTED = AAUDIO_ERROR_DISCONNECTED,
+    OBOE_ERROR_ILLEGAL_ARGUMENT = AAUDIO_ERROR_ILLEGAL_ARGUMENT,
+    // Reserved
+    OBOE_ERROR_INTERNAL = AAUDIO_ERROR_INTERNAL,
+    OBOE_ERROR_INVALID_STATE = AAUDIO_ERROR_INVALID_STATE,
+    // Reserved
+    // Reserved
+    OBOE_ERROR_INVALID_HANDLE = AAUDIO_ERROR_INVALID_HANDLE,
+    // Reserved
+    OBOE_ERROR_UNIMPLEMENTED = AAUDIO_ERROR_UNIMPLEMENTED,
+    OBOE_ERROR_UNAVAILABLE = AAUDIO_ERROR_UNAVAILABLE,
+    OBOE_ERROR_NO_FREE_HANDLES = AAUDIO_ERROR_NO_FREE_HANDLES,
+    OBOE_ERROR_NO_MEMORY = AAUDIO_ERROR_NO_MEMORY,
+    OBOE_ERROR_NULL = AAUDIO_ERROR_NULL,
+    OBOE_ERROR_TIMEOUT = AAUDIO_ERROR_TIMEOUT,
+    OBOE_ERROR_WOULD_BLOCK = AAUDIO_ERROR_WOULD_BLOCK,
+    OBOE_ERROR_INVALID_FORMAT = AAUDIO_ERROR_INVALID_FORMAT,
+    OBOE_ERROR_OUT_OF_RANGE = AAUDIO_ERROR_OUT_OF_RANGE,
+    OBOE_ERROR_NO_SERVICE = AAUDIO_ERROR_NO_SERVICE,
+    OBOE_ERROR_INVALID_RATE = AAUDIO_ERROR_INVALID_RATE
+};
+
+#define oboe_stream_state_t aaudio_stream_state_t
+
+#define OBOE_STREAM_STATE_UNINITIALIZED AAUDIO_STREAM_STATE_UNINITIALIZED
+#define OBOE_STREAM_STATE_OPEN      AAUDIO_STREAM_STATE_OPEN
+#define OBOE_STREAM_STATE_STARTING  AAUDIO_STREAM_STATE_STARTING
+#define OBOE_STREAM_STATE_STARTED   AAUDIO_STREAM_STATE_STARTED
+#define OBOE_STREAM_STATE_PAUSING   AAUDIO_STREAM_STATE_PAUSING
+#define OBOE_STREAM_STATE_PAUSED    AAUDIO_STREAM_STATE_PAUSED
+#define OBOE_STREAM_STATE_FLUSHING  AAUDIO_STREAM_STATE_FLUSHING
+#define OBOE_STREAM_STATE_FLUSHED   AAUDIO_STREAM_STATE_FLUSHED
+#define OBOE_STREAM_STATE_STOPPING  AAUDIO_STREAM_STATE_STOPPING
+#define OBOE_STREAM_STATE_STOPPED   AAUDIO_STREAM_STATE_STOPPED
+#define OBOE_STREAM_STATE_CLOSING   AAUDIO_STREAM_STATE_CLOSING
+#define OBOE_STREAM_STATE_CLOSED    AAUDIO_STREAM_STATE_CLOSED
+
+#define oboe_sharing_mode_t aaudio_sharing_mode_t
+
+    /**
+     * 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.
+     */
+#define OBOE_SHARING_MODE_EXCLUSIVE   AAUDIO_SHARING_MODE_EXCLUSIVE
+    /**
+     * Multiple applications will be mixed by the Oboe Server.
+     * This will have higher latency than the EXCLUSIVE mode.
+     */
+#define OBOE_SHARING_MODE_SHARED      AAUDIO_SHARING_MODE_SHARED
+
+    /**
+     * No particular performance needs. Default.
+     */
+#define OBOE_PERFORMANCE_MODE_NONE AAUDIO_PERFORMANCE_MODE_NONE
+
+    /**
+     * Extending battery life is most important.
+     */
+#define OBOE_PERFORMANCE_MODE_POWER_SAVING AAUDIO_PERFORMANCE_MODE_POWER_SAVING
+
+    /**
+     * Reducing latency is most important.
+     */
+#define OBOE_PERFORMANCE_MODE_LOW_LATENCY  AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
+
+#define oboe_performance_mode_t  aaudio_performance_mode_t
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // OBOE_OBOE_DEFINITIONS_H
diff --git a/include/oboe/LatencyTuner.h b/include/oboe/OboeLatencyTuner.h
similarity index 81%
rename from include/oboe/LatencyTuner.h
rename to include/oboe/OboeLatencyTuner.h
index 0cab7ec41..b5ac6c617 100644
--- a/include/oboe/LatencyTuner.h
+++ b/include/oboe/OboeLatencyTuner.h
@@ -14,15 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_LATENCY_TUNER_
-#define OBOE_LATENCY_TUNER_
+#ifndef OBOE_OBOE_LATENCY_TUNER_
+#define OBOE_OBOE_LATENCY_TUNER_
 
 #include 
-#include 
-#include "oboe/Definitions.h"
-#include "oboe/Stream.h"
-
-namespace oboe {
+#include 
+#include "oboe/OboeDefinitions.h"
+#include "oboe/OboeStream.h"
 
 /**
  * This can be used to dynamically tune the latency of an output stream.
@@ -39,9 +37,9 @@ namespace oboe {
  * stream->getBufferSize() periodically.
  *
  */
-class LatencyTuner {
+class OboeLatencyTuner {
 public:
-    explicit LatencyTuner(Stream &stream);
+    explicit OboeLatencyTuner(OboeStream &stream);
 
     /**
      * Adjust the bufferSizeInFrames to optimize latency.
@@ -51,7 +49,7 @@ class LatencyTuner {
      *
      * @return OBOE_OK or negative error, OBOE_ERROR_UNIMPLEMENTED for OpenSL ES
      */
-    Result tune();
+    oboe_result_t tune();
 
     /**
      * This may be called from another thread. Then tune() will call reset(),
@@ -73,24 +71,23 @@ class LatencyTuner {
      */
     void reset();
 
-    enum class State {
-        Idle,
-        Active,
-        AtMax,
-        Unsupported
+    enum latency_tuner_state_t {
+        STATE_IDLE,
+        STATE_ACTIVE,
+        STATE_AT_MAX,
+        STATE_UNSUPPORTED
     } ;
 
-    // arbitrary number of calls to wait before bumping up the latency
-    static constexpr int32_t kIdleCount = 8;
+    enum {
+        IDLE_COUNT = 8 // arbitrary number of calls to wait before bumping up the latency
+    };
 
-    Stream               &mStream;
-    State                 mState = State::Idle;
+    OboeStream           &mStream;
+    latency_tuner_state_t mState = STATE_IDLE;
     int32_t               mPreviousXRuns = 0;
     int32_t               mIdleCountDown = 0;
     std::atomic  mLatencyTriggerRequests{0}; // TODO user atomic requester from AAudio
     std::atomic  mLatencyTriggerResponses{0};
 };
 
-} // namespace oboe
-
-#endif // OBOE_LATENCY_TUNER_
+#endif // OBOE_OBOE_LATENCY_TUNER_
diff --git a/include/oboe/Stream.h b/include/oboe/OboeStream.h
similarity index 71%
rename from include/oboe/Stream.h
rename to include/oboe/OboeStream.h
index 4ed66bd24..d3a7f9d80 100644
--- a/include/oboe/Stream.h
+++ b/include/oboe/OboeStream.h
@@ -14,31 +14,31 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_STREAM_H_
-#define OBOE_STREAM_H_
+#ifndef OBOE_OBOE_STREAM_H_
+#define OBOE_OBOE_STREAM_H_
 
-#include 
-#include 
-#include "oboe/Definitions.h"
-#include "oboe/StreamBuilder.h"
-#include "oboe/StreamBase.h"
+#include 
+#include 
+#include "oboe/OboeDefinitions.h"
+#include "oboe/OboeStreamCallback.h"
+#include "oboe/OboeStreamBase.h"
 
 /** WARNING - UNDER CONSTRUCTION - THIS API WILL CHANGE. */
 
-namespace oboe {
+class OboeStreamBuilder;
 
-constexpr int64_t kDefaultTimeoutNanos = (2000 * kNanosPerMillisecond);
+#define DEFAULT_TIMEOUT_NANOS    (2000 * OBOE_NANOS_PER_MILLISECOND)
 
 /**
  * Base class for Oboe C++ audio stream.
  */
-class Stream : public StreamBase {
+class OboeStream : public OboeStreamBase {
 public:
 
-    Stream() {}
-    explicit Stream(const StreamBuilder &builder);
+    OboeStream() {}
+    explicit OboeStream(const OboeStreamBuilder &builder);
 
-    virtual ~Stream() = default;
+    virtual ~OboeStream() = default;
 
     /**
      * Open a stream based on the current settings.
@@ -48,35 +48,35 @@ class Stream : public StreamBase {
      *
      * @return
      */
-    virtual Result open();
+    virtual oboe_result_t open();
 
     /**
      * Close the stream and deallocate any resources from the open() call.
      */
-    virtual Result close() = 0;
+    virtual oboe_result_t close() = 0;
 
     /*
      * These are synchronous and will block until the operation is complete.
      */
-    virtual Result start(int64_t timeoutNanoseconds = kDefaultTimeoutNanos);
-    virtual Result pause(int64_t timeoutNanoseconds = kDefaultTimeoutNanos);
-    virtual Result flush(int64_t timeoutNanoseconds = kDefaultTimeoutNanos);
-    virtual Result stop(int64_t timeoutNanoseconds = kDefaultTimeoutNanos);
+    virtual oboe_result_t start(int64_t timeoutNanoseconds = DEFAULT_TIMEOUT_NANOS);
+    virtual oboe_result_t pause(int64_t timeoutNanoseconds = DEFAULT_TIMEOUT_NANOS);
+    virtual oboe_result_t flush(int64_t timeoutNanoseconds = DEFAULT_TIMEOUT_NANOS);
+    virtual oboe_result_t stop(int64_t timeoutNanoseconds = DEFAULT_TIMEOUT_NANOS);
 
     /* Asynchronous requests.
      * Use waitForStateChange() if you need to wait for completion.
      */
-    virtual Result requestStart() = 0;
-    virtual Result requestPause() = 0;
-    virtual Result requestFlush() = 0;
-    virtual Result requestStop() = 0;
+    virtual oboe_result_t requestStart() = 0;
+    virtual oboe_result_t requestPause() = 0;
+    virtual oboe_result_t requestFlush() = 0;
+    virtual oboe_result_t requestStop() = 0;
 
     /**
      * Query the current state, eg. OBOE_STREAM_STATE_PAUSING
      *
      * @return state or a negative error.
      */
-    virtual StreamState getState() = 0;
+    virtual oboe_stream_state_t getState() = 0;
 
     /**
      * Wait until the current state no longer matches the input state.
@@ -88,7 +88,7 @@ class Stream : public StreamBase {
      *
      * 

      * int64_t timeoutNanos = 500 * OBOE_NANOS_PER_MILLISECOND; // arbitrary 1/2 second
-     * StreamState currentState = stream->getState(stream);
+     * oboe_stream_state_t currentState = stream->getState(stream);
      * while (currentState >= 0 && currentState != OBOE_STREAM_STATE_PAUSED) {
      *     currentState = stream->waitForStateChange(
      *                                   stream, currentState, timeoutNanos);
@@ -101,8 +101,8 @@ class Stream : public StreamBase {
      * @param timeoutNanoseconds The maximum time to wait in nanoseconds.
      * @return OBOE_OK or a negative error.
      */
-    virtual Result waitForStateChange(StreamState currentState,
-                                          StreamState *nextState,
+    virtual oboe_result_t waitForStateChange(oboe_stream_state_t currentState,
+                                          oboe_stream_state_t *nextState,
                                           int64_t timeoutNanoseconds) = 0;
 
 
@@ -118,8 +118,8 @@ class Stream : public StreamBase {
     * @param requestedFrames requested number of frames that can be filled without blocking
     * @return resulting buffer size in frames or a negative error
     */
-    virtual Result setBufferSizeInFrames(int32_t requestedFrames) {
-        return Result::ErrorUnimplemented;
+    virtual oboe_result_t setBufferSizeInFrames(int32_t requestedFrames) {
+        return OBOE_ERROR_UNIMPLEMENTED;
     }
 
     /**
@@ -134,7 +134,7 @@ class Stream : public StreamBase {
      * @return the count or negative error.
      */
     virtual int32_t getXRunCount() {
-        return static_cast(Result::ErrorUnimplemented);
+        return OBOE_ERROR_UNIMPLEMENTED;
     }
 
     /**
@@ -146,7 +146,7 @@ class Stream : public StreamBase {
 
     bool isPlaying();
 
-    StreamCallback *getCallback() const { return mStreamCallback; }
+    OboeStreamCallback *getCallback() const { return mStreamCallback; }
 
     int32_t getBytesPerFrame() const { return mChannelCount * getBytesPerSample(); }
 
@@ -158,12 +158,12 @@ class Stream : public StreamBase {
      */
     virtual int64_t getFramesWritten() { return mFramesWritten; }
 
-    virtual int64_t getFramesRead() { return static_cast(Result::ErrorUnimplemented); }
+    virtual int64_t getFramesRead() { return OBOE_ERROR_UNIMPLEMENTED; }
 
-    virtual Result getTimestamp(clockid_t clockId,
+    virtual oboe_result_t getTimestamp(clockid_t clockId,
                                        int64_t *framePosition,
                                        int64_t *timeNanoseconds) {
-        return Result::ErrorUnimplemented;
+        return OBOE_ERROR_UNIMPLEMENTED;
     }
 
     // ============== I/O ===========================
@@ -177,16 +177,16 @@ class Stream : public StreamBase {
      * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
      * @return The number of frames actually written or a negative error.
      */
-    virtual int32_t write(const void *buffer,
+    virtual oboe_result_t write(const void *buffer,
                              int32_t numFrames,
                              int64_t timeoutNanoseconds) {
-        return static_cast(Result::ErrorUnimplemented);
+        return OBOE_ERROR_UNIMPLEMENTED;
     }
 
-    virtual int32_t read(void *buffer,
+    virtual oboe_result_t read(void *buffer,
                             int32_t numFrames,
                             int64_t timeoutNanoseconds) {
-        return static_cast(Result::ErrorUnimplemented);
+        return OBOE_ERROR_UNIMPLEMENTED;
     }
 
     /**
@@ -209,25 +209,24 @@ class Stream : public StreamBase {
      *   if any state that was not the startingState or endingState was observed
      *   or OBOE_ERROR_TIMEOUT.
      */
-    virtual Result waitForStateTransition(StreamState startingState,
-                                              StreamState endingState,
+    virtual oboe_result_t waitForStateTransition(oboe_stream_state_t startingState,
+                                              oboe_stream_state_t endingState,
                                               int64_t timeoutNanoseconds);
 
-    Result fireCallback(void *audioData, int numFrames);
+    oboe_result_t fireCallback(void *audioData, int numFrames);
 
-    virtual void setNativeFormat(AudioFormat format) {
+    virtual void setNativeFormat(oboe_audio_format_t format) {
         mNativeFormat = format;
     }
 
-    // TODO: make private
+    // TODO make private
     // These do not change after open.
-    AudioFormat mNativeFormat = AudioFormat::Invalid;
+    oboe_audio_format_t  mNativeFormat = OBOE_AUDIO_FORMAT_INVALID;
 
 private:
     int64_t              mFramesWritten = 0;
     int                  mPreviousScheduler = -1;
 };
 
-} // namespace oboe
 
-#endif /* OBOE_STREAM_H_ */
+#endif /* OBOE_OBOE_STREAM_H_ */
diff --git a/include/oboe/StreamBase.h b/include/oboe/OboeStreamBase.h
similarity index 60%
rename from include/oboe/StreamBase.h
rename to include/oboe/OboeStreamBase.h
index 1ae131da1..8b77d56cd 100644
--- a/include/oboe/StreamBase.h
+++ b/include/oboe/OboeStreamBase.h
@@ -14,13 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_STREAM_BASE_H_
-#define OBOE_STREAM_BASE_H_
+#ifndef OBOE_OBOE_STREAM_BASE_H_
+#define OBOE_OBOE_STREAM_BASE_H_
 
-#include "oboe/StreamCallback.h"
-#include "oboe/Definitions.h"
-
-namespace oboe {
+#include "oboe/OboeStreamCallback.h"
+#include "oboe/OboeDefinitions.h"
 
 /**
  * Base class containing parameters for Oboe streams and builders.
@@ -30,17 +28,17 @@ namespace oboe {
  * OboeStream will generally return the actual final value, but getFramesPerCallback()
  * can be unspecified even for a stream.
  */
-class StreamBase {
+class OboeStreamBase {
 public:
 
-    StreamBase() {}
+    OboeStreamBase() {}
 
-    virtual ~StreamBase() = default;
+    virtual ~OboeStreamBase() = default;
 
     // This class only contains primitives so we can use default constructor and copy methods.
-    StreamBase(const StreamBase&) = default;
+    OboeStreamBase(const OboeStreamBase&) = default;
 
-    StreamBase& operator=(const StreamBase&) = default;
+    OboeStreamBase& operator=(const OboeStreamBase&) = default;
 
     /**
      * @return number of channels, for example 2 for stereo
@@ -48,9 +46,9 @@ class StreamBase {
     int getChannelCount() const { return mChannelCount; }
 
     /**
-     * @return Direction::Input or Direction::Output
+     * @return OBOE_DIRECTION_INPUT or OBOE_DIRECTION_OUTPUT
      */
-    Direction getDirection() const { return mDirection; }
+    oboe_direction_t getDirection() const { return mDirection; }
 
     /**
      * @return sample rate for the stream
@@ -66,7 +64,7 @@ class StreamBase {
      * @return OBOE_AUDIO_FORMAT_PCM_FLOAT, OBOE_AUDIO_FORMAT_PCM_I16
      *         or OBOE_AUDIO_FORMAT_UNSPECIFIED
      */
-    AudioFormat getFormat() const { return mFormat; }
+    oboe_audio_format_t getFormat() const { return mFormat; }
 
     /**
      * Query the maximum number of frames that can be filled without blocking.
@@ -83,30 +81,28 @@ class StreamBase {
      */
     virtual int32_t getBufferCapacityInFrames() const { return mBufferCapacityInFrames; }
 
-    SharingMode getSharingMode() const { return mSharingMode; }
+    oboe_sharing_mode_t getSharingMode() const { return mSharingMode; }
 
-    PerformanceMode getPerformanceMode() const { return mPerformanceMode; }
+    oboe_performance_mode_t getPerformanceMode() const { return mPerformanceMode; }
 
     int32_t getDeviceId() const { return mDeviceId; }
 
-    StreamCallback *getCallback() const {
+    OboeStreamCallback *getCallback() const {
         return mStreamCallback;
     }
 
 protected:
-    StreamCallback         *mStreamCallback = NULL;
-    int32_t                 mFramesPerCallback = kUnspecified;
-    int32_t                 mChannelCount = kUnspecified;
-    int32_t                 mSampleRate = kUnspecified;
-    int32_t                 mDeviceId = kUnspecified;
-    int32_t                 mBufferCapacityInFrames = kUnspecified;
-
-    SharingMode             mSharingMode = SharingMode::Shared;
-    AudioFormat                  mFormat = AudioFormat::Unspecified;
-    Direction               mDirection = Direction::Output;
-    PerformanceMode         mPerformanceMode = PerformanceMode::None;
+    OboeStreamCallback     *mStreamCallback = NULL;
+    int32_t                 mFramesPerCallback = OBOE_UNSPECIFIED;
+    int32_t                 mChannelCount = OBOE_UNSPECIFIED;
+    int32_t                 mSampleRate = OBOE_UNSPECIFIED;
+    int32_t                 mDeviceId = OBOE_UNSPECIFIED;
+    int32_t                 mBufferCapacityInFrames = OBOE_UNSPECIFIED;
+
+    oboe_sharing_mode_t     mSharingMode = OBOE_SHARING_MODE_SHARED;
+    oboe_audio_format_t     mFormat = OBOE_AUDIO_FORMAT_UNSPECIFIED;
+    oboe_direction_t        mDirection = OBOE_DIRECTION_OUTPUT;
+    oboe_performance_mode_t mPerformanceMode = OBOE_PERFORMANCE_MODE_NONE;
 };
 
-} // namespace oboe
-
-#endif /* OBOE_STREAM_BASE_H_ */
+#endif /* OBOE_OBOE_STREAM_BASE_H_ */
diff --git a/include/oboe/StreamBuilder.h b/include/oboe/OboeStreamBuilder.h
similarity index 77%
rename from include/oboe/StreamBuilder.h
rename to include/oboe/OboeStreamBuilder.h
index f46e702e4..ecb854241 100644
--- a/include/oboe/StreamBuilder.h
+++ b/include/oboe/OboeStreamBuilder.h
@@ -14,39 +14,36 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_STREAM_BUILDER_H_
-#define OBOE_STREAM_BUILDER_H_
+#ifndef OBOE_OBOE_STREAM_BUILDER_H_
+#define OBOE_OBOE_STREAM_BUILDER_H_
 
-#include "oboe/Definitions.h"
-#include "oboe/StreamBase.h"
-
-namespace oboe {
-
-constexpr int32_t kDefaultFramesPerBurst = 192; // arbitrary value, 4 msec at 48000 Hz
+#include "OboeStreamBase.h"
+#include "OboeStream.h"
+#include "oboe/OboeDefinitions.h"
 
 /**
- * Factory class for an audio Stream.
+ * Factory class for an AudioStream.
  */
-class StreamBuilder : public StreamBase {
+class OboeStreamBuilder : public OboeStreamBase {
 public:
 
-    StreamBuilder() : StreamBase() {}
+    OboeStreamBuilder() : OboeStreamBase() {}
 
-    enum class AudioApi {
+    enum audio_api_index_t {
         /**
          * Try to use AAudio. If not available then use OpenSL ES.
          */
-        Unspecified,
+        API_UNSPECIFIED,
 
         /**
          * Use OpenSL ES.
          */
-        OpenSLES,
+        API_OPENSL_ES,
 
         /**
          * Try to use AAudio. Fail if unavailable.
          */
-        AAudio
+        API_AAUDIO
     };
 
 
@@ -56,7 +53,7 @@ class StreamBuilder : public StreamBase {
      * Default is OBOE_UNSPECIFIED. If the value is unspecified then
      * the application should query for the actual value after the stream is opened.
      */
-    StreamBuilder *setChannelCount(int channelCount) {
+    OboeStreamBuilder *setChannelCount(int channelCount) {
         mChannelCount = channelCount;
         return this;
     }
@@ -64,9 +61,9 @@ class StreamBuilder : public StreamBase {
     /**
      * Request the direction for a stream. The default is OBOE_DIRECTION_OUTPUT.
      *
-     * @param direction Direction::Output or Direction::Input
+     * @param direction OBOE_DIRECTION_OUTPUT or OBOE_DIRECTION_INPUT
      */
-    StreamBuilder *setDirection(Direction direction) {
+    OboeStreamBuilder *setDirection(oboe_direction_t direction) {
         mDirection = direction;
         return this;
     }
@@ -82,7 +79,7 @@ class StreamBuilder : public StreamBase {
      * But it is traditionally called "sample rate". Se we use that term.
      *
      */
-    StreamBuilder *setSampleRate(int32_t sampleRate) {
+    OboeStreamBuilder *setSampleRate(int32_t sampleRate) {
         mSampleRate = sampleRate;
         return this;
     }
@@ -90,7 +87,7 @@ class StreamBuilder : public StreamBase {
     /**
      * Request a specific number of frames for the data callback.
      *
-     * Default is kUnspecified. If the value is unspecified then
+     * Default is OBOE_UNSPECIFIED. If the value is unspecified then
      * the actual number may vary from callback to callback.
      *
      * If an application can handle a varying number of frames then we recommend
@@ -101,18 +98,18 @@ class StreamBuilder : public StreamBase {
      * @param framesPerCallback
      * @return
      */
-    StreamBuilder *setFramesPerCallback(int framesPerCallback) {
+    OboeStreamBuilder *setFramesPerCallback(int framesPerCallback) {
         mFramesPerCallback = framesPerCallback;
         return this;
     }
 
     /**
-     * Request a sample data format, for example Format::Float.
+     * Request a sample data format, for example OBOE_FORMAT_PCM_FLOAT.
      *
-     * Default is Format::Unspecified. If the value is unspecified then
+     * Default is OBOE_UNSPECIFIED. If the value is unspecified then
      * the application should query for the actual value after the stream is opened.
      */
-    StreamBuilder *setFormat(AudioFormat format) {
+    OboeStreamBuilder *setFormat(oboe_audio_format_t format) {
         mFormat = format;
         return this;
     }
@@ -126,12 +123,12 @@ class StreamBuilder : public StreamBase {
      * @param frames the desired buffer capacity in frames or OBOE_UNSPECIFIED
      * @return pointer to the builder so calls can be chained
      */
-    StreamBuilder *setBufferCapacityInFrames(int32_t bufferCapacityInFrames) {
+    OboeStreamBuilder *setBufferCapacityInFrames(int32_t bufferCapacityInFrames) {
         mBufferCapacityInFrames = bufferCapacityInFrames;
         return this;
     }
 
-    AudioApi getApiIndex() const { return mAudioApi; }
+    audio_api_index_t getApiIndex() const { return mAudioApi; }
 
     /**
      * Normally you would leave this unspecified, and Oboe will chose the best API
@@ -139,7 +136,7 @@ class StreamBuilder : public StreamBase {
      * @param Must be API_UNSPECIFIED, API_OPENSL_ES or API_AAUDIO.
      * @return pointer to the builder so calls can be chained
      */
-    StreamBuilder *setApiIndex(AudioApi apiIndex) {
+    OboeStreamBuilder *setApiIndex(audio_api_index_t apiIndex) {
         mAudioApi = apiIndex;
         return this;
     }
@@ -158,10 +155,10 @@ class StreamBuilder : public StreamBase {
      * The requested sharing mode may not be available.
      * So the application should query for the actual mode after the stream is opened.
      *
-     * @param sharingMode SharingMode::Shared or SharingMode::Exclusive
+     * @param sharingMode OBOE_SHARING_MODE_LEGACY or OBOE_SHARING_MODE_EXCLUSIVE
      * @return pointer to the builder so calls can be chained
      */
-    StreamBuilder *setSharingMode(SharingMode sharingMode) {
+    OboeStreamBuilder *setSharingMode(oboe_sharing_mode_t sharingMode) {
         mSharingMode = sharingMode;
         return this;
     }
@@ -174,7 +171,7 @@ class StreamBuilder : public StreamBase {
      * @param performanceMode for example, OBOE_PERFORMANCE_MODE_LOW_LATENCY
      * @return pointer to the builder so calls can be chained
      */
-    StreamBuilder *setPerformanceMode(PerformanceMode performanceMode) {
+    OboeStreamBuilder *setPerformanceMode(oboe_performance_mode_t performanceMode) {
         mPerformanceMode = performanceMode;
         return this;
     }
@@ -188,7 +185,7 @@ class StreamBuilder : public StreamBase {
      * @param deviceId device identifier or OBOE_DEVICE_UNSPECIFIED
      * @return pointer to the builder so calls can be chained
      */
-    StreamBuilder *setDeviceId(int32_t deviceId) {
+    OboeStreamBuilder *setDeviceId(int32_t deviceId) {
         mDeviceId = deviceId;
         return this;
     }
@@ -202,7 +199,7 @@ class StreamBuilder : public StreamBase {
      * @param streamCallback
      * @return
      */
-    StreamBuilder *setCallback(StreamCallback *streamCallback) {
+    OboeStreamBuilder *setCallback(OboeStreamCallback *streamCallback) {
         mStreamCallback = streamCallback;
         return this;
     }
@@ -225,7 +222,7 @@ class StreamBuilder : public StreamBase {
      * @param defaultFramesPerBurst
      * @return pointer to the builder so calls can be chained
      */
-    StreamBuilder *setDefaultFramesPerBurst(int32_t defaultFramesPerBurst) {
+    OboeStreamBuilder *setDefaultFramesPerBurst(int32_t defaultFramesPerBurst) {
         mDefaultFramesPerBurst = defaultFramesPerBurst;
         return this;
     }
@@ -240,7 +237,7 @@ class StreamBuilder : public StreamBase {
      * @param stream pointer to a variable to receive the stream address
      * @return OBOE_OK if successful or a negative error code
      */
-    Result openStream(Stream **stream);
+    oboe_result_t openStream(OboeStream **stream);
 
 protected:
 
@@ -251,13 +248,11 @@ class StreamBuilder : public StreamBase {
      *
      * @return pointer to an AudioStream object.
      */
-    oboe::Stream *build();
+    OboeStream *build();
 
-    AudioApi       mAudioApi = AudioApi::Unspecified;
+    audio_api_index_t       mAudioApi = API_UNSPECIFIED;
 
-    int32_t        mDefaultFramesPerBurst = kDefaultFramesPerBurst;
+    int32_t                 mDefaultFramesPerBurst = 192; // arbitrary value, 4 msec at 48000 Hz
 };
 
-} // namespace oboe
-
-#endif /* OBOE_STREAM_BUILDER_H_ */
+#endif /* OBOE_OBOE_STREAM_BUILDER_H_ */
diff --git a/include/oboe/StreamCallback.h b/include/oboe/OboeStreamCallback.h
similarity index 74%
rename from include/oboe/StreamCallback.h
rename to include/oboe/OboeStreamCallback.h
index cdbb16613..da69978f1 100644
--- a/include/oboe/StreamCallback.h
+++ b/include/oboe/OboeStreamCallback.h
@@ -14,18 +14,16 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_STREAM_CALLBACK_H
-#define OBOE_STREAM_CALLBACK_H
+#ifndef OBOE_OBOE_STREAM_CALLBACK_H
+#define OBOE_OBOE_STREAM_CALLBACK_H
 
-#include "oboe/Definitions.h"
+#include "oboe/OboeDefinitions.h"
 
-namespace oboe {
+class OboeStream;
 
-class Stream;
-
-class StreamCallback {
+class OboeStreamCallback {
 public:
-    virtual ~StreamCallback() = default;
+    virtual ~OboeStreamCallback() = default;
 
     /**
      * A buffer is ready for processing.
@@ -33,10 +31,10 @@ class StreamCallback {
      * @param oboeStream pointer to the associated stream
      * @param audioData buffer containing input data or a place to put output data
      * @param numFrames number of frames to be processed
-     * @return DataCallbackResult::Continue or DataCallbackResult::Stop
+     * @return OBOE_CALLBACK_RESULT_CONTINUE or OBOE_CALLBACK_RESULT_STOP
      */
-    virtual DataCallbackResult onAudioReady(
-            Stream *oboeStream,
+    virtual oboe_data_callback_result_t onAudioReady(
+            OboeStream *oboeStream,
             void *audioData,
             int32_t numFrames) = 0;
 
@@ -48,7 +46,7 @@ class StreamCallback {
      * @param oboeStream pointer to the associated stream
      * @param error
      */
-    virtual void onErrorBeforeClose(Stream *oboeStream, Result error) {}
+    virtual void onErrorBeforeClose(OboeStream *oboeStream, oboe_result_t error) {}
 
     /**
      * This will be called when an error occurs on a stream or when the stream is disconnected.
@@ -60,10 +58,8 @@ class StreamCallback {
      * @param oboeStream pointer to the associated stream
      * @param error
      */
-    virtual void onErrorAfterClose(Stream *oboeStream, Result error) {}
+    virtual void onErrorAfterClose(OboeStream *oboeStream, oboe_result_t error) {}
 
 };
 
-} // namespace oboe
-
-#endif //OBOE_STREAM_CALLBACK_H
+#endif //OBOE_OBOE_STREAM_CALLBACK_H
diff --git a/include/oboe/Utilities.h b/include/oboe/OboeUtilities.h
similarity index 76%
rename from include/oboe/Utilities.h
rename to include/oboe/OboeUtilities.h
index 14f77dd74..a5ccbd437 100644
--- a/include/oboe/Utilities.h
+++ b/include/oboe/OboeUtilities.h
@@ -14,22 +14,20 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_UTILITIES_H
-#define OBOE_UTILITIES_H
+#ifndef OBOE_OBOE_UTILITIES_H
+#define OBOE_OBOE_UTILITIES_H
 
 #include 
 #include 
-#include "oboe/Definitions.h"
+#include "oboe/OboeDefinitions.h"
 
-namespace oboe {
-
-void convertFloatToPcm16(const float *source, int16_t *destination, int32_t numSamples);
-void convertPcm16ToFloat(const int16_t *source, float *destination, int32_t numSamples);
+void Oboe_convertFloatToPcm16(const float *source, int16_t *destination, int32_t numSamples);
+void Oboe_convertPcm16ToFloat(const int16_t *source, float *destination, int32_t numSamples);
 
 /**
  * @return the size of a sample of the given format in bytes or OBOE_ERROR_ILLEGAL_ARGUMENT
  */
-int32_t convertFormatToSizeInBytes(AudioFormat format);
+int32_t Oboe_convertFormatToSizeInBytes(oboe_audio_format_t format);
 
 /**
  * The text is the ASCII symbol corresponding to the returnCode,
@@ -39,7 +37,7 @@ int32_t convertFormatToSizeInBytes(AudioFormat format);
  *
  * @return pointer to a text representation of an Oboe result code.
  */
-const char * convertResultToText(Result returnCode);
+const char * Oboe_convertResultToText(oboe_result_t returnCode);
 
 /**
  * The text is the ASCII symbol corresponding to the audio format,
@@ -49,7 +47,7 @@ const char * convertResultToText(Result returnCode);
  *
  * @return pointer to a text representation of an Oboe audio format.
  */
-const char * convertAudioFormatToText(AudioFormat format);
+const char * Oboe_convertAudioFormatToText(oboe_audio_format_t format);
 
 /**
  * The text is the ASCII symbol corresponding to the performance mode,
@@ -59,7 +57,7 @@ const char * convertAudioFormatToText(AudioFormat format);
  *
  * @return pointer to a text representation of an Oboe performance mode.
  */
-const char * convertPerformanceModeToText(PerformanceMode mode);
+const char * Oboe_convertPerformanceModeToText(oboe_performance_mode_t mode);
 
 /**
  * The text is the ASCII symbol corresponding to the sharing mode,
@@ -69,7 +67,7 @@ const char * convertPerformanceModeToText(PerformanceMode mode);
  *
  * @return pointer to a text representation of an Oboe sharing mode.
  */
-const char * convertSharingModeToText(SharingMode mode);
+const char * Oboe_convertSharingModeToText(oboe_sharing_mode_t mode);
 
 /**
  * The text is the ASCII symbol corresponding to the data callback result,
@@ -79,7 +77,7 @@ const char * convertSharingModeToText(SharingMode mode);
  *
  * @return pointer to a text representation of an Oboe data callback result.
  */
-const char * convertDataCallbackResultToText(DataCallbackResult result);
+const char * Oboe_convertDataCallbackResultToText(oboe_data_callback_result_t result);
 
 /**
  * The text is the ASCII symbol corresponding to the stream direction,
@@ -89,8 +87,5 @@ const char * convertDataCallbackResultToText(DataCallbackResult result);
  *
  * @return pointer to a text representation of an Oboe stream direction.
  */
-const char * convertDirectionToText(Direction direction);
-
-} // namespace oboe
-
-#endif //OBOE_UTILITIES_H
+const char *Oboe_convertDirectionToText(oboe_direction_t direction);
+#endif //OBOE_OBOE_UTILITIES_H
diff --git a/src/aaudio/AAudioLoader.cpp b/src/aaudio/AAudioLoader.cpp
index aeaf6f8d5..08704f54c 100644
--- a/src/aaudio/AAudioLoader.cpp
+++ b/src/aaudio/AAudioLoader.cpp
@@ -20,8 +20,6 @@
 
 #define LIB_AAUDIO_NAME "libaaudio.so"
 
-namespace oboe {
-
 AAudioLoader::~AAudioLoader() {
     close(); // TODO dangerous from a destructor, require caller to close()
 }
@@ -192,5 +190,3 @@ AAudioLoader::signature_I_PB AAudioLoader::load_I_PB(const char *functionName) {
     AAudioLoader_check((void *)proc, functionName);
     return proc;
 }
-
-} // namespace oboe
\ No newline at end of file
diff --git a/src/aaudio/AAudioLoader.h b/src/aaudio/AAudioLoader.h
index a4491a26a..e2eb73953 100644
--- a/src/aaudio/AAudioLoader.h
+++ b/src/aaudio/AAudioLoader.h
@@ -18,12 +18,10 @@
 #define OBOE_AAUDIO_LOADER_H_
 
 #include 
-#include "oboe/Definitions.h"
+#include "oboe/OboeDefinitions.h"
 
 #include "aaudio/AAudio.h"
 
-namespace oboe {
-
 /**
  * The AAudio API was not available in early versions of Android.
  * To avoid linker errors, we dynamically link with the functions by name using dlsym().
@@ -162,6 +160,4 @@ class AAudioLoader {
     void *mLibHandle = nullptr;
 };
 
-} // namespace oboe
-
 #endif //OBOE_AAUDIO_LOADER_H_
diff --git a/src/aaudio/StreamAAudio.cpp b/src/aaudio/OboeStreamAAudio.cpp
similarity index 53%
rename from src/aaudio/StreamAAudio.cpp
rename to src/aaudio/OboeStreamAAudio.cpp
index 7689d333b..786adfc1f 100644
--- a/src/aaudio/StreamAAudio.cpp
+++ b/src/aaudio/OboeStreamAAudio.cpp
@@ -18,15 +18,37 @@
 #include 
 
 #include "aaudio/AAudioLoader.h"
-#include "aaudio/StreamAAudio.h"
+#include "aaudio/OboeStreamAAudio.h"
 #include "common/OboeDebug.h"
-#include "oboe/Utilities.h"
+#include "oboe/OboeUtilities.h"
 
+AAudioLoader *OboeStreamAAudio::mLibLoader = nullptr;
 
+/*
+ * Create a stream that uses Oboe Audio API.
+ */
+OboeStreamAAudio::OboeStreamAAudio(const OboeStreamBuilder &builder)
+    : OboeStream(builder)
+    , mFloatCallbackBuffer(nullptr)
+    , mShortCallbackBuffer(nullptr)
+    , mAAudioStream(nullptr)
+{
+    mCallbackThreadEnabled.store(false);
+    LOGD("OboeStreamAAudio() call isSupported()");
+    isSupported();
+}
 
-using namespace oboe;
-AAudioLoader *StreamAAudio::mLibLoader = nullptr;
+OboeStreamAAudio::~OboeStreamAAudio()
+{
+    delete[] mFloatCallbackBuffer;
+    delete[] mShortCallbackBuffer;
+}
 
+bool OboeStreamAAudio::isSupported() {
+    mLibLoader = AAudioLoader::getInstance();
+    int openResult = mLibLoader->open();
+    return openResult == 0;
+}
 
 // 'C' wrapper for the data callback method
 static aaudio_data_callback_result_t oboe_aaudio_data_callback_proc(
@@ -35,18 +57,17 @@ static aaudio_data_callback_result_t oboe_aaudio_data_callback_proc(
         void *audioData,
         int32_t numFrames) {
 
-    StreamAAudio *oboeStream = (StreamAAudio *)userData;
+    OboeStreamAAudio *oboeStream = (OboeStreamAAudio *)userData;
     if (oboeStream != NULL) {
-        return static_cast(
-                oboeStream->callOnAudioReady(stream, audioData, numFrames));
+        return oboeStream->callOnAudioReady(stream, audioData, numFrames);
     } else {
-        return static_cast(DataCallbackResult::Stop);
+        return AAUDIO_CALLBACK_RESULT_STOP;
     }
 }
 
-static void oboe_aaudio_error_thread_proc(StreamAAudio *oboeStream,
+static void oboe_aaudio_error_thread_proc(OboeStreamAAudio *oboeStream,
                                           AAudioStream *stream,
-                                          Result error) {
+                                          oboe_result_t error) {
     if (oboeStream != NULL) {
         oboeStream->onErrorInThread(stream, error);
     }
@@ -58,74 +79,42 @@ static void oboe_aaudio_error_callback_proc(
         void *userData,
         aaudio_result_t error) {
 
-    StreamAAudio *oboeStream = (StreamAAudio *)userData;
+    OboeStreamAAudio *oboeStream = (OboeStreamAAudio *)userData;
     if (oboeStream != NULL) {
         // Handle error on a separate thread
-        std::thread t(oboe_aaudio_error_thread_proc, oboeStream, stream, static_cast(error));
+        std::thread t(oboe_aaudio_error_thread_proc, oboeStream, stream, error);
         t.detach();
     }
 }
 
-
-namespace oboe {
-
-/*
- * Create a stream that uses Oboe Audio API.
- */
-StreamAAudio::StreamAAudio(const StreamBuilder &builder)
-    : Stream(builder)
-    , mFloatCallbackBuffer(nullptr)
-    , mShortCallbackBuffer(nullptr)
-    , mAAudioStream(nullptr)
-{
-    mCallbackThreadEnabled.store(false);
-    LOGD("StreamAAudio() call isSupported()");
-    isSupported();
-}
-
-StreamAAudio::~StreamAAudio()
-{
-    delete[] mFloatCallbackBuffer;
-    delete[] mShortCallbackBuffer;
-}
-
-bool StreamAAudio::isSupported() {
-    mLibLoader = AAudioLoader::getInstance();
-    int openResult = mLibLoader->open();
-    return openResult == 0;
-}
-
-
-Result StreamAAudio::open() {
-    Result result = Result::OK;
+oboe_result_t OboeStreamAAudio::open() {
+    oboe_result_t result = AAUDIO_OK;
 
     if (mAAudioStream != nullptr) {
-        return Result::ErrorInvalidState;
+        return AAUDIO_ERROR_INVALID_STATE;
     }
 
-    result = Stream::open();
-    if (result != Result::OK) {
+    result = OboeStream::open();
+    if (result != AAUDIO_OK) {
         return result;
     }
 
-    LOGD("StreamAAudio():  AAudio_createStreamBuilder()");
+    LOGD("OboeStreamAAudio():  AAudio_createStreamBuilder()");
     AAudioStreamBuilder *aaudioBuilder;
-    result = static_cast(mLibLoader->createStreamBuilder(&aaudioBuilder));
-    if (result != Result::OK) {
+    result = mLibLoader->createStreamBuilder(&aaudioBuilder);
+    if (result != AAUDIO_OK) {
         return result;
     }
 
-    LOGD("StreamAAudio.open() try with deviceId = %d", (int) mDeviceId);
+    LOGD("OboeStreamAAudio.open() try with deviceId = %d", (int) mDeviceId);
     mLibLoader->builder_setBufferCapacityInFrames(aaudioBuilder, mBufferCapacityInFrames);
     mLibLoader->builder_setChannelCount(aaudioBuilder, mChannelCount);
     mLibLoader->builder_setDeviceId(aaudioBuilder, mDeviceId);
-    mLibLoader->builder_setDirection(aaudioBuilder, static_cast(mDirection));
-    mLibLoader->builder_setFormat(aaudioBuilder, static_cast(mFormat));
+    mLibLoader->builder_setDirection(aaudioBuilder, mDirection);
+    mLibLoader->builder_setFormat(aaudioBuilder, mFormat);
     mLibLoader->builder_setSampleRate(aaudioBuilder, mSampleRate);
-    mLibLoader->builder_setSharingMode(aaudioBuilder,
-                                       static_cast(mSharingMode));
-    mLibLoader->builder_setPerformanceMode(aaudioBuilder,
-                                           static_cast(mPerformanceMode));
+    mLibLoader->builder_setSharingMode(aaudioBuilder, mSharingMode);
+    mLibLoader->builder_setPerformanceMode(aaudioBuilder, mPerformanceMode);
 
     // TODO get more parameters from the builder?
 
@@ -137,10 +126,10 @@ Result StreamAAudio::open() {
 
     {
         AAudioStream *stream = nullptr;
-        result = static_cast(mLibLoader->builder_openStream(aaudioBuilder, &stream));
+        result = mLibLoader->builder_openStream(aaudioBuilder, &stream);
         mAAudioStream.store(stream);
     }
-    if (result != Result::OK) {
+    if (result != AAUDIO_OK) {
         goto error2;
     }
 
@@ -148,45 +137,43 @@ Result StreamAAudio::open() {
     mDeviceId = mLibLoader->stream_getDeviceId(mAAudioStream);
     mChannelCount = mLibLoader->stream_getChannelCount(mAAudioStream);
     mSampleRate = mLibLoader->stream_getSampleRate(mAAudioStream);
-    mNativeFormat = static_cast(mLibLoader->stream_getFormat(mAAudioStream));
-    if (mFormat == AudioFormat::Unspecified) {
+    mNativeFormat = mLibLoader->stream_getFormat(mAAudioStream);
+    if (mFormat == OBOE_AUDIO_FORMAT_UNSPECIFIED) {
         mFormat = mNativeFormat;
     }
-    mSharingMode = static_cast(mLibLoader->stream_getSharingMode(mAAudioStream));
-    mPerformanceMode = static_cast(
-            mLibLoader->stream_getPerformanceMode(mAAudioStream));
+    mSharingMode = mLibLoader->stream_getSharingMode(mAAudioStream);
+    mPerformanceMode = mLibLoader->stream_getPerformanceMode(mAAudioStream);
     mBufferCapacityInFrames = mLibLoader->stream_getBufferCapacity(mAAudioStream);
 
-    LOGD("StreamAAudio.open() app    format = %d", (int) mFormat);
-    LOGD("StreamAAudio.open() native format = %d", (int) mNativeFormat);
-    LOGD("StreamAAudio.open() sample rate   = %d", (int) mSampleRate);
-    LOGD("StreamAAudio.open() capacity      = %d", (int) mBufferCapacityInFrames);
+    LOGD("OboeStreamAAudio.open() app    format = %d", (int) mFormat);
+    LOGD("OboeStreamAAudio.open() native format = %d", (int) mNativeFormat);
+    LOGD("OboeStreamAAudio.open() sample rate   = %d", (int) mSampleRate);
+    LOGD("OboeStreamAAudio.open() capacity      = %d", (int) mBufferCapacityInFrames);
 
 error2:
     mLibLoader->builder_delete(aaudioBuilder);
-    LOGD("StreamAAudio.open: AAudioStream_Open() returned %s, mAAudioStream = %p",
-         mLibLoader->convertResultToText(static_cast(result)),
-         mAAudioStream.load());
+    LOGD("OboeStreamAAudio.open: AAudioStream_Open() returned %s, mAAudioStream = %p",
+         mLibLoader->convertResultToText(result), mAAudioStream.load());
     return result;
 }
 
-Result StreamAAudio::close()
+oboe_result_t OboeStreamAAudio::close()
 {
     // The main reason we have this mutex if to prevent a collision between a call
     // by the application to stop a stream at the same time that an onError callback
     // is being executed because of a disconnect. The close will delete the stream,
     // which could otherwise cause the requestStop() to crash.
     std::lock_guard lock(mLock);
-    Result result = Result::OK;
+    oboe_result_t result = OBOE_OK;
     // This will delete the AAudio stream object so we need to null out the pointer.
     AAudioStream *stream = mAAudioStream.exchange(nullptr);
     if (stream != nullptr) {
-        result = static_cast(mLibLoader->stream_close(stream));
+        result = mLibLoader->stream_close(stream);
     }
     return result;
 }
 
-DataCallbackResult StreamAAudio::callOnAudioReady(AAudioStream *stream,
+aaudio_data_callback_result_t OboeStreamAAudio::callOnAudioReady(AAudioStream *stream,
                                                                  void *audioData,
                                                                  int32_t numFrames) {
     return mStreamCallback->onAudioReady(
@@ -195,7 +182,7 @@ DataCallbackResult StreamAAudio::callOnAudioReady(AAudioStream *stream,
             numFrames);
 }
 
-void StreamAAudio::onErrorInThread(AAudioStream *stream, Result error) {
+void OboeStreamAAudio::onErrorInThread(AAudioStream *stream, oboe_result_t error) {
     LOGD("onErrorInThread() - entering ===================================");
     assert(stream == mAAudioStream.load());
     requestStop();
@@ -209,68 +196,67 @@ void StreamAAudio::onErrorInThread(AAudioStream *stream, Result error) {
     LOGD("onErrorInThread() - exiting ===================================");
 }
 
-Result StreamAAudio::convertApplicationDataToNative(int32_t numFrames) {
-    Result result = Result::ErrorUnimplemented;
+oboe_result_t OboeStreamAAudio::convertApplicationDataToNative(int32_t numFrames) {
+    oboe_result_t result = OBOE_ERROR_UNIMPLEMENTED;
     int32_t numSamples = numFrames * getChannelCount();
-    if (mFormat == AudioFormat::Float) {
-        if (mNativeFormat == AudioFormat::I16) {
-            convertFloatToPcm16(mFloatCallbackBuffer, mShortCallbackBuffer, numSamples);
-            result = Result::OK;
+    if (mFormat == OBOE_AUDIO_FORMAT_PCM_FLOAT) {
+        if (mNativeFormat == OBOE_AUDIO_FORMAT_PCM_I16) {
+            Oboe_convertFloatToPcm16(mFloatCallbackBuffer, mShortCallbackBuffer, numSamples);
+            result = AAUDIO_OK;
         }
-    } else if (mFormat == AudioFormat::I16) {
-        if (mNativeFormat == AudioFormat::Float) {
-            convertPcm16ToFloat(mShortCallbackBuffer, mFloatCallbackBuffer, numSamples);
-            result = Result::OK;
+    } else if (mFormat == OBOE_AUDIO_FORMAT_PCM_I16) {
+        if (mNativeFormat == OBOE_AUDIO_FORMAT_PCM_FLOAT) {
+            Oboe_convertPcm16ToFloat(mShortCallbackBuffer, mFloatCallbackBuffer, numSamples);
+            result = AAUDIO_OK;
         }
     }
     return result;
 }
 
-Result StreamAAudio::requestStart()
+oboe_result_t OboeStreamAAudio::requestStart()
 {
     std::lock_guard lock(mLock);
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
-        return static_cast(mLibLoader->stream_requestStart(stream));
+        return mLibLoader->stream_requestStart(stream);
     } else {
-        return Result::ErrorNull;
+        return OBOE_ERROR_NULL;
     }
 }
 
-Result StreamAAudio::requestPause()
+oboe_result_t OboeStreamAAudio::requestPause()
 {
     std::lock_guard lock(mLock);
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
-        return static_cast(mLibLoader->stream_requestPause(stream));
+        return mLibLoader->stream_requestPause(stream);
     } else {
-        return Result::ErrorNull;
+        return OBOE_ERROR_NULL;
     }
 }
 
-Result StreamAAudio::requestFlush() {
+oboe_result_t OboeStreamAAudio::requestFlush() {
     std::lock_guard lock(mLock);
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
-        return static_cast(mLibLoader->stream_requestFlush(stream));
+        return mLibLoader->stream_requestFlush(stream);
     } else {
-        return Result::ErrorNull;
+        return OBOE_ERROR_NULL;
     }
 }
 
-Result StreamAAudio::requestStop()
+oboe_result_t OboeStreamAAudio::requestStop()
 {
     std::lock_guard lock(mLock);
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
-        return static_cast(mLibLoader->stream_requestStop(stream));
+        return mLibLoader->stream_requestStop(stream);
     } else {
-        return Result::ErrorNull;
+        return OBOE_ERROR_NULL;
     }
 }
 
-// TODO: Update to return tuple of Result and framesWritten (avoids cast)
-int32_t StreamAAudio::write(const void *buffer,
+oboe_result_t OboeStreamAAudio::write(const void *buffer,
                                      int32_t numFrames,
                                      int64_t timeoutNanoseconds)
 {
@@ -278,106 +264,97 @@ int32_t StreamAAudio::write(const void *buffer,
     if (stream != nullptr) {
         return mLibLoader->stream_write(mAAudioStream, buffer, numFrames, timeoutNanoseconds);
     } else {
-        return static_cast(Result::ErrorNull);
+        return OBOE_ERROR_NULL;
     }
 }
 
-Result StreamAAudio::waitForStateChange(StreamState currentState,
-                                        StreamState *nextState,
-                                        int64_t timeoutNanoseconds)
+oboe_result_t OboeStreamAAudio::waitForStateChange(oboe_stream_state_t currentState,
+                                                  oboe_stream_state_t *nextState,
+                                                  int64_t timeoutNanoseconds)
 {
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
-
-        aaudio_stream_state_t aaudioNextState;
-        aaudio_result_t result = mLibLoader->stream_waitForStateChange(
-                        mAAudioStream,
-                        static_cast(currentState),
-                        &aaudioNextState,
-                        timeoutNanoseconds);
-        *nextState = static_cast(aaudioNextState);
-        return static_cast(result);
+        return mLibLoader->stream_waitForStateChange(mAAudioStream, currentState,
+                                                     nextState, timeoutNanoseconds);
     } else {
-        return Result::ErrorNull;
+        return OBOE_ERROR_NULL;
     }
 }
 
-Result StreamAAudio::setBufferSizeInFrames(int32_t requestedFrames)
+oboe_result_t OboeStreamAAudio::setBufferSizeInFrames(int32_t requestedFrames)
 {
     if (requestedFrames > mBufferCapacityInFrames) {
         requestedFrames = mBufferCapacityInFrames;
     }
-    return static_cast(mLibLoader->stream_setBufferSize(mAAudioStream, requestedFrames));
+    return mLibLoader->stream_setBufferSize(mAAudioStream, requestedFrames);
 }
 
-StreamState StreamAAudio::getState()
+oboe_stream_state_t OboeStreamAAudio::getState()
 {
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
-        return static_cast(mLibLoader->stream_getState(stream));
+        return mLibLoader->stream_getState(stream);
     } else {
-        return StreamState::Closed;
+        return OBOE_STREAM_STATE_CLOSED;
     }
 }
 
-int32_t StreamAAudio::getBufferSizeInFrames() const {
+int32_t OboeStreamAAudio::getBufferSizeInFrames() const {
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
         return mLibLoader->stream_getBufferSize(stream);
     } else {
-        return static_cast(Result::ErrorNull);
+        return OBOE_ERROR_NULL;
     }
 }
 
-int32_t StreamAAudio::getFramesPerBurst()
+int32_t OboeStreamAAudio::getFramesPerBurst()
 {
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
         return mLibLoader->stream_getFramesPerBurst(stream);
     } else {
-        return static_cast(Result::ErrorNull);
+        return OBOE_ERROR_NULL;
     }
 }
 
-int64_t StreamAAudio::getFramesRead()
+int64_t OboeStreamAAudio::getFramesRead()
 {
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
         return mLibLoader->stream_getFramesRead(stream);
     } else {
-        return static_cast(Result::ErrorNull);
+        return OBOE_ERROR_NULL;
     }
 }
-int64_t StreamAAudio::getFramesWritten()
+int64_t OboeStreamAAudio::getFramesWritten()
 {
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
         return mLibLoader->stream_getFramesWritten(stream);
     } else {
-        return static_cast(Result::ErrorNull);
+        return OBOE_ERROR_NULL;
     }
 }
 
-int32_t StreamAAudio::getXRunCount()
+int32_t OboeStreamAAudio::getXRunCount()
 {
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
         return mLibLoader->stream_getXRunCount(stream);
     } else {
-        return static_cast(Result::ErrorNull);
+        return OBOE_ERROR_NULL;
     }
 }
 
-Result StreamAAudio::getTimestamp(clockid_t clockId,
+oboe_result_t OboeStreamAAudio::getTimestamp(clockid_t clockId,
                                    int64_t *framePosition,
                                    int64_t *timeNanoseconds) {
     AAudioStream *stream = mAAudioStream.load();
     if (stream != nullptr) {
-        return static_cast(mLibLoader->stream_getTimestamp(stream, clockId,
-                                               framePosition, timeNanoseconds));
+        return mLibLoader->stream_getTimestamp(stream, clockId,
+                                               framePosition, timeNanoseconds);
     } else {
-        return Result::ErrorNull;
+        return OBOE_ERROR_NULL;
     }
 }
-
-} // namespace oboe
\ No newline at end of file
diff --git a/src/aaudio/StreamAAudio.h b/src/aaudio/OboeStreamAAudio.h
similarity index 58%
rename from src/aaudio/StreamAAudio.h
rename to src/aaudio/OboeStreamAAudio.h
index 36dbeaaa3..e89288377 100644
--- a/src/aaudio/StreamAAudio.h
+++ b/src/aaudio/OboeStreamAAudio.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_STREAM_AAUDIO_H_
-#define OBOE_STREAM_AAUDIO_H_
+#ifndef OBOE_OBOE_STREAM_AAUDIO_H_
+#define OBOE_OBOE_STREAM_AAUDIO_H_
 
 #include 
 #include 
@@ -23,11 +23,9 @@
 
 #include "aaudio/AAudio.h"
 
-#include "oboe/StreamBuilder.h"
-#include "oboe/Stream.h"
-#include "oboe/Definitions.h"
-
-namespace oboe {
+#include "oboe/OboeStreamBuilder.h"
+#include "oboe/OboeStream.h"
+#include "oboe/OboeDefinitions.h"
 
 class AAudioLoader;
 
@@ -37,12 +35,12 @@ class AAudioLoader;
  * Do not create this class directly.
  * Use an OboeStreamBuilder to create one.
  */
-class StreamAAudio : public Stream {
+class OboeStreamAAudio : public OboeStream {
 public:
-    StreamAAudio();
-    explicit StreamAAudio(const StreamBuilder &builder);
+    OboeStreamAAudio();
+    explicit OboeStreamAAudio(const OboeStreamBuilder &builder);
 
-    ~StreamAAudio();
+    ~OboeStreamAAudio();
 
     /**
      *
@@ -50,21 +48,21 @@ class StreamAAudio : public Stream {
      */
     static bool isSupported();
 
-    // These functions override methods in Stream.
-    // See Stream for documentation.
-    Result open() override;
-    Result close() override;
+    // These functions override methods in OboeStream.
+    // See OboeStream for documentation.
+    oboe_result_t open() override;
+    oboe_result_t close() override;
 
-    Result requestStart() override;
-    Result requestPause() override;
-    Result requestFlush() override;
-    Result requestStop() override;
+    oboe_result_t requestStart() override;
+    oboe_result_t requestPause() override;
+    oboe_result_t requestFlush() override;
+    oboe_result_t requestStop() override;
 
-    int32_t write(const void *buffer,
+    oboe_result_t write(const void *buffer,
                              int32_t numFrames,
                              int64_t timeoutNanoseconds) override;
 
-    Result setBufferSizeInFrames(int32_t requestedFrames) override;
+    oboe_result_t setBufferSizeInFrames(int32_t requestedFrames) override;
     int32_t getBufferSizeInFrames() const override;
     int32_t getFramesPerBurst() override;
     int32_t getXRunCount() override;
@@ -72,15 +70,15 @@ class StreamAAudio : public Stream {
     int64_t getFramesRead() override;
     int64_t getFramesWritten() override;
 
-    Result waitForStateChange(StreamState currentState,
-                              StreamState *nextState,
-                              int64_t timeoutNanoseconds) override;
+    oboe_result_t waitForStateChange(oboe_stream_state_t currentState,
+                                             oboe_stream_state_t *nextState,
+                                             int64_t timeoutNanoseconds) override;
 
-    Result getTimestamp(clockid_t clockId,
+    oboe_result_t getTimestamp(clockid_t clockId,
                                        int64_t *framePosition,
                                        int64_t *timeNanoseconds) override;
 
-    StreamState getState() override;
+    oboe_stream_state_t getState() override;
 
 
     bool usesAAudio() const override {
@@ -88,16 +86,16 @@ class StreamAAudio : public Stream {
     }
 
 public:
-    DataCallbackResult callOnAudioReady(AAudioStream *stream,
+    aaudio_data_callback_result_t callOnAudioReady(AAudioStream *stream,
                                                    void *audioData,
                                                    int32_t numFrames);
 
-    void onErrorCallback(AAudioStream *stream, Result error);
+    void onErrorCallback(AAudioStream *stream, oboe_result_t error);
 
-    void onErrorInThread(AAudioStream *stream, Result error);
+    void onErrorInThread(AAudioStream *stream, oboe_result_t error);
 
 protected:
-    Result convertApplicationDataToNative(int32_t numFrames); // TODO remove?
+    oboe_result_t convertApplicationDataToNative(int32_t numFrames); // TODO remove?
 
 private:
 
@@ -112,6 +110,5 @@ class StreamAAudio : public Stream {
     static AAudioLoader *mLibLoader;
 };
 
-} // namespace oboe
 
-#endif // OBOE_STREAM_AAUDIO_H_
+#endif // OBOE_OBOE_STREAM_AAUDIO_H_
diff --git a/src/aaudio/build.gradle b/src/aaudio/build.gradle
new file mode 100644
index 000000000..f32ecc8ae
--- /dev/null
+++ b/src/aaudio/build.gradle
@@ -0,0 +1,3 @@
+dependencies {
+    compile 'com.android.support.constraint:constraint-layout:1.0.2'
+}
diff --git a/src/common/AudioClock.h b/src/common/AudioClock.h
index 3fe20cb0a..a9bbd0a8e 100644
--- a/src/common/AudioClock.h
+++ b/src/common/AudioClock.h
@@ -18,12 +18,9 @@
 #define OBOE_AUDIO_CLOCK_H
 
 #include 
-#include 
-#include "oboe/Definitions.h"
+#include 
+#include "oboe/OboeDefinitions.h"
 
-namespace oboe {
-
-// TODO: Move this class into the public headers because it is useful when calculating stream latency
 class AudioClock {
 public:
     static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
@@ -32,7 +29,7 @@ class AudioClock {
         if (result < 0) {
             return result;
         }
-        return (time.tv_sec * kNanosPerSecond) + time.tv_nsec;
+        return (time.tv_sec * OBOE_NANOS_PER_SECOND) + time.tv_nsec;
     }
 
     /**
@@ -45,8 +42,8 @@ class AudioClock {
 
     static int sleepUntilNanoTime(int64_t nanoTime, clockid_t clockId = CLOCK_MONOTONIC) {
         struct timespec time;
-        time.tv_sec = nanoTime / kNanosPerSecond;
-        time.tv_nsec = nanoTime - (time.tv_sec * kNanosPerSecond);
+        time.tv_sec = nanoTime / OBOE_NANOS_PER_SECOND;
+        time.tv_nsec = nanoTime - (time.tv_sec * OBOE_NANOS_PER_SECOND);
         return 0 - clock_nanosleep(clockId, TIMER_ABSTIME, &time, NULL);
     }
 
@@ -62,14 +59,13 @@ class AudioClock {
     static int sleepForNanos(int64_t nanoseconds, clockid_t clockId = CLOCK_REALTIME) {
         if (nanoseconds > 0) {
             struct timespec time;
-            time.tv_sec = nanoseconds / kNanosPerSecond;
-            time.tv_nsec = nanoseconds - (time.tv_sec * kNanosPerSecond);
+            time.tv_sec = nanoseconds / OBOE_NANOS_PER_SECOND;
+            time.tv_nsec = nanoseconds - (time.tv_sec * OBOE_NANOS_PER_SECOND);
             return 0 - clock_nanosleep(clockId, 0, &time, NULL);
         }
         return 0;
     }
 };
 
-} // namespace oboe
 
 #endif //OBOE_AUDIO_CLOCK_H
diff --git a/src/common/OboeDebug.h b/src/common/OboeDebug.h
index bc72c93cb..d998ecd57 100644
--- a/src/common/OboeDebug.h
+++ b/src/common/OboeDebug.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  *
  */
-#ifndef OBOE_DEBUG_H
-#define OBOE_DEBUG_H
+#ifndef OBOE_OBOE_DEBUG_H
+#define OBOE_OBOE_DEBUG_H
 #include 
 
 #if 1
@@ -40,4 +40,4 @@
 #define LOGF(...)
 #endif
 
-#endif //OBOE_DEBUG_H
+#endif //OBOE_OBOE_DEBUG_H
diff --git a/src/common/LatencyTuner.cpp b/src/common/OboeLatencyTuner.cpp
similarity index 63%
rename from src/common/LatencyTuner.cpp
rename to src/common/OboeLatencyTuner.cpp
index b6247d9b0..5cac2f818 100644
--- a/src/common/LatencyTuner.cpp
+++ b/src/common/OboeLatencyTuner.cpp
@@ -14,21 +14,19 @@
  * limitations under the License.
  */
 
-#include "oboe/LatencyTuner.h"
+#include "oboe/OboeLatencyTuner.h"
 
-using namespace oboe;
-
-LatencyTuner::LatencyTuner(Stream &stream)
+OboeLatencyTuner::OboeLatencyTuner(OboeStream &stream)
     : mStream(stream) {
     reset();
 }
 
-Result LatencyTuner::tune() {
-    if (mState == State::Unsupported) {
-        return Result::ErrorUnimplemented;
+oboe_result_t OboeLatencyTuner::tune() {
+    if (mState == STATE_UNSUPPORTED) {
+        return OBOE_ERROR_UNIMPLEMENTED;
     }
 
-    Result result = Result::OK;
+    oboe_result_t result = OBOE_OK;
 
     // Process reset requests.
     int32_t numRequests = mLatencyTriggerRequests.load();
@@ -38,50 +36,49 @@ Result LatencyTuner::tune() {
     }
 
     switch (mState) {
-        case State::Idle:
+        case STATE_IDLE:
             if (--mIdleCountDown <= 0) {
-                mState = State::Active;
+                mState = STATE_ACTIVE;
             }
             mPreviousXRuns = mStream.getXRunCount();
             if (mPreviousXRuns < 0) {
-                result = static_cast(mPreviousXRuns); // error code
-                mState = State::Unsupported;
+                result = mPreviousXRuns; // error code
+                mState = STATE_UNSUPPORTED;
             }
             break;
 
-        case State::Active: {
+        case STATE_ACTIVE: {
             int32_t xRuns = mStream.getXRunCount();
             if ((xRuns - mPreviousXRuns) > 0) {
                 mPreviousXRuns = xRuns;
                 int32_t oldBufferSize = mStream.getBufferSizeInFrames();
                 int32_t requestedBufferSize = oldBufferSize + mStream.getFramesPerBurst();
-                int32_t resultingSize = static_cast(
-                        mStream.setBufferSizeInFrames(requestedBufferSize));
+                int32_t resultingSize = mStream.setBufferSizeInFrames(requestedBufferSize);
                 if (resultingSize == oldBufferSize) {
-                    mState = State::AtMax; // can't go any higher
+                    mState = STATE_AT_MAX; // can't go any higher
                 } else if (resultingSize < 0) {
-                    result = static_cast(resultingSize); // error code
-                    mState = State::Unsupported;
+                    result = resultingSize; // error code
+                    mState = STATE_UNSUPPORTED;
                 }
             }
         }
 
-        case State::AtMax:
-        case State::Unsupported:
+        case STATE_AT_MAX:
+        case STATE_UNSUPPORTED:
             break;
     }
     return result;
 }
 
-void LatencyTuner::requestReset() {
-    if (mState != State::Unsupported) {
+void OboeLatencyTuner::requestReset() {
+    if (mState != STATE_UNSUPPORTED) {
         mLatencyTriggerRequests++;
     }
 }
 
-void LatencyTuner::reset() {
-    mState = State::Idle;
-    mIdleCountDown = kIdleCount;
+void OboeLatencyTuner::reset() {
+    mState = STATE_IDLE;
+    mIdleCountDown = IDLE_COUNT;
     // Set to minimal latency
     mStream.setBufferSizeInFrames(mStream.getFramesPerBurst());
 }
diff --git a/src/common/OboeStream.cpp b/src/common/OboeStream.cpp
new file mode 100644
index 000000000..5262e42cb
--- /dev/null
+++ b/src/common/OboeStream.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include 
+#include 
+
+#include "oboe/OboeUtilities.h"
+#include "OboeDebug.h"
+#include "oboe/Oboe.h"
+
+/*
+ * OboeStream
+ */
+
+OboeStream::OboeStream(const OboeStreamBuilder &builder)
+        : OboeStreamBase(builder) {
+}
+
+oboe_result_t OboeStream::open() {
+    // TODO validate parameters or let underlyng API validate them?
+    return OBOE_OK;
+}
+
+oboe_result_t OboeStream::fireCallback(void *audioData, int32_t numFrames)
+{
+    int scheduler = sched_getscheduler(0) & ~SCHED_RESET_ON_FORK; // for current thread
+    if (scheduler != mPreviousScheduler) {
+        LOGD("OboeStream::fireCallback() scheduler = %s",
+             ((scheduler == SCHED_FIFO) ? "SCHED_FIFO" :
+             ((scheduler == SCHED_OTHER) ? "SCHED_OTHER" :
+             ((scheduler == SCHED_RR) ? "SCHED_RR" : "UNKNOWN")))
+        );
+        mPreviousScheduler = scheduler;
+    }
+    if (mStreamCallback == NULL) {
+        return OBOE_ERROR_NULL;
+    } else {
+        oboe_result_t result = mStreamCallback->onAudioReady(this, audioData, numFrames);
+        if (result == OBOE_OK) {
+            mFramesWritten += numFrames;
+        }
+        return result;
+    }
+}
+
+oboe_result_t OboeStream::waitForStateTransition(oboe_stream_state_t startingState,
+                                               oboe_stream_state_t endingState,
+                                               int64_t timeoutNanoseconds)
+{
+    oboe_stream_state_t state = getState();
+    oboe_stream_state_t nextState = state;
+    if (state == startingState && state != endingState) {
+        oboe_result_t result = waitForStateChange(state, &nextState, timeoutNanoseconds);
+        if (result < 0) {
+            return result;
+        }
+    }
+    if (nextState != endingState) {
+        return OBOE_ERROR_INVALID_STATE;
+    } else {
+        return OBOE_OK;
+    }
+}
+
+oboe_result_t OboeStream::start(int64_t timeoutNanoseconds)
+{
+    oboe_result_t result = requestStart();
+    if (result < 0) return result;
+    return waitForStateTransition(OBOE_STREAM_STATE_STARTING,
+                                  OBOE_STREAM_STATE_STARTED, timeoutNanoseconds);
+}
+
+oboe_result_t OboeStream::pause(int64_t timeoutNanoseconds)
+{
+    oboe_result_t result = requestPause();
+    if (result < 0) return result;
+    return waitForStateTransition(OBOE_STREAM_STATE_PAUSING,
+                                  OBOE_STREAM_STATE_PAUSED, timeoutNanoseconds);
+}
+
+oboe_result_t OboeStream::flush(int64_t timeoutNanoseconds)
+{
+    oboe_result_t result = requestFlush();
+    if (result < 0) return result;
+    return waitForStateTransition(OBOE_STREAM_STATE_FLUSHING,
+                                  OBOE_STREAM_STATE_FLUSHED, timeoutNanoseconds);
+}
+
+oboe_result_t OboeStream::stop(int64_t timeoutNanoseconds)
+{
+    oboe_result_t result = requestStop();
+    if (result < 0) return result;
+    return waitForStateTransition(OBOE_STREAM_STATE_STOPPING,
+                                  OBOE_STREAM_STATE_STOPPED, timeoutNanoseconds);
+}
+
+bool OboeStream::isPlaying() {
+    oboe_stream_state_t state = getState();
+    return state == OBOE_STREAM_STATE_STARTING || state == OBOE_STREAM_STATE_STARTED;
+}
+
+int32_t OboeStream::getBytesPerSample() const {
+    return Oboe_convertFormatToSizeInBytes(mFormat);
+}
diff --git a/src/common/StreamBuilder.cpp b/src/common/OboeStreamBuilder.cpp
similarity index 54%
rename from src/common/StreamBuilder.cpp
rename to src/common/OboeStreamBuilder.cpp
index f3da91536..9a450e396 100644
--- a/src/common/StreamBuilder.cpp
+++ b/src/common/OboeStreamBuilder.cpp
@@ -16,51 +16,47 @@
 
 #include 
 
-#include "aaudio/StreamAAudio.h"
+#include "aaudio/OboeStreamAAudio.h"
 #include "OboeDebug.h"
 #include "oboe/Oboe.h"
-#include "oboe/StreamBuilder.h"
-#include "opensles/StreamOpenSLES.h"
+#include "oboe/OboeStreamBuilder.h"
+#include "opensles/OboeStreamOpenSLES.h"
 
-namespace oboe {
-
-bool StreamBuilder::isAAudioSupported() {
-    return StreamAAudio::isSupported();
+bool OboeStreamBuilder::isAAudioSupported() {
+    return OboeStreamAAudio::isSupported();
 }
 
-Stream *StreamBuilder::build() {
-    LOGD("StreamBuilder.build(): mAudioApi %d, mChannelCount = %d, mFramesPerCallback = %d",
+OboeStream *OboeStreamBuilder::build() {
+    LOGD("OboeStreamBuilder.build(): mAudioApi %d, mChannelCount = %d, mFramesPerCallback = %d",
          mAudioApi, mChannelCount, mFramesPerCallback);
-    Stream *stream = nullptr;
+    OboeStream *stream = nullptr;
     switch(mAudioApi) {
-        case AudioApi::Unspecified:
-        case AudioApi::AAudio:
-            if (StreamAAudio::isSupported()) {
-                stream = new StreamAAudio(*this);
+        case API_UNSPECIFIED:
+        case API_AAUDIO:
+            if (OboeStreamAAudio::isSupported()) {
+                stream = new OboeStreamAAudio(*this);
                 break;
             }
             // fall into using older existing API
-        case AudioApi::OpenSLES:
-            stream = new StreamOpenSLES(*this);
+        case API_OPENSL_ES:
+            stream = new OboeStreamOpenSLES(*this);
             break;
     }
     return stream;
 }
 
-Result StreamBuilder::openStream(Stream **streamPP) {
+oboe_result_t OboeStreamBuilder::openStream(OboeStream **streamPP) {
     if (streamPP == nullptr) {
-        return Result::ErrorNull;
+        return OBOE_ERROR_NULL;
     }
     *streamPP = nullptr;
-    Stream *streamP = build();
+    OboeStream *streamP = build();
     if (streamP == nullptr) {
-        return Result::ErrorNull;
+        return OBOE_ERROR_NULL;
     }
-    Result result = streamP->open(); // TODO review API
-    if (result == Result::OK) {
+    oboe_result_t result = streamP->open(); // TODO review API
+    if (result == OBOE_OK) {
         *streamPP = streamP;
     }
     return result;
 }
-
-} // namespace oboe
\ No newline at end of file
diff --git a/src/common/OboeUtilities.cpp b/src/common/OboeUtilities.cpp
new file mode 100644
index 000000000..4b8b83924
--- /dev/null
+++ b/src/common/OboeUtilities.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include 
+#include "oboe/OboeDefinitions.h"
+#include "oboe/OboeUtilities.h"
+
+#define OBOE_CASE_ENUM(name) case name: return #name
+
+void Oboe_convertFloatToPcm16(const float *source, int16_t *destination, int32_t numSamples) {
+    for (int i = 0; i < numSamples; i++) {
+        float fval = source[i];
+        fval += 1.0; // to avoid discontinuity at 0.0 caused by truncation
+        fval *= 32768.0f;
+        int32_t sample = (int32_t) fval;
+        // clip to 16-bit range
+        if (sample < 0) sample = 0;
+        else if (sample > 0x0FFFF) sample = 0x0FFFF;
+        sample -= 32768; // center at zero
+        destination[i] = (int16_t) sample;
+    }
+}
+
+void Oboe_convertPcm16ToFloat(const int16_t *source, float *destination, int32_t numSamples) {
+    for (int i = 0; i < numSamples; i++) {
+        destination[i] = source[i] * (1.0f / 32768.0f);
+    }
+}
+
+int32_t Oboe_convertFormatToSizeInBytes(oboe_audio_format_t format) {
+    int32_t size = OBOE_ERROR_ILLEGAL_ARGUMENT;
+    switch (format) {
+        case OBOE_AUDIO_FORMAT_PCM_I16:
+            size = sizeof(int16_t);
+            break;
+        case OBOE_AUDIO_FORMAT_PCM_FLOAT:
+            size = sizeof(float);
+            break;
+        default:
+            break;
+    }
+    return size;
+}
+
+const char *Oboe_convertResultToText(oboe_result_t returnCode) {
+    switch (returnCode) {
+        OBOE_CASE_ENUM(OBOE_OK);
+        OBOE_CASE_ENUM(OBOE_ERROR_DISCONNECTED);
+        OBOE_CASE_ENUM(OBOE_ERROR_ILLEGAL_ARGUMENT);
+            // reserved
+        OBOE_CASE_ENUM(OBOE_ERROR_INTERNAL);
+        OBOE_CASE_ENUM(OBOE_ERROR_INVALID_STATE);
+            // reserved
+            // reserved
+        OBOE_CASE_ENUM(OBOE_ERROR_INVALID_HANDLE);
+            // reserved
+        OBOE_CASE_ENUM(OBOE_ERROR_UNIMPLEMENTED);
+        OBOE_CASE_ENUM(OBOE_ERROR_UNAVAILABLE);
+        OBOE_CASE_ENUM(OBOE_ERROR_NO_FREE_HANDLES);
+        OBOE_CASE_ENUM(OBOE_ERROR_NO_MEMORY);
+        OBOE_CASE_ENUM(OBOE_ERROR_NULL);
+        OBOE_CASE_ENUM(OBOE_ERROR_TIMEOUT);
+        OBOE_CASE_ENUM(OBOE_ERROR_WOULD_BLOCK);
+        OBOE_CASE_ENUM(OBOE_ERROR_INVALID_FORMAT);
+        OBOE_CASE_ENUM(OBOE_ERROR_OUT_OF_RANGE);
+        OBOE_CASE_ENUM(OBOE_ERROR_NO_SERVICE);
+        OBOE_CASE_ENUM(OBOE_ERROR_INVALID_RATE);
+    }
+    return "Unrecognized Oboe error.";
+}
+
+const char *Oboe_convertAudioFormatToText(oboe_audio_format_t format) {
+    switch (format) {
+        OBOE_CASE_ENUM(OBOE_AUDIO_FORMAT_INVALID);
+        OBOE_CASE_ENUM(OBOE_AUDIO_FORMAT_UNSPECIFIED);
+        OBOE_CASE_ENUM(OBOE_AUDIO_FORMAT_PCM_I16);
+        OBOE_CASE_ENUM(OBOE_AUDIO_FORMAT_PCM_FLOAT);
+    }
+    return "Unrecognized audio format.";
+}
+
+const char *Oboe_convertPerformanceModeToText(oboe_performance_mode_t mode) {
+    switch (mode) {
+        OBOE_CASE_ENUM(OBOE_PERFORMANCE_MODE_LOW_LATENCY);
+        OBOE_CASE_ENUM(OBOE_PERFORMANCE_MODE_NONE);
+        OBOE_CASE_ENUM(OBOE_PERFORMANCE_MODE_POWER_SAVING);
+    }
+    return "Unrecognised performance mode.";
+}
+
+const char *Oboe_convertSharingModeToText(oboe_sharing_mode_t mode) {
+    switch (mode) {
+        OBOE_CASE_ENUM(OBOE_SHARING_MODE_EXCLUSIVE);
+        OBOE_CASE_ENUM(OBOE_SHARING_MODE_SHARED);
+    }
+    return "Unrecognised sharing mode.";
+}
+
+const char *Oboe_convertDataCallbackResultToText(oboe_data_callback_result_t result) {
+    switch (result) {
+        OBOE_CASE_ENUM(OBOE_CALLBACK_RESULT_CONTINUE);
+        OBOE_CASE_ENUM(OBOE_CALLBACK_RESULT_STOP);
+    }
+    return "Unrecognised data callback result.";
+}
+
+const char *Oboe_convertDirectionToText(oboe_direction_t direction) {
+    switch (direction) {
+        OBOE_CASE_ENUM(OBOE_DIRECTION_INPUT);
+        OBOE_CASE_ENUM(OBOE_DIRECTION_OUTPUT);
+    }
+    return "Unrecognised direction.";
+}
diff --git a/src/common/Stream.cpp b/src/common/Stream.cpp
deleted file mode 100644
index 26e593505..000000000
--- a/src/common/Stream.cpp
+++ /dev/null
@@ -1,125 +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.
- */
-
-#include 
-#include 
-#include 
-#include "OboeDebug.h"
-#include 
-
-namespace oboe {
-
-/*
- * Stream
- */
-Stream::Stream(const StreamBuilder &builder)
-        : StreamBase(builder) {
-}
-
-Result Stream::open() {
-    // TODO validate parameters or let underlyng API validate them?
-    return Result::OK;
-}
-
-Result Stream::fireCallback(void *audioData, int32_t numFrames)
-{
-    int scheduler = sched_getscheduler(0) & ~SCHED_RESET_ON_FORK; // for current thread
-    if (scheduler != mPreviousScheduler) {
-        LOGD("Stream::fireCallback() scheduler = %s",
-             ((scheduler == SCHED_FIFO) ? "SCHED_FIFO" :
-             ((scheduler == SCHED_OTHER) ? "SCHED_OTHER" :
-             ((scheduler == SCHED_RR) ? "SCHED_RR" : "UNKNOWN")))
-        );
-        mPreviousScheduler = scheduler;
-    }
-    if (mStreamCallback == NULL) {
-        return Result::ErrorNull;
-    } else {
-        /**
-         * TODO: onAudioRead doesn't return an Result, it returns either Continue or Stop
-         * neither of which tells us whether an error occured. Figure out what to do here.
-         */
-        /*Result result = mStreamCallback->onAudioReady(this, audioData, numFrames);
-        if (result == OBOE_OK) {
-            mFramesWritten += numFrames;
-        }*/
-        mStreamCallback->onAudioReady(this, audioData, numFrames);
-        mFramesWritten += numFrames;
-        return Result::OK;
-    }
-}
-
-Result Stream::waitForStateTransition(StreamState startingState,
-                                               StreamState endingState,
-                                               int64_t timeoutNanoseconds)
-{
-    StreamState state = getState();
-    StreamState nextState = state;
-    if (state == startingState && state != endingState) {
-        Result result = waitForStateChange(state, &nextState, timeoutNanoseconds);
-        if (result != Result::OK) {
-            return result;
-        }
-    }
-    if (nextState != endingState) {
-        return Result::ErrorInvalidState;
-    } else {
-        return Result::OK;
-    }
-}
-
-Result Stream::start(int64_t timeoutNanoseconds)
-{
-    Result result = requestStart();
-    if (result != Result::OK) return result;
-    return waitForStateTransition(StreamState::Starting,
-                                  StreamState::Started, timeoutNanoseconds);
-}
-
-Result Stream::pause(int64_t timeoutNanoseconds)
-{
-    Result result = requestPause();
-    if (result != Result::OK) return result;
-    return waitForStateTransition(StreamState::Pausing,
-                                  StreamState::Paused, timeoutNanoseconds);
-}
-
-Result Stream::flush(int64_t timeoutNanoseconds)
-{
-    Result result = requestFlush();
-    if (result != Result::OK) return result;
-    return waitForStateTransition(StreamState::Flushing,
-                                  StreamState::Flushed, timeoutNanoseconds);
-}
-
-Result Stream::stop(int64_t timeoutNanoseconds)
-{
-    Result result = requestStop();
-    if (result != Result::OK) return result;
-    return waitForStateTransition(StreamState::Stopping,
-                                  StreamState::Stopped, timeoutNanoseconds);
-}
-
-bool Stream::isPlaying() {
-    StreamState state = getState();
-    return state == StreamState::Starting || state == StreamState::Started;
-}
-
-int32_t Stream::getBytesPerSample() const {
-    return convertFormatToSizeInBytes(mFormat);
-}
-
-} // namespace oboe
\ No newline at end of file
diff --git a/src/common/Utilities.cpp b/src/common/Utilities.cpp
deleted file mode 100644
index ed51044bb..000000000
--- a/src/common/Utilities.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include 
-#include "oboe/Definitions.h"
-#include "oboe/Utilities.h"
-
-#define OBOE_CASE_ENUM(name) case name: return #name
-
-namespace oboe {
-
-void convertFloatToPcm16(const float *source, int16_t *destination, int32_t numSamples) {
-    for (int i = 0; i < numSamples; i++) {
-        float fval = source[i];
-        fval += 1.0; // to avoid discontinuity at 0.0 caused by truncation
-        fval *= 32768.0f;
-        auto sample = (int32_t) fval;
-        // clip to 16-bit range
-        if (sample < 0) sample = 0;
-        else if (sample > 0x0FFFF) sample = 0x0FFFF;
-        sample -= 32768; // center at zero
-        destination[i] = (int16_t) sample;
-    }
-}
-
-void convertPcm16ToFloat(const int16_t *source, float *destination, int32_t numSamples) {
-    for (int i = 0; i < numSamples; i++) {
-        destination[i] = source[i] * (1.0f / 32768.0f);
-    }
-}
-
-int32_t convertFormatToSizeInBytes(AudioFormat format) {
-    int32_t size = 0;
-    switch (format) {
-        case AudioFormat::I16:
-            size = sizeof(int16_t);
-            break;
-        case AudioFormat::Float:
-            size = sizeof(float);
-            break;
-        default:
-            break;
-    }
-    return size;
-}
-
-const char *convertResultToText(Result returnCode) {
-    switch (returnCode) {
-        OBOE_CASE_ENUM(Result::OK);
-        OBOE_CASE_ENUM(Result::ErrorBase);
-        OBOE_CASE_ENUM(Result::ErrorDisconnected);
-        OBOE_CASE_ENUM(Result::ErrorIllegalArgument);
-        OBOE_CASE_ENUM(Result::ErrorInternal);
-        OBOE_CASE_ENUM(Result::ErrorInvalidState);
-        OBOE_CASE_ENUM(Result::ErrorInvalidHandle);
-        OBOE_CASE_ENUM(Result::ErrorUnimplemented);
-        OBOE_CASE_ENUM(Result::ErrorUnavailable);
-        OBOE_CASE_ENUM(Result::ErrorNoFreeHandles);
-        OBOE_CASE_ENUM(Result::ErrorNoMemory);
-        OBOE_CASE_ENUM(Result::ErrorNull);
-        OBOE_CASE_ENUM(Result::ErrorTimeout);
-        OBOE_CASE_ENUM(Result::ErrorWouldBlock);
-        OBOE_CASE_ENUM(Result::ErrorInvalidFormat);
-        OBOE_CASE_ENUM(Result::ErrorOutOfRange);
-        OBOE_CASE_ENUM(Result::ErrorNoService);
-        OBOE_CASE_ENUM(Result::ErrorInvalidRate);
-    }
-}
-
-const char *convertAudioFormatToText(AudioFormat format) {
-    switch (format) {
-        OBOE_CASE_ENUM(AudioFormat::Invalid);
-        OBOE_CASE_ENUM(AudioFormat::Unspecified);
-        OBOE_CASE_ENUM(AudioFormat::I16);
-        OBOE_CASE_ENUM(AudioFormat::Float);
-    }
-}
-
-const char *convertPerformanceModeToText(PerformanceMode mode) {
-    switch (mode) {
-        OBOE_CASE_ENUM(PerformanceMode::LowLatency);
-        OBOE_CASE_ENUM(PerformanceMode::None);
-        OBOE_CASE_ENUM(PerformanceMode::PowerSaving);
-    }
-}
-
-const char *convertSharingModeToText(SharingMode mode) {
-    switch (mode) {
-        OBOE_CASE_ENUM(SharingMode::Exclusive);
-        OBOE_CASE_ENUM(SharingMode::Shared);
-    }
-}
-
-const char *convertDataCallbackResultToText(DataCallbackResult result) {
-    switch (result) {
-        OBOE_CASE_ENUM(DataCallbackResult::Continue);
-        OBOE_CASE_ENUM(DataCallbackResult::Stop);
-    }
-}
-
-const char *convertDirectionToText(Direction direction) {
-    switch (direction) {
-        OBOE_CASE_ENUM(Direction::Input);
-        OBOE_CASE_ENUM(Direction::Output);
-    }
-}
-
-} // namespace oboe
\ No newline at end of file
diff --git a/src/fifo/FifoBuffer.cpp b/src/fifo/FifoBuffer.cpp
index 030e57df1..7caea9323 100644
--- a/src/fifo/FifoBuffer.cpp
+++ b/src/fifo/FifoBuffer.cpp
@@ -25,8 +25,6 @@
 #include "fifo/FifoBuffer.h"
 #include "common/AudioClock.h"
 
-namespace oboe {
-
 FifoBuffer::FifoBuffer(uint32_t bytesPerFrame, uint32_t capacityInFrames)
         : mFrameCapacity(capacityInFrames)
         , mBytesPerFrame(bytesPerFrame)
@@ -177,7 +175,7 @@ int64_t FifoBuffer::getNextReadTime(int frameRate) {
     if (mReadAtNanoseconds == 0) {
         return 0;
     }
-    int64_t nanosPerBuffer = (kNanosPerSecond * mLastReadSize) / frameRate;
+    int64_t nanosPerBuffer = (OBOE_NANOS_PER_SECOND * mLastReadSize) / frameRate;
     return mReadAtNanoseconds + nanosPerBuffer;
 }
 
@@ -192,5 +190,3 @@ uint32_t FifoBuffer::getBufferCapacityInFrames() const {
 void FifoBuffer::setThresholdFrames(uint32_t threshold) {
     mFifo->setThreshold(threshold);
 }
-
-} // namespace oboe
\ No newline at end of file
diff --git a/src/fifo/FifoBuffer.h b/src/fifo/FifoBuffer.h
index e23bdd71d..08fb4e700 100644
--- a/src/fifo/FifoBuffer.h
+++ b/src/fifo/FifoBuffer.h
@@ -22,9 +22,7 @@
 
 #include "common/OboeDebug.h"
 #include "FifoControllerBase.h"
-#include "oboe/Definitions.h"
-
-namespace oboe {
+#include "oboe/OboeDefinitions.h"
 
 class FifoBuffer {
 public:
@@ -92,6 +90,4 @@ class FifoBuffer {
     uint32_t mLastReadSize;
 };
 
-} // namespace oboe
-
 #endif //NATIVEOBOE_FIFOPROCESSOR_H
diff --git a/src/fifo/FifoController.cpp b/src/fifo/FifoController.cpp
index c35ea877e..e3ba37346 100644
--- a/src/fifo/FifoController.cpp
+++ b/src/fifo/FifoController.cpp
@@ -19,8 +19,6 @@
 #include "FifoControllerBase.h"
 #include "FifoController.h"
 
-namespace oboe {
-
 FifoController::FifoController(uint32_t numFrames, uint32_t threshold)
         : FifoControllerBase(numFrames, threshold)
 {
@@ -30,6 +28,3 @@ FifoController::FifoController(uint32_t numFrames, uint32_t threshold)
 
 FifoController::~FifoController() {
 }
-
-} // namespace oboe
-
diff --git a/src/fifo/FifoController.h b/src/fifo/FifoController.h
index 200a585cf..d427f4723 100644
--- a/src/fifo/FifoController.h
+++ b/src/fifo/FifoController.h
@@ -21,8 +21,6 @@
 #include "FifoControllerBase.h"
 #include 
 
-namespace oboe {
-
 /**
  * A FifoControllerBase with counters contained in the class.
  */
@@ -51,6 +49,5 @@ class FifoController : public FifoControllerBase
     std::atomic mWriteCounter;
 };
 
-} // namespace oboe
 
 #endif //NATIVEOBOE_FIFOCONTROLLER_H
diff --git a/src/fifo/FifoControllerBase.cpp b/src/fifo/FifoControllerBase.cpp
index 8e50331ba..9aedac5a5 100644
--- a/src/fifo/FifoControllerBase.cpp
+++ b/src/fifo/FifoControllerBase.cpp
@@ -22,8 +22,6 @@
 
 #include "common/OboeDebug.h"
 
-namespace oboe {
-
 FifoControllerBase::FifoControllerBase(uint32_t totalFrames, uint32_t threshold)
         : mTotalFrames(totalFrames)
         , mThreshold(threshold)
@@ -71,5 +69,3 @@ void FifoControllerBase::advanceWriteIndex(uint32_t numFrames) {
 void FifoControllerBase::setThreshold(uint32_t threshold) {
     mThreshold = threshold;
 }
-
-} // namespace oboe
\ No newline at end of file
diff --git a/src/fifo/FifoControllerBase.h b/src/fifo/FifoControllerBase.h
index 5e5a0cab4..feb34c2b7 100644
--- a/src/fifo/FifoControllerBase.h
+++ b/src/fifo/FifoControllerBase.h
@@ -17,9 +17,8 @@
 #ifndef NATIVEOBOE_FIFOCONTROLLERBASE_H
 #define NATIVEOBOE_FIFOCONTROLLERBASE_H
 
-#include 
 
-namespace oboe {
+#include 
 
 /**
  * Manage the read/write indices of a circular buffer.
@@ -90,6 +89,5 @@ class FifoControllerBase {
 //    uint32_t mSmallMask;
 };
 
-} // namespace oboe
 
 #endif //NATIVEOBOE_FIFOCONTROLLERBASE_H
diff --git a/src/fifo/FifoControllerIndirect.cpp b/src/fifo/FifoControllerIndirect.cpp
index 6ef080c79..f52d831c9 100644
--- a/src/fifo/FifoControllerIndirect.cpp
+++ b/src/fifo/FifoControllerIndirect.cpp
@@ -17,8 +17,6 @@
 
 #include "FifoControllerIndirect.h"
 
-namespace oboe {
-
 FifoControllerIndirect::FifoControllerIndirect(uint32_t numFrames,
                                                uint32_t threshold,
                                                int64_t * readCounterAddress,
@@ -31,5 +29,3 @@ FifoControllerIndirect::FifoControllerIndirect(uint32_t numFrames,
 
 FifoControllerIndirect::~FifoControllerIndirect() {
 }
-
-}
\ No newline at end of file
diff --git a/src/fifo/FifoControllerIndirect.h b/src/fifo/FifoControllerIndirect.h
index aa5d0ae47..a8bc7fd1b 100644
--- a/src/fifo/FifoControllerIndirect.h
+++ b/src/fifo/FifoControllerIndirect.h
@@ -20,8 +20,6 @@
 #include "FifoControllerBase.h"
 #include 
 
-namespace oboe {
-
 /**
  * A FifoControllerBase with counters external to the class.
  */
@@ -55,6 +53,4 @@ class FifoControllerIndirect : public FifoControllerBase {
 
 };
 
-} // namespace oboe
-
 #endif //NATIVEOBOE_FIFOCONTROLLERINDIRECT_H
diff --git a/src/opensles/StreamBuffered.cpp b/src/opensles/OboeStreamBuffered.cpp
similarity index 64%
rename from src/opensles/StreamBuffered.cpp
rename to src/opensles/OboeStreamBuffered.cpp
index 670827b9a..b31229638 100644
--- a/src/opensles/StreamBuffered.cpp
+++ b/src/opensles/OboeStreamBuffered.cpp
@@ -16,56 +16,53 @@
 
 #include "oboe/Oboe.h"
 
-#include "opensles/StreamBuffered.h"
+#include "opensles/OboeStreamBuffered.h"
 #include "common/AudioClock.h"
 
-namespace oboe {
-
 /*
- * Stream with a FifoBuffer
+ * OboeStream with a FifoBuffer
  */
-StreamBuffered::StreamBuffered(const StreamBuilder &builder)
-        : Stream(builder)
+OboeStreamBuffered::OboeStreamBuffered(const OboeStreamBuilder &builder)
+        : OboeStream(builder)
         , mFifoBuffer(NULL)
         , mInternalCallback(NULL)
 {
 }
 
-Result StreamBuffered::open() {
+oboe_result_t OboeStreamBuffered::open() {
 
-    Result result = Stream::open();
-    if (result != Result::OK) {
+    oboe_result_t result = OboeStream::open();
+    if (result < 0) {
         return result;
     }
 
     // If the caller does not provide a callback use our own internal
     // callback that reads data from the FIFO.
     if (getCallback() == NULL) {
-        LOGD("StreamBuffered(): new FifoBuffer");
+        LOGD("OboeStreamBuffered(): new FifoBuffer");
         mFifoBuffer = new FifoBuffer(getBytesPerFrame(), 1024); // TODO size?
         // Create a callback that reads from the FIFO
         mInternalCallback = new AudioStreamBufferedCallback(this);
         mStreamCallback = mInternalCallback;
-        LOGD("StreamBuffered(): mInternalCallback = %p", mInternalCallback);
+        LOGD("OboeStreamBuffered(): mInternalCallback = %p", mInternalCallback);
     }
-    return Result::OK;
+    return OBOE_OK;
 }
 
-StreamBuffered::~StreamBuffered() {
+OboeStreamBuffered::~OboeStreamBuffered() {
     delete mInternalCallback;
 }
 
-// TODO: This method should return a tuple of Result,int32_t where the 2nd return param is the frames written
-int32_t StreamBuffered::write(const void *buffer,
-                              int32_t numFrames,
-                              int64_t timeoutNanoseconds)
+oboe_result_t OboeStreamBuffered::write(const void *buffer,
+                                         int32_t numFrames,
+                                         int64_t timeoutNanoseconds)
 {
-    int32_t result = 0;
+    oboe_result_t result = OBOE_OK;
     uint8_t *source = (uint8_t *)buffer;
     int32_t framesLeft = numFrames;
     while(framesLeft > 0 && result >= 0) {
-        result = mFifoBuffer->write(source, numFrames);
-        LOGD("StreamBuffered::writeNow(): wrote %d/%d frames", result, numFrames);
+        oboe_result_t result = mFifoBuffer->write(source, numFrames);
+        LOGD("OboeStreamBuffered::writeNow(): wrote %d/%d frames", result, numFrames);
         if (result > 0) {
             source += mFifoBuffer->convertFramesToBytes(result);
             incrementFramesWritten(result);
@@ -80,34 +77,32 @@ int32_t StreamBuffered::write(const void *buffer,
     return result;
 }
 
-Result StreamBuffered::setBufferSizeInFrames(int32_t requestedFrames)
+oboe_result_t OboeStreamBuffered::setBufferSizeInFrames(int32_t requestedFrames)
 {
     if (mFifoBuffer != nullptr) {
         if (requestedFrames > mFifoBuffer->getBufferCapacityInFrames()) {
             requestedFrames = mFifoBuffer->getBufferCapacityInFrames();
         }
         mFifoBuffer->setThresholdFrames(requestedFrames);
-        return Result::OK;
+        return OBOE_OK;
     } else {
-        return Result::ErrorUnimplemented;
+        return OBOE_ERROR_UNIMPLEMENTED;
     }
 }
 
 
-int32_t StreamBuffered::getBufferSizeInFrames() const {
+int32_t OboeStreamBuffered::getBufferSizeInFrames() const {
     if (mFifoBuffer != nullptr) {
         return mFifoBuffer->getThresholdFrames();
     } else {
-        return Stream::getBufferSizeInFrames();
+        return OboeStream::getBufferSizeInFrames();
     }
 }
 
-int32_t StreamBuffered::getBufferCapacityInFrames() const {
+int32_t OboeStreamBuffered::getBufferCapacityInFrames() const {
     if (mFifoBuffer != nullptr) {
         return mFifoBuffer->getBufferCapacityInFrames(); // Maybe set mBufferCapacity in constructor
     } else {
-        return Stream::getBufferCapacityInFrames();
+        return OboeStream::getBufferCapacityInFrames();
     }
 }
-
-} // namespace oboe
\ No newline at end of file
diff --git a/src/opensles/StreamBuffered.h b/src/opensles/OboeStreamBuffered.h
similarity index 57%
rename from src/opensles/StreamBuffered.h
rename to src/opensles/OboeStreamBuffered.h
index e76304824..118f170b9 100644
--- a/src/opensles/StreamBuffered.h
+++ b/src/opensles/OboeStreamBuffered.h
@@ -14,31 +14,29 @@
  * limitations under the License.
  */
 
-#ifndef OBOE_STREAM_BUFFERED_H
-#define OBOE_STREAM_BUFFERED_H
+#ifndef OBOE_OBOE_STREAM_BUFFERED_H
+#define OBOE_OBOE_STREAM_BUFFERED_H
 
 #include "common/OboeDebug.h"
-#include "oboe/Stream.h"
-#include "oboe/StreamCallback.h"
+#include "oboe/OboeStream.h"
+#include "oboe/OboeStreamCallback.h"
 #include "fifo/FifoBuffer.h"
 
-namespace oboe {
-
 // A stream that contains a FIFO buffer.
-class StreamBuffered : public Stream {
+class OboeStreamBuffered : public OboeStream {
 public:
 
-    StreamBuffered();
-    explicit StreamBuffered(const StreamBuilder &builder);
-    virtual ~StreamBuffered();
+    OboeStreamBuffered();
+    explicit OboeStreamBuffered(const OboeStreamBuilder &builder);
+    virtual ~OboeStreamBuffered();
 
-    Result open() override;
+    oboe_result_t open() override;
 
-    int32_t write(const void *buffer,
-                  int32_t numFrames,
-                  int64_t timeoutNanoseconds) override;
+    oboe_result_t write(const void *buffer,
+                                int32_t numFrames,
+                                int64_t timeoutNanoseconds) override;
 
-    Result setBufferSizeInFrames(int32_t requestedFrames) override;
+    oboe_result_t setBufferSizeInFrames(int32_t requestedFrames) override;
 
     int32_t getBufferSizeInFrames() const override;
 
@@ -46,26 +44,26 @@ class StreamBuffered : public Stream {
 
 protected:
 
-    class AudioStreamBufferedCallback : public StreamCallback {
+    class AudioStreamBufferedCallback : public OboeStreamCallback {
     public:
-        AudioStreamBufferedCallback(StreamBuffered *bufferedStream)
+        AudioStreamBufferedCallback(OboeStreamBuffered *bufferedStream)
                 : mBufferedStream(bufferedStream) {
         }
 
         virtual ~AudioStreamBufferedCallback() {}
 
-        virtual DataCallbackResult onAudioReady(
-                Stream *audioStream,
+        virtual oboe_result_t onAudioReady(
+                OboeStream *audioStream,
                 void *audioData,
                 int numFrames) {
             int32_t framesRead = mBufferedStream->mFifoBuffer->readNow(audioData, numFrames);
             //LOGD("AudioStreamBufferedCallback(): read %d / %d frames", framesRead, numFrames);
-            return (framesRead >= 0) ? DataCallbackResult::Continue : DataCallbackResult::Stop;
+            return (framesRead >= 0) ? OBOE_OK : OBOE_ERROR_INTERNAL;
         }
 
-        virtual void onExit(Result reason) {}
+        virtual void onExit(oboe_result_t reason) {}
     private:
-        StreamBuffered *mBufferedStream;
+        OboeStreamBuffered *mBufferedStream;
     };
 
 private:
@@ -74,6 +72,5 @@ class StreamBuffered : public Stream {
     AudioStreamBufferedCallback *mInternalCallback;
 };
 
-} // namespace oboe
 
-#endif //OBOE_STREAM_BUFFERED_H
+#endif //OBOE_OBOE_STREAM_BUFFERED_H
diff --git a/src/opensles/StreamOpenSLES.cpp b/src/opensles/OboeStreamOpenSLES.cpp
similarity index 76%
rename from src/opensles/StreamOpenSLES.cpp
rename to src/opensles/OboeStreamOpenSLES.cpp
index 75a954d48..d3b62aa23 100644
--- a/src/opensles/StreamOpenSLES.cpp
+++ b/src/opensles/OboeStreamOpenSLES.cpp
@@ -21,8 +21,8 @@
 #include 
 
 #include "common/OboeDebug.h"
-#include "oboe/StreamBuilder.h"
-#include "StreamOpenSLES.h"
+#include "oboe/OboeStreamBuilder.h"
+#include "OboeStreamOpenSLES.h"
 #include "OpenSLESUtilities.h"
 
 #ifndef NULL
@@ -35,8 +35,6 @@
 
 #define OBOE_BITS_PER_BYTE            8      // common value
 
-namespace oboe {
-
 /*
  * OSLES Helpers
  */
@@ -60,7 +58,7 @@ static const char *errStrings[] = {
         "SL_RESULT_CONTROL_LOST"              // 16
 };
 
-const char *getSLErrStr(SLresult code) {
+const char *getSLErrStr(int code) {
     return errStrings[code];
 }
 
@@ -114,10 +112,10 @@ static SLObjectItf sOutputMixObject = 0;
 
 static void CloseSLEngine();
 
-SLresult StreamOpenSLES::enqueueBuffer() {
+SLresult OboeStreamOpenSLES::enqueueBuffer() {
     // Ask the callback to fill the output buffer with data.
-    Result result = fireCallback(mCallbackBuffer, mFramesPerCallback);
-    if (result != Result::OK) {
+    oboe_result_t result = fireCallback(mCallbackBuffer, mFramesPerCallback);
+    if (result != OBOE_OK) {
         LOGE("Oboe callback returned %d", result);
         return SL_RESULT_INTERNAL_ERROR;
     } else {
@@ -128,7 +126,7 @@ SLresult StreamOpenSLES::enqueueBuffer() {
 
 // this callback handler is called every time a buffer finishes playing
 static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
-    ((StreamOpenSLES *) context)->enqueueBuffer();
+    ((OboeStreamOpenSLES *) context)->enqueueBuffer();
 }
 
 static SLresult OpenSLEngine() {
@@ -200,31 +198,32 @@ static void CloseSLEngine() {
     }
 }
 
-StreamOpenSLES::StreamOpenSLES(const StreamBuilder &builder)
-    : StreamBuffered(builder) {
+OboeStreamOpenSLES::OboeStreamOpenSLES(const OboeStreamBuilder &builder)
+    : OboeStreamBuffered(builder) {
     bqPlayerObject_ = NULL;
     bq_ = NULL;
     bqPlayerPlay_ = NULL;
     mFramesPerBurst = builder.getDefaultFramesPerBurst();
     OpenSLEngine();
-    LOGD("StreamOpenSLES(): after OpenSLEngine()");
+    LOGD("OboeStreamOpenSLES(): after OpenSLEngine()");
 }
 
-StreamOpenSLES::~StreamOpenSLES() {
+OboeStreamOpenSLES::~OboeStreamOpenSLES() {
     CloseSLEngine();
     delete[] mCallbackBuffer;
 }
 
-static SLuint32 ConvertFormatToRepresentation(AudioFormat format) {
+static SLuint32 ConvertFormatToRepresentation(oboe_audio_format_t format) {
     switch(format) {
-        case AudioFormat::Invalid:
-        case AudioFormat::Unspecified:
+        case OBOE_AUDIO_FORMAT_INVALID:
+        case OBOE_AUDIO_FORMAT_UNSPECIFIED:
             return 0;
-        case AudioFormat::I16:
+        case OBOE_AUDIO_FORMAT_PCM_I16:
             return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
-        case AudioFormat::Float:
+        case OBOE_AUDIO_FORMAT_PCM_FLOAT:
             return SL_ANDROID_PCM_REPRESENTATION_FLOAT;
     }
+    return 0;
 }
 
 static bool s_isLittleEndian() {
@@ -236,43 +235,43 @@ static SLuint32 s_getDefaultByteOrder() {
     return s_isLittleEndian() ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN;
 }
 
-Result StreamOpenSLES::open() {
+oboe_result_t OboeStreamOpenSLES::open() {
 
     SLresult result;
 
     __android_log_print(ANDROID_LOG_INFO, TAG, "AudioPlayerOpenSLES::Open(chans:%d, rate:%d)",
                         mChannelCount, mSampleRate);
 
-    if (__ANDROID_API__ < __ANDROID_API_L__ && mFormat == AudioFormat::Float){
+    if (__ANDROID_API__ < __ANDROID_API_L__ && mFormat == OBOE_AUDIO_FORMAT_PCM_FLOAT){
         // TODO: Allow floating point format on API <21 using float->int16 converter
-        return Result::ErrorInvalidFormat;
+        return OBOE_ERROR_INVALID_FORMAT;
     }
 
     // If audio format is unspecified then choose a suitable default.
     // API 21+: FLOAT
     // API <21: INT16
-    if (mFormat == AudioFormat::Unspecified){
+    if (mFormat == OBOE_AUDIO_FORMAT_UNSPECIFIED){
         mFormat = (__ANDROID_API__ < __ANDROID_API_L__) ?
-                  AudioFormat::I16 : AudioFormat::Float;
+                  OBOE_AUDIO_FORMAT_PCM_I16 : OBOE_AUDIO_FORMAT_PCM_FLOAT;
     }
 
-    Result oboeResult = StreamBuffered::open();
-    if (oboeResult != Result::OK) {
+    oboe_result_t oboeResult = OboeStreamBuffered::open();
+    if (oboeResult < 0) {
         return oboeResult;
     }
     // Convert to defaults if UNSPECIFIED
-    if (mSampleRate == kUnspecified) {
+    if (mSampleRate == OBOE_UNSPECIFIED) {
         mSampleRate = DEFAULT_SAMPLE_RATE;
     }
-    if (mChannelCount == kUnspecified) {
+    if (mChannelCount == OBOE_UNSPECIFIED) {
         mChannelCount = DEFAULT_CHANNEL_COUNT;
     }
 
     // Decide frames per burst based hints from caller.
     // TODO  Can we query this from OpenSL ES?
-    if (mFramesPerCallback != kUnspecified) {
+    if (mFramesPerCallback != OBOE_UNSPECIFIED) {
         mFramesPerBurst = mFramesPerCallback;
-    } else if (mFramesPerBurst != kUnspecified) { // set from defaultFramesPerBurst
+    } else if (mFramesPerBurst != OBOE_UNSPECIFIED) { // set from defaultFramesPerBurst
         mFramesPerCallback = mFramesPerBurst;
     } else {
         mFramesPerBurst = mFramesPerCallback = DEFAULT_FRAMES_PER_CALLBACK;
@@ -280,8 +279,8 @@ Result StreamOpenSLES::open() {
 
     mBytesPerCallback = mFramesPerCallback * getBytesPerFrame();
     mCallbackBuffer = new uint8_t[mBytesPerCallback];
-    LOGD("StreamOpenSLES(): mFramesPerCallback = %d", mFramesPerCallback);
-    LOGD("StreamOpenSLES(): mBytesPerCallback = %d", mBytesPerCallback);
+    LOGD("OboeStreamOpenSLES(): mFramesPerCallback = %d", mFramesPerCallback);
+    LOGD("OboeStreamOpenSLES(): mBytesPerCallback = %d", mBytesPerCallback);
 
     SLuint32 bitsPerSample = getBytesPerSample() * OBOE_BITS_PER_BYTE;
 
@@ -296,7 +295,7 @@ Result StreamOpenSLES::open() {
     SLDataFormat_PCM format_pcm = {
             SL_DATAFORMAT_PCM,       // formatType
             (SLuint32) mChannelCount,           // numChannels
-            (SLuint32) (mSampleRate * kMillisPerSecond),    // milliSamplesPerSec
+            (SLuint32) (mSampleRate * OBOE_MILLIS_PER_SECOND),    // milliSamplesPerSec
             bitsPerSample,                      // bitsPerSample
             bitsPerSample,                      // containerSize;
             (SLuint32) chanCountToChanMask(mChannelCount), // channelMask
@@ -351,14 +350,14 @@ Result StreamOpenSLES::open() {
     LOGD("register callback result:%s", getSLErrStr(result));
     assert(SL_RESULT_SUCCESS == result);
 
-    mSharingMode = SharingMode::Shared;
+    mSharingMode = OBOE_SHARING_MODE_SHARED;
     mBufferCapacityInFrames = mFramesPerBurst * mBurstsPerBuffer;
 
-    return Result::OK;
+    return OBOE_OK;
 }
 
-Result StreamOpenSLES::close() {
-//    __android_log_write(ANDROID_LOG_INFO, TAG, "StreamOpenSLES()");
+oboe_result_t OboeStreamOpenSLES::close() {
+//    __android_log_write(ANDROID_LOG_INFO, TAG, "OboeStreamOpenSLES()");
     // TODO make sure callback is no longer being called
     if (bqPlayerObject_ != NULL) {
         (*bqPlayerObject_)->Destroy(bqPlayerObject_);
@@ -368,84 +367,83 @@ Result StreamOpenSLES::close() {
         bqPlayerPlay_ = NULL;
         bq_ = NULL;
     }
-    return Result::OK;
+    return OBOE_OK;
 }
 
-Result StreamOpenSLES::setPlayState(SLuint32 newState)
+oboe_result_t OboeStreamOpenSLES::setPlayState(SLuint32 newState)
 {
-    Result result = Result::OK;
-    LOGD("StreamOpenSLES(): setPlayState()");
+    oboe_result_t result = OBOE_OK;
+    LOGD("OboeStreamOpenSLES(): setPlayState()");
     if (bqPlayerPlay_ == NULL) {
-        return Result::ErrorInvalidState;
+        return OBOE_ERROR_INVALID_STATE;
     }
     SLresult slResult = (*bqPlayerPlay_)->SetPlayState(bqPlayerPlay_, newState);
     if(SL_RESULT_SUCCESS != slResult) {
-        LOGD("StreamOpenSLES(): setPlayState() returned %s", getSLErrStr(slResult));
-        result = Result::ErrorInvalidState; // TODO review
+        LOGD("OboeStreamOpenSLES(): setPlayState() returned %s", getSLErrStr(result));
+        result = OBOE_ERROR_INVALID_STATE; // TODO review
     } else {
-        setState(StreamState::Pausing);
+        setState(OBOE_STREAM_STATE_PAUSING);
     }
     return result;
 }
 
-Result StreamOpenSLES::requestStart()
+oboe_result_t OboeStreamOpenSLES::requestStart()
 {
-    LOGD("StreamOpenSLES(): requestStart()");
-    Result result = setPlayState(SL_PLAYSTATE_PLAYING);
-    if(result != Result::OK) {
-        result = Result::ErrorInvalidState; // TODO review
+    LOGD("OboeStreamOpenSLES(): requestStart()");
+    oboe_result_t result = setPlayState(SL_PLAYSTATE_PLAYING);
+    if(result != OBOE_OK) {
+        result = OBOE_ERROR_INVALID_STATE; // TODO review
     } else {
         enqueueBuffer();
-        setState(StreamState::Starting);
+        setState(OBOE_STREAM_STATE_STARTING);
     }
     return result;
 }
 
 
-Result StreamOpenSLES::requestPause() {
-    LOGD("StreamOpenSLES(): requestPause()");
-    Result result = setPlayState(SL_PLAYSTATE_PAUSED);
-    if(result != Result::OK) {
-        result = Result::ErrorInvalidState; // TODO review
+oboe_result_t OboeStreamOpenSLES::requestPause() {
+    LOGD("OboeStreamOpenSLES(): requestPause()");
+    oboe_result_t result = setPlayState(SL_PLAYSTATE_PAUSED);
+    if(result != OBOE_OK) {
+        result = OBOE_ERROR_INVALID_STATE; // TODO review
     } else {
-        setState(StreamState::Pausing);
+        setState(OBOE_STREAM_STATE_PAUSING);
     }
     return result;
 }
 
-Result StreamOpenSLES::requestFlush() {
-    LOGD("StreamOpenSLES(): requestFlush()");
+oboe_result_t OboeStreamOpenSLES::requestFlush() {
+    LOGD("OboeStreamOpenSLES(): requestFlush()");
     if (bqPlayerPlay_ == NULL) {
-        return Result::ErrorInvalidState;
+        return OBOE_ERROR_INVALID_STATE;
     }
-    return Result::ErrorUnimplemented; // TODO
+    return OBOE_ERROR_UNIMPLEMENTED; // TODO
 }
 
-Result StreamOpenSLES::requestStop()
+oboe_result_t OboeStreamOpenSLES::requestStop()
 {
-    LOGD("StreamOpenSLES(): requestStop()");
-    Result result = setPlayState(SL_PLAYSTATE_STOPPED);
-    if(result != Result::OK) {
-        result = Result::ErrorInvalidState; // TODO review
+    LOGD("OboeStreamOpenSLES(): requestStop()");
+    oboe_result_t result = setPlayState(SL_PLAYSTATE_STOPPED);
+    if(result != OBOE_OK) {
+        result = OBOE_ERROR_INVALID_STATE; // TODO review
     } else {
-        setState(StreamState::Stopping);
+        setState(OBOE_STREAM_STATE_STOPPING);
     }
     return result;
 }
 
-Result StreamOpenSLES::waitForStateChange(StreamState currentState,
-                                                      StreamState *nextState,
+oboe_result_t OboeStreamOpenSLES::waitForStateChange(oboe_stream_state_t currentState,
+                                                      oboe_stream_state_t *nextState,
                                                       int64_t timeoutNanoseconds)
 {
-    LOGD("StreamOpenSLES(): waitForStateChange()");
+    LOGD("OboeStreamOpenSLES(): waitForStateChange()");
     if (bqPlayerPlay_ == NULL) {
-        return Result::ErrorInvalidState;
+        return OBOE_ERROR_INVALID_STATE;
     }
-    return Result::ErrorUnimplemented; // TODO
+    return OBOE_ERROR_UNIMPLEMENTED; // TODO
 }
 
-int32_t StreamOpenSLES::getFramesPerBurst() {
+int32_t OboeStreamOpenSLES::getFramesPerBurst() {
     return mFramesPerBurst;
 }
 
-} // namespace oboe
diff --git a/src/opensles/StreamOpenSLES.h b/src/opensles/OboeStreamOpenSLES.h
similarity index 70%
rename from src/opensles/StreamOpenSLES.h
rename to src/opensles/OboeStreamOpenSLES.h
index 2621dcf64..81eb50023 100644
--- a/src/opensles/StreamOpenSLES.h
+++ b/src/opensles/OboeStreamOpenSLES.h
@@ -21,9 +21,7 @@
 #include 
 
 #include "oboe/Oboe.h"
-#include "StreamBuffered.h"
-
-namespace oboe {
+#include "OboeStreamBuffered.h"
 
 /**
  * A stream that wraps OpenSL ES.
@@ -32,27 +30,27 @@ namespace oboe {
  * Use an OboeStreamBuilder to create one.
  */
 //
-class StreamOpenSLES : public StreamBuffered {
+class OboeStreamOpenSLES : public OboeStreamBuffered {
 public:
 
-    StreamOpenSLES();
-    explicit StreamOpenSLES(const StreamBuilder &builder);
+    OboeStreamOpenSLES();
+    explicit OboeStreamOpenSLES(const OboeStreamBuilder &builder);
 
-    virtual ~StreamOpenSLES();
+    virtual ~OboeStreamOpenSLES();
 
-    Result open() override;
-    Result close() override;
+    oboe_result_t open() override;
+    oboe_result_t close() override;
 
-    Result requestStart() override;
-    Result requestPause() override;
-    Result requestFlush() override;
-    Result requestStop() override;
+    oboe_result_t requestStart() override;
+    oboe_result_t requestPause() override;
+    oboe_result_t requestFlush() override;
+    oboe_result_t requestStop() override;
 
     // public, but don't call directly (called by the OSLES callback)
     SLresult enqueueBuffer();
 
-    Result waitForStateChange(StreamState currentState,
-                                             StreamState *nextState,
+    oboe_result_t waitForStateChange(oboe_stream_state_t currentState,
+                                             oboe_stream_state_t *nextState,
                                              int64_t timeoutNanoseconds) override;
 
     /**
@@ -60,7 +58,7 @@ class StreamOpenSLES : public StreamBuffered {
      *
      * @return state or a negative error.
      */
-    StreamState getState() override { return mState; }
+    oboe_stream_state_t getState() override { return mState; }
 
     int32_t getFramesPerBurst() override;
 
@@ -71,7 +69,7 @@ class StreamOpenSLES : public StreamBuffered {
      * Internal use only.
      * Use this instead of directly setting the internal state variable.
      */
-    void setState(StreamState state) {
+    void setState(oboe_stream_state_t state) {
         mState = state;
     }
 
@@ -81,13 +79,13 @@ class StreamOpenSLES : public StreamBuffered {
      * @param newState SL_PLAYSTATE_PAUSED, SL_PLAYSTATE_PLAYING, SL_PLAYSTATE_STOPPED
      * @return
      */
-    Result setPlayState(SLuint32 newState);
+    oboe_result_t setPlayState(SLuint32 newState);
 
     uint8_t              *mCallbackBuffer;
     int32_t               mBytesPerCallback;
     int32_t               mFramesPerBurst = 0;
     int32_t               mBurstsPerBuffer = 2; // Double buffered
-    StreamState           mState = StreamState::Uninitialized;
+    oboe_stream_state_t   mState = OBOE_STREAM_STATE_UNINITIALIZED;
 
     // OpenSLES stuff
     SLObjectItf                   bqPlayerObject_;
@@ -95,6 +93,5 @@ class StreamOpenSLES : public StreamBuffered {
     SLAndroidSimpleBufferQueueItf bq_;
 };
 
-} // namespace oboe
 
 #endif // AUDIO_STREAM_OPENSL_ES_H_
diff --git a/src/opensles/OpenSLESUtilities.cpp b/src/opensles/OpenSLESUtilities.cpp
index 0636bda32..e38b4e56c 100644
--- a/src/opensles/OpenSLESUtilities.cpp
+++ b/src/opensles/OpenSLESUtilities.cpp
@@ -16,8 +16,6 @@
 
 #include "OpenSLESUtilities.h"
 
-namespace oboe {
-
 SLAndroidDataFormat_PCM_EX OpenSLES_createExtendedFormat(
         SLDataFormat_PCM format, SLuint32 representation) {
     SLAndroidDataFormat_PCM_EX format_pcm_ex;
@@ -31,5 +29,3 @@ SLAndroidDataFormat_PCM_EX OpenSLES_createExtendedFormat(
     format_pcm_ex.representation = representation;
     return format_pcm_ex;
 }
-
-} // namespace oboe
\ No newline at end of file
diff --git a/src/opensles/OpenSLESUtilities.h b/src/opensles/OpenSLESUtilities.h
index a0b73af4b..41fd644ae 100644
--- a/src/opensles/OpenSLESUtilities.h
+++ b/src/opensles/OpenSLESUtilities.h
@@ -19,8 +19,6 @@
 
 #include 
 
-namespace oboe {
-
 /**
  * Creates an extended PCM format from the supplied format and data representation. This method
  * should only be called on Android devices with API level 21+. API 21 introduced the
@@ -34,6 +32,4 @@ namespace oboe {
 SLAndroidDataFormat_PCM_EX OpenSLES_createExtendedFormat(SLDataFormat_PCM format,
                                                          SLuint32 representation);
 
-} // namespace oboe
-
 #endif //OBOE_OPENSLES_OPENSLESUTILITIES_H

From ea28de20932c24c9eaf788f8476a0bca29c00c67 Mon Sep 17 00:00:00 2001
From: Don Turner 
Date: Mon, 12 Feb 2018 14:08:19 +0000
Subject: [PATCH 42/45] Revert "oboe: automatically stop and close a stream
 when disconnected"

This reverts commit 2140eb1f8d57811d1cc038c4029ac33457842276.
---
 include/oboe/OboeStreamBuilder.h  |   9 --
 include/oboe/OboeStreamCallback.h |  32 ++----
 src/aaudio/OboeStreamAAudio.cpp   | 164 ++++++------------------------
 src/aaudio/OboeStreamAAudio.h     |  26 ++---
 src/common/OboeStreamBuilder.cpp  |   4 +-
 5 files changed, 49 insertions(+), 186 deletions(-)

diff --git a/include/oboe/OboeStreamBuilder.h b/include/oboe/OboeStreamBuilder.h
index ecb854241..1985b44a0 100644
--- a/include/oboe/OboeStreamBuilder.h
+++ b/include/oboe/OboeStreamBuilder.h
@@ -190,15 +190,6 @@ class OboeStreamBuilder : public OboeStreamBase {
         return this;
     }
 
-    /**
-     * Specifies an object to handle data or error related callbacks from the underlying API.
-     *
-     * When an error callback occurs, the associated stream will be stopped
-     * and closed in a separate thread.
-     *
-     * @param streamCallback
-     * @return
-     */
     OboeStreamBuilder *setCallback(OboeStreamCallback *streamCallback) {
         mStreamCallback = streamCallback;
         return this;
diff --git a/include/oboe/OboeStreamCallback.h b/include/oboe/OboeStreamCallback.h
index da69978f1..102b198ef 100644
--- a/include/oboe/OboeStreamCallback.h
+++ b/include/oboe/OboeStreamCallback.h
@@ -24,42 +24,22 @@ class OboeStream;
 class OboeStreamCallback {
 public:
     virtual ~OboeStreamCallback() = default;
-
     /**
      * A buffer is ready for processing.
      *
-     * @param oboeStream pointer to the associated stream
-     * @param audioData buffer containing input data or a place to put output data
-     * @param numFrames number of frames to be processed
+     * @param input buffer containing recorded audio, may be NULL
+     * @param output fill this with audio data to be played, may be NULL
+     * @param number of frames of input or output
      * @return OBOE_CALLBACK_RESULT_CONTINUE or OBOE_CALLBACK_RESULT_STOP
      */
     virtual oboe_data_callback_result_t onAudioReady(
-            OboeStream *oboeStream,
+            OboeStream *audioStream,
             void *audioData,
             int32_t numFrames) = 0;
 
-    /**
-     * This will be called when an error occurs on a stream or when the stream is discomnnected.
-     * The underlying stream will already be stopped by Oboe but not yet closed.
-     * So the stream can be queried.
-     *
-     * @param oboeStream pointer to the associated stream
-     * @param error
-     */
-    virtual void onErrorBeforeClose(OboeStream *oboeStream, oboe_result_t error) {}
-
-    /**
-     * This will be called when an error occurs on a stream or when the stream is disconnected.
-     * The underlying stream will already be stopped AND closed by Oboe.
-     * So the underlyng stream cannot be referenced.
-     *
-     * This callback could be used to reopen a new stream on another device.
-     *
-     * @param oboeStream pointer to the associated stream
-     * @param error
-     */
-    virtual void onErrorAfterClose(OboeStream *oboeStream, oboe_result_t error) {}
+    virtual void onError(OboeStream *audioStream, oboe_result_t error) {}
 
 };
 
+
 #endif //OBOE_OBOE_STREAM_CALLBACK_H
diff --git a/src/aaudio/OboeStreamAAudio.cpp b/src/aaudio/OboeStreamAAudio.cpp
index 786adfc1f..860f9368b 100644
--- a/src/aaudio/OboeStreamAAudio.cpp
+++ b/src/aaudio/OboeStreamAAudio.cpp
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-#include 
 #include 
 
+#include "oboe/OboeUtilities.h"
+#include "common/OboeDebug.h"
 #include "aaudio/AAudioLoader.h"
 #include "aaudio/OboeStreamAAudio.h"
-#include "common/OboeDebug.h"
-#include "oboe/OboeUtilities.h"
 
 AAudioLoader *OboeStreamAAudio::mLibLoader = nullptr;
 
@@ -65,14 +64,6 @@ static aaudio_data_callback_result_t oboe_aaudio_data_callback_proc(
     }
 }
 
-static void oboe_aaudio_error_thread_proc(OboeStreamAAudio *oboeStream,
-                                          AAudioStream *stream,
-                                          oboe_result_t error) {
-    if (oboeStream != NULL) {
-        oboeStream->onErrorInThread(stream, error);
-    }
-}
-
 // 'C' wrapper for the error callback method
 static void oboe_aaudio_error_callback_proc(
         AAudioStream *stream,
@@ -81,9 +72,7 @@ static void oboe_aaudio_error_callback_proc(
 
     OboeStreamAAudio *oboeStream = (OboeStreamAAudio *)userData;
     if (oboeStream != NULL) {
-        // Handle error on a separate thread
-        std::thread t(oboe_aaudio_error_thread_proc, oboeStream, stream, error);
-        t.detach();
+        oboeStream->callOnError(stream, error);
     }
 }
 
@@ -116,19 +105,15 @@ oboe_result_t OboeStreamAAudio::open() {
     mLibLoader->builder_setSharingMode(aaudioBuilder, mSharingMode);
     mLibLoader->builder_setPerformanceMode(aaudioBuilder, mPerformanceMode);
 
-    // TODO get more parameters from the builder?
+    // TODO get more parameters from the builder
 
     if (mStreamCallback != nullptr) {
         mLibLoader->builder_setDataCallback(aaudioBuilder, oboe_aaudio_data_callback_proc, this);
+        mLibLoader->builder_setErrorCallback(aaudioBuilder, oboe_aaudio_error_callback_proc, this);
         mLibLoader->builder_setFramesPerDataCallback(aaudioBuilder, getFramesPerCallback());
     }
-    mLibLoader->builder_setErrorCallback(aaudioBuilder, oboe_aaudio_error_callback_proc, this);
 
-    {
-        AAudioStream *stream = nullptr;
-        result = mLibLoader->builder_openStream(aaudioBuilder, &stream);
-        mAAudioStream.store(stream);
-    }
+    result = mLibLoader->builder_openStream(aaudioBuilder, &mAAudioStream);
     if (result != AAUDIO_OK) {
         goto error2;
     }
@@ -143,33 +128,23 @@ oboe_result_t OboeStreamAAudio::open() {
     }
     mSharingMode = mLibLoader->stream_getSharingMode(mAAudioStream);
     mPerformanceMode = mLibLoader->stream_getPerformanceMode(mAAudioStream);
-    mBufferCapacityInFrames = mLibLoader->stream_getBufferCapacity(mAAudioStream);
+    mBufferCapacityInFrames = getBufferCapacityInFrames();
 
     LOGD("OboeStreamAAudio.open() app    format = %d", (int) mFormat);
     LOGD("OboeStreamAAudio.open() native format = %d", (int) mNativeFormat);
     LOGD("OboeStreamAAudio.open() sample rate   = %d", (int) mSampleRate);
-    LOGD("OboeStreamAAudio.open() capacity      = %d", (int) mBufferCapacityInFrames);
 
 error2:
     mLibLoader->builder_delete(aaudioBuilder);
     LOGD("OboeStreamAAudio.open: AAudioStream_Open() returned %s, mAAudioStream = %p",
-         mLibLoader->convertResultToText(result), mAAudioStream.load());
+         mLibLoader->convertResultToText(result), mAAudioStream);
     return result;
 }
 
 oboe_result_t OboeStreamAAudio::close()
 {
-    // The main reason we have this mutex if to prevent a collision between a call
-    // by the application to stop a stream at the same time that an onError callback
-    // is being executed because of a disconnect. The close will delete the stream,
-    // which could otherwise cause the requestStop() to crash.
-    std::lock_guard lock(mLock);
-    oboe_result_t result = OBOE_OK;
-    // This will delete the AAudio stream object so we need to null out the pointer.
-    AAudioStream *stream = mAAudioStream.exchange(nullptr);
-    if (stream != nullptr) {
-        result = mLibLoader->stream_close(stream);
-    }
+    oboe_result_t result = mLibLoader->stream_close(mAAudioStream);
+    mAAudioStream = nullptr;
     return result;
 }
 
@@ -182,18 +157,8 @@ aaudio_data_callback_result_t OboeStreamAAudio::callOnAudioReady(AAudioStream *s
             numFrames);
 }
 
-void OboeStreamAAudio::onErrorInThread(AAudioStream *stream, oboe_result_t error) {
-    LOGD("onErrorInThread() - entering ===================================");
-    assert(stream == mAAudioStream.load());
-    requestStop();
-    if (mStreamCallback != nullptr) {
-        mStreamCallback->onErrorBeforeClose(this, error);
-    }
-    close();
-    if (mStreamCallback != nullptr) {
-        mStreamCallback->onErrorAfterClose(this, error);
-    }
-    LOGD("onErrorInThread() - exiting ===================================");
+void OboeStreamAAudio::callOnError(AAudioStream *stream, oboe_result_t error) {
+    mStreamCallback->onError( this, error);
 }
 
 oboe_result_t OboeStreamAAudio::convertApplicationDataToNative(int32_t numFrames) {
@@ -215,146 +180,81 @@ oboe_result_t OboeStreamAAudio::convertApplicationDataToNative(int32_t numFrames
 
 oboe_result_t OboeStreamAAudio::requestStart()
 {
-    std::lock_guard lock(mLock);
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream != nullptr) {
-        return mLibLoader->stream_requestStart(stream);
-    } else {
-        return OBOE_ERROR_NULL;
-    }
+    return mLibLoader->stream_requestStart(mAAudioStream);
 }
 
 oboe_result_t OboeStreamAAudio::requestPause()
 {
-    std::lock_guard lock(mLock);
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream != nullptr) {
-        return mLibLoader->stream_requestPause(stream);
-    } else {
-        return OBOE_ERROR_NULL;
-    }
+    return mLibLoader->stream_requestPause(mAAudioStream);
 }
 
 oboe_result_t OboeStreamAAudio::requestFlush() {
-    std::lock_guard lock(mLock);
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream != nullptr) {
-        return mLibLoader->stream_requestFlush(stream);
-    } else {
-        return OBOE_ERROR_NULL;
-    }
+    return mLibLoader->stream_requestFlush(mAAudioStream);
 }
 
 oboe_result_t OboeStreamAAudio::requestStop()
 {
-    std::lock_guard lock(mLock);
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream != nullptr) {
-        return mLibLoader->stream_requestStop(stream);
-    } else {
-        return OBOE_ERROR_NULL;
-    }
+    return mLibLoader->stream_requestStop(mAAudioStream);
 }
 
 oboe_result_t OboeStreamAAudio::write(const void *buffer,
                                      int32_t numFrames,
                                      int64_t timeoutNanoseconds)
 {
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream != nullptr) {
-        return mLibLoader->stream_write(mAAudioStream, buffer, numFrames, timeoutNanoseconds);
-    } else {
-        return OBOE_ERROR_NULL;
-    }
+    return mLibLoader->stream_write(mAAudioStream, buffer, numFrames, timeoutNanoseconds);
 }
 
 oboe_result_t OboeStreamAAudio::waitForStateChange(oboe_stream_state_t currentState,
                                                   oboe_stream_state_t *nextState,
                                                   int64_t timeoutNanoseconds)
 {
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream != nullptr) {
-        return mLibLoader->stream_waitForStateChange(mAAudioStream, currentState,
-                                                     nextState, timeoutNanoseconds);
-    } else {
-        return OBOE_ERROR_NULL;
-    }
+    return mLibLoader->stream_waitForStateChange(mAAudioStream, currentState,
+                                                 nextState, timeoutNanoseconds);
 }
 
 oboe_result_t OboeStreamAAudio::setBufferSizeInFrames(int32_t requestedFrames)
 {
-    if (requestedFrames > mBufferCapacityInFrames) {
-        requestedFrames = mBufferCapacityInFrames;
-    }
     return mLibLoader->stream_setBufferSize(mAAudioStream, requestedFrames);
 }
 
 oboe_stream_state_t OboeStreamAAudio::getState()
 {
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream != nullptr) {
-        return mLibLoader->stream_getState(stream);
-    } else {
+    if (mAAudioStream == nullptr) {
         return OBOE_STREAM_STATE_CLOSED;
     }
+    return mLibLoader->stream_getState(mAAudioStream);
 }
 
 int32_t OboeStreamAAudio::getBufferSizeInFrames() const {
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream != nullptr) {
-        return mLibLoader->stream_getBufferSize(stream);
-    } else {
-        return OBOE_ERROR_NULL;
-    }
+    return mLibLoader->stream_getBufferSize(mAAudioStream);
+}
+
+int32_t OboeStreamAAudio::getBufferCapacityInFrames() const {
+    return mLibLoader->stream_getBufferCapacity(mAAudioStream);
 }
 
 int32_t OboeStreamAAudio::getFramesPerBurst()
 {
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream != nullptr) {
-        return mLibLoader->stream_getFramesPerBurst(stream);
-    } else {
-        return OBOE_ERROR_NULL;
-    }
+    return mLibLoader->stream_getFramesPerBurst(mAAudioStream);
 }
 
 int64_t OboeStreamAAudio::getFramesRead()
 {
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream != nullptr) {
-        return mLibLoader->stream_getFramesRead(stream);
-    } else {
-        return OBOE_ERROR_NULL;
-    }
+    return mLibLoader->stream_getFramesRead(mAAudioStream);
 }
 int64_t OboeStreamAAudio::getFramesWritten()
 {
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream != nullptr) {
-        return mLibLoader->stream_getFramesWritten(stream);
-    } else {
-        return OBOE_ERROR_NULL;
-    }
+    return mLibLoader->stream_getFramesWritten(mAAudioStream);
 }
 
 int32_t OboeStreamAAudio::getXRunCount()
 {
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream != nullptr) {
-        return mLibLoader->stream_getXRunCount(stream);
-    } else {
-        return OBOE_ERROR_NULL;
-    }
+    return mLibLoader->stream_getXRunCount(mAAudioStream);
 }
 
 oboe_result_t OboeStreamAAudio::getTimestamp(clockid_t clockId,
                                    int64_t *framePosition,
                                    int64_t *timeNanoseconds) {
-    AAudioStream *stream = mAAudioStream.load();
-    if (stream != nullptr) {
-        return mLibLoader->stream_getTimestamp(stream, clockId,
-                                               framePosition, timeNanoseconds);
-    } else {
-        return OBOE_ERROR_NULL;
-    }
+    return mLibLoader->stream_getTimestamp(mAAudioStream, clockId,
+                                   framePosition, timeNanoseconds);
 }
diff --git a/src/aaudio/OboeStreamAAudio.h b/src/aaudio/OboeStreamAAudio.h
index e89288377..fc55975f2 100644
--- a/src/aaudio/OboeStreamAAudio.h
+++ b/src/aaudio/OboeStreamAAudio.h
@@ -18,15 +18,13 @@
 #define OBOE_OBOE_STREAM_AAUDIO_H_
 
 #include 
-#include 
-#include 
-
-#include "aaudio/AAudio.h"
 
 #include "oboe/OboeStreamBuilder.h"
 #include "oboe/OboeStream.h"
 #include "oboe/OboeDefinitions.h"
 
+#include "aaudio/AAudio.h"
+
 class AAudioLoader;
 
 /**
@@ -64,6 +62,7 @@ class OboeStreamAAudio : public OboeStream {
 
     oboe_result_t setBufferSizeInFrames(int32_t requestedFrames) override;
     int32_t getBufferSizeInFrames() const override;
+    int32_t getBufferCapacityInFrames() const override;
     int32_t getFramesPerBurst() override;
     int32_t getXRunCount() override;
 
@@ -89,23 +88,16 @@ class OboeStreamAAudio : public OboeStream {
     aaudio_data_callback_result_t callOnAudioReady(AAudioStream *stream,
                                                    void *audioData,
                                                    int32_t numFrames);
-
-    void onErrorCallback(AAudioStream *stream, oboe_result_t error);
-
-    void onErrorInThread(AAudioStream *stream, oboe_result_t error);
+    void callOnError(AAudioStream *stream, oboe_result_t error);
 
 protected:
-    oboe_result_t convertApplicationDataToNative(int32_t numFrames); // TODO remove?
+    oboe_result_t convertApplicationDataToNative(int32_t numFrames);
 
 private:
-
-    float               *mFloatCallbackBuffer;
-    int16_t             *mShortCallbackBuffer;
-    std::atomic    mCallbackThreadEnabled;
-    std::thread         *mErrorHandlingThread = nullptr;
-
-    std::mutex           mLock; // for synchronizing start/stop/close
-    std::atomic mAAudioStream{nullptr};
+    float              *mFloatCallbackBuffer;
+    int16_t            *mShortCallbackBuffer;
+    std::atomic   mCallbackThreadEnabled;
+    AAudioStream       *mAAudioStream;
 
     static AAudioLoader *mLibLoader;
 };
diff --git a/src/common/OboeStreamBuilder.cpp b/src/common/OboeStreamBuilder.cpp
index 9a450e396..aa184c77e 100644
--- a/src/common/OboeStreamBuilder.cpp
+++ b/src/common/OboeStreamBuilder.cpp
@@ -16,11 +16,11 @@
 
 #include 
 
-#include "aaudio/OboeStreamAAudio.h"
 #include "OboeDebug.h"
 #include "oboe/Oboe.h"
-#include "oboe/OboeStreamBuilder.h"
+
 #include "opensles/OboeStreamOpenSLES.h"
+#include "aaudio/OboeStreamAAudio.h"
 
 bool OboeStreamBuilder::isAAudioSupported() {
     return OboeStreamAAudio::isSupported();

From c6522d88d4092d7bb749a030aff043e6a890945c Mon Sep 17 00:00:00 2001
From: Don Turner 
Date: Mon, 12 Feb 2018 14:08:19 +0000
Subject: [PATCH 43/45] Revert "Update FifoBuffer.cpp"

This reverts commit dcf634a68369137d0d0da8bcd89496800d94b417.
---
 src/fifo/FifoBuffer.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/fifo/FifoBuffer.cpp b/src/fifo/FifoBuffer.cpp
index 7caea9323..24137d4a0 100644
--- a/src/fifo/FifoBuffer.cpp
+++ b/src/fifo/FifoBuffer.cpp
@@ -16,7 +16,6 @@
 
 #include 
 #include 
-#include 
 
 #include "common/OboeDebug.h"
 #include "fifo/FifoControllerBase.h"

From 56374c5b288ecbc6f77b7bb644959635b951602d Mon Sep 17 00:00:00 2001
From: Don Turner 
Date: Mon, 12 Feb 2018 14:08:19 +0000
Subject: [PATCH 44/45] Revert "oboe callback: remove onExit()"

This reverts commit 284021e30b172bbc5dac53200b7c9b59ab7dfd85.
---
 include/oboe/OboeStreamCallback.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/include/oboe/OboeStreamCallback.h b/include/oboe/OboeStreamCallback.h
index 102b198ef..56f7d31b0 100644
--- a/include/oboe/OboeStreamCallback.h
+++ b/include/oboe/OboeStreamCallback.h
@@ -39,6 +39,13 @@ class OboeStreamCallback {
 
     virtual void onError(OboeStream *audioStream, oboe_result_t error) {}
 
+    /**
+     * The callback thread is exiting.
+     *
+     * @param reason Why it is exiting. OBOE_OK if requested.
+     *               Or maybe OBOE_ERROR_TIMEOUT or OBOE_ERROR_DISCONNECTED.
+     */
+    virtual void onExit(oboe_result_t reason) {}
 };
 
 

From f7a8c8ae529691ad819558514dd1c0d39825d6fb Mon Sep 17 00:00:00 2001
From: Don Turner 
Date: Mon, 12 Feb 2018 14:08:19 +0000
Subject: [PATCH 45/45] Revert "oboe: fix dlsym for getFramesWritten/Read"

This reverts commit 3d6c40a0803f89b10fddfd8117678460efc9068d.
---
 src/aaudio/AAudioLoader.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/aaudio/AAudioLoader.cpp b/src/aaudio/AAudioLoader.cpp
index 08704f54c..14d76ac0b 100644
--- a/src/aaudio/AAudioLoader.cpp
+++ b/src/aaudio/AAudioLoader.cpp
@@ -118,8 +118,8 @@ int AAudioLoader::open() {
     stream_getDirection       = load_I_PS("AAudioStream_getDirection");
     stream_getBufferCapacity  = load_I_PS("AAudioStream_getBufferCapacityInFrames");
     stream_getFramesPerBurst  = load_I_PS("AAudioStream_getFramesPerBurst");
-    stream_getFramesRead      = load_L_PS("AAudioStream_getFramesRead");
-    stream_getFramesWritten   = load_L_PS("AAudioStream_getFramesWritten");
+    stream_getFramesRead      = load_L_PS("AAudioStream_getFramesWritten");
+    stream_getFramesWritten   = load_L_PS("AAudioStream_getFramesRead");
     stream_getPerformanceMode = load_I_PS("AAudioStream_getPerformanceMode");
     stream_getSampleRate      = load_I_PS("AAudioStream_getSampleRate");
     stream_getSharingMode     = load_I_PS("AAudioStream_getSharingMode");