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(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