Chromium Code Reviews| Index: Source/modules/webaudio/AudioBufferSourceNode.cpp |
| diff --git a/Source/modules/webaudio/AudioBufferSourceNode.cpp b/Source/modules/webaudio/AudioBufferSourceNode.cpp |
| index 399249364d8bcdde9118834ffe34dae80d774d43..f56d7ccfffe9407446cde126eb37304d9bc2d3a1 100644 |
| --- a/Source/modules/webaudio/AudioBufferSourceNode.cpp |
| +++ b/Source/modules/webaudio/AudioBufferSourceNode.cpp |
| @@ -47,6 +47,12 @@ const double DefaultGrainDuration = 0.020; // 20ms |
| // to minimize linear interpolation aliasing. |
| const double MaxRate = 1024; |
| +// Number of extra frames to use when determining if a source node can be stopped. This should be |
| +// at least one rendering quantum, but we add one more quantum for good measure. This doesn't need |
| +// to be extra precise, just more than one rendering quantum. See |handleStoppableSourceNode()|. |
| +// FIXME: Expose the rendering quantum somehow instead of hardwiring a value here. |
| +const int kExtraStopFrames = 256; |
| + |
| AudioBufferSourceHandler::AudioBufferSourceHandler(AudioNode& node, float sampleRate, AudioParamHandler& playbackRate) |
| : AudioScheduledSourceHandler(NodeTypeAudioBufferSource, node, sampleRate) |
| , m_buffer(nullptr) |
| @@ -489,8 +495,10 @@ double AudioBufferSourceHandler::computePlaybackRate() |
| // Normally it's not an issue because buffers are loaded at the |
| // AudioContext's sample-rate, but we can handle it in any case. |
| double sampleRateFactor = 1.0; |
| - if (buffer()) |
| - sampleRateFactor = buffer()->sampleRate() / sampleRate(); |
| + if (buffer()) { |
| + // Use doubles to compute this to full accuracy. |
| + sampleRateFactor = buffer()->sampleRate() / static_cast<double>(sampleRate()); |
| + } |
| // Use finalValue() to incorporate changes of AudioParamTimeline and |
| // AudioSummingJunction from m_playbackRate AudioParam. |
| @@ -541,7 +549,14 @@ void AudioBufferSourceHandler::handleStoppableSourceNode() |
| // If the source node is not looping, and we have a buffer, we can determine when the |
| // source would stop playing. |
| if (!loop() && buffer() && isPlayingOrScheduled()) { |
| - double stopTime = m_startTime + buffer()->duration(); |
| + // See crbug.com/478301. If a source node is started via start(), the source won't start at |
| + // that time but one quantum (128 frames) later. But we compute the stop time based on the |
| + // start time and the duration, so we end up stopping one quantum early. Thus, add a little |
| + // extra time; we just need to stop the source sometime after it should have stopped if it |
| + // hadn't already. |
| + double extraStopTime = kExtraStopFrames / static_cast<double>(context()->sampleRate()); |
| + double stopTime = m_startTime + buffer()->duration() + extraStopTime; |
|
Ken Russell (switch to Gerrit)
2015/04/22 19:01:50
This seems like a classic rounding error. Does the
Raymond Toy
2015/04/22 20:19:45
Without this fix, it's the last few frames for the
|
| + |
| if (context()->currentTime() > stopTime) { |
| // The context time has passed the time when the source nodes should have stopped |
| // playing. Stop the node now and deref it. (But don't run the onEnded event because the |