音声入力の共有

通常、音声入力は、内蔵マイク、外部マイク、またはデバイスに接続されたオーディオ インターフェースから行われます。音声入力は、電話での会話から取得することもできます。

2 つ以上のアプリが同じ音声入力を「キャプチャ」しようとすることがあります。異なるタスクを実行している可能性があります。たとえば、音声を受信するアプリの中には、シンプルなボイス レコーダーのように「録音」するものもあれば、Google アシスタントや音声コマンドに応答するユーザー補助サービスのように「聞き取り」を行うものもあります。

いずれの場合も、これらのアプリは音声入力を受信する必要があります。このページでは、アプリが録音しているか、単にリッスンしているかにかかわらず、「キャプチャ」という用語を使用します。

2 つ以上のアプリが同時に音声をキャプチャしようとすると、同じソースからすべてのアプリに音声信号を配信する際に問題が発生する可能性があります。このページでは、Android システムが音声をキャプチャする複数のアプリ間で音声入力を共有する方法について説明します。

Android 10 より前の動作

Android 10 より前では、入力音声ストリームを一度にキャプチャできるのは 1 つのアプリだけでした。すでに別のアプリが音声を録音または聴取している場合、アプリは AudioRecord オブジェクトを作成できますが、AudioRecord.startRecording() を呼び出すとエラーが返され、録音は開始されません。

このルールの例外として、特権アプリ(Google アシスタントやユーザー補助サービスなど)が android.permission.CAPTURE_AUDIO_HOTWORD 権限を持ち、HOTWORD タイプの音声ソースを使用している場合がありました。この場合、別のアプリが録音を開始する可能性があります。その際、特権アプリが終了し、新しいアプリが入力内容をキャプチャしました。

Android 9 では、フォアグラウンドで実行されているアプリ(またはフォアグラウンド サービス)のみが音声入力をキャプチャできるという変更が追加されました。フォアグラウンド サービスまたはフォアグラウンド 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 つのアプリが同時にキャプチャしている場合、一方のアプリのみが音声を受信し、もう一方のアプリは無音になります。

Android は、次のルールに従って入力音声を共有します。

  • どちらのアプリもプライバシーに配慮していない場合、UI が最上位にあるアプリがオーディオを受信します。どちらのアプリにも UI がない場合、最後にキャプチャを開始したアプリがオーディオを受信します。
  • アプリの 1 つがプライバシーに配慮している場合、そのアプリがオーディオを受信し、もう一方のアプリは、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 は非公開ではありません。

構成の変更

複数のアプリが同時に音声をキャプチャしている場合、1 つまたは 2 つのアプリのみが「アクティブ」(音声を受信)になり、他のアプリはミュート(無音を受信)になります。アクティブなアプリが変更されると、オーディオ フレームワークは次のルールに従ってオーディオパスを再構成することがあります。

  • アクティブなアプリごとに、音声入力デバイスが変更されることがあります(内蔵マイクから接続された Bluetooth ヘッドセットへの変更など)。
  • 最も優先度の高いアクティブなアプリに関連付けられた前処理が有効になります。他の前処理はすべて無視されます。

優先度の高いアプリがアクティブになると、アクティブなアプリがサイレント モードになる可能性があるため、AudioRecord オブジェクトまたは MediaRecorder オブジェクトに AudioManager.AudioRecordingCallback を登録して、構成が変更されたときに通知を受け取ることができます。考えられる変更は次のとおりです。

  • キャプチャのミュートまたはミュート解除
  • デバイスが変更されました
  • 前処理が変更された
  • ストリーム プロパティの変更(サンプリング レート、チャンネル マスク、サンプル形式)

キャプチャを開始する前に AudioRecord.registerAudioRecordingCallback() を呼び出す必要があります。コールバックは、アプリが音声を受信し、変更が発生した場合にのみ実行されます。

onRecordingConfigChanged() メソッドは、現在の音声キャプチャ状態を含む AudioRecordingConfiguration を返します。変更について確認するには、次の方法を使用します。

isClientSilenced()
クライアントに返されたオーディオが、キャプチャ ポリシーにより現在ミュートされている場合は true を返します。
getAudioDevice()
アクティブなオーディオ機器を返します。
getEffects()
アクティブな前処理エフェクトを返します。クライアントが優先度の最も高いアクティブなアプリでない場合、アクティブなエフェクトは getClientEffects() によって返されるエフェクトと同じではない可能性があります。
getFormat()
ストリームのプロパティを返します。クライアントが受信する実際の音声データは、常に getClientFormat() から返される必要な形式に準拠します。フレームワークは、ハードウェア インターフェースで使用される形式からクライアントが指定した形式への必要なリサンプリング、チャンネル、形式の変換を自動的に実行します。
AudioRecord.getActiveRecordingConfiguration()
アクティブな録画構成を返します。

AudioManager.getActiveRecordingConfigurations() を呼び出すと、デバイス上のすべてのアクティブな録音の概要を取得できます。