Bug 1173016 - Cache the basic waveform PeriodicWaves. r=karlt
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -30,16 +30,17 @@
#include "StereoPannerNode.h"
#include "ChannelMergerNode.h"
#include "ChannelSplitterNode.h"
#include "MediaStreamAudioDestinationNode.h"
#include "WaveShaperNode.h"
#include "PeriodicWave.h"
#include "ConvolverNode.h"
#include "OscillatorNode.h"
+#include "blink/PeriodicWave.h"
#include "nsNetUtil.h"
#include "AudioStream.h"
#include "mozilla/dom/Promise.h"
namespace mozilla {
namespace dom {
// 0 is a special value that MediaStreams use to denote they are not part of a
@@ -1045,10 +1046,53 @@ AudioContext::CollectReports(nsIHandleRe
}
double
AudioContext::ExtraCurrentTime() const
{
return mDestination->ExtraCurrentTime();
}
+BasicWaveFormCache*
+AudioContext::GetBasicWaveFormCache()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (!mBasicWaveFormCache) {
+ mBasicWaveFormCache = new BasicWaveFormCache(SampleRate());
+ }
+ return mBasicWaveFormCache;
+}
+
+BasicWaveFormCache::BasicWaveFormCache(uint32_t aSampleRate)
+ : mSampleRate(aSampleRate)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+}
+BasicWaveFormCache::~BasicWaveFormCache()
+{ }
+
+WebCore::PeriodicWave*
+BasicWaveFormCache::GetBasicWaveForm(OscillatorType aType)
+{
+ MOZ_ASSERT(!NS_IsMainThread());
+ if (aType == OscillatorType::Sawtooth) {
+ if (!mSawtooth) {
+ mSawtooth = WebCore::PeriodicWave::createSawtooth(mSampleRate);
+ }
+ return mSawtooth;
+ } else if (aType == OscillatorType::Square) {
+ if (!mSquare) {
+ mSquare = WebCore::PeriodicWave::createSquare(mSampleRate);
+ }
+ return mSquare;
+ } else if (aType == OscillatorType::Triangle) {
+ if (!mTriangle) {
+ mTriangle = WebCore::PeriodicWave::createTriangle(mSampleRate);
+ }
+ return mTriangle;
+ } else {
+ MOZ_ASSERT(false, "Not reached");
+ return nullptr;
+ }
+}
+
}
}
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -22,16 +22,20 @@
#include "nsIMemoryReporter.h"
// X11 has a #define for CurrentTime. Unbelievable :-(.
// See dom/media/DOMMediaStream.h for more fun!
#ifdef CurrentTime
#undef CurrentTime
#endif
+namespace WebCore {
+ class PeriodicWave;
+};
+
class nsPIDOMWindow;
namespace mozilla {
class DOMMediaStream;
class ErrorResult;
class MediaStream;
class MediaStreamGraph;
@@ -60,16 +64,35 @@ class MediaStreamAudioDestinationNode;
class MediaStreamAudioSourceNode;
class OscillatorNode;
class PannerNode;
class ScriptProcessorNode;
class StereoPannerNode;
class WaveShaperNode;
class PeriodicWave;
class Promise;
+enum class OscillatorType : uint32_t;
+
+// This is addrefed by the OscillatorNodeEngine on the main thread
+// and then used from the MSG thread.
+// It can be released either from the graph thread or the main thread.
+class BasicWaveFormCache
+{
+public:
+ BasicWaveFormCache(uint32_t aSampleRate);
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BasicWaveFormCache)
+ WebCore::PeriodicWave* GetBasicWaveForm(OscillatorType aType);
+private:
+ ~BasicWaveFormCache();
+ nsRefPtr<WebCore::PeriodicWave> mSawtooth;
+ nsRefPtr<WebCore::PeriodicWave> mSquare;
+ nsRefPtr<WebCore::PeriodicWave> mTriangle;
+ uint32_t mSampleRate;
+};
+
/* This runnable allows the MSG to notify the main thread when audio is actually
* flowing */
class StateChangeTask final : public nsRunnable
{
public:
/* This constructor should be used when this event is sent from the main
* thread. */
@@ -289,16 +312,18 @@ public:
double StreamTimeToDOMTime(double aTime) const
{
return aTime + ExtraCurrentTime();
}
void OnStateChanged(void* aPromise, AudioContextState aNewState);
+ BasicWaveFormCache* GetBasicWaveFormCache();
+
IMPL_EVENT_HANDLER(mozinterruptbegin)
IMPL_EVENT_HANDLER(mozinterruptend)
private:
/**
* Returns the amount of extra time added to the current time of the
* AudioDestinationNode's MediaStream to get this AudioContext's currentTime.
* Must be subtracted from all DOM API parameter times that are on the same
@@ -334,16 +359,18 @@ private:
// they are resolved, so we can safely pass them accross threads.
nsTArray<nsRefPtr<Promise>> mPromiseGripArray;
// See RegisterActiveNode. These will keep the AudioContext alive while it
// is rendering and the window remains alive.
nsTHashtable<nsRefPtrHashKey<AudioNode> > mActiveNodes;
// Hashsets containing all the PannerNodes, to compute the doppler shift.
// These are weak pointers.
nsTHashtable<nsPtrHashKey<PannerNode> > mPannerNodes;
+ // Cache to avoid recomputing basic waveforms all the time.
+ nsRefPtr<BasicWaveFormCache> mBasicWaveFormCache;
// Number of channels passed in the OfflineAudioContext ctor.
uint32_t mNumberOfChannels;
// Number of nodes that currently exist for this AudioContext
int32_t mNodeCount;
bool mIsOffline;
bool mIsStarted;
bool mIsShutDown;
// Close has been called, reject suspend and resume call.
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -35,16 +35,18 @@ public:
// Keep the default values in sync with OscillatorNode::OscillatorNode.
, mFrequency(440.f)
, mDetune(0.f)
, mType(OscillatorType::Sine)
, mPhase(0.)
, mRecomputeParameters(true)
, mCustomLength(0)
{
+ MOZ_ASSERT(NS_IsMainThread());
+ mBasicWaveFormCache = aDestination->Context()->GetBasicWaveFormCache();
}
void SetSourceStream(AudioNodeStream* aSource)
{
mSource = aSource;
}
enum Parameters {
@@ -99,23 +101,19 @@ public:
mPeriodicWave = nullptr;
mRecomputeParameters = true;
}
switch (mType) {
case OscillatorType::Sine:
mPhase = 0.0;
break;
case OscillatorType::Square:
- mPeriodicWave = WebCore::PeriodicWave::createSquare(mSource->SampleRate());
- break;
case OscillatorType::Triangle:
- mPeriodicWave = WebCore::PeriodicWave::createTriangle(mSource->SampleRate());
- break;
case OscillatorType::Sawtooth:
- mPeriodicWave = WebCore::PeriodicWave::createSawtooth(mSource->SampleRate());
+ mPeriodicWave = mBasicWaveFormCache->GetBasicWaveForm(mType);
break;
case OscillatorType::Custom:
break;
default:
NS_ERROR("Bad OscillatorNodeEngine type parameter.");
}
// End type switch.
break;
@@ -366,18 +364,19 @@ public:
AudioParamTimeline mFrequency;
AudioParamTimeline mDetune;
OscillatorType mType;
float mPhase;
float mFinalFrequency;
float mPhaseIncrement;
bool mRecomputeParameters;
nsRefPtr<ThreadSharedFloatArrayBufferList> mCustom;
+ nsRefPtr<BasicWaveFormCache> mBasicWaveFormCache;
uint32_t mCustomLength;
- nsAutoPtr<WebCore::PeriodicWave> mPeriodicWave;
+ nsRefPtr<WebCore::PeriodicWave> mPeriodicWave;
};
OscillatorNode::OscillatorNode(AudioContext* aContext)
: AudioNode(aContext,
2,
ChannelCountMode::Max,
ChannelInterpretation::Speakers)
, mType(OscillatorType::Sine)
--- a/dom/media/webaudio/PeriodicWave.h
+++ b/dom/media/webaudio/PeriodicWave.h
@@ -7,17 +7,16 @@
#ifndef PeriodicWave_h_
#define PeriodicWave_h_
#include "nsWrapperCache.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h"
#include "AudioContext.h"
#include "AudioNodeEngine.h"
-#include "nsAutoPtr.h"
namespace mozilla {
namespace dom {
class PeriodicWave final : public nsWrapperCache
{
public:
--- a/dom/media/webaudio/blink/PeriodicWave.h
+++ b/dom/media/webaudio/blink/PeriodicWave.h
@@ -37,16 +37,19 @@
namespace WebCore {
typedef AlignedTArray<float> AlignedAudioFloatArray;
typedef nsTArray<float> AudioFloatArray;
class PeriodicWave {
public:
+
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PeriodicWave);
+
static PeriodicWave* createSine(float sampleRate);
static PeriodicWave* createSquare(float sampleRate);
static PeriodicWave* createSawtooth(float sampleRate);
static PeriodicWave* createTriangle(float sampleRate);
// Creates an arbitrary periodic wave given the frequency components
// (Fourier coefficients).
static PeriodicWave* create(float sampleRate,
@@ -70,16 +73,17 @@ public:
unsigned periodicWaveSize() const { return m_periodicWaveSize; }
float sampleRate() const { return m_sampleRate; }
size_t sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
private:
explicit PeriodicWave(float sampleRate);
+ ~PeriodicWave() {}
void generateBasicWaveform(mozilla::dom::OscillatorType);
float m_sampleRate;
unsigned m_periodicWaveSize;
unsigned m_numberOfRanges;
float m_centsPerRange;