mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
Implement HTMLMediaElement defaultPlaybackRate and playbackRate attributes
This commit is contained in:
parent
44344452e2
commit
deb02ab6d7
6 changed files with 126 additions and 57 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -3513,7 +3513,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servo-media"
|
name = "servo-media"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/media#352072f33b6d118f89aa4ccf000ceaf360a5f663"
|
source = "git+https://github.com/servo/media#35014baeb603b56b1b8b4de75919c58f7390cc30"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"servo-media-audio 0.1.0 (git+https://github.com/servo/media)",
|
"servo-media-audio 0.1.0 (git+https://github.com/servo/media)",
|
||||||
"servo-media-gstreamer 0.1.0 (git+https://github.com/servo/media)",
|
"servo-media-gstreamer 0.1.0 (git+https://github.com/servo/media)",
|
||||||
|
@ -3523,7 +3523,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servo-media-audio"
|
name = "servo-media-audio"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/media#352072f33b6d118f89aa4ccf000ceaf360a5f663"
|
source = "git+https://github.com/servo/media#35014baeb603b56b1b8b4de75919c58f7390cc30"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"boxfnonce 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"boxfnonce 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -3540,7 +3540,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servo-media-gstreamer"
|
name = "servo-media-gstreamer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/media#352072f33b6d118f89aa4ccf000ceaf360a5f663"
|
source = "git+https://github.com/servo/media#35014baeb603b56b1b8b4de75919c58f7390cc30"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -3559,7 +3559,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servo-media-player"
|
name = "servo-media-player"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/media#352072f33b6d118f89aa4ccf000ceaf360a5f663"
|
source = "git+https://github.com/servo/media#35014baeb603b56b1b8b4de75919c58f7390cc30"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -3646,7 +3646,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servo_media_derive"
|
name = "servo_media_derive"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/media#352072f33b6d118f89aa4ccf000ceaf360a5f663"
|
source = "git+https://github.com/servo/media#35014baeb603b56b1b8b4de75919c58f7390cc30"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -67,6 +67,7 @@ print
|
||||||
progress
|
progress
|
||||||
radio
|
radio
|
||||||
range
|
range
|
||||||
|
ratechange
|
||||||
readystatechange
|
readystatechange
|
||||||
reftest-wait
|
reftest-wait
|
||||||
rejectionhandled
|
rejectionhandled
|
||||||
|
|
|
@ -164,6 +164,10 @@ pub struct HTMLMediaElement {
|
||||||
error: MutNullableDom<MediaError>,
|
error: MutNullableDom<MediaError>,
|
||||||
/// <https://html.spec.whatwg.org/multipage/#dom-media-paused>
|
/// <https://html.spec.whatwg.org/multipage/#dom-media-paused>
|
||||||
paused: Cell<bool>,
|
paused: Cell<bool>,
|
||||||
|
/// <https://html.spec.whatwg.org/multipage/#dom-media-defaultplaybackrate>
|
||||||
|
defaultPlaybackRate: Cell<f64>,
|
||||||
|
/// <https://html.spec.whatwg.org/multipage/#dom-media-playbackrate>
|
||||||
|
playbackRate: Cell<f64>,
|
||||||
/// <https://html.spec.whatwg.org/multipage/#attr-media-autoplay>
|
/// <https://html.spec.whatwg.org/multipage/#attr-media-autoplay>
|
||||||
autoplaying: Cell<bool>,
|
autoplaying: Cell<bool>,
|
||||||
/// <https://html.spec.whatwg.org/multipage/#delaying-the-load-event-flag>
|
/// <https://html.spec.whatwg.org/multipage/#delaying-the-load-event-flag>
|
||||||
|
@ -235,6 +239,8 @@ impl HTMLMediaElement {
|
||||||
fired_loadeddata_event: Cell::new(false),
|
fired_loadeddata_event: Cell::new(false),
|
||||||
error: Default::default(),
|
error: Default::default(),
|
||||||
paused: Cell::new(true),
|
paused: Cell::new(true),
|
||||||
|
defaultPlaybackRate: Cell::new(1.0),
|
||||||
|
playbackRate: Cell::new(1.0),
|
||||||
// FIXME(nox): Why is this initialised to true?
|
// FIXME(nox): Why is this initialised to true?
|
||||||
autoplaying: Cell::new(true),
|
autoplaying: Cell::new(true),
|
||||||
delaying_the_load_event_flag: Default::default(),
|
delaying_the_load_event_flag: Default::default(),
|
||||||
|
@ -271,6 +277,15 @@ impl HTMLMediaElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn play_media(&self) {
|
||||||
|
if let Err(e) = self.player.set_rate(self.playbackRate.get()) {
|
||||||
|
warn!("Could not set the playback rate {:?}", e);
|
||||||
|
}
|
||||||
|
if let Err(e) = self.player.play() {
|
||||||
|
warn!("Could not play media {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Marks that element as delaying the load event or not.
|
/// Marks that element as delaying the load event or not.
|
||||||
///
|
///
|
||||||
/// Nothing happens if the element was already delaying the load event and
|
/// Nothing happens if the element was already delaying the load event and
|
||||||
|
@ -358,9 +373,7 @@ impl HTMLMediaElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fulfill_in_flight_play_promises(|| {
|
this.fulfill_in_flight_play_promises(|| {
|
||||||
if let Err(e) = this.player.play() {
|
this.play_media();
|
||||||
eprintln!("Could not play media {:?}", e);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
window.upcast(),
|
window.upcast(),
|
||||||
|
@ -449,9 +462,7 @@ impl HTMLMediaElement {
|
||||||
this.fulfill_in_flight_play_promises(|| {
|
this.fulfill_in_flight_play_promises(|| {
|
||||||
// Step 2.1.
|
// Step 2.1.
|
||||||
this.upcast::<EventTarget>().fire_event(atom!("playing"));
|
this.upcast::<EventTarget>().fire_event(atom!("playing"));
|
||||||
if let Err(e) = this.player.play() {
|
this.play_media();
|
||||||
eprintln!("Could not play media {:?}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2.2.
|
// Step 2.2.
|
||||||
// Done after running this closure in
|
// Done after running this closure in
|
||||||
|
@ -888,6 +899,43 @@ impl HTMLMediaElement {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn queue_ratechange_event(&self) {
|
||||||
|
let window = window_from_node(self);
|
||||||
|
let task_source = window.task_manager().media_element_task_source();
|
||||||
|
task_source.queue_simple_event(self.upcast(), atom!("ratechange"), &window);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#potentially-playing
|
||||||
|
fn is_potentially_playing(&self) -> bool {
|
||||||
|
!self.paused.get() &&
|
||||||
|
// FIXME: We need https://github.com/servo/servo/pull/22348
|
||||||
|
// to know whether playback has ended or not
|
||||||
|
// !self.Ended() &&
|
||||||
|
self.error.get().is_none() &&
|
||||||
|
!self.is_blocked_media_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#blocked-media-element
|
||||||
|
fn is_blocked_media_element(&self) -> bool {
|
||||||
|
self.ready_state.get() <= ReadyState::HaveCurrentData ||
|
||||||
|
self.is_paused_for_user_interaction() ||
|
||||||
|
self.is_paused_for_in_band_content()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#paused-for-user-interaction
|
||||||
|
fn is_paused_for_user_interaction(&self) -> bool {
|
||||||
|
// FIXME: we will likely be able to fill this placeholder once (if) we
|
||||||
|
// implement the MediaSession API.
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#paused-for-in-band-content
|
||||||
|
fn is_paused_for_in_band_content(&self) -> bool {
|
||||||
|
// FIXME: we will likely be able to fill this placeholder once (if) we
|
||||||
|
// implement https://github.com/servo/servo/issues/22314
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#media-element-load-algorithm
|
// https://html.spec.whatwg.org/multipage/#media-element-load-algorithm
|
||||||
fn media_element_load_algorithm(&self) {
|
fn media_element_load_algorithm(&self) {
|
||||||
// Reset the flag that signals whether loadeddata was ever fired for
|
// Reset the flag that signals whether loadeddata was ever fired for
|
||||||
|
@ -960,7 +1008,7 @@ impl HTMLMediaElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 7.
|
// Step 7.
|
||||||
// FIXME(nox): Set playbackRate to defaultPlaybackRate.
|
self.playbackRate.set(self.defaultPlaybackRate.get());
|
||||||
|
|
||||||
// Step 8.
|
// Step 8.
|
||||||
self.error.set(None);
|
self.error.set(None);
|
||||||
|
@ -1350,6 +1398,53 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
|
||||||
self.paused.get()
|
self.paused.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#dom-media-defaultplaybackrate
|
||||||
|
fn GetDefaultPlaybackRate(&self) -> Fallible<Finite<f64>> {
|
||||||
|
Ok(Finite::wrap(self.defaultPlaybackRate.get()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#dom-media-defaultplaybackrate
|
||||||
|
fn SetDefaultPlaybackRate(&self, value: Finite<f64>) -> ErrorResult {
|
||||||
|
let min_allowed = -64.0;
|
||||||
|
let max_allowed = 64.0;
|
||||||
|
if *value < min_allowed || *value > max_allowed {
|
||||||
|
return Err(Error::NotSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
if *value != self.defaultPlaybackRate.get() {
|
||||||
|
self.defaultPlaybackRate.set(*value);
|
||||||
|
self.queue_ratechange_event();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#dom-media-playbackrate
|
||||||
|
fn GetPlaybackRate(&self) -> Fallible<Finite<f64>> {
|
||||||
|
Ok(Finite::wrap(self.playbackRate.get()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#dom-media-playbackrate
|
||||||
|
fn SetPlaybackRate(&self, value: Finite<f64>) -> ErrorResult {
|
||||||
|
let min_allowed = -64.0;
|
||||||
|
let max_allowed = 64.0;
|
||||||
|
if *value < min_allowed || *value > max_allowed {
|
||||||
|
return Err(Error::NotSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
if *value != self.playbackRate.get() {
|
||||||
|
self.playbackRate.set(*value);
|
||||||
|
self.queue_ratechange_event();
|
||||||
|
if self.is_potentially_playing() {
|
||||||
|
if let Err(e) = self.player.set_rate(*value) {
|
||||||
|
warn!("Could not set the playback rate {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-media-duration
|
// https://html.spec.whatwg.org/multipage/#dom-media-duration
|
||||||
fn Duration(&self) -> f64 {
|
fn Duration(&self) -> f64 {
|
||||||
self.duration.get()
|
self.duration.get()
|
||||||
|
|
|
@ -42,8 +42,8 @@ interface HTMLMediaElement : HTMLElement {
|
||||||
readonly attribute unrestricted double duration;
|
readonly attribute unrestricted double duration;
|
||||||
// Date getStartDate();
|
// Date getStartDate();
|
||||||
readonly attribute boolean paused;
|
readonly attribute boolean paused;
|
||||||
// attribute double defaultPlaybackRate;
|
[Throws] attribute double defaultPlaybackRate;
|
||||||
// attribute double playbackRate;
|
[Throws] attribute double playbackRate;
|
||||||
readonly attribute TimeRanges played;
|
readonly attribute TimeRanges played;
|
||||||
// readonly attribute TimeRanges seekable;
|
// readonly attribute TimeRanges seekable;
|
||||||
// readonly attribute boolean ended;
|
// readonly attribute boolean ended;
|
||||||
|
|
|
@ -1041,10 +1041,10 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[HTMLMediaElement interface: document.createElement("video") must inherit property "defaultPlaybackRate" with the proper type]
|
[HTMLMediaElement interface: document.createElement("video") must inherit property "defaultPlaybackRate" with the proper type]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: document.createElement("video") must inherit property "playbackRate" with the proper type]
|
[HTMLMediaElement interface: document.createElement("video") must inherit property "playbackRate" with the proper type]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: document.createElement("video") must inherit property "played" with the proper type]
|
[HTMLMediaElement interface: document.createElement("video") must inherit property "played" with the proper type]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
@ -1113,10 +1113,10 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[HTMLMediaElement interface: document.createElement("audio") must inherit property "defaultPlaybackRate" with the proper type]
|
[HTMLMediaElement interface: document.createElement("audio") must inherit property "defaultPlaybackRate" with the proper type]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: document.createElement("audio") must inherit property "playbackRate" with the proper type]
|
[HTMLMediaElement interface: document.createElement("audio") must inherit property "playbackRate" with the proper type]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: document.createElement("audio") must inherit property "played" with the proper type]
|
[HTMLMediaElement interface: document.createElement("audio") must inherit property "played" with the proper type]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
@ -1248,10 +1248,10 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[HTMLMediaElement interface: new Audio() must inherit property "defaultPlaybackRate" with the proper type]
|
[HTMLMediaElement interface: new Audio() must inherit property "defaultPlaybackRate" with the proper type]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: new Audio() must inherit property "playbackRate" with the proper type]
|
[HTMLMediaElement interface: new Audio() must inherit property "playbackRate" with the proper type]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: new Audio() must inherit property "played" with the proper type]
|
[HTMLMediaElement interface: new Audio() must inherit property "played" with the proper type]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
@ -1401,10 +1401,10 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[HTMLMediaElement interface: attribute defaultPlaybackRate]
|
[HTMLMediaElement interface: attribute defaultPlaybackRate]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: attribute playbackRate]
|
[HTMLMediaElement interface: attribute playbackRate]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: attribute played]
|
[HTMLMediaElement interface: attribute played]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
@ -6775,10 +6775,10 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[HTMLMediaElement interface: document.createElement("video") must inherit property "defaultPlaybackRate" with the proper type]
|
[HTMLMediaElement interface: document.createElement("video") must inherit property "defaultPlaybackRate" with the proper type]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: document.createElement("video") must inherit property "playbackRate" with the proper type]
|
[HTMLMediaElement interface: document.createElement("video") must inherit property "playbackRate" with the proper type]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: document.createElement("video") must inherit property "seekable" with the proper type]
|
[HTMLMediaElement interface: document.createElement("video") must inherit property "seekable" with the proper type]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
@ -6820,10 +6820,10 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[HTMLMediaElement interface: document.createElement("audio") must inherit property "defaultPlaybackRate" with the proper type]
|
[HTMLMediaElement interface: document.createElement("audio") must inherit property "defaultPlaybackRate" with the proper type]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: document.createElement("audio") must inherit property "playbackRate" with the proper type]
|
[HTMLMediaElement interface: document.createElement("audio") must inherit property "playbackRate" with the proper type]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: document.createElement("audio") must inherit property "seekable" with the proper type]
|
[HTMLMediaElement interface: document.createElement("audio") must inherit property "seekable" with the proper type]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
@ -6865,10 +6865,10 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[HTMLMediaElement interface: new Audio() must inherit property "defaultPlaybackRate" with the proper type]
|
[HTMLMediaElement interface: new Audio() must inherit property "defaultPlaybackRate" with the proper type]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: new Audio() must inherit property "playbackRate" with the proper type]
|
[HTMLMediaElement interface: new Audio() must inherit property "playbackRate" with the proper type]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: new Audio() must inherit property "seekable" with the proper type]
|
[HTMLMediaElement interface: new Audio() must inherit property "seekable" with the proper type]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
@ -6985,10 +6985,10 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[HTMLMediaElement interface: attribute defaultPlaybackRate]
|
[HTMLMediaElement interface: attribute defaultPlaybackRate]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: attribute playbackRate]
|
[HTMLMediaElement interface: attribute playbackRate]
|
||||||
expected: FAIL
|
expected: PASS
|
||||||
|
|
||||||
[HTMLMediaElement interface: attribute seekable]
|
[HTMLMediaElement interface: attribute seekable]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
[playbackRate.html]
|
|
||||||
type: testharness
|
|
||||||
expected: TIMEOUT
|
|
||||||
[playbackRate initial value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setting playbackRate]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[playbackRate set to small positive value]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[playbackRate set to large positive value]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[playbackRate set to small negative value]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[playbackRate set to large negative value]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[playbackRate set to 0]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[playbackRate set to -1]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue