Detailed changes
@@ -157,6 +157,7 @@ impl Room {
screen_track: LocalTrack::None,
microphone_track: LocalTrack::None,
next_publish_id: 0,
+ deafened: false,
_maintain_room,
_maintain_tracks: [_maintain_video_tracks, _maintain_audio_tracks],
})
@@ -223,7 +224,9 @@ impl Room {
|| &*util::channel::RELEASE_CHANNEL != &ReleaseChannel::Dev
{
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
@@ -1039,7 +1042,7 @@ impl Room {
let (canceled, muted) = if let LocalTrack::Pending {
publish_id: cur_publish_id,
- muted
+ muted,
} = &live_kit.microphone_track
{
(*cur_publish_id != publish_id, *muted)
@@ -1053,11 +1056,11 @@ impl Room {
live_kit.room.unpublish_track(publication);
} else {
if muted {
- cx.background().spawn(publication.mute()).detach();
+ cx.background().spawn(publication.set_mute(muted)).detach();
}
live_kit.microphone_track = LocalTrack::Published {
track_publication: publication,
- muted
+ muted,
};
cx.notify();
}
@@ -1139,7 +1142,7 @@ impl Room {
live_kit.room.unpublish_track(publication);
} else {
if muted {
- cx.background().spawn(publication.mute()).detach();
+ cx.background().spawn(publication.set_mute(muted)).detach();
}
live_kit.screen_track = LocalTrack::Published {
track_publication: publication,
@@ -1177,11 +1180,7 @@ impl Room {
} => {
*muted = !*muted;
- if *muted {
- Ok(cx.background().spawn(track_publication.mute()))
- } else {
- Ok(cx.background().spawn(track_publication.unmute()))
- }
+ Ok(cx.background().spawn(track_publication.set_mute(*muted)))
}
}
} else {
@@ -1189,9 +1188,32 @@ impl Room {
}
}
- pub fn toggle_deafen(&mut self, _cx: &mut ModelContext<Self>) -> Task<Result<()>> {
- // iterate through publications and mute (?????)
- todo!();
+ pub fn toggle_deafen(&mut self, cx: &mut ModelContext<Self>) -> Result<Task<Result<()>>> {
+ if let Some(live_kit) = &mut self.live_kit {
+ (*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<()> {
@@ -1233,6 +1255,7 @@ struct LiveKitRoom {
room: Arc<live_kit_client::Room>,
screen_track: LocalTrack,
microphone_track: LocalTrack,
+ deafened: bool,
next_publish_id: usize,
_maintain_room: Task<()>,
_maintain_tracks: [Task<()>; 2],
@@ -23,7 +23,7 @@ use theme::{AvatarStyle, Theme};
use util::ResultExt;
use workspace::{FollowNextCollaborator, Workspace};
-const MAX_TITLE_LENGTH: usize = 75;
+// const MAX_TITLE_LENGTH: usize = 75;
actions!(
collab,
@@ -47,12 +47,12 @@ pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) {
pub fn toggle_mute(_: &ToggleMute, cx: &mut AppContext) {
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) {
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();
}
}
@@ -12,7 +12,7 @@ use std::{
sync::Arc,
task::{Context, Poll},
thread,
- time::Duration,
+ time::Duration, panic::Location,
};
use crate::{
@@ -965,10 +965,12 @@ impl<T> Task<T> {
}
impl<T: 'static, E: 'static + Display> Task<Result<T, E>> {
+ #[track_caller]
pub fn detach_and_log_err(self, cx: &mut AppContext) {
cx.spawn(|_| async move {
if let Err(err) = self.await {
- log::error!("{:#}", err);
+ let caller = Location::caller();
+ log::error!("{}:{}: {:#}", caller.file(), caller.line(), err);
}
})
.detach();
@@ -169,6 +169,18 @@ public func LKRoomAudioTracksForRemoteParticipant(room: UnsafeRawPointer, partic
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")
public func LKRoomVideoTracksForRemoteParticipant(room: UnsafeRawPointer, participantId: CFString) -> CFArray? {
@@ -235,33 +247,45 @@ public func LKDisplaySources(data: UnsafeRawPointer, callback: @escaping @conven
}
}
-@_cdecl("LKLocalTrackPublicationMute")
-public func LKLocalTrackPublicationMute(
+@_cdecl("LKLocalTrackPublicationSetMute")
+public func LKLocalTrackPublicationSetMute(
publication: UnsafeRawPointer,
+ muted: Bool,
on_complete: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void,
callback_data: UnsafeRawPointer
) {
let publication = Unmanaged<LocalTrackPublication>.fromOpaque(publication).takeUnretainedValue()
- publication.mute().then {
- on_complete(callback_data, nil)
- }.catch { error in
- on_complete(callback_data, error.localizedDescription as CFString)
+ if muted {
+ publication.mute().then {
+ on_complete(callback_data, nil)
+ }.catch { error in
+ on_complete(callback_data, error.localizedDescription as CFString)
+ }
+ } else {
+ publication.unmute().then {
+ on_complete(callback_data, nil)
+ }.catch { error in
+ on_complete(callback_data, error.localizedDescription as CFString)
+ }
}
-
}
-@_cdecl("LKLocalTrackPublicationUnmute")
-public func LKLocalTrackPublicationUnmute(
+@_cdecl("LKRemoteTrackPublicationSetEnabled")
+public func LKRemoteTrackPublicationSetEnabled(
publication: UnsafeRawPointer,
+ enabled: Bool,
on_complete: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void,
callback_data: UnsafeRawPointer
) {
- let publication = Unmanaged<LocalTrackPublication>.fromOpaque(publication).takeUnretainedValue()
+ let publication = Unmanaged<RemoteTrackPublication>.fromOpaque(publication).takeUnretainedValue()
- publication.unmute().then {
+ publication.set(enabled: enabled).then {
on_complete(callback_data, nil)
}.catch { error in
on_complete(callback_data, error.localizedDescription as CFString)
}
}
+
+
+
@@ -72,6 +72,11 @@ extern "C" {
participant_id: CFStringRef,
) -> CFArrayRef;
+ fn LKRoomAudioTrackPublicationsForRemoteParticipant(
+ room: *const c_void,
+ participant_id: CFStringRef,
+ ) -> CFArrayRef;
+
fn LKRoomVideoTracksForRemoteParticipant(
room: *const c_void,
participant_id: CFStringRef,
@@ -98,13 +103,16 @@ extern "C" {
fn LKCreateScreenShareTrackForDisplay(display: *const c_void) -> *const c_void;
fn LKLocalAudioTrackCreateTrack() -> *const c_void;
- fn LKLocalTrackPublicationMute(
+ fn LKLocalTrackPublicationSetMute(
publication: *const c_void,
+ muted: bool,
on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef),
callback_data: *mut c_void,
);
- fn LKLocalTrackPublicationUnmute(
+
+ fn LKRemoteTrackPublicationSetEnabled(
publication: *const c_void,
+ enabled: bool,
on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef),
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> {
let (tx, rx) = mpsc::unbounded();
self.remote_audio_track_subscribers.lock().push(tx);
@@ -531,7 +562,7 @@ impl Drop for LocalVideoTrack {
pub struct LocalTrackPublication(*const c_void);
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();
extern "C" fn complete_callback(callback_data: *mut c_void, error: CFStringRef) {
@@ -545,8 +576,9 @@ impl LocalTrackPublication {
}
unsafe {
- LKLocalTrackPublicationMute(
+ LKLocalTrackPublicationSetMute(
self.0,
+ muted,
complete_callback,
Box::into_raw(Box::new(tx)) as *mut c_void,
)
@@ -554,8 +586,18 @@ impl LocalTrackPublication {
async move { rx.await.unwrap() }
}
+}
+
+impl Drop for LocalTrackPublication {
+ fn drop(&mut self) {
+ unsafe { CFRelease(self.0) }
+ }
+}
+
+pub struct RemoteTrackPublication(*const c_void);
- pub fn unmute(&self) -> impl Future<Output = Result<()>> {
+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) {
@@ -569,8 +611,9 @@ impl LocalTrackPublication {
}
unsafe {
- LKLocalTrackPublicationUnmute(
+ LKRemoteTrackPublicationSetEnabled(
self.0,
+ enabled,
complete_callback,
Box::into_raw(Box::new(tx)) as *mut c_void,
)
@@ -580,12 +623,13 @@ impl LocalTrackPublication {
}
}
-impl Drop for LocalTrackPublication {
+impl Drop for RemoteTrackPublication {
fn drop(&mut self) {
unsafe { CFRelease(self.0) }
}
}
+
#[derive(Debug)]
pub struct RemoteAudioTrack {
_native_track: *const c_void,
@@ -612,6 +656,18 @@ impl RemoteAudioTrack {
pub fn publisher_id(&self) -> &str {
&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)]
@@ -410,6 +410,25 @@ impl Room {
.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>> {
if !self.is_connected() {
return Vec::new();
@@ -476,16 +495,16 @@ impl Drop for Room {
pub struct LocalTrackPublication;
impl LocalTrackPublication {
- pub fn mute(&self) -> impl Future<Output = Result<()>> {
- async {
- Ok(())
- }
+ pub fn set_mute(&self, _mute: bool) -> impl Future<Output = Result<()>> {
+ async { Ok(()) }
}
+}
- pub fn unmute(&self) -> impl Future<Output = Result<()>> {
- async {
- Ok(())
- }
+pub struct RemoteTrackPublication;
+
+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 {
&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)]