From 274d4d2303fa2986da356dd2d05adcb48d796a2a Mon Sep 17 00:00:00 2001 From: Shinichi Morimoto Date: Wed, 27 Nov 2019 15:17:24 +0900 Subject: [PATCH] implement MediaSession.setPositionState method --- components/script/dom/htmlmediaelement.rs | 12 ++++ components/script/dom/mediasession.rs | 59 +++++++++++++++++++ .../script/dom/webidls/MediaSession.webidl | 9 ++- 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index f8f707a0dd9c..0780a81e2e6d 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -1925,6 +1925,18 @@ impl HTMLMediaElement { media_session.send_event(event); } + + pub fn set_duration(&self, duration: f64) { + self.duration.set(duration); + } + + pub fn reset(&self) { + if let Some(ref player) = *self.player.borrow() { + if let Err(e) = player.lock().unwrap().stop() { + eprintln!("Could not stop player {:?}", e); + } + } + } } // 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 1523e9a0ae60..8dfc88a1c04d 100644 --- a/components/script/dom/mediasession.rs +++ b/components/script/dom/mediasession.rs @@ -9,10 +9,13 @@ use crate::dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaE use crate::dom::bindings::codegen::Bindings::MediaMetadataBinding::MediaMetadataInit; use crate::dom::bindings::codegen::Bindings::MediaMetadataBinding::MediaMetadataMethods; use crate::dom::bindings::codegen::Bindings::MediaSessionBinding; +use crate::dom::bindings::codegen::Bindings::MediaSessionBinding::MediaPositionState; use crate::dom::bindings::codegen::Bindings::MediaSessionBinding::MediaSessionAction; use crate::dom::bindings::codegen::Bindings::MediaSessionBinding::MediaSessionActionHandler; use crate::dom::bindings::codegen::Bindings::MediaSessionBinding::MediaSessionMethods; use crate::dom::bindings::codegen::Bindings::MediaSessionBinding::MediaSessionPlaybackState; +use crate::dom::bindings::error::{Error, Fallible}; +use crate::dom::bindings::num::Finite; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::{DomRoot, MutNullableDom}; use crate::dom::bindings::str::DOMString; @@ -194,6 +197,62 @@ impl MediaSessionMethods for MediaSession { None => self.action_handlers.borrow_mut().remove(&action.into()), }; } + + /// https://w3c.github.io/mediasession/#dom-mediasession-setpositionstate + fn SetPositionState(&self, state: &MediaPositionState) -> Fallible<()> { + // If the state is an empty dictionary then clear the position state. + if state.duration.is_none() && state.position.is_none() && state.playbackRate.is_none() { + if let Some(media_instance) = self.media_instance.get() { + media_instance.reset(); + } + return Ok(()); + } + + // If the duration is not present or its value is null, throw a TypeError. + if state.duration.is_none() { + return Err(Error::Type( + "duration is not present or its value is null".to_owned(), + )); + } + + // If the duration is negative, throw a TypeError. + if let Some(state_duration) = state.duration { + if *state_duration < 0.0 { + return Err(Error::Type("duration is negative".to_owned())); + } + } + + // If the position is negative or greater than duration, throw a TypeError. + if let Some(state_position) = state.position { + if *state_position < 0.0 { + return Err(Error::Type("position is negative".to_owned())); + } + if let Some(state_duration) = state.duration { + if *state_position > *state_duration { + return Err(Error::Type("position is greater than duration".to_owned())); + } + } + } + + // If the playbackRate is zero throw a TypeError. + if let Some(state_playback_rate) = state.playbackRate { + if *state_playback_rate <= 0.0 { + return Err(Error::Type("playbackRate is zero".to_owned())); + } + } + + // Update the position state and last position updated time. + if let Some(media_instance) = self.media_instance.get() { + media_instance.set_duration(state.duration.map(|v| *v).unwrap()); + // If the playbackRate is not present or its value is null, set it to 1.0. + let _ = + media_instance.SetPlaybackRate(state.playbackRate.unwrap_or(Finite::wrap(1.0)))?; + // If the position is not present or its value is null, set it to zero. + media_instance.SetCurrentTime(state.position.unwrap_or(Finite::wrap(0.0))); + } + + Ok(()) + } } impl From for MediaSessionActionType { diff --git a/components/script/dom/webidls/MediaSession.webidl b/components/script/dom/webidls/MediaSession.webidl index 12b3fe062baa..2680ea0c40b6 100644 --- a/components/script/dom/webidls/MediaSession.webidl +++ b/components/script/dom/webidls/MediaSession.webidl @@ -42,6 +42,12 @@ dictionary MediaSessionSeekToActionDetails : MediaSessionActionDetails { boolean? fastSeek; }; +dictionary MediaPositionState { + double duration; + double playbackRate; + double position; +}; + callback MediaSessionActionHandler = void(/*MediaSessionActionDetails details*/); [Exposed=Window] @@ -52,6 +58,5 @@ interface MediaSession { void setActionHandler(MediaSessionAction action, MediaSessionActionHandler? handler); - //void setPositionState(optional MediaPositionState? state); + [Throws] void setPositionState(optional MediaPositionState state = {}); }; -