aboutsummaryrefslogtreecommitdiff
path: root/sdp/src/lib.rs
blob: 68c3c7060c6eb30c203b19bf2db9ece3ae018219 (plain)
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
use anyhow::{anyhow, bail};
use std::str::FromStr;

pub struct SessionDescription {
    pub version: String,
    pub originator: String,
    pub session_name: String,
    pub session_information: Option<String>,
    pub description_uri: Option<String>,
    pub email_address: Option<String>,
    pub phone_number: Option<String>,
    pub connection_information: Option<String>,
    pub bandwidth: Vec<String>,
    pub time_descriptions: Vec<TimeDescription>,
    pub time_zone_adjustments: Option<String>,
    pub encryption_key: Option<String>,
    pub attributes: Vec<String>,
    pub media_descriptions: Vec<MediaDescription>,
}

pub struct TimeDescription {
    pub time: String,
    pub repeat_times: Vec<String>,
}

pub struct MediaDescription {
    pub name: String,
    pub title: Option<String>,
    pub connection_information: Option<String>,
    pub bandwidth: Vec<String>,
    pub encryption_key: Option<String>,
    pub attributes: Vec<String>,
}

impl FromStr for SessionDescription {
    type Err = anyhow::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut version = None;
        let mut originator = None;
        let mut session_name = None;
        let mut session_information = None;
        let mut description_uri = None;
        let mut email_address = None;
        let mut phone_number = None;
        let mut connection_information = None;
        let mut encryption_key = None;
        let mut time_zone_adjustments = None;
        let mut bandwidth = Vec::new();
        let mut time_descriptions = Vec::new();
        let mut media_descriptions = Vec::new();
        let mut attributes = Vec::new();
        for line in s.lines() {
            let (r#type, value) = line.split_once("=").ok_or(anyhow!("sdp line invalid"))?;
            match r#type {
                "v" => version = Some(value.to_string()),
                "o" => originator = Some(value.to_string()),
                "s" => session_name = Some(value.to_string()),
                "i" => session_information = Some(value.to_string()),
                "u" => description_uri = Some(value.to_string()),
                "e" => email_address = Some(value.to_string()),
                "p" => phone_number = Some(value.to_string()),
                "t" => time_descriptions.push(TimeDescription {
                    repeat_times: Vec::new(),
                    time: value.to_string(),
                }),
                "r" => time_descriptions
                    .last_mut()
                    .ok_or(anyhow!("no time desc"))?
                    .repeat_times
                    .push(value.to_string()),
                "z" => time_zone_adjustments = Some(value.to_string()),
                "m" => media_descriptions.push(MediaDescription {
                    connection_information: None,
                    name: value.to_string(),
                    title: None,
                    encryption_key: None,
                    attributes: Vec::new(),
                    bandwidth: Vec::new(),
                }),
                "a" => {
                    if let Some(media_desc) = media_descriptions.last_mut() {
                        media_desc.attributes.push(value.to_string())
                    } else {
                        attributes.push(value.to_string())
                    }
                }
                "b" => {
                    if let Some(media_desc) = media_descriptions.last_mut() {
                        media_desc.bandwidth.push(value.to_string())
                    } else {
                        bandwidth.push(value.to_string())
                    }
                }
                "k" => {
                    if let Some(key) = media_descriptions.last_mut() {
                        key.encryption_key = Some(value.to_string())
                    } else {
                        encryption_key = Some(value.to_string())
                    }
                }
                "c" => {
                    if let Some(media_desc) = media_descriptions.last_mut() {
                        media_desc.connection_information = Some(value.to_string())
                    } else {
                        connection_information = Some(value.to_string())
                    }
                }
                x => bail!("unknown sdp type ({x:?})"),
            }
        }
        Ok(Self {
            bandwidth,
            connection_information,
            attributes,
            description_uri,
            email_address,
            encryption_key,
            phone_number,
            session_information,
            time_zone_adjustments,
            media_descriptions,
            originator: originator.ok_or(anyhow!("originator missing"))?,
            session_name: session_name.ok_or(anyhow!("session name missing"))?,
            version: version.ok_or(anyhow!("version missing"))?,
            time_descriptions,
        })
    }
}