1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
use super::ffi;
use super::libc;
pub use ffi::sdp::janus_sdp_generate_answer as generate_answer;
use std::collections::HashMap;
use std::error::Error;
use std::ffi::CString;
use std::ops::Deref;
use std::str;
use utils::GLibString;
pub type RawSdp = ffi::sdp::janus_sdp;
pub type RawMLine = ffi::sdp::janus_sdp_mline;
pub use ffi::sdp::janus_sdp_mtype as MediaType;
pub use ffi::sdp::janus_sdp_mdirection as MediaDirection;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum AudioCodec {
Opus,
Pcmu,
Pcma,
G722,
Isac16,
Isac32,
}
impl AudioCodec {
pub fn to_str(&self) -> &'static str {
match *self {
AudioCodec::Opus => "opus",
AudioCodec::Pcmu => "pcmu",
AudioCodec::Pcma => "pcma",
AudioCodec::G722 => "g722",
AudioCodec::Isac16 => "isac16",
AudioCodec::Isac32 => "isac32",
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum VideoCodec {
Vp8,
Vp9,
H264,
}
impl VideoCodec {
pub fn to_str(&self) -> &'static str {
match *self {
VideoCodec::Vp8 => "vp8",
VideoCodec::Vp9 => "vp9",
VideoCodec::H264 => "h264",
}
}
}
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum OfferAnswerParameters {
Done = 0,
Audio = 1,
Video = 2,
Data = 3,
AudioDirection = 4,
VideoDirection = 5,
AudioCodec = 6,
VideoCodec = 7,
AudioPayloadType = 8,
VideoPayloadType = 9,
AudioDtmf = 10,
VideoRtcpfbDefaults = 11,
VideoH264Fmtp = 12,
}
#[derive(Debug)]
pub struct Sdp {
pub ptr: *mut RawSdp,
}
impl Sdp {
pub unsafe fn new(ptr: *mut RawSdp) -> Option<Self> {
ptr.as_mut().map(|p| Self { ptr: p })
}
pub fn parse(offer: CString) -> Result<Self, Box<Error>> {
let mut error_buffer = Vec::with_capacity(512);
let error_ptr = error_buffer.as_mut_ptr() as *mut _;
unsafe {
let result = ffi::sdp::janus_sdp_parse(offer.as_ptr(), error_ptr, error_buffer.capacity());
Sdp::new(result).ok_or_else(|| {
error_buffer.set_len(libc::strlen(error_ptr));
From::from(str::from_utf8(&error_buffer).expect("SDP error not valid UTF-8 :("))
})
}
}
pub fn get_mlines(&self) -> HashMap<MediaType, Vec<&RawMLine>> {
let mut result = HashMap::new();
unsafe {
let mut ml_node = (*self.ptr).m_lines;
loop {
match ml_node.as_ref() {
None => return result,
Some(node) => {
let ml = (node.data as *const RawMLine).as_ref().expect("Null data in SDP media node :(");
result.entry(ml.type_).or_insert_with(Vec::new).push(ml);
ml_node = node.next;
}
}
}
}
}
pub fn to_string(&self) -> GLibString {
unsafe {
let sdp = ffi::sdp::janus_sdp_write(self.ptr);
GLibString::from_chars(sdp).expect("Mysterious error writing SDP to string :(")
}
}
}
impl Deref for Sdp {
type Target = RawSdp;
fn deref(&self) -> &RawSdp {
unsafe { &*self.ptr }
}
}
impl Drop for Sdp {
fn drop(&mut self) {
unsafe { ffi::sdp::janus_sdp_free(self.ptr) }
}
}
unsafe impl Send for Sdp {}
#[macro_export]
macro_rules! answer_sdp {
($sdp:expr $(, $param:expr, $value:expr),*) => {{
unsafe {
let result = $crate::sdp::generate_answer(
$sdp.ptr,
$($param, $value,)*
$crate::sdp::OfferAnswerParameters::Done
);
$crate::sdp::Sdp::new(result).expect("Mysterious error generating SDP answer :(")
}
}}
}