[MediaStream iOS] Cleanup video muting/unmuting when tab visibility changes
authoreric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 2 Jun 2017 21:16:53 +0000 (21:16 +0000)
committereric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 2 Jun 2017 21:16:53 +0000 (21:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=172858

Reviewed by Youenn Fablet.

Source/WebCore:

Test: platform/ios/mediastream/video-muted-in-background-tab.html

* dom/Document.cpp:
(WebCore::Document::visibilityStateChanged): Call notifyMediaCaptureOfVisibilityChanged.
(WebCore::Document::notifyMediaCaptureOfVisibilityChanged): Renamed from notifyVisibilityChangedToMediaCapture.
Set m_videoCaptureMutedForVisibilityChange when capture is muted because the document is hidden,
and clear it when visibility changes when capture is disabled. Don't unmute when the document
becomes visible unless this m_videoCaptureMutedForVisibilityChange is still true.
(WebCore::Document::notifyVisibilityChangedToMediaCapture): Deleted.
* dom/Document.h:

* platform/mediastream/RealtimeMediaSource.h:
* platform/mediastream/RealtimeMediaSourceCenter.cpp:
(WebCore::RealtimeMediaSourceCenter::setVideoCaptureMutedForPageVisibility): Renamed from
setVisibility.
(WebCore::RealtimeMediaSourceCenter::setVisibility): Deleted.
* platform/mediastream/RealtimeMediaSourceCenter.h:

* platform/mediastream/mac/AVVideoCaptureSource.mm:
(WebCore::AVVideoCaptureSourceFactory::setVideoCaptureMutedForPageVisibility): Ditto.
(WebCore::AVVideoCaptureSourceFactory::setVisibility): Deleted.

* platform/mock/MockRealtimeVideoSource.cpp:
(WebCore::MockRealtimeVideoSourceFactory::setVideoCaptureMutedForPageVisibility): Ditto.
(WebCore::MockRealtimeVideoSourceFactory::setVisibility): Deleted.

LayoutTests:

* platform/ios/mediastream/video-muted-in-background-tab-expected.txt: Added.
* platform/ios/mediastream/video-muted-in-background-tab.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/platform/ios/mediastream/video-muted-in-background-tab-expected.txt [new file with mode: 0644]
LayoutTests/platform/ios/mediastream/video-muted-in-background-tab.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/platform/mediastream/RealtimeMediaSource.h
Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp
Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h
Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm
Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp

index 4f4c204bbb69dff3c2619387b6ff0ee88639c80c..341c08ba7340c76e4e9a931769b39aa457a72af5 100644 (file)
@@ -1,3 +1,13 @@
+2017-06-02  Eric Carlson  <eric.carlson@apple.com>
+
+        [MediaStream iOS] Cleanup video muting/unmuting when tab visibility changes
+        https://bugs.webkit.org/show_bug.cgi?id=172858
+
+        Reviewed by Youenn Fablet.
+
+        * platform/ios/mediastream/video-muted-in-background-tab-expected.txt: Added.
+        * platform/ios/mediastream/video-muted-in-background-tab.html: Added.
+
 2017-06-02  Matt Lewis  <jlewis3@apple.com>
 
         Moved test expectation for http/tests/preload/viewport/meta-viewport-link-headers.php to correct file.
diff --git a/LayoutTests/platform/ios/mediastream/video-muted-in-background-tab-expected.txt b/LayoutTests/platform/ios/mediastream/video-muted-in-background-tab-expected.txt
new file mode 100644 (file)
index 0000000..2201332
--- /dev/null
@@ -0,0 +1,7 @@
+
+PASS Setup stream 
+PASS Hide page, only video should be muted 
+PASS Show page, video and audio should be unmuted 
+PASS Hide and mute page, video and audio should be muted 
+PASS Show page, video and audio should remain muted 
+
diff --git a/LayoutTests/platform/ios/mediastream/video-muted-in-background-tab.html b/LayoutTests/platform/ios/mediastream/video-muted-in-background-tab.html
new file mode 100644 (file)
index 0000000..4c56661
--- /dev/null
@@ -0,0 +1,70 @@
+
+<!doctype html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>Don't unmute video when a tab becomes visible unless it was muted when the tab was hidden</title>
+        <script src="../../../resources/testharness.js"></script>
+        <script src="../../../resources/testharnessreport.js"></script>
+    </head>
+    <body>
+        <script>
+            let audioTrack;
+            let videoTrack;
+
+            promise_test((t) => {
+                if (window.testRunner)
+                    testRunner.setUserMediaPermission(true);
+                if (!window.internals)
+                    return Promise.reject("this test needs internals API");
+
+                return navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then((stream) => {
+                    audioTrack = stream.getAudioTracks()[0];
+                    videoTrack = stream.getVideoTracks()[0];
+
+                    assert_false(audioTrack.muted, "audio track is active");
+                    assert_false(videoTrack.muted, "video track is active");
+                })
+
+                .then(() => {
+                    test(() => {
+                        if (window.internals)
+                            window.internals.setPageVisibility(false);
+                        assert_false(audioTrack.muted, "audio track is active");
+                        assert_true(videoTrack.muted, "video track is muted");
+                    }, "Hide page, only video should be muted");
+                })
+
+                .then(() => {
+                    test(() => {
+                        if (window.internals)
+                            window.internals.setPageVisibility(true);
+                        assert_false(audioTrack.muted, "audio track is active");
+                        assert_false(videoTrack.muted, "video track is active");
+                    }, "Show page, video and audio should be unmuted");
+                })
+
+                .then(() => {
+                    test(() => {
+                        if (window.internals) {
+                            window.internals.setPageVisibility(false);
+                            window.internals.setPageMuted("capturedevices");
+                        }
+                        assert_true(audioTrack.muted, "audio track is muted");
+                        assert_true(videoTrack.muted, "video track is muted");
+                    }, "Hide and mute page, video and audio should be muted");
+                })
+
+                .then(() => {
+                    test(() => {
+                        if (window.internals)
+                            window.internals.setPageVisibility(true);
+                        assert_true(audioTrack.muted, "audio track is muted");
+                        assert_true(videoTrack.muted, "video track is muted");
+                    }, "Show page, video and audio should remain muted");
+                })
+            }, "Setup stream");
+
+        </script>
+    </body>
+</html>
\ No newline at end of file
index 76f3b31b7f30c15c6ed7032e27b2cb3f3f07350a..2ab52b60ba57354e9c04124518251b070119b28e 100644 (file)
@@ -1,3 +1,36 @@
+2017-06-02  Eric Carlson  <eric.carlson@apple.com>
+
+        [MediaStream iOS] Cleanup video muting/unmuting when tab visibility changes
+        https://bugs.webkit.org/show_bug.cgi?id=172858
+
+        Reviewed by Youenn Fablet.
+
+        Test: platform/ios/mediastream/video-muted-in-background-tab.html
+
+        * dom/Document.cpp:
+        (WebCore::Document::visibilityStateChanged): Call notifyMediaCaptureOfVisibilityChanged.
+        (WebCore::Document::notifyMediaCaptureOfVisibilityChanged): Renamed from notifyVisibilityChangedToMediaCapture.
+        Set m_videoCaptureMutedForVisibilityChange when capture is muted because the document is hidden,
+        and clear it when visibility changes when capture is disabled. Don't unmute when the document
+        becomes visible unless this m_videoCaptureMutedForVisibilityChange is still true.
+        (WebCore::Document::notifyVisibilityChangedToMediaCapture): Deleted.
+        * dom/Document.h:
+
+        * platform/mediastream/RealtimeMediaSource.h:
+        * platform/mediastream/RealtimeMediaSourceCenter.cpp:
+        (WebCore::RealtimeMediaSourceCenter::setVideoCaptureMutedForPageVisibility): Renamed from
+        setVisibility.
+        (WebCore::RealtimeMediaSourceCenter::setVisibility): Deleted.
+        * platform/mediastream/RealtimeMediaSourceCenter.h:
+
+        * platform/mediastream/mac/AVVideoCaptureSource.mm:
+        (WebCore::AVVideoCaptureSourceFactory::setVideoCaptureMutedForPageVisibility): Ditto.
+        (WebCore::AVVideoCaptureSourceFactory::setVisibility): Deleted.
+
+        * platform/mock/MockRealtimeVideoSource.cpp:
+        (WebCore::MockRealtimeVideoSourceFactory::setVideoCaptureMutedForPageVisibility): Ditto.
+        (WebCore::MockRealtimeVideoSourceFactory::setVisibility): Deleted.
+
 2017-06-02  Frederic Wang  <fwang@igalia.com>
 
         [Mac] Include frames in the scrolling tree when ScrollingTreeIncludesFrames=true
index 85870d595538dbd1c422cc592a44c295ae6813e1..2d89c103c7f13ae8d49e917b6247f50a17044314 100644 (file)
@@ -1547,7 +1547,7 @@ void Document::visibilityStateChanged()
     for (auto* client : m_visibilityStateCallbackClients)
         client->visibilityStateChanged();
 
-    notifyVisibilityChangedToMediaCapture();
+    notifyMediaCaptureOfVisibilityChanged();
 }
 
 auto Document::visibilityState() const -> VisibilityState
