• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
AAudioSimpleRecorder()32     AAudioSimpleRecorder() {}
~AAudioSimpleRecorder()33     ~AAudioSimpleRecorder() {
34         close();
35     };
36 
37     /**
38      * Call this before calling open().
39      * @param requestedSharingMode
40      */
setSharingMode(aaudio_sharing_mode_t requestedSharingMode)41     void setSharingMode(aaudio_sharing_mode_t requestedSharingMode) {
42         mRequestedSharingMode = requestedSharingMode;
43     }
44 
45     /**
46      * Call this before calling open().
47      * @param requestedPerformanceMode
48      */
setPerformanceMode(aaudio_performance_mode_t requestedPerformanceMode)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      */
getFramesPerSecond()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      */
getSamplesPerFrame()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      */
getFramesRead()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      */
open(int channelCount,int sampSampleRate,aaudio_format_t format,AAudioStream_dataCallback dataProc,AAudioStream_errorCallback errorProc,void * userContext)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 
close()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.
prime()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.
start()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.
stop()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.
pause()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 
getStream()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.
SimpleRecorderDataCallbackProc(AAudioStream * stream,void * userData,void * audioData,int32_t numFrames)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 
SimpleRecorderErrorCallbackProc(AAudioStream * stream __unused,void * userData __unused,aaudio_result_t error)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