在Swift中中断后如何恢复音频? [英] How to resume audio after interruption in Swift?

查看:128
本文介绍了在Swift中中断后如何恢复音频?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在此处进行操作,我整理了这个测试项目来处理音频播放的中断.具体来说,我使用默认iPhone时钟应用中的闹钟作为中断.似乎正在调用中断处理程序,但未通过let = interruptionType行,因为出现了两次"错误类型".

I am following instructions here, I've put together this test project to handle interruptions to audio play. Specifically, I'm using the alarm from the default iphone clock app as interruption. It appears that the interruption handler is getting called but is not getting past the let = interruptionType line as "wrong type" showed up twice.

import UIKit
import AVFoundation

class ViewController: UIViewController {

    var player = AVAudioPlayer()

    let audioPath = NSBundle.mainBundle().pathForResource("rachmaninov-romance-sixhands-alianello", ofType: "mp3")!

    func handleInterruption(notification: NSNotification) {

        guard let interruptionType = notification.userInfo?[AVAudioSessionInterruptionTypeKey] as? AVAudioSessionInterruptionType else { print("wrong type"); return }

        switch interruptionType {

        case .Began:
            print("began")
            // player is paused and session is inactive. need to update UI)
            player.pause()
            print("audio paused")

        default:
            print("ended")
            /**/
            if let option = notification.userInfo?[AVAudioSessionInterruptionOptionKey] as? AVAudioSessionInterruptionOptions where option == .ShouldResume {
                // ok to resume playing, re activate session and resume playing
                // need to update UI
                player.play()
                print("audio resumed")
            }
            /**/
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        do {
            try player = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: audioPath))
            player.numberOfLoops = -1 // play indefinitely
            player.prepareToPlay()
            //player.delegate = player

        } catch {
            // process error here
        }

        // enable play in background https://stackoverflow.com/a/30280699/1827488 but this audio still gets interrupted by alerts
        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
            print("AVAudioSession Category Playback OK")
            do {
                try AVAudioSession.sharedInstance().setActive(true)
                print("AVAudioSession is Active")
            } catch let error as NSError {
                print(error.localizedDescription)
            }
        } catch let error as NSError {
            print(error.localizedDescription)
        }

        // add observer to handle audio interruptions
        // using 'object: nil' does not have a noticeable effect
        let theSession = AVAudioSession.sharedInstance()
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.handleInterruption(_:)), name: AVAudioSessionInterruptionNotification, object: theSession)

        // start playing audio
        player.play()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

此外,按照一个想法此处,我将处理程序修改为

Furthermore, following an idea here, I have modified the handler to

func handleInterruption(notification: NSNotification) {

        //guard let interruptionType = notification.userInfo?[AVAudioSessionInterruptionTypeKey] as? AVAudioSessionInterruptionType else { print("wrong type"); return }

        if notification.name != AVAudioSessionInterruptionNotification
            || notification.userInfo == nil{
            return
        }

        var info = notification.userInfo!
        var intValue: UInt = 0
        (info[AVAudioSessionInterruptionTypeKey] as! NSValue).getValue(&intValue)
        if let interruptionType = AVAudioSessionInterruptionType(rawValue: intValue) {

            switch interruptionType {

            case .Began:
                print("began")
                // player is paused and session is inactive. need to update UI)
                player.pause()
                print("audio paused")

            default:
                print("ended")
                /** /
                if let option = notification.userInfo?[AVAudioSessionInterruptionOptionKey] as? AVAudioSessionInterruptionOptions where option == .ShouldResume {
                    // ok to resume playing, re activate session and resume playing
                    // need to update UI
                    player.play()
                    print("audio resumed")
                }
                / **/
                player.play()
                print("audio resumed")
            }
        }
    }

结果是所有开始",音频暂停",结束"和音频恢复"都显示在控制台中,但实际上并未恢复音频播放.

Results are that all of "began", "audio paused", "ended" and "audio resumed" show up in console but audio play is not actually resumed.

注意:我将player.play()移出了注释的where option == .ShouldResume if语句之外,因为当.Ended发生中断时,if条件不成立.

Note: I moved the player.play() outside of the commented out where option == .ShouldResume if statement because that if condition is not true when the .Ended interruption occurs.

推荐答案

(代表问题作者,已在问题中发布).

找到解决方案!在讨论之后此处,将其插入viewDidLoad()

Solution found! Following discussion here, inserted this in viewDidLoad()

do {
    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, withOptions: AVAudioSessionCategoryOptions.MixWithOthers)
} catch {        
}

在警报中断上单击确定"后,音频继续播放.与以前提到的不同,该解决方案不需要中断处理程序(@Leo Dabus之后已将其删除).

After clicking "ok" on the alarm interruption, the audio play continued. Unlike previously noted, the solution does NOT require an interruption handler (which @Leo Dabus has since removed).

但是,如果使用中断处理程序,则不能在handleInterruption()中调用.play(),因为这样做不能保证继续播放&似乎阻止了audioPlayerEndInterruption()的调用(请参阅文档).相反,必须在audioPlayerEndInterruption()(它的3个版本中的任何一个)中调用.play(),以确保恢复.

However if you are using an interruption handler, .play() must NOT be invoked within handleInterruption() as doing so does NOT guarantee play to resume & seems to prevent audioPlayerEndInterruption() to be called (see docs). Instead .play() must be invoked within audioPlayerEndInterruption() (any of its 3 versions) to guarantee resumption.

此外,如果您想让应用在后台运行时中断后继续播放,则必须给@cmon>选项赋予AVAudioSession,该选项由@Simon Newstead标注.看来,如果用户希望应用程序在进入后台时继续播放,则可以合理地假设用户也希望该应用程序在后台运行后在中断后继续播放.确实,这就是Apple Music应用程序表现出的行为.

Furthermore, AVAudioSession must be give option .MixWithOthers noted by @Simon Newstead if you want your app to resume play after interruption when your app is in the background. It seems that if a user wants the app to continue playing when it goes into the background, it is logical to assume the user also wants the app to resume playing after an interruption while the app is in the background. Indeed that is the behaviour exhibited by the Apple Music app.

这篇关于在Swift中中断后如何恢复音频?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