gosuto_livekit/room/publication/
mod.rs1use std::sync::Arc;
16
17use livekit_protocol::enum_dispatch;
18use livekit_protocol::{self as proto, AudioTrackFeature};
19use parking_lot::{Mutex, RwLock};
20
21use super::track::TrackDimension;
22use crate::{e2ee::EncryptionType, prelude::*, track::Track};
23
24mod local;
25mod remote;
26
27pub use local::*;
28pub use remote::*;
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum SubscriptionStatus {
32 Desired,
33 Subscribed,
34 Unsubscribed,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum PermissionStatus {
39 Allowed,
40 NotAllowed,
41}
42
43#[derive(Clone, Debug)]
44pub enum TrackPublication {
45 Local(LocalTrackPublication),
46 Remote(RemoteTrackPublication),
47}
48
49impl TrackPublication {
50 enum_dispatch!(
51 [Local, Remote];
52 pub fn sid(self: &Self) -> TrackSid;
53 pub fn name(self: &Self) -> String;
54 pub fn kind(self: &Self) -> TrackKind;
55 pub fn source(self: &Self) -> TrackSource;
56 pub fn simulcasted(self: &Self) -> bool;
57 pub fn dimension(self: &Self) -> TrackDimension;
58 pub fn mime_type(self: &Self) -> String;
59 pub fn is_muted(self: &Self) -> bool;
60 pub fn is_remote(self: &Self) -> bool;
61 pub fn encryption_type(self: &Self) -> EncryptionType;
62 pub fn audio_features(self: &Self) -> Vec<AudioTrackFeature>;
63
64 pub(crate) fn on_muted(self: &Self, on_mute: impl Fn(TrackPublication) + Send + 'static) -> ();
65 pub(crate) fn on_unmuted(self: &Self, on_unmute: impl Fn(TrackPublication) + Send + 'static) -> ();
66 pub(crate) fn proto_info(self: &Self) -> proto::TrackInfo;
67 pub(crate) fn update_info(self: &Self, info: proto::TrackInfo) -> ();
68 );
69
70 #[allow(dead_code)]
71 pub(crate) fn set_track(&self, track: Option<Track>) {
72 match self {
73 TrackPublication::Local(p) => p.set_track(track),
74 TrackPublication::Remote(p) => p.set_track(track.map(|t| t.try_into().unwrap())),
75 }
76 }
77
78 pub fn track(&self) -> Option<Track> {
79 match self {
80 TrackPublication::Local(p) => p.track().map(Into::into),
81 TrackPublication::Remote(p) => p.track().map(Into::into),
82 }
83 }
84}
85
86struct PublicationInfo {
87 pub track: Option<Track>,
88 pub name: String,
89 pub sid: TrackSid,
90 pub kind: TrackKind,
91 pub source: TrackSource,
92 pub simulcasted: bool,
93 pub dimension: TrackDimension,
94 pub mime_type: String,
95 pub muted: bool,
96 pub proto_info: proto::TrackInfo,
97 pub encryption_type: EncryptionType,
98 pub audio_features: Vec<AudioTrackFeature>,
99}
100
101pub(crate) type MutedHandler = Box<dyn Fn(TrackPublication) + Send>;
102pub(crate) type UnmutedHandler = Box<dyn Fn(TrackPublication) + Send>;
103
104#[derive(Default)]
105struct PublicationEvents {
106 muted: Mutex<Option<MutedHandler>>,
107 unmuted: Mutex<Option<UnmutedHandler>>,
108}
109
110pub(super) struct TrackPublicationInner {
111 info: RwLock<PublicationInfo>,
112 events: Arc<PublicationEvents>,
113}
114
115pub(super) fn new_inner(
116 info: proto::TrackInfo,
117 track: Option<Track>,
118) -> Arc<TrackPublicationInner> {
119 let info = PublicationInfo {
120 track,
121 proto_info: info.clone(),
122 source: info.source().into(),
123 kind: info.r#type().try_into().unwrap(),
124 encryption_type: info.encryption().into(),
125 name: info.clone().name,
126 sid: info.sid.clone().try_into().unwrap(),
127 simulcasted: info.simulcast,
128 dimension: TrackDimension(info.width, info.height),
129 mime_type: info.mime_type.clone(),
130 muted: info.muted,
131 audio_features: info
132 .audio_features()
133 .into_iter()
134 .map(|item| item.try_into().unwrap())
135 .collect(),
136 };
137
138 Arc::new(TrackPublicationInner { info: RwLock::new(info), events: Default::default() })
139}
140
141pub(super) fn update_info(
142 inner: &TrackPublicationInner,
143 _publication: &TrackPublication,
144 new_info: proto::TrackInfo,
145) {
146 let mut info = inner.info.write();
147 info.kind = TrackKind::try_from(new_info.r#type()).unwrap();
148 info.source = TrackSource::from(new_info.source());
149 info.encryption_type = new_info.encryption().into();
150 info.proto_info = new_info.clone();
151 info.name = new_info.name.clone();
152 info.sid = new_info.sid.clone().try_into().unwrap();
153 info.dimension = TrackDimension(new_info.width, new_info.height);
154 info.mime_type = new_info.mime_type.clone();
155 info.simulcasted = new_info.simulcast;
156 info.audio_features = new_info.audio_features().collect();
157}
158
159pub(super) fn set_track(
160 inner: &TrackPublicationInner,
161 publication: &TrackPublication,
162 track: Option<Track>,
163) {
164 let mut info = inner.info.write();
165 if let Some(prev_track) = info.track.as_ref() {
166 prev_track.on_muted(|_| {});
167 prev_track.on_unmuted(|_| {});
168 }
169
170 info.track = track.clone();
171
172 if let Some(track) = track.as_ref() {
173 info.sid = track.sid();
174
175 track.on_muted({
176 let events = inner.events.clone();
177 let publication = publication.clone();
178 move |_| {
179 if let Some(on_muted) = events.muted.lock().as_ref() {
180 on_muted(publication.clone());
181 }
182 }
183 });
184
185 track.on_unmuted({
186 let events = inner.events.clone();
187 let publication = publication.clone();
188 move |_| {
189 if let Some(on_unmuted) = events.unmuted.lock().as_ref() {
190 on_unmuted(publication.clone());
191 }
192 }
193 });
194 }
195}