俺、サービス売って家買うんだ

Swift, Kotlin, Vue.js, 統計, GCP / このペースで作ってればいつか2-3億で売れるのがポっと出来るんじゃなかろうか

iOS AVAudioSession周りの覚書

f:id:ie-kau:20190711075808p:plain

音声 x 外部ヘッドセット周りで嵌ったのでメモメモ。φ(・

基礎知識

44,100 Hz

デジタルオーディオにおける一般的なサンプリング周波数。アナログオーディオは一秒間に441000回標本化される。

ハード側

iPhoneのスピーカー

  • 通話用スピーカー
    • 上についているやつ
  • 内蔵スピーカー
    • 右側がスピーカー、左側がマイク

BluetoothHFPとは

Bluetooth Hands-Free Profile の略。

携帯電話 - ヘッドセット間などで用いられる、電話の発着信や通話を行なうためのプロファイル。

アプリケーション側

AVAudioSessionとは?

OS(及びハードウェア)とアプリケーションの仲介を行うオブジェクト。
デフォルトでは以下の設定がされている。

  • 再生はサポートされているが、録音はサポートされていない
  • マナーモードにするとアプリで再生されている音はすべて無音になる (iOSのみ)
  • デバイスがロックされたら音が止まる (iOSのみ)
  • アプリがオーディオを再生し始めたらバックグラウンドで流れている音楽を止める

デフォルトの振る舞いを変更するには audio session category を変更する必要がある。

Audio Session Category とは?

オーディオの振る舞いを定義する Audio Session プロパティ。
playback(再生)だけとか、record(録音)だけとか、 playAndRecord(再生と録音)とか。 さらにsession modeを設定することで、より洗練した音質を提供できる。

Audio Session Mode

category がベースとなる振る舞いを設定するのに対して、 mode は専門的にするために使うカテゴリーの振る舞いを専門化できる。 例えば videoChat は playAndRecord, recod カテゴリといっしょにつかい、音声に対するトーンイコライザの最適化を提供する。また許容されるオーディオルートをビデオチャットに適したものだけに削減する。

※オーディオルート => どこから音を出すかとか、ヘッドフォンとかBluetoothとか。

オーディオルートの変更を検知する

オーディオのアウトプットを外付けスピーカーからBluetoothに変えた場合などを検知する場合は AVAudioSessionRouteChangeNotification を利用すればよい。

(例) 内蔵スピーカーからBluetoothに変わったときの出力

let center = NotificationCenter.default
center.addObserver(self, selector: #selector(didAudioSessionRouteChanged(_:)), name: AVAudioSession.routeChangeNotification, object: nil)
@objc func audioSessionRouteChanged(_ notification: Notification) {
      guard let userInfo = notification.userInfo,
          let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
          let reason = AVAudioSession.RouteChangeReason(rawValue:reasonValue) else {
              return
      }

      let session: AVAudioSession = AVAudioSession.sharedInstance()
      print(session.sampleRate)  // Bluetoothにイヤフォンにした場合サンプルレートが変わってるはず

      switch reason {
      case .newDeviceAvailable:
          print("newDeviceAvailable")

          for output in session.currentRoute.outputs {
              print(output.portType)  // BluetoothHFP
              print(output.portName)  // 製品名 or AirPodsなら自分で登録した名前
          }

      case .oldDeviceUnavailable:
          print("oldDeviceUnavailable")

      case .unknown:
          print("unkonw")

      case .categoryChange:
          print("categoryChange")

      case .override:
          print("override")

      case .wakeFromSleep:
          print("wakeFromSleep")

      case .noSuitableRouteForCategory:
          print("noSuitableRouteForCategory")

      case .routeConfigurationChange:
          print("routeConfigurationChange")

      @unknown default:
          print("default")
      }
}

理解が浅い

  • AVAudioSession.CategoryOptions

参考