LoginSignup
37
30

More than 5 years have passed since last update.

MPRemoteCommandCenterでオーディオファイル再生時のロック画面とコントロールセンターでの操作に対応する

Last updated at Posted at 2016-03-11

はじめに

これはiOSでサーバーからダウンロードした音声ファイルをロック画面で再生するまでの設定を行った際の備忘録です。

当初はiOS9.2のシュミレーターを利用して検証していましたが、コントロールセンターでボタンが表示されない等の現象が見られたので実機を想定しています。

環境

  • Xcode7.2
  • iOS9系 実機

やったこと

Background Audio&AirPlayのチェックボックスをONに

Targets名 => Capabilities => Background Modes => Audio&AirPlay

音声ファイルのパーミッションの設定

今回はAVAudioPlayerを利用して楽曲再生を行いました。

ダウンロードしてストレージに保存した音声ファイルをそのままロック画面で再生しようとすると、パーミッションの関係でAVAudioPlayer play error and the error is Code=-54 エラーが発生します。

NSFileManager.defaultManager.setAttributesで保存先のパーミッションをNSFileProtectionNoneに変更し上記のエラーに対応しました。

    // 保存先ディレクトリパス取得
    func exportDirectoryPath() -> String {
        guard let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first else {
            fatalError()
        }
        return path + "/" + "Clips"
    }

...省略

    // 保存先ディレクトリを作成
    let dirPath = DownloadFilePathAgent.exportDirectoryPath() + "/\(self.task.uuid)"
    let fileManager:NSFileManager = NSFileManager.defaultManager()
    do {
        if fileManager.fileExistsAtPath(dirPath) {
            try fileManager.removeItemAtPath(dirPath)
        }
        try fileManager.createDirectoryAtPath(dirPath, withIntermediateDirectories: true, attributes: nil)
        // ロック時にも再生できるようにパーミッション変更
        try fileManager.setAttributes([NSFileProtectionKey: NSFileProtectionNone], ofItemAtPath: dirPath)
    }
    catch let error as NSError {
        //エラー対応
    }

...省略

    // ファイルダウンロード完了時にもパーミッション変更
    try! NSFileManager.defaultManager().setAttributes([NSFileProtectionKey: NSFileProtectionNone], ofItemAtPath: filePath)

AVAudioPlayerとAVAudioSessionの設定

以下を再生や停止を担当するクラスに実装していきます。

   // initあたりで
   UIApplication.sharedApplication().beginReceivingRemoteControlEvents()

   // AVAudioPlayer#play()実行前に呼び出して即座に再生開始するように
   audioPlayer?.prepareToPlay()

ロック画面でも再生しますよー、の設定です。

プロジェクト設定からBackground Audio&AirPlayをONにします。

Project Navigator -> Project -> target -> Capabilities -> Background Modes

スクリーンショット 2016-04-22 16.08.37.png

AVAudioSession の設定

    session = AVAudioSession.sharedInstance()

    //ロック時も再生のカテゴリを指定
    do {
        try session?.setCategory(AVAudioSessionCategoryPlayback)
    }
    catch let error as NSError {
        print(error.description)
    }

    do {
        //オーディオセッションを有効化
        try session?.setActive(true)
    }
    catch let error as NSError {
        print(error.description)
    }

再生ボタン等の表示設定

iOS 7.1以降はremoteControlReceivedWithEventをオーバライドしてロック画面のハンドリングに対応する方法でなくMPRemoteCommandCenterを利用するように推奨されています。

MPRemoteCommand Class Reference

上記のAVAudioSessionを実装したクラスに追記していきます。

表示するボタンと対応する処理の設定

    let commandCenter = MPRemoteCommandCenter.sharedCommandCenter()
    commandCenter.playCommand.addTarget(self, action: "play")
    commandCenter.playCommand.enabled = true
    commandCenter.pauseCommand.addTarget(self, action: "pause")
    commandCenter.pauseCommand.enabled = true
    commandCenter.skipForwardCommand.addTarget(self, action: "skipForward")
    commandCenter.skipForwardCommand.enabled = true
    commandCenter.skipBackwardCommand.addTarget(self, action: "skipBackward")
    commandCenter.skipBackwardCommand.enabled = true

仕上がり

再生している楽曲情報の設定

    MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo = [
        MPMediaItemPropertyTitle: "タイトル",
        MPMediaItemPropertyArtist : "アーティスト名",
        MPNowPlayingInfoPropertyPlaybackRate : NSNumber(float: 1.0), //再生レート
        MPMediaItemPropertyPlaybackDuration : NSNumber(double: self.duration) //シークバー
    ]

ついでに再生中の電話割り込み/復帰対応

必須機能かと思いますのでついでに実装しておきましょう。

AVAudioPlayerDelegateに準拠しているなら以下の2つのデリゲートメソッドで割り込みに対応できます。


     // 割り込み開始時にプレーヤーを制御するデリゲートメソッド
     func audioPlayerBeginInterruption(player: AVAudioPlayer) {
         // プレーヤー/オーディオセッションはすでに一時停止状態
     }

     // 割り込み終了時にプレーヤーを制御するデリゲートメソッド  
     func audioPlayerEndInterruption(player: AVAudioPlayer) {
         // 復帰処理
     }

上記以外にAVAudioSessionInterruptionNotificationを利用する方法がありました。


    // 通知登録
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "sessionDidInterrupt", name: AVAudioSessionInterruptionNotification, object: nil)

    /**
     電話が鳴って割り込まれた / 電話終わった 際のハンドリング
     */
    func sessionDidInterrupt(notification:NSNotification) {

        guard let typeNumber = notification.userInfo?[AVAudioSessionInterruptionTypeKey],
        let type = AVAudioSessionInterruptionType(rawValue: typeNumber.unsignedLongValue)
            else {
                return
        }

        switch type {
        case .Began:
            dispatch_async(dispatch_get_main_queue(), { [weak self] in
                self?.pause()
            })
        case .Ended:
            dispatch_async(dispatch_get_main_queue(), { [weak self] in
                self?.play()
            })
        }
    }

備考

デフォルトの「ミュージック」のアプリはロック画面のシークバーの把手で再生をコントロールできますがリファレンス等を確認してもその機能は提供されていない模様です。

MixCloudやSoundCloud等のアプリにもなかったので多分そうなのでしょう。

参考

37
30
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
37
30