Match muted behavior with JS SDK (#32)
* attempt 1 * implement * clean up * clean up * cleaner code * mute was opposite * fix suggestion * fix local pub muted * update example * update pubs * format
This commit is contained in:
@@ -6,9 +6,10 @@ import '../exceptions.dart';
|
||||
import '../logger.dart';
|
||||
import '../types.dart';
|
||||
import 'audio_track.dart';
|
||||
import 'local_track.dart';
|
||||
import 'options.dart';
|
||||
|
||||
class LocalAudioTrack extends AudioTrack {
|
||||
class LocalAudioTrack extends AudioTrack with LocalTrack {
|
||||
// private constructor
|
||||
LocalAudioTrack._(
|
||||
TrackSource source,
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import '../internal/events.dart';
|
||||
import '../logger.dart';
|
||||
import 'track.dart';
|
||||
|
||||
mixin LocalTrack on Track {
|
||||
// only local tracks can set muted
|
||||
Future<void> mute() async {
|
||||
logger.fine('LocalTrack.mute() muted: $muted');
|
||||
if (muted) return;
|
||||
await disable();
|
||||
updateMuted(true);
|
||||
events.emit(TrackMuteUpdatedEvent(track: this, muted: muted));
|
||||
}
|
||||
|
||||
Future<void> unmute() async {
|
||||
logger.fine('LocalTrack.unmute() muted: $muted');
|
||||
if (!muted) return;
|
||||
await enable();
|
||||
updateMuted(false);
|
||||
events.emit(TrackMuteUpdatedEvent(track: this, muted: muted));
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
import '../events.dart';
|
||||
import '../extensions.dart';
|
||||
import '../logger.dart';
|
||||
import '../internal/events.dart';
|
||||
import '../participant/local_participant.dart';
|
||||
import '../proto/livekit_models.pb.dart' as lk_models;
|
||||
import 'local_track.dart';
|
||||
import 'track.dart';
|
||||
import 'track_publication.dart';
|
||||
|
||||
@@ -14,7 +15,7 @@ class LocalTrackPublication extends TrackPublication {
|
||||
Track track,
|
||||
this._participant,
|
||||
) : super.fromInfo(info) {
|
||||
this.track = track;
|
||||
updateTrack(track);
|
||||
// register dispose func
|
||||
onDispose(() async {
|
||||
// this object is responsible for disposing track
|
||||
@@ -22,28 +23,42 @@ class LocalTrackPublication extends TrackPublication {
|
||||
});
|
||||
}
|
||||
|
||||
/// Mute or unmute the current track. When muted, track will stop sending data
|
||||
@override
|
||||
set muted(bool val) {
|
||||
if (val == muted) return;
|
||||
logger.finer('setMute: ${val}');
|
||||
Future<bool> updateTrack(Track? newValue) async {
|
||||
final didUpdate = await super.updateTrack(newValue);
|
||||
|
||||
super.muted = val;
|
||||
track?.mediaStreamTrack.enabled = !val;
|
||||
_participant.engine.signalClient.sendMuteTrack(sid, val);
|
||||
|
||||
if (val) {
|
||||
// Track muted
|
||||
[_participant.events, _participant.roomEvents].emit(TrackMutedEvent(
|
||||
participant: _participant,
|
||||
track: this,
|
||||
));
|
||||
} else {
|
||||
// Track un-muted
|
||||
[_participant.events, _participant.roomEvents].emit(TrackUnmutedEvent(
|
||||
participant: _participant,
|
||||
track: this,
|
||||
));
|
||||
if (newValue != null) {
|
||||
// attach listener to track
|
||||
final listener = newValue.createListener()
|
||||
// listen for track muted events
|
||||
..on<TrackMuteUpdatedEvent>((event) {
|
||||
// send signal to server
|
||||
_participant.engine.signalClient.sendMuteTrack(sid, event.muted);
|
||||
// emit events
|
||||
final newEvent = event.muted
|
||||
? TrackMutedEvent(participant: _participant, track: this)
|
||||
: TrackUnmutedEvent(participant: _participant, track: this);
|
||||
[_participant.events, _participant.roomEvents].emit(newEvent);
|
||||
});
|
||||
// dispose listener when the track is disposed
|
||||
newValue.onDispose(() => listener.dispose());
|
||||
}
|
||||
|
||||
return didUpdate;
|
||||
}
|
||||
|
||||
@override
|
||||
bool get muted => track?.muted ?? super.muted;
|
||||
|
||||
Future<void> mute() async {
|
||||
if (track is! LocalTrack) return;
|
||||
// Mute the track associated with this publication
|
||||
return (track as LocalTrack).mute();
|
||||
}
|
||||
|
||||
Future<void> unmute() async {
|
||||
if (track is! LocalTrack) return;
|
||||
// Unmute the track associated with this publication
|
||||
return (track as LocalTrack).unmute();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,14 @@ import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc;
|
||||
import '../exceptions.dart';
|
||||
import '../logger.dart';
|
||||
import '../types.dart';
|
||||
import 'local_track.dart';
|
||||
import 'options.dart';
|
||||
import 'track.dart';
|
||||
import 'video_track.dart';
|
||||
|
||||
/// A video track from the local device. Use static methods in this class to create
|
||||
/// video tracks.
|
||||
class LocalVideoTrack extends VideoTrack {
|
||||
class LocalVideoTrack extends VideoTrack with LocalTrack {
|
||||
//
|
||||
// Options used for this track
|
||||
//
|
||||
|
||||
@@ -60,7 +60,15 @@ class RemoteTrackPublication extends TrackPublication {
|
||||
wait: const Duration(seconds: 2),
|
||||
);
|
||||
|
||||
this.track = track;
|
||||
updateTrack(track);
|
||||
}
|
||||
|
||||
@internal
|
||||
@override
|
||||
void updateFromInfo(lk_models.TrackInfo info) {
|
||||
super.updateFromInfo(info);
|
||||
updateMuted(info.muted);
|
||||
track?.updateMuted(info.muted);
|
||||
}
|
||||
|
||||
// called any time visibility info updates
|
||||
@@ -133,33 +141,33 @@ class RemoteTrackPublication extends TrackPublication {
|
||||
_participant.engine.signalClient.sendUpdateTrackSettings(settings);
|
||||
}
|
||||
|
||||
@internal
|
||||
@override
|
||||
set track(Track? newValue) {
|
||||
if (super.track != newValue) {
|
||||
logger.fine('setTrack ${newValue} $sid ${objectId}');
|
||||
// dispose previous track (if exists)
|
||||
super.track?.dispose();
|
||||
super.track = newValue;
|
||||
Future<bool> updateTrack(Track? newValue) async {
|
||||
final didUpdate = await super.updateTrack(track);
|
||||
|
||||
// Only listen for visibility updates if video optimization is on
|
||||
// and the attached track is a video track
|
||||
if (_participant.engine.connectOptions.optimizeVideo &&
|
||||
newValue != null &&
|
||||
newValue.kind == lk_models.TrackType.VIDEO) {
|
||||
//
|
||||
// Attach visibility event listener (if video track)
|
||||
//
|
||||
final listener = newValue.createListener();
|
||||
listener.on<TrackVisibilityUpdatedEvent>(
|
||||
_onVideoRendererVisibilityUpdateEvent);
|
||||
newValue.onDispose(() async {
|
||||
await listener.dispose();
|
||||
// consider all views are disposed when track is null
|
||||
_visibilities.clear();
|
||||
if (!isDisposed) _visibilityDidUpdate?.call(null);
|
||||
});
|
||||
}
|
||||
// Only listen for visibility updates if video optimization is on
|
||||
// and the attached track is a video track
|
||||
if (didUpdate &&
|
||||
newValue != null &&
|
||||
_participant.engine.connectOptions.optimizeVideo &&
|
||||
newValue.kind == lk_models.TrackType.VIDEO) {
|
||||
//
|
||||
// Attach visibility event listener (if video track)
|
||||
//
|
||||
final listener = newValue.createListener();
|
||||
listener.on<TrackVisibilityUpdatedEvent>(
|
||||
_onVideoRendererVisibilityUpdateEvent);
|
||||
//
|
||||
newValue.onDispose(() async {
|
||||
await listener.dispose();
|
||||
// consider all views are disposed when track is null
|
||||
_visibilities.clear();
|
||||
if (!isDisposed) _visibilityDidUpdate?.call(null);
|
||||
});
|
||||
}
|
||||
|
||||
return didUpdate;
|
||||
}
|
||||
|
||||
set videoQuality(lk_rtc.VideoQuality val) {
|
||||
@@ -190,34 +198,7 @@ class RemoteTrackPublication extends TrackPublication {
|
||||
publication: this,
|
||||
));
|
||||
// Simply set to null for now
|
||||
track = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// for internal use
|
||||
/// {@nodoc}
|
||||
@override
|
||||
@internal
|
||||
set muted(bool val) {
|
||||
if (val == muted) {
|
||||
return;
|
||||
}
|
||||
super.muted = val;
|
||||
if (val) {
|
||||
// Track muted
|
||||
[_participant.events, _participant.roomEvents].emit(TrackMutedEvent(
|
||||
participant: _participant,
|
||||
track: this,
|
||||
));
|
||||
} else {
|
||||
// Track un-muted
|
||||
[_participant.events, _participant.roomEvents].emit(TrackUnmutedEvent(
|
||||
participant: _participant,
|
||||
track: this,
|
||||
));
|
||||
}
|
||||
if (subscribed) {
|
||||
track?.mediaStreamTrack.enabled = !val;
|
||||
updateTrack(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,9 @@ abstract class Track extends DisposableChangeNotifier
|
||||
bool _active = false;
|
||||
bool get isActive => _active;
|
||||
|
||||
bool _muted = false;
|
||||
bool get muted => _muted;
|
||||
|
||||
Track(
|
||||
this.kind,
|
||||
this.source,
|
||||
@@ -52,9 +55,6 @@ abstract class Track extends DisposableChangeNotifier
|
||||
});
|
||||
}
|
||||
|
||||
bool get muted =>
|
||||
mediaStreamTrack.muted == null ? false : mediaStreamTrack.muted!;
|
||||
|
||||
rtc.RTCRtpMediaType get mediaType {
|
||||
switch (kind) {
|
||||
case lk_models.TrackType.AUDIO:
|
||||
@@ -125,4 +125,7 @@ abstract class Track extends DisposableChangeNotifier
|
||||
'[$objectId] set rtc.mediaStreamTrack.enabled did throw ${_}');
|
||||
}
|
||||
}
|
||||
|
||||
@internal
|
||||
void updateMuted(bool muted) => _muted = muted;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import '../support/disposable.dart';
|
||||
import '../proto/livekit_models.pb.dart' as lk_models;
|
||||
import '../types.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../extensions.dart';
|
||||
import '../proto/livekit_models.pb.dart' as lk_models;
|
||||
import '../support/disposable.dart';
|
||||
import '../types.dart';
|
||||
import 'track.dart';
|
||||
|
||||
/// Represents a track that's published to the server. This class contains
|
||||
@@ -16,12 +18,17 @@ abstract class TrackPublication extends Disposable {
|
||||
final lk_models.TrackType kind;
|
||||
final TrackSource source;
|
||||
|
||||
Track? track;
|
||||
bool muted = false;
|
||||
Track? _track;
|
||||
Track? get track => _track;
|
||||
|
||||
// metadata-muted
|
||||
bool _muted = false;
|
||||
bool get muted => _muted;
|
||||
|
||||
bool simulcasted = false;
|
||||
TrackDimension? dimension;
|
||||
|
||||
bool get subscribed => track != null;
|
||||
bool get subscribed => _track != null;
|
||||
|
||||
TrackPublication.fromInfo(lk_models.TrackInfo info)
|
||||
: sid = info.sid,
|
||||
@@ -36,7 +43,6 @@ abstract class TrackPublication extends Disposable {
|
||||
kind == lk_models.TrackType.VIDEO && name == Track.screenShareName;
|
||||
|
||||
void updateFromInfo(lk_models.TrackInfo info) {
|
||||
muted = info.muted;
|
||||
simulcasted = info.simulcast;
|
||||
if (info.type == lk_models.TrackType.VIDEO) {
|
||||
dimension = TrackDimension(info.width, info.height);
|
||||
@@ -51,4 +57,19 @@ abstract class TrackPublication extends Disposable {
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
other is TrackPublication && sid == other.sid;
|
||||
|
||||
@internal
|
||||
void updateMuted(bool muted) => _muted = muted;
|
||||
|
||||
// Update track to new value, dispose previous if exists.
|
||||
// Returns true if value has changed.
|
||||
// Intended for internal use only.
|
||||
@internal
|
||||
Future<bool> updateTrack(Track? newValue) async {
|
||||
if (_track == newValue) return false;
|
||||
// dispose previous track (if exists)
|
||||
await _track?.dispose();
|
||||
_track = newValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user