Loading media/libaaudio/tests/Android.bp +2 −2 Original line number Diff line number Diff line Loading @@ -209,9 +209,9 @@ cc_test { } cc_test { name: "test_stop_hang", name: "test_callback_race", defaults: ["libaaudio_tests_defaults"], srcs: ["test_stop_hang.cpp"], srcs: ["test_callback_race.cpp"], shared_libs: [ "libaaudio", "libbinder", Loading media/libaaudio/tests/test_callback_race.cpp 0 → 100644 +209 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Test whether the callback is joined before the close finishes. * * Start a stream with a callback. * The callback just sleeps for a long time. * While the callback is sleeping, close() the stream from the main thread. * Then check to make sure the callback was joined before the close() returns. * * This can hang if there are deadlocks. So make sure you get a PASSED result. */ #include <atomic> #include <stdio.h> #include <unistd.h> #include <gtest/gtest.h> #include <aaudio/AAudio.h> // Sleep long enough that the foreground has a change to call close. static constexpr int kCallbackSleepMicros = 600 * 1000; class AudioEngine { public: // Check for a crash or late callback if we close without stopping. void checkCloseJoins(aaudio_direction_t direction, aaudio_performance_mode_t perfMode, aaudio_data_callback_result_t callbackResult) { // Make printf print immediately so that debug info is not stuck // in a buffer if we hang or crash. setvbuf(stdout, nullptr, _IONBF, (size_t) 0); mCallbackResult = callbackResult; startStreamForStall(direction, perfMode); // When the callback starts it will go to sleep. waitForCallbackToStart(); printf("call AAudioStream_close()\n"); ASSERT_FALSE(mCallbackFinished); // Still sleeping? aaudio_result_t result = AAudioStream_close(mStream); // May hang here! ASSERT_TRUE(mCallbackFinished); ASSERT_EQ(AAUDIO_OK, result); printf("AAudioStream_close() returned %d\n", result); ASSERT_EQ(AAUDIO_OK, mError.load()); // Did calling stop() from callback fail? It should have. ASSERT_NE(AAUDIO_OK, mStopResult.load()); } private: void startStreamForStall(aaudio_direction_t direction, aaudio_performance_mode_t perfMode) { AAudioStreamBuilder* builder = nullptr; aaudio_result_t result = AAUDIO_OK; // Use an AAudioStreamBuilder to contain requested parameters. result = AAudio_createStreamBuilder(&builder); ASSERT_EQ(AAUDIO_OK, result); // Request stream properties. AAudioStreamBuilder_setDirection(builder, direction); AAudioStreamBuilder_setPerformanceMode(builder, perfMode); AAudioStreamBuilder_setDataCallback(builder, s_myDataCallbackProc, this); AAudioStreamBuilder_setErrorCallback(builder, s_myErrorCallbackProc, this); // Create an AAudioStream using the Builder. result = AAudioStreamBuilder_openStream(builder, &mStream); AAudioStreamBuilder_delete(builder); ASSERT_EQ(AAUDIO_OK, result); // Check to see what kind of stream we actually got. int32_t deviceId = AAudioStream_getDeviceId(mStream); aaudio_performance_mode_t actualPerfMode = AAudioStream_getPerformanceMode(mStream); printf("-------- opened: deviceId = %3d, perfMode = %d\n", deviceId, actualPerfMode); // Start stream. result = AAudioStream_requestStart(mStream); ASSERT_EQ(AAUDIO_OK, result); } void waitForCallbackToStart() { // Wait for callback to say it has been called. int countDownMillis = 2000; constexpr int countDownPeriodMillis = 50; while (!mCallbackStarted && countDownMillis > 0) { printf("Waiting for callback to start, %d\n", countDownMillis); usleep(countDownPeriodMillis * 1000); countDownMillis -= countDownPeriodMillis; } ASSERT_LT(0, countDownMillis); ASSERT_TRUE(mCallbackStarted); } // Callback function that fills the audio output buffer. static aaudio_data_callback_result_t s_myDataCallbackProc( AAudioStream *stream, void *userData, void * /*audioData */, int32_t /* numFrames */ ) { AudioEngine* engine = (AudioEngine*) userData; engine->mCallbackStarted = true; usleep(kCallbackSleepMicros); // it is illegal to call stop() from the callback. It should // return an error and not hang. engine->mStopResult = AAudioStream_requestStop(stream); engine->mCallbackFinished = true; return engine->mCallbackResult; } static void s_myErrorCallbackProc( AAudioStream * /* stream */, void *userData, aaudio_result_t error) { AudioEngine *engine = (AudioEngine *)userData; engine->mError = error; } AAudioStream* mStream = nullptr; std::atomic<aaudio_result_t> mError{AAUDIO_OK}; // written by error callback std::atomic<bool> mCallbackStarted{false}; // written by data callback std::atomic<bool> mCallbackFinished{false}; // written by data callback std::atomic<aaudio_data_callback_result_t> mCallbackResult{AAUDIO_CALLBACK_RESULT_CONTINUE}; std::atomic<aaudio_result_t> mStopResult{AAUDIO_OK}; }; /*********************************************************************/ // Tell the callback to return AAUDIO_CALLBACK_RESULT_CONTINUE. TEST(test_close_timing, aaudio_close_joins_input_none) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT, AAUDIO_PERFORMANCE_MODE_NONE, AAUDIO_CALLBACK_RESULT_CONTINUE); } TEST(test_close_timing, aaudio_close_joins_output_none) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT, AAUDIO_PERFORMANCE_MODE_NONE, AAUDIO_CALLBACK_RESULT_CONTINUE); } TEST(test_close_timing, aaudio_close_joins_input_lowlat) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_CALLBACK_RESULT_CONTINUE); } TEST(test_close_timing, aaudio_close_joins_output_lowlat) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_CALLBACK_RESULT_CONTINUE); } /*********************************************************************/ // Tell the callback to return AAUDIO_CALLBACK_RESULT_STOP. TEST(test_close_timing, aaudio_close_joins_input_lowlat_stop) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_CALLBACK_RESULT_STOP); } TEST(test_close_timing, aaudio_close_joins_output_lowlat_stop) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_CALLBACK_RESULT_STOP); } TEST(test_close_timing, aaudio_close_joins_output_none_stop) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT, AAUDIO_PERFORMANCE_MODE_NONE, AAUDIO_CALLBACK_RESULT_STOP); } TEST(test_close_timing, aaudio_close_joins_input_none_stop) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT, AAUDIO_PERFORMANCE_MODE_NONE, AAUDIO_CALLBACK_RESULT_STOP); } media/libaaudio/tests/test_stop_hang.cppdeleted 100644 → 0 +0 −159 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Return stop from the callback * and then close the stream immediately. */ #include <atomic> #include <mutex> #include <stdio.h> #include <thread> #include <unistd.h> #include <aaudio/AAudio.h> #define DURATION_SECONDS 5 struct AudioEngine { AAudioStreamBuilder *builder = nullptr; AAudioStream *stream = nullptr; std::thread *thread = nullptr; std::atomic<bool> started{false}; std::mutex doneLock; // Use a mutex so we can sleep on it while join()ing. std::atomic<bool> done{false}; aaudio_result_t join() { aaudio_result_t result = AAUDIO_ERROR_INVALID_STATE; if (stream != nullptr) { while (true) { { // Will block if the thread is running. // This mutex is used to close() immediately after the callback returns // and before the requestStop_l() is called. std::lock_guard<std::mutex> lock(doneLock); if (done) break; } printf("join() got mutex but stream not done!"); usleep(10 * 1000); // sleep then check again } result = AAudioStream_close(stream); stream = nullptr; } return result; } }; // Callback function that fills the audio output buffer. static aaudio_data_callback_result_t s_myDataCallbackProc( AAudioStream *stream, void *userData, void *audioData, int32_t numFrames ) { (void) stream; (void) audioData; (void) numFrames; AudioEngine *engine = (struct AudioEngine *)userData; std::lock_guard<std::mutex> lock(engine->doneLock); engine->started = true; usleep(DURATION_SECONDS * 1000 * 1000); // Mimic SynthMark procedure. engine->done = true; return AAUDIO_CALLBACK_RESULT_STOP; } static void s_myErrorCallbackProc( AAudioStream *stream __unused, void *userData __unused, aaudio_result_t error) { printf("%s() - error = %d\n", __func__, error); } static aaudio_result_t s_OpenAudioStream(struct AudioEngine *engine) { // Use an AAudioStreamBuilder to contain requested parameters. aaudio_result_t result = AAudio_createStreamBuilder(&engine->builder); if (result != AAUDIO_OK) { printf("AAudio_createStreamBuilder returned %s", AAudio_convertResultToText(result)); return result; } // Request stream properties. AAudioStreamBuilder_setPerformanceMode(engine->builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY); AAudioStreamBuilder_setDataCallback(engine->builder, s_myDataCallbackProc, engine); AAudioStreamBuilder_setErrorCallback(engine->builder, s_myErrorCallbackProc, engine); // Create an AAudioStream using the Builder. result = AAudioStreamBuilder_openStream(engine->builder, &engine->stream); if (result != AAUDIO_OK) { printf("AAudioStreamBuilder_openStream returned %s", AAudio_convertResultToText(result)); return result; } return result; } int main(int argc, char **argv) { (void) argc; (void) argv; struct AudioEngine engine; aaudio_result_t result = AAUDIO_OK; int errorCount = 0; // Make printf print immediately so that debug info is not stuck // in a buffer if we hang or crash. setvbuf(stdout, nullptr, _IONBF, (size_t) 0); printf("Test Return Stop Hang V1.0\n"); result = s_OpenAudioStream(&engine); if (result != AAUDIO_OK) { printf("s_OpenAudioStream returned %s\n", AAudio_convertResultToText(result)); errorCount++; } // Check to see what kind of stream we actually got. int32_t deviceId = AAudioStream_getDeviceId(engine.stream); aaudio_performance_mode_t actualPerfMode = AAudioStream_getPerformanceMode(engine.stream); printf("-------- opened: deviceId = %3d, perfMode = %d\n", deviceId, actualPerfMode); // Start stream. result = AAudioStream_requestStart(engine.stream); printf("AAudioStream_requestStart() returned %d >>>>>>>>>>>>>>>>>>>>>>\n", result); if (result != AAUDIO_OK) { errorCount++; } else { int counter = 0; while (!engine.started) { printf("Waiting for stream to start, %d\n", counter++); usleep(5 * 1000); } printf("You should see more messages %d seconds after this. If not then the test failed!\n", DURATION_SECONDS); result = engine.join(); // This might hang! AAudioStreamBuilder_delete(engine.builder); engine.builder = nullptr; } printf("aaudio result = %d = %s\n", result, AAudio_convertResultToText(result)); printf("test %s\n", errorCount ? "FAILED" : "PASSED"); return errorCount ? EXIT_FAILURE : EXIT_SUCCESS; } Loading
media/libaaudio/tests/Android.bp +2 −2 Original line number Diff line number Diff line Loading @@ -209,9 +209,9 @@ cc_test { } cc_test { name: "test_stop_hang", name: "test_callback_race", defaults: ["libaaudio_tests_defaults"], srcs: ["test_stop_hang.cpp"], srcs: ["test_callback_race.cpp"], shared_libs: [ "libaaudio", "libbinder", Loading
media/libaaudio/tests/test_callback_race.cpp 0 → 100644 +209 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Test whether the callback is joined before the close finishes. * * Start a stream with a callback. * The callback just sleeps for a long time. * While the callback is sleeping, close() the stream from the main thread. * Then check to make sure the callback was joined before the close() returns. * * This can hang if there are deadlocks. So make sure you get a PASSED result. */ #include <atomic> #include <stdio.h> #include <unistd.h> #include <gtest/gtest.h> #include <aaudio/AAudio.h> // Sleep long enough that the foreground has a change to call close. static constexpr int kCallbackSleepMicros = 600 * 1000; class AudioEngine { public: // Check for a crash or late callback if we close without stopping. void checkCloseJoins(aaudio_direction_t direction, aaudio_performance_mode_t perfMode, aaudio_data_callback_result_t callbackResult) { // Make printf print immediately so that debug info is not stuck // in a buffer if we hang or crash. setvbuf(stdout, nullptr, _IONBF, (size_t) 0); mCallbackResult = callbackResult; startStreamForStall(direction, perfMode); // When the callback starts it will go to sleep. waitForCallbackToStart(); printf("call AAudioStream_close()\n"); ASSERT_FALSE(mCallbackFinished); // Still sleeping? aaudio_result_t result = AAudioStream_close(mStream); // May hang here! ASSERT_TRUE(mCallbackFinished); ASSERT_EQ(AAUDIO_OK, result); printf("AAudioStream_close() returned %d\n", result); ASSERT_EQ(AAUDIO_OK, mError.load()); // Did calling stop() from callback fail? It should have. ASSERT_NE(AAUDIO_OK, mStopResult.load()); } private: void startStreamForStall(aaudio_direction_t direction, aaudio_performance_mode_t perfMode) { AAudioStreamBuilder* builder = nullptr; aaudio_result_t result = AAUDIO_OK; // Use an AAudioStreamBuilder to contain requested parameters. result = AAudio_createStreamBuilder(&builder); ASSERT_EQ(AAUDIO_OK, result); // Request stream properties. AAudioStreamBuilder_setDirection(builder, direction); AAudioStreamBuilder_setPerformanceMode(builder, perfMode); AAudioStreamBuilder_setDataCallback(builder, s_myDataCallbackProc, this); AAudioStreamBuilder_setErrorCallback(builder, s_myErrorCallbackProc, this); // Create an AAudioStream using the Builder. result = AAudioStreamBuilder_openStream(builder, &mStream); AAudioStreamBuilder_delete(builder); ASSERT_EQ(AAUDIO_OK, result); // Check to see what kind of stream we actually got. int32_t deviceId = AAudioStream_getDeviceId(mStream); aaudio_performance_mode_t actualPerfMode = AAudioStream_getPerformanceMode(mStream); printf("-------- opened: deviceId = %3d, perfMode = %d\n", deviceId, actualPerfMode); // Start stream. result = AAudioStream_requestStart(mStream); ASSERT_EQ(AAUDIO_OK, result); } void waitForCallbackToStart() { // Wait for callback to say it has been called. int countDownMillis = 2000; constexpr int countDownPeriodMillis = 50; while (!mCallbackStarted && countDownMillis > 0) { printf("Waiting for callback to start, %d\n", countDownMillis); usleep(countDownPeriodMillis * 1000); countDownMillis -= countDownPeriodMillis; } ASSERT_LT(0, countDownMillis); ASSERT_TRUE(mCallbackStarted); } // Callback function that fills the audio output buffer. static aaudio_data_callback_result_t s_myDataCallbackProc( AAudioStream *stream, void *userData, void * /*audioData */, int32_t /* numFrames */ ) { AudioEngine* engine = (AudioEngine*) userData; engine->mCallbackStarted = true; usleep(kCallbackSleepMicros); // it is illegal to call stop() from the callback. It should // return an error and not hang. engine->mStopResult = AAudioStream_requestStop(stream); engine->mCallbackFinished = true; return engine->mCallbackResult; } static void s_myErrorCallbackProc( AAudioStream * /* stream */, void *userData, aaudio_result_t error) { AudioEngine *engine = (AudioEngine *)userData; engine->mError = error; } AAudioStream* mStream = nullptr; std::atomic<aaudio_result_t> mError{AAUDIO_OK}; // written by error callback std::atomic<bool> mCallbackStarted{false}; // written by data callback std::atomic<bool> mCallbackFinished{false}; // written by data callback std::atomic<aaudio_data_callback_result_t> mCallbackResult{AAUDIO_CALLBACK_RESULT_CONTINUE}; std::atomic<aaudio_result_t> mStopResult{AAUDIO_OK}; }; /*********************************************************************/ // Tell the callback to return AAUDIO_CALLBACK_RESULT_CONTINUE. TEST(test_close_timing, aaudio_close_joins_input_none) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT, AAUDIO_PERFORMANCE_MODE_NONE, AAUDIO_CALLBACK_RESULT_CONTINUE); } TEST(test_close_timing, aaudio_close_joins_output_none) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT, AAUDIO_PERFORMANCE_MODE_NONE, AAUDIO_CALLBACK_RESULT_CONTINUE); } TEST(test_close_timing, aaudio_close_joins_input_lowlat) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_CALLBACK_RESULT_CONTINUE); } TEST(test_close_timing, aaudio_close_joins_output_lowlat) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_CALLBACK_RESULT_CONTINUE); } /*********************************************************************/ // Tell the callback to return AAUDIO_CALLBACK_RESULT_STOP. TEST(test_close_timing, aaudio_close_joins_input_lowlat_stop) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_CALLBACK_RESULT_STOP); } TEST(test_close_timing, aaudio_close_joins_output_lowlat_stop) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, AAUDIO_CALLBACK_RESULT_STOP); } TEST(test_close_timing, aaudio_close_joins_output_none_stop) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT, AAUDIO_PERFORMANCE_MODE_NONE, AAUDIO_CALLBACK_RESULT_STOP); } TEST(test_close_timing, aaudio_close_joins_input_none_stop) { AudioEngine engine; engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT, AAUDIO_PERFORMANCE_MODE_NONE, AAUDIO_CALLBACK_RESULT_STOP); }
media/libaaudio/tests/test_stop_hang.cppdeleted 100644 → 0 +0 −159 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Return stop from the callback * and then close the stream immediately. */ #include <atomic> #include <mutex> #include <stdio.h> #include <thread> #include <unistd.h> #include <aaudio/AAudio.h> #define DURATION_SECONDS 5 struct AudioEngine { AAudioStreamBuilder *builder = nullptr; AAudioStream *stream = nullptr; std::thread *thread = nullptr; std::atomic<bool> started{false}; std::mutex doneLock; // Use a mutex so we can sleep on it while join()ing. std::atomic<bool> done{false}; aaudio_result_t join() { aaudio_result_t result = AAUDIO_ERROR_INVALID_STATE; if (stream != nullptr) { while (true) { { // Will block if the thread is running. // This mutex is used to close() immediately after the callback returns // and before the requestStop_l() is called. std::lock_guard<std::mutex> lock(doneLock); if (done) break; } printf("join() got mutex but stream not done!"); usleep(10 * 1000); // sleep then check again } result = AAudioStream_close(stream); stream = nullptr; } return result; } }; // Callback function that fills the audio output buffer. static aaudio_data_callback_result_t s_myDataCallbackProc( AAudioStream *stream, void *userData, void *audioData, int32_t numFrames ) { (void) stream; (void) audioData; (void) numFrames; AudioEngine *engine = (struct AudioEngine *)userData; std::lock_guard<std::mutex> lock(engine->doneLock); engine->started = true; usleep(DURATION_SECONDS * 1000 * 1000); // Mimic SynthMark procedure. engine->done = true; return AAUDIO_CALLBACK_RESULT_STOP; } static void s_myErrorCallbackProc( AAudioStream *stream __unused, void *userData __unused, aaudio_result_t error) { printf("%s() - error = %d\n", __func__, error); } static aaudio_result_t s_OpenAudioStream(struct AudioEngine *engine) { // Use an AAudioStreamBuilder to contain requested parameters. aaudio_result_t result = AAudio_createStreamBuilder(&engine->builder); if (result != AAUDIO_OK) { printf("AAudio_createStreamBuilder returned %s", AAudio_convertResultToText(result)); return result; } // Request stream properties. AAudioStreamBuilder_setPerformanceMode(engine->builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY); AAudioStreamBuilder_setDataCallback(engine->builder, s_myDataCallbackProc, engine); AAudioStreamBuilder_setErrorCallback(engine->builder, s_myErrorCallbackProc, engine); // Create an AAudioStream using the Builder. result = AAudioStreamBuilder_openStream(engine->builder, &engine->stream); if (result != AAUDIO_OK) { printf("AAudioStreamBuilder_openStream returned %s", AAudio_convertResultToText(result)); return result; } return result; } int main(int argc, char **argv) { (void) argc; (void) argv; struct AudioEngine engine; aaudio_result_t result = AAUDIO_OK; int errorCount = 0; // Make printf print immediately so that debug info is not stuck // in a buffer if we hang or crash. setvbuf(stdout, nullptr, _IONBF, (size_t) 0); printf("Test Return Stop Hang V1.0\n"); result = s_OpenAudioStream(&engine); if (result != AAUDIO_OK) { printf("s_OpenAudioStream returned %s\n", AAudio_convertResultToText(result)); errorCount++; } // Check to see what kind of stream we actually got. int32_t deviceId = AAudioStream_getDeviceId(engine.stream); aaudio_performance_mode_t actualPerfMode = AAudioStream_getPerformanceMode(engine.stream); printf("-------- opened: deviceId = %3d, perfMode = %d\n", deviceId, actualPerfMode); // Start stream. result = AAudioStream_requestStart(engine.stream); printf("AAudioStream_requestStart() returned %d >>>>>>>>>>>>>>>>>>>>>>\n", result); if (result != AAUDIO_OK) { errorCount++; } else { int counter = 0; while (!engine.started) { printf("Waiting for stream to start, %d\n", counter++); usleep(5 * 1000); } printf("You should see more messages %d seconds after this. If not then the test failed!\n", DURATION_SECONDS); result = engine.join(); // This might hang! AAudioStreamBuilder_delete(engine.builder); engine.builder = nullptr; } printf("aaudio result = %d = %s\n", result, AAudio_convertResultToText(result)); printf("test %s\n", errorCount ? "FAILED" : "PASSED"); return errorCount ? EXIT_FAILURE : EXIT_SUCCESS; }