b=991533 limit AudioBuffers from decodeAudioData to the same sample rates as createBuffer r=ehsan

The numberOfChannels array on AudioBuffer is now an infallible array, as this
is considerably smaller than infallible channel data array allocations in
AllocateAudioBlock and similar to channel data pointer array allocations in
AudioChunk.

--HG--
extra : transplant_source : C%29_%13%9C%9C%A1%E1%A3%E8%C9_%93%11%85lM%FC%7E%BC
This commit is contained in:
Karl Tomlinson 2014-05-16 09:23:27 +12:00
parent 651d766fc4
commit 63192b0276
7 changed files with 60 additions and 57 deletions

View File

@ -41,12 +41,13 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AudioBuffer, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioBuffer, Release)
AudioBuffer::AudioBuffer(AudioContext* aContext, uint32_t aLength,
float aSampleRate)
AudioBuffer::AudioBuffer(AudioContext* aContext, uint32_t aNumberOfChannels,
uint32_t aLength, float aSampleRate)
: mContext(aContext),
mLength(aLength),
mSampleRate(aSampleRate)
{
mJSChannels.SetCapacity(aNumberOfChannels);
SetIsDOMBinding();
mozilla::HoldJSObjects(this);
}
@ -63,22 +64,35 @@ AudioBuffer::ClearJSChannels()
mozilla::DropJSObjects(this);
}
bool
AudioBuffer::InitializeBuffers(uint32_t aNumberOfChannels, JSContext* aJSContext)
/* static */ already_AddRefed<AudioBuffer>
AudioBuffer::Create(AudioContext* aContext, uint32_t aNumberOfChannels,
uint32_t aLength, float aSampleRate,
JSContext* aJSContext, ErrorResult& aRv)
{
if (!mJSChannels.SetCapacity(aNumberOfChannels)) {
return false;
}
for (uint32_t i = 0; i < aNumberOfChannels; ++i) {
JS::Rooted<JSObject*> array(aJSContext,
JS_NewFloat32Array(aJSContext, mLength));
if (!array) {
return false;
}
mJSChannels.AppendElement(array.get());
// Note that a buffer with zero channels is permitted here for the sake of
// AudioProcessingEvent, where channel counts must match parameters passed
// to createScriptProcessor(), one of which may be zero.
if (aSampleRate < WebAudioUtils::MinSampleRate ||
aSampleRate > WebAudioUtils::MaxSampleRate ||
!aLength || aLength > INT32_MAX) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
return true;
nsRefPtr<AudioBuffer> buffer =
new AudioBuffer(aContext, aNumberOfChannels, aLength, aSampleRate);
for (uint32_t i = 0; i < aNumberOfChannels; ++i) {
JS::Rooted<JSObject*> array(aJSContext,
JS_NewFloat32Array(aJSContext, aLength));
if (!array) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
buffer->mJSChannels.AppendElement(array.get());
}
return buffer.forget();
}
JSObject*

View File

@ -33,17 +33,13 @@ class AudioContext;
class AudioBuffer MOZ_FINAL : public nsWrapperCache
{
public:
AudioBuffer(AudioContext* aContext, uint32_t aLength,
float aSampleRate);
~AudioBuffer();
static already_AddRefed<AudioBuffer>
Create(AudioContext* aContext, uint32_t aNumberOfChannels,
uint32_t aLength, float aSampleRate,
JSContext* aJSContext, ErrorResult& aRv);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
// This function needs to be called in order to allocate
// all of the channels. It is fallible!
bool InitializeBuffers(uint32_t aNumberOfChannels,
JSContext* aJSContext);
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AudioBuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AudioBuffer)
@ -100,12 +96,16 @@ public:
void SetRawChannelContents(uint32_t aChannel, float* aContents);
protected:
AudioBuffer(AudioContext* aContext, uint32_t aNumberOfChannels,
uint32_t aLength, float aSampleRate);
~AudioBuffer();
bool RestoreJSChannelData(JSContext* aJSContext);
void ClearJSChannels();
nsRefPtr<AudioContext> mContext;
// Float32Arrays
AutoFallibleTArray<JS::Heap<JSObject*>, 2> mJSChannels;
nsAutoTArray<JS::Heap<JSObject*>, 2> mJSChannels;
// mSharedChannels aggregates the data from mJSChannels. This is non-null
// if and only if the mJSChannels are neutered.

View File

@ -204,26 +204,13 @@ AudioContext::CreateBuffer(JSContext* aJSContext, uint32_t aNumberOfChannels,
uint32_t aLength, float aSampleRate,
ErrorResult& aRv)
{
if (aSampleRate < WebAudioUtils::MinSampleRate ||
aSampleRate > WebAudioUtils::MaxSampleRate ||
!aLength || !aNumberOfChannels) {
if (!aNumberOfChannels) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
if (aLength > INT32_MAX) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
nsRefPtr<AudioBuffer> buffer =
new AudioBuffer(this, int32_t(aLength), aSampleRate);
if (!buffer->InitializeBuffers(aNumberOfChannels, aJSContext)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
return buffer.forget();
return AudioBuffer::Create(this, aNumberOfChannels, aLength,
aSampleRate, aJSContext, aRv);
}
namespace {

View File

@ -137,10 +137,11 @@ public:
JSAutoCompartment ac(cx, global);
// Create the input buffer
nsRefPtr<AudioBuffer> renderedBuffer = new AudioBuffer(context,
mLength,
mSampleRate);
if (!renderedBuffer->InitializeBuffers(mInputChannels.Length(), cx)) {
ErrorResult rv;
nsRefPtr<AudioBuffer> renderedBuffer =
AudioBuffer::Create(context, mInputChannels.Length(),
mLength, mSampleRate, cx, rv);
if (rv.Failed()) {
return;
}
for (uint32_t i = 0; i < mInputChannels.Length(); ++i) {

View File

@ -53,13 +53,10 @@ AudioProcessingEvent::LazilyCreateBuffer(uint32_t aNumberOfChannels,
JSAutoCompartment ac(cx, global);
nsRefPtr<AudioBuffer> buffer =
new AudioBuffer(mNode->Context(), mNode->BufferSize(),
mNode->Context()->SampleRate());
if (!buffer->InitializeBuffers(aNumberOfChannels, cx)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
AudioBuffer::Create(mNode->Context(), aNumberOfChannels,
mNode->BufferSize(),
mNode->Context()->SampleRate(), cx, aRv);
MOZ_ASSERT(buffer || aRv.ErrorCode() == NS_ERROR_OUT_OF_MEMORY);
return buffer.forget();
}

View File

@ -413,8 +413,10 @@ WebAudioDecodeJob::AllocateBuffer()
JSAutoCompartment ac(cx, global);
// Now create the AudioBuffer
mOutput = new AudioBuffer(mContext, mWriteIndex, mContext->SampleRate());
if (!mOutput->InitializeBuffers(mChannelBuffers.Length(), cx)) {
ErrorResult rv;
mOutput = AudioBuffer::Create(mContext, mChannelBuffers.Length(),
mWriteIndex, mContext->SampleRate(), cx, rv);
if (rv.Failed()) {
return false;
}

View File

@ -415,10 +415,12 @@ private:
// Create the input buffer
nsRefPtr<AudioBuffer> inputBuffer;
if (!mNullInput) {
inputBuffer = new AudioBuffer(node->Context(),
node->BufferSize(),
node->Context()->SampleRate());
if (!inputBuffer->InitializeBuffers(mInputChannels.Length(), cx)) {
ErrorResult rv;
inputBuffer =
AudioBuffer::Create(node->Context(), mInputChannels.Length(),
node->BufferSize(),
node->Context()->SampleRate(), cx, rv);
if (rv.Failed()) {
return NS_OK;
}
// Put the channel data inside it