GraphDriver.h (35244B)
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/. */ 5 6 #ifndef GRAPHDRIVER_H_ 7 #define GRAPHDRIVER_H_ 8 9 #include <thread> 10 11 #include "AudioBufferUtils.h" 12 #include "AudioMixer.h" 13 #include "AudioSegment.h" 14 #include "SelfRef.h" 15 #include "WavDumper.h" 16 #include "mozilla/Atomics.h" 17 #include "mozilla/DataMutex.h" 18 #include "mozilla/StaticPtr.h" 19 #include "mozilla/TaskQueue.h" 20 #include "mozilla/dom/AudioContext.h" 21 #include "nsAutoRef.h" 22 #include "nsIThread.h" 23 24 struct cubeb_stream; 25 26 template <> 27 class nsAutoRefTraits<cubeb_stream> : public nsPointerRefTraits<cubeb_stream> { 28 public: 29 static void Release(cubeb_stream* aStream) { cubeb_stream_destroy(aStream); } 30 }; 31 32 namespace mozilla { 33 /** 34 * Assume we can run an iteration of the MediaTrackGraph loop in this much time 35 * or less. 36 * We try to run the control loop at this rate. 37 */ 38 static const int MEDIA_GRAPH_TARGET_PERIOD_MS = 10; 39 /** 40 * The SystemClockDriver does not necessarily wake up as precisely as an 41 * AudioCallbackDriver. SleepConditionVariableSRW() has been observed to wake 42 * almost 30ms late on Windows 10 2009 systems, which implies a lower timer 43 * resolution than the 15.6ms default system-wide timer resolution in Windows. 44 * https://download.microsoft.com/download/3/0/2/3027d574-c433-412a-a8b6-5e0a75d5b237/timer-resolution.docx 45 * 46 * Allow a SystemClockDriver to try to catch up when rendering is up to this 47 * many milliseconds late, so that rendered time is close to clock time. When 48 * later than this threshold, SystemClockDriver will declare bankruptcy and 49 * re-sync target render time with a new clock time. 50 */ 51 static const int SYSTEM_CLOCK_BANKRUPTCY_THRESHOLD_MS = 30; 52 /** 53 * After starting a fallback driver, wait this long before attempting to re-init 54 * the audio stream the first time. 55 */ 56 static const int AUDIO_INITIAL_FALLBACK_BACKOFF_STEP_MS = 10; 57 58 /** 59 * The backoff step duration for when to next attempt to re-init the audio 60 * stream is capped at this value. 61 */ 62 static const int AUDIO_MAX_FALLBACK_BACKOFF_STEP_MS = 1000; 63 64 class AudioCallbackDriver; 65 class GraphDriver; 66 class MediaTrack; 67 class OfflineClockDriver; 68 class SystemClockDriver; 69 70 namespace dom { 71 enum class AudioContextOperation : uint8_t; 72 } 73 74 struct GraphInterface : public nsISupports { 75 /** 76 * Object returned from OneIteration() instructing the iterating GraphDriver 77 * what to do. 78 * 79 * - If the result is StillProcessing: keep the iterations coming. 80 * - If the result is Stop: the driver potentially updates its internal state 81 * and interacts with the graph (e.g., NotifyOutputData), then it must call 82 * Stopped() exactly once. 83 * - If the result is SwitchDriver: the driver updates internal state as for 84 * the Stop result, then it must call Switched() exactly once and start 85 * NextDriver(). 86 */ 87 class IterationResult final { 88 struct Undefined {}; 89 struct StillProcessing {}; 90 struct Stop { 91 explicit Stop(RefPtr<Runnable> aStoppedRunnable) 92 : mStoppedRunnable(std::move(aStoppedRunnable)) {} 93 Stop(const Stop&) = delete; 94 Stop(Stop&& aOther) noexcept 95 : mStoppedRunnable(std::move(aOther.mStoppedRunnable)) {} 96 ~Stop() { MOZ_ASSERT(!mStoppedRunnable); } 97 RefPtr<Runnable> mStoppedRunnable; 98 void Stopped() { 99 mStoppedRunnable->Run(); 100 mStoppedRunnable = nullptr; 101 } 102 }; 103 struct SwitchDriver { 104 SwitchDriver(RefPtr<GraphDriver> aDriver, 105 RefPtr<Runnable> aSwitchedRunnable) 106 : mDriver(std::move(aDriver)), 107 mSwitchedRunnable(std::move(aSwitchedRunnable)) {} 108 SwitchDriver(const SwitchDriver&) = delete; 109 SwitchDriver(SwitchDriver&& aOther) noexcept 110 : mDriver(std::move(aOther.mDriver)), 111 mSwitchedRunnable(std::move(aOther.mSwitchedRunnable)) {} 112 ~SwitchDriver() { MOZ_ASSERT(!mSwitchedRunnable); } 113 RefPtr<GraphDriver> mDriver; 114 RefPtr<Runnable> mSwitchedRunnable; 115 void Switched() { 116 mSwitchedRunnable->Run(); 117 mSwitchedRunnable = nullptr; 118 } 119 }; 120 Variant<Undefined, StillProcessing, Stop, SwitchDriver> mResult; 121 122 explicit IterationResult(StillProcessing&& aArg) 123 : mResult(std::move(aArg)) {} 124 explicit IterationResult(Stop&& aArg) : mResult(std::move(aArg)) {} 125 explicit IterationResult(SwitchDriver&& aArg) : mResult(std::move(aArg)) {} 126 127 public: 128 IterationResult() : mResult(Undefined()) {} 129 IterationResult(const IterationResult&) = delete; 130 IterationResult(IterationResult&&) = default; 131 132 IterationResult& operator=(const IterationResult&) = delete; 133 IterationResult& operator=(IterationResult&&) = default; 134 135 static IterationResult CreateStillProcessing() { 136 return IterationResult(StillProcessing()); 137 } 138 static IterationResult CreateStop(RefPtr<Runnable> aStoppedRunnable) { 139 return IterationResult(Stop(std::move(aStoppedRunnable))); 140 } 141 static IterationResult CreateSwitchDriver( 142 RefPtr<GraphDriver> aDriver, RefPtr<Runnable> aSwitchedRunnable) { 143 return IterationResult( 144 SwitchDriver(std::move(aDriver), std::move(aSwitchedRunnable))); 145 } 146 147 bool IsStillProcessing() const { return mResult.is<StillProcessing>(); } 148 bool IsStop() const { return mResult.is<Stop>(); } 149 bool IsSwitchDriver() const { return mResult.is<SwitchDriver>(); } 150 151 void Stopped() { 152 MOZ_ASSERT(IsStop()); 153 mResult.as<Stop>().Stopped(); 154 } 155 156 GraphDriver* NextDriver() const { 157 if (!IsSwitchDriver()) { 158 return nullptr; 159 } 160 return mResult.as<SwitchDriver>().mDriver; 161 } 162 163 void Switched() { 164 MOZ_ASSERT(IsSwitchDriver()); 165 mResult.as<SwitchDriver>().Switched(); 166 } 167 }; 168 169 /* Called on the graph thread after an AudioCallbackDriver with an input 170 * stream has stopped. */ 171 virtual void NotifyInputStopped() = 0; 172 /* Called on the graph thread when there is new input data for listeners. This 173 * is the raw audio input for this MediaTrackGraph. */ 174 virtual void NotifyInputData(const AudioDataValue* aBuffer, size_t aFrames, 175 TrackRate aRate, uint32_t aChannels, 176 uint32_t aAlreadyBuffered) = 0; 177 /* Called on the main thread after an AudioCallbackDriver has attempted an 178 * operation to set the processing params matching aGeneration on the cubeb 179 * stream. */ 180 virtual void NotifySetRequestedInputProcessingParamsResult( 181 AudioCallbackDriver* aDriver, int aGeneration, 182 Result<cubeb_input_processing_params, int>&& aResult) = 0; 183 /* Called every time there are changes to input/output audio devices like 184 * plug/unplug etc. This can be called on any thread, and posts a message to 185 * the main thread so that it can post a message to the graph thread. */ 186 virtual void DeviceChanged() = 0; 187 /* Called by GraphDriver to iterate the graph. Mixed audio output from the 188 * graph is passed into aMixerReceiver, if it is non-null. */ 189 virtual IterationResult OneIteration( 190 GraphTime aStateComputedEnd, MixerCallbackReceiver* aMixerReceiver) = 0; 191 #ifdef DEBUG 192 /* True if we're on aDriver's thread, or if we're on mGraphRunner's thread 193 * and mGraphRunner is currently run by aDriver. */ 194 virtual bool InDriverIteration(const GraphDriver* aDriver) const = 0; 195 #endif 196 }; 197 198 /** 199 * A driver is responsible for the scheduling of the processing, the thread 200 * management, and give the different clocks to a MediaTrackGraph. This is an 201 * abstract base class. A MediaTrackGraph can be driven by an 202 * OfflineClockDriver, if the graph is offline, or a SystemClockDriver or an 203 * AudioCallbackDriver, if the graph is real time. 204 * A MediaTrackGraph holds an owning reference to its driver. 205 * 206 * The lifetime of drivers is a complicated affair. Here are the different 207 * scenarii that can happen: 208 * 209 * Starting a MediaTrackGraph with an AudioCallbackDriver 210 * - A new thread T is created, from the main thread. 211 * - On this thread T, cubeb is initialized if needed, and a cubeb_stream is 212 * created and started 213 * - The thread T posts a message to the main thread to terminate itself. 214 * - The graph runs off the audio thread 215 * 216 * Starting a MediaTrackGraph with a SystemClockDriver: 217 * - A new thread T is created from the main thread. 218 * - The graph runs off this thread. 219 * 220 * Switching from a SystemClockDriver to an AudioCallbackDriver: 221 * - At the end of the MTG iteration, the graph tells the current driver to 222 * switch to an AudioCallbackDriver, which is created and initialized on the 223 * graph thread. 224 * - At the end of the MTG iteration, the SystemClockDriver transfers its timing 225 * info and a reference to itself to the AudioCallbackDriver. It then starts 226 * the AudioCallbackDriver. 227 * - When the AudioCallbackDriver starts, it: 228 * - Starts a fallback SystemClockDriver that runs until the 229 * AudioCallbackDriver is running, in case it takes a long time to start (it 230 * could block on I/O, e.g., negotiating a bluetooth connection). 231 * - Checks if it has been switched from a SystemClockDriver, and if that is 232 * the case, sends a message to the main thread to shut the 233 * SystemClockDriver thread down. 234 * - When the AudioCallbackDriver is running, data callbacks are blocked. The 235 * fallback driver detects this in its callback and stops itself. The first 236 * DataCallback after the fallback driver had stopped goes through. 237 * - The graph now runs off an audio callback. 238 * 239 * Switching from an AudioCallbackDriver to a SystemClockDriver: 240 * - At the end of the MTG iteration, the graph tells the current driver to 241 * switch to a SystemClockDriver. 242 * - the AudioCallbackDriver transfers its timing info and a reference to itself 243 * to the SystemClockDriver. A new SystemClockDriver is started from the 244 * current audio thread. 245 * - When starting, the SystemClockDriver checks if it has been switched from an 246 * AudioCallbackDriver. If yes, it creates a new temporary thread to release 247 * the cubeb_streams. This temporary thread closes the cubeb_stream, and then 248 * dispatches a message to the main thread to be terminated. 249 * - The graph now runs off a normal thread. 250 * 251 * Two drivers cannot run at the same time for the same graph. The thread safety 252 * of the different members of drivers, and their access pattern is documented 253 * next to the members themselves. 254 */ 255 class GraphDriver { 256 public: 257 using IterationResult = GraphInterface::IterationResult; 258 259 GraphDriver(GraphInterface* aGraphInterface, GraphDriver* aPreviousDriver, 260 uint32_t aSampleRate); 261 262 NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING 263 264 /* Start the graph, init the driver, start the thread. 265 * A driver cannot be started twice, it must be shutdown 266 * before being started again. */ 267 virtual void Start() = 0; 268 /* Shutdown GraphDriver */ 269 MOZ_CAN_RUN_SCRIPT virtual void Shutdown() = 0; 270 /* Set the UTF-8 name for system audio streams. 271 * Graph thread, or main thread if the graph is not running. */ 272 virtual void SetStreamName(const nsACString& aStreamName); 273 /* Rate at which the GraphDriver runs, in ms. This can either be user 274 * controlled (because we are using a {System,Offline}ClockDriver, and decide 275 * how often we want to wakeup/how much we want to process per iteration), or 276 * it can be indirectly set by the latency of the audio backend, and the 277 * number of buffers of this audio backend: say we have four buffers, and 40ms 278 * latency, we will get a callback approximately every 10ms. */ 279 virtual TimeDuration IterationDuration() = 0; 280 /* 281 * Signaled by the graph when it needs another iteration. Goes unhandled for 282 * GraphDrivers that are not able to sleep indefinitely (i.e., all drivers but 283 * ThreadedDriver). Can be called on any thread. 284 */ 285 virtual void EnsureNextIteration() = 0; 286 287 // Those are simply for accessing the associated pointer. Graph thread only, 288 // or if one is not running, main thread. 289 GraphDriver* PreviousDriver(); 290 void SetPreviousDriver(GraphDriver* aPreviousDriver); 291 292 virtual AudioCallbackDriver* AsAudioCallbackDriver() { return nullptr; } 293 virtual const AudioCallbackDriver* AsAudioCallbackDriver() const { 294 return nullptr; 295 } 296 297 virtual OfflineClockDriver* AsOfflineClockDriver() { return nullptr; } 298 virtual const OfflineClockDriver* AsOfflineClockDriver() const { 299 return nullptr; 300 } 301 302 virtual SystemClockDriver* AsSystemClockDriver() { return nullptr; } 303 virtual const SystemClockDriver* AsSystemClockDriver() const { 304 return nullptr; 305 } 306 307 /** 308 * Set the state of the driver so it can start at the right point in time, 309 * after switching from another driver. 310 * 311 * aIterationTimeStamp is the system clock time from when rendering began in 312 * the most recent iteration. An audio callback is assumed invoked soon 313 * after the end of the provided portion of the platform audio buffer 314 * becomes available for reading or writing, and so provides a clock edge 315 * such that aCurrentTimeStamp advances consistently with the output time of 316 * the end of the set of frames rendered in each iteration. Actual audio 317 * output time of the last data written would be at least a platform buffer 318 * length after a write buffer portion becomes available. 319 */ 320 void SetState(const nsACString& aStreamName, GraphTime aStateComputedTime, 321 TimeStamp aIterationTimeStamp); 322 323 GraphInterface* Graph() const { return mGraphInterface; } 324 325 #ifdef DEBUG 326 // True if the current thread is currently iterating the MTG. 327 bool InIteration() const; 328 #endif 329 // True if the current thread is the GraphDriver's thread. 330 virtual bool OnThread() const = 0; 331 // GraphDriver's thread has started and the thread is running. 332 virtual bool ThreadRunning() const = 0; 333 334 double MediaTimeToSeconds(MediaTime aTime) const { 335 NS_ASSERTION(aTime > -TRACK_TIME_MAX && aTime <= TRACK_TIME_MAX, 336 "Bad time"); 337 return static_cast<double>(aTime) / mSampleRate; 338 } 339 340 TimeDuration MediaTimeToTimeDuration(MediaTime aTime) const { 341 return TimeDuration::FromSeconds(MediaTimeToSeconds(aTime)); 342 } 343 344 GraphTime SecondsToMediaTime(double aS) const { 345 NS_ASSERTION(0 <= aS && aS <= TRACK_TICKS_MAX / TRACK_RATE_MAX, 346 "Bad seconds"); 347 return mSampleRate * aS; 348 } 349 350 GraphTime MillisecondsToMediaTime(int32_t aMS) const { 351 return RateConvertTicksRoundDown(mSampleRate, 1000, aMS); 352 } 353 354 protected: 355 // The UTF-8 name for system audio streams. Graph thread. 356 nsCString mStreamName; 357 // Time until which the graph has processed data. 358 GraphTime mStateComputedTime = 0; 359 // The system clock time when the iteration should or would start if these 360 // start times advance consistently with the number of frames rendered by 361 // the graph in each iteration. 362 // Initially null, if no previous driver exists to provide a reference time 363 // through SetState(). 364 // SystemClockDriver advances this before waiting to render the next 365 // iteration. 366 // AudioCallbackDriver sets this to approximately now at the start of each 367 // iteration when !HasFallback(). 368 // Unused by OfflineClockDriver. 369 TimeStamp mTargetIterationTimeStamp; 370 // The GraphInterface this driver is currently iterating. 371 const RefPtr<GraphInterface> mGraphInterface; 372 // The sample rate for the graph, and in case of an audio driver, also for the 373 // cubeb stream. 374 const uint32_t mSampleRate; 375 376 // This is non-null only when this driver has recently switched from an other 377 // driver, and has not cleaned it up yet (for example because the audio stream 378 // is currently calling the callback during initialization). 379 // 380 // This is written to when changing driver, from the previous driver's thread, 381 // or a thread created for the occasion. This is read each time we need to 382 // check whether we're changing driver (in Switching()), from the graph 383 // thread. 384 // This must be accessed using the {Set,Get}PreviousDriver methods. 385 RefPtr<GraphDriver> mPreviousDriver; 386 387 virtual ~GraphDriver() = default; 388 }; 389 390 class MediaTrackGraphInitThreadRunnable; 391 392 /** 393 * This class is a driver that manages its own thread. 394 */ 395 class ThreadedDriver : public GraphDriver { 396 class IterationWaitHelper { 397 Monitor mMonitor MOZ_UNANNOTATED; 398 // The below members are guarded by mMonitor. 399 400 // Whether another iteration is required either to process control 401 // messages or to render. 402 // Drivers do not pass on this state when switching to another driver, 403 // so always perform at least one iteration. 404 bool mNeedAnotherIteration = true; 405 TimeStamp mWakeTime; 406 407 public: 408 IterationWaitHelper() : mMonitor("IterationWaitHelper::mMonitor") {} 409 410 /** 411 * If another iteration is needed we wait for aDuration, otherwise we wait 412 * for a wake-up. If a wake-up occurs before aDuration time has passed, we 413 * wait for aDuration nonetheless. 414 */ 415 void WaitForNextIterationAtLeast(TimeDuration aDuration) { 416 MonitorAutoLock lock(mMonitor); 417 TimeStamp now = TimeStamp::Now(); 418 mWakeTime = now + aDuration; 419 while (true) { 420 if (mNeedAnotherIteration && now >= mWakeTime) { 421 break; 422 } 423 if (mNeedAnotherIteration) { 424 lock.Wait(mWakeTime - now); 425 } else { 426 lock.Wait(TimeDuration::Forever()); 427 } 428 now = TimeStamp::Now(); 429 } 430 mWakeTime = TimeStamp(); 431 mNeedAnotherIteration = false; 432 } 433 434 /** 435 * Sets mNeedAnotherIteration to true and notifies the monitor, in case a 436 * driver is currently waiting. 437 */ 438 void EnsureNextIteration() { 439 MonitorAutoLock lock(mMonitor); 440 mNeedAnotherIteration = true; 441 lock.Notify(); 442 } 443 }; 444 445 public: 446 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ThreadedDriver, override); 447 448 ThreadedDriver(GraphInterface* aGraphInterface, GraphDriver* aPreviousDriver, 449 uint32_t aSampleRate); 450 451 void EnsureNextIteration() override; 452 void Start() override; 453 MOZ_CAN_RUN_SCRIPT void Shutdown() override; 454 /** 455 * Runs main control loop on the graph thread. Normally a single invocation 456 * of this runs for the entire lifetime of the graph thread. 457 */ 458 virtual void RunThread(); 459 friend class MediaTrackGraphInitThreadRunnable; 460 TimeDuration IterationDuration() override; 461 462 nsIThread* Thread() const { return mThread; } 463 464 bool OnThread() const override { 465 return !mThread || mThread->IsOnCurrentThread(); 466 } 467 468 bool ThreadRunning() const override { return mThreadRunning; } 469 470 protected: 471 /* Waits until it's time to process more data. */ 472 void WaitForNextIteration(); 473 /* Return the implementation-dependent time that the ThreadedDriver should 474 * wait for the next iteration. Called only once per iteration; 475 * SystemClockDriver advances it's target iteration time stamp.*/ 476 virtual TimeDuration NextIterationWaitDuration() = 0; 477 /* When the graph wakes up to do an iteration, implementations return the 478 * range of time that will be processed. */ 479 virtual MediaTime GetIntervalForIteration() = 0; 480 481 virtual ~ThreadedDriver(); 482 483 nsCOMPtr<nsIThread> mThread; 484 485 private: 486 // This is true if the thread is running. It is false 487 // before starting the thread and after stopping it. 488 Atomic<bool> mThreadRunning; 489 490 // Any thread. 491 IterationWaitHelper mWaitHelper; 492 }; 493 494 /** 495 * A SystemClockDriver drives a GraphInterface using a system clock, and waits 496 * using a monitor, between each iteration. 497 */ 498 class SystemClockDriver final : public ThreadedDriver { 499 public: 500 SystemClockDriver(GraphInterface* aGraphInterface, 501 GraphDriver* aPreviousDriver, uint32_t aSampleRate); 502 virtual ~SystemClockDriver(); 503 SystemClockDriver* AsSystemClockDriver() override { return this; } 504 const SystemClockDriver* AsSystemClockDriver() const override { return this; } 505 const TimeStamp& IterationTimeStamp() const { 506 return mTargetIterationTimeStamp; 507 } 508 509 protected: 510 /* Return the TimeDuration to wait before the next rendering iteration. */ 511 TimeDuration NextIterationWaitDuration() override; 512 MediaTime GetIntervalForIteration() override; 513 514 private: 515 // Those are only modified (after initialization) on the graph thread. The 516 // graph thread does not run during the initialization. 517 TimeStamp mInitialTimeStamp; 518 }; 519 520 /** 521 * An OfflineClockDriver runs the graph as fast as possible, without waiting 522 * between iteration. 523 */ 524 class OfflineClockDriver final : public ThreadedDriver { 525 public: 526 OfflineClockDriver(GraphInterface* aGraphInterface, uint32_t aSampleRate); 527 virtual ~OfflineClockDriver(); 528 OfflineClockDriver* AsOfflineClockDriver() override { return this; } 529 const OfflineClockDriver* AsOfflineClockDriver() const override { 530 return this; 531 } 532 533 void RunThread() override; 534 535 void SetTickCountToRender(uint32_t aTicksToProcess) { 536 MOZ_ASSERT(InIteration()); 537 MOZ_ASSERT(mEndTime == 0); 538 mEndTime = aTicksToProcess; 539 } 540 541 protected: 542 TimeDuration NextIterationWaitDuration() override { return TimeDuration(); } 543 MediaTime GetIntervalForIteration() override; 544 545 private: 546 // The graph will advance up to this time. Graph thread. 547 GraphTime mEndTime = 0; 548 }; 549 550 enum class AudioInputType { Unknown, Voice }; 551 552 struct AudioInputProcessingParamsRequest { 553 int mGeneration{}; 554 cubeb_input_processing_params mParams{}; 555 }; 556 557 /** 558 * This is a graph driver that is based on callback functions called by the 559 * audio api. This ensures minimal audio latency, because it means there is no 560 * buffering happening: the audio is generated inside the callback. 561 * 562 * This design is less flexible than running our own thread: 563 * - We have no control over the thread: 564 * - It cannot block, and it has to run for a shorter amount of time than the 565 * buffer it is going to fill, or an under-run is going to occur (short burst 566 * of silence in the final audio output). 567 * - We can't know for sure when the callback function is going to be called 568 * (although we compute an estimation so we can schedule video frames) 569 * - Creating and shutting the thread down is a blocking operation, that can 570 * take _seconds_ in some cases (because IPC has to be set up, and 571 * sometimes hardware components are involved and need to be warmed up) 572 * - We have no control on how much audio we generate, we have to return exactly 573 * the number of frames asked for by the callback. Since for the Web Audio 574 * API, we have to do block processing at 128 frames per block, we need to 575 * keep a little spill buffer to store the extra frames. 576 */ 577 class AudioCallbackDriver final : public GraphDriver, 578 public MixerCallbackReceiver { 579 using IterationResult = GraphInterface::IterationResult; 580 enum class FallbackDriverState; 581 class FallbackWrapper; 582 583 public: 584 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_EVENT_TARGET( 585 AudioCallbackDriver, mCubebOperationThread, override); 586 587 /** If aInputChannelCount is zero, then this driver is output-only. */ 588 AudioCallbackDriver( 589 GraphInterface* aGraphInterface, GraphDriver* aPreviousDriver, 590 uint32_t aSampleRate, uint32_t aOutputChannelCount, 591 uint32_t aInputChannelCount, CubebUtils::AudioDeviceID aOutputDeviceID, 592 CubebUtils::AudioDeviceID aInputDeviceID, AudioInputType aAudioInputType, 593 Maybe<AudioInputProcessingParamsRequest> aRequestedInputProcessingParams); 594 595 void Start() override; 596 MOZ_CAN_RUN_SCRIPT void Shutdown() override; 597 void SetStreamName(const nsACString& aStreamName) override; 598 599 /* Static wrapper function cubeb calls back. */ 600 static long DataCallback_s(cubeb_stream* aStream, void* aUser, 601 const void* aInputBuffer, void* aOutputBuffer, 602 long aFrames); 603 static void StateCallback_s(cubeb_stream* aStream, void* aUser, 604 cubeb_state aState); 605 static void DeviceChangedCallback_s(void* aUser); 606 607 /* This function is called by the underlying audio backend when a refill is 608 * needed. This is what drives the whole graph when it is used to output 609 * audio. If the return value is exactly aFrames, this function will get 610 * called again. If it is less than aFrames, the stream will go in draining 611 * mode, and this function will not be called again. */ 612 long DataCallback(const AudioDataValue* aInputBuffer, 613 AudioDataValue* aOutputBuffer, long aFrames); 614 /* This function is called by the underlying audio backend, but is only used 615 * for informational purposes at the moment. */ 616 void StateCallback(cubeb_state aState); 617 /* This is an approximation of the number of millisecond there are between two 618 * iterations of the graph. */ 619 TimeDuration IterationDuration() override; 620 /* If the audio stream has started, this does nothing. There will be another 621 * iteration. If there is an active fallback driver, we forward the call so it 622 * can wake up. */ 623 void EnsureNextIteration() override; 624 625 /* This function gets called when the graph has produced the audio frames for 626 * this iteration. */ 627 void MixerCallback(AudioChunk* aMixedBuffer, uint32_t aSampleRate) override; 628 629 AudioCallbackDriver* AsAudioCallbackDriver() override { return this; } 630 const AudioCallbackDriver* AsAudioCallbackDriver() const override { 631 return this; 632 } 633 634 uint32_t OutputChannelCount() const { return mOutputChannelCount; } 635 636 uint32_t InputChannelCount() const { return mInputChannelCount; } 637 638 CubebUtils::AudioDeviceID InputDeviceID() const { return mInputDeviceID; } 639 640 AudioInputType InputDevicePreference() const { 641 if (mInputDevicePreference == CUBEB_DEVICE_PREF_VOICE) { 642 return AudioInputType::Voice; 643 } 644 return AudioInputType::Unknown; 645 } 646 647 /* Get the latest input processing params request from this driver, so 648 * that an external caller can decide whether it is necessary to call the 649 * setter, since it may allocate or dispatch. */ 650 const AudioInputProcessingParamsRequest& RequestedInputProcessingParams() 651 const; 652 653 /* Set the input processing params requested from this driver. */ 654 void RequestInputProcessingParams(AudioInputProcessingParamsRequest); 655 656 std::thread::id ThreadId() const { return mAudioThreadIdInCb.load(); } 657 658 /* Called at the beginning of the audio callback to check if the thread id has 659 * changed. */ 660 bool CheckThreadIdChanged(); 661 662 bool OnThread() const override { 663 return mAudioThreadIdInCb.load() == std::this_thread::get_id(); 664 } 665 666 /* Returns true if this driver has started (perhaps with a fallback driver) 667 * and not yet stopped. */ 668 bool ThreadRunning() const override { 669 return mAudioStreamState == AudioStreamState::Running || 670 mFallbackDriverState == FallbackDriverState::Running; 671 } 672 673 /* Whether the underlying cubeb stream has been started and has not stopped 674 * or errored. */ 675 bool IsStarted() { return mAudioStreamState > AudioStreamState::Starting; }; 676 677 // Returns the output latency for the current audio output stream. 678 TimeDuration AudioOutputLatency(); 679 680 /* Returns true if this driver has a fallback driver and handover to the audio 681 * callback has not been completed. */ 682 bool HasFallback() const; 683 /* Returns true if this driver is currently driven by the fallback driver. */ 684 bool OnFallback() const; 685 686 private: 687 /** 688 * On certain MacBookPro, the microphone is located near the left speaker. 689 * We need to pan the sound output to the right speaker if we are using the 690 * mic and the built-in speaker, or we will have terrible echo. */ 691 void PanOutputIfNeeded(bool aMicrophoneActive); 692 /** 693 * This is called when the output device used by the cubeb stream changes. */ 694 void DeviceChangedCallback(); 695 /* Start the cubeb stream */ 696 bool StartStream(); 697 friend class MediaTrackGraphInitThreadRunnable; 698 void Init(const nsCString& aStreamName); 699 void SetCubebStreamName(const nsCString& aStreamName); 700 void Stop(); 701 /* After the requested input processing params has changed, this applies them 702 * on the cubeb stream. */ 703 void SetInputProcessingParams(AudioInputProcessingParamsRequest aRequest); 704 /* Calls FallbackToSystemClockDriver() if in FallbackDriverState::None. 705 * Returns Ok(true) if the fallback driver was started, or the old 706 * FallbackDriverState in an Err otherwise. */ 707 Result<bool, FallbackDriverState> TryStartingFallbackDriver(); 708 /* Fall back to a SystemClockDriver using a normal thread. If needed, the 709 * graph will try to re-open an audio stream later. */ 710 void FallbackToSystemClockDriver(); 711 /* Called by the fallback driver when it has fully stopped, after finishing 712 * its last iteration. If it stopped after the audio stream started, aState 713 * will be None. If it stopped after the graph told it to stop, or switch, 714 * aState will be Stopped. Hands over state to the audio driver that may 715 * iterate the graph after this has been called. */ 716 void FallbackDriverStopped(GraphTime aStateComputedTime, 717 TimeStamp aIterationTimeStamp, 718 FallbackDriverState aState); 719 720 /* Called at the end of the fallback driver's iteration to see whether we 721 * should attempt to start the AudioStream again. */ 722 void MaybeStartAudioStream(); 723 724 /* This is true when the method is executed on CubebOperation thread pool. */ 725 bool OnCubebOperationThread() { 726 return mCubebOperationThread->IsOnCurrentThreadInfallible(); 727 } 728 729 /* MediaTrackGraphs are always down/up mixed to output channels. */ 730 const uint32_t mOutputChannelCount; 731 /* The size of this buffer comes from the fact that some audio backends can 732 * call back with a number of frames lower than one block (128 frames), so we 733 * need to keep at most two block in the SpillBuffer, because we always round 734 * up to block boundaries during an iteration. 735 * This is only ever accessed on the audio callback thread. */ 736 SpillBuffer<AudioDataValue, WEBAUDIO_BLOCK_SIZE * 2> mScratchBuffer; 737 /* Wrapper to ensure we write exactly the number of frames we need in the 738 * audio buffer cubeb passes us. This is only ever accessed on the audio 739 * callback thread. */ 740 AudioCallbackBufferWrapper<AudioDataValue> mBuffer; 741 // mAudioStream (a cubeb_stream) has a bare pointer to the cubeb context, so 742 // we hold a strong reference on its behalf. 743 RefPtr<CubebUtils::CubebHandle> mCubeb; 744 /* cubeb stream for this graph. This is non-null after a successful 745 * cubeb_stream_init(). CubebOperation thread only. */ 746 nsAutoRef<cubeb_stream> mAudioStream; 747 /* The number of input channels from cubeb. Set before opening cubeb. If it is 748 * zero then the driver is output-only. */ 749 const uint32_t mInputChannelCount; 750 /** 751 * Devices to use for cubeb input & output, or nullptr for default device. 752 */ 753 const CubebUtils::AudioDeviceID mOutputDeviceID; 754 const CubebUtils::AudioDeviceID mInputDeviceID; 755 /* Whether the current or a future audio callback will be the first callback 756 * to iterate the graph. Used only from DataCallback(). 757 * Initialized on transition from AudioStreamState::Starting to Running. */ 758 MOZ_INIT_OUTSIDE_CTOR bool mFirstCallbackIteration; 759 /* Approximation of the time between two callbacks. This is used to schedule 760 * video frames. This is in milliseconds. Only even used (after 761 * inizatialization) on the audio callback thread. */ 762 uint32_t mIterationDurationMS; 763 764 struct AutoInCallback { 765 explicit AutoInCallback(AudioCallbackDriver* aDriver); 766 ~AutoInCallback(); 767 AudioCallbackDriver* mDriver; 768 }; 769 770 static already_AddRefed<TaskQueue> CreateTaskQueue(); 771 772 /* Shared thread pool with up to one thread for off-main-thread 773 * initialization and shutdown of the audio stream and for other tasks that 774 * must run serially for access to mAudioStream. */ 775 const RefPtr<TaskQueue> mCubebOperationThread; 776 cubeb_device_pref mInputDevicePreference; 777 /* Params that have been attempted to set on mAudioStream, after filtering by 778 * supported processing params. Cubeb operation thread only. */ 779 cubeb_input_processing_params mConfiguredInputProcessingParams = 780 CUBEB_INPUT_PROCESSING_PARAM_NONE; 781 /* The input processing params and generation requested from this audio 782 * driver. Once started, audio callback thread only. */ 783 AudioInputProcessingParamsRequest mInputProcessingRequest; 784 /* Contains the id of the audio thread, from profiler_current_thread_id. */ 785 std::atomic<ProfilerThreadId> mAudioThreadId; 786 /* This allows implementing AutoInCallback. This is equal to the current 787 * thread id when in an audio callback, and is an invalid thread id otherwise. 788 */ 789 std::atomic<std::thread::id> mAudioThreadIdInCb; 790 /* State of the audio stream, see inline comments. */ 791 enum class AudioStreamState { 792 /* There is no cubeb_stream or mAudioStream is in CUBEB_STATE_ERROR or 793 * CUBEB_STATE_STOPPED and no pending task exists to Init() a new 794 * cubeb_stream. */ 795 None, 796 /* A task to Init() a new cubeb_stream is pending. */ 797 Pending, 798 /* cubeb_start_stream() is about to be or has been called on mAudioStream. 799 * Any previous cubeb_streams have been destroyed. */ 800 Starting, 801 /* mAudioStream has advertised it will change device. In this state we 802 ignore all data callbacks until the fallback driver has started. */ 803 ChangingDevice, 804 /* mAudioStream is running. */ 805 Running, 806 /* mAudioStream is draining, and will soon stop. */ 807 Stopping 808 }; 809 Atomic<AudioStreamState> mAudioStreamState{AudioStreamState::None}; 810 /* State of the fallback driver, see inline comments. */ 811 enum class FallbackDriverState { 812 /* There is no fallback driver. */ 813 None, 814 /* There is a fallback driver trying to iterate us. */ 815 Running, 816 /* There was a fallback driver and the graph stopped it. No audio callback 817 may iterate the graph. */ 818 Stopped, 819 }; 820 Atomic<FallbackDriverState> mFallbackDriverState{FallbackDriverState::None}; 821 /* SystemClockDriver used as fallback if this AudioCallbackDriver fails to 822 * init or start. */ 823 DataMutex<RefPtr<FallbackWrapper>> mFallback; 824 /* If using a fallback driver, this is the duration to wait after failing to 825 * start it before attempting to start it again. */ 826 TimeDuration mNextReInitBackoffStep; 827 /* If using a fallback driver, this is the next time we'll try to start the 828 * audio stream. */ 829 TimeStamp mNextReInitAttempt; 830 /* The time mAudioStreamState was changed to ChangingDevice. 831 * Synchronized by the mAudioStreamState atomic, i.e. written *before* writing 832 * the atomic, and read *after* reading the atomic. */ 833 TimeStamp mChangingDeviceStartTime; 834 #ifdef XP_MACOSX 835 /* When using the built-in speakers on macbook pro (13 and 15, all models), 836 * it's best to hard pan the audio on the right, to avoid feedback into the 837 * microphone that is located next to the left speaker. */ 838 Atomic<bool> mNeedsPanning; 839 #endif 840 841 WavDumper mInputStreamFile; 842 WavDumper mOutputStreamFile; 843 844 virtual ~AudioCallbackDriver(); 845 const bool mSandboxed = false; 846 }; 847 848 } // namespace mozilla 849 850 #endif // GRAPHDRIVER_H_