音声入力は通常、内蔵マイク、外部マイク、デバイスに接続されたオーディオ インターフェースから行われます。音声入力は、電話での会話から取得することもできます。
2 つ以上のアプリが同じオーディオ入力を「キャプチャ」しようとすることがあります。異なるタスクを実行している可能性があります。たとえば、音声を受信するアプリの中には、単純な音声レコーダーのように「録音」するアプリもあれば、Google アシスタントや音声コマンドに応答するユーザー補助サービスのように「リッスン」するアプリもあります。
どちらの場合も、これらのアプリは音声入力を受け取る必要があります。このページでは、アプリが録音しているかどうかにかかわらず、「キャプチャ」という用語を使用しています。
複数のアプリが同時に音声をキャプチャする場合、同じソースからすべてのアプリに音声信号を配信する際に問題が発生する可能性があります。このページでは、Android システムが音声をキャプチャする複数のアプリ間で音声入力を共有する方法について説明します。
Android 10 より前の動作
Android 10 より前は、入力音声ストリームを一度にキャプチャできるのは 1 つのアプリだけでした。すでに音声を録音またはリッスンしているアプリがある場合、アプリは AudioRecord
オブジェクトを作成できますが、AudioRecord.startRecording()
を呼び出すとエラーが返され、録音は開始されません。
このルールの例外として、特権アプリ(Google アシスタントやユーザー補助サービスなど)が android.permission.CAPTURE_AUDIO_HOTWORD
権限を持ち、HOTWORD
タイプの音声ソースを使用している場合がありました。この場合、別のアプリが録画を開始する可能性があります。その場合、特権アプリは終了し、新しいアプリが入力をキャプチャします。
Android 9 では、もう 1 つの変更が加えられました。フォアグラウンドで実行されているアプリ(またはフォアグラウンド サービス)のみが音声入力をキャプチャできるようになりました。フォアグラウンド サービスまたはフォアグラウンド UI コンポーネントのないアプリがキャプチャを開始すると、そのアプリは引き続き実行されましたが、その時点で音声をキャプチャしている唯一のアプリであっても、無音が記録されました。
Android 10 での動作
Android 10 より前の動作は「先着順」です。アプリが音声のキャプチャを開始すると、音声をキャプチャしているアプリが停止するまで、他のアプリは音声入力にアクセスできなくなります。
Android 10 では、実行中のアプリ間で入力音声ストリームを切り替えることができる優先度スキームが適用されます。ほとんどの場合、新しいアプリが音声入力を取得すると、以前にキャプチャしていたアプリは引き続き実行されますが、無音を受け取ります。場合によっては、システムが両方のアプリに音声を引き続き配信することがあります。さまざまな共有シナリオについて説明します。
このスキームは、オーディオ出力の使用を競う複数のアプリをオーディオ フォーカスが処理する方法と似ています。ただし、音声フォーカスはフォーカスの取得と解放のプログラム リクエストによって管理されますが、ここで説明する入力切り替えスキームは、新しいアプリがオーディオの取得を開始するたびに自動的に適用される優先度ポリシーに基づいています。
音声をキャプチャする目的で、Android では次の 2 種類のアプリを区別しています。
- 「通常」のアプリはユーザーがインストールします。
- 「特権」アプリはデバイスにプリインストールされています。これには、Google アシスタントやすべてのユーザー補助サービスが含まれます。
また、アプリが「機密性の高い」音源(CAMCORDER
または VOICE_COMMUNICATION
)を使用している場合、アプリは異なる方法で処理されます。
音声入力の使用と共有に関する優先順位付けルールは次のとおりです。
- 特権アプリは通常のアプリよりも優先度が高くなります。
- フォアグラウンド UI が表示されているアプリは、バックグラウンド アプリよりも優先度が高くなります。
- プライバシーに配慮したソースから音声をキャプチャするアプリは、そうでないアプリよりも優先度が高くなります。
- 2 つの通常のアプリが同時に音声をキャプチャすることはできません。
- 状況によっては、特権アプリが音声入力を別のアプリと共有できます。
- 同じ優先度の 2 つのバックグラウンド アプリがオーディオをキャプチャしている場合、最後に開始されたアプリの優先度が高くなります。
共有シナリオ
2 つのアプリが音声をキャプチャしようとすると、両方のアプリが入力信号を受信できる場合もあれば、一方のアプリが無音を受信する場合もあります。
主なシナリオは次の 4 つです。
- アシスタント + 通常のアプリ
- ユーザー補助サービスと通常のアプリ
- 2 つの通常のアプリ
- 音声通話 + 通常のアプリ
アシスタント + 通常のアプリ
アシスタントはプリインストールされており、ロール RoleManager.ROLE_ASSISTANT
を保持しているため、特権アプリです。このロールを持つ他のプリインストール アプリも同様に扱われます。
Android は、次のルールに従って入力音声を共有します。
機密性の高い音源を使用している別のアプリがすでにキャプチャを行っていない限り、アシスタントは(フォアグラウンドまたはバックグラウンドにかかわらず)音声を受信できます。
アシスタントの UI コンポーネントが画面上部に表示されていない限り、アプリは音声を受信します。
なお、両方のアプリが音声を受信するのは、アシスタントがバックグラウンドにあり、他のアプリが機密性の高い音源からキャプチャしていない場合のみです。
ユーザー補助サービス + 通常のアプリ
AccessibilityService
には厳格な宣言が必要です。
Android は、次のルールに従って入力音声を共有します。
サービスの UI が最上位にある場合、サービスとアプリの両方が音声入力を受信します。この動作により、音声コマンドで音声通話や動画キャプチャを操作するなどの機能が提供されます。
サービスが最上位にない場合、このケースは以下の通常の 2 つのアプリのケースと同様に扱われます。
2 つの通常のアプリ
2 つのアプリが同時にキャプチャしている場合、1 つのアプリのみが音声を受信し、もう 1 つのアプリはサイレントになります。
Android は、次のルールに従って入力音声を共有します。
- どちらのアプリも機密性が高いものでない場合は、UI が上位にあるアプリが音声を受信します。どちらのアプリにも UI がない場合、最後にキャプチャを開始したアプリがオーディオを受信します。
- どちらかのアプリが機密性が高い場合、そのアプリが音声を受信し、UI が上位にある場合やキャプチャを開始したのが最近であっても、他のアプリは音声を受信しません。
- どちらのアプリも機密性が高い場合、最後にキャプチャを開始したアプリが音声を受信し、もう一方のアプリはサイレンスになります。
音声通話 + 通常のアプリ
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
は違います。
構成の変更
複数のアプリが音声を同時にキャプチャしている場合、1 つまたは 2 つのアプリのみが「アクティブ」(音声を受信)になり、他のアプリはミュート(無音を受信)になります。アクティブなアプリが変更されると、オーディオ フレームワークは次のルールに従ってオーディオ パスを再構成することがあります。
- アクティブなアプリごとに音声入力デバイスが変更されることがあります(内蔵マイクから接続された Bluetooth ヘッドセットなど)。
- 優先度が最も高いアクティブなアプリに関連付けられた前処理が有効になります。その他の前処理はすべて無視されます。
優先度の高いアプリがアクティブになると、アクティブなアプリがミュートされる可能性があるため、AudioRecord
または MediaRecorder
オブジェクトに AudioManager.AudioRecordingCallback を登録して、構成が変更されたときに通知を受け取ることができます。考えられる変更は次のとおりです。
- サイレントまたはサイレント解除の音声をキャプチャする
- デバイスの変更
- 前処理の変更
- ストリームのプロパティが変更された(サンプリング レート、チャンネル マスク、サンプル形式)
キャプチャを開始する前に AudioRecord.registerAudioRecordingCallback()
を呼び出す必要があります。コールバックは、アプリが音声を受信していて、変更が発生した場合にのみ実行されます。
メソッド onRecordingConfigChanged()
は、現在の音声キャプチャの状態を含む AudioRecordingConfiguration
を返します。変更内容については、次の方法で確認できます。
isClientSilenced()
- キャプチャ ポリシーが原因でクライアントに返される音声が現在無音になっている場合は true を返します。
getAudioDevice()
- アクティブなオーディオ デバイスを返します。
getEffects()
- アクティブな前処理エフェクトを返します。クライアントが優先度が最も高いアクティブなアプリでない場合、アクティブなエフェクトは
getClientEffects()
によって返されるエフェクトと同じではない場合があります。 getFormat()
- ストリームのプロパティを返します。クライアントが受信する実際の音声データは、常に
getClientFormat()
から返された必要な形式に従います。フレームワークは、ハードウェア インターフェースで使用される形式からクライアントが指定した形式への必要な再サンプリング、チャンネル、形式変換を自動的に実行します。 AudioRecord.getActiveRecordingConfiguration()
。- アクティブな録画構成を返します。
デバイスでアクティブなすべての録音の概要を取得するには、AudioManager.getActiveRecordingConfigurations()
を呼び出します。