Title: [248046] trunk
Revision
248046
Author
[email protected]
Date
2019-07-31 10:31:17 -0700 (Wed, 31 Jul 2019)

Log Message

Owners of MultiChannelResampler should make sure that the output bus given to it has the same number of channels
https://bugs.webkit.org/show_bug.cgi?id=200248
<rdar://problem/53411051>

Reviewed by Eric Carlson.

Source/WebCore:

When a track's number of channels changes, MediaStreamAudioSourceNode is expected
to update its MultiChannelResampler and its output number of channels.
MultiChannelResampler expects to have the same number of channels as the output
but it is not always the case since the channel numbers are changed in different threads
and locks do not help there.

Instead, whenever detecting that the number of channels do not match, render silence
and wait for the next rendering where the number of channels should again match.

Add internals API to change the number of channels from 2 to 1 or 1 to 2
to allow testing that code path (iOS only as MacOS audio capture is in UIProcess).
Covered by updated test.

* Modules/webaudio/MediaElementAudioSourceNode.cpp:
(WebCore::MediaElementAudioSourceNode::process):
* Modules/webaudio/MediaStreamAudioSourceNode.cpp:
(WebCore::MediaStreamAudioSourceNode::process):
* platform/audio/MultiChannelResampler.cpp:
(WebCore::MultiChannelResampler::process):
* platform/mediastream/RealtimeMediaSource.h:
* platform/mediastream/mac/MockRealtimeAudioSourceMac.mm:
(WebCore::MockRealtimeAudioSourceMac::reconfigure):
* platform/mock/MockRealtimeAudioSource.cpp:
(WebCore::MockRealtimeAudioSource::setChannelCount):
* platform/mock/MockRealtimeAudioSource.h:
(isType):
* platform/mock/MockRealtimeVideoSource.h:
* testing/Internals.cpp:
(WebCore::Internals::setMockAudioTrackChannelNumber):
* testing/Internals.h:
* testing/Internals.idl:

LayoutTests:

* fast/mediastream/getUserMedia-webaudio-expected.txt:
* fast/mediastream/getUserMedia-webaudio.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (248045 => 248046)


--- trunk/LayoutTests/ChangeLog	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/LayoutTests/ChangeLog	2019-07-31 17:31:17 UTC (rev 248046)
@@ -1,3 +1,14 @@
+2019-07-31  Youenn Fablet  <[email protected]>
+
+        Owners of MultiChannelResampler should make sure that the output bus given to it has the same number of channels
+        https://bugs.webkit.org/show_bug.cgi?id=200248
+        <rdar://problem/53411051>
+
+        Reviewed by Eric Carlson.
+
+        * fast/mediastream/getUserMedia-webaudio-expected.txt:
+        * fast/mediastream/getUserMedia-webaudio.html:
+
 2019-07-31  Chris Dumez  <[email protected]>
 
         Element.outerHTML is missing attribute prefixes in some cases in HTML documents

Modified: trunk/LayoutTests/fast/mediastream/getUserMedia-webaudio-expected.txt (248045 => 248046)


--- trunk/LayoutTests/fast/mediastream/getUserMedia-webaudio-expected.txt	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/LayoutTests/fast/mediastream/getUserMedia-webaudio-expected.txt	2019-07-31 17:31:17 UTC (rev 248046)
@@ -1,3 +1,4 @@
 
 PASS Plugging in getUserMedia audio stream into Web Audio 
+PASS Web Audio should work even if number of channels of a track increases from 1 to 2 
 

Modified: trunk/LayoutTests/fast/mediastream/getUserMedia-webaudio.html (248045 => 248046)


--- trunk/LayoutTests/fast/mediastream/getUserMedia-webaudio.html	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/LayoutTests/fast/mediastream/getUserMedia-webaudio.html	2019-07-31 17:31:17 UTC (rev 248046)
@@ -38,6 +38,33 @@
         });
     });
 }, "Plugging in getUserMedia audio stream into Web Audio");
