1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
10 #include "nsIThread.h"
11 #include "AudioBufferUtils.h"
12 #include "AudioMixer.h"
13 #include "AudioSegment.h"
15 #include "mozilla/Atomics.h"
16 #include "mozilla/dom/AudioContext.h"
17 #include "mozilla/DataMutex.h"
18 #include "mozilla/SharedThreadPool.h"
19 #include "mozilla/StaticPtr.h"
20 #include "WavDumper.h"
27 class nsAutoRefTraits
<cubeb_stream
> : public nsPointerRefTraits
<cubeb_stream
> {
29 static void Release(cubeb_stream
* aStream
) { cubeb_stream_destroy(aStream
); }
34 // A thread pool containing only one thread to execute the cubeb operations. We
35 // should always use this thread to init, destroy, start, or stop cubeb streams,
36 // to avoid data racing or deadlock issues across platforms.
37 #define CUBEB_TASK_THREAD SharedThreadPool::Get("CubebOperation"_ns, 1)
40 * Assume we can run an iteration of the MediaTrackGraph loop in this much time
42 * We try to run the control loop at this rate.
44 static const int MEDIA_GRAPH_TARGET_PERIOD_MS
= 10;
47 * Assume that we might miss our scheduled wakeup of the MediaTrackGraph by
50 static const int SCHEDULE_SAFETY_MARGIN_MS
= 10;
53 * Try have this much audio buffered in streams and queued to the hardware.
54 * The maximum delay to the end of the next control loop
55 * is 2*MEDIA_GRAPH_TARGET_PERIOD_MS + SCHEDULE_SAFETY_MARGIN_MS.
56 * There is no point in buffering more audio than this in a stream at any
57 * given time (until we add processing).
58 * This is not optimal yet.
60 static const int AUDIO_TARGET_MS
=
61 2 * MEDIA_GRAPH_TARGET_PERIOD_MS
+ SCHEDULE_SAFETY_MARGIN_MS
;
64 * After starting a fallback driver, wait this long before attempting to re-init
65 * the audio stream the first time.
67 static const int AUDIO_INITIAL_FALLBACK_BACKOFF_STEP_MS
= 10;
70 * The backoff step duration for when to next attempt to re-init the audio
71 * stream is capped at this value.
73 static const int AUDIO_MAX_FALLBACK_BACKOFF_STEP_MS
= 1000;
75 class AudioCallbackDriver
;
78 class OfflineClockDriver
;
79 class SystemClockDriver
;
82 enum class AudioContextOperation
: uint8_t;
85 struct GraphInterface
: public nsISupports
{
87 * Object returned from OneIteration() instructing the iterating GraphDriver
90 * - If the result is StillProcessing: keep the iterations coming.
91 * - If the result is Stop: the driver potentially updates its internal state
92 * and interacts with the graph (e.g., NotifyOutputData), then it must call
93 * Stopped() exactly once.
94 * - If the result is SwitchDriver: the driver updates internal state as for
95 * the Stop result, then it must call Switched() exactly once and start
98 class IterationResult final
{
100 struct StillProcessing
{};
102 explicit Stop(RefPtr
<Runnable
> aStoppedRunnable
)
103 : mStoppedRunnable(std::move(aStoppedRunnable
)) {}
104 Stop(const Stop
&) = delete;
105 Stop(Stop
&& aOther
) noexcept
106 : mStoppedRunnable(std::move(aOther
.mStoppedRunnable
)) {}
107 ~Stop() { MOZ_ASSERT(!mStoppedRunnable
); }
108 RefPtr
<Runnable
> mStoppedRunnable
;
110 mStoppedRunnable
->Run();
111 mStoppedRunnable
= nullptr;
114 struct SwitchDriver
{
115 SwitchDriver(RefPtr
<GraphDriver
> aDriver
,
116 RefPtr
<Runnable
> aSwitchedRunnable
)
117 : mDriver(std::move(aDriver
)),
118 mSwitchedRunnable(std::move(aSwitchedRunnable
)) {}
119 SwitchDriver(const SwitchDriver
&) = delete;
120 SwitchDriver(SwitchDriver
&& aOther
) noexcept
121 : mDriver(std::move(aOther
.mDriver
)),
122 mSwitchedRunnable(std::move(aOther
.mSwitchedRunnable
)) {}
123 ~SwitchDriver() { MOZ_ASSERT(!mSwitchedRunnable
); }
124 RefPtr
<GraphDriver
> mDriver
;
125 RefPtr
<Runnable
> mSwitchedRunnable
;
127 mSwitchedRunnable
->Run();
128 mSwitchedRunnable
= nullptr;
131 Variant
<Undefined
, StillProcessing
, Stop
, SwitchDriver
> mResult
;
133 explicit IterationResult(StillProcessing
&& aArg
)
134 : mResult(std::move(aArg
)) {}
135 explicit IterationResult(Stop
&& aArg
) : mResult(std::move(aArg
)) {}
136 explicit IterationResult(SwitchDriver
&& aArg
) : mResult(std::move(aArg
)) {}
139 IterationResult() : mResult(Undefined()) {}
140 IterationResult(const IterationResult
&) = delete;
141 IterationResult(IterationResult
&&) = default;
143 IterationResult
& operator=(const IterationResult
&) = delete;
144 IterationResult
& operator=(IterationResult
&&) = default;
146 static IterationResult
CreateStillProcessing() {
147 return IterationResult(StillProcessing());
149 static IterationResult
CreateStop(RefPtr
<Runnable
> aStoppedRunnable
) {
150 return IterationResult(Stop(std::move(aStoppedRunnable
)));
152 static IterationResult
CreateSwitchDriver(
153 RefPtr
<GraphDriver
> aDriver
, RefPtr
<Runnable
> aSwitchedRunnable
) {
154 return IterationResult(
155 SwitchDriver(std::move(aDriver
), std::move(aSwitchedRunnable
)));
158 bool IsStillProcessing() const { return mResult
.is
<StillProcessing
>(); }
159 bool IsStop() const { return mResult
.is
<Stop
>(); }
160 bool IsSwitchDriver() const { return mResult
.is
<SwitchDriver
>(); }
163 MOZ_ASSERT(IsStop());
164 mResult
.as
<Stop
>().Stopped();
167 GraphDriver
* NextDriver() const {
168 if (!IsSwitchDriver()) {
171 return mResult
.as
<SwitchDriver
>().mDriver
;
175 MOZ_ASSERT(IsSwitchDriver());
176 mResult
.as
<SwitchDriver
>().Switched();
180 /* Called on the graph thread after an AudioCallbackDriver with an input
181 * stream has stopped. */
182 virtual void NotifyInputStopped() = 0;
183 /* Called on the graph thread when there is new input data for listeners. This
184 * is the raw audio input for this MediaTrackGraph. */
185 virtual void NotifyInputData(const AudioDataValue
* aBuffer
, size_t aFrames
,
186 TrackRate aRate
, uint32_t aChannels
,
187 uint32_t aAlreadyBuffered
) = 0;
188 /* Called every time there are changes to input/output audio devices like
189 * plug/unplug etc. This can be called on any thread, and posts a message to
190 * the main thread so that it can post a message to the graph thread. */
191 virtual void DeviceChanged() = 0;
192 /* Called by GraphDriver to iterate the graph. Mixed audio output from the
193 * graph is passed into aMixerReceiver, if it is non-null. */
194 virtual IterationResult
OneIteration(
195 GraphTime aStateComputedEnd
, GraphTime aIterationEnd
,
196 MixerCallbackReceiver
* aMixerReceiver
) = 0;
198 /* True if we're on aDriver's thread, or if we're on mGraphRunner's thread
199 * and mGraphRunner is currently run by aDriver. */
200 virtual bool InDriverIteration(const GraphDriver
* aDriver
) const = 0;
205 * A driver is responsible for the scheduling of the processing, the thread
206 * management, and give the different clocks to a MediaTrackGraph. This is an
207 * abstract base class. A MediaTrackGraph can be driven by an
208 * OfflineClockDriver, if the graph is offline, or a SystemClockDriver or an
209 * AudioCallbackDriver, if the graph is real time.
210 * A MediaTrackGraph holds an owning reference to its driver.
212 * The lifetime of drivers is a complicated affair. Here are the different
213 * scenarii that can happen:
215 * Starting a MediaTrackGraph with an AudioCallbackDriver
216 * - A new thread T is created, from the main thread.
217 * - On this thread T, cubeb is initialized if needed, and a cubeb_stream is
218 * created and started
219 * - The thread T posts a message to the main thread to terminate itself.
220 * - The graph runs off the audio thread
222 * Starting a MediaTrackGraph with a SystemClockDriver:
223 * - A new thread T is created from the main thread.
224 * - The graph runs off this thread.
226 * Switching from a SystemClockDriver to an AudioCallbackDriver:
227 * - At the end of the MTG iteration, the graph tells the current driver to
228 * switch to an AudioCallbackDriver, which is created and initialized on the
230 * - At the end of the MTG iteration, the SystemClockDriver transfers its timing
231 * info and a reference to itself to the AudioCallbackDriver. It then starts
232 * the AudioCallbackDriver.
233 * - When the AudioCallbackDriver starts, it:
234 * - Starts a fallback SystemClockDriver that runs until the
235 * AudioCallbackDriver is running, in case it takes a long time to start (it
236 * could block on I/O, e.g., negotiating a bluetooth connection).
237 * - Checks if it has been switched from a SystemClockDriver, and if that is
238 * the case, sends a message to the main thread to shut the
239 * SystemClockDriver thread down.
240 * - When the AudioCallbackDriver is running, data callbacks are blocked. The
241 * fallback driver detects this in its callback and stops itself. The first
242 * DataCallback after the fallback driver had stopped goes through.
243 * - The graph now runs off an audio callback.
245 * Switching from an AudioCallbackDriver to a SystemClockDriver:
246 * - At the end of the MTG iteration, the graph tells the current driver to
247 * switch to a SystemClockDriver.
248 * - the AudioCallbackDriver transfers its timing info and a reference to itself
249 * to the SystemClockDriver. A new SystemClockDriver is started from the
250 * current audio thread.
251 * - When starting, the SystemClockDriver checks if it has been switched from an
252 * AudioCallbackDriver. If yes, it creates a new temporary thread to release
253 * the cubeb_streams. This temporary thread closes the cubeb_stream, and then
254 * dispatches a message to the main thread to be terminated.
255 * - The graph now runs off a normal thread.
257 * Two drivers cannot run at the same time for the same graph. The thread safety
258 * of the different members of drivers, and their access pattern is documented
259 * next to the members themselves.
263 using IterationResult
= GraphInterface::IterationResult
;
265 GraphDriver(GraphInterface
* aGraphInterface
, GraphDriver
* aPreviousDriver
,
266 uint32_t aSampleRate
);
268 NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
270 /* Start the graph, init the driver, start the thread.
271 * A driver cannot be started twice, it must be shutdown
272 * before being started again. */
273 virtual void Start() = 0;
274 /* Shutdown GraphDriver */
275 MOZ_CAN_RUN_SCRIPT
virtual void Shutdown() = 0;
276 /* Set the UTF-8 name for system audio streams.
277 * Graph thread, or main thread if the graph is not running. */
278 virtual void SetStreamName(const nsACString
& aStreamName
);
279 /* Rate at which the GraphDriver runs, in ms. This can either be user
280 * controlled (because we are using a {System,Offline}ClockDriver, and decide
281 * how often we want to wakeup/how much we want to process per iteration), or
282 * it can be indirectly set by the latency of the audio backend, and the
283 * number of buffers of this audio backend: say we have four buffers, and 40ms
284 * latency, we will get a callback approximately every 10ms. */
285 virtual uint32_t IterationDuration() = 0;
287 * Signaled by the graph when it needs another iteration. Goes unhandled for
288 * GraphDrivers that are not able to sleep indefinitely (i.e., all drivers but
289 * ThreadedDriver). Can be called on any thread.
291 virtual void EnsureNextIteration() = 0;
293 // Those are simply for accessing the associated pointer. Graph thread only,
294 // or if one is not running, main thread.
295 GraphDriver
* PreviousDriver();
296 void SetPreviousDriver(GraphDriver
* aPreviousDriver
);
298 virtual AudioCallbackDriver
* AsAudioCallbackDriver() { return nullptr; }
299 virtual const AudioCallbackDriver
* AsAudioCallbackDriver() const {
303 virtual OfflineClockDriver
* AsOfflineClockDriver() { return nullptr; }
304 virtual const OfflineClockDriver
* AsOfflineClockDriver() const {
308 virtual SystemClockDriver
* AsSystemClockDriver() { return nullptr; }
309 virtual const SystemClockDriver
* AsSystemClockDriver() const {
314 * Set the state of the driver so it can start at the right point in time,
315 * after switching from another driver.
317 void SetState(const nsACString
& aStreamName
, GraphTime aIterationEnd
,
318 GraphTime aStateComputedTime
);
320 GraphInterface
* Graph() const { return mGraphInterface
; }
323 // True if the current thread is currently iterating the MTG.
324 bool InIteration() const;
326 // True if the current thread is the GraphDriver's thread.
327 virtual bool OnThread() const = 0;
328 // GraphDriver's thread has started and the thread is running.
329 virtual bool ThreadRunning() const = 0;
331 double MediaTimeToSeconds(GraphTime aTime
) const {
332 NS_ASSERTION(aTime
> -TRACK_TIME_MAX
&& aTime
<= TRACK_TIME_MAX
,
334 return static_cast<double>(aTime
) / mSampleRate
;
337 GraphTime
SecondsToMediaTime(double aS
) const {
338 NS_ASSERTION(0 <= aS
&& aS
<= TRACK_TICKS_MAX
/ TRACK_RATE_MAX
,
340 return mSampleRate
* aS
;
343 GraphTime
MillisecondsToMediaTime(int32_t aMS
) const {
344 return RateConvertTicksRoundDown(mSampleRate
, 1000, aMS
);
348 // The UTF-8 name for system audio streams. Graph thread.
349 nsCString mStreamName
;
350 // Time of the end of this graph iteration.
351 GraphTime mIterationEnd
= 0;
352 // Time until which the graph has processed data.
353 GraphTime mStateComputedTime
= 0;
354 // The GraphInterface this driver is currently iterating.
355 const RefPtr
<GraphInterface
> mGraphInterface
;
356 // The sample rate for the graph, and in case of an audio driver, also for the
358 const uint32_t mSampleRate
;
360 // This is non-null only when this driver has recently switched from an other
361 // driver, and has not cleaned it up yet (for example because the audio stream
362 // is currently calling the callback during initialization).
364 // This is written to when changing driver, from the previous driver's thread,
365 // or a thread created for the occasion. This is read each time we need to
366 // check whether we're changing driver (in Switching()), from the graph
368 // This must be accessed using the {Set,Get}PreviousDriver methods.
369 RefPtr
<GraphDriver
> mPreviousDriver
;
371 virtual ~GraphDriver() = default;
374 class MediaTrackGraphInitThreadRunnable
;
377 * This class is a driver that manages its own thread.
379 class ThreadedDriver
: public GraphDriver
{
380 class IterationWaitHelper
{
381 Monitor mMonitor MOZ_UNANNOTATED
;
382 // The below members are guarded by mMonitor.
383 bool mNeedAnotherIteration
= false;
387 IterationWaitHelper() : mMonitor("IterationWaitHelper::mMonitor") {}
390 * If another iteration is needed we wait for aDuration, otherwise we wait
391 * for a wake-up. If a wake-up occurs before aDuration time has passed, we
392 * wait for aDuration nonetheless.
394 void WaitForNextIterationAtLeast(TimeDuration aDuration
) {
395 MonitorAutoLock
lock(mMonitor
);
396 TimeStamp now
= TimeStamp::Now();
397 mWakeTime
= now
+ aDuration
;
399 if (mNeedAnotherIteration
&& now
>= mWakeTime
) {
402 if (mNeedAnotherIteration
) {
403 lock
.Wait(mWakeTime
- now
);
405 lock
.Wait(TimeDuration::Forever());
407 now
= TimeStamp::Now();
409 mWakeTime
= TimeStamp();
410 mNeedAnotherIteration
= false;
414 * Sets mNeedAnotherIteration to true and notifies the monitor, in case a
415 * driver is currently waiting.
417 void EnsureNextIteration() {
418 MonitorAutoLock
lock(mMonitor
);
419 mNeedAnotherIteration
= true;
425 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ThreadedDriver
, override
);
427 ThreadedDriver(GraphInterface
* aGraphInterface
, GraphDriver
* aPreviousDriver
,
428 uint32_t aSampleRate
);
430 void EnsureNextIteration() override
;
431 void Start() override
;
432 MOZ_CAN_RUN_SCRIPT
void Shutdown() override
;
434 * Runs main control loop on the graph thread. Normally a single invocation
435 * of this runs for the entire lifetime of the graph thread.
437 virtual void RunThread();
438 friend class MediaTrackGraphInitThreadRunnable
;
439 uint32_t IterationDuration() override
{ return MEDIA_GRAPH_TARGET_PERIOD_MS
; }
441 nsIThread
* Thread() const { return mThread
; }
443 bool OnThread() const override
{
444 return !mThread
|| mThread
->IsOnCurrentThread();
447 bool ThreadRunning() const override
{ return mThreadRunning
; }
450 /* Waits until it's time to process more data. */
451 void WaitForNextIteration();
452 /* Implementation dependent time the ThreadedDriver should wait between
454 virtual TimeDuration
WaitInterval() = 0;
455 /* When the graph wakes up to do an iteration, implementations return the
456 * range of time that will be processed. This is called only once per
457 * iteration; it may determine the interval from state in a previous
459 virtual MediaTime
GetIntervalForIteration() = 0;
461 virtual ~ThreadedDriver();
463 nsCOMPtr
<nsIThread
> mThread
;
466 // This is true if the thread is running. It is false
467 // before starting the thread and after stopping it.
468 Atomic
<bool> mThreadRunning
;
471 IterationWaitHelper mWaitHelper
;
475 * A SystemClockDriver drives a GraphInterface using a system clock, and waits
476 * using a monitor, between each iteration.
478 class SystemClockDriver
: public ThreadedDriver
{
480 SystemClockDriver(GraphInterface
* aGraphInterface
,
481 GraphDriver
* aPreviousDriver
, uint32_t aSampleRate
);
482 virtual ~SystemClockDriver();
483 SystemClockDriver
* AsSystemClockDriver() override
{ return this; }
484 const SystemClockDriver
* AsSystemClockDriver() const override
{ return this; }
487 /* Return the TimeDuration to wait before the next rendering iteration. */
488 TimeDuration
WaitInterval() override
;
489 MediaTime
GetIntervalForIteration() override
;
492 // Those are only modified (after initialization) on the graph thread. The
493 // graph thread does not run during the initialization.
494 TimeStamp mInitialTimeStamp
;
495 TimeStamp mCurrentTimeStamp
;
496 TimeStamp mLastTimeStamp
;
500 * An OfflineClockDriver runs the graph as fast as possible, without waiting
503 class OfflineClockDriver
: public ThreadedDriver
{
505 OfflineClockDriver(GraphInterface
* aGraphInterface
, uint32_t aSampleRate
,
507 virtual ~OfflineClockDriver();
508 OfflineClockDriver
* AsOfflineClockDriver() override
{ return this; }
509 const OfflineClockDriver
* AsOfflineClockDriver() const override
{
513 void RunThread() override
;
516 TimeDuration
WaitInterval() override
{ return TimeDuration(); }
517 MediaTime
GetIntervalForIteration() override
;
520 // Time, in GraphTime, for each iteration
524 enum class AudioInputType
{ Unknown
, Voice
};
527 * This is a graph driver that is based on callback functions called by the
528 * audio api. This ensures minimal audio latency, because it means there is no
529 * buffering happening: the audio is generated inside the callback.
531 * This design is less flexible than running our own thread:
532 * - We have no control over the thread:
533 * - It cannot block, and it has to run for a shorter amount of time than the
534 * buffer it is going to fill, or an under-run is going to occur (short burst
535 * of silence in the final audio output).
536 * - We can't know for sure when the callback function is going to be called
537 * (although we compute an estimation so we can schedule video frames)
538 * - Creating and shutting the thread down is a blocking operation, that can
539 * take _seconds_ in some cases (because IPC has to be set up, and
540 * sometimes hardware components are involved and need to be warmed up)
541 * - We have no control on how much audio we generate, we have to return exactly
542 * the number of frames asked for by the callback. Since for the Web Audio
543 * API, we have to do block processing at 128 frames per block, we need to
544 * keep a little spill buffer to store the extra frames.
546 class AudioCallbackDriver
: public GraphDriver
, public MixerCallbackReceiver
{
547 using IterationResult
= GraphInterface::IterationResult
;
548 enum class FallbackDriverState
;
549 class FallbackWrapper
;
552 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioCallbackDriver
, override
);
554 /** If aInputChannelCount is zero, then this driver is output-only. */
555 AudioCallbackDriver(GraphInterface
* aGraphInterface
,
556 GraphDriver
* aPreviousDriver
, uint32_t aSampleRate
,
557 uint32_t aOutputChannelCount
, uint32_t aInputChannelCount
,
558 CubebUtils::AudioDeviceID aOutputDeviceID
,
559 CubebUtils::AudioDeviceID aInputDeviceID
,
560 AudioInputType aAudioInputType
);
562 void Start() override
;
563 MOZ_CAN_RUN_SCRIPT
void Shutdown() override
;
564 void SetStreamName(const nsACString
& aStreamName
) override
;
566 /* Static wrapper function cubeb calls back. */
567 static long DataCallback_s(cubeb_stream
* aStream
, void* aUser
,
568 const void* aInputBuffer
, void* aOutputBuffer
,
570 static void StateCallback_s(cubeb_stream
* aStream
, void* aUser
,
572 static void DeviceChangedCallback_s(void* aUser
);
574 /* This function is called by the underlying audio backend when a refill is
575 * needed. This is what drives the whole graph when it is used to output
576 * audio. If the return value is exactly aFrames, this function will get
577 * called again. If it is less than aFrames, the stream will go in draining
578 * mode, and this function will not be called again. */
579 long DataCallback(const AudioDataValue
* aInputBuffer
,
580 AudioDataValue
* aOutputBuffer
, long aFrames
);
581 /* This function is called by the underlying audio backend, but is only used
582 * for informational purposes at the moment. */
583 void StateCallback(cubeb_state aState
);
584 /* This is an approximation of the number of millisecond there are between two
585 * iterations of the graph. */
586 uint32_t IterationDuration() override
;
587 /* If the audio stream has started, this does nothing. There will be another
588 * iteration. If there is an active fallback driver, we forward the call so it
590 void EnsureNextIteration() override
;
592 /* This function gets called when the graph has produced the audio frames for
594 void MixerCallback(AudioChunk
* aMixedBuffer
, uint32_t aSampleRate
) override
;
596 AudioCallbackDriver
* AsAudioCallbackDriver() override
{ return this; }
597 const AudioCallbackDriver
* AsAudioCallbackDriver() const override
{
601 uint32_t OutputChannelCount() { return mOutputChannelCount
; }
603 uint32_t InputChannelCount() { return mInputChannelCount
; }
605 AudioInputType
InputDevicePreference() {
606 if (mInputDevicePreference
== CUBEB_DEVICE_PREF_VOICE
) {
607 return AudioInputType::Voice
;
609 return AudioInputType::Unknown
;
612 std::thread::id
ThreadId() const { return mAudioThreadIdInCb
.load(); }
614 /* Called when the thread servicing the callback has changed. This can be
615 * fairly expensive */
616 void OnThreadIdChanged();
617 /* Called at the beginning of the audio callback to check if the thread id has
619 bool CheckThreadIdChanged();
621 bool OnThread() const override
{
622 return mAudioThreadIdInCb
.load() == std::this_thread::get_id();
625 /* Returns true if this driver has started (perhaps with a fallback driver)
626 * and not yet stopped. */
627 bool ThreadRunning() const override
{
628 return mAudioStreamState
== AudioStreamState::Running
||
629 mFallbackDriverState
== FallbackDriverState::Running
;
632 /* Whether the underlying cubeb stream has been started and has not stopped
634 bool IsStarted() { return mAudioStreamState
> AudioStreamState::Starting
; };
636 // Returns the output latency for the current audio output stream.
637 TimeDuration
AudioOutputLatency();
639 /* Returns true if this driver is currently driven by the fallback driver. */
640 bool OnFallback() const;
644 * On certain MacBookPro, the microphone is located near the left speaker.
645 * We need to pan the sound output to the right speaker if we are using the
646 * mic and the built-in speaker, or we will have terrible echo. */
647 void PanOutputIfNeeded(bool aMicrophoneActive
);
649 * This is called when the output device used by the cubeb stream changes. */
650 void DeviceChangedCallback();
651 /* Start the cubeb stream */
653 friend class MediaTrackGraphInitThreadRunnable
;
654 void Init(const nsCString
& aStreamName
);
655 void SetCubebStreamName(const nsCString
& aStreamName
);
658 * Fall back to a SystemClockDriver using a normal thread. If needed,
659 * the graph will try to re-open an audio stream later. */
660 void FallbackToSystemClockDriver();
661 /* Called by the fallback driver when it has fully stopped, after finishing
662 * its last iteration. If it stopped after the audio stream started, aState
663 * will be None. If it stopped after the graph told it to stop, or switch,
664 * aState will be Stopped. Hands over state to the audio driver that may
665 * iterate the graph after this has been called. */
666 void FallbackDriverStopped(GraphTime aIterationEnd
,
667 GraphTime aStateComputedTime
,
668 FallbackDriverState aState
);
670 /* Called at the end of the fallback driver's iteration to see whether we
671 * should attempt to start the AudioStream again. */
672 void MaybeStartAudioStream();
674 /* This is true when the method is executed on CubebOperation thread pool. */
675 bool OnCubebOperationThread() {
676 return mCubebOperationThread
->IsOnCurrentThreadInfallible();
679 /* MediaTrackGraphs are always down/up mixed to output channels. */
680 const uint32_t mOutputChannelCount
;
681 /* The size of this buffer comes from the fact that some audio backends can
682 * call back with a number of frames lower than one block (128 frames), so we
683 * need to keep at most two block in the SpillBuffer, because we always round
684 * up to block boundaries during an iteration.
685 * This is only ever accessed on the audio callback thread. */
686 SpillBuffer
<AudioDataValue
, WEBAUDIO_BLOCK_SIZE
* 2> mScratchBuffer
;
687 /* Wrapper to ensure we write exactly the number of frames we need in the
688 * audio buffer cubeb passes us. This is only ever accessed on the audio
689 * callback thread. */
690 AudioCallbackBufferWrapper
<AudioDataValue
> mBuffer
;
691 /* cubeb stream for this graph. This is non-null after a successful
692 * cubeb_stream_init(). CubebOperation thread only. */
693 nsAutoRef
<cubeb_stream
> mAudioStream
;
694 /* The number of input channels from cubeb. Set before opening cubeb. If it is
695 * zero then the driver is output-only. */
696 const uint32_t mInputChannelCount
;
698 * Devices to use for cubeb input & output, or nullptr for default device.
700 const CubebUtils::AudioDeviceID mOutputDeviceID
;
701 const CubebUtils::AudioDeviceID mInputDeviceID
;
702 /* Approximation of the time between two callbacks. This is used to schedule
703 * video frames. This is in milliseconds. Only even used (after
704 * inizatialization) on the audio callback thread. */
705 uint32_t mIterationDurationMS
;
707 struct AutoInCallback
{
708 explicit AutoInCallback(AudioCallbackDriver
* aDriver
);
710 AudioCallbackDriver
* mDriver
;
713 /* Shared thread pool with up to one thread for off-main-thread
714 * initialization and shutdown of the audio stream and for other tasks that
715 * must run serially for access to mAudioStream. */
716 const RefPtr
<SharedThreadPool
> mCubebOperationThread
;
717 cubeb_device_pref mInputDevicePreference
;
718 /* Contains the id of the audio thread, from profiler_current_thread_id. */
719 std::atomic
<ProfilerThreadId
> mAudioThreadId
;
720 /* This allows implementing AutoInCallback. This is equal to the current
721 * thread id when in an audio callback, and is an invalid thread id otherwise.
723 std::atomic
<std::thread::id
> mAudioThreadIdInCb
;
724 /* State of the audio stream, see inline comments. */
725 enum class AudioStreamState
{
726 /* There is no cubeb_stream or mAudioStream is in CUBEB_STATE_ERROR or
727 * CUBEB_STATE_STOPPED and no pending task exists to Init() a new
730 /* A task to Init() a new cubeb_stream is pending. */
732 /* cubeb_start_stream() is about to be or has been called on mAudioStream.
733 * Any previous cubeb_streams have been destroyed. */
735 /* mAudioStream is running. */
737 /* mAudioStream is draining, and will soon stop. */
740 Atomic
<AudioStreamState
> mAudioStreamState
{AudioStreamState::None
};
741 /* State of the fallback driver, see inline comments. */
742 enum class FallbackDriverState
{
743 /* There is no fallback driver. */
745 /* There is a fallback driver trying to iterate us. */
747 /* There was a fallback driver and the graph stopped it. No audio callback
748 may iterate the graph. */
751 Atomic
<FallbackDriverState
> mFallbackDriverState
{FallbackDriverState::None
};
752 /* SystemClockDriver used as fallback if this AudioCallbackDriver fails to
754 DataMutex
<RefPtr
<FallbackWrapper
>> mFallback
;
755 /* If using a fallback driver, this is the duration to wait after failing to
756 * start it before attempting to start it again. */
757 TimeDuration mNextReInitBackoffStep
;
758 /* If using a fallback driver, this is the next time we'll try to start the
760 TimeStamp mNextReInitAttempt
;
762 /* When using the built-in speakers on macbook pro (13 and 15, all models),
763 * it's best to hard pan the audio on the right, to avoid feedback into the
764 * microphone that is located next to the left speaker. */
765 Atomic
<bool> mNeedsPanning
;
768 WavDumper mInputStreamFile
;
769 WavDumper mOutputStreamFile
;
771 virtual ~AudioCallbackDriver();
772 const bool mSandboxed
= false;
775 } // namespace mozilla
777 #endif // GRAPHDRIVER_H_