8

ここの指示に従っています。オーディオ再生の中断を処理するために、このテスト プロジェクトをまとめました。具体的には、iPhone のデフォルトの時計アプリのアラームを割り込みとして使用しています。割り込みハンドラが呼び出されているように見えますが、 「間違ったタイプlet = interruptionType」が 2 回表示されたため、行を通過していません。

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.
    }
}

さらに、こちらのアイデアに従って、ハンドラーを次のように変更しました

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")
            }
        }
    }

結果として、「開始」、「オーディオの一時停止」、「終了」、「オーディオの再開」のすべてがコンソールに表示されますが、オーディオの再生は実際には再開されません。

注:player.play()コメントアウトされたwhere option == .ShouldResumeif ステートメントの外側を移動しました。これは、中断が発生ifしたときにその条件が真ではないためです。.Ended

4

2 に答える 2

17

(質問に投稿された後、質問の作成者に代わって投稿されました) .

解決策が見つかりました!ここでの議論に続いて、これを挿入しましたviewDidLoad()

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

アラームの中断で「OK」をクリックすると、オーディオの再生が続行されました。前述とは異なり、ソリューションには割り込みハンドラーは必要ありません (@Leo Dabus はその後削除されました)。

ただし、割り込みハンドラーを使用している場合は、再生が再開されることを保証せず、呼び出されないように見えるため、.play()内で呼び出してはなりません( docsを参照)。代わりに、再開を保証するために (その 3 つのバージョンのいずれか)内で呼び出す必要があります。handleInterruption()audioPlayerEndInterruption().play()audioPlayerEndInterruption()

さらに、アプリがバックグラウンドにあるときに中断後にアプリの再生を再開する場合は、@Simon Newsstead が指摘したAVAudioSessionオプションを指定する必要があります。.MixWithOthersユーザーがアプリがバックグラウンドに移行したときにアプリの再生を継続したい場合、アプリがバックグラウンドにある間に中断した後にアプリの再生を再開することもユーザーが望んでいると想定するのは当然のことです。実際、これは Apple Music アプリが示す動作です。

于 2016-08-06T22:18:28.133 に答える
7

@rockhammersの提案は私にとってはうまくいきました。ここ

授業前

let theSession = AVAudioSession.sharedInstance()

ビューでDidLoad

    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.handleInterruption(notification:)), name: NSNotification.Name.AVAudioSessionInterruption, object: theSession)

そして関数

func handleInterruption(notification: NSNotification) {
    print("handleInterruption")
    guard let value = (notification.userInfo?[AVAudioSessionInterruptionTypeKey] as? NSNumber)?.uintValue,
        let interruptionType =  AVAudioSessionInterruptionType(rawValue: value)
        else {
            print("notification.userInfo?[AVAudioSessionInterruptionTypeKey]", notification.userInfo?[AVAudioSessionInterruptionTypeKey])
            return }
    switch interruptionType {
    case .began:
        print("began")
        vox.pause()
        music.pause()
        print("audioPlayer.playing", vox.isPlaying)
        /**/
        do {
            try theSession.setActive(false)
            print("AVAudioSession is inactive")
        } catch let error as NSError {
            print(error.localizedDescription)
        }
        pause()
    default :
        print("ended")
        if let optionValue = (notification.userInfo?[AVAudioSessionInterruptionOptionKey] as? NSNumber)?.uintValue, AVAudioSessionInterruptionOptions(rawValue: optionValue) == .shouldResume {
            print("should resume")
            // ok to resume playing, re activate session and resume playing
            /**/
            do {
                try theSession.setActive(true)
                print("AVAudioSession is Active again")
                vox.play()
                music.play()
            } catch let error as NSError {
                print(error.localizedDescription)
            }
            play()
        }
    }
}
于 2017-03-29T17:31:05.873 に答える