Get test_app running without crashing

Nathan Sobo created

Change summary

crates/call/src/room.rs                                                        |  2 
crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift | 17 
crates/live_kit_client/examples/test_app.rs                                    | 11 
crates/live_kit_client/src/live_kit_client.rs                                  | 69 
4 files changed, 50 insertions(+), 49 deletions(-)

Detailed changes

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"))?;

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)
     }

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();
         })

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<Arc<RemoteVideoTrack>> {
+    pub fn remote_video_tracks(&self, participant_id: &str) -> Vec<Arc<RemoteVideoTrack>> {
         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<Output = Result<MacOSDisplay>> {
-    extern "C" fn callback(tx: *mut c_void, source: *mut c_void, error: CFStringRef) {
+pub fn display_sources() -> 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<MacOSDisplay>>);
+            let tx = Box::from_raw(tx as *mut oneshot::Sender<Result<Vec<MacOSDisplay>>>);
 
-            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<Output = Result<MacOSDisplay>> {
     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() }