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/. */
6 #ifndef MOZILLA_MEDIATRACKGRAPH_H_
7 #define MOZILLA_MEDIATRACKGRAPH_H_
9 #include "AudioSampleFormat.h"
10 #include "CubebUtils.h"
11 #include "MainThreadUtils.h"
12 #include "MediaSegment.h"
13 #include "mozilla/LinkedList.h"
14 #include "mozilla/Maybe.h"
15 #include "mozilla/Mutex.h"
16 #include "mozilla/StateWatching.h"
17 #include "mozilla/TaskQueue.h"
18 #include "nsAutoRef.h"
19 #include "nsIRunnable.h"
21 #include <speex/speex_resampler.h>
24 class nsIGlobalObject
;
25 class nsPIDOMWindowInner
;
29 class AudioCaptureTrack
;
30 class CrossGraphTransmitter
;
31 class CrossGraphReceiver
;
32 class NativeInputTrack
;
33 }; // namespace mozilla
35 extern mozilla::AsyncLogger gMTGTraceLogger
;
38 class nsAutoRefTraits
<SpeexResamplerState
>
39 : public nsPointerRefTraits
<SpeexResamplerState
> {
41 static void Release(SpeexResamplerState
* aState
) {
42 speex_resampler_destroy(aState
);
48 extern LazyLogModule gMediaTrackGraphLog
;
51 enum class AudioContextOperation
: uint8_t;
52 enum class AudioContextOperationFlags
;
53 enum class AudioContextState
: uint8_t;
57 * MediaTrackGraph is a framework for synchronized audio/video processing
58 * and playback. It is designed to be used by other browser components such as
59 * HTML media elements, media capture APIs, real-time media streaming APIs,
60 * multitrack media APIs, and advanced audio APIs.
62 * The MediaTrackGraph uses a dedicated thread to process media --- the media
63 * graph thread. This ensures that we can process media through the graph
64 * without blocking on main-thread activity. The media graph is only modified
65 * on the media graph thread, to ensure graph changes can be processed without
66 * interfering with media processing. All interaction with the media graph
67 * thread is done with message passing.
69 * APIs that modify the graph or its properties are described as "control APIs".
70 * These APIs are asynchronous; they queue graph changes internally and
71 * those changes are processed all-at-once by the MediaTrackGraph. The
72 * MediaTrackGraph monitors the main thread event loop via
73 * nsIAppShell::RunInStableState to ensure that graph changes from a single
74 * event loop task are always processed all together. Control APIs should only
75 * be used on the main thread, currently; we may be able to relax that later.
77 * To allow precise synchronization of times in the control API, the
78 * MediaTrackGraph maintains a "media timeline". Control APIs that take or
79 * return times use that timeline. Those times never advance during
80 * an event loop task. This time is returned by
81 * MediaTrackGraph::GetCurrentTime().
83 * Media decoding, audio processing and media playback use thread-safe APIs to
84 * the media graph to ensure they can continue while the main thread is blocked.
86 * When the graph is changed, we may need to throw out buffered data and
87 * reprocess it. This is triggered automatically by the MediaTrackGraph.
90 class AudioProcessingTrack
;
91 class AudioNodeEngine
;
92 class AudioNodeExternalInputTrack
;
94 class DirectMediaTrackListener
;
95 class ForwardedInputTrack
;
98 class MediaTrackGraph
;
99 class MediaTrackGraphImpl
;
100 class MediaTrackListener
;
101 class DeviceInputConsumerTrack
;
102 class DeviceInputTrack
;
103 class ProcessedMediaTrack
;
104 class SourceMediaTrack
;
106 class AudioDataListenerInterface
{
108 // Protected destructor, to discourage deletion outside of Release():
109 virtual ~AudioDataListenerInterface() = default;
113 * Number of audio input channels.
115 virtual uint32_t RequestedInputChannelCount(
116 MediaTrackGraph
* aGraph
) const = 0;
119 * The input processing params this listener wants the platform to apply.
121 virtual cubeb_input_processing_params
RequestedInputProcessingParams(
122 MediaTrackGraph
* aGraph
) const = 0;
125 * Whether the underlying audio device is used for voice input.
127 virtual bool IsVoiceInput(MediaTrackGraph
* aGraph
) const = 0;
130 * Called when the underlying audio device has changed.
132 virtual void DeviceChanged(MediaTrackGraph
* aGraph
) = 0;
135 * Called when the underlying audio device is being closed.
137 virtual void Disconnect(MediaTrackGraph
* aGraph
) = 0;
140 * Called sync when attempting to set the input processing params on the
141 * underlying input track. Note that when multiple listeners request distinct
142 * parameters, aRequestedParams is the aggregated form of those parameters.
144 virtual void NotifySetRequestedInputProcessingParams(
145 MediaTrackGraph
* aGraph
, int aGeneration
,
146 cubeb_input_processing_params aRequestedParams
) = 0;
149 * Called async after an attempt to set the input processing params on the
150 * underlying input track.
152 virtual void NotifySetRequestedInputProcessingParamsResult(
153 MediaTrackGraph
* aGraph
, int aGeneration
,
154 const Result
<cubeb_input_processing_params
, int>& aResult
) = 0;
157 class AudioDataListener
: public AudioDataListenerInterface
{
159 // Protected destructor, to discourage deletion outside of Release():
160 virtual ~AudioDataListener() = default;
163 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioDataListener
)
167 * This is a base class for main-thread listener callbacks.
168 * This callback is invoked on the main thread when the main-thread-visible
169 * state of a track has changed.
171 * These methods are called with the media graph monitor held, so
172 * reentry into general media graph methods is not possible.
173 * You should do something non-blocking and non-reentrant (e.g. dispatch an
174 * event) and return. NS_DispatchToCurrentThread would be a good choice.
175 * The listener is allowed to synchronously remove itself from the track, but
176 * not add or remove any other listeners.
178 class MainThreadMediaTrackListener
{
180 virtual void NotifyMainThreadTrackEnded() = 0;
184 * Helper struct used to keep track of memory usage by AudioNodes.
186 struct AudioNodeSizes
{
187 AudioNodeSizes() : mTrack(0), mEngine(0), mNodeType() {}
190 const char* mNodeType
;
194 * Describes how a track should be disabled.
196 * ENABLED Not disabled.
197 * SILENCE_BLACK Audio data is turned into silence, video frames are made
199 * SILENCE_FREEZE Audio data is turned into silence, video freezes at
202 enum class DisabledTrackMode
{ ENABLED
, SILENCE_BLACK
, SILENCE_FREEZE
};
205 * A track of audio or video data. The media type must be known at construction
206 * and cannot change. All tracks progress at the same rate --- "real time".
207 * Tracks cannot seek. The only operation readers can perform on a track is to
208 * read the next data.
210 * Consumers of a track can be reading from it at different offsets, but that
211 * should only happen due to the order in which consumers are being run.
212 * Those offsets must not diverge in the long term, otherwise we would require
213 * unbounded buffering.
215 * (DEPRECATED to be removed in bug 1581074)
216 * Tracks can be in a "blocked" state. While blocked, a track does not
217 * produce data. A track can be explicitly blocked via the control API,
218 * or implicitly blocked by whatever's generating it (e.g. an underrun in the
219 * source resource), or implicitly blocked because something consuming it
220 * blocks, or implicitly because it has ended.
222 * A track can be in an "ended" state. "Ended" tracks are permanently blocked.
223 * The "ended" state is terminal.
225 * Transitions into and out of the "blocked" and "ended" states are managed
226 * by the MediaTrackGraph on the media graph thread.
228 * We buffer media data ahead of the consumers' reading offsets. It is possible
229 * to have buffered data but still be blocked.
231 * Any track can have its audio or video playing when requested. The media
232 * track graph plays audio by constructing audio output tracks as necessary.
233 * Video is played through a DirectMediaTrackListener managed by
236 * The data in a track is managed by mSegment. The segment starts at GraphTime
237 * mStartTime and encodes its own TrackTime duration.
239 * Tracks are explicitly managed. The client creates them via
240 * MediaTrackGraph::Create{Source|ForwardedInput}Track, and releases them by
241 * calling Destroy() when no longer needed (actual destruction will be
242 * deferred). The actual object is owned by the MediaTrackGraph. The basic idea
243 * is that main thread objects will keep Tracks alive as long as necessary
244 * (using the cycle collector to clean up whenever needed).
246 * We make them refcounted only so that track-related messages with
247 * MediaTrack* pointers can be sent to the main thread safely.
249 * The lifetimes of MediaTracks are controlled from the main thread.
250 * For MediaTracks exposed to the DOM, the lifetime is controlled by the DOM
251 * wrapper; the DOM wrappers own their associated MediaTracks. When a DOM
252 * wrapper is destroyed, it sends a Destroy message for the associated
253 * MediaTrack and clears its reference (the last main-thread reference to
254 * the object). When the Destroy message is processed on the graph thread we
255 * immediately release the affected objects (disentangling them from other
256 * objects as necessary).
258 * This could cause problems for media processing if a MediaTrack is destroyed
259 * while a downstream MediaTrack is still using it. Therefore the DOM wrappers
260 * must keep upstream MediaTracks alive as long as they could be used in the
263 * At any time, however, a set of MediaTrack wrappers could be collected via
264 * cycle collection. Destroy messages will be sent for those objects in
265 * arbitrary order and the MediaTrackGraph has to be able to handle this.
267 class MediaTrack
: public mozilla::LinkedListElement
<MediaTrack
> {
269 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaTrack
)
271 MediaTrack(TrackRate aSampleRate
, MediaSegment::Type aType
,
272 MediaSegment
* aSegment
);
274 // The sample rate of the graph.
275 const TrackRate mSampleRate
;
276 const MediaSegment::Type mType
;
279 // Protected destructor, to discourage deletion outside of Release():
280 virtual ~MediaTrack();
284 * Returns the graph that owns this track.
286 MediaTrackGraphImpl
* GraphImpl();
287 const MediaTrackGraphImpl
* GraphImpl() const;
288 MediaTrackGraph
* Graph() { return mGraph
; }
289 const MediaTrackGraph
* Graph() const { return mGraph
; }
291 * Sets the graph that owns this track. Should only be called once.
293 void SetGraphImpl(MediaTrackGraphImpl
* aGraph
);
294 void SetGraphImpl(MediaTrackGraph
* aGraph
);
297 void AddAudioOutput(void* aKey
, const AudioDeviceInfo
* aSink
);
298 void AddAudioOutput(void* aKey
, CubebUtils::AudioDeviceID aDeviceID
,
299 TrackRate aPreferredSampleRate
);
300 void SetAudioOutputVolume(void* aKey
, float aVolume
);
301 void RemoveAudioOutput(void* aKey
);
302 // Explicitly suspend. Useful for example if a media element is pausing
303 // and we need to stop its track emitting its buffered data. As soon as the
304 // Suspend message reaches the graph, the track stops processing. It
305 // ignores its inputs and produces silence/no video until Resumed. Its
306 // current time does not advance.
309 // Events will be dispatched by calling methods of aListener.
310 virtual void AddListener(MediaTrackListener
* aListener
);
311 virtual RefPtr
<GenericPromise
> RemoveListener(MediaTrackListener
* aListener
);
314 * Adds aListener to the source track of this track.
315 * When the MediaTrackGraph processes the added listener, it will traverse
316 * the graph and add it to the track's source track.
317 * Note that the listener will be notified on the MediaTrackGraph thread
318 * with whether the installation of it at the source was successful or not.
320 void AddDirectListener(DirectMediaTrackListener
* aListener
);
323 * Removes aListener from the source track of this track.
324 * Note that the listener has already been removed if the link between the
325 * source and this track has been broken. The caller doesn't have to care
326 * about this, removing when the source cannot be found, or when the listener
327 * had already been removed does nothing.
329 void RemoveDirectListener(DirectMediaTrackListener
* aListener
);
331 // A disabled track has video replaced by black, and audio replaced by
333 void SetDisabledTrackMode(DisabledTrackMode aMode
);
335 // End event will be notified by calling methods of aListener. It is the
336 // responsibility of the caller to remove aListener before it is destroyed.
337 void AddMainThreadListener(MainThreadMediaTrackListener
* aListener
);
338 // It's safe to call this even if aListener is not currently a listener;
339 // the call will be ignored.
340 void RemoveMainThreadListener(MainThreadMediaTrackListener
* aListener
) {
341 MOZ_ASSERT(NS_IsMainThread());
342 MOZ_ASSERT(aListener
);
343 mMainThreadListeners
.RemoveElement(aListener
);
347 * Append to the message queue a control message to execute a given lambda
348 * function with no parameters. The queue is drained during
349 * RunInStableState(). The lambda will be executed on the graph thread.
350 * The lambda will not be executed if the graph has been forced to shut
353 template <typename Function
>
354 void QueueControlMessageWithNoShutdown(Function
&& aFunction
) {
355 QueueMessage(WrapUnique(
356 new ControlMessageWithNoShutdown(std::forward
<Function
>(aFunction
))));
359 enum class IsInShutdown
{ No
, Yes
};
361 * Append to the message queue a control message to execute a given lambda
362 * function with a single IsInShutdown parameter. A No argument indicates
363 * execution on the thread of a graph that is still running. A Yes argument
364 * indicates execution on the main thread when the graph has been forced to
367 template <typename Function
>
368 void QueueControlOrShutdownMessage(Function
&& aFunction
) {
369 QueueMessage(WrapUnique(
370 new ControlOrShutdownMessage(std::forward
<Function
>(aFunction
))));
374 * Ensure a runnable will run on the main thread after running all pending
375 * updates that were sent from the graph thread or will be sent before the
376 * graph thread receives the next graph update.
378 * If the graph has been shut down or destroyed, then the runnable will be
379 * dispatched to the event queue immediately. (There are no pending updates
380 * in this situation.)
384 void RunAfterPendingUpdates(already_AddRefed
<nsIRunnable
> aRunnable
);
386 // Signal that the client is done with this MediaTrack. It will be deleted
388 virtual void Destroy();
390 // Returns the main-thread's view of how much data has been processed by
392 TrackTime
GetCurrentTime() const {
393 NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
394 return mMainThreadCurrentTime
;
396 // Return the main thread's view of whether this track has ended.
397 bool IsEnded() const {
398 NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
399 return mMainThreadEnded
;
402 bool IsDestroyed() const {
403 NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
404 return mMainThreadDestroyed
;
407 friend class MediaTrackGraphImpl
;
408 friend class MediaInputPort
;
409 friend class AudioNodeExternalInputTrack
;
411 virtual AudioProcessingTrack
* AsAudioProcessingTrack() { return nullptr; }
412 virtual SourceMediaTrack
* AsSourceTrack() { return nullptr; }
413 virtual ProcessedMediaTrack
* AsProcessedTrack() { return nullptr; }
414 virtual AudioNodeTrack
* AsAudioNodeTrack() { return nullptr; }
415 virtual ForwardedInputTrack
* AsForwardedInputTrack() { return nullptr; }
416 virtual CrossGraphTransmitter
* AsCrossGraphTransmitter() { return nullptr; }
417 virtual CrossGraphReceiver
* AsCrossGraphReceiver() { return nullptr; }
418 virtual DeviceInputTrack
* AsDeviceInputTrack() { return nullptr; }
419 virtual DeviceInputConsumerTrack
* AsDeviceInputConsumerTrack() {
423 // These Impl methods perform the core functionality of the control methods
424 // above, on the media graph thread.
426 * Stop all track activity and disconnect it from all inputs and outputs.
427 * This must be idempotent.
429 virtual void DestroyImpl();
430 TrackTime
GetEnd() const;
433 * Removes all direct listeners and signals to them that they have been
436 virtual void RemoveAllDirectListenersImpl() {}
437 void RemoveAllResourcesAndListenersImpl();
439 virtual void AddListenerImpl(already_AddRefed
<MediaTrackListener
> aListener
);
440 virtual void RemoveListenerImpl(MediaTrackListener
* aListener
);
441 virtual void AddDirectListenerImpl(
442 already_AddRefed
<DirectMediaTrackListener
> aListener
);
443 virtual void RemoveDirectListenerImpl(DirectMediaTrackListener
* aListener
);
444 virtual void SetDisabledTrackModeImpl(DisabledTrackMode aMode
);
446 void AddConsumer(MediaInputPort
* aPort
) { mConsumers
.AppendElement(aPort
); }
447 void RemoveConsumer(MediaInputPort
* aPort
) {
448 mConsumers
.RemoveElement(aPort
);
450 GraphTime
StartTime() const { return mStartTime
; }
451 bool Ended() const { return mEnded
; }
453 // Returns the current number of channels this track contains if it's an audio
454 // track. Calling this on a video track will trip assertions. Graph thread
456 virtual uint32_t NumberOfChannels() const = 0;
458 // The DisabledTrackMode after combining the explicit mode and that of the
460 virtual DisabledTrackMode
CombinedDisabledMode() const {
461 return mDisabledMode
;
464 template <class SegmentType
>
465 SegmentType
* GetData() const {
469 if (mSegment
->GetType() != SegmentType::StaticType()) {
472 return static_cast<SegmentType
*>(mSegment
.get());
474 MediaSegment
* GetData() const { return mSegment
.get(); }
476 double TrackTimeToSeconds(TrackTime aTime
) const {
477 NS_ASSERTION(0 <= aTime
&& aTime
<= TRACK_TIME_MAX
, "Bad time");
478 return static_cast<double>(aTime
) / mSampleRate
;
480 int64_t TrackTimeToMicroseconds(TrackTime aTime
) const {
481 NS_ASSERTION(0 <= aTime
&& aTime
<= TRACK_TIME_MAX
, "Bad time");
482 return (aTime
* 1000000) / mSampleRate
;
484 TrackTime
SecondsToNearestTrackTime(double aSeconds
) const {
485 NS_ASSERTION(0 <= aSeconds
&& aSeconds
<= TRACK_TICKS_MAX
/ TRACK_RATE_MAX
,
487 return mSampleRate
* aSeconds
+ 0.5;
489 TrackTime
MicrosecondsToTrackTimeRoundDown(int64_t aMicroseconds
) const {
490 return (aMicroseconds
* mSampleRate
) / 1000000;
493 TrackTicks
TimeToTicksRoundUp(TrackRate aRate
, TrackTime aTime
) const {
494 return RateConvertTicksRoundUp(aRate
, mSampleRate
, aTime
);
496 TrackTime
TicksToTimeRoundDown(TrackRate aRate
, TrackTicks aTicks
) const {
497 return RateConvertTicksRoundDown(mSampleRate
, aRate
, aTicks
);
500 * Convert graph time to track time. aTime must be <= mStateComputedTime
501 * to ensure we know exactly how much time this track will be blocked during
504 TrackTime
GraphTimeToTrackTimeWithBlocking(GraphTime aTime
) const;
506 * Convert graph time to track time. This assumes there is no blocking time
507 * to take account of, which is always true except between a track
508 * having its blocking time calculated in UpdateGraph and its blocking time
509 * taken account of in UpdateCurrentTimeForTracks.
511 TrackTime
GraphTimeToTrackTime(GraphTime aTime
) const;
513 * Convert track time to graph time. This assumes there is no blocking time
514 * to take account of, which is always true except between a track
515 * having its blocking time calculated in UpdateGraph and its blocking time
516 * taken account of in UpdateCurrentTimeForTracks.
518 GraphTime
TrackTimeToGraphTime(TrackTime aTime
) const;
520 virtual void ApplyTrackDisabling(MediaSegment
* aSegment
,
521 MediaSegment
* aRawSegment
= nullptr);
523 // Return true if the main thread needs to observe updates from this track.
524 virtual bool MainThreadNeedsUpdates() const { return true; }
526 virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf
) const;
527 virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const;
529 bool IsSuspended() const { return mSuspendedCount
> 0; }
531 * Increment suspend count and move it to GraphImpl()->mSuspendedTracks if
532 * necessary. Graph thread.
534 void IncrementSuspendCount();
536 * Increment suspend count on aTrack and move it to GraphImpl()->mTracks if
537 * necessary. GraphThread.
539 virtual void DecrementSuspendCount();
541 void AssertOnGraphThread() const;
542 void AssertOnGraphThreadOrNotRunning() const;
545 * For use during ProcessedMediaTrack::ProcessInput() or
546 * MediaTrackListener callbacks, when graph state cannot be changed.
547 * Queues a control message to execute a given lambda function with no
548 * parameters after processing, at a time when graph state can be changed.
549 * The lambda will always be executed before handing control of the graph
550 * to the main thread for shutdown.
553 template <typename Function
>
554 void RunAfterProcessing(Function
&& aFunction
) {
555 RunMessageAfterProcessing(WrapUnique(
556 new ControlMessageWithNoShutdown(std::forward
<Function
>(aFunction
))));
559 class ControlMessageInterface
;
562 // Called on graph thread either during destroy handling or before handing
563 // graph control to the main thread to release tracks.
564 virtual void OnGraphThreadDone() {}
566 // |AdvanceTimeVaryingValuesToCurrentTime| will be override in
568 virtual void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime
,
569 GraphTime aBlockedTime
);
572 template <typename Function
>
573 class ControlMessageWithNoShutdown
;
574 template <typename Function
>
575 class ControlOrShutdownMessage
;
577 void QueueMessage(UniquePtr
<ControlMessageInterface
> aMessage
);
578 void RunMessageAfterProcessing(UniquePtr
<ControlMessageInterface
> aMessage
);
580 void NotifyMainThreadListeners() {
581 NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
583 for (int32_t i
= mMainThreadListeners
.Length() - 1; i
>= 0; --i
) {
584 mMainThreadListeners
[i
]->NotifyMainThreadTrackEnded();
586 mMainThreadListeners
.Clear();
589 bool ShouldNotifyTrackEnded() {
590 NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
591 if (!mMainThreadEnded
|| mEndedNotificationSent
) {
595 mEndedNotificationSent
= true;
600 // Notifies listeners and consumers of the change in disabled mode when the
601 // current combined mode is different from aMode.
602 void NotifyIfDisabledModeChangedFrom(DisabledTrackMode aOldMode
);
604 // This state is all initialized on the main thread but
605 // otherwise modified only on the media graph thread.
607 // Buffered data. The start of the buffer corresponds to mStartTime.
608 // Conceptually the buffer contains everything this track has ever played,
609 // but we forget some prefix of the buffered data to bound the space usage.
610 // Note that this may be null for tracks that never contain data, like
611 // non-external AudioNodeTracks.
612 const UniquePtr
<MediaSegment
> mSegment
;
614 // The time when the buffered data could be considered to have started
615 // playing. This increases over time to account for time the track was
616 // blocked before mCurrentTime.
617 GraphTime mStartTime
;
619 // The time until which we last called mSegment->ForgetUpTo().
620 TrackTime mForgottenTime
;
622 // True once we've processed mSegment until the end and no more data will be
623 // added. Note that mSegment might still contain data for the current
627 // True after track listeners have been notified that this track has ended.
630 // Client-set volume of this track
631 nsTArray
<RefPtr
<MediaTrackListener
>> mTrackListeners
;
632 nsTArray
<MainThreadMediaTrackListener
*> mMainThreadListeners
;
633 // This track's associated disabled mode. It can either by disabled by frames
634 // being replaced by black, or by retaining the previous frame.
635 DisabledTrackMode mDisabledMode
;
637 // GraphTime at which this track starts blocking.
638 // This is only valid up to mStateComputedTime. The track is considered to
639 // have not been blocked before mCurrentTime (its mStartTime is
640 // increased as necessary to account for that time instead).
641 GraphTime mStartBlocking
;
643 // MediaInputPorts to which this is connected
644 nsTArray
<MediaInputPort
*> mConsumers
;
647 * Number of outstanding suspend operations on this track. Track is
648 * suspended when this is > 0.
650 int32_t mSuspendedCount
;
652 // Main-thread views of state
653 TrackTime mMainThreadCurrentTime
;
654 bool mMainThreadEnded
;
655 bool mEndedNotificationSent
;
656 bool mMainThreadDestroyed
;
658 // Our media track graph. null if destroyed on the graph thread.
659 MediaTrackGraph
* mGraph
;
663 * This is a track into which a decoder can write audio or video.
665 * Audio or video can be written on any thread, but you probably want to
666 * always write from the same thread to avoid unexpected interleavings.
668 * For audio the sample rate of the written data can differ from the sample rate
669 * of the graph itself. Use SetAppendDataSourceRate to inform the track what
670 * rate written audio data will be sampled in.
672 class SourceMediaTrack
: public MediaTrack
{
674 SourceMediaTrack(MediaSegment::Type aType
, TrackRate aSampleRate
);
676 SourceMediaTrack
* AsSourceTrack() override
{ return this; }
681 * Enable or disable pulling.
682 * When pulling is enabled, NotifyPull gets called on the
683 * MediaTrackListeners for this track during the MediaTrackGraph
684 * control loop. Pulling is initially disabled. Due to unavoidable race
685 * conditions, after a call to SetPullingEnabled(false) it is still possible
686 * for a NotifyPull to occur.
688 void SetPullingEnabled(bool aEnabled
);
690 // MediaTrackGraph thread only
691 void DestroyImpl() override
;
693 // Call these on any thread.
695 * Call all MediaTrackListeners to request new data via the NotifyPull
697 * aDesiredUpToTime (in): end time of new data requested.
699 * Returns true if new data is about to be added.
701 bool PullNewData(GraphTime aDesiredUpToTime
);
704 * Extract any state updates pending in the track, and apply them.
706 void ExtractPendingInput(GraphTime aCurrentTime
, GraphTime aDesiredUpToTime
);
709 * All data appended with AppendData() from this point on will be resampled
710 * from aRate to the graph rate.
712 * Resampling for video does not make sense and is forbidden.
714 void SetAppendDataSourceRate(TrackRate aRate
);
717 * Append media data to this track. Ownership of aSegment remains with the
718 * caller, but aSegment is emptied. Returns 0 if the data was not appended
719 * because the stream has ended. Returns the duration of the appended data in
720 * the graph's track rate otherwise.
722 TrackTime
AppendData(MediaSegment
* aSegment
,
723 MediaSegment
* aRawSegment
= nullptr);
726 * Clear any data appended with AppendData() that hasn't entered the graph
727 * yet. Returns the duration of the cleared data in the graph's track rate.
729 TrackTime
ClearFutureData();
732 * Indicate that this track has ended. Do not do any more API calls affecting
737 void SetDisabledTrackModeImpl(DisabledTrackMode aMode
) override
;
739 uint32_t NumberOfChannels() const override
;
741 void RemoveAllDirectListenersImpl() override
;
743 // The value set here is applied in MoveToSegment so we can avoid the
744 // buffering delay in applying the change. See Bug 1443511.
745 void SetVolume(float aVolume
);
746 float GetVolumeLocked() MOZ_REQUIRES(mMutex
);
748 Mutex
& GetMutex() MOZ_RETURN_CAPABILITY(mMutex
) { return mMutex
; }
750 friend class MediaTrackGraphImpl
;
753 enum TrackCommands
: uint32_t;
755 virtual ~SourceMediaTrack();
758 * Data to cater for appending media data to this track.
761 // Sample rate of the input data.
762 TrackRate mInputRate
;
763 // Resampler if the rate of the input track does not match the
764 // MediaTrackGraph's.
765 nsAutoRef
<SpeexResamplerState
> mResampler
;
766 uint32_t mResamplerChannelCount
;
767 // Each time the track updates are flushed to the media graph thread,
768 // the segment buffer is emptied.
769 UniquePtr
<MediaSegment
> mData
;
770 // True once the producer has signaled that no more data is coming.
772 // True if the producer of this track is having data pulled by the graph.
773 bool mPullingEnabled
;
774 // True if the graph has notified this track that it will not be used
775 // again on the graph thread.
776 bool mGraphThreadDone
;
781 void ResampleAudioToGraphSampleRate(MediaSegment
* aSegment
)
782 MOZ_REQUIRES(mMutex
);
784 void AddDirectListenerImpl(
785 already_AddRefed
<DirectMediaTrackListener
> aListener
) override
;
786 void RemoveDirectListenerImpl(DirectMediaTrackListener
* aListener
) override
;
789 * Notify direct consumers of new data to this track.
790 * The data doesn't have to be resampled (though it may be). This is called
791 * from AppendData on the thread providing the data, and will call
792 * the Listeners on this thread.
794 void NotifyDirectConsumers(MediaSegment
* aSegment
) MOZ_REQUIRES(mMutex
);
796 void OnGraphThreadDone() override
{
797 MutexAutoLock
lock(mMutex
);
801 mUpdateTrack
->mGraphThreadDone
= true;
802 if (!mUpdateTrack
->mData
) {
805 mUpdateTrack
->mData
->Clear();
808 virtual void AdvanceTimeVaryingValuesToCurrentTime(
809 GraphTime aCurrentTime
, GraphTime aBlockedTime
) override
;
811 // This must be acquired *before* MediaTrackGraphImpl's lock, if they are
814 // protected by mMutex
815 float mVolume
MOZ_GUARDED_BY(mMutex
) = 1.0;
816 UniquePtr
<TrackData
> mUpdateTrack
MOZ_GUARDED_BY(mMutex
);
817 // This track's associated disabled mode for uses on the producing thread.
818 // It can either by disabled by frames being replaced by black, or by
819 // retaining the previous frame.
820 DisabledTrackMode mDirectDisabledMode
MOZ_GUARDED_BY(mMutex
) =
821 DisabledTrackMode::ENABLED
;
822 nsTArray
<RefPtr
<DirectMediaTrackListener
>> mDirectTrackListeners
823 MOZ_GUARDED_BY(mMutex
);
827 * A ref-counted wrapper of a MediaTrack that allows multiple users to share a
828 * reference to the same MediaTrack with the purpose of being guaranteed that
829 * the graph it is in is kept alive.
831 * Automatically suspended on creation and destroyed on destruction. Main thread
834 struct SharedDummyTrack
{
835 NS_INLINE_DECL_REFCOUNTING(SharedDummyTrack
)
836 explicit SharedDummyTrack(MediaTrack
* aTrack
) : mTrack(aTrack
) {
839 const RefPtr
<MediaTrack
> mTrack
;
842 ~SharedDummyTrack() { mTrack
->Destroy(); }
846 * Represents a connection between a ProcessedMediaTrack and one of its
848 * We make these refcounted so that track-related messages with MediaInputPort*
849 * pointers can be sent to the main thread safely.
851 * When a port's source or destination track dies, the track's DestroyImpl
852 * calls MediaInputPort::Disconnect to disconnect the port from
853 * the source and destination tracks.
855 * The lifetimes of MediaInputPort are controlled from the main thread.
856 * The media graph adds a reference to the port. When a MediaInputPort is no
857 * longer needed, main-thread code sends a Destroy message for the port and
858 * clears its reference (the last main-thread reference to the object). When
859 * the Destroy message is processed on the graph manager thread we disconnect
860 * the port and drop the graph's reference, destroying the object.
862 class MediaInputPort final
{
864 // Do not call this constructor directly. Instead call
865 // aDest->AllocateInputPort.
866 MediaInputPort(MediaTrackGraphImpl
* aGraph
, MediaTrack
* aSource
,
867 ProcessedMediaTrack
* aDest
, uint16_t aInputNumber
,
868 uint16_t aOutputNumber
)
871 mInputNumber(aInputNumber
),
872 mOutputNumber(aOutputNumber
),
874 MOZ_COUNT_CTOR(MediaInputPort
);
877 // Private destructor, to discourage deletion outside of Release():
878 MOZ_COUNTED_DTOR(MediaInputPort
)
881 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaInputPort
)
884 * Disconnects and destroys the port. The caller must not reference this
885 * object again. Main thread.
889 // The remaining methods and members must always be called on the graph thread
890 // from within MediaTrackGraph.cpp.
893 // Called during message processing to trigger removal of this port's source
894 // and destination tracks.
897 MediaTrack
* GetSource() const;
898 ProcessedMediaTrack
* GetDestination() const;
900 uint16_t InputNumber() const { return mInputNumber
; }
901 uint16_t OutputNumber() const { return mOutputNumber
; }
903 struct InputInterval
{
906 bool mInputIsBlocked
;
908 // Find the next time interval starting at or after aTime during which
909 // aPort->mDest is not blocked and aPort->mSource's blocking status does not
910 // change. A null aPort returns a blocked interval starting at aTime.
911 static InputInterval
GetNextInputInterval(MediaInputPort
const* aPort
,
915 * Returns the graph that owns this port.
917 MediaTrackGraphImpl
* GraphImpl() const;
918 MediaTrackGraph
* Graph() const;
921 * Sets the graph that owns this track. Should only be called once.
923 void SetGraphImpl(MediaTrackGraphImpl
* aGraph
);
926 * Notify the port that the source MediaTrack has been suspended.
931 * Notify the port that the source MediaTrack has been resumed.
935 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf
) const {
945 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const {
946 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf
);
950 friend class ProcessedMediaTrack
;
951 // Never modified after Init()
953 ProcessedMediaTrack
* mDest
;
954 // The input and output numbers are optional, and are currently only used by
956 const uint16_t mInputNumber
;
957 const uint16_t mOutputNumber
;
959 // Our media track graph
960 MediaTrackGraphImpl
* mGraph
;
964 * This track processes zero or more input tracks in parallel to produce
965 * its output. The details of how the output is produced are handled by
966 * subclasses overriding the ProcessInput method.
968 class ProcessedMediaTrack
: public MediaTrack
{
970 ProcessedMediaTrack(TrackRate aSampleRate
, MediaSegment::Type aType
,
971 MediaSegment
* aSegment
)
972 : MediaTrack(aSampleRate
, aType
, aSegment
),
978 * Allocates a new input port attached to source aTrack.
979 * This port can be removed by calling MediaInputPort::Destroy().
981 already_AddRefed
<MediaInputPort
> AllocateInputPort(
982 MediaTrack
* aTrack
, uint16_t aInputNumber
= 0,
983 uint16_t aOutputNumber
= 0);
985 * Queue a message to set the autoend flag on this track (defaults to
986 * true). When this flag is set, and the input track has ended playout
987 * (including if there is no input track), this track automatically
988 * enters the ended state.
990 virtual void QueueSetAutoend(bool aAutoend
);
992 ProcessedMediaTrack
* AsProcessedTrack() override
{ return this; }
994 friend class MediaTrackGraphImpl
;
996 // Do not call these from outside MediaTrackGraph.cpp!
997 virtual void AddInput(MediaInputPort
* aPort
);
998 virtual void RemoveInput(MediaInputPort
* aPort
) {
999 mInputs
.RemoveElement(aPort
) || mSuspendedInputs
.RemoveElement(aPort
);
1001 bool HasInputPort(MediaInputPort
* aPort
) const {
1002 return mInputs
.Contains(aPort
) || mSuspendedInputs
.Contains(aPort
);
1004 uint32_t InputPortCount() const {
1005 return mInputs
.Length() + mSuspendedInputs
.Length();
1007 void InputSuspended(MediaInputPort
* aPort
);
1008 void InputResumed(MediaInputPort
* aPort
);
1009 void DestroyImpl() override
;
1010 void DecrementSuspendCount() override
;
1012 * This gets called after we've computed the blocking states for all
1013 * tracks (mBlocked is up to date up to mStateComputedTime).
1014 * Also, we've produced output for all tracks up to this one. If this track
1015 * is not in a cycle, then all its source tracks have produced data.
1016 * Generate output from aFrom to aTo, where aFrom < aTo.
1017 * This will be called on tracks that have ended. Most track types should
1018 * just return immediately if they're ended, but some may wish to update
1019 * internal state (see AudioNodeTrack).
1020 * ProcessInput is allowed to set mEnded only if ALLOW_END is in aFlags. (This
1021 * flag will be set when aTo >= mStateComputedTime, i.e. when we've produced
1022 * the last block of data we need to produce.) Otherwise we can get into a
1023 * situation where we've determined the track should not block before
1024 * mStateComputedTime, but the track ends before mStateComputedTime, violating
1025 * the invariant that ended tracks are blocked.
1027 enum { ALLOW_END
= 0x01 };
1028 virtual void ProcessInput(GraphTime aFrom
, GraphTime aTo
,
1029 uint32_t aFlags
) = 0;
1030 void SetAutoendImpl(bool aAutoend
) { mAutoend
= aAutoend
; }
1032 // Only valid after MediaTrackGraphImpl::UpdateTrackOrder() has run.
1033 // A DelayNode is considered to break a cycle and so this will not return
1034 // true for echo loops, only for muted cycles.
1035 bool InMutedCycle() const { return mCycleMarker
; }
1037 // Used by ForwardedInputTrack to propagate the disabled mode along the graph.
1038 virtual void OnInputDisabledModeChanged(DisabledTrackMode aMode
) {}
1040 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf
) const override
{
1041 size_t amount
= MediaTrack::SizeOfExcludingThis(aMallocSizeOf
);
1043 // - mInputs elements
1044 // - mSuspendedInputs elements
1045 amount
+= mInputs
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1046 amount
+= mSuspendedInputs
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1050 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const override
{
1051 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf
);
1055 // This state is all accessed only on the media graph thread.
1057 // The list of all inputs that are not currently suspended.
1058 nsTArray
<MediaInputPort
*> mInputs
;
1059 // The list of all inputs that are currently suspended.
1060 nsTArray
<MediaInputPort
*> mSuspendedInputs
;
1062 // After UpdateTrackOrder(), mCycleMarker is either 0 or 1 to indicate
1063 // whether this track is in a muted cycle. During ordering it can contain
1064 // other marker values - see MediaTrackGraphImpl::UpdateTrackOrder().
1065 uint32_t mCycleMarker
;
1069 * There is a single MediaTrackGraph per window.
1070 * Additionaly, each OfflineAudioContext object creates its own MediaTrackGraph
1073 class MediaTrackGraph
{
1075 // We ensure that the graph current time advances in multiples of
1076 // IdealAudioBlockSize()/AudioStream::PreferredSampleRate(). A track that
1077 // never blocks and has the ideal audio rate will produce audio in multiples
1078 // of the block size.
1080 // Initializing a graph that outputs audio can take quite long on some
1081 // platforms. Code that want to output audio at some point can express the
1082 // fact that they will need an audio track at some point by passing
1083 // AUDIO_THREAD_DRIVER when getting an instance of MediaTrackGraph, so that
1084 // the graph starts with the right driver.
1085 enum GraphDriverType
{
1086 AUDIO_THREAD_DRIVER
,
1087 SYSTEM_THREAD_DRIVER
,
1088 OFFLINE_THREAD_DRIVER
1090 // A MediaTrackGraph running an AudioWorklet must always be run from the
1091 // same thread, in order to run js. To acheive this, create the graph with
1092 // a SINGLE_THREAD RunType. DIRECT_DRIVER will run the graph directly off
1093 // the GraphDriver's thread.
1098 static const uint32_t AUDIO_CALLBACK_DRIVER_SHUTDOWN_TIMEOUT
= 20 * 1000;
1099 static const TrackRate REQUEST_DEFAULT_SAMPLE_RATE
= 0;
1100 constexpr static const CubebUtils::AudioDeviceID DEFAULT_OUTPUT_DEVICE
=
1104 static MediaTrackGraph
* GetInstanceIfExists(
1105 nsPIDOMWindowInner
* aWindow
, TrackRate aSampleRate
,
1106 CubebUtils::AudioDeviceID aPrimaryOutputDeviceID
);
1107 static MediaTrackGraph
* GetInstance(
1108 GraphDriverType aGraphDriverRequested
, nsPIDOMWindowInner
* aWindow
,
1109 TrackRate aSampleRate
, CubebUtils::AudioDeviceID aPrimaryOutputDeviceID
);
1110 static MediaTrackGraph
* CreateNonRealtimeInstance(TrackRate aSampleRate
);
1113 void ForceShutDown();
1115 virtual void OpenAudioInput(DeviceInputTrack
* aTrack
) = 0;
1116 virtual void CloseAudioInput(DeviceInputTrack
* aTrack
) = 0;
1120 * Create a track that a media decoder (or some other source of
1121 * media data, such as a camera) can write to.
1123 SourceMediaTrack
* CreateSourceTrack(MediaSegment::Type aType
);
1125 * Create a track that will forward data from its input track.
1127 * A TrackUnionStream can have 0 or 1 input streams. Adding more than that is
1130 * A TrackUnionStream will end when autoending is enabled (default) and there
1131 * is no input, or the input's source is ended. If there is no input and
1132 * autoending is disabled, TrackUnionStream will continue to produce silence
1133 * for audio or the last video frame for video.
1135 ProcessedMediaTrack
* CreateForwardedInputTrack(MediaSegment::Type aType
);
1137 * Create a track that will mix all its audio inputs.
1139 AudioCaptureTrack
* CreateAudioCaptureTrack();
1141 CrossGraphTransmitter
* CreateCrossGraphTransmitter(
1142 CrossGraphReceiver
* aReceiver
);
1143 CrossGraphReceiver
* CreateCrossGraphReceiver(TrackRate aTransmitterRate
);
1146 * Add a new track to the graph. Main thread.
1148 void AddTrack(MediaTrack
* aTrack
);
1150 /* From the main thread, ask the MTG to resolve the returned promise when
1151 * the device specified has started.
1152 * A null aDeviceID indicates the default audio output device.
1153 * The promise is rejected with NS_ERROR_INVALID_ARG if aSink does not
1154 * correspond to any output devices used by the graph, or
1155 * NS_ERROR_NOT_AVAILABLE if outputs to the device are removed or
1156 * NS_ERROR_ILLEGAL_DURING_SHUTDOWN if the graph is force shut down
1157 * before the promise could be resolved.
1159 using GraphStartedPromise
= GenericPromise
;
1160 virtual RefPtr
<GraphStartedPromise
> NotifyWhenDeviceStarted(
1161 CubebUtils::AudioDeviceID aDeviceID
) = 0;
1163 /* From the main thread, suspend, resume or close an AudioContext. Calls
1164 * are not counted. Even Resume calls can be more frequent than Suspend
1167 * aTracks are the tracks of all the AudioNodes of the AudioContext that
1168 * need to be suspended or resumed. Suspend and Resume operations on these
1169 * tracks are counted. Resume operations must not outnumber Suspends and a
1170 * track will not resume until the number of Resume operations matches the
1171 * number of Suspends. This array may be empty if, for example, this is a
1172 * second consecutive suspend call and all the nodes are already suspended.
1174 * This can possibly pause the graph thread, releasing system resources, if
1175 * all tracks have been suspended/closed.
1177 * When the operation is complete, the returned promise is resolved.
1179 using AudioContextOperationPromise
=
1180 MozPromise
<dom::AudioContextState
, bool, true>;
1181 RefPtr
<AudioContextOperationPromise
> ApplyAudioContextOperation(
1182 MediaTrack
* aDestinationTrack
, nsTArray
<RefPtr
<MediaTrack
>> aTracks
,
1183 dom::AudioContextOperation aOperation
);
1185 bool IsNonRealtime() const;
1187 * Start processing non-realtime for a specific number of ticks.
1189 void StartNonRealtimeProcessing(uint32_t aTicksToProcess
);
1192 * NotifyJSContext() is called on the graph thread before content script
1195 void NotifyJSContext(JSContext
* aCx
);
1198 * Media graph thread only.
1199 * Dispatches a runnable that will run on the main thread after all
1200 * main-thread track state has been updated, i.e., during stable state.
1202 * Should only be called during MediaTrackListener callbacks or during
1203 * ProcessedMediaTrack::ProcessInput().
1205 * Note that if called during shutdown the runnable will be ignored and
1206 * released on main thread.
1208 void DispatchToMainThreadStableState(already_AddRefed
<nsIRunnable
> aRunnable
);
1209 /* Called on the graph thread when the input device settings should be
1210 * reevaluated, for example, if the channel count of the input track should
1212 void ReevaluateInputDevice(CubebUtils::AudioDeviceID aID
);
1215 * Returns graph sample rate in Hz.
1217 TrackRate
GraphRate() const { return mSampleRate
; }
1219 * Returns the ID of the device used for audio output through an
1220 * AudioCallbackDriver. This is the device specified when creating the
1221 * graph. Can be called on any thread.
1223 CubebUtils::AudioDeviceID
PrimaryOutputDeviceID() const {
1224 return mPrimaryOutputDeviceID
;
1227 double AudioOutputLatency();
1228 /* Return whether the clock for the audio output device used for the AEC
1229 * reverse stream might drift from the clock for this MediaTrackGraph.
1230 * Graph thread only. */
1231 bool OutputForAECMightDrift();
1233 void RegisterCaptureTrackForWindow(uint64_t aWindowId
,
1234 ProcessedMediaTrack
* aCaptureTrack
);
1235 void UnregisterCaptureTrackForWindow(uint64_t aWindowId
);
1236 already_AddRefed
<MediaInputPort
> ConnectToCaptureTrack(
1237 uint64_t aWindowId
, MediaTrack
* aMediaTrack
);
1239 void AssertOnGraphThread() const { MOZ_ASSERT(OnGraphThread()); }
1240 void AssertOnGraphThreadOrNotRunning() const {
1241 MOZ_ASSERT(OnGraphThreadOrNotRunning());
1245 * Returns a watchable of the graph's main-thread observable graph time.
1248 virtual Watchable
<GraphTime
>& CurrentTime() = 0;
1251 * Graph thread function to return the time at which all processing has been
1252 * completed. Some tracks may have performed processing beyond this time.
1254 GraphTime
ProcessedTime() const;
1256 * For Graph thread logging.
1258 void* CurrentDriver() const;
1260 /* Do not call this directly. For users who need to get a DeviceInputTrack,
1261 * use DeviceInputTrack::OpenAudio() instead. This should only be used in
1262 * DeviceInputTrack to get the existing DeviceInputTrack paired with the given
1263 * device in this graph. Main thread only.*/
1264 DeviceInputTrack
* GetDeviceInputTrackMainThread(
1265 CubebUtils::AudioDeviceID aID
);
1267 /* Do not call this directly. This should only be used in DeviceInputTrack to
1268 * get the existing NativeInputTrackMain thread only.*/
1269 NativeInputTrack
* GetNativeInputTrackMainThread();
1272 explicit MediaTrackGraph(TrackRate aSampleRate
,
1273 CubebUtils::AudioDeviceID aPrimaryOutputDeviceID
)
1274 : mSampleRate(aSampleRate
),
1275 mPrimaryOutputDeviceID(aPrimaryOutputDeviceID
) {
1276 MOZ_COUNT_CTOR(MediaTrackGraph
);
1278 MOZ_COUNTED_DTOR_VIRTUAL(MediaTrackGraph
)
1280 // Intended only for assertions, either on graph thread or not running (in
1281 // which case we must be on the main thread).
1282 virtual bool OnGraphThreadOrNotRunning() const = 0;
1283 virtual bool OnGraphThread() const = 0;
1285 // Intended only for internal assertions. Main thread only.
1286 virtual bool Destroyed() const = 0;
1289 * Sample rate at which this graph runs. For real time graphs, this is
1290 * the rate of the audio mixer. For offline graphs, this is the rate specified
1293 const TrackRate mSampleRate
;
1295 * Device to use for audio output through an AudioCallbackDriver.
1296 * This is the device specified when creating the graph.
1298 const CubebUtils::AudioDeviceID mPrimaryOutputDeviceID
;
1301 inline void MediaTrack::AssertOnGraphThread() const {
1302 Graph()->AssertOnGraphThread();
1304 inline void MediaTrack::AssertOnGraphThreadOrNotRunning() const {
1305 Graph()->AssertOnGraphThreadOrNotRunning();
1309 * This represents a message run on the graph thread to modify track or graph
1310 * state. These are passed from main thread to graph thread by
1311 * QueueControlMessageWithNoShutdown() or QueueControlOrShutdownMessage()
1312 * through AppendMessage(), or scheduled on the graph thread with
1313 * RunAfterProcessing().
1315 class MediaTrack::ControlMessageInterface
{
1317 MOZ_COUNTED_DEFAULT_CTOR(ControlMessageInterface
)
1318 // All these run on the graph thread unless the graph has been forced to
1320 MOZ_COUNTED_DTOR_VIRTUAL(ControlMessageInterface
)
1321 // Do the action of this message on the MediaTrackGraph thread. Any actions
1322 // affecting graph processing should take effect at mProcessedTime.
1323 // All track data for times < mProcessedTime has already been
1325 virtual void Run() = 0;
1326 // RunDuringShutdown() is only relevant to messages generated on the main
1327 // thread by QueueControlOrShutdownMessage() or for AppendMessage().
1328 // When we're shutting down the application, most messages are ignored but
1329 // some cleanup messages should still be processed (on the main thread).
1330 // This must not add new control messages to the graph.
1331 virtual void RunDuringShutdown() {}
1334 template <typename Function
>
1335 class MediaTrack::ControlMessageWithNoShutdown
1336 : public ControlMessageInterface
{
1338 explicit ControlMessageWithNoShutdown(Function
&& aFunction
)
1339 : mFunction(std::forward
<Function
>(aFunction
)) {}
1341 void Run() override
{
1342 static_assert(std::is_void_v
<decltype(mFunction())>,
1343 "The lambda must return void!");
1348 using StoredFunction
= std::decay_t
<Function
>;
1349 StoredFunction mFunction
;
1352 template <typename Function
>
1353 class MediaTrack::ControlOrShutdownMessage
: public ControlMessageInterface
{
1355 explicit ControlOrShutdownMessage(Function
&& aFunction
)
1356 : mFunction(std::forward
<Function
>(aFunction
)) {}
1358 void Run() override
{
1359 static_assert(std::is_void_v
<decltype(mFunction(IsInShutdown()))>,
1360 "The lambda must return void!");
1361 mFunction(IsInShutdown::No
);
1363 void RunDuringShutdown() override
{ mFunction(IsInShutdown::Yes
); }
1366 // The same lambda is used whether or not in shutdown so that captured
1367 // variables are available in both cases.
1368 using StoredFunction
= std::decay_t
<Function
>;
1369 StoredFunction mFunction
;
1372 } // namespace mozilla
1374 #endif /* MOZILLA_MEDIATRACKGRAPH_H_ */