organize track & pub to directory

This commit is contained in:
Hiroshi Horie
2021-11-30 17:29:18 +07:00
parent 11a1d22e7f
commit 2cd3198cdd
19 changed files with 49 additions and 48 deletions
+2 -2
View File
@@ -7,8 +7,8 @@ import 'package:synchronized/synchronized.dart' as sync;
import '../logger.dart';
import '../support/native_audio.dart';
import 'local_audio_track.dart';
import 'local_track.dart';
import 'local/audio.dart';
import 'local.dart';
enum AudioTrackState {
none,
@@ -2,11 +2,11 @@ import 'dart:async';
import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc;
import '../proto/livekit_models.pb.dart' as lk_models;
import '../types.dart';
import 'audio_management.dart';
import 'local_track.dart';
import 'options.dart';
import '../../proto/livekit_models.pb.dart' as lk_models;
import '../../types.dart';
import '../audio_management.dart';
import '../local.dart';
import '../options.dart';
class LocalAudioTrack extends LocalTrack with AudioTrack, AudioManagementMixin {
// Options used for this track
@@ -1,11 +1,11 @@
import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc;
import '../logger.dart';
import '../proto/livekit_models.pb.dart' as lk_models;
import '../types.dart';
import 'local_track.dart';
import 'options.dart';
import 'track.dart';
import '../../logger.dart';
import '../../proto/livekit_models.pb.dart' as lk_models;
import '../../types.dart';
import '../local.dart';
import '../options.dart';
import '../track.dart';
/// A video track from the local device. Use static methods in this class to create
/// video tracks.
@@ -1,67 +0,0 @@
import '../events.dart';
import '../extensions.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';
class LocalTrackPublication extends TrackPublication {
final LocalParticipant _participant;
@override
covariant LocalTrack? track;
LocalTrackPublication(
lk_models.TrackInfo info,
Track track,
this._participant,
) : super.fromInfo(info) {
updateTrack(track);
// register dispose func
onDispose(() async {
// this object is responsible for disposing track
await this.track?.dispose();
});
}
@override
Future<bool> updateTrack(Track? newValue) async {
final didUpdate = await super.updateTrack(newValue);
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();
}
}
@@ -1,11 +1,12 @@
import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc;
import '../proto/livekit_models.pb.dart' as lk_models;
import '../types.dart';
import '_audio_api.dart' if (dart.library.html) '_audio_html.dart' as audio;
import 'audio_management.dart';
import 'local_track.dart';
import 'remote_track.dart';
import '../../proto/livekit_models.pb.dart' as lk_models;
import '../../types.dart';
import '../web/_audio_api.dart' if (dart.library.html) '../web/_audio_html.dart'
as audio;
import '../audio_management.dart';
import '../local.dart';
import '../remote.dart';
class RemoteAudioTrack extends RemoteTrack
with AudioTrack, AudioManagementMixin {
@@ -1,9 +1,9 @@
import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc;
import 'package:livekit_client/src/track/local_track.dart';
import 'package:livekit_client/src/track/local.dart';
import '../proto/livekit_models.pb.dart' as lk_models;
import '../types.dart';
import 'remote_track.dart';
import '../../proto/livekit_models.pb.dart' as lk_models;
import '../../types.dart';
import '../remote.dart';
class RemoteVideoTrack extends RemoteTrack with VideoTrack {
//
-228
View File
@@ -1,228 +0,0 @@
import 'dart:math';
import 'dart:ui';
import 'package:collection/collection.dart';
import 'package:meta/meta.dart';
import '../events.dart';
import '../extensions.dart';
import '../internal/events.dart';
import '../logger.dart';
import '../participant/remote_participant.dart';
import '../proto/livekit_models.pb.dart' as lk_models;
import '../proto/livekit_rtc.pb.dart' as lk_rtc;
import '../utils.dart';
import 'remote_track.dart';
import 'track.dart';
import 'track_publication.dart';
class RendererVisibility {
final String rendererId;
final String trackId;
final bool visible;
final Size size;
RendererVisibility({
required this.rendererId,
required this.trackId,
required this.visible,
required this.size,
});
}
/// Represents a track publication from a RemoteParticipant. Provides methods to
/// control if we should subscribe to the track, and its quality (for video).
class RemoteTrackPublication extends TrackPublication {
@override
covariant RemoteTrack? track;
final RemoteParticipant _participant;
bool _enabled = true;
lk_rtc.VideoQuality _videoQuality = lk_rtc.VideoQuality.HIGH;
lk_rtc.VideoQuality get videoQuality => _videoQuality;
// used to report renderer visibility to the server
// and optimize
final _visibilities = <String, RendererVisibility>{};
Function(void)? _visibilityDidUpdate;
Function? _cancelVisibilityDebounceFunc;
RemoteTrackPublication(
lk_models.TrackInfo info,
this._participant, [
Track? track,
]) : super.fromInfo(info) {
// register dispose func
onDispose(() async {
_cancelVisibilityDebounceFunc?.call();
// this object is responsible for disposing track
await this.track?.dispose();
});
_visibilityDidUpdate = Utils.createDebounceFunc(
_shouldComputeVisibilityUpdate,
cancelFunc: (func) => _cancelVisibilityDebounceFunc = func,
wait: const Duration(seconds: 2),
);
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
// from one of the renderers
void _onVideoRendererVisibilityUpdateEvent(
TrackVisibilityUpdatedEvent event) {
final info = event.info;
final trackSid = event.track.sid;
if (trackSid != null && info != null) {
logger.fine('[Visibility] ${event.rendererId} did update '
'track: ${event.track.sid} '
'visibleFraction: ${info.visibleFraction} '
'size: ${info.size}');
_visibilities[event.rendererId] = RendererVisibility(
rendererId: event.rendererId,
trackId: trackSid,
visible: info.visibleFraction > 0,
size: info.size,
);
// quickly enable if currently disabled
if (!enabled && _hasVisibleRenderers()) {
logger.fine('[Visibility] Trying to re-enable quickly');
_cancelVisibilityDebounceFunc?.call();
_shouldComputeVisibilityUpdate(null);
} else {
_visibilityDidUpdate?.call(null);
}
} else {
// widget as been disposed, but track still exists
logger.fine('[Visibility] ${event.rendererId} was removed');
_visibilities.remove(event.rendererId);
_visibilityDidUpdate?.call(null);
}
logger.fine(
'[Visibility] Ids ${_visibilities.values.map((e) => e.rendererId)}');
}
bool _hasVisibleRenderers() =>
_visibilities.values.firstWhereOrNull((e) => e.visible) != null;
void _shouldComputeVisibilityUpdate(void _) {
if (isDisposed) {
logger.warning('_shouldComputeVisibilityUpdate already disposed');
return;
}
Size maxSize(Size s1, Size s2) => Size(
max(s1.width, s2.width),
max(s1.height, s2.height),
);
_enabled = _hasVisibleRenderers();
final settings = lk_rtc.UpdateTrackSettings(
trackSids: [sid],
disabled: !_enabled,
);
if (_enabled) {
final largest = _visibilities.values
.map((e) => e.size)
.reduce((value, element) => maxSize(value, element));
settings.width = largest.width.floor();
settings.height = largest.height.floor();
}
logger.fine('[Visibility] Sending to server ${settings.toProto3Json()}');
_participant.engine.signalClient.sendUpdateTrackSettings(settings);
}
@internal
@override
Future<bool> updateTrack(Track? newValue) async {
final didUpdate = await super.updateTrack(newValue);
// 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) {
if (val == _videoQuality) return;
_videoQuality = val;
_sendUpdateTrackSettings();
}
bool get enabled => _enabled;
set enabled(bool val) {
if (_enabled == val) return;
_enabled = val;
_sendUpdateTrackSettings();
}
set subscribed(bool val) {
logger.fine('setting subscribed = ${val}');
if (val == super.subscribed) return;
_sendUpdateSubscription(subscribed: val);
if (!val && track != null) {
// Ideally, we should wait for WebRTC's onRemoveTrack event
// but it does not work reliably across platforms.
// So for now we will assume remove track succeeded.
[_participant.events, _participant.roomEvents]
.emit(TrackUnsubscribedEvent(
participant: _participant,
track: track!,
publication: this,
));
// Simply set to null for now
updateTrack(null);
}
}
void _sendUpdateSubscription({required bool subscribed}) {
logger.fine('Sending update subscription... ${sid} ${subscribed}');
final subscription = lk_rtc.UpdateSubscription(
trackSids: [sid],
subscribe: subscribed,
);
_participant.engine.signalClient.sendUpdateSubscription(subscription);
}
void _sendUpdateTrackSettings() {
final settings = lk_rtc.UpdateTrackSettings(
trackSids: [sid],
disabled: !_enabled,
);
if (kind == lk_models.TrackType.VIDEO) {
settings.quality = _videoQuality;
}
_participant.engine.signalClient.sendUpdateTrackSettings(settings);
}
}
-75
View File
@@ -1,75 +0,0 @@
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
/// metadata associated with tracks.
///
/// Base for [RemoteTrackPublication] and [LocalTrackPublication],
/// can not be instantiated directly.
abstract class TrackPublication extends Disposable {
final String sid;
final String name;
final lk_models.TrackType kind;
final TrackSource source;
abstract 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;
TrackPublication.fromInfo(lk_models.TrackInfo info)
: sid = info.sid,
name = info.name,
kind = info.type,
source = info.source.toLKType() {
updateFromInfo(info);
}
/// True when the track is published with name [Track.screenShareName].
bool get isScreenShare =>
kind == lk_models.TrackType.VIDEO && name == Track.screenShareName;
void updateFromInfo(lk_models.TrackInfo info) {
simulcasted = info.simulcast;
if (info.type == lk_models.TrackType.VIDEO) {
dimension = TrackDimension(info.width, info.height);
}
}
// Equality operators
// Object is considered equal when sid is equal
@override
int get hashCode => sid.hashCode;
@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;
}
}