2017-07-28 61 views
0

我正在使用AVPlayer播放流式音频,并且希望阻止它一次播放多个音轨。什么是最好的方法来做到这一点?我的方法完全是编程式的 - 我不使用故事板。当一个URL被发送到ViewController(VC,委托)时,它会建立一个新的播放器实例 - 我认为这是问题,但我不确定。谢谢。防止AVPlayer一次播放多个音轨的最佳方法

//this routine returns the url from control to the VC (delegate) 
    func selectedAudio(_ audioUrl:String?) { 
    if let urlString = audioUrl { 
     setupPlayer(urlString) 
    } 
    } 

    //single button which toggles between play/pause 
    func playOrPauseTouched() { 
    if isPlaying { 
     pausePlayer() 
    } else { 
     playPlayer() 
    } 
    } 

    func playPlayer() { 
    if player == nil || selectedTrackName != currentTrackLabel.text{ 
     if let urlString = selectedAudioUrl { 
     setupPlayer(urlString) 
     currentTrackLabel.text = "Playing: \(selectedTrackName ?? "")" 
     } 
    } 
    player?.play() 
    isPlaying = true 
    playPauseButton.setImage(UIImage(named: "pause"), for: .normal) 
    activityIndicatorView.startAnimating() 
    } 

    func pausePlayer() { 
    player?.pause() 
    isPlaying = false 
    playPauseButton.setImage(UIImage(named: "play"), for: .normal) 
    } 

    func setupPlayer(_ urlString:String) { 
    if let url = URL(string:urlString) { 
     player = AVPlayer(url: url) 
     let playerLayer = AVPlayerLayer(player: player) 
     player?.addObserver(self, forKeyPath: "currentItem.loadedTimeRanges", options: .new, context: nil) 
     let interval = CMTime(value: 1, timescale: 5) //gives smooth thumb movement w/short clips 
     player?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: { (progressTime) in 
     let seconds = CMTimeGetSeconds(progressTime) 
     let secondsString = String(format: "%02d", Int(seconds.truncatingRemainder(dividingBy: 60))) 
     let minutesString = String(format: "%02d", Int(seconds/60)) 
     self.currentTimeLabel.text = "\(minutesString):\(secondsString)" 
     if let duration = self.player?.currentItem?.duration { 
      let durationSeconds = CMTimeGetSeconds(duration) 
      self.audioSlider.value = Float(seconds/durationSeconds) 
     } 
     }) 
    } 
    } 
+0

您是否在创建新实例之前尝试停止'player'? –

+0

我不知道AVPlayer的停止方法(虽然我见过一个AVAudioPlayer)。但我可能会错过一些东西。我知道的唯一文档是Objective-C而不是Swift,这使我很难 –

+0

事实上,没有停止方法。尝试['pause()'](https://developer.apple.com/documentation/avfoundation/avplayer/1387895-pause)有助于了解它是否是之前的“AVPlayer”。 –

回答

1

我的意见是使用KVO,将通知您的AVPlayerItem当前状态。

表示您将获得state,这将帮助您识别当前项目正在播放,推送,缓冲或完成播放。

所以你应该采取一个flag,将处理您当前的项目state

Ex。当项目正在播放

  • 设置标志为假时,项目完成打

    • 设置标志真实的。
    • 当你点击按钮播放另一个项目,然后检查像if flag == false标志,然后开始播放另一个项目,否则不是。

    方式二:

    使用NotificationCenter像下面

    NotificationCenter.default.addObserver(self, selector: Selector(("playerDidFinishPlaying:")), 
         name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem) 
    

    及以下时,项目完成打

    func playerDidFinishPlaying(note: NSNotification) { 
        print("Item finished playing ") 
        // Set flag here 
    } 
    

    和管理的标志作为相同自动调用。

  • +0

    谢谢,您的指示非常明确,但由于我只知道KVO,所以我已经使用它的地方都只是复制其他代码片段。我需要更多地了解如何编写该代码。 –

    +0

    @TonyM - 你可以使用第二种方式 – Govaadiyo