Аудиовход обычно поступает со встроенного микрофона, внешнего микрофона или аудиоинтерфейса, подключенного к устройству. Аудиовход также может исходить от телефонного разговора.
Иногда два или более приложений могут захотеть «захватить» один и тот же аудиовход. Они могут выполнять разные задачи. Например, некоторые приложения, которые получают звук, могут «записывать», как простой диктофон, в то время как другие приложения могут «прослушивать», например, Google Assistant или служба специальных возможностей, реагирующая на голосовые команды.
В любом случае эти приложения хотят получать аудиовход. На этой странице мы используем термин «захват» независимо от того, записывает ли приложение или просто прослушивает.
Если два или более приложений хотят одновременно записывать звук, может возникнуть проблема с доставкой аудиосигнала из одного и того же источника всем им. На этой странице описывается, как система Android распределяет аудиовход между несколькими приложениями, записывающими звук.
Поведение до Android 10
До Android 10 входной аудиопоток мог захватываться только одним приложением одновременно. Если какое-то приложение уже записывало или прослушивало звук, ваше приложение могло бы создать объект AudioRecord
, но при вызове AudioRecord.startRecording()
будет возвращена ошибка, и запись не начнется.
Единственным исключением из этого правила был случай, когда привилегированное приложение (например, Google Assistant или служба специальных возможностей) имело разрешение android.permission.CAPTURE_AUDIO_HOTWORD
и использовало источник звука типа HOTWORD
. В этом случае другое приложение может начать запись. Когда это произошло, привилегированное приложение завершило работу, и новое приложение перехватило входные данные.
В Android 9 было добавлено еще одно изменение: только приложения, работающие на переднем плане (или службы переднего плана), могли захватывать аудиовход. Когда приложение без службы переднего плана или компонента пользовательского интерфейса переднего плана начало захватывать, приложение продолжало работать, но получало тишину, даже если это было единственное приложение, записывающее звук в тот момент.
Поведение Android 10
До Android 10 поведение было «первым пришел — первым обслужен». Как только приложение начинает захватывать звук, никакие другие приложения не смогут получить доступ к аудиовходу, пока приложение, записывающее звук, не остановится.
В Android 10 применяется схема приоритетов, которая позволяет переключать входной аудиопоток между приложениями во время их работы. В большинстве случаев, если новое приложение получает аудиовход, ранее записывающее приложение продолжает работать, но получает тишину. В некоторых случаях система может продолжать передавать звук в оба приложения. Ниже описаны различные сценарии совместного использования .
Эта схема аналогична тому, как фокус аудио обрабатывает несколько приложений, конкурирующих за использование аудиовыхода. Однако фокус звука управляется программными запросами на получение и освобождение фокуса, а описанная здесь схема переключения входов основана на политике определения приоритетов, которая применяется автоматически всякий раз, когда новое приложение начинает захватывать звук.
Для записи звука Android различает два типа приложений:
- «Обычные» приложения устанавливаются пользователем.
- «Привилегированные» приложения предварительно установлены на устройстве. К ним относятся Google Assistant и все службы специальных возможностей.
Кроме того, приложение обрабатывается по-разному, если оно использует источник звука, «чувствительный к конфиденциальности»: 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()
.