content/media/MediaStreamGraph.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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_MEDIASTREAMGRAPH_H_
     7 #define MOZILLA_MEDIASTREAMGRAPH_H_
     9 #include "mozilla/Mutex.h"
    10 #include "mozilla/LinkedList.h"
    11 #include "AudioStream.h"
    12 #include "nsTArray.h"
    13 #include "nsIRunnable.h"
    14 #include "StreamBuffer.h"
    15 #include "TimeVarying.h"
    16 #include "VideoFrameContainer.h"
    17 #include "VideoSegment.h"
    18 #include "MainThreadUtils.h"
    19 #include "nsAutoRef.h"
    20 #include "speex/speex_resampler.h"
    21 #include "AudioMixer.h"
    22 #include "mozilla/dom/AudioChannelBinding.h"
    24 class nsIRunnable;
    26 template <>
    27 class nsAutoRefTraits<SpeexResamplerState> : public nsPointerRefTraits<SpeexResamplerState>
    28 {
    29   public:
    30   static void Release(SpeexResamplerState* aState) { speex_resampler_destroy(aState); }
    31 };
    33 namespace mozilla {
    35 class DOMMediaStream;
    37 #ifdef PR_LOGGING
    38 extern PRLogModuleInfo* gMediaStreamGraphLog;
    39 #endif
    41 /**
    42  * Microseconds relative to the start of the graph timeline.
    43  */
    44 typedef int64_t GraphTime;
    45 const GraphTime GRAPH_TIME_MAX = MEDIA_TIME_MAX;
    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  */
    80 class MediaStreamGraph;
    82 /**
    83  * This is a base class for media graph thread listener callbacks.
    84  * Override methods to be notified of audio or video data or changes in stream
    85  * state.
    86  *
    87  * This can be used by stream recorders or network connections that receive
    88  * stream input. It could also be used for debugging.
    89  *
    90  * All notification methods are called from the media graph thread. Overriders
    91  * of these methods are responsible for all synchronization. Beware!
    92  * These methods are called without the media graph monitor held, so
    93  * reentry into media graph methods is possible, although very much discouraged!
    94  * You should do something non-blocking and non-reentrant (e.g. dispatch an
    95  * event to some thread) and return.
    96  * The listener is not allowed to add/remove any listeners from the stream.
    97  *
    98  * When a listener is first attached, we guarantee to send a NotifyBlockingChanged
    99  * callback to notify of the initial blocking state. Also, if a listener is
   100  * attached to a stream that has already finished, we'll call NotifyFinished.
   101  */
   102 class MediaStreamListener {
   103 protected:
   104   // Protected destructor, to discourage deletion outside of Release():
   105   virtual ~MediaStreamListener() {}
   107 public:
   108   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStreamListener)
   110   enum Consumption {
   111     CONSUMED,
   112     NOT_CONSUMED
   113   };
   114   /**
   115    * Notify that the stream is hooked up and we'd like to start or stop receiving
   116    * data on it. Only fires on SourceMediaStreams.
   117    * The initial state is assumed to be NOT_CONSUMED.
   118    */
   119   virtual void NotifyConsumptionChanged(MediaStreamGraph* aGraph, Consumption aConsuming) {}
   121   /**
   122    * When a SourceMediaStream has pulling enabled, and the MediaStreamGraph
   123    * control loop is ready to pull, this gets called. A NotifyPull implementation
   124    * is allowed to call the SourceMediaStream methods that alter track
   125    * data. It is not allowed to make other MediaStream API calls, including
   126    * calls to add or remove MediaStreamListeners. It is not allowed to block
   127    * for any length of time.
   128    * aDesiredTime is the stream time we would like to get data up to. Data
   129    * beyond this point will not be played until NotifyPull runs again, so there's
   130    * not much point in providing it. Note that if the stream is blocked for
   131    * some reason, then data before aDesiredTime may not be played immediately.
   132    */
   133   virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) {}
   135   enum Blocking {
   136     BLOCKED,
   137     UNBLOCKED
   138   };
   139   /**
   140    * Notify that the blocking status of the stream changed. The initial state
   141    * is assumed to be BLOCKED.
   142    */
   143   virtual void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked) {}
   145   /**
   146    * Notify that the stream has data in each track
   147    * for the stream's current time. Once this state becomes true, it will
   148    * always be true since we block stream time from progressing to times where
   149    * there isn't data in each track.
   150    */
   151   virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph) {}
   153   /**
   154    * Notify that the stream output is advancing. aCurrentTime is the graph's
   155    * current time. MediaStream::GraphTimeToStreamTime can be used to get the
   156    * stream time.
   157    */
   158   virtual void NotifyOutput(MediaStreamGraph* aGraph, GraphTime aCurrentTime) {}
   160   /**
   161    * Notify that the stream finished.
   162    */
   163   virtual void NotifyFinished(MediaStreamGraph* aGraph) {}
   165   /**
   166    * Notify that your listener has been removed, either due to RemoveListener(),
   167    * or due to the stream being destroyed.  You will get no further notifications.
   168    */
   169   virtual void NotifyRemoved(MediaStreamGraph* aGraph) {}
   171   enum {
   172     TRACK_EVENT_CREATED = 0x01,
   173     TRACK_EVENT_ENDED = 0x02
   174   };
   175   /**
   176    * Notify that changes to one of the stream tracks have been queued.
   177    * aTrackEvents can be any combination of TRACK_EVENT_CREATED and
   178    * TRACK_EVENT_ENDED. aQueuedMedia is the data being added to the track
   179    * at aTrackOffset (relative to the start of the stream).
   180    */
   181   virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
   182                                         TrackRate aTrackRate,
   183                                         TrackTicks aTrackOffset,
   184                                         uint32_t aTrackEvents,
   185                                         const MediaSegment& aQueuedMedia) {}
   186 };
   188 /**
   189  * This is a base class for media graph thread listener direct callbacks
   190  * from within AppendToTrack().  Note that your regular listener will
   191  * still get NotifyQueuedTrackChanges() callbacks from the MSG thread, so
   192  * you must be careful to ignore them if AddDirectListener was successful.
   193  */
   194 class MediaStreamDirectListener : public MediaStreamListener
   195 {
   196 public:
   197   virtual ~MediaStreamDirectListener() {}
   199   /*
   200    * This will be called on any MediaStreamDirectListener added to a
   201    * a SourceMediaStream when AppendToTrack() is called.  The MediaSegment
   202    * will be the RawSegment (unresampled) if available in AppendToTrack().
   203    * Note that NotifyQueuedTrackChanges() calls will also still occur.
   204    */
   205   virtual void NotifyRealtimeData(MediaStreamGraph* aGraph, TrackID aID,
   206                                   TrackRate aTrackRate,
   207                                   TrackTicks aTrackOffset,
   208                                   uint32_t aTrackEvents,
   209                                   const MediaSegment& aMedia) {}
   210 };
   212 /**
   213  * This is a base class for main-thread listener callbacks.
   214  * This callback is invoked on the main thread when the main-thread-visible
   215  * state of a stream has changed.
   216  *
   217  * These methods are called with the media graph monitor held, so
   218  * reentry into general media graph methods is not possible.
   219  * You should do something non-blocking and non-reentrant (e.g. dispatch an
   220  * event) and return. DispatchFromMainThreadAfterNextStreamStateUpdate
   221  * would be a good choice.
   222  * The listener is allowed to synchronously remove itself from the stream, but
   223  * not add or remove any other listeners.
   224  */
   225 class MainThreadMediaStreamListener {
   226 public:
   227   virtual void NotifyMainThreadStateChanged() = 0;
   228 };
   230 /**
   231  * Helper struct used to keep track of memory usage by AudioNodes.
   232  */
   233 struct AudioNodeSizes
   234 {
   235   size_t mDomNode;
   236   size_t mStream;
   237   size_t mEngine;
   238   nsCString mNodeType;
   239 };
   241 class MediaStreamGraphImpl;
   242 class SourceMediaStream;
   243 class ProcessedMediaStream;
   244 class MediaInputPort;
   245 class AudioNodeEngine;
   246 class AudioNodeExternalInputStream;
   247 class AudioNodeStream;
   248 struct AudioChunk;
   250 /**
   251  * A stream of synchronized audio and video data. All (not blocked) streams
   252  * progress at the same rate --- "real time". Streams cannot seek. The only
   253  * operation readers can perform on a stream is to read the next data.
   254  *
   255  * Consumers of a stream can be reading from it at different offsets, but that
   256  * should only happen due to the order in which consumers are being run.
   257  * Those offsets must not diverge in the long term, otherwise we would require
   258  * unbounded buffering.
   259  *
   260  * Streams can be in a "blocked" state. While blocked, a stream does not
   261  * produce data. A stream can be explicitly blocked via the control API,
   262  * or implicitly blocked by whatever's generating it (e.g. an underrun in the
   263  * source resource), or implicitly blocked because something consuming it
   264  * blocks, or implicitly because it has finished.
   265  *
   266  * A stream can be in a "finished" state. "Finished" streams are permanently
   267  * blocked.
   268  *
   269  * Transitions into and out of the "blocked" and "finished" states are managed
   270  * by the MediaStreamGraph on the media graph thread.
   271  *
   272  * We buffer media data ahead of the consumers' reading offsets. It is possible
   273  * to have buffered data but still be blocked.
   274  *
   275  * Any stream can have its audio and video playing when requested. The media
   276  * stream graph plays audio by constructing audio output streams as necessary.
   277  * Video is played by setting video frames into an VideoFrameContainer at the right
   278  * time. To ensure video plays in sync with audio, make sure that the same
   279  * stream is playing both the audio and video.
   280  *
   281  * The data in a stream is managed by StreamBuffer. It consists of a set of
   282  * tracks of various types that can start and end over time.
   283  *
   284  * Streams are explicitly managed. The client creates them via
   285  * MediaStreamGraph::CreateInput/ProcessedMediaStream, and releases them by calling
   286  * Destroy() when no longer needed (actual destruction will be deferred).
   287  * The actual object is owned by the MediaStreamGraph. The basic idea is that
   288  * main thread objects will keep Streams alive as long as necessary (using the
   289  * cycle collector to clean up whenever needed).
   290  *
   291  * We make them refcounted only so that stream-related messages with MediaStream*
   292  * pointers can be sent to the main thread safely.
   293  *
   294  * The lifetimes of MediaStreams are controlled from the main thread.
   295  * For MediaStreams exposed to the DOM, the lifetime is controlled by the DOM
   296  * wrapper; the DOM wrappers own their associated MediaStreams. When a DOM
   297  * wrapper is destroyed, it sends a Destroy message for the associated
   298  * MediaStream and clears its reference (the last main-thread reference to
   299  * the object). When the Destroy message is processed on the graph
   300  * manager thread we immediately release the affected objects (disentangling them
   301  * from other objects as necessary).
   302  *
   303  * This could cause problems for media processing if a MediaStream is
   304  * destroyed while a downstream MediaStream is still using it. Therefore
   305  * the DOM wrappers must keep upstream MediaStreams alive as long as they
   306  * could be being used in the media graph.
   307  *
   308  * At any time, however, a set of MediaStream wrappers could be
   309  * collected via cycle collection. Destroy messages will be sent
   310  * for those objects in arbitrary order and the MediaStreamGraph has to be able
   311  * to handle this.
   312  */
   313 class MediaStream : public mozilla::LinkedListElement<MediaStream> {
   314 public:
   315   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStream)
   317   MediaStream(DOMMediaStream* aWrapper);
   319 protected:
   320   // Protected destructor, to discourage deletion outside of Release():
   321   virtual ~MediaStream()
   322   {
   323     MOZ_COUNT_DTOR(MediaStream);
   324     NS_ASSERTION(mMainThreadDestroyed, "Should have been destroyed already");
   325     NS_ASSERTION(mMainThreadListeners.IsEmpty(),
   326                  "All main thread listeners should have been removed");
   327   }
   329 public:
   330   /**
   331    * Returns the graph that owns this stream.
   332    */
   333   MediaStreamGraphImpl* GraphImpl();
   334   MediaStreamGraph* Graph();
   335   /**
   336    * Sets the graph that owns this stream.  Should only be called once.
   337    */
   338   void SetGraphImpl(MediaStreamGraphImpl* aGraph);
   339   void SetGraphImpl(MediaStreamGraph* aGraph);
   341   // Control API.
   342   // Since a stream can be played multiple ways, we need to combine independent
   343   // volume settings. The aKey parameter is used to keep volume settings
   344   // separate. Since the stream is always playing the same contents, only
   345   // a single audio output stream is used; the volumes are combined.
   346   // Currently only the first enabled audio track is played.
   347   // XXX change this so all enabled audio tracks are mixed and played.
   348   virtual void AddAudioOutput(void* aKey);
   349   virtual void SetAudioOutputVolume(void* aKey, float aVolume);
   350   virtual void RemoveAudioOutput(void* aKey);
   351   // Since a stream can be played multiple ways, we need to be able to
   352   // play to multiple VideoFrameContainers.
   353   // Only the first enabled video track is played.
   354   virtual void AddVideoOutput(VideoFrameContainer* aContainer);
   355   virtual void RemoveVideoOutput(VideoFrameContainer* aContainer);
   356   // Explicitly block. Useful for example if a media element is pausing
   357   // and we need to stop its stream emitting its buffered data.
   358   virtual void ChangeExplicitBlockerCount(int32_t aDelta);
   359   // Events will be dispatched by calling methods of aListener.
   360   virtual void AddListener(MediaStreamListener* aListener);
   361   virtual void RemoveListener(MediaStreamListener* aListener);
   362   // A disabled track has video replaced by black, and audio replaced by
   363   // silence.
   364   void SetTrackEnabled(TrackID aTrackID, bool aEnabled);
   365   // Events will be dispatched by calling methods of aListener. It is the
   366   // responsibility of the caller to remove aListener before it is destroyed.
   367   void AddMainThreadListener(MainThreadMediaStreamListener* aListener)
   368   {
   369     NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
   370     mMainThreadListeners.AppendElement(aListener);
   371   }
   372   // It's safe to call this even if aListener is not currently a listener;
   373   // the call will be ignored.
   374   void RemoveMainThreadListener(MainThreadMediaStreamListener* aListener)
   375   {
   376     NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
   377     mMainThreadListeners.RemoveElement(aListener);
   378   }
   379   /**
   380    * Ensure a runnable will run on the main thread after running all pending
   381    * updates that were sent from the graph thread or will be sent before the
   382    * graph thread receives the next graph update.
   383    *
   384    * If the graph has been shut down or destroyed, then the runnable will be
   385    * dispatched to the event queue immediately.  If the graph is non-realtime
   386    * and has not started, then the runnable will be run
   387    * synchronously/immediately.  (There are no pending updates in these
   388    * situations.)
   389    *
   390    * Main thread only.
   391    */
   392   void RunAfterPendingUpdates(nsRefPtr<nsIRunnable> aRunnable);
   394   // Signal that the client is done with this MediaStream. It will be deleted later.
   395   virtual void Destroy();
   396   // Returns the main-thread's view of how much data has been processed by
   397   // this stream.
   398   StreamTime GetCurrentTime()
   399   {
   400     NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
   401     return mMainThreadCurrentTime;
   402   }
   403   // Return the main thread's view of whether this stream has finished.
   404   bool IsFinished()
   405   {
   406     NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
   407     return mMainThreadFinished;
   408   }
   409   bool IsDestroyed()
   410   {
   411     NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
   412     return mMainThreadDestroyed;
   413   }
   415   friend class MediaStreamGraphImpl;
   416   friend class MediaInputPort;
   417   friend class AudioNodeExternalInputStream;
   419   virtual SourceMediaStream* AsSourceStream() { return nullptr; }
   420   virtual ProcessedMediaStream* AsProcessedStream() { return nullptr; }
   421   virtual AudioNodeStream* AsAudioNodeStream() { return nullptr; }
   423   // media graph thread only
   424   void Init();
   425   // These Impl methods perform the core functionality of the control methods
   426   // above, on the media graph thread.
   427   /**
   428    * Stop all stream activity and disconnect it from all inputs and outputs.
   429    * This must be idempotent.
   430    */
   431   virtual void DestroyImpl();
   432   StreamTime GetBufferEnd() { return mBuffer.GetEnd(); }
   433 #ifdef DEBUG
   434   void DumpTrackInfo() { return mBuffer.DumpTrackInfo(); }
   435 #endif
   436   void SetAudioOutputVolumeImpl(void* aKey, float aVolume);
   437   void AddAudioOutputImpl(void* aKey)
   438   {
   439     mAudioOutputs.AppendElement(AudioOutput(aKey));
   440   }
   441   void RemoveAudioOutputImpl(void* aKey);
   442   void AddVideoOutputImpl(already_AddRefed<VideoFrameContainer> aContainer)
   443   {
   444     *mVideoOutputs.AppendElement() = aContainer;
   445   }
   446   void RemoveVideoOutputImpl(VideoFrameContainer* aContainer)
   447   {
   448     mVideoOutputs.RemoveElement(aContainer);
   449   }
   450   void ChangeExplicitBlockerCountImpl(GraphTime aTime, int32_t aDelta)
   451   {
   452     mExplicitBlockerCount.SetAtAndAfter(aTime, mExplicitBlockerCount.GetAt(aTime) + aDelta);
   453   }
   454   void AddListenerImpl(already_AddRefed<MediaStreamListener> aListener);
   455   void RemoveListenerImpl(MediaStreamListener* aListener);
   456   void RemoveAllListenersImpl();
   457   void SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled);
   458   /**
   459    * Returns true when this stream requires the contents of its inputs even if
   460    * its own outputs are not being consumed. This is used to signal inputs to
   461    * this stream that they are being consumed; when they're not being consumed,
   462    * we make some optimizations.
   463    */
   464   virtual bool IsIntrinsicallyConsumed() const
   465   {
   466     return !mAudioOutputs.IsEmpty() || !mVideoOutputs.IsEmpty();
   467   }
   469   void AddConsumer(MediaInputPort* aPort)
   470   {
   471     mConsumers.AppendElement(aPort);
   472   }
   473   void RemoveConsumer(MediaInputPort* aPort)
   474   {
   475     mConsumers.RemoveElement(aPort);
   476   }
   477   uint32_t ConsumerCount()
   478   {
   479     return mConsumers.Length();
   480   }
   481   const StreamBuffer& GetStreamBuffer() { return mBuffer; }
   482   GraphTime GetStreamBufferStartTime() { return mBufferStartTime; }
   483   /**
   484    * Convert graph time to stream time. aTime must be <= mStateComputedTime
   485    * to ensure we know exactly how much time this stream will be blocked during
   486    * the interval.
   487    */
   488   StreamTime GraphTimeToStreamTime(GraphTime aTime);
   489   /**
   490    * Convert graph time to stream time. aTime can be > mStateComputedTime,
   491    * in which case we optimistically assume the stream will not be blocked
   492    * after mStateComputedTime.
   493    */
   494   StreamTime GraphTimeToStreamTimeOptimistic(GraphTime aTime);
   495   /**
   496    * Convert stream time to graph time. The result can be > mStateComputedTime,
   497    * in which case we did the conversion optimistically assuming the stream
   498    * will not be blocked after mStateComputedTime.
   499    */
   500   GraphTime StreamTimeToGraphTime(StreamTime aTime);
   501   bool IsFinishedOnGraphThread() { return mFinished; }
   502   void FinishOnGraphThread();
   503   /**
   504    * Identify which graph update index we are currently processing.
   505    */
   506   int64_t GetProcessingGraphUpdateIndex();
   508   bool HasCurrentData() { return mHasCurrentData; }
   510   StreamBuffer::Track* EnsureTrack(TrackID aTrack, TrackRate aSampleRate);
   512   void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, MediaSegment* aRawSegment = nullptr);
   514   DOMMediaStream* GetWrapper()
   515   {
   516     NS_ASSERTION(NS_IsMainThread(), "Only use DOMMediaStream on main thread");
   517     return mWrapper;
   518   }
   520   // Return true if the main thread needs to observe updates from this stream.
   521   virtual bool MainThreadNeedsUpdates() const
   522   {
   523     return true;
   524   }
   526   virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
   527   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
   529   void SetAudioChannelType(dom::AudioChannel aType) { mAudioChannelType = aType; }
   531 protected:
   532   virtual void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime, GraphTime aBlockedTime)
   533   {
   534     mBufferStartTime += aBlockedTime;
   535     mGraphUpdateIndices.InsertTimeAtStart(aBlockedTime);
   536     mGraphUpdateIndices.AdvanceCurrentTime(aCurrentTime);
   537     mExplicitBlockerCount.AdvanceCurrentTime(aCurrentTime);
   539     mBuffer.ForgetUpTo(aCurrentTime - mBufferStartTime);
   540   }
   542   // This state is all initialized on the main thread but
   543   // otherwise modified only on the media graph thread.
   545   // Buffered data. The start of the buffer corresponds to mBufferStartTime.
   546   // Conceptually the buffer contains everything this stream has ever played,
   547   // but we forget some prefix of the buffered data to bound the space usage.
   548   StreamBuffer mBuffer;
   549   // The time when the buffered data could be considered to have started playing.
   550   // This increases over time to account for time the stream was blocked before
   551   // mCurrentTime.
   552   GraphTime mBufferStartTime;
   554   // Client-set volume of this stream
   555   struct AudioOutput {
   556     AudioOutput(void* aKey) : mKey(aKey), mVolume(1.0f) {}
   557     void* mKey;
   558     float mVolume;
   559   };
   560   nsTArray<AudioOutput> mAudioOutputs;
   561   nsTArray<nsRefPtr<VideoFrameContainer> > mVideoOutputs;
   562   // We record the last played video frame to avoid redundant setting
   563   // of the current video frame.
   564   VideoFrame mLastPlayedVideoFrame;
   565   // The number of times this stream has been explicitly blocked by the control
   566   // API, minus the number of times it has been explicitly unblocked.
   567   TimeVarying<GraphTime,uint32_t,0> mExplicitBlockerCount;
   568   nsTArray<nsRefPtr<MediaStreamListener> > mListeners;
   569   nsTArray<MainThreadMediaStreamListener*> mMainThreadListeners;
   570   nsTArray<TrackID> mDisabledTrackIDs;
   572   // Precomputed blocking status (over GraphTime).
   573   // This is only valid between the graph's mCurrentTime and
   574   // mStateComputedTime. The stream is considered to have
   575   // not been blocked before mCurrentTime (its mBufferStartTime is increased
   576   // as necessary to account for that time instead) --- this avoids us having to
   577   // record the entire history of the stream's blocking-ness in mBlocked.
   578   TimeVarying<GraphTime,bool,5> mBlocked;
   579   // Maps graph time to the graph update that affected this stream at that time
   580   TimeVarying<GraphTime,int64_t,0> mGraphUpdateIndices;
   582   // MediaInputPorts to which this is connected
   583   nsTArray<MediaInputPort*> mConsumers;
   585   // Where audio output is going. There is one AudioOutputStream per
   586   // audio track.
   587   struct AudioOutputStream {
   588     // When we started audio playback for this track.
   589     // Add mStream->GetPosition() to find the current audio playback position.
   590     GraphTime mAudioPlaybackStartTime;
   591     // Amount of time that we've wanted to play silence because of the stream
   592     // blocking.
   593     MediaTime mBlockedAudioTime;
   594     // Last tick written to the audio output.
   595     TrackTicks mLastTickWritten;
   596     RefPtr<AudioStream> mStream;
   597     TrackID mTrackID;
   599     size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   600     {
   601       size_t amount = 0;
   602       amount += mStream->SizeOfIncludingThis(aMallocSizeOf);
   603       return amount;
   604     }
   605   };
   606   nsTArray<AudioOutputStream> mAudioOutputStreams;
   608   /**
   609    * When true, this means the stream will be finished once all
   610    * buffered data has been consumed.
   611    */
   612   bool mFinished;
   613   /**
   614    * When true, mFinished is true and we've played all the data in this stream
   615    * and fired NotifyFinished notifications.
   616    */
   617   bool mNotifiedFinished;
   618   /**
   619    * When true, the last NotifyBlockingChanged delivered to the listeners
   620    * indicated that the stream is blocked.
   621    */
   622   bool mNotifiedBlocked;
   623   /**
   624    * True if some data can be present by this stream if/when it's unblocked.
   625    * Set by the stream itself on the MediaStreamGraph thread. Only changes
   626    * from false to true once a stream has data, since we won't
   627    * unblock it until there's more data.
   628    */
   629   bool mHasCurrentData;
   630   /**
   631    * True if mHasCurrentData is true and we've notified listeners.
   632    */
   633   bool mNotifiedHasCurrentData;
   635   // Temporary data for ordering streams by dependency graph
   636   bool mHasBeenOrdered;
   637   bool mIsOnOrderingStack;
   638   // True if the stream is being consumed (i.e. has track data being played,
   639   // or is feeding into some stream that is being consumed).
   640   bool mIsConsumed;
   641   // Temporary data for computing blocking status of streams
   642   // True if we've added this stream to the set of streams we're computing
   643   // blocking for.
   644   bool mInBlockingSet;
   645   // True if this stream should be blocked in this phase.
   646   bool mBlockInThisPhase;
   648   // This state is only used on the main thread.
   649   DOMMediaStream* mWrapper;
   650   // Main-thread views of state
   651   StreamTime mMainThreadCurrentTime;
   652   bool mMainThreadFinished;
   653   bool mMainThreadDestroyed;
   655   // Our media stream graph.  null if destroyed on the graph thread.
   656   MediaStreamGraphImpl* mGraph;
   658   dom::AudioChannel mAudioChannelType;
   659 };
   661 /**
   662  * This is a stream into which a decoder can write audio and video.
   663  *
   664  * Audio and video can be written on any thread, but you probably want to
   665  * always write from the same thread to avoid unexpected interleavings.
   666  */
   667 class SourceMediaStream : public MediaStream {
   668 public:
   669   SourceMediaStream(DOMMediaStream* aWrapper) :
   670     MediaStream(aWrapper),
   671     mLastConsumptionState(MediaStreamListener::NOT_CONSUMED),
   672     mMutex("mozilla::media::SourceMediaStream"),
   673     mUpdateKnownTracksTime(0),
   674     mPullEnabled(false),
   675     mUpdateFinished(false)
   676   {}
   678   virtual SourceMediaStream* AsSourceStream() { return this; }
   680   // Media graph thread only
   681   virtual void DestroyImpl();
   683   // Call these on any thread.
   684   /**
   685    * Enable or disable pulling. When pulling is enabled, NotifyPull
   686    * gets called on MediaStreamListeners for this stream during the
   687    * MediaStreamGraph control loop. Pulling is initially disabled.
   688    * Due to unavoidable race conditions, after a call to SetPullEnabled(false)
   689    * it is still possible for a NotifyPull to occur.
   690    */
   691   void SetPullEnabled(bool aEnabled);
   693   void AddDirectListener(MediaStreamDirectListener* aListener);
   694   void RemoveDirectListener(MediaStreamDirectListener* aListener);
   696   /**
   697    * Add a new track to the stream starting at the given base time (which
   698    * must be greater than or equal to the last time passed to
   699    * AdvanceKnownTracksTime). Takes ownership of aSegment. aSegment should
   700    * contain data starting after aStart.
   701    */
   702   void AddTrack(TrackID aID, TrackRate aRate, TrackTicks aStart,
   703                 MediaSegment* aSegment);
   705   /**
   706    * Append media data to a track. Ownership of aSegment remains with the caller,
   707    * but aSegment is emptied.
   708    * Returns false if the data was not appended because no such track exists
   709    * or the stream was already finished.
   710    */
   711   bool AppendToTrack(TrackID aID, MediaSegment* aSegment, MediaSegment *aRawSegment = nullptr);
   712   /**
   713    * Returns true if the buffer currently has enough data.
   714    * Returns false if there isn't enough data or if no such track exists.
   715    */
   716   bool HaveEnoughBuffered(TrackID aID);
   717   /**
   718    * Ensures that aSignalRunnable will be dispatched to aSignalThread
   719    * when we don't have enough buffered data in the track (which could be
   720    * immediately). Will dispatch the runnable immediately if the track
   721    * does not exist. No op if a runnable is already present for this track.
   722    */
   723   void DispatchWhenNotEnoughBuffered(TrackID aID,
   724       nsIEventTarget* aSignalThread, nsIRunnable* aSignalRunnable);
   725   /**
   726    * Indicate that a track has ended. Do not do any more API calls
   727    * affecting this track.
   728    * Ignored if the track does not exist.
   729    */
   730   void EndTrack(TrackID aID);
   731   /**
   732    * Indicate that no tracks will be added starting before time aKnownTime.
   733    * aKnownTime must be >= its value at the last call to AdvanceKnownTracksTime.
   734    */
   735   void AdvanceKnownTracksTime(StreamTime aKnownTime);
   736   /**
   737    * Indicate that this stream should enter the "finished" state. All tracks
   738    * must have been ended via EndTrack. The finish time of the stream is
   739    * when all tracks have ended.
   740    */
   741   void FinishWithLockHeld();
   742   void Finish()
   743     {
   744       MutexAutoLock lock(mMutex);
   745       FinishWithLockHeld();
   746     }
   748   // Overriding allows us to hold the mMutex lock while changing the track enable status
   749   void SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled) {
   750     MutexAutoLock lock(mMutex);
   751     MediaStream::SetTrackEnabledImpl(aTrackID, aEnabled);
   752   }
   754   /**
   755    * End all tracks and Finish() this stream.  Used to voluntarily revoke access
   756    * to a LocalMediaStream.
   757    */
   758   void EndAllTrackAndFinish();
   760   /**
   761    * Note: Only call from Media Graph thread (eg NotifyPull)
   762    *
   763    * Returns amount of time (data) that is currently buffered in the track,
   764    * assuming playout via PlayAudio or via a TrackUnion - note that
   765    * NotifyQueuedTrackChanges() on a SourceMediaStream will occur without
   766    * any "extra" buffering, but NotifyQueued TrackChanges() on a TrackUnion
   767    * will be buffered.
   768    */
   769   TrackTicks GetBufferedTicks(TrackID aID);
   771   void RegisterForAudioMixing();
   773   // XXX need a Reset API
   775   friend class MediaStreamGraphImpl;
   777 protected:
   778   struct ThreadAndRunnable {
   779     void Init(nsIEventTarget* aTarget, nsIRunnable* aRunnable)
   780     {
   781       mTarget = aTarget;
   782       mRunnable = aRunnable;
   783     }
   785     nsCOMPtr<nsIEventTarget> mTarget;
   786     nsCOMPtr<nsIRunnable> mRunnable;
   787   };
   788   enum TrackCommands {
   789     TRACK_CREATE = MediaStreamListener::TRACK_EVENT_CREATED,
   790     TRACK_END = MediaStreamListener::TRACK_EVENT_ENDED
   791   };
   792   /**
   793    * Data for each track that hasn't ended.
   794    */
   795   struct TrackData {
   796     TrackID mID;
   797     // Sample rate of the input data.
   798     TrackRate mInputRate;
   799     // Sample rate of the output data, always equal to the sample rate of the
   800     // graph.
   801     TrackRate mOutputRate;
   802     // Resampler if the rate of the input track does not match the
   803     // MediaStreamGraph's.
   804     nsAutoRef<SpeexResamplerState> mResampler;
   805     TrackTicks mStart;
   806     // Each time the track updates are flushed to the media graph thread,
   807     // this is cleared.
   808     uint32_t mCommands;
   809     // Each time the track updates are flushed to the media graph thread,
   810     // the segment buffer is emptied.
   811     nsAutoPtr<MediaSegment> mData;
   812     nsTArray<ThreadAndRunnable> mDispatchWhenNotEnough;
   813     bool mHaveEnough;
   814   };
   816   bool NeedsMixing();
   818   void ResampleAudioToGraphSampleRate(TrackData* aTrackData, MediaSegment* aSegment);
   820   TrackData* FindDataForTrack(TrackID aID)
   821   {
   822     for (uint32_t i = 0; i < mUpdateTracks.Length(); ++i) {
   823       if (mUpdateTracks[i].mID == aID) {
   824         return &mUpdateTracks[i];
   825       }
   826     }
   827     return nullptr;
   828   }
   830   /**
   831    * Notify direct consumers of new data to one of the stream tracks.
   832    * The data doesn't have to be resampled (though it may be).  This is called
   833    * from AppendToTrack on the thread providing the data, and will call
   834    * the Listeners on this thread.
   835    */
   836   void NotifyDirectConsumers(TrackData *aTrack,
   837                              MediaSegment *aSegment);
   839   // Media stream graph thread only
   840   MediaStreamListener::Consumption mLastConsumptionState;
   842   // This must be acquired *before* MediaStreamGraphImpl's lock, if they are
   843   // held together.
   844   Mutex mMutex;
   845   // protected by mMutex
   846   StreamTime mUpdateKnownTracksTime;
   847   nsTArray<TrackData> mUpdateTracks;
   848   nsTArray<nsRefPtr<MediaStreamDirectListener> > mDirectListeners;
   849   bool mPullEnabled;
   850   bool mUpdateFinished;
   851   bool mNeedsMixing;
   852 };
   854 /**
   855  * Represents a connection between a ProcessedMediaStream and one of its
   856  * input streams.
   857  * We make these refcounted so that stream-related messages with MediaInputPort*
   858  * pointers can be sent to the main thread safely.
   859  *
   860  * When a port's source or destination stream dies, the stream's DestroyImpl
   861  * calls MediaInputPort::Disconnect to disconnect the port from
   862  * the source and destination streams.
   863  *
   864  * The lifetimes of MediaInputPort are controlled from the main thread.
   865  * The media graph adds a reference to the port. When a MediaInputPort is no
   866  * longer needed, main-thread code sends a Destroy message for the port and
   867  * clears its reference (the last main-thread reference to the object). When
   868  * the Destroy message is processed on the graph manager thread we disconnect
   869  * the port and drop the graph's reference, destroying the object.
   870  */
   871 class MediaInputPort MOZ_FINAL {
   872 private:
   873   // Do not call this constructor directly. Instead call aDest->AllocateInputPort.
   874   MediaInputPort(MediaStream* aSource, ProcessedMediaStream* aDest,
   875                  uint32_t aFlags, uint16_t aInputNumber,
   876                  uint16_t aOutputNumber)
   877     : mSource(aSource)
   878     , mDest(aDest)
   879     , mFlags(aFlags)
   880     , mInputNumber(aInputNumber)
   881     , mOutputNumber(aOutputNumber)
   882     , mGraph(nullptr)
   883   {
   884     MOZ_COUNT_CTOR(MediaInputPort);
   885   }
   887   // Private destructor, to discourage deletion outside of Release():
   888   ~MediaInputPort()
   889   {
   890     MOZ_COUNT_DTOR(MediaInputPort);
   891   }
   893 public:
   894   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaInputPort)
   896   /**
   897    * The FLAG_BLOCK_INPUT and FLAG_BLOCK_OUTPUT flags can be used to control
   898    * exactly how the blocking statuses of the input and output streams affect
   899    * each other.
   900    */
   901   enum {
   902     // When set, blocking on the output stream forces blocking on the input
   903     // stream.
   904     FLAG_BLOCK_INPUT = 0x01,
   905     // When set, blocking on the input stream forces blocking on the output
   906     // stream.
   907     FLAG_BLOCK_OUTPUT = 0x02
   908   };
   910   // Called on graph manager thread
   911   // Do not call these from outside MediaStreamGraph.cpp!
   912   void Init();
   913   // Called during message processing to trigger removal of this stream.
   914   void Disconnect();
   916   // Control API
   917   /**
   918    * Disconnects and destroys the port. The caller must not reference this
   919    * object again.
   920    */
   921   void Destroy();
   923   // Any thread
   924   MediaStream* GetSource() { return mSource; }
   925   ProcessedMediaStream* GetDestination() { return mDest; }
   927   uint16_t InputNumber() const { return mInputNumber; }
   928   uint16_t OutputNumber() const { return mOutputNumber; }
   930   // Call on graph manager thread
   931   struct InputInterval {
   932     GraphTime mStart;
   933     GraphTime mEnd;
   934     bool mInputIsBlocked;
   935   };
   936   // Find the next time interval starting at or after aTime during which
   937   // mDest is not blocked and mSource's blocking status does not change.
   938   InputInterval GetNextInputInterval(GraphTime aTime);
   940   /**
   941    * Returns the graph that owns this port.
   942    */
   943   MediaStreamGraphImpl* GraphImpl();
   944   MediaStreamGraph* Graph();
   945   /**
   946    * Sets the graph that owns this stream.  Should only be called once.
   947    */
   948   void SetGraphImpl(MediaStreamGraphImpl* aGraph);
   950   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   951   {
   952     size_t amount = 0;
   954     // Not owned:
   955     // - mSource
   956     // - mDest
   957     // - mGraph
   958     return amount;
   959   }
   961   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   962   {
   963     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   964   }
   966 private:
   967   friend class MediaStreamGraphImpl;
   968   friend class MediaStream;
   969   friend class ProcessedMediaStream;
   970   // Never modified after Init()
   971   MediaStream* mSource;
   972   ProcessedMediaStream* mDest;
   973   uint32_t mFlags;
   974   // The input and output numbers are optional, and are currently only used by
   975   // Web Audio.
   976   const uint16_t mInputNumber;
   977   const uint16_t mOutputNumber;
   979   // Our media stream graph
   980   MediaStreamGraphImpl* mGraph;
   981 };
   983 /**
   984  * This stream processes zero or more input streams in parallel to produce
   985  * its output. The details of how the output is produced are handled by
   986  * subclasses overriding the ProcessInput method.
   987  */
   988 class ProcessedMediaStream : public MediaStream {
   989 public:
   990   ProcessedMediaStream(DOMMediaStream* aWrapper)
   991     : MediaStream(aWrapper), mAutofinish(false), mInCycle(false)
   992   {}
   994   // Control API.
   995   /**
   996    * Allocates a new input port attached to source aStream.
   997    * This stream can be removed by calling MediaInputPort::Remove().
   998    */
   999   already_AddRefed<MediaInputPort> AllocateInputPort(MediaStream* aStream,
  1000                                                      uint32_t aFlags = 0,
  1001                                                      uint16_t aInputNumber = 0,
  1002                                                      uint16_t aOutputNumber = 0);
  1003   /**
  1004    * Force this stream into the finished state.
  1005    */
  1006   void Finish();
  1007   /**
  1008    * Set the autofinish flag on this stream (defaults to false). When this flag
  1009    * is set, and all input streams are in the finished state (including if there
  1010    * are no input streams), this stream automatically enters the finished state.
  1011    */
  1012   void SetAutofinish(bool aAutofinish);
  1014   virtual ProcessedMediaStream* AsProcessedStream() { return this; }
  1016   friend class MediaStreamGraphImpl;
  1018   // Do not call these from outside MediaStreamGraph.cpp!
  1019   virtual void AddInput(MediaInputPort* aPort);
  1020   virtual void RemoveInput(MediaInputPort* aPort)
  1022     mInputs.RemoveElement(aPort);
  1024   bool HasInputPort(MediaInputPort* aPort)
  1026     return mInputs.Contains(aPort);
  1028   uint32_t InputPortCount()
  1030     return mInputs.Length();
  1032   virtual void DestroyImpl();
  1033   /**
  1034    * This gets called after we've computed the blocking states for all
  1035    * streams (mBlocked is up to date up to mStateComputedTime).
  1036    * Also, we've produced output for all streams up to this one. If this stream
  1037    * is not in a cycle, then all its source streams have produced data.
  1038    * Generate output from aFrom to aTo.
  1039    * This will be called on streams that have finished. Most stream types should
  1040    * just return immediately if IsFinishedOnGraphThread(), but some may wish to
  1041    * update internal state (see AudioNodeStream).
  1042    * ProcessInput is allowed to call FinishOnGraphThread only if ALLOW_FINISH
  1043    * is in aFlags. (This flag will be set when aTo >= mStateComputedTime, i.e.
  1044    * when we've producing the last block of data we need to produce.) Otherwise
  1045    * we can get into a situation where we've determined the stream should not
  1046    * block before mStateComputedTime, but the stream finishes before
  1047    * mStateComputedTime, violating the invariant that finished streams are blocked.
  1048    */
  1049   enum {
  1050     ALLOW_FINISH = 0x01
  1051   };
  1052   virtual void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) = 0;
  1053   void SetAutofinishImpl(bool aAutofinish) { mAutofinish = aAutofinish; }
  1055   /**
  1056    * Forward SetTrackEnabled() to the input MediaStream(s) and translate the ID
  1057    */
  1058   virtual void ForwardTrackEnabled(TrackID aOutputID, bool aEnabled) {};
  1060   bool InCycle() const { return mInCycle; }
  1062   virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
  1064     size_t amount = MediaStream::SizeOfExcludingThis(aMallocSizeOf);
  1065     // Not owned:
  1066     // - mInputs elements
  1067     amount += mInputs.SizeOfExcludingThis(aMallocSizeOf);
  1068     return amount;
  1071   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
  1073     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
  1076 protected:
  1077   // This state is all accessed only on the media graph thread.
  1079   // The list of all inputs that are currently enabled or waiting to be enabled.
  1080   nsTArray<MediaInputPort*> mInputs;
  1081   bool mAutofinish;
  1082   // True if and only if this stream is in a cycle.
  1083   // Updated by MediaStreamGraphImpl::UpdateStreamOrder.
  1084   bool mInCycle;
  1085 };
  1087 /**
  1088  * Initially, at least, we will have a singleton MediaStreamGraph per
  1089  * process.  Each OfflineAudioContext object creates its own MediaStreamGraph
  1090  * object too.
  1091  */
  1092 class MediaStreamGraph {
  1093 public:
  1094   // We ensure that the graph current time advances in multiples of
  1095   // IdealAudioBlockSize()/AudioStream::PreferredSampleRate(). A stream that
  1096   // never blocks and has a track with the ideal audio rate will produce audio
  1097   // in multiples of the block size.
  1099   // Main thread only
  1100   static MediaStreamGraph* GetInstance();
  1101   static MediaStreamGraph* CreateNonRealtimeInstance(TrackRate aSampleRate);
  1102   // Idempotent
  1103   static void DestroyNonRealtimeInstance(MediaStreamGraph* aGraph);
  1105   // Control API.
  1106   /**
  1107    * Create a stream that a media decoder (or some other source of
  1108    * media data, such as a camera) can write to.
  1109    */
  1110   SourceMediaStream* CreateSourceStream(DOMMediaStream* aWrapper);
  1111   /**
  1112    * Create a stream that will form the union of the tracks of its input
  1113    * streams.
  1114    * A TrackUnionStream contains all the tracks of all its input streams.
  1115    * Adding a new input stream makes that stream's tracks immediately appear as new
  1116    * tracks starting at the time the input stream was added.
  1117    * Removing an input stream makes the output tracks corresponding to the
  1118    * removed tracks immediately end.
  1119    * For each added track, the track ID of the output track is the track ID
  1120    * of the input track or one plus the maximum ID of all previously added
  1121    * tracks, whichever is greater.
  1122    * TODO at some point we will probably need to add API to select
  1123    * particular tracks of each input stream.
  1124    */
  1125   ProcessedMediaStream* CreateTrackUnionStream(DOMMediaStream* aWrapper);
  1126   // Internal AudioNodeStreams can only pass their output to another
  1127   // AudioNode, whereas external AudioNodeStreams can pass their output
  1128   // to an nsAudioStream for playback.
  1129   enum AudioNodeStreamKind { SOURCE_STREAM, INTERNAL_STREAM, EXTERNAL_STREAM };
  1130   /**
  1131    * Create a stream that will process audio for an AudioNode.
  1132    * Takes ownership of aEngine.  aSampleRate is the sampling rate used
  1133    * for the stream.  If 0 is passed, the sampling rate of the engine's
  1134    * node will get used.
  1135    */
  1136   AudioNodeStream* CreateAudioNodeStream(AudioNodeEngine* aEngine,
  1137                                          AudioNodeStreamKind aKind,
  1138                                          TrackRate aSampleRate = 0);
  1140   AudioNodeExternalInputStream*
  1141   CreateAudioNodeExternalInputStream(AudioNodeEngine* aEngine,
  1142                                      TrackRate aSampleRate = 0);
  1144   bool IsNonRealtime() const;
  1145   /**
  1146    * Start processing non-realtime for a specific number of ticks.
  1147    */
  1148   void StartNonRealtimeProcessing(TrackRate aRate, uint32_t aTicksToProcess);
  1150   /**
  1151    * Media graph thread only.
  1152    * Dispatches a runnable that will run on the main thread after all
  1153    * main-thread stream state has been next updated.
  1154    * Should only be called during MediaStreamListener callbacks or during
  1155    * ProcessedMediaStream::ProcessInput().
  1156    */
  1157   void DispatchToMainThreadAfterStreamStateUpdate(already_AddRefed<nsIRunnable> aRunnable)
  1159     *mPendingUpdateRunnables.AppendElement() = aRunnable;
  1162 protected:
  1163   MediaStreamGraph()
  1164     : mNextGraphUpdateIndex(1)
  1166     MOZ_COUNT_CTOR(MediaStreamGraph);
  1168   virtual ~MediaStreamGraph()
  1170     MOZ_COUNT_DTOR(MediaStreamGraph);
  1173   // Media graph thread only
  1174   nsTArray<nsCOMPtr<nsIRunnable> > mPendingUpdateRunnables;
  1176   // Main thread only
  1177   // The number of updates we have sent to the media graph thread + 1.
  1178   // We start this at 1 just to ensure that 0 is usable as a special value.
  1179   int64_t mNextGraphUpdateIndex;
  1180 };
  1184 #endif /* MOZILLA_MEDIASTREAMGRAPH_H_ */

mercurial