• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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  * Handle a DISCONNECT by only opening and starting a new stream
19  * without stopping and closing the old one.
20  * This caused the new stream to use the old disconnected device.
21  */
22 
23 #include <stdio.h>
24 #include <thread>
25 #include <unistd.h>
26 
27 #include <aaudio/AAudio.h>
28 
29 #define DEFAULT_TIMEOUT_NANOS  ((int64_t)1000000000)
30 
31 static void s_myErrorCallbackProc(
32         AAudioStream *stream,
33         void *userData,
34         aaudio_result_t error);
35 
36 struct AudioEngine {
37     AAudioStreamBuilder *builder = nullptr;
38     AAudioStream *stream = nullptr;
39     std::thread *thread = nullptr;
40     int64_t framesRead = 0;
41 };
42 
43 AudioEngine s_AudioEngine;
44 
45 // Callback function that fills the audio output buffer.
s_myDataCallbackProc(AAudioStream * stream,void * userData,void * audioData,int32_t numFrames)46 static aaudio_data_callback_result_t s_myDataCallbackProc(
47         AAudioStream *stream,
48         void *userData,
49         void *audioData,
50         int32_t numFrames
51 ) {
52     (void) userData;
53     (void) audioData;
54     (void) numFrames;
55     s_AudioEngine.framesRead = AAudioStream_getFramesRead(stream);
56     return AAUDIO_CALLBACK_RESULT_CONTINUE;
57 }
58 
s_StartAudio()59 static aaudio_result_t s_StartAudio() {
60     int32_t framesPerBurst = 0;
61     int32_t deviceId = 0;
62 
63     // Use an AAudioStreamBuilder to contain requested parameters.
64     aaudio_result_t result = AAudio_createStreamBuilder(&s_AudioEngine.builder);
65     if (result != AAUDIO_OK) {
66         printf("AAudio_createStreamBuilder returned %s",
67                AAudio_convertResultToText(result));
68         return result;
69     }
70 
71     // Request stream properties.
72     AAudioStreamBuilder_setFormat(s_AudioEngine.builder, AAUDIO_FORMAT_PCM_FLOAT);
73     AAudioStreamBuilder_setPerformanceMode(s_AudioEngine.builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
74     AAudioStreamBuilder_setDataCallback(s_AudioEngine.builder, s_myDataCallbackProc, nullptr);
75     AAudioStreamBuilder_setErrorCallback(s_AudioEngine.builder, s_myErrorCallbackProc, nullptr);
76 
77     // Create an AAudioStream using the Builder.
78     result = AAudioStreamBuilder_openStream(s_AudioEngine.builder, &s_AudioEngine.stream);
79     if (result != AAUDIO_OK) {
80         printf("AAudioStreamBuilder_openStream returned %s",
81                AAudio_convertResultToText(result));
82         return result;
83     }
84 
85     result = AAudioStream_requestStart(s_AudioEngine.stream);
86     if (result != AAUDIO_OK) {
87         printf("AAudioStream_requestStart returned %s",
88                AAudio_convertResultToText(result));
89     }
90 
91     // Check to see what kind of stream we actually got.
92     deviceId = AAudioStream_getDeviceId(s_AudioEngine.stream);
93     framesPerBurst = AAudioStream_getFramesPerBurst(s_AudioEngine.stream);
94 
95     printf("-------- started: deviceId = %3d, framesPerBurst = %3d\n", deviceId, framesPerBurst);
96 
97     return result;
98 }
99 
s_StopAudio()100 static aaudio_result_t s_StopAudio() {
101     aaudio_result_t result = AAUDIO_OK;
102     if (s_AudioEngine.stream != nullptr) {
103         result = AAudioStream_requestStop(s_AudioEngine.stream);
104         if (result != AAUDIO_OK) {
105             printf("AAudioStream_requestStop returned %s\n",
106                    AAudio_convertResultToText(result));
107         }
108         result = AAudioStream_close(s_AudioEngine.stream);
109         if (result != AAUDIO_OK) {
110             printf("AAudioStream_close returned %s\n",
111                    AAudio_convertResultToText(result));
112         }
113         s_AudioEngine.stream = nullptr;
114         AAudioStreamBuilder_delete(s_AudioEngine.builder);
115         s_AudioEngine.builder = nullptr;
116     }
117     return result;
118 }
119 
s_StartThreadProc()120 static void s_StartThreadProc() {
121     // A good app would call s_StopAudio here! This test simulates a bad app.
122     s_StartAudio();
123     s_AudioEngine.thread = nullptr;
124 }
125 
s_myErrorCallbackProc(AAudioStream * stream __unused,void * userData __unused,aaudio_result_t error)126 static void s_myErrorCallbackProc(
127         AAudioStream *stream __unused,
128         void *userData __unused,
129         aaudio_result_t error) {
130     if (error == AAUDIO_ERROR_DISCONNECTED) {
131         // Handle stream restart on a separate thread
132         if (s_AudioEngine.thread == nullptr) {
133             s_AudioEngine.thread = new std::thread(s_StartThreadProc);
134         }
135     }
136 }
137 
main(int argc,char ** argv)138 int main(int argc, char **argv) {
139     (void) argc;
140     (void) argv;
141 
142     aaudio_result_t result = AAUDIO_OK;
143 
144     // Make printf print immediately so that debug info is not stuck
145     // in a buffer if we hang or crash.
146     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
147 
148     printf("Test Bad Disconnect V1.0\n");
149     printf("\n=========== Please PLUG and UNPLUG headphones! ==============\n\n");
150     printf("You should see the deviceID change on each plug event.\n");
151     printf("Headphones will generally get a new deviceId each time.\n");
152     printf("Speakers will have the same deviceId each time.\n");
153     printf("The framesRead should reset on each plug event then increase over time.\n");
154     printf("\n");
155 
156     result = s_StartAudio();
157 
158     if (result == AAUDIO_OK) {
159         for (int i = 20; i > 0; i--) {
160             sleep(1);
161             printf("playing silence #%d, framesRead = %d\n", i, (int) s_AudioEngine.framesRead);
162         }
163     }
164 
165     s_StopAudio();
166 
167     printf("result = %d = %s\n", result, AAudio_convertResultToText(result));
168 }
169