sheave_core/messages/
play.rs

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