오디오 입력 공유

일반적으로 오디오 입력은 내장 마이크, 외부 마이크 또는 기기에 연결된 오디오 인터페이스에서 들어옵니다. 오디오 입력은 전화 통화에서 가져올 수도 있습니다.

두 개 이상의 앱이 모두 동일한 오디오 입력을 '캡처'하려고 할 때가 있습니다. 각 앱은 서로 다른 작업을 수행할 수 있습니다. 예를 들어 오디오를 수신하는 일부 앱은 간단한 음성 녹음기와 같이 '녹음'하는 반면, 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()를 호출하면 기기에 활성화된 모든 녹음된 오디오를 전체적으로 확인할 수 있습니다.