Skip to main content

fcast_protocol/
lib.rs

1//! # FCast Protocol
2//!
3//! Implementation of the data models documented [here](https://gitlab.futo.org/videostreaming/fcast/-/wikis/Protocol-version-3).
4
5// TODO: most strings should be SmolStr
6
7use serde::{Deserialize, Serialize};
8use serde_repr::{Deserialize_repr, Serialize_repr};
9
10pub mod v1;
11pub mod v2;
12pub mod v3;
13
14pub const HEADER_LENGTH: usize = 5;
15
16#[derive(Debug, thiserror::Error)]
17pub enum TryFromByteError {
18    #[error("Unknown opcode: {0}")]
19    UnknownOpcode(u8),
20}
21
22#[derive(Debug, PartialEq, Copy, Clone)]
23pub enum Opcode {
24    /// Not used
25    None = 0,
26    /// Sender message to play media content, body is [`v3::PlayMessage`]
27    Play = 1,
28    /// Sender message to pause media content, no body
29    Pause = 2,
30    /// Sender message to resume media content, no body
31    Resume = 3,
32    /// Sender message to stop media content, no body
33    Stop = 4,
34    /// Sender message to seek, body is [`SeekMessage`]
35    Seek = 5,
36    /// Receiver message to notify an updated playback state, body is [`v3::PlaybackUpdateMessage`]
37    PlaybackUpdate = 6,
38    /// Receiver message to notify when the volume has changed, body is [`VolumeUpdateMessage`]
39    VolumeUpdate = 7,
40    /// Sender message to change volume, body is [`SetVolumeMessage`]
41    SetVolume = 8,
42    /// Server message to notify the sender a playback error happened, body is [`PlaybackErrorMessage`]
43    PlaybackError = 9,
44    /// Sender message to change playback speed, body is [`SetSpeedMessage`]
45    SetSpeed = 10,
46    /// Message to notify the other of the current version, body is [`VersionMessage`]
47    Version = 11,
48    /// Message to get the other party to pong, no body
49    Ping = 12,
50    /// Message to respond to a ping from the other party, no body
51    Pong = 13,
52    /// Message to notify the other party of device information and state, body is InitialSenderMessage if receiver or
53    /// [`v3::InitialReceiverMessage`] if sender
54    Initial = 14,
55    /// Receiver message to notify all senders when any device has sent a [`v3::PlayMessage`], body is [`v3::PlayUpdateMessage`]
56    PlayUpdate = 15,
57    /// Sender message to set the item index in a playlist to play content from, body is [`v3::SetPlaylistItemMessage`]
58    SetPlaylistItem = 16,
59    /// Sender message to subscribe to a receiver event, body is [`v3::SubscribeEventMessage`]
60    SubscribeEvent = 17,
61    /// Sender message to unsubscribe to a receiver event, body is [`v3::UnsubscribeEventMessage`]
62    UnsubscribeEvent = 18,
63    /// Receiver message to notify when a sender subscribed event has occurred, body is [`v3::EventMessage`]
64    Event = 19,
65}
66
67impl TryFrom<u8> for Opcode {
68    type Error = TryFromByteError;
69
70    fn try_from(value: u8) -> Result<Self, Self::Error> {
71        Ok(match value {
72            0 => Opcode::None,
73            1 => Opcode::Play,
74            2 => Opcode::Pause,
75            3 => Opcode::Resume,
76            4 => Opcode::Stop,
77            5 => Opcode::Seek,
78            6 => Opcode::PlaybackUpdate,
79            7 => Opcode::VolumeUpdate,
80            8 => Opcode::SetVolume,
81            9 => Opcode::PlaybackError,
82            10 => Opcode::SetSpeed,
83            11 => Opcode::Version,
84            12 => Opcode::Ping,
85            13 => Opcode::Pong,
86            14 => Opcode::Initial,
87            15 => Opcode::PlayUpdate,
88            16 => Opcode::SetPlaylistItem,
89            17 => Opcode::SubscribeEvent,
90            18 => Opcode::UnsubscribeEvent,
91            19 => Opcode::Event,
92            _ => return Err(TryFromByteError::UnknownOpcode(value)),
93        })
94    }
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
98#[repr(u8)]
99pub enum PlaybackState {
100    Idle = 0,
101    Playing = 1,
102    Paused = 2,
103}
104
105#[allow(dead_code)]
106#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
107pub struct PlaybackErrorMessage {
108    pub message: String,
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
112pub struct VersionMessage {
113    pub version: u64,
114}
115
116#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
117pub struct SetSpeedMessage {
118    pub speed: f64,
119}
120
121#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
122pub struct SetVolumeMessage {
123    pub volume: f64,
124}
125
126#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
127pub struct SeekMessage {
128    pub time: f64,
129}
130
131#[derive(Debug, Serialize, Deserialize)]
132pub struct FCastService {
133    pub port: u16,
134    pub r#type: i32,
135}
136
137#[derive(Debug, Serialize, Deserialize)]
138pub struct FCastNetworkConfig {
139    pub name: String,
140    pub addresses: Vec<String>,
141    pub services: Vec<FCastService>,
142}