cubeb_aaudio.cpp (69734B)
1 /* ex: set tabstop=2 shiftwidth=2 expandtab: 2 * Copyright © 2019 Jan Kelling 3 * 4 * This program is made available under an ISC-style license. See the 5 * accompanying file LICENSE for details. 6 */ 7 #include "cubeb-internal.h" 8 #include "cubeb/cubeb.h" 9 #include "cubeb_android.h" 10 #include "cubeb_log.h" 11 #include "cubeb_resampler.h" 12 #include "cubeb_triple_buffer.h" 13 #include <aaudio/AAudio.h> 14 #include <android/api-level.h> 15 #include <atomic> 16 #include <cassert> 17 #include <chrono> 18 #include <condition_variable> 19 #include <cstdint> 20 #include <cstring> 21 #include <dlfcn.h> 22 #include <inttypes.h> 23 #include <limits> 24 #include <memory> 25 #include <mutex> 26 #include <thread> 27 #include <variant> 28 #include <vector> 29 30 using namespace std; 31 32 #ifdef DISABLE_LIBAAUDIO_DLOPEN 33 #define WRAP(x) x 34 #else 35 #define WRAP(x) AAudioLibrary::get().x 36 #define LIBAAUDIO_API_VISIT(X) \ 37 X(AAudio_convertResultToText) \ 38 X(AAudio_convertStreamStateToText) \ 39 X(AAudio_createStreamBuilder) \ 40 X(AAudioStreamBuilder_openStream) \ 41 X(AAudioStreamBuilder_setChannelCount) \ 42 X(AAudioStreamBuilder_setBufferCapacityInFrames) \ 43 X(AAudioStreamBuilder_setDirection) \ 44 X(AAudioStreamBuilder_setFormat) \ 45 X(AAudioStreamBuilder_setSharingMode) \ 46 X(AAudioStreamBuilder_setPerformanceMode) \ 47 X(AAudioStreamBuilder_setSampleRate) \ 48 X(AAudioStreamBuilder_delete) \ 49 X(AAudioStreamBuilder_setDataCallback) \ 50 X(AAudioStreamBuilder_setErrorCallback) \ 51 X(AAudioStream_close) \ 52 X(AAudioStream_read) \ 53 X(AAudioStream_requestStart) \ 54 X(AAudioStream_requestPause) \ 55 X(AAudioStream_getTimestamp) \ 56 X(AAudioStream_requestFlush) \ 57 X(AAudioStream_requestStop) \ 58 X(AAudioStream_getPerformanceMode) \ 59 X(AAudioStream_getSharingMode) \ 60 X(AAudioStream_getBufferSizeInFrames) \ 61 X(AAudioStream_getBufferCapacityInFrames) \ 62 X(AAudioStream_getSampleRate) \ 63 X(AAudioStream_waitForStateChange) \ 64 X(AAudioStream_getFramesRead) \ 65 X(AAudioStream_getState) \ 66 X(AAudioStream_getFramesWritten) \ 67 X(AAudioStream_getFramesPerBurst) \ 68 X(AAudioStream_setBufferSizeInFrames) \ 69 X(AAudioStreamBuilder_setInputPreset) \ 70 X(AAudioStreamBuilder_setUsage) \ 71 X(AAudioStreamBuilder_setFramesPerDataCallback) 72 73 class AAudioLibrary { 74 public: 75 static AAudioLibrary & get() 76 { 77 static AAudioLibrary singleton; 78 return singleton; 79 } 80 81 bool load() 82 { 83 lock_guard lock(mutex); 84 if (state != State::Uninitialized) { 85 return state == State::Loaded; 86 } 87 88 libaaudio = dlopen("libaaudio.so", RTLD_NOW); 89 if (!libaaudio) { 90 LOG("AAudio: Failed to open libaaudio.so: %s", dlerror()); 91 state = State::Failed; 92 return false; 93 } 94 95 #define LOAD(x) \ 96 x = reinterpret_cast<decltype(::x) *>(dlsym(libaaudio, #x)); \ 97 if (!x) { \ 98 LOG("AAudio: Failed to load symbol %s: %s", #x, dlerror()); \ 99 dlclose(libaaudio); \ 100 libaaudio = nullptr; \ 101 state = State::Failed; \ 102 return false; \ 103 } 104 LIBAAUDIO_API_VISIT(LOAD) 105 #undef LOAD 106 107 state = State::Loaded; 108 return true; 109 } 110 111 #define DECLARE(x) decltype(::x) * x = nullptr; 112 LIBAAUDIO_API_VISIT(DECLARE) 113 #undef DECLARE 114 115 private: 116 enum class State { Uninitialized, Loaded, Failed }; 117 118 AAudioLibrary() = default; 119 120 ~AAudioLibrary() 121 { 122 if (libaaudio) { 123 dlclose(libaaudio); 124 } 125 } 126 127 AAudioLibrary(const AAudioLibrary &) = delete; 128 AAudioLibrary & operator=(const AAudioLibrary &) = delete; 129 130 void * libaaudio = nullptr; 131 State state = State::Uninitialized; 132 mutex mutex; 133 }; 134 #endif 135 136 const uint8_t MAX_STREAMS = 16; 137 const int64_t NS_PER_S = static_cast<int64_t>(1e9); 138 139 static void 140 aaudio_stream_destroy(cubeb_stream * stm); 141 static int 142 aaudio_stream_start(cubeb_stream * stm); 143 static int 144 aaudio_stream_stop(cubeb_stream * stm); 145 146 static int 147 aaudio_stream_init_impl(cubeb_stream * stm, lock_guard<mutex> & lock); 148 static int 149 aaudio_stream_stop_locked(cubeb_stream * stm, lock_guard<mutex> & lock); 150 static void 151 aaudio_stream_destroy_locked(cubeb_stream * stm, lock_guard<mutex> & lock); 152 static int 153 aaudio_stream_start_locked(cubeb_stream * stm, lock_guard<mutex> & lock); 154 155 static void 156 reinitialize_stream(cubeb_stream * stm); 157 158 enum class stream_state { 159 INIT = 0, 160 STOPPED, 161 STOPPING, 162 STARTED, 163 STARTING, 164 DRAINING, 165 ERROR, 166 SHUTDOWN, 167 }; 168 169 struct AAudioTimingInfo { 170 // The timestamp at which the audio engine last called the calback. 171 uint64_t tstamp; 172 // The number of output frames sent to the engine. 173 uint64_t output_frame_index; 174 // The current output latency in frames. 0 if there is no output stream. 175 uint32_t output_latency; 176 // The current input latency in frames. 0 if there is no input stream. 177 uint32_t input_latency; 178 }; 179 180 /* To guess the current position of the stream when it's playing, the elapsed 181 * time between the last callback and now is used. However, when the stream was 182 * stopped and there was no new callback after playing restarted yet, the time 183 * spent in stopped state should be excluded. It's also necessary to track the 184 * number of audio frames written to stream before reinitialization so it can be 185 * used to offset the position later, because 186 * `AAudioTimingInfo.output_frame_index` will restart from zero after 187 * reinitializing. 188 * This class defines an internal state machine that takes the stream state 189 * changes and callback emissions as events to changes it own states and 190 * estimates played time accordingly. 191 * 192 * A simplified |stream_state| transitions of playing looks like: 193 * INIT -> [STARTING/STARTED -> callback* -> STOPPING/STOPPED]* -> SHUTDOWN|INIT 194 * 195 * Internal states: 196 * - None: the initial state. 197 * - Play: stream is playing. 198 * - Pause: stream is not playing. Holds stop timestamp. 199 * - Resume: stream is playing after stopping and no callback emitted yet. Holds 200 * time elapsed in the previous Pause state. 201 * Transitions: 202 * - None -(STARTING)-> Play 203 * - Play -(STOPPING)-> Pause 204 * - Pause -(STARTING)-> Resume 205 * - Resume -(callback)-> Play 206 * - Resume -(STARTING)-> Resume 207 * - Pause -(INIT)-> None 208 */ 209 class position_estimate { 210 public: 211 // Called with the current time when stopping the stream. 212 void stop(uint64_t timestamp) 213 { 214 assert(in_state<Play>() || in_state<Resume>()); 215 // Change to Pause and save the current time in it. Timestamp offset by the 216 // elapsed time in previous Pause if stream stops again before any callback 217 // clears it. 218 set_pause_timestamp(in_state<Play>() ? timestamp 219 : timestamp - get_pause_time()); 220 } 221 222 // Called with the current time when starting the stream. 223 void start(uint64_t timestamp) 224 { 225 assert(in_state<None>() || in_state<Pause>()); 226 if (in_state<Pause>()) { 227 // Change to Resume and record elapsed time in it. 228 set_pause_time(timestamp - get_pause_timestamp()); 229 } else { 230 set_state<Play>(); 231 } 232 } 233 234 // Calculate how much time the stream bas been playing since last callback. 235 uint64_t elapsed_time_since_callback(uint64_t now, 236 uint64_t last_callback_timestamp) 237 { 238 if (in_state<Play>()) { 239 if (callback_timestamp != last_callback_timestamp) { 240 callback_timestamp = last_callback_timestamp; 241 } 242 return now - last_callback_timestamp; 243 } else if (in_state<Resume>()) { 244 if (callback_timestamp == last_callback_timestamp) { 245 // Stream was stopped and no callback emited yet: exclude elapsed time 246 // in Pause state. 247 return now - last_callback_timestamp - get_pause_time(); 248 } 249 // Callback emitted: update callback timestamp and change to Play. 250 callback_timestamp = last_callback_timestamp; 251 set_state<Play>(); 252 return now - last_callback_timestamp; 253 } else if (in_state<Pause>()) { 254 assert(callback_timestamp == last_callback_timestamp); 255 // Use recorded timestamps when Paused. 256 return get_pause_timestamp() - callback_timestamp; 257 } else { 258 assert(in_state<None>()); 259 return 0; 260 } 261 } 262 263 // Called when reinitializing stream. The input parameter is how many frames 264 // have already been written to AAudio since the first initialization. 265 void reinit(uint64_t position) 266 { 267 init_position = position; 268 state = None{}; 269 callback_timestamp = 0; 270 } 271 272 // Frame index when last reinitialized. 273 uint64_t initial_position() { return init_position; } 274 275 private: 276 template <typename T> void set_state() { state.emplace<T>(); } 277 278 template <typename T> bool in_state() 279 { 280 return std::holds_alternative<T>(state); 281 } 282 283 void set_pause_time(uint64_t time) { state.emplace<Resume>(time); } 284 285 uint64_t get_pause_time() 286 { 287 assert(in_state<Resume>()); 288 return std::get<Resume>(state).pause_time; 289 } 290 291 void set_pause_timestamp(uint64_t timestamp) 292 { 293 state.emplace<Pause>(timestamp); 294 } 295 296 uint64_t get_pause_timestamp() 297 { 298 assert(in_state<Pause>()); 299 return std::get<Pause>(state).timestamp; 300 } 301 302 struct None {}; 303 struct Play {}; 304 struct Pause { 305 Pause() = delete; 306 explicit Pause(uint64_t timestamp) : timestamp(timestamp) {} 307 uint64_t timestamp; // The time when stopping stream. 308 }; 309 struct Resume { 310 Resume() = delete; 311 explicit Resume(uint64_t time) : pause_time(time) {} 312 uint64_t pause_time; // Elapsed time from stopping to starting stream. 313 }; 314 std::variant<None, Play, Pause, Resume> state; 315 // Track input callback timestamp to detect callback emission. 316 uint64_t callback_timestamp{0}; 317 // Track number of written frames to adjust position after reinitialization. 318 uint64_t init_position{0}; 319 }; 320 321 struct cubeb_stream { 322 /* Note: Must match cubeb_stream layout in cubeb.c. */ 323 cubeb * context{}; 324 void * user_ptr{}; 325 326 std::atomic<bool> in_use{false}; 327 std::atomic<bool> latency_metrics_available{false}; 328 std::atomic<int64_t> drain_target{-1}; 329 std::atomic<stream_state> state{stream_state::INIT}; 330 std::atomic<bool> in_data_callback{false}; 331 triple_buffer<AAudioTimingInfo> timing_info; 332 333 AAudioStream * ostream{}; 334 AAudioStream * istream{}; 335 cubeb_data_callback data_callback{}; 336 cubeb_state_callback state_callback{}; 337 cubeb_resampler * resampler{}; 338 339 // mutex synchronizes access to the stream from the state thread 340 // and user-called functions. Everything that is accessed in the 341 // aaudio data (or error) callback is synchronized only via atomics. 342 // This lock is acquired for the entirety of the reinitialization period, when 343 // changing device. 344 std::mutex mutex; 345 346 std::vector<uint8_t> in_buf; 347 unsigned in_frame_size{}; // size of one input frame 348 349 unique_ptr<cubeb_stream_params> output_stream_params; 350 unique_ptr<cubeb_stream_params> input_stream_params; 351 uint32_t latency_frames{}; 352 cubeb_sample_format out_format{}; 353 uint32_t sample_rate{}; 354 std::atomic<float> volume{1.f}; 355 unsigned out_channels{}; 356 unsigned out_frame_size{}; 357 bool voice_input{}; 358 bool voice_output{}; 359 uint64_t previous_clock{}; 360 position_estimate pos_estimate; 361 }; 362 363 struct cubeb { 364 struct cubeb_ops const * ops{}; 365 366 struct { 367 // The state thread: it waits for state changes and stops 368 // drained streams. 369 std::thread thread; 370 std::thread notifier; 371 std::mutex mutex; 372 std::condition_variable cond; 373 std::atomic<bool> join{false}; 374 std::atomic<bool> waiting{false}; 375 } state; 376 377 // streams[i].in_use signals whether a stream is used 378 struct cubeb_stream streams[MAX_STREAMS]; 379 }; 380 381 struct AutoInCallback { 382 AutoInCallback(cubeb_stream * stm) : stm(stm) 383 { 384 stm->in_data_callback.store(true); 385 } 386 ~AutoInCallback() { stm->in_data_callback.store(false); } 387 cubeb_stream * stm; 388 }; 389 390 // Returns when aaudio_stream's state is equal to desired_state. 391 // poll_frequency_ns is the duration that is slept in between asking for 392 // state updates and getting the new state. 393 // When waiting for a stream to stop, it is best to pick a value similar 394 // to the callback time because STOPPED will happen after 395 // draining. 396 static int 397 wait_for_state_change(AAudioStream * aaudio_stream, 398 aaudio_stream_state_t * desired_state, 399 int64_t poll_frequency_ns) 400 { 401 aaudio_stream_state_t new_state; 402 do { 403 // See the docs of aaudio getState/waitForStateChange for details, 404 // why we are passing STATE_UNKNOWN. 405 aaudio_result_t res = WRAP(AAudioStream_waitForStateChange)( 406 aaudio_stream, AAUDIO_STREAM_STATE_UNKNOWN, &new_state, 407 poll_frequency_ns); 408 if (res != AAUDIO_OK) { 409 LOG("AAudioStream_waitForStateChange: %s", 410 WRAP(AAudio_convertResultToText)(res)); 411 return CUBEB_ERROR; 412 } 413 } while (*desired_state != AAUDIO_STREAM_STATE_UNINITIALIZED && 414 new_state != *desired_state); 415 416 *desired_state = new_state; 417 418 LOG("wait_for_state_change: current state now: %s", 419 WRAP(AAudio_convertStreamStateToText)(new_state)); 420 421 return CUBEB_OK; 422 } 423 424 // Only allowed from state thread, while mutex on stm is locked 425 static void 426 shutdown_with_error(cubeb_stream * stm) 427 { 428 if (stm->istream) { 429 WRAP(AAudioStream_requestStop)(stm->istream); 430 } 431 if (stm->ostream) { 432 WRAP(AAudioStream_requestStop)(stm->ostream); 433 } 434 435 int64_t poll_frequency_ns = NS_PER_S * stm->out_frame_size / stm->sample_rate; 436 int rv; 437 if (stm->istream) { 438 aaudio_stream_state_t state = AAUDIO_STREAM_STATE_STOPPED; 439 rv = wait_for_state_change(stm->istream, &state, poll_frequency_ns); 440 if (rv != CUBEB_OK) { 441 LOG("Failure when waiting for stream change on the input side when " 442 "shutting down in error"); 443 // Not much we can do, carry on 444 } 445 } 446 if (stm->ostream) { 447 aaudio_stream_state_t state = AAUDIO_STREAM_STATE_STOPPED; 448 rv = wait_for_state_change(stm->ostream, &state, poll_frequency_ns); 449 if (rv != CUBEB_OK) { 450 LOG("Failure when waiting for stream change on the output side when " 451 "shutting down in error"); 452 // Not much we can do, carry on 453 } 454 } 455 456 assert(!stm->in_data_callback.load()); 457 stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); 458 stm->state.store(stream_state::SHUTDOWN); 459 } 460 461 // Returns whether the given state is one in which we wait for 462 // an asynchronous change 463 static bool 464 waiting_state(stream_state state) 465 { 466 switch (state) { 467 case stream_state::DRAINING: 468 case stream_state::STARTING: 469 case stream_state::STOPPING: 470 return true; 471 default: 472 return false; 473 } 474 } 475 476 static void 477 update_state(cubeb_stream * stm) 478 { 479 // Fast path for streams that don't wait for state change or are invalid 480 enum stream_state old_state = stm->state.load(); 481 if (old_state == stream_state::INIT || old_state == stream_state::STARTED || 482 old_state == stream_state::STOPPED || 483 old_state == stream_state::SHUTDOWN) { 484 return; 485 } 486 487 // Requeue a state update if stream is already locked. 488 unique_lock lock(stm->mutex, std::try_to_lock); 489 if (!lock.owns_lock()) { 490 stm->context->state.waiting.store(true); 491 stm->context->state.cond.notify_one(); 492 return; 493 } 494 495 // check again: if this is true now, the stream was destroyed or 496 // changed between our fast path check and locking the mutex 497 old_state = stm->state.load(); 498 if (old_state == stream_state::INIT || old_state == stream_state::STARTED || 499 old_state == stream_state::STOPPED || 500 old_state == stream_state::SHUTDOWN) { 501 return; 502 } 503 504 // We compute the new state the stream has and then compare_exchange it 505 // if it has changed. This way we will never just overwrite state 506 // changes that were set from the audio thread in the meantime, 507 // such as a DRAINING or error state. 508 enum stream_state new_state; 509 do { 510 if (old_state == stream_state::SHUTDOWN) { 511 return; 512 } 513 514 if (old_state == stream_state::ERROR) { 515 shutdown_with_error(stm); 516 return; 517 } 518 519 new_state = old_state; 520 521 aaudio_stream_state_t istate = AAUDIO_STREAM_STATE_UNINITIALIZED; 522 aaudio_stream_state_t ostate = AAUDIO_STREAM_STATE_UNINITIALIZED; 523 524 // We use waitForStateChange (with zero timeout) instead of just 525 // getState since only the former internally updates the state. 526 if (stm->istream) { 527 int res = wait_for_state_change(stm->istream, &istate, 0); 528 if (res != CUBEB_OK) { 529 return; 530 } 531 assert(istate); 532 } 533 534 if (stm->ostream) { 535 int res = wait_for_state_change(stm->ostream, &ostate, 0); 536 if (res != CUBEB_OK) { 537 return; 538 } 539 assert(ostate); 540 } 541 542 // handle invalid stream states 543 if (istate == AAUDIO_STREAM_STATE_FLUSHING || 544 istate == AAUDIO_STREAM_STATE_FLUSHED || 545 istate == AAUDIO_STREAM_STATE_UNKNOWN || 546 istate == AAUDIO_STREAM_STATE_DISCONNECTED) { 547 LOG("Unexpected android input stream state %s", 548 WRAP(AAudio_convertStreamStateToText)(istate)); 549 shutdown_with_error(stm); 550 return; 551 } 552 553 if (ostate == AAUDIO_STREAM_STATE_FLUSHING || 554 ostate == AAUDIO_STREAM_STATE_FLUSHED || 555 ostate == AAUDIO_STREAM_STATE_UNKNOWN || 556 ostate == AAUDIO_STREAM_STATE_DISCONNECTED) { 557 LOG("Unexpected android output stream state %s", 558 WRAP(AAudio_convertStreamStateToText)(ostate)); 559 shutdown_with_error(stm); 560 return; 561 } 562 563 switch (old_state) { 564 case stream_state::STARTING: 565 if ((!istate || istate == AAUDIO_STREAM_STATE_STARTED) && 566 (!ostate || ostate == AAUDIO_STREAM_STATE_STARTED)) { 567 stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED); 568 new_state = stream_state::STARTED; 569 } 570 break; 571 case stream_state::DRAINING: 572 // The DRAINING state means that we want to stop the streams but 573 // may not have done so yet. 574 if (ostate && ostate == AAUDIO_STREAM_STATE_STARTED) { 575 int64_t read = WRAP(AAudioStream_getFramesRead)(stm->ostream); 576 int64_t target = stm->drain_target.load(); 577 LOGV("Output stream DRAINING. Remaining frames: %" PRId64 ".", 578 target - read); 579 if (read < target) { 580 // requestStop says it will wait for buffered data to be drained. 581 // We have observed the end of the stream's written data getting 582 // truncated however, suggesting there is some buffer that it does 583 // not drain. Wait for all written frames to have been read before 584 // draining. 585 return; 586 } 587 } 588 // The aaudio docs state that returning STOP from the callback isn't 589 // enough, the stream has to be stopped from another thread 590 // afterwards. 591 // No callbacks are triggered anymore when requestStop returns. 592 // That is important as we otherwise might read from a closed istream 593 // for a duplex stream. 594 // Therefor it is important to close ostream first. 595 if (ostate && ostate != AAUDIO_STREAM_STATE_STOPPING && 596 ostate != AAUDIO_STREAM_STATE_STOPPED) { 597 LOGV("Output stream DRAINING. Stopping."); 598 aaudio_result_t res = WRAP(AAudioStream_requestStop)(stm->ostream); 599 if (res != AAUDIO_OK) { 600 LOG("AAudioStream_requestStop: %s", 601 WRAP(AAudio_convertResultToText)(res)); 602 return; 603 } 604 } 605 if (istate && istate != AAUDIO_STREAM_STATE_STOPPING && 606 istate != AAUDIO_STREAM_STATE_STOPPED) { 607 LOGV("Input stream DRAINING. Stopping"); 608 aaudio_result_t res = WRAP(AAudioStream_requestStop)(stm->istream); 609 if (res != AAUDIO_OK) { 610 LOG("AAudioStream_requestStop: %s", 611 WRAP(AAudio_convertResultToText)(res)); 612 return; 613 } 614 } 615 616 // we always wait until both streams are stopped until we 617 // send CUBEB_STATE_DRAINED. Then we can directly transition 618 // our logical state to STOPPED, not triggering 619 // an additional CUBEB_STATE_STOPPED callback (which might 620 // be unexpected for the user). 621 if ((!ostate || ostate == AAUDIO_STREAM_STATE_STOPPED) && 622 (!istate || istate == AAUDIO_STREAM_STATE_STOPPED)) { 623 new_state = stream_state::STOPPED; 624 stm->drain_target.store(-1); 625 stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED); 626 } 627 break; 628 case stream_state::STOPPING: 629 // If stream_stop happens while the stream is still starting, we may see 630 // STARTING/STARTED, ignore these and handle STATE_STOPPED once we reach 631 // PAUSED. 632 assert(!istate || istate == AAUDIO_STREAM_STATE_STARTING || 633 istate == AAUDIO_STREAM_STATE_STARTED || 634 istate == AAUDIO_STREAM_STATE_PAUSING || 635 istate == AAUDIO_STREAM_STATE_PAUSED); 636 assert(!ostate || ostate == AAUDIO_STREAM_STATE_STARTING || 637 ostate == AAUDIO_STREAM_STATE_STARTED || 638 ostate == AAUDIO_STREAM_STATE_PAUSING || 639 ostate == AAUDIO_STREAM_STATE_PAUSED); 640 if ((!istate || istate == AAUDIO_STREAM_STATE_PAUSED) && 641 (!ostate || ostate == AAUDIO_STREAM_STATE_PAUSED)) { 642 stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED); 643 new_state = stream_state::STOPPED; 644 } 645 break; 646 default: 647 assert(false && "Unreachable: invalid state"); 648 } 649 } while (old_state != new_state && 650 !stm->state.compare_exchange_strong(old_state, new_state)); 651 } 652 653 // See https://nyorain.github.io/lock-free-wakeup.html for a note 654 // why this is needed. The audio thread notifies the state thread about 655 // state changes and must not block. The state thread on the other hand should 656 // sleep until there is work to be done. So we need a lockfree producer 657 // and blocking producer. This can only be achieved safely with a new thread 658 // that only serves as notifier backup (in case the notification happens 659 // right between the state thread checking and going to sleep in which case 660 // this thread will kick in and signal it right again). 661 static void 662 notifier_thread(cubeb * ctx) 663 { 664 unique_lock lock(ctx->state.mutex); 665 666 while (!ctx->state.join.load()) { 667 ctx->state.cond.wait(lock); 668 if (ctx->state.waiting.load()) { 669 // This must signal our state thread since there is no other 670 // thread currently waiting on the condition variable. 671 // The state change thread is guaranteed to be waiting since 672 // we hold the mutex it locks when awake. 673 ctx->state.cond.notify_one(); 674 } 675 } 676 677 // make sure other thread joins as well 678 ctx->state.cond.notify_one(); 679 LOG("Exiting notifier thread"); 680 } 681 682 static void 683 state_thread(cubeb * ctx) 684 { 685 unique_lock lock(ctx->state.mutex); 686 687 bool waiting = false; 688 while (!ctx->state.join.load()) { 689 waiting |= ctx->state.waiting.load(); 690 if (waiting) { 691 ctx->state.waiting.store(false); 692 waiting = false; 693 for (auto & stream : ctx->streams) { 694 cubeb_stream * stm = &stream; 695 update_state(stm); 696 waiting |= waiting_state(atomic_load(&stm->state)); 697 } 698 699 // state changed from another thread, update again immediately 700 if (ctx->state.waiting.load()) { 701 waiting = true; 702 continue; 703 } 704 705 // Not waiting for any change anymore: we can wait on the 706 // condition variable without timeout 707 if (!waiting) { 708 continue; 709 } 710 711 // while any stream is waiting for state change we sleep with regular 712 // timeouts. But we wake up immediately if signaled. 713 // This might seem like a poor man's implementation of state change 714 // waiting but (as of october 2020), the implementation of 715 // AAudioStream_waitForStateChange is just sleeping with regular 716 // timeouts as well: 717 // https://android.googlesource.com/platform/frameworks/av/+/refs/heads/master/media/libaaudio/src/core/AudioStream.cpp 718 auto dur = std::chrono::milliseconds(5); 719 ctx->state.cond.wait_for(lock, dur); 720 } else { 721 ctx->state.cond.wait(lock); 722 } 723 } 724 725 // make sure other thread joins as well 726 ctx->state.cond.notify_one(); 727 LOG("Exiting state thread"); 728 } 729 730 static char const * 731 aaudio_get_backend_id(cubeb * /* ctx */) 732 { 733 return "aaudio"; 734 } 735 736 static int 737 aaudio_get_max_channel_count(cubeb * ctx, uint32_t * max_channels) 738 { 739 assert(ctx && max_channels); 740 // NOTE: we might get more, AAudio docs don't specify anything. 741 *max_channels = 2; 742 return CUBEB_OK; 743 } 744 745 static void 746 aaudio_destroy(cubeb * ctx) 747 { 748 assert(ctx); 749 750 #ifndef NDEBUG 751 // make sure all streams were destroyed 752 for (auto & stream : ctx->streams) { 753 assert(!stream.in_use.load()); 754 } 755 #endif 756 757 // broadcast joining to both threads 758 // they will additionally signal each other before joining 759 ctx->state.join.store(true); 760 ctx->state.cond.notify_all(); 761 762 if (ctx->state.thread.joinable()) { 763 ctx->state.thread.join(); 764 } 765 if (ctx->state.notifier.joinable()) { 766 ctx->state.notifier.join(); 767 } 768 delete ctx; 769 } 770 771 static void 772 apply_volume(cubeb_stream * stm, void * audio_data, uint32_t num_frames) 773 { 774 float volume = stm->volume.load(); 775 // optimization: we don't have to change anything in this case 776 if (volume == 1.f) { 777 return; 778 } 779 780 switch (stm->out_format) { 781 case CUBEB_SAMPLE_S16NE: { 782 int16_t * integer_data = static_cast<int16_t *>(audio_data); 783 for (uint32_t i = 0u; i < num_frames * stm->out_channels; ++i) { 784 integer_data[i] = 785 static_cast<int16_t>(static_cast<float>(integer_data[i]) * volume); 786 } 787 break; 788 } 789 case CUBEB_SAMPLE_FLOAT32NE: 790 for (uint32_t i = 0u; i < num_frames * stm->out_channels; ++i) { 791 (static_cast<float *>(audio_data))[i] *= volume; 792 } 793 break; 794 default: 795 assert(false && "Unreachable: invalid stream out_format"); 796 } 797 } 798 799 uint64_t 800 now_ns() 801 { 802 using namespace std::chrono; 803 return duration_cast<nanoseconds>(steady_clock::now().time_since_epoch()) 804 .count(); 805 } 806 807 // To be called from the real-time audio callback 808 uint64_t 809 aaudio_get_latency(cubeb_stream * stm, aaudio_direction_t direction, 810 uint64_t tstamp_ns) 811 { 812 bool is_output = direction == AAUDIO_DIRECTION_OUTPUT; 813 int64_t hw_frame_index; 814 int64_t hw_tstamp; 815 AAudioStream * stream = is_output ? stm->ostream : stm->istream; 816 // For an output stream (resp. input stream), get the number of frames 817 // written to (resp read from) the hardware. 818 int64_t app_frame_index = is_output 819 ? WRAP(AAudioStream_getFramesWritten)(stream) 820 : WRAP(AAudioStream_getFramesRead)(stream); 821 822 assert(tstamp_ns < std::numeric_limits<uint64_t>::max()); 823 int64_t signed_tstamp_ns = static_cast<int64_t>(tstamp_ns); 824 825 // Get a timestamp for a particular frame index written to or read from the 826 // hardware. 827 auto result = WRAP(AAudioStream_getTimestamp)(stream, CLOCK_MONOTONIC, 828 &hw_frame_index, &hw_tstamp); 829 if (result != AAUDIO_OK) { 830 LOG("AAudioStream_getTimestamp failure for %s: %s", 831 is_output ? "output" : "input", 832 WRAP(AAudio_convertResultToText)(result)); 833 return 0; 834 } 835 836 // Compute the difference between the app and the hardware indices. 837 int64_t frame_index_delta = app_frame_index - hw_frame_index; 838 // Convert to ns 839 int64_t frame_time_delta = (frame_index_delta * NS_PER_S) / stm->sample_rate; 840 // Extrapolate from the known timestamp for a particular frame presented. 841 int64_t app_frame_hw_time = hw_tstamp + frame_time_delta; 842 // For an output stream, the latency is positive, for an input stream, it's 843 // negative. It can happen in some instances, e.g. around start of the stream 844 // that the latency for output is negative, return 0 in this case. 845 int64_t latency_ns = is_output 846 ? std::max(static_cast<int64_t>(0), 847 app_frame_hw_time - signed_tstamp_ns) 848 : signed_tstamp_ns - app_frame_hw_time; 849 int64_t latency_frames = stm->sample_rate * latency_ns / NS_PER_S; 850 851 LOGV("Latency in frames (%s): %ld (%fms)", is_output ? "output" : "input", 852 latency_frames, latency_ns / 1e6); 853 854 return latency_frames; 855 } 856 857 void 858 compute_and_report_latency_metrics(cubeb_stream * stm) 859 { 860 AAudioTimingInfo info = {}; 861 862 info.tstamp = now_ns(); 863 864 if (stm->ostream) { 865 uint64_t latency_frames = 866 aaudio_get_latency(stm, AAUDIO_DIRECTION_OUTPUT, info.tstamp); 867 if (latency_frames) { 868 info.output_latency = latency_frames; 869 info.output_frame_index = 870 WRAP(AAudioStream_getFramesWritten)(stm->ostream); 871 } 872 } 873 if (stm->istream) { 874 uint64_t latency_frames = 875 aaudio_get_latency(stm, AAUDIO_DIRECTION_INPUT, info.tstamp); 876 if (latency_frames) { 877 info.input_latency = latency_frames; 878 } 879 } 880 881 if (info.output_latency || info.input_latency) { 882 stm->latency_metrics_available = true; 883 stm->timing_info.write(info); 884 } 885 } 886 887 // Returning AAUDIO_CALLBACK_RESULT_STOP seems to put the stream in 888 // an invalid state. Seems like an AAudio bug/bad documentation. 889 // We therefore only return it on error. 890 891 static aaudio_data_callback_result_t 892 aaudio_duplex_data_cb(AAudioStream * astream, void * user_data, 893 void * audio_data, int32_t num_frames) 894 { 895 cubeb_stream * stm = (cubeb_stream *)user_data; 896 AutoInCallback aic(stm); 897 assert(stm->ostream == astream); 898 assert(stm->istream); 899 assert(num_frames >= 0); 900 901 stream_state state = atomic_load(&stm->state); 902 int istate = WRAP(AAudioStream_getState)(stm->istream); 903 int ostate = WRAP(AAudioStream_getState)(stm->ostream); 904 905 // all other states may happen since the callback might be called 906 // from within requestStart 907 assert(state != stream_state::SHUTDOWN); 908 909 // This might happen when we started draining but not yet actually 910 // stopped the stream from the state thread. 911 if (state == stream_state::DRAINING) { 912 LOG("Draining in duplex callback"); 913 std::memset(audio_data, 0x0, num_frames * stm->out_frame_size); 914 return AAUDIO_CALLBACK_RESULT_CONTINUE; 915 } 916 917 if (num_frames * stm->in_frame_size > stm->in_buf.size()) { 918 LOG("Resizing input buffer in duplex callback"); 919 stm->in_buf.resize(num_frames * stm->in_frame_size); 920 } 921 // The aaudio docs state that AAudioStream_read must not be called on 922 // the stream associated with a callback. But we call it on the input stream 923 // while this callback is for the output stream so this is ok. 924 // We also pass timeout 0, giving us strong non-blocking guarantees. 925 // This is exactly how it's done in the aaudio duplex example code snippet. 926 long in_num_frames = 927 WRAP(AAudioStream_read)(stm->istream, stm->in_buf.data(), num_frames, 0); 928 if (in_num_frames < 0) { // error 929 if (in_num_frames == AAUDIO_ERROR_DISCONNECTED) { 930 LOG("AAudioStream_read: %s (reinitializing)", 931 WRAP(AAudio_convertResultToText)(in_num_frames)); 932 reinitialize_stream(stm); 933 } else { 934 stm->state.store(stream_state::ERROR); 935 stm->context->state.waiting.store(true); 936 stm->context->state.cond.notify_one(); 937 } 938 LOG("AAudioStream_read: %s", 939 WRAP(AAudio_convertResultToText)(in_num_frames)); 940 return AAUDIO_CALLBACK_RESULT_STOP; 941 } 942 943 ALOGV("aaudio duplex data cb on stream %p: state %ld (in: %d, out: %d), " 944 "num_frames: %d, read: %ld", 945 (void *)stm, state, istate, ostate, num_frames, in_num_frames); 946 947 compute_and_report_latency_metrics(stm); 948 949 // This can happen shortly after starting the stream. AAudio might immediately 950 // begin to buffer output but not have any input ready yet. We could 951 // block AAudioStream_read (passing a timeout > 0) but that leads to issues 952 // since blocking in this callback is a bad idea in general and it might break 953 // the stream when it is stopped by another thread shortly after being 954 // started. We therefore simply send silent input to the application, as shown 955 // in the AAudio duplex stream code example. 956 if (in_num_frames < num_frames) { 957 // LOG("AAudioStream_read returned not enough frames: %ld instead of %d", 958 // in_num_frames, num_frames); 959 unsigned left = num_frames - in_num_frames; 960 uint8_t * buf = stm->in_buf.data() + in_num_frames * stm->in_frame_size; 961 std::memset(buf, 0x0, left * stm->in_frame_size); 962 in_num_frames = num_frames; 963 } 964 965 long done_frames = 966 cubeb_resampler_fill(stm->resampler, stm->in_buf.data(), &in_num_frames, 967 audio_data, num_frames); 968 969 if (done_frames < 0 || done_frames > num_frames) { 970 LOG("Error in data callback or resampler: %ld", done_frames); 971 stm->state.store(stream_state::ERROR); 972 stm->context->state.waiting.store(true); 973 stm->context->state.cond.notify_one(); 974 return AAUDIO_CALLBACK_RESULT_STOP; 975 } 976 if (done_frames < num_frames) { 977 stm->drain_target.store(WRAP(AAudioStream_getFramesWritten)(stm->ostream) + 978 done_frames); 979 stm->state.store(stream_state::DRAINING); 980 stm->context->state.waiting.store(true); 981 stm->context->state.cond.notify_one(); 982 983 char * begin = 984 static_cast<char *>(audio_data) + done_frames * stm->out_frame_size; 985 std::memset(begin, 0x0, (num_frames - done_frames) * stm->out_frame_size); 986 } 987 988 apply_volume(stm, audio_data, done_frames); 989 return AAUDIO_CALLBACK_RESULT_CONTINUE; 990 } 991 992 static aaudio_data_callback_result_t 993 aaudio_output_data_cb(AAudioStream * astream, void * user_data, 994 void * audio_data, int32_t num_frames) 995 { 996 cubeb_stream * stm = (cubeb_stream *)user_data; 997 AutoInCallback aic(stm); 998 assert(stm->ostream == astream); 999 assert(!stm->istream); 1000 assert(num_frames >= 0); 1001 1002 stream_state state = stm->state.load(); 1003 int ostate = WRAP(AAudioStream_getState)(stm->ostream); 1004 ALOGV("aaudio output data cb on stream %p: state %ld (%d), num_frames: %d", 1005 stm, state, ostate, num_frames); 1006 1007 // all other states may happen since the callback might be called 1008 // from within requestStart 1009 assert(state != stream_state::SHUTDOWN); 1010 1011 // This might happen when we started draining but not yet actually 1012 // stopped the stream from the state thread. 1013 if (state == stream_state::DRAINING) { 1014 std::memset(audio_data, 0x0, num_frames * stm->out_frame_size); 1015 return AAUDIO_CALLBACK_RESULT_CONTINUE; 1016 } 1017 1018 compute_and_report_latency_metrics(stm); 1019 1020 long done_frames = cubeb_resampler_fill(stm->resampler, nullptr, nullptr, 1021 audio_data, num_frames); 1022 if (done_frames < 0 || done_frames > num_frames) { 1023 LOG("Error in data callback or resampler: %ld", done_frames); 1024 stm->state.store(stream_state::ERROR); 1025 stm->context->state.waiting.store(true); 1026 stm->context->state.cond.notify_one(); 1027 return AAUDIO_CALLBACK_RESULT_STOP; 1028 } 1029 1030 if (done_frames < num_frames) { 1031 stm->drain_target.store(WRAP(AAudioStream_getFramesWritten)(stm->ostream) + 1032 done_frames); 1033 stm->state.store(stream_state::DRAINING); 1034 stm->context->state.waiting.store(true); 1035 stm->context->state.cond.notify_one(); 1036 1037 char * begin = 1038 static_cast<char *>(audio_data) + done_frames * stm->out_frame_size; 1039 std::memset(begin, 0x0, (num_frames - done_frames) * stm->out_frame_size); 1040 } 1041 1042 apply_volume(stm, audio_data, done_frames); 1043 return AAUDIO_CALLBACK_RESULT_CONTINUE; 1044 } 1045 1046 static aaudio_data_callback_result_t 1047 aaudio_input_data_cb(AAudioStream * astream, void * user_data, 1048 void * audio_data, int32_t num_frames) 1049 { 1050 cubeb_stream * stm = (cubeb_stream *)user_data; 1051 AutoInCallback aic(stm); 1052 assert(stm->istream == astream); 1053 assert(!stm->ostream); 1054 assert(num_frames >= 0); 1055 1056 stream_state state = stm->state.load(); 1057 int istate = WRAP(AAudioStream_getState)(stm->istream); 1058 ALOGV("aaudio input data cb on stream %p: state %ld (%d), num_frames: %d", 1059 stm, state, istate, num_frames); 1060 1061 // all other states may happen since the callback might be called 1062 // from within requestStart 1063 assert(state != stream_state::SHUTDOWN); 1064 1065 // This might happen when we started draining but not yet actually 1066 // STOPPED the stream from the state thread. 1067 if (state == stream_state::DRAINING) { 1068 return AAUDIO_CALLBACK_RESULT_CONTINUE; 1069 } 1070 1071 compute_and_report_latency_metrics(stm); 1072 1073 long input_frame_count = num_frames; 1074 long done_frames = cubeb_resampler_fill(stm->resampler, audio_data, 1075 &input_frame_count, nullptr, 0); 1076 1077 if (done_frames < 0 || done_frames > num_frames) { 1078 LOG("Error in data callback or resampler: %ld", done_frames); 1079 stm->state.store(stream_state::ERROR); 1080 stm->context->state.waiting.store(true); 1081 stm->context->state.cond.notify_one(); 1082 return AAUDIO_CALLBACK_RESULT_STOP; 1083 } 1084 1085 if (done_frames < input_frame_count) { 1086 // we don't really drain an input stream, just have to 1087 // stop it from the state thread. That is signaled via the 1088 // DRAINING state. 1089 stm->state.store(stream_state::DRAINING); 1090 stm->context->state.waiting.store(true); 1091 stm->context->state.cond.notify_one(); 1092 } 1093 1094 return AAUDIO_CALLBACK_RESULT_CONTINUE; 1095 } 1096 1097 static void 1098 reinitialize_stream(cubeb_stream * stm) 1099 { 1100 // This cannot be done from within the error callback, bounce to another 1101 // thread. 1102 // In this situation, the lock is acquired for the entire duration of the 1103 // function, so that this reinitialization period is atomic. 1104 std::thread([stm] { 1105 lock_guard lock(stm->mutex); 1106 stream_state state = stm->state.load(); 1107 bool was_playing = state == stream_state::STARTED || 1108 state == stream_state::STARTING || 1109 state == stream_state::DRAINING; 1110 int err = aaudio_stream_stop_locked(stm, lock); 1111 // Error ignored. 1112 1113 // Get total number of written frames before destroying the stream. 1114 uint64_t total_frames = stm->pos_estimate.initial_position(); 1115 if (stm->ostream) { 1116 // For output-only and duplex, use the output stream. 1117 total_frames += WRAP(AAudioStream_getFramesWritten)(stm->ostream); 1118 } else if (stm->istream) { 1119 // Input-only, we can only use the input stream. 1120 total_frames += WRAP(AAudioStream_getFramesWritten)(stm->istream); 1121 } 1122 1123 aaudio_stream_destroy_locked(stm, lock); 1124 err = aaudio_stream_init_impl(stm, lock); 1125 1126 assert(stm->in_use.load()); 1127 1128 // Set the new initial position. 1129 stm->pos_estimate.reinit(total_frames); 1130 1131 if (err != CUBEB_OK) { 1132 aaudio_stream_destroy_locked(stm, lock); 1133 LOG("aaudio_stream_init_impl error while reiniting: %s", 1134 WRAP(AAudio_convertResultToText)(err)); 1135 stm->state.store(stream_state::ERROR); 1136 stm->context->state.waiting.store(true); 1137 stm->context->state.cond.notify_one(); 1138 return; 1139 } 1140 1141 if (was_playing) { 1142 err = aaudio_stream_start_locked(stm, lock); 1143 stm->drain_target.store(-1); 1144 if (err != CUBEB_OK) { 1145 aaudio_stream_destroy_locked(stm, lock); 1146 LOG("aaudio_stream_start error while reiniting: %s", 1147 WRAP(AAudio_convertResultToText)(err)); 1148 stm->state.store(stream_state::ERROR); 1149 stm->context->state.waiting.store(true); 1150 stm->context->state.cond.notify_one(); 1151 return; 1152 } 1153 } 1154 }).detach(); 1155 } 1156 1157 static void 1158 aaudio_error_cb(AAudioStream * astream, void * user_data, aaudio_result_t error) 1159 { 1160 cubeb_stream * stm = static_cast<cubeb_stream *>(user_data); 1161 assert(stm->ostream == astream || stm->istream == astream); 1162 1163 // Device change -- reinitialize on the new default device. 1164 if (error == AAUDIO_ERROR_DISCONNECTED || error == AAUDIO_ERROR_TIMEOUT) { 1165 LOG("Audio device change, reinitializing stream"); 1166 reinitialize_stream(stm); 1167 return; 1168 } 1169 1170 LOG("AAudio error callback: %s", WRAP(AAudio_convertResultToText)(error)); 1171 stm->state.store(stream_state::ERROR); 1172 stm->context->state.waiting.store(true); 1173 stm->context->state.cond.notify_one(); 1174 } 1175 1176 static int 1177 realize_stream(AAudioStreamBuilder * sb, const cubeb_stream_params * params, 1178 AAudioStream ** stream, unsigned * frame_size) 1179 { 1180 aaudio_result_t res; 1181 assert(params->rate); 1182 assert(params->channels); 1183 1184 WRAP(AAudioStreamBuilder_setSampleRate) 1185 (sb, static_cast<int32_t>(params->rate)); 1186 WRAP(AAudioStreamBuilder_setChannelCount) 1187 (sb, static_cast<int32_t>(params->channels)); 1188 1189 aaudio_format_t fmt; 1190 switch (params->format) { 1191 case CUBEB_SAMPLE_S16NE: 1192 fmt = AAUDIO_FORMAT_PCM_I16; 1193 *frame_size = sizeof(int16_t) * params->channels; 1194 break; 1195 case CUBEB_SAMPLE_FLOAT32NE: 1196 fmt = AAUDIO_FORMAT_PCM_FLOAT; 1197 *frame_size = sizeof(float) * params->channels; 1198 break; 1199 default: 1200 return CUBEB_ERROR_INVALID_FORMAT; 1201 } 1202 1203 WRAP(AAudioStreamBuilder_setFormat)(sb, fmt); 1204 res = WRAP(AAudioStreamBuilder_openStream)(sb, stream); 1205 if (res == AAUDIO_ERROR_INVALID_FORMAT) { 1206 LOG("AAudio device doesn't support output format %d", fmt); 1207 return CUBEB_ERROR_INVALID_FORMAT; 1208 } 1209 1210 if (params->rate && res == AAUDIO_ERROR_INVALID_RATE) { 1211 // The requested rate is not supported. 1212 // Just try again with default rate, we create a resampler anyways 1213 WRAP(AAudioStreamBuilder_setSampleRate)(sb, AAUDIO_UNSPECIFIED); 1214 res = WRAP(AAudioStreamBuilder_openStream)(sb, stream); 1215 LOG("Requested rate of %u is not supported, inserting resampler", 1216 params->rate); 1217 } 1218 1219 // When the app has no permission to record audio 1220 // (android.permission.RECORD_AUDIO) but requested and input stream, this will 1221 // return INVALID_ARGUMENT. 1222 if (res != AAUDIO_OK) { 1223 LOG("AAudioStreamBuilder_openStream: %s", 1224 WRAP(AAudio_convertResultToText)(res)); 1225 return CUBEB_ERROR; 1226 } 1227 1228 return CUBEB_OK; 1229 } 1230 1231 static void 1232 aaudio_stream_destroy(cubeb_stream * stm) 1233 { 1234 lock_guard lock(stm->mutex); 1235 stm->in_use.store(false); 1236 aaudio_stream_destroy_locked(stm, lock); 1237 } 1238 1239 static void 1240 aaudio_stream_destroy_locked(cubeb_stream * stm, lock_guard<mutex> & lock) 1241 { 1242 assert(stm->state == stream_state::STOPPED || 1243 stm->state == stream_state::STOPPING || 1244 stm->state == stream_state::INIT || 1245 stm->state == stream_state::DRAINING || 1246 stm->state == stream_state::ERROR || 1247 stm->state == stream_state::SHUTDOWN); 1248 1249 aaudio_result_t res; 1250 1251 // No callbacks are triggered anymore when requestStop returns. 1252 // That is important as we otherwise might read from a closed istream 1253 // for a duplex stream. 1254 if (stm->ostream) { 1255 if (stm->state != stream_state::STOPPED && 1256 stm->state != stream_state::STOPPING && 1257 stm->state != stream_state::SHUTDOWN) { 1258 res = WRAP(AAudioStream_requestStop)(stm->ostream); 1259 if (res != AAUDIO_OK) { 1260 LOG("AAudioStreamBuilder_requestStop: %s", 1261 WRAP(AAudio_convertResultToText)(res)); 1262 } 1263 } 1264 1265 WRAP(AAudioStream_close)(stm->ostream); 1266 stm->ostream = nullptr; 1267 } 1268 1269 if (stm->istream) { 1270 if (stm->state != stream_state::STOPPED && 1271 stm->state != stream_state::STOPPING && 1272 stm->state != stream_state::SHUTDOWN) { 1273 res = WRAP(AAudioStream_requestStop)(stm->istream); 1274 if (res != AAUDIO_OK) { 1275 LOG("AAudioStreamBuilder_requestStop: %s", 1276 WRAP(AAudio_convertResultToText)(res)); 1277 } 1278 } 1279 1280 WRAP(AAudioStream_close)(stm->istream); 1281 stm->istream = nullptr; 1282 } 1283 1284 stm->timing_info.invalidate(); 1285 stm->previous_clock = 0; 1286 stm->pos_estimate = {}; 1287 1288 if (stm->resampler) { 1289 cubeb_resampler_destroy(stm->resampler); 1290 stm->resampler = nullptr; 1291 } 1292 1293 stm->in_buf = {}; 1294 stm->in_frame_size = {}; 1295 stm->out_format = {}; 1296 stm->out_channels = {}; 1297 stm->out_frame_size = {}; 1298 1299 stm->state.store(stream_state::INIT); 1300 } 1301 1302 static int 1303 aaudio_stream_init_impl(cubeb_stream * stm, lock_guard<mutex> & lock) 1304 { 1305 assert(stm->state.load() == stream_state::INIT); 1306 1307 cubeb_async_log_reset_threads(); 1308 1309 aaudio_result_t res; 1310 AAudioStreamBuilder * sb; 1311 res = WRAP(AAudio_createStreamBuilder)(&sb); 1312 if (res != AAUDIO_OK) { 1313 LOG("AAudio_createStreamBuilder: %s", 1314 WRAP(AAudio_convertResultToText)(res)); 1315 return CUBEB_ERROR; 1316 } 1317 1318 // make sure the builder is always destroyed 1319 struct StreamBuilderDestructor { 1320 void operator()(AAudioStreamBuilder * sb) 1321 { 1322 WRAP(AAudioStreamBuilder_delete)(sb); 1323 } 1324 }; 1325 1326 std::unique_ptr<AAudioStreamBuilder, StreamBuilderDestructor> sbPtr(sb); 1327 1328 WRAP(AAudioStreamBuilder_setErrorCallback)(sb, aaudio_error_cb, stm); 1329 // Capacity should be at least twice the frames-per-callback to allow double 1330 // buffering. 1331 WRAP(AAudioStreamBuilder_setBufferCapacityInFrames) 1332 (sb, static_cast<int32_t>(2 * stm->latency_frames)); 1333 1334 AAudioStream_dataCallback in_data_callback{}; 1335 AAudioStream_dataCallback out_data_callback{}; 1336 if (stm->output_stream_params && stm->input_stream_params) { 1337 out_data_callback = aaudio_duplex_data_cb; 1338 in_data_callback = nullptr; 1339 } else if (stm->input_stream_params) { 1340 in_data_callback = aaudio_input_data_cb; 1341 } else if (stm->output_stream_params) { 1342 out_data_callback = aaudio_output_data_cb; 1343 } else { 1344 LOG("Tried to open stream without input or output parameters"); 1345 return CUBEB_ERROR; 1346 } 1347 1348 #ifdef CUBEB_AAUDIO_EXCLUSIVE_STREAM 1349 LOG("AAudio setting exclusive share mode for stream"); 1350 WRAP(AAudioStreamBuilder_setSharingMode)(sb, AAUDIO_SHARING_MODE_EXCLUSIVE); 1351 #endif 1352 1353 if (stm->latency_frames <= POWERSAVE_LATENCY_FRAMES_THRESHOLD) { 1354 LOG("AAudio setting low latency mode for stream"); 1355 WRAP(AAudioStreamBuilder_setPerformanceMode) 1356 (sb, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY); 1357 } else { 1358 LOG("AAudio setting power saving mode for stream"); 1359 WRAP(AAudioStreamBuilder_setPerformanceMode) 1360 (sb, AAUDIO_PERFORMANCE_MODE_POWER_SAVING); 1361 } 1362 1363 unsigned frame_size; 1364 1365 // initialize streams 1366 // output 1367 cubeb_stream_params out_params; 1368 if (stm->output_stream_params) { 1369 int output_preset = stm->voice_output ? AAUDIO_USAGE_VOICE_COMMUNICATION 1370 : AAUDIO_USAGE_MEDIA; 1371 WRAP(AAudioStreamBuilder_setUsage)(sb, output_preset); 1372 WRAP(AAudioStreamBuilder_setDirection)(sb, AAUDIO_DIRECTION_OUTPUT); 1373 WRAP(AAudioStreamBuilder_setDataCallback)(sb, out_data_callback, stm); 1374 assert(stm->latency_frames < std::numeric_limits<int32_t>::max()); 1375 LOG("Frames per callback set to %d for output", stm->latency_frames); 1376 WRAP(AAudioStreamBuilder_setFramesPerDataCallback) 1377 (sb, static_cast<int32_t>(stm->latency_frames)); 1378 1379 int res_err = realize_stream(sb, stm->output_stream_params.get(), 1380 &stm->ostream, &frame_size); 1381 if (res_err) { 1382 return res_err; 1383 } 1384 1385 int rate = WRAP(AAudioStream_getSampleRate)(stm->ostream); 1386 int32_t output_burst_frames = 1387 WRAP(AAudioStream_getFramesPerBurst)(stm->ostream); 1388 // 3 times the burst size seems fairly robust, use it as minimum. 1389 int32_t output_buffer_size_frames = 3 * output_burst_frames; 1390 if (stm->latency_frames > POWERSAVE_LATENCY_FRAMES_THRESHOLD) { 1391 // FramesPerBurst is large in power saving mode, reduce the buffer size to 1392 // 2 bursts. 1393 output_buffer_size_frames = 2 * output_burst_frames; 1394 } 1395 // Make output buffer size a function of the requested latency so clients 1396 // can adapt to their use case. 1397 output_buffer_size_frames = 1398 std::max(output_buffer_size_frames, 1399 static_cast<int32_t>(stm->latency_frames / 2)); 1400 int32_t output_final_buffer_size_frames = 1401 WRAP(AAudioStream_setBufferSizeInFrames)(stm->ostream, 1402 output_buffer_size_frames); 1403 1404 LOG("AAudio output stream sharing mode: %d", 1405 WRAP(AAudioStream_getSharingMode)(stm->ostream)); 1406 LOG("AAudio output stream performance mode: %d", 1407 WRAP(AAudioStream_getPerformanceMode)(stm->ostream)); 1408 LOG("AAudio output stream buffer capacity: %d", 1409 WRAP(AAudioStream_getBufferCapacityInFrames)(stm->ostream)); 1410 LOG("AAudio output stream buffer size: %d", 1411 output_final_buffer_size_frames); 1412 LOG("AAudio output stream burst size: %d", output_burst_frames); 1413 LOG("AAudio output stream sample-rate: %d", rate); 1414 1415 stm->sample_rate = stm->output_stream_params->rate; 1416 out_params = *stm->output_stream_params; 1417 out_params.rate = rate; 1418 1419 stm->out_channels = stm->output_stream_params->channels; 1420 stm->out_format = stm->output_stream_params->format; 1421 stm->out_frame_size = frame_size; 1422 stm->volume.store(1.f); 1423 } 1424 1425 // input 1426 cubeb_stream_params in_params; 1427 if (stm->input_stream_params) { 1428 // Match what the OpenSL backend does for now, we could use UNPROCESSED and 1429 // VOICE_COMMUNICATION here, but we'd need to make it clear that 1430 // application-level AEC and other voice processing should be disabled 1431 // there. 1432 int input_preset = stm->voice_input ? AAUDIO_INPUT_PRESET_VOICE_RECOGNITION 1433 : AAUDIO_INPUT_PRESET_CAMCORDER; 1434 WRAP(AAudioStreamBuilder_setInputPreset)(sb, input_preset); 1435 WRAP(AAudioStreamBuilder_setDirection)(sb, AAUDIO_DIRECTION_INPUT); 1436 WRAP(AAudioStreamBuilder_setDataCallback)(sb, in_data_callback, stm); 1437 assert(stm->latency_frames < std::numeric_limits<int32_t>::max()); 1438 LOG("Frames per callback set to %d for input", stm->latency_frames); 1439 WRAP(AAudioStreamBuilder_setFramesPerDataCallback) 1440 (sb, static_cast<int32_t>(stm->latency_frames)); 1441 int res_err = realize_stream(sb, stm->input_stream_params.get(), 1442 &stm->istream, &frame_size); 1443 if (res_err) { 1444 return res_err; 1445 } 1446 1447 int rate = WRAP(AAudioStream_getSampleRate)(stm->istream); 1448 LOG("AAudio input stream burst size: %d", 1449 WRAP(AAudioStream_getFramesPerBurst)(stm->istream)); 1450 LOG("AAudio input stream sharing mode: %d", 1451 WRAP(AAudioStream_getSharingMode)(stm->istream)); 1452 LOG("AAudio input stream performance mode: %d", 1453 WRAP(AAudioStream_getPerformanceMode)(stm->istream)); 1454 LOG("AAudio input stream buffer capacity: %d", 1455 WRAP(AAudioStream_getBufferCapacityInFrames)(stm->istream)); 1456 LOG("AAudio input stream buffer size: %d", 1457 WRAP(AAudioStream_getBufferSizeInFrames)(stm->istream)); 1458 LOG("AAudio input stream sample-rate: %d", rate); 1459 1460 stm->in_buf.resize(stm->latency_frames * frame_size); 1461 assert(!stm->sample_rate || 1462 stm->sample_rate == stm->input_stream_params->rate); 1463 1464 stm->sample_rate = stm->input_stream_params->rate; 1465 in_params = *stm->input_stream_params; 1466 in_params.rate = rate; 1467 stm->in_frame_size = frame_size; 1468 } 1469 1470 // initialize resampler 1471 stm->resampler = cubeb_resampler_create( 1472 stm, stm->input_stream_params ? &in_params : nullptr, 1473 stm->output_stream_params ? &out_params : nullptr, stm->sample_rate, 1474 stm->data_callback, stm->user_ptr, CUBEB_RESAMPLER_QUALITY_DEFAULT, 1475 CUBEB_RESAMPLER_RECLOCK_NONE); 1476 1477 if (!stm->resampler) { 1478 LOG("Failed to create resampler"); 1479 return CUBEB_ERROR; 1480 } 1481 1482 // the stream isn't started initially. We don't need to differentiate 1483 // between a stream that was just initialized and one that played 1484 // already but was stopped. 1485 stm->state.store(stream_state::STOPPED); 1486 LOG("Cubeb stream (%p) INIT success", (void *)stm); 1487 return CUBEB_OK; 1488 } 1489 1490 static int 1491 aaudio_stream_init(cubeb * ctx, cubeb_stream ** stream, 1492 char const * /* stream_name */, cubeb_devid input_device, 1493 cubeb_stream_params * input_stream_params, 1494 cubeb_devid output_device, 1495 cubeb_stream_params * output_stream_params, 1496 unsigned int latency_frames, 1497 cubeb_data_callback data_callback, 1498 cubeb_state_callback state_callback, void * user_ptr) 1499 { 1500 assert(!input_device); 1501 assert(!output_device); 1502 1503 // atomically find a free stream. 1504 cubeb_stream * stm = nullptr; 1505 unique_lock<mutex> lock; 1506 for (auto & stream : ctx->streams) { 1507 // This check is only an optimization, we don't strictly need it 1508 // since we check again after locking the mutex. 1509 if (stream.in_use.load()) { 1510 continue; 1511 } 1512 1513 // if this fails, another thread initialized this stream 1514 // between our check of in_use and this. 1515 lock = unique_lock(stream.mutex, std::try_to_lock); 1516 if (!lock.owns_lock()) { 1517 continue; 1518 } 1519 1520 if (stream.in_use.load()) { 1521 lock = {}; 1522 continue; 1523 } 1524 1525 stm = &stream; 1526 break; 1527 } 1528 1529 if (!stm) { 1530 LOG("Error: maximum number of streams reached"); 1531 return CUBEB_ERROR; 1532 } 1533 1534 stm->in_use.store(true); 1535 stm->context = ctx; 1536 stm->user_ptr = user_ptr; 1537 stm->data_callback = data_callback; 1538 stm->state_callback = state_callback; 1539 stm->voice_input = input_stream_params && 1540 !!(input_stream_params->prefs & CUBEB_STREAM_PREF_VOICE); 1541 stm->voice_output = output_stream_params && 1542 !!(output_stream_params->prefs & CUBEB_STREAM_PREF_VOICE); 1543 stm->previous_clock = 0; 1544 stm->latency_frames = latency_frames; 1545 if (output_stream_params) { 1546 stm->output_stream_params = std::make_unique<cubeb_stream_params>(); 1547 *(stm->output_stream_params) = *output_stream_params; 1548 } else { 1549 stm->output_stream_params = nullptr; 1550 } 1551 if (input_stream_params) { 1552 stm->input_stream_params = std::make_unique<cubeb_stream_params>(); 1553 *(stm->input_stream_params) = *input_stream_params; 1554 } else { 1555 stm->input_stream_params = nullptr; 1556 } 1557 1558 LOG("cubeb stream prefs: voice_input: %s voice_output: %s", 1559 stm->voice_input ? "true" : "false", 1560 stm->voice_output ? "true" : "false"); 1561 1562 // This is ok: the thread is marked as being in use 1563 lock.unlock(); 1564 int err; 1565 1566 { 1567 lock_guard guard(stm->mutex); 1568 err = aaudio_stream_init_impl(stm, guard); 1569 } 1570 1571 if (err != CUBEB_OK) { 1572 aaudio_stream_destroy(stm); 1573 return err; 1574 } 1575 1576 *stream = stm; 1577 return CUBEB_OK; 1578 } 1579 1580 static int 1581 aaudio_stream_start(cubeb_stream * stm) 1582 { 1583 lock_guard lock(stm->mutex); 1584 return aaudio_stream_start_locked(stm, lock); 1585 } 1586 1587 static int 1588 aaudio_stream_start_locked(cubeb_stream * stm, lock_guard<mutex> & lock) 1589 { 1590 assert(stm && stm->in_use.load()); 1591 stream_state state = stm->state.load(); 1592 int istate = stm->istream ? WRAP(AAudioStream_getState)(stm->istream) : 0; 1593 int ostate = stm->ostream ? WRAP(AAudioStream_getState)(stm->ostream) : 0; 1594 LOGV("STARTING stream %p: %d (%d %d)", (void *)stm, state, istate, ostate); 1595 1596 switch (state) { 1597 case stream_state::STARTED: 1598 case stream_state::STARTING: 1599 LOG("cubeb stream %p already STARTING/STARTED", (void *)stm); 1600 return CUBEB_OK; 1601 case stream_state::ERROR: 1602 case stream_state::SHUTDOWN: 1603 return CUBEB_ERROR; 1604 case stream_state::INIT: 1605 assert(false && "Invalid stream"); 1606 return CUBEB_ERROR; 1607 case stream_state::STOPPED: 1608 case stream_state::STOPPING: 1609 case stream_state::DRAINING: 1610 break; 1611 } 1612 1613 aaudio_result_t res; 1614 1615 // Important to start istream before ostream. 1616 // As soon as we start ostream, the callbacks might be triggered an we 1617 // might read from istream (on duplex). If istream wasn't started yet 1618 // this is a problem. 1619 if (stm->istream) { 1620 res = WRAP(AAudioStream_requestStart)(stm->istream); 1621 if (res != AAUDIO_OK) { 1622 LOG("AAudioStream_requestStart (istream): %s", 1623 WRAP(AAudio_convertResultToText)(res)); 1624 stm->state.store(stream_state::ERROR); 1625 return CUBEB_ERROR; 1626 } 1627 } 1628 1629 if (stm->ostream) { 1630 res = WRAP(AAudioStream_requestStart)(stm->ostream); 1631 if (res != AAUDIO_OK) { 1632 LOG("AAudioStream_requestStart (ostream): %s", 1633 WRAP(AAudio_convertResultToText)(res)); 1634 stm->state.store(stream_state::ERROR); 1635 return CUBEB_ERROR; 1636 } 1637 } 1638 1639 int ret = CUBEB_OK; 1640 bool success; 1641 1642 while (!(success = stm->state.compare_exchange_strong( 1643 state, stream_state::STARTING))) { 1644 // we land here only if the state has changed in the meantime 1645 switch (state) { 1646 // If an error ocurred in the meantime, we can't change that. 1647 // The stream will be stopped when shut down. 1648 case stream_state::ERROR: 1649 ret = CUBEB_ERROR; 1650 break; 1651 // The only situation in which the state could have switched to draining 1652 // is if the callback was already fired and requested draining. Don't 1653 // overwrite that. It's not an error either though. 1654 case stream_state::DRAINING: 1655 break; 1656 1657 // If the state switched [DRAINING -> STOPPING] or [DRAINING/STOPPING -> 1658 // STOPPED] in the meantime, we can simply overwrite that since we 1659 // restarted the stream. 1660 case stream_state::STOPPING: 1661 case stream_state::STOPPED: 1662 continue; 1663 1664 // There is no situation in which the state could have been valid before 1665 // but now in shutdown mode, since we hold the streams mutex. 1666 // There is also no way that it switched *into* STARTING or 1667 // STARTED mode. 1668 default: 1669 assert(false && "Invalid state change"); 1670 ret = CUBEB_ERROR; 1671 break; 1672 } 1673 1674 break; 1675 } 1676 1677 if (success) { 1678 stm->pos_estimate.start(now_ns()); 1679 } 1680 1681 // Wake the state thread to trigger STARTED/ERROR state callback. 1682 stm->context->state.waiting.store(true); 1683 stm->context->state.cond.notify_one(); 1684 1685 return ret; 1686 } 1687 1688 static int 1689 aaudio_stream_stop(cubeb_stream * stm) 1690 { 1691 assert(stm && stm->in_use.load()); 1692 lock_guard lock(stm->mutex); 1693 return aaudio_stream_stop_locked(stm, lock); 1694 } 1695 1696 static int 1697 aaudio_stream_stop_locked(cubeb_stream * stm, lock_guard<mutex> & lock) 1698 { 1699 assert(stm && stm->in_use.load()); 1700 1701 stream_state state = stm->state.load(); 1702 aaudio_stream_state_t istate = stm->istream 1703 ? WRAP(AAudioStream_getState)(stm->istream) 1704 : AAUDIO_STREAM_STATE_UNINITIALIZED; 1705 aaudio_stream_state_t ostate = stm->ostream 1706 ? WRAP(AAudioStream_getState)(stm->ostream) 1707 : AAUDIO_STREAM_STATE_UNINITIALIZED; 1708 LOG("STOPPING stream %p: %d (in: %s out: %s)", (void *)stm, state, 1709 WRAP(AAudio_convertStreamStateToText)(istate), 1710 WRAP(AAudio_convertStreamStateToText)(ostate)); 1711 1712 switch (state) { 1713 case stream_state::STOPPED: 1714 case stream_state::STOPPING: 1715 case stream_state::DRAINING: 1716 LOG("cubeb stream %p already STOPPING/STOPPED", (void *)stm); 1717 return CUBEB_OK; 1718 case stream_state::ERROR: 1719 case stream_state::SHUTDOWN: 1720 return CUBEB_ERROR; 1721 case stream_state::INIT: 1722 assert(false && "Invalid stream"); 1723 return CUBEB_ERROR; 1724 case stream_state::STARTED: 1725 case stream_state::STARTING: 1726 break; 1727 } 1728 1729 aaudio_result_t res; 1730 1731 // No callbacks are triggered anymore when requestPause returns. 1732 // That is important as we otherwise might read from a closed istream 1733 // for a duplex stream. 1734 // Therefor it is important to close ostream first. 1735 if (stm->ostream) { 1736 // Could use pause + flush here as well, the public cubeb interface 1737 // doesn't state behavior. 1738 res = WRAP(AAudioStream_requestPause)(stm->ostream); 1739 if (res != AAUDIO_OK) { 1740 LOG("AAudioStream_requestPause (ostream): %s", 1741 WRAP(AAudio_convertResultToText)(res)); 1742 stm->state.store(stream_state::ERROR); 1743 return CUBEB_ERROR; 1744 } 1745 } 1746 1747 if (stm->istream) { 1748 res = WRAP(AAudioStream_requestPause)(stm->istream); 1749 if (res != AAUDIO_OK) { 1750 LOG("AAudioStream_requestPause (istream): %s", 1751 WRAP(AAudio_convertResultToText)(res)); 1752 stm->state.store(stream_state::ERROR); 1753 return CUBEB_ERROR; 1754 } 1755 } 1756 1757 int ret = CUBEB_OK; 1758 bool success; 1759 while (!(success = atomic_compare_exchange_strong(&stm->state, &state, 1760 stream_state::STOPPING))) { 1761 // we land here only if the state has changed in the meantime 1762 switch (state) { 1763 // If an error ocurred in the meantime, we can't change that. 1764 // The stream will be STOPPED when shut down. 1765 case stream_state::ERROR: 1766 ret = CUBEB_ERROR; 1767 break; 1768 // If it was switched to DRAINING in the meantime, it was or 1769 // will be STOPPED soon anyways. We don't interfere with 1770 // the DRAINING process, no matter in which state. 1771 // Not an error 1772 case stream_state::DRAINING: 1773 case stream_state::STOPPING: 1774 case stream_state::STOPPED: 1775 break; 1776 1777 // If the state switched from STARTING to STARTED in the meantime 1778 // we can simply overwrite that since we just STOPPED it. 1779 case stream_state::STARTED: 1780 continue; 1781 1782 // There is no situation in which the state could have been valid before 1783 // but now in shutdown mode, since we hold the streams mutex. 1784 // There is also no way that it switched *into* STARTING mode. 1785 default: 1786 assert(false && "Invalid state change"); 1787 ret = CUBEB_ERROR; 1788 break; 1789 } 1790 1791 break; 1792 } 1793 1794 if (success) { 1795 stm->pos_estimate.stop(now_ns()); 1796 stm->context->state.waiting.store(true); 1797 stm->context->state.cond.notify_one(); 1798 } 1799 1800 return ret; 1801 } 1802 1803 static int 1804 aaudio_stream_get_position(cubeb_stream * stm, uint64_t * position) 1805 { 1806 assert(stm && stm->in_use.load()); 1807 lock_guard lock(stm->mutex); 1808 1809 stream_state state = stm->state.load(); 1810 uint64_t init_position = stm->pos_estimate.initial_position(); 1811 AAudioStream * stream = stm->ostream ? stm->ostream : stm->istream; 1812 switch (state) { 1813 case stream_state::ERROR: 1814 case stream_state::SHUTDOWN: 1815 return CUBEB_ERROR; 1816 case stream_state::DRAINING: 1817 case stream_state::STOPPED: 1818 case stream_state::STOPPING: 1819 // getTimestamp is only valid when the stream is playing. 1820 // Simply return the number of frames passed to aaudio 1821 *position = init_position + WRAP(AAudioStream_getFramesRead)(stream); 1822 if (*position < stm->previous_clock) { 1823 *position = stm->previous_clock; 1824 } else { 1825 stm->previous_clock = *position; 1826 } 1827 return CUBEB_OK; 1828 case stream_state::INIT: 1829 assert(false && "Invalid stream"); 1830 return CUBEB_ERROR; 1831 case stream_state::STARTED: 1832 case stream_state::STARTING: 1833 break; 1834 } 1835 1836 // No callback yet, the stream hasn't really started. 1837 if (stm->previous_clock == 0 && !stm->timing_info.updated()) { 1838 LOG("Not timing info yet"); 1839 *position = init_position; 1840 return CUBEB_OK; 1841 } 1842 1843 AAudioTimingInfo info = stm->timing_info.read(); 1844 LOGV("AAudioTimingInfo idx:%lu tstamp:%lu latency:%u", 1845 info.output_frame_index, info.tstamp, info.output_latency); 1846 // Interpolate client side since the last callback. 1847 uint64_t interpolation = 1848 (stm->sample_rate * 1849 stm->pos_estimate.elapsed_time_since_callback(now_ns(), info.tstamp) / 1850 NS_PER_S); 1851 *position = init_position + info.output_frame_index + interpolation - 1852 info.output_latency; 1853 if (*position < stm->previous_clock) { 1854 *position = stm->previous_clock; 1855 } else { 1856 stm->previous_clock = *position; 1857 } 1858 1859 LOG("aaudio_stream_get_position: %" PRIu64 " frames", *position); 1860 1861 return CUBEB_OK; 1862 } 1863 1864 static int 1865 aaudio_stream_get_latency(cubeb_stream * stm, uint32_t * latency) 1866 { 1867 if (!stm->ostream) { 1868 LOG("error: aaudio_stream_get_latency on input-only stream"); 1869 return CUBEB_ERROR; 1870 } 1871 1872 if (!stm->latency_metrics_available) { 1873 LOG("Not timing info yet (output)"); 1874 return CUBEB_OK; 1875 } 1876 1877 AAudioTimingInfo info = stm->timing_info.read(); 1878 1879 *latency = info.output_latency; 1880 LOG("aaudio_stream_get_latency, %u frames", *latency); 1881 1882 return CUBEB_OK; 1883 } 1884 1885 static int 1886 aaudio_stream_get_input_latency(cubeb_stream * stm, uint32_t * latency) 1887 { 1888 if (!stm->istream) { 1889 LOG("error: aaudio_stream_get_input_latency on an output-only stream"); 1890 return CUBEB_ERROR; 1891 } 1892 1893 if (!stm->latency_metrics_available) { 1894 LOG("Not timing info yet (input)"); 1895 return CUBEB_OK; 1896 } 1897 1898 AAudioTimingInfo info = stm->timing_info.read(); 1899 1900 *latency = info.input_latency; 1901 LOG("aaudio_stream_get_latency, %u frames", *latency); 1902 1903 return CUBEB_OK; 1904 } 1905 1906 static int 1907 aaudio_stream_set_volume(cubeb_stream * stm, float volume) 1908 { 1909 assert(stm && stm->in_use.load() && stm->ostream); 1910 stm->volume.store(volume); 1911 return CUBEB_OK; 1912 } 1913 1914 aaudio_data_callback_result_t 1915 dummy_callback(AAudioStream * stream, void * userData, void * audioData, 1916 int32_t numFrames) 1917 { 1918 return AAUDIO_CALLBACK_RESULT_STOP; 1919 } 1920 1921 // Returns a dummy stream with all default settings 1922 static AAudioStream * 1923 init_dummy_stream() 1924 { 1925 AAudioStreamBuilder * streamBuilder; 1926 aaudio_result_t res; 1927 res = WRAP(AAudio_createStreamBuilder)(&streamBuilder); 1928 if (res != AAUDIO_OK) { 1929 LOG("init_dummy_stream: AAudio_createStreamBuilder: %s", 1930 WRAP(AAudio_convertResultToText)(res)); 1931 return nullptr; 1932 } 1933 WRAP(AAudioStreamBuilder_setDataCallback) 1934 (streamBuilder, dummy_callback, nullptr); 1935 WRAP(AAudioStreamBuilder_setPerformanceMode) 1936 (streamBuilder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY); 1937 1938 AAudioStream * stream; 1939 res = WRAP(AAudioStreamBuilder_openStream)(streamBuilder, &stream); 1940 if (res != AAUDIO_OK) { 1941 LOG("init_dummy_stream: AAudioStreamBuilder_openStream %s", 1942 WRAP(AAudio_convertResultToText)(res)); 1943 return nullptr; 1944 } 1945 WRAP(AAudioStreamBuilder_delete)(streamBuilder); 1946 1947 return stream; 1948 } 1949 1950 static void 1951 destroy_dummy_stream(AAudioStream * stream) 1952 { 1953 WRAP(AAudioStream_close)(stream); 1954 } 1955 1956 static int 1957 aaudio_get_min_latency(cubeb * ctx, cubeb_stream_params params, 1958 uint32_t * latency_frames) 1959 { 1960 AAudioStream * stream = init_dummy_stream(); 1961 1962 if (!stream) { 1963 return CUBEB_ERROR; 1964 } 1965 1966 // https://android.googlesource.com/platform/compatibility/cdd/+/refs/heads/master/5_multimedia/5_6_audio-latency.md 1967 *latency_frames = WRAP(AAudioStream_getFramesPerBurst)(stream); 1968 1969 LOG("aaudio_get_min_latency: %u frames", *latency_frames); 1970 1971 destroy_dummy_stream(stream); 1972 1973 return CUBEB_OK; 1974 } 1975 1976 int 1977 aaudio_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate) 1978 { 1979 AAudioStream * stream = init_dummy_stream(); 1980 1981 if (!stream) { 1982 return CUBEB_ERROR; 1983 } 1984 1985 *rate = WRAP(AAudioStream_getSampleRate)(stream); 1986 1987 LOG("aaudio_get_preferred_sample_rate %uHz", *rate); 1988 1989 destroy_dummy_stream(stream); 1990 1991 return CUBEB_OK; 1992 } 1993 1994 extern "C" int 1995 aaudio_init(cubeb ** context, char const * context_name); 1996 1997 const static struct cubeb_ops aaudio_ops = { 1998 /*.init =*/aaudio_init, 1999 /*.get_backend_id =*/aaudio_get_backend_id, 2000 /*.get_max_channel_count =*/aaudio_get_max_channel_count, 2001 /* .get_min_latency =*/aaudio_get_min_latency, 2002 /*.get_preferred_sample_rate =*/aaudio_get_preferred_sample_rate, 2003 /*.get_supported_input_processing_params =*/nullptr, 2004 /*.enumerate_devices =*/nullptr, 2005 /*.device_collection_destroy =*/nullptr, 2006 /*.destroy =*/aaudio_destroy, 2007 /*.stream_init =*/aaudio_stream_init, 2008 /*.stream_destroy =*/aaudio_stream_destroy, 2009 /*.stream_start =*/aaudio_stream_start, 2010 /*.stream_stop =*/aaudio_stream_stop, 2011 /*.stream_get_position =*/aaudio_stream_get_position, 2012 /*.stream_get_latency =*/aaudio_stream_get_latency, 2013 /*.stream_get_input_latency =*/aaudio_stream_get_input_latency, 2014 /*.stream_set_volume =*/aaudio_stream_set_volume, 2015 /*.stream_set_name =*/nullptr, 2016 /*.stream_get_current_device =*/nullptr, 2017 /*.stream_set_input_mute =*/nullptr, 2018 /*.stream_set_input_processing_params =*/nullptr, 2019 /*.stream_device_destroy =*/nullptr, 2020 /*.stream_register_device_changed_callback =*/nullptr, 2021 /*.register_device_collection_changed =*/nullptr}; 2022 2023 extern "C" /*static*/ int 2024 aaudio_init(cubeb ** context, char const * /* context_name */) 2025 { 2026 if (android_get_device_api_level() <= 30) { 2027 return CUBEB_ERROR; 2028 } 2029 #ifndef DISABLE_LIBAAUDIO_DLOPEN 2030 if (!AAudioLibrary::get().load()) { 2031 return CUBEB_ERROR; 2032 } 2033 #endif 2034 2035 cubeb * ctx = new cubeb; 2036 ctx->ops = &aaudio_ops; 2037 2038 ctx->state.thread = std::thread(state_thread, ctx); 2039 2040 // NOTE: using platform-specific APIs we could set the priority of the 2041 // notifier thread lower than the priority of the state thread. 2042 // This way, it's more likely that the state thread will be woken up 2043 // by the condition variable signal when both are currently waiting 2044 ctx->state.notifier = std::thread(notifier_thread, ctx); 2045 2046 *context = ctx; 2047 return CUBEB_OK; 2048 }