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