Sharing audio input

Audio input usually comes from the built-in mic, an external mic, or an audio interface attached to the device. Audio input can also come from a phone conversation.

Sometimes two or more apps might both want to "capture" the same audio input. They may be performing different tasks. For example, some apps that receive audio might be "recording," like a simple voice recorder, while other apps might be "listening," like the Google Assistant or an accessibility service that respond to voice commands.

In either case, these apps want to receive audio input. Throughout this page, we use the term "capture" regardless of whether an app is recording or just listening.

If two or more apps want to capture audio at the same time, there can be a problem delivering the audio signal from the same source to all of them. This page describes how the Android system shares audio input between multiple apps that capture audio.

Pre-Q behavior

Before Android Q the input audio stream could only be captured by one app at a time. If some app was already recording or listening to audio, your app could create an AudioRecord object, but an error would be returned when you called AudioRecord.startRecording() and the recording would not start.

One exception to this rule was when a privileged app (like Google Assistant or an accessibility service) had the permission android.permission.CAPTURE_AUDIO_HOTWORD and used an audio source of type HOTWORD. In this case another app could start recording. When that happened the privileged app terminated and the new app captured the input.

One more change was added in Android 9: only apps running in the foreground (or a foreground service) could capture the audio input. When an app without a foreground service or foreground UI component started to capture, the app continued running but received silence, even if it was the only app capturing audio at the time.

New behavior

The previous behavior was "first come, first served." Once an app started to capture audio, all other apps had no way to access the audio input until the capturing app stopped.

Android Q imposes a priority scheme that can switch the input audio stream between apps while they are running. In most cases, if a new app acquires the audio input, the previously capturing app continues to run, but receives silence. In some cases the system can continue to deliver audio to both apps. The various sharing scenarios are explained below.

This scheme is similar to the way audio focus handles multiple apps contending for the use of the audio output. However, audio focus is managed by programmatic requests to gain and release focus, while the input switching scheme described here is based on a prioritization policy that's applied automatically whenever a new app starts to capture audio.

For the purpose of capturing audio, Android distinguishes two kinds of apps:

  • "Ordinary" apps are installed by the user.
  • "Privileged" apps come pre-installed on the device. These include the Google Assistant, and all accessibility services.

In addition, an app is treated differently if it uses a "privacy-sensitive" audio source: CAMCORDER or VOICE_COMMUNICATION.

The prioritization rules for using and sharing audio input are as follows:

  • Privileged apps have higher priority than ordinary apps.
  • Apps with visible foreground UIs have higher priority than background apps.
  • Apps capturing audio from a privacy-sensitive source have higher priority than apps that are not.
  • Two ordinary apps can never capture audio at the same time.
  • In some situations, a privileged app can share audio input with another app.
  • If two background apps of same priority are capturing audio, the last one started has higher priority.

Sharing scenarios

When two apps are trying to capture audio, they both may be able to receive the input signal, or one of them may receive silence.

There are four main scenarios:

  • Assistant + ordinary app
  • Accessibility service + ordinary app
  • Two ordinary apps
  • Voice call + ordinary app

Assistant + ordinary app

The Assistant is a privileged app because it is pre-installed and it holds the role RoleManager.ROLE_ASSISTANT. Any other pre-installed app with this role is treated similarly.

Android shares the input audio according to these rules:

  • The Assistant can receive audio (no matter whether it's in the foreground or background) unless another app using a privacy-sensitive audio source is already capturing.

  • The app receives audio unless the Assistant has a visible UI component on top of the screen.

Note that both apps receive audio only when the Assistant is in the background and the other app is not capturing from a privacy-sensitive audio source.

Accessibility service + ordinary app

An AccessibilityService requires a strict declaration.

Android shares the input audio according to these rules:

  • If the service's UI is on top, both the service and the app receive audio input. This behavior offers functionality like controlling a voice call or video capture with voice commands.

  • If the service is not on top, this case is treated like the ordinary two-app case below.

Two ordinary apps

When two apps are capturing concurrently, only one app receives audio and the other gets silence.

Android shares the input audio according to these rules:

  • If neither app is privacy-sensitive, the app with a UI on top receives audio. If neither app has a UI, the one that started capture the most recently receives audio.
  • If one of the apps is privacy-sensitive, it receives audio and the other app gets silence even if it has a UI on top or started capturing more recently.
  • If both apps are privacy-sensitive, the app which started capturing most recently receives audio and the other gets silence.

Voice call + ordinary app

A voice call is active if the audio mode returned by AudioManager.getMode() is MODE_IN_CALL or MODE_IN_COMMUNICATION.

Android shares the input audio according to these rules:

Configuration changes

When several apps are capturing audio simultaneously, only one or two them are "active" (receiving audio); the others are muted (receiving silence). When the active apps change, the audio framework might reconfigure the audio paths according to these rules:

  • The audio input device for each active app might change (for example, from the built-in microphone to an attached bluetooth headset).
  • The preprocessing associated with the highest-priority active app is enabled. All other preprocessing is ignored.

Since an active app might be silenced when a higher-priority app becomes active, you can register an AudioManager.AudioRecordingCallback on the AudioRecord or MediaRecorder object to be notified when the configuration changes. The possible changes could be:

  • Capture silenced or unsilenced
  • Device changed
  • Preprocessing changed
  • Stream properties changed (sampling rate, channel mask, sample format)

You must call AudioRecord.registerAudioRecordingCallback() before the capture is started. The callback is executed only when the app is receiving audio and a change occurs.

The method onRecordingConfigChanged() returns an AudioRecordingConfiguration containing the current audio capture state. Use the following methods to learn about the change:

isClientSilenced()
Returns true if the audio returned to the client is currently being silenced due to the capture policy.
getAudioDevice()
Returns the active audio device.
getEffects()
Returns the active preprocessing effect. Note that the active effect might not be the same as those returned by getClientEffects() if the client is not the highest-priority active app.
getFormat()
Returns the stream properties. Note that the actual audio data received by the client always respects the required format returned by getClientFormat(). The framework automatically performs the necessary resampling, channel, and format conversion from the format used at the hardware interface to the format specified by the client.
AudioRecord.getActiveRecordingConfiguration().
Returns the active recording configuration.

You can get a general view of all active recordings on the device by calling AudioManager.getActiveRecordingConfigurations().