오디오 입력 공유

일반적으로 오디오 입력은 내장 마이크, 외부 마이크 또는 기기에 연결된 오디오 인터페이스에서 제공됩니다. 전화 대화에서도 오디오가 입력될 수 있습니다.

두 개 이상의 앱이 동일한 오디오 입력을 '캡처'하려는 경우가 있습니다. 각 앱은 서로 다른 작업을 수행할 수 있습니다. 예를 들어 오디오를 수신하는 일부 앱은 간단한 음성 녹음기와 같이 '녹음' 중일 수 있고, 다른 앱은 Google 어시스턴트나 음성 명령에 응답하는 접근성 서비스와 같이 '듣기' 상태일 수 있습니다.

어느 경우에 해당하든 이런 앱들은 오디오 입력을 수신하고자 합니다. 이 페이지에서는 앱이 녹음 중인지 아니면 듣기만 하는지와 관계없이 '캡처'라는 용어를 사용합니다.

두 개 이상의 앱이 동시에 오디오를 캡처하려는 경우 동일한 소스에서 모든 앱으로 오디오 신호를 전달하는 데 문제가 발생할 수 있습니다. 이 페이지에서는 Android 시스템이 오디오를 캡처하는 여러 앱 간에 오디오 입력을 공유하는 방법을 설명합니다.

Android 10 이전 동작

Android 10 전에는 입력 오디오 스트림을 한 번에 하나의 앱에서만 캡처할 수 있었습니다. 일부 앱이 이미 오디오를 녹음하거나 듣고 있다면 앱에서 AudioRecord 객체를 만들 수 있지만 AudioRecord.startRecording()를 호출하면 오류가 반환되고 녹음이 시작되지 않습니다.

이 규칙의 한 가지 예외는 권한이 있는 앱 (예: Google 어시스턴트 또는 접근성 서비스)이 android.permission.CAPTURE_AUDIO_HOTWORD 권한을 보유하고 HOTWORD 유형의 오디오 소스를 사용하는 경우입니다. 이 경우에는 다른 앱이 녹음을 시작할 수 있습니다. 이러한 상황이 발생하면 권한이 있는 앱이 종료되고 새 앱이 입력을 캡처했습니다.

Android 9에는 한 가지 변경사항이 추가되었습니다. 포그라운드에서 실행되는 앱 (또는 포그라운드 서비스)만 오디오 입력을 캡처할 수 있습니다. 포그라운드 서비스 또는 포그라운드 UI 구성요소가 없는 앱이 캡처를 시작했을 때 앱은 계속 실행되었지만 그 당시에 오디오를 캡처하는 유일한 앱인 경우에도 무음을 수신했습니다.

Android 10 동작

Android 10 이전의 동작은 '선착순'입니다. 앱에서 오디오 캡처를 시작하면 오디오를 캡처하는 앱이 중지될 때까지 다른 앱은 오디오 입력에 액세스할 수 없습니다.

Android 10은 앱이 실행되는 동안 앱 간에 입력 오디오 스트림을 전환할 수 있는 우선순위 스키마를 적용합니다. 대부분의 경우 새 앱이 오디오 입력을 획득하면 이전에 캡처한 앱은 계속 실행되지만 무음을 수신합니다. 때에 따라 시스템은 두 앱 모두에 오디오를 계속 전달할 수 있습니다. 아래에서는 다양한 공유 시나리오를 설명합니다.

이 체계는 오디오 포커스가 오디오 출력 사용을 두고 경합하는 여러 앱을 처리하는 방식과 유사합니다. 그러나 오디오 포커스는 포커스를 획득하고 해제하기 위한 프로그래매틱 요청에 의해 관리되는 반면, 여기에서 설명하는 입력 전환 스키마는 새 앱이 오디오 캡처를 시작할 때마다 자동으로 적용되는 우선순위 지정 정책을 기반으로 합니다.

Android는 오디오 캡처 시 앱을 두 가지 종류로 구분합니다.

  • '일반' 앱은 사용자가 설치합니다.
  • '권한이 있는' 앱은 기기에 사전 설치되어 있습니다. 여기에는 Google 어시스턴트 및 모든 접근성 서비스가 포함됩니다.

또한 앱은 '개인 정보 보호에 민감한' 오디오 소스(CAMCORDER 또는 VOICE_COMMUNICATION)를 사용하는 경우에도 다르게 처리됩니다.

오디오 입력을 사용하고 공유할 때 우선순위를 지정하는 규칙은 다음과 같습니다.

  • 권한이 있는 앱은 일반 앱보다 우선순위가 높습니다.
  • 가시적인 포그라운드 UI가 있는 앱은 백그라운드 앱보다 우선순위가 높습니다.
  • 개인정보 보호에 민감한 소스에서 오디오를 캡처하는 앱은 그렇지 않은 앱보다 우선순위가 높습니다.
  • 두 개의 일반 앱이 동시에 오디오를 캡처할 수 없습니다.
  • 어떤 경우에는 권한이 있는 앱이 다른 앱과 오디오 입력을 공유할 수 있습니다.
  • 우선순위가 동일한 두 개의 백그라운드 앱이 오디오를 캡처할 경우, 마지막에 시작된 앱의 우선순위가 높습니다.

공유 시나리오

두 앱이 오디오를 캡처하려고 하면 둘 다 입력 신호를 수신할 수 있거나 둘 중 하나가 무음을 수신할 수 있습니다.

4가지의 주요 시나리오가 있습니다.

  • 어시스턴트 + 일반 앱
  • 접근성 서비스 + 일반 앱
  • 일반 앱 2개
  • 음성 통화 + 일반 앱

어시스턴트 + 일반 앱

어시스턴트는 사전 설치되어 있고 RoleManager.ROLE_ASSISTANT 역할을 보유하므로 권한이 있는 앱입니다. 이 역할을 가진 다른 사전 설치 앱은 모두 비슷하게 취급됩니다.

Android는 다음과 같은 규칙에 따라 입력 오디오를 공유합니다.

  • 개인 정보 보호에 민감한 오디오 소스를 사용하는 다른 앱이 이미 캡처하지 않는 한 어시스턴트는 오디오를 (포그라운드에 있든 백그라운드에 있든 관계없이) 수신할 수 있습니다.

  • 어시스턴트의 화면 상단에 UI 구성요소가 표시되어 있지 않으면 앱이 오디오를 수신합니다.

두 앱 모두 어시스턴트가 백그라운드에 있고 다른 앱이 개인 정보 보호에 민감한 오디오 소스에서 캡처하지 않을 때만 오디오를 수신합니다.

접근성 서비스 + 일반 앱

AccessibilityService에는 엄격한 선언이 필요합니다.

Android는 다음과 같은 규칙에 따라 입력 오디오를 공유합니다.

  • 서비스의 UI가 맨 위에 있으면 서비스와 앱 모두 오디오 입력을 수신합니다. 이 동작은 음성 명령으로 음성 통화 또는 동영상 캡처를 제어하는 등의 기능을 제공합니다.

  • 접근성 서비스가 위에 있지 않을 경우에는 아래의 일반 앱 2개와 같이 처리합니다.

일반 앱 2개

두 앱이 동시에 오디오를 캡처할 경우, 한 앱만 오디오를 수신하고 나머지 앱은 무음을 수신합니다.

Android는 다음과 같은 규칙에 따라 입력 오디오를 공유합니다.

  • 두 앱 모두 개인 정보 보호에 민감하지 않다면 UI가 맨 위에 있는 앱이 오디오를 수신합니다. 두 앱에 모두 UI가 없을 경우, 가장 최근에 캡처를 시작한 앱이 오디오를 수신합니다.
  • 앱 중 하나가 개인 정보 보호에 민감한 경우 상단에 UI가 있거나 더 최근에 캡처를 시작했더라도 오디오를 수신하고 다른 앱은 무음을 수신합니다.
  • 두 앱이 모두 개인 정보 보호에 민감하다면 가장 최근에 캡처를 시작한 앱이 오디오를 수신하고 다른 앱은 무음을 수신합니다.

음성 통화 + 일반 앱

AudioManager.getMode()에서 반환된 오디오 모드가 MODE_IN_CALL 또는 MODE_IN_COMMUNICATION이면 음성 통화가 활성 상태입니다.

Android는 다음과 같은 규칙에 따라 입력 오디오를 공유합니다.

Android 11 동작

Android 11 (API 수준 30)은 위에 설명된 Android 10 우선순위 스키마를 따릅니다. 또한 선택한 사용 사례와 관계없이 오디오를 동시에 캡처하는 기능을 사용 설정하거나 사용 중지하는 AudioRecord, MediaRecorder, AAudioStream의 새로운 메서드도 제공합니다.

새로운 메서드는 다음과 같습니다.

setPrivacySensitive()true이면 캡처 사용 사례가 비공개이며 권한이 있는 어시스턴트도 동시에 캡처할 수 없습니다. 이 설정은 오디오 소스에 따라 달라지는 기본 동작을 재정의합니다. 예를 들어 VOICE_COMMUNICATION는 기본적으로 비공개이지만 UNPROCESSED는 비공개가 아닙니다.

구성 변경

여러 앱이 동시에 오디오를 캡처하는 경우 앱 한두 개만 '활성' 상태(오디오 수신)가 되고 나머지 앱은 음소거 (무음 수신)됩니다. 활성 앱이 변경되면 오디오 프레임워크는 다음 규칙에 따라 오디오 경로를 재구성할 수 있습니다.

  • 각 활성 앱의 오디오 입력 장치가 변경될 수 있습니다 (예: 내장 마이크에서 연결된 블루투스 헤드셋으로).
  • 우선순위가 가장 높은 앱과 관련된 사전 처리가 활성화됩니다. 다른 모든 사전 처리는 무시됩니다.

우선순위가 높은 앱이 활성화되면 활성 앱이 음소거될 수 있으므로 AudioRecord 또는 MediaRecorder 객체에 AudioManager.AudioRecordingCallback을 등록하여 구성 변경 시 알림을 받을 수 있습니다. 가능한 구성 변경은 다음과 같습니다.

  • 캡처 음소거 또는 해제
  • 기기 변경
  • 사전 처리 변경
  • 스트림 속성 변경(샘플링 레이트, 채널 마스크, 샘플 형식)

캡처가 시작되기 전에 AudioRecord.registerAudioRecordingCallback()를 호출해야 합니다. 이 콜백은 앱이 오디오를 수신하고 변경이 있을 경우에만 실행됩니다.

onRecordingConfigChanged() 메서드는 현재 오디오 캡처 상태가 포함된 AudioRecordingConfiguration를 반환합니다. 변경사항에 대해 알아보려면 다음 메서드를 사용하세요.

isClientSilenced()
클라이언트로 반환된 오디오가 현재 캡처 정책으로 인해 음소거 중인 경우 true를 반환합니다.
getAudioDevice()
활성 상태의 오디오 기기를 반환합니다.
getEffects()
활성 전처리 효과를 반환합니다. 클라이언트가 우선순위가 가장 높은 활성 앱이 아닌 경우 활성 효과는 getClientEffects()에서 반환된 것과 동일하지 않을 수 있습니다.
getFormat()
스트림 속성을 반환합니다. 클라이언트에서 수신한 실제 오디오 데이터는 항상 getClientFormat()에서 반환된 필수 형식을 따릅니다. 프레임워크는 하드웨어 인터페이스에서 사용되는 형식에서 클라이언트가 지정한 형식으로 필요한 리샘플링, 채널, 형식 변환을 자동으로 실행합니다.
AudioRecord.getActiveRecordingConfiguration().
활성 녹음 구성을 반환합니다.

AudioManager.getActiveRecordingConfigurations()를 호출하여 기기의 모든 활성 녹화 파일을 전반적으로 확인할 수 있습니다.