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