author | Paul Adenot <paul@paul.cx> |
Wed, 03 Sep 2014 15:52:43 +0200 | |
changeset 203397 | dcd375e2750d425af210fee36962219a97a334fd |
parent 203396 | 030dfb5fa2af1d11b3b620291dcb38be7dbc0a23 |
child 203398 | c5249f8eec656983f3f8aec4bc16f76b293838fc |
push id | 27425 |
push user | ryanvm@gmail.com |
push date | Wed, 03 Sep 2014 20:38:59 +0000 |
treeherder | mozilla-central@acbdce59da2f [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jesup |
bugs | 1062293 |
milestone | 35.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/media/GraphDriver.cpp +++ b/content/media/GraphDriver.cpp @@ -82,17 +82,17 @@ void GraphDriver::SetGraphTime(GraphDriv void GraphDriver::SwitchAtNextIteration(GraphDriver* aNextDriver) { LIFECYCLE_LOG("Switching to new driver: %p (%s)", aNextDriver, aNextDriver->AsAudioCallbackDriver() ? "AudioCallbackDriver" : "SystemClockDriver"); // Sometimes we switch twice to a new driver per iteration, this is probably a // bug. - MOZ_ASSERT(!mNextDriver || !mNextDriver->AsAudioCallbackDriver()); + MOZ_ASSERT(!mNextDriver || mNextDriver->AsAudioCallbackDriver()); mNextDriver = aNextDriver; } void GraphDriver::EnsureImmediateWakeUpLocked() { mGraphImpl->GetMonitor().AssertCurrentThreadOwns(); mWaitState = WAITSTATE_WAKING_UP; mGraphImpl->GetMonitor().Notify(); @@ -126,27 +126,16 @@ void GraphDriver::EnsureNextIterationLoc } if (mNeedAnotherIteration) { return; } mNeedAnotherIteration = true; } -ThreadedDriver::ThreadedDriver(MediaStreamGraphImpl* aGraphImpl) - : GraphDriver(aGraphImpl) -{ } - -ThreadedDriver::~ThreadedDriver() -{ - if (mThread) { - mThread->Shutdown(); - } -} - class MediaStreamGraphShutdownThreadRunnable : public nsRunnable { public: explicit MediaStreamGraphShutdownThreadRunnable(GraphDriver* aDriver) : mDriver(aDriver) { } NS_IMETHOD Run() { @@ -168,16 +157,36 @@ public: mDriver = nullptr; } return NS_OK; } private: nsRefPtr<GraphDriver> mDriver; }; +void GraphDriver::Shutdown() +{ + if (AsAudioCallbackDriver()) { + LIFECYCLE_LOG("Releasing audio driver off main thread (GraphDriver::Shutdown).\n"); + nsRefPtr<AsyncCubebTask> releaseEvent = + new AsyncCubebTask(AsAudioCallbackDriver(), AsyncCubebTask::SHUTDOWN); + releaseEvent->Dispatch(); + } +} + +ThreadedDriver::ThreadedDriver(MediaStreamGraphImpl* aGraphImpl) + : GraphDriver(aGraphImpl) +{ } + +ThreadedDriver::~ThreadedDriver() +{ + if (mThread) { + mThread->Shutdown(); + } +} class MediaStreamGraphInitThreadRunnable : public nsRunnable { public: explicit MediaStreamGraphInitThreadRunnable(ThreadedDriver* aDriver) : mDriver(aDriver) { } NS_IMETHOD Run() { @@ -436,16 +445,27 @@ OfflineClockDriver::WaitForNextIteration } void OfflineClockDriver::WakeUp() { MOZ_ASSERT(false, "An offline graph should not have to wake up."); } +AsyncCubebTask::AsyncCubebTask(AudioCallbackDriver* aDriver, AsyncCubebOperation aOperation) + : mDriver(aDriver), + mOperation(aOperation), + mShutdownGrip(aDriver->GraphImpl()) +{ + MOZ_ASSERT(mDriver->mAudioStream || aOperation == INIT, "No audio stream !"); +} + +AsyncCubebTask::~AsyncCubebTask() +{ +} NS_IMETHODIMP AsyncCubebTask::Run() { MOZ_ASSERT(mThread); if (NS_IsMainThread()) { mThread->Shutdown(); // can't shutdown from the thread itself, darn // don't null out mThread! @@ -462,16 +482,17 @@ AsyncCubebTask::Run() case AsyncCubebOperation::INIT: LIFECYCLE_LOG("AsyncCubebOperation::INIT\n"); mDriver->Init(); break; case AsyncCubebOperation::SHUTDOWN: LIFECYCLE_LOG("AsyncCubebOperation::SHUTDOWN\n"); mDriver->Stop(); mDriver = nullptr; + mShutdownGrip = nullptr; break; case AsyncCubebOperation::SLEEP: { { LIFECYCLE_LOG("AsyncCubebOperation::SLEEP\n"); MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor()); // We might just have been awoken if (mDriver->mNeedAnotherIteration) { mDriver->mPauseRequested = false;
--- a/content/media/GraphDriver.h +++ b/content/media/GraphDriver.h @@ -91,16 +91,17 @@ public: /* Start the graph, init the driver, start the thread. */ virtual void Start() = 0; /* Stop the graph, shutting down the thread. */ virtual void Stop() = 0; /* Resume after a stop */ virtual void Resume() = 0; /* Revive this driver, as more messages just arrived. */ virtual void Revive() = 0; + void Shutdown(); /* Rate at which the GraphDriver runs, in ms. This can either be user * controlled (because we are using a {System,Offline}ClockDriver, and decide * how often we want to wakeup/how much we want to process per iteration), or * it can be indirectly set by the latency of the audio backend, and the * number of buffers of this audio backend: say we have four buffers, and 40ms * latency, we will get a callback approximately every 10ms. */ virtual uint32_t IterationDuration() = 0; @@ -459,39 +460,35 @@ class AsyncCubebTask : public nsRunnable public: enum AsyncCubebOperation { INIT, SHUTDOWN, SLEEP }; - AsyncCubebTask(AudioCallbackDriver* aDriver, AsyncCubebOperation aOperation) - : mDriver(aDriver), - mOperation(aOperation) - { - MOZ_ASSERT(mDriver->mAudioStream || aOperation == INIT, "No audio stream !"); - } + AsyncCubebTask(AudioCallbackDriver* aDriver, AsyncCubebOperation aOperation); nsresult Dispatch() { // Can't add 'this' as the event to run, since mThread may not be set yet nsresult rv = NS_NewNamedThread("CubebOperation", getter_AddRefs(mThread)); if (NS_SUCCEEDED(rv)) { // Note: event must not null out mThread! rv = mThread->Dispatch(this, NS_DISPATCH_NORMAL); } return rv; } protected: - virtual ~AsyncCubebTask() {}; + virtual ~AsyncCubebTask(); private: NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL; nsCOMPtr<nsIThread> mThread; nsRefPtr<AudioCallbackDriver> mDriver; AsyncCubebOperation mOperation; + nsRefPtr<MediaStreamGraphImpl> mShutdownGrip; }; } #endif // GRAPHDRIVER_H_
--- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -537,18 +537,21 @@ MediaStreamGraphImpl::UpdateStreamOrder( if (!audioTrackPresent && CurrentDriver()->AsAudioCallbackDriver()) { bool started; { MonitorAutoLock mon(mMonitor); started = CurrentDriver()->AsAudioCallbackDriver()->IsStarted(); } if (started) { - SystemClockDriver* driver = new SystemClockDriver(this); - CurrentDriver()->SwitchAtNextIteration(driver); + MonitorAutoLock mon(mMonitor); + if (mLifecycleState == LIFECYCLE_RUNNING) { + SystemClockDriver* driver = new SystemClockDriver(this); + CurrentDriver()->SwitchAtNextIteration(driver); + } } } if (shouldAEC && !mFarendObserverRef && gFarendObserver) { mFarendObserverRef = gFarendObserver; mMixer.AddCallback(mFarendObserverRef); } else if (!shouldAEC && mFarendObserverRef){ if (mMixer.FindCallback(mFarendObserverRef)) { @@ -916,19 +919,22 @@ MediaStreamGraphImpl::CreateOrDestroyAud aStream->mAudioOutputStreams.AppendElement(); audioOutputStream->mAudioPlaybackStartTime = aAudioOutputStartTime; audioOutputStream->mBlockedAudioTime = 0; audioOutputStream->mLastTickWritten = 0; audioOutputStream->mTrackID = tracks->GetID(); if (!CurrentDriver()->AsAudioCallbackDriver() && !CurrentDriver()->Switching()) { - AudioCallbackDriver* driver = new AudioCallbackDriver(this); - mMixer.AddCallback(driver); - CurrentDriver()->SwitchAtNextIteration(driver); + MonitorAutoLock mon(mMonitor); + if (mLifecycleState == LIFECYCLE_RUNNING) { + AudioCallbackDriver* driver = new AudioCallbackDriver(this); + mMixer.AddCallback(driver); + CurrentDriver()->SwitchAtNextIteration(driver); + } } } } } for (int32_t i = audioOutputStreamsFound.Length() - 1; i >= 0; --i) { if (!audioOutputStreamsFound[i]) { aStream->mAudioOutputStreams.RemoveElementAt(i); @@ -1473,17 +1479,17 @@ public: "We should know the graph thread control loop isn't running!"); LIFECYCLE_LOG("Shutting down graph %p", mGraph.get()); if (mGraph->CurrentDriver()->AsAudioCallbackDriver()) { MOZ_ASSERT(!mGraph->CurrentDriver()->AsAudioCallbackDriver()->InCallback()); } - mGraph->CurrentDriver()->Stop(); + mGraph->CurrentDriver()->Shutdown(); // mGraph's thread is not running so it's OK to do whatever here if (mGraph->IsEmpty()) { // mGraph is no longer needed, so delete it. mGraph->Destroy(); } else { // The graph is not empty. We must be in a forced shutdown, or a // non-realtime graph that has finished processing. Some later @@ -1600,28 +1606,29 @@ MediaStreamGraphImpl::RunInStableState(b } } mStreamUpdates.Clear(); if (mCurrentTaskMessageQueue.IsEmpty()) { if (mLifecycleState == LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP && IsEmpty()) { // Complete shutdown. First, ensure that this graph is no longer used. // A new graph graph will be created if one is needed. - LIFECYCLE_LOG("Disconnecting MediaStreamGraph %p", this); - if (this == gGraph) { - // null out gGraph if that's the graph being shut down - gGraph = nullptr; - } // Asynchronously clean up old graph. We don't want to do this // synchronously because it spins the event loop waiting for threads // to shut down, and we don't want to do that in a stable state handler. mLifecycleState = LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN; LIFECYCLE_LOG("Sending MediaStreamGraphShutDownRunnable %p", this); nsCOMPtr<nsIRunnable> event = new MediaStreamGraphShutDownRunnable(this ); NS_DispatchToMainThread(event); + + LIFECYCLE_LOG("Disconnecting MediaStreamGraph %p", this); + if (this == gGraph) { + // null out gGraph if that's the graph being shut down + gGraph = nullptr; + } } } else { if (mLifecycleState <= LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP) { MessageBlock* block = mBackMessageQueue.AppendElement(); block->mMessages.SwapElements(mCurrentTaskMessageQueue); block->mGraphUpdateIndex = mNextGraphUpdateIndex; ++mNextGraphUpdateIndex; CurrentDriver()->EnsureNextIterationLocked();