为什么 AVPlayer 在后台时不继续播放下一首歌曲?
Why is AVPlayer not continuing to next song while in background?
我一直在使用 AVPlayer 从远程源流式传输音乐。我得到 URLs,使用一个来创建一个 AVPlayerItem,然后我将其与我的 AVPlayer 实例相关联。我向与玩家相关联的项目添加了一个观察者,以观察该项目何时结束播放 ( AVPlayerItemDidPlayToEndTimeNotification
)。当观察者在项目结束时通知我时,我然后创建一个新的 AVPlayerItem 并重新做一遍。这在 iOS 9.2 的前台和后台运行良好。
问题: 因为我已经更新到 iOS 9.3 这在后台不起作用。这是相关代码:
var portionToBurffer = Double()
var player = AVPlayer()
func prepareAudioPlayer(songNSURL: NSURL, portionOfSongToBuffer: Double){
self.portionToBuffer = portionOfSongToBuffer
//create AVPlayerItem
let createdItem = AVPlayerItem(URL: songNSURL)
//Associate createdItem with AVPlayer
player = AVPlayer(playerItem: createdItem)
//Add item end observer
NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerItemDidReachEnd:", name: AVPlayerItemDidPlayToEndTimeNotification, object: player.currentItem)
//Use KVO to see how much is loaded
player.currentItem?.addObserver(self, forKeyPath: "loadedTimeRanges", options: .New, context: nil)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if keyPath == "loadedTimeRanges" {
if let loadedRangeAsNSValueArray = player.currentItem?.loadedTimeRanges {
let loadedRangeAsCMTimeRange = loadedRangeAsNSValueArray[0].CMTimeRangeValue
let endPointLoaded = CMTimeRangeGetEnd(loadedRangeAsCMTimeRange)
let secondsLoaded = CMTimeGetSeconds(endPointLoaded)
print("the endPointLoaded is \(secondsLoaded) and the duration is \(CMTimeGetSeconds((player.currentItem?.duration)!))")
if secondsLoaded >= portionToBuffer {
player.currentItem?.removeObserver(self, forKeyPath: "loadedTimeRanges")
player.play()
}
}
}
}
func playerItemDidReachEnd(notification: NSNotification){
recievedItemEndNotification()
}
func recievedItemEndNotification() {
//register background task
bgTasker.registerBackgroundTask()
if session.playlistSongIndex == session.playlistSongTitles.count-1 {
session.playlistSongIndex = 0
} else {
session.playlistSongIndex += 1
}
prepareAudioPlayer(songURL: session.songURLs[session.playlistSongIndex], portionOfSongToBuffer: 30.00)
}
我设置了断点以查看 player.play()
在后台被调用。当我打印 player.rate
时,它显示为 0.0
。我检查了 AVPlayerItem 的 属性 playbackLikelyToKeepUp
,它是 true
。我还确认新的 URL 已成功用于创建新的 AVPlayerItem 并在应用程序处于后台时与 AVPlayer 关联。我已经打开音频和 airplay 后台功能,我什至打开了一个有限长度的后台任务(在上面的代码中为 bgTasker.registerBackgroundTask
)。不知道发生了什么。
我找到了 THIS,但我不确定它是否有帮助。任何建议都很好,谢谢
When the observer notifies me at the item end, I then create a new AVPlayerItem and do it all over again
但问题是同时停止播放,规则是只有在前台播放时才允许后台播放,然后继续在后台播放。
我建议使用 AVQueuePlayer 而不是 AVPlayer。这将允许您在当前项目仍在播放时将下一个项目加入队列——因此,我们可能希望,这将被视为继续播放。
我遇到了类似的问题,我在google上搜索了很多网站,但没有找到答案。
现象
我的应用程序的问题是,当我开始播放音频时,将应用程序切换到后台,它会完成当前音频的播放,而在播放第二个音频时,它会加载一些数据,但是然后它停止了,如果我把应用程序转到前台,它会播放音频。
解决方案
我的解决方法是添加如下调用。
UIApplication.shared.beginReceivingRemoteControlEvents()
所以启用后台音频功能还不够,我们需要开始接收遥控器事件。
我一直在使用 AVPlayer 从远程源流式传输音乐。我得到 URLs,使用一个来创建一个 AVPlayerItem,然后我将其与我的 AVPlayer 实例相关联。我向与玩家相关联的项目添加了一个观察者,以观察该项目何时结束播放 ( AVPlayerItemDidPlayToEndTimeNotification
)。当观察者在项目结束时通知我时,我然后创建一个新的 AVPlayerItem 并重新做一遍。这在 iOS 9.2 的前台和后台运行良好。
问题: 因为我已经更新到 iOS 9.3 这在后台不起作用。这是相关代码:
var portionToBurffer = Double()
var player = AVPlayer()
func prepareAudioPlayer(songNSURL: NSURL, portionOfSongToBuffer: Double){
self.portionToBuffer = portionOfSongToBuffer
//create AVPlayerItem
let createdItem = AVPlayerItem(URL: songNSURL)
//Associate createdItem with AVPlayer
player = AVPlayer(playerItem: createdItem)
//Add item end observer
NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerItemDidReachEnd:", name: AVPlayerItemDidPlayToEndTimeNotification, object: player.currentItem)
//Use KVO to see how much is loaded
player.currentItem?.addObserver(self, forKeyPath: "loadedTimeRanges", options: .New, context: nil)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if keyPath == "loadedTimeRanges" {
if let loadedRangeAsNSValueArray = player.currentItem?.loadedTimeRanges {
let loadedRangeAsCMTimeRange = loadedRangeAsNSValueArray[0].CMTimeRangeValue
let endPointLoaded = CMTimeRangeGetEnd(loadedRangeAsCMTimeRange)
let secondsLoaded = CMTimeGetSeconds(endPointLoaded)
print("the endPointLoaded is \(secondsLoaded) and the duration is \(CMTimeGetSeconds((player.currentItem?.duration)!))")
if secondsLoaded >= portionToBuffer {
player.currentItem?.removeObserver(self, forKeyPath: "loadedTimeRanges")
player.play()
}
}
}
}
func playerItemDidReachEnd(notification: NSNotification){
recievedItemEndNotification()
}
func recievedItemEndNotification() {
//register background task
bgTasker.registerBackgroundTask()
if session.playlistSongIndex == session.playlistSongTitles.count-1 {
session.playlistSongIndex = 0
} else {
session.playlistSongIndex += 1
}
prepareAudioPlayer(songURL: session.songURLs[session.playlistSongIndex], portionOfSongToBuffer: 30.00)
}
我设置了断点以查看 player.play()
在后台被调用。当我打印 player.rate
时,它显示为 0.0
。我检查了 AVPlayerItem 的 属性 playbackLikelyToKeepUp
,它是 true
。我还确认新的 URL 已成功用于创建新的 AVPlayerItem 并在应用程序处于后台时与 AVPlayer 关联。我已经打开音频和 airplay 后台功能,我什至打开了一个有限长度的后台任务(在上面的代码中为 bgTasker.registerBackgroundTask
)。不知道发生了什么。
我找到了 THIS,但我不确定它是否有帮助。任何建议都很好,谢谢
When the observer notifies me at the item end, I then create a new AVPlayerItem and do it all over again
但问题是同时停止播放,规则是只有在前台播放时才允许后台播放,然后继续在后台播放。
我建议使用 AVQueuePlayer 而不是 AVPlayer。这将允许您在当前项目仍在播放时将下一个项目加入队列——因此,我们可能希望,这将被视为继续播放。
我遇到了类似的问题,我在google上搜索了很多网站,但没有找到答案。
现象
我的应用程序的问题是,当我开始播放音频时,将应用程序切换到后台,它会完成当前音频的播放,而在播放第二个音频时,它会加载一些数据,但是然后它停止了,如果我把应用程序转到前台,它会播放音频。
解决方案
我的解决方法是添加如下调用。
UIApplication.shared.beginReceivingRemoteControlEvents()
所以启用后台音频功能还不够,我们需要开始接收遥控器事件。