<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[203388] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/203388">203388</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-07-18 17:47:40 -0700 (Mon, 18 Jul 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>If previous media session interruptions were prevented, still allow subsequent interruptions to try.
https://bugs.webkit.org/show_bug.cgi?id=157553
rdar://problem/25740804

Patch by Jeremy Jones &lt;jeremyj@apple.com&gt; on 2016-07-18
Reviewed by Eric Carlson.

Source/WebCore:

Test: platform/ios-simulator/media/video-interruption-suspendunderlock.html

When suspending under lock on iOS, there is first a resign active event, then a
suspend under lock. PiP prevents resign active from interrupting playback. But it should allow the
suspend under lock to interrupt playback.

Currently if there are nested interruptions only the first one is acted upon.

This change allows subsequent, nested interruptions to have a chance to interrupt playback if the
previous interruptions were ignored.

This test is for iPad only, so it must be run manually.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::shouldOverrideBackgroundPlaybackRestriction):
* platform/audio/PlatformMediaSession.cpp:
(WebCore::PlatformMediaSession::beginInterruption):
* testing/Internals.cpp:
(WebCore::Internals::beginMediaSessionInterruption):

LayoutTests:

When suspending under lock on iOS, there is first a resign active event, then a
suspend under lock. PiP prevents resign active from interrupting playback. But it should allow the
suspend under lock to interrupt playback.

Currently if there are nested interruptions only the first one is acted upon.

This change allows subsequent, nested interruptions to have a chance to interrupt playback if the
previous interruptions were ignored.

This test is for iPad only, so it must be run manually.

