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 <sched.h> 23#include <unistd.h> 24 25#include <aaudio/AAudio.h> 26#include "AAudioArgsParser.h" 27#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// Arbitrary period for glitches 34#define FORCED_UNDERRUN_PERIOD_FRAMES (2 * 48000) 35// How long to sleep in a callback to cause an intentional glitch. For testing. 36#define FORCED_UNDERRUN_SLEEP_MICROS (10 * 1000) 37 38#define MAX_TIMESTAMPS 16 39 40typedef struct Timestamp { 41 int64_t position; 42 int64_t nanoseconds; 43} Timestamp; 44 45/** 46 * Simple wrapper for AAudio that opens an output stream either in callback or blocking write mode. 47 */ 48class AAudioSimplePlayer { 49public: 50 AAudioSimplePlayer() {} 51 ~AAudioSimplePlayer() { 52 close(); 53 }; 54 55 /** 56 * Call this before calling open(). 57 * @param requestedSharingMode 58 */ 59 void setSharingMode(aaudio_sharing_mode_t requestedSharingMode) { 60 mRequestedSharingMode = requestedSharingMode; 61 } 62 63 /** 64 * Call this before calling open(). 65 * @param requestedPerformanceMode 66 */ 67 void setPerformanceMode(aaudio_performance_mode_t requestedPerformanceMode) { 68 mRequestedPerformanceMode = requestedPerformanceMode; 69 } 70 71 // TODO Extract a common base class for record and playback. 72 73 /** 74 * Only call this after open() has been called. 75 */ 76 int32_t getSampleRate() const { 77 if (mStream == nullptr) { 78 return AAUDIO_ERROR_INVALID_STATE; 79 } 80 return AAudioStream_getSampleRate(mStream); 81 } 82 83 /** 84 * Only call this after open() has been called. 85 */ 86 int32_t getChannelCount() { 87 if (mStream == nullptr) { 88 return AAUDIO_ERROR_INVALID_STATE; 89 } 90 return AAudioStream_getChannelCount(mStream); 91 } 92 93 /** 94 * Open a stream 95 */ 96 aaudio_result_t open(const AAudioParameters ¶meters, 97 AAudioStream_dataCallback dataCallback = nullptr, 98 AAudioStream_errorCallback errorCallback = nullptr, 99 void *userContext = nullptr) { 100 aaudio_result_t result = AAUDIO_OK; 101 102 // Use an AAudioStreamBuilder to contain requested parameters. 103 AAudioStreamBuilder *builder = nullptr; 104 result = AAudio_createStreamBuilder(&builder); 105 if (result != AAUDIO_OK) return result; 106 107 parameters.applyParameters(builder); // apply args 108 109 AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT); 110 111 if (dataCallback != nullptr) { 112 AAudioStreamBuilder_setDataCallback(builder, dataCallback, userContext); 113 } 114 if (errorCallback != nullptr) { 115 AAudioStreamBuilder_setErrorCallback(builder, errorCallback, userContext); 116 } 117 //AAudioStreamBuilder_setFramesPerDataCallback(builder, CALLBACK_SIZE_FRAMES); 118 //AAudioStreamBuilder_setBufferCapacityInFrames(builder, 48 * 8); 119 120 // Open an AAudioStream using the Builder. 121 result = AAudioStreamBuilder_openStream(builder, &mStream); 122 123 if (result == AAUDIO_OK) { 124 int32_t sizeInBursts = parameters.getNumberOfBursts(); 125 if (sizeInBursts > 0) { 126 int32_t framesPerBurst = AAudioStream_getFramesPerBurst(mStream); 127 AAudioStream_setBufferSizeInFrames(mStream, sizeInBursts * framesPerBurst); 128 } 129 } 130 131 AAudioStreamBuilder_delete(builder); 132 return result; 133 } 134 135 aaudio_result_t open(int channelCount, int sampSampleRate, aaudio_format_t format, 136 AAudioStream_dataCallback dataProc, 137 AAudioStream_errorCallback errorProc, 138 void *userContext) { 139 aaudio_result_t result = AAUDIO_OK; 140 141 // Use an AAudioStreamBuilder to contain requested parameters. 142 AAudioStreamBuilder *builder = nullptr; 143 result = AAudio_createStreamBuilder(&builder); 144 if (result != AAUDIO_OK) return result; 145 146 AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT); 147 AAudioStreamBuilder_setPerformanceMode(builder, mRequestedPerformanceMode); 148 AAudioStreamBuilder_setSharingMode(builder, mRequestedSharingMode); 149 150 AAudioStreamBuilder_setChannelCount(builder, channelCount); 151 AAudioStreamBuilder_setSampleRate(builder, sampSampleRate); 152 AAudioStreamBuilder_setFormat(builder, format); 153 154 if (dataProc != nullptr) { 155 AAudioStreamBuilder_setDataCallback(builder, dataProc, userContext); 156 } 157 if (errorProc != nullptr) { 158 AAudioStreamBuilder_setErrorCallback(builder, errorProc, userContext); 159 } 160 //AAudioStreamBuilder_setFramesPerDataCallback(builder, CALLBACK_SIZE_FRAMES); 161 //AAudioStreamBuilder_setBufferCapacityInFrames(builder, 48 * 8); 162 163 // Open an AAudioStream using the Builder. 164 result = AAudioStreamBuilder_openStream(builder, &mStream); 165 166 AAudioStreamBuilder_delete(builder); 167 168 return result; 169 } 170 171 aaudio_result_t close() { 172 if (mStream != nullptr) { 173 AAudioStream_close(mStream); 174 mStream = nullptr; 175 } 176 return AAUDIO_OK; 177 } 178 179 // Write zero data to fill up the buffer and prevent underruns. 180 aaudio_result_t prime() { 181 int32_t samplesPerFrame = AAudioStream_getChannelCount(mStream); 182 const int numFrames = 32; 183 float zeros[numFrames * samplesPerFrame]; 184 memset(zeros, 0, sizeof(zeros)); 185 aaudio_result_t result = numFrames; 186 while (result == numFrames) { 187 result = AAudioStream_write(mStream, zeros, numFrames, 0); 188 } 189 return result; 190 } 191 192 // Start the stream. AAudio will start calling your callback function. 193 aaudio_result_t start() { 194 aaudio_result_t result = AAudioStream_requestStart(mStream); 195 if (result != AAUDIO_OK) { 196 printf("ERROR - AAudioStream_requestStart() returned %d %s\n", 197 result, AAudio_convertResultToText(result)); 198 } 199 return result; 200 } 201 202 // Stop the stream. AAudio will stop calling your callback function. 203 aaudio_result_t stop() { 204 aaudio_result_t result = AAudioStream_requestStop(mStream); 205 if (result != AAUDIO_OK) { 206 printf("ERROR - AAudioStream_requestStop() returned %d %s\n", 207 result, AAudio_convertResultToText(result)); 208 } 209 int32_t xRunCount = AAudioStream_getXRunCount(mStream); 210 printf("AAudioStream_getXRunCount %d\n", xRunCount); 211 return result; 212 } 213 214 // Pause the stream. AAudio will stop calling your callback function. 215 aaudio_result_t pause() { 216 aaudio_result_t result = AAudioStream_requestPause(mStream); 217 if (result != AAUDIO_OK) { 218 printf("ERROR - AAudioStream_requestPause() returned %d %s\n", 219 result, AAudio_convertResultToText(result)); 220 } 221 int32_t xRunCount = AAudioStream_getXRunCount(mStream); 222 printf("AAudioStream_getXRunCount %d\n", xRunCount); 223 return result; 224 } 225 226 // Flush the stream. AAudio will stop calling your callback function. 227 aaudio_result_t flush() { 228 aaudio_result_t result = AAudioStream_requestFlush(mStream); 229 if (result != AAUDIO_OK) { 230 printf("ERROR - AAudioStream_requestFlush() returned %d %s\n", 231 result, AAudio_convertResultToText(result)); 232 } 233 return result; 234 } 235 236 AAudioStream *getStream() const { 237 return mStream; 238 } 239 240private: 241 AAudioStream *mStream = nullptr; 242 aaudio_sharing_mode_t mRequestedSharingMode = SHARING_MODE; 243 aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE; 244 245}; 246 247typedef struct SineThreadedData_s { 248 249 SineGenerator sineOscillators[MAX_CHANNELS]; 250 Timestamp timestamps[MAX_TIMESTAMPS]; 251 int64_t framesTotal = 0; 252 int64_t nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES; 253 int32_t minNumFrames = INT32_MAX; 254 int32_t maxNumFrames = 0; 255 int32_t timestampCount = 0; // in timestamps 256 int32_t sampleRate = 48000; 257 int32_t prefixToneFrames = 0; 258 bool sweepSetup = false; 259 260 int scheduler = 0; 261 bool schedulerChecked = false; 262 bool forceUnderruns = false; 263 264 AAudioSimplePlayer simplePlayer; 265 int32_t callbackCount = 0; 266 WakeUp waker{AAUDIO_OK}; 267 268 /** 269 * Set sampleRate first. 270 */ 271 void setupSineBlip() { 272 for (int i = 0; i < MAX_CHANNELS; ++i) { 273 double centerFrequency = 880.0 * (i + 2); 274 sineOscillators[i].setup(centerFrequency, sampleRate); 275 sineOscillators[i].setSweep(centerFrequency, centerFrequency, 0.0); 276 } 277 } 278 279 void setupSineSweeps() { 280 for (int i = 0; i < MAX_CHANNELS; ++i) { 281 double centerFrequency = 220.0 * (i + 2); 282 sineOscillators[i].setup(centerFrequency, sampleRate); 283 double minFrequency = centerFrequency * 2.0 / 3.0; 284 // Change range slightly so they will go out of phase. 285 double maxFrequency = centerFrequency * 3.0 / 2.0; 286 double sweepSeconds = 5.0 + i; 287 sineOscillators[i].setSweep(minFrequency, maxFrequency, sweepSeconds); 288 } 289 sweepSetup = true; 290 } 291 292} SineThreadedData_t; 293 294// Callback function that fills the audio output buffer. 295aaudio_data_callback_result_t SimplePlayerDataCallbackProc( 296 AAudioStream *stream, 297 void *userData, 298 void *audioData, 299 int32_t numFrames 300 ) { 301 302 // should not happen but just in case... 303 if (userData == nullptr) { 304 printf("ERROR - SimplePlayerDataCallbackProc needs userData\n"); 305 return AAUDIO_CALLBACK_RESULT_STOP; 306 } 307 SineThreadedData_t *sineData = (SineThreadedData_t *) userData; 308 309 // Play an initial high tone so we can tell whether the beginning was truncated. 310 if (!sineData->sweepSetup && sineData->framesTotal >= sineData->prefixToneFrames) { 311 sineData->setupSineSweeps(); 312 } 313 314 if (sineData->forceUnderruns) { 315 if (sineData->framesTotal > sineData->nextFrameToGlitch) { 316 usleep(FORCED_UNDERRUN_SLEEP_MICROS); 317 printf("Simulate glitch at %lld\n", (long long) sineData->framesTotal); 318 sineData->nextFrameToGlitch += FORCED_UNDERRUN_PERIOD_FRAMES; 319 } 320 } 321 322 if (!sineData->schedulerChecked) { 323 sineData->scheduler = sched_getscheduler(gettid()); 324 sineData->schedulerChecked = true; 325 } 326 327 if (sineData->timestampCount < MAX_TIMESTAMPS) { 328 Timestamp *timestamp = &sineData->timestamps[sineData->timestampCount]; 329 aaudio_result_t result = AAudioStream_getTimestamp(stream, 330 CLOCK_MONOTONIC, ×tamp->position, ×tamp->nanoseconds); 331 if (result == AAUDIO_OK && // valid? 332 (sineData->timestampCount == 0 || // first one? 333 (timestamp->position != (timestamp - 1)->position))) { // advanced position? 334 sineData->timestampCount++; // keep this one 335 } 336 } 337 338 if (numFrames > sineData->maxNumFrames) { 339 sineData->maxNumFrames = numFrames; 340 } 341 if (numFrames < sineData->minNumFrames) { 342 sineData->minNumFrames = numFrames; 343 } 344 345 int32_t samplesPerFrame = AAudioStream_getChannelCount(stream); 346 347 348 int numActiveOscilators = (samplesPerFrame > MAX_CHANNELS) ? MAX_CHANNELS : samplesPerFrame; 349 switch (AAudioStream_getFormat(stream)) { 350 case AAUDIO_FORMAT_PCM_I16: { 351 int16_t *audioBuffer = (int16_t *) audioData; 352 for (int i = 0; i < numActiveOscilators; ++i) { 353 sineData->sineOscillators[i].render(&audioBuffer[i], samplesPerFrame, 354 numFrames); 355 } 356 } 357 break; 358 case AAUDIO_FORMAT_PCM_FLOAT: { 359 float *audioBuffer = (float *) audioData; 360 for (int i = 0; i < numActiveOscilators; ++i) { 361 sineData->sineOscillators[i].render(&audioBuffer[i], samplesPerFrame, 362 numFrames); 363 } 364 } 365 break; 366 default: 367 return AAUDIO_CALLBACK_RESULT_STOP; 368 } 369 370 sineData->callbackCount++; 371 sineData->framesTotal += numFrames; 372 return AAUDIO_CALLBACK_RESULT_CONTINUE; 373} 374 375void SimplePlayerErrorCallbackProc( 376 AAudioStream *stream __unused, 377 void *userData __unused, 378 aaudio_result_t error) { 379 // should not happen but just in case... 380 if (userData == nullptr) { 381 printf("ERROR - MyPlayerErrorCallbackProc needs userData\n"); 382 return; 383 } 384 SineThreadedData_t *sineData = (SineThreadedData_t *) userData; 385 android::status_t ret = sineData->waker.wake(error); 386 printf("Error Callback, error: %d, futex wake returns %d\n", error, ret); 387} 388 389 390#endif //AAUDIO_SIMPLE_PLAYER_H 391