servo_media_webrtc/
thread.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::sync::mpsc::{Sender, channel};
6use std::thread;
7
8use log::error;
9use servo_media_streams::MediaStreamType;
10
11use crate::datachannel::{DataChannelEvent, DataChannelId, DataChannelInit, DataChannelMessage};
12use crate::{
13    BundlePolicy, DescriptionType, IceCandidate, MediaStreamId, SdpType, SessionDescription,
14    WebRtcBackend, WebRtcControllerBackend, WebRtcSignaller,
15};
16
17#[derive(Clone)]
18/// Entry point for all client webrtc interactions.
19pub struct WebRtcController {
20    sender: Sender<RtcThreadEvent>,
21}
22
23impl WebRtcController {
24    pub fn new<T: WebRtcBackend>(signaller: Box<dyn WebRtcSignaller>) -> Self {
25        let (sender, receiver) = channel();
26
27        let t = WebRtcController { sender };
28
29        let mut controller = T::construct_webrtc_controller(signaller, t.clone());
30
31        thread::spawn(move || {
32            while let Ok(event) = receiver.recv() {
33                if !handle_rtc_event(&mut controller, event) {
34                    // shut down event loop
35                    break;
36                }
37            }
38        });
39
40        t
41    }
42    pub fn configure(&self, stun_server: String, policy: BundlePolicy) {
43        let _ = self
44            .sender
45            .send(RtcThreadEvent::ConfigureStun(stun_server, policy));
46    }
47    pub fn set_remote_description(
48        &self,
49        desc: SessionDescription,
50        cb: Box<dyn FnOnce() + Send + 'static>,
51    ) {
52        let _ = self
53            .sender
54            .send(RtcThreadEvent::SetRemoteDescription(desc, cb));
55    }
56    pub fn set_local_description(
57        &self,
58        desc: SessionDescription,
59        cb: Box<dyn FnOnce() + Send + 'static>,
60    ) {
61        let _ = self
62            .sender
63            .send(RtcThreadEvent::SetLocalDescription(desc, cb));
64    }
65    pub fn add_ice_candidate(&self, candidate: IceCandidate) {
66        let _ = self.sender.send(RtcThreadEvent::AddIceCandidate(candidate));
67    }
68    pub fn create_offer(&self, cb: Box<dyn FnOnce(SessionDescription) + Send + 'static>) {
69        let _ = self.sender.send(RtcThreadEvent::CreateOffer(cb));
70    }
71    pub fn create_answer(&self, cb: Box<dyn FnOnce(SessionDescription) + Send + 'static>) {
72        let _ = self.sender.send(RtcThreadEvent::CreateAnswer(cb));
73    }
74    pub fn add_stream(&self, stream: &MediaStreamId) {
75        let _ = self.sender.send(RtcThreadEvent::AddStream(*stream));
76    }
77    pub fn create_data_channel(&self, init: DataChannelInit) -> Option<DataChannelId> {
78        let (sender, receiver) = channel();
79        let _ = self
80            .sender
81            .send(RtcThreadEvent::CreateDataChannel(init, sender));
82        receiver.recv().unwrap()
83    }
84    pub fn send_data_channel_message(&self, id: &DataChannelId, message: DataChannelMessage) {
85        let _ = self
86            .sender
87            .send(RtcThreadEvent::SendDataChannelMessage(*id, message));
88    }
89    pub fn close_data_channel(&self, id: &DataChannelId) {
90        let _ = self.sender.send(RtcThreadEvent::CloseDataChannel(*id));
91    }
92
93    /// This should not be invoked by clients
94    pub fn internal_event(&self, event: InternalEvent) {
95        let _ = self.sender.send(RtcThreadEvent::InternalEvent(event));
96    }
97
98    pub fn quit(&self) {
99        let _ = self.sender.send(RtcThreadEvent::Quit);
100    }
101}
102
103pub enum RtcThreadEvent {
104    ConfigureStun(String, BundlePolicy),
105    SetRemoteDescription(SessionDescription, Box<dyn FnOnce() + Send + 'static>),
106    SetLocalDescription(SessionDescription, Box<dyn FnOnce() + Send + 'static>),
107    AddIceCandidate(IceCandidate),
108    CreateOffer(Box<dyn FnOnce(SessionDescription) + Send + 'static>),
109    CreateAnswer(Box<dyn FnOnce(SessionDescription) + Send + 'static>),
110    AddStream(MediaStreamId),
111    CreateDataChannel(DataChannelInit, Sender<Option<DataChannelId>>),
112    CloseDataChannel(DataChannelId),
113    SendDataChannelMessage(DataChannelId, DataChannelMessage),
114    InternalEvent(InternalEvent),
115    Quit,
116}
117
118/// To allow everything to occur on the event loop,
119/// the backend may need to send signals to itself
120///
121/// This is a somewhat leaky abstraction, but we don't
122/// plan on having too many backends anyway
123pub enum InternalEvent {
124    OnNegotiationNeeded,
125    OnIceCandidate(IceCandidate),
126    OnAddStream(MediaStreamId, MediaStreamType),
127    OnDataChannelEvent(DataChannelId, DataChannelEvent),
128    DescriptionAdded(
129        Box<dyn FnOnce() + Send + 'static>,
130        DescriptionType,
131        SdpType,
132        /* remote offer generation */ u32,
133    ),
134    UpdateSignalingState,
135    UpdateGatheringState,
136    UpdateIceConnectionState,
137}
138
139pub fn handle_rtc_event(
140    controller: &mut dyn WebRtcControllerBackend,
141    event: RtcThreadEvent,
142) -> bool {
143    let result = match event {
144        RtcThreadEvent::ConfigureStun(server, policy) => controller.configure(&server, policy),
145        RtcThreadEvent::SetRemoteDescription(desc, cb) => {
146            controller.set_remote_description(desc, cb)
147        },
148        RtcThreadEvent::SetLocalDescription(desc, cb) => controller.set_local_description(desc, cb),
149        RtcThreadEvent::AddIceCandidate(candidate) => controller.add_ice_candidate(candidate),
150        RtcThreadEvent::CreateOffer(cb) => controller.create_offer(cb),
151        RtcThreadEvent::CreateAnswer(cb) => controller.create_answer(cb),
152        RtcThreadEvent::AddStream(media) => controller.add_stream(&media),
153        RtcThreadEvent::CreateDataChannel(init, sender) => controller
154            .create_data_channel(&init)
155            .map(|id| {
156                let _ = sender.send(Some(id));
157            })
158            .inspect_err(|_| {
159                let _ = sender.send(None);
160            }),
161        RtcThreadEvent::CloseDataChannel(id) => controller.close_data_channel(&id),
162        RtcThreadEvent::SendDataChannelMessage(id, message) => {
163            controller.send_data_channel_message(&id, &message)
164        },
165        RtcThreadEvent::InternalEvent(e) => controller.internal_event(e),
166        RtcThreadEvent::Quit => {
167            controller.quit();
168            return false;
169        },
170    };
171    if let Err(e) = result {
172        error!("WebRTC backend encountered error: {:?}", e);
173    }
174    true
175}