+
+function waitFor(duration)
+{
+    return new Promise(resolve => setTimeout(resolve, duration));
+}
+
+promise_test(async (test) => {
+    if (!window.internals)
+        return Promise.reject("Internals API required");
+
+    const stream = await navigator.mediaDevices.getUserMedia({ audio: {deviceId: true}});
+    internals.setMockAudioTrackChannelNumber(stream.getAudioTracks()[0], 1);
+
+    var audioContext = new webkitAudioContext();
+    var script = audioContext.createScriptProcessor(2048, 1, 1);
+    let source = audioContext.createMediaStreamSource(stream);
+    source.connect(script);
+    script.connect(audioContext.destination);
+
+    await waitFor(200);
+
+    internals.setMockAudioTrackChannelNumber(stream.getAudioTracks()[0], 2);
+    await waitFor(200);
+
+    source.disconnect(script);
+    script.disconnect(audioContext.destination);
+}, "Web Audio should work even if number of channels of a track increases from 1 to 2");
         </script>
     </body>
 </html>

Modified: trunk/Source/WebCore/ChangeLog (248045 => 248046)


--- trunk/Source/WebCore/ChangeLog	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/Source/WebCore/ChangeLog	2019-07-31 17:31:17 UTC (rev 248046)
@@ -1,3 +1,43 @@
+2019-07-31  Youenn Fablet  <[email protected]>
+
+        Owners of MultiChannelResampler should make sure that the output bus given to it has the same number of channels
+        https://bugs.webkit.org/show_bug.cgi?id=200248
+        <rdar://problem/53411051>
+
+        Reviewed by Eric Carlson.
+
+        When a track's number of channels changes, MediaStreamAudioSourceNode is expected
+        to update its MultiChannelResampler and its output number of channels.
+        MultiChannelResampler expects to have the same number of channels as the output
+        but it is not always the case since the channel numbers are changed in different threads
+        and locks do not help there.
+
+        Instead, whenever detecting that the number of channels do not match, render silence
+        and wait for the next rendering where the number of channels should again match.
+
+        Add internals API to change the number of channels from 2 to 1 or 1 to 2
+        to allow testing that code path (iOS only as MacOS audio capture is in UIProcess).
+        Covered by updated test.
+
+        * Modules/webaudio/MediaElementAudioSourceNode.cpp:
+        (WebCore::MediaElementAudioSourceNode::process):
+        * Modules/webaudio/MediaStreamAudioSourceNode.cpp:
+        (WebCore::MediaStreamAudioSourceNode::process):
+        * platform/audio/MultiChannelResampler.cpp:
+        (WebCore::MultiChannelResampler::process):
+        * platform/mediastream/RealtimeMediaSource.h:
+        * platform/mediastream/mac/MockRealtimeAudioSourceMac.mm:
+        (WebCore::MockRealtimeAudioSourceMac::reconfigure):
+        * platform/mock/MockRealtimeAudioSource.cpp:
+        (WebCore::MockRealtimeAudioSource::setChannelCount):
+        * platform/mock/MockRealtimeAudioSource.h:
+        (isType):
+        * platform/mock/MockRealtimeVideoSource.h:
+        * testing/Internals.cpp:
+        (WebCore::Internals::setMockAudioTrackChannelNumber):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2019-07-31  Chris Dumez  <[email protected]>
 
         Element.outerHTML is missing attribute prefixes in some cases in HTML documents

Modified: trunk/Source/WebCore/Modules/webaudio/MediaElementAudioSourceNode.cpp (248045 => 248046)


--- trunk/Source/WebCore/Modules/webaudio/MediaElementAudioSourceNode.cpp	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/Source/WebCore/Modules/webaudio/MediaElementAudioSourceNode.cpp	2019-07-31 17:31:17 UTC (rev 248046)
@@ -137,6 +137,10 @@
         outputBus->zero();
         return;
     }
