Better audio management (#10)
* add audio_session package * `AudioManager` initial design * try to integrate audio manager * configure audio session * `DisposeAware` disposing if already published causes exception. * organize * guard flutter_webrtc calls * websocket async fix * use `ConnectionState` instead of `_isClosed` and `isReconnecting` * change create audio track defaults * update protos * protocol 3 speaker updates * fix exception * emit `RoomDisconnectedEvent` only once * fix exception * keep track of local / remote audio tracks * explicit types * manage track state * re-structure audio management * change defaults * unpublish all * use experimental build * change defaults * configuring is optional * call native `RTCAudioSession.setConfiguration` * defaults adjustment * iOS only for now * use lib 92.4515.07 * clean up * revert audio options for now * remove pod source * rename apple related audio * `createListener` method * organize native audio * `SpeakingChangedEvent` only on `Participant` * refactoring * fix ios compile * fix configure audio only for iOS logic * minor fix & clean up * change dispose logic * format protos * fix unpublishTrack * `createListener` into a mixin * simplify * use flutter_webrtc master * unpublish for example * update ios icon * android icon * web icon * favicon
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
import 'package:async/async.dart';
|
||||
|
||||
class CancelableDelayManager {
|
||||
import '../support/disposable.dart';
|
||||
|
||||
class CancelableDelayManager extends Disposable {
|
||||
//
|
||||
final _delays = <CancelableOperation<void>>[];
|
||||
|
||||
CancelableDelayManager() {
|
||||
onDispose(() async => await cancelAll());
|
||||
}
|
||||
// delay but cancelable
|
||||
Future<void> waitFor(
|
||||
Duration wait, {
|
||||
@@ -19,7 +24,16 @@ class CancelableDelayManager {
|
||||
if (!op.isCanceled) ifNotCancelled?.call();
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
// @override
|
||||
// Future<bool> dispose() async {
|
||||
// final didDispose = await super.dispose();
|
||||
// if (didDispose) {
|
||||
// await cancelAll();
|
||||
// }
|
||||
// return didDispose;
|
||||
// }
|
||||
|
||||
Future<void> cancelAll() async {
|
||||
// cancel all delays
|
||||
if (_delays.isEmpty) return;
|
||||
// make a copy so we don't mutate while iterating
|
||||
|
||||
+38
-20
@@ -1,13 +1,19 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:synchronized/synchronized.dart' as sync;
|
||||
|
||||
import '../errors.dart';
|
||||
import '../exceptions.dart';
|
||||
import '../extensions.dart';
|
||||
import '../logger.dart';
|
||||
import '../support/disposable.dart';
|
||||
import '../types.dart';
|
||||
|
||||
mixin EventsEmittable<T> {
|
||||
final events = EventsEmitter<T>();
|
||||
EventsListener<T> createListener({bool synchronized = false}) =>
|
||||
EventsListener<T>(events, synchronized: synchronized);
|
||||
}
|
||||
|
||||
// Type-safe, multi-listenable, dispose safe event handling
|
||||
// TODO: Move to a separate package
|
||||
|
||||
@@ -17,7 +23,9 @@ class EventsEmitter<T> extends EventsListenable<T> {
|
||||
|
||||
EventsEmitter({
|
||||
bool listenSynchronized = false,
|
||||
}) : super(synchronized: listenSynchronized);
|
||||
}) : super(synchronized: listenSynchronized) {
|
||||
onDispose(() async => await streamCtrl.close());
|
||||
}
|
||||
|
||||
@override
|
||||
EventsEmitter<T> get emitter => this;
|
||||
@@ -28,13 +36,6 @@ class EventsEmitter<T> extends EventsListenable<T> {
|
||||
// emit the event
|
||||
streamCtrl.add(event);
|
||||
}
|
||||
|
||||
@override
|
||||
@mustCallSuper
|
||||
Future<void> dispose() async {
|
||||
await streamCtrl.close();
|
||||
await super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// for listening only
|
||||
@@ -51,7 +52,7 @@ class EventsListener<T> extends EventsListenable<T> {
|
||||
}
|
||||
|
||||
// ensures all listeners will close on dispose
|
||||
abstract class EventsListenable<T> {
|
||||
abstract class EventsListenable<T> extends Disposable {
|
||||
// the emitter to listen to
|
||||
EventsEmitter<T> get emitter;
|
||||
|
||||
@@ -62,17 +63,34 @@ abstract class EventsListenable<T> {
|
||||
|
||||
EventsListenable({
|
||||
required this.synchronized,
|
||||
});
|
||||
|
||||
@mustCallSuper
|
||||
Future<void> dispose() async {
|
||||
// Stop listening to all events
|
||||
logger.fine('${objectId} dispose() cancelling ${_listeners.length} event(s)');
|
||||
for (final listener in _listeners) {
|
||||
await listener.cancel();
|
||||
}
|
||||
}) {
|
||||
onDispose(() async {
|
||||
if (_listeners.isNotEmpty) {
|
||||
// Stop listening to all events
|
||||
logger.fine('${objectId} cancelling ${_listeners.length} listeners(s)');
|
||||
for (final listener in _listeners) {
|
||||
await listener.cancel();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// @override
|
||||
// @mustCallSuper
|
||||
// Future<bool> dispose() async {
|
||||
// // mark as disposed
|
||||
// final didDispose = await super.dispose();
|
||||
// if (didDispose && _listeners.isNotEmpty) {
|
||||
// // Stop listening to all events
|
||||
// logger.fine('${objectId} dispose() cancelling ${_listeners.length} event(s)');
|
||||
// for (final listener in _listeners) {
|
||||
// await listener.cancel();
|
||||
// }
|
||||
// }
|
||||
|
||||
// return didDispose;
|
||||
// }
|
||||
|
||||
// listens to all events, guaranteed to be cancelled on dispose
|
||||
CancelListenFunc listen(FutureOr<void> Function(T) onEvent) {
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user