sheave_core/messages/play.rs
1mod play_mode;
2
3use std::io::Result as IOResult;
4use super::{
5 Channel,
6 ChunkData,
7 Command,
8 headers::MessageType
9};
10use crate::{
11 Decoder,
12 Encoder,
13 ByteBuffer,
14 messages::amf::v0::{
15 AmfString,
16 Null,
17 Number
18 }
19};
20pub use self::play_mode::*;
21
22/// The command to tell playing information.
23///
24/// Following format is required:
25///
26/// |Field|AMF Type|Value|
27/// | :- | :- | :- |
28/// ||[`Null`]|Nothing but an AMF's type marker is in.|
29/// |Stream Name|[`String`]|A name for subscribing a data from the server.|
30/// |Start Time|[`Number`]|Time offset of data subscribing.<br />*Note this can be several negative number* (See [Play Mode](#play-mode)).|
31///
32/// # Play Mode
33///
34/// |Value|Play Mode|Description|
35/// | :- | :- | :- |
36/// |`-2`|Both|Subscribes recorded data if its data isn't on a livestream (default).|
37/// |`-1`|Live|Subscribes only as livestream.|
38/// |`0`<br />(And above)|Recorded|Subscribes only as recorded data.|
39///
40/// Note the server can treat as some error if its data doesn't exist as specified mode.
41///
42/// [`Number`]: crate::messages::amf::v0::Number
43/// [`String`]: crate::messages::amf::v0::AmfString
44/// [`Null`]: crate::messages::amf::v0::Null
45#[derive(Debug, Clone, PartialEq)]
46pub struct Play {
47 stream_name: AmfString,
48 start_time: Number
49}
50
51impl Play {
52 /// Constructs a Play command.
53 pub fn new(stream_name: AmfString, start_time: Number) -> Self {
54 Self {
55 stream_name,
56 start_time
57 }
58 }
59
60 /// Gets the stream name. (e.g. filename)
61 pub fn get_stream_name(&self) -> &AmfString {
62 &self.stream_name
63 }
64
65 /// Gets the start time.
66 pub fn get_start_time(&self) -> Number {
67 self.start_time
68 }
69
70 /// Gets the play mode.
71 pub fn get_play_mode(&self) -> PlayMode {
72 self.start_time.into()
73 }
74}
75
76impl From<Play> for (AmfString, Number) {
77 fn from(play: Play) -> Self {
78 (play.stream_name, play.start_time)
79 }
80}
81
82impl ChunkData for Play {
83 const CHANNEL: Channel = Channel::Source;
84 const MESSAGE_TYPE: MessageType = MessageType::Command;
85}
86
87impl Command for Play {}
88
89impl Decoder<Play> for ByteBuffer {
90 /// Decodes bytes into a Play command.
91 ///
92 /// # Errors
93 ///
94 /// * [`InsufficientBufferLength`]
95 ///
96 /// When some field misses.
97 ///
98 /// * [`InconsistentMarker`]
99 ///
100 /// When some value is inconsistent with its marker.
101 ///
102 /// * [`InvalidString`]
103 ///
104 /// When some value is invalid for UTF-8 string.
105 ///
106 /// # Examples
107 ///
108 /// ```rust
109 /// use sheave_core::{
110 /// ByteBuffer,
111 /// Decoder,
112 /// Encoder,
113 /// messages::{
114 /// Play,
115 /// amf::v0::{
116 /// AmfString,
117 /// Null,
118 /// Number
119 /// }
120 /// }
121 /// };
122 ///
123 /// let mut buffer = ByteBuffer::default();
124 /// buffer.encode(&Null);
125 /// buffer.encode(&AmfString::default());
126 /// buffer.encode(&Number::new(-2000f64));
127 /// assert!(Decoder::<Play>::decode(&mut buffer).is_ok());
128 ///
129 /// let mut buffer = ByteBuffer::default();
130 /// assert!(Decoder::<Play>::decode(&mut buffer).is_err())
131 /// ```
132 ///
133 /// [`InsufficientBufferLength`]: crate::byte_buffer::InsufficientBufferLength
134 /// [`InconsistentMarker`]: crate::messages::amf::InconsistentMarker
135 /// [`InvalidString`]: crate::messages::amf::InvalidString
136 fn decode(&mut self) -> IOResult<Play> {
137 Decoder::<Null>::decode(self)?;
138 let stream_name: AmfString = self.decode()?;
139 let start_time: Number = self.decode()?;
140
141 Ok(Play { stream_name, start_time })
142 }
143}
144
145impl Encoder<Play> for ByteBuffer {
146 /// Encodes a Play command into bytes.
147 fn encode(&mut self, play: &Play) {
148 self.encode(&Null);
149 self.encode(play.get_stream_name());
150 self.encode(&play.get_start_time());
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 #[test]
159 fn decode_play() {
160 let mut buffer = ByteBuffer::default();
161 buffer.encode(&Null);
162 buffer.encode(&AmfString::default());
163 buffer.encode(&Number::new(-2000f64));
164 let result: IOResult<Play> = buffer.decode();
165 assert!(result.is_ok());
166 let actual = result.unwrap();
167 let expected = Play::new(AmfString::default(), Number::new(-2000f64));
168 assert_eq!(expected, actual)
169 }
170
171 #[test]
172 fn encode_play() {
173 let mut buffer = ByteBuffer::default();
174 let expected_stream_name = "";
175 let expected_start_time = -2000f64;
176 let expected = Play::new(AmfString::from(expected_stream_name), Number::new(expected_start_time));
177 buffer.encode(&expected);
178 Decoder::<Null>::decode(&mut buffer).unwrap();
179 let actual_stream_name: AmfString = buffer.decode().unwrap();
180 assert_eq!(expected_stream_name, actual_stream_name);
181 let actual_start_time: Number = buffer.decode().unwrap();
182 assert_eq!(expected_start_time, actual_start_time)
183 }
184}