aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2019-12-03 12:13:06 -0500
committerGitHub <noreply@github.com>2019-12-03 12:13:06 -0500
commitf31a88d85de2a7bdee65216b3b66b697b459a31d (patch)
tree05d957e792a1e3651c2b775a76327e1898544596 /components/script/dom
parent54d88fd042d3d1d382b36bf5d53308dabc35991d (diff)
parent41ff93eca2bf3e8a15d99fedbf7da3a7f9af638a (diff)
downloadservo-f31a88d85de2a7bdee65216b3b66b697b459a31d.tar.gz
servo-f31a88d85de2a7bdee65216b3b66b697b459a31d.zip
Auto merge of #24885 - shnmorimoto:implement_mediasession_set_positon_state, r=ferjm
Implement mediasession set positon state <!-- Please describe your changes on the following line: --> fix #24808 > Bonus points if you want to tweak the existing UI by adding a progress bar, and the info about the current position and total duration. I haven't implemented this yet. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #24808 (GitHub issue number if applicable) <!-- Either: --> - [x] There are tests for these changes OR <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/htmlmediaelement.rs23
-rw-r--r--components/script/dom/mediasession.rs59
-rw-r--r--components/script/dom/webidls/MediaSession.webidl9
3 files changed, 88 insertions, 3 deletions
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index 651084cfb84..91acd4b97e7 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -67,7 +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::{MediaSessionEvent, MediaSessionPlaybackState};
+use embedder_traits::{MediaPositionState, MediaSessionEvent, MediaSessionPlaybackState};
use euclid::default::Size2D;
use headers::{ContentLength, ContentRange, HeaderMapExt};
use html5ever::{LocalName, Prefix};
@@ -1780,6 +1780,15 @@ impl HTMLMediaElement {
.add(self.playback_position.get(), position);
self.playback_position.set(position);
self.time_marches_on();
+ let media_position_state =
+ MediaPositionState::new(self.duration.get(), self.playbackRate.get(), position);
+ debug!(
+ "Sending media session event set position state {:?}",
+ media_position_state
+ );
+ self.send_media_session_event(MediaSessionEvent::SetPositionState(
+ media_position_state,
+ ));
},
PlayerEvent::SeekData(p, ref seek_lock) => {
self.fetch_request(Some(p), Some(seek_lock.clone()));
@@ -1925,6 +1934,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 1523e9a0ae6..8dfc88a1c04 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<MediaSessionAction> for MediaSessionActionType {
diff --git a/components/script/dom/webidls/MediaSession.webidl b/components/script/dom/webidls/MediaSession.webidl
index 12b3fe062ba..2680ea0c40b 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 = {});
};
-