From 84b9ef130fedafa1eeed9cf82689649183a69b85 Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Fri, 8 Apr 2022 01:58:49 +0900 Subject: [PATCH] Change AudioSession configuration logic (#104) * impl * ref * ref --- lib/src/participant/local.dart | 9 +++ lib/src/track/audio_management.dart | 119 ++++++++++++++++------------ lib/src/track/local/audio.dart | 3 +- lib/src/track/local/local.dart | 33 +++++++- lib/src/track/remote/audio.dart | 2 +- 5 files changed, 111 insertions(+), 55 deletions(-) diff --git a/lib/src/participant/local.dart b/lib/src/participant/local.dart index 248a82c..b1d5bff 100644 --- a/lib/src/participant/local.dart +++ b/lib/src/participant/local.dart @@ -81,6 +81,9 @@ class LocalParticipant extends Participant { ); addTrackPublication(pub); + // did publish + await track.onPublish(); + [events, room.events].emit(LocalTrackPublishedEvent( participant: this, publication: pub, @@ -175,6 +178,9 @@ class LocalParticipant extends Participant { ); addTrackPublication(pub); + // did publish + await track.onPublish(); + [events, room.events].emit(LocalTrackPublishedEvent( participant: this, publication: pub, @@ -215,6 +221,9 @@ class LocalParticipant extends Participant { await room.engine.negotiate(); } } + + // did unpublish + await track.onUnpublish(); } if (notify) { diff --git a/lib/src/track/audio_management.dart b/lib/src/track/audio_management.dart index de0bc06..f303e37 100644 --- a/lib/src/track/audio_management.dart +++ b/lib/src/track/audio_management.dart @@ -4,8 +4,8 @@ import '../logger.dart'; import '../support/native.dart'; import '../support/native_audio.dart'; import '../support/platform.dart'; -import 'local/audio.dart'; import 'local/local.dart'; +import 'remote/remote.dart'; enum AudioTrackState { none, @@ -17,29 +17,51 @@ enum AudioTrackState { typedef ConfigureNativeAudioFunc = Future Function( AudioTrackState state); -mixin AudioManagementMixin on AudioTrack { - // it's possible to set custom function here to customize audio session configuration - static ConfigureNativeAudioFunc nativeAudioConfigurationForAudioTrackState = - defaultNativeAudioConfigurationFunc; +// it's possible to set custom function here to customize audio session configuration +ConfigureNativeAudioFunc onConfigureNativeAudio = + defaultNativeAudioConfigurationFunc; - static final _trackCounterLock = sync.Lock(); - static AudioTrackState audioTrackState = AudioTrackState.none; - static int _localTrackCount = 0; - static int _remoteTrackCount = 0; +final _trackCounterLock = sync.Lock(); +AudioTrackState _audioTrackState = AudioTrackState.none; +int _localTrackCount = 0; +int _remoteTrackCount = 0; +mixin LocalAudioManagementMixin on LocalTrack, AudioTrack { + @override + Future onPublish() async { + final didUpdate = await super.onPublish(); + if (didUpdate) { + // update counter + await _trackCounterLock.synchronized(() async { + _localTrackCount++; + await _onAudioTrackCountDidChange(); + }); + } + return didUpdate; + } + + @override + Future onUnpublish() async { + final didUpdate = await super.onUnpublish(); + if (didUpdate) { + // update counter + await _trackCounterLock.synchronized(() async { + _localTrackCount--; + await _onAudioTrackCountDidChange(); + }); + } + return didUpdate; + } +} +mixin RemoteAudioManagementMixin on RemoteTrack, AudioTrack { /// Start playing audio track. On web platform, create an audio element and /// start playback @override Future start() async { final didStart = await super.start(); if (didStart) { - // update counter await _trackCounterLock.synchronized(() async { - if (this is LocalAudioTrack) { - _localTrackCount++; - } else if (this is! LocalAudioTrack) { - _remoteTrackCount++; - } + _remoteTrackCount++; await _onAudioTrackCountDidChange(); }); } @@ -50,59 +72,52 @@ mixin AudioManagementMixin on AudioTrack { Future stop() async { final didStop = await super.stop(); if (didStop) { - // update counter await _trackCounterLock.synchronized(() async { - if (this is LocalAudioTrack) { - _localTrackCount--; - } else if (this is! LocalAudioTrack) { - _remoteTrackCount--; - } + _remoteTrackCount--; await _onAudioTrackCountDidChange(); }); } return didStop; } +} - Future _onAudioTrackCountDidChange() async { - logger.fine('[$runtimeType] onAudioTrackCountDidChange: ' - 'local: $_localTrackCount, remote: $_remoteTrackCount'); +Future _onAudioTrackCountDidChange() async { + logger.fine('onAudioTrackCountDidChange: ' + 'local: $_localTrackCount, remote: $_remoteTrackCount'); - final newState = _computeAudioTrackState(); + final newState = _computeAudioTrackState(); - if (audioTrackState != newState) { - audioTrackState = newState; - logger.fine('[$runtimeType] didUpdateSate: $audioTrackState'); + if (_audioTrackState != newState) { + _audioTrackState = newState; + logger.fine('didUpdateSate: $_audioTrackState'); - NativeAudioConfiguration? config; - if (lkPlatformIs(PlatformType.iOS)) { - // Only iOS for now... - config = await nativeAudioConfigurationForAudioTrackState - .call(audioTrackState); - } + NativeAudioConfiguration? config; + if (lkPlatformIs(PlatformType.iOS)) { + // Only iOS for now... + config = await onConfigureNativeAudio.call(_audioTrackState); + } - if (config != null) { - logger.fine( - '[$runtimeType] configuring for ${audioTrackState} using ${config}...'); - try { - await Native.configureAudio(config); - } catch (error) { - logger.warning('[$runtimeType] Failed to configure ${error}'); - } + if (config != null) { + logger.fine('configuring for ${_audioTrackState} using ${config}...'); + try { + await Native.configureAudio(config); + } catch (error) { + logger.warning('failed to configure ${error}'); } } } +} - static AudioTrackState _computeAudioTrackState() { - if (_localTrackCount > 0 && _remoteTrackCount == 0) { - return AudioTrackState.localOnly; - } else if (_localTrackCount == 0 && _remoteTrackCount > 0) { - return AudioTrackState.remoteOnly; - } else if (_localTrackCount > 0 && _remoteTrackCount > 0) { - return AudioTrackState.localAndRemote; - } - // Default - return AudioTrackState.none; +AudioTrackState _computeAudioTrackState() { + if (_localTrackCount > 0 && _remoteTrackCount == 0) { + return AudioTrackState.localOnly; + } else if (_localTrackCount == 0 && _remoteTrackCount > 0) { + return AudioTrackState.remoteOnly; + } else if (_localTrackCount > 0 && _remoteTrackCount > 0) { + return AudioTrackState.localAndRemote; } + // Default + return AudioTrackState.none; } Future defaultNativeAudioConfigurationFunc( diff --git a/lib/src/track/local/audio.dart b/lib/src/track/local/audio.dart index 121b222..3ab25e5 100644 --- a/lib/src/track/local/audio.dart +++ b/lib/src/track/local/audio.dart @@ -8,7 +8,8 @@ import '../audio_management.dart'; import '../options.dart'; import 'local.dart'; -class LocalAudioTrack extends LocalTrack with AudioTrack, AudioManagementMixin { +class LocalAudioTrack extends LocalTrack + with AudioTrack, LocalAudioManagementMixin { // Options used for this track @override covariant AudioCaptureOptions currentOptions; diff --git a/lib/src/track/local/local.dart b/lib/src/track/local/local.dart index 26792de..69e4aa5 100644 --- a/lib/src/track/local/local.dart +++ b/lib/src/track/local/local.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; - import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; import 'package:meta/meta.dart'; import '../../events.dart'; import '../../exceptions.dart'; +import '../../extensions.dart'; import '../../logger.dart'; import '../../participant/remote.dart'; import '../../proto/livekit_models.pb.dart' as lk_models; @@ -46,6 +46,9 @@ abstract class LocalTrack extends Track { /// Options used for this track abstract LocalTrackOptions currentOptions; + bool _published = false; + bool get isPublished => _published; + LocalTrack( String name, lk_models.TrackType kind, @@ -170,4 +173,32 @@ abstract class LocalTrack extends Track { // mark as started await start(); } + + @internal + @mustCallSuper + Future onPublish() async { + if (_published) { + // already published + return false; + } + + logger.fine('$objectId.publish()'); + + _published = true; + return true; + } + + @internal + @mustCallSuper + Future onUnpublish() async { + if (!_published) { + // already unpublished + return false; + } + + logger.fine('$objectId.unpublish()'); + + _published = false; + return true; + } } diff --git a/lib/src/track/remote/audio.dart b/lib/src/track/remote/audio.dart index c8b7b58..fc38088 100644 --- a/lib/src/track/remote/audio.dart +++ b/lib/src/track/remote/audio.dart @@ -10,7 +10,7 @@ import '../web/_audio_api.dart' if (dart.library.html) '../web/_audio_html.dart' as audio; class RemoteAudioTrack extends RemoteTrack - with AudioTrack, AudioManagementMixin { + with AudioTrack, RemoteAudioManagementMixin { // RemoteAudioTrack( String name,