MediaTrackGraph.h (52353B)
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 MOZILLA_MEDIATRACKGRAPH_H_ 7 #define MOZILLA_MEDIATRACKGRAPH_H_ 8 9 #include <speex/speex_resampler.h> 10 11 #include "AudioSampleFormat.h" 12 #include "CubebUtils.h" 13 #include "MainThreadUtils.h" 14 #include "MediaSegment.h" 15 #include "mozilla/LinkedList.h" 16 #include "mozilla/Maybe.h" 17 #include "mozilla/Mutex.h" 18 #include "mozilla/StateWatching.h" 19 #include "mozilla/TaskQueue.h" 20 #include "nsAutoRef.h" 21 #include "nsIRunnable.h" 22 #include "nsTArray.h" 23 24 class nsIRunnable; 25 class nsIGlobalObject; 26 class nsPIDOMWindowInner; 27 28 namespace mozilla { 29 class AsyncLogger; 30 class AudioCaptureTrack; 31 class CrossGraphTransmitter; 32 class CrossGraphReceiver; 33 class NativeInputTrack; 34 }; // namespace mozilla 35 36 extern mozilla::AsyncLogger gMTGTraceLogger; 37 38 template <> 39 class nsAutoRefTraits<SpeexResamplerState> 40 : public nsPointerRefTraits<SpeexResamplerState> { 41 public: 42 static void Release(SpeexResamplerState* aState) { 43 speex_resampler_destroy(aState); 44 } 45 }; 46 47 namespace mozilla { 48 49 extern LazyLogModule gMediaTrackGraphLog; 50 51 namespace dom { 52 enum class AudioContextOperation : uint8_t; 53 enum class AudioContextOperationFlags; 54 enum class AudioContextState : uint8_t; 55 } // namespace dom 56 57 /* 58 * MediaTrackGraph is a framework for synchronized audio/video processing 59 * and playback. It is designed to be used by other browser components such as 60 * HTML media elements, media capture APIs, real-time media streaming APIs, 61 * multitrack media APIs, and advanced audio APIs. 62 * 63 * The MediaTrackGraph uses a dedicated thread to process media --- the media 64 * graph thread. This ensures that we can process media through the graph 65 * without blocking on main-thread activity. The media graph is only modified 66 * on the media graph thread, to ensure graph changes can be processed without 67 * interfering with media processing. All interaction with the media graph 68 * thread is done with message passing. 69 * 70 * APIs that modify the graph or its properties are described as "control APIs". 71 * These APIs are asynchronous; they queue graph changes internally and 72 * those changes are processed all-at-once by the MediaTrackGraph. The 73 * MediaTrackGraph monitors the main thread event loop via 74 * nsIAppShell::RunInStableState to ensure that graph changes from a single 75 * event loop task are always processed all together. Control APIs should only 76 * be used on the main thread, currently; we may be able to relax that later. 77 * 78 * To allow precise synchronization of times in the control API, the 79 * MediaTrackGraph maintains a "media timeline". Control APIs that take or 80 * return times use that timeline. Those times never advance during 81 * an event loop task. This time is returned by 82 * MediaTrackGraph::GetCurrentTime(). 83 * 84 * Media decoding, audio processing and media playback use thread-safe APIs to 85 * the media graph to ensure they can continue while the main thread is blocked. 86 * 87 * When the graph is changed, we may need to throw out buffered data and 88 * reprocess it. This is triggered automatically by the MediaTrackGraph. 89 */ 90 91 class AudioProcessingTrack; 92 class AudioNodeEngine; 93 class AudioNodeExternalInputTrack; 94 class AudioNodeTrack; 95 class DirectMediaTrackListener; 96 class ForwardedInputTrack; 97 class MediaInputPort; 98 class MediaTrack; 99 class MediaTrackGraph; 100 class MediaTrackGraphImpl; 101 class MediaTrackListener; 102 class DeviceInputConsumerTrack; 103 class DeviceInputTrack; 104 class ProcessedMediaTrack; 105 class SourceMediaTrack; 106 107 class AudioDataListenerInterface { 108 protected: 109 // Protected destructor, to discourage deletion outside of Release(): 110 virtual ~AudioDataListenerInterface() = default; 111 112 public: 113 /** 114 * Number of audio input channels. 115 */ 116 virtual uint32_t RequestedInputChannelCount( 117 MediaTrackGraph* aGraph) const = 0; 118 119 /** 120 * The input processing params this listener wants the platform to apply. 121 */ 122 virtual cubeb_input_processing_params RequestedInputProcessingParams( 123 MediaTrackGraph* aGraph) const = 0; 124 125 /** 126 * Whether the underlying audio device is used for voice input. 127 */ 128 virtual bool IsVoiceInput(MediaTrackGraph* aGraph) const = 0; 129 130 /** 131 * Called when the underlying audio device has changed. 132 */ 133 virtual void DeviceChanged(MediaTrackGraph* aGraph) = 0; 134 135 /** 136 * Called when the underlying audio device is being closed. 137 */ 138 virtual void Disconnect(MediaTrackGraph* aGraph) = 0; 139 140 /** 141 * Called sync when attempting to set the input processing params on the 142 * underlying input track. Note that when multiple listeners request distinct 143 * parameters, aRequestedParams is the aggregated form of those parameters. 144 */ 145 virtual void NotifySetRequestedInputProcessingParams( 146 MediaTrackGraph* aGraph, int aGeneration, 147 cubeb_input_processing_params aRequestedParams) = 0; 148 149 /** 150 * Called async after an attempt to set the input processing params on the 151 * underlying input track. 152 */ 153 virtual void NotifySetRequestedInputProcessingParamsResult( 154 MediaTrackGraph* aGraph, int aGeneration, 155 const Result<cubeb_input_processing_params, int>& aResult) = 0; 156 }; 157 158 class AudioDataListener : public AudioDataListenerInterface { 159 protected: 160 // Protected destructor, to discourage deletion outside of Release(): 161 virtual ~AudioDataListener() = default; 162 163 public: 164 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioDataListener) 165 }; 166 167 /** 168 * This is a base class for main-thread listener callbacks. 169 * This callback is invoked on the main thread when the main-thread-visible 170 * state of a track has changed. 171 * 172 * These methods are called with the media graph monitor held, so 173 * reentry into general media graph methods is not possible. 174 * You should do something non-blocking and non-reentrant (e.g. dispatch an 175 * event) and return. NS_DispatchToCurrentThread would be a good choice. 176 * The listener is allowed to synchronously remove itself from the track, but 177 * not add or remove any other listeners. 178 */ 179 class MainThreadMediaTrackListener { 180 public: 181 virtual void NotifyMainThreadTrackEnded() = 0; 182 }; 183 184 /** 185 * Helper struct used to keep track of memory usage by AudioNodes. 186 */ 187 struct AudioNodeSizes { 188 AudioNodeSizes() : mTrack(0), mEngine(0), mNodeType() {} 189 size_t mTrack; 190 size_t mEngine; 191 const char* mNodeType; 192 }; 193 194 /** 195 * Describes how a track should be disabled. 196 * 197 * ENABLED Not disabled. 198 * SILENCE_BLACK Audio data is turned into silence, video frames are made 199 * black. 200 * SILENCE_FREEZE Audio data is turned into silence, video freezes at 201 * last frame. 202 */ 203 enum class DisabledTrackMode { ENABLED, SILENCE_BLACK, SILENCE_FREEZE }; 204 205 /** 206 * A track of audio or video data. The media type must be known at construction 207 * and cannot change. All tracks progress at the same rate --- "real time". 208 * Tracks cannot seek. The only operation readers can perform on a track is to 209 * read the next data. 210 * 211 * Consumers of a track can be reading from it at different offsets, but that 212 * should only happen due to the order in which consumers are being run. 213 * Those offsets must not diverge in the long term, otherwise we would require 214 * unbounded buffering. 215 * 216 * (DEPRECATED to be removed in bug 1581074) 217 * Tracks can be in a "blocked" state. While blocked, a track does not 218 * produce data. A track can be explicitly blocked via the control API, 219 * or implicitly blocked by whatever's generating it (e.g. an underrun in the 220 * source resource), or implicitly blocked because something consuming it 221 * blocks, or implicitly because it has ended. 222 * 223 * A track can be in an "ended" state. "Ended" tracks are permanently blocked. 224 * The "ended" state is terminal. 225 * 226 * Transitions into and out of the "blocked" and "ended" states are managed 227 * by the MediaTrackGraph on the media graph thread. 228 * 229 * We buffer media data ahead of the consumers' reading offsets. It is possible 230 * to have buffered data but still be blocked. 231 * 232 * Any track can have its audio or video playing when requested. The media 233 * track graph plays audio by constructing audio output tracks as necessary. 234 * Video is played through a DirectMediaTrackListener managed by 235 * VideoStreamTrack. 236 * 237 * The data in a track is managed by mSegment. The segment starts at GraphTime 238 * mStartTime and encodes its own TrackTime duration. 239 * 240 * Tracks are explicitly managed. The client creates them via 241 * MediaTrackGraph::Create{Source|ForwardedInput}Track, and releases them by 242 * calling Destroy() when no longer needed (actual destruction will be 243 * deferred). The actual object is owned by the MediaTrackGraph. The basic idea 244 * is that main thread objects will keep Tracks alive as long as necessary 245 * (using the cycle collector to clean up whenever needed). 246 * 247 * We make them refcounted only so that track-related messages with 248 * MediaTrack* pointers can be sent to the main thread safely. 249 * 250 * The lifetimes of MediaTracks are controlled from the main thread. 251 * For MediaTracks exposed to the DOM, the lifetime is controlled by the DOM 252 * wrapper; the DOM wrappers own their associated MediaTracks. When a DOM 253 * wrapper is destroyed, it sends a Destroy message for the associated 254 * MediaTrack and clears its reference (the last main-thread reference to 255 * the object). When the Destroy message is processed on the graph thread we 256 * immediately release the affected objects (disentangling them from other 257 * objects as necessary). 258 * 259 * This could cause problems for media processing if a MediaTrack is destroyed 260 * while a downstream MediaTrack is still using it. Therefore the DOM wrappers 261 * must keep upstream MediaTracks alive as long as they could be used in the 262 * media graph. 263 * 264 * At any time, however, a set of MediaTrack wrappers could be collected via 265 * cycle collection. Destroy messages will be sent for those objects in 266 * arbitrary order and the MediaTrackGraph has to be able to handle this. 267 */ 268 class MediaTrack : public mozilla::LinkedListElement<MediaTrack> { 269 public: 270 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaTrack) 271 272 MediaTrack(TrackRate aSampleRate, MediaSegment::Type aType, 273 MediaSegment* aSegment); 274 275 // The sample rate of the graph. 276 const TrackRate mSampleRate; 277 const MediaSegment::Type mType; 278 279 protected: 280 // Protected destructor, to discourage deletion outside of Release(): 281 virtual ~MediaTrack(); 282 283 public: 284 /** 285 * Returns the graph that owns this track. 286 */ 287 MediaTrackGraphImpl* GraphImpl(); 288 const MediaTrackGraphImpl* GraphImpl() const; 289 MediaTrackGraph* Graph() { return mGraph; } 290 const MediaTrackGraph* Graph() const { return mGraph; } 291 /** 292 * Sets the graph that owns this track. Should only be called once. 293 */ 294 void SetGraphImpl(MediaTrackGraphImpl* aGraph); 295 void SetGraphImpl(MediaTrackGraph* aGraph); 296 297 // Control API. 298 void AddAudioOutput(void* aKey, const AudioDeviceInfo* aSink); 299 void AddAudioOutput(void* aKey, CubebUtils::AudioDeviceID aDeviceID, 300 TrackRate aPreferredSampleRate); 301 void SetAudioOutputVolume(void* aKey, float aVolume); 302 void RemoveAudioOutput(void* aKey); 303 // Explicitly suspend. Useful for example if a media element is pausing 304 // and we need to stop its track emitting its buffered data. As soon as the 305 // Suspend message reaches the graph, the track stops processing. It 306 // ignores its inputs and produces silence/no video until Resumed. Its 307 // current time does not advance. 308 void Suspend(); 309 void Resume(); 310 // Events will be dispatched by calling methods of aListener. 311 virtual void AddListener(MediaTrackListener* aListener); 312 virtual RefPtr<GenericPromise> RemoveListener(MediaTrackListener* aListener); 313 314 /** 315 * Adds aListener to the source track of this track. 316 * When the MediaTrackGraph processes the added listener, it will traverse 317 * the graph and add it to the track's source track. 318 * Note that the listener will be notified on the MediaTrackGraph thread 319 * with whether the installation of it at the source was successful or not. 320 */ 321 void AddDirectListener(DirectMediaTrackListener* aListener); 322 323 /** 324 * Removes aListener from the source track of this track. 325 * Note that the listener has already been removed if the link between the 326 * source and this track has been broken. The caller doesn't have to care 327 * about this, removing when the source cannot be found, or when the listener 328 * had already been removed does nothing. 329 */ 330 void RemoveDirectListener(DirectMediaTrackListener* aListener); 331 332 // A disabled track has video replaced by black, and audio replaced by 333 // silence. 334 void SetDisabledTrackMode(DisabledTrackMode aMode); 335 336 // End event will be notified by calling methods of aListener. It is the 337 // responsibility of the caller to remove aListener before it is destroyed. 338 void AddMainThreadListener(MainThreadMediaTrackListener* aListener); 339 // It's safe to call this even if aListener is not currently a listener; 340 // the call will be ignored. 341 void RemoveMainThreadListener(MainThreadMediaTrackListener* aListener) { 342 MOZ_ASSERT(NS_IsMainThread()); 343 MOZ_ASSERT(aListener); 344 mMainThreadListeners.RemoveElement(aListener); 345 } 346 347 /** 348 * Append to the message queue a control message to execute a given lambda 349 * function with no parameters. The queue is drained during 350 * RunInStableState(). The lambda will be executed on the graph thread. 351 * The lambda will not be executed if the graph has been forced to shut 352 * down. 353 **/ 354 template <typename Function> 355 void QueueControlMessageWithNoShutdown(Function&& aFunction) { 356 QueueMessage(WrapUnique( 357 new ControlMessageWithNoShutdown(std::forward<Function>(aFunction)))); 358 } 359 360 enum class IsInShutdown { No, Yes }; 361 /** 362 * Append to the message queue a control message to execute a given lambda 363 * function with a single IsInShutdown parameter. A No argument indicates 364 * execution on the thread of a graph that is still running. A Yes argument 365 * indicates execution on the main thread when the graph has been forced to 366 * shut down. 367 **/ 368 template <typename Function> 369 void QueueControlOrShutdownMessage(Function&& aFunction) { 370 QueueMessage(WrapUnique( 371 new ControlOrShutdownMessage(std::forward<Function>(aFunction)))); 372 } 373 374 /** 375 * Ensure a runnable will run on the main thread after running all pending 376 * updates that were sent from the graph thread or will be sent before the 377 * graph thread receives the next graph update. 378 * 379 * If the graph has been shut down or destroyed, then the runnable will be 380 * dispatched to the event queue immediately. (There are no pending updates 381 * in this situation.) 382 * 383 * Main thread only. 384 */ 385 void RunAfterPendingUpdates(already_AddRefed<nsIRunnable> aRunnable); 386 387 // Signal that the client is done with this MediaTrack. It will be deleted 388 // later. 389 virtual void Destroy(); 390 391 // Returns the main-thread's view of how much data has been processed by 392 // this track. 393 TrackTime GetCurrentTime() const { 394 NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); 395 return mMainThreadCurrentTime; 396 } 397 // Return the main thread's view of whether this track has ended. 398 bool IsEnded() const { 399 NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); 400 return mMainThreadEnded; 401 } 402 403 bool IsDestroyed() const { 404 NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); 405 return mMainThreadDestroyed; 406 } 407 408 uint64_t GetWindowId() const; 409 410 friend class MediaTrackGraphImpl; 411 friend class MediaInputPort; 412 friend class AudioNodeExternalInputTrack; 413 414 virtual AudioProcessingTrack* AsAudioProcessingTrack() { return nullptr; } 415 virtual SourceMediaTrack* AsSourceTrack() { return nullptr; } 416 virtual ProcessedMediaTrack* AsProcessedTrack() { return nullptr; } 417 virtual AudioNodeTrack* AsAudioNodeTrack() { return nullptr; } 418 virtual ForwardedInputTrack* AsForwardedInputTrack() { return nullptr; } 419 virtual CrossGraphTransmitter* AsCrossGraphTransmitter() { return nullptr; } 420 virtual CrossGraphReceiver* AsCrossGraphReceiver() { return nullptr; } 421 virtual DeviceInputTrack* AsDeviceInputTrack() { return nullptr; } 422 virtual DeviceInputConsumerTrack* AsDeviceInputConsumerTrack() { 423 return nullptr; 424 } 425 426 // These Impl methods perform the core functionality of the control methods 427 // above, on the media graph thread. 428 /** 429 * Stop all track activity and disconnect it from all inputs and outputs. 430 * This must be idempotent. 431 */ 432 virtual void DestroyImpl(); 433 TrackTime GetEnd() const; 434 435 /** 436 * Removes all direct listeners and signals to them that they have been 437 * uninstalled. 438 */ 439 virtual void RemoveAllDirectListenersImpl() {} 440 void RemoveAllResourcesAndListenersImpl(); 441 442 virtual void AddListenerImpl(already_AddRefed<MediaTrackListener> aListener); 443 virtual void RemoveListenerImpl(MediaTrackListener* aListener); 444 virtual void AddDirectListenerImpl( 445 already_AddRefed<DirectMediaTrackListener> aListener); 446 virtual void RemoveDirectListenerImpl(DirectMediaTrackListener* aListener); 447 virtual void SetDisabledTrackModeImpl(DisabledTrackMode aMode); 448 449 void AddConsumer(MediaInputPort* aPort) { mConsumers.AppendElement(aPort); } 450 void RemoveConsumer(MediaInputPort* aPort) { 451 mConsumers.RemoveElement(aPort); 452 } 453 GraphTime StartTime() const { return mStartTime; } 454 bool Ended() const { return mEnded; } 455 456 // Returns the current number of channels this track contains if it's an audio 457 // track. Calling this on a video track will trip assertions. Graph thread 458 // only. 459 virtual uint32_t NumberOfChannels() const = 0; 460 461 // The DisabledTrackMode after combining the explicit mode and that of the 462 // input, if any. 463 virtual DisabledTrackMode CombinedDisabledMode() const { 464 return mDisabledMode; 465 } 466 467 template <class SegmentType> 468 SegmentType* GetData() const { 469 if (!mSegment) { 470 return nullptr; 471 } 472 if (mSegment->GetType() != SegmentType::StaticType()) { 473 return nullptr; 474 } 475 return static_cast<SegmentType*>(mSegment.get()); 476 } 477 MediaSegment* GetData() const { return mSegment.get(); } 478 479 double TrackTimeToSeconds(TrackTime aTime) const { 480 NS_ASSERTION(0 <= aTime && aTime <= TRACK_TIME_MAX, "Bad time"); 481 return static_cast<double>(aTime) / mSampleRate; 482 } 483 int64_t TrackTimeToMicroseconds(TrackTime aTime) const { 484 NS_ASSERTION(0 <= aTime && aTime <= TRACK_TIME_MAX, "Bad time"); 485 return (aTime * 1000000) / mSampleRate; 486 } 487 TrackTime SecondsToNearestTrackTime(double aSeconds) const { 488 NS_ASSERTION(0 <= aSeconds && aSeconds <= TRACK_TICKS_MAX / TRACK_RATE_MAX, 489 "Bad seconds"); 490 return mSampleRate * aSeconds + 0.5; 491 } 492 TrackTime MicrosecondsToTrackTimeRoundDown(int64_t aMicroseconds) const { 493 return (aMicroseconds * mSampleRate) / 1000000; 494 } 495 496 TrackTicks TimeToTicksRoundUp(TrackRate aRate, TrackTime aTime) const { 497 return RateConvertTicksRoundUp(aRate, mSampleRate, aTime); 498 } 499 TrackTime TicksToTimeRoundDown(TrackRate aRate, TrackTicks aTicks) const { 500 return RateConvertTicksRoundDown(mSampleRate, aRate, aTicks); 501 } 502 /** 503 * Convert graph time to track time. aTime must be <= mStateComputedTime 504 * to ensure we know exactly how much time this track will be blocked during 505 * the interval. 506 */ 507 TrackTime GraphTimeToTrackTimeWithBlocking(GraphTime aTime) const; 508 /** 509 * Convert graph time to track time. This assumes there is no blocking time 510 * to take account of, which is always true except between a track 511 * having its blocking time calculated in UpdateGraph and its blocking time 512 * taken account of in UpdateCurrentTimeForTracks. 513 */ 514 TrackTime GraphTimeToTrackTime(GraphTime aTime) const; 515 /** 516 * Convert track time to graph time. This assumes there is no blocking time 517 * to take account of, which is always true except between a track 518 * having its blocking time calculated in UpdateGraph and its blocking time 519 * taken account of in UpdateCurrentTimeForTracks. 520 */ 521 GraphTime TrackTimeToGraphTime(TrackTime aTime) const; 522 523 virtual void ApplyTrackDisabling(MediaSegment* aSegment, 524 MediaSegment* aRawSegment = nullptr); 525 526 // Return true if the main thread needs to observe updates from this track. 527 virtual bool MainThreadNeedsUpdates() const { return true; } 528 529 virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const; 530 virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; 531 532 bool IsSuspended() const { return mSuspendedCount > 0; } 533 /** 534 * Increment suspend count and move it to GraphImpl()->mSuspendedTracks if 535 * necessary. Graph thread. 536 */ 537 void IncrementSuspendCount(); 538 /** 539 * Increment suspend count on aTrack and move it to GraphImpl()->mTracks if 540 * necessary. GraphThread. 541 */ 542 virtual void DecrementSuspendCount(); 543 544 void AssertOnGraphThread() const; 545 void AssertOnGraphThreadOrNotRunning() const; 546 547 /** 548 * For use during ProcessedMediaTrack::ProcessInput() or 549 * MediaTrackListener callbacks, when graph state cannot be changed. 550 * Queues a control message to execute a given lambda function with no 551 * parameters after processing, at a time when graph state can be changed. 552 * The lambda will always be executed before handing control of the graph 553 * to the main thread for shutdown. 554 * Graph thread. 555 */ 556 template <typename Function> 557 void RunAfterProcessing(Function&& aFunction) { 558 RunMessageAfterProcessing(WrapUnique( 559 new ControlMessageWithNoShutdown(std::forward<Function>(aFunction)))); 560 } 561 562 class ControlMessageInterface; 563 564 protected: 565 // Called on graph thread either during destroy handling or before handing 566 // graph control to the main thread to release tracks. 567 virtual void OnGraphThreadDone() {} 568 569 // |AdvanceTimeVaryingValuesToCurrentTime| will be override in 570 // SourceMediaTrack. 571 virtual void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime, 572 GraphTime aBlockedTime); 573 574 private: 575 template <typename Function> 576 class ControlMessageWithNoShutdown; 577 template <typename Function> 578 class ControlOrShutdownMessage; 579 580 void QueueMessage(UniquePtr<ControlMessageInterface> aMessage); 581 void RunMessageAfterProcessing(UniquePtr<ControlMessageInterface> aMessage); 582 583 void NotifyMainThreadListeners() { 584 NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); 585 586 for (int32_t i = mMainThreadListeners.Length() - 1; i >= 0; --i) { 587 mMainThreadListeners[i]->NotifyMainThreadTrackEnded(); 588 } 589 mMainThreadListeners.Clear(); 590 } 591 592 bool ShouldNotifyTrackEnded() { 593 NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); 594 if (!mMainThreadEnded || mEndedNotificationSent) { 595 return false; 596 } 597 598 mEndedNotificationSent = true; 599 return true; 600 } 601 602 protected: 603 // Notifies listeners and consumers of the change in disabled mode when the 604 // current combined mode is different from aMode. 605 void NotifyIfDisabledModeChangedFrom(DisabledTrackMode aOldMode); 606 607 // This state is all initialized on the main thread but 608 // otherwise modified only on the media graph thread. 609 610 // Buffered data. The start of the buffer corresponds to mStartTime. 611 // Conceptually the buffer contains everything this track has ever played, 612 // but we forget some prefix of the buffered data to bound the space usage. 613 // Note that this may be null for tracks that never contain data, like 614 // non-external AudioNodeTracks. 615 const UniquePtr<MediaSegment> mSegment; 616 617 // The time when the buffered data could be considered to have started 618 // playing. This increases over time to account for time the track was 619 // blocked before mCurrentTime. 620 GraphTime mStartTime; 621 622 // The time until which we last called mSegment->ForgetUpTo(). 623 TrackTime mForgottenTime; 624 625 // True once we've processed mSegment until the end and no more data will be 626 // added. Note that mSegment might still contain data for the current 627 // iteration. 628 bool mEnded; 629 630 // True after track listeners have been notified that this track has ended. 631 bool mNotifiedEnded; 632 633 // Client-set volume of this track 634 nsTArray<RefPtr<MediaTrackListener>> mTrackListeners; 635 nsTArray<MainThreadMediaTrackListener*> mMainThreadListeners; 636 // This track's associated disabled mode. It can either by disabled by frames 637 // being replaced by black, or by retaining the previous frame. 638 DisabledTrackMode mDisabledMode; 639 640 // GraphTime at which this track starts blocking. 641 // This is only valid up to mStateComputedTime. The track is considered to 642 // have not been blocked before mCurrentTime (its mStartTime is 643 // increased as necessary to account for that time instead). 644 GraphTime mStartBlocking; 645 646 // MediaInputPorts to which this is connected 647 nsTArray<MediaInputPort*> mConsumers; 648 649 /** 650 * Number of outstanding suspend operations on this track. Track is 651 * suspended when this is > 0. 652 */ 653 int32_t mSuspendedCount; 654 655 // Main-thread views of state 656 TrackTime mMainThreadCurrentTime; 657 bool mMainThreadEnded; 658 bool mEndedNotificationSent; 659 bool mMainThreadDestroyed; 660 661 // Our media track graph. null if destroyed on the graph thread. 662 MediaTrackGraph* mGraph; 663 }; 664 665 /** 666 * This is a track into which a decoder can write audio or video. 667 * 668 * Audio or video can be written on any thread, but you probably want to 669 * always write from the same thread to avoid unexpected interleavings. 670 * 671 * For audio the sample rate of the written data can differ from the sample rate 672 * of the graph itself. Use SetAppendDataSourceRate to inform the track what 673 * rate written audio data will be sampled in. 674 */ 675 class SourceMediaTrack : public MediaTrack { 676 public: 677 SourceMediaTrack(MediaSegment::Type aType, TrackRate aSampleRate); 678 679 SourceMediaTrack* AsSourceTrack() override { return this; } 680 681 // Main thread only 682 683 /** 684 * Enable or disable pulling. 685 * When pulling is enabled, NotifyPull gets called on the 686 * MediaTrackListeners for this track during the MediaTrackGraph 687 * control loop. Pulling is initially disabled. Due to unavoidable race 688 * conditions, after a call to SetPullingEnabled(false) it is still possible 689 * for a NotifyPull to occur. 690 */ 691 void SetPullingEnabled(bool aEnabled); 692 693 // MediaTrackGraph thread only 694 void DestroyImpl() override; 695 696 // Call these on any thread. 697 /** 698 * Call all MediaTrackListeners to request new data via the NotifyPull 699 * API (if enabled). 700 * aDesiredUpToTime (in): end time of new data requested. 701 * 702 * Returns true if new data is about to be added. 703 */ 704 bool PullNewData(GraphTime aDesiredUpToTime); 705 706 /** 707 * Extract any state updates pending in the track, and apply them. 708 */ 709 void ExtractPendingInput(GraphTime aCurrentTime, GraphTime aDesiredUpToTime); 710 711 /** 712 * All data appended with AppendData() from this point on will be resampled 713 * from aRate to the graph rate. 714 * 715 * Resampling for video does not make sense and is forbidden. 716 */ 717 void SetAppendDataSourceRate(TrackRate aRate); 718 719 /** 720 * Append media data to this track. Ownership of aSegment remains with the 721 * caller, but aSegment is emptied. Returns 0 if the data was not appended 722 * because the stream has ended. Returns the duration of the appended data in 723 * the graph's track rate otherwise. 724 */ 725 TrackTime AppendData(MediaSegment* aSegment, 726 MediaSegment* aRawSegment = nullptr); 727 728 /** 729 * Clear any data appended with AppendData() that hasn't entered the graph 730 * yet. Returns the duration of the cleared data in the graph's track rate. 731 */ 732 TrackTime ClearFutureData(); 733 734 /** 735 * Indicate that this track has ended. Do not do any more API calls affecting 736 * this track. 737 */ 738 void End(); 739 740 void SetDisabledTrackModeImpl(DisabledTrackMode aMode) override; 741 742 uint32_t NumberOfChannels() const override; 743 744 void RemoveAllDirectListenersImpl() override; 745 746 // The value set here is applied in MoveToSegment so we can avoid the 747 // buffering delay in applying the change. See Bug 1443511. 748 void SetVolume(float aVolume); 749 float GetVolumeLocked() MOZ_REQUIRES(mMutex); 750 751 Mutex& GetMutex() MOZ_RETURN_CAPABILITY(mMutex) { return mMutex; } 752 753 friend class MediaTrackGraphImpl; 754 755 protected: 756 enum TrackCommands : uint32_t; 757 758 virtual ~SourceMediaTrack(); 759 760 /** 761 * Data to cater for appending media data to this track. 762 */ 763 struct TrackData { 764 // Sample rate of the input data. 765 TrackRate mInputRate; 766 // Resampler if the rate of the input track does not match the 767 // MediaTrackGraph's. 768 nsAutoRef<SpeexResamplerState> mResampler; 769 uint32_t mResamplerChannelCount; 770 // Each time the track updates are flushed to the media graph thread, 771 // the segment buffer is emptied. 772 UniquePtr<MediaSegment> mData; 773 // True once the producer has signaled that no more data is coming. 774 bool mEnded; 775 // True if the producer of this track is having data pulled by the graph. 776 bool mPullingEnabled; 777 // True if the graph has notified this track that it will not be used 778 // again on the graph thread. 779 bool mGraphThreadDone; 780 }; 781 782 bool NeedsMixing(); 783 784 void ResampleAudioToGraphSampleRate(MediaSegment* aSegment) 785 MOZ_REQUIRES(mMutex); 786 787 void AddDirectListenerImpl( 788 already_AddRefed<DirectMediaTrackListener> aListener) override; 789 void RemoveDirectListenerImpl(DirectMediaTrackListener* aListener) override; 790 791 /** 792 * Notify direct consumers of new data to this track. 793 * The data doesn't have to be resampled (though it may be). This is called 794 * from AppendData on the thread providing the data, and will call 795 * the Listeners on this thread. 796 */ 797 void NotifyDirectConsumers(MediaSegment* aSegment) MOZ_REQUIRES(mMutex); 798 799 void OnGraphThreadDone() override { 800 MutexAutoLock lock(mMutex); 801 if (!mUpdateTrack) { 802 return; 803 } 804 mUpdateTrack->mGraphThreadDone = true; 805 if (!mUpdateTrack->mData) { 806 return; 807 } 808 mUpdateTrack->mData->Clear(); 809 } 810 811 virtual void AdvanceTimeVaryingValuesToCurrentTime( 812 GraphTime aCurrentTime, GraphTime aBlockedTime) override; 813 814 // This must be acquired *before* MediaTrackGraphImpl's lock, if they are 815 // held together. 816 Mutex mMutex; 817 // protected by mMutex 818 float mVolume MOZ_GUARDED_BY(mMutex) = 1.0; 819 UniquePtr<TrackData> mUpdateTrack MOZ_GUARDED_BY(mMutex); 820 // This track's associated disabled mode for uses on the producing thread. 821 // It can either by disabled by frames being replaced by black, or by 822 // retaining the previous frame. 823 DisabledTrackMode mDirectDisabledMode MOZ_GUARDED_BY(mMutex) = 824 DisabledTrackMode::ENABLED; 825 nsTArray<RefPtr<DirectMediaTrackListener>> mDirectTrackListeners 826 MOZ_GUARDED_BY(mMutex); 827 }; 828 829 /** 830 * A ref-counted wrapper of a MediaTrack that allows multiple users to share a 831 * reference to the same MediaTrack with the purpose of being guaranteed that 832 * the graph it is in is kept alive. 833 * 834 * Automatically suspended on creation and destroyed on destruction. Main thread 835 * only. 836 */ 837 struct SharedDummyTrack { 838 NS_INLINE_DECL_REFCOUNTING(SharedDummyTrack) 839 explicit SharedDummyTrack(MediaTrack* aTrack) : mTrack(aTrack) { 840 mTrack->Suspend(); 841 } 842 const RefPtr<MediaTrack> mTrack; 843 844 private: 845 ~SharedDummyTrack() { mTrack->Destroy(); } 846 }; 847 848 /** 849 * Represents a connection between a ProcessedMediaTrack and one of its 850 * input tracks. 851 * We make these refcounted so that track-related messages with MediaInputPort* 852 * pointers can be sent to the main thread safely. 853 * 854 * When a port's source or destination track dies, the track's DestroyImpl 855 * calls MediaInputPort::Disconnect to disconnect the port from 856 * the source and destination tracks. 857 * 858 * The lifetimes of MediaInputPort are controlled from the main thread. 859 * The media graph adds a reference to the port. When a MediaInputPort is no 860 * longer needed, main-thread code sends a Destroy message for the port and 861 * clears its reference (the last main-thread reference to the object). When 862 * the Destroy message is processed on the graph manager thread we disconnect 863 * the port and drop the graph's reference, destroying the object. 864 */ 865 class MediaInputPort final { 866 private: 867 // Do not call this constructor directly. Instead call 868 // aDest->AllocateInputPort. 869 MediaInputPort(MediaTrackGraphImpl* aGraph, MediaTrack* aSource, 870 ProcessedMediaTrack* aDest, uint16_t aInputNumber, 871 uint16_t aOutputNumber) 872 : mSource(aSource), 873 mDest(aDest), 874 mInputNumber(aInputNumber), 875 mOutputNumber(aOutputNumber), 876 mGraph(aGraph) { 877 MOZ_COUNT_CTOR(MediaInputPort); 878 } 879 880 // Private destructor, to discourage deletion outside of Release(): 881 MOZ_COUNTED_DTOR(MediaInputPort) 882 883 public: 884 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaInputPort) 885 886 /** 887 * Disconnects and destroys the port. The caller must not reference this 888 * object again. Main thread. 889 */ 890 void Destroy(); 891 892 // The remaining methods and members must always be called on the graph thread 893 // from within MediaTrackGraph.cpp. 894 895 void Init(); 896 // Called during message processing to trigger removal of this port's source 897 // and destination tracks. 898 void Disconnect(); 899 900 MediaTrack* GetSource() const; 901 ProcessedMediaTrack* GetDestination() const; 902 903 uint16_t InputNumber() const { return mInputNumber; } 904 uint16_t OutputNumber() const { return mOutputNumber; } 905 906 struct InputInterval { 907 GraphTime mStart; 908 GraphTime mEnd; 909 bool mInputIsBlocked; 910 }; 911 // Find the next time interval starting at or after aTime during which 912 // aPort->mDest is not blocked and aPort->mSource's blocking status does not 913 // change. A null aPort returns a blocked interval starting at aTime. 914 static InputInterval GetNextInputInterval(MediaInputPort const* aPort, 915 GraphTime aTime); 916 917 /** 918 * Returns the graph that owns this port. 919 */ 920 MediaTrackGraphImpl* GraphImpl() const; 921 MediaTrackGraph* Graph() const; 922 923 /** 924 * Sets the graph that owns this track. Should only be called once. 925 */ 926 void SetGraphImpl(MediaTrackGraphImpl* aGraph); 927 928 /** 929 * Notify the port that the source MediaTrack has been suspended. 930 */ 931 void Suspended(); 932 933 /** 934 * Notify the port that the source MediaTrack has been resumed. 935 */ 936 void Resumed(); 937 938 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { 939 size_t amount = 0; 940 941 // Not owned: 942 // - mSource 943 // - mDest 944 // - mGraph 945 return amount; 946 } 947 948 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { 949 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 950 } 951 952 private: 953 friend class ProcessedMediaTrack; 954 // Never modified after Init() 955 MediaTrack* mSource; 956 ProcessedMediaTrack* mDest; 957 // The input and output numbers are optional, and are currently only used by 958 // Web Audio. 959 const uint16_t mInputNumber; 960 const uint16_t mOutputNumber; 961 962 // Our media track graph 963 MediaTrackGraphImpl* mGraph; 964 }; 965 966 /** 967 * This track processes zero or more input tracks in parallel to produce 968 * its output. The details of how the output is produced are handled by 969 * subclasses overriding the ProcessInput method. 970 */ 971 class ProcessedMediaTrack : public MediaTrack { 972 public: 973 ProcessedMediaTrack(TrackRate aSampleRate, MediaSegment::Type aType, 974 MediaSegment* aSegment) 975 : MediaTrack(aSampleRate, aType, aSegment), 976 mAutoend(true), 977 mCycleMarker(0) {} 978 979 // Control API. 980 /** 981 * Allocates a new input port attached to source aTrack. 982 * This port can be removed by calling MediaInputPort::Destroy(). 983 */ 984 already_AddRefed<MediaInputPort> AllocateInputPort( 985 MediaTrack* aTrack, uint16_t aInputNumber = 0, 986 uint16_t aOutputNumber = 0); 987 /** 988 * Queue a message to set the autoend flag on this track (defaults to 989 * true). When this flag is set, and the input track has ended playout 990 * (including if there is no input track), this track automatically 991 * enters the ended state. 992 */ 993 virtual void QueueSetAutoend(bool aAutoend); 994 995 ProcessedMediaTrack* AsProcessedTrack() override { return this; } 996 997 friend class MediaTrackGraphImpl; 998 999 // Do not call these from outside MediaTrackGraph.cpp! 1000 virtual void AddInput(MediaInputPort* aPort); 1001 virtual void RemoveInput(MediaInputPort* aPort) { 1002 mInputs.RemoveElement(aPort) || mSuspendedInputs.RemoveElement(aPort); 1003 } 1004 bool HasInputPort(MediaInputPort* aPort) const { 1005 return mInputs.Contains(aPort) || mSuspendedInputs.Contains(aPort); 1006 } 1007 uint32_t InputPortCount() const { 1008 return mInputs.Length() + mSuspendedInputs.Length(); 1009 } 1010 void InputSuspended(MediaInputPort* aPort); 1011 void InputResumed(MediaInputPort* aPort); 1012 void DestroyImpl() override; 1013 void DecrementSuspendCount() override; 1014 /** 1015 * This gets called after we've computed the blocking states for all 1016 * tracks (mBlocked is up to date up to mStateComputedTime). 1017 * Also, we've produced output for all tracks up to this one. If this track 1018 * is not in a cycle, then all its source tracks have produced data. 1019 * Generate output from aFrom to aTo, where aFrom < aTo. 1020 * This will be called on tracks that have ended. Most track types should 1021 * just return immediately if they're ended, but some may wish to update 1022 * internal state (see AudioNodeTrack). 1023 * ProcessInput is allowed to set mEnded only if ALLOW_END is in aFlags. (This 1024 * flag will be set when aTo >= mStateComputedTime, i.e. when we've produced 1025 * the last block of data we need to produce.) Otherwise we can get into a 1026 * situation where we've determined the track should not block before 1027 * mStateComputedTime, but the track ends before mStateComputedTime, violating 1028 * the invariant that ended tracks are blocked. 1029 */ 1030 enum { ALLOW_END = 0x01 }; 1031 virtual void ProcessInput(GraphTime aFrom, GraphTime aTo, 1032 uint32_t aFlags) = 0; 1033 void SetAutoendImpl(bool aAutoend) { mAutoend = aAutoend; } 1034 1035 // Only valid after MediaTrackGraphImpl::UpdateTrackOrder() has run. 1036 // A DelayNode is considered to break a cycle and so this will not return 1037 // true for echo loops, only for muted cycles. 1038 bool InMutedCycle() const { return mCycleMarker; } 1039 1040 // Used by ForwardedInputTrack to propagate the disabled mode along the graph. 1041 virtual void OnInputDisabledModeChanged(DisabledTrackMode aMode) {} 1042 1043 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override { 1044 size_t amount = MediaTrack::SizeOfExcludingThis(aMallocSizeOf); 1045 // Not owned: 1046 // - mInputs elements 1047 // - mSuspendedInputs elements 1048 amount += mInputs.ShallowSizeOfExcludingThis(aMallocSizeOf); 1049 amount += mSuspendedInputs.ShallowSizeOfExcludingThis(aMallocSizeOf); 1050 return amount; 1051 } 1052 1053 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override { 1054 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 1055 } 1056 1057 protected: 1058 // This state is all accessed only on the media graph thread. 1059 1060 // The list of all inputs that are not currently suspended. 1061 nsTArray<MediaInputPort*> mInputs; 1062 // The list of all inputs that are currently suspended. 1063 nsTArray<MediaInputPort*> mSuspendedInputs; 1064 bool mAutoend; 1065 // After UpdateTrackOrder(), mCycleMarker is either 0 or 1 to indicate 1066 // whether this track is in a muted cycle. During ordering it can contain 1067 // other marker values - see MediaTrackGraphImpl::UpdateTrackOrder(). 1068 uint32_t mCycleMarker; 1069 }; 1070 1071 /** 1072 * There is a single MediaTrackGraph per window. 1073 * Additionaly, each OfflineAudioContext object creates its own MediaTrackGraph 1074 * object too. 1075 */ 1076 class MediaTrackGraph { 1077 public: 1078 // We ensure that the graph current time advances in multiples of 1079 // IdealAudioBlockSize()/AudioStream::PreferredSampleRate(). A track that 1080 // never blocks and has the ideal audio rate will produce audio in multiples 1081 // of the block size. 1082 1083 // Initializing a graph that outputs audio can take quite long on some 1084 // platforms. Code that want to output audio at some point can express the 1085 // fact that they will need an audio track at some point by passing 1086 // AUDIO_THREAD_DRIVER when getting an instance of MediaTrackGraph, so that 1087 // the graph starts with the right driver. 1088 enum GraphDriverType { 1089 AUDIO_THREAD_DRIVER, 1090 SYSTEM_THREAD_DRIVER, 1091 OFFLINE_THREAD_DRIVER 1092 }; 1093 // A MediaTrackGraph running an AudioWorklet must always be run from the 1094 // same thread, in order to run js. To acheive this, create the graph with 1095 // a SINGLE_THREAD RunType. DIRECT_DRIVER will run the graph directly off 1096 // the GraphDriver's thread. 1097 enum GraphRunType { 1098 DIRECT_DRIVER, 1099 SINGLE_THREAD, 1100 }; 1101 static const uint32_t AUDIO_CALLBACK_DRIVER_SHUTDOWN_TIMEOUT = 20 * 1000; 1102 static const TrackRate REQUEST_DEFAULT_SAMPLE_RATE = 0; 1103 constexpr static const CubebUtils::AudioDeviceID DEFAULT_OUTPUT_DEVICE = 1104 nullptr; 1105 1106 // Main thread only 1107 static MediaTrackGraph* GetInstanceIfExists( 1108 nsPIDOMWindowInner* aWindow, TrackRate aSampleRate, 1109 CubebUtils::AudioDeviceID aPrimaryOutputDeviceID); 1110 static MediaTrackGraph* GetInstance( 1111 GraphDriverType aGraphDriverRequested, nsPIDOMWindowInner* aWindow, 1112 TrackRate aSampleRate, CubebUtils::AudioDeviceID aPrimaryOutputDeviceID); 1113 static MediaTrackGraph* CreateNonRealtimeInstance(TrackRate aSampleRate); 1114 1115 // Idempotent 1116 void ForceShutDown(); 1117 1118 virtual void OpenAudioInput(DeviceInputTrack* aTrack) = 0; 1119 virtual void CloseAudioInput(DeviceInputTrack* aTrack) = 0; 1120 1121 // Control API. 1122 /** 1123 * Create a track that a media decoder (or some other source of 1124 * media data, such as a camera) can write to. 1125 */ 1126 SourceMediaTrack* CreateSourceTrack(MediaSegment::Type aType); 1127 /** 1128 * Create a track that will forward data from its input track. 1129 * 1130 * A TrackUnionStream can have 0 or 1 input streams. Adding more than that is 1131 * an error. 1132 * 1133 * A TrackUnionStream will end when autoending is enabled (default) and there 1134 * is no input, or the input's source is ended. If there is no input and 1135 * autoending is disabled, TrackUnionStream will continue to produce silence 1136 * for audio or the last video frame for video. 1137 */ 1138 ProcessedMediaTrack* CreateForwardedInputTrack(MediaSegment::Type aType); 1139 /** 1140 * Create a track that will mix all its audio inputs. 1141 */ 1142 AudioCaptureTrack* CreateAudioCaptureTrack(); 1143 1144 CrossGraphTransmitter* CreateCrossGraphTransmitter( 1145 CrossGraphReceiver* aReceiver); 1146 CrossGraphReceiver* CreateCrossGraphReceiver(TrackRate aTransmitterRate); 1147 1148 /** 1149 * Add a new track to the graph. Main thread. 1150 */ 1151 void AddTrack(MediaTrack* aTrack); 1152 1153 /* From the main thread, ask the MTG to resolve the returned promise when 1154 * the device specified has started. 1155 * A null aDeviceID indicates the default audio output device. 1156 * The promise is rejected with NS_ERROR_INVALID_ARG if aDeviceID does not 1157 * correspond to any output devices used by the graph, or 1158 * NS_ERROR_NOT_AVAILABLE if outputs to the device are removed or 1159 * NS_ERROR_ILLEGAL_DURING_SHUTDOWN if the graph is force shut down 1160 * before the promise could be resolved. 1161 */ 1162 using GraphStartedPromise = GenericPromise; 1163 virtual RefPtr<GraphStartedPromise> NotifyWhenDeviceStarted( 1164 CubebUtils::AudioDeviceID aDeviceID) = 0; 1165 1166 /* From the main thread, suspend, resume or close an AudioContext. Calls 1167 * are not counted. Even Resume calls can be more frequent than Suspend 1168 * calls. 1169 * 1170 * aTracks are the tracks of all the AudioNodes of the AudioContext that 1171 * need to be suspended or resumed. Suspend and Resume operations on these 1172 * tracks are counted. Resume operations must not outnumber Suspends and a 1173 * track will not resume until the number of Resume operations matches the 1174 * number of Suspends. This array may be empty if, for example, this is a 1175 * second consecutive suspend call and all the nodes are already suspended. 1176 * 1177 * This can possibly pause the graph thread, releasing system resources, if 1178 * all tracks have been suspended/closed. 1179 * 1180 * When the operation is complete, the returned promise is resolved. 1181 */ 1182 using AudioContextOperationPromise = 1183 MozPromise<dom::AudioContextState, bool, true>; 1184 RefPtr<AudioContextOperationPromise> ApplyAudioContextOperation( 1185 MediaTrack* aDestinationTrack, nsTArray<RefPtr<MediaTrack>> aTracks, 1186 dom::AudioContextOperation aOperation); 1187 1188 bool IsNonRealtime() const; 1189 /** 1190 * Start processing non-realtime for a specific number of ticks. 1191 */ 1192 void StartNonRealtimeProcessing(uint32_t aTicksToProcess); 1193 1194 /** 1195 * NotifyJSContext() is called on the graph thread before content script 1196 * runs. 1197 */ 1198 void NotifyJSContext(JSContext* aCx); 1199 1200 /** 1201 * Media graph thread only. 1202 * Dispatches a runnable that will run on the main thread after all 1203 * main-thread track state has been updated, i.e., during stable state. 1204 * 1205 * Should only be called during MediaTrackListener callbacks or during 1206 * ProcessedMediaTrack::ProcessInput(). 1207 * 1208 * Note that if called during shutdown the runnable will be ignored and 1209 * released on main thread. 1210 */ 1211 void DispatchToMainThreadStableState(already_AddRefed<nsIRunnable> aRunnable); 1212 /* Called on the graph thread when the input device settings should be 1213 * reevaluated, for example, if the channel count of the input track should 1214 * be changed. */ 1215 void ReevaluateInputDevice(CubebUtils::AudioDeviceID aID); 1216 1217 /** 1218 * Returns graph sample rate in Hz. 1219 */ 1220 TrackRate GraphRate() const { return mSampleRate; } 1221 /** 1222 * Returns the ID of the device used for audio output through an 1223 * AudioCallbackDriver. This is the device specified when creating the 1224 * graph. Can be called on any thread. 1225 */ 1226 CubebUtils::AudioDeviceID PrimaryOutputDeviceID() const { 1227 return mPrimaryOutputDeviceID; 1228 } 1229 1230 double AudioOutputLatency(); 1231 /* Return whether the clock for the audio output device used for the AEC 1232 * reverse stream might drift from the clock for this MediaTrackGraph. 1233 * Graph thread only. */ 1234 bool OutputForAECMightDrift(); 1235 /* Return whether the audio output device used for the aec reverse stream 1236 * corresponds to the primary output device, explicitly or implicitly, 1237 * implicitly meaning when the primary output device is the system default 1238 * output device, and the output device used for the aec reverse stream is 1239 * explicit and matches the current system default output device. 1240 * Graph thread only. */ 1241 bool OutputForAECIsPrimary(); 1242 1243 void RegisterCaptureTrackForWindow(uint64_t aWindowId, 1244 ProcessedMediaTrack* aCaptureTrack); 1245 void UnregisterCaptureTrackForWindow(uint64_t aWindowId); 1246 already_AddRefed<MediaInputPort> ConnectToCaptureTrack( 1247 uint64_t aWindowId, MediaTrack* aMediaTrack); 1248 1249 void AssertOnGraphThread() const { MOZ_ASSERT(OnGraphThread()); } 1250 void AssertOnGraphThreadOrNotRunning() const { 1251 MOZ_ASSERT(OnGraphThreadOrNotRunning()); 1252 } 1253 1254 /** 1255 * Returns a watchable of the graph's main-thread observable graph time. 1256 * Main thread only. 1257 */ 1258 virtual Watchable<GraphTime>& CurrentTime() = 0; 1259 1260 /** 1261 * Graph thread function to return the time at which all processing has been 1262 * completed. Some tracks may have performed processing beyond this time. 1263 */ 1264 GraphTime ProcessedTime() const; 1265 /** 1266 * For Graph thread logging. 1267 */ 1268 void* CurrentDriver() const; 1269 1270 /* Do not call this directly. For users who need to get a DeviceInputTrack, 1271 * use DeviceInputTrack::OpenAudio() instead. This should only be used in 1272 * DeviceInputTrack to get the existing DeviceInputTrack paired with the given 1273 * device in this graph. Main thread only.*/ 1274 DeviceInputTrack* GetDeviceInputTrackMainThread( 1275 CubebUtils::AudioDeviceID aID); 1276 1277 /* Do not call this directly. This should only be used in DeviceInputTrack to 1278 * get the existing NativeInputTrackMain thread only.*/ 1279 NativeInputTrack* GetNativeInputTrackMainThread(); 1280 1281 /* Return a positive monotonically increasing graph-unique generation id for 1282 * AudioInputProcessingParamsRequest::mGeneration. */ 1283 int ProcessingParamsGeneration() { return ++mProcessingParamsGeneration; } 1284 1285 protected: 1286 explicit MediaTrackGraph(TrackRate aSampleRate, 1287 CubebUtils::AudioDeviceID aPrimaryOutputDeviceID) 1288 : mSampleRate(aSampleRate), 1289 mPrimaryOutputDeviceID(aPrimaryOutputDeviceID) { 1290 MOZ_COUNT_CTOR(MediaTrackGraph); 1291 } 1292 MOZ_COUNTED_DTOR_VIRTUAL(MediaTrackGraph) 1293 1294 // Intended only for assertions, either on graph thread or not running (in 1295 // which case we must be on the main thread). 1296 virtual bool OnGraphThreadOrNotRunning() const = 0; 1297 virtual bool OnGraphThread() const = 0; 1298 1299 // Intended only for internal assertions. Main thread only. 1300 virtual bool Destroyed() const = 0; 1301 1302 /** 1303 * Sample rate at which this graph runs. For real time graphs, this is 1304 * the rate of the audio mixer. For offline graphs, this is the rate specified 1305 * at construction. 1306 */ 1307 const TrackRate mSampleRate; 1308 /** 1309 * Device to use for audio output through an AudioCallbackDriver. 1310 * This is the device specified when creating the graph. 1311 */ 1312 const CubebUtils::AudioDeviceID mPrimaryOutputDeviceID; 1313 1314 /* A monotonically increasing graph-unique generation for 1315 * AudioInputProcessingParamsRequest::mGeneration. */ 1316 int mProcessingParamsGeneration = 0; 1317 }; 1318 1319 inline void MediaTrack::AssertOnGraphThread() const { 1320 Graph()->AssertOnGraphThread(); 1321 } 1322 inline void MediaTrack::AssertOnGraphThreadOrNotRunning() const { 1323 Graph()->AssertOnGraphThreadOrNotRunning(); 1324 } 1325 1326 /** 1327 * This represents a message run on the graph thread to modify track or graph 1328 * state. These are passed from main thread to graph thread by 1329 * QueueControlMessageWithNoShutdown() or QueueControlOrShutdownMessage() 1330 * through AppendMessage(), or scheduled on the graph thread with 1331 * RunAfterProcessing(). 1332 */ 1333 class MediaTrack::ControlMessageInterface { 1334 public: 1335 MOZ_COUNTED_DEFAULT_CTOR(ControlMessageInterface) 1336 // All these run on the graph thread unless the graph has been forced to 1337 // shut down. 1338 MOZ_COUNTED_DTOR_VIRTUAL(ControlMessageInterface) 1339 // Do the action of this message on the MediaTrackGraph thread. Any actions 1340 // affecting graph processing should take effect at mProcessedTime. 1341 // All track data for times < mProcessedTime has already been 1342 // computed. 1343 virtual void Run() = 0; 1344 // RunDuringShutdown() is only relevant to messages generated on the main 1345 // thread by QueueControlOrShutdownMessage() or for AppendMessage(). 1346 // When we're shutting down the application, most messages are ignored but 1347 // some cleanup messages should still be processed (on the main thread). 1348 // This must not add new control messages to the graph. 1349 virtual void RunDuringShutdown() {} 1350 }; 1351 1352 template <typename Function> 1353 class MediaTrack::ControlMessageWithNoShutdown 1354 : public ControlMessageInterface { 1355 public: 1356 explicit ControlMessageWithNoShutdown(Function&& aFunction) 1357 : mFunction(std::forward<Function>(aFunction)) {} 1358 1359 void Run() override { 1360 static_assert(std::is_void_v<decltype(mFunction())>, 1361 "The lambda must return void!"); 1362 mFunction(); 1363 } 1364 1365 private: 1366 using StoredFunction = std::decay_t<Function>; 1367 StoredFunction mFunction; 1368 }; 1369 1370 template <typename Function> 1371 class MediaTrack::ControlOrShutdownMessage : public ControlMessageInterface { 1372 public: 1373 explicit ControlOrShutdownMessage(Function&& aFunction) 1374 : mFunction(std::forward<Function>(aFunction)) {} 1375 1376 void Run() override { 1377 static_assert(std::is_void_v<decltype(mFunction(IsInShutdown()))>, 1378 "The lambda must return void!"); 1379 mFunction(IsInShutdown::No); 1380 } 1381 void RunDuringShutdown() override { mFunction(IsInShutdown::Yes); } 1382 1383 private: 1384 // The same lambda is used whether or not in shutdown so that captured 1385 // variables are available in both cases. 1386 using StoredFunction = std::decay_t<Function>; 1387 StoredFunction mFunction; 1388 }; 1389 1390 } // namespace mozilla 1391 1392 #endif /* MOZILLA_MEDIATRACKGRAPH_H_ */