Handling System Audio Interruptions

Audio interruptions are a common occurrence on mobile devices that can disrupt ongoing video calls. The Stream Video Flutter SDK provides built-in support for handling these interruptions gracefully, allowing you to maintain a smooth user experience even when external audio events occur.

What are Audio Interruptions?

Audio interruptions happen when the system or other applications take over the audio session, temporarily pausing or stopping your app’s audio. Common examples include:

iOS Interruptions

  • Incoming phone calls
  • Siri activation
  • Alarm or timer sounds
  • Audio from other apps taking over (e.g., voice memo, navigation apps)

Android Interruptions

The interruption sources depend on the configured AndroidInterruptionSource:

With Audio Focus:

  • Other media apps interrupting (e.g., Spotify, YouTube)
  • Assistant voice prompts (e.g., Google Assistant)
  • Alarms and notifications

With Telephony:

  • Phone calls (requires READ_PHONE_STATE permission)

Basic Implementation

The SDK provides the handleCallInterruptionCallbacks method through RtcMediaDeviceNotifier to manage audio interruptions.

In this example, we disable the microphone during an interruption:

import 'package:stream_video_flutter/stream_video_flutter.dart';

bool? _microphoneEnabledBeforeInterruption;

void _handleMobileAudioInterruptions() {
  if (!CurrentPlatform.isMobile) return;

  RtcMediaDeviceNotifier.instance.handleCallInterruptionCallbacks(
    onInterruptionStart: () {
      // Mute the microphone when the interruption starts
      final call = StreamVideo.instance.activeCall;
      _microphoneEnabledBeforeInterruption =
            call?.state.value.localParticipant?.isAudioEnabled;
      
      call?.setMicrophoneEnabled(enabled: false);
    },
    onInterruptionEnd: () {
      // Unmute the microphone when the interruption ends
      if (_microphoneEnabledBeforeInterruption == true) {
        StreamVideo.instance.activeCall?.setMicrophoneEnabled(enabled: true);
      }
      _microphoneEnabledBeforeInterruption = null;
    },
    androidInterruptionSource: AndroidInterruptionSource.audioFocusAndTelephony,
  );
}

When multiple active calls are enabled, use StreamVideo.instance.activeCalls instead.

In this example, we mute audio playout during a phone call:

import 'package:stream_webrtc_flutter/stream_webrtc_flutter.dart' as rtc;
import 'package:stream_video_flutter/stream_video_flutter.dart';

void _handleMobileAudioInterruptions() {
  if (!CurrentPlatform.isMobile) return;

  RtcMediaDeviceNotifier.instance.handleCallInterruptionCallbacks(
    onInterruptionStart: () {
      rtc.Helper.pauseAudioPlayout();
    },
    onInterruptionEnd: () {
      rtc.Helper.resumeAudioPlayout();
    },
    androidInterruptionSource: AndroidInterruptionSource.telephonyOnly,
  );
}

On Android, audio focus may not be restored automatically. To ensure you receive onInterruptionEnd, explicitly call rtc.Helper.resumeAudioPlayout(); (for example, when the app resumes from background).

Method Parameters

handleCallInterruptionCallbacks

Future<void> handleCallInterruptionCallbacks({
  void Function()? onInterruptionStart,
  void Function()? onInterruptionEnd,
  AndroidInterruptionSource androidInterruptionSource = 
      AndroidInterruptionSource.audioFocusAndTelephony,
})

Parameters:

  • onInterruptionStart: Callback function executed when an audio interruption starts
  • onInterruptionEnd: Callback function executed when an audio interruption ends
  • androidInterruptionSource: Specifies which interruption sources to monitor on Android

On Android, you can filter interruptions for audio and/or telephony; on iOS, all interruptions are enabled.

Android Interruption Sources

enum AndroidInterruptionSource {
  audioFocusOnly,           // Monitor audio focus changes only
  telephonyOnly,           // Monitor phone calls only
  audioFocusAndTelephony, // Monitor both (default)
}

Platform Setup

iOS

No additional configuration is required for iOS. The SDK integrates with the system audio session and handles interruption events for you.

Android Permissions

To handle phone call interruptions on Android, add the following permissions to your android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

Runtime Permission Request

Request the phone permission at runtime for Android:

import 'package:permission_handler/permission_handler.dart';

void _requestPermissions() async {
  if (CurrentPlatform.isAndroid) {
    await Permission.phone.request();
  }
}

Best Practices

1. Initialize Early

Set up interruption handling as early as possible in your app lifecycle:

@override
void initState() {
  super.initState();
  _handleMobileAudioInterruptions();
}

2. Platform Check

Always check if the platform is mobile before setting up interruption handling:

void _setupInterruptions() {
  if (!CurrentPlatform.isMobile) return;
  // Setup interruption handling
}

3. Graceful Degradation

Handle cases where permissions might not be granted:

void _setupWithPermissionCheck() async {
  if (CurrentPlatform.isAndroid) {
    final phonePermission = await Permission.phone.status;
    if (phonePermission.isDenied) {
      // Handle telephony interruptions only if permission is granted
      await Permission.phone.request();
    }
  }
  
  _handleMobileAudioInterruptions();
}

4. Explain Permissions

Requesting low‑level permissions such as READ_PHONE_STATE can worry users. Onboard users first and explain why the permission is needed before requesting it.

© Getstream.io, Inc. All Rights Reserved.