diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 4434aa77e0..32f22d41e0 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -600,7 +600,7 @@ impl Room { }; cx.foreground().spawn(async move { - let display = live_kit_client::display_source().await?; + let display = live_kit_client::display_sources().await?; // let display = displays // .first() // .ok_or_else(|| anyhow!("no display found"))?; diff --git a/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift b/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift index 4401b06b30..109b9fb84a 100644 --- a/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift +++ b/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift @@ -100,15 +100,7 @@ public func LKRoomVideoTracksForRemoteParticipant(room: UnsafeRawPointer, partic for (_, participant) in room.remoteParticipants { if participant.identity == participantId as String { - var tracks = [UnsafeMutableRawPointer]() - for publication in participant.videoTracks { - let track = publication.track as? RemoteVideoTrack - if track != nil { - tracks.append(Unmanaged.passRetained(track!).toOpaque()) - } - - } - return tracks as CFArray? + return participant.videoTracks.compactMap { $0.track as? RemoteVideoTrack } as CFArray? } } @@ -140,11 +132,10 @@ public func LKRemoteVideoTrackGetSid(track: UnsafeRawPointer) -> CFString { return track.sid! as CFString } -@_cdecl("LKDisplaySource") -public func LKDisplaySource(data: UnsafeRawPointer, callback: @escaping @convention(c) (UnsafeRawPointer, UnsafeRawPointer?, CFString?) -> Void) { +@_cdecl("LKDisplaySources") +public func LKDisplaySources(data: UnsafeRawPointer, callback: @escaping @convention(c) (UnsafeRawPointer, CFArray?, CFString?) -> Void) { MacOSScreenCapturer.sources(for: .display, includeCurrentApplication: false, preferredMethod: .legacy).then { displaySources in - let displaySource = displaySources.first.map { Unmanaged.passRetained($0).toOpaque() } - callback(data, displaySource, nil) + callback(data, displaySources as CFArray, nil) }.catch { error in callback(data, nil, error.localizedDescription as CFString) } diff --git a/crates/live_kit_client/examples/test_app.rs b/crates/live_kit_client/examples/test_app.rs index 370d20354f..d35e9fc549 100644 --- a/crates/live_kit_client/examples/test_app.rs +++ b/crates/live_kit_client/examples/test_app.rs @@ -60,7 +60,8 @@ fn main() { let mut track_changes = room_b.remote_video_track_updates(); - let display = live_kit_client::display_source().await.unwrap(); + let displays = live_kit_client::display_sources().await.unwrap(); + let display = displays.into_iter().next().unwrap(); let track_a = LocalVideoTrack::screen_share_for_display(&display); room_a.publish_video_track(&track_a).await.unwrap(); @@ -68,19 +69,13 @@ fn main() { let next_update = track_changes.next().await.unwrap(); if let RemoteVideoTrackUpdate::Subscribed(track) = next_update { - println!("A !!!!!!!!!!!!"); let remote_tracks = room_b.remote_video_tracks("test-participant-1"); - println!("B !!!!!!!!!!!!"); assert_eq!(remote_tracks.len(), 1); - println!("C !!!!!!!!!!!!"); assert_eq!(remote_tracks[0].publisher_id(), "test-participant-1"); - println!("D !!!!!!!!!!!!"); - // dbg!(track.id()); - // assert_eq!(track.id(), "test-participant-1"); + assert_eq!(track.publisher_id(), "test-participant-1"); } else { panic!("unexpected message") } - println!("E !!!!!!!!!!!!"); cx.platform().quit(); }) diff --git a/crates/live_kit_client/src/live_kit_client.rs b/crates/live_kit_client/src/live_kit_client.rs index 2d871d31b4..ccd0ba6775 100644 --- a/crates/live_kit_client/src/live_kit_client.rs +++ b/crates/live_kit_client/src/live_kit_client.rs @@ -1,7 +1,7 @@ use anyhow::{anyhow, Context, Result}; use core_foundation::{ array::{CFArray, CFArrayRef}, - base::TCFType, + base::{CFRetain, TCFType}, string::{CFString, CFStringRef}, }; use futures::{ @@ -65,11 +65,11 @@ extern "C" { fn LKVideoTrackAddRenderer(track: *const c_void, renderer: *const c_void); fn LKRemoteVideoTrackGetSid(track: *const c_void) -> CFStringRef; - fn LKDisplaySource( + fn LKDisplaySources( callback_data: *mut c_void, callback: extern "C" fn( callback_data: *mut c_void, - source: *mut c_void, + sources: CFArrayRef, error: CFStringRef, ), ); @@ -119,33 +119,29 @@ impl Room { async { rx.await.unwrap().context("error publishing video track") } } - pub fn remote_video_tracks(&self, participant_sid: &sid) -> Vec> { + pub fn remote_video_tracks(&self, participant_id: &str) -> Vec> { unsafe { let tracks = LKRoomVideoTracksForRemoteParticipant( self.native_room, - CFString::new(participant_sid).as_concrete_TypeRef(), + CFString::new(participant_id).as_concrete_TypeRef(), ); if tracks.is_null() { Vec::new() } else { - println!("aaaa >>>>>>>>>>>>>>>"); let tracks = CFArray::wrap_under_get_rule(tracks); - println!("bbbb >>>>>>>>>>>>>>>"); tracks .into_iter() .map(|native_track| { let native_track = *native_track; - println!("cccc >>>>>>>>>>>>>>>"); let id = CFString::wrap_under_get_rule(LKRemoteVideoTrackGetSid(native_track)) .to_string(); - println!("dddd >>>>>>>>>>>>>>>"); - Arc::new(RemoteVideoTrack { + Arc::new(RemoteVideoTrack::new( native_track, - publisher_id: participant_sid.into(), id, - }) + participant_id.into(), + )) }) .collect() } @@ -235,15 +231,10 @@ impl RoomDelegate { let room = unsafe { Weak::from_raw(room as *mut Room) }; let publisher_id = unsafe { CFString::wrap_under_get_rule(publisher_id).to_string() }; let track_id = unsafe { CFString::wrap_under_get_rule(track_id).to_string() }; - let track = RemoteVideoTrack { - id: track_id, - native_track: track, - publisher_id, - }; + let track = RemoteVideoTrack::new(track, track_id, publisher_id); if let Some(room) = room.upgrade() { room.did_subscribe_to_remote_video_track(track); } - // let _ = Weak::into_raw(room); } extern "C" fn on_did_unsubscribe_from_remote_video_track( @@ -286,12 +277,23 @@ impl Drop for LocalVideoTrack { #[derive(Debug)] pub struct RemoteVideoTrack { - id: Sid, native_track: *const c_void, - publisher_id: Sid, + id: Sid, + publisher_id: String, } impl RemoteVideoTrack { + pub fn new(native_track: *const c_void, id: Sid, publisher_id: String) -> Self { + unsafe { + CFRetain(native_track); + } + Self { + native_track, + id, + publisher_id, + } + } + pub fn id(&self) -> &str { &self.id } @@ -343,22 +345,35 @@ pub enum RemoteVideoTrackUpdate { pub struct MacOSDisplay(*const c_void); +impl MacOSDisplay { + fn new(ptr: *const c_void) -> Self { + unsafe { + CFRetain(ptr); + } + Self(ptr) + } +} + impl Drop for MacOSDisplay { fn drop(&mut self) { unsafe { LKRelease(self.0) } } } -pub fn display_source() -> impl Future> { - extern "C" fn callback(tx: *mut c_void, source: *mut c_void, error: CFStringRef) { +pub fn display_sources() -> impl Future>> { + extern "C" fn callback(tx: *mut c_void, sources: CFArrayRef, error: CFStringRef) { unsafe { - let tx = Box::from_raw(tx as *mut oneshot::Sender>); + let tx = Box::from_raw(tx as *mut oneshot::Sender>>); - if source.is_null() { + if sources.is_null() { let _ = tx.send(Err(anyhow!("{}", CFString::wrap_under_get_rule(error)))); } else { - let source = MacOSDisplay(source); - let _ = tx.send(Ok(source)); + let sources = CFArray::wrap_under_get_rule(sources) + .into_iter() + .map(|source| MacOSDisplay::new(*source)) + .collect(); + + let _ = tx.send(Ok(sources)); } } } @@ -366,7 +381,7 @@ pub fn display_source() -> impl Future> { let (tx, rx) = oneshot::channel(); unsafe { - LKDisplaySource(Box::into_raw(Box::new(tx)) as *mut _, callback); + LKDisplaySources(Box::into_raw(Box::new(tx)) as *mut _, callback); } async move { rx.await.unwrap() }