LCOV - code coverage report
Current view: top level - dom/media - MediaStreamGraph.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 173 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 91 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       4             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #ifndef MOZILLA_MEDIASTREAMGRAPH_H_
       7             : #define MOZILLA_MEDIASTREAMGRAPH_H_
       8             : 
       9             : #include "AudioStream.h"
      10             : #include "MainThreadUtils.h"
      11             : #include "MediaStreamTypes.h"
      12             : #include "StreamTracks.h"
      13             : #include "VideoSegment.h"
      14             : #include "mozilla/LinkedList.h"
      15             : #include "mozilla/Mutex.h"
      16             : #include "mozilla/TaskQueue.h"
      17             : #include "mozilla/dom/AudioChannelBinding.h"
      18             : #include "nsAutoPtr.h"
      19             : #include "nsAutoRef.h"
      20             : #include "nsIRunnable.h"
      21             : #include "nsTArray.h"
      22             : #include <speex/speex_resampler.h>
      23             : 
      24             : class nsIRunnable;
      25             : class nsIGlobalObject;
      26             : class nsPIDOMWindowInner;
      27             : 
      28             : template <>
      29           0 : class nsAutoRefTraits<SpeexResamplerState> : public nsPointerRefTraits<SpeexResamplerState>
      30             : {
      31             :   public:
      32           0 :   static void Release(SpeexResamplerState* aState) { speex_resampler_destroy(aState); }
      33             : };
      34             : 
      35             : namespace mozilla {
      36             : 
      37             : extern LazyLogModule gMediaStreamGraphLog;
      38             : 
      39             : namespace dom {
      40             :   enum class AudioContextOperation;
      41             : }
      42             : 
      43             : namespace media {
      44             :   template<typename V, typename E> class Pledge;
      45             : }
      46             : 
      47             : /*
      48             :  * MediaStreamGraph is a framework for synchronized audio/video processing
      49             :  * and playback. It is designed to be used by other browser components such as
      50             :  * HTML media elements, media capture APIs, real-time media streaming APIs,
      51             :  * multitrack media APIs, and advanced audio APIs.
      52             :  *
      53             :  * The MediaStreamGraph uses a dedicated thread to process media --- the media
      54             :  * graph thread. This ensures that we can process media through the graph
      55             :  * without blocking on main-thread activity. The media graph is only modified
      56             :  * on the media graph thread, to ensure graph changes can be processed without
      57             :  * interfering with media processing. All interaction with the media graph
      58             :  * thread is done with message passing.
      59             :  *
      60             :  * APIs that modify the graph or its properties are described as "control APIs".
      61             :  * These APIs are asynchronous; they queue graph changes internally and
      62             :  * those changes are processed all-at-once by the MediaStreamGraph. The
      63             :  * MediaStreamGraph monitors the main thread event loop via nsIAppShell::RunInStableState
      64             :  * to ensure that graph changes from a single event loop task are always
      65             :  * processed all together. Control APIs should only be used on the main thread,
      66             :  * currently; we may be able to relax that later.
      67             :  *
      68             :  * To allow precise synchronization of times in the control API, the
      69             :  * MediaStreamGraph maintains a "media timeline". Control APIs that take or
      70             :  * return times use that timeline. Those times never advance during
      71             :  * an event loop task. This time is returned by MediaStreamGraph::GetCurrentTime().
      72             :  *
      73             :  * Media decoding, audio processing and media playback use thread-safe APIs to
      74             :  * the media graph to ensure they can continue while the main thread is blocked.
      75             :  *
      76             :  * When the graph is changed, we may need to throw out buffered data and
      77             :  * reprocess it. This is triggered automatically by the MediaStreamGraph.
      78             :  */
      79             : 
      80             : class AudioNodeEngine;
      81             : class AudioNodeExternalInputStream;
      82             : class AudioNodeStream;
      83             : class MediaInputPort;
      84             : class MediaStream;
      85             : class MediaStreamGraph;
      86             : class MediaStreamGraphImpl;
      87             : class ProcessedMediaStream;
      88             : class SourceMediaStream;
      89             : 
      90           0 : class AudioDataListenerInterface {
      91             : protected:
      92             :   // Protected destructor, to discourage deletion outside of Release():
      93           0 :   virtual ~AudioDataListenerInterface() {}
      94             : 
      95             : public:
      96             :   /* These are for cubeb audio input & output streams: */
      97             :   /**
      98             :    * Output data to speakers, for use as the "far-end" data for echo
      99             :    * cancellation.  This is not guaranteed to be in any particular size
     100             :    * chunks.
     101             :    */
     102             :   virtual void NotifyOutputData(MediaStreamGraph* aGraph,
     103             :                                 AudioDataValue* aBuffer, size_t aFrames,
     104             :                                 TrackRate aRate, uint32_t aChannels) = 0;
     105             :   /**
     106             :    * Input data from a microphone (or other audio source.  This is not
     107             :    * guaranteed to be in any particular size chunks.
     108             :    */
     109             :   virtual void NotifyInputData(MediaStreamGraph* aGraph,
     110             :                                const AudioDataValue* aBuffer, size_t aFrames,
     111             :                                TrackRate aRate, uint32_t aChannels) = 0;
     112             : 
     113             :   /**
     114             :    * Called when the underlying audio device has changed.
     115             :    */
     116             :   virtual void DeviceChanged() = 0;
     117             : };
     118             : 
     119           0 : class AudioDataListener : public AudioDataListenerInterface {
     120             : protected:
     121             :   // Protected destructor, to discourage deletion outside of Release():
     122           0 :   virtual ~AudioDataListener() {}
     123             : 
     124             : public:
     125           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioDataListener)
     126             : };
     127             : 
     128             : /**
     129             :  * This is a base class for main-thread listener callbacks.
     130             :  * This callback is invoked on the main thread when the main-thread-visible
     131             :  * state of a stream has changed.
     132             :  *
     133             :  * These methods are called with the media graph monitor held, so
     134             :  * reentry into general media graph methods is not possible.
     135             :  * You should do something non-blocking and non-reentrant (e.g. dispatch an
     136             :  * event) and return. DispatchFromMainThreadAfterNextStreamStateUpdate
     137             :  * would be a good choice.
     138             :  * The listener is allowed to synchronously remove itself from the stream, but
     139             :  * not add or remove any other listeners.
     140             :  */
     141           0 : class MainThreadMediaStreamListener {
     142             : public:
     143             :   virtual void NotifyMainThreadStreamFinished() = 0;
     144             : };
     145             : 
     146             : /**
     147             :  * Helper struct used to keep track of memory usage by AudioNodes.
     148             :  */
     149             : struct AudioNodeSizes
     150             : {
     151           0 :   AudioNodeSizes() : mStream(0), mEngine(0), mNodeType() {}
     152             :   size_t mStream;
     153             :   size_t mEngine;
     154             :   const char* mNodeType;
     155             : };
     156             : 
     157             : class AudioNodeEngine;
     158             : class AudioNodeExternalInputStream;
     159             : class AudioNodeStream;
     160             : class AudioSegment;
     161             : class DirectMediaStreamListener;
     162             : class DirectMediaStreamTrackListener;
     163             : class MediaInputPort;
     164             : class MediaStreamGraphImpl;
     165             : class MediaStreamListener;
     166             : class MediaStreamTrackListener;
     167             : class MediaStreamVideoSink;
     168             : class ProcessedMediaStream;
     169             : class SourceMediaStream;
     170             : class TrackUnionStream;
     171             : 
     172             : /**
     173             :  * Helper struct for binding a track listener to a specific TrackID.
     174             :  */
     175             : template<typename Listener>
     176           0 : struct TrackBound
     177             : {
     178             :   RefPtr<Listener> mListener;
     179             :   TrackID mTrackID;
     180             : };
     181             : 
     182             : /**
     183             :  * A stream of synchronized audio and video data. All (not blocked) streams
     184             :  * progress at the same rate --- "real time". Streams cannot seek. The only
     185             :  * operation readers can perform on a stream is to read the next data.
     186             :  *
     187             :  * Consumers of a stream can be reading from it at different offsets, but that
     188             :  * should only happen due to the order in which consumers are being run.
     189             :  * Those offsets must not diverge in the long term, otherwise we would require
     190             :  * unbounded buffering.
     191             :  *
     192             :  * Streams can be in a "blocked" state. While blocked, a stream does not
     193             :  * produce data. A stream can be explicitly blocked via the control API,
     194             :  * or implicitly blocked by whatever's generating it (e.g. an underrun in the
     195             :  * source resource), or implicitly blocked because something consuming it
     196             :  * blocks, or implicitly because it has finished.
     197             :  *
     198             :  * A stream can be in a "finished" state. "Finished" streams are permanently
     199             :  * blocked.
     200             :  *
     201             :  * Transitions into and out of the "blocked" and "finished" states are managed
     202             :  * by the MediaStreamGraph on the media graph thread.
     203             :  *
     204             :  * We buffer media data ahead of the consumers' reading offsets. It is possible
     205             :  * to have buffered data but still be blocked.
     206             :  *
     207             :  * Any stream can have its audio and video playing when requested. The media
     208             :  * stream graph plays audio by constructing audio output streams as necessary.
     209             :  * Video is played by setting video frames into an MediaStreamVideoSink at the right
     210             :  * time. To ensure video plays in sync with audio, make sure that the same
     211             :  * stream is playing both the audio and video.
     212             :  *
     213             :  * The data in a stream is managed by StreamTracks. It consists of a set of
     214             :  * tracks of various types that can start and end over time.
     215             :  *
     216             :  * Streams are explicitly managed. The client creates them via
     217             :  * MediaStreamGraph::CreateInput/ProcessedMediaStream, and releases them by calling
     218             :  * Destroy() when no longer needed (actual destruction will be deferred).
     219             :  * The actual object is owned by the MediaStreamGraph. The basic idea is that
     220             :  * main thread objects will keep Streams alive as long as necessary (using the
     221             :  * cycle collector to clean up whenever needed).
     222             :  *
     223             :  * We make them refcounted only so that stream-related messages with MediaStream*
     224             :  * pointers can be sent to the main thread safely.
     225             :  *
     226             :  * The lifetimes of MediaStreams are controlled from the main thread.
     227             :  * For MediaStreams exposed to the DOM, the lifetime is controlled by the DOM
     228             :  * wrapper; the DOM wrappers own their associated MediaStreams. When a DOM
     229             :  * wrapper is destroyed, it sends a Destroy message for the associated
     230             :  * MediaStream and clears its reference (the last main-thread reference to
     231             :  * the object). When the Destroy message is processed on the graph manager
     232             :  * thread we immediately release the affected objects (disentangling them
     233             :  * from other objects as necessary).
     234             :  *
     235             :  * This could cause problems for media processing if a MediaStream is
     236             :  * destroyed while a downstream MediaStream is still using it. Therefore
     237             :  * the DOM wrappers must keep upstream MediaStreams alive as long as they
     238             :  * could be being used in the media graph.
     239             :  *
     240             :  * At any time, however, a set of MediaStream wrappers could be
     241             :  * collected via cycle collection. Destroy messages will be sent
     242             :  * for those objects in arbitrary order and the MediaStreamGraph has to be able
     243             :  * to handle this.
     244             :  */
     245             : 
     246             : // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
     247             : // GetTickCount() and conflicts with MediaStream::GetCurrentTime.
     248             : #ifdef GetCurrentTime
     249             : #undef GetCurrentTime
     250             : #endif
     251             : 
     252             : class MediaStream : public mozilla::LinkedListElement<MediaStream>
     253             : {
     254             : public:
     255           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStream)
     256             : 
     257             :   explicit MediaStream();
     258             : 
     259             : protected:
     260             :   // Protected destructor, to discourage deletion outside of Release():
     261             :   virtual ~MediaStream();
     262             : 
     263             : public:
     264             :   /**
     265             :    * Returns the graph that owns this stream.
     266             :    */
     267             :   MediaStreamGraphImpl* GraphImpl();
     268             :   MediaStreamGraph* Graph();
     269             :   /**
     270             :    * Sets the graph that owns this stream.  Should only be called once.
     271             :    */
     272             :   void SetGraphImpl(MediaStreamGraphImpl* aGraph);
     273             :   void SetGraphImpl(MediaStreamGraph* aGraph);
     274             : 
     275             :   /**
     276             :    * Returns sample rate of the graph.
     277             :    */
     278           0 :   TrackRate GraphRate() { return mTracks.GraphRate(); }
     279             : 
     280             :   // Control API.
     281             :   // Since a stream can be played multiple ways, we need to combine independent
     282             :   // volume settings. The aKey parameter is used to keep volume settings
     283             :   // separate. Since the stream is always playing the same contents, only
     284             :   // a single audio output stream is used; the volumes are combined.
     285             :   // Currently only the first enabled audio track is played.
     286             :   // XXX change this so all enabled audio tracks are mixed and played.
     287             :   virtual void AddAudioOutput(void* aKey);
     288             :   virtual void SetAudioOutputVolume(void* aKey, float aVolume);
     289             :   virtual void RemoveAudioOutput(void* aKey);
     290             :   // Since a stream can be played multiple ways, we need to be able to
     291             :   // play to multiple MediaStreamVideoSinks.
     292             :   // Only the first enabled video track is played.
     293             :   virtual void AddVideoOutput(MediaStreamVideoSink* aSink,
     294             :                               TrackID aID = TRACK_ANY);
     295             :   virtual void RemoveVideoOutput(MediaStreamVideoSink* aSink,
     296             :                                  TrackID aID = TRACK_ANY);
     297             :   // Explicitly suspend. Useful for example if a media element is pausing
     298             :   // and we need to stop its stream emitting its buffered data. As soon as the
     299             :   // Suspend message reaches the graph, the stream stops processing. It
     300             :   // ignores its inputs and produces silence/no video until Resumed. Its
     301             :   // current time does not advance.
     302             :   virtual void Suspend();
     303             :   virtual void Resume();
     304             :   // Events will be dispatched by calling methods of aListener.
     305             :   virtual void AddListener(MediaStreamListener* aListener);
     306             :   virtual void RemoveListener(MediaStreamListener* aListener);
     307             :   virtual void AddTrackListener(MediaStreamTrackListener* aListener,
     308             :                                 TrackID aTrackID);
     309             :   virtual void RemoveTrackListener(MediaStreamTrackListener* aListener,
     310             :                                    TrackID aTrackID);
     311             : 
     312             :   /**
     313             :    * Adds aListener to the source stream of track aTrackID in this stream.
     314             :    * When the MediaStreamGraph processes the added listener, it will traverse
     315             :    * the graph and add it to the track's source stream (remapping the TrackID
     316             :    * along the way).
     317             :    * Note that the listener will be notified on the MediaStreamGraph thread
     318             :    * with whether the installation of it at the source was successful or not.
     319             :    */
     320             :   virtual void AddDirectTrackListener(DirectMediaStreamTrackListener* aListener,
     321             :                                       TrackID aTrackID);
     322             : 
     323             :   /**
     324             :    * Removes aListener from the source stream of track aTrackID in this stream.
     325             :    * Note that the listener has already been removed if the link between the
     326             :    * source of track aTrackID and this stream has been broken (and made track
     327             :    * aTrackID end). The caller doesn't have to care about this, removing when
     328             :    * the source cannot be found, or when the listener had already been removed
     329             :    * does nothing.
     330             :    */
     331             :   virtual void RemoveDirectTrackListener(DirectMediaStreamTrackListener* aListener,
     332             :                                          TrackID aTrackID);
     333             : 
     334             :   // A disabled track has video replaced by black, and audio replaced by
     335             :   // silence.
     336             :   void SetTrackEnabled(TrackID aTrackID, DisabledTrackMode aMode);
     337             : 
     338             :   // Finish event will be notified by calling methods of aListener. It is the
     339             :   // responsibility of the caller to remove aListener before it is destroyed.
     340             :   void AddMainThreadListener(MainThreadMediaStreamListener* aListener);
     341             :   // It's safe to call this even if aListener is not currently a listener;
     342             :   // the call will be ignored.
     343           0 :   void RemoveMainThreadListener(MainThreadMediaStreamListener* aListener)
     344             :   {
     345           0 :     MOZ_ASSERT(NS_IsMainThread());
     346           0 :     MOZ_ASSERT(aListener);
     347           0 :     mMainThreadListeners.RemoveElement(aListener);
     348           0 :   }
     349             : 
     350             :   /**
     351             :    * Ensure a runnable will run on the main thread after running all pending
     352             :    * updates that were sent from the graph thread or will be sent before the
     353             :    * graph thread receives the next graph update.
     354             :    *
     355             :    * If the graph has been shut down or destroyed, then the runnable will be
     356             :    * dispatched to the event queue immediately.  If the graph is non-realtime
     357             :    * and has not started, then the runnable will be run
     358             :    * synchronously/immediately.  (There are no pending updates in these
     359             :    * situations.)
     360             :    *
     361             :    * Main thread only.
     362             :    */
     363             :   void RunAfterPendingUpdates(already_AddRefed<nsIRunnable> aRunnable);
     364             : 
     365             :   // Signal that the client is done with this MediaStream. It will be deleted
     366             :   // later. Do not mix usage of Destroy() with RegisterUser()/UnregisterUser().
     367             :   // That will cause the MediaStream to be destroyed twice, which will cause
     368             :   // some assertions to fail.
     369             :   virtual void Destroy();
     370             :   // Signal that a client is using this MediaStream. Useful to not have to
     371             :   // explicitly manage ownership (responsibility to Destroy()) when there are
     372             :   // multiple clients using a MediaStream.
     373             :   void RegisterUser();
     374             :   // Signal that a client no longer needs this MediaStream. When the number of
     375             :   // clients using this MediaStream reaches 0, it will be destroyed.
     376             :   void UnregisterUser();
     377             : 
     378             :   // Returns the main-thread's view of how much data has been processed by
     379             :   // this stream.
     380           0 :   StreamTime GetCurrentTime()
     381             :   {
     382           0 :     NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
     383           0 :     return mMainThreadCurrentTime;
     384             :   }
     385             :   // Return the main thread's view of whether this stream has finished.
     386           0 :   bool IsFinished()
     387             :   {
     388           0 :     NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
     389           0 :     return mMainThreadFinished;
     390             :   }
     391             : 
     392           0 :   bool IsDestroyed()
     393             :   {
     394           0 :     NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
     395           0 :     return mMainThreadDestroyed;
     396             :   }
     397             : 
     398             :   friend class MediaStreamGraphImpl;
     399             :   friend class MediaInputPort;
     400             :   friend class AudioNodeExternalInputStream;
     401             : 
     402           0 :   virtual SourceMediaStream* AsSourceStream() { return nullptr; }
     403           0 :   virtual ProcessedMediaStream* AsProcessedStream() { return nullptr; }
     404           0 :   virtual AudioNodeStream* AsAudioNodeStream() { return nullptr; }
     405           0 :   virtual TrackUnionStream* AsTrackUnionStream() { return nullptr; }
     406             : 
     407             :   // These Impl methods perform the core functionality of the control methods
     408             :   // above, on the media graph thread.
     409             :   /**
     410             :    * Stop all stream activity and disconnect it from all inputs and outputs.
     411             :    * This must be idempotent.
     412             :    */
     413             :   virtual void DestroyImpl();
     414           0 :   StreamTime GetTracksEnd() { return mTracks.GetEnd(); }
     415             : #ifdef DEBUG
     416           0 :   void DumpTrackInfo() { return mTracks.DumpTrackInfo(); }
     417             : #endif
     418             :   void SetAudioOutputVolumeImpl(void* aKey, float aVolume);
     419             :   void AddAudioOutputImpl(void* aKey);
     420             :   // Returns true if this stream has an audio output.
     421             :   bool HasAudioOutput()
     422             :   {
     423             :     return !mAudioOutputs.IsEmpty();
     424             :   }
     425             :   void RemoveAudioOutputImpl(void* aKey);
     426             :   void AddVideoOutputImpl(already_AddRefed<MediaStreamVideoSink> aSink,
     427             :                           TrackID aID);
     428             :   void RemoveVideoOutputImpl(MediaStreamVideoSink* aSink, TrackID aID);
     429             :   void AddListenerImpl(already_AddRefed<MediaStreamListener> aListener);
     430             :   void RemoveListenerImpl(MediaStreamListener* aListener);
     431             :   void RemoveAllListenersImpl();
     432             :   virtual void AddTrackListenerImpl(already_AddRefed<MediaStreamTrackListener> aListener,
     433             :                                     TrackID aTrackID);
     434             :   virtual void RemoveTrackListenerImpl(MediaStreamTrackListener* aListener,
     435             :                                        TrackID aTrackID);
     436             :   virtual void AddDirectTrackListenerImpl(already_AddRefed<DirectMediaStreamTrackListener> aListener,
     437             :                                           TrackID aTrackID);
     438             :   virtual void RemoveDirectTrackListenerImpl(DirectMediaStreamTrackListener* aListener,
     439             :                                              TrackID aTrackID);
     440             :   virtual void SetTrackEnabledImpl(TrackID aTrackID, DisabledTrackMode aMode);
     441             :   DisabledTrackMode GetDisabledTrackMode(TrackID aTrackID);
     442             : 
     443           0 :   void AddConsumer(MediaInputPort* aPort)
     444             :   {
     445           0 :     mConsumers.AppendElement(aPort);
     446           0 :   }
     447           0 :   void RemoveConsumer(MediaInputPort* aPort)
     448             :   {
     449           0 :     mConsumers.RemoveElement(aPort);
     450           0 :   }
     451             :   uint32_t ConsumerCount()
     452             :   {
     453             :     return mConsumers.Length();
     454             :   }
     455           0 :   StreamTracks& GetStreamTracks() { return mTracks; }
     456             :   GraphTime GetStreamTracksStartTime() { return mTracksStartTime; }
     457             : 
     458           0 :   double StreamTimeToSeconds(StreamTime aTime)
     459             :   {
     460           0 :     NS_ASSERTION(0 <= aTime && aTime <= STREAM_TIME_MAX, "Bad time");
     461           0 :     return static_cast<double>(aTime)/mTracks.GraphRate();
     462             :   }
     463           0 :   int64_t StreamTimeToMicroseconds(StreamTime aTime)
     464             :   {
     465           0 :     NS_ASSERTION(0 <= aTime && aTime <= STREAM_TIME_MAX, "Bad time");
     466           0 :     return (aTime*1000000)/mTracks.GraphRate();
     467             :   }
     468           0 :   StreamTime SecondsToNearestStreamTime(double aSeconds)
     469             :   {
     470           0 :     NS_ASSERTION(0 <= aSeconds && aSeconds <= TRACK_TICKS_MAX/TRACK_RATE_MAX,
     471             :                  "Bad seconds");
     472           0 :     return mTracks.GraphRate() * aSeconds + 0.5;
     473             :   }
     474           0 :   StreamTime MicrosecondsToStreamTimeRoundDown(int64_t aMicroseconds) {
     475           0 :     return (aMicroseconds*mTracks.GraphRate())/1000000;
     476             :   }
     477             : 
     478           0 :   TrackTicks TimeToTicksRoundUp(TrackRate aRate, StreamTime aTime)
     479             :   {
     480           0 :     return RateConvertTicksRoundUp(aRate, mTracks.GraphRate(), aTime);
     481             :   }
     482           0 :   StreamTime TicksToTimeRoundDown(TrackRate aRate, TrackTicks aTicks)
     483             :   {
     484           0 :     return RateConvertTicksRoundDown(mTracks.GraphRate(), aRate, aTicks);
     485             :   }
     486             :   /**
     487             :    * Convert graph time to stream time. aTime must be <= mStateComputedTime
     488             :    * to ensure we know exactly how much time this stream will be blocked during
     489             :    * the interval.
     490             :    */
     491             :   StreamTime GraphTimeToStreamTimeWithBlocking(GraphTime aTime);
     492             :   /**
     493             :    * Convert graph time to stream time. This assumes there is no blocking time
     494             :    * to take account of, which is always true except between a stream
     495             :    * having its blocking time calculated in UpdateGraph and its blocking time
     496             :    * taken account of in UpdateCurrentTimeForStreams.
     497             :    */
     498             :   StreamTime GraphTimeToStreamTime(GraphTime aTime);
     499             :   /**
     500             :    * Convert stream time to graph time. This assumes there is no blocking time
     501             :    * to take account of, which is always true except between a stream
     502             :    * having its blocking time calculated in UpdateGraph and its blocking time
     503             :    * taken account of in UpdateCurrentTimeForStreams.
     504             :    */
     505             :   GraphTime StreamTimeToGraphTime(StreamTime aTime);
     506             : 
     507           0 :   bool IsFinishedOnGraphThread() { return mFinished; }
     508             :   void FinishOnGraphThread();
     509             : 
     510           0 :   bool HasCurrentData() { return mHasCurrentData; }
     511             : 
     512             :   /**
     513             :    * Find track by track id.
     514             :    */
     515             :   StreamTracks::Track* FindTrack(TrackID aID);
     516             : 
     517             :   StreamTracks::Track* EnsureTrack(TrackID aTrack);
     518             : 
     519             :   virtual void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, MediaSegment* aRawSegment = nullptr);
     520             : 
     521             :   // Return true if the main thread needs to observe updates from this stream.
     522           0 :   virtual bool MainThreadNeedsUpdates() const
     523             :   {
     524           0 :     return true;
     525             :   }
     526             : 
     527             :   virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
     528             :   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
     529             : 
     530           0 :   void SetAudioChannelType(dom::AudioChannel aType) { mAudioChannelType = aType; }
     531             :   dom::AudioChannel AudioChannelType() const { return mAudioChannelType; }
     532             : 
     533           0 :   bool IsSuspended() { return mSuspendedCount > 0; }
     534             :   void IncrementSuspendCount();
     535             :   void DecrementSuspendCount();
     536             : 
     537             : protected:
     538             :   // |AdvanceTimeVaryingValuesToCurrentTime| will be override in SourceMediaStream.
     539           0 :   virtual void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime,
     540             :                                                      GraphTime aBlockedTime)
     541             :   {
     542           0 :     mTracksStartTime += aBlockedTime;
     543           0 :     mTracks.ForgetUpTo(aCurrentTime - mTracksStartTime);
     544           0 :   }
     545             : 
     546           0 :   void NotifyMainThreadListeners()
     547             :   {
     548           0 :     NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
     549             : 
     550           0 :     for (int32_t i = mMainThreadListeners.Length() - 1; i >= 0; --i) {
     551           0 :       mMainThreadListeners[i]->NotifyMainThreadStreamFinished();
     552             :     }
     553           0 :     mMainThreadListeners.Clear();
     554           0 :   }
     555             : 
     556           0 :   bool ShouldNotifyStreamFinished()
     557             :   {
     558           0 :     NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
     559           0 :     if (!mMainThreadFinished || mFinishedNotificationSent) {
     560           0 :       return false;
     561             :     }
     562             : 
     563           0 :     mFinishedNotificationSent = true;
     564           0 :     return true;
     565             :   }
     566             : 
     567             :   // This state is all initialized on the main thread but
     568             :   // otherwise modified only on the media graph thread.
     569             : 
     570             :   // Buffered data. The start of the buffer corresponds to mTracksStartTime.
     571             :   // Conceptually the buffer contains everything this stream has ever played,
     572             :   // but we forget some prefix of the buffered data to bound the space usage.
     573             :   StreamTracks mTracks;
     574             :   // The time when the buffered data could be considered to have started playing.
     575             :   // This increases over time to account for time the stream was blocked before
     576             :   // mCurrentTime.
     577             :   GraphTime mTracksStartTime;
     578             : 
     579             :   // Client-set volume of this stream
     580             :   struct AudioOutput {
     581           0 :     explicit AudioOutput(void* aKey) : mKey(aKey), mVolume(1.0f) {}
     582             :     void* mKey;
     583             :     float mVolume;
     584             :   };
     585             :   nsTArray<AudioOutput> mAudioOutputs;
     586             :   nsTArray<TrackBound<MediaStreamVideoSink>> mVideoOutputs;
     587             :   // We record the last played video frame to avoid playing the frame again
     588             :   // with a different frame id.
     589             :   VideoFrame mLastPlayedVideoFrame;
     590             :   nsTArray<RefPtr<MediaStreamListener> > mListeners;
     591             :   nsTArray<TrackBound<MediaStreamTrackListener>> mTrackListeners;
     592             :   nsTArray<MainThreadMediaStreamListener*> mMainThreadListeners;
     593             :   // List of disabled TrackIDs and their associated disabled mode.
     594             :   // They can either by disabled by frames being replaced by black, or by
     595             :   // retaining the previous frame.
     596             :   nsTArray<DisabledTrack> mDisabledTracks;
     597             : 
     598             :   // GraphTime at which this stream starts blocking.
     599             :   // This is only valid up to mStateComputedTime. The stream is considered to
     600             :   // have not been blocked before mCurrentTime (its mTracksStartTime is increased
     601             :   // as necessary to account for that time instead).
     602             :   GraphTime mStartBlocking;
     603             : 
     604             :   // MediaInputPorts to which this is connected
     605             :   nsTArray<MediaInputPort*> mConsumers;
     606             : 
     607             :   // Where audio output is going. There is one AudioOutputStream per
     608             :   // audio track.
     609             :   struct AudioOutputStream
     610             :   {
     611             :     // When we started audio playback for this track.
     612             :     // Add mStream->GetPosition() to find the current audio playback position.
     613             :     GraphTime mAudioPlaybackStartTime;
     614             :     // Amount of time that we've wanted to play silence because of the stream
     615             :     // blocking.
     616             :     MediaTime mBlockedAudioTime;
     617             :     // Last tick written to the audio output.
     618             :     StreamTime mLastTickWritten;
     619             :     TrackID mTrackID;
     620             :   };
     621             :   nsTArray<AudioOutputStream> mAudioOutputStreams;
     622             : 
     623             :   /**
     624             :    * Number of outstanding suspend operations on this stream. Stream is
     625             :    * suspended when this is > 0.
     626             :    */
     627             :   int32_t mSuspendedCount;
     628             : 
     629             :   /**
     630             :    * When true, this means the stream will be finished once all
     631             :    * buffered data has been consumed.
     632             :    */
     633             :   bool mFinished;
     634             :   /**
     635             :    * When true, mFinished is true and we've played all the data in this stream
     636             :    * and fired NotifyFinished notifications.
     637             :    */
     638             :   bool mNotifiedFinished;
     639             :   /**
     640             :    * When true, the last NotifyBlockingChanged delivered to the listeners
     641             :    * indicated that the stream is blocked.
     642             :    */
     643             :   bool mNotifiedBlocked;
     644             :   /**
     645             :    * True if some data can be present by this stream if/when it's unblocked.
     646             :    * Set by the stream itself on the MediaStreamGraph thread. Only changes
     647             :    * from false to true once a stream has data, since we won't
     648             :    * unblock it until there's more data.
     649             :    */
     650             :   bool mHasCurrentData;
     651             :   /**
     652             :    * True if mHasCurrentData is true and we've notified listeners.
     653             :    */
     654             :   bool mNotifiedHasCurrentData;
     655             : 
     656             :   // Main-thread views of state
     657             :   StreamTime mMainThreadCurrentTime;
     658             :   bool mMainThreadFinished;
     659             :   bool mFinishedNotificationSent;
     660             :   bool mMainThreadDestroyed;
     661             :   int mNrOfMainThreadUsers;
     662             : 
     663             :   // Our media stream graph.  null if destroyed on the graph thread.
     664             :   MediaStreamGraphImpl* mGraph;
     665             : 
     666             :   dom::AudioChannel mAudioChannelType;
     667             : };
     668             : 
     669             : /**
     670             :  * This is a stream into which a decoder can write audio and video.
     671             :  *
     672             :  * Audio and video can be written on any thread, but you probably want to
     673             :  * always write from the same thread to avoid unexpected interleavings.
     674             :  */
     675             : class SourceMediaStream : public MediaStream
     676             : {
     677             : public:
     678             :   explicit SourceMediaStream();
     679             : 
     680           0 :   SourceMediaStream* AsSourceStream() override { return this; }
     681             : 
     682             :   // Media graph thread only
     683             : 
     684             :   // Users of audio inputs go through the stream so it can track when the
     685             :   // last stream referencing an input goes away, so it can close the cubeb
     686             :   // input.  Also note: callable on any thread (though it bounces through
     687             :   // MainThread to set the command if needed).
     688             :   nsresult OpenAudioInput(int aID,
     689             :                           AudioDataListener *aListener);
     690             :   // Note: also implied when Destroy() happens
     691             :   void CloseAudioInput();
     692             : 
     693             :   void DestroyImpl() override;
     694             : 
     695             :   // Call these on any thread.
     696             :   /**
     697             :    * Enable or disable pulling. When pulling is enabled, NotifyPull
     698             :    * gets called on MediaStreamListeners for this stream during the
     699             :    * MediaStreamGraph control loop. Pulling is initially disabled.
     700             :    * Due to unavoidable race conditions, after a call to SetPullEnabled(false)
     701             :    * it is still possible for a NotifyPull to occur.
     702             :    */
     703             :   void SetPullEnabled(bool aEnabled);
     704             : 
     705             :   /**
     706             :    * These add/remove DirectListeners, which allow bypassing the graph and any
     707             :    * synchronization delays for e.g. PeerConnection, which wants the data ASAP
     708             :    * and lets the far-end handle sync and playout timing.
     709             :    */
     710             :   void NotifyListenersEventImpl(MediaStreamGraphEvent aEvent);
     711             :   void NotifyListenersEvent(MediaStreamGraphEvent aEvent);
     712             :   void AddDirectListener(DirectMediaStreamListener* aListener);
     713             :   void RemoveDirectListener(DirectMediaStreamListener* aListener);
     714             : 
     715             :   enum {
     716             :     ADDTRACK_QUEUED    = 0x01 // Queue track add until FinishAddTracks()
     717             :   };
     718             :   /**
     719             :    * Add a new track to the stream starting at the given base time (which
     720             :    * must be greater than or equal to the last time passed to
     721             :    * AdvanceKnownTracksTime). Takes ownership of aSegment. aSegment should
     722             :    * contain data starting after aStart.
     723             :    */
     724           0 :   void AddTrack(TrackID aID, StreamTime aStart, MediaSegment* aSegment,
     725             :                 uint32_t aFlags = 0)
     726             :   {
     727           0 :     AddTrackInternal(aID, GraphRate(), aStart, aSegment, aFlags);
     728           0 :   }
     729             : 
     730             :   /**
     731             :    * Like AddTrack, but resamples audio from aRate to the graph rate.
     732             :    */
     733             :   void AddAudioTrack(TrackID aID, TrackRate aRate, StreamTime aStart,
     734             :                      AudioSegment* aSegment, uint32_t aFlags = 0);
     735             : 
     736             :   /**
     737             :    * Call after a series of AddTrack or AddAudioTrack calls to implement
     738             :    * any pending track adds.
     739             :    */
     740             :   void FinishAddTracks();
     741             : 
     742             :   /**
     743             :    * Append media data to a track. Ownership of aSegment remains with the caller,
     744             :    * but aSegment is emptied.
     745             :    * Returns false if the data was not appended because no such track exists
     746             :    * or the stream was already finished.
     747             :    */
     748             :   virtual bool AppendToTrack(TrackID aID, MediaSegment* aSegment, MediaSegment *aRawSegment = nullptr);
     749             :   /**
     750             :    * Get the stream time of the end of the data that has been appended so far.
     751             :    * Can be called from any thread but won't be useful if it can race with
     752             :    * an AppendToTrack call, so should probably just be called from the thread
     753             :    * that also calls AppendToTrack.
     754             :    */
     755             :   StreamTime GetEndOfAppendedData(TrackID aID);
     756             :   /**
     757             :    * Indicate that a track has ended. Do not do any more API calls
     758             :    * affecting this track.
     759             :    * Ignored if the track does not exist.
     760             :    */
     761             :   void EndTrack(TrackID aID);
     762             :   /**
     763             :    * Indicate that no tracks will be added starting before time aKnownTime.
     764             :    * aKnownTime must be >= its value at the last call to AdvanceKnownTracksTime.
     765             :    */
     766             :   void AdvanceKnownTracksTime(StreamTime aKnownTime);
     767             :   /**
     768             :    * Indicate that this stream should enter the "finished" state. All tracks
     769             :    * must have been ended via EndTrack. The finish time of the stream is
     770             :    * when all tracks have ended.
     771             :    */
     772             :   void FinishWithLockHeld();
     773           0 :   void Finish()
     774             :   {
     775           0 :     MutexAutoLock lock(mMutex);
     776           0 :     FinishWithLockHeld();
     777           0 :   }
     778             : 
     779             :   // Overriding allows us to hold the mMutex lock while changing the track enable status
     780             :   void SetTrackEnabledImpl(TrackID aTrackID, DisabledTrackMode aMode) override;
     781             : 
     782             :   // Overriding allows us to ensure mMutex is locked while changing the track enable status
     783             :   void
     784           0 :   ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment,
     785             :                       MediaSegment* aRawSegment = nullptr) override {
     786           0 :     mMutex.AssertCurrentThreadOwns();
     787           0 :     MediaStream::ApplyTrackDisabling(aTrackID, aSegment, aRawSegment);
     788           0 :   }
     789             : 
     790             :   /**
     791             :    * End all tracks and Finish() this stream.  Used to voluntarily revoke access
     792             :    * to a LocalMediaStream.
     793             :    */
     794             :   void EndAllTrackAndFinish();
     795             : 
     796             :   void RegisterForAudioMixing();
     797             : 
     798             :   /**
     799             :    * Returns true if this SourceMediaStream contains at least one audio track
     800             :    * that is in pending state.
     801             :    * This is thread safe, and takes the SourceMediaStream mutex.
     802             :    */
     803             :   bool HasPendingAudioTrack();
     804             : 
     805           0 :   TimeStamp GetStreamTracksStrartTimeStamp() {
     806           0 :     MutexAutoLock lock(mMutex);
     807           0 :     return mStreamTracksStartTimeStamp;
     808             :   }
     809             : 
     810             :   bool OpenNewAudioCallbackDriver(AudioDataListener *aListener);
     811             : 
     812             :   // XXX need a Reset API
     813             : 
     814             :   friend class MediaStreamGraphImpl;
     815             : 
     816             : protected:
     817             :   enum TrackCommands : uint32_t;
     818             : 
     819             :   virtual ~SourceMediaStream();
     820             : 
     821             :   /**
     822             :    * Data for each track that hasn't ended.
     823             :    */
     824           0 :   struct TrackData {
     825             :     TrackID mID;
     826             :     // Sample rate of the input data.
     827             :     TrackRate mInputRate;
     828             :     // Resampler if the rate of the input track does not match the
     829             :     // MediaStreamGraph's.
     830             :     nsAutoRef<SpeexResamplerState> mResampler;
     831             :     int mResamplerChannelCount;
     832             :     StreamTime mStart;
     833             :     // End-time of data already flushed to the track (excluding mData)
     834             :     StreamTime mEndOfFlushedData;
     835             :     // Each time the track updates are flushed to the media graph thread,
     836             :     // the segment buffer is emptied.
     837             :     nsAutoPtr<MediaSegment> mData;
     838             :     // Each time the track updates are flushed to the media graph thread,
     839             :     // this is cleared.
     840             :     uint32_t mCommands;
     841             :   };
     842             : 
     843             :   bool NeedsMixing();
     844             : 
     845             :   void ResampleAudioToGraphSampleRate(TrackData* aTrackData, MediaSegment* aSegment);
     846             : 
     847             :   void AddDirectTrackListenerImpl(already_AddRefed<DirectMediaStreamTrackListener> aListener,
     848             :                                   TrackID aTrackID) override;
     849             :   void RemoveDirectTrackListenerImpl(DirectMediaStreamTrackListener* aListener,
     850             :                                      TrackID aTrackID) override;
     851             : 
     852             :   void AddTrackInternal(TrackID aID, TrackRate aRate,
     853             :                         StreamTime aStart, MediaSegment* aSegment,
     854             :                         uint32_t aFlags);
     855             : 
     856           0 :   TrackData* FindDataForTrack(TrackID aID)
     857             :   {
     858           0 :     mMutex.AssertCurrentThreadOwns();
     859           0 :     for (uint32_t i = 0; i < mUpdateTracks.Length(); ++i) {
     860           0 :       if (mUpdateTracks[i].mID == aID) {
     861           0 :         return &mUpdateTracks[i];
     862             :       }
     863             :     }
     864           0 :     return nullptr;
     865             :   }
     866             : 
     867             :   /**
     868             :    * Notify direct consumers of new data to one of the stream tracks.
     869             :    * The data doesn't have to be resampled (though it may be).  This is called
     870             :    * from AppendToTrack on the thread providing the data, and will call
     871             :    * the Listeners on this thread.
     872             :    */
     873             :   void NotifyDirectConsumers(TrackData *aTrack,
     874             :                              MediaSegment *aSegment);
     875             : 
     876             :   virtual void
     877             :   AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime,
     878             :                                         GraphTime aBlockedTime) override;
     879           0 :   void SetStreamTracksStartTimeStamp(const TimeStamp& aTimeStamp)
     880             :   {
     881           0 :     MutexAutoLock lock(mMutex);
     882           0 :     mStreamTracksStartTimeStamp = aTimeStamp;
     883           0 :   }
     884             : 
     885             :   // Only accessed on the MSG thread.  Used so to ask the MSGImpl to usecount
     886             :   // users of a specific input.
     887             :   // XXX Should really be a CubebUtils::AudioDeviceID, but they aren't
     888             :   // copyable (opaque pointers)
     889             :   RefPtr<AudioDataListener> mInputListener;
     890             : 
     891             :   // This must be acquired *before* MediaStreamGraphImpl's lock, if they are
     892             :   // held together.
     893             :   Mutex mMutex;
     894             :   // protected by mMutex
     895             :   StreamTime mUpdateKnownTracksTime;
     896             :   // This time stamp will be updated in adding and blocked SourceMediaStream,
     897             :   // |AddStreamGraphThread| and |AdvanceTimeVaryingValuesToCurrentTime| in
     898             :   // particularly.
     899             :   TimeStamp mStreamTracksStartTimeStamp;
     900             :   nsTArray<TrackData> mUpdateTracks;
     901             :   nsTArray<TrackData> mPendingTracks;
     902             :   nsTArray<RefPtr<DirectMediaStreamListener>> mDirectListeners;
     903             :   nsTArray<TrackBound<DirectMediaStreamTrackListener>> mDirectTrackListeners;
     904             :   bool mPullEnabled;
     905             :   bool mUpdateFinished;
     906             :   bool mNeedsMixing;
     907             : };
     908             : 
     909             : /**
     910             :  * The blocking mode decides how a track should be blocked in a MediaInputPort.
     911             :  */
     912             : enum class BlockingMode
     913             : {
     914             :   /**
     915             :    * BlockingMode CREATION blocks the source track from being created
     916             :    * in the destination. It'll end if it already exists.
     917             :    */
     918             :   CREATION,
     919             :   /**
     920             :    * BlockingMode END_EXISTING allows a track to be created in the destination
     921             :    * but will end it before any data has been passed through.
     922             :    */
     923             :   END_EXISTING,
     924             : };
     925             : 
     926             : /**
     927             :  * Represents a connection between a ProcessedMediaStream and one of its
     928             :  * input streams.
     929             :  * We make these refcounted so that stream-related messages with MediaInputPort*
     930             :  * pointers can be sent to the main thread safely.
     931             :  *
     932             :  * A port can be locked to a specific track in the source stream, in which case
     933             :  * only this track will be forwarded to the destination stream. TRACK_ANY
     934             :  * can used to signal that all tracks shall be forwarded.
     935             :  *
     936             :  * When a port is locked to a specific track in the source stream, it may also
     937             :  * indicate a TrackID to map this source track to in the destination stream
     938             :  * by setting aDestTrack to an explicit ID. When we do this, we must know
     939             :  * that this TrackID in the destination stream is available. We assert during
     940             :  * processing that the ID is available and that there are no generic input
     941             :  * ports already attached to the destination stream.
     942             :  * Note that this is currently only handled by TrackUnionStreams.
     943             :  *
     944             :  * When a port's source or destination stream dies, the stream's DestroyImpl
     945             :  * calls MediaInputPort::Disconnect to disconnect the port from
     946             :  * the source and destination streams.
     947             :  *
     948             :  * The lifetimes of MediaInputPort are controlled from the main thread.
     949             :  * The media graph adds a reference to the port. When a MediaInputPort is no
     950             :  * longer needed, main-thread code sends a Destroy message for the port and
     951             :  * clears its reference (the last main-thread reference to the object). When
     952             :  * the Destroy message is processed on the graph manager thread we disconnect
     953             :  * the port and drop the graph's reference, destroying the object.
     954             :  */
     955             : class MediaInputPort final
     956             : {
     957             : private:
     958             :   // Do not call this constructor directly. Instead call aDest->AllocateInputPort.
     959           0 :   MediaInputPort(MediaStream* aSource,
     960             :                  TrackID& aSourceTrack,
     961             :                  ProcessedMediaStream* aDest,
     962             :                  TrackID& aDestTrack,
     963             :                  uint16_t aInputNumber,
     964             :                  uint16_t aOutputNumber)
     965           0 :     : mSource(aSource)
     966             :     , mSourceTrack(aSourceTrack)
     967             :     , mDest(aDest)
     968             :     , mDestTrack(aDestTrack)
     969             :     , mInputNumber(aInputNumber)
     970             :     , mOutputNumber(aOutputNumber)
     971           0 :     , mGraph(nullptr)
     972             :   {
     973           0 :     MOZ_COUNT_CTOR(MediaInputPort);
     974           0 :   }
     975             : 
     976             :   // Private destructor, to discourage deletion outside of Release():
     977           0 :   ~MediaInputPort()
     978           0 :   {
     979           0 :     MOZ_COUNT_DTOR(MediaInputPort);
     980           0 :   }
     981             : 
     982             : public:
     983           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaInputPort)
     984             : 
     985             :   // Called on graph manager thread
     986             :   // Do not call these from outside MediaStreamGraph.cpp!
     987             :   void Init();
     988             :   // Called during message processing to trigger removal of this stream.
     989             :   void Disconnect();
     990             : 
     991             :   // Control API
     992             :   /**
     993             :    * Disconnects and destroys the port. The caller must not reference this
     994             :    * object again.
     995             :    */
     996             :   void Destroy();
     997             : 
     998             :   // Any thread
     999           0 :   MediaStream* GetSource() { return mSource; }
    1000           0 :   TrackID GetSourceTrackId() { return mSourceTrack; }
    1001           0 :   ProcessedMediaStream* GetDestination() { return mDest; }
    1002           0 :   TrackID GetDestinationTrackId() { return mDestTrack; }
    1003             : 
    1004             :   /**
    1005             :    * Block aTrackId in the source stream from being passed through the port.
    1006             :    * Consumers will interpret this track as ended.
    1007             :    * Returns a pledge that resolves on the main thread after the track block has
    1008             :    * been applied by the MSG.
    1009             :    */
    1010             :   already_AddRefed<media::Pledge<bool, nsresult>> BlockSourceTrackId(TrackID aTrackId,
    1011             :                                                                      BlockingMode aBlockingMode);
    1012             : private:
    1013             :   void BlockSourceTrackIdImpl(TrackID aTrackId, BlockingMode aBlockingMode);
    1014             : 
    1015             : public:
    1016             :   // Returns true if aTrackId has not been blocked for any reason and this port
    1017             :   // has not been locked to another track.
    1018           0 :   bool PassTrackThrough(TrackID aTrackId) {
    1019           0 :     bool blocked = false;
    1020           0 :     for (auto pair : mBlockedTracks) {
    1021           0 :       if (pair.first() == aTrackId &&
    1022           0 :           (pair.second() == BlockingMode::CREATION ||
    1023           0 :            pair.second() == BlockingMode::END_EXISTING)) {
    1024           0 :         blocked = true;
    1025           0 :         break;
    1026             :       }
    1027             :     }
    1028           0 :     return !blocked && (mSourceTrack == TRACK_ANY || mSourceTrack == aTrackId);
    1029             :   }
    1030             : 
    1031             :   // Returns true if aTrackId has not been blocked for track creation and this
    1032             :   // port has not been locked to another track.
    1033           0 :   bool AllowCreationOf(TrackID aTrackId) {
    1034           0 :     bool blocked = false;
    1035           0 :     for (auto pair : mBlockedTracks) {
    1036           0 :       if (pair.first() == aTrackId &&
    1037           0 :           pair.second() == BlockingMode::CREATION) {
    1038           0 :         blocked = true;
    1039           0 :         break;
    1040             :       }
    1041             :     }
    1042           0 :     return !blocked && (mSourceTrack == TRACK_ANY || mSourceTrack == aTrackId);
    1043             :   }
    1044             : 
    1045           0 :   uint16_t InputNumber() const { return mInputNumber; }
    1046           0 :   uint16_t OutputNumber() const { return mOutputNumber; }
    1047             : 
    1048             :   // Call on graph manager thread
    1049             :   struct InputInterval {
    1050             :     GraphTime mStart;
    1051             :     GraphTime mEnd;
    1052             :     bool mInputIsBlocked;
    1053             :   };
    1054             :   // Find the next time interval starting at or after aTime during which
    1055             :   // mDest is not blocked and mSource's blocking status does not change.
    1056             :   InputInterval GetNextInputInterval(GraphTime aTime);
    1057             : 
    1058             :   /**
    1059             :    * Returns the graph that owns this port.
    1060             :    */
    1061             :   MediaStreamGraphImpl* GraphImpl();
    1062             :   MediaStreamGraph* Graph();
    1063             : 
    1064             :   /**
    1065             :    * Sets the graph that owns this stream.  Should only be called once.
    1066             :    */
    1067             :   void SetGraphImpl(MediaStreamGraphImpl* aGraph);
    1068             : 
    1069             :   /**
    1070             :    * Notify the port that the source MediaStream has been suspended.
    1071             :   */
    1072             :   void Suspended();
    1073             : 
    1074             :   /**
    1075             :    * Notify the port that the source MediaStream has been resumed.
    1076             :   */
    1077             :   void Resumed();
    1078             : 
    1079           0 :   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
    1080             :   {
    1081           0 :     size_t amount = 0;
    1082             : 
    1083             :     // Not owned:
    1084             :     // - mSource
    1085             :     // - mDest
    1086             :     // - mGraph
    1087           0 :     return amount;
    1088             :   }
    1089             : 
    1090           0 :   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
    1091             :   {
    1092           0 :     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    1093             :   }
    1094             : 
    1095             : private:
    1096             :   friend class MediaStreamGraphImpl;
    1097             :   friend class MediaStream;
    1098             :   friend class ProcessedMediaStream;
    1099             :   // Never modified after Init()
    1100             :   MediaStream* mSource;
    1101             :   TrackID mSourceTrack;
    1102             :   ProcessedMediaStream* mDest;
    1103             :   TrackID mDestTrack;
    1104             :   // The input and output numbers are optional, and are currently only used by
    1105             :   // Web Audio.
    1106             :   const uint16_t mInputNumber;
    1107             :   const uint16_t mOutputNumber;
    1108             : 
    1109             :   typedef Pair<TrackID, BlockingMode> BlockedTrack;
    1110             :   nsTArray<BlockedTrack> mBlockedTracks;
    1111             : 
    1112             :   // Our media stream graph
    1113             :   MediaStreamGraphImpl* mGraph;
    1114             : };
    1115             : 
    1116             : /**
    1117             :  * This stream processes zero or more input streams in parallel to produce
    1118             :  * its output. The details of how the output is produced are handled by
    1119             :  * subclasses overriding the ProcessInput method.
    1120             :  */
    1121           0 : class ProcessedMediaStream : public MediaStream
    1122             : {
    1123             : public:
    1124           0 :   explicit ProcessedMediaStream()
    1125           0 :     : MediaStream()
    1126             :     , mAutofinish(false)
    1127           0 :     , mCycleMarker(0)
    1128           0 :   {}
    1129             : 
    1130             :   // Control API.
    1131             :   /**
    1132             :    * Allocates a new input port attached to source aStream.
    1133             :    * This stream can be removed by calling MediaInputPort::Remove().
    1134             :    *
    1135             :    * The input port is tied to aTrackID in the source stream.
    1136             :    * aTrackID can be set to TRACK_ANY to automatically forward all tracks from
    1137             :    * aStream.
    1138             :    *
    1139             :    * If aTrackID is an explicit ID, aDestTrackID can also be made explicit
    1140             :    * to ensure that the track is assigned this ID in the destination stream.
    1141             :    * To avoid intermittent TrackID collisions the destination stream may not
    1142             :    * have any existing generic input ports (with TRACK_ANY source track) when
    1143             :    * you allocate an input port with a destination TrackID.
    1144             :    *
    1145             :    * To end a track in the destination stream forwarded with TRACK_ANY,
    1146             :    * it can be blocked in the input port through MediaInputPort::BlockTrackId().
    1147             :    *
    1148             :    * Tracks in aBlockedTracks will be blocked in the input port initially. This
    1149             :    * ensures that they don't get created by the MSG-thread before we can
    1150             :    * BlockTrackId() on the main thread.
    1151             :    */
    1152             :   already_AddRefed<MediaInputPort>
    1153             :   AllocateInputPort(MediaStream* aStream,
    1154             :                     TrackID aTrackID = TRACK_ANY,
    1155             :                     TrackID aDestTrackID = TRACK_ANY,
    1156             :                     uint16_t aInputNumber = 0,
    1157             :                     uint16_t aOutputNumber = 0,
    1158             :                     nsTArray<TrackID>* aBlockedTracks = nullptr);
    1159             :   /**
    1160             :    * Force this stream into the finished state.
    1161             :    */
    1162             :   void Finish();
    1163             :   /**
    1164             :    * Set the autofinish flag on this stream (defaults to false). When this flag
    1165             :    * is set, and all input streams are in the finished state (including if there
    1166             :    * are no input streams), this stream automatically enters the finished state.
    1167             :    */
    1168             :   void SetAutofinish(bool aAutofinish);
    1169             : 
    1170           0 :   ProcessedMediaStream* AsProcessedStream() override { return this; }
    1171             : 
    1172             :   friend class MediaStreamGraphImpl;
    1173             : 
    1174             :   // Do not call these from outside MediaStreamGraph.cpp!
    1175             :   virtual void AddInput(MediaInputPort* aPort);
    1176           0 :   virtual void RemoveInput(MediaInputPort* aPort)
    1177             :   {
    1178           0 :     mInputs.RemoveElement(aPort) || mSuspendedInputs.RemoveElement(aPort);
    1179           0 :   }
    1180             :   bool HasInputPort(MediaInputPort* aPort)
    1181             :   {
    1182             :     return mInputs.Contains(aPort) || mSuspendedInputs.Contains(aPort);
    1183             :   }
    1184             :   uint32_t InputPortCount()
    1185             :   {
    1186             :     return mInputs.Length() + mSuspendedInputs.Length();
    1187             :   }
    1188             :   void InputSuspended(MediaInputPort* aPort);
    1189             :   void InputResumed(MediaInputPort* aPort);
    1190           0 :   virtual MediaStream* GetInputStreamFor(TrackID aTrackID) { return nullptr; }
    1191           0 :   virtual TrackID GetInputTrackIDFor(TrackID aTrackID) { return TRACK_NONE; }
    1192             :   void DestroyImpl() override;
    1193             :   /**
    1194             :    * This gets called after we've computed the blocking states for all
    1195             :    * streams (mBlocked is up to date up to mStateComputedTime).
    1196             :    * Also, we've produced output for all streams up to this one. If this stream
    1197             :    * is not in a cycle, then all its source streams have produced data.
    1198             :    * Generate output from aFrom to aTo.
    1199             :    * This will be called on streams that have finished. Most stream types should
    1200             :    * just return immediately if IsFinishedOnGraphThread(), but some may wish to
    1201             :    * update internal state (see AudioNodeStream).
    1202             :    * ProcessInput is allowed to call FinishOnGraphThread only if ALLOW_FINISH
    1203             :    * is in aFlags. (This flag will be set when aTo >= mStateComputedTime, i.e.
    1204             :    * when we've producing the last block of data we need to produce.) Otherwise
    1205             :    * we can get into a situation where we've determined the stream should not
    1206             :    * block before mStateComputedTime, but the stream finishes before
    1207             :    * mStateComputedTime, violating the invariant that finished streams are blocked.
    1208             :    */
    1209             :   enum {
    1210             :     ALLOW_FINISH = 0x01
    1211             :   };
    1212             :   virtual void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) = 0;
    1213           0 :   void SetAutofinishImpl(bool aAutofinish) { mAutofinish = aAutofinish; }
    1214             : 
    1215             :   // Only valid after MediaStreamGraphImpl::UpdateStreamOrder() has run.
    1216             :   // A DelayNode is considered to break a cycle and so this will not return
    1217             :   // true for echo loops, only for muted cycles.
    1218           0 :   bool InMutedCycle() const { return mCycleMarker; }
    1219             : 
    1220           0 :   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
    1221             :   {
    1222           0 :     size_t amount = MediaStream::SizeOfExcludingThis(aMallocSizeOf);
    1223             :     // Not owned:
    1224             :     // - mInputs elements
    1225             :     // - mSuspendedInputs elements
    1226           0 :     amount += mInputs.ShallowSizeOfExcludingThis(aMallocSizeOf);
    1227           0 :     amount += mSuspendedInputs.ShallowSizeOfExcludingThis(aMallocSizeOf);
    1228           0 :     return amount;
    1229             :   }
    1230             : 
    1231           0 :   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
    1232             :   {
    1233           0 :     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    1234             :   }
    1235             : 
    1236             : protected:
    1237             :   // This state is all accessed only on the media graph thread.
    1238             : 
    1239             :   // The list of all inputs that are not currently suspended.
    1240             :   nsTArray<MediaInputPort*> mInputs;
    1241             :   // The list of all inputs that are currently suspended.
    1242             :   nsTArray<MediaInputPort*> mSuspendedInputs;
    1243             :   bool mAutofinish;
    1244             :   // After UpdateStreamOrder(), mCycleMarker is either 0 or 1 to indicate
    1245             :   // whether this stream is in a muted cycle.  During ordering it can contain
    1246             :   // other marker values - see MediaStreamGraphImpl::UpdateStreamOrder().
    1247             :   uint32_t mCycleMarker;
    1248             : };
    1249             : 
    1250             : /**
    1251             :  * There is a single MediaStreamGraph per window.
    1252             :  * Additionaly, each OfflineAudioContext object creates its own MediaStreamGraph
    1253             :  * object too..
    1254             :  */
    1255             : class MediaStreamGraph
    1256             : {
    1257             : public:
    1258             : 
    1259             :   // We ensure that the graph current time advances in multiples of
    1260             :   // IdealAudioBlockSize()/AudioStream::PreferredSampleRate(). A stream that
    1261             :   // never blocks and has a track with the ideal audio rate will produce audio
    1262             :   // in multiples of the block size.
    1263             : 
    1264             :   // Initializing an graph that outputs audio can be quite long on some
    1265             :   // platforms. Code that want to output audio at some point can express the
    1266             :   // fact that they will need an audio stream at some point by passing
    1267             :   // AUDIO_THREAD_DRIVER when getting an instance of MediaStreamGraph, so that
    1268             :   // the graph starts with the right driver.
    1269             :   enum GraphDriverType {
    1270             :     AUDIO_THREAD_DRIVER,
    1271             :     SYSTEM_THREAD_DRIVER,
    1272             :     OFFLINE_THREAD_DRIVER
    1273             :   };
    1274             :   static const uint32_t AUDIO_CALLBACK_DRIVER_SHUTDOWN_TIMEOUT = 20*1000;
    1275             : 
    1276             :   // Main thread only
    1277             :   static MediaStreamGraph* GetInstance(GraphDriverType aGraphDriverRequested,
    1278             :                                        dom::AudioChannel aChannel,
    1279             :                                        nsPIDOMWindowInner* aWindow);
    1280             :   static MediaStreamGraph* CreateNonRealtimeInstance(
    1281             :     TrackRate aSampleRate,
    1282             :     nsPIDOMWindowInner* aWindowId);
    1283             : 
    1284             :   // Return the correct main thread for this graph. This always returns
    1285             :   // something that is valid. Thread safe.
    1286             :   AbstractThread* AbstractMainThread();
    1287             : 
    1288             :   // Idempotent
    1289             :   static void DestroyNonRealtimeInstance(MediaStreamGraph* aGraph);
    1290             : 
    1291           0 :   virtual nsresult OpenAudioInput(int aID,
    1292             :                                   AudioDataListener *aListener) {
    1293           0 :     return NS_ERROR_FAILURE;
    1294             :   }
    1295           0 :   virtual void CloseAudioInput(AudioDataListener *aListener) {}
    1296             : 
    1297             :   // Control API.
    1298             :   /**
    1299             :    * Create a stream that a media decoder (or some other source of
    1300             :    * media data, such as a camera) can write to.
    1301             :    */
    1302             :   SourceMediaStream* CreateSourceStream();
    1303             :   /**
    1304             :    * Create a stream that will form the union of the tracks of its input
    1305             :    * streams.
    1306             :    * A TrackUnionStream contains all the tracks of all its input streams.
    1307             :    * Adding a new input stream makes that stream's tracks immediately appear as new
    1308             :    * tracks starting at the time the input stream was added.
    1309             :    * Removing an input stream makes the output tracks corresponding to the
    1310             :    * removed tracks immediately end.
    1311             :    * For each added track, the track ID of the output track is the track ID
    1312             :    * of the input track or one plus the maximum ID of all previously added
    1313             :    * tracks, whichever is greater.
    1314             :    * TODO at some point we will probably need to add API to select
    1315             :    * particular tracks of each input stream.
    1316             :    */
    1317             :   ProcessedMediaStream* CreateTrackUnionStream();
    1318             :   /**
    1319             :    * Create a stream that will mix all its audio input.
    1320             :    */
    1321             :   ProcessedMediaStream* CreateAudioCaptureStream(TrackID aTrackId);
    1322             : 
    1323             :   /**
    1324             :    * Add a new stream to the graph.  Main thread.
    1325             :    */
    1326             :   void AddStream(MediaStream* aStream);
    1327             : 
    1328             :   /* From the main thread, ask the MSG to send back an event when the graph
    1329             :    * thread is running, and audio is being processed. */
    1330             :   void NotifyWhenGraphStarted(AudioNodeStream* aNodeStream);
    1331             :   /* From the main thread, suspend, resume or close an AudioContext.
    1332             :    * aStreams are the streams of all the AudioNodes of the AudioContext that
    1333             :    * need to be suspended or resumed. This can be empty if this is a second
    1334             :    * consecutive suspend call and all the nodes are already suspended.
    1335             :    *
    1336             :    * This can possibly pause the graph thread, releasing system resources, if
    1337             :    * all streams have been suspended/closed.
    1338             :    *
    1339             :    * When the operation is complete, aPromise is resolved.
    1340             :    */
    1341             :   void ApplyAudioContextOperation(MediaStream* aDestinationStream,
    1342             :                                   const nsTArray<MediaStream*>& aStreams,
    1343             :                                   dom::AudioContextOperation aState,
    1344             :                                   void* aPromise);
    1345             : 
    1346             :   bool IsNonRealtime() const;
    1347             :   /**
    1348             :    * Start processing non-realtime for a specific number of ticks.
    1349             :    */
    1350             :   void StartNonRealtimeProcessing(uint32_t aTicksToProcess);
    1351             : 
    1352             :   /**
    1353             :    * Media graph thread only.
    1354             :    * Dispatches a runnable that will run on the main thread after all
    1355             :    * main-thread stream state has been next updated.
    1356             :    *
    1357             :    * Should only be called during MediaStreamListener callbacks or during
    1358             :    * ProcessedMediaStream::ProcessInput().
    1359             :    */
    1360             :   virtual void DispatchToMainThreadAfterStreamStateUpdate(
    1361             :     already_AddRefed<nsIRunnable> aRunnable);
    1362             : 
    1363             :   /**
    1364             :    * Returns graph sample rate in Hz.
    1365             :    */
    1366           0 :   TrackRate GraphRate() const { return mSampleRate; }
    1367             : 
    1368             :   void RegisterCaptureStreamForWindow(uint64_t aWindowId,
    1369             :                                       ProcessedMediaStream* aCaptureStream);
    1370             :   void UnregisterCaptureStreamForWindow(uint64_t aWindowId);
    1371             :   already_AddRefed<MediaInputPort> ConnectToCaptureStream(
    1372             :     uint64_t aWindowId, MediaStream* aMediaStream);
    1373             : 
    1374             :   /**
    1375             :    * Data going to the speakers from the GraphDriver's DataCallback
    1376             :    * to notify any listeners (for echo cancellation).
    1377             :    */
    1378             :   void NotifyOutputData(AudioDataValue* aBuffer, size_t aFrames,
    1379             :                         TrackRate aRate, uint32_t aChannels);
    1380             : 
    1381             :   void AssertOnGraphThreadOrNotRunning() const;
    1382             : 
    1383             : protected:
    1384           0 :   explicit MediaStreamGraph(TrackRate aSampleRate)
    1385           0 :     : mSampleRate(aSampleRate)
    1386             :   {
    1387           0 :     MOZ_COUNT_CTOR(MediaStreamGraph);
    1388           0 :   }
    1389           0 :   virtual ~MediaStreamGraph()
    1390           0 :   {
    1391           0 :     MOZ_COUNT_DTOR(MediaStreamGraph);
    1392           0 :   }
    1393             : 
    1394             :   // Media graph thread only
    1395             :   nsTArray<nsCOMPtr<nsIRunnable> > mPendingUpdateRunnables;
    1396             : 
    1397             :   /**
    1398             :    * Sample rate at which this graph runs. For real time graphs, this is
    1399             :    * the rate of the audio mixer. For offline graphs, this is the rate specified
    1400             :    * at construction.
    1401             :    */
    1402             :   TrackRate mSampleRate;
    1403             : 
    1404             :   /**
    1405             :    * CloseAudioInput is async, so hold a reference here.
    1406             :    */
    1407             :   nsTArray<RefPtr<AudioDataListener>> mAudioInputs;
    1408             : };
    1409             : 
    1410             : } // namespace mozilla
    1411             : 
    1412             : #endif /* MOZILLA_MEDIASTREAMGRAPH_H_ */

Generated by: LCOV version 1.13