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 <aaudio/AAudio.h>
13 #include <atomic>
14 #include <cassert>
15 #include <chrono>
16 #include <condition_variable>
17 #include <cstring>
18 #include <dlfcn.h>
19 #include <memory>
20 #include <mutex>
21 #include <thread>
22 #include <time.h>
23
24 #ifdef DISABLE_LIBAAUDIO_DLOPEN
25 #define WRAP(x) x
26 #else
27 #define WRAP(x) (*cubeb_##x)
28 #define LIBAAUDIO_API_VISIT(X) \
29 X(AAudio_convertResultToText) \
30 X(AAudio_convertStreamStateToText) \
31 X(AAudio_createStreamBuilder) \
32 X(AAudioStreamBuilder_openStream) \
33 X(AAudioStreamBuilder_setChannelCount) \
34 X(AAudioStreamBuilder_setBufferCapacityInFrames) \
35 X(AAudioStreamBuilder_setDirection) \
36 X(AAudioStreamBuilder_setFormat) \
37 X(AAudioStreamBuilder_setSharingMode) \
38 X(AAudioStreamBuilder_setPerformanceMode) \
39 X(AAudioStreamBuilder_setSampleRate) \
40 X(AAudioStreamBuilder_delete) \
41 X(AAudioStreamBuilder_setDataCallback) \
42 X(AAudioStreamBuilder_setErrorCallback) \
43 X(AAudioStream_close) \
44 X(AAudioStream_read) \
45 X(AAudioStream_requestStart) \
46 X(AAudioStream_requestPause) \
47 X(AAudioStream_setBufferSizeInFrames) \
48 X(AAudioStream_getTimestamp) \
49 X(AAudioStream_requestFlush) \
50 X(AAudioStream_requestStop) \
51 X(AAudioStream_getPerformanceMode) \
52 X(AAudioStream_getSharingMode) \
53 X(AAudioStream_getBufferSizeInFrames) \
54 X(AAudioStream_getBufferCapacityInFrames) \
55 X(AAudioStream_getSampleRate) \
56 X(AAudioStream_waitForStateChange) \
57 X(AAudioStream_getFramesRead) \
58 X(AAudioStream_getState) \
59 X(AAudioStream_getFramesWritten) \
60 X(AAudioStream_getFramesPerBurst) \
61 X(AAudioStreamBuilder_setInputPreset) \
62 X(AAudioStreamBuilder_setUsage)
63
64 // not needed or added later on
65 // X(AAudioStreamBuilder_setFramesPerDataCallback) \
66 // X(AAudioStreamBuilder_setDeviceId) \
67 // X(AAudioStreamBuilder_setSamplesPerFrame) \
68 // X(AAudioStream_getSamplesPerFrame) \
69 // X(AAudioStream_getDeviceId) \
70 // X(AAudioStream_write) \
71 // X(AAudioStream_getChannelCount) \
72 // X(AAudioStream_getFormat) \
73 // X(AAudioStream_getXRunCount) \
74 // X(AAudioStream_isMMapUsed) \
75 // X(AAudioStreamBuilder_setContentType) \
76 // X(AAudioStreamBuilder_setSessionId) \
77 // X(AAudioStream_getUsage) \
78 // X(AAudioStream_getContentType) \
79 // X(AAudioStream_getInputPreset) \
80 // X(AAudioStream_getSessionId) \
81 // END: not needed or added later on
82
83 #define MAKE_TYPEDEF(x) static decltype(x) * cubeb_##x;
84 LIBAAUDIO_API_VISIT(MAKE_TYPEDEF)
85 #undef MAKE_TYPEDEF
86 #endif
87
88 const uint8_t MAX_STREAMS = 16;
89
90 using unique_lock = std::unique_lock<std::mutex>;
91 using lock_guard = std::lock_guard<std::mutex>;
92
93 enum class stream_state {
94 INIT = 0,
95 STOPPED,
96 STOPPING,
97 STARTED,
98 STARTING,
99 DRAINING,
100 ERROR,
101 SHUTDOWN,
102 };
103
104 struct cubeb_stream {
105 /* Note: Must match cubeb_stream layout in cubeb.c. */
106 cubeb * context{};
107 void * user_ptr{};
108
109 std::atomic<bool> in_use{false};
110 std::atomic<stream_state> state{stream_state::INIT};
111
112 AAudioStream * ostream{};
113 AAudioStream * istream{};
114 cubeb_data_callback data_callback{};
115 cubeb_state_callback state_callback{};
116 cubeb_resampler * resampler{};
117
118 // mutex synchronizes access to the stream from the state thread
119 // and user-called functions. Everything that is accessed in the
120 // aaudio data (or error) callback is synchronized only via atomics.
121 std::mutex mutex;
122
123 std::unique_ptr<char[]> in_buf;
124 unsigned in_frame_size{}; // size of one input frame
125
126 cubeb_sample_format out_format{};
127 std::atomic<float> volume{1.f};
128 unsigned out_channels{};
129 unsigned out_frame_size{};
130 int64_t latest_output_latency = 0;
131 int64_t latest_input_latency = 0;
132 bool voice_input;
133 bool voice_output;
134 uint64_t previous_clock;
135 };
136
137 struct cubeb {
138 struct cubeb_ops const * ops{};
139 void * libaaudio{};
140
141 struct {
142 // The state thread: it waits for state changes and stops
143 // drained streams.
144 std::thread thread;
145 std::thread notifier;
146 std::mutex mutex;
147 std::condition_variable cond;
148 std::atomic<bool> join{false};
149 std::atomic<bool> waiting{false};
150 } state;
151
152 // streams[i].in_use signals whether a stream is used
153 struct cubeb_stream streams[MAX_STREAMS];
154 };
155
156 // Only allowed from state thread, while mutex on stm is locked
157 static void
shutdown(cubeb_stream * stm)158 shutdown(cubeb_stream * stm)
159 {
160 if (stm->istream) {
161 WRAP(AAudioStream_requestStop)(stm->istream);
162 }
163 if (stm->ostream) {
164 WRAP(AAudioStream_requestStop)(stm->ostream);
165 }
166
167 stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
168 stm->state.store(stream_state::SHUTDOWN);
169 }
170
171 // Returns whether the given state is one in which we wait for
172 // an asynchronous change
173 static bool
waiting_state(stream_state state)174 waiting_state(stream_state state)
175 {
176 switch (state) {
177 case stream_state::DRAINING:
178 case stream_state::STARTING:
179 case stream_state::STOPPING:
180 return true;
181 default:
182 return false;
183 }
184 }
185
186 static void
update_state(cubeb_stream * stm)187 update_state(cubeb_stream * stm)
188 {
189 // Fast path for streams that don't wait for state change or are invalid
190 enum stream_state old_state = stm->state.load();
191 if (old_state == stream_state::INIT || old_state == stream_state::STARTED ||
192 old_state == stream_state::STOPPED ||
193 old_state == stream_state::SHUTDOWN) {
194 return;
195 }
196
197 // If the main thread currently operates on this thread, we don't
198 // have to wait for it
199 unique_lock lock(stm->mutex, std::try_to_lock);
200 if (!lock.owns_lock()) {
201 return;
202 }
203
204 // check again: if this is true now, the stream was destroyed or
205 // changed between our fast path check and locking the mutex
206 old_state = stm->state.load();
207 if (old_state == stream_state::INIT || old_state == stream_state::STARTED ||
208 old_state == stream_state::STOPPED ||
209 old_state == stream_state::SHUTDOWN) {
210 return;
211 }
212
213 // We compute the new state the stream has and then compare_exchange it
214 // if it has changed. This way we will never just overwrite state
215 // changes that were set from the audio thread in the meantime,
216 // such as a DRAINING or error state.
217 enum stream_state new_state;
218 do {
219 if (old_state == stream_state::SHUTDOWN) {
220 return;
221 }
222
223 if (old_state == stream_state::ERROR) {
224 shutdown(stm);
225 return;
226 }
227
228 new_state = old_state;
229
230 aaudio_stream_state_t istate = 0;
231 aaudio_stream_state_t ostate = 0;
232
233 // We use waitForStateChange (with zero timeout) instead of just
234 // getState since only the former internally updates the state.
235 // See the docs of aaudio getState/waitForStateChange for details,
236 // why we are passing STATE_UNKNOWN.
237 aaudio_result_t res;
238 if (stm->istream) {
239 res = WRAP(AAudioStream_waitForStateChange)(
240 stm->istream, AAUDIO_STREAM_STATE_UNKNOWN, &istate, 0);
241 if (res != AAUDIO_OK) {
242 LOG("AAudioStream_waitForStateChanged: %s",
243 WRAP(AAudio_convertResultToText)(res));
244 return;
245 }
246 assert(istate);
247 }
248
249 if (stm->ostream) {
250 res = WRAP(AAudioStream_waitForStateChange)(
251 stm->ostream, AAUDIO_STREAM_STATE_UNKNOWN, &ostate, 0);
252 if (res != AAUDIO_OK) {
253 LOG("AAudioStream_waitForStateChanged: %s",
254 WRAP(AAudio_convertResultToText)(res));
255 return;
256 }
257 assert(ostate);
258 }
259
260 // handle invalid stream states
261 if (istate == AAUDIO_STREAM_STATE_PAUSING ||
262 istate == AAUDIO_STREAM_STATE_PAUSED ||
263 istate == AAUDIO_STREAM_STATE_FLUSHING ||
264 istate == AAUDIO_STREAM_STATE_FLUSHED ||
265 istate == AAUDIO_STREAM_STATE_UNKNOWN ||
266 istate == AAUDIO_STREAM_STATE_DISCONNECTED) {
267 const char * name = WRAP(AAudio_convertStreamStateToText)(istate);
268 LOG("Unexpected android input stream state %s", name);
269 shutdown(stm);
270 return;
271 }
272
273 if (ostate == AAUDIO_STREAM_STATE_PAUSING ||
274 ostate == AAUDIO_STREAM_STATE_PAUSED ||
275 ostate == AAUDIO_STREAM_STATE_FLUSHING ||
276 ostate == AAUDIO_STREAM_STATE_FLUSHED ||
277 ostate == AAUDIO_STREAM_STATE_UNKNOWN ||
278 ostate == AAUDIO_STREAM_STATE_DISCONNECTED) {
279 const char * name = WRAP(AAudio_convertStreamStateToText)(istate);
280 LOG("Unexpected android output stream state %s", name);
281 shutdown(stm);
282 return;
283 }
284
285 switch (old_state) {
286 case stream_state::STARTING:
287 if ((!istate || istate == AAUDIO_STREAM_STATE_STARTED) &&
288 (!ostate || ostate == AAUDIO_STREAM_STATE_STARTED)) {
289 stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED);
290 new_state = stream_state::STARTED;
291 }
292 break;
293 case stream_state::DRAINING:
294 // The DRAINING state means that we want to stop the streams but
295 // may not have done so yet.
296 // The aaudio docs state that returning STOP from the callback isn't
297 // enough, the stream has to be stopped from another thread
298 // afterwards.
299 // No callbacks are triggered anymore when requestStop returns.
300 // That is important as we otherwise might read from a closed istream
301 // for a duplex stream.
302 // Therefor it is important to close ostream first.
303 if (ostate && ostate != AAUDIO_STREAM_STATE_STOPPING &&
304 ostate != AAUDIO_STREAM_STATE_STOPPED) {
305 res = WRAP(AAudioStream_requestStop)(stm->ostream);
306 if (res != AAUDIO_OK) {
307 LOG("AAudioStream_requestStop: %s",
308 WRAP(AAudio_convertResultToText)(res));
309 return;
310 }
311 }
312 if (istate && istate != AAUDIO_STREAM_STATE_STOPPING &&
313 istate != AAUDIO_STREAM_STATE_STOPPED) {
314 res = WRAP(AAudioStream_requestStop)(stm->istream);
315 if (res != AAUDIO_OK) {
316 LOG("AAudioStream_requestStop: %s",
317 WRAP(AAudio_convertResultToText)(res));
318 return;
319 }
320 }
321
322 // we always wait until both streams are stopped until we
323 // send CUBEB_STATE_DRAINED. Then we can directly transition
324 // our logical state to STOPPED, not triggering
325 // an additional CUBEB_STATE_STOPPED callback (which might
326 // be unexpected for the user).
327 if ((!ostate || ostate == AAUDIO_STREAM_STATE_STOPPED) &&
328 (!istate || istate == AAUDIO_STREAM_STATE_STOPPED)) {
329 new_state = stream_state::STOPPED;
330 stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
331 }
332 break;
333 case stream_state::STOPPING:
334 assert(!istate || istate == AAUDIO_STREAM_STATE_STOPPING ||
335 istate == AAUDIO_STREAM_STATE_STOPPED);
336 assert(!ostate || ostate == AAUDIO_STREAM_STATE_STOPPING ||
337 ostate == AAUDIO_STREAM_STATE_STOPPED);
338 if ((!istate || istate == AAUDIO_STREAM_STATE_STOPPED) &&
339 (!ostate || ostate == AAUDIO_STREAM_STATE_STOPPED)) {
340 stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
341 new_state = stream_state::STOPPED;
342 }
343 break;
344 default:
345 assert(false && "Unreachable: invalid state");
346 }
347 } while (old_state != new_state &&
348 !stm->state.compare_exchange_strong(old_state, new_state));
349 }
350
351 // See https://nyorain.github.io/lock-free-wakeup.html for a note
352 // why this is needed. The audio thread notifies the state thread about
353 // state changes and must not block. The state thread on the other hand should
354 // sleep until there is work to be done. So we need a lockfree producer
355 // and blocking producer. This can only be achieved safely with a new thread
356 // that only serves as notifier backup (in case the notification happens
357 // right between the state thread checking and going to sleep in which case
358 // this thread will kick in and signal it right again).
359 static void
notifier_thread(cubeb * ctx)360 notifier_thread(cubeb * ctx)
361 {
362 unique_lock lock(ctx->state.mutex);
363
364 while (!ctx->state.join.load()) {
365 ctx->state.cond.wait(lock);
366 if (ctx->state.waiting.load()) {
367 // This must signal our state thread since there is no other
368 // thread currently waiting on the condition variable.
369 // The state change thread is guaranteed to be waiting since
370 // we hold the mutex it locks when awake.
371 ctx->state.cond.notify_one();
372 }
373 }
374
375 // make sure other thread joins as well
376 ctx->state.cond.notify_one();
377 LOG("Exiting notifier thread");
378 }
379
380 static void
state_thread(cubeb * ctx)381 state_thread(cubeb * ctx)
382 {
383 unique_lock lock(ctx->state.mutex);
384
385 bool waiting = false;
386 while (!ctx->state.join.load()) {
387 waiting |= ctx->state.waiting.load();
388 if (waiting) {
389 ctx->state.waiting.store(false);
390 waiting = false;
391 for (unsigned i = 0u; i < MAX_STREAMS; ++i) {
392 cubeb_stream * stm = &ctx->streams[i];
393 update_state(stm);
394 waiting |= waiting_state(atomic_load(&stm->state));
395 }
396
397 // state changed from another thread, update again immediately
398 if (ctx->state.waiting.load()) {
399 waiting = true;
400 continue;
401 }
402
403 // Not waiting for any change anymore: we can wait on the
404 // condition variable without timeout
405 if (!waiting) {
406 continue;
407 }
408
409 // while any stream is waiting for state change we sleep with regular
410 // timeouts. But we wake up immediately if signaled.
411 // This might seem like a poor man's implementation of state change
412 // waiting but (as of october 2020), the implementation of
413 // AAudioStream_waitForStateChange is just sleeping with regular
414 // timeouts as well:
415 // https://android.googlesource.com/platform/frameworks/av/+/refs/heads/master/media/libaaudio/src/core/AudioStream.cpp
416 auto dur = std::chrono::milliseconds(5);
417 ctx->state.cond.wait_for(lock, dur);
418 } else {
419 ctx->state.cond.wait(lock);
420 }
421 }
422
423 // make sure other thread joins as well
424 ctx->state.cond.notify_one();
425 LOG("Exiting state thread");
426 }
427
428 static char const *
aaudio_get_backend_id(cubeb *)429 aaudio_get_backend_id(cubeb * /* ctx */)
430 {
431 return "aaudio";
432 }
433
434 static int
aaudio_get_max_channel_count(cubeb * ctx,uint32_t * max_channels)435 aaudio_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
436 {
437 assert(ctx && max_channels);
438 // NOTE: we might get more, AAudio docs don't specify anything.
439 *max_channels = 2;
440 return CUBEB_OK;
441 }
442
443 static void
aaudio_destroy(cubeb * ctx)444 aaudio_destroy(cubeb * ctx)
445 {
446 assert(ctx);
447
448 #ifndef NDEBUG
449 // make sure all streams were destroyed
450 for (unsigned i = 0u; i < MAX_STREAMS; ++i) {
451 assert(!ctx->streams[i].in_use.load());
452 }
453 #endif
454
455 // broadcast joining to both threads
456 // they will additionally signal each other before joining
457 ctx->state.join.store(true);
458 ctx->state.cond.notify_all();
459
460 if (ctx->state.thread.joinable()) {
461 ctx->state.thread.join();
462 }
463 if (ctx->state.notifier.joinable()) {
464 ctx->state.notifier.join();
465 }
466
467 if (ctx->libaaudio) {
468 dlclose(ctx->libaaudio);
469 }
470 delete ctx;
471 }
472
473 static void
apply_volume(cubeb_stream * stm,void * audio_data,uint32_t num_frames)474 apply_volume(cubeb_stream * stm, void * audio_data, uint32_t num_frames)
475 {
476 float volume = stm->volume.load();
477 // optimization: we don't have to change anything in this case
478 if (volume == 1.f) {
479 return;
480 }
481
482 switch (stm->out_format) {
483 case CUBEB_SAMPLE_S16NE:
484 for (uint32_t i = 0u; i < num_frames * stm->out_channels; ++i) {
485 (static_cast<int16_t *>(audio_data))[i] *= volume;
486 }
487 break;
488 case CUBEB_SAMPLE_FLOAT32NE:
489 for (uint32_t i = 0u; i < num_frames * stm->out_channels; ++i) {
490 (static_cast<float *>(audio_data))[i] *= volume;
491 }
492 break;
493 default:
494 assert(false && "Unreachable: invalid stream out_format");
495 }
496 }
497
498 // Returning AAUDIO_CALLBACK_RESULT_STOP seems to put the stream in
499 // an invalid state. Seems like an AAudio bug/bad documentation.
500 // We therefore only return it on error.
501
502 static aaudio_data_callback_result_t
aaudio_duplex_data_cb(AAudioStream * astream,void * user_data,void * audio_data,int32_t num_frames)503 aaudio_duplex_data_cb(AAudioStream * astream, void * user_data,
504 void * audio_data, int32_t num_frames)
505 {
506 cubeb_stream * stm = (cubeb_stream *)user_data;
507 assert(stm->ostream == astream);
508 assert(stm->istream);
509 assert(num_frames >= 0);
510
511 stream_state state = atomic_load(&stm->state);
512 // int istate = WRAP(AAudioStream_getState)(stm->istream);
513 // int ostate = WRAP(AAudioStream_getState)(stm->ostream);
514 // ALOGV("aaudio duplex data cb on stream %p: state %ld (in: %d, out: %d),
515 // num_frames: %ld",
516 // (void*) stm, state, istate, ostate, num_frames);
517
518 // all other states may happen since the callback might be called
519 // from within requestStart
520 assert(state != stream_state::SHUTDOWN);
521
522 // This might happen when we started draining but not yet actually
523 // stopped the stream from the state thread.
524 if (state == stream_state::DRAINING) {
525 std::memset(audio_data, 0x0, num_frames * stm->out_frame_size);
526 return AAUDIO_CALLBACK_RESULT_CONTINUE;
527 }
528
529 // The aaudio docs state that AAudioStream_read must not be called on
530 // the stream associated with a callback. But we call it on the input stream
531 // while this callback is for the output stream so this is ok.
532 // We also pass timeout 0, giving us strong non-blocking guarantees.
533 // This is exactly how it's done in the aaudio duplex example code snippet.
534 long in_num_frames =
535 WRAP(AAudioStream_read)(stm->istream, stm->in_buf.get(), num_frames, 0);
536 if (in_num_frames < 0) { // error
537 stm->state.store(stream_state::ERROR);
538 LOG("AAudioStream_read: %s",
539 WRAP(AAudio_convertResultToText)(in_num_frames));
540 return AAUDIO_CALLBACK_RESULT_STOP;
541 }
542
543 // This can happen shortly after starting the stream. AAudio might immediately
544 // begin to buffer output but not have any input ready yet. We could
545 // block AAudioStream_read (passing a timeout > 0) but that leads to issues
546 // since blocking in this callback is a bad idea in general and it might break
547 // the stream when it is stopped by another thread shortly after being
548 // started. We therefore simply send silent input to the application, as shown
549 // in the AAudio duplex stream code example.
550 if (in_num_frames < num_frames) {
551 // LOG("AAudioStream_read returned not enough frames: %ld instead of %d",
552 // in_num_frames, num_frames);
553 unsigned left = num_frames - in_num_frames;
554 char * buf = stm->in_buf.get() + in_num_frames * stm->in_frame_size;
555 std::memset(buf, 0x0, left * stm->in_frame_size);
556 in_num_frames = num_frames;
557 }
558
559 long done_frames =
560 cubeb_resampler_fill(stm->resampler, stm->in_buf.get(), &in_num_frames,
561 audio_data, num_frames);
562
563 if (done_frames < 0 || done_frames > num_frames) {
564 LOG("Error in data callback or resampler: %ld", done_frames);
565 stm->state.store(stream_state::ERROR);
566 return AAUDIO_CALLBACK_RESULT_STOP;
567 } else if (done_frames < num_frames) {
568 stm->state.store(stream_state::DRAINING);
569 stm->context->state.waiting.store(true);
570 stm->context->state.cond.notify_one();
571
572 char * begin =
573 static_cast<char *>(audio_data) + done_frames * stm->out_frame_size;
574 std::memset(begin, 0x0, (num_frames - done_frames) * stm->out_frame_size);
575 }
576
577 apply_volume(stm, audio_data, done_frames);
578 return AAUDIO_CALLBACK_RESULT_CONTINUE;
579 }
580
581 static aaudio_data_callback_result_t
aaudio_output_data_cb(AAudioStream * astream,void * user_data,void * audio_data,int32_t num_frames)582 aaudio_output_data_cb(AAudioStream * astream, void * user_data,
583 void * audio_data, int32_t num_frames)
584 {
585 cubeb_stream * stm = (cubeb_stream *)user_data;
586 assert(stm->ostream == astream);
587 assert(!stm->istream);
588 assert(num_frames >= 0);
589
590 stream_state state = stm->state.load();
591 // int ostate = WRAP(AAudioStream_getState)(stm->ostream);
592 // ALOGV("aaudio output data cb on stream %p: state %ld (%d), num_frames:
593 // %ld",
594 // (void*) stm, state, ostate, num_frames);
595
596 // all other states may happen since the callback might be called
597 // from within requestStart
598 assert(state != stream_state::SHUTDOWN);
599
600 // This might happen when we started draining but not yet actually
601 // stopped the stream from the state thread.
602 if (state == stream_state::DRAINING) {
603 std::memset(audio_data, 0x0, num_frames * stm->out_frame_size);
604 return AAUDIO_CALLBACK_RESULT_CONTINUE;
605 }
606
607 long done_frames =
608 cubeb_resampler_fill(stm->resampler, NULL, NULL, audio_data, num_frames);
609 if (done_frames < 0 || done_frames > num_frames) {
610 LOG("Error in data callback or resampler: %ld", done_frames);
611 stm->state.store(stream_state::ERROR);
612 return AAUDIO_CALLBACK_RESULT_STOP;
613 } else if (done_frames < num_frames) {
614 stm->state.store(stream_state::DRAINING);
615 stm->context->state.waiting.store(true);
616 stm->context->state.cond.notify_one();
617
618 char * begin =
619 static_cast<char *>(audio_data) + done_frames * stm->out_frame_size;
620 std::memset(begin, 0x0, (num_frames - done_frames) * stm->out_frame_size);
621 }
622
623 apply_volume(stm, audio_data, done_frames);
624 return AAUDIO_CALLBACK_RESULT_CONTINUE;
625 }
626
627 static aaudio_data_callback_result_t
aaudio_input_data_cb(AAudioStream * astream,void * user_data,void * audio_data,int32_t num_frames)628 aaudio_input_data_cb(AAudioStream * astream, void * user_data,
629 void * audio_data, int32_t num_frames)
630 {
631 cubeb_stream * stm = (cubeb_stream *)user_data;
632 assert(stm->istream == astream);
633 assert(!stm->ostream);
634 assert(num_frames >= 0);
635
636 stream_state state = stm->state.load();
637 // int istate = WRAP(AAudioStream_getState)(stm->istream);
638 // ALOGV("aaudio input data cb on stream %p: state %ld (%d), num_frames: %ld",
639 // (void*) stm, state, istate, num_frames);
640
641 // all other states may happen since the callback might be called
642 // from within requestStart
643 assert(state != stream_state::SHUTDOWN);
644
645 // This might happen when we started draining but not yet actually
646 // STOPPED the stream from the state thread.
647 if (state == stream_state::DRAINING) {
648 return AAUDIO_CALLBACK_RESULT_CONTINUE;
649 }
650
651 long input_frame_count = num_frames;
652 long done_frames = cubeb_resampler_fill(stm->resampler, audio_data,
653 &input_frame_count, NULL, 0);
654 if (done_frames < 0 || done_frames > num_frames) {
655 LOG("Error in data callback or resampler: %ld", done_frames);
656 stm->state.store(stream_state::ERROR);
657 return AAUDIO_CALLBACK_RESULT_STOP;
658 } else if (done_frames < input_frame_count) {
659 // we don't really drain an input stream, just have to
660 // stop it from the state thread. That is signaled via the
661 // DRAINING state.
662 stm->state.store(stream_state::DRAINING);
663 stm->context->state.waiting.store(true);
664 stm->context->state.cond.notify_one();
665 }
666
667 return AAUDIO_CALLBACK_RESULT_CONTINUE;
668 }
669
670 static void
aaudio_error_cb(AAudioStream * astream,void * user_data,aaudio_result_t error)671 aaudio_error_cb(AAudioStream * astream, void * user_data, aaudio_result_t error)
672 {
673 cubeb_stream * stm = static_cast<cubeb_stream *>(user_data);
674 assert(stm->ostream == astream || stm->istream == astream);
675 LOG("AAudio error callback: %s", WRAP(AAudio_convertResultToText)(error));
676 stm->state.store(stream_state::ERROR);
677 }
678
679 static int
realize_stream(AAudioStreamBuilder * sb,const cubeb_stream_params * params,AAudioStream ** stream,unsigned * frame_size)680 realize_stream(AAudioStreamBuilder * sb, const cubeb_stream_params * params,
681 AAudioStream ** stream, unsigned * frame_size)
682 {
683 aaudio_result_t res;
684 assert(params->rate);
685 assert(params->channels);
686
687 WRAP(AAudioStreamBuilder_setSampleRate)(sb, params->rate);
688 WRAP(AAudioStreamBuilder_setChannelCount)(sb, params->channels);
689
690 aaudio_format_t fmt;
691 switch (params->format) {
692 case CUBEB_SAMPLE_S16NE:
693 fmt = AAUDIO_FORMAT_PCM_I16;
694 *frame_size = sizeof(int16_t) * params->channels;
695 break;
696 case CUBEB_SAMPLE_FLOAT32NE:
697 fmt = AAUDIO_FORMAT_PCM_FLOAT;
698 *frame_size = sizeof(float) * params->channels;
699 break;
700 default:
701 return CUBEB_ERROR_INVALID_FORMAT;
702 }
703
704 WRAP(AAudioStreamBuilder_setFormat)(sb, fmt);
705 res = WRAP(AAudioStreamBuilder_openStream)(sb, stream);
706 if (res == AAUDIO_ERROR_INVALID_FORMAT) {
707 LOG("AAudio device doesn't support output format %d", fmt);
708 return CUBEB_ERROR_INVALID_FORMAT;
709 } else if (params->rate && res == AAUDIO_ERROR_INVALID_RATE) {
710 // The requested rate is not supported.
711 // Just try again with default rate, we create a resampler anyways
712 WRAP(AAudioStreamBuilder_setSampleRate)(sb, AAUDIO_UNSPECIFIED);
713 res = WRAP(AAudioStreamBuilder_openStream)(sb, stream);
714 LOG("Requested rate of %u is not supported, inserting resampler",
715 params->rate);
716 }
717
718 // When the app has no permission to record audio
719 // (android.permission.RECORD_AUDIO) but requested and input stream, this will
720 // return INVALID_ARGUMENT.
721 if (res != AAUDIO_OK) {
722 LOG("AAudioStreamBuilder_openStream: %s",
723 WRAP(AAudio_convertResultToText)(res));
724 return CUBEB_ERROR;
725 }
726
727 return CUBEB_OK;
728 }
729
730 static void
aaudio_stream_destroy(cubeb_stream * stm)731 aaudio_stream_destroy(cubeb_stream * stm)
732 {
733 lock_guard lock(stm->mutex);
734 assert(stm->state == stream_state::STOPPED ||
735 stm->state == stream_state::STOPPING ||
736 stm->state == stream_state::INIT ||
737 stm->state == stream_state::DRAINING ||
738 stm->state == stream_state::ERROR ||
739 stm->state == stream_state::SHUTDOWN);
740
741 aaudio_result_t res;
742
743 // No callbacks are triggered anymore when requestStop returns.
744 // That is important as we otherwise might read from a closed istream
745 // for a duplex stream.
746 if (stm->ostream) {
747 if (stm->state != stream_state::STOPPED &&
748 stm->state != stream_state::STOPPING &&
749 stm->state != stream_state::SHUTDOWN) {
750 res = WRAP(AAudioStream_requestStop)(stm->ostream);
751 if (res != AAUDIO_OK) {
752 LOG("AAudioStreamBuilder_requestStop: %s",
753 WRAP(AAudio_convertResultToText)(res));
754 }
755 }
756
757 WRAP(AAudioStream_close)(stm->ostream);
758 stm->ostream = NULL;
759 }
760
761 if (stm->istream) {
762 if (stm->state != stream_state::STOPPED &&
763 stm->state != stream_state::STOPPING &&
764 stm->state != stream_state::SHUTDOWN) {
765 res = WRAP(AAudioStream_requestStop)(stm->istream);
766 if (res != AAUDIO_OK) {
767 LOG("AAudioStreamBuilder_requestStop: %s",
768 WRAP(AAudio_convertResultToText)(res));
769 }
770 }
771
772 WRAP(AAudioStream_close)(stm->istream);
773 stm->istream = NULL;
774 }
775
776 if (stm->resampler) {
777 cubeb_resampler_destroy(stm->resampler);
778 stm->resampler = NULL;
779 }
780
781 stm->in_buf = {};
782 stm->in_frame_size = {};
783 stm->out_format = {};
784 stm->out_channels = {};
785 stm->out_frame_size = {};
786
787 stm->state.store(stream_state::INIT);
788 stm->in_use.store(false);
789 }
790
791 static int
aaudio_stream_init_impl(cubeb_stream * stm,cubeb_devid input_device,cubeb_stream_params * input_stream_params,cubeb_devid output_device,cubeb_stream_params * output_stream_params,unsigned int latency_frames)792 aaudio_stream_init_impl(cubeb_stream * stm, cubeb_devid input_device,
793 cubeb_stream_params * input_stream_params,
794 cubeb_devid output_device,
795 cubeb_stream_params * output_stream_params,
796 unsigned int latency_frames)
797 {
798 assert(stm->state.load() == stream_state::INIT);
799 stm->in_use.store(true);
800
801 aaudio_result_t res;
802 AAudioStreamBuilder * sb;
803 res = WRAP(AAudio_createStreamBuilder)(&sb);
804 if (res != AAUDIO_OK) {
805 LOG("AAudio_createStreamBuilder: %s",
806 WRAP(AAudio_convertResultToText)(res));
807 return CUBEB_ERROR;
808 }
809
810 // make sure the builder is always destroyed
811 struct StreamBuilderDestructor {
812 void operator()(AAudioStreamBuilder * sb)
813 {
814 WRAP(AAudioStreamBuilder_delete)(sb);
815 }
816 };
817
818 std::unique_ptr<AAudioStreamBuilder, StreamBuilderDestructor> sbPtr(sb);
819
820 WRAP(AAudioStreamBuilder_setErrorCallback)(sb, aaudio_error_cb, stm);
821 WRAP(AAudioStreamBuilder_setBufferCapacityInFrames)(sb, latency_frames);
822
823 AAudioStream_dataCallback in_data_callback{};
824 AAudioStream_dataCallback out_data_callback{};
825 if (output_stream_params && input_stream_params) {
826 out_data_callback = aaudio_duplex_data_cb;
827 in_data_callback = NULL;
828 } else if (input_stream_params) {
829 in_data_callback = aaudio_input_data_cb;
830 } else if (output_stream_params) {
831 out_data_callback = aaudio_output_data_cb;
832 } else {
833 LOG("Tried to open stream without input or output parameters");
834 return CUBEB_ERROR;
835 }
836
837 #ifdef CUBEB_AAUDIO_EXCLUSIVE_STREAM
838 LOG("AAudio setting exclusive share mode for stream");
839 WRAP(AAudioStreamBuilder_setSharingMode)(sb, AAUDIO_SHARING_MODE_EXCLUSIVE);
840 #endif
841
842 if (latency_frames <= POWERSAVE_LATENCY_FRAMES_THRESHOLD) {
843 LOG("AAudio setting low latency mode for stream");
844 WRAP(AAudioStreamBuilder_setPerformanceMode)
845 (sb, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
846 } else {
847 LOG("AAudio setting power saving mode for stream");
848 WRAP(AAudioStreamBuilder_setPerformanceMode)
849 (sb, AAUDIO_PERFORMANCE_MODE_POWER_SAVING);
850 }
851
852 unsigned frame_size;
853
854 // initialize streams
855 // output
856 uint32_t target_sample_rate = 0;
857 cubeb_stream_params out_params;
858 if (output_stream_params) {
859 int output_preset = stm->voice_output ? AAUDIO_USAGE_VOICE_COMMUNICATION
860 : AAUDIO_USAGE_MEDIA;
861 WRAP(AAudioStreamBuilder_setUsage)(sb, output_preset);
862 WRAP(AAudioStreamBuilder_setDirection)(sb, AAUDIO_DIRECTION_OUTPUT);
863 WRAP(AAudioStreamBuilder_setDataCallback)(sb, out_data_callback, stm);
864 int res_err =
865 realize_stream(sb, output_stream_params, &stm->ostream, &frame_size);
866 if (res_err) {
867 return res_err;
868 }
869
870 // output debug information
871 aaudio_sharing_mode_t sm = WRAP(AAudioStream_getSharingMode)(stm->ostream);
872 aaudio_performance_mode_t pm =
873 WRAP(AAudioStream_getPerformanceMode)(stm->ostream);
874 int bcap = WRAP(AAudioStream_getBufferCapacityInFrames)(stm->ostream);
875 int bsize = WRAP(AAudioStream_getBufferSizeInFrames)(stm->ostream);
876 int rate = WRAP(AAudioStream_getSampleRate)(stm->ostream);
877 LOG("AAudio output stream sharing mode: %d", sm);
878 LOG("AAudio output stream performance mode: %d", pm);
879 LOG("AAudio output stream buffer capacity: %d", bcap);
880 LOG("AAudio output stream buffer size: %d", bsize);
881 LOG("AAudio output stream buffer rate: %d", rate);
882
883 target_sample_rate = output_stream_params->rate;
884 out_params = *output_stream_params;
885 out_params.rate = rate;
886
887 stm->out_channels = output_stream_params->channels;
888 stm->out_format = output_stream_params->format;
889 stm->out_frame_size = frame_size;
890 stm->volume.store(1.f);
891 }
892
893 // input
894 cubeb_stream_params in_params;
895 if (input_stream_params) {
896 // Match what the OpenSL backend does for now, we could use UNPROCESSED and
897 // VOICE_COMMUNICATION here, but we'd need to make it clear that
898 // application-level AEC and other voice processing should be disabled
899 // there.
900 int input_preset = stm->voice_input ? AAUDIO_INPUT_PRESET_VOICE_RECOGNITION
901 : AAUDIO_INPUT_PRESET_CAMCORDER;
902 WRAP(AAudioStreamBuilder_setInputPreset)(sb, input_preset);
903 WRAP(AAudioStreamBuilder_setDirection)(sb, AAUDIO_DIRECTION_INPUT);
904 WRAP(AAudioStreamBuilder_setDataCallback)(sb, in_data_callback, stm);
905 int res_err =
906 realize_stream(sb, input_stream_params, &stm->istream, &frame_size);
907 if (res_err) {
908 return res_err;
909 }
910
911 // output debug information
912 aaudio_sharing_mode_t sm = WRAP(AAudioStream_getSharingMode)(stm->istream);
913 aaudio_performance_mode_t pm =
914 WRAP(AAudioStream_getPerformanceMode)(stm->istream);
915 int bcap = WRAP(AAudioStream_getBufferCapacityInFrames)(stm->istream);
916 int bsize = WRAP(AAudioStream_getBufferSizeInFrames)(stm->istream);
917 int rate = WRAP(AAudioStream_getSampleRate)(stm->istream);
918 LOG("AAudio input stream sharing mode: %d", sm);
919 LOG("AAudio input stream performance mode: %d", pm);
920 LOG("AAudio input stream buffer capacity: %d", bcap);
921 LOG("AAudio input stream buffer size: %d", bsize);
922 LOG("AAudio input stream buffer rate: %d", rate);
923
924 stm->in_buf.reset(new char[bcap * frame_size]());
925 assert(!target_sample_rate ||
926 target_sample_rate == input_stream_params->rate);
927
928 target_sample_rate = input_stream_params->rate;
929 in_params = *input_stream_params;
930 in_params.rate = rate;
931 stm->in_frame_size = frame_size;
932 }
933
934 // initialize resampler
935 stm->resampler = cubeb_resampler_create(
936 stm, input_stream_params ? &in_params : NULL,
937 output_stream_params ? &out_params : NULL, target_sample_rate,
938 stm->data_callback, stm->user_ptr, CUBEB_RESAMPLER_QUALITY_DEFAULT);
939
940 if (!stm->resampler) {
941 LOG("Failed to create resampler");
942 return CUBEB_ERROR;
943 }
944
945 // the stream isn't started initially. We don't need to differentiate
946 // between a stream that was just initialized and one that played
947 // already but was stopped.
948 stm->state.store(stream_state::STOPPED);
949 LOG("Cubeb stream (%p) INIT success", (void *)stm);
950 return CUBEB_OK;
951 }
952
953 static int
aaudio_stream_init(cubeb * ctx,cubeb_stream ** stream,char const *,cubeb_devid input_device,cubeb_stream_params * input_stream_params,cubeb_devid output_device,cubeb_stream_params * output_stream_params,unsigned int latency_frames,cubeb_data_callback data_callback,cubeb_state_callback state_callback,void * user_ptr)954 aaudio_stream_init(cubeb * ctx, cubeb_stream ** stream,
955 char const * /* stream_name */, cubeb_devid input_device,
956 cubeb_stream_params * input_stream_params,
957 cubeb_devid output_device,
958 cubeb_stream_params * output_stream_params,
959 unsigned int latency_frames,
960 cubeb_data_callback data_callback,
961 cubeb_state_callback state_callback, void * user_ptr)
962 {
963 assert(!input_device);
964 assert(!output_device);
965
966 // atomically find a free stream.
967 cubeb_stream * stm = NULL;
968 unique_lock lock;
969 for (unsigned i = 0u; i < MAX_STREAMS; ++i) {
970 // This check is only an optimization, we don't strictly need it
971 // since we check again after locking the mutex.
972 if (ctx->streams[i].in_use.load()) {
973 continue;
974 }
975
976 // if this fails, another thread initialized this stream
977 // between our check of in_use and this.
978 lock = unique_lock(ctx->streams[i].mutex, std::try_to_lock);
979 if (!lock.owns_lock()) {
980 continue;
981 }
982
983 if (ctx->streams[i].in_use.load()) {
984 lock = {};
985 continue;
986 }
987
988 stm = &ctx->streams[i];
989 break;
990 }
991
992 if (!stm) {
993 LOG("Error: maximum number of streams reached");
994 return CUBEB_ERROR;
995 }
996
997 stm->context = ctx;
998 stm->user_ptr = user_ptr;
999 stm->data_callback = data_callback;
1000 stm->state_callback = state_callback;
1001 stm->voice_input = input_stream_params &&
1002 !!(input_stream_params->prefs & CUBEB_STREAM_PREF_VOICE);
1003 stm->voice_output = output_stream_params &&
1004 !!(output_stream_params->prefs & CUBEB_STREAM_PREF_VOICE);
1005 stm->previous_clock = 0;
1006
1007 LOG("cubeb stream prefs: voice_input: %s voice_output: %s",
1008 stm->voice_input ? "true" : "false",
1009 stm->voice_output ? "true" : "false");
1010
1011 int err = aaudio_stream_init_impl(stm, input_device, input_stream_params,
1012 output_device, output_stream_params,
1013 latency_frames);
1014 if (err != CUBEB_OK) {
1015 // This is needed since aaudio_stream_destroy will lock the mutex again.
1016 // It's no problem that there is a gap in between as the stream isn't
1017 // actually in u se.
1018 lock.unlock();
1019 aaudio_stream_destroy(stm);
1020 return err;
1021 }
1022
1023 *stream = stm;
1024 return CUBEB_OK;
1025 }
1026
1027 static int
aaudio_stream_start(cubeb_stream * stm)1028 aaudio_stream_start(cubeb_stream * stm)
1029 {
1030 assert(stm && stm->in_use.load());
1031 lock_guard lock(stm->mutex);
1032
1033 stream_state state = stm->state.load();
1034 int istate = stm->istream ? WRAP(AAudioStream_getState)(stm->istream) : 0;
1035 int ostate = stm->ostream ? WRAP(AAudioStream_getState)(stm->ostream) : 0;
1036 LOGV("STARTING stream %p: %d (%d %d)", (void *)stm, state, istate, ostate);
1037
1038 switch (state) {
1039 case stream_state::STARTED:
1040 case stream_state::STARTING:
1041 LOG("cubeb stream %p already STARTING/STARTED", (void *)stm);
1042 return CUBEB_OK;
1043 case stream_state::ERROR:
1044 case stream_state::SHUTDOWN:
1045 return CUBEB_ERROR;
1046 case stream_state::INIT:
1047 assert(false && "Invalid stream");
1048 return CUBEB_ERROR;
1049 case stream_state::STOPPED:
1050 case stream_state::STOPPING:
1051 case stream_state::DRAINING:
1052 break;
1053 }
1054
1055 aaudio_result_t res;
1056
1057 // Important to start istream before ostream.
1058 // As soon as we start ostream, the callbacks might be triggered an we
1059 // might read from istream (on duplex). If istream wasn't started yet
1060 // this is a problem.
1061 if (stm->istream) {
1062 res = WRAP(AAudioStream_requestStart)(stm->istream);
1063 if (res != AAUDIO_OK) {
1064 LOG("AAudioStream_requestStart (istream): %s",
1065 WRAP(AAudio_convertResultToText)(res));
1066 stm->state.store(stream_state::ERROR);
1067 return CUBEB_ERROR;
1068 }
1069 }
1070
1071 if (stm->ostream) {
1072 res = WRAP(AAudioStream_requestStart)(stm->ostream);
1073 if (res != AAUDIO_OK) {
1074 LOG("AAudioStream_requestStart (ostream): %s",
1075 WRAP(AAudio_convertResultToText)(res));
1076 stm->state.store(stream_state::ERROR);
1077 return CUBEB_ERROR;
1078 }
1079 }
1080
1081 int ret = CUBEB_OK;
1082 bool success;
1083
1084 while (!(success = stm->state.compare_exchange_strong(
1085 state, stream_state::STARTING))) {
1086 // we land here only if the state has changed in the meantime
1087 switch (state) {
1088 // If an error ocurred in the meantime, we can't change that.
1089 // The stream will be stopped when shut down.
1090 case stream_state::ERROR:
1091 ret = CUBEB_ERROR;
1092 break;
1093 // The only situation in which the state could have switched to draining
1094 // is if the callback was already fired and requested draining. Don't
1095 // overwrite that. It's not an error either though.
1096 case stream_state::DRAINING:
1097 break;
1098
1099 // If the state switched [DRAINING -> STOPPING] or [DRAINING/STOPPING ->
1100 // STOPPED] in the meantime, we can simply overwrite that since we restarted
1101 // the stream.
1102 case stream_state::STOPPING:
1103 case stream_state::STOPPED:
1104 continue;
1105
1106 // There is no situation in which the state could have been valid before
1107 // but now in shutdown mode, since we hold the streams mutex.
1108 // There is also no way that it switched *into* STARTING or
1109 // STARTED mode.
1110 default:
1111 assert(false && "Invalid state change");
1112 ret = CUBEB_ERROR;
1113 break;
1114 }
1115
1116 break;
1117 }
1118
1119 if (success) {
1120 stm->context->state.waiting.store(true);
1121 stm->context->state.cond.notify_one();
1122 }
1123
1124 return ret;
1125 }
1126
1127 static int
aaudio_stream_stop(cubeb_stream * stm)1128 aaudio_stream_stop(cubeb_stream * stm)
1129 {
1130 assert(stm && stm->in_use.load());
1131 lock_guard lock(stm->mutex);
1132
1133 stream_state state = stm->state.load();
1134 int istate = stm->istream ? WRAP(AAudioStream_getState)(stm->istream) : 0;
1135 int ostate = stm->ostream ? WRAP(AAudioStream_getState)(stm->ostream) : 0;
1136 LOGV("STOPPING stream %p: %d (%d %d)", (void *)stm, state, istate, ostate);
1137
1138 switch (state) {
1139 case stream_state::STOPPED:
1140 case stream_state::STOPPING:
1141 case stream_state::DRAINING:
1142 LOG("cubeb stream %p already STOPPING/STOPPED", (void *)stm);
1143 return CUBEB_OK;
1144 case stream_state::ERROR:
1145 case stream_state::SHUTDOWN:
1146 return CUBEB_ERROR;
1147 case stream_state::INIT:
1148 assert(false && "Invalid stream");
1149 return CUBEB_ERROR;
1150 case stream_state::STARTED:
1151 case stream_state::STARTING:
1152 break;
1153 }
1154
1155 aaudio_result_t res;
1156
1157 // No callbacks are triggered anymore when requestStop returns.
1158 // That is important as we otherwise might read from a closed istream
1159 // for a duplex stream.
1160 // Therefor it is important to close ostream first.
1161 if (stm->ostream) {
1162 // Could use pause + flush here as well, the public cubeb interface
1163 // doesn't state behavior.
1164 res = WRAP(AAudioStream_requestStop)(stm->ostream);
1165 if (res != AAUDIO_OK) {
1166 LOG("AAudioStream_requestStop (ostream): %s",
1167 WRAP(AAudio_convertResultToText)(res));
1168 stm->state.store(stream_state::ERROR);
1169 return CUBEB_ERROR;
1170 }
1171 }
1172
1173 if (stm->istream) {
1174 res = WRAP(AAudioStream_requestStop)(stm->istream);
1175 if (res != AAUDIO_OK) {
1176 LOG("AAudioStream_requestStop (istream): %s",
1177 WRAP(AAudio_convertResultToText)(res));
1178 stm->state.store(stream_state::ERROR);
1179 return CUBEB_ERROR;
1180 }
1181 }
1182
1183 int ret = CUBEB_OK;
1184 bool success;
1185 while (!(success = atomic_compare_exchange_strong(&stm->state, &state,
1186 stream_state::STOPPING))) {
1187 // we land here only if the state has changed in the meantime
1188 switch (state) {
1189 // If an error ocurred in the meantime, we can't change that.
1190 // The stream will be STOPPED when shut down.
1191 case stream_state::ERROR:
1192 ret = CUBEB_ERROR;
1193 break;
1194 // If it was switched to DRAINING in the meantime, it was or
1195 // will be STOPPED soon anyways. We don't interfere with
1196 // the DRAINING process, no matter in which state.
1197 // Not an error
1198 case stream_state::DRAINING:
1199 case stream_state::STOPPING:
1200 case stream_state::STOPPED:
1201 break;
1202
1203 // If the state switched from STARTING to STARTED in the meantime
1204 // we can simply overwrite that since we just STOPPED it.
1205 case stream_state::STARTED:
1206 continue;
1207
1208 // There is no situation in which the state could have been valid before
1209 // but now in shutdown mode, since we hold the streams mutex.
1210 // There is also no way that it switched *into* STARTING mode.
1211 default:
1212 assert(false && "Invalid state change");
1213 ret = CUBEB_ERROR;
1214 break;
1215 }
1216
1217 break;
1218 }
1219
1220 if (success) {
1221 stm->context->state.waiting.store(true);
1222 stm->context->state.cond.notify_one();
1223 }
1224
1225 return ret;
1226 }
1227
1228 static int
aaudio_stream_get_position(cubeb_stream * stm,uint64_t * position)1229 aaudio_stream_get_position(cubeb_stream * stm, uint64_t * position)
1230 {
1231 assert(stm && stm->in_use.load());
1232 lock_guard lock(stm->mutex);
1233
1234 stream_state state = stm->state.load();
1235 AAudioStream * stream = stm->ostream ? stm->ostream : stm->istream;
1236 switch (state) {
1237 case stream_state::ERROR:
1238 case stream_state::SHUTDOWN:
1239 return CUBEB_ERROR;
1240 case stream_state::DRAINING:
1241 case stream_state::STOPPED:
1242 case stream_state::STOPPING:
1243 // getTimestamp is only valid when the stream is playing.
1244 // Simply return the number of frames passed to aaudio
1245 *position = WRAP(AAudioStream_getFramesRead)(stream);
1246 if (*position < stm->previous_clock) {
1247 *position = stm->previous_clock;
1248 } else {
1249 stm->previous_clock = *position;
1250 }
1251 return CUBEB_OK;
1252 case stream_state::INIT:
1253 assert(false && "Invalid stream");
1254 return CUBEB_ERROR;
1255 case stream_state::STARTED:
1256 case stream_state::STARTING:
1257 break;
1258 }
1259
1260 int64_t pos;
1261 int64_t ns;
1262 aaudio_result_t res;
1263 res = WRAP(AAudioStream_getTimestamp)(stream, CLOCK_MONOTONIC, &pos, &ns);
1264 if (res != AAUDIO_OK) {
1265 // When the audio stream is not running, invalid_state is returned and we
1266 // simply fall back to the method we use for non-playing streams.
1267 if (res == AAUDIO_ERROR_INVALID_STATE) {
1268 *position = WRAP(AAudioStream_getFramesRead)(stream);
1269 if (*position < stm->previous_clock) {
1270 *position = stm->previous_clock;
1271 } else {
1272 stm->previous_clock = *position;
1273 }
1274 return CUBEB_OK;
1275 }
1276
1277 LOG("AAudioStream_getTimestamp: %s", WRAP(AAudio_convertResultToText)(res));
1278 return CUBEB_ERROR;
1279 }
1280
1281 *position = pos;
1282 if (*position < stm->previous_clock) {
1283 *position = stm->previous_clock;
1284 } else {
1285 stm->previous_clock = *position;
1286 }
1287 return CUBEB_OK;
1288 }
1289
1290 static int
aaudio_stream_get_latency(cubeb_stream * stm,uint32_t * latency)1291 aaudio_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
1292 {
1293 int64_t pos;
1294 int64_t ns;
1295 aaudio_result_t res;
1296
1297 if (!stm->ostream) {
1298 LOG("error: aaudio_stream_get_latency on input-only stream");
1299 return CUBEB_ERROR;
1300 }
1301
1302 res =
1303 WRAP(AAudioStream_getTimestamp)(stm->ostream, CLOCK_MONOTONIC, &pos, &ns);
1304 if (res != AAUDIO_OK) {
1305 LOG("aaudio_stream_get_latency, AAudioStream_getTimestamp: %s, returning "
1306 "memoized value",
1307 WRAP(AAudio_convertResultToText)(res));
1308 // Expected when the stream is paused.
1309 *latency = stm->latest_output_latency;
1310 return CUBEB_OK;
1311 }
1312
1313 int64_t read = WRAP(AAudioStream_getFramesRead)(stm->ostream);
1314
1315 *latency = stm->latest_output_latency = read - pos;
1316 LOG("aaudio_stream_get_latency, %u", *latency);
1317
1318 return CUBEB_OK;
1319 }
1320
1321 static int
aaudio_stream_get_input_latency(cubeb_stream * stm,uint32_t * latency)1322 aaudio_stream_get_input_latency(cubeb_stream * stm, uint32_t * latency)
1323 {
1324 int64_t pos;
1325 int64_t ns;
1326 aaudio_result_t res;
1327
1328 if (!stm->istream) {
1329 LOG("error: aaudio_stream_get_input_latency on an ouput-only stream");
1330 return CUBEB_ERROR;
1331 }
1332
1333 res =
1334 WRAP(AAudioStream_getTimestamp)(stm->istream, CLOCK_MONOTONIC, &pos, &ns);
1335 if (res != AAUDIO_OK) {
1336 // Expected when the stream is paused.
1337 LOG("aaudio_stream_get_input_latency, AAudioStream_getTimestamp: %s, "
1338 "returning memoized value",
1339 WRAP(AAudio_convertResultToText)(res));
1340 *latency = stm->latest_input_latency;
1341 return CUBEB_OK;
1342 }
1343
1344 int64_t written = WRAP(AAudioStream_getFramesWritten)(stm->istream);
1345
1346 *latency = stm->latest_input_latency = written - pos;
1347 LOG("aaudio_stream_get_input_latency, %u", *latency);
1348
1349 return CUBEB_OK;
1350 }
1351
1352 static int
aaudio_stream_set_volume(cubeb_stream * stm,float volume)1353 aaudio_stream_set_volume(cubeb_stream * stm, float volume)
1354 {
1355 assert(stm && stm->in_use.load() && stm->ostream);
1356 stm->volume.store(volume);
1357 return CUBEB_OK;
1358 }
1359
1360 aaudio_data_callback_result_t
dummy_callback(AAudioStream * stream,void * userData,void * audioData,int32_t numFrames)1361 dummy_callback(AAudioStream * stream, void * userData, void * audioData,
1362 int32_t numFrames)
1363 {
1364 return AAUDIO_CALLBACK_RESULT_STOP;
1365 }
1366
1367 // Returns a dummy stream with all default settings
1368 static AAudioStream *
init_dummy_stream()1369 init_dummy_stream()
1370 {
1371 AAudioStreamBuilder * streamBuilder;
1372 aaudio_result_t res;
1373 res = WRAP(AAudio_createStreamBuilder)(&streamBuilder);
1374 if (res != AAUDIO_OK) {
1375 LOG("init_dummy_stream: AAudio_createStreamBuilder: %s",
1376 WRAP(AAudio_convertResultToText)(res));
1377 return nullptr;
1378 }
1379 WRAP(AAudioStreamBuilder_setDataCallback)
1380 (streamBuilder, dummy_callback, nullptr);
1381 WRAP(AAudioStreamBuilder_setPerformanceMode)
1382 (streamBuilder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
1383
1384 AAudioStream * stream;
1385 res = WRAP(AAudioStreamBuilder_openStream)(streamBuilder, &stream);
1386 if (res != AAUDIO_OK) {
1387 LOG("init_dummy_stream: AAudioStreamBuilder_openStream %s",
1388 WRAP(AAudio_convertResultToText)(res));
1389 return nullptr;
1390 }
1391 WRAP(AAudioStreamBuilder_delete)(streamBuilder);
1392
1393 return stream;
1394 }
1395
1396 static void
destroy_dummy_stream(AAudioStream * stream)1397 destroy_dummy_stream(AAudioStream * stream)
1398 {
1399 WRAP(AAudioStream_close)(stream);
1400 }
1401
1402 static int
aaudio_get_min_latency(cubeb * ctx,cubeb_stream_params params,uint32_t * latency_frames)1403 aaudio_get_min_latency(cubeb * ctx, cubeb_stream_params params,
1404 uint32_t * latency_frames)
1405 {
1406 AAudioStream * stream = init_dummy_stream();
1407
1408 if (!stream) {
1409 return CUBEB_ERROR;
1410 }
1411
1412 // https://android.googlesource.com/platform/compatibility/cdd/+/refs/heads/master/5_multimedia/5_6_audio-latency.md
1413 *latency_frames = WRAP(AAudioStream_getFramesPerBurst)(stream);
1414
1415 LOG("aaudio_get_min_latency: %u frames", *latency_frames);
1416
1417 destroy_dummy_stream(stream);
1418
1419 return CUBEB_OK;
1420 }
1421
1422 int
aaudio_get_preferred_sample_rate(cubeb * ctx,uint32_t * rate)1423 aaudio_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
1424 {
1425 AAudioStream * stream = init_dummy_stream();
1426
1427 if (!stream) {
1428 return CUBEB_ERROR;
1429 }
1430
1431 *rate = WRAP(AAudioStream_getSampleRate)(stream);
1432
1433 LOG("aaudio_get_preferred_sample_rate %uHz", *rate);
1434
1435 destroy_dummy_stream(stream);
1436
1437 return CUBEB_OK;
1438 }
1439
1440 extern "C" int
1441 aaudio_init(cubeb ** context, char const * context_name);
1442
1443 const static struct cubeb_ops aaudio_ops = {
1444 /*.init =*/aaudio_init,
1445 /*.get_backend_id =*/aaudio_get_backend_id,
1446 /*.get_max_channel_count =*/aaudio_get_max_channel_count,
1447 /* .get_min_latency =*/aaudio_get_min_latency,
1448 /*.get_preferred_sample_rate =*/aaudio_get_preferred_sample_rate,
1449 /*.enumerate_devices =*/NULL,
1450 /*.device_collection_destroy =*/NULL,
1451 /*.destroy =*/aaudio_destroy,
1452 /*.stream_init =*/aaudio_stream_init,
1453 /*.stream_destroy =*/aaudio_stream_destroy,
1454 /*.stream_start =*/aaudio_stream_start,
1455 /*.stream_stop =*/aaudio_stream_stop,
1456 /*.stream_get_position =*/aaudio_stream_get_position,
1457 /*.stream_get_latency =*/aaudio_stream_get_latency,
1458 /*.stream_get_input_latency =*/aaudio_stream_get_input_latency,
1459 /*.stream_set_volume =*/aaudio_stream_set_volume,
1460 /*.stream_set_name =*/NULL,
1461 /*.stream_get_current_device =*/NULL,
1462 /*.stream_device_destroy =*/NULL,
1463 /*.stream_register_device_changed_callback =*/NULL,
1464 /*.register_device_collection_changed =*/NULL};
1465
1466 extern "C" /*static*/ int
aaudio_init(cubeb ** context,char const *)1467 aaudio_init(cubeb ** context, char const * /* context_name */)
1468 {
1469 // load api
1470 void * libaaudio = NULL;
1471 #ifndef DISABLE_LIBAAUDIO_DLOPEN
1472 libaaudio = dlopen("libaaudio.so", RTLD_NOW);
1473 if (!libaaudio) {
1474 return CUBEB_ERROR;
1475 }
1476
1477 #define LOAD(x) \
1478 { \
1479 cubeb_##x = (decltype(x) *)(dlsym(libaaudio, #x)); \
1480 if (!WRAP(x)) { \
1481 LOG("AAudio: Failed to load %s", #x); \
1482 dlclose(libaaudio); \
1483 return CUBEB_ERROR; \
1484 } \
1485 }
1486
1487 LIBAAUDIO_API_VISIT(LOAD);
1488 #undef LOAD
1489 #endif
1490
1491 cubeb * ctx = new cubeb;
1492 ctx->ops = &aaudio_ops;
1493 ctx->libaaudio = libaaudio;
1494
1495 ctx->state.thread = std::thread(state_thread, ctx);
1496
1497 // NOTE: using platform-specific APIs we could set the priority of the
1498 // notifier thread lower than the priority of the state thread.
1499 // This way, it's more likely that the state thread will be woken up
1500 // by the condition variable signal when both are currently waiting
1501 ctx->state.notifier = std::thread(notifier_thread, ctx);
1502
1503 *context = ctx;
1504 return CUBEB_OK;
1505 }
1506