1use std::ffi::{c_void, CStr, CString};
2use std::os::raw::c_char;
3use std::{ptr, slice};
4
5use datachannel_sys as sys;
6use webrtc_sdp::media_type::{parse_media_vector, SdpMedia};
7use webrtc_sdp::{parse_sdp_line, SdpLine};
8
9use crate::error::{check, Result};
10use crate::logger;
11
12#[derive(Debug, Clone, Copy)]
13#[cfg_attr(any(not(target_os = "windows"), target_env = "gnu"), repr(u32))]
14#[cfg_attr(all(target_os = "windows", not(target_env = "gnu")), repr(i32))]
15pub enum Direction {
16 Unknown = sys::rtcDirection_RTC_DIRECTION_UNKNOWN,
17 SendOnly = sys::rtcDirection_RTC_DIRECTION_SENDONLY,
18 RecvOnly = sys::rtcDirection_RTC_DIRECTION_RECVONLY,
19 SendRecv = sys::rtcDirection_RTC_DIRECTION_SENDRECV,
20 Inactive = sys::rtcDirection_RTC_DIRECTION_INACTIVE,
21}
22
23#[cfg(any(not(target_os = "windows"), target_env = "gnu"))]
24impl TryFrom<u32> for Direction {
25 type Error = ();
26
27 fn try_from(v: u32) -> std::result::Result<Self, Self::Error> {
28 match v {
29 x if x == Self::Unknown as u32 => Ok(Self::Unknown),
30 x if x == Self::SendOnly as u32 => Ok(Self::SendOnly),
31 x if x == Self::RecvOnly as u32 => Ok(Self::RecvOnly),
32 x if x == Self::SendRecv as u32 => Ok(Self::SendRecv),
33 x if x == Self::Inactive as u32 => Ok(Self::Inactive),
34 _ => Err(()),
35 }
36 }
37}
38
39#[cfg(all(target_os = "windows", not(target_env = "gnu")))]
40impl TryFrom<i32> for Direction {
41 type Error = ();
42
43 fn try_from(v: i32) -> std::result::Result<Self, Self::Error> {
44 match v {
45 x if x == Self::Unknown as i32 => Ok(Self::Unknown),
46 x if x == Self::SendOnly as i32 => Ok(Self::SendOnly),
47 x if x == Self::RecvOnly as i32 => Ok(Self::RecvOnly),
48 x if x == Self::SendRecv as i32 => Ok(Self::SendRecv),
49 x if x == Self::Inactive as i32 => Ok(Self::Inactive),
50 _ => Err(()),
51 }
52 }
53}
54
55#[derive(Debug, Clone, Copy)]
56#[cfg_attr(any(not(target_os = "windows"), target_env = "gnu"), repr(u32))]
57#[cfg_attr(all(target_os = "windows", not(target_env = "gnu")), repr(i32))]
58pub enum Codec {
59 H264 = sys::rtcCodec_RTC_CODEC_H264,
60 VP8 = sys::rtcCodec_RTC_CODEC_VP8,
61 VP9 = sys::rtcCodec_RTC_CODEC_VP9,
62 Opus = sys::rtcCodec_RTC_CODEC_OPUS,
63}
64
65#[derive(Debug, Clone)]
66pub struct TrackInit {
67 pub direction: Direction,
68 pub codec: Codec,
69 pub payload_type: i32,
70 pub ssrc: u32,
71 pub mid: CString,
72 pub name: Option<CString>,
73 pub msid: Option<CString>,
74 pub track_id: Option<CString>,
75 pub profile: Option<CString>,
76}
77
78impl TrackInit {
79 pub(crate) fn as_raw(&self) -> sys::rtcTrackInit {
80 sys::rtcTrackInit {
81 direction: self.direction as _,
82 codec: self.codec as _,
83 payloadType: self.payload_type,
84 ssrc: self.ssrc,
85 mid: self.mid.as_ptr(),
86 name: self
87 .name
88 .as_ref()
89 .map(|s| s.as_ptr())
90 .unwrap_or(std::ptr::null()),
91 msid: self
92 .msid
93 .as_ref()
94 .map(|s| s.as_ptr())
95 .unwrap_or(std::ptr::null()),
96 trackId: self
97 .track_id
98 .as_ref()
99 .map(|s| s.as_ptr())
100 .unwrap_or(std::ptr::null()),
101 profile: self
102 .profile
103 .as_ref()
104 .map(|s| s.as_ptr())
105 .unwrap_or(std::ptr::null()),
106 }
107 }
108}
109
110#[allow(unused_variables)]
111pub trait TrackHandler {
112 fn on_open(&mut self) {}
113 fn on_closed(&mut self) {}
114 fn on_error(&mut self, err: &str) {}
115 fn on_message(&mut self, msg: &[u8]) {}
116 fn on_available(&mut self) {}
117}
118
119pub struct RtcTrack<T> {
120 id: i32,
121 t_handler: T,
122}
123
124impl<T> RtcTrack<T>
125where
126 T: TrackHandler + Send,
127{
128 pub(crate) fn new(id: i32, t_handler: T) -> Result<Box<Self>> {
129 unsafe {
130 let mut rtc_t = Box::new(RtcTrack { id, t_handler });
131 let ptr = &mut *rtc_t;
132
133 sys::rtcSetUserPointer(id, ptr as *mut _ as *mut c_void);
134
135 check(sys::rtcSetOpenCallback(id, Some(RtcTrack::<T>::open_cb)))?;
136
137 check(sys::rtcSetClosedCallback(
138 id,
139 Some(RtcTrack::<T>::closed_cb),
140 ))?;
141
142 check(sys::rtcSetErrorCallback(id, Some(RtcTrack::<T>::error_cb)))?;
143
144 check(sys::rtcSetMessageCallback(
145 id,
146 Some(RtcTrack::<T>::message_cb),
147 ))?;
148
149 check(sys::rtcSetAvailableCallback(
150 id,
151 Some(RtcTrack::<T>::available_cb),
152 ))?;
153
154 Ok(rtc_t)
155 }
156 }
157
158 unsafe extern "C" fn open_cb(_: i32, ptr: *mut c_void) {
159 let rtc_t = &mut *(ptr as *mut RtcTrack<T>);
160 rtc_t.t_handler.on_open()
161 }
162
163 unsafe extern "C" fn closed_cb(_: i32, ptr: *mut c_void) {
164 let rtc_t = &mut *(ptr as *mut RtcTrack<T>);
165 rtc_t.t_handler.on_closed()
166 }
167
168 unsafe extern "C" fn error_cb(_: i32, err: *const c_char, ptr: *mut c_void) {
169 let rtc_t = &mut *(ptr as *mut RtcTrack<T>);
170 let err = CStr::from_ptr(err).to_string_lossy();
171 rtc_t.t_handler.on_error(&err)
172 }
173
174 unsafe extern "C" fn message_cb(_: i32, msg: *const c_char, size: i32, ptr: *mut c_void) {
175 let rtc_t = &mut *(ptr as *mut RtcTrack<T>);
176 let msg = if size < 0 {
177 CStr::from_ptr(msg).to_bytes()
178 } else {
179 slice::from_raw_parts(msg as *const u8, size as usize)
180 };
181 rtc_t.t_handler.on_message(msg)
182 }
183
184 unsafe extern "C" fn available_cb(_: i32, ptr: *mut c_void) {
185 let rtc_t = &mut *(ptr as *mut RtcTrack<T>);
186 rtc_t.t_handler.on_available()
187 }
188
189 pub fn send(&mut self, msg: &[u8]) -> Result<()> {
190 check(unsafe {
191 sys::rtcSendMessage(self.id, msg.as_ptr() as *const c_char, msg.len() as i32)
192 })
193 .map(|_| ())
194 }
195
196 pub fn description(&self) -> Option<Vec<SdpMedia>> {
197 let buf_size = check(unsafe {
198 sys::rtcGetTrackDescription(self.id, ptr::null_mut() as *mut c_char, 0)
199 })
200 .expect("Couldn't get buffer size") as usize;
201
202 let mut buf = vec![0; buf_size];
203 check(unsafe {
204 sys::rtcGetTrackDescription(self.id, buf.as_mut_ptr() as *mut c_char, buf_size as i32)
205 })
206 .map_err(|err| {
207 logger::warn!(
208 "Couldn't get description for RtcTrack id={} {:p}, {}",
209 self.id,
210 self,
211 err
212 );
213 })
214 .ok()
215 .and_then(|_| {
216 crate::ffi_string(&buf)
217 .map_err(|err| {
218 logger::error!(
219 "Couldn't get description for RtcTrack id={} {:p}, {}",
220 self.id,
221 self,
222 err
223 );
224 })
225 .ok()
226 })
227 .and_then(|description| {
228 description
229 .split('\n')
230 .enumerate()
231 .map(|(line_number, line)| parse_sdp_line(line, line_number))
232 .collect::<std::result::Result<Vec<SdpLine>, _>>()
233 .map_err(|err| logger::error!("Couldn't parse SdpLine: {}", err))
234 .ok()
235 })
236 .and_then(|mut sdp_lines| {
237 parse_media_vector(&mut sdp_lines)
238 .map_err(|err| logger::error!("Couldn't parse SdpMedia: {}", err))
239 .ok()
240 })
241 }
242
243 pub fn mid(&self) -> String {
244 let buf_size =
245 check(unsafe { sys::rtcGetTrackMid(self.id, ptr::null_mut() as *mut c_char, 0) })
246 .expect("Couldn't get buffer size") as usize;
247
248 let mut buf = vec![0; buf_size];
249 check(unsafe {
250 sys::rtcGetTrackMid(self.id, buf.as_mut_ptr() as *mut c_char, buf_size as i32)
251 })
252 .map_err(|err| {
253 logger::warn!(
254 "Couldn't get mid for RtcTrack id={} {:p}, {}",
255 self.id,
256 self,
257 err
258 );
259 })
260 .ok()
261 .and_then(|_| {
262 crate::ffi_string(&buf)
263 .map_err(|err| {
264 logger::error!(
265 "Couldn't get mid for RtcTrack id={} {:p}, {}",
266 self.id,
267 self,
268 err
269 );
270 })
271 .ok()
272 })
273 .unwrap_or_default()
274 }
275
276 pub fn direction(&self) -> Direction {
277 let mut direction = sys::rtcDirection_RTC_DIRECTION_UNKNOWN;
278 check(unsafe { sys::rtcGetTrackDirection(self.id, &mut direction) })
279 .expect("Couldn't get RtcTrack direction");
280 Direction::try_from(direction).unwrap_or(Direction::Unknown)
281 }
282}
283
284impl<T> Drop for RtcTrack<T> {
285 fn drop(&mut self) {
286 if let Err(err) = check(unsafe { sys::rtcDeleteTrack(self.id) }) {
287 logger::error!(
288 "Error while dropping RtcTrack id={} {:p}: {}",
289 self.id,
290 self,
291 err
292 );
293 }
294 }
295}