From 31c4421faf48f61dd1ab367a0e17744c57efaa46 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Thu, 9 Apr 2015 13:44:27 +0200 Subject: [PATCH] Backed out changeset 7fc52c48e6e3 (bug 1094764) for mulet m-3 perma failure in /test_dataChannel_basicAudioVideo.html --- dom/base/nsGlobalWindow.cpp | 6 +- dom/media/GraphDriver.cpp | 120 ++-- dom/media/GraphDriver.h | 31 +- dom/media/MediaStreamGraph.cpp | 543 +++--------------- dom/media/MediaStreamGraph.h | 35 -- dom/media/MediaStreamGraphImpl.h | 55 +- dom/media/TrackUnionStream.cpp | 18 +- dom/media/webaudio/AudioContext.cpp | 343 +---------- dom/media/webaudio/AudioContext.h | 87 +-- dom/media/webaudio/AudioDestinationNode.cpp | 11 +- .../webaudio/AudioNodeExternalInputStream.cpp | 4 +- .../webaudio/AudioNodeExternalInputStream.h | 2 +- dom/media/webaudio/AudioNodeStream.cpp | 4 +- dom/media/webaudio/AudioNodeStream.h | 10 +- .../webaudio/MediaStreamAudioSourceNode.h | 1 - dom/media/webaudio/moz.build | 1 - dom/media/webaudio/test/mochitest.ini | 2 - .../test_audioContextSuspendResumeClose.html | 400 ------------- dom/media/webaudio/test/webaudio.js | 12 - dom/webidl/AudioContext.webidl | 34 +- 20 files changed, 191 insertions(+), 1528 deletions(-) delete mode 100644 dom/media/webaudio/test/test_audioContextSuspendResumeClose.html diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index e388ce896229..ea201ceef19c 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -13057,8 +13057,7 @@ nsGlobalWindow::SuspendTimeouts(uint32_t aIncrease, // Suspend all of the AudioContexts for this window for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) { - ErrorResult dummy; - nsRefPtr d = mAudioContexts[i]->Suspend(dummy); + mAudioContexts[i]->Suspend(); } } @@ -13118,8 +13117,7 @@ nsGlobalWindow::ResumeTimeouts(bool aThawChildren) // Resume all of the AudioContexts for this window for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) { - ErrorResult dummy; - nsRefPtr d = mAudioContexts[i]->Resume(dummy); + mAudioContexts[i]->Resume(); } // Thaw all of the workers for this window. diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp index c9fab58cb31f..0228edabea2f 100644 --- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -23,7 +23,7 @@ extern PRLogModuleInfo* gMediaStreamGraphLog; #ifdef ENABLE_LIFECYCLE_LOG #ifdef ANDROID #include "android/log.h" -#define LIFECYCLE_LOG(...) __android_log_print(ANDROID_LOG_INFO, "Gecko - MSG" , __VA_ARGS__); printf(__VA_ARGS__);printf("\n"); +#define LIFECYCLE_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gecko - MSG" , ## __VA_ARGS__); printf(__VA_ARGS__);printf("\n"); #else #define LIFECYCLE_LOG(...) printf(__VA_ARGS__);printf("\n"); #endif @@ -95,6 +95,9 @@ 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()); mNextDriver = aNextDriver; } @@ -142,7 +145,7 @@ public: LIFECYCLE_LOG("Releasing audio driver off main thread."); nsRefPtr releaseEvent = new AsyncCubebTask(mDriver->AsAudioCallbackDriver(), - AsyncCubebOperation::SHUTDOWN); + AsyncCubebTask::SHUTDOWN); mDriver = nullptr; releaseEvent->Dispatch(); } else { @@ -160,7 +163,7 @@ void GraphDriver::Shutdown() if (AsAudioCallbackDriver()) { LIFECYCLE_LOG("Releasing audio driver off main thread (GraphDriver::Shutdown).\n"); nsRefPtr releaseEvent = - new AsyncCubebTask(AsAudioCallbackDriver(), AsyncCubebOperation::SHUTDOWN); + new AsyncCubebTask(AsAudioCallbackDriver(), AsyncCubebTask::SHUTDOWN); releaseEvent->Dispatch(); } else { Stop(); @@ -201,7 +204,7 @@ public: // because the osx audio stack is currently switching output device. if (!mDriver->mPreviousDriver->AsAudioCallbackDriver()->IsSwitchingDevice()) { nsRefPtr releaseEvent = - new AsyncCubebTask(mDriver->mPreviousDriver->AsAudioCallbackDriver(), AsyncCubebOperation::SHUTDOWN); + new AsyncCubebTask(mDriver->mPreviousDriver->AsAudioCallbackDriver(), AsyncCubebTask::SHUTDOWN); mDriver->mPreviousDriver = nullptr; releaseEvent->Dispatch(); } @@ -502,21 +505,36 @@ AsyncCubebTask::Run() MOZ_ASSERT(mDriver); switch(mOperation) { - case AsyncCubebOperation::INIT: { + case AsyncCubebOperation::INIT: LIFECYCLE_LOG("AsyncCubebOperation::INIT\n"); mDriver->Init(); - mDriver->CompleteAudioContextOperations(mOperation); break; - } - case AsyncCubebOperation::SHUTDOWN: { + case AsyncCubebOperation::SHUTDOWN: LIFECYCLE_LOG("AsyncCubebOperation::SHUTDOWN\n"); mDriver->Stop(); - - mDriver->CompleteAudioContextOperations(mOperation); - 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->mGraphImpl->mNeedAnotherIteration) { + mDriver->mPauseRequested = false; + mDriver->mWaitState = AudioCallbackDriver::WAITSTATE_RUNNING; + mDriver->mGraphImpl->mGraphDriverAsleep = false ; // atomic + break; + } + mDriver->Stop(); + mDriver->mGraphImpl->mGraphDriverAsleep = true; // atomic + mDriver->mWaitState = AudioCallbackDriver::WAITSTATE_WAITING_INDEFINITELY; + mDriver->mPauseRequested = false; + mDriver->mGraphImpl->GetMonitor().Wait(PR_INTERVAL_NO_TIMEOUT); + } + STREAM_LOG(PR_LOG_DEBUG, ("Restarting audio stream from sleep.")); + mDriver->StartStream(); + break; } default: MOZ_CRASH("Operation not implemented."); @@ -528,16 +546,6 @@ AsyncCubebTask::Run() return NS_OK; } -StreamAndPromiseForOperation::StreamAndPromiseForOperation(MediaStream* aStream, - void* aPromise, - dom::AudioContextOperation aOperation) - : mStream(aStream) - , mPromise(aPromise) - , mOperation(aOperation) -{ - // MOZ_ASSERT(aPromise); -} - AudioCallbackDriver::AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl, dom::AudioChannel aChannel) : GraphDriver(aGraphImpl) , mIterationDurationMS(MEDIA_GRAPH_TARGET_PERIOD_MS) @@ -553,9 +561,7 @@ AudioCallbackDriver::AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl, dom:: } AudioCallbackDriver::~AudioCallbackDriver() -{ - MOZ_ASSERT(mPromisesForOperation.IsEmpty()); -} +{} void AudioCallbackDriver::Init() @@ -645,18 +651,12 @@ AudioCallbackDriver::Start() if (NS_IsMainThread()) { STREAM_LOG(PR_LOG_DEBUG, ("Starting audio threads for MediaStreamGraph %p from a new thread.", mGraphImpl)); nsRefPtr initEvent = - new AsyncCubebTask(this, AsyncCubebOperation::INIT); + new AsyncCubebTask(this, AsyncCubebTask::INIT); initEvent->Dispatch(); } else { STREAM_LOG(PR_LOG_DEBUG, ("Starting audio threads for MediaStreamGraph %p from the previous driver's thread", mGraphImpl)); Init(); - // Check if we need to resolve promises because the driver just got switched - // because of a resuming AudioContext - if (!mPromisesForOperation.IsEmpty()) { - CompleteAudioContextOperations(AsyncCubebOperation::INIT); - } - if (mPreviousDriver) { nsCOMPtr event = new MediaStreamGraphShutdownThreadRunnable(mPreviousDriver); @@ -704,7 +704,7 @@ AudioCallbackDriver::Revive() } else { STREAM_LOG(PR_LOG_DEBUG, ("Starting audio threads for MediaStreamGraph %p from a new thread.", mGraphImpl)); nsRefPtr initEvent = - new AsyncCubebTask(this, AsyncCubebOperation::INIT); + new AsyncCubebTask(this, AsyncCubebTask::INIT); initEvent->Dispatch(); } } @@ -729,6 +729,20 @@ AudioCallbackDriver::GetCurrentTime() void AudioCallbackDriver::WaitForNextIteration() { +#if 0 + mGraphImpl->GetMonitor().AssertCurrentThreadOwns(); + + // We can't block on the monitor in the audio callback, so we kick off a new + // thread that will pause the audio stream, and restart it when unblocked. + // We don't want to sleep when we haven't started the driver yet. + if (!mGraphImpl->mNeedAnotherIteration && mAudioStream && mGraphImpl->Running()) { + STREAM_LOG(PR_LOG_DEBUG+1, ("AudioCallbackDriver going to sleep")); + mPauseRequested = true; + nsRefPtr sleepEvent = + new AsyncCubebTask(this, AsyncCubebTask::SLEEP); + sleepEvent->Dispatch(); + } +#endif } void @@ -1060,47 +1074,5 @@ AudioCallbackDriver::IsStarted() { return mStarted; } -void -AudioCallbackDriver::EnqueueStreamAndPromiseForOperation(MediaStream* aStream, - void* aPromise, - dom::AudioContextOperation aOperation) -{ - MonitorAutoLock mon(mGraphImpl->GetMonitor()); - mPromisesForOperation.AppendElement(StreamAndPromiseForOperation(aStream, - aPromise, - aOperation)); -} - -void AudioCallbackDriver::CompleteAudioContextOperations(AsyncCubebOperation aOperation) -{ - nsAutoTArray array; - - // We can't lock for the whole function because AudioContextOperationCompleted - // will grab the monitor - { - MonitorAutoLock mon(GraphImpl()->GetMonitor()); - array.SwapElements(mPromisesForOperation); - } - - for (int32_t i = array.Length() - 1; i >= 0; i--) { - StreamAndPromiseForOperation& s = array[i]; - if ((aOperation == AsyncCubebOperation::INIT && - s.mOperation == AudioContextOperation::Resume) || - (aOperation == AsyncCubebOperation::SHUTDOWN && - s.mOperation != AudioContextOperation::Resume)) { - - GraphImpl()->AudioContextOperationCompleted(s.mStream, - s.mPromise, - s.mOperation); - array.RemoveElementAt(i); - } - } - - if (!array.IsEmpty()) { - MonitorAutoLock mon(GraphImpl()->GetMonitor()); - mPromisesForOperation.AppendElements(array); - } -} - } // namepace mozilla diff --git a/dom/media/GraphDriver.h b/dom/media/GraphDriver.h index 5bc64866c24d..de387ec17621 100644 --- a/dom/media/GraphDriver.h +++ b/dom/media/GraphDriver.h @@ -13,7 +13,6 @@ #include "AudioSegment.h" #include "SelfRef.h" #include "mozilla/Atomics.h" -#include "AudioContext.h" struct cubeb_stream; @@ -322,21 +321,6 @@ private: GraphTime mSlice; }; -struct StreamAndPromiseForOperation -{ - StreamAndPromiseForOperation(MediaStream* aStream, - void* aPromise, - dom::AudioContextOperation aOperation); - nsRefPtr mStream; - void* mPromise; - dom::AudioContextOperation mOperation; -}; - -enum AsyncCubebOperation { - INIT, - SHUTDOWN -}; - /** * This is a graph driver that is based on callback functions called by the * audio api. This ensures minimal audio latency, because it means there is no @@ -408,12 +392,6 @@ public: return this; } - /* Enqueue a promise that is going to be resolved when a specific operation - * occurs on the cubeb stream. */ - void EnqueueStreamAndPromiseForOperation(MediaStream* aStream, - void* aPromise, - dom::AudioContextOperation aOperation); - bool IsSwitchingDevice() { #ifdef XP_MACOSX return mSelfReference; @@ -436,8 +414,6 @@ public: /* Tell the driver whether this process is using a microphone or not. This is * thread safe. */ void SetMicrophoneActive(bool aActive); - - void CompleteAudioContextOperations(AsyncCubebOperation aOperation); private: /** * On certain MacBookPro, the microphone is located near the left speaker. @@ -495,7 +471,6 @@ private: /* Thread for off-main-thread initialization and * shutdown of the audio stream. */ nsCOMPtr mInitShutdownThread; - nsAutoTArray mPromisesForOperation; dom::AudioChannel mAudioChannel; Atomic mInCallback; /* A thread has been created to be able to pause and restart the audio thread, @@ -523,6 +498,12 @@ private: class AsyncCubebTask : public nsRunnable { public: + enum AsyncCubebOperation { + INIT, + SHUTDOWN, + SLEEP + }; + AsyncCubebTask(AudioCallbackDriver* aDriver, AsyncCubebOperation aOperation); diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index 5730c9077f6b..83614b3dc88e 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -24,7 +24,6 @@ #include "AudioNodeEngine.h" #include "AudioNodeStream.h" #include "AudioNodeExternalInputStream.h" -#include "mozilla/dom/AudioContextBinding.h" #include #include "DOMMediaStream.h" #include "GeckoProfiler.h" @@ -103,31 +102,12 @@ MediaStreamGraphImpl::FinishStream(MediaStream* aStream) SetStreamOrderDirty(); } -static const GraphTime START_TIME_DELAYED = -1; - void MediaStreamGraphImpl::AddStream(MediaStream* aStream) { - // Check if we're adding a stream to a suspended context, in which case, we - // add it to mSuspendedStreams, and delay setting mBufferStartTime - bool contextSuspended = false; - if (aStream->AsAudioNodeStream()) { - for (uint32_t i = 0; i < mSuspendedStreams.Length(); i++) { - if (aStream->AudioContextId() == mSuspendedStreams[i]->AudioContextId()) { - contextSuspended = true; - } - } - } - - if (contextSuspended) { - aStream->mBufferStartTime = START_TIME_DELAYED; - mSuspendedStreams.AppendElement(aStream); - STREAM_LOG(PR_LOG_DEBUG, ("Adding media stream %p to the graph, in the suspended stream array", aStream)); - } else { - aStream->mBufferStartTime = IterationEnd(); - mStreams.AppendElement(aStream); - STREAM_LOG(PR_LOG_DEBUG, ("Adding media stream %p to the graph", aStream)); - } + aStream->mBufferStartTime = IterationEnd(); + mStreams.AppendElement(aStream); + STREAM_LOG(PR_LOG_DEBUG, ("Adding media stream %p to the graph", aStream)); SetStreamOrderDirty(); } @@ -151,8 +131,6 @@ MediaStreamGraphImpl::RemoveStream(MediaStream* aStream) SetStreamOrderDirty(); mStreams.RemoveElement(aStream); - mSuspendedStreams.RemoveElement(aStream); - NS_RELEASE(aStream); // probably destroying it STREAM_LOG(PR_LOG_DEBUG, ("Removing media stream %p from the graph", aStream)); @@ -402,64 +380,49 @@ MediaStreamGraphImpl::UpdateCurrentTimeForStreams(GraphTime aPrevCurrentTime, Gr { nsTArray streamsReadyToFinish; nsAutoTArray streamHasOutput; - - nsTArray* runningAndSuspendedPair[2]; - runningAndSuspendedPair[0] = &mStreams; - runningAndSuspendedPair[1] = &mSuspendedStreams; - streamHasOutput.SetLength(mStreams.Length()); + for (uint32_t i = 0; i < mStreams.Length(); ++i) { + MediaStream* stream = mStreams[i]; - for (uint32_t array = 0; array < 2; array++) { - for (uint32_t i = 0; i < runningAndSuspendedPair[array]->Length(); ++i) { - MediaStream* stream = (*runningAndSuspendedPair[array])[i]; - - // Calculate blocked time and fire Blocked/Unblocked events - GraphTime blockedTime = 0; - GraphTime t = aPrevCurrentTime; - // include |nextCurrentTime| to ensure NotifyBlockingChanged() is called - // before NotifyEvent(this, EVENT_FINISHED) when |nextCurrentTime == - // stream end time| - while (t <= aNextCurrentTime) { - GraphTime end; - bool blocked = stream->mBlocked.GetAt(t, &end); - if (blocked) { - blockedTime += std::min(end, aNextCurrentTime) - t; - } - if (blocked != stream->mNotifiedBlocked) { - for (uint32_t j = 0; j < stream->mListeners.Length(); ++j) { - MediaStreamListener* l = stream->mListeners[j]; - l->NotifyBlockingChanged(this, blocked - ? MediaStreamListener::BLOCKED - : MediaStreamListener::UNBLOCKED); - } - stream->mNotifiedBlocked = blocked; - } - t = end; + // Calculate blocked time and fire Blocked/Unblocked events + GraphTime blockedTime = 0; + GraphTime t = aPrevCurrentTime; + // include |nextCurrentTime| to ensure NotifyBlockingChanged() is called + // before NotifyEvent(this, EVENT_FINISHED) when |nextCurrentTime == stream end time| + while (t <= aNextCurrentTime) { + GraphTime end; + bool blocked = stream->mBlocked.GetAt(t, &end); + if (blocked) { + blockedTime += std::min(end, aNextCurrentTime) - t; } - - stream->AdvanceTimeVaryingValuesToCurrentTime(aNextCurrentTime, - blockedTime); - // Advance mBlocked last so that implementations of - // AdvanceTimeVaryingValuesToCurrentTime can rely on the value of - // mBlocked. - stream->mBlocked.AdvanceCurrentTime(aNextCurrentTime); - - if (runningAndSuspendedPair[array] == &mStreams) { - streamHasOutput[i] = blockedTime < aNextCurrentTime - aPrevCurrentTime; - // Make this an assertion when bug 957832 is fixed. - NS_WARN_IF_FALSE( - !streamHasOutput[i] || !stream->mNotifiedFinished, - "Shouldn't have already notified of finish *and* have output!"); - - if (stream->mFinished && !stream->mNotifiedFinished) { - streamsReadyToFinish.AppendElement(stream); + if (blocked != stream->mNotifiedBlocked) { + for (uint32_t j = 0; j < stream->mListeners.Length(); ++j) { + MediaStreamListener* l = stream->mListeners[j]; + l->NotifyBlockingChanged(this, + blocked ? MediaStreamListener::BLOCKED : MediaStreamListener::UNBLOCKED); } + stream->mNotifiedBlocked = blocked; } - STREAM_LOG(PR_LOG_DEBUG + 1, - ("MediaStream %p bufferStartTime=%f blockedTime=%f", stream, - MediaTimeToSeconds(stream->mBufferStartTime), - MediaTimeToSeconds(blockedTime))); + t = end; } + + + stream->AdvanceTimeVaryingValuesToCurrentTime(aNextCurrentTime, blockedTime); + // Advance mBlocked last so that implementations of + // AdvanceTimeVaryingValuesToCurrentTime can rely on the value of mBlocked. + stream->mBlocked.AdvanceCurrentTime(aNextCurrentTime); + + streamHasOutput[i] = blockedTime < aNextCurrentTime - aPrevCurrentTime; + // Make this an assertion when bug 957832 is fixed. + NS_WARN_IF_FALSE(!streamHasOutput[i] || !stream->mNotifiedFinished, + "Shouldn't have already notified of finish *and* have output!"); + + if (stream->mFinished && !stream->mNotifiedFinished) { + streamsReadyToFinish.AppendElement(stream); + } + STREAM_LOG(PR_LOG_DEBUG+1, ("MediaStream %p bufferStartTime=%f blockedTime=%f", + stream, MediaTimeToSeconds(stream->mBufferStartTime), + MediaTimeToSeconds(blockedTime))); } @@ -557,21 +520,6 @@ MediaStreamGraphImpl::MarkConsumed(MediaStream* aStream) } } -bool -MediaStreamGraphImpl::StreamSuspended(MediaStream* aStream) -{ - // Only AudioNodeStreams can be suspended, so we can shortcut here. - return aStream->AsAudioNodeStream() && - mSuspendedStreams.IndexOf(aStream) != mSuspendedStreams.NoIndex; -} - -namespace { - // Value of mCycleMarker for unvisited streams in cycle detection. - const uint32_t NOT_VISITED = UINT32_MAX; - // Value of mCycleMarker for ordered streams in muted cycles. - const uint32_t IN_MUTED_CYCLE = 1; -} - void MediaStreamGraphImpl::UpdateStreamOrder() { @@ -579,6 +527,11 @@ MediaStreamGraphImpl::UpdateStreamOrder() bool shouldAEC = false; #endif bool audioTrackPresent = false; + // Value of mCycleMarker for unvisited streams in cycle detection. + const uint32_t NOT_VISITED = UINT32_MAX; + // Value of mCycleMarker for ordered streams in muted cycles. + const uint32_t IN_MUTED_CYCLE = 1; + for (uint32_t i = 0; i < mStreams.Length(); ++i) { MediaStream* stream = mStreams[i]; stream->mIsConsumed = false; @@ -694,17 +647,10 @@ MediaStreamGraphImpl::UpdateStreamOrder() // Not-visited input streams should be processed first. // SourceMediaStreams have already been ordered. for (uint32_t i = inputs.Length(); i--; ) { - if (StreamSuspended(inputs[i]->mSource)) { - continue; - } auto input = inputs[i]->mSource->AsProcessedStream(); if (input && input->mCycleMarker == NOT_VISITED) { - // It can be that this stream has an input which is from a suspended - // AudioContext. - if (input->isInList()) { - input->remove(); - dfsStack.insertFront(input); - } + input->remove(); + dfsStack.insertFront(input); } } continue; @@ -720,9 +666,6 @@ MediaStreamGraphImpl::UpdateStreamOrder() // unless it is part of the cycle. uint32_t cycleStackMarker = 0; for (uint32_t i = inputs.Length(); i--; ) { - if (StreamSuspended(inputs[i]->mSource)) { - continue; - } auto input = inputs[i]->mSource->AsProcessedStream(); if (input) { cycleStackMarker = std::max(cycleStackMarker, input->mCycleMarker); @@ -818,37 +761,30 @@ MediaStreamGraphImpl::RecomputeBlocking(GraphTime aEndBlockingDecisions) STREAM_LOG(PR_LOG_DEBUG+1, ("Media graph %p computing blocking for time %f", this, MediaTimeToSeconds(CurrentDriver()->StateComputedTime()))); - nsTArray* runningAndSuspendedPair[2]; - runningAndSuspendedPair[0] = &mStreams; - runningAndSuspendedPair[1] = &mSuspendedStreams; - - for (uint32_t array = 0; array < 2; array++) { - for (uint32_t i = 0; i < (*runningAndSuspendedPair[array]).Length(); ++i) { - MediaStream* stream = (*runningAndSuspendedPair[array])[i]; - if (!stream->mInBlockingSet) { - // Compute a partition of the streams containing 'stream' such that we - // can - // compute the blocking status of each subset independently. - nsAutoTArray streamSet; - AddBlockingRelatedStreamsToSet(&streamSet, stream); - - GraphTime end; - for (GraphTime t = CurrentDriver()->StateComputedTime(); - t < aEndBlockingDecisions; t = end) { - end = GRAPH_TIME_MAX; - RecomputeBlockingAt(streamSet, t, aEndBlockingDecisions, &end); - if (end < GRAPH_TIME_MAX) { - blockingDecisionsWillChange = true; - } - } - } + for (uint32_t i = 0; i < mStreams.Length(); ++i) { + MediaStream* stream = mStreams[i]; + if (!stream->mInBlockingSet) { + // Compute a partition of the streams containing 'stream' such that we can + // compute the blocking status of each subset independently. + nsAutoTArray streamSet; + AddBlockingRelatedStreamsToSet(&streamSet, stream); GraphTime end; - stream->mBlocked.GetAt(IterationEnd(), &end); - if (end < GRAPH_TIME_MAX) { - blockingDecisionsWillChange = true; + for (GraphTime t = CurrentDriver()->StateComputedTime(); + t < aEndBlockingDecisions; t = end) { + end = GRAPH_TIME_MAX; + RecomputeBlockingAt(streamSet, t, aEndBlockingDecisions, &end); + if (end < GRAPH_TIME_MAX) { + blockingDecisionsWillChange = true; + } } } + + GraphTime end; + stream->mBlocked.GetAt(IterationEnd(), &end); + if (end < GRAPH_TIME_MAX) { + blockingDecisionsWillChange = true; + } } STREAM_LOG(PR_LOG_DEBUG+1, ("Media graph %p computed blocking for interval %f to %f", this, MediaTimeToSeconds(CurrentDriver()->StateComputedTime()), @@ -1062,6 +998,14 @@ MediaStreamGraphImpl::PlayAudio(MediaStream* aStream, // sample. One sample may be played twice, but this should not happen // again during an unblocked sequence of track samples. StreamTime offset = GraphTimeToStreamTime(aStream, aFrom); + if (audioOutput.mLastTickWritten && + audioOutput.mLastTickWritten != offset) { + // If there is a global underrun of the MSG, this property won't hold, and + // we reset the sample count tracking. + if (offset - audioOutput.mLastTickWritten == 1) { + offset = audioOutput.mLastTickWritten; + } + } // We don't update aStream->mBufferStartTime here to account for time spent // blocked. Instead, we'll update it in UpdateCurrentTimeForStreams after @@ -1093,13 +1037,11 @@ MediaStreamGraphImpl::PlayAudio(MediaStream* aStream, } else { StreamTime endTicksNeeded = offset + toWrite; StreamTime endTicksAvailable = audio->GetDuration(); + STREAM_LOG(PR_LOG_DEBUG+1, ("MediaStream %p writing %ld samples for %f to %f (samples %ld to %ld)\n", + aStream, toWrite, MediaTimeToSeconds(t), MediaTimeToSeconds(end), + offset, endTicksNeeded)); if (endTicksNeeded <= endTicksAvailable) { - STREAM_LOG(PR_LOG_DEBUG + 1, - ("MediaStream %p writing %ld samples for %f to %f " - "(samples %ld to %ld)\n", - aStream, toWrite, MediaTimeToSeconds(t), - MediaTimeToSeconds(end), offset, endTicksNeeded)); output.AppendSlice(*audio, offset, endTicksNeeded); ticksWritten += toWrite; offset = endTicksNeeded; @@ -1110,22 +1052,12 @@ MediaStreamGraphImpl::PlayAudio(MediaStream* aStream, if (endTicksNeeded > endTicksAvailable && offset < endTicksAvailable) { output.AppendSlice(*audio, offset, endTicksAvailable); - STREAM_LOG(PR_LOG_DEBUG + 1, - ("MediaStream %p writing %ld samples for %f to %f " - "(samples %ld to %ld)\n", - aStream, toWrite, MediaTimeToSeconds(t), - MediaTimeToSeconds(end), offset, endTicksNeeded)); uint32_t available = endTicksAvailable - offset; ticksWritten += available; toWrite -= available; offset = endTicksAvailable; } output.AppendNullData(toWrite); - STREAM_LOG(PR_LOG_DEBUG + 1, - ("MediaStream %p writing %ld padding slsamples for %f to " - "%f (samples %ld to %ld)\n", - aStream, toWrite, MediaTimeToSeconds(t), - MediaTimeToSeconds(end), offset, endTicksNeeded)); ticksWritten += toWrite; } output.ApplyVolume(volume); @@ -1857,7 +1789,7 @@ MediaStreamGraphImpl::EnsureStableStateEventPosted() void MediaStreamGraphImpl::AppendMessage(ControlMessage* aMessage) { - MOZ_ASSERT(NS_IsMainThread(), "main thread only"); + NS_ASSERTION(NS_IsMainThread(), "main thread only"); NS_ASSERTION(!aMessage->GetStream() || !aMessage->GetStream()->IsDestroyed(), "Stream already destroyed"); @@ -2216,46 +2148,6 @@ MediaStream::ChangeExplicitBlockerCount(int32_t aDelta) GraphImpl()->AppendMessage(new Message(this, aDelta)); } -void -MediaStream::BlockStreamIfNeeded() -{ - class Message : public ControlMessage { - public: - explicit Message(MediaStream* aStream) : ControlMessage(aStream) - { } - virtual void Run() - { - mStream->BlockStreamIfNeededImpl( - mStream->GraphImpl()->CurrentDriver()->StateComputedTime()); - } - }; - - if (mMainThreadDestroyed) { - return; - } - GraphImpl()->AppendMessage(new Message(this)); -} - -void -MediaStream::UnblockStreamIfNeeded() -{ - class Message : public ControlMessage { - public: - explicit Message(MediaStream* aStream) : ControlMessage(aStream) - { } - virtual void Run() - { - mStream->UnblockStreamIfNeededImpl( - mStream->GraphImpl()->CurrentDriver()->StateComputedTime()); - } - }; - - if (mMainThreadDestroyed) { - return; - } - GraphImpl()->AppendMessage(new Message(this)); -} - void MediaStream::AddListenerImpl(already_AddRefed aListener) { @@ -3139,8 +3031,7 @@ MediaStreamGraph::CreateAudioNodeExternalInputStream(AudioNodeEngine* aEngine, T if (!aSampleRate) { aSampleRate = aEngine->NodeMainThread()->Context()->SampleRate(); } - AudioNodeExternalInputStream* stream = new AudioNodeExternalInputStream( - aEngine, aSampleRate, aEngine->NodeMainThread()->Context()->Id()); + AudioNodeExternalInputStream* stream = new AudioNodeExternalInputStream(aEngine, aSampleRate); NS_ADDREF(stream); MediaStreamGraphImpl* graph = static_cast(this); stream->SetGraphImpl(graph); @@ -3157,12 +3048,7 @@ MediaStreamGraph::CreateAudioNodeStream(AudioNodeEngine* aEngine, if (!aSampleRate) { aSampleRate = aEngine->NodeMainThread()->Context()->SampleRate(); } - // MediaRecorders use an AudioNodeStream, but no AudioNode - AudioNode* node = aEngine->NodeMainThread(); - dom::AudioContext::AudioContextId contextIdForStream = node ? node->Context()->Id() : - NO_AUDIO_CONTEXT; - AudioNodeStream* stream = new AudioNodeStream(aEngine, aKind, aSampleRate, - contextIdForStream); + AudioNodeStream* stream = new AudioNodeStream(aEngine, aKind, aSampleRate); NS_ADDREF(stream); MediaStreamGraphImpl* graph = static_cast(this); stream->SetGraphImpl(graph); @@ -3175,273 +3061,6 @@ MediaStreamGraph::CreateAudioNodeStream(AudioNodeEngine* aEngine, return stream; } -class GraphStartedRunnable final : public nsRunnable -{ -public: - GraphStartedRunnable(AudioNodeStream* aStream, MediaStreamGraph* aGraph) - : mStream(aStream) - , mGraph(aGraph) - { } - - NS_IMETHOD Run() { - mGraph->NotifyWhenGraphStarted(mStream); - return NS_OK; - } - -private: - nsRefPtr mStream; - MediaStreamGraph* mGraph; -}; - -void -MediaStreamGraph::NotifyWhenGraphStarted(AudioNodeStream* aStream) -{ - class GraphStartedNotificationControlMessage : public ControlMessage - { - public: - explicit GraphStartedNotificationControlMessage(AudioNodeStream* aStream) - : ControlMessage(aStream) - { - } - virtual void Run() - { - // This runs on the graph thread, so when this runs, and the current - // driver is an AudioCallbackDriver, we know the audio hardware is - // started. If not, we are going to switch soon, keep reposting this - // ControlMessage. - MediaStreamGraphImpl* graphImpl = mStream->GraphImpl(); - if (graphImpl->CurrentDriver()->AsAudioCallbackDriver()) { - nsCOMPtr event = new dom::StateChangeTask( - mStream->AsAudioNodeStream(), nullptr, AudioContextState::Running); - NS_DispatchToMainThread(event); - } else { - nsCOMPtr event = new GraphStartedRunnable( - mStream->AsAudioNodeStream(), mStream->Graph()); - NS_DispatchToMainThread(event); - } - } - virtual void RunDuringShutdown() - { - MOZ_ASSERT(false, "We should be reviving the graph?"); - } - }; - - MediaStreamGraphImpl* graphImpl = static_cast(this); - graphImpl->AppendMessage(new GraphStartedNotificationControlMessage(aStream)); -} - -void -MediaStreamGraphImpl::ResetVisitedStreamState() -{ - // Reset the visited/consumed/blocked state of the streams. - nsTArray* runningAndSuspendedPair[2]; - runningAndSuspendedPair[0] = &mStreams; - runningAndSuspendedPair[1] = &mSuspendedStreams; - - for (uint32_t array = 0; array < 2; array++) { - for (uint32_t i = 0; i < runningAndSuspendedPair[array]->Length(); ++i) { - ProcessedMediaStream* ps = - (*runningAndSuspendedPair[array])[i]->AsProcessedStream(); - if (ps) { - ps->mCycleMarker = NOT_VISITED; - ps->mIsConsumed = false; - ps->mInBlockingSet = false; - } - } - } -} - -void -MediaStreamGraphImpl::StreamSetForAudioContext(dom::AudioContext::AudioContextId aAudioContextId, - mozilla::LinkedList& aStreamSet) -{ - nsTArray* runningAndSuspendedPair[2]; - runningAndSuspendedPair[0] = &mStreams; - runningAndSuspendedPair[1] = &mSuspendedStreams; - - for (uint32_t array = 0; array < 2; array++) { - for (uint32_t i = 0; i < runningAndSuspendedPair[array]->Length(); ++i) { - MediaStream* stream = (*runningAndSuspendedPair[array])[i]; - if (aAudioContextId == stream->AudioContextId()) { - aStreamSet.insertFront(stream); - } - } - } -} - -void -MediaStreamGraphImpl::MoveStreams(AudioContextOperation aAudioContextOperation, - mozilla::LinkedList& aStreamSet) -{ - // For our purpose, Suspend and Close are equivalent: we want to remove the - // streams from the set of streams that are going to be processed. - nsTArray& from = - aAudioContextOperation == AudioContextOperation::Resume ? mSuspendedStreams - : mStreams; - nsTArray& to = - aAudioContextOperation == AudioContextOperation::Resume ? mStreams - : mSuspendedStreams; - - MediaStream* stream; - while ((stream = aStreamSet.getFirst())) { - // It is posible to not find the stream here, if there has been two - // suspend/resume/close calls in a row. - auto i = from.IndexOf(stream); - if (i != from.NoIndex) { - from.RemoveElementAt(i); - to.AppendElement(stream); - } - - // If streams got added during a period where an AudioContext was suspended, - // set their buffer start time to the appropriate value now: - if (aAudioContextOperation == AudioContextOperation::Resume && - stream->mBufferStartTime == START_TIME_DELAYED) { - stream->mBufferStartTime = IterationEnd(); - } - - stream->remove(); - } - STREAM_LOG(PR_LOG_DEBUG, ("Moving streams between suspended and running" - "state: mStreams: %d, mSuspendedStreams: %d\n", mStreams.Length(), - mSuspendedStreams.Length())); -#ifdef DEBUG - // The intersection of the two arrays should be null. - for (uint32_t i = 0; i < mStreams.Length(); i++) { - for (uint32_t j = 0; j < mSuspendedStreams.Length(); j++) { - MOZ_ASSERT( - mStreams[i] != mSuspendedStreams[j], - "The suspended stream set and running stream set are not disjoint."); - } - } -#endif -} - -void -MediaStreamGraphImpl::AudioContextOperationCompleted(MediaStream* aStream, - void* aPromise, - AudioContextOperation aOperation) -{ - // This can be called from the thread created to do cubeb operation, or the - // MSG thread. The pointers passed back here are refcounted, so are still - // alive. - MonitorAutoLock lock(mMonitor); - - AudioContextState state; - switch (aOperation) { - case Suspend: state = AudioContextState::Suspended; break; - case Resume: state = AudioContextState::Running; break; - case Close: state = AudioContextState::Closed; break; - default: MOZ_CRASH("Not handled."); - } - - nsCOMPtr event = new dom::StateChangeTask( - aStream->AsAudioNodeStream(), aPromise, state); - NS_DispatchToMainThread(event); -} - -void -MediaStreamGraphImpl::ApplyAudioContextOperationImpl(AudioNodeStream* aStream, - AudioContextOperation aOperation, - void* aPromise) -{ - MOZ_ASSERT(CurrentDriver()->OnThread()); - mozilla::LinkedList streamSet; - - SetStreamOrderDirty(); - - ResetVisitedStreamState(); - - StreamSetForAudioContext(aStream->AudioContextId(), streamSet); - - MoveStreams(aOperation, streamSet); - MOZ_ASSERT(!streamSet.getFirst(), - "Streams should be removed from the list after having been moved."); - - // If we have suspended the last AudioContext, and we don't have other - // streams that have audio, this graph will automatically switch to a - // SystemCallbackDriver, because it can't find a MediaStream that has an audio - // track. When resuming, force switching to an AudioCallbackDriver. It would - // have happened at the next iteration anyways, but doing this now save - // some time. - if (aOperation == AudioContextOperation::Resume) { - if (!CurrentDriver()->AsAudioCallbackDriver()) { - AudioCallbackDriver* driver = new AudioCallbackDriver(this); - driver->EnqueueStreamAndPromiseForOperation(aStream, aPromise, aOperation); - mMixer.AddCallback(driver); - CurrentDriver()->SwitchAtNextIteration(driver); - } else { - // We are resuming a context, but we are already using an - // AudioCallbackDriver, we can resolve the promise now. - AudioContextOperationCompleted(aStream, aPromise, aOperation); - } - } - // Close, suspend: check if we are going to switch to a - // SystemAudioCallbackDriver, and pass the promise to the AudioCallbackDriver - // if that's the case, so it can notify the content. - // This is the same logic as in UpdateStreamOrder, but it's simpler to have it - // here as well so we don't have to store the Promise(s) on the Graph. - if (aOperation != AudioContextOperation::Resume) { - bool audioTrackPresent = false; - for (uint32_t i = 0; i < mStreams.Length(); ++i) { - MediaStream* stream = mStreams[i]; - if (stream->AsAudioNodeStream()) { - audioTrackPresent = true; - } - for (StreamBuffer::TrackIter tracks(stream->GetStreamBuffer(), MediaSegment::AUDIO); - !tracks.IsEnded(); tracks.Next()) { - audioTrackPresent = true; - } - } - if (!audioTrackPresent && CurrentDriver()->AsAudioCallbackDriver()) { - CurrentDriver()->AsAudioCallbackDriver()-> - EnqueueStreamAndPromiseForOperation(aStream, aPromise, aOperation); - - SystemClockDriver* driver = new SystemClockDriver(this); - CurrentDriver()->SwitchAtNextIteration(driver); - } else { - // We are closing or suspending an AudioContext, but something else is - // using the audio stream, we can resolve the promise now. - AudioContextOperationCompleted(aStream, aPromise, aOperation); - } - } -} - -void -MediaStreamGraph::ApplyAudioContextOperation(AudioNodeStream* aNodeStream, - AudioContextOperation aOperation, - void* aPromise) -{ - class AudioContextOperationControlMessage : public ControlMessage - { - public: - AudioContextOperationControlMessage(AudioNodeStream* aStream, - AudioContextOperation aOperation, - void* aPromise) - : ControlMessage(aStream) - , mAudioContextOperation(aOperation) - , mPromise(aPromise) - { - } - virtual void Run() - { - mStream->GraphImpl()->ApplyAudioContextOperationImpl( - mStream->AsAudioNodeStream(), mAudioContextOperation, mPromise); - } - virtual void RunDuringShutdown() - { - MOZ_ASSERT(false, "We should be reviving the graph?"); - } - - private: - AudioContextOperation mAudioContextOperation; - void* mPromise; - }; - - MediaStreamGraphImpl* graphImpl = static_cast(this); - graphImpl->AppendMessage( - new AudioContextOperationControlMessage(aNodeStream, aOperation, aPromise)); -} - bool MediaStreamGraph::IsNonRealtime() const { diff --git a/dom/media/MediaStreamGraph.h b/dom/media/MediaStreamGraph.h index 43a0cd0aaca2..efd07611e7c9 100644 --- a/dom/media/MediaStreamGraph.h +++ b/dom/media/MediaStreamGraph.h @@ -22,7 +22,6 @@ #include #include "mozilla/dom/AudioChannelBinding.h" #include "DOMMediaStream.h" -#include "AudioContext.h" class nsIRunnable; @@ -319,7 +318,6 @@ public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStream) explicit MediaStream(DOMMediaStream* aWrapper); - virtual dom::AudioContext::AudioContextId AudioContextId() const { return 0; } protected: // Protected destructor, to discourage deletion outside of Release(): @@ -366,8 +364,6 @@ public: // Explicitly block. Useful for example if a media element is pausing // and we need to stop its stream emitting its buffered data. virtual void ChangeExplicitBlockerCount(int32_t aDelta); - void BlockStreamIfNeeded(); - void UnblockStreamIfNeeded(); // Events will be dispatched by calling methods of aListener. virtual void AddListener(MediaStreamListener* aListener); virtual void RemoveListener(MediaStreamListener* aListener); @@ -469,22 +465,6 @@ public: { mExplicitBlockerCount.SetAtAndAfter(aTime, mExplicitBlockerCount.GetAt(aTime) + aDelta); } - void BlockStreamIfNeededImpl(GraphTime aTime) - { - bool blocked = mExplicitBlockerCount.GetAt(aTime) > 0; - if (blocked) { - return; - } - ChangeExplicitBlockerCountImpl(aTime, 1); - } - void UnblockStreamIfNeededImpl(GraphTime aTime) - { - bool blocked = mExplicitBlockerCount.GetAt(aTime) > 0; - if (!blocked) { - return; - } - ChangeExplicitBlockerCountImpl(aTime, -1); - } void AddListenerImpl(already_AddRefed aListener); void RemoveListenerImpl(MediaStreamListener* aListener); void RemoveAllListenersImpl(); @@ -1247,21 +1227,6 @@ public: CreateAudioNodeExternalInputStream(AudioNodeEngine* aEngine, TrackRate aSampleRate = 0); - /* From the main thread, ask the MSG to send back an event when the graph - * thread is running, and audio is being processed. */ - void NotifyWhenGraphStarted(AudioNodeStream* aNodeStream); - /* From the main thread, suspend, resume or close an AudioContext. - * aNodeStream is the stream of the DestinationNode of the AudioContext. - * - * This can possibly pause the graph thread, releasing system resources, if - * all streams have been suspended/closed. - * - * When the operation is complete, aPromise is resolved. - */ - void ApplyAudioContextOperation(AudioNodeStream* aNodeStream, - dom::AudioContextOperation aState, - void * aPromise); - bool IsNonRealtime() const; /** * Start processing non-realtime for a specific number of ticks. diff --git a/dom/media/MediaStreamGraphImpl.h b/dom/media/MediaStreamGraphImpl.h index 5e25740ca853..a4b57b7d1655 100644 --- a/dom/media/MediaStreamGraphImpl.h +++ b/dom/media/MediaStreamGraphImpl.h @@ -248,49 +248,6 @@ public: * Mark aStream and all its inputs (recursively) as consumed. */ static void MarkConsumed(MediaStream* aStream); - - /** - * Given the Id of an AudioContext, return the set of all MediaStreams that - * are part of this context. - */ - void StreamSetForAudioContext(dom::AudioContext::AudioContextId aAudioContextId, - mozilla::LinkedList& aStreamSet); - - /** - * Called when a suspend/resume/close operation has been completed, on the - * graph thread. - */ - void AudioContextOperationCompleted(MediaStream* aStream, - void* aPromise, - dom::AudioContextOperation aOperation); - - /** - * Apply and AudioContext operation (suspend/resume/closed), on the graph - * thread. - */ - void ApplyAudioContextOperationImpl(AudioNodeStream* aStream, - dom::AudioContextOperation aOperation, - void* aPromise); - - /* - * Move streams from the mStreams to mSuspendedStream if suspending/closing an - * AudioContext, or the inverse when resuming an AudioContext. - */ - void MoveStreams(dom::AudioContextOperation aAudioContextOperation, - mozilla::LinkedList& aStreamSet); - - /* - * Reset some state about the streams before suspending them, or resuming - * them. - */ - void ResetVisitedStreamState(); - - /* - * True if a stream is suspended, that is, is not in mStreams, but in - * mSuspendedStream. - */ - bool StreamSuspended(MediaStream* aStream); - /** * Sort mStreams so that every stream not in a cycle is after any streams * it depends on, and every stream in a cycle is marked as being in a cycle. @@ -411,10 +368,7 @@ public: /** * Returns true when there are no active streams. */ - bool IsEmpty() - { - return mStreams.IsEmpty() && mSuspendedStreams.IsEmpty() && mPortCount == 0; - } + bool IsEmpty() { return mStreams.IsEmpty() && mPortCount == 0; } // For use by control messages, on graph thread only. /** @@ -533,13 +487,6 @@ public: * unnecessary thread-safe refcount changes. */ nsTArray mStreams; - /** - * This stores MediaStreams that are part of suspended AudioContexts. - * mStreams and mSuspendStream are disjoint sets: a stream is either suspended - * or not suspended. Suspended streams are not ordered in UpdateStreamOrder, - * and are therefore not doing any processing. - */ - nsTArray mSuspendedStreams; /** * Streams from mFirstCycleBreaker to the end of mStreams produce output * before they receive input. They correspond to DelayNodes that are in diff --git a/dom/media/TrackUnionStream.cpp b/dom/media/TrackUnionStream.cpp index fddc04ad05d8..bb59bf9867b8 100644 --- a/dom/media/TrackUnionStream.cpp +++ b/dom/media/TrackUnionStream.cpp @@ -24,10 +24,10 @@ #include "AudioNodeEngine.h" #include "AudioNodeStream.h" #include "AudioNodeExternalInputStream.h" -#include "webaudio/MediaStreamAudioDestinationNode.h" #include #include "DOMMediaStream.h" #include "GeckoProfiler.h" +#include "mozilla/unused.h" #ifdef MOZ_WEBRTC #include "AudioOutputObserver.h" #endif @@ -275,16 +275,12 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) : } else if (InMutedCycle()) { segment->AppendNullData(ticks); } else { - if (GraphImpl()->StreamSuspended(source)) { - segment->AppendNullData(aTo - aFrom); - } else { - MOZ_ASSERT(outputTrack->GetEnd() == GraphTimeToStreamTime(interval.mStart), - "Samples missing"); - StreamTime inputStart = source->GraphTimeToStreamTime(interval.mStart); - segment->AppendSlice(*aInputTrack->GetSegment(), - std::min(inputTrackEndPoint, inputStart), - std::min(inputTrackEndPoint, inputEnd)); - } + MOZ_ASSERT(outputTrack->GetEnd() == GraphTimeToStreamTime(interval.mStart), + "Samples missing"); + StreamTime inputStart = source->GraphTimeToStreamTime(interval.mStart); + segment->AppendSlice(*aInputTrack->GetSegment(), + std::min(inputTrackEndPoint, inputStart), + std::min(inputTrackEndPoint, inputEnd)); } ApplyTrackDisabling(outputTrack->GetID(), segment); for (uint32_t j = 0; j < mListeners.Length(); ++j) { diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp index 7779d197d641..81033d1cec0f 100644 --- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -9,8 +9,8 @@ #include "nsPIDOMWindow.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/AnalyserNode.h" -#include "mozilla/dom/HTMLMediaElement.h" #include "mozilla/dom/AudioContextBinding.h" +#include "mozilla/dom/HTMLMediaElement.h" #include "mozilla/dom/OfflineAudioContextBinding.h" #include "mozilla/dom/OwningNonNull.h" #include "MediaStreamGraph.h" @@ -42,10 +42,6 @@ namespace mozilla { namespace dom { -// 0 is a special value that MediaStreams use to denote they are not part of a -// AudioContext. -static dom::AudioContext::AudioContextId gAudioContextId = 1; - NS_IMPL_CYCLE_COLLECTION_CLASS(AudioContext) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioContext) @@ -89,15 +85,12 @@ AudioContext::AudioContext(nsPIDOMWindow* aWindow, uint32_t aLength, float aSampleRate) : DOMEventTargetHelper(aWindow) - , mId(gAudioContextId++) , mSampleRate(GetSampleRateForAudioContext(aIsOffline, aSampleRate)) - , mAudioContextState(AudioContextState::Suspended) , mNumberOfChannels(aNumberOfChannels) , mNodeCount(0) , mIsOffline(aIsOffline) , mIsStarted(!aIsOffline) , mIsShutDown(false) - , mCloseCalled(false) { aWindow->AddAudioContext(this); @@ -204,22 +197,9 @@ AudioContext::Constructor(const GlobalObject& aGlobal, return object.forget(); } -bool AudioContext::CheckClosed(ErrorResult& aRv) -{ - if (mAudioContextState == AudioContextState::Closed) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return true; - } - return false; -} - already_AddRefed -AudioContext::CreateBufferSource(ErrorResult& aRv) +AudioContext::CreateBufferSource() { - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr bufferNode = new AudioBufferSourceNode(this); return bufferNode.forget(); @@ -267,10 +247,6 @@ AudioContext::CreateMediaStreamDestination(ErrorResult& aRv) return nullptr; } - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr node = new MediaStreamAudioDestinationNode(this); return node.forget(); @@ -290,10 +266,6 @@ AudioContext::CreateScriptProcessor(uint32_t aBufferSize, return nullptr; } - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr scriptProcessor = new ScriptProcessorNode(this, aBufferSize, aNumberOfInputChannels, aNumberOfOutputChannels); @@ -301,23 +273,15 @@ AudioContext::CreateScriptProcessor(uint32_t aBufferSize, } already_AddRefed -AudioContext::CreateAnalyser(ErrorResult& aRv) +AudioContext::CreateAnalyser() { - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr analyserNode = new AnalyserNode(this); return analyserNode.forget(); } already_AddRefed -AudioContext::CreateStereoPanner(ErrorResult& aRv) +AudioContext::CreateStereoPanner() { - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr stereoPannerNode = new StereoPannerNode(this); return stereoPannerNode.forget(); } @@ -336,11 +300,6 @@ AudioContext::CreateMediaElementSource(HTMLMediaElement& aMediaElement, return nullptr; } #endif - - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr stream = aMediaElement.MozCaptureStream(aRv, mDestination->Stream()->Graph()); if (aRv.Failed()) { @@ -359,34 +318,21 @@ AudioContext::CreateMediaStreamSource(DOMMediaStream& aMediaStream, aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return nullptr; } - - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr mediaStreamAudioSourceNode = new MediaStreamAudioSourceNode(this, &aMediaStream); return mediaStreamAudioSourceNode.forget(); } already_AddRefed -AudioContext::CreateGain(ErrorResult& aRv) +AudioContext::CreateGain() { - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr gainNode = new GainNode(this); return gainNode.forget(); } already_AddRefed -AudioContext::CreateWaveShaper(ErrorResult& aRv) +AudioContext::CreateWaveShaper() { - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr waveShaperNode = new WaveShaperNode(this); return waveShaperNode.forget(); } @@ -394,38 +340,25 @@ AudioContext::CreateWaveShaper(ErrorResult& aRv) already_AddRefed AudioContext::CreateDelay(double aMaxDelayTime, ErrorResult& aRv) { - if (CheckClosed(aRv)) { - return nullptr; - } - if (aMaxDelayTime > 0. && aMaxDelayTime < 180.) { nsRefPtr delayNode = new DelayNode(this, aMaxDelayTime); return delayNode.forget(); } - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return nullptr; } already_AddRefed -AudioContext::CreatePanner(ErrorResult& aRv) +AudioContext::CreatePanner() { - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr pannerNode = new PannerNode(this); mPannerNodes.PutEntry(pannerNode); return pannerNode.forget(); } already_AddRefed -AudioContext::CreateConvolver(ErrorResult& aRv) +AudioContext::CreateConvolver() { - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr convolverNode = new ConvolverNode(this); return convolverNode.forget(); } @@ -439,10 +372,6 @@ AudioContext::CreateChannelSplitter(uint32_t aNumberOfOutputs, ErrorResult& aRv) return nullptr; } - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr splitterNode = new ChannelSplitterNode(this, aNumberOfOutputs); return splitterNode.forget(); @@ -457,46 +386,30 @@ AudioContext::CreateChannelMerger(uint32_t aNumberOfInputs, ErrorResult& aRv) return nullptr; } - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr mergerNode = new ChannelMergerNode(this, aNumberOfInputs); return mergerNode.forget(); } already_AddRefed -AudioContext::CreateDynamicsCompressor(ErrorResult& aRv) +AudioContext::CreateDynamicsCompressor() { - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr compressorNode = new DynamicsCompressorNode(this); return compressorNode.forget(); } already_AddRefed -AudioContext::CreateBiquadFilter(ErrorResult& aRv) +AudioContext::CreateBiquadFilter() { - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr filterNode = new BiquadFilterNode(this); return filterNode.forget(); } already_AddRefed -AudioContext::CreateOscillator(ErrorResult& aRv) +AudioContext::CreateOscillator() { - if (CheckClosed(aRv)) { - return nullptr; - } - nsRefPtr oscillatorNode = new OscillatorNode(this); return oscillatorNode.forget(); @@ -684,239 +597,22 @@ AudioContext::Shutdown() } } -AudioContextState AudioContext::State() const +void +AudioContext::Suspend() { - return mAudioContextState; -} - -StateChangeTask::StateChangeTask(AudioContext* aAudioContext, - void* aPromise, - AudioContextState aNewState) - : mAudioContext(aAudioContext) - , mPromise(aPromise) - , mAudioNodeStream(nullptr) - , mNewState(aNewState) -{ - MOZ_ASSERT(NS_IsMainThread(), - "This constructor should be used from the main thread."); -} - -StateChangeTask::StateChangeTask(AudioNodeStream* aStream, - void* aPromise, - AudioContextState aNewState) - : mAudioContext(nullptr) - , mPromise(aPromise) - , mAudioNodeStream(aStream) - , mNewState(aNewState) -{ - MOZ_ASSERT(!NS_IsMainThread(), - "This constructor should be used from the graph thread."); -} - -NS_IMETHODIMP -StateChangeTask::Run() -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (!mAudioContext && !mAudioNodeStream) { - return NS_OK; + MediaStream* ds = DestinationStream(); + if (ds) { + ds->ChangeExplicitBlockerCount(1); } - if (mAudioNodeStream) { - AudioNode* node = mAudioNodeStream->Engine()->NodeMainThread(); - if (!node) { - return NS_OK; - } - mAudioContext = node->Context(); - if (!mAudioContext) { - return NS_OK; - } - } - - mAudioContext->OnStateChanged(mPromise, mNewState); - // We have can't call Release() on the AudioContext on the MSG thread, so we - // unref it here, on the main thread. - mAudioContext = nullptr; - - return NS_OK; } -/* This runnable allows to fire the "statechange" event */ -class OnStateChangeTask final : public nsRunnable -{ -public: - explicit OnStateChangeTask(AudioContext* aAudioContext) - : mAudioContext(aAudioContext) - {} - - NS_IMETHODIMP - Run() override - { - nsCOMPtr parent = do_QueryInterface(mAudioContext->GetParentObject()); - if (!parent) { - return NS_ERROR_FAILURE; - } - - nsIDocument* doc = parent->GetExtantDoc(); - if (!doc) { - return NS_ERROR_FAILURE; - } - - return nsContentUtils::DispatchTrustedEvent(doc, - static_cast(mAudioContext), - NS_LITERAL_STRING("statechange"), - false, false); - } - -private: - nsRefPtr mAudioContext; -}; - - - void -AudioContext::OnStateChanged(void* aPromise, AudioContextState aNewState) +AudioContext::Resume() { - MOZ_ASSERT(NS_IsMainThread()); - - MOZ_ASSERT((mAudioContextState == AudioContextState::Suspended && - aNewState == AudioContextState::Running) || - (mAudioContextState == AudioContextState::Running && - aNewState == AudioContextState::Suspended) || - (mAudioContextState == AudioContextState::Running && - aNewState == AudioContextState::Closed) || - (mAudioContextState == AudioContextState::Suspended && - aNewState == AudioContextState::Closed) || - (mAudioContextState == aNewState), - "Invalid AudioContextState transition"); - - MOZ_ASSERT( - mIsOffline || aPromise || aNewState == AudioContextState::Running, - "We should have a promise here if this is a real-time AudioContext." - "Or this is the first time we switch to \"running\"."); - - if (aPromise) { - Promise* promise = reinterpret_cast(aPromise); - promise->MaybeResolve(JS::UndefinedHandleValue); - DebugOnly rv = mPromiseGripArray.RemoveElement(promise); - MOZ_ASSERT(rv, "Promise wasn't in the grip array?"); - } - - if (mAudioContextState != aNewState) { - nsRefPtr onStateChangeTask = - new OnStateChangeTask(this); - NS_DispatchToMainThread(onStateChangeTask); - } - - mAudioContextState = aNewState; -} - -already_AddRefed -AudioContext::Suspend(ErrorResult& aRv) -{ - nsCOMPtr parentObject = do_QueryInterface(GetParentObject()); - nsRefPtr promise; - promise = Promise::Create(parentObject, aRv); - if (aRv.Failed()) { - return nullptr; - } - if (mIsOffline) { - promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return promise.forget(); - } - - if (mAudioContextState == AudioContextState::Closed || - mCloseCalled) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); - return promise.forget(); - } - - if (mAudioContextState == AudioContextState::Suspended) { - promise->MaybeResolve(JS::UndefinedHandleValue); - return promise.forget(); - } - MediaStream* ds = DestinationStream(); if (ds) { - ds->BlockStreamIfNeeded(); + ds->ChangeExplicitBlockerCount(-1); } - - mPromiseGripArray.AppendElement(promise); - Graph()->ApplyAudioContextOperation(DestinationStream()->AsAudioNodeStream(), - AudioContextOperation::Suspend, promise); - - return promise.forget(); -} - -already_AddRefed -AudioContext::Resume(ErrorResult& aRv) -{ - nsCOMPtr parentObject = do_QueryInterface(GetParentObject()); - nsRefPtr promise; - promise = Promise::Create(parentObject, aRv); - if (aRv.Failed()) { - return nullptr; - } - - if (mIsOffline) { - promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return promise.forget(); - } - - if (mAudioContextState == AudioContextState::Closed || - mCloseCalled) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); - return promise.forget(); - } - - if (mAudioContextState == AudioContextState::Running) { - promise->MaybeResolve(JS::UndefinedHandleValue); - return promise.forget(); - } - - MediaStream* ds = DestinationStream(); - if (ds) { - ds->UnblockStreamIfNeeded(); - } - - mPromiseGripArray.AppendElement(promise); - Graph()->ApplyAudioContextOperation(DestinationStream()->AsAudioNodeStream(), - AudioContextOperation::Resume, promise); - - return promise.forget(); -} - -already_AddRefed -AudioContext::Close(ErrorResult& aRv) -{ - nsCOMPtr parentObject = do_QueryInterface(GetParentObject()); - nsRefPtr promise; - promise = Promise::Create(parentObject, aRv); - if (aRv.Failed()) { - return nullptr; - } - - if (mIsOffline) { - promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return promise.forget(); - } - - if (mAudioContextState == AudioContextState::Closed) { - promise->MaybeResolve(NS_ERROR_DOM_INVALID_STATE_ERR); - return promise.forget(); - } - - mCloseCalled = true; - - mPromiseGripArray.AppendElement(promise); - Graph()->ApplyAudioContextOperation(DestinationStream()->AsAudioNodeStream(), - AudioContextOperation::Close, promise); - - MediaStream* ds = DestinationStream(); - if (ds) { - ds->BlockStreamIfNeeded(); - } - - return promise.forget(); } void @@ -957,9 +653,6 @@ AudioContext::StartRendering(ErrorResult& aRv) mIsStarted = true; nsRefPtr promise = Promise::Create(parentObject, aRv); mDestination->StartRendering(promise); - - OnStateChanged(nullptr, AudioContextState::Running); - return promise.forget(); } diff --git a/dom/media/webaudio/AudioContext.h b/dom/media/webaudio/AudioContext.h index 20e7f5b64823..ed9a7fe55bd9 100644 --- a/dom/media/webaudio/AudioContext.h +++ b/dom/media/webaudio/AudioContext.h @@ -35,12 +35,9 @@ class DOMMediaStream; class ErrorResult; class MediaStream; class MediaStreamGraph; -class AudioNodeEngine; -class AudioNodeStream; namespace dom { -enum class AudioContextState : uint32_t; class AnalyserNode; class AudioBuffer; class AudioBufferSourceNode; @@ -67,30 +64,6 @@ class WaveShaperNode; class PeriodicWave; class Promise; -/* This runnable allows the MSG to notify the main thread when audio is actually - * flowing */ -class StateChangeTask final : public nsRunnable -{ -public: - /* This constructor should be used when this event is sent from the main - * thread. */ - StateChangeTask(AudioContext* aAudioContext, void* aPromise, AudioContextState aNewState); - - /* This constructor should be used when this event is sent from the audio - * thread. */ - StateChangeTask(AudioNodeStream* aStream, void* aPromise, AudioContextState aNewState); - - NS_IMETHOD Run() override; - -private: - nsRefPtr mAudioContext; - void* mPromise; - nsRefPtr mAudioNodeStream; - AudioContextState mNewState; -}; - -enum AudioContextOperation { Suspend, Resume, Close }; - class AudioContext final : public DOMEventTargetHelper, public nsIMemoryReporter { @@ -103,8 +76,6 @@ class AudioContext final : public DOMEventTargetHelper, ~AudioContext(); public: - typedef uint64_t AudioContextId; - NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioContext, DOMEventTargetHelper) @@ -116,6 +87,8 @@ public: } void Shutdown(); // idempotent + void Suspend(); + void Resume(); virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; @@ -151,31 +124,11 @@ public: return mSampleRate; } - AudioContextId Id() const - { - return mId; - } - double CurrentTime() const; AudioListener* Listener(); - AudioContextState State() const; - // Those three methods return a promise to content, that is resolved when an - // (possibly long) operation is completed on the MSG (and possibly other) - // thread(s). To avoid having to match the calls and asychronous result when - // the operation is completed, we keep a reference to the promises on the main - // thread, and then send the promises pointers down the MSG thread, as a void* - // (to make it very clear that the pointer is to merely be treated as an ID). - // When back on the main thread, we can resolve or reject the promise, by - // casting it back to a `Promise*` while asserting we're back on the main - // thread and removing the reference we added. - already_AddRefed Suspend(ErrorResult& aRv); - already_AddRefed Resume(ErrorResult& aRv); - already_AddRefed Close(ErrorResult& aRv); - IMPL_EVENT_HANDLER(statechange) - - already_AddRefed CreateBufferSource(ErrorResult& aRv); + already_AddRefed CreateBufferSource(); already_AddRefed CreateBuffer(JSContext* aJSContext, uint32_t aNumberOfChannels, @@ -192,16 +145,16 @@ public: ErrorResult& aRv); already_AddRefed - CreateStereoPanner(ErrorResult& aRv); + CreateStereoPanner(); already_AddRefed - CreateAnalyser(ErrorResult& aRv); + CreateAnalyser(); already_AddRefed - CreateGain(ErrorResult& aRv); + CreateGain(); already_AddRefed - CreateWaveShaper(ErrorResult& aRv); + CreateWaveShaper(); already_AddRefed CreateMediaElementSource(HTMLMediaElement& aMediaElement, ErrorResult& aRv); @@ -212,10 +165,10 @@ public: CreateDelay(double aMaxDelayTime, ErrorResult& aRv); already_AddRefed - CreatePanner(ErrorResult& aRv); + CreatePanner(); already_AddRefed - CreateConvolver(ErrorResult& aRv); + CreateConvolver(); already_AddRefed CreateChannelSplitter(uint32_t aNumberOfOutputs, ErrorResult& aRv); @@ -224,13 +177,13 @@ public: CreateChannelMerger(uint32_t aNumberOfInputs, ErrorResult& aRv); already_AddRefed - CreateDynamicsCompressor(ErrorResult& aRv); + CreateDynamicsCompressor(); already_AddRefed - CreateBiquadFilter(ErrorResult& aRv); + CreateBiquadFilter(); already_AddRefed - CreateOscillator(ErrorResult& aRv); + CreateOscillator(); already_AddRefed CreatePeriodicWave(const Float32Array& aRealData, const Float32Array& aImagData, @@ -291,8 +244,6 @@ public: return aTime + ExtraCurrentTime(); } - void OnStateChanged(void* aPromise, AudioContextState aNewState); - IMPL_EVENT_HANDLER(mozinterruptbegin) IMPL_EVENT_HANDLER(mozinterruptend) @@ -315,23 +266,13 @@ private: friend struct ::mozilla::WebAudioDecodeJob; - bool CheckClosed(ErrorResult& aRv); - private: - // Each AudioContext has an id, that is passed down the MediaStreams that - // back the AudioNodes, so we can easily compute the set of all the - // MediaStreams for a given context, on the MediasStreamGraph side. - const AudioContextId mId; // Note that it's important for mSampleRate to be initialized before // mDestination, as mDestination's constructor needs to access it! const float mSampleRate; - AudioContextState mAudioContextState; nsRefPtr mDestination; nsRefPtr mListener; nsTArray > mDecodeJobs; - // This array is used to keep the suspend/resume/close promises alive until - // they are resolved, so we can safely pass them accross threads. - nsTArray> mPromiseGripArray; // See RegisterActiveNode. These will keep the AudioContext alive while it // is rendering and the window remains alive. nsTHashtable > mActiveNodes; @@ -345,12 +286,8 @@ private: bool mIsOffline; bool mIsStarted; bool mIsShutDown; - // Close has been called, reject suspend and resume call. - bool mCloseCalled; }; -static const dom::AudioContext::AudioContextId NO_AUDIO_CONTEXT = 0; - } } diff --git a/dom/media/webaudio/AudioDestinationNode.cpp b/dom/media/webaudio/AudioDestinationNode.cpp index 172bbd7c858c..08030c0f72ec 100644 --- a/dom/media/webaudio/AudioDestinationNode.cpp +++ b/dom/media/webaudio/AudioDestinationNode.cpp @@ -5,7 +5,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AudioDestinationNode.h" -#include "AudioContext.h" #include "mozilla/dom/AudioDestinationNodeBinding.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/Preferences.h" @@ -177,11 +176,9 @@ public: aNode->ResolvePromise(renderedBuffer); - nsRefPtr onCompleteTask = + nsRefPtr task = new OnCompleteTask(context, renderedBuffer); - NS_DispatchToMainThread(onCompleteTask); - - context->OnStateChanged(nullptr, AudioContextState::Closed); + NS_DispatchToMainThread(task); } virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override @@ -370,10 +367,6 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext, mStream->AddMainThreadListener(this); mStream->AddAudioOutput(&gWebAudioOutputKey); - if (!aIsOffline) { - graph->NotifyWhenGraphStarted(mStream->AsAudioNodeStream()); - } - if (aChannel != AudioChannel::Normal) { ErrorResult rv; SetMozAudioChannelType(aChannel, rv); diff --git a/dom/media/webaudio/AudioNodeExternalInputStream.cpp b/dom/media/webaudio/AudioNodeExternalInputStream.cpp index b165af71d0c9..15442c27f432 100644 --- a/dom/media/webaudio/AudioNodeExternalInputStream.cpp +++ b/dom/media/webaudio/AudioNodeExternalInputStream.cpp @@ -12,8 +12,8 @@ using namespace mozilla::dom; namespace mozilla { -AudioNodeExternalInputStream::AudioNodeExternalInputStream(AudioNodeEngine* aEngine, TrackRate aSampleRate, uint32_t aContextId) - : AudioNodeStream(aEngine, MediaStreamGraph::INTERNAL_STREAM, aSampleRate, aContextId) +AudioNodeExternalInputStream::AudioNodeExternalInputStream(AudioNodeEngine* aEngine, TrackRate aSampleRate) + : AudioNodeStream(aEngine, MediaStreamGraph::INTERNAL_STREAM, aSampleRate) { MOZ_COUNT_CTOR(AudioNodeExternalInputStream); } diff --git a/dom/media/webaudio/AudioNodeExternalInputStream.h b/dom/media/webaudio/AudioNodeExternalInputStream.h index d2248a8232e7..92b9b782d336 100644 --- a/dom/media/webaudio/AudioNodeExternalInputStream.h +++ b/dom/media/webaudio/AudioNodeExternalInputStream.h @@ -20,7 +20,7 @@ namespace mozilla { */ class AudioNodeExternalInputStream : public AudioNodeStream { public: - AudioNodeExternalInputStream(AudioNodeEngine* aEngine, TrackRate aSampleRate, uint32_t aContextId); + AudioNodeExternalInputStream(AudioNodeEngine* aEngine, TrackRate aSampleRate); protected: ~AudioNodeExternalInputStream(); diff --git a/dom/media/webaudio/AudioNodeStream.cpp b/dom/media/webaudio/AudioNodeStream.cpp index 8e23ec160850..2fcf4ab8edfe 100644 --- a/dom/media/webaudio/AudioNodeStream.cpp +++ b/dom/media/webaudio/AudioNodeStream.cpp @@ -27,12 +27,10 @@ namespace mozilla { AudioNodeStream::AudioNodeStream(AudioNodeEngine* aEngine, MediaStreamGraph::AudioNodeStreamKind aKind, - TrackRate aSampleRate, - AudioContext::AudioContextId aContextId) + TrackRate aSampleRate) : ProcessedMediaStream(nullptr), mEngine(aEngine), mSampleRate(aSampleRate), - mAudioContextId(aContextId), mKind(aKind), mNumberOfInputChannels(2), mMarkAsFinishedAfterThisBlock(false), diff --git a/dom/media/webaudio/AudioNodeStream.h b/dom/media/webaudio/AudioNodeStream.h index 52711abefba5..0956478873f4 100644 --- a/dom/media/webaudio/AudioNodeStream.h +++ b/dom/media/webaudio/AudioNodeStream.h @@ -47,8 +47,7 @@ public: */ AudioNodeStream(AudioNodeEngine* aEngine, MediaStreamGraph::AudioNodeStreamKind aKind, - TrackRate aSampleRate, - AudioContext::AudioContextId aContextId); + TrackRate aSampleRate); protected: ~AudioNodeStream(); @@ -122,7 +121,6 @@ public: // Any thread AudioNodeEngine* Engine() { return mEngine; } TrackRate SampleRate() const { return mSampleRate; } - AudioContext::AudioContextId AudioContextId() const override { return mAudioContextId; } /** * Convert a time in seconds on the destination stream to ticks @@ -149,7 +147,6 @@ public: void SizeOfAudioNodesIncludingThis(MallocSizeOf aMallocSizeOf, AudioNodeSizes& aUsage) const; - protected: void AdvanceOutputSegment(); void FinishOutput(); @@ -169,11 +166,8 @@ protected: OutputChunks mLastChunks; // The stream's sampling rate const TrackRate mSampleRate; - // This is necessary to be able to find all the nodes for a given - // AudioContext. It is set on the main thread, in the constructor. - const AudioContext::AudioContextId mAudioContextId; // Whether this is an internal or external stream - const MediaStreamGraph::AudioNodeStreamKind mKind; + MediaStreamGraph::AudioNodeStreamKind mKind; // The number of input channels that this stream requires. 0 means don't care. uint32_t mNumberOfInputChannels; // The mixing modes diff --git a/dom/media/webaudio/MediaStreamAudioSourceNode.h b/dom/media/webaudio/MediaStreamAudioSourceNode.h index 1fcfff1f3ea3..a121c4a6111b 100644 --- a/dom/media/webaudio/MediaStreamAudioSourceNode.h +++ b/dom/media/webaudio/MediaStreamAudioSourceNode.h @@ -35,7 +35,6 @@ public: NS_ERROR("MediaStreamAudioSourceNodeEngine bad parameter index"); } } - private: bool mEnabled; }; diff --git a/dom/media/webaudio/moz.build b/dom/media/webaudio/moz.build index 966c7294c03a..b1bc05dd250f 100644 --- a/dom/media/webaudio/moz.build +++ b/dom/media/webaudio/moz.build @@ -31,7 +31,6 @@ EXPORTS += [ EXPORTS.mozilla += [ 'FFTBlock.h', - 'MediaStreamAudioDestinationNode.h', ] EXPORTS.mozilla.dom += [ diff --git a/dom/media/webaudio/test/mochitest.ini b/dom/media/webaudio/test/mochitest.ini index fcfceb737371..13424971599b 100644 --- a/dom/media/webaudio/test/mochitest.ini +++ b/dom/media/webaudio/test/mochitest.ini @@ -44,8 +44,6 @@ skip-if = (toolkit == 'android' && (processor == 'x86' || debug)) || os == 'win' skip-if = (toolkit == 'gonk') || (toolkit == 'android') || debug #bug 906752 [test_audioBufferSourceNodePassThrough.html] [test_AudioContext.html] -skip-if = android_version == '10' # bug 1138462 -[test_audioContextSuspendResumeClose.html] [test_audioDestinationNode.html] [test_AudioListener.html] [test_audioParamExponentialRamp.html] diff --git a/dom/media/webaudio/test/test_audioContextSuspendResumeClose.html b/dom/media/webaudio/test/test_audioContextSuspendResumeClose.html deleted file mode 100644 index 3007699d4010..000000000000 --- a/dom/media/webaudio/test/test_audioContextSuspendResumeClose.html +++ /dev/null @@ -1,400 +0,0 @@ - - - - Test suspend, resume and close method of the AudioContext - - - - - -
-
-
- - diff --git a/dom/media/webaudio/test/webaudio.js b/dom/media/webaudio/test/webaudio.js index 34a69fa92fc7..0effda1a1e7c 100644 --- a/dom/media/webaudio/test/webaudio.js +++ b/dom/media/webaudio/test/webaudio.js @@ -33,18 +33,6 @@ function expectTypeError(func) { ok(threw, "The exception was thrown"); } -function expectRejectedPromise(that, func, exceptionName) { - var promise = that[func](); - - ok(promise instanceof Promise, "Expect a Promise"); - - promise.then(function(res) { - ok(false, "Promise resolved when it should have been rejected."); - }).catch(function(err) { - is(err.name, exceptionName, "Promise correctly reject with " + exceptionName); - }); -} - function fuzzyCompare(a, b) { return Math.abs(a - b) < 9e-3; } diff --git a/dom/webidl/AudioContext.webidl b/dom/webidl/AudioContext.webidl index 791c3568af9f..94e1ac158d3f 100644 --- a/dom/webidl/AudioContext.webidl +++ b/dom/webidl/AudioContext.webidl @@ -13,12 +13,6 @@ callback DecodeSuccessCallback = void (AudioBuffer decodedData); callback DecodeErrorCallback = void (); -enum AudioContextState { - "suspended", - "running", - "closed" -}; - [Constructor, Constructor(AudioChannel audioChannelType)] interface AudioContext : EventTarget { @@ -27,14 +21,6 @@ interface AudioContext : EventTarget { readonly attribute float sampleRate; readonly attribute double currentTime; readonly attribute AudioListener listener; - readonly attribute AudioContextState state; - [Throws] - Promise suspend(); - [Throws] - Promise resume(); - [Throws] - Promise close(); - attribute EventHandler onstatechange; [NewObject, Throws] AudioBuffer createBuffer(unsigned long numberOfChannels, unsigned long length, float sampleRate); @@ -45,7 +31,7 @@ interface AudioContext : EventTarget { optional DecodeErrorCallback errorCallback); // AudioNode creation - [NewObject, Throws] + [NewObject] AudioBufferSourceNode createBufferSource(); [NewObject, Throws] @@ -56,25 +42,25 @@ interface AudioContext : EventTarget { optional unsigned long numberOfInputChannels = 2, optional unsigned long numberOfOutputChannels = 2); - [NewObject, Throws] + [NewObject] StereoPannerNode createStereoPanner(); - [NewObject, Throws] + [NewObject] AnalyserNode createAnalyser(); [NewObject, Throws, UnsafeInPrerendering] MediaElementAudioSourceNode createMediaElementSource(HTMLMediaElement mediaElement); [NewObject, Throws, UnsafeInPrerendering] MediaStreamAudioSourceNode createMediaStreamSource(MediaStream mediaStream); - [NewObject, Throws] + [NewObject] GainNode createGain(); [NewObject, Throws] DelayNode createDelay(optional double maxDelayTime = 1); - [NewObject, Throws] + [NewObject] BiquadFilterNode createBiquadFilter(); - [NewObject, Throws] + [NewObject] WaveShaperNode createWaveShaper(); - [NewObject, Throws] + [NewObject] PannerNode createPanner(); - [NewObject, Throws] + [NewObject] ConvolverNode createConvolver(); [NewObject, Throws] @@ -82,10 +68,10 @@ interface AudioContext : EventTarget { [NewObject, Throws] ChannelMergerNode createChannelMerger(optional unsigned long numberOfInputs = 6); - [NewObject, Throws] + [NewObject] DynamicsCompressorNode createDynamicsCompressor(); - [NewObject, Throws] + [NewObject] OscillatorNode createOscillator(); [NewObject, Throws] PeriodicWave createPeriodicWave(Float32Array real, Float32Array imag);