diff --git a/components/script/dom/audiotrack.rs b/components/script/dom/audiotrack.rs index 6a43eed64b2..b66ea5bf4cc 100644 --- a/components/script/dom/audiotrack.rs +++ b/components/script/dom/audiotrack.rs @@ -2,9 +2,10 @@ * 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/. */ +use crate::dom::audiotracklist::AudioTrackList; use crate::dom::bindings::codegen::Bindings::AudioTrackBinding::{self, AudioTrackMethods}; 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::window::Window; use dom_struct::dom_struct; @@ -18,6 +19,7 @@ pub struct AudioTrack { label: DOMString, language: DOMString, enabled: Cell, + track_list: Option>, } impl AudioTrack { @@ -26,6 +28,7 @@ impl AudioTrack { kind: DOMString, label: DOMString, language: DOMString, + track_list: Option<&AudioTrackList>, ) -> AudioTrack { AudioTrack { reflector_: Reflector::new(), @@ -34,6 +37,7 @@ impl AudioTrack { label: label.into(), language: language.into(), enabled: Cell::new(false), + track_list: track_list.map(|t| Dom::from_ref(t)), } } @@ -43,9 +47,12 @@ impl AudioTrack { kind: DOMString, label: DOMString, language: DOMString, + track_list: Option<&AudioTrackList>, ) -> DomRoot { reflect_dom_object( - Box::new(AudioTrack::new_inherited(id, kind, label, language)), + Box::new(AudioTrack::new_inherited( + id, kind, label, language, track_list, + )), window, AudioTrackBinding::Wrap, ) @@ -96,6 +103,11 @@ impl AudioTrackMethods for AudioTrack { // https://html.spec.whatwg.org/multipage/#dom-audiotrack-enabled 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); } } diff --git a/components/script/dom/audiotracklist.rs b/components/script/dom/audiotracklist.rs index 353c97c2598..e26f23cb2a8 100644 --- a/components/script/dom/audiotracklist.rs +++ b/components/script/dom/audiotracklist.rs @@ -11,6 +11,7 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::DOMString; use crate::dom::eventtarget::EventTarget; +use crate::dom::htmlmediaelement::HTMLMediaElement; use crate::dom::window::Window; use crate::task_source::TaskSource; use dom_struct::dom_struct; @@ -19,19 +20,28 @@ use dom_struct::dom_struct; pub struct AudioTrackList { eventtarget: EventTarget, tracks: DomRefCell>>, + media_element: Option>, } impl AudioTrackList { - pub fn new_inherited(tracks: &[&AudioTrack]) -> AudioTrackList { + pub fn new_inherited( + tracks: &[&AudioTrack], + media_element: Option<&HTMLMediaElement>, + ) -> AudioTrackList { AudioTrackList { eventtarget: EventTarget::new_inherited(), 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 { + pub fn new( + window: &Window, + tracks: &[&AudioTrack], + media_element: Option<&HTMLMediaElement>, + ) -> DomRoot { reflect_dom_object( - Box::new(AudioTrackList::new_inherited(tracks)), + Box::new(AudioTrackList::new_inherited(tracks, media_element)), window, AudioTrackListBinding::Wrap, ) @@ -41,6 +51,10 @@ impl AudioTrackList { self.tracks.borrow().len() } + pub fn find(&self, track: &AudioTrack) -> Option { + self.tracks.borrow().iter().position(|t| &**t == track) + } + pub fn item(&self, idx: usize) -> Option> { self.tracks .borrow() @@ -55,7 +69,6 @@ impl AudioTrackList { .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) { let track = match self.item(idx) { Some(t) => t, @@ -68,6 +81,9 @@ impl AudioTrackList { } // Set the tracks enabled status. 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. let global = &self.global(); diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index a607c915802..e3cb0dfb5b2 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -1435,6 +1435,22 @@ impl HTMLMediaElement { 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) { match *event { PlayerEvent::EndOfStream => { @@ -1530,6 +1546,7 @@ impl HTMLMediaElement { kind, DOMString::new(), DOMString::new(), + Some(&*self.AudioTracks()), ); // Steps 2. & 3. @@ -1585,6 +1602,7 @@ impl HTMLMediaElement { kind, DOMString::new(), DOMString::new(), + Some(&*self.VideoTracks()), ); // Steps 2. & 3. @@ -2217,14 +2235,14 @@ impl HTMLMediaElementMethods for HTMLMediaElement { fn AudioTracks(&self) -> DomRoot { let window = window_from_node(self); 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 fn VideoTracks(&self) -> DomRoot { let window = window_from_node(self); 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 diff --git a/components/script/dom/videotrack.rs b/components/script/dom/videotrack.rs index 5dc13c09645..b1453da0df4 100644 --- a/components/script/dom/videotrack.rs +++ b/components/script/dom/videotrack.rs @@ -4,8 +4,9 @@ use crate::dom::bindings::codegen::Bindings::VideoTrackBinding::{self, VideoTrackMethods}; 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::videotracklist::VideoTrackList; use crate::dom::window::Window; use dom_struct::dom_struct; use std::cell::Cell; @@ -18,6 +19,7 @@ pub struct VideoTrack { label: DOMString, language: DOMString, selected: Cell, + track_list: Option>, } impl VideoTrack { @@ -26,6 +28,7 @@ impl VideoTrack { kind: DOMString, label: DOMString, language: DOMString, + track_list: Option<&VideoTrackList>, ) -> VideoTrack { VideoTrack { reflector_: Reflector::new(), @@ -34,6 +37,7 @@ impl VideoTrack { label: label.into(), language: language.into(), selected: Cell::new(false), + track_list: track_list.map(|t| Dom::from_ref(t)), } } @@ -43,9 +47,12 @@ impl VideoTrack { kind: DOMString, label: DOMString, language: DOMString, + track_list: Option<&VideoTrackList>, ) -> DomRoot { reflect_dom_object( - Box::new(VideoTrack::new_inherited(id, kind, label, language)), + Box::new(VideoTrack::new_inherited( + id, kind, label, language, track_list, + )), window, VideoTrackBinding::Wrap, ) @@ -96,6 +103,11 @@ impl VideoTrackMethods for VideoTrack { // https://html.spec.whatwg.org/multipage/#dom-videotrack-selected 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); } } diff --git a/components/script/dom/videotracklist.rs b/components/script/dom/videotracklist.rs index 497d3f0ce55..9654123d3f3 100644 --- a/components/script/dom/videotracklist.rs +++ b/components/script/dom/videotracklist.rs @@ -11,6 +11,7 @@ use crate::dom::bindings::root::Dom; use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::DOMString; use crate::dom::eventtarget::EventTarget; +use crate::dom::htmlmediaelement::HTMLMediaElement; use crate::dom::videotrack::VideoTrack; use crate::dom::window::Window; use crate::task_source::TaskSource; @@ -20,19 +21,28 @@ use dom_struct::dom_struct; pub struct VideoTrackList { eventtarget: EventTarget, tracks: DomRefCell>>, + media_element: Option>, } impl VideoTrackList { - pub fn new_inherited(tracks: &[&VideoTrack]) -> VideoTrackList { + pub fn new_inherited( + tracks: &[&VideoTrack], + media_element: Option<&HTMLMediaElement>, + ) -> VideoTrackList { VideoTrackList { eventtarget: EventTarget::new_inherited(), 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 { + pub fn new( + window: &Window, + tracks: &[&VideoTrack], + media_element: Option<&HTMLMediaElement>, + ) -> DomRoot { reflect_dom_object( - Box::new(VideoTrackList::new_inherited(tracks)), + Box::new(VideoTrackList::new_inherited(tracks, media_element)), window, VideoTrackListBinding::Wrap, ) @@ -42,6 +52,10 @@ impl VideoTrackList { self.tracks.borrow().len() } + pub fn find(&self, track: &VideoTrack) -> Option { + self.tracks.borrow().iter().position(|t| &**t == track) + } + pub fn item(&self, idx: usize) -> Option> { self.tracks .borrow() @@ -56,7 +70,6 @@ impl VideoTrackList { .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) { let track = match self.item(idx) { Some(t) => t, @@ -80,6 +93,9 @@ impl VideoTrackList { } 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( task!(media_track_change: move || {