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 // Play sine waves using an AAudio callback.
18 
19 #ifndef AAUDIO_SIMPLE_PLAYER_H
20 #define AAUDIO_SIMPLE_PLAYER_H
21 
22 #include <unistd.h>
23 #include <sched.h>
24 
25 #include <aaudio/AAudio.h>
26 #include "SineGenerator.h"
27 
28 //#define SHARING_MODE  AAUDIO_SHARING_MODE_EXCLUSIVE
29 #define SHARING_MODE  AAUDIO_SHARING_MODE_SHARED
30 #define PERFORMANCE_MODE AAUDIO_PERFORMANCE_MODE_NONE
31 
32 /**
33  * Simple wrapper for AAudio that opens an output stream either in callback or blocking write mode.
34  */
35 class AAudioSimplePlayer {
36 public:
AAudioSimplePlayer()37     AAudioSimplePlayer() {}
~AAudioSimplePlayer()38     ~AAudioSimplePlayer() {
39         close();
40     };
41 
42     /**
43      * Call this before calling open().
44      * @param requestedSharingMode
45      */
setSharingMode(aaudio_sharing_mode_t requestedSharingMode)46     void setSharingMode(aaudio_sharing_mode_t requestedSharingMode) {
47         mRequestedSharingMode = requestedSharingMode;
48     }
49 
50     /**
51      * Call this before calling open().
52      * @param requestedPerformanceMode
53      */
setPerformanceMode(aaudio_performance_mode_t requestedPerformanceMode)54     void setPerformanceMode(aaudio_performance_mode_t requestedPerformanceMode) {
55         mRequestedPerformanceMode = requestedPerformanceMode;
56     }
57 
58     /**
59      * Also known as "sample rate"
60      * Only call this after open() has been called.
61      */
getFramesPerSecond()62     int32_t getFramesPerSecond() {
63         if (mStream == nullptr) {
64             return AAUDIO_ERROR_INVALID_STATE;
65         }
66         return AAudioStream_getSampleRate(mStream);;
67     }
68 
69     /**
70      * Only call this after open() has been called.
71      */
getChannelCount()72     int32_t getChannelCount() {
73         if (mStream == nullptr) {
74             return AAUDIO_ERROR_INVALID_STATE;
75         }
76         return AAudioStream_getChannelCount(mStream);;
77     }
78 
79     /**
80      * Open a stream
81      */
open(int channelCount,int sampSampleRate,aaudio_format_t format,AAudioStream_dataCallback dataProc,AAudioStream_errorCallback errorProc,void * userContext)82     aaudio_result_t open(int channelCount, int sampSampleRate, aaudio_format_t format,
83                          AAudioStream_dataCallback dataProc, AAudioStream_errorCallback errorProc,
84                          void *userContext) {
85         aaudio_result_t result = AAUDIO_OK;
86 
87         // Use an AAudioStreamBuilder to contain requested parameters.
88         result = AAudio_createStreamBuilder(&mBuilder);
89         if (result != AAUDIO_OK) return result;
90 
91         //AAudioStreamBuilder_setSampleRate(mBuilder, 44100);
92         AAudioStreamBuilder_setPerformanceMode(mBuilder, mRequestedPerformanceMode);
93         AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode);
94         if (dataProc != nullptr) {
95             AAudioStreamBuilder_setDataCallback(mBuilder, dataProc, userContext);
96         }
97         if (errorProc != nullptr) {
98             AAudioStreamBuilder_setErrorCallback(mBuilder, errorProc, userContext);
99         }
100         AAudioStreamBuilder_setChannelCount(mBuilder, channelCount);
101         AAudioStreamBuilder_setSampleRate(mBuilder, sampSampleRate);
102         AAudioStreamBuilder_setFormat(mBuilder, format);
103         //AAudioStreamBuilder_setFramesPerDataCallback(mBuilder, CALLBACK_SIZE_FRAMES);
104         AAudioStreamBuilder_setBufferCapacityInFrames(mBuilder, 48 * 8);
105 
106         //aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_NONE;
107         aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
108         //aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
109         AAudioStreamBuilder_setPerformanceMode(mBuilder, perfMode);
110 
111         // Open an AAudioStream using the Builder.
112         result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
113         if (result != AAUDIO_OK) goto finish1;
114 
115         printf("AAudioStream_getFramesPerBurst() = %d\n",
116                AAudioStream_getFramesPerBurst(mStream));
117         printf("AAudioStream_getBufferSizeInFrames() = %d\n",
118                AAudioStream_getBufferSizeInFrames(mStream));
119         printf("AAudioStream_getBufferCapacityInFrames() = %d\n",
120                AAudioStream_getBufferCapacityInFrames(mStream));
121         printf("AAudioStream_getPerformanceMode() = %d, requested %d\n",
122                AAudioStream_getPerformanceMode(mStream), perfMode);
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_getChannelCount(mStream);
144         const int numFrames = 32;
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             printf("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             printf("ERROR - AAudioStream_requestStop() returned %d %s\n",
169                     result, AAudio_convertResultToText(result));
170         }
171         int32_t xRunCount = AAudioStream_getXRunCount(mStream);
172         printf("AAudioStream_getXRunCount %d\n", xRunCount);
173         return result;
174     }
175 
getStream()176     AAudioStream *getStream() const {
177         return mStream;
178     }
179 
180 private:
181     AAudioStreamBuilder      *mBuilder = nullptr;
182     AAudioStream             *mStream = nullptr;
183     aaudio_sharing_mode_t     mRequestedSharingMode = SHARING_MODE;
184     aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE;
185 };
186 
187 typedef struct SineThreadedData_s {
188     SineGenerator  sineOsc1;
189     SineGenerator  sineOsc2;
190     int            scheduler;
191     bool           schedulerChecked;
192 } SineThreadedData_t;
193 
194 // Callback function that fills the audio output buffer.
SimplePlayerDataCallbackProc(AAudioStream * stream,void * userData,void * audioData,int32_t numFrames)195 aaudio_data_callback_result_t SimplePlayerDataCallbackProc(
196         AAudioStream *stream,
197         void *userData,
198         void *audioData,
199         int32_t numFrames
200         ) {
201 
202     // should not happen but just in case...
203     if (userData == nullptr) {
204         fprintf(stderr, "ERROR - SimplePlayerDataCallbackProc needs userData\n");
205         return AAUDIO_CALLBACK_RESULT_STOP;
206     }
207     SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
208 
209     if (!sineData->schedulerChecked) {
210         sineData->scheduler = sched_getscheduler(gettid());
211         sineData->schedulerChecked = true;
212     }
213 
214     int32_t samplesPerFrame = AAudioStream_getChannelCount(stream);
215     // This code only plays on the first one or two channels.
216     // TODO Support arbitrary number of channels.
217     switch (AAudioStream_getFormat(stream)) {
218         case AAUDIO_FORMAT_PCM_I16: {
219             int16_t *audioBuffer = (int16_t *) audioData;
220             // Render sine waves as shorts to first channel.
221             sineData->sineOsc1.render(&audioBuffer[0], samplesPerFrame, numFrames);
222             // Render sine waves to second channel if there is one.
223             if (samplesPerFrame > 1) {
224                 sineData->sineOsc2.render(&audioBuffer[1], samplesPerFrame, numFrames);
225             }
226         }
227         break;
228         case AAUDIO_FORMAT_PCM_FLOAT: {
229             float *audioBuffer = (float *) audioData;
230             // Render sine waves as floats to first channel.
231             sineData->sineOsc1.render(&audioBuffer[0], samplesPerFrame, numFrames);
232             // Render sine waves to second channel if there is one.
233             if (samplesPerFrame > 1) {
234                 sineData->sineOsc2.render(&audioBuffer[1], samplesPerFrame, numFrames);
235             }
236         }
237         break;
238         default:
239             return AAUDIO_CALLBACK_RESULT_STOP;
240     }
241 
242     return AAUDIO_CALLBACK_RESULT_CONTINUE;
243 }
244 
SimplePlayerErrorCallbackProc(AAudioStream * stream __unused,void * userData __unused,aaudio_result_t error)245 void SimplePlayerErrorCallbackProc(
246         AAudioStream *stream __unused,
247         void *userData __unused,
248         aaudio_result_t error)
249 {
250     printf("Error Callback, error: %d\n",(int)error);
251 }
252 
253 #endif //AAUDIO_SIMPLE_PLAYER_H
254