o_sfu_protocol/
host_bridge.rs1use 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;