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)
This commit is contained in:
2021-03-16 09:22:31 +08:00
parent ae2cd1d073
commit 7bd3227e5d
65 changed files with 662 additions and 401 deletions
+3 -4
View File
@@ -475,11 +475,10 @@ DOMMediaStream::NotifyMediaStreamGraphShutdown()
}
void
DOMMediaStream::NotifyStreamStateChanged()
DOMMediaStream::NotifyStreamFinished()
{
if (IsFinished()) {
mConsumersToKeepAlive.Clear();
}
MOZ_ASSERT(IsFinished());
mConsumersToKeepAlive.Clear();
}
void
+2 -2
View File
@@ -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.
+8 -5
View File
@@ -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*
+51 -5
View File
@@ -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<MediaStream> mStream;
};
nsRefPtr<nsRunnable> runnable = new NotifyRunnable(this);
if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)))) {
return;
}
mNotificationMainThreadRunnable = runnable;
}
void
SourceMediaStream::DestroyImpl()
{
+31 -8
View File
@@ -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<GraphTime,uint32_t,0> mExplicitBlockerCount;
nsTArray<nsRefPtr<MediaStreamListener> > mListeners;
nsTArray<MainThreadMediaStreamListener*> mMainThreadListeners;
nsRefPtr<nsRunnable> mNotificationMainThreadRunnable;
nsTArray<TrackID> 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.
+18 -29
View File
@@ -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<AnalyserNode> 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<AnalyserNode*>(mStream->Engine()->Node());
}
nsRefPtr<AnalyserNode> node =
static_cast<AnalyserNode*>(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<float*>(
const_cast<void*>(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<float*>(
const_cast<void*>(aOutput->mChannelData[channel]));
AudioBlockInPlaceScale(samples, aOutput->mVolume);
}
nsRefPtr<TransferBuffer> 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<float*>(const_cast<void*>(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<float*>(const_cast<void*>(aOutput->mChannelData[channel]));
AudioBlockInPlaceScale(samples, aOutput->mVolume);
}
nsRefPtr<TransferBuffer> transfer = new TransferBuffer(aStream, *aOutput);
NS_DispatchToMainThread(transfer);
}
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
+1 -1
View File
@@ -15,7 +15,7 @@ namespace dom {
class AudioContext;
class AnalyserNode : public AudioNode
class AnalyserNode final : public AudioNode
{
public:
explicit AnalyserNode(AudioContext* aContext);
+91 -51
View File
@@ -14,6 +14,7 @@
#include "AudioDestinationNode.h"
#include "AudioParamTimeline.h"
#include <limits>
#include <algorithm>
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<AudioNodeStream*>(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<int32_t>(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<AudioNodeStream*>(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<AudioNodeStream*>(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<AudioNodeStream*>(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<AudioNodeStream*>(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<AudioBufferSourceNode> 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<AudioBufferSourceNode> 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<AudioBufferSourceNode*>(aNode);
if (!This->mStream) {
return;
}
SendTimelineParameterToStream(This, PLAYBACKRATE, *This->mPlaybackRate);
}
void
AudioBufferSourceNode::SendDetuneToStream(AudioNode* aNode)
{
AudioBufferSourceNode* This = static_cast<AudioBufferSourceNode*>(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();
+12 -11
View File
@@ -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<AudioBuffer> mBuffer;
nsRefPtr<AudioParam> mPlaybackRate;
nsRefPtr<AudioParam> mDetune;
bool mLoop;
bool mStartCalled;
bool mStopped;
};
} // namespace dom
+14 -17
View File
@@ -29,7 +29,7 @@ namespace dom {
static uint8_t gWebAudioOutputKey;
class OfflineDestinationNodeEngine : public AudioNodeEngine
class OfflineDestinationNodeEngine final : public AudioNodeEngine
{
public:
typedef AutoFallibleTArray<nsAutoArrayPtr<float>, 2> InputChannels;
@@ -134,7 +134,7 @@ public:
, mRenderedBuffer(aRenderedBuffer)
{}
NS_IMETHOD Run()
NS_IMETHOD Run() override
{
nsRefPtr<OfflineAudioCompletionEvent> 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<AudioNode> 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<nsIRunnable> runnable =
NS_NewRunnableMethod(this, &AudioDestinationNode::FireOfflineCompletionEvent);
NS_DispatchToCurrentThread(runnable);
}
MOZ_ASSERT(mStream->IsFinished());
if (mIsOffline) {
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this, &AudioDestinationNode::FireOfflineCompletionEvent);
NS_DispatchToCurrentThread(runnable);
}
}
void
AudioDestinationNode::FireOfflineCompletionEvent()
{
AudioNodeStream* stream = static_cast<AudioNodeStream*>(Stream());
OfflineDestinationNodeEngine* engine =
static_cast<OfflineDestinationNodeEngine*>(stream->Engine());
static_cast<OfflineDestinationNodeEngine*>(Stream()->Engine());
engine->FireOfflineCompletionEvent(this);
}
+1 -2
View File
@@ -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;
+4 -2
View File
@@ -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,
+35 -42
View File
@@ -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<ProcessedMediaStream*>(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<uint16_t>(aInput),
static_cast<uint16_t>(aOutput));
}
@@ -260,43 +258,41 @@ AudioNode::Connect(AudioParam& aDestination, uint32_t aOutput,
MediaStream* stream = aDestination.Stream();
MOZ_ASSERT(stream->AsProcessedStream());
ProcessedMediaStream* ps = static_cast<ProcessedMediaStream*>(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<uint16_t>(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<uint16_t>(aOutput));
}
}
void
AudioNode::SendDoubleParameterToStream(uint32_t aIndex, double aValue)
{
AudioNodeStream* ns = static_cast<AudioNodeStream*>(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<AudioNodeStream*>(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<AudioNodeStream*>(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<AudioNodeStream*>(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<AudioNodeStream*>(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<AudioNode> 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<nsIRunnable> runnable =
new RunnableRelease(mOutputNodes[i].forget());
nsRefPtr<AudioNode> output = mOutputNodes[i].forget();
mOutputNodes.RemoveElementAt(i);
mStream->RunAfterPendingUpdates(runnable.forget());
if (mStream) {
nsRefPtr<nsIRunnable> 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<AudioNodeStream*>(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<AudioNodeStream*>(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
+7 -6
View File
@@ -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<InputNode>& InputNodes() const
{
@@ -218,9 +220,8 @@ private:
nsRefPtr<AudioContext> mContext;
protected:
// Must be set in the constructor. Must not be null.
// If MaxNumberOfInputs() is > 0, then mStream must be a ProcessedMediaStream.
nsRefPtr<MediaStream> mStream;
// Must be set in the constructor. Must not be null unless finished.
nsRefPtr<AudioNodeStream> mStream;
private:
// For every InputNode, there is a corresponding entry in mOutputNodes of the
+7 -14
View File
@@ -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<AudioChunk, 1> 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;
};
@@ -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:
/**
+41 -25
View File
@@ -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<AudioNodeStream*>(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<AudioNodeStream*>(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<AudioNodeStream*>(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<AudioNodeStream*>(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<AudioNodeStream*>(mStream)->Engine()->
SetThreeDPointParameter(mIndex, mValue);
@@ -208,12 +218,14 @@ AudioNodeStream::SetThreeDPointParameter(uint32_t aIndex, const ThreeDPoint& aVa
void
AudioNodeStream::SetBuffer(already_AddRefed<ThreadSharedFloatArrayBufferList>&& aBuffer)
{
class Message : public ControlMessage {
class Message final : public ControlMessage
{
public:
Message(AudioNodeStream* aStream,
already_AddRefed<ThreadSharedFloatArrayBufferList>& aBuffer)
: ControlMessage(aStream), mBuffer(aBuffer) {}
virtual void Run()
: ControlMessage(aStream), mBuffer(aBuffer)
{}
virtual void Run() override
{
static_cast<AudioNodeStream*>(mStream)->Engine()->
SetBuffer(mBuffer.forget());
@@ -227,7 +239,8 @@ AudioNodeStream::SetBuffer(already_AddRefed<ThreadSharedFloatArrayBufferList>&&
void
AudioNodeStream::SetRawArrayData(nsTArray<float>& aData)
{
class Message : public ControlMessage {
class Message final : public ControlMessage
{
public:
Message(AudioNodeStream* aStream,
nsTArray<float>& aData)
@@ -235,7 +248,7 @@ AudioNodeStream::SetRawArrayData(nsTArray<float>& aData)
{
mData.SwapElements(aData);
}
virtual void Run()
virtual void Run() override
{
static_cast<AudioNodeStream*>(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<AudioNodeStream*>(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<AudioNodeStream*>(mStream)->mPassThrough = mPassThrough;
}
+2 -1
View File
@@ -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;
+8 -5
View File
@@ -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<ProcessedMediaStream*>(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);
+13 -1
View File
@@ -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<AudioNode::InputNode> 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<MediaInputPort> mNodeStreamPort;
};
+1 -1
View File
@@ -14,7 +14,7 @@
namespace mozilla {
namespace dom {
class AudioProcessingEvent : public Event
class AudioProcessingEvent final : public Event
{
public:
AudioProcessingEvent(ScriptProcessorNode* aOwner,
+7 -7
View File
@@ -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<AudioNodeStream*> (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<AudioNodeStream*> (mStream.get()));
engine->SetSourceStream(mStream);
}
BiquadFilterNode::~BiquadFilterNode()
+1 -1
View File
@@ -16,7 +16,7 @@ namespace dom {
class AudioContext;
class BiquadFilterNode : public AudioNode
class BiquadFilterNode final : public AudioNode
{
public:
explicit BiquadFilterNode(AudioContext* aContext);
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -14,7 +14,7 @@ namespace dom {
class AudioContext;
class ChannelMergerNode : public AudioNode
class ChannelMergerNode final : public AudioNode
{
public:
ChannelMergerNode(AudioContext* aContext,
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -14,7 +14,7 @@ namespace dom {
class AudioContext;
class ChannelSplitterNode : public AudioNode
class ChannelSplitterNode final : public AudioNode
{
public:
ChannelSplitterNode(AudioContext* aContext,
+2 -2
View File
@@ -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<AudioNodeStream*>(mStream.get());
AudioNodeStream* ns = mStream;
MOZ_ASSERT(ns, "Why don't we have a stream here?");
if (mBuffer) {
uint32_t length = mBuffer->Length();
+1 -1
View File
@@ -13,7 +13,7 @@
namespace mozilla {
namespace dom {
class ConvolverNode : public AudioNode
class ConvolverNode final : public AudioNode
{
public:
explicit ConvolverNode(AudioContext* aContext);
+2 -1
View File
@@ -13,7 +13,8 @@
namespace mozilla {
class DelayBuffer {
class DelayBuffer final
{
typedef dom::ChannelInterpretation ChannelInterpretation;
public:
+4 -4
View File
@@ -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<AudioNodeStream*> (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<AudioNodeStream*> (mStream.get()));
engine->SetSourceStream(mStream);
}
DelayNode::~DelayNode()
+1 -1
View File
@@ -15,7 +15,7 @@ namespace dom {
class AudioContext;
class DelayNode : public AudioNode
class DelayNode final : public AudioNode
{
public:
DelayNode(AudioContext* aContext, double aMaxDelay);
+15 -24
View File
@@ -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<AudioNodeStream*> (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<DynamicsCompressorNode> 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<DynamicsCompressorNode*>(mStream->Engine()->Node());
}
nsRefPtr<DynamicsCompressorNode> node =
static_cast<DynamicsCompressorNode*>
(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<AudioNodeStream*> (mStream.get()));
engine->SetSourceStream(mStream);
}
DynamicsCompressorNode::~DynamicsCompressorNode()
+13 -7
View File
@@ -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<AudioParam> mThreshold;
nsRefPtr<AudioParam> mKnee;
nsRefPtr<AudioParam> mRatio;
nsRefPtr<AudioParam> mReduction;
float mReduction;
nsRefPtr<AudioParam> mAttack;
nsRefPtr<AudioParam> mRelease;
};
+2 -1
View File
@@ -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)
+4 -4
View File
@@ -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<AudioNodeStream*> (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<AudioNodeStream*> (mStream.get()));
engine->SetSourceStream(mStream);
}
GainNode::~GainNode()
+1 -1
View File
@@ -15,7 +15,7 @@ namespace dom {
class AudioContext;
class GainNode : public AudioNode
class GainNode final : public AudioNode
{
public:
explicit GainNode(AudioContext* aContext);
+6 -4
View File
@@ -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)
@@ -12,7 +12,7 @@
namespace mozilla {
namespace dom {
class MediaElementAudioSourceNode : public MediaStreamAudioSourceNode
class MediaElementAudioSourceNode final : public MediaStreamAudioSourceNode
{
public:
static already_AddRefed<MediaElementAudioSourceNode>
@@ -12,7 +12,7 @@
namespace mozilla {
namespace dom {
class MediaStreamAudioDestinationNode : public AudioNode
class MediaStreamAudioDestinationNode final : public AudioNode
{
public:
explicit MediaStreamAudioDestinationNode(AudioContext* aContext);
@@ -15,7 +15,7 @@ namespace mozilla {
namespace dom {
class MediaStreamAudioSourceNodeEngine : public AudioNodeEngine
class MediaStreamAudioSourceNodeEngine final : public AudioNodeEngine
{
public:
explicit MediaStreamAudioSourceNodeEngine(AudioNode* aNode)
@@ -15,7 +15,7 @@ namespace dom {
class AudioContext;
class OfflineAudioCompletionEvent : public Event
class OfflineAudioCompletionEvent final : public Event
{
public:
OfflineAudioCompletionEvent(AudioContext* aOwner,
+57 -44
View File
@@ -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<AudioNodeStream*> (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<AudioNodeStream*> (mStream.get()));
engine->SetSourceStream(mStream);
mStream->AddMainThreadListener(this);
}
@@ -422,10 +421,22 @@ OscillatorNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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<OscillatorNode*>(aNode);
if (!This->mStream) {
return;
}
SendTimelineParameterToStream(This, OscillatorNodeEngine::FREQUENCY, *This->mFrequency);
}
@@ -433,12 +444,18 @@ void
OscillatorNode::SendDetuneToStream(AudioNode* aNode)
{
OscillatorNode* This = static_cast<OscillatorNode*>(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<AudioNodeStream*>(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<ThreadSharedFloatArrayBufferList> 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<AudioNodeStream*>(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<AudioNodeStream*>(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<OscillatorNode> 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<OscillatorNode> mNode;
};
NS_DispatchToMainThread(new EndedEventDispatcher(this));
// Drop the playing reference
// Warning: The below line might delete this.
MarkInactive();
}
} // namespace dom
+5 -11
View File
@@ -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<JSObject*> 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<AudioParam> mFrequency;
nsRefPtr<AudioParam> mDetune;
bool mStartCalled;
bool mStopped;
};
} // namespace dom
+4 -3
View File
@@ -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);
}
}
+2 -2
View File
@@ -21,8 +21,8 @@ namespace dom {
class AudioContext;
class AudioBufferSourceNode;
class PannerNode : public AudioNode,
public SupportsWeakPtr<PannerNode>
class PannerNode final : public AudioNode,
public SupportsWeakPtr<PannerNode>
{
public:
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(PannerNode)
+2 -10
View File
@@ -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<AudioNode> 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<AudioNode> node = mStream->Engine()->NodeMainThread();
if (node) {
if (mChange == ADDREF) {
node->MarkActive();
+1 -1
View File
@@ -12,7 +12,7 @@
namespace mozilla {
class ReportDecodeResultTask : public nsRunnable
class ReportDecodeResultTask final : public nsRunnable
{
public:
ReportDecodeResultTask(DecodeJob& aDecodeJob,
+7 -15
View File
@@ -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<nsAutoArrayPtr<float>, 2> InputChannels;
@@ -249,7 +249,7 @@ public:
: AudioNodeEngine(aNode)
, mSharedBuffers(aNode->GetSharedBuffers())
, mSource(nullptr)
, mDestination(static_cast<AudioNodeStream*> (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<ScriptProcessorNode> node = static_cast<ScriptProcessorNode*>
(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<AudioNodeStream*> (mStream.get()));
engine->SetSourceStream(mStream);
}
ScriptProcessorNode::~ScriptProcessorNode()
+1 -1
View File
@@ -16,7 +16,7 @@ namespace dom {
class AudioContext;
class SharedBuffers;
class ScriptProcessorNode : public AudioNode
class ScriptProcessorNode final : public AudioNode
{
public:
ScriptProcessorNode(AudioContext* aContext,
+4 -4
View File
@@ -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<AudioNodeStream*>(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<AudioNodeStream*>(mStream.get()));
engine->SetSourceStream(mStream);
}
StereoPannerNode::~StereoPannerNode()
+1 -1
View File
@@ -15,7 +15,7 @@ namespace dom {
class AudioContext;
class StereoPannerNode : public AudioNode
class StereoPannerNode final : public AudioNode
{
public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(StereoPannerNode)
+2 -1
View File
@@ -14,7 +14,8 @@ namespace mozilla {
namespace dom {
struct ThreeDPoint {
struct ThreeDPoint final
{
ThreeDPoint()
: x(0.)
, y(0.)
+3 -3
View File
@@ -48,7 +48,7 @@ static uint32_t ValueOf(OverSampleType aType)
}
}
class Resampler
class Resampler final
{
public:
Resampler()
@@ -161,7 +161,7 @@ private:
nsTArray<float> mBuffer;
};
class WaveShaperNodeEngine : public AudioNodeEngine
class WaveShaperNodeEngine final : public AudioNodeEngine
{
public:
explicit WaveShaperNodeEngine(AudioNode* aNode)
@@ -324,7 +324,7 @@ WaveShaperNode::SetCurve(const Nullable<Float32Array>& aCurve)
mCurve = nullptr;
}
AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
AudioNodeStream* ns = mStream;
MOZ_ASSERT(ns, "Why don't we have a stream here?");
ns->SetRawArrayData(curve);
}
+1 -1
View File
@@ -16,7 +16,7 @@ namespace dom {
class AudioContext;
class WaveShaperNode : public AudioNode
class WaveShaperNode final : public AudioNode
{
public:
explicit WaveShaperNode(AudioContext *aContext);
+1
View File
@@ -2,3 +2,4 @@
skip-if = buildapp == 'b2g'
[test_AudioNodeDevtoolsAPI.html]
[test_AudioParamDevtoolsAPI.html]
+1
View File
@@ -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]
@@ -0,0 +1,48 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test the devtool AudioParam API</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
Components.utils.import('resource://gre/modules/Services.jsm');
function checkIdAndName(node, name) {
is(node.id, node[name].parentNodeId, "The parent id should be correct");
is(node[name].name, name, "The name of the AudioParam should be correct.");
}
var ac = new AudioContext(),
gain = ac.createGain(),
osc = ac.createOscillator(),
del = ac.createDelay(),
source = ac.createBufferSource(),
stereoPanner = ac.createStereoPanner(),
comp = ac.createDynamicsCompressor(),
biquad = ac.createBiquadFilter();
checkIdAndName(gain, "gain");
checkIdAndName(osc, "frequency");
checkIdAndName(osc, "detune");
checkIdAndName(del, "delayTime");
checkIdAndName(source, "playbackRate");
checkIdAndName(source, "detune");
checkIdAndName(stereoPanner, "pan");
checkIdAndName(comp, "threshold");
checkIdAndName(comp, "knee");
checkIdAndName(comp, "ratio");
checkIdAndName(comp, "attack");
checkIdAndName(comp, "release");
checkIdAndName(biquad, "frequency");
checkIdAndName(biquad, "detune");
checkIdAndName(biquad, "Q");
checkIdAndName(biquad, "gain");
</script>
</pre>
</body>
</html>
@@ -0,0 +1,66 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test AudioBufferSourceNode</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
var rate = 44100;
var off = new OfflineAudioContext(1, rate, rate);
var off2 = new OfflineAudioContext(1, rate, rate);
var source = off.createBufferSource();
var source2 = off2.createBufferSource();
// a buffer of a 440Hz at half the length. If we detune by -1200 or set the
// playbackRate to 0.5, we should get 44100 samples back with a sine at 220Hz.
var buf = off.createBuffer(1, rate / 2, rate);
var bufarray = buf.getChannelData(0);
for (var i = 0; i < bufarray.length; i++) {
bufarray[i] = Math.sin(i * 440 * 2 * Math.PI / rate);
}
source.buffer = buf;
source.playbackRate.value = 0.5; // 50% slowdown
source.connect(off.destination);
source.start(0);
source2.buffer = buf;
source2.detune.value = -1200; // one octave -> 50% slowdown
source2.connect(off2.destination);
source2.start(0);
var finished = 0;
function finish() {
finished++;
if (finished == 2) {
SimpleTest.finish();
}
}
off.startRendering().then((renderedPlaybackRate) => {
// we don't care about comparing the value here, we just want to know whether
// the second part is noisy.
var rmsValue = rms(renderedPlaybackRate, 0, 22050);
ok(rmsValue != 0, "Resampling happened (rms of the second part " + rmsValue + ")");
off2.startRendering().then((renderedDetune) => {
var rmsValue = rms(renderedDetune, 0, 22050);
ok(rmsValue != 0, "Resampling happened (rms of the second part " + rmsValue + ")");
// The two buffers should be the same: detune of -1200 is a 50% slowdown
compareBuffers(renderedPlaybackRate, renderedDetune);
SimpleTest.finish();
});
});
</script>
</pre>
</body>
</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");
}
+19
View File
@@ -105,6 +105,25 @@ function compareBuffers(got, expected) {
}
}
/**
* Compute the root mean square (RMS,
* <http://en.wikipedia.org/wiki/Root_mean_square>) 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);
}
+1
View File
@@ -15,6 +15,7 @@ interface AudioBufferSourceNode : AudioNode {
attribute AudioBuffer? buffer;
readonly attribute AudioParam playbackRate;
readonly attribute AudioParam detune;
attribute boolean loop;
attribute double loopStart;
+10
View File
@@ -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;
};
+1 -1
View File
@@ -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