Home | History | Annotate | Download | only in tests
      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.
     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 
     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 
    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 
    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 
    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 
    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