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: 34 AAudioSimpleRecorder() {} 35 ~AAudioSimpleRecorder() { 36 close(); 37 }; 38 39 /** 40 * Call this before calling open(). 41 * @param requestedSharingMode 42 */ 43 void setSharingMode(aaudio_sharing_mode_t requestedSharingMode) { 44 mRequestedSharingMode = requestedSharingMode; 45 } 46 47 /** 48 * Call this before calling open(). 49 * @param requestedPerformanceMode 50 */ 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 */ 59 int32_t getFramesPerSecond() const { 60 return getSampleRate(); // alias 61 } 62 63 /** 64 * Only call this after open() has been called. 65 */ 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 */ 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 */ 86 int32_t getSamplesPerFrame() { 87 return getChannelCount(); 88 } 89 90 /** 91 * Only call this after open() has been called. 92 */ 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 */ 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 179 aaudio_result_t close() { 180 if (mStream != nullptr) { 181 printf("call AAudioStream_close(%p)\n", mStream); fflush(stdout); 182 AAudioStream_close(mStream); 183 mStream = nullptr; 184 } 185 return AAUDIO_OK; 186 } 187 188 // Write zero data to fill up the buffer and prevent underruns. 189 aaudio_result_t prime() { 190 int32_t samplesPerFrame = AAudioStream_getChannelCount(mStream); 191 const int numFrames = 32; // arbitrary 192 float zeros[numFrames * samplesPerFrame]; 193 memset(zeros, 0, sizeof(zeros)); 194 aaudio_result_t result = numFrames; 195 while (result == numFrames) { 196 result = AAudioStream_write(mStream, zeros, numFrames, 0); 197 } 198 return result; 199 } 200 201 // Start the stream. AAudio will start calling your callback function. 202 aaudio_result_t start() { 203 aaudio_result_t result = AAudioStream_requestStart(mStream); 204 if (result != AAUDIO_OK) { 205 fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d %s\n", 206 result, AAudio_convertResultToText(result)); 207 } 208 return result; 209 } 210 211 // Stop the stream. AAudio will stop calling your callback function. 212 aaudio_result_t stop() { 213 aaudio_result_t result = AAudioStream_requestStop(mStream); 214 if (result != AAUDIO_OK) { 215 fprintf(stderr, "ERROR - AAudioStream_requestStop() returned %d %s\n", 216 result, AAudio_convertResultToText(result)); 217 } 218 return result; 219 } 220 221 // Pause the stream. AAudio will stop calling your callback function. 222 aaudio_result_t pause() { 223 aaudio_result_t result = AAudioStream_requestPause(mStream); 224 if (result != AAUDIO_OK) { 225 fprintf(stderr, "ERROR - AAudioStream_requestPause() returned %d %s\n", 226 result, AAudio_convertResultToText(result)); 227 } 228 return result; 229 } 230 231 AAudioStream *getStream() const { 232 return mStream; 233 } 234 235 private: 236 AAudioStream *mStream = nullptr; 237 aaudio_sharing_mode_t mRequestedSharingMode = SHARING_MODE; 238 aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE; 239 }; 240 241 // Application data that gets passed to the callback. 242 typedef struct PeakTrackerData { 243 float peakLevel; 244 } PeakTrackerData_t; 245 246 #define DECAY_FACTOR 0.999 247 248 // Callback function that fills the audio output buffer. 249 aaudio_data_callback_result_t SimpleRecorderDataCallbackProc( 250 AAudioStream *stream, 251 void *userData, 252 void *audioData, 253 int32_t numFrames 254 ) { 255 256 // should not happen but just in case... 257 if (userData == nullptr) { 258 fprintf(stderr, "ERROR - SimpleRecorderDataCallbackProc needs userData\n"); 259 return AAUDIO_CALLBACK_RESULT_STOP; 260 } 261 PeakTrackerData_t *data = (PeakTrackerData_t *) userData; 262 // printf("MyCallbackProc(): frameCount = %d\n", numFrames); 263 int32_t samplesPerFrame = AAudioStream_getChannelCount(stream); 264 float sample; 265 // This code assume mono or stereo. 266 switch (AAudioStream_getFormat(stream)) { 267 case AAUDIO_FORMAT_PCM_I16: { 268 int16_t *audioBuffer = (int16_t *) audioData; 269 // Peak follower 270 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) { 271 sample = audioBuffer[frameIndex * samplesPerFrame] * (1.0/32768); 272 data->peakLevel *= DECAY_FACTOR; 273 if (sample > data->peakLevel) { 274 data->peakLevel = sample; 275 } 276 } 277 } 278 break; 279 case AAUDIO_FORMAT_PCM_FLOAT: { 280 float *audioBuffer = (float *) audioData; 281 // Peak follower 282 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) { 283 sample = audioBuffer[frameIndex * samplesPerFrame]; 284 data->peakLevel *= DECAY_FACTOR; 285 if (sample > data->peakLevel) { 286 data->peakLevel = sample; 287 } 288 } 289 } 290 break; 291 default: 292 return AAUDIO_CALLBACK_RESULT_STOP; 293 } 294 295 return AAUDIO_CALLBACK_RESULT_CONTINUE; 296 } 297 298 void SimpleRecorderErrorCallbackProc( 299 AAudioStream *stream __unused, 300 void *userData __unused, 301 aaudio_result_t error) 302 { 303 printf("Error Callback, error: %d\n",(int)error); 304 } 305 306 #endif //AAUDIO_SIMPLE_RECORDER_H 307