freeswitch_types/sdp/
options.rs1use crate::sdp::{codec::SdpCodec, codec_string::CodecStringEntry, error::CodecStringError};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct CodecStringOptions {
25 emit_rate: bool,
26 emit_ptime: bool,
29 emit_bitrate: bool,
30 emit_channels: bool,
31 emit_fmtp: bool,
34}
35
36impl Default for CodecStringOptions {
37 fn default() -> Self {
39 Self {
40 emit_rate: true,
41 emit_ptime: true,
42 emit_bitrate: true,
43 emit_channels: true,
44 emit_fmtp: false,
45 }
46 }
47}
48
49impl CodecStringOptions {
50 pub fn audio() -> Self {
52 Self::default()
53 }
54
55 pub fn video() -> Self {
59 Self {
60 emit_rate: false,
61 emit_ptime: false,
62 emit_bitrate: false,
63 emit_channels: false,
64 emit_fmtp: true,
65 }
66 }
67
68 pub fn with_rate(mut self, emit: bool) -> Self {
70 self.emit_rate = emit;
71 self
72 }
73
74 pub fn with_ptime(mut self, emit: bool) -> Self {
82 self.emit_ptime = emit;
83 self
84 }
85
86 pub fn with_bitrate(mut self, emit: bool) -> Self {
88 self.emit_bitrate = emit;
89 self
90 }
91
92 pub fn with_channels(mut self, emit: bool) -> Self {
94 self.emit_channels = emit;
95 self
96 }
97
98 pub fn with_fmtp(mut self, emit: bool) -> Self {
100 self.emit_fmtp = emit;
101 self
102 }
103
104 pub fn emits_rate(&self) -> bool {
106 self.emit_rate
107 }
108
109 pub fn emits_ptime(&self) -> bool {
111 self.emit_ptime
112 }
113
114 pub fn emits_bitrate(&self) -> bool {
116 self.emit_bitrate
117 }
118
119 pub fn emits_channels(&self) -> bool {
121 self.emit_channels
122 }
123
124 pub fn emits_fmtp(&self) -> bool {
126 self.emit_fmtp
127 }
128
129 pub fn sdp_codec_to_entry(
134 &self,
135 codec: &SdpCodec,
136 ) -> Result<CodecStringEntry, CodecStringError> {
137 let mut entry = CodecStringEntry::new(codec.name())?;
138
139 if self.emit_fmtp {
140 if let Some(fmtp) = codec.fmtp() {
141 entry = entry.with_fmtp(fmtp)?;
143 }
144 }
145
146 Ok(self.apply_qualifiers(entry, codec))
147 }
148
149 pub(crate) fn apply_qualifiers(
156 &self,
157 mut entry: CodecStringEntry,
158 codec: &SdpCodec,
159 ) -> CodecStringEntry {
160 if self.emit_rate {
161 entry = entry.with_rate(codec.clock_rate());
162 }
163
164 if self.emit_ptime {
165 if let Some(p) = codec.ptime() {
166 entry = entry.with_ptime(p);
167 }
168 }
169
170 if self.emit_bitrate {
171 if let Some(b) = codec.bitrate() {
172 entry = entry.with_bitrate(b);
173 }
174 }
175
176 if self.emit_channels {
177 if let Some(c) = codec.channels() {
178 entry = entry.with_channels(c);
179 }
180 }
181
182 entry
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189 use crate::sdp::codec::SdpMediaType;
190
191 fn make_audio_codec(name: &str, rate: u32, ptime: u32) -> SdpCodec {
192 SdpCodec::new(SdpMediaType::Audio, 0, name, rate)
193 .with_channels(1)
194 .with_ptime(ptime)
195 .with_bitrate(64000)
196 }
197
198 fn make_video_codec(name: &str) -> SdpCodec {
199 SdpCodec::new(SdpMediaType::Video, 99, name, 90000)
200 .with_fmtp("profile-level-id=42e01f")
201 .with_rtpmap()
202 }
203
204 #[test]
207 fn audio_defaults_emit_rate_ptime_bitrate_channels_not_fmtp() {
208 let opts = CodecStringOptions::audio();
209 assert!(opts.emits_rate());
210 assert!(opts.emits_ptime());
211 assert!(opts.emits_bitrate());
212 assert!(opts.emits_channels());
213 assert!(!opts.emits_fmtp(), "audio fmtp must be off by default");
214 }
215
216 #[test]
217 fn video_defaults_emit_only_fmtp() {
218 let opts = CodecStringOptions::video();
219 assert!(!opts.emits_rate());
220 assert!(!opts.emits_ptime());
221 assert!(!opts.emits_bitrate());
222 assert!(!opts.emits_channels());
223 assert!(opts.emits_fmtp());
224 }
225
226 #[test]
229 fn audio_entry_has_rate_ptime_bitrate_no_fmtp() {
230 let codec = make_audio_codec("PCMU", 8000, 20);
231 let entry = CodecStringOptions::audio()
232 .sdp_codec_to_entry(&codec)
233 .unwrap();
234 assert_eq!(entry.name(), "PCMU");
235 assert_eq!(entry.rate(), Some(8000));
236 assert_eq!(entry.ptime(), Some(20));
237 assert_eq!(entry.bitrate(), Some(64000));
238 assert_eq!(entry.channels(), Some(1));
239 assert!(
240 entry
241 .fmtp()
242 .is_none(),
243 "audio fmtp must not be emitted by default"
244 );
245 }
246
247 #[test]
248 fn video_entry_emits_no_qualifiers() {
249 let codec = make_video_codec("H264");
250 let entry = CodecStringOptions::video()
251 .sdp_codec_to_entry(&codec)
252 .unwrap();
253 assert_eq!(entry.name(), "H264");
254 assert!(
255 entry
256 .rate()
257 .is_none(),
258 "video must not emit rate"
259 );
260 assert!(
261 entry
262 .ptime()
263 .is_none(),
264 "video must not emit ptime"
265 );
266 assert!(
267 entry
268 .bitrate()
269 .is_none(),
270 "video must not emit bitrate"
271 );
272 assert!(
273 entry
274 .channels()
275 .is_none(),
276 "video must not emit channels"
277 );
278 assert_eq!(
279 entry.fmtp(),
280 Some("profile-level-id=42e01f"),
281 "video must emit fmtp"
282 );
283 }
284
285 #[test]
288 fn codec_string_options_clone_and_eq() {
289 let a = CodecStringOptions::audio();
290 let b = a.clone();
291 assert_eq!(a, b);
292 let c = CodecStringOptions::video();
293 assert_ne!(a, c);
294 }
295}