-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
"targetavailabilitychanged" event fired even when media element has d…
…isabledRemotePlayback = true https://bugs.webkit.org/show_bug.cgi?id=274220 rdar://128137977 Reviewed by Eric Carlson. The expectation is that `disableRemotePlayback = true` should cause all remote playback events to not fire. Instead, disabling remote playback seems to have no effect on disabling these events, and default media controls remote playback buttons still appear. Add some utility methods to HTMLMediaElement to make it a bit cheaper to check whether remote playback is disabled, and whether remote playback event listeners exist. When changing the state of `disableRemotePlayback`, ensure that an event is fired saying no remote playback targets exist, which cause media controls (including the native ones) to hide the remote playback button. * LayoutTests/media/airplay-target-availability-disableremoteplayback-expected.txt: Added. * LayoutTests/media/airplay-target-availability-disableremoteplayback.html: Added. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::HTMLMediaElement::~HTMLMediaElement): (WebCore::HTMLMediaElement::attributeChanged): (WebCore::HTMLMediaElement::setReadyState): (WebCore::HTMLMediaElement::clearMediaPlayer): (WebCore::HTMLMediaElement::wirelessRoutesAvailableDidChange): (WebCore::HTMLMediaElement::enqueuePlaybackTargetAvailabilityChangedEvent): (WebCore::HTMLMediaElement::remoteHasAvailabilityCallbacksChanged): (WebCore::HTMLMediaElement::hasTargetAvailabilityListeners): (WebCore::HTMLMediaElement::hasEnabledTargetAvailabilityListeners): (WebCore::HTMLMediaElement::isWirelessPlaybackTargetDisabledChanged): (WebCore::HTMLMediaElement::isWirelessPlaybackTargetDisabled const): (WebCore::HTMLMediaElement::addEventListener): (WebCore::HTMLMediaElement::removeEventListener): * Source/WebCore/html/HTMLMediaElement.h: Canonical link: https://commits.webkit.org/278933@main
- Loading branch information
Showing
5 changed files
with
235 additions
and
13 deletions.
There are no files selected for viewing
37 changes: 37 additions & 0 deletions
37
LayoutTests/media/airplay-target-availability-disableremoteplayback-expected.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
Test that a webkitplaybacktargetavailabilitychanged is not fired when adding an event listener to a media element with disableRemotePlayback set | ||
RUN(video = document.body.appendChild(document.createElement('video'))) | ||
RUN(video.disableRemotePlayback = true) | ||
Promise rejected correctly OK | ||
Correctly failed to receive targetavailabilitychanged event OK | ||
Test completed OK | ||
|
||
Test that a webkitplaybacktargetavailabilitychanged is fired when setting disableRemotePlayback on an element with an event listener | ||
RUN(video = document.body.appendChild(document.createElement('video'))) | ||
EVENT(webkitplaybacktargetavailabilitychanged) | ||
EXPECTED (event.availability == 'available') OK | ||
RUN(video.disableRemotePlayback = true) | ||
EVENT(webkitplaybacktargetavailabilitychanged) | ||
EXPECTED (event.availability == 'not-available') OK | ||
Test completed OK | ||
|
||
Test that a webkitplaybacktargetavailabilitychanged is fired when clearing disableRemotePlayback on an element with an event listener | ||
RUN(video = document.body.appendChild(document.createElement('video'))) | ||
RUN(video.disableRemotePlayback = true) | ||
Promise rejected correctly OK | ||
Correctly failed to receive targetavailabilitychanged event OK | ||
RUN(video.disableRemotePlayback = false) | ||
EVENT(webkitplaybacktargetavailabilitychanged) | ||
EXPECTED (event.availability == 'available') OK | ||
Test completed OK | ||
|
||
Test that a webkitplaybacktargetavailabilitychanged is not received when setting disableRemotePlayback, when no targets were previously available | ||
RUN(video = document.body.appendChild(document.createElement('video'))) | ||
EVENT(webkitplaybacktargetavailabilitychanged) | ||
EXPECTED (event.availability == 'not-available') OK | ||
RUN(video.disableRemotePlayback = true) | ||
Promise rejected correctly OK | ||
Correctly failed to receive targetavailabilitychanged event OK | ||
Test completed OK | ||
|
||
END OF TEST | ||
|
134 changes: 134 additions & 0 deletions
134
LayoutTests/media/airplay-target-availability-disableremoteplayback.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
<html> | ||
<head> | ||
<script src='media-file.js'></script> | ||
<script src='video-test.js'></script> | ||
<script> | ||
window.addEventListener('load', async event => { | ||
await runTest().then(endTest).catch(failTest); | ||
}); | ||
|
||
function waitForTargetAvailableToBecome(element, state, duration, message) { | ||
return new Promise(async (resolve, reject) => { | ||
var timeout; | ||
var listener; | ||
|
||
let cleanup = () => { | ||
clearTimeout(timeout); | ||
element.removeEventListener('webkitplaybacktargetavailabilitychanged', listener); | ||
}; | ||
|
||
listener = event => { | ||
if (event.availability !== state) | ||
return; | ||
consoleWrite(`EVENT(${event.type})`); | ||
resolve(event); | ||
cleanup(); | ||
}; | ||
element.addEventListener('webkitplaybacktargetavailabilitychanged', listener); | ||
|
||
timeout = setTimeout(() => { | ||
reject(new Error(message)); | ||
cleanup(); | ||
}, duration); | ||
}); | ||
} | ||
|
||
async function runTest() { | ||
const tenSeconds = 10000; | ||
let tests = [ | ||
async function() { | ||
consoleWrite('Test that a webkitplaybacktargetavailabilitychanged is not fired when adding an event listener to a media element with disableRemotePlayback set'); | ||
|
||
if (window.internals) | ||
internals.setMockMediaPlaybackTargetPickerState('Sleepy TV', 'DeviceAvailable'); | ||
|
||
run(`video = document.body.appendChild(document.createElement('video'))`); | ||
run(`video.disableRemotePlayback = true`); | ||
|
||
await shouldReject(waitForEventWithTimeout(video, 'webkitplaybacktargetavailabilitychanged', 100)); | ||
logResult(Success, 'Correctly failed to receive targetavailabilitychanged event') | ||
}, | ||
async function() { | ||
consoleWrite('Test that a webkitplaybacktargetavailabilitychanged is fired when setting disableRemotePlayback on an element with an event listener'); | ||
|
||
if (window.internals) | ||
internals.setMockMediaPlaybackTargetPickerState('Sleepy TV', 'DeviceAvailable'); | ||
|
||
run(`video = document.body.appendChild(document.createElement('video'))`); | ||
|
||
event = await waitForTargetAvailableToBecome(video, 'available', tenSeconds, 'Failed to receive targetavailabilitychanged event'); | ||
testExpected('event.availability', 'available'); | ||
|
||
let eventPromise = waitForTargetAvailableToBecome(video, 'not-available', tenSeconds, 'Failed to receive targetavailabilitychanged event'); | ||
run(`video.disableRemotePlayback = true`); | ||
|
||
event = await eventPromise; | ||
testExpected('event.availability', 'not-available'); | ||
}, | ||
async function() { | ||
consoleWrite('Test that a webkitplaybacktargetavailabilitychanged is fired when clearing disableRemotePlayback on an element with an event listener'); | ||
|
||
if (window.internals) | ||
internals.setMockMediaPlaybackTargetPickerState('Sleepy TV', 'DeviceAvailable'); | ||
|
||
run(`video = document.body.appendChild(document.createElement('video'))`); | ||
run(`video.disableRemotePlayback = true`); | ||
|
||
await shouldReject(waitForEventWithTimeout(video, 'webkitplaybacktargetavailabilitychanged', tenSeconds)); | ||
logResult(Success, 'Correctly failed to receive targetavailabilitychanged event') | ||
|
||
let eventPromise = waitForTargetAvailableToBecome(video, 'available', tenSeconds, 'Failed to receive targetavailabilitychanged event'); | ||
run(`video.disableRemotePlayback = false`); | ||
|
||
event = await eventPromise; | ||
testExpected('event.availability', 'available'); | ||
}, | ||
async function() { | ||
consoleWrite('Test that a webkitplaybacktargetavailabilitychanged is not received when setting disableRemotePlayback, when no targets were previously available'); | ||
|
||
if (window.internals) | ||
internals.setMockMediaPlaybackTargetPickerState('Sleepy TV', 'DeviceUnavailable'); | ||
|
||
run(`video = document.body.appendChild(document.createElement('video'))`); | ||
|
||
event = await waitForTargetAvailableToBecome(video, 'not-available', tenSeconds); | ||
testExpected('event.availability', 'not-available'); | ||
|
||
run(`video.disableRemotePlayback = true`); | ||
|
||
await shouldReject(waitForEventWithTimeout(video, 'webkitplaybacktargetavailabilitychanged', tenSeconds)); | ||
logResult(Success, 'Correctly failed to receive targetavailabilitychanged event') | ||
}, | ||
]; | ||
|
||
if (window.internals) | ||
internals.setMockMediaPlaybackTargetPickerEnabled(true); | ||
|
||
for (var test of tests) { | ||
try { | ||
await test(); | ||
logResult(Success, 'Test completed'); | ||
} catch(e) { | ||
logResult(Failed, `ERROR: ${e.message}`); | ||
} finally { | ||
if (window.internals) | ||
internals.setMockMediaPlaybackTargetPickerState('Sleepy TV', 'DeviceUnavailable'); | ||
video.src = ''; | ||
video.load(); | ||
document.body.removeChild(video); | ||
consoleWrite(''); | ||
} | ||
} | ||
|
||
if (window.internals) { | ||
internals.setMockMediaPlaybackTargetPickerState('Sleepy TV', 'DeviceUnavailable'); | ||
internals.setMockMediaPlaybackTargetPickerEnabled(false); | ||
} | ||
} | ||
|
||
</script> | ||
</head> | ||
|
||
<body> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters