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(
45        &self,
46        desc: SessionDescription,
47        cb: Box<dyn FnOnce() + Send + 'static>,
48    ) {
49        let _ = self
50            .sender
51            .send(RtcThreadEvent::SetRemoteDescription(desc, cb));
52    }
53    pub fn set_local_description(
54        &self,
55        desc: SessionDescription,
56        cb: Box<dyn FnOnce() + Send + 'static>,
57    ) {
58        let _ = self
59            .sender
60            .send(RtcThreadEvent::SetLocalDescription(desc, cb));
61    }
62    pub fn add_ice_candidate(&self, candidate: IceCandidate) {
63        let _ = self.sender.send(RtcThreadEvent::AddIceCandidate(candidate));
64    }
65    pub fn create_offer(&self, cb: Box<dyn FnOnce(SessionDescription) + Send + 'static>) {
66        let _ = self.sender.send(RtcThreadEvent::CreateOffer(cb));
67    }
68    pub fn create_answer(&self, cb: Box<dyn FnOnce(SessionDescription) + Send + 'static>) {
69        let _ = self.sender.send(RtcThreadEvent::CreateAnswer(cb));
70    }
71    pub fn add_stream(&self, stream: &MediaStreamId) {
72        let _ = self.sender.send(RtcThreadEvent::AddStream(stream.clone()));
73    }
74    pub fn create_data_channel(&self, init: DataChannelInit) -> Option<DataChannelId> {
75        let (sender, receiver) = channel();
76        let _ = self
77            .sender
78            .send(RtcThreadEvent::CreateDataChannel(init, sender));
79        receiver.recv().unwrap()
80    }
81    pub fn send_data_channel_message(&self, id: &DataChannelId, message: DataChannelMessage) {
82        let _ = self
83            .sender
84            .send(RtcThreadEvent::SendDataChannelMessage(*id, message));
85    }
86    pub fn close_data_channel(&self, id: &DataChannelId) {
87        let _ = self.sender.send(RtcThreadEvent::CloseDataChannel(*id));
88    }
89
90    /// This should not be invoked by clients
91    pub fn internal_event(&self, event: InternalEvent) {
92        let _ = self.sender.send(RtcThreadEvent::InternalEvent(event));
93    }
94
95    pub fn quit(&self) {
96        let _ = self.sender.send(RtcThreadEvent::Quit);
97    }
98}
99
100pub enum RtcThreadEvent {
101    ConfigureStun(String, BundlePolicy),
102    SetRemoteDescription(SessionDescription, Box<dyn FnOnce() + Send + 'static>),
103    SetLocalDescription(SessionDescription, Box<dyn FnOnce() + Send + 'static>),
104    AddIceCandidate(IceCandidate),
105    CreateOffer(Box<dyn FnOnce(SessionDescription) + Send + 'static>),
106    CreateAnswer(Box<dyn FnOnce(SessionDescription) + Send + 'static>),
107    AddStream(MediaStreamId),
108    CreateDataChannel(DataChannelInit, Sender<Option<DataChannelId>>),
109    CloseDataChannel(DataChannelId),
110    SendDataChannelMessage(DataChannelId, DataChannelMessage),
111    InternalEvent(InternalEvent),
112    Quit,
113}
114
115/// To allow everything to occur on the event loop,
116/// the backend may need to send signals to itself
117///
118/// This is a somewhat leaky abstraction, but we don't
119/// plan on having too many backends anyway
120pub enum InternalEvent {
121    OnNegotiationNeeded,
122    OnIceCandidate(IceCandidate),
123    OnAddStream(MediaStreamId, MediaStreamType),
124    OnDataChannelEvent(DataChannelId, DataChannelEvent),
125    DescriptionAdded(
126        Box<dyn FnOnce() + Send + 'static>,
127        DescriptionType,
128        SdpType,
129        /* remote offer generation */ u32,
130    ),
131    UpdateSignalingState,
132    UpdateGatheringState,
133    UpdateIceConnectionState,
134}
135
136pub fn handle_rtc_event(
137    controller: &mut dyn WebRtcControllerBackend,
138    event: RtcThreadEvent,
139) -> bool {
140    let result = match event {
141        RtcThreadEvent::ConfigureStun(server, policy) => controller.configure(&server, policy),
142        RtcThreadEvent::SetRemoteDescription(desc, cb) => {
143            controller.set_remote_description(desc, cb)
144        },
145        RtcThreadEvent::SetLocalDescription(desc, cb) => controller.set_local_description(desc, cb),
146        RtcThreadEvent::AddIceCandidate(candidate) => controller.add_ice_candidate(candidate),
147        RtcThreadEvent::CreateOffer(cb) => controller.create_offer(cb),
148        RtcThreadEvent::CreateAnswer(cb) => controller.create_answer(cb),
149        RtcThreadEvent::AddStream(media) => controller.add_stream(&media),
150        RtcThreadEvent::CreateDataChannel(init, sender) => controller
151            .create_data_channel(&init)
152            .map(|id| {
153                let _ = sender.send(Some(id));
154                ()
155            })
156            .map_err(|e| {
157                let _ = sender.send(None);
158                e
159            }),
160        RtcThreadEvent::CloseDataChannel(id) => controller.close_data_channel(&id),
161        RtcThreadEvent::SendDataChannelMessage(id, message) => {
162            controller.send_data_channel_message(&id, &message)
163        },
164        RtcThreadEvent::InternalEvent(e) => controller.internal_event(e),
165        RtcThreadEvent::Quit => {
166            controller.quit();
167            return false;
168        },
169    };
170    if let Err(e) = result {
171        error!("WebRTC backend encountered error: {:?}", e);
172    }
173    true
174}