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