michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef MOZILLA_MEDIASTREAMGRAPHIMPL_H_ michael@0: #define MOZILLA_MEDIASTREAMGRAPHIMPL_H_ michael@0: michael@0: #include "MediaStreamGraph.h" michael@0: michael@0: #include "mozilla/Monitor.h" michael@0: #include "mozilla/TimeStamp.h" michael@0: #include "nsIMemoryReporter.h" michael@0: #include "nsIThread.h" michael@0: #include "nsIRunnable.h" michael@0: #include "Latency.h" michael@0: #include "mozilla/WeakPtr.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: template michael@0: class LinkedList; michael@0: michael@0: class AudioMixer; michael@0: michael@0: /** michael@0: * Assume we can run an iteration of the MediaStreamGraph loop in this much time michael@0: * or less. michael@0: * We try to run the control loop at this rate. michael@0: */ michael@0: static const int MEDIA_GRAPH_TARGET_PERIOD_MS = 10; michael@0: michael@0: /** michael@0: * Assume that we might miss our scheduled wakeup of the MediaStreamGraph by michael@0: * this much. michael@0: */ michael@0: static const int SCHEDULE_SAFETY_MARGIN_MS = 10; michael@0: michael@0: /** michael@0: * Try have this much audio buffered in streams and queued to the hardware. michael@0: * The maximum delay to the end of the next control loop michael@0: * is 2*MEDIA_GRAPH_TARGET_PERIOD_MS + SCHEDULE_SAFETY_MARGIN_MS. michael@0: * There is no point in buffering more audio than this in a stream at any michael@0: * given time (until we add processing). michael@0: * This is not optimal yet. michael@0: */ michael@0: static const int AUDIO_TARGET_MS = 2*MEDIA_GRAPH_TARGET_PERIOD_MS + michael@0: SCHEDULE_SAFETY_MARGIN_MS; michael@0: michael@0: /** michael@0: * Try have this much video buffered. Video frames are set michael@0: * near the end of the iteration of the control loop. The maximum delay michael@0: * to the setting of the next video frame is 2*MEDIA_GRAPH_TARGET_PERIOD_MS + michael@0: * SCHEDULE_SAFETY_MARGIN_MS. This is not optimal yet. michael@0: */ michael@0: static const int VIDEO_TARGET_MS = 2*MEDIA_GRAPH_TARGET_PERIOD_MS + michael@0: SCHEDULE_SAFETY_MARGIN_MS; michael@0: michael@0: /** michael@0: * A per-stream update message passed from the media graph thread to the michael@0: * main thread. michael@0: */ michael@0: struct StreamUpdate { michael@0: int64_t mGraphUpdateIndex; michael@0: nsRefPtr mStream; michael@0: StreamTime mNextMainThreadCurrentTime; michael@0: bool mNextMainThreadFinished; michael@0: }; michael@0: michael@0: /** michael@0: * This represents a message passed from the main thread to the graph thread. michael@0: * A ControlMessage always has a weak reference a particular affected stream. michael@0: */ michael@0: class ControlMessage { michael@0: public: michael@0: explicit ControlMessage(MediaStream* aStream) : mStream(aStream) michael@0: { michael@0: MOZ_COUNT_CTOR(ControlMessage); michael@0: } michael@0: // All these run on the graph thread michael@0: virtual ~ControlMessage() michael@0: { michael@0: MOZ_COUNT_DTOR(ControlMessage); michael@0: } michael@0: // Do the action of this message on the MediaStreamGraph thread. Any actions michael@0: // affecting graph processing should take effect at mStateComputedTime. michael@0: // All stream data for times < mStateComputedTime has already been michael@0: // computed. michael@0: virtual void Run() = 0; michael@0: // When we're shutting down the application, most messages are ignored but michael@0: // some cleanup messages should still be processed (on the main thread). michael@0: // This must not add new control messages to the graph. michael@0: virtual void RunDuringShutdown() {} michael@0: MediaStream* GetStream() { return mStream; } michael@0: michael@0: protected: michael@0: // We do not hold a reference to mStream. The graph will be holding michael@0: // a reference to the stream until the Destroy message is processed. The michael@0: // last message referencing a stream is the Destroy message for that stream. michael@0: MediaStream* mStream; michael@0: }; michael@0: michael@0: /** michael@0: * The implementation of a media stream graph. This class is private to this michael@0: * file. It's not in the anonymous namespace because MediaStream needs to michael@0: * be able to friend it. michael@0: * michael@0: * Currently we have one global instance per process, and one per each michael@0: * OfflineAudioContext object. michael@0: */ michael@0: class MediaStreamGraphImpl : public MediaStreamGraph, michael@0: public nsIMemoryReporter { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIMEMORYREPORTER michael@0: michael@0: /** michael@0: * Set aRealtime to true in order to create a MediaStreamGraph which provides michael@0: * support for real-time audio and video. Set it to false in order to create michael@0: * a non-realtime instance which just churns through its inputs and produces michael@0: * output. Those objects currently only support audio, and are used to michael@0: * implement OfflineAudioContext. They do not support MediaStream inputs. michael@0: */ michael@0: explicit MediaStreamGraphImpl(bool aRealtime, TrackRate aSampleRate); michael@0: michael@0: /** michael@0: * Unregisters memory reporting and deletes this instance. This should be michael@0: * called instead of calling the destructor directly. michael@0: */ michael@0: void Destroy(); michael@0: michael@0: // Main thread only. michael@0: /** michael@0: * This runs every time we need to sync state from the media graph thread michael@0: * to the main thread while the main thread is not in the middle michael@0: * of a script. It runs during a "stable state" (per HTML5) or during michael@0: * an event posted to the main thread. michael@0: */ michael@0: void RunInStableState(); michael@0: /** michael@0: * Ensure a runnable to run RunInStableState is posted to the appshell to michael@0: * run at the next stable state (per HTML5). michael@0: * See EnsureStableStateEventPosted. michael@0: */ michael@0: void EnsureRunInStableState(); michael@0: /** michael@0: * Called to apply a StreamUpdate to its stream. michael@0: */ michael@0: void ApplyStreamUpdate(StreamUpdate* aUpdate); michael@0: /** michael@0: * Append a ControlMessage to the message queue. This queue is drained michael@0: * during RunInStableState; the messages will run on the graph thread. michael@0: */ michael@0: void AppendMessage(ControlMessage* aMessage); michael@0: /** michael@0: * Make this MediaStreamGraph enter forced-shutdown state. This state michael@0: * will be noticed by the media graph thread, which will shut down all streams michael@0: * and other state controlled by the media graph thread. michael@0: * This is called during application shutdown. michael@0: */ michael@0: void ForceShutDown(); michael@0: /** michael@0: * Shutdown() this MediaStreamGraph's threads and return when they've shut down. michael@0: */ michael@0: void ShutdownThreads(); michael@0: michael@0: /** michael@0: * Called before the thread runs. michael@0: */ michael@0: void Init(); michael@0: // The following methods run on the graph thread (or possibly the main thread if michael@0: // mLifecycleState > LIFECYCLE_RUNNING) michael@0: /** michael@0: * Runs main control loop on the graph thread. Normally a single invocation michael@0: * of this runs for the entire lifetime of the graph thread. michael@0: */ michael@0: void RunThread(); michael@0: /** michael@0: * Call this to indicate that another iteration of the control loop is michael@0: * required on its regular schedule. The monitor must not be held. michael@0: */ michael@0: void EnsureNextIteration(); michael@0: /** michael@0: * As above, but with the monitor already held. michael@0: */ michael@0: void EnsureNextIterationLocked(MonitorAutoLock& aLock); michael@0: /** michael@0: * Call this to indicate that another iteration of the control loop is michael@0: * required immediately. The monitor must already be held. michael@0: */ michael@0: void EnsureImmediateWakeUpLocked(MonitorAutoLock& aLock); michael@0: /** michael@0: * Ensure there is an event posted to the main thread to run RunInStableState. michael@0: * mMonitor must be held. michael@0: * See EnsureRunInStableState michael@0: */ michael@0: void EnsureStableStateEventPosted(); michael@0: /** michael@0: * Generate messages to the main thread to update it for all state changes. michael@0: * mMonitor must be held. michael@0: */ michael@0: void PrepareUpdatesToMainThreadState(bool aFinalUpdate); michael@0: /** michael@0: * Returns false if there is any stream that has finished but not yet finished michael@0: * playing out. michael@0: */ michael@0: bool AllFinishedStreamsNotified(); michael@0: /** michael@0: * If we are rendering in non-realtime mode, we don't want to send messages to michael@0: * the main thread at each iteration for performance reasons. We instead michael@0: * notify the main thread at the same rate michael@0: */ michael@0: bool ShouldUpdateMainThread(); michael@0: // The following methods are the various stages of RunThread processing. michael@0: /** michael@0: * Compute a new current time for the graph and advance all on-graph-thread michael@0: * state to the new current time. michael@0: */ michael@0: void UpdateCurrentTime(); michael@0: /** michael@0: * Update the consumption state of aStream to reflect whether its data michael@0: * is needed or not. michael@0: */ michael@0: void UpdateConsumptionState(SourceMediaStream* aStream); michael@0: /** michael@0: * Extract any state updates pending in aStream, and apply them. michael@0: */ michael@0: void ExtractPendingInput(SourceMediaStream* aStream, michael@0: GraphTime aDesiredUpToTime, michael@0: bool* aEnsureNextIteration); michael@0: /** michael@0: * Update "have enough data" flags in aStream. michael@0: */ michael@0: void UpdateBufferSufficiencyState(SourceMediaStream* aStream); michael@0: /* michael@0: * If aStream hasn't already been ordered, push it onto aStack and order michael@0: * its children. michael@0: */ michael@0: void UpdateStreamOrderForStream(mozilla::LinkedList* aStack, michael@0: already_AddRefed aStream); michael@0: /** michael@0: * Mark aStream and all its inputs (recursively) as consumed. michael@0: */ michael@0: static void MarkConsumed(MediaStream* aStream); michael@0: /** michael@0: * Sort mStreams so that every stream not in a cycle is after any streams michael@0: * it depends on, and every stream in a cycle is marked as being in a cycle. michael@0: * Also sets mIsConsumed on every stream. michael@0: */ michael@0: void UpdateStreamOrder(); michael@0: /** michael@0: * Compute the blocking states of streams from mStateComputedTime michael@0: * until the desired future time aEndBlockingDecisions. michael@0: * Updates mStateComputedTime and sets MediaStream::mBlocked michael@0: * for all streams. michael@0: */ michael@0: void RecomputeBlocking(GraphTime aEndBlockingDecisions); michael@0: // The following methods are used to help RecomputeBlocking. michael@0: /** michael@0: * If aStream isn't already in aStreams, add it and recursively call michael@0: * AddBlockingRelatedStreamsToSet on all the streams whose blocking michael@0: * status could depend on or affect the state of aStream. michael@0: */ michael@0: void AddBlockingRelatedStreamsToSet(nsTArray* aStreams, michael@0: MediaStream* aStream); michael@0: /** michael@0: * Mark a stream blocked at time aTime. If this results in decisions that need michael@0: * to be revisited at some point in the future, *aEnd will be reduced to the michael@0: * first time in the future to recompute those decisions. michael@0: */ michael@0: void MarkStreamBlocking(MediaStream* aStream); michael@0: /** michael@0: * Recompute blocking for the streams in aStreams for the interval starting at aTime. michael@0: * If this results in decisions that need to be revisited at some point michael@0: * in the future, *aEnd will be reduced to the first time in the future to michael@0: * recompute those decisions. michael@0: */ michael@0: void RecomputeBlockingAt(const nsTArray& aStreams, michael@0: GraphTime aTime, GraphTime aEndBlockingDecisions, michael@0: GraphTime* aEnd); michael@0: /** michael@0: * Produce data for all streams >= aStreamIndex for the given time interval. michael@0: * Advances block by block, each iteration producing data for all streams michael@0: * for a single block. michael@0: * This is called whenever we have an AudioNodeStream in the graph. michael@0: */ michael@0: void ProduceDataForStreamsBlockByBlock(uint32_t aStreamIndex, michael@0: TrackRate aSampleRate, michael@0: GraphTime aFrom, michael@0: GraphTime aTo); michael@0: /** michael@0: * Returns true if aStream will underrun at aTime for its own playback. michael@0: * aEndBlockingDecisions is when we plan to stop making blocking decisions. michael@0: * *aEnd will be reduced to the first time in the future to recompute these michael@0: * decisions. michael@0: */ michael@0: bool WillUnderrun(MediaStream* aStream, GraphTime aTime, michael@0: GraphTime aEndBlockingDecisions, GraphTime* aEnd); michael@0: /** michael@0: * Given a graph time aTime, convert it to a stream time taking into michael@0: * account the time during which aStream is scheduled to be blocked. michael@0: */ michael@0: StreamTime GraphTimeToStreamTime(MediaStream* aStream, GraphTime aTime); michael@0: /** michael@0: * Given a graph time aTime, convert it to a stream time taking into michael@0: * account the time during which aStream is scheduled to be blocked, and michael@0: * when we don't know whether it's blocked or not, we assume it's not blocked. michael@0: */ michael@0: StreamTime GraphTimeToStreamTimeOptimistic(MediaStream* aStream, GraphTime aTime); michael@0: enum { michael@0: INCLUDE_TRAILING_BLOCKED_INTERVAL = 0x01 michael@0: }; michael@0: /** michael@0: * Given a stream time aTime, convert it to a graph time taking into michael@0: * account the time during which aStream is scheduled to be blocked. michael@0: * aTime must be <= mStateComputedTime since blocking decisions michael@0: * are only known up to that point. michael@0: * If aTime is exactly at the start of a blocked interval, then the blocked michael@0: * interval is included in the time returned if and only if michael@0: * aFlags includes INCLUDE_TRAILING_BLOCKED_INTERVAL. michael@0: */ michael@0: GraphTime StreamTimeToGraphTime(MediaStream* aStream, StreamTime aTime, michael@0: uint32_t aFlags = 0); michael@0: /** michael@0: * Get the current audio position of the stream's audio output. michael@0: */ michael@0: GraphTime GetAudioPosition(MediaStream* aStream); michael@0: /** michael@0: * Call NotifyHaveCurrentData on aStream's listeners. michael@0: */ michael@0: void NotifyHasCurrentData(MediaStream* aStream); michael@0: /** michael@0: * If aStream needs an audio stream but doesn't have one, create it. michael@0: * If aStream doesn't need an audio stream but has one, destroy it. michael@0: */ michael@0: void CreateOrDestroyAudioStreams(GraphTime aAudioOutputStartTime, michael@0: MediaStream* aStream); michael@0: /** michael@0: * Queue audio (mix of stream audio and silence for blocked intervals) michael@0: * to the audio output stream. Returns the number of frames played. michael@0: */ michael@0: TrackTicks PlayAudio(MediaStream* aStream, GraphTime aFrom, GraphTime aTo); michael@0: /** michael@0: * Set the correct current video frame for stream aStream. michael@0: */ michael@0: void PlayVideo(MediaStream* aStream); michael@0: /** michael@0: * No more data will be forthcoming for aStream. The stream will end michael@0: * at the current buffer end point. The StreamBuffer's tracks must be michael@0: * explicitly set to finished by the caller. michael@0: */ michael@0: void FinishStream(MediaStream* aStream); michael@0: /** michael@0: * Compute how much stream data we would like to buffer for aStream. michael@0: */ michael@0: StreamTime GetDesiredBufferEnd(MediaStream* aStream); michael@0: /** michael@0: * Returns true when there are no active streams. michael@0: */ michael@0: bool IsEmpty() { return mStreams.IsEmpty() && mPortCount == 0; } michael@0: michael@0: // For use by control messages, on graph thread only. michael@0: /** michael@0: * Identify which graph update index we are currently processing. michael@0: */ michael@0: int64_t GetProcessingGraphUpdateIndex() { return mProcessingGraphUpdateIndex; } michael@0: /** michael@0: * Add aStream to the graph and initializes its graph-specific state. michael@0: */ michael@0: void AddStream(MediaStream* aStream); michael@0: /** michael@0: * Remove aStream from the graph. Ensures that pending messages about the michael@0: * stream back to the main thread are flushed. michael@0: */ michael@0: void RemoveStream(MediaStream* aStream); michael@0: /** michael@0: * Remove aPort from the graph and release it. michael@0: */ michael@0: void DestroyPort(MediaInputPort* aPort); michael@0: /** michael@0: * Mark the media stream order as dirty. michael@0: */ michael@0: void SetStreamOrderDirty() michael@0: { michael@0: mStreamOrderDirty = true; michael@0: } michael@0: /** michael@0: * Pause all AudioStreams being written to by MediaStreams michael@0: */ michael@0: void PauseAllAudioOutputs(); michael@0: /** michael@0: * Resume all AudioStreams being written to by MediaStreams michael@0: */ michael@0: void ResumeAllAudioOutputs(); michael@0: michael@0: TrackRate AudioSampleRate() { return mSampleRate; } michael@0: michael@0: // Data members michael@0: michael@0: /** michael@0: * Media graph thread. michael@0: * Readonly after initialization on the main thread. michael@0: */ michael@0: nsCOMPtr mThread; michael@0: michael@0: // The following state is managed on the graph thread only, unless michael@0: // mLifecycleState > LIFECYCLE_RUNNING in which case the graph thread michael@0: // is not running and this state can be used from the main thread. michael@0: michael@0: nsTArray > mStreams; michael@0: /** michael@0: * mOldStreams is used as temporary storage for streams when computing the michael@0: * order in which we compute them. michael@0: */ michael@0: nsTArray > mOldStreams; michael@0: /** michael@0: * The current graph time for the current iteration of the RunThread control michael@0: * loop. michael@0: */ michael@0: GraphTime mCurrentTime; michael@0: /** michael@0: * Blocking decisions and all stream contents have been computed up to this michael@0: * time. The next batch of updates from the main thread will be processed michael@0: * at this time. Always >= mCurrentTime. michael@0: */ michael@0: GraphTime mStateComputedTime; michael@0: /** michael@0: * This is only used for logging. michael@0: */ michael@0: TimeStamp mInitialTimeStamp; michael@0: /** michael@0: * The real timestamp of the latest run of UpdateCurrentTime. michael@0: */ michael@0: TimeStamp mCurrentTimeStamp; michael@0: /** michael@0: * Date of the last time we updated the main thread with the graph state. michael@0: */ michael@0: TimeStamp mLastMainThreadUpdate; michael@0: /** michael@0: * Which update batch we are currently processing. michael@0: */ michael@0: int64_t mProcessingGraphUpdateIndex; michael@0: /** michael@0: * Number of active MediaInputPorts michael@0: */ michael@0: int32_t mPortCount; michael@0: michael@0: // mMonitor guards the data below. michael@0: // MediaStreamGraph normally does its work without holding mMonitor, so it is michael@0: // not safe to just grab mMonitor from some thread and start monkeying with michael@0: // the graph. Instead, communicate with the graph thread using provided michael@0: // mechanisms such as the ControlMessage queue. michael@0: Monitor mMonitor; michael@0: michael@0: // Data guarded by mMonitor (must always be accessed with mMonitor held, michael@0: // regardless of the value of mLifecycleState. michael@0: michael@0: /** michael@0: * State to copy to main thread michael@0: */ michael@0: nsTArray mStreamUpdates; michael@0: /** michael@0: * Runnables to run after the next update to main thread state. michael@0: */ michael@0: nsTArray > mUpdateRunnables; michael@0: struct MessageBlock { michael@0: int64_t mGraphUpdateIndex; michael@0: nsTArray > mMessages; michael@0: }; michael@0: /** michael@0: * A list of batches of messages to process. Each batch is processed michael@0: * as an atomic unit. michael@0: */ michael@0: nsTArray mMessageQueue; michael@0: /** michael@0: * This enum specifies where this graph is in its lifecycle. This is used michael@0: * to control shutdown. michael@0: * Shutdown is tricky because it can happen in two different ways: michael@0: * 1) Shutdown due to inactivity. RunThread() detects that it has no michael@0: * pending messages and no streams, and exits. The next RunInStableState() michael@0: * checks if there are new pending messages from the main thread (true only michael@0: * if new stream creation raced with shutdown); if there are, it revives michael@0: * RunThread(), otherwise it commits to shutting down the graph. New stream michael@0: * creation after this point will create a new graph. An async event is michael@0: * dispatched to Shutdown() the graph's threads and then delete the graph michael@0: * object. michael@0: * 2) Forced shutdown at application shutdown, or completion of a michael@0: * non-realtime graph. A flag is set, RunThread() detects the flag and michael@0: * exits, the next RunInStableState() detects the flag, and dispatches the michael@0: * async event to Shutdown() the graph's threads. However the graph object michael@0: * is not deleted. New messages for the graph are processed synchronously on michael@0: * the main thread if necessary. When the last stream is destroyed, the michael@0: * graph object is deleted. michael@0: */ michael@0: enum LifecycleState { michael@0: // The graph thread hasn't started yet. michael@0: LIFECYCLE_THREAD_NOT_STARTED, michael@0: // RunThread() is running normally. michael@0: LIFECYCLE_RUNNING, michael@0: // In the following states, the graph thread is not running so michael@0: // all "graph thread only" state in this class can be used safely michael@0: // on the main thread. michael@0: // RunThread() has exited and we're waiting for the next michael@0: // RunInStableState(), at which point we can clean up the main-thread michael@0: // side of the graph. michael@0: LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP, michael@0: // RunInStableState() posted a ShutdownRunnable, and we're waiting for it michael@0: // to shut down the graph thread(s). michael@0: LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN, michael@0: // Graph threads have shut down but we're waiting for remaining streams michael@0: // to be destroyed. Only happens during application shutdown and on michael@0: // completed non-realtime graphs, since normally we'd only shut down a michael@0: // realtime graph when it has no streams. michael@0: LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION michael@0: }; michael@0: LifecycleState mLifecycleState; michael@0: /** michael@0: * This enum specifies the wait state of the graph thread. michael@0: */ michael@0: enum WaitState { michael@0: // RunThread() is running normally michael@0: WAITSTATE_RUNNING, michael@0: // RunThread() is paused waiting for its next iteration, which will michael@0: // happen soon michael@0: WAITSTATE_WAITING_FOR_NEXT_ITERATION, michael@0: // RunThread() is paused indefinitely waiting for something to change michael@0: WAITSTATE_WAITING_INDEFINITELY, michael@0: // Something has signaled RunThread() to wake up immediately, michael@0: // but it hasn't done so yet michael@0: WAITSTATE_WAKING_UP michael@0: }; michael@0: WaitState mWaitState; michael@0: /** michael@0: * The graph should stop processing at or after this time. michael@0: */ michael@0: GraphTime mEndTime; michael@0: michael@0: /** michael@0: * Sample rate at which this graph runs. For real time graphs, this is michael@0: * the rate of the audio mixer. For offline graphs, this is the rate specified michael@0: * at construction. michael@0: */ michael@0: TrackRate mSampleRate; michael@0: /** michael@0: * True when another iteration of the control loop is required. michael@0: */ michael@0: bool mNeedAnotherIteration; michael@0: /** michael@0: * True when we need to do a forced shutdown during application shutdown. michael@0: */ michael@0: bool mForceShutDown; michael@0: /** michael@0: * True when we have posted an event to the main thread to run michael@0: * RunInStableState() and the event hasn't run yet. michael@0: */ michael@0: bool mPostedRunInStableStateEvent; michael@0: michael@0: // Main thread only michael@0: michael@0: /** michael@0: * Messages posted by the current event loop task. These are forwarded to michael@0: * the media graph thread during RunInStableState. We can't forward them michael@0: * immediately because we want all messages between stable states to be michael@0: * processed as an atomic batch. michael@0: */ michael@0: nsTArray > mCurrentTaskMessageQueue; michael@0: /** michael@0: * True when RunInStableState has determined that mLifecycleState is > michael@0: * LIFECYCLE_RUNNING. Since only the main thread can reset mLifecycleState to michael@0: * LIFECYCLE_RUNNING, this can be relied on to not change unexpectedly. michael@0: */ michael@0: bool mDetectedNotRunning; michael@0: /** michael@0: * True when a stable state runner has been posted to the appshell to run michael@0: * RunInStableState at the next stable state. michael@0: */ michael@0: bool mPostedRunInStableState; michael@0: /** michael@0: * True when processing real-time audio/video. False when processing non-realtime michael@0: * audio. michael@0: */ michael@0: bool mRealtime; michael@0: /** michael@0: * True when a non-realtime MediaStreamGraph has started to process input. This michael@0: * value is only accessed on the main thread. michael@0: */ michael@0: bool mNonRealtimeProcessing; michael@0: /** michael@0: * True when a change has happened which requires us to recompute the stream michael@0: * blocking order. michael@0: */ michael@0: bool mStreamOrderDirty; michael@0: /** michael@0: * Hold a ref to the Latency logger michael@0: */ michael@0: nsRefPtr mLatencyLog; michael@0: /** michael@0: * If this is not null, all the audio output for the MSG will be mixed down. michael@0: */ michael@0: nsAutoPtr mMixer; michael@0: michael@0: private: michael@0: virtual ~MediaStreamGraphImpl(); michael@0: michael@0: MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf) michael@0: michael@0: /** michael@0: * Used to signal that a memory report has been requested. michael@0: */ michael@0: Monitor mMemoryReportMonitor; michael@0: /** michael@0: * This class uses manual memory management, and all pointers to it are raw michael@0: * pointers. However, in order for it to implement nsIMemoryReporter, it needs michael@0: * to implement nsISupports and so be ref-counted. So it maintains a single michael@0: * nsRefPtr to itself, giving it a ref-count of 1 during its entire lifetime, michael@0: * and Destroy() nulls this self-reference in order to trigger self-deletion. michael@0: */ michael@0: nsRefPtr mSelfRef; michael@0: /** michael@0: * Used to pass memory report information across threads. michael@0: */ michael@0: nsTArray mAudioStreamSizes; michael@0: /** michael@0: * Indicates that the MSG thread should gather data for a memory report. michael@0: */ michael@0: bool mNeedsMemoryReport; michael@0: michael@0: #ifdef DEBUG michael@0: /** michael@0: * Used to assert when AppendMessage() runs ControlMessages synchronously. michael@0: */ michael@0: bool mCanRunMessagesSynchronously; michael@0: #endif michael@0: michael@0: }; michael@0: michael@0: } michael@0: michael@0: #endif /* MEDIASTREAMGRAPHIMPL_H_ */