xref: /xiu/protocol/rtmp/src/amf0/amf0_reader.rs (revision 5377b641)
1 use {
2     super::{amf0_markers, errors::Amf0ReadErrorValue, Amf0ReadError, Amf0ValueType},
3     byteorder::BigEndian,
4     bytes::BytesMut,
5     networkio::bytes_reader::BytesReader,
6     std::collections::HashMap,
7 };
8 
9 pub struct Amf0Reader {
10     reader: BytesReader,
11 }
12 
13 impl Amf0Reader {
14     pub fn new(reader: BytesReader) -> Self {
15         Self { reader: reader }
16     }
17     pub fn read_all(&mut self) -> Result<Vec<Amf0ValueType>, Amf0ReadError> {
18         let mut results = vec![];
19 
20         loop {
21             let result = self.read_any()?;
22 
23             match result {
24                 Amf0ValueType::END => {
25                     break;
26                 }
27                 _ => {
28                     results.push(result);
29                 }
30             }
31         }
32 
33         Ok(results)
34     }
35     pub fn read_any(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
36         if self.reader.len() == 0 {
37             return Ok(Amf0ValueType::END);
38         }
39         let markers = self.reader.read_u8()?;
40 
41         if markers == amf0_markers::OBJECT_END {
42             return Ok(Amf0ValueType::END);
43         }
44 
45         match markers {
46             amf0_markers::NUMBER => self.read_number(),
47             amf0_markers::BOOLEAN => self.read_bool(),
48             amf0_markers::STRING => self.read_string(),
49             amf0_markers::OBJECT => self.read_object(),
50             amf0_markers::NULL => self.read_null(),
51             amf0_markers::ECMA_ARRAY => self.read_ecma_array(),
52             amf0_markers::LONG_STRING => self.read_long_string(),
53             _ => Err(Amf0ReadError {
54                 value: Amf0ReadErrorValue::UnknownMarker { marker: markers },
55             }),
56         }
57     }
58     pub fn read_with_type(&mut self, specified_marker: u8) -> Result<Amf0ValueType, Amf0ReadError> {
59         let marker = self.reader.advance_u8()?;
60 
61         if marker != specified_marker {
62             return Err(Amf0ReadError {
63                 value: Amf0ReadErrorValue::WrongType,
64             });
65         }
66 
67         return self.read_any();
68     }
69 
70     pub fn read_number(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
71         let number = self.reader.read_f64::<BigEndian>()?;
72         let value = Amf0ValueType::Number(number);
73         Ok(value)
74     }
75 
76     pub fn read_bool(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
77         let value = self.reader.read_u8()?;
78 
79         match value {
80             1 => Ok(Amf0ValueType::Boolean(true)),
81             _ => Ok(Amf0ValueType::Boolean(false)),
82         }
83     }
84 
85     pub fn read_raw_string(&mut self) -> Result<String, Amf0ReadError> {
86         let l = self.reader.read_u16::<BigEndian>()?;
87 
88         let bytes = self.reader.read_bytes(l as usize)?;
89         let val = String::from_utf8(bytes.to_vec())?;
90 
91         Ok(val)
92     }
93 
94     pub fn read_string(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
95         let raw_string = self.read_raw_string()?;
96         Ok(Amf0ValueType::UTF8String(raw_string))
97     }
98 
99     pub fn read_null(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
100         Ok(Amf0ValueType::Null)
101     }
102 
103     pub fn is_read_object_eof(&mut self) -> Result<bool, Amf0ReadError> {
104         let marker = self.reader.advance_u24::<BigEndian>()?;
105         if marker == amf0_markers::OBJECT_END as u32 {
106             self.reader.read_u24::<BigEndian>()?;
107             return Ok(true);
108         }
109         Ok(false)
110     }
111 
112     pub fn read_object(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
113         let mut properties = HashMap::new();
114 
115         loop {
116             let is_eof = self.is_read_object_eof()?;
117 
118             if is_eof {
119                 break;
120             }
121 
122             let key = self.read_raw_string()?;
123             let val = self.read_any()?;
124 
125             properties.insert(key, val);
126         }
127 
128         Ok(Amf0ValueType::Object(properties))
129     }
130 
131     pub fn read_ecma_array(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
132         let len = self.reader.read_u32::<BigEndian>()?;
133 
134         let mut properties = HashMap::new();
135 
136         for _ in 0..len {
137             let key = self.read_raw_string()?;
138             let val = self.read_any()?;
139             properties.insert(key, val);
140         }
141 
142         self.is_read_object_eof()?;
143 
144         Ok(Amf0ValueType::Object(properties))
145     }
146 
147     pub fn read_long_string(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
148         let l = self.reader.read_u32::<BigEndian>()?;
149 
150         let buff = self.reader.read_bytes(l as usize)?;
151 
152         let val = String::from_utf8(buff.to_vec())?;
153         Ok(Amf0ValueType::LongUTF8String(val))
154     }
155 
156     pub fn get_remaining_bytes(&mut self) -> BytesMut {
157         return self.reader.get_remaining_bytes();
158     }
159 }
160 
161 #[cfg(test)]
162 mod tests {
163 
164     #[test]
165     fn test_byte_order() {
166         use byteorder::{BigEndian, ByteOrder};
167 
168         let phi = 1.6180339887;
169         let mut buf = [0; 8];
170         BigEndian::write_f64(&mut buf, phi);
171         assert_eq!(phi, BigEndian::read_f64(&buf));
172         println!("tsetstt")
173     }
174 
175     use super::amf0_markers;
176     use super::Amf0Reader;
177     use super::Amf0ValueType;
178     use bytes::BytesMut;
179     use networkio::bytes_reader::BytesReader;
180     use std::collections::HashMap;
181 
182     #[test]
183     fn test_amf_reader() {
184         let data: [u8; 177] = [
185             2, 0, 7, 99, 111, 110, 110, 101, 99, 116, 0, 63, 240, 0, 0, 0, 0, 0, 0, //body
186             3, 0, 3, 97, 112, 112, 2, 0, 6, 104, 97, 114, 108, 97, 110, 0, 4, 116, 121, 112, 101,
187             2, 0, 10, 110, 111, 110, 112, 114, 105, 118, 97, 116, 101, 0, 8, 102, 108, 97, 115,
188             104, 86, 101, 114, 2, 0, 31, 70, 77, 76, 69, 47, 51, 46, 48, 32, 40, 99, 111, 109, 112,
189             97, 116, 105, 98, 108, 101, 59, 32, 70, 77, 83, 99, 47, 49, 46, 48, 41, 0, 6, 115, 119,
190             102, 85, 114, 108, 2, 0, 28, 114, 116, 109, 112, 58, 47, 47, 108, 111, 99, 97, 108,
191             104, 111, 115, 116, 58, 49, 57, 51, 53, 47, 104, 97, 114, 108, 97, 110, 0, 5, 116, 99,
192             85, 114, 108, 2, 0, 28, 114, 116, 109, 112, 58, 47, 47, 108, 111, 99, 97, 108, 104,
193             111, 115, 116, 58, 49, 57, 51, 53, 47, 104, 97, 114, 108, 97, 110, 0, 0, 9,
194         ];
195 
196         let mut bytes_reader = BytesReader::new(BytesMut::new());
197         bytes_reader.extend_from_slice(&data);
198         let mut amf_reader = Amf0Reader::new(bytes_reader);
199 
200         let command_name = amf_reader.read_with_type(amf0_markers::STRING).unwrap();
201         assert_eq!(
202             command_name,
203             Amf0ValueType::UTF8String(String::from("connect"))
204         );
205 
206         let transaction_id = amf_reader.read_with_type(amf0_markers::NUMBER).unwrap();
207         assert_eq!(transaction_id, Amf0ValueType::Number(1.0));
208 
209         let command_obj_raw = amf_reader.read_with_type(amf0_markers::OBJECT).unwrap();
210         let mut properties = HashMap::new();
211         properties.insert(
212             String::from("app"),
213             Amf0ValueType::UTF8String(String::from("harlan")),
214         );
215         properties.insert(
216             String::from("type"),
217             Amf0ValueType::UTF8String(String::from("nonprivate")),
218         );
219         properties.insert(
220             String::from("flashVer"),
221             Amf0ValueType::UTF8String(String::from("FMLE/3.0 (compatible; FMSc/1.0)")),
222         );
223         properties.insert(
224             String::from("swfUrl"),
225             Amf0ValueType::UTF8String(String::from("rtmp://localhost:1935/harlan")),
226         );
227         properties.insert(
228             String::from("tcUrl"),
229             Amf0ValueType::UTF8String(String::from("rtmp://localhost:1935/harlan")),
230         );
231         assert_eq!(command_obj_raw, Amf0ValueType::Object(properties));
232 
233         let _ = amf_reader.read_all();
234 
235         print!("test")
236     }
237 
238     #[test]
239     fn test_player_connect_reader() {
240         // chunk header
241         // 0000   03 00 00 00 00 00 aa 14 00 00 00 00
242         //amf0 data
243         //                                            02 00 07 63  ...............c
244         // 0010   6f 6e 6e 65 63 74 00 3f f0 00 00 00 00 00 00 03  onnect.?........
245         // 0020   00 03 61 70 70 02 00 04 6c 69 76 65 00 05 74 63  ..app...live..tc
246         // 0030   55 72 6c 02 00 1a 72 74 6d 70 3a 2f 2f 6c 6f 63  Url...rtmp://loc
247         // 0040   61 6c 68 6f 73 74 3a 31 39 33 35 2f 6c 69 76 65  alhost:1935/live
248         // 0050   00 04 66 70 61 64 01 00 00 0c 63 61 70 61 62 69  ..fpad....capabi
249         // 0060   6c 69 74 69 65 73 00 40 2e 00 00 00 00 00 00 00  lities.@........
250         // 0070   0b 61 75 64 69 6f 43 6f 64 65 63 73 00 40 a8 ee  .audioCodecs.@..
251         // 0080   00 00 00 00 00 00 0b 76 69 64 65 6f 43 6f 64 65  .......videoCode 118 105
252         // 0090   63 73 00 40 6f 80 00 00 00 00 00 00 0d 76 69 64  [email protected]
253         // 00a0   65 6f 46 75 6e 63 74 69 6f 6e 00 3f f0 00 00 00  eoFunction.?....
254         // 0b00   00 00 00 00 00 09                                ......
255 
256         let data: [u8; 171] = [
257             2, 0, 7, 99, 111, 110, 110, 101, 99, 116, 0, 63, 240, 0, 0, 0, 0, 0, 0, 3, 0, 3, 97,
258             112, 112, 2, 0, 4, 108, 105, 118, 101, 0, 5, 116, 99, 85, 114, 108, 2, 0, 26, 114, 116,
259             109, 112, 58, 47, 47, 108, 111, 99, 97, 108, 104, 111, 115, 116, 58, 49, 57, 51, 53,
260             47, 108, 105, 118, 101, 0, 4, 102, 112, 97, 100, 1, 0, 0, 12, 99, 97, 112, 97, 98, 105,
261             108, 105, 116, 105, 101, 115, 0, 64, 46, 0, 0, 0, 0, 0, 0, 0, 11, 97, 117, 100, 105,
262             111, 67, 111, 100, 101, 99, 115, 0, 64, 168, 238, 0, 0, 0, 0, 0, 0, 11, 118, 105, 100,
263             101, 111, 195, 67, 111, 100, 101, 99, 115, 0, 64, 111, 128, 0, 0, 0, 0, 0, 0, 13, 118,
264             105, 100, 101, 111, 70, 117, 110, 99, 116, 105, 111, 110, 0, 63, 240, 0, 0, 0, 0, 0, 0,
265             0, 0, 9,
266         ];
267 
268         //76 69 64 65 6f 43 6f 64 65 63 73
269         // 118 105 100 101  111 67 111 100 101 99 115
270 
271         let mut bytes_reader = BytesReader::new(BytesMut::new());
272         bytes_reader.extend_from_slice(&data);
273         let mut amf_reader = Amf0Reader::new(bytes_reader);
274 
275         let command_name = amf_reader.read_with_type(amf0_markers::STRING).unwrap();
276         assert_eq!(
277             command_name,
278             Amf0ValueType::UTF8String(String::from("connect"))
279         );
280 
281         let transaction_id = amf_reader.read_with_type(amf0_markers::NUMBER).unwrap();
282         assert_eq!(transaction_id, Amf0ValueType::Number(1.0));
283 
284         let command_obj_raw = amf_reader.read_with_type(amf0_markers::OBJECT);
285         let mut properties = HashMap::new();
286         properties.insert(
287             String::from("app"),
288             Amf0ValueType::UTF8String(String::from("live")),
289         );
290         properties.insert(
291             String::from("tcUrl"),
292             Amf0ValueType::UTF8String(String::from("rtmp://localhost:1935/live")),
293         );
294         properties.insert(String::from("fpad"), Amf0ValueType::Boolean(false));
295         properties.insert(String::from("capabilities"), Amf0ValueType::Number(15.0));
296         properties.insert(String::from("audioCodecs"), Amf0ValueType::Number(3191.0));
297 
298         properties.insert(String::from("videoCodecs"), Amf0ValueType::Number(252.0));
299 
300         properties.insert(String::from("videoFunction"), Amf0ValueType::Number(1.0));
301 
302         assert_eq!(command_obj_raw.unwrap(), Amf0ValueType::Object(properties));
303     }
304 }
305