@@ -7005,10 +7005,19 @@ void Document::orientationChanged(int orientation)
     m_orientationNotifier.orientationChanged(orientation);
 }
 
-void Document::notifyVisibilityChangedToMediaCapture()
+void Document::notifyMediaCaptureOfVisibilityChanged()
 {
 #if ENABLE(MEDIA_STREAM)
-    RealtimeMediaSourceCenter::singleton().setVisibility(!hidden());
+    if (!page() || page()->isMediaCaptureMuted()) {
+        m_videoCaptureMutedForVisibilityChange = false;
+        return;
+    }
+
+    if (!hidden() && !m_videoCaptureMutedForVisibilityChange)
+        return;
+
+    m_videoCaptureMutedForVisibilityChange = hidden();
+    RealtimeMediaSourceCenter::singleton().setVideoCaptureMutedForPageVisibility(m_videoCaptureMutedForVisibilityChange);
 #endif
 }
 
index 987aa4251c1a64cd4efe3a79a74048c41110ba92..87cc8c6dc59c4410d87b78961fccdbb0f2678cdd 100644 (file)
@@ -1603,7 +1603,7 @@ private:
     void clearScriptedAnimationController();
     RefPtr<ScriptedAnimationController> m_scriptedAnimationController;
 
-    void notifyVisibilityChangedToMediaCapture();
+    void notifyMediaCaptureOfVisibilityChanged();
 
 #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS)
     std::unique_ptr<DeviceMotionClient> m_deviceMotionClient;
@@ -1770,6 +1770,7 @@ private:
     HashSet<HTMLMediaElement*> m_mediaStreamStateChangeElements;
     String m_idHashSalt;
     bool m_hasHadActiveMediaStreamTrack { false };
+    bool m_videoCaptureMutedForVisibilityChange { false };
 #endif
 
 #ifndef NDEBUG
index 4bf7219a818dbcdbac15af0e59dcaf0a941b8ec2..1fd91e0e9cb2ab2cc9553d39770a4b1492388d88 100644 (file)
@@ -120,7 +120,7 @@ public:
     public:
         virtual ~VideoCaptureFactory() = default;
         virtual CaptureSourceOrError createVideoCaptureSource(const String& videoDeviceID, const MediaConstraints*) = 0;
-        virtual void setVisibility(bool) { }
+        virtual void setVideoCaptureMutedForPageVisibility(bool) { }
 
     protected:
         VideoCaptureFactory() = default;
index 025c4ec3d157feb6c3e1ddd6f51d95b567f81b2f..f2da05f8b8dd0400273b2d3ffa3a24ced31edf3a 100644 (file)
@@ -334,9 +334,9 @@ void RealtimeMediaSourceCenter::validateRequestConstraints(ValidConstraintsHandl
     validHandler(WTFMove(audioSourceIds), WTFMove(videoSourceIds), WTFMove(deviceIdentifierHashSalt));
 }
 
-void RealtimeMediaSourceCenter::setVisibility(bool isVisible)
+void RealtimeMediaSourceCenter::setVideoCaptureMutedForPageVisibility(bool shouldMute)
 {
-    videoFactory().setVisibility(isVisible);
+    videoFactory().setVideoCaptureMutedForPageVisibility(shouldMute);
 }
 
 } // namespace WebCore
index 121a7f17430ece12495473abd405539a7f0f15bb..a120333a8d11568bcacbc34513b824b93ff248b1 100644 (file)
@@ -100,7 +100,7 @@ public:
     void removeDevicesChangedObserver(DevicesChangedObserverToken);
     void captureDevicesChanged();
 
-    void setVisibility(bool isVisible);
+    void setVideoCaptureMutedForPageVisibility(bool);
 
 protected:
     RealtimeMediaSourceCenter();
index facab4c27776b61c1b9a112aa952bd5ccd17d22f..308abeec15cb5b323054d4f1b2f6b5f122038d66 100644 (file)
@@ -125,10 +125,10 @@ public:
 
 #if PLATFORM(IOS)
 private:
-    void setVisibility(bool isVisible)
+    void setVideoCaptureMutedForPageVisibility(bool shouldMute)
     {
         if (activeSource())
-            activeSource()->setMuted(!isVisible);
+            activeSource()->setMuted(shouldMute);
     }
 #endif
 };
index e675321377c9b9402d2fa8df4b98b6af289b3c56..1df2ec3643a927e2efb0825bc23d7a040fba03ec 100644 (file)
@@ -63,10 +63,10 @@ public:
     }
 #if PLATFORM(IOS)
 private:
-    void setVisibility(bool isVisible)
+    void setVideoCaptureMutedForPageVisibility(bool shouldMute)
     {
         if (activeSource())
-            activeSource()->setMuted(!isVisible);
+            activeSource()->setMuted(shouldMute);
     }
 #endif
 };