AVFoundation

複数のAirPods接続時のAudioの挙動
– FILM REDの副音声上映で困った原因を追究する –

複数のAirPods接続時のAudioの挙動 – FILM REDの副音声上映で困った原因を追究する –

この記事はpotatotips #81 iOS/Android開発Tips共有会で発表した時の内容をまとめたブログになります。スライドは以下から確認できます

テーマきっかけの経緯

ある日、ONEPIECE FILM REDの副音声上映を友達と見に行きました
副音声上映とは、専用アプリを使って、副音声を聴きながら映画を見る上映方法です(アプリのサイト)
専用アプリを起動した状態で映画を見ると、その映画の音声を拾って、それに合わせた時間の副音声をながしてくれるので、それをイヤホンで聴くというスタイルです

しかしトラブルが。。
友達が副音声アプリのことを知らなかったので、映画館にイヤホンを持ってきていない&アプリをインストールしていなかった
おまけにスマホのバッテリー残量も全然ない
このままでは友達が副音声を聴くことができない。。。

そこで解決策をひらめく🙄

  • 自分はメイン使用のAirPodsProと予備のBeatsのイヤホンをいつも持っている
  • 自分はメイン使用のAirPodsProと予備のBeatsのイヤホンをいつも持っている
  • W1/H1チップ搭載のBeatsのイヤホンも対象

発表者のiPhoneに2つのイヤホンを接続して、発表者と友達がそれぞれイヤホン装着すれば、解決では??

閃いた自分

しかしトラブルが発生!
事前にYouTubeで2台同時に接続した状態で両方とも音声が流れることを確認したが、いざ映画が始まると自分のBeatsのイヤホンの音声だけが聞こえない。。
友達にこっそり確認すると、友達のAirPodsは聞こえているっぽい
上映中なので、細かく調査することもできない。。
上映中に大パニックになり、冒頭のライブシーンをほぼ聴き逃す。。
結局映画はAirPodsを2人で1つずつ付けて聞きました!

この経験から、もしかして実装の設定次第で、AirPodsの接続の仕方が変わることがあるのでは
と思って、これは調べるしかない!と思って、調査することにしました!

調べたこと

今回調査したのは以下の内容です

  1. 今回の事象の再現
    • 音声再生時に、AVAudioSessionでどのような設定をすれば、2台接続していたAirPodsが1台にのみ接続されるようになるか
  2. 2台接続時のAVAudioSessionの挙動
    • コードの実装で何ができるかの調査

今回の事象の再現

結論としては、以下の設定で1つのAirPodsしか繋がらなくなるという事象を再現できました
詳細の仕様やドキュメントは見つけられませんでした。。
ちなみにイヤホンが1つしか接続していない時に、もう一つのAirPodsを選択すると、端末のスピーカーに切り替わるという挙動も確認してます

do {
    var output = AVAudioSessionDataSourceDescription()
    try session.setCategory(.playAndRecord, mode: .default, options: [.allowBluetoothA2DP, .mixWithOthers])
    try session.setActive(true)
} catch {
    print(error)
}

言語化すると、AVAudioSessionのsetCategory()のメソッドを以下の設定で実行することで再現しました。

  1. category: .playAndRecord
  2. options: ↓の両方を満たす
    • .allowBluetooth or .allowBluetoothA2DP
    • .mixWithOthers or .duckOthers

再現環境

  1. iOS16.2
  2. Xcode14.2

2台接続時のAVAudioSessionの挙動

調査前は以下のようになるかな?と仮説を立てていました

○仮説
AVAudioSession.sharedInstance().route.outputsの配列から、AirPodsの情報が2つ取得できる?

○確認結果

  1. 1つのAirPodsの情報しか取得できない
  2. どのAirPods情報が取得できるのかの法則は確認できず。。
  3. ちなみに設定適応時に一瞬音が途切れる

実際にprintしてみても、1台のAirPodsしか取得できない↓

for desc in route.outputs {
    print("PortName: \(desc.portName), PortType: \(desc.portType)")
}
// PortUID: xx:xx:xx:xx:xx:xx-tacl, PortName: Yugos-AirPodsPro, PortType: BluetoothA2DPOutput

接続されるAirPodsや上記のprintされるイヤホンがどちらになるのか、以下の観点で確認してみました

  1. AirPodsPro->Beatsの順で接続
    • 基本AirPodsProだけが接続状態になる&printされる
  2. Beats->AirPodsProの順で接続
    • Beatsだけが接続状態になる&printされる

しかしたまに以下のようになる時があった。。

  • たまに接続: AirPodsPro&Beats: printのように、接続している&printされるイヤホンが一致しない場合がある。。(なんでだ??)

ちなみに2台のAirPods接続時に電話がかかってきた時も1台のAirPodsのみ接続状態になるのですが、その場合は以下のような挙動になりました

  1. AirPodsPro->Beatsの順で接続
    • Beatsにだけ着信メッセージが流れる
  2. Beats->AirPodsProの順で接続
    • AirPodsProにだけ着信メッセージが流れる

アプリでの検証と真逆の結果に混乱する自分。。

まとめ

  1. AVAudioSessionの設定次第で、AirPodsを複数台接続した時に、片方のAirPodsしか繋がらなくなる時がある
  2. 正確なルールや仕様は不明で、実際の挙動から推測することしかできない
    • イヤホンの接続順が関係ありそうな気がする
  3. アプリについて困ったことで調べられるのはエンジニアの特権!
  4. 音声系のアプリは、AirPods2台接続した時の動作確認も必要!?
  5. もしこの辺りの挙動に詳しい人、もしくは今回の発表内容で間違っている点があれば、ご指摘を!
+1

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA