Skip to main content

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