From 7bd3227e5d07fd25571135924dd066dc124d62db Mon Sep 17 00:00:00 2001 From: roytam1 Date: Tue, 16 Mar 2021 09:22:31 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 1141282 - DynamicCompressorNode's readonly 'reduction' should be a float. r=ehsan (4685d2cf8) - Bug 1153783 - Implement the `detune` AudioParam for the AudioBufferSourceNode. r=ehsan (8e6b3aca4) - Bug 1134034 - Add a chrome-only parentId and name on AudioParam for devtools. r=ehsan (13815cb94) - Bug 1159290 - "Add final/override to WebAudio classes". r=padenot (83cb303ea) - Bug 1161946 - MainThreadMediaStreamListener should be notified just when the stream is finished - patch 1, r=padenot (c2a126103) - Bug 1161946 - MainThreadMediaStreamListener should be notified just when the stream is finished - patch 2, r=padenot (a1f408cce) - Bug 1161946 - patch 3 - explicit CTOR for NotifyRunnable CLOSED TREE (f304c1ef0) - Bug 974089 - Destroy WebAudio MediaStream when a source finishes. r=padenot (66d7e20df) - Bug 1175510 - Update the AudioBufferSourceNode <=> PannerNode mapping when destroying AudioNodeStream. r=karlt (156741d15) - bug 1179662 uninline DestroyMediaStream overrides so that mStream type need not be complete r=padenot (08d0ebd62) - bug 1179662 specify AudioNode::mStream as AudioNodeStream r=padenot (3aaa3a544) - bug 1179662 handle null AudioNodeStream stream r=padenot (980a8296b) - bug 914392 don't check engine's Node existence in ProcessBlock r=padenot (583176721) --- dom/media/DOMMediaStream.cpp | 7 +- dom/media/DOMMediaStream.h | 4 +- dom/media/MediaRecorder.cpp | 13 +- dom/media/MediaStreamGraph.cpp | 56 ++++++- dom/media/MediaStreamGraph.h | 39 ++++- dom/media/webaudio/AnalyserNode.cpp | 47 +++--- dom/media/webaudio/AnalyserNode.h | 2 +- dom/media/webaudio/AudioBufferSourceNode.cpp | 142 +++++++++++------- dom/media/webaudio/AudioBufferSourceNode.h | 23 +-- dom/media/webaudio/AudioDestinationNode.cpp | 31 ++-- dom/media/webaudio/AudioDestinationNode.h | 3 +- dom/media/webaudio/AudioEventTimeline.h | 6 +- dom/media/webaudio/AudioNode.cpp | 77 +++++----- dom/media/webaudio/AudioNode.h | 13 +- dom/media/webaudio/AudioNodeEngine.h | 21 +-- .../webaudio/AudioNodeExternalInputStream.h | 9 +- dom/media/webaudio/AudioNodeStream.cpp | 66 +++++--- dom/media/webaudio/AudioNodeStream.h | 3 +- dom/media/webaudio/AudioParam.cpp | 13 +- dom/media/webaudio/AudioParam.h | 14 +- dom/media/webaudio/AudioProcessingEvent.h | 2 +- dom/media/webaudio/BiquadFilterNode.cpp | 14 +- dom/media/webaudio/BiquadFilterNode.h | 2 +- dom/media/webaudio/BufferDecoder.h | 2 +- dom/media/webaudio/ChannelMergerNode.cpp | 2 +- dom/media/webaudio/ChannelMergerNode.h | 2 +- dom/media/webaudio/ChannelSplitterNode.cpp | 2 +- dom/media/webaudio/ChannelSplitterNode.h | 2 +- dom/media/webaudio/ConvolverNode.cpp | 4 +- dom/media/webaudio/ConvolverNode.h | 2 +- dom/media/webaudio/DelayBuffer.h | 3 +- dom/media/webaudio/DelayNode.cpp | 8 +- dom/media/webaudio/DelayNode.h | 2 +- dom/media/webaudio/DynamicsCompressorNode.cpp | 39 ++--- dom/media/webaudio/DynamicsCompressorNode.h | 20 ++- dom/media/webaudio/FFTBlock.h | 3 +- dom/media/webaudio/GainNode.cpp | 8 +- dom/media/webaudio/GainNode.h | 2 +- dom/media/webaudio/MediaBufferDecoder.cpp | 10 +- .../webaudio/MediaElementAudioSourceNode.h | 2 +- .../MediaStreamAudioDestinationNode.h | 2 +- .../webaudio/MediaStreamAudioSourceNode.h | 2 +- .../webaudio/OfflineAudioCompletionEvent.h | 2 +- dom/media/webaudio/OscillatorNode.cpp | 101 +++++++------ dom/media/webaudio/OscillatorNode.h | 16 +- dom/media/webaudio/PannerNode.cpp | 7 +- dom/media/webaudio/PannerNode.h | 4 +- dom/media/webaudio/PlayingRefChangeHandler.h | 12 +- dom/media/webaudio/ReportDecodeResultTask.h | 2 +- dom/media/webaudio/ScriptProcessorNode.cpp | 22 +-- dom/media/webaudio/ScriptProcessorNode.h | 2 +- dom/media/webaudio/StereoPannerNode.cpp | 8 +- dom/media/webaudio/StereoPannerNode.h | 2 +- dom/media/webaudio/ThreeDPoint.h | 3 +- dom/media/webaudio/WaveShaperNode.cpp | 6 +- dom/media/webaudio/WaveShaperNode.h | 2 +- dom/media/webaudio/test/chrome.ini | 1 + dom/media/webaudio/test/mochitest.ini | 1 + .../test/test_AudioParamDevtoolsAPI.html | 48 ++++++ .../test/test_audioBufferSourceNodeRate.html | 66 ++++++++ .../test/test_dynamicsCompressorNode.html | 2 +- dom/media/webaudio/test/webaudio.js | 19 +++ dom/webidl/AudioBufferSourceNode.webidl | 1 + dom/webidl/AudioParam.webidl | 10 ++ dom/webidl/DynamicsCompressorNode.webidl | 2 +- 65 files changed, 662 insertions(+), 401 deletions(-) create mode 100644 dom/media/webaudio/test/test_AudioParamDevtoolsAPI.html create mode 100644 dom/media/webaudio/test/test_audioBufferSourceNodeRate.html diff --git a/dom/media/DOMMediaStream.cpp b/dom/media/DOMMediaStream.cpp index 507f4973ba..1f012f8fcd 100644 --- a/dom/media/DOMMediaStream.cpp +++ b/dom/media/DOMMediaStream.cpp @@ -475,11 +475,10 @@ DOMMediaStream::NotifyMediaStreamGraphShutdown() } void -DOMMediaStream::NotifyStreamStateChanged() +DOMMediaStream::NotifyStreamFinished() { - if (IsFinished()) { - mConsumersToKeepAlive.Clear(); - } + MOZ_ASSERT(IsFinished()); + mConsumersToKeepAlive.Clear(); } void diff --git a/dom/media/DOMMediaStream.h b/dom/media/DOMMediaStream.h index 83e96f0fe1..5c50796be0 100644 --- a/dom/media/DOMMediaStream.h +++ b/dom/media/DOMMediaStream.h @@ -178,9 +178,9 @@ public: */ void NotifyMediaStreamGraphShutdown(); /** - * Called when the main-thread state of the MediaStream changed. + * Called when the main-thread state of the MediaStream goes to finished. */ - void NotifyStreamStateChanged(); + void NotifyStreamFinished(); // Webrtc allows the remote side to name a stream whatever it wants, and we // need to surface this to content. diff --git a/dom/media/MediaRecorder.cpp b/dom/media/MediaRecorder.cpp index e1ef5f0032..9be55fe183 100644 --- a/dom/media/MediaRecorder.cpp +++ b/dom/media/MediaRecorder.cpp @@ -773,10 +773,13 @@ MediaRecorder::MediaRecorder(AudioNode& aSrcAudioNode, mPipeStream = ctx->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::EXTERNAL_STREAM, ctx->SampleRate()); - mInputPort = mPipeStream->AllocateInputPort(aSrcAudioNode.Stream(), - MediaInputPort::FLAG_BLOCK_INPUT, - 0, - aSrcOutput); + AudioNodeStream* ns = aSrcAudioNode.Stream(); + if (ns) { + mInputPort = mPipeStream->AllocateInputPort(aSrcAudioNode.Stream(), + MediaInputPort::FLAG_BLOCK_INPUT, + 0, + aSrcOutput); + } } mAudioNode = &aSrcAudioNode; if (!gMediaRecorderLog) { @@ -1153,7 +1156,7 @@ MediaRecorder::GetSourceMediaStream() return mDOMStream->GetStream(); } MOZ_ASSERT(mAudioNode != nullptr); - return mPipeStream != nullptr ? mPipeStream : mAudioNode->Stream(); + return mPipeStream != nullptr ? mPipeStream.get() : mAudioNode->Stream(); } nsIPrincipal* diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index 4d4d1965e0..264aa1eaa8 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -1557,11 +1557,12 @@ MediaStreamGraphImpl::ApplyStreamUpdate(StreamUpdate* aUpdate) stream->mMainThreadCurrentTime = aUpdate->mNextMainThreadCurrentTime; stream->mMainThreadFinished = aUpdate->mNextMainThreadFinished; - if (stream->mWrapper) { - stream->mWrapper->NotifyStreamStateChanged(); - } - for (int32_t i = stream->mMainThreadListeners.Length() - 1; i >= 0; --i) { - stream->mMainThreadListeners[i]->NotifyMainThreadStateChanged(); + if (stream->ShouldNotifyStreamFinished()) { + if (stream->mWrapper) { + stream->mWrapper->NotifyStreamFinished(); + } + + stream->NotifyMainThreadListeners(); } } @@ -1930,6 +1931,7 @@ MediaStream::MediaStream(DOMMediaStream* aWrapper) , mWrapper(aWrapper) , mMainThreadCurrentTime(0) , mMainThreadFinished(false) + , mFinishedNotificationSent(false) , mMainThreadDestroyed(false) , mGraph(nullptr) , mAudioChannelType(dom::AudioChannel::Normal) @@ -2415,6 +2417,50 @@ MediaStream::ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, Media } } +void +MediaStream::AddMainThreadListener(MainThreadMediaStreamListener* aListener) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aListener); + MOZ_ASSERT(!mMainThreadListeners.Contains(aListener)); + + mMainThreadListeners.AppendElement(aListener); + + // If we have to send the notification or we have a runnable that will do it, + // let finish here. + if (!mFinishedNotificationSent || mNotificationMainThreadRunnable) { + return; + } + + class NotifyRunnable final : public nsRunnable + { + public: + explicit NotifyRunnable(MediaStream* aStream) + : mStream(aStream) + {} + + NS_IMETHOD Run() override + { + MOZ_ASSERT(NS_IsMainThread()); + mStream->mNotificationMainThreadRunnable = nullptr; + mStream->NotifyMainThreadListeners(); + return NS_OK; + } + + private: + ~NotifyRunnable() {} + + nsRefPtr mStream; + }; + + nsRefPtr runnable = new NotifyRunnable(this); + if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)))) { + return; + } + + mNotificationMainThreadRunnable = runnable; +} + void SourceMediaStream::DestroyImpl() { diff --git a/dom/media/MediaStreamGraph.h b/dom/media/MediaStreamGraph.h index bed79cd70f..c660f1a2a7 100644 --- a/dom/media/MediaStreamGraph.h +++ b/dom/media/MediaStreamGraph.h @@ -224,7 +224,7 @@ public: */ class MainThreadMediaStreamListener { public: - virtual void NotifyMainThreadStateChanged() = 0; + virtual void NotifyMainThreadStreamFinished() = 0; }; /** @@ -371,20 +371,19 @@ public: // A disabled track has video replaced by black, and audio replaced by // silence. void SetTrackEnabled(TrackID aTrackID, bool aEnabled); - // Events will be dispatched by calling methods of aListener. It is the + + // Finish event will be notified by calling methods of aListener. It is the // responsibility of the caller to remove aListener before it is destroyed. - void AddMainThreadListener(MainThreadMediaStreamListener* aListener) - { - NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); - mMainThreadListeners.AppendElement(aListener); - } + void AddMainThreadListener(MainThreadMediaStreamListener* aListener); // It's safe to call this even if aListener is not currently a listener; // the call will be ignored. void RemoveMainThreadListener(MainThreadMediaStreamListener* aListener) { - NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aListener); mMainThreadListeners.RemoveElement(aListener); } + /** * Ensure a runnable will run on the main thread after running all pending * updates that were sent from the graph thread or will be sent before the @@ -415,6 +414,7 @@ public: NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); return mMainThreadFinished; } + bool IsDestroyed() { NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); @@ -594,6 +594,27 @@ protected: mBuffer.ForgetUpTo(aCurrentTime - mBufferStartTime); } + void NotifyMainThreadListeners() + { + NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); + + for (int32_t i = mMainThreadListeners.Length() - 1; i >= 0; --i) { + mMainThreadListeners[i]->NotifyMainThreadStreamFinished(); + } + mMainThreadListeners.Clear(); + } + + bool ShouldNotifyStreamFinished() + { + NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); + if (!mMainThreadFinished || mFinishedNotificationSent) { + return false; + } + + mFinishedNotificationSent = true; + return true; + } + // This state is all initialized on the main thread but // otherwise modified only on the media graph thread. @@ -622,6 +643,7 @@ protected: TimeVarying mExplicitBlockerCount; nsTArray > mListeners; nsTArray mMainThreadListeners; + nsRefPtr mNotificationMainThreadRunnable; nsTArray mDisabledTrackIDs; // Precomputed blocking status (over GraphTime). @@ -694,6 +716,7 @@ protected: // Main-thread views of state StreamTime mMainThreadCurrentTime; bool mMainThreadFinished; + bool mFinishedNotificationSent; bool mMainThreadDestroyed; // Our media stream graph. null if destroyed on the graph thread. diff --git a/dom/media/webaudio/AnalyserNode.cpp b/dom/media/webaudio/AnalyserNode.cpp index 663d5ba797..ca9b3ce5be 100644 --- a/dom/media/webaudio/AnalyserNode.cpp +++ b/dom/media/webaudio/AnalyserNode.cpp @@ -16,9 +16,9 @@ namespace dom { NS_IMPL_ISUPPORTS_INHERITED0(AnalyserNode, AudioNode) -class AnalyserNodeEngine : public AudioNodeEngine +class AnalyserNodeEngine final : public AudioNodeEngine { - class TransferBuffer : public nsRunnable + class TransferBuffer final : public nsRunnable { public: TransferBuffer(AudioNodeStream* aStream, @@ -30,15 +30,8 @@ class AnalyserNodeEngine : public AudioNodeEngine NS_IMETHOD Run() { - nsRefPtr node; - { - // No need to keep holding the lock for the whole duration of this - // function, since we're holding a strong reference to it, so if - // we can obtain the reference, we will hold the node alive in - // this function. - MutexAutoLock lock(mStream->Engine()->NodeMutex()); - node = static_cast(mStream->Engine()->Node()); - } + nsRefPtr node = + static_cast(mStream->Engine()->NodeMainThread()); if (node) { node->AppendChunk(mChunk); } @@ -64,25 +57,21 @@ public: { *aOutput = aInput; - MutexAutoLock lock(NodeMutex()); - - if (Node()) { - // If the input is silent, we sill need to send a silent buffer - if (aOutput->IsNull()) { - AllocateAudioBlock(1, aOutput); - float* samples = static_cast( - const_cast(aOutput->mChannelData[0])); - PodZero(samples, WEBAUDIO_BLOCK_SIZE); - } - uint32_t channelCount = aOutput->mChannelData.Length(); - for (uint32_t channel = 0; channel < channelCount; ++channel) { - float* samples = static_cast( - const_cast(aOutput->mChannelData[channel])); - AudioBlockInPlaceScale(samples, aOutput->mVolume); - } - nsRefPtr transfer = new TransferBuffer(aStream, *aOutput); - NS_DispatchToMainThread(transfer); + // If the input is silent, we sill need to send a silent buffer + if (aOutput->IsNull()) { + AllocateAudioBlock(1, aOutput); + float* samples = + static_cast(const_cast(aOutput->mChannelData[0])); + PodZero(samples, WEBAUDIO_BLOCK_SIZE); } + uint32_t channelCount = aOutput->mChannelData.Length(); + for (uint32_t channel = 0; channel < channelCount; ++channel) { + float* samples = + static_cast(const_cast(aOutput->mChannelData[channel])); + AudioBlockInPlaceScale(samples, aOutput->mVolume); + } + nsRefPtr transfer = new TransferBuffer(aStream, *aOutput); + NS_DispatchToMainThread(transfer); } virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override diff --git a/dom/media/webaudio/AnalyserNode.h b/dom/media/webaudio/AnalyserNode.h index e73865bf89..3d4e18fe77 100644 --- a/dom/media/webaudio/AnalyserNode.h +++ b/dom/media/webaudio/AnalyserNode.h @@ -15,7 +15,7 @@ namespace dom { class AudioContext; -class AnalyserNode : public AudioNode +class AnalyserNode final : public AudioNode { public: explicit AnalyserNode(AudioContext* aContext); diff --git a/dom/media/webaudio/AudioBufferSourceNode.cpp b/dom/media/webaudio/AudioBufferSourceNode.cpp index 75412a5f5a..0961ff9fd2 100644 --- a/dom/media/webaudio/AudioBufferSourceNode.cpp +++ b/dom/media/webaudio/AudioBufferSourceNode.cpp @@ -14,6 +14,7 @@ #include "AudioDestinationNode.h" #include "AudioParamTimeline.h" #include +#include namespace mozilla { namespace dom { @@ -23,19 +24,16 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(AudioBufferSourceNode) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioBufferSourceNode) NS_IMPL_CYCLE_COLLECTION_UNLINK(mBuffer) NS_IMPL_CYCLE_COLLECTION_UNLINK(mPlaybackRate) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDetune) if (tmp->Context()) { - // AudioNode's Unlink implementation disconnects us from the graph - // too, but we need to do this right here to make sure that - // UnregisterAudioBufferSourceNode can properly untangle us from - // the possibly connected PannerNodes. tmp->DisconnectFromGraph(); - tmp->Context()->UnregisterAudioBufferSourceNode(tmp); } NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(AudioNode) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(AudioBufferSourceNode, AudioNode) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBuffer) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlaybackRate) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDetune) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioBufferSourceNode) @@ -50,11 +48,11 @@ NS_IMPL_RELEASE_INHERITED(AudioBufferSourceNode, AudioNode) * AudioNodeStream::SetBuffer) and a non-zero mBufferEnd has been set (via * AudioNodeStream::SetInt32Parameter). */ -class AudioBufferSourceNodeEngine : public AudioNodeEngine +class AudioBufferSourceNodeEngine final : public AudioNodeEngine { public: - explicit AudioBufferSourceNodeEngine(AudioNode* aNode, - AudioDestinationNode* aDestination) : + AudioBufferSourceNodeEngine(AudioNode* aNode, + AudioDestinationNode* aDestination) : AudioNodeEngine(aNode), mStart(0.0), mBeginProcessing(0), mStop(STREAM_TIME_MAX), @@ -63,8 +61,10 @@ public: mLoopStart(0), mLoopEnd(0), mBufferSampleRate(0), mBufferPosition(0), mChannels(0), mDopplerShift(1.0f), - mDestination(static_cast(aDestination->Stream())), - mPlaybackRateTimeline(1.0f), mLoop(false) + mDestination(aDestination->Stream()), + mPlaybackRateTimeline(1.0f), + mDetuneTimeline(0.0f), + mLoop(false) {} ~AudioBufferSourceNodeEngine() @@ -88,6 +88,10 @@ public: mPlaybackRateTimeline = aValue; WebAudioUtils::ConvertAudioParamToTicks(mPlaybackRateTimeline, mSource, mDestination); break; + case AudioBufferSourceNode::DETUNE: + mDetuneTimeline = aValue; + WebAudioUtils::ConvertAudioParamToTicks(mDetuneTimeline, mSource, mDestination); + break; default: NS_ERROR("Bad AudioBufferSourceNodeEngine TimelineParameter"); } @@ -226,7 +230,7 @@ public: } // Resamples input data to an output buffer, according to |mBufferSampleRate| and - // the playbackRate. + // the playbackRate/detune. // The number of frames consumed/produced depends on the amount of space // remaining in both the input and output buffer, and the playback rate (that // is, the ratio between the output samplerate and the input samplerate). @@ -397,30 +401,39 @@ public: } } - int32_t ComputeFinalOutSampleRate(float aPlaybackRate) + int32_t ComputeFinalOutSampleRate(float aPlaybackRate, float aDetune) { + float computedPlaybackRate = aPlaybackRate * pow(2, aDetune / 1200.f); // Make sure the playback rate and the doppler shift are something // our resampler can work with. int32_t rate = WebAudioUtils:: TruncateFloatToInt(mSource->SampleRate() / - (aPlaybackRate * mDopplerShift)); + (computedPlaybackRate * mDopplerShift)); return rate ? rate : mBufferSampleRate; } void UpdateSampleRateIfNeeded(uint32_t aChannels) { float playbackRate; + float detune; if (mPlaybackRateTimeline.HasSimpleValue()) { playbackRate = mPlaybackRateTimeline.GetValue(); } else { playbackRate = mPlaybackRateTimeline.GetValueAtTime(mSource->GetCurrentPosition()); } + if (mDetuneTimeline.HasSimpleValue()) { + detune = mDetuneTimeline.GetValue(); + } else { + detune = mDetuneTimeline.GetValueAtTime(mSource->GetCurrentPosition()); + } if (playbackRate <= 0 || mozilla::IsNaN(playbackRate)) { playbackRate = 1.0f; } - int32_t outRate = ComputeFinalOutSampleRate(playbackRate); + detune = std::min(std::max(-1200.f, detune), 1200.f); + + int32_t outRate = ComputeFinalOutSampleRate(playbackRate, detune); UpdateResampler(outRate, aChannels); } @@ -440,9 +453,6 @@ public: return; } - // WebKit treats the playbackRate as a k-rate parameter in their code, - // despite the spec saying that it should be an a-rate parameter. We treat - // it as k-rate. Spec bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=21592 UpdateSampleRateIfNeeded(channels); uint32_t written = 0; @@ -488,6 +498,7 @@ public: // Not owned: // - mBuffer - shared w/ AudioNode // - mPlaybackRateTimeline - shared w/ AudioNode + // - mDetuneTimeline - shared w/ AudioNode size_t amount = AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf); @@ -530,6 +541,7 @@ public: AudioNodeStream* mDestination; AudioNodeStream* mSource; AudioParamTimeline mPlaybackRateTimeline; + AudioParamTimeline mDetuneTimeline; bool mLoop; }; @@ -541,19 +553,28 @@ AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext) , mLoopStart(0.0) , mLoopEnd(0.0) // mOffset and mDuration are initialized in Start(). - , mPlaybackRate(new AudioParam(this, SendPlaybackRateToStream, 1.0f)) + , mPlaybackRate(new AudioParam(this, SendPlaybackRateToStream, 1.0f, "playbackRate")) + , mDetune(new AudioParam(this, SendDetuneToStream, 0.0f, "detune")) , mLoop(false) , mStartCalled(false) - , mStopped(false) { AudioBufferSourceNodeEngine* engine = new AudioBufferSourceNodeEngine(this, aContext->Destination()); mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::SOURCE_STREAM); - engine->SetSourceStream(static_cast(mStream.get())); + engine->SetSourceStream(mStream); mStream->AddMainThreadListener(this); } AudioBufferSourceNode::~AudioBufferSourceNode() { +} + +void +AudioBufferSourceNode::DestroyMediaStream() +{ + if (mStream) { + mStream->RemoveMainThreadListener(this); + } + AudioNode::DestroyMediaStream(); if (Context()) { Context()->UnregisterAudioBufferSourceNode(this); } @@ -568,6 +589,7 @@ AudioBufferSourceNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const } amount += mPlaybackRate->SizeOfIncludingThis(aMallocSizeOf); + amount += mDetune->SizeOfIncludingThis(aMallocSizeOf); return amount; } @@ -599,7 +621,7 @@ AudioBufferSourceNode::Start(double aWhen, double aOffset, } mStartCalled = true; - AudioNodeStream* ns = static_cast(mStream.get()); + AudioNodeStream* ns = mStream; if (!ns) { // Nothing to play, or we're already dead for some reason return; @@ -624,8 +646,10 @@ AudioBufferSourceNode::Start(double aWhen, double aOffset, void AudioBufferSourceNode::SendBufferParameterToStream(JSContext* aCx) { - AudioNodeStream* ns = static_cast(mStream.get()); - MOZ_ASSERT(ns, "Why don't we have a stream here?"); + AudioNodeStream* ns = mStream; + if (!ns) { + return; + } if (mBuffer) { float rate = mBuffer->SampleRate(); @@ -681,7 +705,7 @@ AudioBufferSourceNode::Stop(double aWhen, ErrorResult& aRv) return; } - AudioNodeStream* ns = static_cast(mStream.get()); + AudioNodeStream* ns = mStream; if (!ns || !Context()) { // We've already stopped and had our stream shut down return; @@ -691,56 +715,72 @@ AudioBufferSourceNode::Stop(double aWhen, ErrorResult& aRv) } void -AudioBufferSourceNode::NotifyMainThreadStateChanged() +AudioBufferSourceNode::NotifyMainThreadStreamFinished() { - if (mStream->IsFinished()) { - class EndedEventDispatcher : public nsRunnable - { - public: - explicit EndedEventDispatcher(AudioBufferSourceNode* aNode) - : mNode(aNode) {} - NS_IMETHODIMP Run() - { - // If it's not safe to run scripts right now, schedule this to run later - if (!nsContentUtils::IsSafeToRunScript()) { - nsContentUtils::AddScriptRunner(this); - return NS_OK; - } + MOZ_ASSERT(mStream->IsFinished()); - mNode->DispatchTrustedEvent(NS_LITERAL_STRING("ended")); + class EndedEventDispatcher final : public nsRunnable + { + public: + explicit EndedEventDispatcher(AudioBufferSourceNode* aNode) + : mNode(aNode) {} + NS_IMETHODIMP Run() override + { + // If it's not safe to run scripts right now, schedule this to run later + if (!nsContentUtils::IsSafeToRunScript()) { + nsContentUtils::AddScriptRunner(this); return NS_OK; } - private: - nsRefPtr mNode; - }; - if (!mStopped) { - // Only dispatch the ended event once - NS_DispatchToMainThread(new EndedEventDispatcher(this)); - mStopped = true; - } - // Drop the playing reference - // Warning: The below line might delete this. - MarkInactive(); - } + mNode->DispatchTrustedEvent(NS_LITERAL_STRING("ended")); + // Release stream resources. + mNode->DestroyMediaStream(); + return NS_OK; + } + private: + nsRefPtr mNode; + }; + + NS_DispatchToMainThread(new EndedEventDispatcher(this)); + + // Drop the playing reference + // Warning: The below line might delete this. + MarkInactive(); } void AudioBufferSourceNode::SendPlaybackRateToStream(AudioNode* aNode) { AudioBufferSourceNode* This = static_cast(aNode); + if (!This->mStream) { + return; + } SendTimelineParameterToStream(This, PLAYBACKRATE, *This->mPlaybackRate); } +void +AudioBufferSourceNode::SendDetuneToStream(AudioNode* aNode) +{ + AudioBufferSourceNode* This = static_cast(aNode); + if (!This->mStream) { + return; + } + SendTimelineParameterToStream(This, DETUNE, *This->mDetune); +} + void AudioBufferSourceNode::SendDopplerShiftToStream(double aDopplerShift) { + MOZ_ASSERT(mStream, "Should have disconnected panner if no stream"); SendDoubleParameterToStream(DOPPLERSHIFT, aDopplerShift); } void AudioBufferSourceNode::SendLoopParametersToStream() { + if (!mStream) { + return; + } // Don't compute and set the loop parameters unnecessarily if (mLoop && mBuffer) { float rate = mBuffer->SampleRate(); diff --git a/dom/media/webaudio/AudioBufferSourceNode.h b/dom/media/webaudio/AudioBufferSourceNode.h index 159e617724..c9f5cd169c 100644 --- a/dom/media/webaudio/AudioBufferSourceNode.h +++ b/dom/media/webaudio/AudioBufferSourceNode.h @@ -15,19 +15,14 @@ namespace dom { class AudioParam; -class AudioBufferSourceNode : public AudioNode, - public MainThreadMediaStreamListener +class AudioBufferSourceNode final : public AudioNode, + public MainThreadMediaStreamListener { public: explicit AudioBufferSourceNode(AudioContext* aContext); - virtual void DestroyMediaStream() override - { - if (mStream) { - mStream->RemoveMainThreadListener(this); - } - AudioNode::DestroyMediaStream(); - } + virtual void DestroyMediaStream() override; + virtual uint16_t NumberOfInputs() const final override { return 0; @@ -59,6 +54,10 @@ public: { return mPlaybackRate; } + AudioParam* Detune() const + { + return mDetune; + } bool Loop() const { return mLoop; @@ -90,7 +89,7 @@ public: IMPL_EVENT_HANDLER(ended) - virtual void NotifyMainThreadStateChanged() override; + virtual void NotifyMainThreadStreamFinished() override; virtual const char* NodeType() const override { @@ -123,6 +122,7 @@ private: LOOPSTART, LOOPEND, PLAYBACKRATE, + DETUNE, DOPPLERSHIFT }; @@ -130,6 +130,7 @@ private: void SendBufferParameterToStream(JSContext* aCx); void SendOffsetAndDurationParametersToStream(AudioNodeStream* aStream); static void SendPlaybackRateToStream(AudioNode* aNode); + static void SendDetuneToStream(AudioNode* aNode); private: double mLoopStart; @@ -138,9 +139,9 @@ private: double mDuration; nsRefPtr mBuffer; nsRefPtr mPlaybackRate; + nsRefPtr mDetune; bool mLoop; bool mStartCalled; - bool mStopped; }; } // namespace dom diff --git a/dom/media/webaudio/AudioDestinationNode.cpp b/dom/media/webaudio/AudioDestinationNode.cpp index b60ecdcf3a..80f81a6740 100644 --- a/dom/media/webaudio/AudioDestinationNode.cpp +++ b/dom/media/webaudio/AudioDestinationNode.cpp @@ -29,7 +29,7 @@ namespace dom { static uint8_t gWebAudioOutputKey; -class OfflineDestinationNodeEngine : public AudioNodeEngine +class OfflineDestinationNodeEngine final : public AudioNodeEngine { public: typedef AutoFallibleTArray, 2> InputChannels; @@ -134,7 +134,7 @@ public: , mRenderedBuffer(aRenderedBuffer) {} - NS_IMETHOD Run() + NS_IMETHOD Run() override { nsRefPtr event = new OfflineAudioCompletionEvent(mAudioContext, nullptr, nullptr); @@ -209,7 +209,7 @@ private: bool mBufferAllocated; }; -class InputMutedRunnable : public nsRunnable +class InputMutedRunnable final : public nsRunnable { public: InputMutedRunnable(AudioNodeStream* aStream, @@ -219,7 +219,7 @@ public: { } - NS_IMETHOD Run() + NS_IMETHOD Run() override { MOZ_ASSERT(NS_IsMainThread()); nsRefPtr node = mStream->Engine()->NodeMainThread(); @@ -237,7 +237,7 @@ private: bool mInputMuted; }; -class DestinationNodeEngine : public AudioNodeEngine +class DestinationNodeEngine final : public AudioNodeEngine { public: explicit DestinationNodeEngine(AudioDestinationNode* aNode) @@ -350,7 +350,6 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext, , mFramesToProduce(aLength) , mAudioChannel(AudioChannel::Normal) , mIsOffline(aIsOffline) - , mHasFinished(false) , mAudioChannelAgentPlaying(false) , mExtraCurrentTime(0) , mExtraCurrentTimeSinceLastStartedBlocking(0) @@ -370,7 +369,7 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext, mStream->AddAudioOutput(&gWebAudioOutputKey); if (!aIsOffline) { - graph->NotifyWhenGraphStarted(mStream->AsAudioNodeStream()); + graph->NotifyWhenGraphStarted(mStream); } if (aChannel != AudioChannel::Normal) { @@ -425,24 +424,22 @@ AudioDestinationNode::DestroyMediaStream() } void -AudioDestinationNode::NotifyMainThreadStateChanged() +AudioDestinationNode::NotifyMainThreadStreamFinished() { - if (mStream->IsFinished() && !mHasFinished) { - mHasFinished = true; - if (mIsOffline) { - nsCOMPtr runnable = - NS_NewRunnableMethod(this, &AudioDestinationNode::FireOfflineCompletionEvent); - NS_DispatchToCurrentThread(runnable); - } + MOZ_ASSERT(mStream->IsFinished()); + + if (mIsOffline) { + nsCOMPtr runnable = + NS_NewRunnableMethod(this, &AudioDestinationNode::FireOfflineCompletionEvent); + NS_DispatchToCurrentThread(runnable); } } void AudioDestinationNode::FireOfflineCompletionEvent() { - AudioNodeStream* stream = static_cast(Stream()); OfflineDestinationNodeEngine* engine = - static_cast(stream->Engine()); + static_cast(Stream()->Engine()); engine->FireOfflineCompletionEvent(this); } diff --git a/dom/media/webaudio/AudioDestinationNode.h b/dom/media/webaudio/AudioDestinationNode.h index 8200855aba..cadf113a16 100644 --- a/dom/media/webaudio/AudioDestinationNode.h +++ b/dom/media/webaudio/AudioDestinationNode.h @@ -63,7 +63,7 @@ public: AudioChannel MozAudioChannelType() const; - virtual void NotifyMainThreadStateChanged() override; + virtual void NotifyMainThreadStreamFinished() override; void FireOfflineCompletionEvent(); // An amount that should be added to the MediaStream's current time to @@ -109,7 +109,6 @@ private: // Audio Channel Type. AudioChannel mAudioChannel; bool mIsOffline; - bool mHasFinished; bool mAudioChannelAgentPlaying; TimeStamp mStartedBlockingDueToBeingOnlyNode; diff --git a/dom/media/webaudio/AudioEventTimeline.h b/dom/media/webaudio/AudioEventTimeline.h index b94fb5851b..eb8fc75e36 100644 --- a/dom/media/webaudio/AudioEventTimeline.h +++ b/dom/media/webaudio/AudioEventTimeline.h @@ -21,8 +21,10 @@ namespace mozilla { namespace dom { // This is an internal helper class and should not be used outside of this header. -struct AudioTimelineEvent { - enum Type : uint32_t { +struct AudioTimelineEvent final +{ + enum Type : uint32_t + { SetValue, LinearRamp, ExponentialRamp, diff --git a/dom/media/webaudio/AudioNode.cpp b/dom/media/webaudio/AudioNode.cpp index 9d62606629..5d84e54a96 100644 --- a/dom/media/webaudio/AudioNode.cpp +++ b/dom/media/webaudio/AudioNode.cpp @@ -212,15 +212,13 @@ AudioNode::Connect(AudioNode& aDestination, uint32_t aOutput, input->mInputNode = this; input->mInputPort = aInput; input->mOutputPort = aOutput; - if (aDestination.mStream) { + AudioNodeStream* destinationStream = aDestination.mStream; + if (mStream && destinationStream) { // Connect streams in the MediaStreamGraph - MOZ_ASSERT(aDestination.mStream->AsProcessedStream()); - ProcessedMediaStream* ps = - static_cast(aDestination.mStream.get()); MOZ_ASSERT(aInput <= UINT16_MAX, "Unexpected large input port number"); MOZ_ASSERT(aOutput <= UINT16_MAX, "Unexpected large output port number"); - input->mStreamPort = - ps->AllocateInputPort(mStream, MediaInputPort::FLAG_BLOCK_INPUT, + input->mStreamPort = destinationStream-> + AllocateInputPort(mStream, MediaInputPort::FLAG_BLOCK_INPUT, static_cast(aInput), static_cast(aOutput)); } @@ -260,43 +258,41 @@ AudioNode::Connect(AudioParam& aDestination, uint32_t aOutput, MediaStream* stream = aDestination.Stream(); MOZ_ASSERT(stream->AsProcessedStream()); ProcessedMediaStream* ps = static_cast(stream); - - // Setup our stream as an input to the AudioParam's stream - MOZ_ASSERT(aOutput <= UINT16_MAX, "Unexpected large output port number"); - input->mStreamPort = ps->AllocateInputPort(mStream, MediaInputPort::FLAG_BLOCK_INPUT, - 0, static_cast(aOutput)); + if (mStream) { + // Setup our stream as an input to the AudioParam's stream + MOZ_ASSERT(aOutput <= UINT16_MAX, "Unexpected large output port number"); + input->mStreamPort = + ps->AllocateInputPort(mStream, MediaInputPort::FLAG_BLOCK_INPUT, + 0, static_cast(aOutput)); + } } void AudioNode::SendDoubleParameterToStream(uint32_t aIndex, double aValue) { - AudioNodeStream* ns = static_cast(mStream.get()); - MOZ_ASSERT(ns, "How come we don't have a stream here?"); - ns->SetDoubleParameter(aIndex, aValue); + MOZ_ASSERT(mStream, "How come we don't have a stream here?"); + mStream->SetDoubleParameter(aIndex, aValue); } void AudioNode::SendInt32ParameterToStream(uint32_t aIndex, int32_t aValue) { - AudioNodeStream* ns = static_cast(mStream.get()); - MOZ_ASSERT(ns, "How come we don't have a stream here?"); - ns->SetInt32Parameter(aIndex, aValue); + MOZ_ASSERT(mStream, "How come we don't have a stream here?"); + mStream->SetInt32Parameter(aIndex, aValue); } void AudioNode::SendThreeDPointParameterToStream(uint32_t aIndex, const ThreeDPoint& aValue) { - AudioNodeStream* ns = static_cast(mStream.get()); - MOZ_ASSERT(ns, "How come we don't have a stream here?"); - ns->SetThreeDPointParameter(aIndex, aValue); + MOZ_ASSERT(mStream, "How come we don't have a stream here?"); + mStream->SetThreeDPointParameter(aIndex, aValue); } void AudioNode::SendChannelMixingParametersToStream() { - AudioNodeStream* ns = static_cast(mStream.get()); - MOZ_ASSERT(ns, "How come we don't have a stream here?"); - ns->SetChannelMixingParameters(mChannelCount, mChannelCountMode, + MOZ_ASSERT(mStream, "How come we don't have a stream here?"); + mStream->SetChannelMixingParameters(mChannelCount, mChannelCountMode, mChannelInterpretation); } @@ -304,7 +300,7 @@ void AudioNode::SendTimelineParameterToStream(AudioNode* aNode, uint32_t aIndex, const AudioParamTimeline& aValue) { - AudioNodeStream* ns = static_cast(aNode->mStream.get()); + AudioNodeStream* ns = aNode->mStream; MOZ_ASSERT(ns, "How come we don't have a stream here?"); ns->SetTimelineParameter(aIndex, aValue); } @@ -322,7 +318,8 @@ AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv) // ADDREF message to this (main) thread. Wait for a round trip before // releasing nodes, to give engines receiving sound now time to keep their // nodes alive. - class RunnableRelease : public nsRunnable { + class RunnableRelease final : public nsRunnable + { public: explicit RunnableRelease(already_AddRefed aNode) : mNode(aNode) {} @@ -348,10 +345,12 @@ AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv) // Remove one instance of 'dest' from mOutputNodes. There could be // others, and it's not correct to remove them all since some of them // could be for different output ports. - nsCOMPtr runnable = - new RunnableRelease(mOutputNodes[i].forget()); + nsRefPtr output = mOutputNodes[i].forget(); mOutputNodes.RemoveElementAt(i); - mStream->RunAfterPendingUpdates(runnable.forget()); + if (mStream) { + nsRefPtr runnable = new RunnableRelease(output.forget()); + mStream->RunAfterPendingUpdates(runnable.forget()); + } break; } } @@ -380,17 +379,12 @@ void AudioNode::DestroyMediaStream() { if (mStream) { - { - // Remove the node reference on the engine, and take care to not - // hold the lock when the stream gets destroyed, because that will - // cause the engine to be destroyed as well, and we don't want to - // be holding the lock as we're trying to destroy it! - AudioNodeStream* ns = static_cast(mStream.get()); - MutexAutoLock lock(ns->Engine()->NodeMutex()); - MOZ_ASSERT(ns, "How come we don't have a stream here?"); - MOZ_ASSERT(ns->Engine()->Node() == this, "Invalid node reference"); - ns->Engine()->ClearNode(); - } + // Remove the node pointer on the engine. + AudioNodeStream* ns = mStream; + MOZ_ASSERT(ns, "How come we don't have a stream here?"); + MOZ_ASSERT(ns->Engine()->NodeMainThread() == this, + "Invalid node reference"); + ns->Engine()->ClearNode(); mStream->Destroy(); mStream = nullptr; @@ -422,9 +416,8 @@ AudioNode::SetPassThrough(bool aPassThrough) { MOZ_ASSERT(NumberOfInputs() <= 1 && NumberOfOutputs() == 1); mPassThrough = aPassThrough; - AudioNodeStream* ns = static_cast(mStream.get()); - MOZ_ASSERT(ns, "How come we don't have a stream here?"); - ns->SetPassThrough(mPassThrough); + MOZ_ASSERT(mStream, "How come we don't have a stream here?"); + mStream->SetPassThrough(mPassThrough); } } // namespace dom diff --git a/dom/media/webaudio/AudioNode.h b/dom/media/webaudio/AudioNode.h index 0ac4a6c737..2866efbe1f 100644 --- a/dom/media/webaudio/AudioNode.h +++ b/dom/media/webaudio/AudioNode.h @@ -74,7 +74,8 @@ public: NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioNode, DOMEventTargetHelper) - virtual AudioBufferSourceNode* AsAudioBufferSourceNode() { + virtual AudioBufferSourceNode* AsAudioBufferSourceNode() + { return nullptr; } @@ -137,7 +138,8 @@ public: SendChannelMixingParametersToStream(); } - struct InputNode { + struct InputNode final + { ~InputNode() { if (mStreamPort) { @@ -165,7 +167,7 @@ public: uint32_t mOutputPort; }; - MediaStream* Stream() { return mStream; } + AudioNodeStream* Stream() { return mStream; } const nsTArray& InputNodes() const { @@ -218,9 +220,8 @@ private: nsRefPtr mContext; protected: - // Must be set in the constructor. Must not be null. - // If MaxNumberOfInputs() is > 0, then mStream must be a ProcessedMediaStream. - nsRefPtr mStream; + // Must be set in the constructor. Must not be null unless finished. + nsRefPtr mStream; private: // For every InputNode, there is a corresponding entry in mOutputNodes of the diff --git a/dom/media/webaudio/AudioNodeEngine.h b/dom/media/webaudio/AudioNodeEngine.h index 1105b10b38..8202837db3 100644 --- a/dom/media/webaudio/AudioNodeEngine.h +++ b/dom/media/webaudio/AudioNodeEngine.h @@ -27,7 +27,8 @@ class AudioNodeStream; * pointers can be different (e.g. if the buffers are contained inside * some malloced object). */ -class ThreadSharedFloatArrayBufferList : public ThreadSharedObject { +class ThreadSharedFloatArrayBufferList final : public ThreadSharedObject +{ public: /** * Construct with null data. @@ -37,7 +38,8 @@ public: mContents.SetLength(aCount); } - struct Storage { + struct Storage final + { Storage() : mDataToFree(nullptr), mFree(nullptr), @@ -234,14 +236,14 @@ AudioBufferSumOfSquares(const float* aInput, uint32_t aLength); * All methods of this class and its subclasses are called on the * MediaStreamGraph thread. */ -class AudioNodeEngine { +class AudioNodeEngine +{ public: // This should be compatible with AudioNodeStream::OutputChunks. typedef nsAutoTArray OutputChunks; explicit AudioNodeEngine(dom::AudioNode* aNode) : mNode(aNode) - , mNodeMutex("AudioNodeEngine::mNodeMutex") , mInputCount(aNode ? aNode->NumberOfInputs() : 1) , mOutputCount(aNode ? aNode->NumberOfOutputs() : 0) { @@ -341,19 +343,12 @@ public: aOutput[0] = aInput[0]; } - Mutex& NodeMutex() { return mNodeMutex;} - bool HasNode() const { + MOZ_ASSERT(NS_IsMainThread()); return !!mNode; } - dom::AudioNode* Node() const - { - mNodeMutex.AssertCurrentThreadOwns(); - return mNode; - } - dom::AudioNode* NodeMainThread() const { MOZ_ASSERT(NS_IsMainThread()); @@ -364,7 +359,6 @@ public: { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mNode != nullptr); - mNodeMutex.AssertCurrentThreadOwns(); mNode = nullptr; } @@ -394,7 +388,6 @@ public: private: dom::AudioNode* mNode; - Mutex mNodeMutex; const uint16_t mInputCount; const uint16_t mOutputCount; }; diff --git a/dom/media/webaudio/AudioNodeExternalInputStream.h b/dom/media/webaudio/AudioNodeExternalInputStream.h index 12df5a39a7..84b81320b3 100644 --- a/dom/media/webaudio/AudioNodeExternalInputStream.h +++ b/dom/media/webaudio/AudioNodeExternalInputStream.h @@ -18,14 +18,17 @@ namespace mozilla { * input --- handling any number of audio tracks and handling blocking of * the input MediaStream. */ -class AudioNodeExternalInputStream : public AudioNodeStream { +class AudioNodeExternalInputStream final : public AudioNodeStream +{ public: - AudioNodeExternalInputStream(AudioNodeEngine* aEngine, TrackRate aSampleRate, uint32_t aContextId); + AudioNodeExternalInputStream(AudioNodeEngine* aEngine, TrackRate aSampleRate, + uint32_t aContextId); protected: ~AudioNodeExternalInputStream(); public: - virtual void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) override; + virtual void ProcessInput(GraphTime aFrom, GraphTime aTo, + uint32_t aFlags) override; private: /** diff --git a/dom/media/webaudio/AudioNodeStream.cpp b/dom/media/webaudio/AudioNodeStream.cpp index 2268d26ebf..ecbfbc4810 100644 --- a/dom/media/webaudio/AudioNodeStream.cpp +++ b/dom/media/webaudio/AudioNodeStream.cpp @@ -95,13 +95,15 @@ void AudioNodeStream::SetStreamTimeParameter(uint32_t aIndex, AudioContext* aContext, double aStreamTime) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, uint32_t aIndex, MediaStream* aRelativeToStream, double aStreamTime) : ControlMessage(aStream), mStreamTime(aStreamTime), - mRelativeToStream(aRelativeToStream), mIndex(aIndex) {} - virtual void Run() + mRelativeToStream(aRelativeToStream), mIndex(aIndex) + {} + virtual void Run() override { static_cast(mStream)-> SetStreamTimeParameterImpl(mIndex, mRelativeToStream, mStreamTime); @@ -127,11 +129,13 @@ AudioNodeStream::SetStreamTimeParameterImpl(uint32_t aIndex, MediaStream* aRelat void AudioNodeStream::SetDoubleParameter(uint32_t aIndex, double aValue) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, uint32_t aIndex, double aValue) - : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {} - virtual void Run() + : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) + {} + virtual void Run() override { static_cast(mStream)->Engine()-> SetDoubleParameter(mIndex, mValue); @@ -146,11 +150,13 @@ AudioNodeStream::SetDoubleParameter(uint32_t aIndex, double aValue) void AudioNodeStream::SetInt32Parameter(uint32_t aIndex, int32_t aValue) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, uint32_t aIndex, int32_t aValue) - : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {} - virtual void Run() + : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) + {} + virtual void Run() override { static_cast(mStream)->Engine()-> SetInt32Parameter(mIndex, mValue); @@ -166,15 +172,17 @@ void AudioNodeStream::SetTimelineParameter(uint32_t aIndex, const AudioParamTimeline& aValue) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, uint32_t aIndex, const AudioParamTimeline& aValue) : ControlMessage(aStream), mValue(aValue), mSampleRate(aStream->SampleRate()), - mIndex(aIndex) {} - virtual void Run() + mIndex(aIndex) + {} + virtual void Run() override { static_cast(mStream)->Engine()-> SetTimelineParameter(mIndex, mValue, mSampleRate); @@ -189,11 +197,13 @@ AudioNodeStream::SetTimelineParameter(uint32_t aIndex, void AudioNodeStream::SetThreeDPointParameter(uint32_t aIndex, const ThreeDPoint& aValue) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, uint32_t aIndex, const ThreeDPoint& aValue) - : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {} - virtual void Run() + : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) + {} + virtual void Run() override { static_cast(mStream)->Engine()-> SetThreeDPointParameter(mIndex, mValue); @@ -208,12 +218,14 @@ AudioNodeStream::SetThreeDPointParameter(uint32_t aIndex, const ThreeDPoint& aVa void AudioNodeStream::SetBuffer(already_AddRefed&& aBuffer) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, already_AddRefed& aBuffer) - : ControlMessage(aStream), mBuffer(aBuffer) {} - virtual void Run() + : ControlMessage(aStream), mBuffer(aBuffer) + {} + virtual void Run() override { static_cast(mStream)->Engine()-> SetBuffer(mBuffer.forget()); @@ -227,7 +239,8 @@ AudioNodeStream::SetBuffer(already_AddRefed&& void AudioNodeStream::SetRawArrayData(nsTArray& aData) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, nsTArray& aData) @@ -235,7 +248,7 @@ AudioNodeStream::SetRawArrayData(nsTArray& aData) { mData.SwapElements(aData); } - virtual void Run() + virtual void Run() override { static_cast(mStream)->Engine()->SetRawArrayData(mData); } @@ -250,7 +263,8 @@ AudioNodeStream::SetChannelMixingParameters(uint32_t aNumberOfChannels, ChannelCountMode aChannelCountMode, ChannelInterpretation aChannelInterpretation) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, uint32_t aNumberOfChannels, @@ -261,7 +275,7 @@ AudioNodeStream::SetChannelMixingParameters(uint32_t aNumberOfChannels, mChannelCountMode(aChannelCountMode), mChannelInterpretation(aChannelInterpretation) {} - virtual void Run() + virtual void Run() override { static_cast(mStream)-> SetChannelMixingParametersImpl(mNumberOfChannels, mChannelCountMode, @@ -280,11 +294,13 @@ AudioNodeStream::SetChannelMixingParameters(uint32_t aNumberOfChannels, void AudioNodeStream::SetPassThrough(bool aPassThrough) { - class Message : public ControlMessage { + class Message final : public ControlMessage + { public: Message(AudioNodeStream* aStream, bool aPassThrough) - : ControlMessage(aStream), mPassThrough(aPassThrough) {} - virtual void Run() + : ControlMessage(aStream), mPassThrough(aPassThrough) + {} + virtual void Run() override { static_cast(mStream)->mPassThrough = mPassThrough; } diff --git a/dom/media/webaudio/AudioNodeStream.h b/dom/media/webaudio/AudioNodeStream.h index af2b2efd35..0b8b1cfa91 100644 --- a/dom/media/webaudio/AudioNodeStream.h +++ b/dom/media/webaudio/AudioNodeStream.h @@ -31,7 +31,8 @@ class AudioNodeEngine; * actual audio processing. AudioNodeStream contains the glue code that * integrates audio processing with the MediaStreamGraph. */ -class AudioNodeStream : public ProcessedMediaStream { +class AudioNodeStream : public ProcessedMediaStream +{ typedef dom::ChannelCountMode ChannelCountMode; typedef dom::ChannelInterpretation ChannelInterpretation; diff --git a/dom/media/webaudio/AudioParam.cpp b/dom/media/webaudio/AudioParam.cpp index ae13d82648..a8b1e6adff 100644 --- a/dom/media/webaudio/AudioParam.cpp +++ b/dom/media/webaudio/AudioParam.cpp @@ -45,11 +45,13 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioParam, Release) AudioParam::AudioParam(AudioNode* aNode, AudioParam::CallbackType aCallback, - float aDefaultValue) + float aDefaultValue, + const char* aName) : AudioParamTimeline(aDefaultValue) , mNode(aNode) , mCallback(aCallback) , mDefaultValue(aDefaultValue) + , mName(aName) { } @@ -111,10 +113,11 @@ AudioParam::Stream() mStream = stream.forget(); // Setup the AudioParam's stream as an input to the owner AudioNode's stream - MediaStream* nodeStream = mNode->Stream(); - MOZ_ASSERT(nodeStream->AsProcessedStream()); - ProcessedMediaStream* ps = static_cast(nodeStream); - mNodeStreamPort = ps->AllocateInputPort(mStream, MediaInputPort::FLAG_BLOCK_INPUT); + AudioNodeStream* nodeStream = mNode->Stream(); + if (nodeStream) { + mNodeStreamPort = + nodeStream->AllocateInputPort(mStream, MediaInputPort::FLAG_BLOCK_INPUT); + } // Let the MSG's copy of AudioParamTimeline know about the change in the stream mCallback(mNode); diff --git a/dom/media/webaudio/AudioParam.h b/dom/media/webaudio/AudioParam.h index 82f0490cff..289833e85b 100644 --- a/dom/media/webaudio/AudioParam.h +++ b/dom/media/webaudio/AudioParam.h @@ -30,7 +30,8 @@ public: AudioParam(AudioNode* aNode, CallbackType aCallback, - float aDefaultValue); + float aDefaultValue, + const char* aName); NS_IMETHOD_(MozExternalRefCountType) AddRef(void); NS_IMETHOD_(MozExternalRefCountType) Release(void); @@ -121,6 +122,16 @@ public: mCallback(mNode); } + uint32_t ParentNodeId() + { + return mNode->Id(); + } + + void GetName(nsAString& aName) + { + aName.AssignASCII(mName); + } + float DefaultValue() const { return mDefaultValue; @@ -183,6 +194,7 @@ private: nsTArray mInputNodes; CallbackType mCallback; const float mDefaultValue; + const char* mName; // The input port used to connect the AudioParam's stream to its node's stream nsRefPtr mNodeStreamPort; }; diff --git a/dom/media/webaudio/AudioProcessingEvent.h b/dom/media/webaudio/AudioProcessingEvent.h index 17dce9031c..4f32a7b469 100644 --- a/dom/media/webaudio/AudioProcessingEvent.h +++ b/dom/media/webaudio/AudioProcessingEvent.h @@ -14,7 +14,7 @@ namespace mozilla { namespace dom { -class AudioProcessingEvent : public Event +class AudioProcessingEvent final : public Event { public: AudioProcessingEvent(ScriptProcessorNode* aOwner, diff --git a/dom/media/webaudio/BiquadFilterNode.cpp b/dom/media/webaudio/BiquadFilterNode.cpp index 855e8a5847..b5bf83a70d 100644 --- a/dom/media/webaudio/BiquadFilterNode.cpp +++ b/dom/media/webaudio/BiquadFilterNode.cpp @@ -73,13 +73,13 @@ SetParamsOnBiquad(WebCore::Biquad& aBiquad, } } -class BiquadFilterNodeEngine : public AudioNodeEngine +class BiquadFilterNodeEngine final : public AudioNodeEngine { public: BiquadFilterNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination) : AudioNodeEngine(aNode) , mSource(nullptr) - , mDestination(static_cast (aDestination->Stream())) + , mDestination(aDestination->Stream()) // Keep the default values in sync with the default values in // BiquadFilterNode::BiquadFilterNode , mType(BiquadFilterType::Lowpass) @@ -244,14 +244,14 @@ BiquadFilterNode::BiquadFilterNode(AudioContext* aContext) ChannelCountMode::Max, ChannelInterpretation::Speakers) , mType(BiquadFilterType::Lowpass) - , mFrequency(new AudioParam(this, SendFrequencyToStream, 350.f)) - , mDetune(new AudioParam(this, SendDetuneToStream, 0.f)) - , mQ(new AudioParam(this, SendQToStream, 1.f)) - , mGain(new AudioParam(this, SendGainToStream, 0.f)) + , mFrequency(new AudioParam(this, SendFrequencyToStream, 350.f, "frequency")) + , mDetune(new AudioParam(this, SendDetuneToStream, 0.f, "detune")) + , mQ(new AudioParam(this, SendQToStream, 1.f, "Q")) + , mGain(new AudioParam(this, SendGainToStream, 0.f, "gain")) { BiquadFilterNodeEngine* engine = new BiquadFilterNodeEngine(this, aContext->Destination()); mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM); - engine->SetSourceStream(static_cast (mStream.get())); + engine->SetSourceStream(mStream); } BiquadFilterNode::~BiquadFilterNode() diff --git a/dom/media/webaudio/BiquadFilterNode.h b/dom/media/webaudio/BiquadFilterNode.h index 43a82807c1..33edb0957d 100644 --- a/dom/media/webaudio/BiquadFilterNode.h +++ b/dom/media/webaudio/BiquadFilterNode.h @@ -16,7 +16,7 @@ namespace dom { class AudioContext; -class BiquadFilterNode : public AudioNode +class BiquadFilterNode final : public AudioNode { public: explicit BiquadFilterNode(AudioContext* aContext); diff --git a/dom/media/webaudio/BufferDecoder.h b/dom/media/webaudio/BufferDecoder.h index 9569ccacc4..56575e846e 100644 --- a/dom/media/webaudio/BufferDecoder.h +++ b/dom/media/webaudio/BufferDecoder.h @@ -18,7 +18,7 @@ namespace mozilla { * This class provides a decoder object which decodes a media file that lives in * a memory buffer. */ -class BufferDecoder : public AbstractMediaDecoder +class BufferDecoder final : public AbstractMediaDecoder { public: // This class holds a weak pointer to MediaResource. It's the responsibility diff --git a/dom/media/webaudio/ChannelMergerNode.cpp b/dom/media/webaudio/ChannelMergerNode.cpp index 9c641e453c..b095e7a818 100644 --- a/dom/media/webaudio/ChannelMergerNode.cpp +++ b/dom/media/webaudio/ChannelMergerNode.cpp @@ -14,7 +14,7 @@ namespace dom { NS_IMPL_ISUPPORTS_INHERITED0(ChannelMergerNode, AudioNode) -class ChannelMergerNodeEngine : public AudioNodeEngine +class ChannelMergerNodeEngine final : public AudioNodeEngine { public: explicit ChannelMergerNodeEngine(ChannelMergerNode* aNode) diff --git a/dom/media/webaudio/ChannelMergerNode.h b/dom/media/webaudio/ChannelMergerNode.h index ebf13cd442..772c3a879c 100644 --- a/dom/media/webaudio/ChannelMergerNode.h +++ b/dom/media/webaudio/ChannelMergerNode.h @@ -14,7 +14,7 @@ namespace dom { class AudioContext; -class ChannelMergerNode : public AudioNode +class ChannelMergerNode final : public AudioNode { public: ChannelMergerNode(AudioContext* aContext, diff --git a/dom/media/webaudio/ChannelSplitterNode.cpp b/dom/media/webaudio/ChannelSplitterNode.cpp index 4644e38390..e15255bf57 100644 --- a/dom/media/webaudio/ChannelSplitterNode.cpp +++ b/dom/media/webaudio/ChannelSplitterNode.cpp @@ -14,7 +14,7 @@ namespace dom { NS_IMPL_ISUPPORTS_INHERITED0(ChannelSplitterNode, AudioNode) -class ChannelSplitterNodeEngine : public AudioNodeEngine +class ChannelSplitterNodeEngine final : public AudioNodeEngine { public: explicit ChannelSplitterNodeEngine(ChannelSplitterNode* aNode) diff --git a/dom/media/webaudio/ChannelSplitterNode.h b/dom/media/webaudio/ChannelSplitterNode.h index ba3bd557e8..f23603cfa9 100644 --- a/dom/media/webaudio/ChannelSplitterNode.h +++ b/dom/media/webaudio/ChannelSplitterNode.h @@ -14,7 +14,7 @@ namespace dom { class AudioContext; -class ChannelSplitterNode : public AudioNode +class ChannelSplitterNode final : public AudioNode { public: ChannelSplitterNode(AudioContext* aContext, diff --git a/dom/media/webaudio/ConvolverNode.cpp b/dom/media/webaudio/ConvolverNode.cpp index 594af577a7..4aa5bd31d6 100644 --- a/dom/media/webaudio/ConvolverNode.cpp +++ b/dom/media/webaudio/ConvolverNode.cpp @@ -22,7 +22,7 @@ NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(ConvolverNode, AudioNode) NS_IMPL_RELEASE_INHERITED(ConvolverNode, AudioNode) -class ConvolverNodeEngine : public AudioNodeEngine +class ConvolverNodeEngine final : public AudioNodeEngine { typedef PlayingRefChangeHandler PlayingRefChanged; public: @@ -241,7 +241,7 @@ ConvolverNode::SetBuffer(JSContext* aCx, AudioBuffer* aBuffer, ErrorResult& aRv) mBuffer = aBuffer; // Send the buffer to the stream - AudioNodeStream* ns = static_cast(mStream.get()); + AudioNodeStream* ns = mStream; MOZ_ASSERT(ns, "Why don't we have a stream here?"); if (mBuffer) { uint32_t length = mBuffer->Length(); diff --git a/dom/media/webaudio/ConvolverNode.h b/dom/media/webaudio/ConvolverNode.h index 0bd2d5ed86..9748d3e81d 100644 --- a/dom/media/webaudio/ConvolverNode.h +++ b/dom/media/webaudio/ConvolverNode.h @@ -13,7 +13,7 @@ namespace mozilla { namespace dom { -class ConvolverNode : public AudioNode +class ConvolverNode final : public AudioNode { public: explicit ConvolverNode(AudioContext* aContext); diff --git a/dom/media/webaudio/DelayBuffer.h b/dom/media/webaudio/DelayBuffer.h index ebefd7c5bf..86ff03c055 100644 --- a/dom/media/webaudio/DelayBuffer.h +++ b/dom/media/webaudio/DelayBuffer.h @@ -13,7 +13,8 @@ namespace mozilla { -class DelayBuffer { +class DelayBuffer final +{ typedef dom::ChannelInterpretation ChannelInterpretation; public: diff --git a/dom/media/webaudio/DelayNode.cpp b/dom/media/webaudio/DelayNode.cpp index 035f6d2212..81195ac13b 100644 --- a/dom/media/webaudio/DelayNode.cpp +++ b/dom/media/webaudio/DelayNode.cpp @@ -25,7 +25,7 @@ NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(DelayNode, AudioNode) NS_IMPL_RELEASE_INHERITED(DelayNode, AudioNode) -class DelayNodeEngine : public AudioNodeEngine +class DelayNodeEngine final : public AudioNodeEngine { typedef PlayingRefChangeHandler PlayingRefChanged; public: @@ -33,7 +33,7 @@ public: double aMaxDelayTicks) : AudioNodeEngine(aNode) , mSource(nullptr) - , mDestination(static_cast (aDestination->Stream())) + , mDestination(aDestination->Stream()) // Keep the default value in sync with the default value in DelayNode::DelayNode. , mDelay(0.f) // Use a smoothing range of 20ms @@ -190,13 +190,13 @@ DelayNode::DelayNode(AudioContext* aContext, double aMaxDelay) 2, ChannelCountMode::Max, ChannelInterpretation::Speakers) - , mDelay(new AudioParam(this, SendDelayToStream, 0.0f)) + , mDelay(new AudioParam(this, SendDelayToStream, 0.0f, "delayTime")) { DelayNodeEngine* engine = new DelayNodeEngine(this, aContext->Destination(), aContext->SampleRate() * aMaxDelay); mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM); - engine->SetSourceStream(static_cast (mStream.get())); + engine->SetSourceStream(mStream); } DelayNode::~DelayNode() diff --git a/dom/media/webaudio/DelayNode.h b/dom/media/webaudio/DelayNode.h index dcfea67be6..d27febdc48 100644 --- a/dom/media/webaudio/DelayNode.h +++ b/dom/media/webaudio/DelayNode.h @@ -15,7 +15,7 @@ namespace dom { class AudioContext; -class DelayNode : public AudioNode +class DelayNode final : public AudioNode { public: DelayNode(AudioContext* aContext, double aMaxDelay); diff --git a/dom/media/webaudio/DynamicsCompressorNode.cpp b/dom/media/webaudio/DynamicsCompressorNode.cpp index ca35f4993b..378a18cd85 100644 --- a/dom/media/webaudio/DynamicsCompressorNode.cpp +++ b/dom/media/webaudio/DynamicsCompressorNode.cpp @@ -21,7 +21,6 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(DynamicsCompressorNode, AudioNode, mThreshold, mKnee, mRatio, - mReduction, mAttack, mRelease) @@ -31,14 +30,14 @@ NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(DynamicsCompressorNode, AudioNode) NS_IMPL_RELEASE_INHERITED(DynamicsCompressorNode, AudioNode) -class DynamicsCompressorNodeEngine : public AudioNodeEngine +class DynamicsCompressorNodeEngine final : public AudioNodeEngine { public: explicit DynamicsCompressorNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination) : AudioNodeEngine(aNode) , mSource(nullptr) - , mDestination(static_cast (aDestination->Stream())) + , mDestination(aDestination->Stream()) // Keep the default value in sync with the default value in // DynamicsCompressorNode::DynamicsCompressorNode. , mThreshold(-24.f) @@ -152,7 +151,7 @@ private: { MOZ_ASSERT(!NS_IsMainThread()); - class Command : public nsRunnable + class Command final : public nsRunnable { public: Command(AudioNodeStream* aStream, float aReduction) @@ -161,21 +160,13 @@ private: { } - NS_IMETHODIMP Run() + NS_IMETHOD Run() override { - nsRefPtr node; - { - // No need to keep holding the lock for the whole duration of this - // function, since we're holding a strong reference to it, so if - // we can obtain the reference, we will hold the node alive in - // this function. - MutexAutoLock lock(mStream->Engine()->NodeMutex()); - node = static_cast(mStream->Engine()->Node()); - } + nsRefPtr node = + static_cast + (mStream->Engine()->NodeMainThread()); if (node) { - AudioParam* reduction = node->Reduction(); - reduction->CancelAllEvents(); - reduction->SetValue(mReduction); + node->SetReduction(mReduction); } return NS_OK; } @@ -204,16 +195,16 @@ DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext) 2, ChannelCountMode::Explicit, ChannelInterpretation::Speakers) - , mThreshold(new AudioParam(this, SendThresholdToStream, -24.f)) - , mKnee(new AudioParam(this, SendKneeToStream, 30.f)) - , mRatio(new AudioParam(this, SendRatioToStream, 12.f)) - , mReduction(new AudioParam(this, Callback, 0.f)) - , mAttack(new AudioParam(this, SendAttackToStream, 0.003f)) - , mRelease(new AudioParam(this, SendReleaseToStream, 0.25f)) + , mThreshold(new AudioParam(this, SendThresholdToStream, -24.f, "threshold")) + , mKnee(new AudioParam(this, SendKneeToStream, 30.f, "knee")) + , mRatio(new AudioParam(this, SendRatioToStream, 12.f, "ratio")) + , mReduction(0) + , mAttack(new AudioParam(this, SendAttackToStream, 0.003f, "attack")) + , mRelease(new AudioParam(this, SendReleaseToStream, 0.25f, "release")) { DynamicsCompressorNodeEngine* engine = new DynamicsCompressorNodeEngine(this, aContext->Destination()); mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM); - engine->SetSourceStream(static_cast (mStream.get())); + engine->SetSourceStream(mStream); } DynamicsCompressorNode::~DynamicsCompressorNode() diff --git a/dom/media/webaudio/DynamicsCompressorNode.h b/dom/media/webaudio/DynamicsCompressorNode.h index 10df51ebee..3e237450f9 100644 --- a/dom/media/webaudio/DynamicsCompressorNode.h +++ b/dom/media/webaudio/DynamicsCompressorNode.h @@ -15,7 +15,7 @@ namespace dom { class AudioContext; -class DynamicsCompressorNode : public AudioNode +class DynamicsCompressorNode final : public AudioNode { public: explicit DynamicsCompressorNode(AudioContext* aContext); @@ -40,11 +40,6 @@ public: return mRatio; } - AudioParam* Reduction() const - { - return mReduction; - } - AudioParam* Attack() const { return mAttack; @@ -56,6 +51,11 @@ public: return mRelease; } + float Reduction() const + { + return mReduction; + } + virtual const char* NodeType() const override { return "DynamicsCompressorNode"; @@ -64,6 +64,12 @@ public: virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override; virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override; + void SetReduction(float aReduction) + { + MOZ_ASSERT(NS_IsMainThread()); + mReduction = aReduction; + } + protected: virtual ~DynamicsCompressorNode(); @@ -78,7 +84,7 @@ private: nsRefPtr mThreshold; nsRefPtr mKnee; nsRefPtr mRatio; - nsRefPtr mReduction; + float mReduction; nsRefPtr mAttack; nsRefPtr mRelease; }; diff --git a/dom/media/webaudio/FFTBlock.h b/dom/media/webaudio/FFTBlock.h index f8b4063eee..03dbedad87 100644 --- a/dom/media/webaudio/FFTBlock.h +++ b/dom/media/webaudio/FFTBlock.h @@ -16,7 +16,8 @@ namespace mozilla { // This class defines an FFT block, loosely modeled after Blink's FFTFrame // class to make sharing code with Blink easy. // Currently it's implemented on top of KissFFT on all platforms. -class FFTBlock { +class FFTBlock final +{ public: explicit FFTBlock(uint32_t aFFTSize) : mFFT(nullptr) diff --git a/dom/media/webaudio/GainNode.cpp b/dom/media/webaudio/GainNode.cpp index 830d1a4708..fce6a532a7 100644 --- a/dom/media/webaudio/GainNode.cpp +++ b/dom/media/webaudio/GainNode.cpp @@ -23,13 +23,13 @@ NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(GainNode, AudioNode) NS_IMPL_RELEASE_INHERITED(GainNode, AudioNode) -class GainNodeEngine : public AudioNodeEngine +class GainNodeEngine final : public AudioNodeEngine { public: GainNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination) : AudioNodeEngine(aNode) , mSource(nullptr) - , mDestination(static_cast (aDestination->Stream())) + , mDestination(aDestination->Stream()) // Keep the default value in sync with the default value in GainNode::GainNode. , mGain(1.f) { @@ -125,11 +125,11 @@ GainNode::GainNode(AudioContext* aContext) 2, ChannelCountMode::Max, ChannelInterpretation::Speakers) - , mGain(new AudioParam(this, SendGainToStream, 1.0f)) + , mGain(new AudioParam(this, SendGainToStream, 1.0f, "gain")) { GainNodeEngine* engine = new GainNodeEngine(this, aContext->Destination()); mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM); - engine->SetSourceStream(static_cast (mStream.get())); + engine->SetSourceStream(mStream); } GainNode::~GainNode() diff --git a/dom/media/webaudio/GainNode.h b/dom/media/webaudio/GainNode.h index 46a21bb002..7d5f9e9ece 100644 --- a/dom/media/webaudio/GainNode.h +++ b/dom/media/webaudio/GainNode.h @@ -15,7 +15,7 @@ namespace dom { class AudioContext; -class GainNode : public AudioNode +class GainNode final : public AudioNode { public: explicit GainNode(AudioContext* aContext); diff --git a/dom/media/webaudio/MediaBufferDecoder.cpp b/dom/media/webaudio/MediaBufferDecoder.cpp index 537b29199d..10a6117416 100644 --- a/dom/media/webaudio/MediaBufferDecoder.cpp +++ b/dom/media/webaudio/MediaBufferDecoder.cpp @@ -50,7 +50,7 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebAudioDecodeJob, Release) using namespace dom; -class ReportResultTask : public nsRunnable +class ReportResultTask final : public nsRunnable { public: ReportResultTask(WebAudioDecodeJob& aDecodeJob, @@ -82,13 +82,14 @@ private: WebAudioDecodeJob::ErrorCode mErrorCode; }; -enum class PhaseEnum : int { +enum class PhaseEnum : int +{ Decode, AllocateBuffer, Done }; -class MediaDecodeTask : public nsRunnable +class MediaDecodeTask final : public nsRunnable { public: MediaDecodeTask(const char* aContentType, uint8_t* aBuffer, @@ -217,7 +218,8 @@ MediaDecodeTask::CreateReader() return true; } -class AutoResampler { +class AutoResampler final +{ public: AutoResampler() : mResampler(nullptr) diff --git a/dom/media/webaudio/MediaElementAudioSourceNode.h b/dom/media/webaudio/MediaElementAudioSourceNode.h index 8a131f6a6b..3365dff3f6 100644 --- a/dom/media/webaudio/MediaElementAudioSourceNode.h +++ b/dom/media/webaudio/MediaElementAudioSourceNode.h @@ -12,7 +12,7 @@ namespace mozilla { namespace dom { -class MediaElementAudioSourceNode : public MediaStreamAudioSourceNode +class MediaElementAudioSourceNode final : public MediaStreamAudioSourceNode { public: static already_AddRefed diff --git a/dom/media/webaudio/MediaStreamAudioDestinationNode.h b/dom/media/webaudio/MediaStreamAudioDestinationNode.h index a7f184552a..1b5d3412d0 100644 --- a/dom/media/webaudio/MediaStreamAudioDestinationNode.h +++ b/dom/media/webaudio/MediaStreamAudioDestinationNode.h @@ -12,7 +12,7 @@ namespace mozilla { namespace dom { -class MediaStreamAudioDestinationNode : public AudioNode +class MediaStreamAudioDestinationNode final : public AudioNode { public: explicit MediaStreamAudioDestinationNode(AudioContext* aContext); diff --git a/dom/media/webaudio/MediaStreamAudioSourceNode.h b/dom/media/webaudio/MediaStreamAudioSourceNode.h index e013239a93..1ffa2881db 100644 --- a/dom/media/webaudio/MediaStreamAudioSourceNode.h +++ b/dom/media/webaudio/MediaStreamAudioSourceNode.h @@ -15,7 +15,7 @@ namespace mozilla { namespace dom { -class MediaStreamAudioSourceNodeEngine : public AudioNodeEngine +class MediaStreamAudioSourceNodeEngine final : public AudioNodeEngine { public: explicit MediaStreamAudioSourceNodeEngine(AudioNode* aNode) diff --git a/dom/media/webaudio/OfflineAudioCompletionEvent.h b/dom/media/webaudio/OfflineAudioCompletionEvent.h index 1d6a9f0841..58e5d95f3a 100644 --- a/dom/media/webaudio/OfflineAudioCompletionEvent.h +++ b/dom/media/webaudio/OfflineAudioCompletionEvent.h @@ -15,7 +15,7 @@ namespace dom { class AudioContext; -class OfflineAudioCompletionEvent : public Event +class OfflineAudioCompletionEvent final : public Event { public: OfflineAudioCompletionEvent(AudioContext* aOwner, diff --git a/dom/media/webaudio/OscillatorNode.cpp b/dom/media/webaudio/OscillatorNode.cpp index f1a0c7e653..727e95d430 100644 --- a/dom/media/webaudio/OscillatorNode.cpp +++ b/dom/media/webaudio/OscillatorNode.cpp @@ -23,13 +23,13 @@ NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(OscillatorNode, AudioNode) NS_IMPL_RELEASE_INHERITED(OscillatorNode, AudioNode) -class OscillatorNodeEngine : public AudioNodeEngine +class OscillatorNodeEngine final : public AudioNodeEngine { public: OscillatorNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination) : AudioNodeEngine(aNode) , mSource(nullptr) - , mDestination(static_cast (aDestination->Stream())) + , mDestination(aDestination->Stream()) , mStart(-1) , mStop(STREAM_TIME_MAX) // Keep the default values in sync with OscillatorNode::OscillatorNode. @@ -381,14 +381,13 @@ OscillatorNode::OscillatorNode(AudioContext* aContext) ChannelCountMode::Max, ChannelInterpretation::Speakers) , mType(OscillatorType::Sine) - , mFrequency(new AudioParam(this, SendFrequencyToStream, 440.0f)) - , mDetune(new AudioParam(this, SendDetuneToStream, 0.0f)) + , mFrequency(new AudioParam(this, SendFrequencyToStream, 440.0f, "frequency")) + , mDetune(new AudioParam(this, SendDetuneToStream, 0.0f, "detune")) , mStartCalled(false) - , mStopped(false) { OscillatorNodeEngine* engine = new OscillatorNodeEngine(this, aContext->Destination()); mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::SOURCE_STREAM); - engine->SetSourceStream(static_cast (mStream.get())); + engine->SetSourceStream(mStream); mStream->AddMainThreadListener(this); } @@ -422,10 +421,22 @@ OscillatorNode::WrapObject(JSContext* aCx, JS::Handle aGivenProto) return OscillatorNodeBinding::Wrap(aCx, this, aGivenProto); } +void +OscillatorNode::DestroyMediaStream() +{ + if (mStream) { + mStream->RemoveMainThreadListener(this); + } + AudioNode::DestroyMediaStream(); +} + void OscillatorNode::SendFrequencyToStream(AudioNode* aNode) { OscillatorNode* This = static_cast(aNode); + if (!This->mStream) { + return; + } SendTimelineParameterToStream(This, OscillatorNodeEngine::FREQUENCY, *This->mFrequency); } @@ -433,12 +444,18 @@ void OscillatorNode::SendDetuneToStream(AudioNode* aNode) { OscillatorNode* This = static_cast(aNode); + if (!This->mStream) { + return; + } SendTimelineParameterToStream(This, OscillatorNodeEngine::DETUNE, *This->mDetune); } void OscillatorNode::SendTypeToStream() { + if (!mStream) { + return; + } if (mType == OscillatorType::Custom) { // The engine assumes we'll send the custom data before updating the type. SendPeriodicWaveToStream(); @@ -450,14 +467,13 @@ void OscillatorNode::SendPeriodicWaveToStream() { NS_ASSERTION(mType == OscillatorType::Custom, "Sending custom waveform to engine thread with non-custom type"); - AudioNodeStream* ns = static_cast(mStream.get()); - MOZ_ASSERT(ns, "Missing node stream."); + MOZ_ASSERT(mStream, "Missing node stream."); MOZ_ASSERT(mPeriodicWave, "Send called without PeriodicWave object."); SendInt32ParameterToStream(OscillatorNodeEngine::PERIODICWAVE, mPeriodicWave->DataLength()); nsRefPtr data = mPeriodicWave->GetThreadSharedBuffer(); - ns->SetBuffer(data.forget()); + mStream->SetBuffer(data.forget()); } void @@ -474,15 +490,14 @@ OscillatorNode::Start(double aWhen, ErrorResult& aRv) } mStartCalled = true; - AudioNodeStream* ns = static_cast(mStream.get()); - if (!ns) { + if (!mStream) { // Nothing to play, or we're already dead for some reason return; } // TODO: Perhaps we need to do more here. - ns->SetStreamTimeParameter(OscillatorNodeEngine::START, - Context(), aWhen); + mStream->SetStreamTimeParameter(OscillatorNodeEngine::START, + Context(), aWhen); MarkActive(); } @@ -500,50 +515,48 @@ OscillatorNode::Stop(double aWhen, ErrorResult& aRv) return; } - AudioNodeStream* ns = static_cast(mStream.get()); - if (!ns || !Context()) { + if (!mStream || !Context()) { // We've already stopped and had our stream shut down return; } // TODO: Perhaps we need to do more here. - ns->SetStreamTimeParameter(OscillatorNodeEngine::STOP, - Context(), std::max(0.0, aWhen)); + mStream->SetStreamTimeParameter(OscillatorNodeEngine::STOP, + Context(), std::max(0.0, aWhen)); } void -OscillatorNode::NotifyMainThreadStateChanged() +OscillatorNode::NotifyMainThreadStreamFinished() { - if (mStream->IsFinished()) { - class EndedEventDispatcher : public nsRunnable - { - public: - explicit EndedEventDispatcher(OscillatorNode* aNode) - : mNode(aNode) {} - NS_IMETHODIMP Run() - { - // If it's not safe to run scripts right now, schedule this to run later - if (!nsContentUtils::IsSafeToRunScript()) { - nsContentUtils::AddScriptRunner(this); - return NS_OK; - } + MOZ_ASSERT(mStream->IsFinished()); - mNode->DispatchTrustedEvent(NS_LITERAL_STRING("ended")); + class EndedEventDispatcher final : public nsRunnable + { + public: + explicit EndedEventDispatcher(OscillatorNode* aNode) + : mNode(aNode) {} + NS_IMETHOD Run() override + { + // If it's not safe to run scripts right now, schedule this to run later + if (!nsContentUtils::IsSafeToRunScript()) { + nsContentUtils::AddScriptRunner(this); return NS_OK; } - private: - nsRefPtr mNode; - }; - if (!mStopped) { - // Only dispatch the ended event once - NS_DispatchToMainThread(new EndedEventDispatcher(this)); - mStopped = true; - } - // Drop the playing reference - // Warning: The below line might delete this. - MarkInactive(); - } + mNode->DispatchTrustedEvent(NS_LITERAL_STRING("ended")); + // Release stream resources. + mNode->DestroyMediaStream(); + return NS_OK; + } + private: + nsRefPtr mNode; + }; + + NS_DispatchToMainThread(new EndedEventDispatcher(this)); + + // Drop the playing reference + // Warning: The below line might delete this. + MarkInactive(); } } // namespace dom diff --git a/dom/media/webaudio/OscillatorNode.h b/dom/media/webaudio/OscillatorNode.h index 99bcabde24..39262e1c34 100644 --- a/dom/media/webaudio/OscillatorNode.h +++ b/dom/media/webaudio/OscillatorNode.h @@ -18,8 +18,8 @@ namespace dom { class AudioContext; -class OscillatorNode : public AudioNode, - public MainThreadMediaStreamListener +class OscillatorNode final : public AudioNode, + public MainThreadMediaStreamListener { public: explicit OscillatorNode(AudioContext* aContext); @@ -29,13 +29,8 @@ public: virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - virtual void DestroyMediaStream() override - { - if (mStream) { - mStream->RemoveMainThreadListener(this); - } - AudioNode::DestroyMediaStream(); - } + virtual void DestroyMediaStream() override; + virtual uint16_t NumberOfInputs() const final override { return 0; @@ -78,7 +73,7 @@ public: IMPL_EVENT_HANDLER(ended) - virtual void NotifyMainThreadStateChanged() override; + virtual void NotifyMainThreadStreamFinished() override; virtual const char* NodeType() const override { @@ -103,7 +98,6 @@ private: nsRefPtr mFrequency; nsRefPtr mDetune; bool mStartCalled; - bool mStopped; }; } // namespace dom diff --git a/dom/media/webaudio/PannerNode.cpp b/dom/media/webaudio/PannerNode.cpp index a9526144a0..20964a28c9 100644 --- a/dom/media/webaudio/PannerNode.cpp +++ b/dom/media/webaudio/PannerNode.cpp @@ -39,7 +39,7 @@ NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(PannerNode, AudioNode) NS_IMPL_RELEASE_INHERITED(PannerNode, AudioNode) -class PannerNodeEngine : public AudioNodeEngine +class PannerNodeEngine final : public AudioNodeEngine { public: explicit PannerNodeEngine(AudioNode* aNode) @@ -540,9 +540,10 @@ PannerNode::FindConnectedSources(AudioNode* aNode, // Recurse FindConnectedSources(inputNodes[i].mInputNode, aSources, aNodesSeen); - // Check if this node is an AudioBufferSourceNode + // Check if this node is an AudioBufferSourceNode that still have a stream, + // which means it has not finished playing. AudioBufferSourceNode* node = inputNodes[i].mInputNode->AsAudioBufferSourceNode(); - if (node) { + if (node && node->Stream()) { aSources.AppendElement(node); } } diff --git a/dom/media/webaudio/PannerNode.h b/dom/media/webaudio/PannerNode.h index bc997a7a3f..2310a313bc 100644 --- a/dom/media/webaudio/PannerNode.h +++ b/dom/media/webaudio/PannerNode.h @@ -21,8 +21,8 @@ namespace dom { class AudioContext; class AudioBufferSourceNode; -class PannerNode : public AudioNode, - public SupportsWeakPtr +class PannerNode final : public AudioNode, + public SupportsWeakPtr { public: MOZ_DECLARE_WEAKREFERENCE_TYPENAME(PannerNode) diff --git a/dom/media/webaudio/PlayingRefChangeHandler.h b/dom/media/webaudio/PlayingRefChangeHandler.h index 27b29b7551..4da8e7966c 100644 --- a/dom/media/webaudio/PlayingRefChangeHandler.h +++ b/dom/media/webaudio/PlayingRefChangeHandler.h @@ -13,7 +13,7 @@ namespace mozilla { namespace dom { -class PlayingRefChangeHandler : public nsRunnable +class PlayingRefChangeHandler final : public nsRunnable { public: enum ChangeType { ADDREF, RELEASE }; @@ -25,15 +25,7 @@ public: NS_IMETHOD Run() { - nsRefPtr node; - { - // No need to keep holding the lock for the whole duration of this - // function, since we're holding a strong reference to it, so if - // we can obtain the reference, we will hold the node alive in - // this function. - MutexAutoLock lock(mStream->Engine()->NodeMutex()); - node = mStream->Engine()->Node(); - } + nsRefPtr node = mStream->Engine()->NodeMainThread(); if (node) { if (mChange == ADDREF) { node->MarkActive(); diff --git a/dom/media/webaudio/ReportDecodeResultTask.h b/dom/media/webaudio/ReportDecodeResultTask.h index c24d0fcbf7..e0f0f7ec98 100644 --- a/dom/media/webaudio/ReportDecodeResultTask.h +++ b/dom/media/webaudio/ReportDecodeResultTask.h @@ -12,7 +12,7 @@ namespace mozilla { -class ReportDecodeResultTask : public nsRunnable +class ReportDecodeResultTask final : public nsRunnable { public: ReportDecodeResultTask(DecodeJob& aDecodeJob, diff --git a/dom/media/webaudio/ScriptProcessorNode.cpp b/dom/media/webaudio/ScriptProcessorNode.cpp index a3ad900afe..f0eb3b82aa 100644 --- a/dom/media/webaudio/ScriptProcessorNode.cpp +++ b/dom/media/webaudio/ScriptProcessorNode.cpp @@ -28,10 +28,10 @@ NS_IMPL_ISUPPORTS_INHERITED0(ScriptProcessorNode, AudioNode) // This class manages a queue of output buffers shared between // the main thread and the Media Stream Graph thread. -class SharedBuffers +class SharedBuffers final { private: - class OutputQueue + class OutputQueue final { public: explicit OutputQueue(const char* aName) @@ -237,7 +237,7 @@ private: bool mDroppingBuffers; }; -class ScriptProcessorNodeEngine : public AudioNodeEngine +class ScriptProcessorNodeEngine final : public AudioNodeEngine { public: typedef nsAutoTArray, 2> InputChannels; @@ -249,7 +249,7 @@ public: : AudioNodeEngine(aNode) , mSharedBuffers(aNode->GetSharedBuffers()) , mSource(nullptr) - , mDestination(static_cast (aDestination->Stream())) + , mDestination(aDestination->Stream()) , mBufferSize(aBufferSize) , mInputWriteIndex(0) , mSeenNonSilenceInput(false) @@ -268,14 +268,6 @@ public: AudioChunk* aOutput, bool* aFinished) override { - MutexAutoLock lock(NodeMutex()); - - // If our node is dead, just output silence. - if (!Node()) { - aOutput->SetNull(WEBAUDIO_BLOCK_SIZE); - return; - } - // This node is not connected to anything. Per spec, we don't fire the // onaudioprocess event. We also want to clear out the input and output // buffer queue, and output a null buffer. @@ -361,7 +353,7 @@ private: double playbackTime = mSource->DestinationTimeFromTicks(mDestination, playbackTick); - class Command : public nsRunnable + class Command final : public nsRunnable { public: Command(AudioNodeStream* aStream, @@ -380,7 +372,7 @@ private: } } - NS_IMETHODIMP Run() + NS_IMETHOD Run() override { nsRefPtr node = static_cast (mStream->Engine()->NodeMainThread()); @@ -490,7 +482,7 @@ ScriptProcessorNode::ScriptProcessorNode(AudioContext* aContext, BufferSize(), aNumberOfInputChannels); mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM); - engine->SetSourceStream(static_cast (mStream.get())); + engine->SetSourceStream(mStream); } ScriptProcessorNode::~ScriptProcessorNode() diff --git a/dom/media/webaudio/ScriptProcessorNode.h b/dom/media/webaudio/ScriptProcessorNode.h index b4a971b8f1..0bbbca06ae 100644 --- a/dom/media/webaudio/ScriptProcessorNode.h +++ b/dom/media/webaudio/ScriptProcessorNode.h @@ -16,7 +16,7 @@ namespace dom { class AudioContext; class SharedBuffers; -class ScriptProcessorNode : public AudioNode +class ScriptProcessorNode final : public AudioNode { public: ScriptProcessorNode(AudioContext* aContext, diff --git a/dom/media/webaudio/StereoPannerNode.cpp b/dom/media/webaudio/StereoPannerNode.cpp index a3b713d4b2..d2a82aaed5 100644 --- a/dom/media/webaudio/StereoPannerNode.cpp +++ b/dom/media/webaudio/StereoPannerNode.cpp @@ -27,14 +27,14 @@ NS_INTERFACE_MAP_END_INHERITING(AudioNode) NS_IMPL_ADDREF_INHERITED(StereoPannerNode, AudioNode) NS_IMPL_RELEASE_INHERITED(StereoPannerNode, AudioNode) -class StereoPannerNodeEngine : public AudioNodeEngine +class StereoPannerNodeEngine final : public AudioNodeEngine { public: StereoPannerNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination) : AudioNodeEngine(aNode) , mSource(nullptr) - , mDestination(static_cast(aDestination->Stream())) + , mDestination(aDestination->Stream()) // Keep the default value in sync with the default value in // StereoPannerNode::StereoPannerNode. , mPan(0.f) @@ -176,12 +176,12 @@ StereoPannerNode::StereoPannerNode(AudioContext* aContext) 2, ChannelCountMode::Clamped_max, ChannelInterpretation::Speakers) - , mPan(new AudioParam(this, SendPanToStream, 0.f)) + , mPan(new AudioParam(this, SendPanToStream, 0.f, "pan")) { StereoPannerNodeEngine* engine = new StereoPannerNodeEngine(this, aContext->Destination()); mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM); - engine->SetSourceStream(static_cast(mStream.get())); + engine->SetSourceStream(mStream); } StereoPannerNode::~StereoPannerNode() diff --git a/dom/media/webaudio/StereoPannerNode.h b/dom/media/webaudio/StereoPannerNode.h index 66674c79e3..35e6da908a 100644 --- a/dom/media/webaudio/StereoPannerNode.h +++ b/dom/media/webaudio/StereoPannerNode.h @@ -15,7 +15,7 @@ namespace dom { class AudioContext; -class StereoPannerNode : public AudioNode +class StereoPannerNode final : public AudioNode { public: MOZ_DECLARE_REFCOUNTED_TYPENAME(StereoPannerNode) diff --git a/dom/media/webaudio/ThreeDPoint.h b/dom/media/webaudio/ThreeDPoint.h index 27b9e05533..b6d51e69a3 100644 --- a/dom/media/webaudio/ThreeDPoint.h +++ b/dom/media/webaudio/ThreeDPoint.h @@ -14,7 +14,8 @@ namespace mozilla { namespace dom { -struct ThreeDPoint { +struct ThreeDPoint final +{ ThreeDPoint() : x(0.) , y(0.) diff --git a/dom/media/webaudio/WaveShaperNode.cpp b/dom/media/webaudio/WaveShaperNode.cpp index c5d2f9cbb8..089da6dbfd 100644 --- a/dom/media/webaudio/WaveShaperNode.cpp +++ b/dom/media/webaudio/WaveShaperNode.cpp @@ -48,7 +48,7 @@ static uint32_t ValueOf(OverSampleType aType) } } -class Resampler +class Resampler final { public: Resampler() @@ -161,7 +161,7 @@ private: nsTArray mBuffer; }; -class WaveShaperNodeEngine : public AudioNodeEngine +class WaveShaperNodeEngine final : public AudioNodeEngine { public: explicit WaveShaperNodeEngine(AudioNode* aNode) @@ -324,7 +324,7 @@ WaveShaperNode::SetCurve(const Nullable& aCurve) mCurve = nullptr; } - AudioNodeStream* ns = static_cast(mStream.get()); + AudioNodeStream* ns = mStream; MOZ_ASSERT(ns, "Why don't we have a stream here?"); ns->SetRawArrayData(curve); } diff --git a/dom/media/webaudio/WaveShaperNode.h b/dom/media/webaudio/WaveShaperNode.h index 7c0d50eb38..9d32663638 100644 --- a/dom/media/webaudio/WaveShaperNode.h +++ b/dom/media/webaudio/WaveShaperNode.h @@ -16,7 +16,7 @@ namespace dom { class AudioContext; -class WaveShaperNode : public AudioNode +class WaveShaperNode final : public AudioNode { public: explicit WaveShaperNode(AudioContext *aContext); diff --git a/dom/media/webaudio/test/chrome.ini b/dom/media/webaudio/test/chrome.ini index 4de3332be8..035b1a405c 100644 --- a/dom/media/webaudio/test/chrome.ini +++ b/dom/media/webaudio/test/chrome.ini @@ -2,3 +2,4 @@ skip-if = buildapp == 'b2g' [test_AudioNodeDevtoolsAPI.html] +[test_AudioParamDevtoolsAPI.html] diff --git a/dom/media/webaudio/test/mochitest.ini b/dom/media/webaudio/test/mochitest.ini index c73b742718..41ba04ca36 100644 --- a/dom/media/webaudio/test/mochitest.ini +++ b/dom/media/webaudio/test/mochitest.ini @@ -43,6 +43,7 @@ skip-if = (toolkit == 'android' && (processor == 'x86' || debug)) || os == 'win' [test_audioBufferSourceNodeOffset.html] skip-if = (toolkit == 'gonk') || (toolkit == 'android') || debug #bug 906752 [test_audioBufferSourceNodePassThrough.html] +[test_audioBufferSourceNodeRate.html] [test_AudioContext.html] [test_audioContextSuspendResumeClose.html] [test_audioDestinationNode.html] diff --git a/dom/media/webaudio/test/test_AudioParamDevtoolsAPI.html b/dom/media/webaudio/test/test_AudioParamDevtoolsAPI.html new file mode 100644 index 0000000000..f859277307 --- /dev/null +++ b/dom/media/webaudio/test/test_AudioParamDevtoolsAPI.html @@ -0,0 +1,48 @@ + + + + Test the devtool AudioParam API + + + + +
+
+
+ + diff --git a/dom/media/webaudio/test/test_audioBufferSourceNodeRate.html b/dom/media/webaudio/test/test_audioBufferSourceNodeRate.html new file mode 100644 index 0000000000..2cdcd72702 --- /dev/null +++ b/dom/media/webaudio/test/test_audioBufferSourceNodeRate.html @@ -0,0 +1,66 @@ + + + + Test AudioBufferSourceNode + + + + + +
+
+
+ + diff --git a/dom/media/webaudio/test/test_dynamicsCompressorNode.html b/dom/media/webaudio/test/test_dynamicsCompressorNode.html index d68964031a..5eb5c253e9 100644 --- a/dom/media/webaudio/test/test_dynamicsCompressorNode.html +++ b/dom/media/webaudio/test/test_dynamicsCompressorNode.html @@ -41,7 +41,7 @@ addLoadEvent(function() { near(threshold.defaultValue, -24, "Correct default value for threshold"); near(knee.defaultValue, 30, "Correct default value for knee"); near(ratio.defaultValue, 12, "Correct default value for ratio"); - near(reduction.defaultValue, 0, "Correct default value for reduction"); + near(reduction, 0, "Correct default value for reduction"); near(attack.defaultValue, 0.003, "Correct default value for attack"); near(release.defaultValue, 0.25, "Correct default value for release"); } diff --git a/dom/media/webaudio/test/webaudio.js b/dom/media/webaudio/test/webaudio.js index 34a69fa92f..4cf68a8f92 100644 --- a/dom/media/webaudio/test/webaudio.js +++ b/dom/media/webaudio/test/webaudio.js @@ -105,6 +105,25 @@ function compareBuffers(got, expected) { } } +/** + * Compute the root mean square (RMS, + * ) of a channel of a slice + * (defined by `start` and `end`) of an AudioBuffer. + * + * This is useful to detect that a buffer is noisy or silent. + */ +function rms(audiobuffer, channel = 0, start = 0, end = audiobuffer.length) { + var buffer= audiobuffer.getChannelData(channel); + var rms = 0; + for (var i = start; i < end; i++) { + rms += buffer[i] * buffer[i]; + } + + rms /= buffer.length; + rms = Math.sqrt(rms); + return rms; +} + function getEmptyBuffer(context, length) { return context.createBuffer(gTest.numberOfChannels, length, context.sampleRate); } diff --git a/dom/webidl/AudioBufferSourceNode.webidl b/dom/webidl/AudioBufferSourceNode.webidl index dd029481f9..bdb46ea03f 100644 --- a/dom/webidl/AudioBufferSourceNode.webidl +++ b/dom/webidl/AudioBufferSourceNode.webidl @@ -15,6 +15,7 @@ interface AudioBufferSourceNode : AudioNode { attribute AudioBuffer? buffer; readonly attribute AudioParam playbackRate; + readonly attribute AudioParam detune; attribute boolean loop; attribute double loopStart; diff --git a/dom/webidl/AudioParam.webidl b/dom/webidl/AudioParam.webidl index 375ab62791..e5b53a2dc5 100644 --- a/dom/webidl/AudioParam.webidl +++ b/dom/webidl/AudioParam.webidl @@ -37,3 +37,13 @@ interface AudioParam { void cancelScheduledValues(double startTime); }; + +// Mozilla extension +partial interface AudioParam { + // The ID of the AudioNode this AudioParam belongs to. + [ChromeOnly] + readonly attribute unsigned long parentNodeId; + // The name of the AudioParam + [ChromeOnly] + readonly attribute DOMString name; +}; diff --git a/dom/webidl/DynamicsCompressorNode.webidl b/dom/webidl/DynamicsCompressorNode.webidl index 5e7021cdc2..7f55250913 100644 --- a/dom/webidl/DynamicsCompressorNode.webidl +++ b/dom/webidl/DynamicsCompressorNode.webidl @@ -15,7 +15,7 @@ interface DynamicsCompressorNode : AudioNode { readonly attribute AudioParam threshold; // in Decibels readonly attribute AudioParam knee; // in Decibels readonly attribute AudioParam ratio; // unit-less - readonly attribute AudioParam reduction; // in Decibels + readonly attribute float reduction; // in Decibels readonly attribute AudioParam attack; // in Seconds readonly attribute AudioParam release; // in Seconds