use std::ops::Deref;
use serde::{Deserialize, Serialize};
#[cfg(feature = "utoipa")]
use utoipa::ToSchema;
use crate::v1::types::{util::Time, Channel, SessionId, SfuId, UserId};
use super::ChannelId;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct SessionDescription(pub String);
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct IceCandidate(pub String);
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct TrackId(pub String);
impl Deref for SessionDescription {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Deref for IceCandidate {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Deref for TrackId {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct VoiceState {
pub user_id: UserId,
pub thread_id: ChannelId,
pub session_id: Option<SessionId>,
pub joined_at: Time,
pub mute: bool,
pub deaf: bool,
pub self_deaf: bool,
pub self_mute: bool,
pub self_video: bool,
pub self_screen: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct VoiceStateUpdate {
pub thread_id: ChannelId,
pub self_deaf: bool,
pub self_mute: bool,
pub self_video: bool,
pub self_screen: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct TrackMetadata {
pub mid: TrackId,
pub kind: MediaKind,
pub key: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
#[serde(tag = "type")]
pub enum SignallingMessage {
Ready {
sfu_id: SfuId,
},
Offer {
sdp: SessionDescription,
tracks: Vec<TrackMetadata>,
},
Answer { sdp: SessionDescription },
Candidate { candidate: IceCandidate },
Have {
thread_id: ChannelId,
user_id: UserId,
tracks: Vec<TrackMetadata>,
},
Want { tracks: Vec<TrackId> },
VoiceState { state: Option<VoiceStateUpdate> },
Reconnect,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub enum MediaKind {
Video,
Audio,
}
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
#[serde(transparent)]
pub struct SpeakingFlags(pub u8);
impl SpeakingFlags {
#[inline]
pub fn has_audio(&self) -> bool {
self.0 & 1 == 1
}
#[inline]
pub fn has_indicator(&self) -> bool {
self.0 & 2 == 2
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Speaking {
pub user_id: UserId,
pub flags: SpeakingFlags,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SpeakingWithoutUserId {
pub flags: SpeakingFlags,
}
impl VoiceState {
pub fn muted(&self) -> bool {
self.mute || self.self_mute
}
pub fn deafened(&self) -> bool {
self.deaf || self.self_deaf
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SfuCommand {
Ready {
sfu_id: SfuId,
},
Signalling {
user_id: UserId,
inner: SignallingMessage,
},
VoiceState {
user_id: UserId,
state: Option<VoiceState>,
permissions: SfuPermissions,
},
Thread {
thread: SfuThread,
},
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum SfuEvent {
VoiceDispatch {
user_id: UserId,
payload: SignallingMessage,
},
VoiceState {
user_id: UserId,
old: Option<VoiceState>,
state: Option<VoiceState>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SfuPermissions {
pub speak: bool,
pub video: bool,
pub priority: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SfuThread {
pub id: ChannelId,
pub name: String,
pub bitrate: Option<u64>,
pub user_limit: Option<u64>,
}
impl From<Channel> for SfuThread {
fn from(value: Channel) -> Self {
Self {
id: value.id,
name: value.name,
bitrate: value.bitrate,
user_limit: value.user_limit,
}
}
}
#[cfg(feature = "str0m")]
mod str0m {
use super::MediaKind;
use str0m::media::MediaKind as MediaKindStr0m;
impl From<MediaKind> for MediaKindStr0m {
fn from(value: MediaKind) -> Self {
match value {
MediaKind::Video => MediaKindStr0m::Video,
MediaKind::Audio => MediaKindStr0m::Audio,
}
}
}
impl From<MediaKindStr0m> for MediaKind {
fn from(value: MediaKindStr0m) -> Self {
match value {
MediaKindStr0m::Video => MediaKind::Video,
MediaKindStr0m::Audio => MediaKind::Audio,
}
}
}
}