+    if (m_sourceNumberOfChannels != outputBus->numberOfChannels()) {
+        outputBus->zero();
+        return;
+    }
 
     if (AudioSourceProvider* provider = mediaElement().audioSourceProvider()) {
         if (m_multiChannelResampler.get()) {

Modified: trunk/Source/WebCore/Modules/webaudio/MediaStreamAudioSourceNode.cpp (248045 => 248046)


--- trunk/Source/WebCore/Modules/webaudio/MediaStreamAudioSourceNode.cpp	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/Source/WebCore/Modules/webaudio/MediaStreamAudioSourceNode.cpp	2019-07-31 17:31:17 UTC (rev 248046)
@@ -126,6 +126,10 @@
         outputBus->zero();
         return;
     }
+    if (m_sourceNumberOfChannels != outputBus->numberOfChannels()) {
+        outputBus->zero();
+        return;
+    }
 
     if (m_multiChannelResampler.get()) {
         ASSERT(m_sourceSampleRate != sampleRate());

Modified: trunk/Source/WebCore/platform/audio/MultiChannelResampler.cpp (248045 => 248046)


--- trunk/Source/WebCore/platform/audio/MultiChannelResampler.cpp	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/Source/WebCore/platform/audio/MultiChannelResampler.cpp	2019-07-31 17:31:17 UTC (rev 248046)
@@ -102,6 +102,8 @@
 
 void MultiChannelResampler::process(AudioSourceProvider* provider, AudioBus* destination, size_t framesToProcess)
 {
+    ASSERT(m_numberOfChannels == destination->numberOfChannels());
+
     // 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.

Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h (248045 => 248046)


--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h	2019-07-31 17:31:17 UTC (rev 248046)
@@ -172,6 +172,7 @@
 
     virtual bool isIsolated() const { return false; }
 
+    virtual bool isMockSource() const { return false; }
     virtual bool isCaptureSource() const { return false; }
     virtual CaptureDevice::DeviceType deviceType() const { return CaptureDevice::DeviceType::Unknown; }
 

Modified: trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm (248045 => 248046)


--- trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm	2019-07-31 17:31:17 UTC (rev 248046)
@@ -128,7 +128,7 @@
 
     const int bytesPerFloat = sizeof(Float32);
     const int bitsPerByte = 8;
-    const int channelCount = 2;
+    const int channelCount = m_channelCount;
     const bool isFloat = true;
     const bool isBigEndian = false;
     const bool isNonInterleaved = true;

Modified: trunk/Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp (248045 => 248046)


--- trunk/Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp	2019-07-31 17:31:17 UTC (rev 248046)
@@ -98,6 +98,15 @@
     return m_currentSettings.value();
 }
 
+void MockRealtimeAudioSource::setChannelCount(unsigned channelCount)
+{
+    if (channelCount > 2)
+        return;
+
+    m_channelCount = channelCount;
+    settingsDidChange(RealtimeMediaSourceSettings::Flag::SampleRate);
+}
+
 const RealtimeMediaSourceCapabilities& MockRealtimeAudioSource::capabilities()
 {
     if (!m_capabilities) {

Modified: trunk/Source/WebCore/platform/mock/MockRealtimeAudioSource.h (248045 => 248046)


--- trunk/Source/WebCore/platform/mock/MockRealtimeAudioSource.h	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeAudioSource.h	2019-07-31 17:31:17 UTC (rev 248046)
@@ -45,6 +45,8 @@
     static CaptureSourceOrError create(String&& deviceID, String&& name, String&& hashSalt, const MediaConstraints*);
     virtual ~MockRealtimeAudioSource();
 
+    WEBCORE_EXPORT void setChannelCount(unsigned);
+
 protected:
     MockRealtimeAudioSource(String&& deviceID, String&& name, String&& hashSalt);
 
@@ -64,11 +66,13 @@
     CaptureDevice::DeviceType deviceType() const final { return CaptureDevice::DeviceType::Microphone; }
 
     void delaySamples(Seconds) final;
+    bool isMockSource() const final { return true; }
 
     void tick();
 
 protected:
     Ref<WorkQueue> m_workQueue;
+    unsigned m_channelCount { 2 };
 
 private:
     Optional<RealtimeMediaSourceCapabilities> m_capabilities;
@@ -85,4 +89,9 @@
 
 } // namespace WebCore
 
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::MockRealtimeAudioSource)
+    static bool isType(const WebCore::RealtimeMediaSource& source) { return source.isCaptureSource() && source.isMockSource() && source.deviceType() == WebCore::CaptureDevice::DeviceType::Microphone; }
+SPECIALIZE_TYPE_TRAITS_END()
+
+
 #endif // ENABLE(MEDIA_STREAM)

Modified: trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.h (248045 => 248046)


--- trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.h	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.h	2019-07-31 17:31:17 UTC (rev 248046)
@@ -78,6 +78,8 @@
 
     void generatePresets() final;
 
+    bool isMockSource() const final { return true; }
+
     // OrientationNotifier::Observer
     void orientationChanged(int orientation) final;
     void monitorOrientation(OrientationNotifier&) final;

Modified: trunk/Source/WebCore/testing/Internals.cpp (248045 => 248046)


--- trunk/Source/WebCore/testing/Internals.cpp	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/Source/WebCore/testing/Internals.cpp	2019-07-31 17:31:17 UTC (rev 248046)
@@ -4705,6 +4705,13 @@
 #endif
 
 #if ENABLE(MEDIA_STREAM)
+void Internals::setMockAudioTrackChannelNumber(MediaStreamTrack& track, unsigned short channelNumber)
+{
+    auto& source = track.source();
+    if (!is<MockRealtimeAudioSource>(source))
+        return;
+    downcast<MockRealtimeAudioSource>(source).setChannelCount(channelNumber);
+}
 
 void Internals::setCameraMediaStreamTrackOrientation(MediaStreamTrack& track, int orientation)
 {

Modified: trunk/Source/WebCore/testing/Internals.h (248045 => 248046)


--- trunk/Source/WebCore/testing/Internals.h	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/Source/WebCore/testing/Internals.h	2019-07-31 17:31:17 UTC (rev 248046)
@@ -709,6 +709,7 @@
 #endif
 
 #if ENABLE(MEDIA_STREAM)
+    void setMockAudioTrackChannelNumber(MediaStreamTrack&, unsigned short);
     void setCameraMediaStreamTrackOrientation(MediaStreamTrack&, int orientation);
     unsigned long trackAudioSampleCount() const { return m_trackAudioSampleCount; }
     unsigned long trackVideoSampleCount() const { return m_trackVideoSampleCount; }

Modified: trunk/Source/WebCore/testing/Internals.idl (248045 => 248046)


--- trunk/Source/WebCore/testing/Internals.idl	2019-07-31 16:28:02 UTC (rev 248045)
+++ trunk/Source/WebCore/testing/Internals.idl	2019-07-31 17:31:17 UTC (rev 248046)
@@ -694,6 +694,7 @@
     [Conditional=WEB_RTC] void setH264HardwareEncoderAllowed(boolean allowed);
     [Conditional=WEB_RTC] void applyRotationForOutgoingVideoSources(RTCPeerConnection connection);
 
+    [Conditional=MEDIA_STREAM] void setMockAudioTrackChannelNumber(MediaStreamTrack track, unsigned short count);
     [Conditional=MEDIA_STREAM] void setShouldInterruptAudioOnPageVisibilityChange(boolean shouldInterrupt);
     [Conditional=MEDIA_STREAM] void setCameraMediaStreamTrackOrientation(MediaStreamTrack track, short orientation);
     [Conditional=MEDIA_STREAM] void observeMediaStreamTrack(MediaStreamTrack track);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to