Integrates media track selection

This commit is contained in:
sreeise 2019-09-11 19:16:28 -04:00
parent 4fe8238b14
commit 5ea79c64f9
5 changed files with 88 additions and 14 deletions

View file

@ -2,9 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::audiotracklist::AudioTrackList;
use crate::dom::bindings::codegen::Bindings::AudioTrackBinding::{self, AudioTrackMethods}; use crate::dom::bindings::codegen::Bindings::AudioTrackBinding::{self, AudioTrackMethods};
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::window::Window; use crate::dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
@ -18,6 +19,7 @@ pub struct AudioTrack {
label: DOMString, label: DOMString,
language: DOMString, language: DOMString,
enabled: Cell<bool>, enabled: Cell<bool>,
track_list: Option<Dom<AudioTrackList>>,
} }
impl AudioTrack { impl AudioTrack {
@ -26,6 +28,7 @@ impl AudioTrack {
kind: DOMString, kind: DOMString,
label: DOMString, label: DOMString,
language: DOMString, language: DOMString,
track_list: Option<&AudioTrackList>,
) -> AudioTrack { ) -> AudioTrack {
AudioTrack { AudioTrack {
reflector_: Reflector::new(), reflector_: Reflector::new(),
@ -34,6 +37,7 @@ impl AudioTrack {
label: label.into(), label: label.into(),
language: language.into(), language: language.into(),
enabled: Cell::new(false), enabled: Cell::new(false),
track_list: track_list.map(|t| Dom::from_ref(t)),
} }
} }
@ -43,9 +47,12 @@ impl AudioTrack {
kind: DOMString, kind: DOMString,
label: DOMString, label: DOMString,
language: DOMString, language: DOMString,
track_list: Option<&AudioTrackList>,
) -> DomRoot<AudioTrack> { ) -> DomRoot<AudioTrack> {
reflect_dom_object( reflect_dom_object(
Box::new(AudioTrack::new_inherited(id, kind, label, language)), Box::new(AudioTrack::new_inherited(
id, kind, label, language, track_list,
)),
window, window,
AudioTrackBinding::Wrap, AudioTrackBinding::Wrap,
) )
@ -96,6 +103,11 @@ impl AudioTrackMethods for AudioTrack {
// https://html.spec.whatwg.org/multipage/#dom-audiotrack-enabled // https://html.spec.whatwg.org/multipage/#dom-audiotrack-enabled
fn SetEnabled(&self, value: bool) { fn SetEnabled(&self, value: bool) {
if let Some(list) = self.track_list.as_ref() {
if let Some(idx) = list.find(self) {
list.set_enabled(idx, value);
}
}
self.set_enabled(value); self.set_enabled(value);
} }
} }

View file

@ -11,6 +11,7 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
use crate::dom::htmlmediaelement::HTMLMediaElement;
use crate::dom::window::Window; use crate::dom::window::Window;
use crate::task_source::TaskSource; use crate::task_source::TaskSource;
use dom_struct::dom_struct; use dom_struct::dom_struct;
@ -19,19 +20,28 @@ use dom_struct::dom_struct;
pub struct AudioTrackList { pub struct AudioTrackList {
eventtarget: EventTarget, eventtarget: EventTarget,
tracks: DomRefCell<Vec<Dom<AudioTrack>>>, tracks: DomRefCell<Vec<Dom<AudioTrack>>>,
media_element: Option<Dom<HTMLMediaElement>>,
} }
impl AudioTrackList { impl AudioTrackList {
pub fn new_inherited(tracks: &[&AudioTrack]) -> AudioTrackList { pub fn new_inherited(
tracks: &[&AudioTrack],
media_element: Option<&HTMLMediaElement>,
) -> AudioTrackList {
AudioTrackList { AudioTrackList {
eventtarget: EventTarget::new_inherited(), eventtarget: EventTarget::new_inherited(),
tracks: DomRefCell::new(tracks.iter().map(|track| Dom::from_ref(&**track)).collect()), tracks: DomRefCell::new(tracks.iter().map(|track| Dom::from_ref(&**track)).collect()),
media_element: media_element.map(|m| Dom::from_ref(m)),
} }
} }
pub fn new(window: &Window, tracks: &[&AudioTrack]) -> DomRoot<AudioTrackList> { pub fn new(
window: &Window,
tracks: &[&AudioTrack],
media_element: Option<&HTMLMediaElement>,
) -> DomRoot<AudioTrackList> {
reflect_dom_object( reflect_dom_object(
Box::new(AudioTrackList::new_inherited(tracks)), Box::new(AudioTrackList::new_inherited(tracks, media_element)),
window, window,
AudioTrackListBinding::Wrap, AudioTrackListBinding::Wrap,
) )
@ -41,6 +51,10 @@ impl AudioTrackList {
self.tracks.borrow().len() self.tracks.borrow().len()
} }
pub fn find(&self, track: &AudioTrack) -> Option<usize> {
self.tracks.borrow().iter().position(|t| &**t == track)
}
pub fn item(&self, idx: usize) -> Option<DomRoot<AudioTrack>> { pub fn item(&self, idx: usize) -> Option<DomRoot<AudioTrack>> {
self.tracks self.tracks
.borrow() .borrow()
@ -55,7 +69,6 @@ impl AudioTrackList {
.position(|track| track.enabled()) .position(|track| track.enabled())
} }
// TODO(#22799) Integrate DOM Audio and Video track selection with media player.
pub fn set_enabled(&self, idx: usize, value: bool) { pub fn set_enabled(&self, idx: usize, value: bool) {
let track = match self.item(idx) { let track = match self.item(idx) {
Some(t) => t, Some(t) => t,
@ -68,6 +81,9 @@ impl AudioTrackList {
} }
// Set the tracks enabled status. // Set the tracks enabled status.
track.set_enabled(value); track.set_enabled(value);
if let Some(media_element) = self.media_element.as_ref() {
media_element.set_audio_track(idx, value);
}
// Queue a task to fire an event named change. // Queue a task to fire an event named change.
let global = &self.global(); let global = &self.global();

View file

@ -1435,6 +1435,22 @@ impl HTMLMediaElement {
Ok(()) Ok(())
} }
pub fn set_audio_track(&self, idx: usize, enabled: bool) {
if let Some(ref player) = *self.player.borrow() {
if let Err(err) = player.lock().unwrap().set_audio_track(idx as i32, enabled) {
warn!("Could not set audio track {:#?}", err);
}
}
}
pub fn set_video_track(&self, idx: usize, enabled: bool) {
if let Some(ref player) = *self.player.borrow() {
if let Err(err) = player.lock().unwrap().set_video_track(idx as i32, enabled) {
warn!("Could not set video track {:#?}", err);
}
}
}
fn handle_player_event(&self, event: &PlayerEvent) { fn handle_player_event(&self, event: &PlayerEvent) {
match *event { match *event {
PlayerEvent::EndOfStream => { PlayerEvent::EndOfStream => {
@ -1530,6 +1546,7 @@ impl HTMLMediaElement {
kind, kind,
DOMString::new(), DOMString::new(),
DOMString::new(), DOMString::new(),
Some(&*self.AudioTracks()),
); );
// Steps 2. & 3. // Steps 2. & 3.
@ -1585,6 +1602,7 @@ impl HTMLMediaElement {
kind, kind,
DOMString::new(), DOMString::new(),
DOMString::new(), DOMString::new(),
Some(&*self.VideoTracks()),
); );
// Steps 2. & 3. // Steps 2. & 3.
@ -2217,14 +2235,14 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
fn AudioTracks(&self) -> DomRoot<AudioTrackList> { fn AudioTracks(&self) -> DomRoot<AudioTrackList> {
let window = window_from_node(self); let window = window_from_node(self);
self.audio_tracks_list self.audio_tracks_list
.or_init(|| AudioTrackList::new(&window, &[])) .or_init(|| AudioTrackList::new(&window, &[], Some(self)))
} }
// https://html.spec.whatwg.org/multipage/#dom-media-videotracks // https://html.spec.whatwg.org/multipage/#dom-media-videotracks
fn VideoTracks(&self) -> DomRoot<VideoTrackList> { fn VideoTracks(&self) -> DomRoot<VideoTrackList> {
let window = window_from_node(self); let window = window_from_node(self);
self.video_tracks_list self.video_tracks_list
.or_init(|| VideoTrackList::new(&window, &[])) .or_init(|| VideoTrackList::new(&window, &[], Some(self)))
} }
// https://html.spec.whatwg.org/multipage/#dom-media-texttracks // https://html.spec.whatwg.org/multipage/#dom-media-texttracks

View file

@ -4,8 +4,9 @@
use crate::dom::bindings::codegen::Bindings::VideoTrackBinding::{self, VideoTrackMethods}; use crate::dom::bindings::codegen::Bindings::VideoTrackBinding::{self, VideoTrackMethods};
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::videotracklist::VideoTrackList;
use crate::dom::window::Window; use crate::dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use std::cell::Cell; use std::cell::Cell;
@ -18,6 +19,7 @@ pub struct VideoTrack {
label: DOMString, label: DOMString,
language: DOMString, language: DOMString,
selected: Cell<bool>, selected: Cell<bool>,
track_list: Option<Dom<VideoTrackList>>,
} }
impl VideoTrack { impl VideoTrack {
@ -26,6 +28,7 @@ impl VideoTrack {
kind: DOMString, kind: DOMString,
label: DOMString, label: DOMString,
language: DOMString, language: DOMString,
track_list: Option<&VideoTrackList>,
) -> VideoTrack { ) -> VideoTrack {
VideoTrack { VideoTrack {
reflector_: Reflector::new(), reflector_: Reflector::new(),
@ -34,6 +37,7 @@ impl VideoTrack {
label: label.into(), label: label.into(),
language: language.into(), language: language.into(),
selected: Cell::new(false), selected: Cell::new(false),
track_list: track_list.map(|t| Dom::from_ref(t)),
} }
} }
@ -43,9 +47,12 @@ impl VideoTrack {
kind: DOMString, kind: DOMString,
label: DOMString, label: DOMString,
language: DOMString, language: DOMString,
track_list: Option<&VideoTrackList>,
) -> DomRoot<VideoTrack> { ) -> DomRoot<VideoTrack> {
reflect_dom_object( reflect_dom_object(
Box::new(VideoTrack::new_inherited(id, kind, label, language)), Box::new(VideoTrack::new_inherited(
id, kind, label, language, track_list,
)),
window, window,
VideoTrackBinding::Wrap, VideoTrackBinding::Wrap,
) )
@ -96,6 +103,11 @@ impl VideoTrackMethods for VideoTrack {
// https://html.spec.whatwg.org/multipage/#dom-videotrack-selected // https://html.spec.whatwg.org/multipage/#dom-videotrack-selected
fn SetSelected(&self, value: bool) { fn SetSelected(&self, value: bool) {
if let Some(list) = self.track_list.as_ref() {
if let Some(idx) = list.find(self) {
list.set_selected(idx, value);
}
}
self.set_selected(value); self.set_selected(value);
} }
} }

View file

@ -11,6 +11,7 @@ use crate::dom::bindings::root::Dom;
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
use crate::dom::htmlmediaelement::HTMLMediaElement;
use crate::dom::videotrack::VideoTrack; use crate::dom::videotrack::VideoTrack;
use crate::dom::window::Window; use crate::dom::window::Window;
use crate::task_source::TaskSource; use crate::task_source::TaskSource;
@ -20,19 +21,28 @@ use dom_struct::dom_struct;
pub struct VideoTrackList { pub struct VideoTrackList {
eventtarget: EventTarget, eventtarget: EventTarget,
tracks: DomRefCell<Vec<Dom<VideoTrack>>>, tracks: DomRefCell<Vec<Dom<VideoTrack>>>,
media_element: Option<Dom<HTMLMediaElement>>,
} }
impl VideoTrackList { impl VideoTrackList {
pub fn new_inherited(tracks: &[&VideoTrack]) -> VideoTrackList { pub fn new_inherited(
tracks: &[&VideoTrack],
media_element: Option<&HTMLMediaElement>,
) -> VideoTrackList {
VideoTrackList { VideoTrackList {
eventtarget: EventTarget::new_inherited(), eventtarget: EventTarget::new_inherited(),
tracks: DomRefCell::new(tracks.iter().map(|track| Dom::from_ref(&**track)).collect()), tracks: DomRefCell::new(tracks.iter().map(|track| Dom::from_ref(&**track)).collect()),
media_element: media_element.map(|m| Dom::from_ref(m)),
} }
} }
pub fn new(window: &Window, tracks: &[&VideoTrack]) -> DomRoot<VideoTrackList> { pub fn new(
window: &Window,
tracks: &[&VideoTrack],
media_element: Option<&HTMLMediaElement>,
) -> DomRoot<VideoTrackList> {
reflect_dom_object( reflect_dom_object(
Box::new(VideoTrackList::new_inherited(tracks)), Box::new(VideoTrackList::new_inherited(tracks, media_element)),
window, window,
VideoTrackListBinding::Wrap, VideoTrackListBinding::Wrap,
) )
@ -42,6 +52,10 @@ impl VideoTrackList {
self.tracks.borrow().len() self.tracks.borrow().len()
} }
pub fn find(&self, track: &VideoTrack) -> Option<usize> {
self.tracks.borrow().iter().position(|t| &**t == track)
}
pub fn item(&self, idx: usize) -> Option<DomRoot<VideoTrack>> { pub fn item(&self, idx: usize) -> Option<DomRoot<VideoTrack>> {
self.tracks self.tracks
.borrow() .borrow()
@ -56,7 +70,6 @@ impl VideoTrackList {
.position(|track| track.selected()) .position(|track| track.selected())
} }
// TODO(#22799) Integrate DOM Audio and Video track selection with media player.
pub fn set_selected(&self, idx: usize, value: bool) { pub fn set_selected(&self, idx: usize, value: bool) {
let track = match self.item(idx) { let track = match self.item(idx) {
Some(t) => t, Some(t) => t,
@ -80,6 +93,9 @@ impl VideoTrackList {
} }
track.set_selected(value); track.set_selected(value);
if let Some(media_element) = self.media_element.as_ref() {
media_element.set_video_track(idx, value);
}
let _ = source.queue_with_canceller( let _ = source.queue_with_canceller(
task!(media_track_change: move || { task!(media_track_change: move || {