音声入力の共有

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

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

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

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

Android 10 より前の動作

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

このルールの例外の 1 つは、特権アプリ(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 ヘッドセットなど)。
  • 優先度が最も高いアクティブなアプリに関連付けられている前処理が有効になっています。他のすべての前処理は無視されます。

優先度の高いアプリがアクティブになると、アクティブなアプリが消音になっている可能性があるため、AudioRecord または MediaRecorder オブジェクトに AudioManager.AudioRecordingCallback を登録して、構成が変更されたときに通知されるようにできます。考えられる変更は次のとおりです。

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

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

メソッド onRecordingConfigChanged() は、現在の音声キャプチャ状態を含む AudioRecordingConfiguration を返します。変更の詳細を確認するには、次の操作を行います。

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

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