1use std::{
16 error::Error,
17 fmt::{Display, Formatter},
18};
19
20use crate::impl_thread_safety;
21
22#[cxx::bridge(namespace = "livekit_ffi")]
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 #[cxx::bridge(namespace = "livekit_ffi")]
103 pub mod ffi_tests {
104 unsafe extern "C++" {
105 include!("livekit/jsep.h");
106
107 fn serialize_sdp_parse_error_for_test() -> String;
108 }
109 }
110
111 use crate::jsep::ffi;
112
113 #[test]
116 fn sdp_parse_error_deserialization() {
117 let serialized = ffi_tests::serialize_sdp_parse_error_for_test();
118 let err = unsafe { ffi::SdpParseError::from(&serialized) };
119
120 assert!(!err.line.is_empty(), "error line should not be empty");
121 assert!(!err.description.is_empty(), "error description should not be empty");
122 }
123}