* platform/ios-simulator/TestExpectations:
* platform/ios-simulator/media/video-interruption-suspendunderlock-expcted.txt: Added.
* platform/ios-simulator/media/video-interruption-suspendunderlock.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsplatformiossimulatorTestExpectations">trunk/LayoutTests/platform/ios-simulator/TestExpectations</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLMediaElementcpp">trunk/Source/WebCore/html/HTMLMediaElement.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformaudioPlatformMediaSessioncpp">trunk/Source/WebCore/platform/audio/PlatformMediaSession.cpp</a></li>
<li><a href="#trunkSourceWebCoretestingInternalscpp">trunk/Source/WebCore/testing/Internals.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsplatformiossimulatormediavideointerruptionsuspendunderlockexpctedtxt">trunk/LayoutTests/platform/ios-simulator/media/video-interruption-suspendunderlock-expcted.txt</a></li>
<li><a href="#trunkLayoutTestsplatformiossimulatormediavideointerruptionsuspendunderlockhtml">trunk/LayoutTests/platform/ios-simulator/media/video-interruption-suspendunderlock.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (203387 => 203388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-07-19 00:38:23 UTC (rev 203387)
+++ trunk/LayoutTests/ChangeLog        2016-07-19 00:47:40 UTC (rev 203388)
</span><span class="lines">@@ -1,3 +1,26 @@
</span><ins>+2016-07-18  Jeremy Jones  &lt;jeremyj@apple.com&gt;
+
+        If previous media session interruptions were prevented, still allow subsequent interruptions to try.
+        https://bugs.webkit.org/show_bug.cgi?id=157553
+        rdar://problem/25740804
+
+        Reviewed by Eric Carlson.
+
+        When suspending under lock on iOS, there is first a resign active event, then a
+        suspend under lock. PiP prevents resign active from interrupting playback. But it should allow the
+        suspend under lock to interrupt playback.
+
+        Currently if there are nested interruptions only the first one is acted upon.
+
+        This change allows subsequent, nested interruptions to have a chance to interrupt playback if the
+        previous interruptions were ignored.
+
+        This test is for iPad only, so it must be run manually.
+
+        * platform/ios-simulator/TestExpectations:
+        * platform/ios-simulator/media/video-interruption-suspendunderlock-expcted.txt: Added.
+        * platform/ios-simulator/media/video-interruption-suspendunderlock.html: Added.
+
</ins><span class="cx"> 2016-07-18  Brent Fulgham  &lt;bfulgham@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Don't associate form-associated elements with forms in other trees.
</span></span></pre></div>
<a id="trunkLayoutTestsplatformiossimulatorTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/ios-simulator/TestExpectations (203387 => 203388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/ios-simulator/TestExpectations        2016-07-19 00:38:23 UTC (rev 203387)
+++ trunk/LayoutTests/platform/ios-simulator/TestExpectations        2016-07-19 00:47:40 UTC (rev 203388)
</span><span class="lines">@@ -3005,6 +3005,7 @@
</span><span class="cx"> # These tests hardcode platform-specific font aliases.
</span><span class="cx"> webkit.org/b/158649 fast/text/chinese-font-name-aliases-2.html [ ImageOnlyFailure ]
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> webkit.org/b/159214 fast/multicol/fixed-stack.html [ ImageOnlyFailure ]
</span><span class="cx"> 
</span><span class="cx"> webkit.org/b/157592 fast/images/composited-animated-gif-outside-viewport.html [ Pass Timeout ]
</span><span class="lines">@@ -3016,3 +3017,6 @@
</span><span class="cx"> webkit.org/b/158640 imported/blink/storage/indexeddb/blob-valid-after-deletion.html [ Pass Failure ]
</span><span class="cx"> 
</span><span class="cx"> webkit.org/b/142969 editing/spelling/copy-paste-crash.html
</span><ins>+
+# This test is iPad only
+platform/ios-simulator/media/video-interruption-suspendunderlock.html [ Skip ]
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformiossimulatormediavideointerruptionsuspendunderlockexpctedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/platform/ios-simulator/media/video-interruption-suspendunderlock-expcted.txt (0 => 203388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/ios-simulator/media/video-interruption-suspendunderlock-expcted.txt                                (rev 0)
+++ trunk/LayoutTests/platform/ios-simulator/media/video-interruption-suspendunderlock-expcted.txt        2016-07-19 00:47:40 UTC (rev 203388)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+
+Test that playback is paused by an SuspendUnderLock, even when it is not paused by EnteringBackground, and that ending the interruption does not automatically resume playback.
+
+Start
+EVENT(canplaythrough)
+RUN(video.play())
+EVENT(playing)
+RUN(video.webkitSetPresentationMode('picture-in-picture'))
+RUN(internals.beginMediaSessionInterruption('EnteringBackground'))
+EXPECTED (video.paused == 'false') OK
+RUN(internals.beginMediaSessionInterruption('SuspendedUnderLock'))
+EXPECTED (video.paused == 'true') OK
+RUN(internals.endMediaSessionInterruption('MayResumePlaying'))
+EXPECTED (video.paused == 'true') OK
+RUN(internals.endMediaSessionInterruption(''))
+EXPECTED (video.paused == 'true') OK
+END OF TEST
+
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformiossimulatormediavideointerruptionsuspendunderlockhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/platform/ios-simulator/media/video-interruption-suspendunderlock.html (0 => 203388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/ios-simulator/media/video-interruption-suspendunderlock.html                                (rev 0)
+++ trunk/LayoutTests/platform/ios-simulator/media/video-interruption-suspendunderlock.html        2016-07-19 00:47:40 UTC (rev 203388)
</span><span class="lines">@@ -0,0 +1,85 @@
</span><ins>+&lt;html&gt;
+    &lt;head&gt;
+        &lt;script src=&quot;../../../media/media-file.js&quot;&gt;&lt;/script&gt;
+        &lt;script src=&quot;../../../media/video-test.js&quot;&gt;&lt;/script&gt;
+        &lt;script&gt;
+            if (window.internals)
+                window.internals.settings.setAllowsPictureInPictureMediaPlayback(true);
+
+            function start()
+            {
+                if (!window.internals) {
+                    failTest('This test requires window.internals.');
+                    return;
+                }
+
+                findMediaElement();
+                waitForEvent('canplaythrough', canplaythrough);
+                waitForEvent('playing', playing);
+                video.src = findMediaFile(&quot;video&quot;, &quot;content/test&quot;);
+                consoleWrite(&quot;Start&quot;);
+            }
+
+            function canplaythrough()
+            {
+                video.removeEventListener('canplaythrough', canplaythrough);
+                run(&quot;video.play()&quot;);
+            }
+
+            function playing()
+            {
+                video.removeEventListener('playing', playing);
+
+                if (!('webkitSupportsPresentationMode' in video &amp;&amp; 'webkitPresentationMode' in video)) {
+                    failTest(&quot;Presentation mode is not supported in this video element.&quot;)
+                    return;
+                }
+                if (!video.webkitSupportsPresentationMode('picture-in-picture')) {
+                    failTest(&quot;picture-in-picture is not supported for this video element&quot;);
+                }
+                video.addEventListener('webkitpresentationmodechanged', onpresentationmodechanged);
+                runWithKeyDown(function() { run(&quot;video.webkitSetPresentationMode('picture-in-picture')&quot;); });
+            }
+
+            function onpresentationmodechanged()
+            {
+                video.removeEventListener('webkitpresentationmodechanged', onpresentationmodechanged);
+                run(&quot;internals.beginMediaSessionInterruption('EnteringBackground')&quot;);
+                setTimeout(pipInBackground, 100);
+            }
+
+            function pipInBackground()
+            {
+                testExpected(&quot;video.paused&quot;, false);
+                run(&quot;internals.beginMediaSessionInterruption('SuspendedUnderLock')&quot;);
+                setTimeout(pipUnderLock, 100);
+            }
+
+            function pipUnderLock()
+            {
+                testExpected(&quot;video.paused&quot;, true);
+                run(&quot;internals.endMediaSessionInterruption('MayResumePlaying')&quot;);
+                setTimeout(pipUnlocked, 100);
+            }
+
+            function pipUnlocked()
+            {
+                testExpected(&quot;video.paused&quot;, true);
+                run(&quot;internals.endMediaSessionInterruption('')&quot;);
+                setTimeout(pipForeground, 100);
+            }
+
+            function pipForeground()
+            {
+                testExpected(&quot;video.paused&quot;, true);
+                endTest();
+            }
+
+        &lt;/script&gt;
+    &lt;/head&gt;
+
+    &lt;body onload=&quot;start()&quot;&gt;
+        &lt;video controls &gt;&lt;/video&gt;
+        &lt;p&gt;Test that playback is paused by an SuspendUnderLock, and that ending the interruption does not automatically resume playback.&lt;/p&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (203387 => 203388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-07-19 00:38:23 UTC (rev 203387)
+++ trunk/Source/WebCore/ChangeLog        2016-07-19 00:47:40 UTC (rev 203388)
</span><span class="lines">@@ -1,3 +1,31 @@
</span><ins>+2016-07-18  Jeremy Jones  &lt;jeremyj@apple.com&gt;
+
+        If previous media session interruptions were prevented, still allow subsequent interruptions to try.
+        https://bugs.webkit.org/show_bug.cgi?id=157553
+        rdar://problem/25740804
+
+        Reviewed by Eric Carlson.
+
+        Test: platform/ios-simulator/media/video-interruption-suspendunderlock.html
+
+        When suspending under lock on iOS, there is first a resign active event, then a
+        suspend under lock. PiP prevents resign active from interrupting playback. But it should allow the
+        suspend under lock to interrupt playback.
+
+        Currently if there are nested interruptions only the first one is acted upon.
+
+        This change allows subsequent, nested interruptions to have a chance to interrupt playback if the
+        previous interruptions were ignored.
+
+        This test is for iPad only, so it must be run manually.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::shouldOverrideBackgroundPlaybackRestriction):
+        * platform/audio/PlatformMediaSession.cpp:
+        (WebCore::PlatformMediaSession::beginInterruption):
+        * testing/Internals.cpp:
+        (WebCore::Internals::beginMediaSessionInterruption):
+
</ins><span class="cx"> 2016-07-18  Brent Fulgham  &lt;bfulgham@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Don't associate form-associated elements with forms in other trees.
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (203387 => 203388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaElement.cpp        2016-07-19 00:38:23 UTC (rev 203387)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp        2016-07-19 00:47:40 UTC (rev 203388)
</span><span class="lines">@@ -6859,23 +6859,27 @@
</span><span class="cx"> 
</span><span class="cx"> bool HTMLMediaElement::shouldOverrideBackgroundPlaybackRestriction(PlatformMediaSession::InterruptionType type) const
</span><span class="cx"> {
</span><del>-    if (type != PlatformMediaSession::EnteringBackground) {
-        LOG(Media, &quot;HTMLMediaElement::shouldOverrideBackgroundPlaybackRestriction(%p) - returning false because type != PlatformMediaSession::EnteringBackground&quot;, this);
-        return false;
-    }
-
</del><ins>+    if (type == PlatformMediaSession::EnteringBackground) {
</ins><span class="cx"> #if ENABLE(WIRELESS_PLAYBACK_TARGET)
</span><del>-    if (m_isPlayingToWirelessTarget) {
-        LOG(Media, &quot;HTMLMediaElement::shouldOverrideBackgroundPlaybackRestriction(%p) - returning true because m_isPlayingToWirelessTarget is true&quot;, this);
-        return true;
-    }
</del><ins>+        if (m_isPlayingToWirelessTarget) {
+            LOG(Media, &quot;HTMLMediaElement::shouldOverrideBackgroundPlaybackRestriction(%p) - returning true because m_isPlayingToWirelessTarget is true&quot;, this);
+            return true;
+        }
</ins><span class="cx"> #endif
</span><del>-    if (m_videoFullscreenMode &amp; VideoFullscreenModePictureInPicture)
-        return true;
</del><ins>+        if (m_videoFullscreenMode &amp; VideoFullscreenModePictureInPicture)
+            return true;
</ins><span class="cx"> #if PLATFORM(IOS) || (PLATFORM(MAC) &amp;&amp; ENABLE(VIDEO_PRESENTATION_MODE))
</span><del>-    if (m_videoFullscreenMode == VideoFullscreenModeStandard &amp;&amp; supportsPictureInPicture() &amp;&amp; isPlaying())
-        return true;
</del><ins>+        if (m_videoFullscreenMode == VideoFullscreenModeStandard &amp;&amp; supportsPictureInPicture() &amp;&amp; isPlaying())
+            return true;
</ins><span class="cx"> #endif
</span><ins>+    } else if (type == PlatformMediaSession::SuspendedUnderLock) {
+#if ENABLE(WIRELESS_PLAYBACK_TARGET)
+        if (m_isPlayingToWirelessTarget) {
+            LOG(Media, &quot;HTMLMediaElement::shouldOverrideBackgroundPlaybackRestriction(%p) - returning true because m_isPlayingToWirelessTarget is true&quot;, this);
+            return true;
+        }
+#endif
+    }
</ins><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformaudioPlatformMediaSessioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/audio/PlatformMediaSession.cpp (203387 => 203388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/audio/PlatformMediaSession.cpp        2016-07-19 00:38:23 UTC (rev 203387)
+++ trunk/Source/WebCore/platform/audio/PlatformMediaSession.cpp        2016-07-19 00:47:40 UTC (rev 203388)
</span><span class="lines">@@ -100,7 +100,9 @@
</span><span class="cx"> {
</span><span class="cx">     LOG(Media, &quot;PlatformMediaSession::beginInterruption(%p), state = %s, interruption type = %s, interruption count = %i&quot;, this, stateName(m_state), interruptionName(type), m_interruptionCount);
</span><span class="cx"> 
</span><del>-    if (++m_interruptionCount &gt; 1)
</del><ins>+    // When interruptions are overridden, m_interruptionType doesn't get set.
+    // Give nested interruptions a chance when the previous interruptions were overridden.
+    if (++m_interruptionCount &gt; 1 &amp;&amp; m_interruptionType != NoInterruption)
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     if (client().shouldOverrideBackgroundPlaybackRestriction(type)) {
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.cpp (203387 => 203388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.cpp        2016-07-19 00:38:23 UTC (rev 203387)
+++ trunk/Source/WebCore/testing/Internals.cpp        2016-07-19 00:47:40 UTC (rev 203388)
</span><span class="lines">@@ -2771,6 +2771,8 @@
</span><span class="cx">         interruption = PlatformMediaSession::SystemSleep;
</span><span class="cx">     else if (equalLettersIgnoringASCIICase(interruptionString, &quot;enteringbackground&quot;))
</span><span class="cx">         interruption = PlatformMediaSession::EnteringBackground;
</span><ins>+    else if (equalLettersIgnoringASCIICase(interruptionString, &quot;suspendedunderlock&quot;))
+        interruption = PlatformMediaSession::SuspendedUnderLock;
</ins><span class="cx">     else {
</span><span class="cx">         ec = INVALID_ACCESS_ERR;
</span><span class="cx">         return;
</span></span></pre>
</div>
</div>

</body>
</html>