Skip to main content

o_sfu_protocol/
host_bridge.rs

1use std::{borrow::Cow, collections::BTreeMap};
2
3use serde::{Serialize, Serializer};
4
5use crate::{
6    bundle_api::{
7        BundleBroadcastUpdate, BundleDisconnectUpdate, BundleRecordingFlags,
8        BundleRecordingStateUpdate, BundleRemoteMediaUpdate, BundleSessionInfoSnapshotById,
9        BundleUpdate, bundle_session_info_key,
10    },
11    core::ProtocolEvent,
12    shared::{AvailableFeatures, JsonPayload, RecordingState, UserId, UserInfo},
13    signaling::TrackBinding,
14};
15
16#[derive(Serialize)]
17#[serde(tag = "name", content = "payload", rename_all = "snake_case")]
18enum BundleUpdateRef<'a> {
19    RemoteMedia {
20        bindings: &'a [TrackBinding],
21    },
22    Broadcast {
23        #[serde(rename = "senderId")]
24        sender_id: &'a UserId,
25        message: &'a JsonPayload,
26    },
27    Disconnect {
28        #[serde(rename = "sessionId")]
29        user_id: &'a UserId,
30    },
31    #[serde(rename = "info_change")]
32    SessionInfoChange(BTreeMap<Cow<'a, str>, &'a UserInfo>),
33    ChannelInfoChange(BundleRecordingStateUpdate),
34}
35
36pub(crate) fn serialize_features<S>(
37    features: &AvailableFeatures,
38    serializer: S,
39) -> Result<S::Ok, S::Error>
40where
41    S: Serializer,
42{
43    #[derive(Serialize)]
44    struct Features {
45        rtc: bool,
46        recording: BundleRecordingFlags,
47    }
48    Features {
49        rtc: features.rtc,
50        recording: BundleRecordingFlags {
51            audio: features.audio_recording,
52            video: features.video_recording,
53            transcription: features.transcription,
54        },
55    }
56    .serialize(serializer)
57}
58
59pub(crate) fn serialize_recording_state<S>(
60    state: &RecordingState,
61    serializer: S,
62) -> Result<S::Ok, S::Error>
63where
64    S: Serializer,
65{
66    BundleRecordingFlags::from(state).serialize(serializer)
67}
68
69#[must_use]
70pub fn project_protocol_event(event: ProtocolEvent) -> BundleUpdate {
71    match event {
72        ProtocolEvent::TrackSnapshot { bindings } => {
73            BundleUpdate::RemoteMedia(BundleRemoteMediaUpdate { bindings })
74        }
75        ProtocolEvent::PeerSnapshot { peers } => BundleUpdate::SessionInfoChange(
76            peers
77                .into_iter()
78                .map(|peer| (bundle_session_info_key(&peer.user_id), peer.info))
79                .collect::<BundleSessionInfoSnapshotById>(),
80        ),
81        ProtocolEvent::PeerInfo { user_id, info } => BundleUpdate::SessionInfoChange(
82            BundleSessionInfoSnapshotById::from([(bundle_session_info_key(&user_id), info)]),
83        ),
84        ProtocolEvent::PeerLeft { user_id } => {
85            BundleUpdate::Disconnect(BundleDisconnectUpdate { user_id })
86        }
87        ProtocolEvent::Broadcast { sender_id, message } => {
88            BundleUpdate::Broadcast(BundleBroadcastUpdate { sender_id, message })
89        }
90        ProtocolEvent::RecordingStateChanged { state } => {
91            BundleUpdate::ChannelInfoChange((&state).into())
92        }
93    }
94}
95
96pub(crate) fn serialize_protocol_event<S>(
97    event: &ProtocolEvent,
98    serializer: S,
99) -> Result<S::Ok, S::Error>
100where
101    S: Serializer,
102{
103    let update = match event {
104        ProtocolEvent::TrackSnapshot { bindings } => BundleUpdateRef::RemoteMedia { bindings },
105        ProtocolEvent::PeerSnapshot { peers } => BundleUpdateRef::SessionInfoChange(
106            peers
107                .iter()
108                .map(|peer| (peer.user_id.path_segment(), &peer.info))
109                .collect(),
110        ),
111        ProtocolEvent::PeerInfo { user_id, info } => {
112            BundleUpdateRef::SessionInfoChange(BTreeMap::from([(user_id.path_segment(), info)]))
113        }
114        ProtocolEvent::PeerLeft { user_id } => BundleUpdateRef::Disconnect { user_id },
115        ProtocolEvent::Broadcast { sender_id, message } => {
116            BundleUpdateRef::Broadcast { sender_id, message }
117        }
118        ProtocolEvent::RecordingStateChanged { state } => {
119            BundleUpdateRef::ChannelInfoChange(state.into())
120        }
121    };
122    update.serialize(serializer)
123}
124
125#[cfg(test)]
126#[path = "host_bridge/TESTS/mod.rs"]
127mod tests;