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)]
15pub 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 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 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
107pub 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 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}