Аудиовход обычно поступает со встроенного микрофона, внешнего микрофона или аудиоинтерфейса, подключенного к устройству. Аудиовход также может поступать во время телефонного разговора.
Иногда двум или более приложениям одновременно требуется «захватывать» один и тот же аудиовход. Они могут выполнять разные задачи. Например, некоторые приложения, принимающие аудио, могут «записывать», как простой диктофон, в то время как другие приложения могут «прослушивать», как Google Ассистент или служба специальных возможностей, реагирующая на голосовые команды.
В любом случае этим приложениям требуется аудиовход. На этой странице мы используем термин «захват» независимо от того, записывает ли приложение звук или просто слушает.
Если два или более приложений одновременно пытаются записывать звук, могут возникнуть проблемы с передачей аудиосигнала из одного источника всем приложениям. На этой странице описывается, как система Android распределяет аудиовход между несколькими приложениями, которые записывают звук.
Поведение до Android 10
До Android 10 входной аудиопоток мог быть записан только одним приложением одновременно. Если какое-либо приложение уже записывало или прослушивало аудио, ваше приложение могло создать объект AudioRecord
, но при вызове AudioRecord.startRecording()
возвращалась ошибка, и запись не начиналась.
Исключением из этого правила было приложение, имеющее разрешение android.permission.CAPTURE_AUDIO_HOTWORD
и использующее источник звука типа HOTWORD
. В этом случае другое приложение могло начать запись. При этом приложение завершало работу, а новое приложение захватывало входные данные.
В Android 9 было добавлено ещё одно изменение: только приложения, работающие на переднем плане (или активная служба), могли захватывать аудиовход. Когда приложение без активной службы или активного компонента пользовательского интерфейса начинало захват, оно продолжало работать, но получало тишину, даже если в тот момент оно было единственным приложением, записывающим аудио.
Поведение Android 10
До Android 10 действовал принцип «первым пришёл, первым обслужен». Как только приложение начинает запись звука, другие приложения не могут получить доступ к аудиовходу, пока приложение, записывающее звук, не остановит запись.
В Android 10 реализована схема приоритетов, которая позволяет переключать входящий аудиопоток между приложениями во время их работы. В большинстве случаев, если новое приложение получает аудиовход, предыдущее приложение, осуществлявшее захват, продолжает работать, но получает тишину. В некоторых случаях система может продолжать передавать аудио обоим приложениям. Различные сценарии передачи аудио описаны ниже.
Эта схема похожа на то, как аудиофокус управляет несколькими приложениями, конкурирующими за аудиовыход. Однако аудиофокус управляется программными запросами на получение и снятие фокуса, в то время как описанная здесь схема переключения входов основана на политике приоритетов, которая применяется автоматически при каждом начале записи звука новым приложением.
Для записи звука Android различает два типа приложений:
- «Обычные» приложения устанавливаются пользователем.
- «Привилегированные» приложения предустановлены на устройстве. К ним относятся Google Ассистент и все службы специальных возможностей.
Кроме того, приложение обрабатывается по-другому, если оно использует «чувствительный к конфиденциальности» источник звука: CAMCORDER
или VOICE_COMMUNICATION
.
Правила приоритетности использования и совместного использования аудиовхода следующие:
- Привилегированные приложения имеют более высокий приоритет, чем обычные приложения.
- Приложения с видимым пользовательским интерфейсом на переднем плане имеют более высокий приоритет, чем фоновые приложения.
- Приложения, записывающие аудио из конфиденциальных источников, имеют более высокий приоритет, чем приложения, не требующие соблюдения конфиденциальности.
- Два обычных приложения никогда не смогут записывать звук одновременно.
- В некоторых ситуациях привилегированное приложение может использовать общий аудиовход с другим приложением.
- Если два фоновых приложения с одинаковым приоритетом записывают звук, то приоритет имеет последнее запущенное приложение.
Совместное использование сценариев
Когда два приложения пытаются записать звук, они оба могут получить входной сигнал, либо одно из них может получить тишину.
Существует четыре основных сценария:
- Помощник + обычное приложение
- Служба доступности + обычное приложение
- Два обычных приложения
- Голосовой вызов + обычное приложение
Помощник + обычное приложение
Помощник является привилегированным приложением, поскольку он предустановлен и имеет роль RoleManager.ROLE_ASSISTANT
. Любое другое предустановленное приложение с этой ролью обрабатывается аналогично.
Android распределяет входящий звук в соответствии со следующими правилами:
Помощник может принимать аудио (независимо от того, находится ли оно на переднем плане или в фоновом режиме), если другое приложение, использующее конфиденциальный источник звука, уже не осуществляет запись.
Приложение получает звук, если у Помощника нет видимого компонента пользовательского интерфейса в верхней части экрана.
Обратите внимание, что оба приложения получают аудио только тогда, когда Ассистент находится в фоновом режиме, а другое приложение не осуществляет запись из источника звука, конфиденциальность которого имеет значение.
Служба доступности + обычное приложение
AccessibilityService
требует строгого объявления .
Android распределяет входящий звук в соответствии со следующими правилами:
Если пользовательский интерфейс сервиса находится поверх экрана, и сервис, и приложение получают аудиовход. Это позволяет реализовать такие функции, как управление голосовым вызовом или записью видео с помощью голосовых команд.
Если служба не находится наверху, этот случай рассматривается как обычный случай с двумя приложениями, описанный ниже.
Два обычных приложения
Когда два приложения выполняют запись одновременно, только одно приложение получает звук, а другое получает тишину.
Android распределяет входящий звук в соответствии со следующими правилами:
- Если ни одно из приложений не обеспечивает конфиденциальность, звук получает приложение с пользовательским интерфейсом. Если ни одно из приложений не имеет пользовательского интерфейса, звук получает то, которое начало запись последним.
- Если одно из приложений чувствительно к конфиденциальности, оно принимает звук, а другое приложение получает тишину, даже если у него есть пользовательский интерфейс или оно начало запись совсем недавно.
- Если оба приложения чувствительны к конфиденциальности, то приложение, которое начало запись последним, получает звук, а другое получает тишину.
Голосовой вызов + обычное приложение
Голосовой вызов активен, если аудиорежим, возвращаемый AudioManager.getMode()
, равен MODE_IN_CALL
или MODE_IN_COMMUNICATION
.
Android распределяет входящий звук в соответствии со следующими правилами:
- Вызов всегда сопровождается звуком.
- Приложение может записывать аудио, если оно является службой специальных возможностей .
Приложение может захватить голосовой вызов, если оно является привилегированным (предустановленным) приложением с разрешением
CAPTURE_AUDIO_OUTPUT
.Чтобы захватить восходящий канал (TX), нисходящий канал (RX) голосового вызова или оба, приложение должно указать источники звука
MediaRecorder.AudioSource.VOICE_UPLINK
илиMediaRecorder.AudioSource.VOICE_DOWNLINK
и/или устройствоAudioDeviceInfo.TYPE_TELEPHONY
.
Поведение Android 11
В Android 11 (API уровня 30) реализована описанная выше схема приоритетов Android 10. Кроме того, в AudioRecord
, MediaRecorder
и AAudioStream
представлены новые методы, которые включают и отключают возможность одновременного захвата звука, независимо от выбранного варианта использования.
Новые методы:
-
AudioRecord.Builder.setPrivacySensitive()
-
AudioRecord.isPrivacySensitive()
-
MediaRecorder.setPrivacySensitive()
-
MediaRecorder.isPrivacySensitive()
-
AAudioStreamBuilder_setPrivacySensitive()
-
AAudioStream_isPrivacySensitive()
Если setPrivacySensitive()
имеет true
, сценарий захвата является конфиденциальным, и даже привилегированный помощник не может одновременно записывать звук. Эта настройка переопределяет поведение по умолчанию, зависящее от источника звука. Например, VOICE_COMMUNICATION
по умолчанию является конфиденциальным, а UNPROCESSED
— нет.
Изменения конфигурации
Когда несколько приложений одновременно записывают звук, только одно или два из них «активны» (получают звук); остальные отключены (получают тишину). При смене активных приложений аудиофреймворк может перенастроить аудиотракты в соответствии со следующими правилами:
- Устройство аудиоввода для каждого активного приложения может меняться (например, со встроенного микрофона на подключенную Bluetooth-гарнитуру).
- Включается предварительная обработка, связанная с активным приложением с наивысшим приоритетом. Вся остальная предварительная обработка игнорируется.
Поскольку активное приложение может быть отключено при активации приложения с более высоким приоритетом, вы можете зарегистрировать метод AudioManager.AudioRecordingCallback для объекта AudioRecord
или MediaRecorder
, чтобы получать уведомления об изменении конфигурации. Возможные изменения:
- Захват с глушителем или без глушителя
- Устройство изменено
- Предварительная обработка изменена
- Изменены свойства потока (частота дискретизации, маска канала, формат выборки)
Перед началом захвата необходимо вызвать AudioRecord.registerAudioRecordingCallback()
. Обратный вызов выполняется только тогда, когда приложение получает аудио и происходит изменение.
Метод onRecordingConfigChanged()
возвращает AudioRecordingConfiguration
, содержащий текущее состояние аудиозахвата. Чтобы узнать об изменении, используйте следующие методы:
-
isClientSilenced()
- Возвращает значение true, если звук, возвращаемый клиенту, в настоящее время отключается из-за политики захвата.
-
getAudioDevice()
- Возвращает активное аудиоустройство.
-
getEffects()
- Возвращает активный эффект предварительной обработки. Обратите внимание, что активный эффект может отличаться от возвращаемых методом
getClientEffects()
если клиент не является активным приложением с наивысшим приоритетом. -
getFormat()
- Возвращает свойства потока. Обратите внимание, что фактические аудиоданные, получаемые клиентом, всегда соответствуют требуемому формату, возвращаемому функцией
getClientFormat()
. Фреймворк автоматически выполняет необходимую передискретизацию, преобразование каналов и форматов из формата, используемого на аппаратном интерфейсе, в формат, указанный клиентом. -
AudioRecord.getActiveRecordingConfiguration()
. - Возвращает активную конфигурацию записи.
Общий вид всех активных записей на устройстве можно получить, вызвав AudioManager.getActiveRecordingConfigurations()
.