Add deafen controls

This commit is contained in:
Mikayla Maki 2023-06-20 12:34:32 -07:00
parent e58f0ac72f
commit b828a74ad6
No known key found for this signature in database
7 changed files with 197 additions and 65 deletions

View file

@ -157,6 +157,7 @@ impl Room {
screen_track: LocalTrack::None, screen_track: LocalTrack::None,
microphone_track: LocalTrack::None, microphone_track: LocalTrack::None,
next_publish_id: 0, next_publish_id: 0,
deafened: false,
_maintain_room, _maintain_room,
_maintain_tracks: [_maintain_video_tracks, _maintain_audio_tracks], _maintain_tracks: [_maintain_video_tracks, _maintain_audio_tracks],
}) })
@ -223,7 +224,9 @@ impl Room {
|| &*util::channel::RELEASE_CHANNEL != &ReleaseChannel::Dev || &*util::channel::RELEASE_CHANNEL != &ReleaseChannel::Dev
{ {
let share_mic = room.update(&mut cx, |room, cx| room.share_mic(cx)); let share_mic = room.update(&mut cx, |room, cx| room.share_mic(cx));
cx.background().spawn(share_mic).detach(); cx.update(|cx| {
cx.background().spawn(share_mic).detach_and_log_err(cx);
});
} }
match room match room
@ -1039,7 +1042,7 @@ impl Room {
let (canceled, muted) = if let LocalTrack::Pending { let (canceled, muted) = if let LocalTrack::Pending {
publish_id: cur_publish_id, publish_id: cur_publish_id,
muted muted,
} = &live_kit.microphone_track } = &live_kit.microphone_track
{ {
(*cur_publish_id != publish_id, *muted) (*cur_publish_id != publish_id, *muted)
@ -1053,11 +1056,11 @@ impl Room {
live_kit.room.unpublish_track(publication); live_kit.room.unpublish_track(publication);
} else { } else {
if muted { if muted {
cx.background().spawn(publication.mute()).detach(); cx.background().spawn(publication.set_mute(muted)).detach();
} }
live_kit.microphone_track = LocalTrack::Published { live_kit.microphone_track = LocalTrack::Published {
track_publication: publication, track_publication: publication,
muted muted,
}; };
cx.notify(); cx.notify();
} }
@ -1139,7 +1142,7 @@ impl Room {
live_kit.room.unpublish_track(publication); live_kit.room.unpublish_track(publication);
} else { } else {
if muted { if muted {
cx.background().spawn(publication.mute()).detach(); cx.background().spawn(publication.set_mute(muted)).detach();
} }
live_kit.screen_track = LocalTrack::Published { live_kit.screen_track = LocalTrack::Published {
track_publication: publication, track_publication: publication,
@ -1177,11 +1180,7 @@ impl Room {
} => { } => {
*muted = !*muted; *muted = !*muted;
if *muted { Ok(cx.background().spawn(track_publication.set_mute(*muted)))
Ok(cx.background().spawn(track_publication.mute()))
} else {
Ok(cx.background().spawn(track_publication.unmute()))
}
} }
} }
} else { } else {
@ -1189,9 +1188,32 @@ impl Room {
} }
} }
pub fn toggle_deafen(&mut self, _cx: &mut ModelContext<Self>) -> Task<Result<()>> { pub fn toggle_deafen(&mut self, cx: &mut ModelContext<Self>) -> Result<Task<Result<()>>> {
// iterate through publications and mute (?????) if let Some(live_kit) = &mut self.live_kit {
todo!(); (*live_kit).deafened = !live_kit.deafened
}
if let Some(live_kit) = &self.live_kit {
let mut tasks = Vec::with_capacity(self.remote_participants.len());
for participant in self.remote_participants.values() {
for track in live_kit
.room
.remote_audio_track_publications(&participant.user.id.to_string())
{
tasks.push(cx.background().spawn(track.set_enabled(live_kit.deafened)));
}
}
Ok(cx.background().spawn(async move {
for task in tasks {
task.await?;
}
Ok(())
}))
} else {
Err(anyhow!("LiveKit not started"))
}
} }
pub fn unshare_screen(&mut self, cx: &mut ModelContext<Self>) -> Result<()> { pub fn unshare_screen(&mut self, cx: &mut ModelContext<Self>) -> Result<()> {
@ -1233,6 +1255,7 @@ struct LiveKitRoom {
room: Arc<live_kit_client::Room>, room: Arc<live_kit_client::Room>,
screen_track: LocalTrack, screen_track: LocalTrack,
microphone_track: LocalTrack, microphone_track: LocalTrack,
deafened: bool,
next_publish_id: usize, next_publish_id: usize,
_maintain_room: Task<()>, _maintain_room: Task<()>,
_maintain_tracks: [Task<()>; 2], _maintain_tracks: [Task<()>; 2],

View file

@ -23,7 +23,7 @@ use theme::{AvatarStyle, Theme};
use util::ResultExt; use util::ResultExt;
use workspace::{FollowNextCollaborator, Workspace}; use workspace::{FollowNextCollaborator, Workspace};
const MAX_TITLE_LENGTH: usize = 75; // const MAX_TITLE_LENGTH: usize = 75;
actions!( actions!(
collab, collab,

View file

@ -47,12 +47,12 @@ pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) {
pub fn toggle_mute(_: &ToggleMute, cx: &mut AppContext) { pub fn toggle_mute(_: &ToggleMute, cx: &mut AppContext) {
if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() {
room.update(cx, Room::toggle_mute).map(Task::detach).log_err(); room.update(cx, Room::toggle_mute).map(|task| task.detach_and_log_err(cx)).log_err();
} }
} }
pub fn toggle_deafen(_: &ToggleDeafen, cx: &mut AppContext) { pub fn toggle_deafen(_: &ToggleDeafen, cx: &mut AppContext) {
if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() {
room.update(cx, Room::toggle_deafen).detach_and_log_err(cx); room.update(cx, Room::toggle_deafen).map(|task| task.detach_and_log_err(cx)).log_err();
} }
} }

View file

@ -12,7 +12,7 @@ use std::{
sync::Arc, sync::Arc,
task::{Context, Poll}, task::{Context, Poll},
thread, thread,
time::Duration, time::Duration, panic::Location,
}; };
use crate::{ use crate::{
@ -965,10 +965,12 @@ impl<T> Task<T> {
} }
impl<T: 'static, E: 'static + Display> Task<Result<T, E>> { impl<T: 'static, E: 'static + Display> Task<Result<T, E>> {
#[track_caller]
pub fn detach_and_log_err(self, cx: &mut AppContext) { pub fn detach_and_log_err(self, cx: &mut AppContext) {
cx.spawn(|_| async move { cx.spawn(|_| async move {
if let Err(err) = self.await { if let Err(err) = self.await {
log::error!("{:#}", err); let caller = Location::caller();
log::error!("{}:{}: {:#}", caller.file(), caller.line(), err);
} }
}) })
.detach(); .detach();

View file

@ -169,6 +169,18 @@ public func LKRoomAudioTracksForRemoteParticipant(room: UnsafeRawPointer, partic
return nil; return nil;
} }
@_cdecl("LKRoomAudioTrackPublicationsForRemoteParticipant")
public func LKRoomAudioTrackPublicationsForRemoteParticipant(room: UnsafeRawPointer, participantId: CFString) -> CFArray? {
let room = Unmanaged<Room>.fromOpaque(room).takeUnretainedValue()
for (_, participant) in room.remoteParticipants {
if participant.identity == participantId as String {
return participant.audioTracks.compactMap { $0 as? RemoteTrackPublication } as CFArray?
}
}
return nil;
}
@_cdecl("LKRoomVideoTracksForRemoteParticipant") @_cdecl("LKRoomVideoTracksForRemoteParticipant")
public func LKRoomVideoTracksForRemoteParticipant(room: UnsafeRawPointer, participantId: CFString) -> CFArray? { public func LKRoomVideoTracksForRemoteParticipant(room: UnsafeRawPointer, participantId: CFString) -> CFArray? {
@ -235,33 +247,45 @@ public func LKDisplaySources(data: UnsafeRawPointer, callback: @escaping @conven
} }
} }
@_cdecl("LKLocalTrackPublicationMute") @_cdecl("LKLocalTrackPublicationSetMute")
public func LKLocalTrackPublicationMute( public func LKLocalTrackPublicationSetMute(
publication: UnsafeRawPointer, publication: UnsafeRawPointer,
muted: Bool,
on_complete: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, on_complete: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void,
callback_data: UnsafeRawPointer callback_data: UnsafeRawPointer
) { ) {
let publication = Unmanaged<LocalTrackPublication>.fromOpaque(publication).takeUnretainedValue() let publication = Unmanaged<LocalTrackPublication>.fromOpaque(publication).takeUnretainedValue()
if muted {
publication.mute().then { publication.mute().then {
on_complete(callback_data, nil) on_complete(callback_data, nil)
}.catch { error in }.catch { error in
on_complete(callback_data, error.localizedDescription as CFString) on_complete(callback_data, error.localizedDescription as CFString)
} }
} else {
}
@_cdecl("LKLocalTrackPublicationUnmute")
public func LKLocalTrackPublicationUnmute(
publication: UnsafeRawPointer,
on_complete: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void,
callback_data: UnsafeRawPointer
) {
let publication = Unmanaged<LocalTrackPublication>.fromOpaque(publication).takeUnretainedValue()
publication.unmute().then { publication.unmute().then {
on_complete(callback_data, nil) on_complete(callback_data, nil)
}.catch { error in }.catch { error in
on_complete(callback_data, error.localizedDescription as CFString) on_complete(callback_data, error.localizedDescription as CFString)
} }
} }
}
@_cdecl("LKRemoteTrackPublicationSetEnabled")
public func LKRemoteTrackPublicationSetEnabled(
publication: UnsafeRawPointer,
enabled: Bool,
on_complete: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void,
callback_data: UnsafeRawPointer
) {
let publication = Unmanaged<RemoteTrackPublication>.fromOpaque(publication).takeUnretainedValue()
publication.set(enabled: enabled).then {
on_complete(callback_data, nil)
}.catch { error in
on_complete(callback_data, error.localizedDescription as CFString)
}
}

View file

@ -72,6 +72,11 @@ extern "C" {
participant_id: CFStringRef, participant_id: CFStringRef,
) -> CFArrayRef; ) -> CFArrayRef;
fn LKRoomAudioTrackPublicationsForRemoteParticipant(
room: *const c_void,
participant_id: CFStringRef,
) -> CFArrayRef;
fn LKRoomVideoTracksForRemoteParticipant( fn LKRoomVideoTracksForRemoteParticipant(
room: *const c_void, room: *const c_void,
participant_id: CFStringRef, participant_id: CFStringRef,
@ -98,13 +103,16 @@ extern "C" {
fn LKCreateScreenShareTrackForDisplay(display: *const c_void) -> *const c_void; fn LKCreateScreenShareTrackForDisplay(display: *const c_void) -> *const c_void;
fn LKLocalAudioTrackCreateTrack() -> *const c_void; fn LKLocalAudioTrackCreateTrack() -> *const c_void;
fn LKLocalTrackPublicationMute( fn LKLocalTrackPublicationSetMute(
publication: *const c_void, publication: *const c_void,
muted: bool,
on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef), on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef),
callback_data: *mut c_void, callback_data: *mut c_void,
); );
fn LKLocalTrackPublicationUnmute(
fn LKRemoteTrackPublicationSetEnabled(
publication: *const c_void, publication: *const c_void,
enabled: bool,
on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef), on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef),
callback_data: *mut c_void, callback_data: *mut c_void,
); );
@ -318,6 +326,29 @@ impl Room {
} }
} }
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 = *native_track_publication;
Arc::new(RemoteTrackPublication(native_track_publication))
})
.collect()
}
}
}
pub fn remote_audio_track_updates(&self) -> mpsc::UnboundedReceiver<RemoteAudioTrackUpdate> { pub fn remote_audio_track_updates(&self) -> mpsc::UnboundedReceiver<RemoteAudioTrackUpdate> {
let (tx, rx) = mpsc::unbounded(); let (tx, rx) = mpsc::unbounded();
self.remote_audio_track_subscribers.lock().push(tx); self.remote_audio_track_subscribers.lock().push(tx);
@ -531,7 +562,7 @@ impl Drop for LocalVideoTrack {
pub struct LocalTrackPublication(*const c_void); pub struct LocalTrackPublication(*const c_void);
impl LocalTrackPublication { impl LocalTrackPublication {
pub fn mute(&self) -> impl Future<Output = Result<()>> { pub fn set_mute(&self, muted: bool) -> impl Future<Output = Result<()>> {
let (tx, rx) = futures::channel::oneshot::channel(); let (tx, rx) = futures::channel::oneshot::channel();
extern "C" fn complete_callback(callback_data: *mut c_void, error: CFStringRef) { extern "C" fn complete_callback(callback_data: *mut c_void, error: CFStringRef) {
@ -545,32 +576,9 @@ impl LocalTrackPublication {
} }
unsafe { unsafe {
LKLocalTrackPublicationMute( LKLocalTrackPublicationSetMute(
self.0,
complete_callback,
Box::into_raw(Box::new(tx)) as *mut c_void,
)
}
async move { rx.await.unwrap() }
}
pub fn unmute(&self) -> impl Future<Output = Result<()>> {
let (tx, rx) = futures::channel::oneshot::channel();
extern "C" fn complete_callback(callback_data: *mut c_void, error: CFStringRef) {
let tx = unsafe { Box::from_raw(callback_data as *mut oneshot::Sender<Result<()>>) };
if error.is_null() {
tx.send(Ok(())).ok();
} else {
let error = unsafe { CFString::wrap_under_get_rule(error).to_string() };
tx.send(Err(anyhow!(error))).ok();
}
}
unsafe {
LKLocalTrackPublicationUnmute(
self.0, self.0,
muted,
complete_callback, complete_callback,
Box::into_raw(Box::new(tx)) as *mut c_void, Box::into_raw(Box::new(tx)) as *mut c_void,
) )
@ -586,6 +594,42 @@ impl Drop for LocalTrackPublication {
} }
} }
pub struct RemoteTrackPublication(*const c_void);
impl RemoteTrackPublication {
pub fn set_enabled(&self, enabled: bool) -> impl Future<Output = Result<()>> {
let (tx, rx) = futures::channel::oneshot::channel();
extern "C" fn complete_callback(callback_data: *mut c_void, error: CFStringRef) {
let tx = unsafe { Box::from_raw(callback_data as *mut oneshot::Sender<Result<()>>) };
if error.is_null() {
tx.send(Ok(())).ok();
} else {
let error = unsafe { CFString::wrap_under_get_rule(error).to_string() };
tx.send(Err(anyhow!(error))).ok();
}
}
unsafe {
LKRemoteTrackPublicationSetEnabled(
self.0,
enabled,
complete_callback,
Box::into_raw(Box::new(tx)) as *mut c_void,
)
}
async move { rx.await.unwrap() }
}
}
impl Drop for RemoteTrackPublication {
fn drop(&mut self) {
unsafe { CFRelease(self.0) }
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct RemoteAudioTrack { pub struct RemoteAudioTrack {
_native_track: *const c_void, _native_track: *const c_void,
@ -612,6 +656,18 @@ impl RemoteAudioTrack {
pub fn publisher_id(&self) -> &str { pub fn publisher_id(&self) -> &str {
&self.publisher_id &self.publisher_id
} }
pub fn enable(&self) -> impl Future<Output = Result<()>> {
async {
Ok(())
}
}
pub fn disable(&self) -> impl Future<Output = Result<()>> {
async {
Ok(())
}
}
} }
#[derive(Debug)] #[derive(Debug)]

View file

@ -410,6 +410,25 @@ impl Room {
.collect() .collect()
} }
pub fn remote_audio_track_publications(
&self,
publisher_id: &str,
) -> Vec<Arc<RemoteTrackPublication>> {
if !self.is_connected() {
return Vec::new();
}
self.test_server()
.audio_tracks(self.token())
.unwrap()
.into_iter()
.filter(|track| track.publisher_id() == publisher_id)
.map(|_track| {
Arc::new(RemoteTrackPublication {})
})
.collect()
}
pub fn remote_video_tracks(&self, publisher_id: &str) -> Vec<Arc<RemoteVideoTrack>> { pub fn remote_video_tracks(&self, publisher_id: &str) -> Vec<Arc<RemoteVideoTrack>> {
if !self.is_connected() { if !self.is_connected() {
return Vec::new(); return Vec::new();
@ -476,16 +495,16 @@ impl Drop for Room {
pub struct LocalTrackPublication; pub struct LocalTrackPublication;
impl LocalTrackPublication { impl LocalTrackPublication {
pub fn mute(&self) -> impl Future<Output = Result<()>> { pub fn set_mute(&self, _mute: bool) -> impl Future<Output = Result<()>> {
async { async { Ok(()) }
Ok(())
} }
} }
pub fn unmute(&self) -> impl Future<Output = Result<()>> { pub struct RemoteTrackPublication;
async {
Ok(()) impl RemoteTrackPublication {
} pub fn set_enabled(&self, _enabled: bool) -> impl Future<Output = Result<()>> {
async { Ok(()) }
} }
} }
@ -545,6 +564,14 @@ impl RemoteAudioTrack {
pub fn publisher_id(&self) -> &str { pub fn publisher_id(&self) -> &str {
&self.publisher_id &self.publisher_id
} }
pub fn enable(&self) -> impl Future<Output = Result<()>> {
async { Ok(()) }
}
pub fn disable(&self) -> impl Future<Output = Result<()>> {
async { Ok(()) }
}
} }
#[derive(Clone)] #[derive(Clone)]