音声入力の共有

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

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

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

2 つ以上のアプリで音声を同時にキャプチャする場合、同じソースからすべてのアプリへのオーディオ信号の配信に問題が発生する可能性があります。このページでは、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 つのアプリが同時に音声をキャプチャしている場合、一方のアプリは音声を受信し、もう一方のアプリは無音になります。

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 ヘッドセットなど)。
  • 優先度が最も高いアクティブなアプリに関連付けられた前処理が有効になります。その他の前処理はすべて無視されます。

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

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

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

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

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

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