音声入力の共有

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

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

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

複数のアプリが同時に音声をキャプチャしようとすると、同じソースからすべてのアプリに音声信号を配信する際に問題が発生する可能性があります。このページでは、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 つのアプリが同時にキャプチャしている場合、1 つのアプリのみが音声を受け取り、もう 1 つのアプリは無音になります。

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

  • どちらのアプリもプライバシーに配慮したアプリでない場合、UI が最上位にあるアプリがオーディオを受信します。どちらのアプリも UI がない場合、最後にキャプチャを開始したアプリがオーディオを受信します。
  • プライバシーが重要なアプリがある場合、そのアプリがオーディオを受信し、UI が最上位にあるアプリや、より最近キャプチャを開始したアプリであっても、もう一方のアプリは無音になります。
  • 両方のアプリがプライバシーに配慮している場合、最後にキャプチャを開始したアプリが音声を受信し、もう一方のアプリは無音になります。

音声通話 + 通常のアプリ

AudioManager.getMode() から返された音声モードが MODE_IN_CALL または MODE_IN_COMMUNICATION の場合、音声通話はアクティブです。

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

Android 11 の動作

Android 11(API レベル 30)では、上記の Android 10 の優先度スキームが適用されます。また、選択したユースケースに関係なく、音声を同時にキャプチャする機能を有効または無効にする AudioRecordMediaRecorderAAudioStream の新しいメソッドも提供します。

新しいメソッドは以下のとおりです。

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() を呼び出すことで、デバイス上のすべてのアクティブな録音の概要を取得できます。