【问题标题】:When do AVPlayer and AVPlayerItem status change?AVPlayer 和 AVPlayerItem 状态什么时候改变?
【发布时间】:2019-10-05 08:57:39
【问题描述】:

我正在使用 AVFoundation 在颤振中开发一个音乐播放器插件,我想在 iOS 和 Android 上创建一个统一的界面。

我想捕获AVPlayer 可能引发的错误,例如,给定的AVPlayerItem 无效(包含不受支持的文件的URL,如png 文件)。

我希望AVPlayer.replace() 抛出异常或更改AVPlayerItemAVPlayer 的状态,或者至少在NSNotificationCeter 上发出一些相关通知。我尝试听/观察所有这些,但没有一个报告任何类型的错误。事实上,AVPlayer 报告了“ready-to-play”状态。

    mediaPlayer = AVPlayer();
    playerItem = AVPlayerItem(url: URL(fileURLWithPath: Bundle.main.path(forResource: "image", ofType: "png")!))

    playerItem?.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), options: [.old, .new], context: &playerItemContext)
    mediaPlayer?.addObserver(self, forKeyPath: #keyPath(AVPlayer.status), options: [.old, .new], context: &mediaPlayerContext)

    mediaPlayer?.replaceCurrentItem(with: playerItem); // this changes player status to - "ready-to-play"
    mediaPlayer?.play() // this does not report anything

我是一名 Android 开发人员,无法理解 AVPlayer 的工作原理。我怎样才能做到这一点?

注意:我不能使用AVAudioPlayer,因为文档说在播放来自网络或可能有延迟的来源的音乐时不应该使用它。

self.mediaPlayer?.replaceCurrentItem(with: nil)
self.mediaPlayer?.play()

即使这段代码也不会产生错误

【问题讨论】:

  • 这与AVPlayer无关。如果媒体播放器本身为 nil,self.mediaPlayer?.play() 什么都不做。该行代码只是中止。那么它怎么可能产生错误呢?这不是 Swift 的工作方式。
  • 可以观察avplayer的current itemerror属性
  • @matt 问题已被编辑。

标签: ios swift xcode avfoundation avplayer


【解决方案1】:
private func addObserverPlayerItem()
    {
        if let playerItem = self.player?.currentItem{
            playerItem.addObserver(self, forKeyPath: "playbackBufferEmpty", options: .new, context: nil)
            playerItem.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: .new, context: nil)
            playerItem.addObserver(self, forKeyPath: "playbackBufferFull", options: .new, context: nil)
            playerItem.addObserver(self, forKeyPath: "loadedTimeRanges", options: [.new], context: nil)
            self.player?.addObserver(self, forKeyPath: #keyPath(AVPlayer.currentItem.status), options: [.new, .initial], context: nil)
            self.player?.addObserver(self, forKeyPath: #keyPath(AVPlayer.status), options: [.new, .initial], context: nil)
        }
    }

override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if object is AVPlayerItem {
            switch keyPath {

            case "loadedTimeRanges":

                let duration = self.currentItem?.totalBuffer() ?? 0
                let totalduration = currentItem?.asset.duration
                self.videoControll?.slider.bufferEndValue = totalduration?.seconds ?? 0
                self.videoControll?.slider.bufferStartValue = (duration) / (totalduration?.seconds ?? 1)
                print((duration) / (totalduration?.seconds ?? 1))

            case "playbackBufferEmpty":
                // Show loader
                self.activityIndicator?.startAnimating()

            case "playbackLikelyToKeepUp":
                // Hide loader
                self.activityIndicator?.stopAnimating()

            case "playbackBufferFull":
                // Hide loader
                self.activityIndicator?.stopAnimating()
            case #keyPath(AVPlayer.currentItem.status):

                let newStatus: AVPlayerItem.Status
                if let newStatusAsNumber = change?[NSKeyValueChangeKey.newKey] as? NSNumber {
                    newStatus = AVPlayerItem.Status(rawValue: newStatusAsNumber.intValue)!
                } else {
                    newStatus = .unknown
                }
                if newStatus == .failed {
                    NSLog("SA Detected Error: \(String(describing: self.player?.currentItem?.error?.localizedDescription)), error: \(String(describing: self.player?.currentItem?.error))")
                }
            case #keyPath(AVPlayer.status):
                print()
            case .none:
                self.activityIndicator?.stopAnimating()
            case .some(_):
                self.activityIndicator?.stopAnimating()
            }
        }
    }

【讨论】:

    【解决方案2】:

    您可以借助 AVplayer 的 属性跟踪播放器的状态。

    当 timeControlStatus 的值为 AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate 时,此属性描述了播放器当前等待的原因。否则为零。 您可以使用 reasonForWaitingToPlay 的值来有条件地显示指示玩家等待状态的 UI。 该属性是可观察的键值。 可能的值为 AVPlayerWaitingWithNoItemToPlayReason、AVPlayerWaitingWhileEvaluatingBufferingRateReason 和 AVPlayerWaitingToMinimizeStallsReason。

    如果此属性的值为 nil,则表示当前玩家正在玩游戏。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多