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:
@@ -0,0 +1,122 @@
|
||||
// https://developer.apple.com/documentation/avfaudio/avaudiosession/category
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../logger.dart';
|
||||
|
||||
enum AppleAudioCategory {
|
||||
soloAmbient,
|
||||
playback,
|
||||
record,
|
||||
playAndRecord,
|
||||
multiRoute,
|
||||
}
|
||||
|
||||
// https://developer.apple.com/documentation/avfaudio/avaudiosession/categoryoptions
|
||||
enum AppleAudioCategoryOption {
|
||||
mixWithOthers, // Only playAndRecord, playback, or multiRoute.
|
||||
duckOthers, // Only playAndRecord, playback, or multiRoute.
|
||||
interruptSpokenAudioAndMixWithOthers,
|
||||
allowBluetooth, // Only playAndRecord or record.
|
||||
allowBluetoothA2DP,
|
||||
allowAirPlay,
|
||||
defaultToSpeaker,
|
||||
}
|
||||
|
||||
// https://developer.apple.com/documentation/avfaudio/avaudiosession/mode
|
||||
enum AppleAudioMode {
|
||||
default_,
|
||||
gameChat,
|
||||
measurement,
|
||||
moviePlayback,
|
||||
spokenAudio,
|
||||
videoChat,
|
||||
videoRecording,
|
||||
voiceChat,
|
||||
voicePrompt,
|
||||
}
|
||||
|
||||
extension AppleAudioCategoryExt on AppleAudioCategory {
|
||||
String toStringValue() => <AppleAudioCategory, String>{
|
||||
AppleAudioCategory.soloAmbient: 'soloAmbient',
|
||||
AppleAudioCategory.playback: 'playback',
|
||||
AppleAudioCategory.record: 'record',
|
||||
AppleAudioCategory.playAndRecord: 'playAndRecord',
|
||||
AppleAudioCategory.multiRoute: 'multiRoute',
|
||||
}[this]!;
|
||||
}
|
||||
|
||||
extension AppleAudioCategoryOptionExt on AppleAudioCategoryOption {
|
||||
String toStringValue() => <AppleAudioCategoryOption, String>{
|
||||
AppleAudioCategoryOption.mixWithOthers: 'mixWithOthers',
|
||||
AppleAudioCategoryOption.duckOthers: 'duckOthers',
|
||||
AppleAudioCategoryOption.interruptSpokenAudioAndMixWithOthers:
|
||||
'interruptSpokenAudioAndMixWithOthers',
|
||||
AppleAudioCategoryOption.allowBluetooth: 'allowBluetooth',
|
||||
AppleAudioCategoryOption.allowBluetoothA2DP: 'allowBluetoothA2DP',
|
||||
AppleAudioCategoryOption.allowAirPlay: 'allowAirPlay',
|
||||
AppleAudioCategoryOption.defaultToSpeaker: 'defaultToSpeaker',
|
||||
}[this]!;
|
||||
}
|
||||
|
||||
extension AppleAudioModeExt on AppleAudioMode {
|
||||
String toStringValue() => <AppleAudioMode, String>{
|
||||
AppleAudioMode.default_: 'default',
|
||||
AppleAudioMode.gameChat: 'gameChat',
|
||||
AppleAudioMode.measurement: 'measurement',
|
||||
AppleAudioMode.moviePlayback: 'moviePlayback',
|
||||
AppleAudioMode.spokenAudio: 'spokenAudio',
|
||||
AppleAudioMode.videoChat: 'videoChat',
|
||||
AppleAudioMode.videoRecording: 'videoRecording',
|
||||
AppleAudioMode.voiceChat: 'voiceChat',
|
||||
AppleAudioMode.voicePrompt: 'voicePrompt',
|
||||
}[this]!;
|
||||
}
|
||||
|
||||
class NativeAudioConfiguration {
|
||||
final AppleAudioCategory? appleAudioCategory;
|
||||
final Set<AppleAudioCategoryOption>? appleAudioCategoryOptions;
|
||||
final AppleAudioMode? appleAudioMode;
|
||||
|
||||
NativeAudioConfiguration({
|
||||
// for iOS / Mac
|
||||
this.appleAudioCategory,
|
||||
this.appleAudioCategoryOptions,
|
||||
this.appleAudioMode,
|
||||
// Android options
|
||||
// ...
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() => <String, dynamic>{
|
||||
if (appleAudioCategory != null) 'appleAudioCategory': appleAudioCategory!.toStringValue(),
|
||||
if (appleAudioCategoryOptions != null)
|
||||
'appleAudioCategoryOptions':
|
||||
appleAudioCategoryOptions!.map((e) => e.toStringValue()).toList(),
|
||||
if (appleAudioMode != null) 'appleAudioMode': appleAudioMode!.toStringValue(),
|
||||
};
|
||||
|
||||
NativeAudioConfiguration copyWith({
|
||||
AppleAudioCategory? appleAudioCategory,
|
||||
Set<AppleAudioCategoryOption>? appleAudioCategoryOptions,
|
||||
AppleAudioMode? appleAudioMode,
|
||||
}) =>
|
||||
NativeAudioConfiguration(
|
||||
appleAudioCategory: appleAudioCategory ?? this.appleAudioCategory,
|
||||
appleAudioCategoryOptions: appleAudioCategoryOptions ?? this.appleAudioCategoryOptions,
|
||||
appleAudioMode: appleAudioMode ?? this.appleAudioMode,
|
||||
);
|
||||
}
|
||||
|
||||
const _lkMethodChannel = MethodChannel('livekit_client');
|
||||
|
||||
Future<bool> configureNativeAudio(NativeAudioConfiguration configuration) async {
|
||||
try {
|
||||
final result = await _lkMethodChannel.invokeMethod<bool>(
|
||||
'configureNativeAudio',
|
||||
configuration.toMap(),
|
||||
);
|
||||
return result == true;
|
||||
} catch (_) {
|
||||
logger.warning('configureAudioSession did throw $_');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user