audio_session

repository·master·Indexed 41 days ago

https://github.com/ryanheise/audio_session

A Flutter plugin that manages the application's audio session by providing a unified interface for iOS's AVAudioSession and Android's AudioManager. It allows developers to configure audio nature (e.g., music vs. speech), handle audio interruptions like phone calls, and react to hardware changes such as headphone unplugging via the AudioSession singleton.

Tokens
3.5K
Snippets
13
Records
16
Agent score
100%

What's inside audio_session

  1. Getting started with the audio_session example

    master
    The audio_session_example project serves as a starting point for a Flutter application demonstrating how to use the audio_session plugin. If you are new to Flutter, you can refer to the official Flutter documentation, codelabs, and cookbooks to understand the basics of Flutter development before integrating the plugin.
  2. Enable microphone access on iOS

    master

    To use microphone-related APIs (getRecordPermission, requestRecordPermission), you must perform two steps:

    1. Add the NSMicrophoneUsageDescription key to your Info.plist.
    2. Enable the microphone code in your build by setting the AUDIO_SESSION_MICROPHONE=1 preprocessor definition.

    CocoaPods Setup

    Add the following to your ios/Podfile:

    post_install do |installer|
      installer.pods_project.targets.each do |target|
        flutter_additional_ios_build_settings(target)
        
        target.build_configurations.each do |config|
          config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
            '$(inherited)',
            'AUDIO_SESSION_MICROPHONE=1'
          ]
        end
      end
    end

    SwiftPM Setup

    Export the environment variable before running your build command. You must run flutter clean whenever you change this value.

    AUDIO_SESSION_MICROPHONE=1 flutter run
  3. Customize the iOS launch screen assets

    master

    To customize the launch screen for your iOS application, you can replace the image files located in the example/ios/Runner/Assets.xcassets/LaunchImage.imageset/ directory with your own assets.

    Alternatively, you can manage these assets using Xcode:

    1. Open your Flutter project's iOS workspace using open ios/Runner.xcworkspace.
    2. In the Xcode Project Navigator, navigate to Runner/Assets.xcassets.
    3. Drag and drop your desired images into the asset catalog to replace the existing launch images.
    open ios/Runner.xcworkspace
  4. React to headphone unplugging and device changes

    master

    Use the following streams to handle hardware changes:

    • session.becomingNoisyEventStream: Emits when headphones are unplugged (the app should typically pause or lower volume).
    • session.devicesChangedEventStream: Emits when audio devices are added or removed. The event contains devicesAdded and devicesRemoved lists.
    // Observe unplugged headphones
    session.becomingNoisyEventStream.listen((_) {
      // The user unplugged the headphones, so we should pause or lower the volume.
    });
    
    // Observe when devices are added or removed
    session.devicesChangedEventStream.listen((event) {
      print('Devices added:   ${event.devicesAdded}');
      print('Devices removed: ${event.devicesRemoved}');
    });
  5. Activate the audio session

    master

    While most audio plugins activate the audio session automatically when playing audio, you can manually activate it using session.setActive(true). This informs the OS that your app is actively using audio. The method returns a bool indicating if the request was successful (e.g., it might fail if a phone call is in progress).

    // Activate the audio session before playing audio.
    if (await session.setActive(true)) {
      // Now play audio.
    } else {
      // The request was denied and the app should not play audio
    }
  6. Configure the audio session for music or speech

    master

    Use AudioSession.instance.configure() to set the app's audio behavior. The plugin provides pre-defined configurations for common use cases like music or speech (podcasts/audiobooks).

    Important Note on Shared State: On iOS, there is a single audio session shared by all audio plugins in your app. To prevent other plugins from overwriting your settings, it is recommended to apply your preferred configuration using audio_session after all other audio plugins have loaded.

    final session = await AudioSession.instance;
    
    // For music
    await session.configure(AudioSessionConfiguration.music());
    
    // For podcasts/audiobooks
    await session.configure(AudioSessionConfiguration.speech());
  7. React to audio interruptions

    master

    You can listen to session.interruptionEventStream to handle cases where other apps (like a phone app or navigator) request your app to pause or duck its audio.

    An interruption event contains a begin boolean (true if the interruption is starting, false if it is ending) and a type (e.g., AudioInterruptionType.duck or AudioInterruptionType.pause).

    session.interruptionEventStream.listen((event) {
      if (event.begin) {
        switch (event.type) {
          case AudioInterruptionType.duck:
            // Another app started playing audio and we should duck.
            break;
          case AudioInterruptionType.pause:
          case AudioInterruptionType.unknown:
            // Another app started playing audio and we should pause.
            break;
        }
      } else {
        switch (event.type) {
          case AudioInterruptionType.duck:
            // The interruption ended and we should unduck.
            break;
          case AudioInterruptionType.pause:
            // The interruption ended and we should resume.
          case AudioInterruptionType.unknown:
            // The interruption ended but we should not resume.
            break;
        }
      }
    });
  8. Implement Android AudioAttributes in a plugin

    master

    On Android, audio attributes are per-player/track rather than app-wide. To ensure a plugin respects the global configuration set via audio_session, it should listen to the configurationStream. This stream emits the latest configuration as its first event and subsequent changes thereafter.

    audioSession.configurationStream
        .map((conf) => conf?.androidAudioAttributes)
        .distinct()
        .listen((attributes) {
      // apply the attributes to this Android audio track
      _channel.invokeMethod("setAudioAttributes", attributes.toJson());
    });
  9. Understand AudioDevice and AudioDeviceType

    master

    An AudioDevice represents a piece of audio hardware. It includes:

    • id: A unique identifier.
    • name: The device name.
    • isInput: Whether it can record audio.
    • isOutput: Whether it can play audio.
    • type: An AudioDeviceType describing the hardware category.

    AudioDeviceType is an enumeration covering various types such as builtInSpeaker, wiredHeadphones, bluetoothA2dp, usbAudio, airPlay, and more. Note that AudioDeviceType is currently marked as @experimental.

  10. Configure a custom AudioSessionConfiguration

    master

    For granular control, you can instantiate AudioSessionConfiguration manually. This allows you to specify iOS-specific settings (like avAudioSessionCategory) and Android-specific settings (like androidAudioAttributes and androidAudioFocusGainType).

    final session = await AudioSession.instance;
    await session.configure(AudioSessionConfiguration(
      avAudioSessionCategory: AVAudioSessionCategory.playAndRecord,
      avAudioSessionCategoryOptions: AVAudioSessionCategoryOptions.allowBluetooth,
      avAudioSessionMode: AVAudioSessionMode.spokenAudio,
      avAudioSessionRouteSharingPolicy: AVAudioSessionRouteSharingPolicy.defaultPolicy,
      avAudioSessionSetActiveOptions: AVAudioSessionSetActiveOptions.none,
      androidAudioAttributes: const AndroidAudioAttributes(
        contentType: AndroidAudioContentType.speech,
        flags: AndroidAudioFlags.none,
        usage: AndroidAudioUsage.voiceCommunication,
      ),
      androidAudioFocusGainType: AndroidAudioFocusGainType.gain,
      androidWillPauseWhenDucked: true,
    ));
  11. Access the AudioSession singleton

    master

    To interact with the audio session, you must obtain the singleton instance of AudioSession. This instance is shared across all Flutter engines and should be used to configure the app's audio behavior during startup.

    final session = await AudioSession.instance;
  12. Listen for audio device changes

    master

    Use devicesChangedEventStream to detect when audio hardware (like headphones or Bluetooth devices) is added or removed.

    An AudioDevicesChangedEvent contains:

    • devicesAdded: A set of AudioDevice objects that were just connected.
    • devicesRemoved: A set of AudioDevice objects that were just disconnected.

    Alternatively, use devicesStream to get the current complete set of connected devices whenever any change occurs.

    final session = await AudioSession.instance;
    
    // Listen for specific changes
    session.devicesChangedEventStream.listen((event) {
      print('Added: ${event.devicesAdded}');
      print('Removed: ${event.devicesRemoved}');
    });
    
    // Or listen to the full set of current devices
    session.devicesStream.listen((devices) {
      print('Current devices: $devices');
    });
    final session = await AudioSession.instance;
    session.devicesChangedEventStream.listen((event) {
      print('Added: ${event.devicesAdded}');
    });