1use std::fmt;
2use std::net::IpAddr;
3
4use super::{
5 codec::{CodecInfo, MediaAttributes},
6 fmt::FMT_RTP_PAYLOAD_DYNAMIC,
7 ip::ip_addr_type,
8 time::unix_epoch_timestamp,
9 timing::TimeRange,
10};
11
12#[derive(Debug, Clone)]
13pub struct Sdp {
14 pub version: Version,
16 pub origin_username: String,
18 pub origin_session_id: String,
19 pub origin_session_version: String,
20 pub origin_network_type: NetworkType,
21 pub origin_address_type: AddressType,
22 pub origin_unicast_address: String,
23 pub session_name: String,
25 pub session_description: Option<String>,
27 pub connection_network_type: NetworkType,
29 pub connection_address_type: AddressType,
30 pub connection_address: String,
31 pub timing: (u64, u64),
33 pub tags: Vec<Tag>,
35 pub media: Vec<Media>,
37}
38
39impl Sdp {
40 pub fn new(origin: IpAddr, name: String, destination: IpAddr, time_range: TimeRange) -> Self {
41 Self {
42 version: Version::V0,
43 origin_username: "-".to_string(),
44 origin_session_id: unix_epoch_timestamp().to_string(),
45 origin_session_version: 0_u64.to_string(),
46 origin_network_type: NetworkType::Internet,
47 origin_address_type: ip_addr_type(&origin),
48 origin_unicast_address: origin.to_string(),
49 session_name: name,
50 session_description: None,
51 connection_network_type: NetworkType::Internet,
52 connection_address_type: ip_addr_type(&destination),
53 connection_address: destination.to_string(),
54 tags: Vec::new(),
55 timing: time_range.into(),
56 media: Vec::new(),
57 }
58 }
59
60 pub fn with_username(mut self, username: &str) -> Self {
61 self.origin_username = username.to_string();
62 self
63 }
64
65 pub fn with_session_version(mut self, version: usize) -> Self {
66 self.origin_session_version = version.to_string();
67 self
68 }
69
70 pub fn with_description(mut self, description: &str) -> Self {
71 self.session_description = Some(description.to_string());
72 self
73 }
74
75 pub fn with_tag(mut self, tag: Tag) -> Self {
76 self.tags.push(tag);
77 self
78 }
79
80 pub fn with_tags(mut self, tags: impl IntoIterator<Item = Tag>) -> Self {
81 self.tags.extend(tags);
82 self
83 }
84
85 pub fn with_media(
86 mut self,
87 kind: Kind,
88 port: u16,
89 protocol: Protocol,
90 codec_info: CodecInfo,
91 direction: Direction,
92 ) -> Self {
93 let mut tags = codec_info.media_attributes();
94 tags.push(Tag::Property(direction.to_string()));
95
96 self.media.push(Media {
97 kind,
98 port,
99 protocol,
100 format: FMT_RTP_PAYLOAD_DYNAMIC,
101 tags,
102 });
103 self
104 }
105}
106
107impl fmt::Display for Sdp {
108 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
109 writeln!(f, "v={}", self.version)?;
110 writeln!(
111 f,
112 "o={} {} {} {} {} {}",
113 self.origin_username,
114 self.origin_session_id,
115 self.origin_session_version,
116 self.origin_network_type,
117 self.origin_address_type,
118 self.origin_unicast_address
119 )?;
120
121 writeln!(f, "s={}", self.session_name)?;
122 if let Some(session_description) = self.session_description.as_ref() {
123 writeln!(f, "i={}", session_description)?;
124 }
125
126 writeln!(
127 f,
128 "c={} {} {}",
129 self.connection_network_type, self.connection_address_type, self.connection_address
130 )?;
131
132 writeln!(f, "t={} {}", self.timing.0, self.timing.1)?;
133
134 for tag in &self.tags {
135 writeln!(f, "a={}", tag)?;
136 }
137
138 for media in &self.media {
139 write!(f, "{}", media)?;
140 }
141
142 Ok(())
143 }
144}
145
146#[derive(Debug, Clone)]
147pub struct Media {
148 pub kind: Kind,
150 pub port: u16,
151 pub protocol: Protocol,
152 pub format: usize,
153 pub tags: Vec<Tag>,
155}
156
157impl fmt::Display for Media {
158 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159 writeln!(
160 f,
161 "m={} {} {} {}",
162 self.kind, self.port, self.protocol, self.format,
163 )?;
164
165 for tag in &self.tags {
166 writeln!(f, "a={}", tag)?;
167 }
168
169 Ok(())
170 }
171}
172
173#[derive(Debug, Clone)]
174pub struct Timing {
175 pub start: u64,
176 pub stop: u64,
177}
178
179impl fmt::Display for Timing {
180 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
181 write!(f, "{} {}", self.start, self.stop)
182 }
183}
184
185#[derive(Debug, Clone)]
186pub enum Version {
187 V0,
188}
189
190impl fmt::Display for Version {
191 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
192 match self {
193 Version::V0 => write!(f, "0"),
194 }
195 }
196}
197
198#[derive(Debug, Clone)]
199pub enum NetworkType {
200 Internet,
201}
202
203impl fmt::Display for NetworkType {
204 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205 match self {
206 NetworkType::Internet => write!(f, "IN"),
207 }
208 }
209}
210
211#[derive(Debug, Clone)]
212pub enum AddressType {
213 IpV4,
214 IpV6,
215}
216
217impl fmt::Display for AddressType {
218 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
219 match self {
220 AddressType::IpV4 => write!(f, "IP4"),
221 AddressType::IpV6 => write!(f, "IP6"),
222 }
223 }
224}
225
226#[derive(Debug, Clone)]
227pub enum Tag {
228 Property(String),
229 Value(String, String),
230}
231
232impl fmt::Display for Tag {
233 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
234 match self {
235 Tag::Property(value) => write!(f, "{value}"),
236 Tag::Value(variable, value) => write!(f, "{variable}:{value}"),
237 }
238 }
239}
240
241#[derive(Debug, Clone)]
242pub enum Direction {
243 ReceiveOnly,
244 SendOnly,
245 SendAndReceive,
246}
247
248impl fmt::Display for Direction {
249 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250 match self {
251 Direction::ReceiveOnly => write!(f, "recvonly"),
252 Direction::SendOnly => write!(f, "sendonly"),
253 Direction::SendAndReceive => write!(f, "sendrecv"),
254 }
255 }
256}
257
258#[derive(Debug, Clone)]
259pub enum Kind {
260 Video,
261 Audio,
262 Text,
263 Application,
264 Message,
265}
266
267impl fmt::Display for Kind {
268 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
269 match self {
270 Kind::Video => write!(f, "video"),
271 Kind::Audio => write!(f, "audio"),
272 Kind::Text => write!(f, "text"),
273 Kind::Application => write!(f, "application"),
274 Kind::Message => write!(f, "message"),
275 }
276 }
277}
278
279#[derive(Debug, Clone)]
280pub enum Protocol {
281 RtpAvp,
282 RtpSAvp,
283}
284
285impl fmt::Display for Protocol {
286 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
287 match self {
288 Protocol::RtpAvp => write!(f, "RTP/AVP"),
289 Protocol::RtpSAvp => write!(f, "RTP/SAVP"),
290 }
291 }
292}