content/media/MediaStreamGraph.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/media/MediaStreamGraph.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1184 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.7 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifndef MOZILLA_MEDIASTREAMGRAPH_H_
    1.10 +#define MOZILLA_MEDIASTREAMGRAPH_H_
    1.11 +
    1.12 +#include "mozilla/Mutex.h"
    1.13 +#include "mozilla/LinkedList.h"
    1.14 +#include "AudioStream.h"
    1.15 +#include "nsTArray.h"
    1.16 +#include "nsIRunnable.h"
    1.17 +#include "StreamBuffer.h"
    1.18 +#include "TimeVarying.h"
    1.19 +#include "VideoFrameContainer.h"
    1.20 +#include "VideoSegment.h"
    1.21 +#include "MainThreadUtils.h"
    1.22 +#include "nsAutoRef.h"
    1.23 +#include "speex/speex_resampler.h"
    1.24 +#include "AudioMixer.h"
    1.25 +#include "mozilla/dom/AudioChannelBinding.h"
    1.26 +
    1.27 +class nsIRunnable;
    1.28 +
    1.29 +template <>
    1.30 +class nsAutoRefTraits<SpeexResamplerState> : public nsPointerRefTraits<SpeexResamplerState>
    1.31 +{
    1.32 +  public:
    1.33 +  static void Release(SpeexResamplerState* aState) { speex_resampler_destroy(aState); }
    1.34 +};
    1.35 +
    1.36 +namespace mozilla {
    1.37 +
    1.38 +class DOMMediaStream;
    1.39 +
    1.40 +#ifdef PR_LOGGING
    1.41 +extern PRLogModuleInfo* gMediaStreamGraphLog;
    1.42 +#endif
    1.43 +
    1.44 +/**
    1.45 + * Microseconds relative to the start of the graph timeline.
    1.46 + */
    1.47 +typedef int64_t GraphTime;
    1.48 +const GraphTime GRAPH_TIME_MAX = MEDIA_TIME_MAX;
    1.49 +
    1.50 +/*
    1.51 + * MediaStreamGraph is a framework for synchronized audio/video processing
    1.52 + * and playback. It is designed to be used by other browser components such as
    1.53 + * HTML media elements, media capture APIs, real-time media streaming APIs,
    1.54 + * multitrack media APIs, and advanced audio APIs.
    1.55 + *
    1.56 + * The MediaStreamGraph uses a dedicated thread to process media --- the media
    1.57 + * graph thread. This ensures that we can process media through the graph
    1.58 + * without blocking on main-thread activity. The media graph is only modified
    1.59 + * on the media graph thread, to ensure graph changes can be processed without
    1.60 + * interfering with media processing. All interaction with the media graph
    1.61 + * thread is done with message passing.
    1.62 + *
    1.63 + * APIs that modify the graph or its properties are described as "control APIs".
    1.64 + * These APIs are asynchronous; they queue graph changes internally and
    1.65 + * those changes are processed all-at-once by the MediaStreamGraph. The
    1.66 + * MediaStreamGraph monitors the main thread event loop via nsIAppShell::RunInStableState
    1.67 + * to ensure that graph changes from a single event loop task are always
    1.68 + * processed all together. Control APIs should only be used on the main thread,
    1.69 + * currently; we may be able to relax that later.
    1.70 + *
    1.71 + * To allow precise synchronization of times in the control API, the
    1.72 + * MediaStreamGraph maintains a "media timeline". Control APIs that take or
    1.73 + * return times use that timeline. Those times never advance during
    1.74 + * an event loop task. This time is returned by MediaStreamGraph::GetCurrentTime().
    1.75 + *
    1.76 + * Media decoding, audio processing and media playback use thread-safe APIs to
    1.77 + * the media graph to ensure they can continue while the main thread is blocked.
    1.78 + *
    1.79 + * When the graph is changed, we may need to throw out buffered data and
    1.80 + * reprocess it. This is triggered automatically by the MediaStreamGraph.
    1.81 + */
    1.82 +
    1.83 +class MediaStreamGraph;
    1.84 +
    1.85 +/**
    1.86 + * This is a base class for media graph thread listener callbacks.
    1.87 + * Override methods to be notified of audio or video data or changes in stream
    1.88 + * state.
    1.89 + *
    1.90 + * This can be used by stream recorders or network connections that receive
    1.91 + * stream input. It could also be used for debugging.
    1.92 + *
    1.93 + * All notification methods are called from the media graph thread. Overriders
    1.94 + * of these methods are responsible for all synchronization. Beware!
    1.95 + * These methods are called without the media graph monitor held, so
    1.96 + * reentry into media graph methods is possible, although very much discouraged!
    1.97 + * You should do something non-blocking and non-reentrant (e.g. dispatch an
    1.98 + * event to some thread) and return.
    1.99 + * The listener is not allowed to add/remove any listeners from the stream.
   1.100 + *
   1.101 + * When a listener is first attached, we guarantee to send a NotifyBlockingChanged
   1.102 + * callback to notify of the initial blocking state. Also, if a listener is
   1.103 + * attached to a stream that has already finished, we'll call NotifyFinished.
   1.104 + */
   1.105 +class MediaStreamListener {
   1.106 +protected:
   1.107 +  // Protected destructor, to discourage deletion outside of Release():
   1.108 +  virtual ~MediaStreamListener() {}
   1.109 +
   1.110 +public:
   1.111 +  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStreamListener)
   1.112 +
   1.113 +  enum Consumption {
   1.114 +    CONSUMED,
   1.115 +    NOT_CONSUMED
   1.116 +  };
   1.117 +  /**
   1.118 +   * Notify that the stream is hooked up and we'd like to start or stop receiving
   1.119 +   * data on it. Only fires on SourceMediaStreams.
   1.120 +   * The initial state is assumed to be NOT_CONSUMED.
   1.121 +   */
   1.122 +  virtual void NotifyConsumptionChanged(MediaStreamGraph* aGraph, Consumption aConsuming) {}
   1.123 +
   1.124 +  /**
   1.125 +   * When a SourceMediaStream has pulling enabled, and the MediaStreamGraph
   1.126 +   * control loop is ready to pull, this gets called. A NotifyPull implementation
   1.127 +   * is allowed to call the SourceMediaStream methods that alter track
   1.128 +   * data. It is not allowed to make other MediaStream API calls, including
   1.129 +   * calls to add or remove MediaStreamListeners. It is not allowed to block
   1.130 +   * for any length of time.
   1.131 +   * aDesiredTime is the stream time we would like to get data up to. Data
   1.132 +   * beyond this point will not be played until NotifyPull runs again, so there's
   1.133 +   * not much point in providing it. Note that if the stream is blocked for
   1.134 +   * some reason, then data before aDesiredTime may not be played immediately.
   1.135 +   */
   1.136 +  virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) {}
   1.137 +
   1.138 +  enum Blocking {
   1.139 +    BLOCKED,
   1.140 +    UNBLOCKED
   1.141 +  };
   1.142 +  /**
   1.143 +   * Notify that the blocking status of the stream changed. The initial state
   1.144 +   * is assumed to be BLOCKED.
   1.145 +   */
   1.146 +  virtual void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked) {}
   1.147 +
   1.148 +  /**
   1.149 +   * Notify that the stream has data in each track
   1.150 +   * for the stream's current time. Once this state becomes true, it will
   1.151 +   * always be true since we block stream time from progressing to times where
   1.152 +   * there isn't data in each track.
   1.153 +   */
   1.154 +  virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph) {}
   1.155 +
   1.156 +  /**
   1.157 +   * Notify that the stream output is advancing. aCurrentTime is the graph's
   1.158 +   * current time. MediaStream::GraphTimeToStreamTime can be used to get the
   1.159 +   * stream time.
   1.160 +   */
   1.161 +  virtual void NotifyOutput(MediaStreamGraph* aGraph, GraphTime aCurrentTime) {}
   1.162 +
   1.163 +  /**
   1.164 +   * Notify that the stream finished.
   1.165 +   */
   1.166 +  virtual void NotifyFinished(MediaStreamGraph* aGraph) {}
   1.167 +
   1.168 +  /**
   1.169 +   * Notify that your listener has been removed, either due to RemoveListener(),
   1.170 +   * or due to the stream being destroyed.  You will get no further notifications.
   1.171 +   */
   1.172 +  virtual void NotifyRemoved(MediaStreamGraph* aGraph) {}
   1.173 +
   1.174 +  enum {
   1.175 +    TRACK_EVENT_CREATED = 0x01,
   1.176 +    TRACK_EVENT_ENDED = 0x02
   1.177 +  };
   1.178 +  /**
   1.179 +   * Notify that changes to one of the stream tracks have been queued.
   1.180 +   * aTrackEvents can be any combination of TRACK_EVENT_CREATED and
   1.181 +   * TRACK_EVENT_ENDED. aQueuedMedia is the data being added to the track
   1.182 +   * at aTrackOffset (relative to the start of the stream).
   1.183 +   */
   1.184 +  virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
   1.185 +                                        TrackRate aTrackRate,
   1.186 +                                        TrackTicks aTrackOffset,
   1.187 +                                        uint32_t aTrackEvents,
   1.188 +                                        const MediaSegment& aQueuedMedia) {}
   1.189 +};
   1.190 +
   1.191 +/**
   1.192 + * This is a base class for media graph thread listener direct callbacks
   1.193 + * from within AppendToTrack().  Note that your regular listener will
   1.194 + * still get NotifyQueuedTrackChanges() callbacks from the MSG thread, so
   1.195 + * you must be careful to ignore them if AddDirectListener was successful.
   1.196 + */
   1.197 +class MediaStreamDirectListener : public MediaStreamListener
   1.198 +{
   1.199 +public:
   1.200 +  virtual ~MediaStreamDirectListener() {}
   1.201 +
   1.202 +  /*
   1.203 +   * This will be called on any MediaStreamDirectListener added to a
   1.204 +   * a SourceMediaStream when AppendToTrack() is called.  The MediaSegment
   1.205 +   * will be the RawSegment (unresampled) if available in AppendToTrack().
   1.206 +   * Note that NotifyQueuedTrackChanges() calls will also still occur.
   1.207 +   */
   1.208 +  virtual void NotifyRealtimeData(MediaStreamGraph* aGraph, TrackID aID,
   1.209 +                                  TrackRate aTrackRate,
   1.210 +                                  TrackTicks aTrackOffset,
   1.211 +                                  uint32_t aTrackEvents,
   1.212 +                                  const MediaSegment& aMedia) {}
   1.213 +};
   1.214 +
   1.215 +/**
   1.216 + * This is a base class for main-thread listener callbacks.
   1.217 + * This callback is invoked on the main thread when the main-thread-visible
   1.218 + * state of a stream has changed.
   1.219 + *
   1.220 + * These methods are called with the media graph monitor held, so
   1.221 + * reentry into general media graph methods is not possible.
   1.222 + * You should do something non-blocking and non-reentrant (e.g. dispatch an
   1.223 + * event) and return. DispatchFromMainThreadAfterNextStreamStateUpdate
   1.224 + * would be a good choice.
   1.225 + * The listener is allowed to synchronously remove itself from the stream, but
   1.226 + * not add or remove any other listeners.
   1.227 + */
   1.228 +class MainThreadMediaStreamListener {
   1.229 +public:
   1.230 +  virtual void NotifyMainThreadStateChanged() = 0;
   1.231 +};
   1.232 +
   1.233 +/**
   1.234 + * Helper struct used to keep track of memory usage by AudioNodes.
   1.235 + */
   1.236 +struct AudioNodeSizes
   1.237 +{
   1.238 +  size_t mDomNode;
   1.239 +  size_t mStream;
   1.240 +  size_t mEngine;
   1.241 +  nsCString mNodeType;
   1.242 +};
   1.243 +
   1.244 +class MediaStreamGraphImpl;
   1.245 +class SourceMediaStream;
   1.246 +class ProcessedMediaStream;
   1.247 +class MediaInputPort;
   1.248 +class AudioNodeEngine;
   1.249 +class AudioNodeExternalInputStream;
   1.250 +class AudioNodeStream;
   1.251 +struct AudioChunk;
   1.252 +
   1.253 +/**
   1.254 + * A stream of synchronized audio and video data. All (not blocked) streams
   1.255 + * progress at the same rate --- "real time". Streams cannot seek. The only
   1.256 + * operation readers can perform on a stream is to read the next data.
   1.257 + *
   1.258 + * Consumers of a stream can be reading from it at different offsets, but that
   1.259 + * should only happen due to the order in which consumers are being run.
   1.260 + * Those offsets must not diverge in the long term, otherwise we would require
   1.261 + * unbounded buffering.
   1.262 + *
   1.263 + * Streams can be in a "blocked" state. While blocked, a stream does not
   1.264 + * produce data. A stream can be explicitly blocked via the control API,
   1.265 + * or implicitly blocked by whatever's generating it (e.g. an underrun in the
   1.266 + * source resource), or implicitly blocked because something consuming it
   1.267 + * blocks, or implicitly because it has finished.
   1.268 + *
   1.269 + * A stream can be in a "finished" state. "Finished" streams are permanently
   1.270 + * blocked.
   1.271 + *
   1.272 + * Transitions into and out of the "blocked" and "finished" states are managed
   1.273 + * by the MediaStreamGraph on the media graph thread.
   1.274 + *
   1.275 + * We buffer media data ahead of the consumers' reading offsets. It is possible
   1.276 + * to have buffered data but still be blocked.
   1.277 + *
   1.278 + * Any stream can have its audio and video playing when requested. The media
   1.279 + * stream graph plays audio by constructing audio output streams as necessary.
   1.280 + * Video is played by setting video frames into an VideoFrameContainer at the right
   1.281 + * time. To ensure video plays in sync with audio, make sure that the same
   1.282 + * stream is playing both the audio and video.
   1.283 + *
   1.284 + * The data in a stream is managed by StreamBuffer. It consists of a set of
   1.285 + * tracks of various types that can start and end over time.
   1.286 + *
   1.287 + * Streams are explicitly managed. The client creates them via
   1.288 + * MediaStreamGraph::CreateInput/ProcessedMediaStream, and releases them by calling
   1.289 + * Destroy() when no longer needed (actual destruction will be deferred).
   1.290 + * The actual object is owned by the MediaStreamGraph. The basic idea is that
   1.291 + * main thread objects will keep Streams alive as long as necessary (using the
   1.292 + * cycle collector to clean up whenever needed).
   1.293 + *
   1.294 + * We make them refcounted only so that stream-related messages with MediaStream*
   1.295 + * pointers can be sent to the main thread safely.
   1.296 + *
   1.297 + * The lifetimes of MediaStreams are controlled from the main thread.
   1.298 + * For MediaStreams exposed to the DOM, the lifetime is controlled by the DOM
   1.299 + * wrapper; the DOM wrappers own their associated MediaStreams. When a DOM
   1.300 + * wrapper is destroyed, it sends a Destroy message for the associated
   1.301 + * MediaStream and clears its reference (the last main-thread reference to
   1.302 + * the object). When the Destroy message is processed on the graph
   1.303 + * manager thread we immediately release the affected objects (disentangling them
   1.304 + * from other objects as necessary).
   1.305 + *
   1.306 + * This could cause problems for media processing if a MediaStream is
   1.307 + * destroyed while a downstream MediaStream is still using it. Therefore
   1.308 + * the DOM wrappers must keep upstream MediaStreams alive as long as they
   1.309 + * could be being used in the media graph.
   1.310 + *
   1.311 + * At any time, however, a set of MediaStream wrappers could be
   1.312 + * collected via cycle collection. Destroy messages will be sent
   1.313 + * for those objects in arbitrary order and the MediaStreamGraph has to be able
   1.314 + * to handle this.
   1.315 + */
   1.316 +class MediaStream : public mozilla::LinkedListElement<MediaStream> {
   1.317 +public:
   1.318 +  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStream)
   1.319 +
   1.320 +  MediaStream(DOMMediaStream* aWrapper);
   1.321 +
   1.322 +protected:
   1.323 +  // Protected destructor, to discourage deletion outside of Release():
   1.324 +  virtual ~MediaStream()
   1.325 +  {
   1.326 +    MOZ_COUNT_DTOR(MediaStream);
   1.327 +    NS_ASSERTION(mMainThreadDestroyed, "Should have been destroyed already");
   1.328 +    NS_ASSERTION(mMainThreadListeners.IsEmpty(),
   1.329 +                 "All main thread listeners should have been removed");
   1.330 +  }
   1.331 +
   1.332 +public:
   1.333 +  /**
   1.334 +   * Returns the graph that owns this stream.
   1.335 +   */
   1.336 +  MediaStreamGraphImpl* GraphImpl();
   1.337 +  MediaStreamGraph* Graph();
   1.338 +  /**
   1.339 +   * Sets the graph that owns this stream.  Should only be called once.
   1.340 +   */
   1.341 +  void SetGraphImpl(MediaStreamGraphImpl* aGraph);
   1.342 +  void SetGraphImpl(MediaStreamGraph* aGraph);
   1.343 +
   1.344 +  // Control API.
   1.345 +  // Since a stream can be played multiple ways, we need to combine independent
   1.346 +  // volume settings. The aKey parameter is used to keep volume settings
   1.347 +  // separate. Since the stream is always playing the same contents, only
   1.348 +  // a single audio output stream is used; the volumes are combined.
   1.349 +  // Currently only the first enabled audio track is played.
   1.350 +  // XXX change this so all enabled audio tracks are mixed and played.
   1.351 +  virtual void AddAudioOutput(void* aKey);
   1.352 +  virtual void SetAudioOutputVolume(void* aKey, float aVolume);
   1.353 +  virtual void RemoveAudioOutput(void* aKey);
   1.354 +  // Since a stream can be played multiple ways, we need to be able to
   1.355 +  // play to multiple VideoFrameContainers.
   1.356 +  // Only the first enabled video track is played.
   1.357 +  virtual void AddVideoOutput(VideoFrameContainer* aContainer);
   1.358 +  virtual void RemoveVideoOutput(VideoFrameContainer* aContainer);
   1.359 +  // Explicitly block. Useful for example if a media element is pausing
   1.360 +  // and we need to stop its stream emitting its buffered data.
   1.361 +  virtual void ChangeExplicitBlockerCount(int32_t aDelta);
   1.362 +  // Events will be dispatched by calling methods of aListener.
   1.363 +  virtual void AddListener(MediaStreamListener* aListener);
   1.364 +  virtual void RemoveListener(MediaStreamListener* aListener);
   1.365 +  // A disabled track has video replaced by black, and audio replaced by
   1.366 +  // silence.
   1.367 +  void SetTrackEnabled(TrackID aTrackID, bool aEnabled);
   1.368 +  // Events will be dispatched by calling methods of aListener. It is the
   1.369 +  // responsibility of the caller to remove aListener before it is destroyed.
   1.370 +  void AddMainThreadListener(MainThreadMediaStreamListener* aListener)
   1.371 +  {
   1.372 +    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
   1.373 +    mMainThreadListeners.AppendElement(aListener);
   1.374 +  }
   1.375 +  // It's safe to call this even if aListener is not currently a listener;
   1.376 +  // the call will be ignored.
   1.377 +  void RemoveMainThreadListener(MainThreadMediaStreamListener* aListener)
   1.378 +  {
   1.379 +    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
   1.380 +    mMainThreadListeners.RemoveElement(aListener);
   1.381 +  }
   1.382 +  /**
   1.383 +   * Ensure a runnable will run on the main thread after running all pending
   1.384 +   * updates that were sent from the graph thread or will be sent before the
   1.385 +   * graph thread receives the next graph update.
   1.386 +   *
   1.387 +   * If the graph has been shut down or destroyed, then the runnable will be
   1.388 +   * dispatched to the event queue immediately.  If the graph is non-realtime
   1.389 +   * and has not started, then the runnable will be run
   1.390 +   * synchronously/immediately.  (There are no pending updates in these
   1.391 +   * situations.)
   1.392 +   *
   1.393 +   * Main thread only.
   1.394 +   */
   1.395 +  void RunAfterPendingUpdates(nsRefPtr<nsIRunnable> aRunnable);
   1.396 +
   1.397 +  // Signal that the client is done with this MediaStream. It will be deleted later.
   1.398 +  virtual void Destroy();
   1.399 +  // Returns the main-thread's view of how much data has been processed by
   1.400 +  // this stream.
   1.401 +  StreamTime GetCurrentTime()
   1.402 +  {
   1.403 +    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
   1.404 +    return mMainThreadCurrentTime;
   1.405 +  }
   1.406 +  // Return the main thread's view of whether this stream has finished.
   1.407 +  bool IsFinished()
   1.408 +  {
   1.409 +    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
   1.410 +    return mMainThreadFinished;
   1.411 +  }
   1.412 +  bool IsDestroyed()
   1.413 +  {
   1.414 +    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
   1.415 +    return mMainThreadDestroyed;
   1.416 +  }
   1.417 +
   1.418 +  friend class MediaStreamGraphImpl;
   1.419 +  friend class MediaInputPort;
   1.420 +  friend class AudioNodeExternalInputStream;
   1.421 +
   1.422 +  virtual SourceMediaStream* AsSourceStream() { return nullptr; }
   1.423 +  virtual ProcessedMediaStream* AsProcessedStream() { return nullptr; }
   1.424 +  virtual AudioNodeStream* AsAudioNodeStream() { return nullptr; }
   1.425 +
   1.426 +  // media graph thread only
   1.427 +  void Init();
   1.428 +  // These Impl methods perform the core functionality of the control methods
   1.429 +  // above, on the media graph thread.
   1.430 +  /**
   1.431 +   * Stop all stream activity and disconnect it from all inputs and outputs.
   1.432 +   * This must be idempotent.
   1.433 +   */
   1.434 +  virtual void DestroyImpl();
   1.435 +  StreamTime GetBufferEnd() { return mBuffer.GetEnd(); }
   1.436 +#ifdef DEBUG
   1.437 +  void DumpTrackInfo() { return mBuffer.DumpTrackInfo(); }
   1.438 +#endif
   1.439 +  void SetAudioOutputVolumeImpl(void* aKey, float aVolume);
   1.440 +  void AddAudioOutputImpl(void* aKey)
   1.441 +  {
   1.442 +    mAudioOutputs.AppendElement(AudioOutput(aKey));
   1.443 +  }
   1.444 +  void RemoveAudioOutputImpl(void* aKey);
   1.445 +  void AddVideoOutputImpl(already_AddRefed<VideoFrameContainer> aContainer)
   1.446 +  {
   1.447 +    *mVideoOutputs.AppendElement() = aContainer;
   1.448 +  }
   1.449 +  void RemoveVideoOutputImpl(VideoFrameContainer* aContainer)
   1.450 +  {
   1.451 +    mVideoOutputs.RemoveElement(aContainer);
   1.452 +  }
   1.453 +  void ChangeExplicitBlockerCountImpl(GraphTime aTime, int32_t aDelta)
   1.454 +  {
   1.455 +    mExplicitBlockerCount.SetAtAndAfter(aTime, mExplicitBlockerCount.GetAt(aTime) + aDelta);
   1.456 +  }
   1.457 +  void AddListenerImpl(already_AddRefed<MediaStreamListener> aListener);
   1.458 +  void RemoveListenerImpl(MediaStreamListener* aListener);
   1.459 +  void RemoveAllListenersImpl();
   1.460 +  void SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled);
   1.461 +  /**
   1.462 +   * Returns true when this stream requires the contents of its inputs even if
   1.463 +   * its own outputs are not being consumed. This is used to signal inputs to
   1.464 +   * this stream that they are being consumed; when they're not being consumed,
   1.465 +   * we make some optimizations.
   1.466 +   */
   1.467 +  virtual bool IsIntrinsicallyConsumed() const
   1.468 +  {
   1.469 +    return !mAudioOutputs.IsEmpty() || !mVideoOutputs.IsEmpty();
   1.470 +  }
   1.471 +
   1.472 +  void AddConsumer(MediaInputPort* aPort)
   1.473 +  {
   1.474 +    mConsumers.AppendElement(aPort);
   1.475 +  }
   1.476 +  void RemoveConsumer(MediaInputPort* aPort)
   1.477 +  {
   1.478 +    mConsumers.RemoveElement(aPort);
   1.479 +  }
   1.480 +  uint32_t ConsumerCount()
   1.481 +  {
   1.482 +    return mConsumers.Length();
   1.483 +  }
   1.484 +  const StreamBuffer& GetStreamBuffer() { return mBuffer; }
   1.485 +  GraphTime GetStreamBufferStartTime() { return mBufferStartTime; }
   1.486 +  /**
   1.487 +   * Convert graph time to stream time. aTime must be <= mStateComputedTime
   1.488 +   * to ensure we know exactly how much time this stream will be blocked during
   1.489 +   * the interval.
   1.490 +   */
   1.491 +  StreamTime GraphTimeToStreamTime(GraphTime aTime);
   1.492 +  /**
   1.493 +   * Convert graph time to stream time. aTime can be > mStateComputedTime,
   1.494 +   * in which case we optimistically assume the stream will not be blocked
   1.495 +   * after mStateComputedTime.
   1.496 +   */
   1.497 +  StreamTime GraphTimeToStreamTimeOptimistic(GraphTime aTime);
   1.498 +  /**
   1.499 +   * Convert stream time to graph time. The result can be > mStateComputedTime,
   1.500 +   * in which case we did the conversion optimistically assuming the stream
   1.501 +   * will not be blocked after mStateComputedTime.
   1.502 +   */
   1.503 +  GraphTime StreamTimeToGraphTime(StreamTime aTime);
   1.504 +  bool IsFinishedOnGraphThread() { return mFinished; }
   1.505 +  void FinishOnGraphThread();
   1.506 +  /**
   1.507 +   * Identify which graph update index we are currently processing.
   1.508 +   */
   1.509 +  int64_t GetProcessingGraphUpdateIndex();
   1.510 +
   1.511 +  bool HasCurrentData() { return mHasCurrentData; }
   1.512 +
   1.513 +  StreamBuffer::Track* EnsureTrack(TrackID aTrack, TrackRate aSampleRate);
   1.514 +
   1.515 +  void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, MediaSegment* aRawSegment = nullptr);
   1.516 +
   1.517 +  DOMMediaStream* GetWrapper()
   1.518 +  {
   1.519 +    NS_ASSERTION(NS_IsMainThread(), "Only use DOMMediaStream on main thread");
   1.520 +    return mWrapper;
   1.521 +  }
   1.522 +
   1.523 +  // Return true if the main thread needs to observe updates from this stream.
   1.524 +  virtual bool MainThreadNeedsUpdates() const
   1.525 +  {
   1.526 +    return true;
   1.527 +  }
   1.528 +
   1.529 +  virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
   1.530 +  virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
   1.531 +
   1.532 +  void SetAudioChannelType(dom::AudioChannel aType) { mAudioChannelType = aType; }
   1.533 +
   1.534 +protected:
   1.535 +  virtual void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime, GraphTime aBlockedTime)
   1.536 +  {
   1.537 +    mBufferStartTime += aBlockedTime;
   1.538 +    mGraphUpdateIndices.InsertTimeAtStart(aBlockedTime);
   1.539 +    mGraphUpdateIndices.AdvanceCurrentTime(aCurrentTime);
   1.540 +    mExplicitBlockerCount.AdvanceCurrentTime(aCurrentTime);
   1.541 +
   1.542 +    mBuffer.ForgetUpTo(aCurrentTime - mBufferStartTime);
   1.543 +  }
   1.544 +
   1.545 +  // This state is all initialized on the main thread but
   1.546 +  // otherwise modified only on the media graph thread.
   1.547 +
   1.548 +  // Buffered data. The start of the buffer corresponds to mBufferStartTime.
   1.549 +  // Conceptually the buffer contains everything this stream has ever played,
   1.550 +  // but we forget some prefix of the buffered data to bound the space usage.
   1.551 +  StreamBuffer mBuffer;
   1.552 +  // The time when the buffered data could be considered to have started playing.
   1.553 +  // This increases over time to account for time the stream was blocked before
   1.554 +  // mCurrentTime.
   1.555 +  GraphTime mBufferStartTime;
   1.556 +
   1.557 +  // Client-set volume of this stream
   1.558 +  struct AudioOutput {
   1.559 +    AudioOutput(void* aKey) : mKey(aKey), mVolume(1.0f) {}
   1.560 +    void* mKey;
   1.561 +    float mVolume;
   1.562 +  };
   1.563 +  nsTArray<AudioOutput> mAudioOutputs;
   1.564 +  nsTArray<nsRefPtr<VideoFrameContainer> > mVideoOutputs;
   1.565 +  // We record the last played video frame to avoid redundant setting
   1.566 +  // of the current video frame.
   1.567 +  VideoFrame mLastPlayedVideoFrame;
   1.568 +  // The number of times this stream has been explicitly blocked by the control
   1.569 +  // API, minus the number of times it has been explicitly unblocked.
   1.570 +  TimeVarying<GraphTime,uint32_t,0> mExplicitBlockerCount;
   1.571 +  nsTArray<nsRefPtr<MediaStreamListener> > mListeners;
   1.572 +  nsTArray<MainThreadMediaStreamListener*> mMainThreadListeners;
   1.573 +  nsTArray<TrackID> mDisabledTrackIDs;
   1.574 +
   1.575 +  // Precomputed blocking status (over GraphTime).
   1.576 +  // This is only valid between the graph's mCurrentTime and
   1.577 +  // mStateComputedTime. The stream is considered to have
   1.578 +  // not been blocked before mCurrentTime (its mBufferStartTime is increased
   1.579 +  // as necessary to account for that time instead) --- this avoids us having to
   1.580 +  // record the entire history of the stream's blocking-ness in mBlocked.
   1.581 +  TimeVarying<GraphTime,bool,5> mBlocked;
   1.582 +  // Maps graph time to the graph update that affected this stream at that time
   1.583 +  TimeVarying<GraphTime,int64_t,0> mGraphUpdateIndices;
   1.584 +
   1.585 +  // MediaInputPorts to which this is connected
   1.586 +  nsTArray<MediaInputPort*> mConsumers;
   1.587 +
   1.588 +  // Where audio output is going. There is one AudioOutputStream per
   1.589 +  // audio track.
   1.590 +  struct AudioOutputStream {
   1.591 +    // When we started audio playback for this track.
   1.592 +    // Add mStream->GetPosition() to find the current audio playback position.
   1.593 +    GraphTime mAudioPlaybackStartTime;
   1.594 +    // Amount of time that we've wanted to play silence because of the stream
   1.595 +    // blocking.
   1.596 +    MediaTime mBlockedAudioTime;
   1.597 +    // Last tick written to the audio output.
   1.598 +    TrackTicks mLastTickWritten;
   1.599 +    RefPtr<AudioStream> mStream;
   1.600 +    TrackID mTrackID;
   1.601 +
   1.602 +    size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   1.603 +    {
   1.604 +      size_t amount = 0;
   1.605 +      amount += mStream->SizeOfIncludingThis(aMallocSizeOf);
   1.606 +      return amount;
   1.607 +    }
   1.608 +  };
   1.609 +  nsTArray<AudioOutputStream> mAudioOutputStreams;
   1.610 +
   1.611 +  /**
   1.612 +   * When true, this means the stream will be finished once all
   1.613 +   * buffered data has been consumed.
   1.614 +   */
   1.615 +  bool mFinished;
   1.616 +  /**
   1.617 +   * When true, mFinished is true and we've played all the data in this stream
   1.618 +   * and fired NotifyFinished notifications.
   1.619 +   */
   1.620 +  bool mNotifiedFinished;
   1.621 +  /**
   1.622 +   * When true, the last NotifyBlockingChanged delivered to the listeners
   1.623 +   * indicated that the stream is blocked.
   1.624 +   */
   1.625 +  bool mNotifiedBlocked;
   1.626 +  /**
   1.627 +   * True if some data can be present by this stream if/when it's unblocked.
   1.628 +   * Set by the stream itself on the MediaStreamGraph thread. Only changes
   1.629 +   * from false to true once a stream has data, since we won't
   1.630 +   * unblock it until there's more data.
   1.631 +   */
   1.632 +  bool mHasCurrentData;
   1.633 +  /**
   1.634 +   * True if mHasCurrentData is true and we've notified listeners.
   1.635 +   */
   1.636 +  bool mNotifiedHasCurrentData;
   1.637 +
   1.638 +  // Temporary data for ordering streams by dependency graph
   1.639 +  bool mHasBeenOrdered;
   1.640 +  bool mIsOnOrderingStack;
   1.641 +  // True if the stream is being consumed (i.e. has track data being played,
   1.642 +  // or is feeding into some stream that is being consumed).
   1.643 +  bool mIsConsumed;
   1.644 +  // Temporary data for computing blocking status of streams
   1.645 +  // True if we've added this stream to the set of streams we're computing
   1.646 +  // blocking for.
   1.647 +  bool mInBlockingSet;
   1.648 +  // True if this stream should be blocked in this phase.
   1.649 +  bool mBlockInThisPhase;
   1.650 +
   1.651 +  // This state is only used on the main thread.
   1.652 +  DOMMediaStream* mWrapper;
   1.653 +  // Main-thread views of state
   1.654 +  StreamTime mMainThreadCurrentTime;
   1.655 +  bool mMainThreadFinished;
   1.656 +  bool mMainThreadDestroyed;
   1.657 +
   1.658 +  // Our media stream graph.  null if destroyed on the graph thread.
   1.659 +  MediaStreamGraphImpl* mGraph;
   1.660 +
   1.661 +  dom::AudioChannel mAudioChannelType;
   1.662 +};
   1.663 +
   1.664 +/**
   1.665 + * This is a stream into which a decoder can write audio and video.
   1.666 + *
   1.667 + * Audio and video can be written on any thread, but you probably want to
   1.668 + * always write from the same thread to avoid unexpected interleavings.
   1.669 + */
   1.670 +class SourceMediaStream : public MediaStream {
   1.671 +public:
   1.672 +  SourceMediaStream(DOMMediaStream* aWrapper) :
   1.673 +    MediaStream(aWrapper),
   1.674 +    mLastConsumptionState(MediaStreamListener::NOT_CONSUMED),
   1.675 +    mMutex("mozilla::media::SourceMediaStream"),
   1.676 +    mUpdateKnownTracksTime(0),
   1.677 +    mPullEnabled(false),
   1.678 +    mUpdateFinished(false)
   1.679 +  {}
   1.680 +
   1.681 +  virtual SourceMediaStream* AsSourceStream() { return this; }
   1.682 +
   1.683 +  // Media graph thread only
   1.684 +  virtual void DestroyImpl();
   1.685 +
   1.686 +  // Call these on any thread.
   1.687 +  /**
   1.688 +   * Enable or disable pulling. When pulling is enabled, NotifyPull
   1.689 +   * gets called on MediaStreamListeners for this stream during the
   1.690 +   * MediaStreamGraph control loop. Pulling is initially disabled.
   1.691 +   * Due to unavoidable race conditions, after a call to SetPullEnabled(false)
   1.692 +   * it is still possible for a NotifyPull to occur.
   1.693 +   */
   1.694 +  void SetPullEnabled(bool aEnabled);
   1.695 +
   1.696 +  void AddDirectListener(MediaStreamDirectListener* aListener);
   1.697 +  void RemoveDirectListener(MediaStreamDirectListener* aListener);
   1.698 +
   1.699 +  /**
   1.700 +   * Add a new track to the stream starting at the given base time (which
   1.701 +   * must be greater than or equal to the last time passed to
   1.702 +   * AdvanceKnownTracksTime). Takes ownership of aSegment. aSegment should
   1.703 +   * contain data starting after aStart.
   1.704 +   */
   1.705 +  void AddTrack(TrackID aID, TrackRate aRate, TrackTicks aStart,
   1.706 +                MediaSegment* aSegment);
   1.707 +
   1.708 +  /**
   1.709 +   * Append media data to a track. Ownership of aSegment remains with the caller,
   1.710 +   * but aSegment is emptied.
   1.711 +   * Returns false if the data was not appended because no such track exists
   1.712 +   * or the stream was already finished.
   1.713 +   */
   1.714 +  bool AppendToTrack(TrackID aID, MediaSegment* aSegment, MediaSegment *aRawSegment = nullptr);
   1.715 +  /**
   1.716 +   * Returns true if the buffer currently has enough data.
   1.717 +   * Returns false if there isn't enough data or if no such track exists.
   1.718 +   */
   1.719 +  bool HaveEnoughBuffered(TrackID aID);
   1.720 +  /**
   1.721 +   * Ensures that aSignalRunnable will be dispatched to aSignalThread
   1.722 +   * when we don't have enough buffered data in the track (which could be
   1.723 +   * immediately). Will dispatch the runnable immediately if the track
   1.724 +   * does not exist. No op if a runnable is already present for this track.
   1.725 +   */
   1.726 +  void DispatchWhenNotEnoughBuffered(TrackID aID,
   1.727 +      nsIEventTarget* aSignalThread, nsIRunnable* aSignalRunnable);
   1.728 +  /**
   1.729 +   * Indicate that a track has ended. Do not do any more API calls
   1.730 +   * affecting this track.
   1.731 +   * Ignored if the track does not exist.
   1.732 +   */
   1.733 +  void EndTrack(TrackID aID);
   1.734 +  /**
   1.735 +   * Indicate that no tracks will be added starting before time aKnownTime.
   1.736 +   * aKnownTime must be >= its value at the last call to AdvanceKnownTracksTime.
   1.737 +   */
   1.738 +  void AdvanceKnownTracksTime(StreamTime aKnownTime);
   1.739 +  /**
   1.740 +   * Indicate that this stream should enter the "finished" state. All tracks
   1.741 +   * must have been ended via EndTrack. The finish time of the stream is
   1.742 +   * when all tracks have ended.
   1.743 +   */
   1.744 +  void FinishWithLockHeld();
   1.745 +  void Finish()
   1.746 +    {
   1.747 +      MutexAutoLock lock(mMutex);
   1.748 +      FinishWithLockHeld();
   1.749 +    }
   1.750 +
   1.751 +  // Overriding allows us to hold the mMutex lock while changing the track enable status
   1.752 +  void SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled) {
   1.753 +    MutexAutoLock lock(mMutex);
   1.754 +    MediaStream::SetTrackEnabledImpl(aTrackID, aEnabled);
   1.755 +  }
   1.756 +
   1.757 +  /**
   1.758 +   * End all tracks and Finish() this stream.  Used to voluntarily revoke access
   1.759 +   * to a LocalMediaStream.
   1.760 +   */
   1.761 +  void EndAllTrackAndFinish();
   1.762 +
   1.763 +  /**
   1.764 +   * Note: Only call from Media Graph thread (eg NotifyPull)
   1.765 +   *
   1.766 +   * Returns amount of time (data) that is currently buffered in the track,
   1.767 +   * assuming playout via PlayAudio or via a TrackUnion - note that
   1.768 +   * NotifyQueuedTrackChanges() on a SourceMediaStream will occur without
   1.769 +   * any "extra" buffering, but NotifyQueued TrackChanges() on a TrackUnion
   1.770 +   * will be buffered.
   1.771 +   */
   1.772 +  TrackTicks GetBufferedTicks(TrackID aID);
   1.773 +
   1.774 +  void RegisterForAudioMixing();
   1.775 +
   1.776 +  // XXX need a Reset API
   1.777 +
   1.778 +  friend class MediaStreamGraphImpl;
   1.779 +
   1.780 +protected:
   1.781 +  struct ThreadAndRunnable {
   1.782 +    void Init(nsIEventTarget* aTarget, nsIRunnable* aRunnable)
   1.783 +    {
   1.784 +      mTarget = aTarget;
   1.785 +      mRunnable = aRunnable;
   1.786 +    }
   1.787 +
   1.788 +    nsCOMPtr<nsIEventTarget> mTarget;
   1.789 +    nsCOMPtr<nsIRunnable> mRunnable;
   1.790 +  };
   1.791 +  enum TrackCommands {
   1.792 +    TRACK_CREATE = MediaStreamListener::TRACK_EVENT_CREATED,
   1.793 +    TRACK_END = MediaStreamListener::TRACK_EVENT_ENDED
   1.794 +  };
   1.795 +  /**
   1.796 +   * Data for each track that hasn't ended.
   1.797 +   */
   1.798 +  struct TrackData {
   1.799 +    TrackID mID;
   1.800 +    // Sample rate of the input data.
   1.801 +    TrackRate mInputRate;
   1.802 +    // Sample rate of the output data, always equal to the sample rate of the
   1.803 +    // graph.
   1.804 +    TrackRate mOutputRate;
   1.805 +    // Resampler if the rate of the input track does not match the
   1.806 +    // MediaStreamGraph's.
   1.807 +    nsAutoRef<SpeexResamplerState> mResampler;
   1.808 +    TrackTicks mStart;
   1.809 +    // Each time the track updates are flushed to the media graph thread,
   1.810 +    // this is cleared.
   1.811 +    uint32_t mCommands;
   1.812 +    // Each time the track updates are flushed to the media graph thread,
   1.813 +    // the segment buffer is emptied.
   1.814 +    nsAutoPtr<MediaSegment> mData;
   1.815 +    nsTArray<ThreadAndRunnable> mDispatchWhenNotEnough;
   1.816 +    bool mHaveEnough;
   1.817 +  };
   1.818 +
   1.819 +  bool NeedsMixing();
   1.820 +
   1.821 +  void ResampleAudioToGraphSampleRate(TrackData* aTrackData, MediaSegment* aSegment);
   1.822 +
   1.823 +  TrackData* FindDataForTrack(TrackID aID)
   1.824 +  {
   1.825 +    for (uint32_t i = 0; i < mUpdateTracks.Length(); ++i) {
   1.826 +      if (mUpdateTracks[i].mID == aID) {
   1.827 +        return &mUpdateTracks[i];
   1.828 +      }
   1.829 +    }
   1.830 +    return nullptr;
   1.831 +  }
   1.832 +
   1.833 +  /**
   1.834 +   * Notify direct consumers of new data to one of the stream tracks.
   1.835 +   * The data doesn't have to be resampled (though it may be).  This is called
   1.836 +   * from AppendToTrack on the thread providing the data, and will call
   1.837 +   * the Listeners on this thread.
   1.838 +   */
   1.839 +  void NotifyDirectConsumers(TrackData *aTrack,
   1.840 +                             MediaSegment *aSegment);
   1.841 +
   1.842 +  // Media stream graph thread only
   1.843 +  MediaStreamListener::Consumption mLastConsumptionState;
   1.844 +
   1.845 +  // This must be acquired *before* MediaStreamGraphImpl's lock, if they are
   1.846 +  // held together.
   1.847 +  Mutex mMutex;
   1.848 +  // protected by mMutex
   1.849 +  StreamTime mUpdateKnownTracksTime;
   1.850 +  nsTArray<TrackData> mUpdateTracks;
   1.851 +  nsTArray<nsRefPtr<MediaStreamDirectListener> > mDirectListeners;
   1.852 +  bool mPullEnabled;
   1.853 +  bool mUpdateFinished;
   1.854 +  bool mNeedsMixing;
   1.855 +};
   1.856 +
   1.857 +/**
   1.858 + * Represents a connection between a ProcessedMediaStream and one of its
   1.859 + * input streams.
   1.860 + * We make these refcounted so that stream-related messages with MediaInputPort*
   1.861 + * pointers can be sent to the main thread safely.
   1.862 + *
   1.863 + * When a port's source or destination stream dies, the stream's DestroyImpl
   1.864 + * calls MediaInputPort::Disconnect to disconnect the port from
   1.865 + * the source and destination streams.
   1.866 + *
   1.867 + * The lifetimes of MediaInputPort are controlled from the main thread.
   1.868 + * The media graph adds a reference to the port. When a MediaInputPort is no
   1.869 + * longer needed, main-thread code sends a Destroy message for the port and
   1.870 + * clears its reference (the last main-thread reference to the object). When
   1.871 + * the Destroy message is processed on the graph manager thread we disconnect
   1.872 + * the port and drop the graph's reference, destroying the object.
   1.873 + */
   1.874 +class MediaInputPort MOZ_FINAL {
   1.875 +private:
   1.876 +  // Do not call this constructor directly. Instead call aDest->AllocateInputPort.
   1.877 +  MediaInputPort(MediaStream* aSource, ProcessedMediaStream* aDest,
   1.878 +                 uint32_t aFlags, uint16_t aInputNumber,
   1.879 +                 uint16_t aOutputNumber)
   1.880 +    : mSource(aSource)
   1.881 +    , mDest(aDest)
   1.882 +    , mFlags(aFlags)
   1.883 +    , mInputNumber(aInputNumber)
   1.884 +    , mOutputNumber(aOutputNumber)
   1.885 +    , mGraph(nullptr)
   1.886 +  {
   1.887 +    MOZ_COUNT_CTOR(MediaInputPort);
   1.888 +  }
   1.889 +
   1.890 +  // Private destructor, to discourage deletion outside of Release():
   1.891 +  ~MediaInputPort()
   1.892 +  {
   1.893 +    MOZ_COUNT_DTOR(MediaInputPort);
   1.894 +  }
   1.895 +
   1.896 +public:
   1.897 +  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaInputPort)
   1.898 +
   1.899 +  /**
   1.900 +   * The FLAG_BLOCK_INPUT and FLAG_BLOCK_OUTPUT flags can be used to control
   1.901 +   * exactly how the blocking statuses of the input and output streams affect
   1.902 +   * each other.
   1.903 +   */
   1.904 +  enum {
   1.905 +    // When set, blocking on the output stream forces blocking on the input
   1.906 +    // stream.
   1.907 +    FLAG_BLOCK_INPUT = 0x01,
   1.908 +    // When set, blocking on the input stream forces blocking on the output
   1.909 +    // stream.
   1.910 +    FLAG_BLOCK_OUTPUT = 0x02
   1.911 +  };
   1.912 +
   1.913 +  // Called on graph manager thread
   1.914 +  // Do not call these from outside MediaStreamGraph.cpp!
   1.915 +  void Init();
   1.916 +  // Called during message processing to trigger removal of this stream.
   1.917 +  void Disconnect();
   1.918 +
   1.919 +  // Control API
   1.920 +  /**
   1.921 +   * Disconnects and destroys the port. The caller must not reference this
   1.922 +   * object again.
   1.923 +   */
   1.924 +  void Destroy();
   1.925 +
   1.926 +  // Any thread
   1.927 +  MediaStream* GetSource() { return mSource; }
   1.928 +  ProcessedMediaStream* GetDestination() { return mDest; }
   1.929 +
   1.930 +  uint16_t InputNumber() const { return mInputNumber; }
   1.931 +  uint16_t OutputNumber() const { return mOutputNumber; }
   1.932 +
   1.933 +  // Call on graph manager thread
   1.934 +  struct InputInterval {
   1.935 +    GraphTime mStart;
   1.936 +    GraphTime mEnd;
   1.937 +    bool mInputIsBlocked;
   1.938 +  };
   1.939 +  // Find the next time interval starting at or after aTime during which
   1.940 +  // mDest is not blocked and mSource's blocking status does not change.
   1.941 +  InputInterval GetNextInputInterval(GraphTime aTime);
   1.942 +
   1.943 +  /**
   1.944 +   * Returns the graph that owns this port.
   1.945 +   */
   1.946 +  MediaStreamGraphImpl* GraphImpl();
   1.947 +  MediaStreamGraph* Graph();
   1.948 +  /**
   1.949 +   * Sets the graph that owns this stream.  Should only be called once.
   1.950 +   */
   1.951 +  void SetGraphImpl(MediaStreamGraphImpl* aGraph);
   1.952 +
   1.953 +  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   1.954 +  {
   1.955 +    size_t amount = 0;
   1.956 +
   1.957 +    // Not owned:
   1.958 +    // - mSource
   1.959 +    // - mDest
   1.960 +    // - mGraph
   1.961 +    return amount;
   1.962 +  }
   1.963 +
   1.964 +  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   1.965 +  {
   1.966 +    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   1.967 +  }
   1.968 +
   1.969 +private:
   1.970 +  friend class MediaStreamGraphImpl;
   1.971 +  friend class MediaStream;
   1.972 +  friend class ProcessedMediaStream;
   1.973 +  // Never modified after Init()
   1.974 +  MediaStream* mSource;
   1.975 +  ProcessedMediaStream* mDest;
   1.976 +  uint32_t mFlags;
   1.977 +  // The input and output numbers are optional, and are currently only used by
   1.978 +  // Web Audio.
   1.979 +  const uint16_t mInputNumber;
   1.980 +  const uint16_t mOutputNumber;
   1.981 +
   1.982 +  // Our media stream graph
   1.983 +  MediaStreamGraphImpl* mGraph;
   1.984 +};
   1.985 +
   1.986 +/**
   1.987 + * This stream processes zero or more input streams in parallel to produce
   1.988 + * its output. The details of how the output is produced are handled by
   1.989 + * subclasses overriding the ProcessInput method.
   1.990 + */
   1.991 +class ProcessedMediaStream : public MediaStream {
   1.992 +public:
   1.993 +  ProcessedMediaStream(DOMMediaStream* aWrapper)
   1.994 +    : MediaStream(aWrapper), mAutofinish(false), mInCycle(false)
   1.995 +  {}
   1.996 +
   1.997 +  // Control API.
   1.998 +  /**
   1.999 +   * Allocates a new input port attached to source aStream.
  1.1000 +   * This stream can be removed by calling MediaInputPort::Remove().
  1.1001 +   */
  1.1002 +  already_AddRefed<MediaInputPort> AllocateInputPort(MediaStream* aStream,
  1.1003 +                                                     uint32_t aFlags = 0,
  1.1004 +                                                     uint16_t aInputNumber = 0,
  1.1005 +                                                     uint16_t aOutputNumber = 0);
  1.1006 +  /**
  1.1007 +   * Force this stream into the finished state.
  1.1008 +   */
  1.1009 +  void Finish();
  1.1010 +  /**
  1.1011 +   * Set the autofinish flag on this stream (defaults to false). When this flag
  1.1012 +   * is set, and all input streams are in the finished state (including if there
  1.1013 +   * are no input streams), this stream automatically enters the finished state.
  1.1014 +   */
  1.1015 +  void SetAutofinish(bool aAutofinish);
  1.1016 +
  1.1017 +  virtual ProcessedMediaStream* AsProcessedStream() { return this; }
  1.1018 +
  1.1019 +  friend class MediaStreamGraphImpl;
  1.1020 +
  1.1021 +  // Do not call these from outside MediaStreamGraph.cpp!
  1.1022 +  virtual void AddInput(MediaInputPort* aPort);
  1.1023 +  virtual void RemoveInput(MediaInputPort* aPort)
  1.1024 +  {
  1.1025 +    mInputs.RemoveElement(aPort);
  1.1026 +  }
  1.1027 +  bool HasInputPort(MediaInputPort* aPort)
  1.1028 +  {
  1.1029 +    return mInputs.Contains(aPort);
  1.1030 +  }
  1.1031 +  uint32_t InputPortCount()
  1.1032 +  {
  1.1033 +    return mInputs.Length();
  1.1034 +  }
  1.1035 +  virtual void DestroyImpl();
  1.1036 +  /**
  1.1037 +   * This gets called after we've computed the blocking states for all
  1.1038 +   * streams (mBlocked is up to date up to mStateComputedTime).
  1.1039 +   * Also, we've produced output for all streams up to this one. If this stream
  1.1040 +   * is not in a cycle, then all its source streams have produced data.
  1.1041 +   * Generate output from aFrom to aTo.
  1.1042 +   * This will be called on streams that have finished. Most stream types should
  1.1043 +   * just return immediately if IsFinishedOnGraphThread(), but some may wish to
  1.1044 +   * update internal state (see AudioNodeStream).
  1.1045 +   * ProcessInput is allowed to call FinishOnGraphThread only if ALLOW_FINISH
  1.1046 +   * is in aFlags. (This flag will be set when aTo >= mStateComputedTime, i.e.
  1.1047 +   * when we've producing the last block of data we need to produce.) Otherwise
  1.1048 +   * we can get into a situation where we've determined the stream should not
  1.1049 +   * block before mStateComputedTime, but the stream finishes before
  1.1050 +   * mStateComputedTime, violating the invariant that finished streams are blocked.
  1.1051 +   */
  1.1052 +  enum {
  1.1053 +    ALLOW_FINISH = 0x01
  1.1054 +  };
  1.1055 +  virtual void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) = 0;
  1.1056 +  void SetAutofinishImpl(bool aAutofinish) { mAutofinish = aAutofinish; }
  1.1057 +
  1.1058 +  /**
  1.1059 +   * Forward SetTrackEnabled() to the input MediaStream(s) and translate the ID
  1.1060 +   */
  1.1061 +  virtual void ForwardTrackEnabled(TrackID aOutputID, bool aEnabled) {};
  1.1062 +
  1.1063 +  bool InCycle() const { return mInCycle; }
  1.1064 +
  1.1065 +  virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
  1.1066 +  {
  1.1067 +    size_t amount = MediaStream::SizeOfExcludingThis(aMallocSizeOf);
  1.1068 +    // Not owned:
  1.1069 +    // - mInputs elements
  1.1070 +    amount += mInputs.SizeOfExcludingThis(aMallocSizeOf);
  1.1071 +    return amount;
  1.1072 +  }
  1.1073 +
  1.1074 +  virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
  1.1075 +  {
  1.1076 +    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
  1.1077 +  }
  1.1078 +
  1.1079 +protected:
  1.1080 +  // This state is all accessed only on the media graph thread.
  1.1081 +
  1.1082 +  // The list of all inputs that are currently enabled or waiting to be enabled.
  1.1083 +  nsTArray<MediaInputPort*> mInputs;
  1.1084 +  bool mAutofinish;
  1.1085 +  // True if and only if this stream is in a cycle.
  1.1086 +  // Updated by MediaStreamGraphImpl::UpdateStreamOrder.
  1.1087 +  bool mInCycle;
  1.1088 +};
  1.1089 +
  1.1090 +/**
  1.1091 + * Initially, at least, we will have a singleton MediaStreamGraph per
  1.1092 + * process.  Each OfflineAudioContext object creates its own MediaStreamGraph
  1.1093 + * object too.
  1.1094 + */
  1.1095 +class MediaStreamGraph {
  1.1096 +public:
  1.1097 +  // We ensure that the graph current time advances in multiples of
  1.1098 +  // IdealAudioBlockSize()/AudioStream::PreferredSampleRate(). A stream that
  1.1099 +  // never blocks and has a track with the ideal audio rate will produce audio
  1.1100 +  // in multiples of the block size.
  1.1101 +
  1.1102 +  // Main thread only
  1.1103 +  static MediaStreamGraph* GetInstance();
  1.1104 +  static MediaStreamGraph* CreateNonRealtimeInstance(TrackRate aSampleRate);
  1.1105 +  // Idempotent
  1.1106 +  static void DestroyNonRealtimeInstance(MediaStreamGraph* aGraph);
  1.1107 +
  1.1108 +  // Control API.
  1.1109 +  /**
  1.1110 +   * Create a stream that a media decoder (or some other source of
  1.1111 +   * media data, such as a camera) can write to.
  1.1112 +   */
  1.1113 +  SourceMediaStream* CreateSourceStream(DOMMediaStream* aWrapper);
  1.1114 +  /**
  1.1115 +   * Create a stream that will form the union of the tracks of its input
  1.1116 +   * streams.
  1.1117 +   * A TrackUnionStream contains all the tracks of all its input streams.
  1.1118 +   * Adding a new input stream makes that stream's tracks immediately appear as new
  1.1119 +   * tracks starting at the time the input stream was added.
  1.1120 +   * Removing an input stream makes the output tracks corresponding to the
  1.1121 +   * removed tracks immediately end.
  1.1122 +   * For each added track, the track ID of the output track is the track ID
  1.1123 +   * of the input track or one plus the maximum ID of all previously added
  1.1124 +   * tracks, whichever is greater.
  1.1125 +   * TODO at some point we will probably need to add API to select
  1.1126 +   * particular tracks of each input stream.
  1.1127 +   */
  1.1128 +  ProcessedMediaStream* CreateTrackUnionStream(DOMMediaStream* aWrapper);
  1.1129 +  // Internal AudioNodeStreams can only pass their output to another
  1.1130 +  // AudioNode, whereas external AudioNodeStreams can pass their output
  1.1131 +  // to an nsAudioStream for playback.
  1.1132 +  enum AudioNodeStreamKind { SOURCE_STREAM, INTERNAL_STREAM, EXTERNAL_STREAM };
  1.1133 +  /**
  1.1134 +   * Create a stream that will process audio for an AudioNode.
  1.1135 +   * Takes ownership of aEngine.  aSampleRate is the sampling rate used
  1.1136 +   * for the stream.  If 0 is passed, the sampling rate of the engine's
  1.1137 +   * node will get used.
  1.1138 +   */
  1.1139 +  AudioNodeStream* CreateAudioNodeStream(AudioNodeEngine* aEngine,
  1.1140 +                                         AudioNodeStreamKind aKind,
  1.1141 +                                         TrackRate aSampleRate = 0);
  1.1142 +
  1.1143 +  AudioNodeExternalInputStream*
  1.1144 +  CreateAudioNodeExternalInputStream(AudioNodeEngine* aEngine,
  1.1145 +                                     TrackRate aSampleRate = 0);
  1.1146 +
  1.1147 +  bool IsNonRealtime() const;
  1.1148 +  /**
  1.1149 +   * Start processing non-realtime for a specific number of ticks.
  1.1150 +   */
  1.1151 +  void StartNonRealtimeProcessing(TrackRate aRate, uint32_t aTicksToProcess);
  1.1152 +
  1.1153 +  /**
  1.1154 +   * Media graph thread only.
  1.1155 +   * Dispatches a runnable that will run on the main thread after all
  1.1156 +   * main-thread stream state has been next updated.
  1.1157 +   * Should only be called during MediaStreamListener callbacks or during
  1.1158 +   * ProcessedMediaStream::ProcessInput().
  1.1159 +   */
  1.1160 +  void DispatchToMainThreadAfterStreamStateUpdate(already_AddRefed<nsIRunnable> aRunnable)
  1.1161 +  {
  1.1162 +    *mPendingUpdateRunnables.AppendElement() = aRunnable;
  1.1163 +  }
  1.1164 +
  1.1165 +protected:
  1.1166 +  MediaStreamGraph()
  1.1167 +    : mNextGraphUpdateIndex(1)
  1.1168 +  {
  1.1169 +    MOZ_COUNT_CTOR(MediaStreamGraph);
  1.1170 +  }
  1.1171 +  virtual ~MediaStreamGraph()
  1.1172 +  {
  1.1173 +    MOZ_COUNT_DTOR(MediaStreamGraph);
  1.1174 +  }
  1.1175 +
  1.1176 +  // Media graph thread only
  1.1177 +  nsTArray<nsCOMPtr<nsIRunnable> > mPendingUpdateRunnables;
  1.1178 +
  1.1179 +  // Main thread only
  1.1180 +  // The number of updates we have sent to the media graph thread + 1.
  1.1181 +  // We start this at 1 just to ensure that 0 is usable as a special value.
  1.1182 +  int64_t mNextGraphUpdateIndex;
  1.1183 +};
  1.1184 +
  1.1185 +}
  1.1186 +
  1.1187 +#endif /* MOZILLA_MEDIASTREAMGRAPH_H_ */

mercurial