Wire in audio APIs from swift
co-authored-by: nathan <nathan@zed.dev>
This commit is contained in:
parent
8ccb75029f
commit
bbf05c8eac
5 changed files with 355 additions and 14 deletions
|
@ -21,6 +21,17 @@ 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: *const c_void,
|
||||
),
|
||||
on_did_unsubscribe_from_remote_audio_track: extern "C" fn(
|
||||
callback_data: *mut c_void,
|
||||
publisher_id: CFStringRef,
|
||||
track_id: CFStringRef,
|
||||
),
|
||||
on_did_subscribe_to_remote_video_track: extern "C" fn(
|
||||
callback_data: *mut c_void,
|
||||
publisher_id: CFStringRef,
|
||||
|
@ -49,7 +60,18 @@ extern "C" {
|
|||
callback: extern "C" fn(*mut c_void, *mut c_void, CFStringRef),
|
||||
callback_data: *mut c_void,
|
||||
);
|
||||
fn LKRoomPublishAudioTrack(
|
||||
room: *const c_void,
|
||||
track: *const c_void,
|
||||
callback: extern "C" fn(*mut c_void, *mut c_void, CFStringRef),
|
||||
callback_data: *mut c_void,
|
||||
);
|
||||
fn LKRoomUnpublishTrack(room: *const c_void, publication: *const c_void);
|
||||
fn LKRoomAudioTracksForRemoteParticipant(
|
||||
room: *const c_void,
|
||||
participant_id: CFStringRef,
|
||||
) -> CFArrayRef;
|
||||
|
||||
fn LKRoomVideoTracksForRemoteParticipant(
|
||||
room: *const c_void,
|
||||
participant_id: CFStringRef,
|
||||
|
@ -61,6 +83,7 @@ extern "C" {
|
|||
on_drop: extern "C" fn(callback_data: *mut c_void),
|
||||
) -> *const c_void;
|
||||
|
||||
fn LKRemoteAudioTrackGetSid(track: *const c_void) -> CFStringRef;
|
||||
fn LKVideoTrackAddRenderer(track: *const c_void, renderer: *const c_void);
|
||||
fn LKRemoteVideoTrackGetSid(track: *const c_void) -> CFStringRef;
|
||||
|
||||
|
@ -73,6 +96,7 @@ extern "C" {
|
|||
),
|
||||
);
|
||||
fn LKCreateScreenShareTrackForDisplay(display: *const c_void) -> *const c_void;
|
||||
fn LKLocalAudioTrackCreateTrack() -> *const c_void;
|
||||
}
|
||||
|
||||
pub type Sid = String;
|
||||
|
@ -89,6 +113,7 @@ pub struct Room {
|
|||
watch::Sender<ConnectionState>,
|
||||
watch::Receiver<ConnectionState>,
|
||||
)>,
|
||||
remote_audio_track_subscribers: Mutex<Vec<mpsc::UnboundedSender<RemoteAudioTrackUpdate>>>,
|
||||
remote_video_track_subscribers: Mutex<Vec<mpsc::UnboundedSender<RemoteVideoTrackUpdate>>>,
|
||||
_delegate: RoomDelegate,
|
||||
}
|
||||
|
@ -100,6 +125,7 @@ impl Room {
|
|||
Self {
|
||||
native_room: unsafe { LKRoomCreate(delegate.native_delegate) },
|
||||
connection: Mutex::new(watch::channel_with(ConnectionState::Disconnected)),
|
||||
remote_audio_track_subscribers: Default::default(),
|
||||
remote_video_track_subscribers: Default::default(),
|
||||
_delegate: delegate,
|
||||
}
|
||||
|
@ -191,6 +217,32 @@ impl Room {
|
|||
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: *mut c_void, error: CFStringRef) {
|
||||
let tx =
|
||||
unsafe { Box::from_raw(tx as *mut oneshot::Sender<Result<LocalTrackPublication>>) };
|
||||
if error.is_null() {
|
||||
let _ = tx.send(Ok(LocalTrackPublication(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 video track") }
|
||||
}
|
||||
|
||||
pub fn unpublish_track(&self, publication: LocalTrackPublication) {
|
||||
unsafe {
|
||||
LKRoomUnpublishTrack(self.native_room, publication.0);
|
||||
|
@ -226,12 +278,66 @@ impl Room {
|
|||
}
|
||||
}
|
||||
|
||||
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 = *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_updates(&self) -> mpsc::UnboundedReceiver<RemoteAudioTrackUpdate> {
|
||||
let (tx, rx) = mpsc::unbounded();
|
||||
self.remote_audio_track_subscribers.lock().push(tx);
|
||||
rx
|
||||
}
|
||||
|
||||
pub fn remote_video_track_updates(&self) -> mpsc::UnboundedReceiver<RemoteVideoTrackUpdate> {
|
||||
let (tx, rx) = mpsc::unbounded();
|
||||
self.remote_video_track_subscribers.lock().push(tx);
|
||||
rx
|
||||
}
|
||||
|
||||
fn did_subscribe_to_remote_audio_track(&self, track: RemoteAudioTrack) {
|
||||
let track = Arc::new(track);
|
||||
self.remote_audio_track_subscribers.lock().retain(|tx| {
|
||||
tx.unbounded_send(RemoteAudioTrackUpdate::Subscribed(track.clone()))
|
||||
.is_ok()
|
||||
});
|
||||
}
|
||||
|
||||
fn did_unsubscribe_from_remote_audio_track(&self, publisher_id: String, track_id: String) {
|
||||
self.remote_audio_track_subscribers.lock().retain(|tx| {
|
||||
tx.unbounded_send(RemoteAudioTrackUpdate::Unsubscribed {
|
||||
publisher_id: publisher_id.clone(),
|
||||
track_id: track_id.clone(),
|
||||
})
|
||||
.is_ok()
|
||||
});
|
||||
}
|
||||
|
||||
fn did_subscribe_to_remote_video_track(&self, track: RemoteVideoTrack) {
|
||||
let track = Arc::new(track);
|
||||
self.remote_video_track_subscribers.lock().retain(|tx| {
|
||||
|
@ -294,6 +400,8 @@ impl RoomDelegate {
|
|||
LKRoomDelegateCreate(
|
||||
weak_room as *mut c_void,
|
||||
Self::on_did_disconnect,
|
||||
Self::on_did_subscribe_to_remote_audio_track,
|
||||
Self::on_did_unsubscribe_from_remote_audio_track,
|
||||
Self::on_did_subscribe_to_remote_video_track,
|
||||
Self::on_did_unsubscribe_from_remote_video_track,
|
||||
)
|
||||
|
@ -312,6 +420,36 @@ impl RoomDelegate {
|
|||
let _ = Weak::into_raw(room);
|
||||
}
|
||||
|
||||
extern "C" fn on_did_subscribe_to_remote_audio_track(
|
||||
room: *mut c_void,
|
||||
publisher_id: CFStringRef,
|
||||
track_id: CFStringRef,
|
||||
track: *const c_void,
|
||||
) {
|
||||
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 = RemoteAudioTrack::new(track, track_id, publisher_id);
|
||||
if let Some(room) = room.upgrade() {
|
||||
room.did_subscribe_to_remote_audio_track(track);
|
||||
}
|
||||
let _ = Weak::into_raw(room);
|
||||
}
|
||||
|
||||
extern "C" fn on_did_unsubscribe_from_remote_audio_track(
|
||||
room: *mut c_void,
|
||||
publisher_id: CFStringRef,
|
||||
track_id: CFStringRef,
|
||||
) {
|
||||
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() };
|
||||
if let Some(room) = room.upgrade() {
|
||||
room.did_unsubscribe_from_remote_audio_track(publisher_id, track_id);
|
||||
}
|
||||
let _ = Weak::into_raw(room);
|
||||
}
|
||||
|
||||
extern "C" fn on_did_subscribe_to_remote_video_track(
|
||||
room: *mut c_void,
|
||||
publisher_id: CFStringRef,
|
||||
|
@ -352,6 +490,20 @@ impl Drop for RoomDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct LocalAudioTrack(*const c_void);
|
||||
|
||||
impl LocalAudioTrack {
|
||||
pub fn create() -> Self {
|
||||
Self(unsafe { LKLocalAudioTrackCreateTrack() })
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for LocalAudioTrack {
|
||||
fn drop(&mut self) {
|
||||
unsafe { CFRelease(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LocalVideoTrack(*const c_void);
|
||||
|
||||
impl LocalVideoTrack {
|
||||
|
@ -374,6 +526,35 @@ impl Drop for LocalTrackPublication {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RemoteAudioTrack {
|
||||
native_track: *const c_void,
|
||||
sid: Sid,
|
||||
publisher_id: String,
|
||||
}
|
||||
|
||||
impl RemoteAudioTrack {
|
||||
fn new(native_track: *const c_void, sid: Sid, publisher_id: String) -> Self {
|
||||
unsafe {
|
||||
CFRetain(native_track);
|
||||
}
|
||||
Self {
|
||||
native_track,
|
||||
sid,
|
||||
publisher_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sid(&self) -> &str {
|
||||
&self.sid
|
||||
}
|
||||
|
||||
pub fn publisher_id(&self) -> &str {
|
||||
&self.publisher_id
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RemoteVideoTrack {
|
||||
native_track: *const c_void,
|
||||
|
@ -453,6 +634,12 @@ pub enum RemoteVideoTrackUpdate {
|
|||
Unsubscribed { publisher_id: Sid, track_id: Sid },
|
||||
}
|
||||
|
||||
pub enum RemoteAudioTrackUpdate {
|
||||
Subscribed(Arc<RemoteAudioTrack>),
|
||||
Unsubscribed { publisher_id: Sid, track_id: Sid },
|
||||
}
|
||||
|
||||
|
||||
pub struct MacOSDisplay(*const c_void);
|
||||
|
||||
impl MacOSDisplay {
|
||||
|
|
|
@ -209,6 +209,10 @@ impl TestServer {
|
|||
.ok_or_else(|| anyhow!("room {} does not exist", room_name))?;
|
||||
Ok(room.tracks.clone())
|
||||
}
|
||||
|
||||
async fn publish_audio_track(&self, _token: String, _local_track: &LocalAudioTrack) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -266,6 +270,10 @@ struct RoomState {
|
|||
watch::Receiver<ConnectionState>,
|
||||
),
|
||||
display_sources: Vec<MacOSDisplay>,
|
||||
audio_track_updates: (
|
||||
async_broadcast::Sender<RemoteAudioTrackUpdate>,
|
||||
async_broadcast::Receiver<RemoteAudioTrackUpdate>,
|
||||
),
|
||||
video_track_updates: (
|
||||
async_broadcast::Sender<RemoteVideoTrackUpdate>,
|
||||
async_broadcast::Receiver<RemoteVideoTrackUpdate>,
|
||||
|
@ -286,6 +294,7 @@ impl Room {
|
|||
connection: watch::channel_with(ConnectionState::Disconnected),
|
||||
display_sources: Default::default(),
|
||||
video_track_updates: async_broadcast::broadcast(128),
|
||||
audio_track_updates: async_broadcast::broadcast(128),
|
||||
})))
|
||||
}
|
||||
|
||||
|
@ -327,9 +336,26 @@ impl Room {
|
|||
Ok(LocalTrackPublication)
|
||||
}
|
||||
}
|
||||
pub fn publish_audio_track(
|
||||
self: &Arc<Self>,
|
||||
track: &LocalAudioTrack,
|
||||
) -> impl Future<Output = Result<LocalTrackPublication>> {
|
||||
let this = self.clone();
|
||||
let track = track.clone();
|
||||
async move {
|
||||
this.test_server()
|
||||
.publish_audio_track(this.token(), &track)
|
||||
.await?;
|
||||
Ok(LocalTrackPublication)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unpublish_track(&self, _: LocalTrackPublication) {}
|
||||
|
||||
pub fn remote_audio_tracks(&self, _publisher_id: &str) -> Vec<Arc<RemoteAudioTrack>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn remote_video_tracks(&self, publisher_id: &str) -> Vec<Arc<RemoteVideoTrack>> {
|
||||
if !self.is_connected() {
|
||||
return Vec::new();
|
||||
|
@ -343,6 +369,10 @@ impl Room {
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub fn remote_audio_track_updates(&self) -> impl Stream<Item = RemoteAudioTrackUpdate> {
|
||||
self.0.lock().audio_track_updates.1.clone()
|
||||
}
|
||||
|
||||
pub fn remote_video_track_updates(&self) -> impl Stream<Item = RemoteVideoTrackUpdate> {
|
||||
self.0.lock().video_track_updates.1.clone()
|
||||
}
|
||||
|
@ -404,6 +434,15 @@ impl LocalVideoTrack {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LocalAudioTrack;
|
||||
|
||||
impl LocalAudioTrack {
|
||||
pub fn create() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RemoteVideoTrack {
|
||||
sid: Sid,
|
||||
publisher_id: Sid,
|
||||
|
@ -424,12 +463,33 @@ impl RemoteVideoTrack {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct RemoteAudioTrack {
|
||||
sid: Sid,
|
||||
publisher_id: Sid,
|
||||
}
|
||||
|
||||
impl RemoteAudioTrack {
|
||||
pub fn sid(&self) -> &str {
|
||||
&self.sid
|
||||
}
|
||||
|
||||
pub fn publisher_id(&self) -> &str {
|
||||
&self.publisher_id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum RemoteVideoTrackUpdate {
|
||||
Subscribed(Arc<RemoteVideoTrack>),
|
||||
Unsubscribed { publisher_id: Sid, track_id: Sid },
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum RemoteAudioTrackUpdate {
|
||||
Subscribed(Arc<RemoteAudioTrack>),
|
||||
Unsubscribed { publisher_id: Sid, track_id: Sid },
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MacOSDisplay {
|
||||
frames: (
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue