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}