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}