【Swift】動画再生中にイヤホン(Bluetooth)の抜き差しをチェックする

動画再生中にイヤホンの抜き差しが発生した時に検知する必要があったので
Extensionを作成しました。

検知に利用するのは**「AVAudioSession」**と**「Notification」**です。
NotificationでAVAudioSessionの値の監視を行います。
また、今回はRxのExtensionとして実装しましたが、普通にNotificationの実装をすればRxを使わなくても実装可能です。

## ソースコード

```swift:Rx+AVAudioSession.swift

import Foundation
import RxSwift
import AVFoundation

extension Reactive {
    
    // イヤホン(Bluetooth含む)の抜き差しをチェック
    var isConnectedHeadPhone: Observable<Bool> {
        AVAudioSession.sharedInstance()
        return NotificationCenter.default.rx.notification(.AVAudioSessionRouteChange,
                                                          object: nil)
            .map { didChage in
                
                guard let desc = didChage.userInfo?[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription
                    else { return false }
                let outputs = desc.outputs
                for component in outputs {
                    if component.portType == AVAudioSessionPortHeadphones ||
                        component.portType == AVAudioSessionPortBluetoothA2DP ||
                        component.portType == AVAudioSessionPortBluetoothLE ||
                        component.portType == AVAudioSessionPortBluetoothHFP {
                        // イヤホン(Bluetooth含む)が抜かれた
                        return false
                    }
                }
                // イヤホン(Bluetooth含む)が差された
                return true
        }
    }
}

```
## Usage

```swift:ViewController.swift

import UIKit
import RxSwift

final class ViewController: UIViewController {

    private let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        rx.isConnectedHeadPhone
            .subscribe { isConnected in
                guard let isConnected = isConnected.element else { return }
                if isConnected {
                    // イヤホン(Bluetooth含む)が差された時の処理
                } else {
                    // イヤホン(Bluetooth含む)が差された時の処理
                }
            }
            .disposed(by: disposeBag)
    }
}
```
## Rxを使わない時は
Rxを使わない場合はこんな感じでいけると思います。

```swift:ViewController.swift

import UIKit

final class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        AVAudioSession.sharedInstance()
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(self.didAudioSessionRouteChanged(_:)),
                                               name: .AVAudioSessionRouteChange, object: nil)
    }

    @objc
    private func didAudioSessionRouteChanged(_ notification: Notification) {
        
        guard let desc = notification.userInfo?[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription
            else { return }
        let outputs = desc.outputs
        for component in outputs {
            if component.portType == AVAudioSessionPortHeadphones ||
                component.portType == AVAudioSessionPortBluetoothA2DP ||
                component.portType == AVAudioSessionPortBluetoothLE ||
                component.portType == AVAudioSessionPortBluetoothHFP {
                // イヤホン(Bluetooth含む)が差された時の処理
                return
            }
        }
        // イヤホン(Bluetooth含む)が差された時の処理
    }
}
```
## まとめ
イヤホン(Bluetooth)の抜き差しの判定が思っていたよりも簡単にできましたね。
これまで動画関連は深く踏み込んで触っていなかったので、いろいろ触ってみようと思います。

以上です。