servo_media_webrtc/
thread.rs

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