Bug 1941046 - Part 4: Send a callback request for impression and clicks of MARS Top...
[gecko.git] / dom / media / MediaTrackGraph.h
blobe9d38efdd1707664ecd50aa0baf1cc044c0c059b
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"
20 #include "nsTArray.h"
21 #include <speex/speex_resampler.h>
23 class nsIRunnable;
24 class nsIGlobalObject;
25 class nsPIDOMWindowInner;
27 namespace mozilla {
28 class AsyncLogger;
29 class AudioCaptureTrack;
30 class CrossGraphTransmitter;
31 class CrossGraphReceiver;
32 class NativeInputTrack;
33 }; // namespace mozilla
35 extern mozilla::AsyncLogger gMTGTraceLogger;
37 template <>
38 class nsAutoRefTraits<SpeexResamplerState>
39 : public nsPointerRefTraits<SpeexResamplerState> {
40 public:
41 static void Release(SpeexResamplerState* aState) {
42 speex_resampler_destroy(aState);
46 namespace mozilla {
48 extern LazyLogModule gMediaTrackGraphLog;
50 namespace dom {
51 enum class AudioContextOperation : uint8_t;
52 enum class AudioContextOperationFlags;
53 enum class AudioContextState : uint8_t;
54 } // namespace dom
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;
93 class AudioNodeTrack;
94 class DirectMediaTrackListener;
95 class ForwardedInputTrack;
96 class MediaInputPort;
97 class MediaTrack;
98 class MediaTrackGraph;
99 class MediaTrackGraphImpl;
100 class MediaTrackListener;
101 class DeviceInputConsumerTrack;
102 class DeviceInputTrack;
103 class ProcessedMediaTrack;
104 class SourceMediaTrack;
106 class AudioDataListenerInterface {
107 protected:
108 // Protected destructor, to discourage deletion outside of Release():
109 virtual ~AudioDataListenerInterface() = default;
111 public:
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 {
158 protected:
159 // Protected destructor, to discourage deletion outside of Release():
160 virtual ~AudioDataListener() = default;
162 public:
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 {
179 public:
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() {}
188 size_t mTrack;
189 size_t mEngine;
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
198 * black.
199 * SILENCE_FREEZE Audio data is turned into silence, video freezes at
200 * last frame.
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
234 * VideoStreamTrack.
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
261 * media graph.
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> {
268 public:
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;
278 protected:
279 // Protected destructor, to discourage deletion outside of Release():
280 virtual ~MediaTrack();
282 public:
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);
296 // Control API.
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.
307 void Suspend();
308 void Resume();
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
332 // silence.
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
351 * down.
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
365 * shut down.
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.)
382 * Main thread only.
384 void RunAfterPendingUpdates(already_AddRefed<nsIRunnable> aRunnable);
386 // Signal that the client is done with this MediaTrack. It will be deleted
387 // later.
388 virtual void Destroy();
390 // Returns the main-thread's view of how much data has been processed by
391 // this track.
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() {
420 return nullptr;
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
434 * uninstalled.
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
455 // only.
456 virtual uint32_t NumberOfChannels() const = 0;
458 // The DisabledTrackMode after combining the explicit mode and that of the
459 // input, if any.
460 virtual DisabledTrackMode CombinedDisabledMode() const {
461 return mDisabledMode;
464 template <class SegmentType>
465 SegmentType* GetData() const {
466 if (!mSegment) {
467 return nullptr;
469 if (mSegment->GetType() != SegmentType::StaticType()) {
470 return nullptr;
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,
486 "Bad seconds");
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
502 * the interval.
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.
551 * Graph thread.
553 template <typename Function>
554 void RunAfterProcessing(Function&& aFunction) {
555 RunMessageAfterProcessing(WrapUnique(
556 new ControlMessageWithNoShutdown(std::forward<Function>(aFunction))));
559 class ControlMessageInterface;
561 protected:
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
567 // SourceMediaTrack.
568 virtual void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime,
569 GraphTime aBlockedTime);
571 private:
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) {
592 return false;
595 mEndedNotificationSent = true;
596 return true;
599 protected:
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
624 // iteration.
625 bool mEnded;
627 // True after track listeners have been notified that this track has ended.
628 bool mNotifiedEnded;
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 {
673 public:
674 SourceMediaTrack(MediaSegment::Type aType, TrackRate aSampleRate);
676 SourceMediaTrack* AsSourceTrack() override { return this; }
678 // Main thread only
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
696 * API (if enabled).
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
733 * this track.
735 void End();
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;
752 protected:
753 enum TrackCommands : uint32_t;
755 virtual ~SourceMediaTrack();
758 * Data to cater for appending media data to this track.
760 struct TrackData {
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.
771 bool mEnded;
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;
779 bool NeedsMixing();
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);
798 if (!mUpdateTrack) {
799 return;
801 mUpdateTrack->mGraphThreadDone = true;
802 if (!mUpdateTrack->mData) {
803 return;
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
812 // held together.
813 Mutex mMutex;
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
832 * only.
834 struct SharedDummyTrack {
835 NS_INLINE_DECL_REFCOUNTING(SharedDummyTrack)
836 explicit SharedDummyTrack(MediaTrack* aTrack) : mTrack(aTrack) {
837 mTrack->Suspend();
839 const RefPtr<MediaTrack> mTrack;
841 private:
842 ~SharedDummyTrack() { mTrack->Destroy(); }
846 * Represents a connection between a ProcessedMediaTrack and one of its
847 * input tracks.
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 {
863 private:
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)
869 : mSource(aSource),
870 mDest(aDest),
871 mInputNumber(aInputNumber),
872 mOutputNumber(aOutputNumber),
873 mGraph(aGraph) {
874 MOZ_COUNT_CTOR(MediaInputPort);
877 // Private destructor, to discourage deletion outside of Release():
878 MOZ_COUNTED_DTOR(MediaInputPort)
880 public:
881 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaInputPort)
884 * Disconnects and destroys the port. The caller must not reference this
885 * object again. Main thread.
887 void Destroy();
889 // The remaining methods and members must always be called on the graph thread
890 // from within MediaTrackGraph.cpp.
892 void Init();
893 // Called during message processing to trigger removal of this port's source
894 // and destination tracks.
895 void Disconnect();
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 {
904 GraphTime mStart;
905 GraphTime mEnd;
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,
912 GraphTime aTime);
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.
928 void Suspended();
931 * Notify the port that the source MediaTrack has been resumed.
933 void Resumed();
935 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
936 size_t amount = 0;
938 // Not owned:
939 // - mSource
940 // - mDest
941 // - mGraph
942 return amount;
945 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
946 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
949 private:
950 friend class ProcessedMediaTrack;
951 // Never modified after Init()
952 MediaTrack* mSource;
953 ProcessedMediaTrack* mDest;
954 // The input and output numbers are optional, and are currently only used by
955 // Web Audio.
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 {
969 public:
970 ProcessedMediaTrack(TrackRate aSampleRate, MediaSegment::Type aType,
971 MediaSegment* aSegment)
972 : MediaTrack(aSampleRate, aType, aSegment),
973 mAutoend(true),
974 mCycleMarker(0) {}
976 // Control API.
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);
1042 // Not owned:
1043 // - mInputs elements
1044 // - mSuspendedInputs elements
1045 amount += mInputs.ShallowSizeOfExcludingThis(aMallocSizeOf);
1046 amount += mSuspendedInputs.ShallowSizeOfExcludingThis(aMallocSizeOf);
1047 return amount;
1050 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
1051 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
1054 protected:
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;
1061 bool mAutoend;
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
1071 * object too.
1073 class MediaTrackGraph {
1074 public:
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.
1094 enum GraphRunType {
1095 DIRECT_DRIVER,
1096 SINGLE_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 =
1101 nullptr;
1103 // Main thread only
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);
1112 // Idempotent
1113 void ForceShutDown();
1115 virtual void OpenAudioInput(DeviceInputTrack* aTrack) = 0;
1116 virtual void CloseAudioInput(DeviceInputTrack* aTrack) = 0;
1118 // Control API.
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
1128 * an error.
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
1165 * calls.
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
1193 * runs.
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
1211 * be changed. */
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.
1246 * Main thread only.
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();
1271 protected:
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
1291 * at construction.
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 {
1316 public:
1317 MOZ_COUNTED_DEFAULT_CTOR(ControlMessageInterface)
1318 // All these run on the graph thread unless the graph has been forced to
1319 // shut down.
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
1324 // computed.
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 {
1337 public:
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!");
1344 mFunction();
1347 private:
1348 using StoredFunction = std::decay_t<Function>;
1349 StoredFunction mFunction;
1352 template <typename Function>
1353 class MediaTrack::ControlOrShutdownMessage : public ControlMessageInterface {
1354 public:
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); }
1365 private:
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_ */