aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFernando Jiménez Moreno <ferjmoreno@gmail.com>2019-10-08 10:18:13 +0200
committerFernando Jiménez Moreno <ferjmoreno@gmail.com>2019-11-20 13:33:14 +0100
commit4d147d2c56465405e7c3281073ef57fe1bd1c062 (patch)
tree7098eaa3bcccf06c44696023352eec78736b7027
parent9c329a79354cb8b6c1000aa7c78364a5541de421 (diff)
downloadservo-4d147d2c56465405e7c3281073ef57fe1bd1c062.tar.gz
servo-4d147d2c56465405e7c3281073ef57fe1bd1c062.zip
Register media instance with session and prepare communication with embedder
-rw-r--r--components/constellation/constellation.rs7
-rw-r--r--components/script/dom/htmlmediaelement.rs10
-rw-r--r--components/script/dom/mediasession.rs19
-rw-r--r--components/script/dom/navigator.rs22
-rw-r--r--components/script/script_thread.rs13
-rw-r--r--components/script_traits/lib.rs31
-rw-r--r--components/script_traits/script_msg.rs5
-rw-r--r--ports/glutin/browser.rs4
8 files changed, 107 insertions, 4 deletions
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs
index 8f549ea685e..8b0a7b073a3 100644
--- a/components/constellation/constellation.rs
+++ b/components/constellation/constellation.rs
@@ -474,6 +474,9 @@ pub struct Constellation<Message, LTF, STF> {
/// Mechanism to force the compositor to process events.
event_loop_waker: Option<Box<dyn EventLoopWaker>>,
+
+ /// Browser ID of the active media session, if any.
+ active_media_session: Option<TopLevelBrowsingContextId>,
}
/// State needed to construct a constellation.
@@ -843,6 +846,7 @@ where
glplayer_threads: state.glplayer_threads,
player_context: state.player_context,
event_loop_waker: state.event_loop_waker,
+ active_media_session: None,
};
constellation.run();
@@ -1774,6 +1778,9 @@ where
new_value,
);
},
+ FromScriptMsg::MediaSessionEventMsg(browser_id, event) => {
+ // TODO
+ },
}
}
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index d10801c5779..c816a69ca1a 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -15,8 +15,10 @@ use crate::dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaE
use crate::dom::bindings::codegen::Bindings::HTMLSourceElementBinding::HTMLSourceElementMethods;
use crate::dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorConstants::*;
use crate::dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorMethods;
+use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorBinding::NavigatorMethods;
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeBinding::NodeMethods;
use crate::dom::bindings::codegen::Bindings::TextTrackBinding::{TextTrackKind, TextTrackMode};
+use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use crate::dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId};
use crate::dom::bindings::codegen::InheritTypes::{HTMLMediaElementTypeId, NodeTypeId};
use crate::dom::bindings::codegen::UnionTypes::{
@@ -78,6 +80,7 @@ use net_traits::request::{Destination, Referrer};
use net_traits::{CoreResourceMsg, FetchChannels, FetchMetadata, FetchResponseListener, Metadata};
use net_traits::{NetworkError, ResourceFetchTiming, ResourceTimingType};
use script_layout_interface::HTMLMediaData;
+use script_traits::MediaSessionEvent;
use servo_config::pref;
use servo_media::player::audio::AudioRenderer;
use servo_media::player::video::{VideoFrame, VideoFrameRenderer};
@@ -592,7 +595,6 @@ impl HTMLMediaElement {
match (old_ready_state, ready_state) {
(ReadyState::HaveNothing, ReadyState::HaveMetadata) => {
task_source.queue_simple_event(self.upcast(), atom!("loadedmetadata"), &window);
-
// No other steps are applicable in this case.
return;
},
@@ -1883,6 +1885,12 @@ impl HTMLMediaElement {
self.media_element_load_algorithm();
}
}
+
+ fn send_media_session_event(&self, event: MediaSessionEvent) {
+ let global = self.global();
+ let media_session = global.as_window().Navigator().MediaSession();
+ media_session.send_event(event);
+ }
}
// XXX Placeholder for [https://github.com/servo/servo/issues/22293]
diff --git a/components/script/dom/mediasession.rs b/components/script/dom/mediasession.rs
index 139264953ca..f87b0dbee63 100644
--- a/components/script/dom/mediasession.rs
+++ b/components/script/dom/mediasession.rs
@@ -11,12 +11,13 @@ use crate::dom::bindings::codegen::Bindings::MediaSessionBinding::MediaSessionMe
use crate::dom::bindings::codegen::Bindings::MediaSessionBinding::MediaSessionPlaybackState;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
+use crate::dom::htmlmediaelement::HTMLMediaElement;
use crate::dom::mediametadata::MediaMetadata;
use crate::dom::window::Window;
use crate::script_thread::ScriptThread;
use dom_struct::dom_struct;
use msg::constellation_msg::TopLevelBrowsingContextId;
-use script_traits::MediaSessionActionType;
+use script_traits::{MediaSessionActionType, MediaSessionEvent, ScriptMsg};
use std::collections::HashMap;
use std::rc::Rc;
@@ -30,6 +31,9 @@ pub struct MediaSession {
/// https://w3c.github.io/mediasession/#supported-media-session-actions
#[ignore_malloc_size_of = "Rc"]
action_handlers: DomRefCell<HashMap<MediaSessionActionType, Rc<MediaSessionActionHandler>>>,
+ /// The media instance controlled by this media session.
+ /// For now only HTMLMediaElements are controlled by media sessions.
+ media_instance: MutNullableDom<HTMLMediaElement>,
}
impl MediaSession {
@@ -40,6 +44,7 @@ impl MediaSession {
metadata: Default::default(),
playback_state: DomRefCell::new(MediaSessionPlaybackState::None),
action_handlers: DomRefCell::new(HashMap::new()),
+ media_instance: Default::default(),
};
ScriptThread::register_media_session(&media_session, browsing_context_id);
media_session
@@ -63,6 +68,18 @@ impl MediaSession {
}
// TODO default action.
}
+
+ pub fn send_event(&self, event: MediaSessionEvent) {
+ let global = self.global();
+ let browser_id = global
+ .as_window()
+ .window_proxy()
+ .top_level_browsing_context_id();
+ let _ = global
+ .script_to_constellation_chan()
+ .send(ScriptMsg::MediaSessionEventMsg(browser_id, event))
+ .unwrap();
+ }
}
impl MediaSessionMethods for MediaSession {
diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs
index 2b0d0ab128b..a759d3dbe54 100644
--- a/components/script/dom/navigator.rs
+++ b/components/script/dom/navigator.rs
@@ -21,6 +21,7 @@ use crate::dom::promise::Promise;
use crate::dom::serviceworkercontainer::ServiceWorkerContainer;
use crate::dom::window::Window;
use crate::dom::xr::XR;
+use crate::script_thread::ScriptThread;
use dom_struct::dom_struct;
use std::rc::Rc;
@@ -192,7 +193,24 @@ impl NavigatorMethods for Navigator {
/// https://w3c.github.io/mediasession/#dom-navigator-mediasession
fn MediaSession(&self) -> DomRoot<MediaSession> {
- self.mediasession
- .or_init(|| MediaSession::new(self.global().as_window()))
+ self.mediasession.or_init(|| {
+ // There is a single MediaSession instance per top level browsing context
+ // and only one active MediaSession globally.
+ //
+ // MediaSession creation can happen in two cases:
+ //
+ // - If content gets `navigator.mediaSession`
+ // - If a media instance (HTMLMediaElement so far) starts playing media.
+ //
+ // The MediaSession constructor is in charge of registering itself with
+ // the script thread.
+ let global = self.global();
+ let window = global.as_window();
+ let browsing_context_id = window.window_proxy().top_level_browsing_context_id();
+ match ScriptThread::get_media_session(browsing_context_id) {
+ Some(session) => session,
+ None => MediaSession::new(window),
+ }
+ })
}
}
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index ec1f5852060..e7b39d26420 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -3993,6 +3993,19 @@ impl ScriptThread {
.remove(&browsing_context_id);
})
}
+
+ pub fn get_media_session(
+ browsing_context_id: TopLevelBrowsingContextId,
+ ) -> Option<DomRoot<MediaSession>> {
+ SCRIPT_THREAD_ROOT.with(|root| {
+ let script_thread = unsafe { &*root.get().unwrap() };
+ script_thread
+ .media_sessions
+ .borrow()
+ .get(&browsing_context_id)
+ .map(|s| DomRoot::from_ref(&**s))
+ })
+ }
}
impl Drop for ScriptThread {
diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs
index b4b85889ea0..f5006f1df6f 100644
--- a/components/script_traits/lib.rs
+++ b/components/script_traits/lib.rs
@@ -1087,3 +1087,34 @@ pub enum MediaSessionActionType {
/// The action intent is to move the playback time to a specific time.
SeekTo,
}
+
+/// https://w3c.github.io/mediasession/#mediametadata
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct MediaMetadata {
+ /// Title
+ pub title: String,
+ /// Artist
+ pub artist: Option<String>,
+ /// Album
+ pub album: Option<String>,
+}
+
+/// https://w3c.github.io/mediasession/#enumdef-mediasessionplaybackstate
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub enum MediaSessionPlaybackState {
+ /// The browsing context does not specify whether it’s playing or paused.
+ None_,
+ /// The browsing context has paused media and it can be resumed.
+ Playing,
+ /// The browsing context is currently playing media and it can be paused.
+ Paused,
+}
+
+/// Type of events sent from script to the constellation about the media session.
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub enum MediaSessionEvent {
+ /// Indicates that the media metadata is available.
+ SetMetadata(MediaMetadata),
+ /// Indicates that the playback state has changed.
+ PlaybackStateChange(MediaSessionPlaybackState),
+}
diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs
index a12101380c9..df1889ab6b2 100644
--- a/components/script_traits/script_msg.rs
+++ b/components/script_traits/script_msg.rs
@@ -8,6 +8,7 @@ use crate::DocumentState;
use crate::IFrameLoadInfoWithData;
use crate::LayoutControlMsg;
use crate::LoadData;
+use crate::MediaSessionEvent;
use crate::MessagePortMsg;
use crate::PortMessageTask;
use crate::StructuredSerializedData;
@@ -254,6 +255,9 @@ pub enum ScriptMsg {
GetScreenSize(IpcSender<DeviceIntSize>),
/// Get the available screen size (pixel)
GetScreenAvailSize(IpcSender<DeviceIntSize>),
+ /// Notifies the constellation about media session events
+ /// (i.e. when there is metadata for the active media session, playback state changes...).
+ MediaSessionEventMsg(TopLevelBrowsingContextId, MediaSessionEvent),
}
impl fmt::Debug for ScriptMsg {
@@ -305,6 +309,7 @@ impl fmt::Debug for ScriptMsg {
GetClientWindow(..) => "GetClientWindow",
GetScreenSize(..) => "GetScreenSize",
GetScreenAvailSize(..) => "GetScreenAvailSize",
+ MediaSessionEventMsg(..) => "MediaSessionEventMsg",
};
write!(formatter, "ScriptMsg::{}", variant)
}
diff --git a/ports/glutin/browser.rs b/ports/glutin/browser.rs
index e3da4d13d61..95bea1e72bb 100644
--- a/ports/glutin/browser.rs
+++ b/ports/glutin/browser.rs
@@ -449,6 +449,10 @@ where
error!("Failed to store profile: {}", e);
}
},
+ EmbedderMsg::MediaSession(_) => {
+ debug!("MediaSession received");
+ // TODO(ferjm)
+ },
}
}
}