Implement MediaElementAudioSourceNode::setFormat() so numberOfChannels and sampleRate...
authorcrogers@google.com <crogers@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Dec 2011 22:40:00 +0000 (22:40 +0000)
committercrogers@google.com <crogers@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Dec 2011 22:40:00 +0000 (22:40 +0000)
https://bugs.webkit.org/show_bug.cgi?id=75057

Reviewed by Eric Carlson.

* GNUmakefile.list.am:
* WebCore.gypi:
* WebCore.xcodeproj/project.pbxproj:
Add MultiChannelResampler source files to makefiles.
* platform/audio/MultiChannelResampler.cpp: Added.
(WebCore::MultiChannelResampler::MultiChannelResampler):
(WebCore::MultiChannelResampler::process):
* platform/audio/MultiChannelResampler.h: Added.
Add MultiChannelResampler implementation which uses one SincResampler per channel.
* webaudio/MediaElementAudioSourceNode.cpp:
(WebCore::MediaElementAudioSourceNode::create):
(WebCore::MediaElementAudioSourceNode::MediaElementAudioSourceNode):
(WebCore::MediaElementAudioSourceNode::setFormat):
(WebCore::MediaElementAudioSourceNode::process):
Implement MediaElementAudioSourceNode::setFormat() so that we can
properly setup a sample-rate converter and set the number of channels
of the MediaElementAudioSourceNode output.
* webaudio/MediaElementAudioSourceNode.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@103581 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/audio/MultiChannelResampler.cpp [new file with mode: 0644]
Source/WebCore/platform/audio/MultiChannelResampler.h [new file with mode: 0644]
Source/WebCore/webaudio/MediaElementAudioSourceNode.cpp
Source/WebCore/webaudio/MediaElementAudioSourceNode.h

index 3562d15e970b0d90cf536cbf6fe435ae925e39d3..e6f2de34559842f743f8431d66d3551b00680390 100644 (file)
@@ -1,3 +1,29 @@
+2011-12-22  Chris Rogers  <crogers@google.com>
+
+        Implement MediaElementAudioSourceNode::setFormat() so numberOfChannels and sampleRate are accounted for
+        https://bugs.webkit.org/show_bug.cgi?id=75057
+
+        Reviewed by Eric Carlson.
+
+        * GNUmakefile.list.am:
+        * WebCore.gypi:
+        * WebCore.xcodeproj/project.pbxproj:
+        Add MultiChannelResampler source files to makefiles.
+        * platform/audio/MultiChannelResampler.cpp: Added.
+        (WebCore::MultiChannelResampler::MultiChannelResampler):
+        (WebCore::MultiChannelResampler::process):
+        * platform/audio/MultiChannelResampler.h: Added.
+        Add MultiChannelResampler implementation which uses one SincResampler per channel.
+        * webaudio/MediaElementAudioSourceNode.cpp:
+        (WebCore::MediaElementAudioSourceNode::create):
+        (WebCore::MediaElementAudioSourceNode::MediaElementAudioSourceNode):
+        (WebCore::MediaElementAudioSourceNode::setFormat):
+        (WebCore::MediaElementAudioSourceNode::process):
+        Implement MediaElementAudioSourceNode::setFormat() so that we can
+        properly setup a sample-rate converter and set the number of channels
+        of the MediaElementAudioSourceNode output.
+        * webaudio/MediaElementAudioSourceNode.h:
+
 2011-12-22  Chris Fleizach  <cfleizach@apple.com>
 
         AX: WebKit should ignore ARIA role=presentation on focusable elements
index 6a8b2663cb032e4b5425a396caea19c7fd35af45..b7fdc658b25c99fdc1862a05c571ca36d3350ef4 100644 (file)
@@ -4829,6 +4829,8 @@ webcore_sources += \
        Source/WebCore/platform/audio/HRTFKernel.h \
        Source/WebCore/platform/audio/HRTFPanner.cpp \
        Source/WebCore/platform/audio/HRTFPanner.h \
+       Source/WebCore/platform/audio/MultiChannelResampler.cpp \
+       Source/WebCore/platform/audio/MultiChannelResampler.h \
        Source/WebCore/platform/audio/Panner.cpp \
        Source/WebCore/platform/audio/Panner.h \
        Source/WebCore/platform/audio/ReverbAccumulationBuffer.cpp \
index abfc51fcff9370e37e88de0dd9c546dbc66d1f1b..76c89cde52bb561452318403d829b5b2491ed7f3 100644 (file)
             'platform/audio/HRTFKernel.h',
             'platform/audio/HRTFPanner.cpp',
             'platform/audio/HRTFPanner.h',
+            'platform/audio/MultiChannelResampler.cpp',
+            'platform/audio/MultiChannelResampler.h',
             'platform/audio/Panner.cpp',
             'platform/audio/Panner.h',
             'platform/audio/Reverb.cpp',
index 180aa330718149a37c3e909265d6a9ac72f56587..3bfb42dbcf77d486a51fc849ddc1f7c43f8ed4f0 100644 (file)
                FDA3E95A134A49EF008D4B5A /* OfflineAudioCompletionEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = FDA3E956134A49EF008D4B5A /* OfflineAudioCompletionEvent.h */; };
                FDA3E95B134A49EF008D4B5A /* OfflineAudioDestinationNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FDA3E957134A49EF008D4B5A /* OfflineAudioDestinationNode.cpp */; };
                FDA3E95C134A49EF008D4B5A /* OfflineAudioDestinationNode.h in Headers */ = {isa = PBXBuildFile; fileRef = FDA3E958134A49EF008D4B5A /* OfflineAudioDestinationNode.h */; };
+               FDB1700514A2BAB200A2B5D9 /* MultiChannelResampler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FDB1700314A2BAB200A2B5D9 /* MultiChannelResampler.cpp */; };
+               FDB1700614A2BAB200A2B5D9 /* MultiChannelResampler.h in Headers */ = {isa = PBXBuildFile; fileRef = FDB1700414A2BAB200A2B5D9 /* MultiChannelResampler.h */; };
                FDC54F041399B0DA008D9117 /* BiquadFilterNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FDC54F011399B0DA008D9117 /* BiquadFilterNode.cpp */; };
                FDC54F051399B0DA008D9117 /* BiquadFilterNode.h in Headers */ = {isa = PBXBuildFile; fileRef = FDC54F021399B0DA008D9117 /* BiquadFilterNode.h */; };
                FDEAAAF312B02EE400DCF33B /* JSAudioBufferSourceNodeCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FDEAAAEF12B02EE400DCF33B /* JSAudioBufferSourceNodeCustom.cpp */; };
                FDA3E957134A49EF008D4B5A /* OfflineAudioDestinationNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OfflineAudioDestinationNode.cpp; sourceTree = "<group>"; };
                FDA3E958134A49EF008D4B5A /* OfflineAudioDestinationNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OfflineAudioDestinationNode.h; sourceTree = "<group>"; };
                FDA3E95D134A49FF008D4B5A /* OfflineAudioCompletionEvent.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OfflineAudioCompletionEvent.idl; sourceTree = "<group>"; };
+               FDB1700314A2BAB200A2B5D9 /* MultiChannelResampler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MultiChannelResampler.cpp; sourceTree = "<group>"; };
+               FDB1700414A2BAB200A2B5D9 /* MultiChannelResampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MultiChannelResampler.h; sourceTree = "<group>"; };
                FDC54F011399B0DA008D9117 /* BiquadFilterNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BiquadFilterNode.cpp; sourceTree = "<group>"; };
                FDC54F021399B0DA008D9117 /* BiquadFilterNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BiquadFilterNode.h; sourceTree = "<group>"; };
                FDC54F031399B0DA008D9117 /* BiquadFilterNode.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BiquadFilterNode.idl; sourceTree = "<group>"; };
                                FD31606912B026F700C1A359 /* HRTFKernel.h */,
                                FD31606A12B026F700C1A359 /* HRTFPanner.cpp */,
                                FD31606B12B026F700C1A359 /* HRTFPanner.h */,
+                               FDB1700314A2BAB200A2B5D9 /* MultiChannelResampler.cpp */,
+                               FDB1700414A2BAB200A2B5D9 /* MultiChannelResampler.h */,
                                FD31606C12B026F700C1A359 /* Panner.cpp */,
                                FD31606D12B026F700C1A359 /* Panner.h */,
                                FD31606E12B026F700C1A359 /* Reverb.cpp */,
                                1AA7160B149BC4DB0016EC19 /* TileCache.h in Headers */,
                                C37CDEBD149EF2030042090D /* ColorChooserClient.h in Headers */,
                                1AC6926A14A1253200BD85F1 /* ScrollableAreaClient.h in Headers */,
+                               FDB1700614A2BAB200A2B5D9 /* MultiChannelResampler.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                A80A9423149F225E00989291 /* JSDOMWindowWebAudioCustom.cpp in Sources */,
                                A80A9425149F227100989291 /* JSDOMWindowWebSocketCustom.cpp in Sources */,
                                52F52E1114A0134F00ACC397 /* NSScrollerImpDetails.mm in Sources */,
+                               FDB1700514A2BAB200A2B5D9 /* MultiChannelResampler.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
diff --git a/Source/WebCore/platform/audio/MultiChannelResampler.cpp b/Source/WebCore/platform/audio/MultiChannelResampler.cpp
new file mode 100644 (file)
index 0000000..db51e90
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "MultiChannelResampler.h"
+
+#include "AudioBus.h"
+
+namespace WebCore {
+
+namespace {
+
+// ChannelProvider provides a single channel of audio data (one channel at a time) for each channel
+// of data provided to us in a multi-channel provider.
+
+class ChannelProvider : public AudioSourceProvider {
+public:
+    ChannelProvider(AudioSourceProvider* multiChannelProvider, unsigned numberOfChannels)
+        : m_multiChannelProvider(multiChannelProvider)
+        , m_numberOfChannels(numberOfChannels)
+        , m_currentChannel(0)
+        , m_framesToProcess(0)
+    {
+    }
+
+    // provideInput() will be called once for each channel, starting with the first channel.
+    // Each time it's called, it will provide the next channel of data.
+    virtual void provideInput(AudioBus* bus, size_t framesToProcess)
+    {
+        bool isBusGood = bus && bus->numberOfChannels() == 1;
+        ASSERT(isBusGood);
+        if (!isBusGood)
+            return;
+
+        // Get the data from the multi-channel provider when the first channel asks for it.
+        // For subsequent channels, we can just dish out the channel data from that (stored in m_multiChannelBus).
+        if (!m_currentChannel) {
+            m_framesToProcess = framesToProcess;
+            m_multiChannelBus = adoptPtr(new AudioBus(m_numberOfChannels, framesToProcess));
+            m_multiChannelProvider->provideInput(m_multiChannelBus.get(), framesToProcess);
+        }
+
+        // All channels must ask for the same amount. This should always be the case, but let's just make sure.
+        bool isGood = m_multiChannelBus.get() && framesToProcess == m_framesToProcess;
+        ASSERT(isGood);
+        if (!isGood)
+            return;
+
+        // Copy the channel data from what we received from m_multiChannelProvider.
+        ASSERT(m_currentChannel <= m_numberOfChannels);
+        if (m_currentChannel < m_numberOfChannels) {
+            memcpy(bus->channel(0)->data(), m_multiChannelBus->channel(m_currentChannel)->data(), sizeof(float) * framesToProcess);
+            ++m_currentChannel;
+        }
+    }
+
+private:
+    AudioSourceProvider* m_multiChannelProvider;
+    OwnPtr<AudioBus> m_multiChannelBus;
+    unsigned m_numberOfChannels;
+    unsigned m_currentChannel;
+    size_t m_framesToProcess; // Used to verify that all channels ask for the same amount.
+};
+
+} // namespace
+
+MultiChannelResampler::MultiChannelResampler(double scaleFactor, unsigned numberOfChannels)
+    : m_numberOfChannels(numberOfChannels)
+{
+    // Create each channel's resampler.
+    for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex)
+        m_kernels.append(adoptPtr(new SincResampler(scaleFactor)));
+}
+
+void MultiChannelResampler::process(AudioSourceProvider* provider, AudioBus* destination, size_t framesToProcess)
+{
+    // The provider can provide us with multi-channel audio data. But each of our single-channel resamplers (kernels)
+    // below requires a provider which provides a single unique channel of data.
+    // channelProvider wraps the original multi-channel provider and dishes out one channel at a time.
+    ChannelProvider channelProvider(provider, m_numberOfChannels);
+
+    for (unsigned channelIndex = 0; channelIndex < m_numberOfChannels; ++channelIndex) {
+        // Depending on the sample-rate scale factor, and the internal buffering used in a SincResampler
+        // kernel, this call to process() will only sometimes call provideInput() on the channelProvider.
+        // However, if it calls provideInput() for the first channel, then it will call it for the remaining
+        // channels, since they all buffer in the same way and are processing the same number of frames.
+        m_kernels[channelIndex]->process(&channelProvider,
+                                         destination->channel(channelIndex)->data(),
+                                         framesToProcess);
+    }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/MultiChannelResampler.h b/Source/WebCore/platform/audio/MultiChannelResampler.h
new file mode 100644 (file)
index 0000000..150729d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MultiChannelResampler_h
+#define MultiChannelResampler_h
+
+#include "SincResampler.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class AudioBus;
+    
+class MultiChannelResampler {
+public:   
+    MultiChannelResampler(double scaleFactor, unsigned numberOfChannels);
+    
+    // Process given AudioSourceProvider for streaming applications.
+    void process(AudioSourceProvider*, AudioBus* destination, size_t framesToProcess);
+
+private:
+    // FIXME: the mac port can have a more highly optimized implementation based on CoreAudio
+    // instead of SincResampler. For now the default implementation will be used on all ports.
+    // https://bugs.webkit.org/show_bug.cgi?id=75118
+    
+    // Each channel will be resampled using a high-quality SincResampler.
+    Vector<OwnPtr<SincResampler> > m_kernels;
+    
+    unsigned m_numberOfChannels;
+};
+
+} // namespace WebCore
+
+#endif // MultiChannelResampler_h
index 7a6116d7926873b2a07edc0c7436a4baa9b880fd..35395b1f490a017dcc4c3a568dc5afe3559b00a9 100644 (file)
 
 #include "AudioContext.h"
 #include "AudioNodeOutput.h"
+#include "Locker.h"
+#include "Logging.h"
 #include "MediaPlayer.h"
 
+// These are somewhat arbitrary limits, but we need to do some kind of sanity-checking.
+const unsigned minSampleRate = 8000;
+const unsigned maxSampleRate = 192000;
+
 namespace WebCore {
 
 PassRefPtr<MediaElementAudioSourceNode> MediaElementAudioSourceNode::create(AudioContext* context, HTMLMediaElement* mediaElement)
 {
-    return adoptRef(new MediaElementAudioSourceNode(context, mediaElement));      
+    return adoptRef(new MediaElementAudioSourceNode(context, mediaElement));
 }
 
 MediaElementAudioSourceNode::MediaElementAudioSourceNode(AudioContext* context, HTMLMediaElement* mediaElement)
     : AudioSourceNode(context, context->sampleRate())
     , m_mediaElement(mediaElement)
+    , m_sourceNumberOfChannels(0)
+    , m_sourceSampleRate(0)
 {
     // Default to stereo. This could change depending on what the media element .src is set to.
     addOutput(adoptPtr(new AudioNodeOutput(this, 2)));
-    
+
     setNodeType(NodeTypeMediaElementAudioSource);
 
     initialize();
@@ -57,32 +65,75 @@ MediaElementAudioSourceNode::~MediaElementAudioSourceNode()
     uninitialize();
 }
 
-void MediaElementAudioSourceNode::setFormat(size_t, float)
+void MediaElementAudioSourceNode::setFormat(size_t numberOfChannels, float sourceSampleRate)
 {
-    // FIXME: setup a sample-rate converter if necessary to convert to the AudioContext sample-rate.
-    ASSERT_NOT_REACHED();
+    if (numberOfChannels != m_sourceNumberOfChannels || sourceSampleRate != m_sourceSampleRate) {
+        // FIXME: implement multi-channel greater than stereo.
+        // https://bugs.webkit.org/show_bug.cgi?id=75119
+        if (!numberOfChannels || numberOfChannels > 2 || sourceSampleRate < minSampleRate || sourceSampleRate > maxSampleRate) {
+            // process() will generate silence for these uninitialized values.
+            LOG(Media, "MediaElementAudioSourceNode::setFormat(%u, %f) - unhandled format change", static_cast<unsigned>(numberOfChannels), sourceSampleRate);
+            m_sourceNumberOfChannels = 0;
+            m_sourceSampleRate = 0;
+            return;
+        }
+
+        m_sourceNumberOfChannels = numberOfChannels;
+        m_sourceSampleRate = sourceSampleRate;
+
+        // Synchronize with process().
+        Locker<MediaElementAudioSourceNode> locker(*this);
+
+        if (sourceSampleRate != sampleRate()) {
+            double scaleFactor = sourceSampleRate / sampleRate();
+            m_multiChannelResampler = adoptPtr(new MultiChannelResampler(scaleFactor, numberOfChannels));
+        } else {
+            // Bypass resampling.
+            m_multiChannelResampler.clear();
+        }
+
+        {
+            // The context must be locked when changing the number of output channels.
+            AudioContext::AutoLocker contextLocker(context());
+
+            // Do any necesssary re-configuration to the output's number of channels.
+            output(0)->setNumberOfChannels(numberOfChannels);
+        }
+    }
 }
 
 void MediaElementAudioSourceNode::process(size_t numberOfFrames)
 {
     AudioBus* outputBus = output(0)->bus();
 
-    if (!mediaElement()) {
+    if (!mediaElement() || !m_sourceNumberOfChannels || !m_sourceSampleRate) {
         outputBus->zero();
         return;
     }
-    
+
     // Use a tryLock() to avoid contention in the real-time audio thread.
     // If we fail to acquire the lock then the HTMLMediaElement must be in the middle of
     // reconfiguring its playback engine, so we output silence in this case.
     if (m_processLock.tryLock()) {
-        if (AudioSourceProvider* provider = mediaElement()->audioSourceProvider())
-            provider->provideInput(outputBus, numberOfFrames);
-        else
+        if (AudioSourceProvider* provider = mediaElement()->audioSourceProvider()) {
+            if (m_multiChannelResampler.get()) {
+                ASSERT(m_sourceSampleRate != sampleRate());
+                m_multiChannelResampler->process(provider, outputBus, numberOfFrames);
+            } else {
+                // Bypass the resampler completely if the source is at the context's sample-rate.
+                ASSERT(m_sourceSampleRate == sampleRate());
+                provider->provideInput(outputBus, numberOfFrames);
+            }
+        } else {
+            // Either this port doesn't yet support HTMLMediaElement audio stream access,
+            // or the stream is not yet available.
             outputBus->zero();
+        }
         m_processLock.unlock();
-    } else
+    } else {
+        // We failed to acquire the lock.
         outputBus->zero();
+    }
 }
 
 void MediaElementAudioSourceNode::reset()
index 07ebf67ebdc62e8634193b67d1387604758672b2..06ec7e16b442a10c2f48e2776cd2cc44679e5f18 100644 (file)
@@ -30,6 +30,8 @@
 #include "AudioSourceNode.h"
 #include "AudioSourceProviderClient.h"
 #include "HTMLMediaElement.h"
+#include "MultiChannelResampler.h"
+#include <wtf/OwnPtr.h>
 #include <wtf/PassRefPtr.h>
 #include <wtf/Threading.h>
 
@@ -60,6 +62,11 @@ private:
 
     RefPtr<HTMLMediaElement> m_mediaElement;
     Mutex m_processLock;
+
+    unsigned m_sourceNumberOfChannels;
+    double m_sourceSampleRate;
+
+    OwnPtr<MultiChannelResampler> m_multiChannelResampler;
 };
 
 } // namespace WebCore