SwiftでミュートON/OFF

Swiftでミュート機能をつけます。シンプルにアプリ内のUIから音量のON/OFFのみという機能を目指します。
環境は下記。ターゲットは一応 iOS 9.2 です。

* MacOS 10.11.3(El Capitan)
* Xcode 7.2.1
* Swift 2.1

結論、MPVolumeViewから音量スライダーを取ってくるようにしてみました。
色々調べつつやってみたので、過程も含めておさらい。

## UIの作成

UIはボタンのイメージ。

```swift:SampleViewController.swift
class SampleViewController: UIViewController {
    @IBOutlet weak var btnSound: UIButton!

    //  storyboardで「TouchUpInside」からバインド
    @IBAction func pushSound(sender :AnyObject) {
        btnSound.selected = !btnSound.selected
        changeSound()
    }

    func changeSound() {
      // ミュート(音量のON/OFF)処理
    }
}
```

## ミュート機能をつける

UIは良いとしても、探してみればミュート設定にピンポイントなAPIとかライブラリがない。
公式から辿ればまず出てくるのがAVAudioSession。

* [Audio Session プログラミングガイド - Apple Developer](https://developer.apple.com/jp/documentation/AudioSessionProgrammingGuide.pdf)

でもこれは読んでみると、「複数のバックグラウンドアプリと起動中のアプリの相互音声設定」が焦点にされている印象だった。

アプリ設計思想上そこまで考慮はすべきなのかもしれないけど、今回やりたいのはもっとシンプルにアプリ内完結でよい。ってことで次に出てきた候補がMPVolumeViewを使う方法。

* [MPVolumeView Class Reference - Apple Developer](https://developer.apple.com/library/prerelease/ios/documentation/MediaPlayer/Reference/MPVolumeView_Class/index.html)

なんだけどコーディングがわからん。

* [[iOS]ミュート状態・音量を取得したい](http://qiita.com/sadoru/items/3894ef0871a939a6fc8d)

良い記事。わかりやすかった。でもObjective-CなのでSwiftに翻訳。

## やってみた

先ほどのコードに追加です。

```swift:SampleViewController.swift

import AVFoundation
import MediaPlayer
class SampleViewController: UIViewController {

    // 参照保持用にスライダーを宣言。
    var volumeSlider: UISlider!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 音量調整のため、システム音量設定画面をaddview
        self.view.backgroundColor = UIColor.clearColor()
        let mpVolumeView = MPVolumeView(frame: self.view.bounds)
        mpVolumeView.hidden = true;
        self.view.addSubview(mpVolumeView)
        
        // 音量調整用のスライダーを取得
        for childView in mpVolumeView.subviews {
            // UISliderクラスで探索
            if (childView.isKindOfClass(UISlider)){
                self.volumeSlider = childView as! UISlider
            }
        }
    }

    // ミュート(音量のON/OFF)処理
    func changeSound() {
        if(btnSound.selected){
            self.volumeSlider.setValue(1.0, animated: false)
            btnSound.setImage(UIImage(named: "btnSoundOn"), forState: UIControlState.Normal)
        } else {
            self.volumeSlider.setValue(0.0, animated: false)
            btnSound.setImage(UIImage(named: "btnSoundOff"), forState: UIControlState.Normal)
        }
    }
}
```

* MPVolumeViewでシステム音量画面を取ってくる。
* その中のスライダーから音量を取ってくる。
* スライダーは参照保存しておいて、UIイベントから操作できるようにしておく。
* UIイベントからは保存したスライダーの音量の変更をする。

調整する音量の値はONで1.0(音量最大)とかだと不親切すぎるので、そこは前回値適用などに調整する。

## 補足

スライダー取得をちゃんと(?)やるならこうかな。
正直リテラルあまり使いたくないし、ループで回すのも気持ち悪いんだけど。

```swift:SampleViewController.swift
      // 音量調整用のスライダーを取得
      for childView in mpVolumeView.subviews {
          // MPVolumeSliderクラスで探索
          if (NSStringFromClass((childView as NSObject).dynamicType).isEqual("MPVolumeSlider")) {
                self.volumeSlider = childView as! UISlider
          }
      }

```









# 参考サイト

* [Audio Session プログラミングガイド - Apple Developer](https://developer.apple.com/jp/documentation/AudioSessionProgrammingGuide.pdf)
* [AVAudioSession細かいことまとめ(late 2014) ](http://samekard.blogspot.jp/2014/12/avaudiosessionlate-2014_3.html)
 →AVAudioSession使わなかったけど、わかりやすくて勉強になる記事です。

* [MPVolumeView Class Reference - Apple Developer](https://developer.apple.com/library/prerelease/ios/documentation/MediaPlayer/Reference/MPVolumeView_Class/index.html)

* [[iOS]ミュート状態・音量を取得したい](http://qiita.com/sadoru/items/3894ef0871a939a6fc8d)