• 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 // Record input using AAudio and display the peak amplitudes.
18 
19 #ifndef AAUDIO_SIMPLE_RECORDER_H
20 #define AAUDIO_SIMPLE_RECORDER_H
21 
22 #include <aaudio/AAudio.h>
23 #include "AAudioArgsParser.h"
24 
25 //#define SHARING_MODE  AAUDIO_SHARING_MODE_EXCLUSIVE
26 #define SHARING_MODE  AAUDIO_SHARING_MODE_SHARED
27 #define PERFORMANCE_MODE AAUDIO_PERFORMANCE_MODE_NONE
28 
29 /**
30  * Simple wrapper for AAudio that opens an input stream either in callback or blocking read mode.
31  */
32 class AAudioSimpleRecorder {
33 public:
AAudioSimpleRecorder()34     AAudioSimpleRecorder() {}
~AAudioSimpleRecorder()35     ~AAudioSimpleRecorder() {
36         close();
37     };
38 
39     /**
40      * Call this before calling open().
41      * @param requestedSharingMode
42      */
setSharingMode(aaudio_sharing_mode_t requestedSharingMode)43     void setSharingMode(aaudio_sharing_mode_t requestedSharingMode) {
44         mRequestedSharingMode = requestedSharingMode;
45     }
46 
47     /**
48      * Call this before calling open().
49      * @param requestedPerformanceMode
50      */
setPerformanceMode(aaudio_performance_mode_t requestedPerformanceMode)51     void setPerformanceMode(aaudio_performance_mode_t requestedPerformanceMode) {
52         mRequestedPerformanceMode = requestedPerformanceMode;
53     }
54 
55     /**
56      * Also known as "sample rate"
57      * Only call this after open() has been called.
58      */
getFramesPerSecond()59     int32_t getFramesPerSecond() const {
60         return getSampleRate(); // alias
61     }
62 
63     /**
64      * Only call this after open() has been called.
65      */
getSampleRate()66     int32_t getSampleRate() const {
67         if (mStream == nullptr) {
68             return AAUDIO_ERROR_INVALID_STATE;
69         }
70         return AAudioStream_getSampleRate(mStream);
71     }
72 
73     /**
74      * Only call this after open() has been called.
75      */
getChannelCount()76     int32_t getChannelCount() {
77         if (mStream == nullptr) {
78             return AAUDIO_ERROR_INVALID_STATE;
79         }
80         return AAudioStream_getChannelCount(mStream);;
81     }
82 
83     /**
84      * @deprecated use getChannelCount()
85      */
getSamplesPerFrame()86     int32_t getSamplesPerFrame() {
87         return getChannelCount();
88     }
89 
90     /**
91      * Only call this after open() has been called.
92      */
getFramesRead()93     int64_t getFramesRead() {
94         if (mStream == nullptr) {
95             return AAUDIO_ERROR_INVALID_STATE;
96         }
97         return AAudioStream_getFramesRead(mStream);
98     }
99 
100     aaudio_result_t open(const AAudioParameters &parameters,
101                          AAudioStream_dataCallback dataCallback = nullptr,
102                          AAudioStream_errorCallback errorCallback = nullptr,
103                          void *userContext = nullptr) {
104         aaudio_result_t result = AAUDIO_OK;
105 
106         // Use an AAudioStreamBuilder to contain requested parameters.
107         AAudioStreamBuilder *builder = nullptr;
108         result = AAudio_createStreamBuilder(&builder);
109         if (result != AAUDIO_OK) return result;
110 
111         parameters.applyParameters(builder); // apply args
112 
113         AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT);
114 
115         if (dataCallback != nullptr) {
116             AAudioStreamBuilder_setDataCallback(builder, dataCallback, userContext);
117         }
118         if (errorCallback != nullptr) {
119             AAudioStreamBuilder_setErrorCallback(builder, errorCallback, userContext);
120         }
121 
122         // Open an AAudioStream using the Builder.
123         result = AAudioStreamBuilder_openStream(builder, &mStream);
124         if (result != AAUDIO_OK) {
125             fprintf(stderr, "ERROR - AAudioStreamBuilder_openStream() returned %d %s\n",
126                     result, AAudio_convertResultToText(result));
127         }
128 
129         if (result == AAUDIO_OK) {
130             int32_t sizeInBursts = parameters.getNumberOfBursts();
131             if (sizeInBursts > 0) {
132                 int32_t framesPerBurst = AAudioStream_getFramesPerBurst(mStream);
133                 AAudioStream_setBufferSizeInFrames(mStream, sizeInBursts * framesPerBurst);
134             }
135         }
136 
137         AAudioStreamBuilder_delete(builder);
138         return result;
139     }
140 
141     /**
142      * Open a stream
143      */
open(int channelCount,int sampSampleRate,aaudio_format_t format,AAudioStream_dataCallback dataProc,AAudioStream_errorCallback errorProc,void * userContext)144     aaudio_result_t open(int channelCount, int sampSampleRate, aaudio_format_t format,
145                          AAudioStream_dataCallback dataProc,
146                          AAudioStream_errorCallback errorProc,
147                          void *userContext) {
148         aaudio_result_t result = AAUDIO_OK;
149 
150         // Use an AAudioStreamBuilder to contain requested parameters.
151         AAudioStreamBuilder *builder = nullptr;
152         result = AAudio_createStreamBuilder(&builder);
153         if (result != AAUDIO_OK) return result;
154 
155         AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT);
156         AAudioStreamBuilder_setPerformanceMode(builder, mRequestedPerformanceMode);
157         AAudioStreamBuilder_setSharingMode(builder, mRequestedSharingMode);
158         if (dataProc != nullptr) {
159             AAudioStreamBuilder_setDataCallback(builder, dataProc, userContext);
160         }
161         if (errorProc != nullptr) {
162             AAudioStreamBuilder_setErrorCallback(builder, errorProc, userContext);
163         }
164         AAudioStreamBuilder_setChannelCount(builder, channelCount);
165         AAudioStreamBuilder_setSampleRate(builder, sampSampleRate);
166         AAudioStreamBuilder_setFormat(builder, format);
167 
168         // Open an AAudioStream using the Builder.
169         result = AAudioStreamBuilder_openStream(builder, &mStream);
170         if (result != AAUDIO_OK) {
171             fprintf(stderr, "ERROR - AAudioStreamBuilder_openStream() returned %d %s\n",
172                     result, AAudio_convertResultToText(result));
173         }
174 
175         AAudioStreamBuilder_delete(builder);
176         return result;
177     }
178 
close()179     aaudio_result_t close() {
180         if (mStream != nullptr) {
181             AAudioStream_close(mStream);
182             mStream = nullptr;
183         }
184         return AAUDIO_OK;
185     }
186 
187     // Write zero data to fill up the buffer and prevent underruns.
prime()188     aaudio_result_t prime() {
189         int32_t samplesPerFrame = AAudioStream_getChannelCount(mStream);
190         const int numFrames = 32; // arbitrary
191         float zeros[numFrames * samplesPerFrame];
192         memset(zeros, 0, sizeof(zeros));
193         aaudio_result_t result = numFrames;
194         while (result == numFrames) {
195             result = AAudioStream_write(mStream, zeros, numFrames, 0);
196         }
197         return result;
198     }
199 
200     // Start the stream. AAudio will start calling your callback function.
start()201      aaudio_result_t start() {
202         aaudio_result_t result = AAudioStream_requestStart(mStream);
203         if (result != AAUDIO_OK) {
204             fprintf(stderr, "ERROR - AAudioStream_requestStart(input) returned %d %s\n",
205                     result, AAudio_convertResultToText(result));
206             fprintf(stderr, "        Did you remember to enter:   adb root    ????\n");
207 
208         }
209         return result;
210     }
211 
212     // Stop the stream. AAudio will stop calling your callback function.
stop()213     aaudio_result_t stop() {
214         aaudio_result_t result = AAudioStream_requestStop(mStream);
215         if (result != AAUDIO_OK) {
216             fprintf(stderr, "ERROR - AAudioStream_requestStop(input) returned %d %s\n",
217                     result, AAudio_convertResultToText(result));
218 
219         }
220         return result;
221     }
222 
223     // Pause the stream. AAudio will stop calling your callback function.
pause()224     aaudio_result_t pause() {
225         aaudio_result_t result = AAudioStream_requestPause(mStream);
226         if (result != AAUDIO_OK) {
227             fprintf(stderr, "ERROR - AAudioStream_requestPause(input) returned %d %s\n",
228                     result, AAudio_convertResultToText(result));
229         }
230         return result;
231     }
232 
getStream()233     AAudioStream *getStream() const {
234         return mStream;
235     }
236 
237 private:
238     AAudioStream             *mStream = nullptr;
239     aaudio_sharing_mode_t     mRequestedSharingMode = SHARING_MODE;
240     aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE;
241 };
242 
243 // Application data that gets passed to the callback.
244 typedef struct PeakTrackerData {
245     float peakLevel;
246 } PeakTrackerData_t;
247 
248 #define DECAY_FACTOR   0.999
249 
250 // Callback function that fills the audio output buffer.
SimpleRecorderDataCallbackProc(AAudioStream * stream,void * userData,void * audioData,int32_t numFrames)251 aaudio_data_callback_result_t SimpleRecorderDataCallbackProc(
252         AAudioStream *stream,
253         void *userData,
254         void *audioData,
255         int32_t numFrames
256         ) {
257 
258     // should not happen but just in case...
259     if (userData == nullptr) {
260         fprintf(stderr, "ERROR - SimpleRecorderDataCallbackProc needs userData\n");
261         return AAUDIO_CALLBACK_RESULT_STOP;
262     }
263     PeakTrackerData_t *data = (PeakTrackerData_t *) userData;
264     // printf("MyCallbackProc(): frameCount = %d\n", numFrames);
265     int32_t samplesPerFrame = AAudioStream_getChannelCount(stream);
266     float sample;
267     // This code assume mono or stereo.
268     switch (AAudioStream_getFormat(stream)) {
269         case AAUDIO_FORMAT_PCM_I16: {
270             int16_t *audioBuffer = (int16_t *) audioData;
271             // Peak follower
272             for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
273                 sample = audioBuffer[frameIndex * samplesPerFrame] * (1.0/32768);
274                 data->peakLevel *= DECAY_FACTOR;
275                 if (sample > data->peakLevel) {
276                     data->peakLevel = sample;
277                 }
278             }
279         }
280         break;
281         case AAUDIO_FORMAT_PCM_FLOAT: {
282             float *audioBuffer = (float *) audioData;
283             // Peak follower
284             for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
285                 sample = audioBuffer[frameIndex * samplesPerFrame];
286                 data->peakLevel *= DECAY_FACTOR;
287                 if (sample > data->peakLevel) {
288                     data->peakLevel = sample;
289                 }
290             }
291         }
292         break;
293         default:
294             return AAUDIO_CALLBACK_RESULT_STOP;
295     }
296 
297     return AAUDIO_CALLBACK_RESULT_CONTINUE;
298 }
299 
SimpleRecorderErrorCallbackProc(AAudioStream * stream __unused,void * userData __unused,aaudio_result_t error)300 void SimpleRecorderErrorCallbackProc(
301         AAudioStream *stream __unused,
302         void *userData __unused,
303         aaudio_result_t error)
304 {
305     printf("Error Callback, error: %d\n",(int)error);
306 }
307 
308 #endif //AAUDIO_SIMPLE_RECORDER_H
309