001f688729
* 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
123 lines
4.1 KiB
Dart
123 lines
4.1 KiB
Dart
// 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;
|
|
}
|
|
}
|