Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Switch to alternate <source> element for AirPlay when necessary
https://bugs.webkit.org/show_bug.cgi?id=246466 <rdar://101136233> Reviewed by Jer Noble. * LayoutTests/media/media-source/remoteplayback-from-source-element-expected.txt: Added. * LayoutTests/media/media-source/remoteplayback-from-source-element.html: Added. * LayoutTests/TestExpectations: New test skipped everywhere. * LayoutTests/platform/mac/TestExpectations: New test enabled. * Source/WebCore/Modules/remoteplayback/RemotePlayback.cpp: (WebCore::RemotePlayback::watchAvailability): Add runtime logging. (WebCore::RemotePlayback::cancelWatchAvailability): Ditto. (WebCore::RemotePlayback::prompt): Ditto. (WebCore::RemotePlayback::shouldPlayToRemoteTargetChanged): Ditto. (WebCore::RemotePlayback::setState): Ditto. (WebCore::RemotePlayback::disconnect): Ditto. (WebCore::RemotePlayback::availabilityChanged): Ditto. (WebCore::RemotePlayback::setLogger): Ditto. (WebCore::RemotePlayback::logChannel const): Ditto. * Source/WebCore/Modules/remoteplayback/RemotePlayback.h: * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::HTMLMediaElement::HTMLMediaElement): Set remote logger. (WebCore::HTMLMediaElement::checkPlaybackTargetCompatibility): If loaded from a <source> element and is another <source> uses a media engine that supports remote playback, try loading that. (WebCore::HTMLMediaElement::loadResource): Don't bother trying MSE, MediaStream, or blob if the load requires remote playback. (WebCore::HTMLMediaElement::applyConfiguration): Apply the stored configuration. (WebCore::HTMLMediaElement::setReadyState): Apply the remote configuration once HAVE_FUTURE_DATA is reached. (WebCore::HTMLMediaElement::selectNextSourceChild): Set parameter `requiresRemotePlayback` field. (WebCore::HTMLMediaElement::clearMediaPlayer): Force a target availability event. (WebCore::HTMLMediaElement::wirelessRoutesAvailableDidChange): Only post availability event when availability actually changes. (WebCore::HTMLMediaElement::setIsPlayingToWirelessTarget): (WebCore::HTMLMediaElement::enqueuePlaybackTargetAvailabilityChangedEvent): Add parameter so we don't necessarily post events when availability doesn't change. (WebCore::HTMLMediaElement::addEventListener): Force a target availability event. * Source/WebCore/html/HTMLMediaElement.h: * Source/WebCore/html/MediaElementSession.cpp: (WebCore::MediaElementSession::showPlaybackTargetPicker): Always log. * Source/WebCore/platform/graphics/MediaPlayer.cpp: (WebCore::MediaPlayer::load): Add `requiresRemotePlayback` parameter. * Source/WebCore/platform/graphics/MediaPlayer.h: (WebCore::MediaEngineSupportParameters::encode const): (WebCore::MediaEngineSupportParameters::decode): * Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm: (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::supportsType): Consider new support field. * Source/WebCore/platform/graphics/cocoa/MediaPlayerPrivateWebM.mm: (WebCore::MediaPlayerPrivateWebM::supportsType): Ditto. * Source/WebCore/testing/Internals.cpp: (WebCore::Internals::setMockMediaPlaybackTargetPickerEnabled): NULL-check frame and page. (WebCore::Internals::setMockMediaPlaybackTargetPickerState): Ditto. (WebCore::Internals::mockMediaPlaybackTargetPickerDismissPopup): Ditto. * Source/WebKit/GPUProcess/media/RemoteMediaPlayerProxy.cpp: (WebKit::RemoteMediaPlayerProxy::load): Add "requires remote playback" parameter. * Source/WebKit/GPUProcess/media/RemoteMediaPlayerProxy.h: * Source/WebKit/GPUProcess/media/RemoteMediaPlayerProxy.messages.in: Ditto. * Source/WebKit/WebProcess/GPU/media/MediaPlayerPrivateRemote.cpp: (WebKit::MediaPlayerPrivateRemote::load): Ditto. * Source/WebKit/WebProcess/GPU/media/RemoteMediaPlayerMIMETypeCache.cpp: (WebKit::RemoteMediaPlayerMIMETypeCache::supportsTypeAndCodecs): Ditto. * Source/WebKit/WebProcess/GPU/media/RemoteMediaPlayerMIMETypeCache.h: Canonical link: https://commits.webkit.org/255624@main
- Loading branch information
1 parent
114ef69
commit 4ec10f6
Showing
20 changed files
with
333 additions
and
64 deletions.
There are no files selected for viewing
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
28 changes: 28 additions & 0 deletions
28
LayoutTests/media/media-source/remoteplayback-from-source-element-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,28 @@ | ||
|
||
|
||
** Setup MSE and URL <source> elements | ||
EXPECTED (source.readyState == 'closed') OK | ||
EVENT(sourceopen) | ||
EVENT(update) | ||
EVENT(update) | ||
EVENT(update) | ||
EVENT(update) | ||
EVENT(update) | ||
EVENT(update) | ||
EVENT(update) | ||
EVENT(update) | ||
EVENT(update) | ||
EVENT(update) | ||
EVENT(update) | ||
EXPECTED (video.currentSrc.indexOf("blob:") === '0') OK | ||
EXPECTED (video.readyState >= '1') OK | ||
|
||
** Simulate a device becoming available | ||
|
||
** Simulate selecting a device | ||
EVENT(connect) | ||
EXPECTED (video.currentSrc.indexOf("blob:") < '0') OK | ||
EXPECTED (video.readyState >= '1') OK | ||
|
||
END OF TEST | ||
|
132 changes: 132 additions & 0 deletions
132
LayoutTests/media/media-source/remoteplayback-from-source-element.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,132 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>Remote playback from source element</title> | ||
<script src="media-source-loader.js"></script> | ||
<script src="../video-test.js"></script> | ||
<script src="../media-file.js"></script> | ||
<script> | ||
|
||
let source; | ||
|
||
if (window.internals) { | ||
internals.setMockMediaPlaybackTargetPickerEnabled(true); | ||
internals.settings.setAllowsAirPlayForMediaPlayback(true); | ||
} | ||
|
||
async function setupSources() | ||
{ | ||
consoleWrite('<br>** Setup MSE and URL <source> elements') | ||
|
||
let canPlayListener = new Promise(resolve => { | ||
video.addEventListener('canplay', event => { | ||
resolve(event); | ||
}, { once: true }); | ||
}); | ||
|
||
let loader = new MediaSourceLoader('content/test-fragmented-manifest.json'); | ||
await new Promise((resolve, reject) => { | ||
loader.onload = resolve; | ||
loader.onerror = reject; | ||
}); | ||
|
||
source = new MediaSource(); | ||
testExpected('source.readyState', 'closed'); | ||
|
||
let sourceElement = document.createElement('source'); | ||
sourceElement.id = 'MSE'; | ||
sourceElement.type = loader.type(); | ||
sourceElement.src = URL.createObjectURL(source); | ||
video.appendChild(sourceElement); | ||
await waitFor(source, 'sourceopen'); | ||
|
||
let sourceBuffer = source.addSourceBuffer(loader.type()); | ||
sourceBuffer.appendBuffer(loader.initSegment()); | ||
await waitFor(sourceBuffer, 'update'); | ||
|
||
for (i = 0; i < loader.mediaSegmentsLength(); i++) { | ||
sourceBuffer.appendBuffer(loader.mediaSegment(i)); | ||
await waitForEventWithTimeout(sourceBuffer, 'update', 5000, '"update" for sample never fired') | ||
} | ||
|
||
sourceElement = document.createElement('source'); | ||
let sourceFile = findMediaFile('video', '../content/test'); | ||
sourceElement.id = 'MP4'; | ||
sourceElement.src = sourceFile | ||
sourceElement.type = mimeTypeForFile(sourceFile); | ||
video.appendChild(sourceElement); | ||
|
||
await canPlayListener; | ||
testExpected('video.currentSrc.indexOf("blob:")', 0, '==='); | ||
testExpected('video.readyState', HTMLMediaElement.HAVE_METADATA, '>='); | ||
} | ||
|
||
async function setupRemote() | ||
{ | ||
consoleWrite('<br>** Simulate a device becoming available') | ||
|
||
let pendingTimeout = setTimeout(_ => { | ||
failTest(`<br>Remote device not available after 8 seconds!`); | ||
}, 8000); | ||
|
||
let resolveCallback; | ||
try { | ||
video.remote.watchAvailability((available) => { | ||
if (!available) | ||
return; | ||
|
||
video.remote.cancelWatchAvailability(); | ||
clearTimeout(pendingTimeout); | ||
resolveCallback(); | ||
}); | ||
} catch (error) { | ||
failTest(`<br>'watchAvailability' threw error ${error}`); | ||
} | ||
|
||
if (window.internals) | ||
internals.setMockMediaPlaybackTargetPickerState('Sleepy', 'DeviceAvailable'); | ||
|
||
return new Promise(resolve => { resolveCallback = resolve; }); | ||
} | ||
|
||
async function connectToRemote() | ||
{ | ||
consoleWrite('<br>** Simulate selecting a device'); | ||
|
||
await video.play(); | ||
video.pause(); | ||
|
||
runWithKeyDown(async () => { | ||
video.remote.prompt().catch(error => { | ||
consoleWrite(`remote.prompt() failed with error '${ error }'`); | ||
}) | ||
}); | ||
|
||
await waitForEventWithTimeout(video.remote, 'connect', 8000, "'connect' not fired after 8 seconds"); | ||
|
||
await testExpectedEventually('video.currentSrc.indexOf("blob:")', 0, '<', 8000); | ||
testExpected('video.readyState', HTMLMediaElement.HAVE_METADATA, '>='); | ||
consoleWrite(''); | ||
} | ||
|
||
async function runTest() | ||
{ | ||
findMediaElement(); | ||
|
||
waitForEventAndFail('error'); | ||
|
||
await setupSources(); | ||
|
||
await setupRemote(); | ||
|
||
await connectToRemote(); | ||
|
||
endTest(); | ||
} | ||
|
||
</script> | ||
</head> | ||
<body onload="runTest()"> | ||
<video muted controls></video> | ||
</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
Oops, something went wrong.