reconfigure method

Future<void> reconfigure({
  1. bool force = false,
  2. AudioSpeakerKind? preferredSpeaker,
})

Configures the current AudioSession to reflect the AudioModes applied.

Implementation

Future<void> reconfigure({
  bool force = false,
  AudioSpeakerKind? preferredSpeaker,
}) async {
  Log.debug(
    'reconfigure($force, $preferredSpeaker) -> intents are [${_intents.values.map((e) => e.mode.name).join(', ')}]',
    '$runtimeType',
  );

  await _categoryGuard.protect(() async {
    if (_intents.isEmpty) {
      if (!PlatformUtils.isWeb) {
        // Reset back to speaker, but only if headphones are disconnected.
        if (speaker.value != AudioSpeakerKind.headphones) {
          await setSpeaker(AudioSpeakerKind.speaker);
        }

        if (PlatformUtils.isIOS) {
          await AVAudioSession().setActive(false);
        }
      }
    } else {
      final bool needsMic = _intents.values.any((e) => e.mode.needsMic);

      final AudioSessionConfiguration configuration =
          AudioSessionConfiguration(
            avAudioSessionCategory: needsMic
                ? AVAudioSessionCategory.playAndRecord
                : AVAudioSessionCategory.playback,
            avAudioSessionMode: needsMic
                ? AVAudioSessionMode.voiceChat
                : AVAudioSessionMode.defaultMode,
            avAudioSessionCategoryOptions: needsMic
                ? AVAudioSessionCategoryOptions.allowBluetooth |
                      AVAudioSessionCategoryOptions.duckOthers
                : AVAudioSessionCategoryOptions.mixWithOthers,
            androidAudioAttributes: AndroidAudioAttributes(
              contentType: needsMic
                  ? AndroidAudioContentType.speech
                  : AndroidAudioContentType.music,
              usage: needsMic
                  ? AndroidAudioUsage.voiceCommunication
                  : AndroidAudioUsage.media,
            ),
            androidAudioFocusGainType:
                AndroidAudioFocusGainType.gainTransient,
          );

      if (configuration.toJson() == _previousConfiguration?.toJson()) {
        Log.debug(
          'reconfigure() -> ignoring ${_intents.values.map((e) => e.mode.name).join(', ')}',
          '$runtimeType',
        );

        return;
      }

      _previousConfiguration = configuration;

      final AudioSession session = await AudioSession.instance;

      try {
        await session.configure(configuration);

        Log.debug('await session.configure()... done!', '$runtimeType');

        Log.debug('await session.setActive(true)...', '$runtimeType');
        await session.setActive(true, fallbackConfiguration: configuration);
        Log.debug('await session.setActive(true)... done!', '$runtimeType');
      } catch (e) {
        Log.warning(
          'Failed to `session.configure()` due to: $e',
          '$runtimeType',
        );
      }

      if (preferredSpeaker != null) {
        // If we're using headphones, then shouldn't switch.
        if (speaker.value == AudioSpeakerKind.headphones) {
          // No-op.
        } else {
          await setSpeaker(
            preferredSpeaker,

            // `Speaker` kind should always be switched always after
            // `session.configure()` due to that call resetting the setting.
            force: preferredSpeaker == AudioSpeakerKind.speaker,
          );
        }
      } else if (_isMobile) {
        if (speaker.value != null) {
          await setSpeaker(speaker.value!, force: force);
        }
      }
    }
  });
}