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 ¶meters,
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() returned %d %s\n",
205 result, AAudio_convertResultToText(result));
206 }
207 return result;
208 }
209
210 // Stop the stream. AAudio will stop calling your callback function.
stop()211 aaudio_result_t stop() {
212 aaudio_result_t result = AAudioStream_requestStop(mStream);
213 if (result != AAUDIO_OK) {
214 fprintf(stderr, "ERROR - AAudioStream_requestStop() returned %d %s\n",
215 result, AAudio_convertResultToText(result));
216 }
217 return result;
218 }
219
220 // Pause the stream. AAudio will stop calling your callback function.
pause()221 aaudio_result_t pause() {
222 aaudio_result_t result = AAudioStream_requestPause(mStream);
223 if (result != AAUDIO_OK) {
224 fprintf(stderr, "ERROR - AAudioStream_requestPause() returned %d %s\n",
225 result, AAudio_convertResultToText(result));
226 }
227 return result;
228 }
229
getStream()230 AAudioStream *getStream() const {
231 return mStream;
232 }
233
234 private:
235 AAudioStream *mStream = nullptr;
236 aaudio_sharing_mode_t mRequestedSharingMode = SHARING_MODE;
237 aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE;
238 };
239
240 // Application data that gets passed to the callback.
241 typedef struct PeakTrackerData {
242 float peakLevel;
243 } PeakTrackerData_t;
244
245 #define DECAY_FACTOR 0.999
246
247 // Callback function that fills the audio output buffer.
SimpleRecorderDataCallbackProc(AAudioStream * stream,void * userData,void * audioData,int32_t numFrames)248 aaudio_data_callback_result_t SimpleRecorderDataCallbackProc(
249 AAudioStream *stream,
250 void *userData,
251 void *audioData,
252 int32_t numFrames
253 ) {
254
255 // should not happen but just in case...
256 if (userData == nullptr) {
257 fprintf(stderr, "ERROR - SimpleRecorderDataCallbackProc needs userData\n");
258 return AAUDIO_CALLBACK_RESULT_STOP;
259 }
260 PeakTrackerData_t *data = (PeakTrackerData_t *) userData;
261 // printf("MyCallbackProc(): frameCount = %d\n", numFrames);
262 int32_t samplesPerFrame = AAudioStream_getChannelCount(stream);
263 float sample;
264 // This code assume mono or stereo.
265 switch (AAudioStream_getFormat(stream)) {
266 case AAUDIO_FORMAT_PCM_I16: {
267 int16_t *audioBuffer = (int16_t *) audioData;
268 // Peak follower
269 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
270 sample = audioBuffer[frameIndex * samplesPerFrame] * (1.0/32768);
271 data->peakLevel *= DECAY_FACTOR;
272 if (sample > data->peakLevel) {
273 data->peakLevel = sample;
274 }
275 }
276 }
277 break;
278 case AAUDIO_FORMAT_PCM_FLOAT: {
279 float *audioBuffer = (float *) audioData;
280 // Peak follower
281 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
282 sample = audioBuffer[frameIndex * samplesPerFrame];
283 data->peakLevel *= DECAY_FACTOR;
284 if (sample > data->peakLevel) {
285 data->peakLevel = sample;
286 }
287 }
288 }
289 break;
290 default:
291 return AAUDIO_CALLBACK_RESULT_STOP;
292 }
293
294 return AAUDIO_CALLBACK_RESULT_CONTINUE;
295 }
296
SimpleRecorderErrorCallbackProc(AAudioStream * stream __unused,void * userData __unused,aaudio_result_t error)297 void SimpleRecorderErrorCallbackProc(
298 AAudioStream *stream __unused,
299 void *userData __unused,
300 aaudio_result_t error)
301 {
302 printf("Error Callback, error: %d\n",(int)error);
303 }
304
305 #endif //AAUDIO_SIMPLE_RECORDER_H
306