Commit 3194c190 authored by zqzhang's avatar zqzhang Committed by Commit bot

[Blink>MediaSession] Use setActionCallback() instead of event listeners for media control actions

As the MediaSession spec changed from using event-listener-based
to callback-based fashion for media controls, we need to keep the
implementation up to date.

Spec PR:
https://github.com/WICG/mediasession/pull/159

BUG=675963

Review-Url: https://codereview.chromium.org/2589893002
Cr-Commit-Position: refs/heads/master@{#441787}
parent ddded05f
...@@ -48,12 +48,6 @@ PASS window.cached_navigator_connection.onchange is null ...@@ -48,12 +48,6 @@ PASS window.cached_navigator_connection.onchange is null
PASS window.cached_navigator_connection.ontypechange is null PASS window.cached_navigator_connection.ontypechange is null
PASS window.cached_navigator_mediaDevices.ondevicechange is null PASS window.cached_navigator_mediaDevices.ondevicechange is null
PASS window.cached_navigator_mediaSession.metadata is null PASS window.cached_navigator_mediaSession.metadata is null
PASS window.cached_navigator_mediaSession.onnexttrack is null
PASS window.cached_navigator_mediaSession.onpause is null
PASS window.cached_navigator_mediaSession.onplay is null
PASS window.cached_navigator_mediaSession.onprevioustrack is null
PASS window.cached_navigator_mediaSession.onseekbackward is null
PASS window.cached_navigator_mediaSession.onseekforward is null
PASS window.cached_navigator_mediaSession.playbackState is 'none' PASS window.cached_navigator_mediaSession.playbackState is 'none'
PASS window.cached_navigator_presentation.defaultRequest is null PASS window.cached_navigator_presentation.defaultRequest is null
PASS window.cached_navigator_presentation.receiver is null PASS window.cached_navigator_presentation.receiver is null
......
...@@ -48,12 +48,6 @@ PASS window.cached_navigator_connection.onchange is null ...@@ -48,12 +48,6 @@ PASS window.cached_navigator_connection.onchange is null
PASS window.cached_navigator_connection.ontypechange is null PASS window.cached_navigator_connection.ontypechange is null
PASS window.cached_navigator_mediaDevices.ondevicechange is null PASS window.cached_navigator_mediaDevices.ondevicechange is null
PASS window.cached_navigator_mediaSession.metadata is null PASS window.cached_navigator_mediaSession.metadata is null
PASS window.cached_navigator_mediaSession.onnexttrack is null
PASS window.cached_navigator_mediaSession.onpause is null
PASS window.cached_navigator_mediaSession.onplay is null
PASS window.cached_navigator_mediaSession.onprevioustrack is null
PASS window.cached_navigator_mediaSession.onseekbackward is null
PASS window.cached_navigator_mediaSession.onseekforward is null
PASS window.cached_navigator_mediaSession.playbackState is 'none' PASS window.cached_navigator_mediaSession.playbackState is 'none'
PASS window.cached_navigator_presentation.defaultRequest is null PASS window.cached_navigator_presentation.defaultRequest is null
PASS window.cached_navigator_presentation.receiver is null PASS window.cached_navigator_presentation.receiver is null
......
...@@ -48,12 +48,6 @@ PASS window.cached_navigator_connection.onchange is null ...@@ -48,12 +48,6 @@ PASS window.cached_navigator_connection.onchange is null
PASS window.cached_navigator_connection.ontypechange is null PASS window.cached_navigator_connection.ontypechange is null
PASS window.cached_navigator_mediaDevices.ondevicechange is null PASS window.cached_navigator_mediaDevices.ondevicechange is null
PASS window.cached_navigator_mediaSession.metadata is null PASS window.cached_navigator_mediaSession.metadata is null
PASS window.cached_navigator_mediaSession.onnexttrack is null
PASS window.cached_navigator_mediaSession.onpause is null
PASS window.cached_navigator_mediaSession.onplay is null
PASS window.cached_navigator_mediaSession.onprevioustrack is null
PASS window.cached_navigator_mediaSession.onseekbackward is null
PASS window.cached_navigator_mediaSession.onseekforward is null
PASS window.cached_navigator_mediaSession.playbackState is 'none' PASS window.cached_navigator_mediaSession.playbackState is 'none'
PASS window.cached_navigator_presentation.defaultRequest is null PASS window.cached_navigator_presentation.defaultRequest is null
PASS window.cached_navigator_presentation.receiver is null PASS window.cached_navigator_presentation.receiver is null
......
...@@ -50,12 +50,6 @@ PASS oldChildWindow.navigator.language is newChildWindow.navigator.language ...@@ -50,12 +50,6 @@ PASS oldChildWindow.navigator.language is newChildWindow.navigator.language
PASS oldChildWindow.navigator.maxTouchPoints is newChildWindow.navigator.maxTouchPoints PASS oldChildWindow.navigator.maxTouchPoints is newChildWindow.navigator.maxTouchPoints
PASS oldChildWindow.navigator.mediaDevices.ondevicechange is newChildWindow.navigator.mediaDevices.ondevicechange PASS oldChildWindow.navigator.mediaDevices.ondevicechange is newChildWindow.navigator.mediaDevices.ondevicechange
PASS oldChildWindow.navigator.mediaSession.metadata is newChildWindow.navigator.mediaSession.metadata PASS oldChildWindow.navigator.mediaSession.metadata is newChildWindow.navigator.mediaSession.metadata
PASS oldChildWindow.navigator.mediaSession.onnexttrack is newChildWindow.navigator.mediaSession.onnexttrack
PASS oldChildWindow.navigator.mediaSession.onpause is newChildWindow.navigator.mediaSession.onpause
PASS oldChildWindow.navigator.mediaSession.onplay is newChildWindow.navigator.mediaSession.onplay
PASS oldChildWindow.navigator.mediaSession.onprevioustrack is newChildWindow.navigator.mediaSession.onprevioustrack
PASS oldChildWindow.navigator.mediaSession.onseekbackward is newChildWindow.navigator.mediaSession.onseekbackward
PASS oldChildWindow.navigator.mediaSession.onseekforward is newChildWindow.navigator.mediaSession.onseekforward
PASS oldChildWindow.navigator.mediaSession.playbackState is newChildWindow.navigator.mediaSession.playbackState PASS oldChildWindow.navigator.mediaSession.playbackState is newChildWindow.navigator.mediaSession.playbackState
PASS oldChildWindow.navigator.onLine is newChildWindow.navigator.onLine PASS oldChildWindow.navigator.onLine is newChildWindow.navigator.onLine
PASS oldChildWindow.navigator.platform is newChildWindow.navigator.platform PASS oldChildWindow.navigator.platform is newChildWindow.navigator.platform
......
...@@ -29,12 +29,6 @@ PASS childWindow.navigator.language is window.navigator.language ...@@ -29,12 +29,6 @@ PASS childWindow.navigator.language is window.navigator.language
PASS childWindow.navigator.maxTouchPoints is 0 PASS childWindow.navigator.maxTouchPoints is 0
PASS childWindow.navigator.mediaDevices.ondevicechange is null PASS childWindow.navigator.mediaDevices.ondevicechange is null
PASS childWindow.navigator.mediaSession.metadata is null PASS childWindow.navigator.mediaSession.metadata is null
PASS childWindow.navigator.mediaSession.onnexttrack is null
PASS childWindow.navigator.mediaSession.onpause is null
PASS childWindow.navigator.mediaSession.onplay is null
PASS childWindow.navigator.mediaSession.onprevioustrack is null
PASS childWindow.navigator.mediaSession.onseekbackward is null
PASS childWindow.navigator.mediaSession.onseekforward is null
PASS childWindow.navigator.mediaSession.playbackState is 'none' PASS childWindow.navigator.mediaSession.playbackState is 'none'
PASS childWindow.navigator.onLine is window.navigator.onLine PASS childWindow.navigator.onLine is window.navigator.onLine
PASS childWindow.navigator.platform is window.navigator.platform PASS childWindow.navigator.platform is window.navigator.platform
......
...@@ -29,12 +29,6 @@ PASS childWindow.navigator.language is window.navigator.language ...@@ -29,12 +29,6 @@ PASS childWindow.navigator.language is window.navigator.language
PASS childWindow.navigator.maxTouchPoints is 0 PASS childWindow.navigator.maxTouchPoints is 0
PASS childWindow.navigator.mediaDevices.ondevicechange is null PASS childWindow.navigator.mediaDevices.ondevicechange is null
PASS childWindow.navigator.mediaSession.metadata is null PASS childWindow.navigator.mediaSession.metadata is null
PASS childWindow.navigator.mediaSession.onnexttrack is null
PASS childWindow.navigator.mediaSession.onpause is null
PASS childWindow.navigator.mediaSession.onplay is null
PASS childWindow.navigator.mediaSession.onprevioustrack is null
PASS childWindow.navigator.mediaSession.onseekbackward is null
PASS childWindow.navigator.mediaSession.onseekforward is null
PASS childWindow.navigator.mediaSession.playbackState is 'none' PASS childWindow.navigator.mediaSession.playbackState is 'none'
PASS childWindow.navigator.onLine is window.navigator.onLine PASS childWindow.navigator.onLine is window.navigator.onLine
PASS childWindow.navigator.platform is window.navigator.platform PASS childWindow.navigator.platform is window.navigator.platform
......
<!DOCTYPE html>
<title>Test that setting MediaSession event handler should notify the service</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script>
test(function(t) {
window.navigator.mediaSession.setActionHandler("play", null);
window.navigator.mediaSession.setActionHandler("pause", null);
window.navigator.mediaSession.setActionHandler("previoustrack", null);
window.navigator.mediaSession.setActionHandler("nexttrack", null);
window.navigator.mediaSession.setActionHandler("seekbackward", null);
window.navigator.mediaSession.setActionHandler("seekforward", null);
}, "Test that setActionHandler() can be executed for supported actions");
test(function(t) {
assert_throws(
new TypeError("Failed to execute 'setActionHandler' on 'MediaSession':" +
"The provided value 'invalid' is not a valid enum value" +
"of type MediaSessionAction."),
_ => { window.navigator.mediaSession.setActionHandler("invalid", null); });
}, "Test that setActionHandler() throws exception for unsupported actions");
</script>
<!DOCTYPE html>
<title>Test that setting MediaSession callbacks are alive after garbage-collection</title>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../resources/mojo-helpers.js"></script>
<script src="resources/mediasessionservice-mock.js"></script>
<script src="resources/utils.js"></script>
<script>
var mock;
function gc() {
if (window.GCController) {
GCController.collect();
} else {
for (var i = 0; i < 10000; ++i) {
({ });
}
}
}
async_test(function(t) {
mediaSessionServiceMock.then(m => {
mock = m;
mock.setClientCallback(_ => {
gc();
setTimeout(_ => {
mock.getClient().didReceiveAction(MediaSessionAction.PLAY);
});
});
window.navigator.mediaSession.setActionHandler("play", _ => { t.done(); });
});
});
</script>
...@@ -20,20 +20,26 @@ var expectations = [ ...@@ -20,20 +20,26 @@ var expectations = [
var nextExpectation = 0; var nextExpectation = 0;
function checkExpectation(t, event) { function checkExpectation(t, action) {
var expectedEvent = expectations[nextExpectation]; var expectedEvent = expectations[nextExpectation];
assert_equals(expectedEvent, event.type); assert_equals(expectedEvent, action);
if (++nextExpectation >= expectations.length) if (++nextExpectation >= expectations.length)
t.done(); t.done();
} }
function runTests(t) { function runTests(t) {
window.navigator.mediaSession.onplay = t.step_func(checkExpectation.bind(null, t)); window.navigator.mediaSession.setActionHandler(
window.navigator.mediaSession.onpause = t.step_func(checkExpectation.bind(null, t)); "play", t.step_func(checkExpectation.bind(null, t, "play")));
window.navigator.mediaSession.onprevioustrack = t.step_func(checkExpectation.bind(null, t)); window.navigator.mediaSession.setActionHandler(
window.navigator.mediaSession.onnexttrack = t.step_func(checkExpectation.bind(null, t)); "pause", t.step_func(checkExpectation.bind(null, t, "pause")));
window.navigator.mediaSession.onseekforward = t.step_func(checkExpectation.bind(null, t)); window.navigator.mediaSession.setActionHandler(
window.navigator.mediaSession.onseekbackward = t.step_func(checkExpectation.bind(null, t)); "previoustrack", t.step_func(checkExpectation.bind(null, t, "previoustrack")));
window.navigator.mediaSession.setActionHandler(
"nexttrack", t.step_func(checkExpectation.bind(null, t, "nexttrack")));
window.navigator.mediaSession.setActionHandler(
"seekbackward", t.step_func(checkExpectation.bind(null, t, "seekbackward")));
window.navigator.mediaSession.setActionHandler(
"seekforward", t.step_func(checkExpectation.bind(null, t, "seekforward")));
mock.getClient().didReceiveAction(MediaSessionAction.PLAY); mock.getClient().didReceiveAction(MediaSessionAction.PLAY);
mock.getClient().didReceiveAction(MediaSessionAction.PAUSE); mock.getClient().didReceiveAction(MediaSessionAction.PAUSE);
......
...@@ -22,23 +22,17 @@ function getExpectations() { ...@@ -22,23 +22,17 @@ function getExpectations() {
[ MediaSessionAction.SEEK_BACKWARD, true ], [ MediaSessionAction.SEEK_BACKWARD, true ],
[ MediaSessionAction.SEEK_FORWARD, true ], [ MediaSessionAction.SEEK_FORWARD, true ],
[ MediaSessionAction.PLAY, false ], [ MediaSessionAction.PLAY, false ],
[ MediaSessionAction.PLAY, true ],
[ MediaSessionAction.PAUSE, false ], [ MediaSessionAction.PAUSE, false ],
[ MediaSessionAction.PAUSE, true ],
[ MediaSessionAction.PREVIOUS_TRACK, false ], [ MediaSessionAction.PREVIOUS_TRACK, false ],
[ MediaSessionAction.PREVIOUS_TRACK, true ],
[ MediaSessionAction.NEXT_TRACK, false ], [ MediaSessionAction.NEXT_TRACK, false ],
[ MediaSessionAction.NEXT_TRACK, true ],
[ MediaSessionAction.SEEK_BACKWARD, false ], [ MediaSessionAction.SEEK_BACKWARD, false ],
[ MediaSessionAction.SEEK_BACKWARD, true ],
[ MediaSessionAction.SEEK_FORWARD, false ], [ MediaSessionAction.SEEK_FORWARD, false ],
[ MediaSessionAction.PLAY, true ],
[ MediaSessionAction.PAUSE, true ],
[ MediaSessionAction.PREVIOUS_TRACK, true ],
[ MediaSessionAction.NEXT_TRACK, true ],
[ MediaSessionAction.SEEK_BACKWARD, true ],
[ MediaSessionAction.SEEK_FORWARD, true ], [ MediaSessionAction.SEEK_FORWARD, true ],
[ MediaSessionAction.PLAY, false ],
[ MediaSessionAction.PAUSE, false ],
[ MediaSessionAction.PREVIOUS_TRACK, false ],
[ MediaSessionAction.NEXT_TRACK, false ],
[ MediaSessionAction.SEEK_BACKWARD, false ],
[ MediaSessionAction.SEEK_FORWARD, false ],
]; ];
} }
return expectations; return expectations;
...@@ -55,32 +49,45 @@ async_test(function(t) { ...@@ -55,32 +49,45 @@ async_test(function(t) {
t.done(); t.done();
})); }));
// Setting handlers // Setting handlers should notify the service.
window.navigator.mediaSession.onresize = _ => {}; // Unknown event. window.navigator.mediaSession.setActionHandler("play", _ => {});
window.navigator.mediaSession.onplay = _ => {}; window.navigator.mediaSession.setActionHandler("pause", _ => {});
window.navigator.mediaSession.onpause = _ => {}; window.navigator.mediaSession.setActionHandler("previoustrack", _ => {});
window.navigator.mediaSession.onprevioustrack = _ => {}; window.navigator.mediaSession.setActionHandler("nexttrack", _ => {});
window.navigator.mediaSession.onnexttrack = _ => {}; window.navigator.mediaSession.setActionHandler("seekbackward", _ => {});
window.navigator.mediaSession.onseekbackward = _ => {}; window.navigator.mediaSession.setActionHandler("seekforward", _ => {});
window.navigator.mediaSession.onseekforward = _ => {};
// Setting handlers again should not notify the service.
window.navigator.mediaSession.setActionHandler("play", _ => {});
window.navigator.mediaSession.setActionHandler("pause", _ => {});
window.navigator.mediaSession.setActionHandler("previoustrack", _ => {});
window.navigator.mediaSession.setActionHandler("nexttrack", _ => {});
window.navigator.mediaSession.setActionHandler("seekbackward", _ => {});
window.navigator.mediaSession.setActionHandler("seekforward", _ => {});
// Unsetting handlers should notify the service.
window.navigator.mediaSession.setActionHandler("play", null);
window.navigator.mediaSession.setActionHandler("pause", null);
window.navigator.mediaSession.setActionHandler("previoustrack", null);
window.navigator.mediaSession.setActionHandler("nexttrack", null);
window.navigator.mediaSession.setActionHandler("seekbackward", null);
window.navigator.mediaSession.setActionHandler("seekforward", null);
// Resetting handlers // Unsetting handlers should not notify the service.
window.navigator.mediaSession.onresize = _ => {}; // Unknown event. window.navigator.mediaSession.setActionHandler("play", null);
window.navigator.mediaSession.onplay = _ => {}; window.navigator.mediaSession.setActionHandler("pause", null);
window.navigator.mediaSession.onpause = _ => {}; window.navigator.mediaSession.setActionHandler("previoustrack", null);
window.navigator.mediaSession.onprevioustrack = _ => {}; window.navigator.mediaSession.setActionHandler("nexttrack", null);
window.navigator.mediaSession.onnexttrack = _ => {}; window.navigator.mediaSession.setActionHandler("seekbackward", null);
window.navigator.mediaSession.onseekbackward = _ => {}; window.navigator.mediaSession.setActionHandler("seekforward", null);
window.navigator.mediaSession.onseekforward = _ => {};
// Unsetting handlers // Setting handlers again should notify the service.
window.navigator.mediaSession.onresize = null; // Unknown event. window.navigator.mediaSession.setActionHandler("play", _ => {});
window.navigator.mediaSession.onplay = null; window.navigator.mediaSession.setActionHandler("pause", _ => {});
window.navigator.mediaSession.onpause = null; window.navigator.mediaSession.setActionHandler("previoustrack", _ => {});
window.navigator.mediaSession.onprevioustrack = null; window.navigator.mediaSession.setActionHandler("nexttrack", _ => {});
window.navigator.mediaSession.onnexttrack = null; window.navigator.mediaSession.setActionHandler("seekbackward", _ => {});
window.navigator.mediaSession.onseekbackward = null; window.navigator.mediaSession.setActionHandler("seekforward", _ => {});
window.navigator.mediaSession.onseekforward = null;
}); });
}, "test that setting event handler notifies the mojo service"); }, "test that setting event handler notifies the mojo service");
......
...@@ -3933,21 +3933,10 @@ interface MediaRecorder : EventTarget ...@@ -3933,21 +3933,10 @@ interface MediaRecorder : EventTarget
interface MediaSession : EventTarget interface MediaSession : EventTarget
attribute @@toStringTag attribute @@toStringTag
getter metadata getter metadata
getter onnexttrack
getter onpause
getter onplay
getter onprevioustrack
getter onseekbackward
getter onseekforward
getter playbackState getter playbackState
method constructor method constructor
method setActionHandler
setter metadata setter metadata
setter onnexttrack
setter onpause
setter onplay
setter onprevioustrack
setter onseekbackward
setter onseekforward
setter playbackState setter playbackState
interface MediaSettingsRange interface MediaSettingsRange
attribute @@toStringTag attribute @@toStringTag
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "bindings/modules/v8/V8MediaSession.h"
#include "bindings/core/v8/V8DOMWrapper.h"
#include "modules/mediasession/MediaSession.h"
namespace blink {
void V8MediaSession::visitDOMWrapperCustom(
v8::Isolate* isolate,
ScriptWrappable* scriptWrappable,
const v8::Persistent<v8::Object>& wrapper) {
scriptWrappable->toImpl<MediaSession>()->setV8ReferencesForHandlers(isolate,
wrapper);
}
} // namespace blink
...@@ -9,6 +9,7 @@ bindings_modules_v8_custom_files = ...@@ -9,6 +9,7 @@ bindings_modules_v8_custom_files =
"V8DeviceMotionEventCustom.cpp", "V8DeviceMotionEventCustom.cpp",
"V8ExtendableMessageEventCustom.cpp", "V8ExtendableMessageEventCustom.cpp",
"V8IDBObserverCustom.cpp", "V8IDBObserverCustom.cpp",
"V8MediaSessionCustom.cpp",
"V8RemotePlaybackCustom.cpp", "V8RemotePlaybackCustom.cpp",
"V8WebGLRenderingContextCustom.cpp", "V8WebGLRenderingContextCustom.cpp",
"V8WebGL2RenderingContextCustom.cpp", "V8WebGL2RenderingContextCustom.cpp",
......
...@@ -65,6 +65,8 @@ bindings_modules_generated_union_type_files = [ ...@@ -65,6 +65,8 @@ bindings_modules_generated_union_type_files = [
generated_modules_callback_function_files = [ generated_modules_callback_function_files = [
"$bindings_modules_v8_output_dir/IDBObserverCallback.cpp", "$bindings_modules_v8_output_dir/IDBObserverCallback.cpp",
"$bindings_modules_v8_output_dir/IDBObserverCallback.h", "$bindings_modules_v8_output_dir/IDBObserverCallback.h",
"$bindings_modules_v8_output_dir/MediaSessionActionHandler.cpp",
"$bindings_modules_v8_output_dir/MediaSessionActionHandler.h",
"$bindings_modules_v8_output_dir/RemotePlaybackAvailabilityCallback.cpp", "$bindings_modules_v8_output_dir/RemotePlaybackAvailabilityCallback.cpp",
"$bindings_modules_v8_output_dir/RemotePlaybackAvailabilityCallback.h", "$bindings_modules_v8_output_dir/RemotePlaybackAvailabilityCallback.h",
] ]
......
...@@ -151,7 +151,6 @@ mouseup ...@@ -151,7 +151,6 @@ mouseup
mousewheel mousewheel
mute mute
negotiationneeded negotiationneeded
nexttrack
nomatch nomatch
notificationclick notificationclick
notificationclose notificationclose
...@@ -170,7 +169,6 @@ paymentrequest ...@@ -170,7 +169,6 @@ paymentrequest
periodicsync periodicsync
play play
playing playing
playpause
pointercancel pointercancel
pointerdown pointerdown
pointerenter pointerenter
...@@ -182,7 +180,6 @@ pointerout ...@@ -182,7 +180,6 @@ pointerout
pointerover pointerover
pointerup pointerup
popstate popstate
previoustrack
progress progress
push push
ratechange ratechange
...@@ -200,9 +197,7 @@ resume ...@@ -200,9 +197,7 @@ resume
scroll scroll
search search
securitypolicyviolation securitypolicyviolation
seekbackward
seeked seeked
seekforward
seeking seeking
select select
selectionchange selectionchange
......
...@@ -14,7 +14,6 @@ modules/indexeddb/IDBOpenDBRequest ...@@ -14,7 +14,6 @@ modules/indexeddb/IDBOpenDBRequest
modules/indexeddb/IDBRequest modules/indexeddb/IDBRequest
modules/indexeddb/IDBTransaction modules/indexeddb/IDBTransaction
modules/mediarecorder/MediaRecorder modules/mediarecorder/MediaRecorder
modules/mediasession/MediaSession
modules/mediasource/MediaSource modules/mediasource/MediaSource
modules/mediasource/SourceBuffer modules/mediasource/SourceBuffer
modules/mediasource/SourceBufferList modules/mediasource/SourceBufferList
......
...@@ -4,12 +4,11 @@ ...@@ -4,12 +4,11 @@
#include "modules/mediasession/MediaSession.h" #include "modules/mediasession/MediaSession.h"
#include "bindings/modules/v8/MediaSessionActionHandler.h"
#include "core/dom/Document.h" #include "core/dom/Document.h"
#include "core/dom/DocumentUserGestureToken.h" #include "core/dom/DocumentUserGestureToken.h"
#include "core/dom/ExecutionContext.h" #include "core/dom/ExecutionContext.h"
#include "core/events/Event.h"
#include "core/frame/LocalFrame.h" #include "core/frame/LocalFrame.h"
#include "modules/EventTargetModules.h"
#include "modules/mediasession/MediaMetadata.h" #include "modules/mediasession/MediaMetadata.h"
#include "modules/mediasession/MediaMetadataSanitizer.h" #include "modules/mediasession/MediaMetadataSanitizer.h"
#include "platform/UserGestureIndicator.h" #include "platform/UserGestureIndicator.h"
...@@ -23,39 +22,49 @@ namespace { ...@@ -23,39 +22,49 @@ namespace {
using ::blink::mojom::blink::MediaSessionAction; using ::blink::mojom::blink::MediaSessionAction;
const AtomicString& mojomActionToEventName(MediaSessionAction action) { const AtomicString& mojomActionToActionName(MediaSessionAction action) {
DEFINE_STATIC_LOCAL(const AtomicString, playActionName, ("play"));
DEFINE_STATIC_LOCAL(const AtomicString, pauseActionName, ("pause"));
DEFINE_STATIC_LOCAL(const AtomicString, previousTrackActionName,
("previoustrack"));
DEFINE_STATIC_LOCAL(const AtomicString, nextTrackActionName, ("nexttrack"));
DEFINE_STATIC_LOCAL(const AtomicString, seekBackwardActionName,
("seekbackward"));
DEFINE_STATIC_LOCAL(const AtomicString, seekForwardActionName,
("seekforward"));
switch (action) { switch (action) {
case MediaSessionAction::PLAY: case MediaSessionAction::PLAY:
return EventTypeNames::play; return playActionName;
case MediaSessionAction::PAUSE: case MediaSessionAction::PAUSE:
return EventTypeNames::pause; return pauseActionName;
case MediaSessionAction::PREVIOUS_TRACK: case MediaSessionAction::PREVIOUS_TRACK:
return EventTypeNames::previoustrack; return previousTrackActionName;
case MediaSessionAction::NEXT_TRACK: case MediaSessionAction::NEXT_TRACK:
return EventTypeNames::nexttrack; return nextTrackActionName;
case MediaSessionAction::SEEK_BACKWARD: case MediaSessionAction::SEEK_BACKWARD:
return EventTypeNames::seekbackward; return seekBackwardActionName;
case MediaSessionAction::SEEK_FORWARD: case MediaSessionAction::SEEK_FORWARD:
return EventTypeNames::seekforward; return seekForwardActionName;
default: default:
NOTREACHED(); NOTREACHED();
} }
return WTF::emptyAtom; return WTF::emptyAtom;
} }
WTF::Optional<MediaSessionAction> eventNameToMojomAction( WTF::Optional<MediaSessionAction> actionNameToMojomAction(
const AtomicString& eventName) { const String& actionName) {
if (EventTypeNames::play == eventName) if ("play" == actionName)
return MediaSessionAction::PLAY; return MediaSessionAction::PLAY;
if (EventTypeNames::pause == eventName) if ("pause" == actionName)
return MediaSessionAction::PAUSE; return MediaSessionAction::PAUSE;
if (EventTypeNames::previoustrack == eventName) if ("previoustrack" == actionName)
return MediaSessionAction::PREVIOUS_TRACK; return MediaSessionAction::PREVIOUS_TRACK;
if (EventTypeNames::nexttrack == eventName) if ("nexttrack" == actionName)
return MediaSessionAction::NEXT_TRACK; return MediaSessionAction::NEXT_TRACK;
if (EventTypeNames::seekbackward == eventName) if ("seekbackward" == actionName)
return MediaSessionAction::SEEK_BACKWARD; return MediaSessionAction::SEEK_BACKWARD;
if (EventTypeNames::seekforward == eventName) if ("seekforward" == actionName)
return MediaSessionAction::SEEK_FORWARD; return MediaSessionAction::SEEK_FORWARD;
NOTREACHED(); NOTREACHED();
...@@ -140,12 +149,43 @@ void MediaSession::onMetadataChanged() { ...@@ -140,12 +149,43 @@ void MediaSession::onMetadataChanged() {
m_metadata, getExecutionContext())); m_metadata, getExecutionContext()));
} }
const WTF::AtomicString& MediaSession::interfaceName() const { void MediaSession::setActionHandler(const String& action,
return EventTargetNames::MediaSession; MediaSessionActionHandler* handler) {
if (handler) {
auto addResult = m_actionHandlers.set(
action, TraceWrapperMember<MediaSessionActionHandler>(this, handler));
if (!addResult.isNewEntry)
return;
notifyActionChange(action, ActionChangeType::ActionEnabled);
} else {
if (m_actionHandlers.find(action) == m_actionHandlers.end())
return;
m_actionHandlers.remove(action);
notifyActionChange(action, ActionChangeType::ActionDisabled);
}
} }
ExecutionContext* MediaSession::getExecutionContext() const { void MediaSession::notifyActionChange(const String& action,
return ContextClient::getExecutionContext(); ActionChangeType type) {
mojom::blink::MediaSessionService* service = getService();
if (!service)
return;
auto mojomAction = actionNameToMojomAction(action);
DCHECK(mojomAction.has_value());
switch (type) {
case ActionChangeType::ActionEnabled:
service->EnableAction(mojomAction.value());
break;
case ActionChangeType::ActionDisabled:
service->DisableAction(mojomAction.value());
break;
}
} }
mojom::blink::MediaSessionService* MediaSession::getService() { mojom::blink::MediaSessionService* MediaSession::getService() {
...@@ -171,43 +211,36 @@ mojom::blink::MediaSessionService* MediaSession::getService() { ...@@ -171,43 +211,36 @@ mojom::blink::MediaSessionService* MediaSession::getService() {
return m_service.get(); return m_service.get();
} }
bool MediaSession::addEventListenerInternal(
const AtomicString& eventType,
EventListener* listener,
const AddEventListenerOptionsResolved& options) {
if (mojom::blink::MediaSessionService* service = getService()) {
auto mojomAction = eventNameToMojomAction(eventType);
DCHECK(mojomAction.has_value());
service->EnableAction(mojomAction.value());
}
return EventTarget::addEventListenerInternal(eventType, listener, options);
}
bool MediaSession::removeEventListenerInternal(
const AtomicString& eventType,
const EventListener* listener,
const EventListenerOptions& options) {
if (mojom::blink::MediaSessionService* service = getService()) {
auto mojomAction = eventNameToMojomAction(eventType);
DCHECK(mojomAction.has_value());
service->DisableAction(mojomAction.value());
}
return EventTarget::removeEventListenerInternal(eventType, listener, options);
}
void MediaSession::DidReceiveAction( void MediaSession::DidReceiveAction(
blink::mojom::blink::MediaSessionAction action) { blink::mojom::blink::MediaSessionAction action) {
DCHECK(getExecutionContext()->isDocument()); DCHECK(getExecutionContext()->isDocument());
Document* document = toDocument(getExecutionContext()); Document* document = toDocument(getExecutionContext());
UserGestureIndicator gestureIndicator( UserGestureIndicator gestureIndicator(
DocumentUserGestureToken::create(document)); DocumentUserGestureToken::create(document));
dispatchEvent(Event::create(mojomActionToEventName(action)));
auto iter = m_actionHandlers.find(mojomActionToActionName(action));
if (iter == m_actionHandlers.end())
return;
iter->value->call(this);
}
void MediaSession::setV8ReferencesForHandlers(
v8::Isolate* isolate,
const v8::Persistent<v8::Object>& wrapper) {
for (auto handler : m_actionHandlers.values())
handler->setWrapperReference(isolate, wrapper);
} }
DEFINE_TRACE(MediaSession) { DEFINE_TRACE(MediaSession) {
visitor->trace(m_metadata); visitor->trace(m_metadata);
EventTargetWithInlineData::trace(visitor); visitor->trace(m_actionHandlers);
ContextClient::trace(visitor); ContextClient::trace(visitor);
} }
DEFINE_TRACE_WRAPPERS(MediaSession) {
for (auto handler : m_actionHandlers.values())
visitor->traceWrappers(handler);
}
} // namespace blink } // namespace blink
...@@ -6,22 +6,25 @@ ...@@ -6,22 +6,25 @@
#define MediaSession_h #define MediaSession_h
#include "bindings/core/v8/ScriptWrappable.h" #include "bindings/core/v8/ScriptWrappable.h"
#include "bindings/core/v8/TraceWrapperMember.h"
#include "core/dom/ContextLifecycleObserver.h" #include "core/dom/ContextLifecycleObserver.h"
#include "core/events/EventTarget.h"
#include "modules/ModulesExport.h" #include "modules/ModulesExport.h"
#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding.h"
#include "platform/heap/Handle.h" #include "platform/heap/Handle.h"
#include "public/platform/modules/mediasession/media_session.mojom-blink.h" #include "public/platform/modules/mediasession/media_session.mojom-blink.h"
#include "wtf/text/WTFString.h"
#include <memory> #include <memory>
namespace blink { namespace blink {
class ExecutionContext; class ExecutionContext;
class MediaMetadata; class MediaMetadata;
class MediaSessionActionHandler;
class MODULES_EXPORT MediaSession final class MODULES_EXPORT MediaSession final
: public EventTargetWithInlineData, : public GarbageCollectedFinalized<MediaSession>,
public ContextClient, public ContextClient,
public ScriptWrappable,
blink::mojom::blink::MediaSessionClient { blink::mojom::blink::MediaSessionClient {
USING_GARBAGE_COLLECTED_MIXIN(MediaSession); USING_GARBAGE_COLLECTED_MIXIN(MediaSession);
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
...@@ -38,45 +41,41 @@ class MODULES_EXPORT MediaSession final ...@@ -38,45 +41,41 @@ class MODULES_EXPORT MediaSession final
void setMetadata(MediaMetadata*); void setMetadata(MediaMetadata*);
MediaMetadata* metadata() const; MediaMetadata* metadata() const;
// EventTarget implementation. void setActionHandler(const String& action, MediaSessionActionHandler*);
const WTF::AtomicString& interfaceName() const override;
ExecutionContext* getExecutionContext() const override;
// Called by the MediaMetadata owned by |this| when it has updates. Also used // Called by the MediaMetadata owned by |this| when it has updates. Also used
// internally when a new MediaMetadata object is set. // internally when a new MediaMetadata object is set.
void onMetadataChanged(); void onMetadataChanged();
DEFINE_ATTRIBUTE_EVENT_LISTENER(play);
DEFINE_ATTRIBUTE_EVENT_LISTENER(pause);
DEFINE_ATTRIBUTE_EVENT_LISTENER(previoustrack);
DEFINE_ATTRIBUTE_EVENT_LISTENER(nexttrack);
DEFINE_ATTRIBUTE_EVENT_LISTENER(seekforward);
DEFINE_ATTRIBUTE_EVENT_LISTENER(seekbackward);
DECLARE_VIRTUAL_TRACE(); DECLARE_VIRTUAL_TRACE();
DECLARE_VIRTUAL_TRACE_WRAPPERS();
private: private:
friend class V8MediaSession;
friend class MediaSessionTest; friend class MediaSessionTest;
enum class ActionChangeType {
ActionEnabled,
ActionDisabled,
};
explicit MediaSession(ExecutionContext*); explicit MediaSession(ExecutionContext*);
// EventTarget overrides void notifyActionChange(const String& action, ActionChangeType);
bool addEventListenerInternal(
const AtomicString& eventType,
EventListener*,
const AddEventListenerOptionsResolved&) override;
bool removeEventListenerInternal(const AtomicString& eventType,
const EventListener*,
const EventListenerOptions&) override;
// blink::mojom::blink::MediaSessionClient implementation. // blink::mojom::blink::MediaSessionClient implementation.
void DidReceiveAction(blink::mojom::blink::MediaSessionAction) override; void DidReceiveAction(blink::mojom::blink::MediaSessionAction) override;
void setV8ReferencesForHandlers(v8::Isolate*,
const v8::Persistent<v8::Object>& wrapper);
// Returns null when the ExecutionContext is not document. // Returns null when the ExecutionContext is not document.
mojom::blink::MediaSessionService* getService(); mojom::blink::MediaSessionService* getService();
mojom::blink::MediaSessionPlaybackState m_playbackState; mojom::blink::MediaSessionPlaybackState m_playbackState;
Member<MediaMetadata> m_metadata; Member<MediaMetadata> m_metadata;
HeapHashMap<String, TraceWrapperMember<MediaSessionActionHandler>>
m_actionHandlers;
mojom::blink::MediaSessionServicePtr m_service; mojom::blink::MediaSessionServicePtr m_service;
mojo::Binding<blink::mojom::blink::MediaSessionClient> m_clientBinding; mojo::Binding<blink::mojom::blink::MediaSessionClient> m_clientBinding;
}; };
......
...@@ -12,17 +12,24 @@ enum MediaSessionPlaybackState { ...@@ -12,17 +12,24 @@ enum MediaSessionPlaybackState {
// https://wicg.github.io/mediasession/#the-mediasession-interface // https://wicg.github.io/mediasession/#the-mediasession-interface
enum MediaSessionAction {
"play",
"pause",
"previoustrack",
"nexttrack",
"seekbackward",
"seekforward"
};
callback MediaSessionActionHandler = void ();
[ [
Custom=VisitDOMWrapper,
RuntimeEnabled=MediaSession, RuntimeEnabled=MediaSession,
] interface MediaSession : EventTarget { ] interface MediaSession : EventTarget {
attribute MediaMetadata? metadata; attribute MediaMetadata? metadata;
attribute MediaSessionPlaybackState playbackState; attribute MediaSessionPlaybackState playbackState;
attribute EventHandler onplay; void setActionHandler(MediaSessionAction action,
attribute EventHandler onpause; MediaSessionActionHandler? handler);
attribute EventHandler onprevioustrack;
attribute EventHandler onnexttrack;
attribute EventHandler onseekforward;
attribute EventHandler onseekbackward;
}; };
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include "modules/mediasession/NavigatorMediaSession.h" #include "modules/mediasession/NavigatorMediaSession.h"
#include "bindings/core/v8/ExceptionStatePlaceholder.h" #include "bindings/core/v8/ScriptState.h"
#include "modules/mediasession/MediaSession.h" #include "modules/mediasession/MediaSession.h"
#include "platform/Supplementable.h" #include "platform/Supplementable.h"
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
namespace blink { namespace blink {
class Navigator; class Navigator;
class ScriptState;
// Provides MediaSession as a supplement of Navigator as an attribute. // Provides MediaSession as a supplement of Navigator as an attribute.
class NavigatorMediaSession final class NavigatorMediaSession final
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment