• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /**
18  * Test whether the callback is joined before the close finishes.
19  *
20  * Start a stream with a callback.
21  * The callback just sleeps for a long time.
22  * While the callback is sleeping, close() the stream from the main thread.
23  * Then check to make sure the callback was joined before the close() returns.
24  *
25  * This can hang if there are deadlocks. So make sure you get a PASSED result.
26  */
27 
28 #include <atomic>
29 #include <stdio.h>
30 #include <unistd.h>
31 
32 #include <gtest/gtest.h>
33 
34 #include <aaudio/AAudio.h>
35 
36 // Sleep long enough that the foreground has a change to call close.
37 static constexpr int kCallbackSleepMicros = 600 * 1000;
38 
39 class AudioEngine {
40 public:
41 
42     // Check for a crash or late callback if we close without stopping.
checkCloseJoins(aaudio_direction_t direction,aaudio_performance_mode_t perfMode,aaudio_data_callback_result_t callbackResult)43     void checkCloseJoins(aaudio_direction_t direction,
44                              aaudio_performance_mode_t perfMode,
45                              aaudio_data_callback_result_t callbackResult) {
46 
47         // Make printf print immediately so that debug info is not stuck
48         // in a buffer if we hang or crash.
49         setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
50 
51         mCallbackResult = callbackResult;
52         startStreamForStall(direction, perfMode);
53         // When the callback starts it will go to sleep.
54         waitForCallbackToStart();
55 
56         printf("call AAudioStream_close()\n");
57         ASSERT_FALSE(mCallbackFinished); // Still sleeping?
58         aaudio_result_t result = AAudioStream_close(mStream); // May hang here!
59         ASSERT_TRUE(mCallbackFinished);
60         ASSERT_EQ(AAUDIO_OK, result);
61         printf("AAudioStream_close() returned %d\n", result);
62 
63         ASSERT_EQ(AAUDIO_OK, mError.load());
64         // Did calling stop() from callback fail? It should have.
65         ASSERT_NE(AAUDIO_OK, mStopResult.load());
66     }
67 
68 private:
startStreamForStall(aaudio_direction_t direction,aaudio_performance_mode_t perfMode)69     void startStreamForStall(aaudio_direction_t direction,
70                              aaudio_performance_mode_t perfMode) {
71         AAudioStreamBuilder* builder = nullptr;
72         aaudio_result_t result = AAUDIO_OK;
73 
74         // Use an AAudioStreamBuilder to contain requested parameters.
75         result = AAudio_createStreamBuilder(&builder);
76         ASSERT_EQ(AAUDIO_OK, result);
77 
78         // Request stream properties.
79         AAudioStreamBuilder_setDirection(builder, direction);
80         AAudioStreamBuilder_setPerformanceMode(builder, perfMode);
81         AAudioStreamBuilder_setDataCallback(builder, s_myDataCallbackProc, this);
82         AAudioStreamBuilder_setErrorCallback(builder, s_myErrorCallbackProc, this);
83 
84         // Create an AAudioStream using the Builder.
85         result = AAudioStreamBuilder_openStream(builder, &mStream);
86         AAudioStreamBuilder_delete(builder);
87         ASSERT_EQ(AAUDIO_OK, result);
88 
89         // Check to see what kind of stream we actually got.
90         int32_t deviceId = AAudioStream_getDeviceId(mStream);
91         aaudio_performance_mode_t
92             actualPerfMode = AAudioStream_getPerformanceMode(mStream);
93         printf("-------- opened: deviceId = %3d, perfMode = %d\n",
94                deviceId,
95                actualPerfMode);
96 
97         // Start stream.
98         result = AAudioStream_requestStart(mStream);
99         ASSERT_EQ(AAUDIO_OK, result);
100     }
101 
waitForCallbackToStart()102     void waitForCallbackToStart() {
103         // Wait for callback to say it has been called.
104         int countDownMillis = 2000;
105         constexpr int countDownPeriodMillis = 50;
106         while (!mCallbackStarted && countDownMillis > 0) {
107             printf("Waiting for callback to start, %d\n", countDownMillis);
108             usleep(countDownPeriodMillis * 1000);
109             countDownMillis -= countDownPeriodMillis;
110         }
111         ASSERT_LT(0, countDownMillis);
112         ASSERT_TRUE(mCallbackStarted);
113     }
114 
115 // Callback function that fills the audio output buffer.
s_myDataCallbackProc(AAudioStream * stream,void * userData,void *,int32_t)116     static aaudio_data_callback_result_t s_myDataCallbackProc(
117             AAudioStream *stream,
118             void *userData,
119             void * /*audioData */,
120             int32_t /* numFrames */
121     ) {
122         AudioEngine* engine = (AudioEngine*) userData;
123         engine->mCallbackStarted = true;
124         usleep(kCallbackSleepMicros);
125         // it is illegal to call stop() from the callback. It should
126         // return an error and not hang.
127         engine->mStopResult = AAudioStream_requestStop(stream);
128         engine->mCallbackFinished = true;
129         return engine->mCallbackResult;
130     }
131 
s_myErrorCallbackProc(AAudioStream *,void * userData,aaudio_result_t error)132     static void s_myErrorCallbackProc(
133                 AAudioStream * /* stream */,
134                 void *userData,
135                 aaudio_result_t error) {
136         AudioEngine *engine = (AudioEngine *)userData;
137         engine->mError = error;
138     }
139 
140     AAudioStream* mStream = nullptr;
141 
142     std::atomic<aaudio_result_t> mError{AAUDIO_OK}; // written by error callback
143     std::atomic<bool> mCallbackStarted{false};   // written by data callback
144     std::atomic<bool> mCallbackFinished{false};  // written by data callback
145     std::atomic<aaudio_data_callback_result_t> mCallbackResult{AAUDIO_CALLBACK_RESULT_CONTINUE};
146     std::atomic<aaudio_result_t> mStopResult{AAUDIO_OK};
147 };
148 
149 /*********************************************************************/
150 // Tell the callback to return AAUDIO_CALLBACK_RESULT_CONTINUE.
151 
TEST(test_close_timing,aaudio_close_joins_input_none)152 TEST(test_close_timing, aaudio_close_joins_input_none) {
153     AudioEngine engine;
154     engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT,
155         AAUDIO_PERFORMANCE_MODE_NONE,
156         AAUDIO_CALLBACK_RESULT_CONTINUE);
157 }
158 
TEST(test_close_timing,aaudio_close_joins_output_none)159 TEST(test_close_timing, aaudio_close_joins_output_none) {
160     AudioEngine engine;
161     engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT,
162         AAUDIO_PERFORMANCE_MODE_NONE,
163         AAUDIO_CALLBACK_RESULT_CONTINUE);
164 }
165 
TEST(test_close_timing,aaudio_close_joins_input_lowlat)166 TEST(test_close_timing, aaudio_close_joins_input_lowlat) {
167     AudioEngine engine;
168     engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT,
169         AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
170         AAUDIO_CALLBACK_RESULT_CONTINUE);
171 }
172 
TEST(test_close_timing,aaudio_close_joins_output_lowlat)173 TEST(test_close_timing, aaudio_close_joins_output_lowlat) {
174     AudioEngine engine;
175     engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT,
176         AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
177         AAUDIO_CALLBACK_RESULT_CONTINUE);
178 }
179 
180 /*********************************************************************/
181 // Tell the callback to return AAUDIO_CALLBACK_RESULT_STOP.
182 
TEST(test_close_timing,aaudio_close_joins_input_lowlat_stop)183 TEST(test_close_timing, aaudio_close_joins_input_lowlat_stop) {
184     AudioEngine engine;
185     engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT,
186         AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
187         AAUDIO_CALLBACK_RESULT_STOP);
188 }
189 
TEST(test_close_timing,aaudio_close_joins_output_lowlat_stop)190 TEST(test_close_timing, aaudio_close_joins_output_lowlat_stop) {
191     AudioEngine engine;
192     engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT,
193         AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
194         AAUDIO_CALLBACK_RESULT_STOP);
195 }
196 
TEST(test_close_timing,aaudio_close_joins_output_none_stop)197 TEST(test_close_timing, aaudio_close_joins_output_none_stop) {
198     AudioEngine engine;
199     engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT,
200         AAUDIO_PERFORMANCE_MODE_NONE,
201         AAUDIO_CALLBACK_RESULT_STOP);
202 }
203 
TEST(test_close_timing,aaudio_close_joins_input_none_stop)204 TEST(test_close_timing, aaudio_close_joins_input_none_stop) {
205     AudioEngine engine;
206     engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT,
207         AAUDIO_PERFORMANCE_MODE_NONE,
208         AAUDIO_CALLBACK_RESULT_STOP);
209 }
210