Skip to main content

script/dom/media/
mediastream.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use dom_struct::dom_struct;
6use js::rust::HandleObject;
7use script_bindings::cell::{DomRefCell, Ref};
8use script_bindings::reflector::reflect_dom_object_with_proto_and_cx;
9use servo_media::streams::MediaStreamType;
10use servo_media::streams::registry::MediaStreamId;
11
12use crate::dom::bindings::codegen::Bindings::MediaStreamBinding::MediaStreamMethods;
13use crate::dom::bindings::error::Fallible;
14use crate::dom::bindings::reflector::DomGlobal;
15use crate::dom::bindings::root::{Dom, DomRoot};
16use crate::dom::bindings::str::DOMString;
17use crate::dom::eventtarget::EventTarget;
18use crate::dom::globalscope::GlobalScope;
19use crate::dom::media::mediastreamtrack::MediaStreamTrack;
20use crate::dom::window::Window;
21
22#[dom_struct]
23pub(crate) struct MediaStream {
24    eventtarget: EventTarget,
25    tracks: DomRefCell<Vec<Dom<MediaStreamTrack>>>,
26}
27
28impl MediaStream {
29    pub(crate) fn new_inherited() -> MediaStream {
30        MediaStream {
31            eventtarget: EventTarget::new_inherited(),
32            tracks: DomRefCell::new(vec![]),
33        }
34    }
35
36    pub(crate) fn new(
37        cx: &mut js::context::JSContext,
38        global: &GlobalScope,
39    ) -> DomRoot<MediaStream> {
40        Self::new_with_proto(cx, global, None)
41    }
42
43    fn new_with_proto(
44        cx: &mut js::context::JSContext,
45        global: &GlobalScope,
46        proto: Option<HandleObject>,
47    ) -> DomRoot<MediaStream> {
48        reflect_dom_object_with_proto_and_cx(
49            Box::new(MediaStream::new_inherited()),
50            global,
51            proto,
52            cx,
53        )
54    }
55
56    pub(crate) fn new_single(
57        cx: &mut js::context::JSContext,
58        global: &GlobalScope,
59        id: MediaStreamId,
60        ty: MediaStreamType,
61    ) -> DomRoot<MediaStream> {
62        let this = Self::new(cx, global);
63        let track = MediaStreamTrack::new(cx, global, id, ty);
64        this.AddTrack(&track);
65        this
66    }
67
68    pub(crate) fn get_tracks(&self) -> Ref<'_, [Dom<MediaStreamTrack>]> {
69        Ref::map(self.tracks.borrow(), |tracks| &**tracks)
70    }
71
72    pub(crate) fn add_track(&self, track: &MediaStreamTrack) {
73        self.tracks.borrow_mut().push(Dom::from_ref(track))
74    }
75}
76
77impl MediaStreamMethods<crate::DomTypeHolder> for MediaStream {
78    /// <https://w3c.github.io/mediacapture-main/#dom-mediastream-constructor>
79    fn Constructor(
80        cx: &mut js::context::JSContext,
81        global: &Window,
82        proto: Option<HandleObject>,
83    ) -> Fallible<DomRoot<MediaStream>> {
84        Ok(MediaStream::new_with_proto(cx, &global.global(), proto))
85    }
86
87    /// <https://w3c.github.io/mediacapture-main/#dom-mediastream-constructor>
88    fn Constructor_(
89        cx: &mut js::context::JSContext,
90        _: &Window,
91        proto: Option<HandleObject>,
92        stream: &MediaStream,
93    ) -> Fallible<DomRoot<MediaStream>> {
94        Ok(stream.clone_with_proto(cx, proto))
95    }
96
97    /// <https://w3c.github.io/mediacapture-main/#dom-mediastream-constructor>
98    fn Constructor__(
99        cx: &mut js::context::JSContext,
100        global: &Window,
101        proto: Option<HandleObject>,
102        tracks: Vec<DomRoot<MediaStreamTrack>>,
103    ) -> Fallible<DomRoot<MediaStream>> {
104        let new = MediaStream::new_with_proto(cx, &global.global(), proto);
105        for track in tracks {
106            // this is quadratic, but shouldn't matter much
107            // if this becomes a problem we can use a hash map
108            new.AddTrack(&track)
109        }
110        Ok(new)
111    }
112
113    /// <https://w3c.github.io/mediacapture-main/#dom-mediastream-gettracks>
114    fn GetTracks(&self) -> Vec<DomRoot<MediaStreamTrack>> {
115        self.tracks
116            .borrow()
117            .iter()
118            .map(|x| DomRoot::from_ref(&**x))
119            .collect()
120    }
121
122    /// <https://w3c.github.io/mediacapture-main/#dom-mediastream-getaudiotracks>
123    fn GetAudioTracks(&self) -> Vec<DomRoot<MediaStreamTrack>> {
124        self.tracks
125            .borrow()
126            .iter()
127            .filter(|x| x.ty() == MediaStreamType::Audio)
128            .map(|x| DomRoot::from_ref(&**x))
129            .collect()
130    }
131
132    /// <https://w3c.github.io/mediacapture-main/#dom-mediastream-getvideotracks>
133    fn GetVideoTracks(&self) -> Vec<DomRoot<MediaStreamTrack>> {
134        self.tracks
135            .borrow()
136            .iter()
137            .filter(|x| x.ty() == MediaStreamType::Video)
138            .map(|x| DomRoot::from_ref(&**x))
139            .collect()
140    }
141
142    /// <https://w3c.github.io/mediacapture-main/#dom-mediastream-gettrackbyid>
143    fn GetTrackById(&self, id: DOMString) -> Option<DomRoot<MediaStreamTrack>> {
144        self.tracks
145            .borrow()
146            .iter()
147            .find(|x| x.id().id().to_string() == id)
148            .map(|x| DomRoot::from_ref(&**x))
149    }
150
151    /// <https://w3c.github.io/mediacapture-main/#dom-mediastream-addtrack>
152    fn AddTrack(&self, track: &MediaStreamTrack) {
153        let existing = self.tracks.borrow().iter().any(|x| x == &track);
154
155        if existing {
156            return;
157        }
158        self.add_track(track)
159    }
160
161    /// <https://w3c.github.io/mediacapture-main/#dom-mediastream-removetrack>
162    fn RemoveTrack(&self, track: &MediaStreamTrack) {
163        self.tracks.borrow_mut().retain(|x| *x != track);
164    }
165
166    /// <https://w3c.github.io/mediacapture-main/#dom-mediastream-clone>
167    fn Clone(&self, cx: &mut js::context::JSContext) -> DomRoot<MediaStream> {
168        self.clone_with_proto(cx, None)
169    }
170}
171
172impl MediaStream {
173    fn clone_with_proto(
174        &self,
175        cx: &mut js::context::JSContext,
176        proto: Option<HandleObject>,
177    ) -> DomRoot<MediaStream> {
178        let new = MediaStream::new_with_proto(cx, &self.global(), proto);
179        for track in &*self.tracks.borrow() {
180            new.add_track(track)
181        }
182        new
183    }
184}