participant.rs

  1use crate::{
  2    AudioStream, ConnectionQuality, LocalAudioTrack, LocalTrackPublication, LocalVideoTrack,
  3    Participant, ParticipantIdentity, RemoteTrack, RemoteTrackPublication, TrackSid,
  4    test::{Room, WeakRoom},
  5};
  6use anyhow::Result;
  7use collections::HashMap;
  8use gpui::{
  9    AsyncApp, DevicePixels, ScreenCaptureSource, ScreenCaptureStream, SourceMetadata, size,
 10};
 11use std::sync::{Arc, atomic::AtomicU64};
 12
 13#[derive(Clone, Debug)]
 14pub struct LocalParticipant {
 15    pub(crate) identity: ParticipantIdentity,
 16    pub(crate) room: Room,
 17}
 18
 19#[derive(Clone, Debug)]
 20pub struct RemoteParticipant {
 21    pub(crate) identity: ParticipantIdentity,
 22    pub(crate) room: WeakRoom,
 23}
 24
 25impl Participant {
 26    pub fn identity(&self) -> ParticipantIdentity {
 27        match self {
 28            Participant::Local(participant) => participant.identity.clone(),
 29            Participant::Remote(participant) => participant.identity.clone(),
 30        }
 31    }
 32
 33    pub fn connection_quality(&self) -> ConnectionQuality {
 34        match self {
 35            Participant::Local(p) => p.connection_quality(),
 36            Participant::Remote(p) => p.connection_quality(),
 37        }
 38    }
 39
 40    pub fn audio_level(&self) -> f32 {
 41        match self {
 42            Participant::Local(p) => p.audio_level(),
 43            Participant::Remote(p) => p.audio_level(),
 44        }
 45    }
 46}
 47
 48impl LocalParticipant {
 49    pub fn connection_quality(&self) -> ConnectionQuality {
 50        ConnectionQuality::Excellent
 51    }
 52
 53    pub fn audio_level(&self) -> f32 {
 54        0.0
 55    }
 56
 57    pub async fn unpublish_track(&self, track: TrackSid, _cx: &AsyncApp) -> Result<()> {
 58        self.room
 59            .test_server()
 60            .unpublish_track(self.room.token(), &track)
 61            .await
 62    }
 63
 64    pub(crate) async fn publish_microphone_track(
 65        &self,
 66        _cx: &AsyncApp,
 67    ) -> Result<(LocalTrackPublication, AudioStream, Arc<AtomicU64>)> {
 68        let this = self.clone();
 69        let server = this.room.test_server();
 70        let sid = server
 71            .publish_audio_track(this.room.token(), &LocalAudioTrack {})
 72            .await?;
 73
 74        Ok((
 75            LocalTrackPublication {
 76                room: self.room.downgrade(),
 77                sid,
 78            },
 79            AudioStream {},
 80            Arc::new(AtomicU64::new(0)),
 81        ))
 82    }
 83
 84    pub async fn publish_screenshare_track(
 85        &self,
 86        _source: &dyn ScreenCaptureSource,
 87        _cx: &mut AsyncApp,
 88    ) -> Result<(LocalTrackPublication, Box<dyn ScreenCaptureStream>)> {
 89        let this = self.clone();
 90        let server = this.room.test_server();
 91        let sid = server
 92            .publish_video_track(this.room.token(), LocalVideoTrack {})
 93            .await?;
 94        Ok((
 95            LocalTrackPublication {
 96                room: self.room.downgrade(),
 97                sid,
 98            },
 99            Box::new(TestScreenCaptureStream {}),
100        ))
101    }
102
103    #[cfg(target_os = "linux")]
104    pub async fn publish_screenshare_track_wayland(
105        &self,
106        _cx: &mut AsyncApp,
107    ) -> Result<(
108        LocalTrackPublication,
109        Box<dyn ScreenCaptureStream>,
110        futures::channel::oneshot::Receiver<()>,
111    )> {
112        let (_failure_tx, failure_rx) = futures::channel::oneshot::channel();
113        let this = self.clone();
114        let server = this.room.test_server();
115        let sid = server
116            .publish_video_track(this.room.token(), LocalVideoTrack {})
117            .await?;
118        Ok((
119            LocalTrackPublication {
120                room: self.room.downgrade(),
121                sid,
122            },
123            Box::new(TestWaylandScreenCaptureStream::new()),
124            failure_rx,
125        ))
126    }
127}
128
129impl RemoteParticipant {
130    pub fn connection_quality(&self) -> ConnectionQuality {
131        ConnectionQuality::Excellent
132    }
133
134    pub fn audio_level(&self) -> f32 {
135        0.0
136    }
137
138    pub fn track_publications(&self) -> HashMap<TrackSid, RemoteTrackPublication> {
139        if let Some(room) = self.room.upgrade() {
140            let server = room.test_server();
141            let audio = server
142                .audio_tracks(room.token())
143                .unwrap()
144                .into_iter()
145                .filter(|track| track.publisher_id() == self.identity)
146                .map(|track| {
147                    (
148                        track.sid(),
149                        RemoteTrackPublication {
150                            sid: track.sid(),
151                            room: self.room.clone(),
152                            track: RemoteTrack::Audio(track),
153                        },
154                    )
155                });
156            let video = server
157                .video_tracks(room.token())
158                .unwrap()
159                .into_iter()
160                .filter(|track| track.publisher_id() == self.identity)
161                .map(|track| {
162                    (
163                        track.sid(),
164                        RemoteTrackPublication {
165                            sid: track.sid(),
166                            room: self.room.clone(),
167                            track: RemoteTrack::Video(track),
168                        },
169                    )
170                });
171            audio.chain(video).collect()
172        } else {
173            HashMap::default()
174        }
175    }
176
177    pub fn identity(&self) -> ParticipantIdentity {
178        self.identity.clone()
179    }
180}
181
182struct TestScreenCaptureStream;
183
184impl ScreenCaptureStream for TestScreenCaptureStream {
185    fn metadata(&self) -> Result<SourceMetadata> {
186        Ok(SourceMetadata {
187            id: 0,
188            is_main: None,
189            label: None,
190            resolution: size(DevicePixels(1), DevicePixels(1)),
191        })
192    }
193}
194
195#[cfg(target_os = "linux")]
196static NEXT_TEST_WAYLAND_SHARE_ID: AtomicU64 = AtomicU64::new(1);
197
198#[cfg(target_os = "linux")]
199struct TestWaylandScreenCaptureStream {
200    id: u64,
201}
202
203#[cfg(target_os = "linux")]
204impl TestWaylandScreenCaptureStream {
205    fn new() -> Self {
206        Self {
207            id: NEXT_TEST_WAYLAND_SHARE_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
208        }
209    }
210}
211
212#[cfg(target_os = "linux")]
213impl ScreenCaptureStream for TestWaylandScreenCaptureStream {
214    fn metadata(&self) -> Result<SourceMetadata> {
215        Ok(SourceMetadata {
216            id: self.id,
217            is_main: None,
218            label: None,
219            resolution: size(DevicePixels(1), DevicePixels(1)),
220        })
221    }
222}