From 1d6ee2a1c8db4821616954516b8083a3eba5073c Mon Sep 17 00:00:00 2001 From: td <152161658+td-famedly@users.noreply.github.com> Date: Mon, 20 May 2024 18:53:54 +0530 Subject: [PATCH] feat: provide option to skip stop/restartTrack for mute/unmute (#516) * feat: provide option to skip stop/restartTrack for mute/unmute also fallsback to the default capture options for respective setSourceEnableds * chore: skip mute/replaceTrack for firefox because .enabled works as expected --- lib/src/core/room.dart | 13 +++++++++++-- lib/src/participant/local.dart | 15 +++++++++++++-- lib/src/publication/local.dart | 6 ++++-- lib/src/support/platform.dart | 7 +++++++ lib/src/track/local/local.dart | 8 ++++---- lib/src/track/options.dart | 18 +++++++++++++++++- 6 files changed, 56 insertions(+), 11 deletions(-) diff --git a/lib/src/core/room.dart b/lib/src/core/room.dart index 61f02a40..7a3377b2 100644 --- a/lib/src/core/room.dart +++ b/lib/src/core/room.dart @@ -347,10 +347,19 @@ class Room extends DisposableChangeNotifier with EventsEmittable { }) ..on((event) async { final publication = localParticipant?.trackPublications[event.sid]; + + final stopOnMute = switch (publication?.source) { + TrackSource.camera => + roomOptions.defaultCameraCaptureOptions.stopCameraCaptureOnMute, + TrackSource.microphone => + roomOptions.defaultAudioCaptureOptions.stopAudioCaptureOnMute, + _ => true, + }; + if (event.muted) { - await publication?.mute(); + await publication?.mute(stopOnMute: stopOnMute); } else { - await publication?.unmute(); + await publication?.unmute(stopOnMute: stopOnMute); } }) ..on((event) async { diff --git a/lib/src/participant/local.dart b/lib/src/participant/local.dart index d3cacbd8..9117e6e9 100644 --- a/lib/src/participant/local.dart +++ b/lib/src/participant/local.dart @@ -510,6 +510,7 @@ class LocalParticipant extends Participant { /// Shortcut for publishing a [TrackSource.camera] Future setCameraEnabled(bool enabled, {CameraCaptureOptions? cameraCaptureOptions}) async { + cameraCaptureOptions ??= room.roomOptions.defaultCameraCaptureOptions; return setSourceEnabled(TrackSource.camera, enabled, cameraCaptureOptions: cameraCaptureOptions); } @@ -517,6 +518,7 @@ class LocalParticipant extends Participant { /// Shortcut for publishing a [TrackSource.microphone] Future setMicrophoneEnabled(bool enabled, {AudioCaptureOptions? audioCaptureOptions}) async { + audioCaptureOptions ??= room.roomOptions.defaultAudioCaptureOptions; return setSourceEnabled(TrackSource.microphone, enabled, audioCaptureOptions: audioCaptureOptions); } @@ -525,6 +527,8 @@ class LocalParticipant extends Participant { Future setScreenShareEnabled(bool enabled, {bool? captureScreenAudio, ScreenShareCaptureOptions? screenShareCaptureOptions}) async { + screenShareCaptureOptions ??= + room.roomOptions.defaultScreenShareCaptureOptions; return setSourceEnabled(TrackSource.screenShareVideo, enabled, captureScreenAudio: captureScreenAudio, screenShareCaptureOptions: screenShareCaptureOptions); @@ -547,8 +551,15 @@ class LocalParticipant extends Participant { final publication = getTrackPublicationBySource(source); if (publication != null) { + final stopOnMute = switch (publication.source) { + TrackSource.camera => + cameraCaptureOptions?.stopCameraCaptureOnMute ?? true, + TrackSource.microphone => + audioCaptureOptions?.stopAudioCaptureOnMute ?? true, + _ => true, + }; if (enabled) { - await publication.unmute(); + await publication.unmute(stopOnMute: stopOnMute); } else { if (source == TrackSource.screenShareVideo) { await removePublishedTrack(publication.sid); @@ -558,7 +569,7 @@ class LocalParticipant extends Participant { await removePublishedTrack(screenAudio.sid); } } else { - await publication.mute(); + await publication.mute(stopOnMute: stopOnMute); } } await room.applyAudioSpeakerSettings(); diff --git a/lib/src/publication/local.dart b/lib/src/publication/local.dart index cbc6b0bc..84075ec3 100644 --- a/lib/src/publication/local.dart +++ b/lib/src/publication/local.dart @@ -41,10 +41,12 @@ class LocalTrackPublication extends TrackPublication { } /// Mute the track associated with this publication - Future mute() async => await track?.mute(); + Future mute({bool stopOnMute = true}) async => + await track?.mute(stopOnMute: stopOnMute); /// Unmute the track associated with this publication - Future unmute() async => await track?.unmute(); + Future unmute({bool stopOnMute = true}) async => + await track?.unmute(stopOnMute: stopOnMute); lk_rtc.TrackPublishedResponse toPBTrackPublishedResponse() => lk_rtc.TrackPublishedResponse( diff --git a/lib/src/support/platform.dart b/lib/src/support/platform.dart index 2fcdce74..a39bb362 100644 --- a/lib/src/support/platform.dart +++ b/lib/src/support/platform.dart @@ -40,6 +40,13 @@ BrowserType lkBrowser() => lkBrowserImplementation(); BrowserVersion lkBrowserVersion() => lkBrowserVersionImplementation(); +/// skips stop/replaceTrack for the following platforms and only toggles +/// track.enabled. +bool skipStopForTrackMute() => + {PlatformType.windows}.contains(lkPlatform()) || + (lkPlatformIs(PlatformType.web) && + [BrowserType.firefox].contains(lkBrowser())); + enum PlatformType { web, windows, diff --git a/lib/src/track/local/local.dart b/lib/src/track/local/local.dart index c14ab022..3e317715 100644 --- a/lib/src/track/local/local.dart +++ b/lib/src/track/local/local.dart @@ -91,11 +91,11 @@ abstract class LocalTrack extends Track { /// Mutes this [LocalTrack]. This will stop the sending of track data /// and notify the [RemoteParticipant] with [TrackMutedEvent]. /// Returns true if muted, false if unchanged. - Future mute() async { + Future mute({bool stopOnMute = true}) async { logger.fine('LocalTrack.mute() muted: $muted'); if (muted) return false; // already muted await disable(); - if (!lkPlatformIs(PlatformType.windows)) { + if (!skipStopForTrackMute() && stopOnMute) { await stop(); } updateMuted(true, shouldSendSignal: true); @@ -105,10 +105,10 @@ abstract class LocalTrack extends Track { /// Un-mutes this [LocalTrack]. This will re-start the sending of track data /// and notify the [RemoteParticipant] with [TrackUnmutedEvent]. /// Returns true if un-muted, false if unchanged. - Future unmute() async { + Future unmute({bool stopOnMute = true}) async { logger.fine('LocalTrack.unmute() muted: $muted'); if (!muted) return false; // already un-muted - if (!lkPlatformIs(PlatformType.windows)) { + if (!skipStopForTrackMute() && stopOnMute) { await restartTrack(); } await enable(); diff --git a/lib/src/track/options.dart b/lib/src/track/options.dart index ad0ce6fa..158e4329 100644 --- a/lib/src/track/options.dart +++ b/lib/src/track/options.dart @@ -38,15 +38,24 @@ extension CameraPositionExt on CameraPosition { class CameraCaptureOptions extends VideoCaptureOptions { final CameraPosition cameraPosition; + /// set to false to only toggle enabled instead of stop/replaceTrack for muting + final bool stopCameraCaptureOnMute; + const CameraCaptureOptions({ this.cameraPosition = CameraPosition.front, String? deviceId, double? maxFrameRate, VideoParameters params = VideoParametersPresets.h720_169, - }) : super(params: params, deviceId: deviceId, maxFrameRate: maxFrameRate); + this.stopCameraCaptureOnMute = true, + }) : super( + params: params, + deviceId: deviceId, + maxFrameRate: maxFrameRate, + ); CameraCaptureOptions.from({required VideoCaptureOptions captureOptions}) : cameraPosition = CameraPosition.front, + stopCameraCaptureOnMute = true, super( params: captureOptions.params, deviceId: captureOptions.deviceId, @@ -82,12 +91,15 @@ class CameraCaptureOptions extends VideoCaptureOptions { CameraPosition? cameraPosition, String? deviceId, double? maxFrameRate, + bool? stopCameraCaptureOnMute, }) => CameraCaptureOptions( params: params ?? this.params, cameraPosition: cameraPosition ?? this.cameraPosition, deviceId: deviceId ?? this.deviceId, maxFrameRate: maxFrameRate ?? this.maxFrameRate, + stopCameraCaptureOnMute: + stopCameraCaptureOnMute ?? this.stopCameraCaptureOnMute, ); } @@ -235,6 +247,9 @@ class AudioCaptureOptions extends LocalTrackOptions { /// Defaults to true. final bool typingNoiseDetection; + /// set to false to only toggle enabled instead of stop/replaceTrack for muting + final bool stopAudioCaptureOnMute; + const AudioCaptureOptions({ this.deviceId, this.noiseSuppression = true, @@ -242,6 +257,7 @@ class AudioCaptureOptions extends LocalTrackOptions { this.autoGainControl = true, this.highPassFilter = false, this.typingNoiseDetection = true, + this.stopAudioCaptureOnMute = true, }); @override