Commit 51acf0d0 authored by rtoy@chromium.org's avatar rtoy@chromium.org

Defer changes to the channel count mode to the pre or post-render phase

In some situations, the channel count mode is updated just before the
audio rendering starts. During audio processing, the channel count
mode is used to set the number of channels for processing.  However,
for AudioBasicProcessor's, the number of kernels has not yet been
updated to the correct number of channels, so the incorrect number of
channels is accessed.

We delay the setting of the channel count mode until the pre or post
rendering phase of the audio thread where it is safe to change things
since the audio graph is not being pulled.

BUG=407489

Review URL: https://codereview.chromium.org/543073004

git-svn-id: svn://svn.chromium.org/blink/trunk@181573 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 0dcfa979
......@@ -673,6 +673,9 @@ void AudioContext::handlePreRenderTasks()
// It's OK if the tryLock() fails, we'll just take slightly longer to pick up the changes.
bool mustReleaseLock;
if (tryLock(mustReleaseLock)) {
// Update the channel count mode.
updateChangedChannelCountMode();
// Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutputs.
handleDirtyAudioSummingJunctions();
handleDirtyAudioNodeOutputs();
......@@ -693,6 +696,9 @@ void AudioContext::handlePostRenderTasks()
// from the render graph (in which case they'll render silence).
bool mustReleaseLock;
if (tryLock(mustReleaseLock)) {
// Update the channel count mode.
updateChangedChannelCountMode();
// Take care of AudioNode tasks where the tryLock() failed previously.
handleDeferredAudioNodeTasks();
......@@ -890,6 +896,30 @@ void AudioContext::trace(Visitor* visitor)
EventTargetWithInlineData::trace(visitor);
}
void AudioContext::addChangedChannelCountMode(AudioNode* node)
{
ASSERT(isGraphOwner());
ASSERT(isMainThread());
m_deferredCountModeChange.add(node);
}
void AudioContext::removeChangedChannelCountMode(AudioNode* node)
{
ASSERT(isGraphOwner());
m_deferredCountModeChange.remove(node);
}
void AudioContext::updateChangedChannelCountMode()
{
ASSERT(isGraphOwner());
for (HashSet<AudioNode*>::iterator k = m_deferredCountModeChange.begin(); k != m_deferredCountModeChange.end(); ++k)
(*k)->updateChannelCountMode();
m_deferredCountModeChange.clear();
}
} // namespace blink
#endif // ENABLE(WEB_AUDIO)
......@@ -151,6 +151,12 @@ public:
// Called right before handlePostRenderTasks() to handle nodes which need to be pulled even when they are not connected to anything.
void processAutomaticPullNodes(size_t framesToProcess);
// Keep track of AudioNode's that have their channel count mode changed. We process the changes
// in the post rendering phase.
void addChangedChannelCountMode(AudioNode*);
void removeChangedChannelCountMode(AudioNode*);
void updateChangedChannelCountMode();
// Keeps track of the number of connections made.
void incrementConnectionCount()
{
......@@ -342,6 +348,11 @@ private:
AsyncAudioDecoder m_audioDecoder;
// Collection of nodes where the channel count mode has changed. We want the channel count mode
// to change in the pre- or post-rendering phase so as not to disturb the running audio thread.
GC_PLUGIN_IGNORE("http://crbug.com/404527")
HashSet<AudioNode*> m_deferredCountModeChange;
// This is considering 32 is large enough for multiple channels audio.
// It is somewhat arbitrary and could be increased if necessary.
enum { MaxNumberOfChannels = 32 };
......
......@@ -54,6 +54,7 @@ AudioNode::AudioNode(AudioContext* context, float sampleRate)
, m_lastNonSilentTime(-1)
, m_connectionRefCount(0)
, m_isDisabled(false)
, m_newChannelCountMode(Max)
, m_channelCount(2)
, m_channelCountMode(Max)
, m_channelInterpretation(AudioBus::Speakers)
......@@ -92,6 +93,7 @@ void AudioNode::dispose()
ASSERT(isMainThread());
ASSERT(context()->isGraphOwner());
context()->removeChangedChannelCountMode(this);
context()->removeAutomaticPullNode(this);
context()->disposeOutputs(*this);
for (unsigned i = 0; i < m_outputs.size(); ++i)
......@@ -308,17 +310,17 @@ void AudioNode::setChannelCountMode(const String& mode, ExceptionState& exceptio
ChannelCountMode oldMode = m_channelCountMode;
if (mode == "max") {
m_channelCountMode = Max;
m_newChannelCountMode = Max;
} else if (mode == "clamped-max") {
m_channelCountMode = ClampedMax;
m_newChannelCountMode = ClampedMax;
} else if (mode == "explicit") {
m_channelCountMode = Explicit;
m_newChannelCountMode = Explicit;
} else {
ASSERT_NOT_REACHED();
}
if (m_channelCountMode != oldMode)
updateChannelsForInputs();
if (m_newChannelCountMode != oldMode)
context()->addChangedChannelCountMode(this);
}
String AudioNode::channelInterpretation()
......@@ -550,6 +552,12 @@ void AudioNode::trace(Visitor* visitor)
EventTargetWithInlineData::trace(visitor);
}
void AudioNode::updateChannelCountMode()
{
m_channelCountMode = m_newChannelCountMode;
updateChannelsForInputs();
}
} // namespace blink
#endif // ENABLE(WEB_AUDIO)
......@@ -183,6 +183,8 @@ public:
virtual const AtomicString& interfaceName() const OVERRIDE FINAL;
virtual ExecutionContext* executionContext() const OVERRIDE FINAL;
void updateChannelCountMode();
virtual void trace(Visitor*) OVERRIDE;
protected:
......@@ -219,6 +221,9 @@ private:
#endif
static unsigned s_instanceCount;
// The new channel count mode that will be used to set the actual mode in the pre or post
// rendering phase.
ChannelCountMode m_newChannelCountMode;
protected:
unsigned m_channelCount;
ChannelCountMode m_channelCountMode;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment