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 // Record input using AAudio and display the peak amplitudes.
18 
19 #include <assert.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <math.h>
24 #include <time.h>
25 #include <aaudio/AAudio.h>
26 #include "AAudioExampleUtils.h"
27 #include "AAudioSimpleRecorder.h"
28 
main(int argc,const char ** argv)29 int main(int argc, const char **argv)
30 {
31     AAudioArgsParser      argParser;
32     AAudioSimpleRecorder  recorder;
33     PeakTrackerData_t     myData = {0.0};
34     AAudioStream         *aaudioStream = nullptr;
35     aaudio_result_t       result;
36     aaudio_stream_state_t state;
37 
38     int       loopsNeeded = 0;
39     const int displayRateHz = 20; // arbitrary
40 
41     // Make printf print immediately so that debug info is not stuck
42     // in a buffer if we hang or crash.
43     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
44     printf("%s - Display audio input using an AAudio callback, V0.1.3\n", argv[0]);
45 
46     if (argParser.parseArgs(argc, argv)) {
47         return EXIT_FAILURE;
48     }
49 
50     result = recorder.open(argParser,
51                            SimpleRecorderDataCallbackProc,
52                            SimpleRecorderErrorCallbackProc,
53                            &myData);
54     if (result != AAUDIO_OK) {
55         fprintf(stderr, "ERROR -  recorder.open() returned %d\n", result);
56         printf("IMPORTANT - Did you remember to enter:   adb root\n");
57         goto error;
58     }
59     aaudioStream = recorder.getStream();
60     argParser.compareWithStream(aaudioStream);
61 
62     printf("recorder.getFramesPerSecond() = %d\n", recorder.getFramesPerSecond());
63     printf("recorder.getSamplesPerFrame() = %d\n", recorder.getSamplesPerFrame());
64 
65     result = recorder.start();
66     if (result != AAUDIO_OK) {
67         fprintf(stderr, "ERROR -  recorder.start() returned %d\n", result);
68         goto error;
69     }
70 
71     printf("Sleep for %d seconds while audio record in a callback thread.\n",
72            argParser.getDurationSeconds());
73     loopsNeeded = argParser.getDurationSeconds() * displayRateHz;
74     for (int i = 0; i < loopsNeeded; i++)
75     {
76         const struct timespec request = { .tv_sec = 0,
77                 .tv_nsec = NANOS_PER_SECOND / displayRateHz };
78         (void) clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, &request, NULL /*remain*/);
79         printf("%08d: ", (int)recorder.getFramesRead());
80         displayPeakLevel(myData.peakLevel);
81 
82         result = AAudioStream_waitForStateChange(aaudioStream,
83                                                  AAUDIO_STREAM_STATE_CLOSED,
84                                                  &state,
85                                                  0);
86         if (result != AAUDIO_OK) {
87             fprintf(stderr, "ERROR - AAudioStream_waitForStateChange() returned %d\n", result);
88             goto error;
89         }
90         if (state != AAUDIO_STREAM_STATE_STARTING && state != AAUDIO_STREAM_STATE_STARTED) {
91             printf("Stream state is %d %s!\n", state, AAudio_convertStreamStateToText(state));
92             break;
93         }
94     }
95     printf("Woke up. Stop for a moment.\n");
96 
97     result = recorder.stop();
98     if (result != AAUDIO_OK) {
99         goto error;
100     }
101     usleep(2000 * 1000);
102     result = recorder.start();
103     if (result != AAUDIO_OK) {
104         fprintf(stderr, "ERROR -  recorder.start() returned %d\n", result);
105         goto error;
106     }
107 
108     printf("Sleep for %d seconds while audio records in a callback thread.\n",
109            argParser.getDurationSeconds());
110     for (int i = 0; i < loopsNeeded; i++)
111     {
112         const struct timespec request = { .tv_sec = 0,
113                 .tv_nsec = NANOS_PER_SECOND / displayRateHz };
114         (void) clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, &request, NULL /*remain*/);
115         printf("%08d: ", (int)recorder.getFramesRead());
116         displayPeakLevel(myData.peakLevel);
117 
118         state = AAudioStream_getState(aaudioStream);
119         if (state != AAUDIO_STREAM_STATE_STARTING && state != AAUDIO_STREAM_STATE_STARTED) {
120             printf("Stream state is %d %s!\n", state, AAudio_convertStreamStateToText(state));
121             break;
122         }
123     }
124     printf("Woke up now.\n");
125     argParser.compareWithStream(aaudioStream);
126 
127     result = recorder.stop();
128     if (result != AAUDIO_OK) {
129         goto error;
130     }
131     result = recorder.close();
132     if (result != AAUDIO_OK) {
133         goto error;
134     }
135 
136     printf("SUCCESS\n");
137     return EXIT_SUCCESS;
138 error:
139     recorder.close();
140     printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
141     return EXIT_FAILURE;
142 }
143 
144