简体   繁体   English

快速的AVPlayer状态监听器

[英]AVPlayer state listener in swift

I want to know how to get the state of my player (AVPlayer) (buffering, playing, stopped, error) and update the ui according to those states (including the player on the lock screen). 我想知道如何获取播放器(AVPlayer)的状态(缓冲,播放,停止,错误)并根据这些状态(包括锁定屏幕上的播放器)更新ui。 How exactly should I do it? 我应该怎么做?

I have a label that may contain: "Buffering...", "Playing", "Stopped" or "Error". 我有一个标签,其中可能包含:“正在缓冲...”,“正在播放”,“已停止”或“错误”。

Basically, I have the following: 基本上,我有以下几点:

MediaPlayer : MediaPlayer

import Foundation
import AVFoundation

class MediaPlayer {

    static let sharedInstance = MediaPlayer()
    fileprivate var player = AVPlayer(url: URL(string: "my_hls_stream_url_here")!)
    fileprivate var isPlaying = false

    func play() {
        player.play()
        isPlaying = true
    }

    func pause() {
        player.pause()
        isPlaying = false
    }

    func toggle() {
        if isPlaying == true {
            pause()
        } else {
            play()
        }
    }

    func currentlyPlaying() -> Bool {
        return isPlaying
    }

}

PlayerViewController : PlayerViewController

class PlayerViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    @IBAction func playStopButtonAction(_ sender: UIButton) {
        MediaPlayer.sharedInstance.toggle()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        label.text = "Disconnected"

        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
            try AVAudioSession.sharedInstance().setActive(true)

            print("Audio session ok\n")
        } catch {
            print("Error: Audio session.\n")
        }

        // Show only play/pause button on the lock screen
        if #available(iOS 9.1, *) {

            let center = MPRemoteCommandCenter.shared()

            [center.previousTrackCommand, center.nextTrackCommand, center.seekForwardCommand, center.seekBackwardCommand, center.skipForwardCommand, center.skipBackwardCommand, center.ratingCommand, center.changePlaybackRateCommand, center.likeCommand, center.dislikeCommand, center.bookmarkCommand, center.changePlaybackPositionCommand].forEach {
                $0.isEnabled = false
            }

            center.togglePlayPauseCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
                MediaPlayer.sharedInstance.toggle()
                return MPRemoteCommandHandlerStatus.success
            }

            center.playCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
                MediaPlayer.sharedInstance.play()
                return MPRemoteCommandHandlerStatus.success
            }

            center.pauseCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
                MediaPlayer.sharedInstance.pause()
                return MPRemoteCommandHandlerStatus.success
            }

        } else {
            // Fallback on earlier versions
            print("Error (MPRemoteCommandCenter)")
        }


    }


    override func remoteControlReceived(with event: UIEvent?) {
        guard let event = event else {
            print("No event\n")
            return
        }
        guard event.type == UIEventType.remoteControl else {
            print("Another event received\n")
            return
        }
        switch event.subtype {
        case UIEventSubtype.remoteControlPlay:
            print("'Play' event received\n")
        case UIEventSubtype.remoteControlPause:
            print("'Pause' event received\n")
        case UIEventSubtype.remoteControlTogglePlayPause:
            print("'Toggle' event received\n")
        default:
            print("\(event.subtype)\n")
        }
    }

}

I think you could use the timeControlStatus property of AVPlayer . 我认为您可以使用AVPlayertimeControlStatus属性。 According to the doc it can be paused , waitingToPlayAtSpecifiedRate which is basically what you call buffering or playing . 根据文档,它可以pausedwaitingToPlayAtSpecifiedRate ,这基本上就是您所说的bufferingplaying

If you really need the error state, you could observe the error property or whether the status property is set to failed . 如果确实需要error状态,则可以观察error 属性status 属性是否设置为failed

A simple KVO observer on these properties would do the trick. 一个简单的关于这些属性的KVO观察者就可以解决问题。

A place to start could be through using the AVPlayer's "status" property. 首先可以使用AVPlayer的“ status”属性。 It is an enumeration that contains the following values (this is taken directly from the documentation): 它是一个包含以下值的枚举(直接从文档中获取):

  1. 'unknown' : Indicates that the status of the player is not yet known because it has not tried to load new media resources for playback. '未知' :表示播放器的状态未知,因为它尚未尝试加载新的媒体资源进行播放。

  2. 'readyToPlay' : Indicates that the player is ready to play AVPlayerItem instances. 'readyToPlay' :指示播放器已准备好播放AVPlayerItem实例。

  3. 'failed' : Indicates that the player can no longer play AVPlayerItem instances because of an error. 'failed' :指示播放器由于错误而无法播放AVPlayerItem实例。

As to how you could tell if the content is actually playing, you could just use boolean checks as it seems you have partially implemented. 至于如何判断内容是否真正在播放,则可以使用布尔检查,因为看起来好像已经部分实现了。 For pausing and stopping, you could just keep the file loaded for pause, and delete the file for stop that way you could differentiate the two. 对于暂停和停止,您可以仅使文件加载以暂停,然后通过停止删除文件来区分两者。

For buffering, if the enum is not unknown or readyToPlay then that theoretically should mean that there is a file being attached but is not quite ready to play (ie buffering). 对于缓冲,如果枚举不是未知的readyToPlay则从理论上讲应该意味着已附加文件但还没有准备好播放(即缓冲)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM