Skip to main content

servo_media_ohos/
lib.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 std::collections::HashMap;
6use std::sync::atomic::{AtomicUsize, Ordering};
7use std::sync::mpsc::{self, Sender};
8use std::sync::{Arc, Mutex, Weak};
9use std::thread;
10
11use log::{debug, warn};
12use mime::Mime;
13use servo_media::player::StreamType;
14use servo_media::{
15    Backend, BackendInit, BackendMsg, ClientContextId, MediaInstance, MediaInstanceError,
16    SupportsMediaType,
17};
18
19use crate::player::OhosAvPlayer;
20use crate::registry_scanner::OHOS_REGISTRY_SCANNER;
21mod ohos_media;
22mod player;
23mod registry_scanner;
24
25type MediaInstanceMap = HashMap<ClientContextId, Vec<(usize, Weak<Mutex<dyn MediaInstance>>)>>;
26
27pub struct OhosBackend {
28    instances: Arc<Mutex<MediaInstanceMap>>,
29    next_instance_id: AtomicUsize,
30    backend_chan: Arc<Mutex<Sender<BackendMsg>>>,
31}
32
33impl OhosBackend {
34    fn media_instance_action(
35        &self,
36        id: &ClientContextId,
37        cb: &dyn Fn(&dyn MediaInstance) -> Result<(), MediaInstanceError>,
38    ) {
39        let mut instances = self.instances.lock().unwrap();
40        match instances.get_mut(id) {
41            Some(vec) => vec.retain(|(_, weak)| {
42                if let Some(instance) = weak.upgrade() {
43                    if cb(&*(instance.lock().unwrap())).is_err() {
44                        warn!("Error executing media instance action");
45                    }
46                    true
47                } else {
48                    false
49                }
50            }),
51            None => {
52                warn!("Trying to exec media action on an unknown client context");
53            },
54        }
55    }
56}
57
58impl BackendInit for OhosBackend {
59    fn init() -> Box<dyn Backend> {
60        let instances: Arc<Mutex<MediaInstanceMap>> = Arc::new(Mutex::new(HashMap::new()));
61
62        let instances_ = instances.clone();
63        let (backend_chan, recvr) = mpsc::channel();
64        thread::Builder::new()
65            .name("OhosBackend ShutdownThread".to_owned())
66            .spawn(move || {
67                match recvr.recv().unwrap() {
68                    BackendMsg::Shutdown {
69                        context,
70                        id,
71                        tx_ack,
72                    } => {
73                        let mut map = instances_.lock().unwrap();
74                        if let Some(vec) = map.get_mut(&context) {
75                            vec.retain(|m| m.0 != id);
76                            if vec.is_empty() {
77                                map.remove(&context);
78                            }
79                        }
80                        let _ = tx_ack.send(());
81                    },
82                };
83            })
84            .unwrap();
85        Box::new(OhosBackend {
86            next_instance_id: AtomicUsize::new(0),
87            instances,
88            backend_chan: Arc::new(Mutex::new(backend_chan)),
89        })
90    }
91}
92
93// https://developer.huawei.com/consumer/en/doc/harmonyos-guides/obtain-supported-codecs
94// https://developer.huawei.com/consumer/en/doc/harmonyos-guides/media-kit-intro-V5#supported-formats-and-protocols
95
96impl Backend for OhosBackend {
97    fn create_player(
98        &self,
99        context_id: &servo_media::ClientContextId,
100        stream_type: servo_media_player::StreamType,
101        sender: servo_media_player::ipc_channel::ipc::IpcSender<servo_media_player::PlayerEvent>,
102        video_renderer: Option<
103            std::sync::Arc<std::sync::Mutex<dyn servo_media_player::video::VideoFrameRenderer>>,
104        >,
105        audio_renderer: Option<
106            std::sync::Arc<std::sync::Mutex<dyn servo_media_player::audio::AudioRenderer>>,
107        >,
108        _gl_context: Box<dyn servo_media_player::context::PlayerGLContext>,
109    ) -> std::sync::Arc<std::sync::Mutex<dyn servo_media_player::Player>> {
110        // TODO: Choose different Player Impl depends on stream_type
111        match stream_type {
112            StreamType::Stream => {
113                todo!("Stream Type currently not supported!")
114            },
115            StreamType::Seekable => (),
116        }
117
118        if let Some(_audio_renderer) = audio_renderer {
119            warn!("Audio Rendering Currently Not Supported!");
120        }
121
122        let player_id = self.next_instance_id.fetch_add(1, Ordering::Relaxed);
123        debug!("Creating Player in OhosBackend");
124        let mut player = OhosAvPlayer::new(
125            player_id,
126            *context_id,
127            sender,
128            video_renderer,
129            self.backend_chan.clone(),
130        );
131
132        player.setup_info_event();
133        player.setup_data_source();
134        Arc::new(Mutex::new(player))
135    }
136
137    fn create_audiostream(&self) -> servo_media_streams::MediaStreamId {
138        todo!()
139    }
140
141    fn create_videostream(&self) -> servo_media_streams::MediaStreamId {
142        todo!()
143    }
144
145    fn create_stream_output(&self) -> Box<dyn servo_media_streams::MediaOutput> {
146        todo!()
147    }
148
149    fn create_stream_and_socket(
150        &self,
151        _ty: servo_media_streams::MediaStreamType,
152    ) -> (
153        Box<dyn servo_media_streams::MediaSocket>,
154        servo_media_streams::MediaStreamId,
155    ) {
156        todo!()
157    }
158
159    fn create_audioinput_stream(
160        &self,
161        _set: servo_media_streams::capture::MediaTrackConstraintSet,
162    ) -> Option<servo_media_streams::MediaStreamId> {
163        todo!()
164    }
165
166    fn create_videoinput_stream(
167        &self,
168        _set: servo_media_streams::capture::MediaTrackConstraintSet,
169    ) -> Option<servo_media_streams::MediaStreamId> {
170        todo!()
171    }
172
173    fn create_audio_context(
174        &self,
175        _id: &servo_media::ClientContextId,
176        _options: servo_media_audio::context::AudioContextOptions,
177    ) -> Result<
178        std::sync::Arc<std::sync::Mutex<servo_media_audio::context::AudioContext>>,
179        servo_media_audio::sink::AudioSinkError,
180    > {
181        todo!()
182    }
183
184    fn create_webrtc(
185        &self,
186        _signaller: Box<dyn servo_media_webrtc::WebRtcSignaller>,
187    ) -> servo_media_webrtc::WebRtcController {
188        todo!()
189    }
190
191    fn can_play_type(&self, media_type: &str) -> servo_media::SupportsMediaType {
192        if let Ok(mime) = media_type.parse::<Mime>() {
193            let mime_type = mime.type_().as_str().to_owned() + "/" + mime.subtype().as_str();
194            let codecs = match mime.get_param("codecs") {
195                Some(codecs) => codecs
196                    .as_str()
197                    .split(',')
198                    .map(|codec| codec.trim())
199                    .collect(),
200                None => vec![],
201            };
202
203            if OHOS_REGISTRY_SCANNER.are_mime_and_codecs_supported(&mime_type, &codecs) {
204                if codecs.is_empty() {
205                    return SupportsMediaType::Maybe;
206                }
207                return SupportsMediaType::Probably;
208            }
209        }
210        SupportsMediaType::No
211    }
212
213    fn get_device_monitor(
214        &self,
215    ) -> Box<dyn servo_media_streams::device_monitor::MediaDeviceMonitor> {
216        todo!()
217    }
218
219    fn mute(&self, id: &ClientContextId, val: bool) {
220        self.media_instance_action(
221            id,
222            &(move |instance: &dyn MediaInstance| instance.mute(val)),
223        );
224    }
225
226    fn resume(&self, id: &ClientContextId) {
227        self.media_instance_action(id, &(move |instance: &dyn MediaInstance| instance.resume()));
228    }
229
230    fn suspend(&self, id: &ClientContextId) {
231        self.media_instance_action(
232            id,
233            &(move |instance: &dyn MediaInstance| instance.suspend()),
234        );
235    }
236}