Introduce embedder MediaSessionEvent and move active session to Servo

This commit is contained in:
Fernando Jiménez Moreno 2019-10-09 12:16:35 +02:00
parent 4d147d2c56
commit 89d9e3ad78
9 changed files with 90 additions and 61 deletions

View file

@ -1778,9 +1778,6 @@ where
new_value,
);
},
FromScriptMsg::MediaSessionEventMsg(browser_id, event) => {
// TODO
},
}
}

View file

@ -162,9 +162,9 @@ pub enum EmbedderMsg {
Shutdown,
/// Report a complete sampled profile
ReportProfile(Vec<u8>),
/// Sent when a media session is activated or deactivated.
/// There can only be a single active media session.
MediaSession(bool),
/// Notifies the embedder about media session events
/// (i.e. when there is metadata for the active media session, playback state changes...).
MediaSessionEvent(MediaSessionEvent),
}
impl Debug for EmbedderMsg {
@ -197,7 +197,7 @@ impl Debug for EmbedderMsg {
EmbedderMsg::AllowOpeningBrowser(..) => write!(f, "AllowOpeningBrowser"),
EmbedderMsg::BrowserCreated(..) => write!(f, "BrowserCreated"),
EmbedderMsg::ReportProfile(..) => write!(f, "ReportProfile"),
EmbedderMsg::MediaSession(..) => write!(f, "MediaSession"),
EmbedderMsg::MediaSessionEvent(..) => write!(f, "MediaSessionEvent"),
}
}
}
@ -206,3 +206,34 @@ impl Debug for EmbedderMsg {
/// the `String` content is expected to be extension (e.g, "doc", without the prefixing ".")
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct FilterPattern(pub String);
/// 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 its 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 embedder 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),
}

View file

@ -67,6 +67,7 @@ use crate::script_thread::ScriptThread;
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use embedder_traits::resources::{self, Resource as EmbedderResource};
use embedder_traits::{MediaMetadata, MediaSessionEvent};
use euclid::default::Size2D;
use headers::{ContentLength, ContentRange, HeaderMapExt};
use html5ever::{LocalName, Prefix};
@ -80,7 +81,6 @@ 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};
@ -1727,6 +1727,14 @@ impl HTMLMediaElement {
if self.Controls() {
self.render_controls();
}
// Send a media session event with the obtained metadata.
self.send_media_session_event(MediaSessionEvent::SetMetadata(MediaMetadata {
// TODO(ferjm) set url if no title.
title: metadata.title.clone().unwrap_or("".to_string()),
artist: None,
album: None,
}));
},
PlayerEvent::NeedData => {
// The player needs more data.

View file

@ -16,8 +16,9 @@ use crate::dom::mediametadata::MediaMetadata;
use crate::dom::window::Window;
use crate::script_thread::ScriptThread;
use dom_struct::dom_struct;
use embedder_traits::{EmbedderMsg, MediaSessionEvent};
use msg::constellation_msg::TopLevelBrowsingContextId;
use script_traits::{MediaSessionActionType, MediaSessionEvent, ScriptMsg};
use script_traits::MediaSessionActionType;
use std::collections::HashMap;
use std::rc::Rc;
@ -71,14 +72,8 @@ impl MediaSession {
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();
let window = global.as_window();
window.send_to_embedder(EmbedderMsg::MediaSessionEvent(event));
}
}

View file

@ -1087,34 +1087,3 @@ 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 its 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),
}

View file

@ -255,9 +255,6 @@ 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 {
@ -309,7 +306,6 @@ impl fmt::Debug for ScriptMsg {
GetClientWindow(..) => "GetClientWindow",
GetScreenSize(..) => "GetScreenSize",
GetScreenAvailSize(..) => "GetScreenAvailSize",
MediaSessionEventMsg(..) => "MediaSessionEventMsg",
};
write!(formatter, "ScriptMsg::{}", variant)
}

View file

@ -83,6 +83,7 @@ use constellation::{Constellation, InitialConstellationState, UnprivilegedPipeli
use constellation::{FromCompositorLogger, FromScriptLogger};
use crossbeam_channel::{unbounded, Sender};
use embedder_traits::{EmbedderMsg, EmbedderProxy, EmbedderReceiver, EventLoopWaker};
use embedder_traits::{MediaSessionEvent, MediaSessionPlaybackState};
use env_logger::Builder as EnvLoggerBuilder;
use euclid::{Scale, Size2D};
#[cfg(all(
@ -270,6 +271,9 @@ pub struct Servo<Window: WindowMethods + 'static + ?Sized> {
embedder_receiver: EmbedderReceiver,
embedder_events: Vec<(Option<BrowserId>, EmbedderMsg)>,
profiler_enabled: bool,
webgl_thread_data: Option<Rc<WebGLMainThread>>,
/// Browser ID of the active media session, if any.
active_media_session: Option<BrowserId>,
}
#[derive(Clone)]
@ -555,6 +559,8 @@ where
embedder_receiver: embedder_receiver,
embedder_events: Vec::new(),
profiler_enabled: false,
webgl_thread_data,
active_media_session: None,
}
}
@ -744,6 +750,31 @@ where
self.embedder_events.push(event);
},
(EmbedderMsg::MediaSessionEvent(event), ShutdownState::NotShuttingDown) => {
// Unlikely at this point, but we may receive events coming from
// different media sessions, so we set the active media session based
// on Playing events.
// The last media session claiming to be in playing state is set to
// the active media session.
// Events coming from inactive media sessions are discarded.
if self.active_media_session.is_some() {
match event {
MediaSessionEvent::PlaybackStateChange(ref state) => {
match state {
MediaSessionPlaybackState::Playing => (),
_ => return,
};
},
_ => (),
};
}
self.active_media_session = top_level_browsing_context;
self.embedder_events.push((
top_level_browsing_context,
EmbedderMsg::MediaSessionEvent(event),
));
},
(msg, ShutdownState::NotShuttingDown) => {
self.embedder_events.push((top_level_browsing_context, msg));
},