981 lines · 31.5 KB · Rust
RawDownload
use crate::{ConnectionState, RoomUpdate, Sid};use anyhow::{anyhow, Context as _, Result};use core_foundation::{    array::{CFArray, CFArrayRef},    base::{CFRelease, CFRetain, TCFType},    string::{CFString, CFStringRef},};use futures::{    channel::{mpsc, oneshot},    Future,};pub use media::core_video::CVImageBuffer;use media::core_video::CVImageBufferRef;use parking_lot::Mutex;use postage::watch;use std::{    ffi::c_void,    sync::{Arc, Weak},}; macro_rules! pointer_type {    ($pointer_name:ident) => {        #[repr(transparent)]        #[derive(Copy, Clone, Debug)]        pub struct $pointer_name(pub *const std::ffi::c_void);        unsafe impl Send for $pointer_name {}    };} mod swift {    pointer_type!(Room);    pointer_type!(LocalAudioTrack);    pointer_type!(RemoteAudioTrack);    pointer_type!(LocalVideoTrack);    pointer_type!(RemoteVideoTrack);    pointer_type!(LocalTrackPublication);    pointer_type!(RemoteTrackPublication);    pointer_type!(MacOSDisplay);    pointer_type!(RoomDelegate);} extern "C" {    fn LKRoomDelegateCreate(        callback_data: *mut c_void,        on_did_disconnect: extern "C" fn(callback_data: *mut c_void),        on_did_subscribe_to_remote_audio_track: extern "C" fn(            callback_data: *mut c_void,            publisher_id: CFStringRef,            track_id: CFStringRef,            remote_track: swift::RemoteAudioTrack,            remote_publication: swift::RemoteTrackPublication,        ),        on_did_unsubscribe_from_remote_audio_track: extern "C" fn(            callback_data: *mut c_void,            publisher_id: CFStringRef,            track_id: CFStringRef,        ),        on_mute_changed_from_remote_audio_track: extern "C" fn(            callback_data: *mut c_void,            track_id: CFStringRef,            muted: bool,        ),        on_active_speakers_changed: extern "C" fn(            callback_data: *mut c_void,            participants: CFArrayRef,        ),        on_did_subscribe_to_remote_video_track: extern "C" fn(            callback_data: *mut c_void,            publisher_id: CFStringRef,            track_id: CFStringRef,            remote_track: swift::RemoteVideoTrack,        ),        on_did_unsubscribe_from_remote_video_track: extern "C" fn(            callback_data: *mut c_void,            publisher_id: CFStringRef,            track_id: CFStringRef,        ),        on_did_publish_or_unpublish_local_audio_track: extern "C" fn(            callback_data: *mut c_void,            publication: swift::LocalTrackPublication,            is_published: bool,        ),        on_did_publish_or_unpublish_local_video_track: extern "C" fn(            callback_data: *mut c_void,            publication: swift::LocalTrackPublication,            is_published: bool,        ),    ) -> swift::RoomDelegate;     fn LKRoomCreate(delegate: swift::RoomDelegate) -> swift::Room;    fn LKRoomConnect(        room: swift::Room,        url: CFStringRef,        token: CFStringRef,        callback: extern "C" fn(*mut c_void, CFStringRef),        callback_data: *mut c_void,    );    fn LKRoomDisconnect(room: swift::Room);    fn LKRoomPublishVideoTrack(        room: swift::Room,        track: swift::LocalVideoTrack,        callback: extern "C" fn(*mut c_void, swift::LocalTrackPublication, CFStringRef),        callback_data: *mut c_void,    );    fn LKRoomPublishAudioTrack(        room: swift::Room,        track: swift::LocalAudioTrack,        callback: extern "C" fn(*mut c_void, swift::LocalTrackPublication, CFStringRef),        callback_data: *mut c_void,    );    fn LKRoomUnpublishTrack(room: swift::Room, publication: swift::LocalTrackPublication);     fn LKRoomAudioTracksForRemoteParticipant(        room: swift::Room,        participant_id: CFStringRef,    ) -> CFArrayRef;     fn LKRoomAudioTrackPublicationsForRemoteParticipant(        room: swift::Room,        participant_id: CFStringRef,    ) -> CFArrayRef;     fn LKRoomVideoTracksForRemoteParticipant(        room: swift::Room,        participant_id: CFStringRef,    ) -> CFArrayRef;     fn LKVideoRendererCreate(        callback_data: *mut c_void,        on_frame: extern "C" fn(callback_data: *mut c_void, frame: CVImageBufferRef) -> bool,        on_drop: extern "C" fn(callback_data: *mut c_void),    ) -> *const c_void;     fn LKRemoteAudioTrackGetSid(track: swift::RemoteAudioTrack) -> CFStringRef;    fn LKRemoteVideoTrackGetSid(track: swift::RemoteVideoTrack) -> CFStringRef;    fn LKRemoteAudioTrackStart(track: swift::RemoteAudioTrack);    fn LKRemoteAudioTrackStop(track: swift::RemoteAudioTrack);    fn LKVideoTrackAddRenderer(track: swift::RemoteVideoTrack, renderer: *const c_void);     fn LKDisplaySources(        callback_data: *mut c_void,        callback: extern "C" fn(            callback_data: *mut c_void,            sources: CFArrayRef,            error: CFStringRef,        ),    );    fn LKCreateScreenShareTrackForDisplay(display: swift::MacOSDisplay) -> swift::LocalVideoTrack;    fn LKLocalAudioTrackCreateTrack() -> swift::LocalAudioTrack;     fn LKLocalTrackPublicationSetMute(        publication: swift::LocalTrackPublication,        muted: bool,        on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef),        callback_data: *mut c_void,    );     fn LKRemoteTrackPublicationSetEnabled(        publication: swift::RemoteTrackPublication,        enabled: bool,        on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef),        callback_data: *mut c_void,    );     fn LKLocalTrackPublicationIsMuted(publication: swift::LocalTrackPublication) -> bool;    fn LKRemoteTrackPublicationIsMuted(publication: swift::RemoteTrackPublication) -> bool;    fn LKLocalTrackPublicationGetSid(publication: swift::LocalTrackPublication) -> CFStringRef;    fn LKRemoteTrackPublicationGetSid(publication: swift::RemoteTrackPublication) -> CFStringRef;} pub struct Room {    native_room: swift::Room,    connection: Mutex<(        watch::Sender<ConnectionState>,        watch::Receiver<ConnectionState>,    )>,    update_subscribers: Mutex<Vec<mpsc::UnboundedSender<RoomUpdate>>>,    _delegate: RoomDelegate,} impl Room {    pub fn new() -> Arc<Self> {        Arc::new_cyclic(|weak_room| {            let delegate = RoomDelegate::new(weak_room.clone());            Self {                native_room: unsafe { LKRoomCreate(delegate.native_delegate) },                connection: Mutex::new(watch::channel_with(ConnectionState::Disconnected)),                update_subscribers: Default::default(),                _delegate: delegate,            }        })    }     pub fn status(&self) -> watch::Receiver<ConnectionState> {        self.connection.lock().1.clone()    }     pub fn connect(self: &Arc<Self>, url: &str, token: &str) -> impl Future<Output = Result<()>> {        let url = CFString::new(url);        let token = CFString::new(token);        let (did_connect, tx, rx) = Self::build_done_callback();        unsafe {            LKRoomConnect(                self.native_room,                url.as_concrete_TypeRef(),                token.as_concrete_TypeRef(),                did_connect,                tx,            )        }         let this = self.clone();        let url = url.to_string();        let token = token.to_string();        async move {            rx.await.unwrap().context("error connecting to room")?;            *this.connection.lock().0.borrow_mut() = ConnectionState::Connected { url, token };            Ok(())        }    }     fn did_disconnect(&self) {        *self.connection.lock().0.borrow_mut() = ConnectionState::Disconnected;    }     pub fn display_sources(self: &Arc<Self>) -> impl Future<Output = Result<Vec<MacOSDisplay>>> {        extern "C" fn callback(tx: *mut c_void, sources: CFArrayRef, error: CFStringRef) {            unsafe {                let tx = Box::from_raw(tx as *mut oneshot::Sender<Result<Vec<MacOSDisplay>>>);                 if sources.is_null() {                    let _ = tx.send(Err(anyhow!("{}", CFString::wrap_under_get_rule(error))));                } else {                    let sources = CFArray::wrap_under_get_rule(sources)                        .into_iter()                        .map(|source| MacOSDisplay::new(swift::MacOSDisplay(*source)))                        .collect();                     let _ = tx.send(Ok(sources));                }            }        }         let (tx, rx) = oneshot::channel();         unsafe {            LKDisplaySources(Box::into_raw(Box::new(tx)) as *mut _, callback);        }         async move { rx.await.unwrap() }    }     pub fn publish_video_track(        self: &Arc<Self>,        track: LocalVideoTrack,    ) -> impl Future<Output = Result<LocalTrackPublication>> {        let (tx, rx) = oneshot::channel::<Result<LocalTrackPublication>>();        extern "C" fn callback(            tx: *mut c_void,            publication: swift::LocalTrackPublication,            error: CFStringRef,        ) {            let tx =                unsafe { Box::from_raw(tx as *mut oneshot::Sender<Result<LocalTrackPublication>>) };            if error.is_null() {                let _ = tx.send(Ok(LocalTrackPublication::new(publication)));            } else {                let error = unsafe { CFString::wrap_under_get_rule(error).to_string() };                let _ = tx.send(Err(anyhow!(error)));            }        }        unsafe {            LKRoomPublishVideoTrack(                self.native_room,                track.0,                callback,                Box::into_raw(Box::new(tx)) as *mut c_void,            );        }        async { rx.await.unwrap().context("error publishing video track") }    }     pub fn publish_audio_track(        self: &Arc<Self>,        track: LocalAudioTrack,    ) -> impl Future<Output = Result<LocalTrackPublication>> {        let (tx, rx) = oneshot::channel::<Result<LocalTrackPublication>>();        extern "C" fn callback(            tx: *mut c_void,            publication: swift::LocalTrackPublication,            error: CFStringRef,        ) {            let tx =                unsafe { Box::from_raw(tx as *mut oneshot::Sender<Result<LocalTrackPublication>>) };            if error.is_null() {                let _ = tx.send(Ok(LocalTrackPublication::new(publication)));            } else {                let error = unsafe { CFString::wrap_under_get_rule(error).to_string() };                let _ = tx.send(Err(anyhow!(error)));            }        }        unsafe {            LKRoomPublishAudioTrack(                self.native_room,                track.0,                callback,                Box::into_raw(Box::new(tx)) as *mut c_void,            );        }        async { rx.await.unwrap().context("error publishing audio track") }    }     pub fn unpublish_track(&self, publication: LocalTrackPublication) {        unsafe {            LKRoomUnpublishTrack(self.native_room, publication.0);        }    }     pub fn remote_video_tracks(&self, participant_id: &str) -> Vec<Arc<RemoteVideoTrack>> {        unsafe {            let tracks = LKRoomVideoTracksForRemoteParticipant(                self.native_room,                CFString::new(participant_id).as_concrete_TypeRef(),            );             if tracks.is_null() {                Vec::new()            } else {                let tracks = CFArray::wrap_under_get_rule(tracks);                tracks                    .into_iter()                    .map(|native_track| {                        let native_track = swift::RemoteVideoTrack(*native_track);                        let id =                            CFString::wrap_under_get_rule(LKRemoteVideoTrackGetSid(native_track))                                .to_string();                        Arc::new(RemoteVideoTrack::new(                            native_track,                            id,                            participant_id.into(),                        ))                    })                    .collect()            }        }    }     pub fn remote_audio_tracks(&self, participant_id: &str) -> Vec<Arc<RemoteAudioTrack>> {        unsafe {            let tracks = LKRoomAudioTracksForRemoteParticipant(                self.native_room,                CFString::new(participant_id).as_concrete_TypeRef(),            );             if tracks.is_null() {                Vec::new()            } else {                let tracks = CFArray::wrap_under_get_rule(tracks);                tracks                    .into_iter()                    .map(|native_track| {                        let native_track = swift::RemoteAudioTrack(*native_track);                        let id =                            CFString::wrap_under_get_rule(LKRemoteAudioTrackGetSid(native_track))                                .to_string();                        Arc::new(RemoteAudioTrack::new(                            native_track,                            id,                            participant_id.into(),                        ))                    })                    .collect()            }        }    }     pub fn remote_audio_track_publications(        &self,        participant_id: &str,    ) -> Vec<Arc<RemoteTrackPublication>> {        unsafe {            let tracks = LKRoomAudioTrackPublicationsForRemoteParticipant(                self.native_room,                CFString::new(participant_id).as_concrete_TypeRef(),            );             if tracks.is_null() {                Vec::new()            } else {                let tracks = CFArray::wrap_under_get_rule(tracks);                tracks                    .into_iter()                    .map(|native_track_publication| {                        let native_track_publication =                            swift::RemoteTrackPublication(*native_track_publication);                        Arc::new(RemoteTrackPublication::new(native_track_publication))                    })                    .collect()            }        }    }     pub fn updates(&self) -> mpsc::UnboundedReceiver<RoomUpdate> {        let (tx, rx) = mpsc::unbounded();        self.update_subscribers.lock().push(tx);        rx    }     fn did_subscribe_to_remote_audio_track(        &self,        track: RemoteAudioTrack,        publication: RemoteTrackPublication,    ) {        let track = Arc::new(track);        let publication = Arc::new(publication);        self.update_subscribers.lock().retain(|tx| {            tx.unbounded_send(RoomUpdate::SubscribedToRemoteAudioTrack(                track.clone(),                publication.clone(),            ))            .is_ok()        });    }     fn did_unsubscribe_from_remote_audio_track(&self, publisher_id: String, track_id: String) {        self.update_subscribers.lock().retain(|tx| {            tx.unbounded_send(RoomUpdate::UnsubscribedFromRemoteAudioTrack {                publisher_id: publisher_id.clone(),                track_id: track_id.clone(),            })            .is_ok()        });    }     fn mute_changed_from_remote_audio_track(&self, track_id: String, muted: bool) {        self.update_subscribers.lock().retain(|tx| {            tx.unbounded_send(RoomUpdate::RemoteAudioTrackMuteChanged {                track_id: track_id.clone(),                muted,            })            .is_ok()        });    }     fn active_speakers_changed(&self, speakers: Vec<String>) {        self.update_subscribers.lock().retain(move |tx| {            tx.unbounded_send(RoomUpdate::ActiveSpeakersChanged {                speakers: speakers.clone(),            })            .is_ok()        });    }     fn did_subscribe_to_remote_video_track(&self, track: RemoteVideoTrack) {        let track = Arc::new(track);        self.update_subscribers.lock().retain(|tx| {            tx.unbounded_send(RoomUpdate::SubscribedToRemoteVideoTrack(track.clone()))                .is_ok()        });    }     fn did_unsubscribe_from_remote_video_track(&self, publisher_id: String, track_id: String) {        self.update_subscribers.lock().retain(|tx| {            tx.unbounded_send(RoomUpdate::UnsubscribedFromRemoteVideoTrack {                publisher_id: publisher_id.clone(),                track_id: track_id.clone(),            })            .is_ok()        });    }     fn build_done_callback() -> (        extern "C" fn(*mut c_void, CFStringRef),        *mut c_void,        oneshot::Receiver<Result<()>>,    ) {        let (tx, rx) = oneshot::channel();        extern "C" fn done_callback(tx: *mut c_void, error: CFStringRef) {            let tx = unsafe { Box::from_raw(tx as *mut oneshot::Sender<Result<()>>) };            if error.is_null() {                let _ = tx.send(Ok(()));            } else {                let error = unsafe { CFString::wrap_under_get_rule(error).to_string() };                let _ = tx.send(Err(anyhow!(error)));            }        }        (            done_callback,            Box::into_raw(Box::new(tx)) as *mut c_void,            rx,        )    }     pub fn set_display_sources(&self, _: Vec<MacOSDisplay>) {        unreachable!("This is a test-only function")    }} impl Drop for Room {    fn drop(&mut self) {

Lines 1–500 of 981.