audio: add test_return_stop.cpp
Test returning a STOP code from the callback.
Bug: 120845500
Test: this is a test
Change-Id: I88aa46b356443ab055c194cb430d93618980894d
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 319467e..cb243a0 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -184,3 +184,15 @@
"libutils",
],
}
+
+cc_test {
+ name: "test_return_stop",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_return_stop.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
diff --git a/media/libaaudio/tests/test_return_stop.cpp b/media/libaaudio/tests/test_return_stop.cpp
new file mode 100644
index 0000000..f34c3c8
--- /dev/null
+++ b/media/libaaudio/tests/test_return_stop.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 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.
+ */
+
+/**
+ * Return stop from the callback.
+ * Expect the callback to cease.
+ * Check the logcat for bad behavior.
+ */
+
+#include <stdio.h>
+#include <thread>
+#include <unistd.h>
+
+#include <aaudio/AAudio.h>
+
+#define DEFAULT_TIMEOUT_NANOS ((int64_t)1000000000)
+#define STOP_AT_MSEC 1000
+#define LOOP_DURATION_MSEC 4000
+#define SLEEP_DURATION_MSEC 200
+
+static void s_myErrorCallbackProc(
+ AAudioStream *stream,
+ void *userData,
+ aaudio_result_t error);
+
+struct AudioEngine {
+ AAudioStreamBuilder *builder = nullptr;
+ AAudioStream *stream = nullptr;
+ std::thread *thread = nullptr;
+ int32_t stopAtFrame = 0;
+ bool stopped = false;
+ // These counters are read and written by the callback and the main thread.
+ std::atomic<int32_t> framesRead{};
+ std::atomic<int32_t> startingFramesRead{};
+ std::atomic<int32_t> framesCalled{};
+ std::atomic<int32_t> callbackCount{};
+ std::atomic<int32_t> callbackCountAfterStop{};
+
+ void reset() {
+ framesRead.store(0);
+ startingFramesRead.store(0);
+ framesCalled.store(0);
+ callbackCount.store(0);
+ callbackCountAfterStop.store(0);
+ stopped = false;
+ }
+};
+
+// 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) audioData;
+ (void) numFrames;
+ AudioEngine *engine = (struct AudioEngine *)userData;
+ engine->callbackCount++;
+ if (engine->stopped) {
+ engine->callbackCountAfterStop++;
+ }
+
+ engine->framesRead = (int32_t)AAudioStream_getFramesRead(stream);
+ if (engine->startingFramesRead == 0) {
+ engine->startingFramesRead.store(engine->framesRead.load());
+ }
+ engine->framesCalled += numFrames;
+ if (engine->framesCalled >= engine->stopAtFrame) {
+ engine->stopped = true;
+ return AAUDIO_CALLBACK_RESULT_STOP;
+ } else {
+ return AAUDIO_CALLBACK_RESULT_CONTINUE;
+ }
+}
+
+static aaudio_result_t s_OpenAudioStream(struct AudioEngine *engine,
+ aaudio_direction_t direction,
+ aaudio_sharing_mode_t sharingMode,
+ aaudio_performance_mode_t perfMode) {
+ // 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_setFormat(engine->builder, AAUDIO_FORMAT_PCM_FLOAT);
+ AAudioStreamBuilder_setPerformanceMode(engine->builder, perfMode);
+ AAudioStreamBuilder_setSharingMode(engine->builder, sharingMode);
+ AAudioStreamBuilder_setDirection(engine->builder, direction);
+ 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;
+}
+
+static aaudio_result_t s_CloseAudioStream(struct AudioEngine *engine) {
+ aaudio_result_t result = AAUDIO_OK;
+ if (engine->stream != nullptr) {
+ result = AAudioStream_close(engine->stream);
+ if (result != AAUDIO_OK) {
+ printf("AAudioStream_close returned %s\n",
+ AAudio_convertResultToText(result));
+ }
+ engine->stream = nullptr;
+ }
+ AAudioStreamBuilder_delete(engine->builder);
+ engine->builder = nullptr;
+ return result;
+}
+
+static void s_myErrorCallbackProc(
+ AAudioStream *stream __unused,
+ void *userData __unused,
+ aaudio_result_t error) {
+ printf("%s() - error = %d\n", __func__, error);
+}
+
+void usage() {
+ printf("test_return_stop [-i] [-x] [-n] [-c]\n");
+ printf(" -i direction INPUT, otherwise OUTPUT\n");
+ printf(" -x sharing mode EXCLUSIVE, otherwise SHARED\n");
+ printf(" -n performance mode NONE, otherwise LOW_LATENCY\n");
+ printf(" -c always return CONTINUE from callback, not STOP\n");
+}
+
+int main(int argc, char **argv) {
+ (void) argc;
+ (void) argv;
+ struct AudioEngine engine;
+ aaudio_sharing_mode_t sharingMode = AAUDIO_SHARING_MODE_SHARED;
+ aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
+ aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT;
+ aaudio_result_t result = AAUDIO_OK;
+ bool alwaysContinue = false;
+ int errorCount = 0;
+ int callbackResult = EXIT_SUCCESS;
+
+ // 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 V1.0\n");
+ printf("Wait for a few seconds.\n");
+ printf("You should see callbackCount and framesRead stop advancing\n");
+ printf("when callbackCount reaches %d msec\n", STOP_AT_MSEC);
+ printf("\n");
+
+ for (int i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+ if (arg[0] == '-') {
+ char option = arg[1];
+ switch (option) {
+ case 'c':
+ alwaysContinue = true;
+ break;
+ case 'i':
+ direction = AAUDIO_DIRECTION_INPUT;
+ break;
+ case 'n':
+ perfMode = AAUDIO_PERFORMANCE_MODE_NONE;
+ break;
+ case 'x':
+ sharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
+ break;
+ default:
+ usage();
+ exit(EXIT_FAILURE);
+ break;
+ }
+ } else {
+ usage();
+ exit(EXIT_FAILURE);
+ break;
+ }
+ }
+
+ result = s_OpenAudioStream(&engine, direction, sharingMode, perfMode);
+ if (result != AAUDIO_OK) {
+ printf("s_OpenAudioStream returned %s",
+ AAudio_convertResultToText(result));
+ errorCount++;
+ }
+
+ int32_t framesPerBurst = AAudioStream_getFramesPerBurst(engine.stream);
+ // 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, framesPerBurst = %3d, perfMode = %d\n",
+ deviceId, framesPerBurst, actualPerfMode);
+
+ // Calculate how many callbacks needed.
+ if (alwaysContinue) {
+ engine.stopAtFrame = INT32_MAX;
+ } else {
+ int32_t sampleRate = AAudioStream_getSampleRate(engine.stream);
+ engine.stopAtFrame = STOP_AT_MSEC * sampleRate / 1000;
+ }
+
+ for (int loops = 0; loops < 2 && result == AAUDIO_OK; loops++) {
+ engine.reset();
+
+ // Start stream.
+ result = AAudioStream_requestStart(engine.stream);
+ printf("AAudioStream_requestStart() returned %d >>>>>>>>>>>>>>>>>>>>>>\n", result);
+ if (result != AAUDIO_OK) {
+ printf("ERROR - AAudioStream_requestStart returned %s",
+ AAudio_convertResultToText(result));
+ errorCount++;
+ break;
+ }
+
+ if (result == AAUDIO_OK) {
+ const int watchLoops = LOOP_DURATION_MSEC / SLEEP_DURATION_MSEC;
+ for (int i = watchLoops; i > 0; i--) {
+ printf("playing silence #%02d, framesRead = %7d, framesWritten = %7d,"
+ " framesCalled = %6d, callbackCount = %4d\n",
+ i,
+ (int32_t) AAudioStream_getFramesRead(engine.stream),
+ (int32_t) AAudioStream_getFramesWritten(engine.stream),
+ engine.framesCalled.load(),
+ engine.callbackCount.load()
+ );
+ usleep(SLEEP_DURATION_MSEC * 1000);
+ }
+ }
+
+ if (engine.stopAtFrame != INT32_MAX) {
+ callbackResult = (engine.callbackCountAfterStop == 0) ? EXIT_SUCCESS
+ : EXIT_FAILURE;
+ if (callbackResult) {
+ printf("ERROR - Callback count after STOP = %d\n",
+ engine.callbackCountAfterStop.load());
+ errorCount++;
+ }
+ }
+
+ if (engine.startingFramesRead.load() == engine.framesRead.load()) {
+ printf("ERROR - framesRead did not advance across callbacks\n");
+ errorCount++;
+ }
+
+ result = AAudioStream_requestStop(engine.stream);
+ printf("AAudioStream_requestStop() returned %d <<<<<<<<<<<<<<<<<<<<<\n", result);
+ if (result != AAUDIO_OK) {
+ errorCount++;
+ }
+ usleep(SLEEP_DURATION_MSEC * 1000);
+ printf("getFramesRead() = %d, getFramesWritten() = %d\n",
+ (int32_t) AAudioStream_getFramesRead(engine.stream),
+ (int32_t) AAudioStream_getFramesWritten(engine.stream));
+ }
+
+ s_CloseAudioStream(&engine);
+
+ printf("aaudio result = %d = %s\n", result, AAudio_convertResultToText(result));
+ printf("test %s\n", errorCount ? "FAILED" : "PASSED");
+
+ return errorCount ? EXIT_FAILURE : EXIT_SUCCESS;
+}