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 
     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:
     32     AAudioSimpleRecorder() {}
     33     ~AAudioSimpleRecorder() {
     34         close();
     35     };
     36 
     37     /**
     38      * Call this before calling open().
     39      * @param requestedSharingMode
     40      */
     41     void setSharingMode(aaudio_sharing_mode_t requestedSharingMode) {
     42         mRequestedSharingMode = requestedSharingMode;
     43     }
     44 
     45     /**
     46      * Call this before calling open().
     47      * @param requestedPerformanceMode
     48      */
     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      */
     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      */
     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      */
     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      */
     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 
    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.
    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.
    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.
    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.
    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 
    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.
    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 
    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