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