livekit_datatrack/remote/
proto.rs1use super::events::*;
22use crate::{
23 api::{DataTrackInfo, DataTrackSid, InternalError},
24 packet::Handle,
25};
26use livekit_protocol as proto;
27use std::{collections::HashMap, mem};
28
29impl TryFrom<proto::DataTrackSubscriberHandles> for SfuSubscriberHandles {
32 type Error = InternalError;
33
34 fn try_from(msg: proto::DataTrackSubscriberHandles) -> Result<Self, Self::Error> {
35 let mapping = msg
36 .sub_handles
37 .into_iter()
38 .map(|(handle, info)| -> Result<_, InternalError> {
39 let handle: Handle = handle.try_into().map_err(anyhow::Error::from)?;
40 let sid: DataTrackSid = info.track_sid.try_into().map_err(anyhow::Error::from)?;
41 Ok((handle, sid))
42 })
43 .collect::<Result<HashMap<Handle, DataTrackSid>, _>>()?;
44 Ok(SfuSubscriberHandles { mapping })
45 }
46}
47
48pub fn event_from_join(
54 msg: &mut proto::JoinResponse,
55) -> Result<SfuPublicationUpdates, InternalError> {
56 event_from_participant_info(&mut msg.other_participants, None)
57}
58
59pub fn event_from_participant_update(
65 msg: &mut proto::ParticipantUpdate,
66 local_participant_identity: &str,
67) -> Result<SfuPublicationUpdates, InternalError> {
68 event_from_participant_info(&mut msg.participants, local_participant_identity.into())
70}
71
72fn event_from_participant_info(
73 msg: &mut [proto::ParticipantInfo],
74 local_participant_identity: Option<&str>,
75) -> Result<SfuPublicationUpdates, InternalError> {
76 let updates = msg
77 .iter_mut()
78 .filter(|participant| {
79 local_participant_identity.is_none_or(|identity| participant.identity != identity)
80 })
81 .map(|participant| -> Result<_, InternalError> {
82 Ok((participant.identity.clone(), extract_track_info(participant)?))
83 })
84 .collect::<Result<HashMap<String, Vec<DataTrackInfo>>, _>>()?;
85 Ok(SfuPublicationUpdates { updates })
86}
87
88fn extract_track_info(
89 msg: &mut proto::ParticipantInfo,
90) -> Result<Vec<DataTrackInfo>, InternalError> {
91 mem::take(&mut msg.data_tracks)
92 .into_iter()
93 .map(TryInto::<DataTrackInfo>::try_into)
94 .collect::<Result<Vec<_>, InternalError>>()
95}
96
97impl From<SfuUpdateSubscription> for proto::UpdateDataSubscription {
100 fn from(event: SfuUpdateSubscription) -> Self {
101 let update = proto::update_data_subscription::Update {
102 track_sid: event.sid.into(),
103 subscribe: event.subscribe,
104 options: Default::default(),
105 };
106 Self { updates: vec![update] }
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn test_from_subscriber_handles() {
116 let sub_handles = [
117 (
118 1,
119 proto::data_track_subscriber_handles::PublishedDataTrack {
120 track_sid: "DTR_1234".into(),
121 ..Default::default()
122 },
123 ),
124 (
125 2,
126 proto::data_track_subscriber_handles::PublishedDataTrack {
127 track_sid: "DTR_4567".into(),
128 ..Default::default()
129 },
130 ),
131 ];
132 let subscriber_handles =
133 proto::DataTrackSubscriberHandles { sub_handles: HashMap::from(sub_handles) };
134
135 let event: SfuSubscriberHandles = subscriber_handles.try_into().unwrap();
136 assert_eq!(
137 event.mapping.get(&1u32.try_into().unwrap()).unwrap(),
138 &"DTR_1234".to_string().try_into().unwrap()
139 );
140 assert_eq!(
141 event.mapping.get(&2u32.try_into().unwrap()).unwrap(),
142 &"DTR_4567".to_string().try_into().unwrap()
143 );
144 }
145
146 #[test]
147 fn test_extract_track_info() {
148 let data_tracks = vec![proto::DataTrackInfo {
149 pub_handle: 1,
150 sid: "DTR_1234".into(),
151 name: "track1".into(),
152 encryption: proto::encryption::Type::Gcm.into(),
153 schema: None,
154 frame_encoding: None,
155 }];
156 let mut participant_info = proto::ParticipantInfo { data_tracks, ..Default::default() };
157
158 let track_info = extract_track_info(&mut participant_info).unwrap();
159 assert!(participant_info.data_tracks.is_empty(), "Expected original vec taken");
160 assert_eq!(track_info.len(), 1);
161
162 let first = track_info.first().unwrap();
163 assert_eq!(first.pub_handle, 1u32.try_into().unwrap());
164 assert_eq!(first.name, "track1");
165 assert_eq!(*first.sid.read().unwrap(), "DTR_1234".to_string().try_into().unwrap());
166 }
167}