Register to publishing of remote tracks

This commit is contained in:
Antonio Scandurra 2022-09-07 18:32:39 +02:00
parent 37ca5651ee
commit 645338cff8
3 changed files with 143 additions and 34 deletions

View file

@ -1,5 +1,7 @@
mod live_kit_token; mod live_kit_token;
use std::time::Duration;
use gpui::{ use gpui::{
actions, actions,
elements::{Canvas, *}, elements::{Canvas, *},
@ -34,25 +36,38 @@ fn main() {
let live_kit_key = std::env::var("LIVE_KIT_KEY").unwrap(); let live_kit_key = std::env::var("LIVE_KIT_KEY").unwrap();
let live_kit_secret = std::env::var("LIVE_KIT_SECRET").unwrap(); let live_kit_secret = std::env::var("LIVE_KIT_SECRET").unwrap();
let token = live_kit_token::create_token( let background = cx.background().clone();
&live_kit_key,
&live_kit_secret,
"test-room",
"test-participant",
)
.unwrap();
let room = Room::new();
cx.foreground() cx.foreground()
.spawn(async move { .spawn(async move {
println!("connecting..."); println!("connecting...");
room.connect(&live_kit_url, &token).await.unwrap(); let user1_token = live_kit_token::create_token(
&live_kit_key,
&live_kit_secret,
"test-room",
"test-participant-1",
)
.unwrap();
let room1 = Room::new("user-1 room");
room1.connect(&live_kit_url, &user1_token).await.unwrap();
let user2_token = live_kit_token::create_token(
&live_kit_key,
&live_kit_secret,
"test-room",
"test-participant-2",
)
.unwrap();
let room2 = Room::new("user-2 room");
room2.connect(&live_kit_url, &user2_token).await.unwrap();
let windows = live_kit::list_windows(); let windows = live_kit::list_windows();
println!("connected! {:?}", windows); println!("connected! {:?}", windows);
let window_id = windows.iter().next().unwrap().id; let window_id = windows.iter().next().unwrap().id;
let track = LocalVideoTrack::screen_share_for_window(window_id); let track = LocalVideoTrack::screen_share_for_window(window_id);
room.publish_video_track(&track).await.unwrap(); room1.publish_video_track(&track).await.unwrap();
background.timer(Duration::from_secs(120)).await;
}) })
.detach(); .detach();

View file

@ -1,40 +1,61 @@
import Foundation import Foundation
import LiveKit import LiveKit
class LKRoomDelegate: RoomDelegate {
var data: UnsafeRawPointer
var onDidSubscribeToRemoteTrack: @convention(c) (UnsafeRawPointer, UnsafeRawPointer) -> Void
init(data: UnsafeRawPointer, onDidSubscribeToRemoteTrack: @escaping @convention(c) (UnsafeRawPointer, UnsafeRawPointer) -> Void) {
self.data = data
self.onDidSubscribeToRemoteTrack = onDidSubscribeToRemoteTrack
}
func room(_ room: Room, participant: RemoteParticipant, didSubscribe publication: RemoteTrackPublication, track: Track) {
self.onDidSubscribeToRemoteTrack(self.data, Unmanaged.passRetained(track).toOpaque())
}
}
@_cdecl("LKRelease") @_cdecl("LKRelease")
public func LKRelease(ptr: UnsafeRawPointer) { public func LKRelease(ptr: UnsafeRawPointer) {
let _ = Unmanaged<AnyObject>.fromOpaque(ptr).takeRetainedValue(); let _ = Unmanaged<AnyObject>.fromOpaque(ptr).takeRetainedValue()
}
@_cdecl("LKRoomDelegateCreate")
public func LKRoomDelegateCreate(data: UnsafeRawPointer, onDidSubscribeToRemoteTrack: @escaping @convention(c) (UnsafeRawPointer, UnsafeRawPointer) -> Void) -> UnsafeMutableRawPointer {
let delegate = LKRoomDelegate(data: data, onDidSubscribeToRemoteTrack: onDidSubscribeToRemoteTrack)
return Unmanaged.passRetained(delegate).toOpaque()
} }
@_cdecl("LKRoomCreate") @_cdecl("LKRoomCreate")
public func LKRoomCreate() -> UnsafeMutableRawPointer { public func LKRoomCreate(delegate: UnsafeRawPointer) -> UnsafeMutableRawPointer {
Unmanaged.passRetained(Room()).toOpaque() let delegate = Unmanaged<LKRoomDelegate>.fromOpaque(delegate).takeUnretainedValue()
return Unmanaged.passRetained(Room(delegate: delegate)).toOpaque()
} }
@_cdecl("LKRoomConnect") @_cdecl("LKRoomConnect")
public func LKRoomConnect(room: UnsafeRawPointer, url: CFString, token: CFString, callback: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, callback_data: UnsafeRawPointer) { public func LKRoomConnect(room: UnsafeRawPointer, url: CFString, token: CFString, callback: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, callback_data: UnsafeRawPointer) {
let room = Unmanaged<Room>.fromOpaque(room).takeUnretainedValue(); let room = Unmanaged<Room>.fromOpaque(room).takeUnretainedValue()
room.connect(url as String, token as String).then { _ in room.connect(url as String, token as String).then { _ in
callback(callback_data, UnsafeRawPointer(nil) as! CFString?); callback(callback_data, UnsafeRawPointer(nil) as! CFString?)
}.catch { error in }.catch { error in
callback(callback_data, error.localizedDescription as CFString); callback(callback_data, error.localizedDescription as CFString)
}; }
} }
@_cdecl("LKRoomPublishVideoTrack") @_cdecl("LKRoomPublishVideoTrack")
public func LKRoomPublishVideoTrack(room: UnsafeRawPointer, track: UnsafeRawPointer, callback: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, callback_data: UnsafeRawPointer) { public func LKRoomPublishVideoTrack(room: UnsafeRawPointer, track: UnsafeRawPointer, callback: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, callback_data: UnsafeRawPointer) {
let room = Unmanaged<Room>.fromOpaque(room).takeUnretainedValue(); let room = Unmanaged<Room>.fromOpaque(room).takeUnretainedValue()
let track = Unmanaged<LocalVideoTrack>.fromOpaque(track).takeUnretainedValue(); let track = Unmanaged<LocalVideoTrack>.fromOpaque(track).takeUnretainedValue()
room.localParticipant?.publishVideoTrack(track: track).then { _ in room.localParticipant?.publishVideoTrack(track: track).then { _ in
callback(callback_data, UnsafeRawPointer(nil) as! CFString?); callback(callback_data, UnsafeRawPointer(nil) as! CFString?)
}.catch { error in }.catch { error in
callback(callback_data, error.localizedDescription as CFString); callback(callback_data, error.localizedDescription as CFString)
}; }
} }
@_cdecl("LKCreateScreenShareTrackForWindow") @_cdecl("LKCreateScreenShareTrackForWindow")
public func LKCreateScreenShareTrackForWindow(windowId: uint32) -> UnsafeMutableRawPointer { public func LKCreateScreenShareTrackForWindow(windowId: uint32) -> UnsafeMutableRawPointer {
let track = LocalVideoTrack.createMacOSScreenShareTrack(source: .window(id: windowId)); let track = LocalVideoTrack.createMacOSScreenShareTrack(source: .window(id: windowId))
return Unmanaged.passRetained(track).toOpaque() return Unmanaged.passRetained(track).toOpaque()
} }

View file

@ -11,34 +11,56 @@ use core_graphics::window::{
kCGWindowNumber, kCGWindowOwnerName, kCGWindowOwnerPID, CGWindowListCopyWindowInfo, kCGWindowNumber, kCGWindowOwnerName, kCGWindowOwnerPID, CGWindowListCopyWindowInfo,
}; };
use futures::{channel::oneshot, Future}; use futures::{channel::oneshot, Future};
use std::ffi::c_void; use std::{
ffi::c_void,
sync::{Arc, Weak},
};
extern "C" { extern "C" {
fn LKRelease(object: *const c_void); fn LKRelease(object: *const c_void);
fn LKRoomCreate() -> *const c_void; fn LKRoomDelegateCreate(
callback_data: *const c_void,
on_did_subscribe_to_remote_track: extern "C" fn(
callback_data: *mut c_void,
remote_track: *const c_void,
),
) -> *const c_void;
fn LKRoomCreate(delegate: *const c_void) -> *const c_void;
fn LKRoomConnect( fn LKRoomConnect(
room: *const c_void, room: *const c_void,
url: CFStringRef, url: CFStringRef,
token: CFStringRef, token: CFStringRef,
callback: extern "C" fn(*mut c_void, CFStringRef) -> (), callback: extern "C" fn(*mut c_void, CFStringRef),
callback_data: *mut c_void, callback_data: *mut c_void,
); );
fn LKRoomPublishVideoTrack( fn LKRoomPublishVideoTrack(
room: *const c_void, room: *const c_void,
track: *const c_void, track: *const c_void,
callback: extern "C" fn(*mut c_void, CFStringRef) -> (), callback: extern "C" fn(*mut c_void, CFStringRef),
callback_data: *mut c_void, callback_data: *mut c_void,
); );
fn LKCreateScreenShareTrackForWindow(windowId: u32) -> *const c_void; fn LKCreateScreenShareTrackForWindow(windowId: u32) -> *const c_void;
} }
pub struct Room(*const c_void); pub struct Room {
debug_name: &'static str,
native_room: *const c_void,
_delegate: RoomDelegate,
}
impl Room { impl Room {
pub fn new() -> Self { pub fn new(debug_name: &'static str) -> Arc<Self> {
Self(unsafe { LKRoomCreate() }) Arc::new_cyclic(|weak_room| {
let delegate = RoomDelegate::new(weak_room.clone());
Self {
debug_name,
native_room: unsafe { LKRoomCreate(delegate.native_delegate) },
_delegate: delegate,
}
})
} }
pub fn connect(&self, url: &str, token: &str) -> impl Future<Output = Result<()>> { pub fn connect(&self, url: &str, token: &str) -> impl Future<Output = Result<()>> {
@ -47,7 +69,7 @@ impl Room {
let (did_connect, tx, rx) = Self::build_done_callback(); let (did_connect, tx, rx) = Self::build_done_callback();
unsafe { unsafe {
LKRoomConnect( LKRoomConnect(
self.0, self.native_room,
url.as_concrete_TypeRef(), url.as_concrete_TypeRef(),
token.as_concrete_TypeRef(), token.as_concrete_TypeRef(),
did_connect, did_connect,
@ -61,11 +83,15 @@ impl Room {
pub fn publish_video_track(&self, track: &LocalVideoTrack) -> impl Future<Output = Result<()>> { pub fn publish_video_track(&self, track: &LocalVideoTrack) -> impl Future<Output = Result<()>> {
let (did_publish, tx, rx) = Self::build_done_callback(); let (did_publish, tx, rx) = Self::build_done_callback();
unsafe { unsafe {
LKRoomPublishVideoTrack(self.0, track.0, did_publish, tx); LKRoomPublishVideoTrack(self.native_room, track.0, did_publish, tx);
} }
async { rx.await.unwrap().context("error publishing video track") } async { rx.await.unwrap().context("error publishing video track") }
} }
fn did_subscribe_to_remote_track(&self, track: RemoteVideoTrack) {
println!("{}: !!!!!!!!!!!!!!!!!!", self.debug_name);
}
fn build_done_callback() -> ( fn build_done_callback() -> (
extern "C" fn(*mut c_void, CFStringRef), extern "C" fn(*mut c_void, CFStringRef),
*mut c_void, *mut c_void,
@ -91,7 +117,46 @@ impl Room {
impl Drop for Room { impl Drop for Room {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { LKRelease(self.0) } unsafe { LKRelease(self.native_room) }
}
}
struct RoomDelegate {
native_delegate: *const c_void,
weak_room: *const Room,
}
impl RoomDelegate {
fn new(weak_room: Weak<Room>) -> Self {
let weak_room = Weak::into_raw(weak_room);
let native_delegate = unsafe {
LKRoomDelegateCreate(
weak_room as *const c_void,
Self::on_did_subscribe_to_remote_track,
)
};
Self {
native_delegate,
weak_room,
}
}
extern "C" fn on_did_subscribe_to_remote_track(room: *mut c_void, track: *const c_void) {
let room = unsafe { Weak::from_raw(room as *mut Room) };
let track = unsafe { RemoteVideoTrack(track) };
if let Some(room) = room.upgrade() {
room.did_subscribe_to_remote_track(track);
}
let _ = Weak::into_raw(room);
}
}
impl Drop for RoomDelegate {
fn drop(&mut self) {
unsafe {
LKRelease(self.native_delegate);
let _ = Weak::from_raw(self.weak_room);
}
} }
} }
@ -109,6 +174,14 @@ impl Drop for LocalVideoTrack {
} }
} }
pub struct RemoteVideoTrack(*const c_void);
impl Drop for RemoteVideoTrack {
fn drop(&mut self) {
unsafe { LKRelease(self.0) }
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct WindowInfo { pub struct WindowInfo {
pub id: u32, pub id: u32,