オーディオセッションプログラミングガイド 日本語訳 本文編
Audio Session Programming Guide オリジナルです
Introduction
iOS, tvOS, watchOSの役割の中に、オーディオ管理があります。システムはオーディオセッション( AVAudioSession
)を使用することで、(単独の)アプリ、複数のアプリ間、デバイスレベル(ハードウェア寄りの領域)でオーディオの動作を管理します。
図 システム全体
図やソースコードはこちらの日本語訳に載せません。オリジナルのページを見て下さい。
あなたのアプリでオーディオをどのように使うかを、オーディオセッションを使ってシステムに伝えます。オーディオセッションは、アプリとオペレーティングシステムの仲介役として機能します。さらに(アプリから見て)その先にあるオーディオハードウェアとの仲介役にもなります。それを使って、あなたのアプリのオーディオの性質をオペレーティングシステムに伝えますが、具体的な動作やオーディオハードウェアとの必要なやり取りを詳述する必要がありません。このような管理をオーディオセッションに任せることで、ユーザーのオーディオ体験を最適にすることができます。
At a Glance
AVAudioSession
のインスタンスを使って次のことが出来ます。(それぞれはこの資料を通して詳しくやります)
- オーディオセッションのカテゴリとモードを設定し、アプリでオーディオをどのように使用するかをシステムに伝えます
- カテゴリとモードの設定を有効にするために、アプリのオーディオセッションをアクティブにします
- オーディオセッションに関する通知(notification)を設定して受信できるようにします。通知の種類は、(他のアプリの)再生の割り込みや、オーディオ経路の変更など。
- サンプルレートの設定、I/Oバッファによる待ち時間、チャンネル数の設定など、オーディオデバイスの高度な設定をします
An Audio Session Manages Audio Behavior
オーディオセッションは、アプリとオペレーティングシステム間の仲介役で、アプリのオーディオ動作を設定するために使用されます。アプリを起動すると、自動的にシングルトンオーディオセッションが提供されます。(使い方は)オーディオセッションに必要な設定をして、設定を有効にするためにオーディオセッションをアクティブにします。
Categories Express Audio Roles
オーディオの振る舞いを決めるための基本の設定が、オーディオセッションカテゴリです。カテゴリは以下のことを設定します(一部です)。
- アプリが入力経路と出力経路のどちら(or 両方)を使うか
- オーディオと一緒に音楽を再生し続けるか(ここでは、自分のアプリの効果音と他のアプリのBGMのことかと思われる)
カテゴリの指定によって決まる挙動は、ユーザーの期待に応えるものでなければなりません。内容はiOS Human Interface GuidelinesのAudioで説明されています。
(AVAudioSessionが含まれている)AVFoundation(最近ではAVFAudioも可)は、多くのオーディオセッションカテゴリを定義しています。さらに(カテゴリを補うように)モードとオプションという追加の設定があります。これらによってアプリの個性や役割に応じてオーディオの動作をカスタマイズできるようにしています。カテゴリには再生、録音、録音付き再生をサポートするものがあり、システムが(カテゴリ設定によって)あなたのアプリのオーディオの役割を認識すると、ハードウェアリソース(録音ありなら入力装置、再生ありなら出力装置)への適切なアクセスを提供します。システムはまた、デバイス上の他のアプリのオーディオが、あなたのアプリに適した方法で動作し、ユーザーの期待に沿うようにします。
カテゴリによっては、モードを指定することでさらにカスタマイズすることができます。例えば、アプリがビデオ録画モードを使用する場合、システムはデフォルトモードを使用する場合とは異なる内蔵マイクを選択するかもしれません(撮影方向にあるマイクを使用するということらしい)。システムはまた、ビデオ録画向けに調整されたマイク信号処理を行うかもしれません(小さい音、大きい音などを補正することやマイクの指向性などかと思われる)。
Notifications Support Interruption Handling
(interruptionという言葉をこういう意味で使いますよという宣言)
audio interruptionとは、あなたのアプリのオーディオセッションが非アクティブ化され、あなたのオーディオが即座に停止することです。
interruptionが発生するのは、競合するアプリのオーディオセッションがアクティブになり、そのオーディオセッションがあなたのオーディオセッションとミックスされない(かつ、あなたのアプリが負ける)とシステムによって判断された場合です。このときあなたのアプリは、状態を保存したり、ユーザーインターフェイスを更新するなどして、interruptionに対応する必要があります。interruptionの開始と終了で通知を受けるには、AVAudioSessionInterruptionNotification
or interruptionNotification
(新) の通知を受けるようにします。
Notifications Support Audio Route Change Handling
ユーザーが、(何かへの)デバイス装着のオンオフ、またはヘッドセットの抜き差しによってオーディオルートの変更を開始する場合、どういう挙動になるかを想定しています。iOSヒューマンインターフェイスガイドラインはこれらの期待について説明し、それらに従う方法についてのガイドラインを提供します。ルート変更を処理するには次の通知を受信するように登録してください。AVAudioSessionRouteChangeNotification
or routeChangeNotification
(新)
Audio Sessions Control Device Configuration
アプリはデバイスのハードウェアを直接コントロールすることはできませんが、オーディオセッションによって、好みのハードウェアデバイス設定が要求できます。この仲介機能により、サンプルレート、I/Oバッファによる待ち時間、オーディオチャンネル数など、高度なオーディオデバイス設定を行うことができます。
Audio Sessions Protect User Privacy
音声を録音するアプリ(音声単独、またはビデオとの組み合わせ)は、録音の前にユーザーの明示的な許可を得る必要があります。ユーザーがアプリに録音許可を与えるまで、アプリが録音するものは無音です(要確認)。AVAudioSessionはこの許可を求めるインターフェース(画面の真ん中に出てくるやつ)を提供し、ユーザーのプライバシー設定を決定できます。
Configuring an Audio Session
オーディオセッションカテゴリは、アプリのオーディオ動作を決定する鍵です。カテゴリを設定することでオーディオの意図をシステムに示すことができます。例えばRinger/Silentスイッチ(マナーモードスイッチ)が操作されたときにオーディオを継続するかどうかなどです。複数のオーディオセッションカテゴリと、モード、オプションを使えば、アプリのオーディオ動作をカスタマイズできます。
Table B-1に表示されているように、カテゴリによって決定する挙動には次のものがあります。
- ミキシング不可能な他のアプリのオーディオを中断するかどうか: Yesの場合、あなたのアプリがオーディオセッションをアクティブにすると、ミックス不可能な他のアプリのオーディオが中断されます。
- サイレントスイッチで無音になるかどうか: Yesの場合、ユーザーがSilentスイッチを作動させると、音声が消されます(iPhoneの場合、このスイッチはRing/Silentスイッチ(or マナーモードスイッチ)と呼ばれます)。
- 音声入力を使うかどうか: Yesの場合、アプリのオーディオ入力(録音)が許可されます。
- 音声出力を使うかどうか: Yesの場合、アプリのオーディオ出力(再生)が許可されます。
ほとんどのアプリは、カテゴリの設定は起動時の一度だけでよいです。ただ、変更の必要があれば途中で変更してもかまいません。変更はオーディオセッションがアクティブな間でもできますが、一度オーディオセッションを非アクティブにしてから、カテゴリや他のオーディオセッションプロパティを変更するのが望ましいです。オーディオセッションが非アクティブになっている間にこれらの変更をすることで、オーディオシステムの不必要な再構成を防ぐことができます。
Audio Session Default Behavior
iOS、tvOS、watchOSのすべてのアプリには、デフォルトのオーディオセッションがあり、以下のようにあらかじめ設定されています。
- 再生はサポートされているが、録音は禁止されている。
- iOSでは、Ring/Silentスイッチ(マナーモードスイッチ)をサイレントモードに設定すると、アプリが再生している音声はすべて無音になる。
- iOSでは、デバイスがロックされると、アプリの音声は消される。
- あなたのアプリがオーディオを再生すると、他のバックグラウンドオーディオ(ミュージックアプリが再生しているオーディオなど)は消される(相手がmixWithOthers=ONの場合を要確認)。
デフォルトのオーディオセッションは便利な動作をしますが、ほとんどの場合、アプリのニーズに合わせてカスタマイズする必要があります。動作を変更するには、アプリのオーディオセッションを設定します。
Configuring Your Audio Session
オーディオセッションを設定する基本の方法は、カテゴリーを設定することです。オーディオセッションの各カテゴリは、オーディオの動作に関する複数の挙動をまとめて定義しています。各カテゴリーに関連する正確な動作は、あなたのアプリの制御下にはなく、オペレーティングシステムによって設定されます。AppleはOSの将来のバージョンでカテゴリの動作を改良する可能性があるので、あなたが望むオーディオ動作の意図を最も正確に表すカテゴリを選ぶのが、最善の戦略です。Audio Session Categories and Modes に、各カテゴリの動作の詳細がまとめられています。
カテゴリはアプリの基本的なオーディオ動作を設定しますが、カテゴリのモードを設定することで、カテゴリの動作をさらに特殊化することができます。例えば、AVAudioSessionCategoryPlayAndRecord
カテゴリを使用したVoIPアプリは、オーディオセッションのモードを AVAudioSessionModeVoiceChat
に設定することで、VoIPアプリ用にこのカテゴリの動作を特殊化できます。このモードは、システムが提供する信号処理によって、信号が音声用に最適化されることを保証します。
特定のカテゴリは、カテゴリオプションを設定することで、デフォルトの動作を上書きすることができます(AVAudioSessionCategoryOptions を参照)。例えば、AVAudioSessionCategoryPlayback
カテゴリのデフォルトの動作は、オーディオセッションがアクティブ化されるとき、他のシステムオーディオを中断します。ほとんどの場合、再生アプリはこの動作が適しています。しかし、オーディオを他のシステムオーディオとミックスしたい場合は、AVAudioSessionCategoryOptionMixWithOthers
オプションを設定することで、挙動を上書きし、他のオーディオと混ぜることができます。
オーディオセッションカテゴリーとモードとオプションを設定するには、リスト 1-1 で示されるように、 setCategory:mode:options:error:
メソッドを呼び出します。
Listing 1-1
Expanding Options Using the Multiroute Category
(カテゴリのひとつである)マルチルート・カテゴリは、他のカテゴリとは若干異なる働きをします。他のすべてのカテゴリは、入力または出力ルートが複数ある場合、採用するルートの決定方法として、「最後に接続されたデバイスが勝つ」ルールに従います。しかし、マルチルート・カテゴリでは、接続されているすべての出力ポートをアプリが使用できるようになります。例えば、HDMI出力ルートでオーディオを聴いているときにヘッドホンを接続すると、アプリはHDMI出力ルートでオーディオを再生しながら、ヘッドホンでもオーディオを再生し続けます。
マルチルートカテゴリを使えば、オーディオソースを複数持ったアプリは、それぞれを異なる出力ルートに送ることもできます。例えば、1つのオーディオソースを左ヘッドフォンに送り、もう1つを右ヘッドフォンに、そして3つ目をHDMIルートに送ることができます。Figure 1-1に、複数のオーディオソースを異なるオーディオ出力に送る例を示します。
Figure 1-1
有効な出力ルートの組み合わせは以下の通りです。
ただし、デバイスと、接続されているアクセサリーによります。
- USBとヘッドフォン
- HDMIとヘッドフォン
- ラインアウトとヘッドフォン
マルチルートカテゴリーは、単一の入力ポートの使用が可能です(要確認)。
重要:内蔵スピーカーは、他の対象出力ポート(USB、HDMI、LineOut)が接続されていない場合にのみ使用できます。
Choosing Categories and Modes for AirPlay
AirPlayをサポートするのは特定のカテゴリーとモードに限定されます。
AirPlayのミラーリング版と非ミラーリング版の両方をサポートするのが次の3つのカテゴリです。
- AVAudioSessionCategorySoloAmbient
- AVAudioSessionCategoryAmbient
- AVAudioSessionCategoryPlayback
AirPlayのミラーリング版のみのサポートになるのがAVAudioSessionCategoryPlayAndRecord
カテゴリ、かつ次のモードに設定した場合です。
- AVAudioSessionModeDefault
- AVAudioSessionModeVideoChat
- AVAudioSessionModeGameChat
Note:
iOS10から、AVAudioSessionCategoryPlayAndRecord
カテゴリを使用していても、非ミラーリング AirPlay 出力を有効にすることができます。次の方法を行ってください。AVAudioSessionCategoryOptionAllowAirPlay
オプションを設定してから、オーディオセッションをアクティブにする。
Enabling Background Audio
iOSとtvOSのアプリは、バックグラウンド操作のためにその機能を有効にする必要があります。通常、再生アプリに求められる機能は、バックグラウンドオーディオの再生です。この機能を有効にすると、ユーザーが別のアプリに切り替えたり、iOSデバイス(の画面)をロックしたりしても、アプリのオーディオを継続できます。この機能は、AirPlayストリーミングやiOSのピクチャ・イン・ピクチャ再生などの高度な再生機能を有効にするためにも必要です。
これらの機能を設定する最も簡単な方法は、Xcodeを使用することです。Xcodeでアプリのターゲットを選択し、Capabilitiesタブを選択します。「+ Capabilities」ボタンで設定箇所を追加してから、Background Modesスイッチをオンに設定し、利用可能なモードのリストからAudio, AirPlay, and Picture in Pictureオプションを選択します。
Xcodeの図
このバックグラウンドモードを有効にし、オーディオセッションに適切なカテゴリを設定すれば、アプリはバックグラウンドオーディオを再生する準備が整います。
Note:
ビデオプレゼンテーションのオーディオ部分をバックグラウンドで再生するには、『メディア再生プログラミングガイド』の「バックグラウンドオーディオの再生」を参照してください。
Activating an Audio Session
(ここまでの話で)オーディオセッションのカテゴリ、オプション、モードを設定しました。設定を有効にするには、オーディオセッションをアクティブにする必要があります。
How the System Resolves Competing Audio Demands
アプリが起動すると、標準アプリ(メッセージ、ミュージック、Safari、電話)がバックグラウンドで動作している可能性があります。これらのアプリは音を発生するかもしれません。例えば
- テキストメッセージが届く
- 10分前に始めたポッドキャストの再生が続く
など
デバイスを空港に見立てると、アプリは誘導される飛行機になり、システムは管制塔の役割をします。あなたのアプリはリクエストを投げ、優先扱いの希望を表明することができますが、滑走路で何が起こるかについての最終的な権限はシステムが持っています。あなたはオーディオセッションを使って管制塔と通信します。Figure 2-1は、典型的な例を示しています。つまり、ミュージック・アプリがすでに再生中のときに、あなたのアプリ(MyApp)がオーディオの使用を要求している場合です。この例では、あなたのアプリ(MyApp)はミュージック・アプリに割り込みます(そしてあなたのアプリが勝つ)。
Figure 2-1 システムは競合するオーディオ要求を管理する
図のステップ1(赤丸の1)で、アプリ(MyApp)はオーディオセッションのアクティブ化を要求します。このようなアクティブ化リクエストは、アプリの起動時や、オーディオ録音・再生アプリでユーザーが再生ボタンをタップした時などに行います。
セリフ1「Core Audio、こちらMyApp。アクティブ化を希望します」
ステップ2(赤丸の2)で、システムはアクティブ化リクエストを検討します。具体的には、オーディオセッションに割り当てたカテゴリを検討します。Figure 2-1では、アプリ(MyApp)は、他のオーディオを消音する必要があるカテゴリを使用しています(図には明記されてないが)。
ステップ3と4で、システムはミュージックアプリのオーディオセッションを非アクティブにし、オーディオ再生を停止します。
セリフ3「ミュージックアプリ、こちらCore Audio。そちらのオーディオセッションを非アクティブにした」
セリフ4「私は非アクティブになった」
最後にステップ5で、システムがアプリ(MyApp)のオーディオセッションをアクティブにし、再生が開始できるようになります。
セリフ5「MyApp、こちらCore Audio。あなたのオーディオセッションはアクティブ化が完了した。」
Activating and Deactivating Your Audio Session
AVFoundation
の再生クラスと録音クラスは(オーディオ動作開始時に)自動的にオーディオセッションをアクティブにしますが、アクティブ指令を手動で行うことで、アクティブ化が成功したかどうかの結果を知ることができます。ただし、アプリに再生/一時停止のUI要素がある場合は、ユーザーが再生を押してからオーディオセッションがアクティブになるようにコードを書いてください(裏で先に鳴っているものを出来るだけ引き伸ばす)。同様に、オーディオセッションのアクティブ/非アクティブの状態を変更するときは、呼び出しが成功したかどうかを確認して下さい。システムがセッションをアクティブにすることを拒否したときに、きちんと対処するようにコードを書いてください。
時計やカレンダーのアラーム、または電話の着信に対して、システムは(邪魔になるアプリの)オーディオセッションを非アクティブにします。ユーザーがアラームを解除したり、電話の着信を無視したりすると、システムは中断されたオーディオセッションのアクティブ化を許可できる状態になります。中断の終了時にセッションを再アクティブ化するかどうかは、アプリの種類によって異なります。詳細はAudio Guidelines By App Type
Listing 2-1
オーディオセッションを非アクティブにするには、setActiveメソッドにfalseを渡します。
AVFoundationオブジェクト(AVPlayer、AVAudioRecorderなど)でオーディオを再生または録音する場合、中断終了時にオーディオセッションの再アクティブ化はシステムが行います(要確認)。しかし、通知の登録をして通知メッセージを受け取り、明示的にオーディオセッションを再アクティブ化すれば、再アクティブ化が成功したことを確認でき、アプリの状態とユーザーインターフェースを更新することができます。詳細については、Figure 3-1 を参照してください。
多くのアプリは、オーディオセッションを明示的に停止する必要はありません。重要な例外は、VoIPアプリ、仕事をするのは交差点だけのナビゲーションアプリ(アプリ起動時間に対してオーディオを使用する時間が短い)、そして場合によっては再生アプリや録音アプリなどです(例?要確認)。
- 通常バックグラウンドで実行される VoIP アプリのオーディオ・セッションは、アプリが通話を処理している間だけアクティブになるようにします。バックグラウンドで通話を受ける準備中の状態では、VoIPアプリのオーディオ・セッションをアクティブにすべきではありません。
- 録音カテゴリを使用するアプリのオーディオセッションは、録音中のみアクティブになるようにします。録音を開始する前と終了した後は、セッションが非アクティブになるようにして、メッセージの着信アラートなど、他のサウンドを再生できるようにします。
- バックグラウンドでのオーディオ再生または録音をサポートしているアプリがバックグラウンドに入る時点でオーディオを使用していない(またはオーディオを使用する準備をしている?いない?訳判断迷い)場合は、オーディオセッションを非アクティブにします。そうすることで、システムがオーディオリソースを解放し、他のプロセスで使用できるようになります。また、アプリのオーディオセッションのプロセス中にオペレーティングシステムによって非アクティブにされるのを防ぎます(AVAudioSessionInterruptionWasSuspendedKeyを参照)。
Checking Whether Other Audio Is Playing
アプリがアクティブになった時、デバイスでは既にサウンドが再生されているかもしれません。例えば、ユーザーがアプリを起動したとき、ミュージックアプリが曲を再生しているかもしれませんし、Safariがオーディオをストリーミングしているかもしれません。他のオーディオが再生されているかどうかを知ることは、アプリがゲームの場合、特に重要です。多くのゲームには、効果音だけでなく音楽サウンドトラックがあります。iOS Human Interface Guidelines(iOSヒューマンインターフェイスガイドライン)のオーディオでは次のようにアドバイスしています。ユーザーが継続された他のオーディオとゲームの効果音を一緒に鳴らしてゲームを行うこと期待していることを想定しましょう。
アプリデリゲートの applicationDidBecomeActive: メソッドで、オーディオセッションの secondaryAudioShouldBeSilencedHint プロパティ調べ、(他の)オーディオが既に再生されているかどうかを確かめます。この値は、他のアプリが、ミキシング不可能なオーディオセッションでオーディオを再生している場合にtrueになります。アプリはこのプロパティをヒントとして使用し、アプリの機能にとって重要でない自分のBGMを無音にすることが出来ます。例えば、AVAudioSessionCategoryAmbientを使用しているゲームは(自分の)サウンドトラックをミュートするかどうかをこのプロパティを使用して判断し、(それとは別に)効果音は必ず出す、ということが出来ます。
また、AVAudioSessionSilenceSecondaryAudioHintNotification の通知を購読することで、(下にある別アプリの音のON/OFFの挙動を)アプリに確実に通知して、自分のアプリの補助的なオーディオのミュートを開始または終了できます(下のアプリの音が消えたら自分のアプリで重要さがあまりない音を出す)。この通知は、現在フォアグラウンドにあり、アクティブなオーディオセッションを持っている登録リスナーのみに送信されます。
コード
この通知の userInfo 辞書には、AVAudioSessionSilenceSecondaryAudioHintTypeKey の AVAudioSessionSilenceSecondaryAudioHintType 値(begin or end)が含まれています。自分のアプリの補助的なオーディオのミュートを開始するか終了するかを決定するために、オーディオヒントタイプを使用します。
Responding to Interruptions
オーディオセッションのコードに、割り込み(interruption)に対応する部分を追加することで、次のような状況でもアプリのオーディオがきちんと動作し続けるようになります。
- 電話がかかってきた
- 時計やカレンダーのアラームが鳴った
- 他のアプリがオーディオセッションをアクティブにした
オーディオの割り込み(interruption)とは、アプリのオーディオセッションが非アクティブになり、オーディオが即座に停止することです。割り込み(interruption)は、競合するアプリのオーディオセッションがアクティブになった場合に発生します。ただし、そのセッションはあなたのセッションとミックスされないとシステムが判断した場合です。あなたのセッションが非アクティブになった後、システムは "あなたは中断されました" というメッセージを送信します。それに反応することによって、アプリの状態を保存したり、ユーザーインターフェイスを更新したりすることができます。
割り込みが発生した後にはアプリが保留(suspended)されることがあります。これは、ユーザーが電話を受けたときに発生します(suspendedはアプリのライフサイクルのsuspendedかと)。ユーザーが通話を無視した場合、またはアラームを消した場合、システムは「中断終了」メッセージを発行し、アプリは実行を継続します。オーディオを再開するには、オーディオセッションを再アクティブ化する必要があります。
The Interruption Life Cycle
Figure 3-1 は、再生アプリのオーディオセッションの中断前、中断中、中断後という一連のイベントの流れを示しています。
Figure 3-1
割り込みイベント(この例ではFaceTimeリクエストの到着)は以下のように進行する。工程の番号は図の番号に対応する。
- あなたのアプリがオーディオセッションがアクティブになり、オーディオが再生されます。
- FaceTimeリクエストが届く。システムはFaceTimeアプリのオーディオセッションをアクティブにする。
- システムがあなたのアプリのオーディオセッションを非アクティブにします。この時点で、あなたのアプリでのオーディオの再生は停止されてます。
- システムは、あなたのセッションが非アクティブにされたことを示す通知をあなたのアプリに送信します。
- あなたは通知に対応しては適切なアクションを取ります。例えば、ユーザーインターフェイスを更新したり、必要な情報を保存して再生を停止した地点からまた再開できるようにします。
- ユーザーが中断を解除した場合、つまりFaceTimeの着信要求を無視した場合、システムは中断が終了したことを示す通知をあなたのアプリに送信します。
- その通知に対応し、中断の終了に適切なアクションを取ります。例えば、ユーザーインターフェースの更新、オーディオセッションの再アクティブ化、オーディオ再生の再開などです。
- (図には示されていませんが) ステップ6で中断を解除する代わりに、ユーザーが電話を受けると、アプリはsuspended(アプリの状態を表す専門用語と思うので訳さない)されます。
Audio Interruption Handling Techniques
割り込みを処理するには、AVAudioSessionによる割り込み通知を利用してください(昔は他にもやり方があったので注意している)。割り込み対応コードの中で何をするかは、使用するオーディオ技術や使用する目的によって異なります。目的とは、再生、録音、オーディオフォーマットの変換、ストリームオーディオパケットの読み込みなどです。一般的に言えば、UXの観点から、可能な限り最小限の中断と、可能な限り感じのよい回復を保証する必要があります。
Table 3-1 は、中断の適切な動作をまとめたものです。AVFoundation再生または録音オブジェクトを使用する場合、これらの一部はシステムによって自動的に処理されます。
Table 3-1 オーディオセッションの中断でやるべきこと
タイミング | やること |
---|---|
中断の開始 | 状態と状況を保存 ユーザーインターフェースの更新 |
中断の終了 | 状態と状況の復元 ユーザーインターフェースの更新 必要であれば、オーディオセッションを再開 |
Table 3-2は、技術に応じたオーディオ中断の処理方法をまとめたものです。詳細を説明をこの章の残りでします。
Table 3-2 オーディオ技術に応じたオーディオ中断処理内容
技術 | 中断の仕組み |
---|---|
AVFoundation framework | 中断時に再生/録音を自動的に一時停止します。(復帰後の)再生または録音を再開するときにオーディオセッションを(自動で)アクティブ化します。アプリの終了時に再生位置を保存して次の起動で再生位置を復元する場合、アプリの終了時と同様に中断時も再生位置を保存してください。 |
Audio Queue Services I/O audio unit |
中断の処理をコントロールするのはあなたのアプリです(要確認)。再生または録音位置の保存や中断終了後のオーディオセッションの再アクティブ化は再開はあなたの責任です。 |
System Sound Services | システムサウンドサービスを使用して再生されたサウンドは、中断が始まると無音になります。中断が終了すると、サウンドは再び再生されます(要確認)。システムサウンドサービスを使用するサウンドの中断動作に、あなたのアプリが影響を与えることはできません。 |
Handling Interruptions from Siri
Siriがアプリのオーディオ再生を中断したとき、中断されている間にSiriが発行した指令を記録しておく必要があります。中断中は、Siriが発行した指令を記録し、中断が終了したら、それに対応します。例えば、中断中にユーザーがSiriにアプリのオーディオ再生の一時停止を依頼したとします。中断が終了したことがアプリに通知されたとき、再生は自動的に再開してはいけません。また、アプリのUIは、アプリが一時停止状態にあることを示す必要があります。
Observing Audio Interruptions
オーディオの割り込みを処理するには、AVAudioSessionInterruptionNotification or interruptionNotification(新) 型の通知を監視するように登録することから始めます。
コード
送られてきたNSNotificationインスタンスには、割り込みの詳細を提供するuserInfo辞書が含まれています。割り込みのタイプは、userInfo辞書からAVAudioSessionInterruptionType値を取得することでわかります。割り込みタイプとは、中断が開始されたのか終了したのかです。
コード
割り込みタイプが AVAudioSessionInterruptionTypeEnded の場合、userInfo 辞書は AVAudioSessionInterruptionOptions 値を含むかもしれません。AVAudioSessionInterruptionOptionShouldResumeという値は、中断されたとき(中断開始時のこと)に再生中だった場合、アプリが(中断終了時に)自動的に再生を再開するかどうかを判断するヒントになります。メディア再生アプリは、中断後に再生を開始する前に、常にこのフラグを調べる必要があります。このフラグがない場合、ユーザーによって開始されるまで再生は再開してはいけません。ただし、ゲームなどの再生操作インターフェースを表示しないアプリは、このフラグを無視して、中断が終了したときにBGMの再生を再開してもよいでしょう。
Note:
開始割り込みに対応する終了割り込みがあるという保証はありません。アプリは、フォアグラウンドのへの切り替わりや、ユーザーが再生ボタンを押したことを認識する必要があります。いずれの場合も、アプリがオーディオセッションを再アクティブ化すべきかどうかを判断します。(次のような設計は避ける。割り込み終了待ちという状態を持ち、割り込み終了が来るまで何も出来ない。)
Responding to a Media Server Reset
メディアサーバーは、オーディオやその他のマルチメディア機能を共有のサーバープロセスを通じて提供します(ざっくりとOSのメデイア担当部分?)。まれですが、アプリがアクティブな間にメディアサーバーがリセットされる可能性があります。メディアサーバーのリセットを監視するには、AVAudioSessionMediaServicesWereResetNotification 通知に登録します。通知を受信した後、アプリは以下を行う必要があります:
- 宙ぶらりんになったオーディオオブジェクト(プレーヤー、レコーダー、コンバーター、オーディオキューなど)を破棄し、新しいオブジェクトを作成する。
- アプリ内部で管理しているオーディオの状態や、AVAudioSession のすべてのプロパティをリセットする
- 必要に応じて、setActive:error: メソッドを使用してAVAudioSessionインスタンスを再アクティブ化します。(自動でアクティブ化する技術を使っている場合は除く)
重要:
アプリは次のことをする必要はありません。
- AVAudioSessionの通知のための再登録
- AVAudioSessionプロパティのKey-Valueオブザーバーのリセット
(Resetより前の段階の)メディアサーバーが利用できなくなった段階でそれを知りたい場合は、AVAudioSessionMediaServicesWereLostNotification 通知に登録することもできます。しかし、ほとんどのアプリはリセット通知に応答するだけでよいです。メディアサーバーが失われ(Lost)てから、メディアサーバーがリセットされるまでの間に、アプリがユーザーイベントに応答する必要がある場合にのみ、Lost通知を使用してください。
Note:
デバイスの[設定]の[開発者]メニューから[メディアサービスのリセット]を選択すると、メディアサーバーのクラッシュと再起動を(模擬?)実行できます。この機能を使用すると、メディアサービスがリセットされた場合にアプリが適切に応答するかどうかを簡単に確認できます。
Responding to Route Changes
アプリの実行中に、ユーザーがヘッドセットを抜き差ししたり、オーディオ接続のあるドッキングステーションを使用したりするかもしれません。アプリがこのようなイベントにどのように対応すべきかをiOS Human Interface Guidelinesで説明しています。推奨事項を実装するには、オーディオ・ハードウェア・ルートの変更を処理するコードをオーディオセッションを使って記述します。ゲームのような特定のタイプのアプリは、常にルート変更に応答する必要があるというわけではありません(意図を要確認)。しかし、メディアプレーヤーのような他のタイプのアプリは、すべてのルート変更に応答する必要があります。
Varieties of Audio Hardware Route Change
オーディオ信号を送る電気経路をオーディオハードウェアルートといいます。ユーザーがデバイスのヘッドセットを差し込んだり外したりすると、システムは自動的にオーディオハードウェアルートを変更します。アプリがそのような変更の通知を受けるにはAVAudioSessionRouteChangeNotification or routeChangeNotification(新)の監視を登録します。
Figure 4-1 は、録画と再生に関する様々なルート変更イベントのパターンを示しています。イベントに対してあなたは適切な処理を書き、その起こりうる結果が図の下側部分に示した4つの結果になります。
Figure 4-1 オーディオ・ハードウェアのルート変更への対応
図に示すように、システムはアプリの起動後、最初にオーディオルートを決定します。アプリの実行中は、システムはアクティブなルートを監視し続けます。
まず、図の左側にある "Recording starts "で表される、ユーザーがアプリの録音ボタンをタップした場合を考えましょう。録音中、ユーザーはヘッドセットのプラグを差し込んだり抜いたりすることがあるかもしれません(図の左下にある菱形の判断分岐要素を参照)。これが起こると、システムはルート変更通知を送信します。そこには変更の理由と以前のルートを含みます。そしてあなたのアプリは録音を停止します。
再生の場合も似たようなものではありますが、図の右側に示すように結果が異なります。再生中にユーザーがヘッドセットのプラグを抜いた場合、アプリはオーディオを一時停止する必要があります。再生中にユーザーがヘッドセットのプラグを差し込んだ場合、アプリは再生を続行させるべきです。
Observing Audio Route Changes
オーディオルートの変更は様々な理由で発生します。例えば、ユーザーがヘッドホンを接続したり、Bluetooth LEヘッドセットを接続したり、USBオーディオインターフェイスを抜いたりするなどがあります。このような変更がいつ発生するかを知ることは、アプリにとって重要であり、ユーザーインターフェースの更新や内部状態の変更を行うことができます。オーディオルートの変更の通知を受けるには、AVAudioSessionRouteChangeNotification or routeChangeNotification(新)を受信するように登録してください。
コード
通知の中にあるuserInfo 辞書にはルート変更の詳細が含まれます。userInfo辞書からAVAudioSessionRouteChangeReasonの値を取得することで、変更の理由を知ることができます。
- 新しいデバイスが接続された場合、その理由は AVAudioSessionRouteChangeReasonNewDeviceAvailable となり、
- デバイスが削除された場合は AVAudioSessionRouteChangeReasonOldDeviceUnavailable となります。
コード
新しいデバイスが利用可能になったとき、オーディオ出力が現在どこにルーティングされているかを調べるにはオーディオセッションの currentRoute プロパティを見てください。それはAVAudioSessionRouteDescriptionを返し、その中にオーディオセッションの全ての入力と出力のリストがあります。
デバイスが削除された場合は、userInfo辞書から以前のルートのAVAudioSessionRouteDescriptionオブジェクトを取得します。
どちらの場合(追加、削除)も、RouteDescriptionの outputs というプロパティが、音声出力ルートの詳細を提供する AVAudioSessionPortDescription オブジェクトの配列になっています。
コード
重要:
メディア再生アプリは、ルート変更の理由が
- AVAudioSessionRouteChangeReasonOldDeviceUnavailableの場合、再生を一時停止すべき
- AVAudioSessionRouteChangeReasonOverrideの場合は一時停止すべきではありません。
Note:
オーディオルートを変更すると、ハードウェア関連の値も変更されることがあります。サンプルレート、I/Oバッファ時間、チャンネル数、などです。これらの値がアプリにとって重要であれば、ルート変更後に、それらの値が変更されたかどうかを確認します。
(訳した時に追加)各オブジェクトの関係は次のようになっている。
AVAudioSession
var currentRoute: AVAudioSessionRouteDescription
var availableInputs: [AVAudioSessionPortDescription]?
func setPreferredInput(_ inPort: AVAudioSessionPortDescription?) throws
//Route
AVAudioSessionRouteDescription
var inputs: [AVAudioSessionPortDescription]
var outputs: [AVAudioSessionPortDescription]
//Port
AVAudioSessionPortDescription
var portType: AVAudioSession.Port
var dataSources: [AVAudioSessionDataSourceDescription]?
func setPreferredDataSource(_ dataSource: AVAudioSessionDataSourceDescription?) throws
AVAudioSessionDataSourceDescription
var supportedPolarPatterns: [AVAudioSession.PolarPattern]
func setPreferredPolarPattern(_ pattern: AVAudioSession.PolarPattern?) throws
//ルートチェンジの通知内
userInfo
AVAudioSessionRouteChangeReason //keyはAVAudioSessionRouteChangeReasonKey
以前のルートを表すAVAudioSessionRouteDescriptionオブジェクト //keyはAVAudioSessionRouteChangePreviousRouteKey
outputs
portType
Configuring Device Hardware
オーディオセッションのプロパティを使用すると、アプリの実行時にデバイスハードウェアに関するオーディオ動作を最適化できます。これにより、実行中のデバイスの特性にコードで適応させることができます。アプリの実行中にユーザーによって加えられた変更(ヘッドセットの接続やデバイスのドッキングなど)に対応するのと同様です。
AVAudioSession
を使うことによって
- サンプルレートとI/Oバッファ時間に希望の値を指定できる
- 多くのハードウェア情報を引き出せる。例えば入出力レイテンシー、入出力チャンネル数、ハードウェアサンプルレート、ハードウェアボリューム設定、オーディオ入力の有効/無効など
Choosing Preferred Audio Hardware Values
オーディオセッションを使用して、サンプルレートやハードウェアI/Oバッファ時間など、好みのデバイス設定を指定します。表 5-1 に、これらの設定の利点とコストを示します。
Table 5-1
例えば、アプリで音質が非常に重要で、大きなファイルサイズやバッファサイズが重要な問題でない場合、高いサンプルレートを優先的に指定することができます。
Note:
デフォルトのオーディオI/Oバッファ時間(44.1 kHzオーディオで約0.02秒)は、ほとんどのアプリに十分な応答性を提供します。楽器のライブモニターなど、レイテンシーが重要なアプリではI/Oバッファ時間を短く設定できますが、ほとんどのアプリでこの設定(44.1kHz 0.02秒)を変更する必要はないでしょう。
Setting Preferred Audio Hardware Values
ハードウェアの希望値を設定するのはオーディオセッションをアクティブにする前に行ってください。すでにオーディオセッションがアクティブの場合は、そのオーディオセッションを非アクティブにしてください。設定した値の変更は、オーディオセッションがアクティブになった後に有効になり、その時点なら変更を確認が可能になります(要確認)。Listing 5-1は、希望ハードウェア値を設定する方法と、それを検証する方法を示しています。
Listing 5-1
Note:
複数のアプリが希望ハードウェア値を設定し競合する場合、システムはミキシング不可能なオーディオセッションを優先します。つまり、AVAudioSessionCategoryAmbient
カテゴリや、 AVAudioSessionCategoryOptionMixWithOthers
オプションを使用しているオーディオセッションは、希望ハードウェア設定が採用される可能性が低いです。
Selecting and Configuring Microphones
2つ以上のマイクが内蔵されているiOSデバイスでは、使用するマイクの選択にオーディオセッションモードが使われます。モードは、入力に使用されるデジタル信号処理(DSP)と、可能なルートを指定します。入力とルートは、各モードの想定される使い方に合わせて最適化されます。モードの設定は、使用されるルートの他の側面にも影響する場合があります。
また、開発者は手動でマイクを選択することもでき、ハードウェアがサポートしていれば、好みのマイク極性パターンを選択することもできます。
重要:
入力選択機能を使用する前に、アプリのオーディオセッションのカテゴリとモードを設定し、オーディオセッションをアクティブ化してください。
Setting a Preferred Input
オーディオセッションの availableInputs
を使用すると、内蔵または接続された入力ポートを検出できます。このプロパティは、デバイスの利用可能な入力ポートを記述するAVAudioSessionPortDescription
オブジェクトの配列を返します。ポートは portType
プロパティで識別できます。希望の入力ポート(内蔵マイク、有線マイク、USB入力など)を設定するには、オーディオセッションの setPreferredInput:error:
メソッドを使います。
Setting a Preferred Data Source
内蔵マイクや一部のUSBアクセサリなど、一部のポートはデータソースをサポートしています。アプリは、PortDescription
の dataSources
プロパティ (型は[AVAudioSessionDataSourceDescription]?) を調べることで、利用可能なデータソースを検出できます。内蔵マイクの場合、返されるデータソース記述オブジェクト AVAudioSessionDataSourceDescription は、個々のマイクを表します。異なる機種は、内蔵マイクの違いにより異なる値を返します。例えば、iPhone 4とiPhone 4Sには、下部と上部の2つのマイクがあります。iPhone 5には、底面、前面、背面の3つのマイクがあります。
個々の内蔵マイクは、データソース記述オブジェクトの位置プロパティ(上、下)と方向プロパティ(前、後ろなど)の組み合わせで識別できます。アプリはAVAudioSessionPortDescriptionオブジェクトのsetPreferredDataSource:error:メソッドを使用して優先データソースを設定することができます。
Setting a Preferred Polar Pattern
iOSデバイスの中には、内蔵マイクの指向性を設定できるものがあります。マイクの指向性は、方向に対する感度を定義します。今のiPhoneでは、前面と背面の内蔵マイクの指向性を設定できます。使用可能なパターンは、データソース記述オブジェクトの supportedPolarPatterns
プロパティを使用して返されます。このプロパティは、データソースでサポートされている指向性パターン(単一指向性、無指向性など)の配列を返すか、選択可能なパターンがない場合はnilを返します。データソースにサポートされている指向性パターンが複数ある場合は、データソース記述の setPreferredPolarPattern:error:
メソッドを使用して、優先する指向性パターンを設定できます。
Putting It All Together
次に簡単な例のコードを出し、特定のマイクを選択し、その指向性を設定する方法です。
コード
このコードをiPhone 6sで実行すると、次のようなコンソール出力が得られる:
コンソール出力
Running Your App in Simulator
アプリにオーディオセッションサポートを追加すると、シミュレータまたはデバイス上でアプリを実行できます。ただし、Simulatorでは、異なるプロセスのオーディオセッション間の相互作用のほとんどやオーディオルートの変更はシミュレートされません。Simulatorでアプリを実行する場合、以下のことはできません:
- 割り込み発生
- ヘッドセットの接続/非接続
- サイレントスイッチ(マナーモードボタン)の切り替え
- スクリーンロックのシミュレート
- オーディオミックスの挙動、ミュージックアプリなど他のアプリとあなたのアプリの再生の両立
シミュレータの特性上、シミュレータでの部分的なテストを可能にするために、コードを条件付きにしたくなるかもしれません。リスト5-2はその方法を示しています。(古い?)
Listing 5-2
Protecting User Privacy
ユーザーのプライバシーを保護するため、アプリは音声を録音する前にユーザーに許可を求めて認めてもらう必要があります。ユーザーが許可しない場合、録音しても無音です。システムが自動的にユーザーに許可を求めるプロンプトの表示が、録音ありのカテゴリのアプリが入力ルートを使用しようとしたときに自動的に起こります。
Requesting Permission to Record Audio
ユーザーに録画許可を求めることをシステムに頼らず、手動で requestRecordPermission:
メソッドを使用して許可を求めることができます。このメソッドを(いいタイミングで)使うことで、中断することのない、アプリの自然なフローで許可を得ることができ、より良いユーザーエクスペリエンスが得られます。
コード
重要:
iOS10以降、デバイスのマイクにアクセスするすべてのアプリは、その意図を静的(statically = ビルド時に文章が決定の意味?)に宣言する必要があります。そのためには、アプリはInfo.plistファイルに NSMicrophoneUsageDescription
キーを含め、このキーに使用目的の文字列(purpose string)を提供する必要があります。システムがユーザーにアクセスを許可するよう促すと、この文字列がアラートの一部として表示されます。
このキーと値がない状態で、アプリがデバイスのマイクにアクセスしようとすると、アプリは終了します。
History
元資料が変更になって、この記事が対応したこと書く欄です。気になる部分をちょっと変更した程度のことは書きません。
2024-2-29 元資料の2017-09-19版に対応
Discussion