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