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: Duration,
52    play_mode: PlayMode
53}
54
55impl Play {
56    /// Constructs a Play command.
57    pub fn new(stream_name: AmfString, start_time: Duration, play_mode: PlayMode) -> Self {
58        Self {
59            stream_name,
60            start_time,
61            play_mode
62        }
63    }
64
65    /// Gets the stream name. (e.g. filename)
66    pub fn get_stream_name(&self) -> &AmfString {
67        &self.stream_name
68    }
69
70    /// Gets the start time.
71    pub fn get_start_time(&self) -> Duration {
72        self.start_time
73    }
74
75    /// Gets the play mode.
76    pub fn get_play_mode(&self) -> PlayMode {
77        self.play_mode
78    }
79}
80
81impl From<Play> for (AmfString, Duration, PlayMode) {
82    fn from(play: Play) -> Self {
83        (play.stream_name, play.start_time, play.play_mode)
84    }
85}
86
87impl ChunkData for Play {
88    const CHANNEL: Channel = Channel::Source;
89    const MESSAGE_TYPE: MessageType = MessageType::Command;
90}
91
92impl Command for Play {}
93
94impl Decoder<Play> for ByteBuffer {
95    /// Decodes bytes into a Play command.
96    ///
97    /// # Errors
98    ///
99    /// * [`InsufficientBufferLength`]
100    ///
101    /// When some field misses.
102    ///
103    /// * [`InconsistentMarker`]
104    ///
105    /// When some value is inconsistent with its marker.
106    ///
107    /// * [`InvalidString`]
108    ///
109    /// When some value is invalid for UTF-8 string.
110    ///
111    /// # Examples
112    ///
113    /// ```rust
114    /// use sheave_core::{
115    ///     ByteBuffer,
116    ///     Decoder,
117    ///     Encoder,
118    ///     messages::{
119    ///         Play,
120    ///         amf::v0::{
121    ///             AmfString,
122    ///             Null,
123    ///             Number
124    ///         }
125    ///     }
126    /// };
127    ///
128    /// let mut buffer = ByteBuffer::default();
129    /// buffer.encode(&Null);
130    /// buffer.encode(&AmfString::default());
131    /// buffer.encode(&Number::new(-2000f64));
132    /// assert!(Decoder::<Play>::decode(&mut buffer).is_ok());
133    ///
134    /// let mut buffer = ByteBuffer::default();
135    /// assert!(Decoder::<Play>::decode(&mut buffer).is_err())
136    /// ```
137    ///
138    /// [`InsufficientBufferLength`]: crate::byte_buffer::InsufficientBufferLength
139    /// [`InconsistentMarker`]: crate::messages::amf::InconsistentMarker
140    /// [`InvalidString`]: crate::messages::amf::InvalidString
141    fn decode(&mut self) -> IOResult<Play> {
142        Decoder::<Null>::decode(self)?;
143        let stream_name: AmfString = self.decode()?;
144        let start_time: Number = self.decode()?;
145        let play_mode: PlayMode = (start_time / 1000f64).into();
146
147        let start_time = if start_time < 0f64 {
148            Duration::default()
149        } else {
150            Duration::from_secs(start_time.as_integer())
151        };
152        Ok(Play { stream_name, start_time, play_mode })
153    }
154}
155
156impl Encoder<Play> for ByteBuffer {
157    /// Encodes a Play command into bytes.
158    fn encode(&mut self, play: &Play) {
159        use PlayMode::*;
160
161        let start_time = match play.get_play_mode() {
162            Both => -2000f64,
163            Live => -1000f64,
164            Record => (play.get_start_time().as_secs() * 1000) as f64,
165            Other => unimplemented!("Play mode is neither both, live nor recorded.")
166        };
167
168        self.encode(&Null);
169        self.encode(play.get_stream_name());
170        self.encode(&Number::new(start_time));
171    }
172}
173
174#[cfg(test)]
175mod tests {
176    use super::*;
177
178    #[test]
179    fn decode_play() {
180        let mut buffer = ByteBuffer::default();
181        buffer.encode(&Null);
182        buffer.encode(&AmfString::default());
183        buffer.encode(&Number::new(-2000f64));
184        let result: IOResult<Play> = buffer.decode();
185        assert!(result.is_ok());
186        let actual = result.unwrap();
187        let expected = Play::new(AmfString::default(), Number::new(-2000f64));
188        assert_eq!(expected, actual)
189    }
190
191    #[test]
192    fn encode_play() {
193        let mut buffer = ByteBuffer::default();
194        let expected_stream_name = "";
195        let expected_start_time = -2000f64;
196        let expected = Play::new(AmfString::from(expected_stream_name), Number::new(expected_start_time));
197        buffer.encode(&expected);
198        Decoder::<Null>::decode(&mut buffer).unwrap();
199        let actual_stream_name: AmfString = buffer.decode().unwrap();
200        assert_eq!(expected_stream_name, actual_stream_name);
201        let actual_start_time: Number = buffer.decode().unwrap();
202        assert_eq!(expected_start_time, actual_start_time)
203    }
204}