Bug 886657. Don't play anything from an AudioBufferSourceNode until a buffer has been set and start() has been called. r=ehsan

This commit is contained in:
Robert O'Callahan 2013-06-26 04:00:42 +12:00
parent 6045ea2dc7
commit 315060d0c1
3 changed files with 54 additions and 6 deletions

View File

@ -41,6 +41,12 @@ NS_INTERFACE_MAP_END_INHERITING(AudioNode)
NS_IMPL_ADDREF_INHERITED(AudioBufferSourceNode, AudioNode)
NS_IMPL_RELEASE_INHERITED(AudioBufferSourceNode, AudioNode)
/**
* Media-thread playback engine for AudioBufferSourceNode.
* Nothing is played until a non-null buffer has been set (via
* AudioNodeStream::SetBuffer) and a non-zero duration has been set (via
* AudioNodeStream::SetInt32Parameter).
*/
class AudioBufferSourceNodeEngine : public AudioNodeEngine
{
public:
@ -353,8 +359,9 @@ public:
AudioChunk* aOutput,
bool* aFinished)
{
if (!mBuffer)
if (!mBuffer || !mDuration) {
return;
}
uint32_t channels = mBuffer->GetChannels();
if (!channels) {
@ -484,7 +491,9 @@ AudioBufferSourceNode::Start(double aWhen, double aOffset,
std::numeric_limits<double>::min();
SendOffsetAndDurationParametersToStream(ns, aOffset, duration);
} else {
// Remember our arguments so that we can use them once we have a buffer
// Remember our arguments so that we can use them once we have a buffer.
// We can't send these parameters now because we don't know the buffer
// sample rate.
mOffset = aOffset;
mDuration = aDuration.WasPassed() ?
aDuration.Value() :
@ -512,11 +521,13 @@ AudioBufferSourceNode::SendBufferParameterToStream(JSContext* aCx)
mBuffer->GetThreadSharedChannelsForRate(aCx);
ns->SetBuffer(data.forget());
ns->SetInt32Parameter(SAMPLE_RATE, rate);
if (mStartCalled) {
SendOffsetAndDurationParametersToStream(ns, mOffset, mDuration);
}
} else {
ns->SetBuffer(nullptr);
}
SendOffsetAndDurationParametersToStream(ns, mOffset, mDuration);
}
void
@ -524,8 +535,11 @@ AudioBufferSourceNode::SendOffsetAndDurationParametersToStream(AudioNodeStream*
double aOffset,
double aDuration)
{
float rate = mBuffer ? mBuffer->SampleRate() : Context()->SampleRate();
int32_t lengthSamples = mBuffer ? mBuffer->Length() : 0;
NS_ASSERTION(mBuffer && mStartCalled,
"Only call this when we have a buffer and start() has been called");
float rate = mBuffer->SampleRate();
int32_t lengthSamples = mBuffer->Length();
double length = double(lengthSamples) / rate;
double offset = std::max(0.0, aOffset);
double endOffset = aDuration == std::numeric_limits<double>::min() ?

View File

@ -44,6 +44,7 @@ MOCHITEST_FILES := \
test_audioBufferSourceNodeLoop.html \
test_audioBufferSourceNodeLoopStartEnd.html \
test_audioBufferSourceNodeLoopStartEndSame.html \
test_audioBufferSourceNodeNoStart.html \
test_audioBufferSourceNodeNullBuffer.html \
test_badConnect.html \
test_biquadFilterNode.html \

View File

@ -0,0 +1,33 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test AudioBufferSourceNode when start() is not called</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">
var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var buffer = context.createBuffer(1, 2048, context.sampleRate);
var data = buffer.getChannelData(0);
for (var i = 0; i < data.length; ++i) {
data[i] = (i%100)/100 - 0.5;
}
var source = context.createBufferSource();
source.buffer = buffer;
return source;
},
};
runTest();
</script>
</pre>
</body>
</html>