1use std::{
16 error::Error,
17 fmt::{Display, Formatter},
18};
19
20use crate::impl_thread_safety;
21
22#[cxx::bridge(namespace = "livekit")]
23pub mod ffi {
24 #[derive(Debug)]
25 #[repr(i32)]
26 pub enum SdpType {
27 Offer,
28 PrAnswer,
29 Answer,
30 Rollback,
31 }
32
33 #[derive(Debug)]
34 pub struct SdpParseError {
35 pub line: String,
36 pub description: String,
37 }
38
39 extern "C++" {
40 include!("livekit/rtc_error.h");
41
42 type RtcError = crate::rtc_error::ffi::RtcError;
43 }
44
45 unsafe extern "C++" {
46 include!("livekit/jsep.h");
47
48 type IceCandidate;
49 type SessionDescription;
50
51 fn sdp_mid(self: &IceCandidate) -> String;
52 fn sdp_mline_index(self: &IceCandidate) -> i32;
53 fn candidate(self: &IceCandidate) -> String;
54 fn stringify(self: &IceCandidate) -> String;
55
56 fn sdp_type(self: &SessionDescription) -> SdpType;
57 fn stringify(self: &SessionDescription) -> String;
58 fn clone(self: &SessionDescription) -> UniquePtr<SessionDescription>;
59
60 fn create_ice_candidate(
61 sdp_mid: String,
62 sdp_mline_index: i32,
63 sdp: String,
64 ) -> Result<SharedPtr<IceCandidate>>;
65
66 fn create_session_description(
67 sdp_type: SdpType,
68 sdp: String,
69 ) -> Result<UniquePtr<SessionDescription>>;
70
71 fn _shared_ice_candidate() -> SharedPtr<IceCandidate>; fn _unique_session_description() -> UniquePtr<SessionDescription>; }
74}
75
76impl Error for ffi::SdpParseError {}
77
78impl Display for ffi::SdpParseError {
79 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
80 write!(f, "SdpParseError occurred {}: {}", self.line, self.description)
81 }
82}
83
84impl_thread_safety!(ffi::SessionDescription, Send + Sync);
85impl_thread_safety!(ffi::IceCandidate, Send + Sync);
86
87impl ffi::SdpParseError {
88 pub unsafe fn from(value: &str) -> Self {
91 let line_length = u32::from_str_radix(&value[0..8], 16).unwrap() as usize + 8;
93 let line = String::from(&value[8..line_length]);
94 let description = String::from(&value[line_length..]);
95
96 Self { line, description }
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use log::info;
103
104 use crate::jsep::ffi;
105
106 #[test]
107 fn throw_error() {
108 let sdp_string = "v=0
109o=- 6549709950142776241 2 IN IP4 127.0.0.1
110s=-
111t=0 0
112======================== ERROR HERE
113a=group:BUNDLE 0
114a=extmap-allow-mixed
115a=msid-semantic: WMS
116m=application 9 UDP/DTLS/SCTP webrtc-datachannel
117c=IN IP4 0.0.0.0
118a=ice-ufrag:Tw7h
119a=ice-pwd:6XOVUD6HpcB4c1M8EB8jXJE9
120a=ice-options:trickle
121a=fingerprint:sha-256 4F:EC:23:59:5D:A5:E6:3E:3E:5D:8A:09:B6:FA:04:AA:19:99:49:67:BD:65:93:06:BB:EE:AC:D5:21:0F:57:D6
122a=setup:actpass
123a=mid:0
124a=sctp-port:5000
125a=max-message-size:262144
126";
127
128 let sdp = ffi::create_session_description(ffi::SdpType::Offer, sdp_string.to_string());
129 let err = unsafe { ffi::SdpParseError::from(sdp.err().unwrap().what()) };
130 info!("parse err: {:?}", err)
131 }
132}