use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", content = "payload")]
pub enum Message {
#[serde(rename = "client/hello")]
ClientHello(ClientHello),
#[serde(rename = "server/hello")]
ServerHello(ServerHello),
#[serde(rename = "client/time")]
ClientTime(ClientTime),
#[serde(rename = "server/time")]
ServerTime(ServerTime),
#[serde(rename = "client/state")]
ClientState(ClientState),
#[serde(rename = "server/state")]
ServerState(ServerState),
#[serde(rename = "server/command")]
ServerCommand(ServerCommand),
#[serde(rename = "client/command")]
ClientCommand(ClientCommand),
#[serde(rename = "stream/start")]
StreamStart(StreamStart),
#[serde(rename = "stream/end")]
StreamEnd(StreamEnd),
#[serde(rename = "stream/clear")]
StreamClear(StreamClear),
#[serde(rename = "stream/request-format")]
StreamRequestFormat(StreamRequestFormat),
#[serde(rename = "group/update")]
GroupUpdate(GroupUpdate),
#[serde(rename = "client/goodbye")]
ClientGoodbye(ClientGoodbye),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClientHello {
pub client_id: String,
pub name: String,
pub version: u32,
pub supported_roles: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub device_info: Option<DeviceInfo>,
#[serde(rename = "player@v1_support", skip_serializing_if = "Option::is_none")]
pub player_v1_support: Option<PlayerV1Support>,
#[serde(rename = "artwork@v1_support", skip_serializing_if = "Option::is_none")]
pub artwork_v1_support: Option<ArtworkV1Support>,
#[serde(
rename = "visualizer@v1_support",
skip_serializing_if = "Option::is_none"
)]
pub visualizer_v1_support: Option<VisualizerV1Support>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeviceInfo {
#[serde(skip_serializing_if = "Option::is_none")]
pub product_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub manufacturer: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub software_version: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlayerV1Support {
pub supported_formats: Vec<AudioFormatSpec>,
pub buffer_capacity: u32,
pub supported_commands: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AudioFormatSpec {
pub codec: String,
pub channels: u8,
pub sample_rate: u32,
pub bit_depth: u8,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArtworkV1Support {
pub channels: Vec<ArtworkChannel>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArtworkChannel {
pub source: ArtworkSource,
pub format: ImageFormat,
pub media_width: u32,
pub media_height: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ArtworkSource {
Album,
Artist,
None,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ImageFormat {
Jpeg,
Png,
Bmp,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VisualizerV1Support {
pub buffer_capacity: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerHello {
pub server_id: String,
pub name: String,
pub version: u32,
pub active_roles: Vec<String>,
pub connection_reason: ConnectionReason,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ConnectionReason {
Discovery,
Playback,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClientTime {
pub client_transmitted: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerTime {
pub client_transmitted: i64,
pub server_received: i64,
pub server_transmitted: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClientState {
#[serde(skip_serializing_if = "Option::is_none")]
pub player: Option<PlayerState>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlayerState {
pub state: PlayerSyncState,
#[serde(skip_serializing_if = "Option::is_none")]
pub volume: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub muted: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum PlayerSyncState {
Synchronized,
Error,
ExternalSource,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerState {
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<MetadataState>,
#[serde(skip_serializing_if = "Option::is_none")]
pub controller: Option<ControllerState>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetadataState {
pub timestamp: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub artist: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub album_artist: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub album: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub artwork_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub year: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub track: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub progress: Option<TrackProgress>,
#[serde(skip_serializing_if = "Option::is_none")]
pub repeat: Option<RepeatMode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub shuffle: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrackProgress {
pub track_progress: i64,
pub track_duration: i64,
pub playback_speed: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum RepeatMode {
Off,
One,
All,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ControllerState {
pub supported_commands: Vec<String>,
pub volume: u8,
pub muted: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerCommand {
#[serde(skip_serializing_if = "Option::is_none")]
pub player: Option<PlayerCommand>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlayerCommand {
pub command: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub volume: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mute: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClientCommand {
#[serde(skip_serializing_if = "Option::is_none")]
pub controller: Option<ControllerCommand>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ControllerCommand {
pub command: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub volume: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mute: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamStart {
#[serde(skip_serializing_if = "Option::is_none")]
pub player: Option<StreamPlayerConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub artwork: Option<StreamArtworkConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visualizer: Option<StreamVisualizerConfig>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamPlayerConfig {
pub codec: String,
pub sample_rate: u32,
pub channels: u8,
pub bit_depth: u8,
#[serde(skip_serializing_if = "Option::is_none")]
pub codec_header: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamArtworkConfig {
pub channels: Vec<u8>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamVisualizerConfig {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamEnd {
#[serde(skip_serializing_if = "Option::is_none")]
pub roles: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamClear {
#[serde(skip_serializing_if = "Option::is_none")]
pub roles: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamRequestFormat {
#[serde(skip_serializing_if = "Option::is_none")]
pub player: Option<PlayerFormatRequest>,
#[serde(skip_serializing_if = "Option::is_none")]
pub artwork: Option<ArtworkFormatRequest>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlayerFormatRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub codec: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub channels: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sample_rate: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bit_depth: Option<u8>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArtworkFormatRequest {
pub channel: u8,
#[serde(skip_serializing_if = "Option::is_none")]
pub source: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub media_width: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub media_height: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GroupUpdate {
#[serde(skip_serializing_if = "Option::is_none")]
pub playback_state: Option<PlaybackState>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum PlaybackState {
Playing,
Stopped,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClientGoodbye {
pub reason: GoodbyeReason,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum GoodbyeReason {
AnotherServer,
Shutdown,
Restart,
UserRequest,
}
#[deprecated(note = "Use PlayerV1Support instead")]
pub type PlayerSupport = PlayerV1Support;
#[deprecated(note = "Use ClientState instead")]
pub type PlayerUpdate = ClientState;