Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 59 additions & 9 deletions lib/src/track/local/local.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ abstract class LocalTrack extends Track {
bool _stopped = false;

TrackProcessor? _processor;

// Store original sender parameters to restore on unmute
rtc.RTCRtpParameters? _originalSenderParameters;

TrackProcessor? get processor => _processor;

Expand All @@ -103,30 +106,77 @@ abstract class LocalTrack extends Track {
};
}

/// Mutes this [LocalTrack]. This will stop the sending of track data
/// Mutes this [LocalTrack]. This will zero the audio frames
/// and notify the [RemoteParticipant] with [TrackMutedEvent].
/// Returns true if muted, false if unchanged.
Future<bool> mute({bool stopOnMute = true}) async {
logger.fine('LocalTrack.mute() muted: $muted');
if (muted) return false; // already muted
await disable();
if (!skipStopForTrackMute() && stopOnMute) {
await stop();

// For audio tracks, zero the frames by manipulating sender parameters
if (this is AudioTrack && sender != null) {
try {
final parameters = sender!.parameters;
// Store original parameters if not already stored
if (_originalSenderParameters == null) {
_originalSenderParameters = parameters;
}
// Zero out the audio by setting maxBitrate to 0 for all encodings
if (parameters.encodings != null && parameters.encodings!.isNotEmpty) {
for (var encoding in parameters.encodings!) {
encoding.maxBitrate = 0;
}
await sender!.setParameters(parameters);
}
} catch (error) {
logger.warning('Failed to modify sender parameters on mute: $error');
}
} else {
// For video tracks, use the original disable logic
await disable();
if (!skipStopForTrackMute() && stopOnMute) {
await stop();
}
}

updateMuted(true, shouldSendSignal: true);
return true;
}

/// Un-mutes this [LocalTrack]. This will re-start the sending of track data
/// Un-mutes this [LocalTrack]. This will restore the audio frames to normal
/// and notify the [RemoteParticipant] with [TrackUnmutedEvent].
/// Returns true if un-muted, false if unchanged.
Future<bool> unmute({bool stopOnMute = true}) async {
logger.fine('LocalTrack.unmute() muted: $muted');
if (!muted) return false; // already un-muted
if (!skipStopForTrackMute() && stopOnMute) {
await restartTrack();

// For audio tracks, restore the frames by restoring sender parameters
if (this is AudioTrack && sender != null) {
try {
if (_originalSenderParameters != null) {
// Restore the original sender parameters
await sender!.setParameters(_originalSenderParameters!);
} else {
// If no stored parameters, reset to allow full bitrate
final parameters = sender!.parameters;
if (parameters.encodings != null && parameters.encodings!.isNotEmpty) {
for (var encoding in parameters.encodings!) {
encoding.maxBitrate = null; // Remove bitrate limitation
}
await sender!.setParameters(parameters);
}
}
} catch (error) {
logger.warning('Failed to restore sender parameters on unmute: $error');
}
} else {
// For video tracks, use the original enable logic
if (!skipStopForTrackMute() && stopOnMute) {
await restartTrack();
}
await enable();
}
await enable();

updateMuted(false, shouldSendSignal: true);
return true;
}
Expand Down Expand Up @@ -322,4 +372,4 @@ abstract class LocalTrack extends Track {
_published = false;
return true;
}
}
}
10 changes: 10 additions & 0 deletions lib/src/track/remote/audio.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ import '../web/_audio_api.dart'
class RemoteAudioTrack extends RemoteTrack
with AudioTrack, RemoteAudioManagementMixin {
String? _deviceId;
double _volume = 1.0;
double get volume => _volume;

Future<void> setVolume(double newVolume) async {
final double clamped = newVolume.clamp(0.0, 4.0).toDouble();
_volume = clamped;
try {
await rtc.Helper.setVolume(clamped, mediaStreamTrack);
} catch (_) {}
}
RemoteAudioTrack(
TrackSource source, rtc.MediaStream stream, rtc.MediaStreamTrack track,
{rtc.RTCRtpReceiver? receiver})
Expand Down
7 changes: 3 additions & 4 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -219,10 +219,9 @@ packages:
flutter_webrtc:
dependency: "direct main"
description:
name: flutter_webrtc
sha256: "945d0a38b90fbca8257eadb167d8fb9fa7075d9a1939fd2953c10054454d1de2"
url: "https://pub.dev"
source: hosted
path: "../flutter-webrtc"
relative: true
source: path
version: "1.1.0"
glob:
dependency: transitive
Expand Down
3 changes: 2 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ dependencies:
uuid: ^4.5.1
synchronized: ^3.0.0+3
protobuf: ^4.1.0
flutter_webrtc: ^1.1.0
flutter_webrtc:
path: ../flutter-webrtc
device_info_plus: ^11.3.0
dart_webrtc: ^1.5.3+hotfix.5
sdp_transform: ^0.3.2
Expand Down