1use super::FtlError;
2
3#[derive(Default, Debug, Clone)]
4pub struct Vendor {
5 pub name: Option<String>,
6 pub version: Option<String>,
7}
8
9#[derive(Default, Debug, Clone)]
10pub struct Video {
11 pub codec: Option<String>,
12 pub height: Option<isize>,
13 pub width: Option<isize>,
14 pub payload_type: Option<u8>,
15 pub ssrc: Option<u32>,
16}
17
18#[derive(Default, Debug, Clone)]
19pub struct Audio {
20 pub codec: Option<String>,
21 pub payload_type: Option<u8>,
22 pub ssrc: Option<u32>,
23}
24
25#[derive(Default, Debug, Clone)]
26pub struct FtlHandshake {
27 pub protocol_version: Option<(isize, isize)>,
28 pub vendor: Vendor,
29 pub video: Option<Video>,
30 pub audio: Option<Audio>,
31}
32
33impl FtlHandshake {
34 pub fn insert(&mut self, key: String, value: String) -> Result<(), FtlError> {
36 match key.as_ref() {
38 "ProtocolVersion" => {
39 let mut parts = value.split('.');
40 self.protocol_version = Some((
41 parts.next().unwrap().parse().unwrap(),
42 parts.next().unwrap().parse().unwrap()
43 ));
44 }
45 "VendorName" => self.vendor.name = Some(value),
46 "VendorVersion" => self.vendor.version = Some(value),
47 "Video" |
48 "Audio" => match value.as_ref() {
49 "true" => {
50 if key == "Video" {
51 self.video = Some(Video::default());
52 } else {
53 self.audio = Some(Audio::default());
54 }
55 },
56 "false" => {},
57 _ => panic!("Failed to deserialise boolean.")
58 }
59 "VideoCodec" |
60 "VideoHeight" |
61 "VideoWidth" |
62 "VideoPayloadType" |
63 "VideoIngestSSRC" => if let Some(mut video) = self.video.as_mut() {
64 match key.as_ref() {
65 "VideoCodec" => video.codec = Some(value),
66 "VideoHeight" => video.height = Some(value.parse().unwrap()),
67 "VideoWidth" => video.width = Some(value.parse().unwrap()),
68 "VideoPayloadType" => video.payload_type = Some(value.parse().unwrap()),
69 "VideoIngestSSRC" => video.ssrc = Some(value.parse().unwrap()),
70 _ => unreachable!()
71 }
72 }
73 "AudioCodec" |
74 "AudioPayloadType" |
75 "AudioIngestSSRC" => if let Some(mut audio) = self.audio.as_mut() {
76 match key.as_ref() {
77 "AudioCodec" => audio.codec = Some(value),
78 "AudioPayloadType" => audio.payload_type = Some(value.parse().unwrap()),
79 "AudioIngestSSRC" => audio.ssrc = Some(value.parse().unwrap()),
80 _ => unreachable!()
81 }
82 }
83 _ => {}
84 }
85
86 Ok(())
87 }
88}
89
90#[derive(Debug, Clone)]
92pub struct KnownVideo {
93 pub codec: String,
94 pub height: isize,
95 pub width: isize,
96 pub payload_type: u8,
97 pub ssrc: u32,
98}
99
100#[derive(Debug, Clone)]
101pub struct KnownAudio {
102 pub codec: String,
103 pub payload_type: u8,
104 pub ssrc: u32,
105}
106
107#[derive(Debug, Clone)]
108pub struct FtlHandshakeFinalised {
109 pub protocol_version: (isize, isize),
110 pub vendor: Vendor,
111 pub video: Option<KnownVideo>,
112 pub audio: Option<KnownAudio>,
113}
114
115impl FtlHandshake {
116 pub fn finalise(self) -> Result<FtlHandshakeFinalised, FtlError> {
117 Ok(FtlHandshakeFinalised {
118 protocol_version: if let Some((major, minor)) = self.protocol_version {
119 if major != 0 && minor != 9 {
120 return Err(FtlError::UnsupportedProtocolVersion)
121 }
122
123 (major, minor)
124 } else {
125 return Err(FtlError::InvalidProtocolVersion)
126 },
127 vendor: self.vendor,
128 video: if let Some(video) = self.video {
129 match (video.codec, video.width, video.height, video.payload_type, video.ssrc) {
130 (Some(codec), Some(width), Some(height), Some(payload_type), Some(ssrc)) =>
131 Some(KnownVideo { codec, width, height, payload_type, ssrc }),
132 _ => return Err(FtlError::MissingCodecInformation)
133 }
134 } else { None },
135 audio: if let Some(audio) = self.audio {
136 match (audio.codec, audio.payload_type, audio.ssrc) {
137 (Some(codec), Some(payload_type), Some(ssrc)) =>
138 Some(KnownAudio { codec, payload_type, ssrc }),
139 _ => return Err(FtlError::MissingCodecInformation)
140 }
141 } else { None }
142 })
143 }
144}
145#[cfg(test)]
148mod tests {
149 #[test]
150 fn full_test() {
151 use crate::protocol::{FtlCommand, FtlHandshake};
152
153 let mut handshake = FtlHandshake::default();
155
156 let command = FtlCommand::Attribute {
158 key: "ProtocolVersion".to_string(),
159 value: "0.9".to_string()
160 };
161
162 if let FtlCommand::Attribute { key, value } = command {
164 handshake.insert(key, value).unwrap();
165 }
168
169 let handshake = handshake.finalise().unwrap();
175 assert_eq!(handshake.protocol_version.1, 9);
176 }
177}