content/media/MediaStreamGraphImpl.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.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #ifndef MOZILLA_MEDIASTREAMGRAPHIMPL_H_
michael@0 7 #define MOZILLA_MEDIASTREAMGRAPHIMPL_H_
michael@0 8
michael@0 9 #include "MediaStreamGraph.h"
michael@0 10
michael@0 11 #include "mozilla/Monitor.h"
michael@0 12 #include "mozilla/TimeStamp.h"
michael@0 13 #include "nsIMemoryReporter.h"
michael@0 14 #include "nsIThread.h"
michael@0 15 #include "nsIRunnable.h"
michael@0 16 #include "Latency.h"
michael@0 17 #include "mozilla/WeakPtr.h"
michael@0 18
michael@0 19 namespace mozilla {
michael@0 20
michael@0 21 template <typename T>
michael@0 22 class LinkedList;
michael@0 23
michael@0 24 class AudioMixer;
michael@0 25
michael@0 26 /**
michael@0 27 * Assume we can run an iteration of the MediaStreamGraph loop in this much time
michael@0 28 * or less.
michael@0 29 * We try to run the control loop at this rate.
michael@0 30 */
michael@0 31 static const int MEDIA_GRAPH_TARGET_PERIOD_MS = 10;
michael@0 32
michael@0 33 /**
michael@0 34 * Assume that we might miss our scheduled wakeup of the MediaStreamGraph by
michael@0 35 * this much.
michael@0 36 */
michael@0 37 static const int SCHEDULE_SAFETY_MARGIN_MS = 10;
michael@0 38
michael@0 39 /**
michael@0 40 * Try have this much audio buffered in streams and queued to the hardware.
michael@0 41 * The maximum delay to the end of the next control loop
michael@0 42 * is 2*MEDIA_GRAPH_TARGET_PERIOD_MS + SCHEDULE_SAFETY_MARGIN_MS.
michael@0 43 * There is no point in buffering more audio than this in a stream at any
michael@0 44 * given time (until we add processing).
michael@0 45 * This is not optimal yet.
michael@0 46 */
michael@0 47 static const int AUDIO_TARGET_MS = 2*MEDIA_GRAPH_TARGET_PERIOD_MS +
michael@0 48 SCHEDULE_SAFETY_MARGIN_MS;
michael@0 49
michael@0 50 /**
michael@0 51 * Try have this much video buffered. Video frames are set
michael@0 52 * near the end of the iteration of the control loop. The maximum delay
michael@0 53 * to the setting of the next video frame is 2*MEDIA_GRAPH_TARGET_PERIOD_MS +
michael@0 54 * SCHEDULE_SAFETY_MARGIN_MS. This is not optimal yet.
michael@0 55 */
michael@0 56 static const int VIDEO_TARGET_MS = 2*MEDIA_GRAPH_TARGET_PERIOD_MS +
michael@0 57 SCHEDULE_SAFETY_MARGIN_MS;
michael@0 58
michael@0 59 /**
michael@0 60 * A per-stream update message passed from the media graph thread to the
michael@0 61 * main thread.
michael@0 62 */
michael@0 63 struct StreamUpdate {
michael@0 64 int64_t mGraphUpdateIndex;
michael@0 65 nsRefPtr<MediaStream> mStream;
michael@0 66 StreamTime mNextMainThreadCurrentTime;
michael@0 67 bool mNextMainThreadFinished;
michael@0 68 };
michael@0 69
michael@0 70 /**
michael@0 71 * This represents a message passed from the main thread to the graph thread.
michael@0 72 * A ControlMessage always has a weak reference a particular affected stream.
michael@0 73 */
michael@0 74 class ControlMessage {
michael@0 75 public:
michael@0 76 explicit ControlMessage(MediaStream* aStream) : mStream(aStream)
michael@0 77 {
michael@0 78 MOZ_COUNT_CTOR(ControlMessage);
michael@0 79 }
michael@0 80 // All these run on the graph thread
michael@0 81 virtual ~ControlMessage()
michael@0 82 {
michael@0 83 MOZ_COUNT_DTOR(ControlMessage);
michael@0 84 }
michael@0 85 // Do the action of this message on the MediaStreamGraph thread. Any actions
michael@0 86 // affecting graph processing should take effect at mStateComputedTime.
michael@0 87 // All stream data for times < mStateComputedTime has already been
michael@0 88 // computed.
michael@0 89 virtual void Run() = 0;
michael@0 90 // When we're shutting down the application, most messages are ignored but
michael@0 91 // some cleanup messages should still be processed (on the main thread).
michael@0 92 // This must not add new control messages to the graph.
michael@0 93 virtual void RunDuringShutdown() {}
michael@0 94 MediaStream* GetStream() { return mStream; }
michael@0 95
michael@0 96 protected:
michael@0 97 // We do not hold a reference to mStream. The graph will be holding
michael@0 98 // a reference to the stream until the Destroy message is processed. The
michael@0 99 // last message referencing a stream is the Destroy message for that stream.
michael@0 100 MediaStream* mStream;
michael@0 101 };
michael@0 102
michael@0 103 /**
michael@0 104 * The implementation of a media stream graph. This class is private to this
michael@0 105 * file. It's not in the anonymous namespace because MediaStream needs to
michael@0 106 * be able to friend it.
michael@0 107 *
michael@0 108 * Currently we have one global instance per process, and one per each
michael@0 109 * OfflineAudioContext object.
michael@0 110 */
michael@0 111 class MediaStreamGraphImpl : public MediaStreamGraph,
michael@0 112 public nsIMemoryReporter {
michael@0 113 public:
michael@0 114 NS_DECL_ISUPPORTS
michael@0 115 NS_DECL_NSIMEMORYREPORTER
michael@0 116
michael@0 117 /**
michael@0 118 * Set aRealtime to true in order to create a MediaStreamGraph which provides
michael@0 119 * support for real-time audio and video. Set it to false in order to create
michael@0 120 * a non-realtime instance which just churns through its inputs and produces
michael@0 121 * output. Those objects currently only support audio, and are used to
michael@0 122 * implement OfflineAudioContext. They do not support MediaStream inputs.
michael@0 123 */
michael@0 124 explicit MediaStreamGraphImpl(bool aRealtime, TrackRate aSampleRate);
michael@0 125
michael@0 126 /**
michael@0 127 * Unregisters memory reporting and deletes this instance. This should be
michael@0 128 * called instead of calling the destructor directly.
michael@0 129 */
michael@0 130 void Destroy();
michael@0 131
michael@0 132 // Main thread only.
michael@0 133 /**
michael@0 134 * This runs every time we need to sync state from the media graph thread
michael@0 135 * to the main thread while the main thread is not in the middle
michael@0 136 * of a script. It runs during a "stable state" (per HTML5) or during
michael@0 137 * an event posted to the main thread.
michael@0 138 */
michael@0 139 void RunInStableState();
michael@0 140 /**
michael@0 141 * Ensure a runnable to run RunInStableState is posted to the appshell to
michael@0 142 * run at the next stable state (per HTML5).
michael@0 143 * See EnsureStableStateEventPosted.
michael@0 144 */
michael@0 145 void EnsureRunInStableState();
michael@0 146 /**
michael@0 147 * Called to apply a StreamUpdate to its stream.
michael@0 148 */
michael@0 149 void ApplyStreamUpdate(StreamUpdate* aUpdate);
michael@0 150 /**
michael@0 151 * Append a ControlMessage to the message queue. This queue is drained
michael@0 152 * during RunInStableState; the messages will run on the graph thread.
michael@0 153 */
michael@0 154 void AppendMessage(ControlMessage* aMessage);
michael@0 155 /**
michael@0 156 * Make this MediaStreamGraph enter forced-shutdown state. This state
michael@0 157 * will be noticed by the media graph thread, which will shut down all streams
michael@0 158 * and other state controlled by the media graph thread.
michael@0 159 * This is called during application shutdown.
michael@0 160 */
michael@0 161 void ForceShutDown();
michael@0 162 /**
michael@0 163 * Shutdown() this MediaStreamGraph's threads and return when they've shut down.
michael@0 164 */
michael@0 165 void ShutdownThreads();
michael@0 166
michael@0 167 /**
michael@0 168 * Called before the thread runs.
michael@0 169 */
michael@0 170 void Init();
michael@0 171 // The following methods run on the graph thread (or possibly the main thread if
michael@0 172 // mLifecycleState > LIFECYCLE_RUNNING)
michael@0 173 /**
michael@0 174 * Runs main control loop on the graph thread. Normally a single invocation
michael@0 175 * of this runs for the entire lifetime of the graph thread.
michael@0 176 */
michael@0 177 void RunThread();
michael@0 178 /**
michael@0 179 * Call this to indicate that another iteration of the control loop is
michael@0 180 * required on its regular schedule. The monitor must not be held.
michael@0 181 */
michael@0 182 void EnsureNextIteration();
michael@0 183 /**
michael@0 184 * As above, but with the monitor already held.
michael@0 185 */
michael@0 186 void EnsureNextIterationLocked(MonitorAutoLock& aLock);
michael@0 187 /**
michael@0 188 * Call this to indicate that another iteration of the control loop is
michael@0 189 * required immediately. The monitor must already be held.
michael@0 190 */
michael@0 191 void EnsureImmediateWakeUpLocked(MonitorAutoLock& aLock);
michael@0 192 /**
michael@0 193 * Ensure there is an event posted to the main thread to run RunInStableState.
michael@0 194 * mMonitor must be held.
michael@0 195 * See EnsureRunInStableState
michael@0 196 */
michael@0 197 void EnsureStableStateEventPosted();
michael@0 198 /**
michael@0 199 * Generate messages to the main thread to update it for all state changes.
michael@0 200 * mMonitor must be held.
michael@0 201 */
michael@0 202 void PrepareUpdatesToMainThreadState(bool aFinalUpdate);
michael@0 203 /**
michael@0 204 * Returns false if there is any stream that has finished but not yet finished
michael@0 205 * playing out.
michael@0 206 */
michael@0 207 bool AllFinishedStreamsNotified();
michael@0 208 /**
michael@0 209 * If we are rendering in non-realtime mode, we don't want to send messages to
michael@0 210 * the main thread at each iteration for performance reasons. We instead
michael@0 211 * notify the main thread at the same rate
michael@0 212 */
michael@0 213 bool ShouldUpdateMainThread();
michael@0 214 // The following methods are the various stages of RunThread processing.
michael@0 215 /**
michael@0 216 * Compute a new current time for the graph and advance all on-graph-thread
michael@0 217 * state to the new current time.
michael@0 218 */
michael@0 219 void UpdateCurrentTime();
michael@0 220 /**
michael@0 221 * Update the consumption state of aStream to reflect whether its data
michael@0 222 * is needed or not.
michael@0 223 */
michael@0 224 void UpdateConsumptionState(SourceMediaStream* aStream);
michael@0 225 /**
michael@0 226 * Extract any state updates pending in aStream, and apply them.
michael@0 227 */
michael@0 228 void ExtractPendingInput(SourceMediaStream* aStream,
michael@0 229 GraphTime aDesiredUpToTime,
michael@0 230 bool* aEnsureNextIteration);
michael@0 231 /**
michael@0 232 * Update "have enough data" flags in aStream.
michael@0 233 */
michael@0 234 void UpdateBufferSufficiencyState(SourceMediaStream* aStream);
michael@0 235 /*
michael@0 236 * If aStream hasn't already been ordered, push it onto aStack and order
michael@0 237 * its children.
michael@0 238 */
michael@0 239 void UpdateStreamOrderForStream(mozilla::LinkedList<MediaStream>* aStack,
michael@0 240 already_AddRefed<MediaStream> aStream);
michael@0 241 /**
michael@0 242 * Mark aStream and all its inputs (recursively) as consumed.
michael@0 243 */
michael@0 244 static void MarkConsumed(MediaStream* aStream);
michael@0 245 /**
michael@0 246 * Sort mStreams so that every stream not in a cycle is after any streams
michael@0 247 * it depends on, and every stream in a cycle is marked as being in a cycle.
michael@0 248 * Also sets mIsConsumed on every stream.
michael@0 249 */
michael@0 250 void UpdateStreamOrder();
michael@0 251 /**
michael@0 252 * Compute the blocking states of streams from mStateComputedTime
michael@0 253 * until the desired future time aEndBlockingDecisions.
michael@0 254 * Updates mStateComputedTime and sets MediaStream::mBlocked
michael@0 255 * for all streams.
michael@0 256 */
michael@0 257 void RecomputeBlocking(GraphTime aEndBlockingDecisions);
michael@0 258 // The following methods are used to help RecomputeBlocking.
michael@0 259 /**
michael@0 260 * If aStream isn't already in aStreams, add it and recursively call
michael@0 261 * AddBlockingRelatedStreamsToSet on all the streams whose blocking
michael@0 262 * status could depend on or affect the state of aStream.
michael@0 263 */
michael@0 264 void AddBlockingRelatedStreamsToSet(nsTArray<MediaStream*>* aStreams,
michael@0 265 MediaStream* aStream);
michael@0 266 /**
michael@0 267 * Mark a stream blocked at time aTime. If this results in decisions that need
michael@0 268 * to be revisited at some point in the future, *aEnd will be reduced to the
michael@0 269 * first time in the future to recompute those decisions.
michael@0 270 */
michael@0 271 void MarkStreamBlocking(MediaStream* aStream);
michael@0 272 /**
michael@0 273 * Recompute blocking for the streams in aStreams for the interval starting at aTime.
michael@0 274 * If this results in decisions that need to be revisited at some point
michael@0 275 * in the future, *aEnd will be reduced to the first time in the future to
michael@0 276 * recompute those decisions.
michael@0 277 */
michael@0 278 void RecomputeBlockingAt(const nsTArray<MediaStream*>& aStreams,
michael@0 279 GraphTime aTime, GraphTime aEndBlockingDecisions,
michael@0 280 GraphTime* aEnd);
michael@0 281 /**
michael@0 282 * Produce data for all streams >= aStreamIndex for the given time interval.
michael@0 283 * Advances block by block, each iteration producing data for all streams
michael@0 284 * for a single block.
michael@0 285 * This is called whenever we have an AudioNodeStream in the graph.
michael@0 286 */
michael@0 287 void ProduceDataForStreamsBlockByBlock(uint32_t aStreamIndex,
michael@0 288 TrackRate aSampleRate,
michael@0 289 GraphTime aFrom,
michael@0 290 GraphTime aTo);
michael@0 291 /**
michael@0 292 * Returns true if aStream will underrun at aTime for its own playback.
michael@0 293 * aEndBlockingDecisions is when we plan to stop making blocking decisions.
michael@0 294 * *aEnd will be reduced to the first time in the future to recompute these
michael@0 295 * decisions.
michael@0 296 */
michael@0 297 bool WillUnderrun(MediaStream* aStream, GraphTime aTime,
michael@0 298 GraphTime aEndBlockingDecisions, GraphTime* aEnd);
michael@0 299 /**
michael@0 300 * Given a graph time aTime, convert it to a stream time taking into
michael@0 301 * account the time during which aStream is scheduled to be blocked.
michael@0 302 */
michael@0 303 StreamTime GraphTimeToStreamTime(MediaStream* aStream, GraphTime aTime);
michael@0 304 /**
michael@0 305 * Given a graph time aTime, convert it to a stream time taking into
michael@0 306 * account the time during which aStream is scheduled to be blocked, and
michael@0 307 * when we don't know whether it's blocked or not, we assume it's not blocked.
michael@0 308 */
michael@0 309 StreamTime GraphTimeToStreamTimeOptimistic(MediaStream* aStream, GraphTime aTime);
michael@0 310 enum {
michael@0 311 INCLUDE_TRAILING_BLOCKED_INTERVAL = 0x01
michael@0 312 };
michael@0 313 /**
michael@0 314 * Given a stream time aTime, convert it to a graph time taking into
michael@0 315 * account the time during which aStream is scheduled to be blocked.
michael@0 316 * aTime must be <= mStateComputedTime since blocking decisions
michael@0 317 * are only known up to that point.
michael@0 318 * If aTime is exactly at the start of a blocked interval, then the blocked
michael@0 319 * interval is included in the time returned if and only if
michael@0 320 * aFlags includes INCLUDE_TRAILING_BLOCKED_INTERVAL.
michael@0 321 */
michael@0 322 GraphTime StreamTimeToGraphTime(MediaStream* aStream, StreamTime aTime,
michael@0 323 uint32_t aFlags = 0);
michael@0 324 /**
michael@0 325 * Get the current audio position of the stream's audio output.
michael@0 326 */
michael@0 327 GraphTime GetAudioPosition(MediaStream* aStream);
michael@0 328 /**
michael@0 329 * Call NotifyHaveCurrentData on aStream's listeners.
michael@0 330 */
michael@0 331 void NotifyHasCurrentData(MediaStream* aStream);
michael@0 332 /**
michael@0 333 * If aStream needs an audio stream but doesn't have one, create it.
michael@0 334 * If aStream doesn't need an audio stream but has one, destroy it.
michael@0 335 */
michael@0 336 void CreateOrDestroyAudioStreams(GraphTime aAudioOutputStartTime,
michael@0 337 MediaStream* aStream);
michael@0 338 /**
michael@0 339 * Queue audio (mix of stream audio and silence for blocked intervals)
michael@0 340 * to the audio output stream. Returns the number of frames played.
michael@0 341 */
michael@0 342 TrackTicks PlayAudio(MediaStream* aStream, GraphTime aFrom, GraphTime aTo);
michael@0 343 /**
michael@0 344 * Set the correct current video frame for stream aStream.
michael@0 345 */
michael@0 346 void PlayVideo(MediaStream* aStream);
michael@0 347 /**
michael@0 348 * No more data will be forthcoming for aStream. The stream will end
michael@0 349 * at the current buffer end point. The StreamBuffer's tracks must be
michael@0 350 * explicitly set to finished by the caller.
michael@0 351 */
michael@0 352 void FinishStream(MediaStream* aStream);
michael@0 353 /**
michael@0 354 * Compute how much stream data we would like to buffer for aStream.
michael@0 355 */
michael@0 356 StreamTime GetDesiredBufferEnd(MediaStream* aStream);
michael@0 357 /**
michael@0 358 * Returns true when there are no active streams.
michael@0 359 */
michael@0 360 bool IsEmpty() { return mStreams.IsEmpty() && mPortCount == 0; }
michael@0 361
michael@0 362 // For use by control messages, on graph thread only.
michael@0 363 /**
michael@0 364 * Identify which graph update index we are currently processing.
michael@0 365 */
michael@0 366 int64_t GetProcessingGraphUpdateIndex() { return mProcessingGraphUpdateIndex; }
michael@0 367 /**
michael@0 368 * Add aStream to the graph and initializes its graph-specific state.
michael@0 369 */
michael@0 370 void AddStream(MediaStream* aStream);
michael@0 371 /**
michael@0 372 * Remove aStream from the graph. Ensures that pending messages about the
michael@0 373 * stream back to the main thread are flushed.
michael@0 374 */
michael@0 375 void RemoveStream(MediaStream* aStream);
michael@0 376 /**
michael@0 377 * Remove aPort from the graph and release it.
michael@0 378 */
michael@0 379 void DestroyPort(MediaInputPort* aPort);
michael@0 380 /**
michael@0 381 * Mark the media stream order as dirty.
michael@0 382 */
michael@0 383 void SetStreamOrderDirty()
michael@0 384 {
michael@0 385 mStreamOrderDirty = true;
michael@0 386 }
michael@0 387 /**
michael@0 388 * Pause all AudioStreams being written to by MediaStreams
michael@0 389 */
michael@0 390 void PauseAllAudioOutputs();
michael@0 391 /**
michael@0 392 * Resume all AudioStreams being written to by MediaStreams
michael@0 393 */
michael@0 394 void ResumeAllAudioOutputs();
michael@0 395
michael@0 396 TrackRate AudioSampleRate() { return mSampleRate; }
michael@0 397
michael@0 398 // Data members
michael@0 399
michael@0 400 /**
michael@0 401 * Media graph thread.
michael@0 402 * Readonly after initialization on the main thread.
michael@0 403 */
michael@0 404 nsCOMPtr<nsIThread> mThread;
michael@0 405
michael@0 406 // The following state is managed on the graph thread only, unless
michael@0 407 // mLifecycleState > LIFECYCLE_RUNNING in which case the graph thread
michael@0 408 // is not running and this state can be used from the main thread.
michael@0 409
michael@0 410 nsTArray<nsRefPtr<MediaStream> > mStreams;
michael@0 411 /**
michael@0 412 * mOldStreams is used as temporary storage for streams when computing the
michael@0 413 * order in which we compute them.
michael@0 414 */
michael@0 415 nsTArray<nsRefPtr<MediaStream> > mOldStreams;
michael@0 416 /**
michael@0 417 * The current graph time for the current iteration of the RunThread control
michael@0 418 * loop.
michael@0 419 */
michael@0 420 GraphTime mCurrentTime;
michael@0 421 /**
michael@0 422 * Blocking decisions and all stream contents have been computed up to this
michael@0 423 * time. The next batch of updates from the main thread will be processed
michael@0 424 * at this time. Always >= mCurrentTime.
michael@0 425 */
michael@0 426 GraphTime mStateComputedTime;
michael@0 427 /**
michael@0 428 * This is only used for logging.
michael@0 429 */
michael@0 430 TimeStamp mInitialTimeStamp;
michael@0 431 /**
michael@0 432 * The real timestamp of the latest run of UpdateCurrentTime.
michael@0 433 */
michael@0 434 TimeStamp mCurrentTimeStamp;
michael@0 435 /**
michael@0 436 * Date of the last time we updated the main thread with the graph state.
michael@0 437 */
michael@0 438 TimeStamp mLastMainThreadUpdate;
michael@0 439 /**
michael@0 440 * Which update batch we are currently processing.
michael@0 441 */
michael@0 442 int64_t mProcessingGraphUpdateIndex;
michael@0 443 /**
michael@0 444 * Number of active MediaInputPorts
michael@0 445 */
michael@0 446 int32_t mPortCount;
michael@0 447
michael@0 448 // mMonitor guards the data below.
michael@0 449 // MediaStreamGraph normally does its work without holding mMonitor, so it is
michael@0 450 // not safe to just grab mMonitor from some thread and start monkeying with
michael@0 451 // the graph. Instead, communicate with the graph thread using provided
michael@0 452 // mechanisms such as the ControlMessage queue.
michael@0 453 Monitor mMonitor;
michael@0 454
michael@0 455 // Data guarded by mMonitor (must always be accessed with mMonitor held,
michael@0 456 // regardless of the value of mLifecycleState.
michael@0 457
michael@0 458 /**
michael@0 459 * State to copy to main thread
michael@0 460 */
michael@0 461 nsTArray<StreamUpdate> mStreamUpdates;
michael@0 462 /**
michael@0 463 * Runnables to run after the next update to main thread state.
michael@0 464 */
michael@0 465 nsTArray<nsCOMPtr<nsIRunnable> > mUpdateRunnables;
michael@0 466 struct MessageBlock {
michael@0 467 int64_t mGraphUpdateIndex;
michael@0 468 nsTArray<nsAutoPtr<ControlMessage> > mMessages;
michael@0 469 };
michael@0 470 /**
michael@0 471 * A list of batches of messages to process. Each batch is processed
michael@0 472 * as an atomic unit.
michael@0 473 */
michael@0 474 nsTArray<MessageBlock> mMessageQueue;
michael@0 475 /**
michael@0 476 * This enum specifies where this graph is in its lifecycle. This is used
michael@0 477 * to control shutdown.
michael@0 478 * Shutdown is tricky because it can happen in two different ways:
michael@0 479 * 1) Shutdown due to inactivity. RunThread() detects that it has no
michael@0 480 * pending messages and no streams, and exits. The next RunInStableState()
michael@0 481 * checks if there are new pending messages from the main thread (true only
michael@0 482 * if new stream creation raced with shutdown); if there are, it revives
michael@0 483 * RunThread(), otherwise it commits to shutting down the graph. New stream
michael@0 484 * creation after this point will create a new graph. An async event is
michael@0 485 * dispatched to Shutdown() the graph's threads and then delete the graph
michael@0 486 * object.
michael@0 487 * 2) Forced shutdown at application shutdown, or completion of a
michael@0 488 * non-realtime graph. A flag is set, RunThread() detects the flag and
michael@0 489 * exits, the next RunInStableState() detects the flag, and dispatches the
michael@0 490 * async event to Shutdown() the graph's threads. However the graph object
michael@0 491 * is not deleted. New messages for the graph are processed synchronously on
michael@0 492 * the main thread if necessary. When the last stream is destroyed, the
michael@0 493 * graph object is deleted.
michael@0 494 */
michael@0 495 enum LifecycleState {
michael@0 496 // The graph thread hasn't started yet.
michael@0 497 LIFECYCLE_THREAD_NOT_STARTED,
michael@0 498 // RunThread() is running normally.
michael@0 499 LIFECYCLE_RUNNING,
michael@0 500 // In the following states, the graph thread is not running so
michael@0 501 // all "graph thread only" state in this class can be used safely
michael@0 502 // on the main thread.
michael@0 503 // RunThread() has exited and we're waiting for the next
michael@0 504 // RunInStableState(), at which point we can clean up the main-thread
michael@0 505 // side of the graph.
michael@0 506 LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP,
michael@0 507 // RunInStableState() posted a ShutdownRunnable, and we're waiting for it
michael@0 508 // to shut down the graph thread(s).
michael@0 509 LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN,
michael@0 510 // Graph threads have shut down but we're waiting for remaining streams
michael@0 511 // to be destroyed. Only happens during application shutdown and on
michael@0 512 // completed non-realtime graphs, since normally we'd only shut down a
michael@0 513 // realtime graph when it has no streams.
michael@0 514 LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION
michael@0 515 };
michael@0 516 LifecycleState mLifecycleState;
michael@0 517 /**
michael@0 518 * This enum specifies the wait state of the graph thread.
michael@0 519 */
michael@0 520 enum WaitState {
michael@0 521 // RunThread() is running normally
michael@0 522 WAITSTATE_RUNNING,
michael@0 523 // RunThread() is paused waiting for its next iteration, which will
michael@0 524 // happen soon
michael@0 525 WAITSTATE_WAITING_FOR_NEXT_ITERATION,
michael@0 526 // RunThread() is paused indefinitely waiting for something to change
michael@0 527 WAITSTATE_WAITING_INDEFINITELY,
michael@0 528 // Something has signaled RunThread() to wake up immediately,
michael@0 529 // but it hasn't done so yet
michael@0 530 WAITSTATE_WAKING_UP
michael@0 531 };
michael@0 532 WaitState mWaitState;
michael@0 533 /**
michael@0 534 * The graph should stop processing at or after this time.
michael@0 535 */
michael@0 536 GraphTime mEndTime;
michael@0 537
michael@0 538 /**
michael@0 539 * Sample rate at which this graph runs. For real time graphs, this is
michael@0 540 * the rate of the audio mixer. For offline graphs, this is the rate specified
michael@0 541 * at construction.
michael@0 542 */
michael@0 543 TrackRate mSampleRate;
michael@0 544 /**
michael@0 545 * True when another iteration of the control loop is required.
michael@0 546 */
michael@0 547 bool mNeedAnotherIteration;
michael@0 548 /**
michael@0 549 * True when we need to do a forced shutdown during application shutdown.
michael@0 550 */
michael@0 551 bool mForceShutDown;
michael@0 552 /**
michael@0 553 * True when we have posted an event to the main thread to run
michael@0 554 * RunInStableState() and the event hasn't run yet.
michael@0 555 */
michael@0 556 bool mPostedRunInStableStateEvent;
michael@0 557
michael@0 558 // Main thread only
michael@0 559
michael@0 560 /**
michael@0 561 * Messages posted by the current event loop task. These are forwarded to
michael@0 562 * the media graph thread during RunInStableState. We can't forward them
michael@0 563 * immediately because we want all messages between stable states to be
michael@0 564 * processed as an atomic batch.
michael@0 565 */
michael@0 566 nsTArray<nsAutoPtr<ControlMessage> > mCurrentTaskMessageQueue;
michael@0 567 /**
michael@0 568 * True when RunInStableState has determined that mLifecycleState is >
michael@0 569 * LIFECYCLE_RUNNING. Since only the main thread can reset mLifecycleState to
michael@0 570 * LIFECYCLE_RUNNING, this can be relied on to not change unexpectedly.
michael@0 571 */
michael@0 572 bool mDetectedNotRunning;
michael@0 573 /**
michael@0 574 * True when a stable state runner has been posted to the appshell to run
michael@0 575 * RunInStableState at the next stable state.
michael@0 576 */
michael@0 577 bool mPostedRunInStableState;
michael@0 578 /**
michael@0 579 * True when processing real-time audio/video. False when processing non-realtime
michael@0 580 * audio.
michael@0 581 */
michael@0 582 bool mRealtime;
michael@0 583 /**
michael@0 584 * True when a non-realtime MediaStreamGraph has started to process input. This
michael@0 585 * value is only accessed on the main thread.
michael@0 586 */
michael@0 587 bool mNonRealtimeProcessing;
michael@0 588 /**
michael@0 589 * True when a change has happened which requires us to recompute the stream
michael@0 590 * blocking order.
michael@0 591 */
michael@0 592 bool mStreamOrderDirty;
michael@0 593 /**
michael@0 594 * Hold a ref to the Latency logger
michael@0 595 */
michael@0 596 nsRefPtr<AsyncLatencyLogger> mLatencyLog;
michael@0 597 /**
michael@0 598 * If this is not null, all the audio output for the MSG will be mixed down.
michael@0 599 */
michael@0 600 nsAutoPtr<AudioMixer> mMixer;
michael@0 601
michael@0 602 private:
michael@0 603 virtual ~MediaStreamGraphImpl();
michael@0 604
michael@0 605 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
michael@0 606
michael@0 607 /**
michael@0 608 * Used to signal that a memory report has been requested.
michael@0 609 */
michael@0 610 Monitor mMemoryReportMonitor;
michael@0 611 /**
michael@0 612 * This class uses manual memory management, and all pointers to it are raw
michael@0 613 * pointers. However, in order for it to implement nsIMemoryReporter, it needs
michael@0 614 * to implement nsISupports and so be ref-counted. So it maintains a single
michael@0 615 * nsRefPtr to itself, giving it a ref-count of 1 during its entire lifetime,
michael@0 616 * and Destroy() nulls this self-reference in order to trigger self-deletion.
michael@0 617 */
michael@0 618 nsRefPtr<MediaStreamGraphImpl> mSelfRef;
michael@0 619 /**
michael@0 620 * Used to pass memory report information across threads.
michael@0 621 */
michael@0 622 nsTArray<AudioNodeSizes> mAudioStreamSizes;
michael@0 623 /**
michael@0 624 * Indicates that the MSG thread should gather data for a memory report.
michael@0 625 */
michael@0 626 bool mNeedsMemoryReport;
michael@0 627
michael@0 628 #ifdef DEBUG
michael@0 629 /**
michael@0 630 * Used to assert when AppendMessage() runs ControlMessages synchronously.
michael@0 631 */
michael@0 632 bool mCanRunMessagesSynchronously;
michael@0 633 #endif
michael@0 634
michael@0 635 };
michael@0 636
michael@0 637 }
michael@0 638
michael@0 639 #endif /* MEDIASTREAMGRAPHIMPL_H_ */

mercurial