blob: 19f8affbfa7b8437d4f986a09a326dff73146dc0 [file] [log] [blame]
Eric Laurent629afae2017-05-25 18:25:51 -07001/*
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>
Phil Burk44795232017-06-30 16:27:38 -070026#include "AAudioArgsParser.h"
Eric Laurent629afae2017-05-25 18:25:51 -070027#include "SineGenerator.h"
28
29//#define SHARING_MODE AAUDIO_SHARING_MODE_EXCLUSIVE
30#define SHARING_MODE AAUDIO_SHARING_MODE_SHARED
31#define PERFORMANCE_MODE AAUDIO_PERFORMANCE_MODE_NONE
32
33/**
34 * Simple wrapper for AAudio that opens an output stream either in callback or blocking write mode.
35 */
36class AAudioSimplePlayer {
37public:
38 AAudioSimplePlayer() {}
39 ~AAudioSimplePlayer() {
40 close();
41 };
42
43 /**
44 * Call this before calling open().
45 * @param requestedSharingMode
46 */
47 void setSharingMode(aaudio_sharing_mode_t requestedSharingMode) {
48 mRequestedSharingMode = requestedSharingMode;
49 }
50
51 /**
52 * Call this before calling open().
53 * @param requestedPerformanceMode
54 */
55 void setPerformanceMode(aaudio_performance_mode_t requestedPerformanceMode) {
56 mRequestedPerformanceMode = requestedPerformanceMode;
57 }
58
Phil Burk44795232017-06-30 16:27:38 -070059 // TODO Extract a common base class for record and playback.
Eric Laurent629afae2017-05-25 18:25:51 -070060 /**
61 * Also known as "sample rate"
62 * Only call this after open() has been called.
63 */
Phil Burk44795232017-06-30 16:27:38 -070064 int32_t getFramesPerSecond() const {
65 return getSampleRate(); // alias
66 }
67
68 /**
69 * Only call this after open() has been called.
70 */
71 int32_t getSampleRate() const {
Eric Laurent629afae2017-05-25 18:25:51 -070072 if (mStream == nullptr) {
73 return AAUDIO_ERROR_INVALID_STATE;
74 }
Phil Burk44795232017-06-30 16:27:38 -070075 return AAudioStream_getSampleRate(mStream);
Eric Laurent629afae2017-05-25 18:25:51 -070076 }
77
78 /**
79 * Only call this after open() has been called.
80 */
81 int32_t getChannelCount() {
82 if (mStream == nullptr) {
83 return AAUDIO_ERROR_INVALID_STATE;
84 }
Phil Burk44795232017-06-30 16:27:38 -070085 return AAudioStream_getChannelCount(mStream);
Eric Laurent629afae2017-05-25 18:25:51 -070086 }
87
88 /**
89 * Open a stream
90 */
Phil Burk44795232017-06-30 16:27:38 -070091 aaudio_result_t open(const AAudioParameters &parameters,
92 AAudioStream_dataCallback dataCallback = nullptr,
93 AAudioStream_errorCallback errorCallback = nullptr,
94 void *userContext = nullptr) {
95 aaudio_result_t result = AAUDIO_OK;
96
97 // Use an AAudioStreamBuilder to contain requested parameters.
98 AAudioStreamBuilder *builder = nullptr;
99 result = AAudio_createStreamBuilder(&builder);
100 if (result != AAUDIO_OK) return result;
101
102 parameters.applyParameters(builder); // apply args
103
104 AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
105
106 if (dataCallback != nullptr) {
107 AAudioStreamBuilder_setDataCallback(builder, dataCallback, userContext);
108 }
109 if (errorCallback != nullptr) {
110 AAudioStreamBuilder_setErrorCallback(builder, errorCallback, userContext);
111 }
112 //AAudioStreamBuilder_setFramesPerDataCallback(builder, CALLBACK_SIZE_FRAMES);
113 //AAudioStreamBuilder_setBufferCapacityInFrames(builder, 48 * 8);
114
115 // Open an AAudioStream using the Builder.
116 result = AAudioStreamBuilder_openStream(builder, &mStream);
117
118 if (result == AAUDIO_OK) {
119 int32_t sizeInBursts = parameters.getNumberOfBursts();
120 if (sizeInBursts > 0) {
121 int32_t framesPerBurst = AAudioStream_getFramesPerBurst(mStream);
122 AAudioStream_setBufferSizeInFrames(mStream, sizeInBursts * framesPerBurst);
123 }
124 }
125
126 AAudioStreamBuilder_delete(builder);
127 return result;
128 }
129
Eric Laurent629afae2017-05-25 18:25:51 -0700130 aaudio_result_t open(int channelCount, int sampSampleRate, aaudio_format_t format,
Phil Burk44795232017-06-30 16:27:38 -0700131 AAudioStream_dataCallback dataProc,
132 AAudioStream_errorCallback errorProc,
Eric Laurent629afae2017-05-25 18:25:51 -0700133 void *userContext) {
134 aaudio_result_t result = AAUDIO_OK;
135
136 // Use an AAudioStreamBuilder to contain requested parameters.
Phil Burk44795232017-06-30 16:27:38 -0700137 AAudioStreamBuilder *builder = nullptr;
138 result = AAudio_createStreamBuilder(&builder);
Eric Laurent629afae2017-05-25 18:25:51 -0700139 if (result != AAUDIO_OK) return result;
140
Phil Burk44795232017-06-30 16:27:38 -0700141 AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
142 AAudioStreamBuilder_setPerformanceMode(builder, mRequestedPerformanceMode);
143 AAudioStreamBuilder_setSharingMode(builder, mRequestedSharingMode);
144
145 AAudioStreamBuilder_setChannelCount(builder, channelCount);
146 AAudioStreamBuilder_setSampleRate(builder, sampSampleRate);
147 AAudioStreamBuilder_setFormat(builder, format);
148
Eric Laurent629afae2017-05-25 18:25:51 -0700149 if (dataProc != nullptr) {
Phil Burk44795232017-06-30 16:27:38 -0700150 AAudioStreamBuilder_setDataCallback(builder, dataProc, userContext);
Eric Laurent629afae2017-05-25 18:25:51 -0700151 }
152 if (errorProc != nullptr) {
Phil Burk44795232017-06-30 16:27:38 -0700153 AAudioStreamBuilder_setErrorCallback(builder, errorProc, userContext);
Eric Laurent629afae2017-05-25 18:25:51 -0700154 }
Phil Burk44795232017-06-30 16:27:38 -0700155 //AAudioStreamBuilder_setFramesPerDataCallback(builder, CALLBACK_SIZE_FRAMES);
156 //AAudioStreamBuilder_setBufferCapacityInFrames(builder, 48 * 8);
Eric Laurent629afae2017-05-25 18:25:51 -0700157
158 // Open an AAudioStream using the Builder.
Phil Burk44795232017-06-30 16:27:38 -0700159 result = AAudioStreamBuilder_openStream(builder, &mStream);
Eric Laurent629afae2017-05-25 18:25:51 -0700160
Phil Burk44795232017-06-30 16:27:38 -0700161 AAudioStreamBuilder_delete(builder);
Eric Laurent629afae2017-05-25 18:25:51 -0700162 return result;
163 }
164
165 aaudio_result_t close() {
166 if (mStream != nullptr) {
167 printf("call AAudioStream_close(%p)\n", mStream); fflush(stdout);
168 AAudioStream_close(mStream);
169 mStream = nullptr;
Eric Laurent629afae2017-05-25 18:25:51 -0700170 }
171 return AAUDIO_OK;
172 }
173
174 // Write zero data to fill up the buffer and prevent underruns.
175 aaudio_result_t prime() {
176 int32_t samplesPerFrame = AAudioStream_getChannelCount(mStream);
177 const int numFrames = 32;
178 float zeros[numFrames * samplesPerFrame];
179 memset(zeros, 0, sizeof(zeros));
180 aaudio_result_t result = numFrames;
181 while (result == numFrames) {
182 result = AAudioStream_write(mStream, zeros, numFrames, 0);
183 }
184 return result;
185 }
186
187 // Start the stream. AAudio will start calling your callback function.
188 aaudio_result_t start() {
189 aaudio_result_t result = AAudioStream_requestStart(mStream);
190 if (result != AAUDIO_OK) {
191 printf("ERROR - AAudioStream_requestStart() returned %d %s\n",
192 result, AAudio_convertResultToText(result));
193 }
194 return result;
195 }
196
197 // Stop the stream. AAudio will stop calling your callback function.
198 aaudio_result_t stop() {
199 aaudio_result_t result = AAudioStream_requestStop(mStream);
200 if (result != AAUDIO_OK) {
201 printf("ERROR - AAudioStream_requestStop() returned %d %s\n",
202 result, AAudio_convertResultToText(result));
203 }
204 int32_t xRunCount = AAudioStream_getXRunCount(mStream);
205 printf("AAudioStream_getXRunCount %d\n", xRunCount);
206 return result;
207 }
208
209 AAudioStream *getStream() const {
210 return mStream;
211 }
212
213private:
Eric Laurent629afae2017-05-25 18:25:51 -0700214 AAudioStream *mStream = nullptr;
215 aaudio_sharing_mode_t mRequestedSharingMode = SHARING_MODE;
216 aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE;
217};
218
219typedef struct SineThreadedData_s {
220 SineGenerator sineOsc1;
221 SineGenerator sineOsc2;
222 int scheduler;
223 bool schedulerChecked;
224} SineThreadedData_t;
225
226// Callback function that fills the audio output buffer.
227aaudio_data_callback_result_t SimplePlayerDataCallbackProc(
228 AAudioStream *stream,
229 void *userData,
230 void *audioData,
231 int32_t numFrames
232 ) {
233
234 // should not happen but just in case...
235 if (userData == nullptr) {
236 fprintf(stderr, "ERROR - SimplePlayerDataCallbackProc needs userData\n");
237 return AAUDIO_CALLBACK_RESULT_STOP;
238 }
239 SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
240
241 if (!sineData->schedulerChecked) {
242 sineData->scheduler = sched_getscheduler(gettid());
243 sineData->schedulerChecked = true;
244 }
245
246 int32_t samplesPerFrame = AAudioStream_getChannelCount(stream);
247 // This code only plays on the first one or two channels.
248 // TODO Support arbitrary number of channels.
249 switch (AAudioStream_getFormat(stream)) {
250 case AAUDIO_FORMAT_PCM_I16: {
251 int16_t *audioBuffer = (int16_t *) audioData;
252 // Render sine waves as shorts to first channel.
253 sineData->sineOsc1.render(&audioBuffer[0], samplesPerFrame, numFrames);
254 // Render sine waves to second channel if there is one.
255 if (samplesPerFrame > 1) {
256 sineData->sineOsc2.render(&audioBuffer[1], samplesPerFrame, numFrames);
257 }
258 }
259 break;
260 case AAUDIO_FORMAT_PCM_FLOAT: {
261 float *audioBuffer = (float *) audioData;
262 // Render sine waves as floats to first channel.
263 sineData->sineOsc1.render(&audioBuffer[0], samplesPerFrame, numFrames);
264 // Render sine waves to second channel if there is one.
265 if (samplesPerFrame > 1) {
266 sineData->sineOsc2.render(&audioBuffer[1], samplesPerFrame, numFrames);
267 }
268 }
269 break;
270 default:
271 return AAUDIO_CALLBACK_RESULT_STOP;
272 }
273
274 return AAUDIO_CALLBACK_RESULT_CONTINUE;
275}
276
277void SimplePlayerErrorCallbackProc(
278 AAudioStream *stream __unused,
279 void *userData __unused,
280 aaudio_result_t error)
281{
282 printf("Error Callback, error: %d\n",(int)error);
283}
284
285#endif //AAUDIO_SIMPLE_PLAYER_H