Home | History | Annotate | Download | only in utils
      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 &parameters,
    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