MPMusicPlayerController.systemMusicPlayer setQueue 困难
MPMusicPlayerController.systemMusicPlayer setQueue difficulties
我的音乐应用程序有问题。这个想法是点击一个按钮并播放当前正在播放的艺术家的更多歌曲。当我在应用程序中并点击下一首歌曲时,它工作正常。但是,如果我让歌曲自然结束,应用程序会随机播放一首歌曲。所以我添加了逻辑来说明如果歌曲剩余时间为 0,则使用媒体播放器功能播放下一首歌曲,因为我知道这行得通。这解决了它,除非应用程序在后台。如果应用程序在后台运行,我试图让它保持活动状态,但我想这不起作用。
每次我认为我已经解决了问题,但问题又回来了。
我希望发生的事情 是锁定艺术家,将应用程序关闭到后台,当歌曲结束时播放另一首艺术家的歌曲。
实际发生的事情 是当我锁定艺术家并将应用程序关闭到后台时,歌曲将结束,有时它会播放正确的歌曲。有时它不会。 然而 当它播放错误的歌曲并且我重新打开应用程序时它会结束当前(错误)播放的歌曲并开始播放正确艺术家的歌曲
要清楚,我认为当歌曲剩余时间为 0 时需要运行逻辑以跳到下一首歌曲是不明智的,但无论出于何种原因我需要它
我已将功能设置为后台获取和音频 Airplay 以及画中画
我试过按顺序只post相关代码..
我有一个属性
let mediaPlayer = MPMusicPlayerController.systemMusicPlayer
var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
在我的 ViewDidLoad
try? AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategorySoloAmbient)
try? AVAudioSession.sharedInstance().setActive(true)
DispatchQueue.main.async {
self.clearSongInfo()
MediaManager.shared.getAllSongs { (songs) in
guard let theSongs = songs else {
return
}
self.mediaPlayer.nowPlayingItem = nil
self.newSongs = theSongs.filter({ (item) -> Bool in
return !MediaManager.shared.playedSongs.contains(item)
})
self.aSongIsInChamber = true
self.mediaPlayer.setQueue(with: MPMediaItemCollection(items: self.newSongs.shuffled())
)
self.mediaPlayer.shuffleMode = .off
self.mediaPlayer.repeatMode = .none
}
NotificationCenter.default.addObserver(self, selector: #selector(self.songChanged(_:)), name: NSNotification.Name.MPMusicPlayerControllerNowPlayingItemDidChange, object: self.mediaPlayer)
self.mediaPlayer.beginGeneratingPlaybackNotifications()
}
我有一个函数可以更新播放时间和剩余时间,我有
if Int(self.songProgressSlider.maximumValue - self.songProgressSlider.value) < 1 {
print("song ended naturally, skipped")
mediaPlayer.prepareToPlay(completionHandler: { (error) in
DispatchQueue.main.async {
self.mediaPlayer.skipToNextItem()
}
})
}
当我播放音乐时我有一个布尔值 isPlaying
如果是,那么时间是 运行 我有这个
let app = UIApplication.shared
var task: UIBackgroundTaskIdentifier?
task = app.beginBackgroundTask {
app.endBackgroundTask(task!)
}
我要让计时器在后台保持开启状态,以便在剩余时间为 0 时播放下一首歌曲
现在要锁定一位艺术家,我有以下在点击按钮时执行的代码
let artistPredicate: MPMediaPropertyPredicate = MPMediaPropertyPredicate(value: nowPlaying.artist, forProperty: MPMediaItemPropertyArtist)
let query: MPMediaQuery = MPMediaQuery.artists()
let musicPlayerController: MPMusicPlayerController = MPMusicPlayerController.systemMusicPlayer
query.addFilterPredicate(artistPredicate)
musicPlayerController.setQueue(with: query)
我找到了一个不是 100% 我想要的解决方案,但现在我会接受它。
在我锁定艺术家的 IBAction 上,我最初只是
self.mediaPlayer.prepareToPlay { error in
let artistPredicate: MPMediaPropertyPredicate = MPMediaPropertyPredicate(value: nowPlaying.artist, forProperty: MPMediaItemPropertyArtist)
let query: MPMediaQuery = MPMediaQuery.artists()
let musicPlayerController: MPMusicPlayerController = MPMusicPlayerController.systemMusicPlayer
query.addFilterPredicate(artistPredicate)
musicPlayerController.setQueue(with: query)
}
添加了我为解决问题所做的工作
musicPlayerController.play()
设置队列后
这种方法的缺点是,如果我正在播放一首歌曲并点击按钮锁定艺术家,应用程序会立即结束正在播放的歌曲并转到该艺术家的歌曲,我宁愿歌曲完成播放然后播放我想要的歌曲。
如果有人能想出一种方法来使用 play() 并让歌曲自然结束,请将答案标记为正确...
注意 我从不想使用检查歌曲剩余时长的逻辑,也从不想使用后台代码。所以我摆脱了它,它仍然适用于新想法。
我发现设置队列不会 "take" 直到你说 prepareToPlay
(字面上或隐含地说 play
)。我的书的当前版本说:
My experience is that the player can behave in unexpected ways if you don't ask it to play
, or at least prepareToPlay
, immediately after setting the queue. Apparently the queue does not actually take effect until you do that.
你也说过(在评论中):
ideally I would like the song to finish first and then go onto the queue I have
好的,但也许您想要的是(iOS 11 中的新增功能)append
功能,它允许您修改队列而不完全替换它。
我的音乐应用程序有问题。这个想法是点击一个按钮并播放当前正在播放的艺术家的更多歌曲。当我在应用程序中并点击下一首歌曲时,它工作正常。但是,如果我让歌曲自然结束,应用程序会随机播放一首歌曲。所以我添加了逻辑来说明如果歌曲剩余时间为 0,则使用媒体播放器功能播放下一首歌曲,因为我知道这行得通。这解决了它,除非应用程序在后台。如果应用程序在后台运行,我试图让它保持活动状态,但我想这不起作用。
每次我认为我已经解决了问题,但问题又回来了。
我希望发生的事情 是锁定艺术家,将应用程序关闭到后台,当歌曲结束时播放另一首艺术家的歌曲。
实际发生的事情 是当我锁定艺术家并将应用程序关闭到后台时,歌曲将结束,有时它会播放正确的歌曲。有时它不会。 然而 当它播放错误的歌曲并且我重新打开应用程序时它会结束当前(错误)播放的歌曲并开始播放正确艺术家的歌曲
要清楚,我认为当歌曲剩余时间为 0 时需要运行逻辑以跳到下一首歌曲是不明智的,但无论出于何种原因我需要它
我已将功能设置为后台获取和音频 Airplay 以及画中画
我试过按顺序只post相关代码..
我有一个属性
let mediaPlayer = MPMusicPlayerController.systemMusicPlayer
var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
在我的 ViewDidLoad
try? AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategorySoloAmbient)
try? AVAudioSession.sharedInstance().setActive(true)
DispatchQueue.main.async {
self.clearSongInfo()
MediaManager.shared.getAllSongs { (songs) in
guard let theSongs = songs else {
return
}
self.mediaPlayer.nowPlayingItem = nil
self.newSongs = theSongs.filter({ (item) -> Bool in
return !MediaManager.shared.playedSongs.contains(item)
})
self.aSongIsInChamber = true
self.mediaPlayer.setQueue(with: MPMediaItemCollection(items: self.newSongs.shuffled())
)
self.mediaPlayer.shuffleMode = .off
self.mediaPlayer.repeatMode = .none
}
NotificationCenter.default.addObserver(self, selector: #selector(self.songChanged(_:)), name: NSNotification.Name.MPMusicPlayerControllerNowPlayingItemDidChange, object: self.mediaPlayer)
self.mediaPlayer.beginGeneratingPlaybackNotifications()
}
我有一个函数可以更新播放时间和剩余时间,我有
if Int(self.songProgressSlider.maximumValue - self.songProgressSlider.value) < 1 {
print("song ended naturally, skipped")
mediaPlayer.prepareToPlay(completionHandler: { (error) in
DispatchQueue.main.async {
self.mediaPlayer.skipToNextItem()
}
})
}
当我播放音乐时我有一个布尔值 isPlaying
如果是,那么时间是 运行 我有这个
let app = UIApplication.shared
var task: UIBackgroundTaskIdentifier?
task = app.beginBackgroundTask {
app.endBackgroundTask(task!)
}
我要让计时器在后台保持开启状态,以便在剩余时间为 0 时播放下一首歌曲
现在要锁定一位艺术家,我有以下在点击按钮时执行的代码
let artistPredicate: MPMediaPropertyPredicate = MPMediaPropertyPredicate(value: nowPlaying.artist, forProperty: MPMediaItemPropertyArtist)
let query: MPMediaQuery = MPMediaQuery.artists()
let musicPlayerController: MPMusicPlayerController = MPMusicPlayerController.systemMusicPlayer
query.addFilterPredicate(artistPredicate)
musicPlayerController.setQueue(with: query)
我找到了一个不是 100% 我想要的解决方案,但现在我会接受它。
在我锁定艺术家的 IBAction 上,我最初只是
self.mediaPlayer.prepareToPlay { error in
let artistPredicate: MPMediaPropertyPredicate = MPMediaPropertyPredicate(value: nowPlaying.artist, forProperty: MPMediaItemPropertyArtist)
let query: MPMediaQuery = MPMediaQuery.artists()
let musicPlayerController: MPMusicPlayerController = MPMusicPlayerController.systemMusicPlayer
query.addFilterPredicate(artistPredicate)
musicPlayerController.setQueue(with: query)
}
添加了我为解决问题所做的工作
musicPlayerController.play()
设置队列后
这种方法的缺点是,如果我正在播放一首歌曲并点击按钮锁定艺术家,应用程序会立即结束正在播放的歌曲并转到该艺术家的歌曲,我宁愿歌曲完成播放然后播放我想要的歌曲。
如果有人能想出一种方法来使用 play() 并让歌曲自然结束,请将答案标记为正确...
注意 我从不想使用检查歌曲剩余时长的逻辑,也从不想使用后台代码。所以我摆脱了它,它仍然适用于新想法。
我发现设置队列不会 "take" 直到你说 prepareToPlay
(字面上或隐含地说 play
)。我的书的当前版本说:
My experience is that the player can behave in unexpected ways if you don't ask it to
play
, or at leastprepareToPlay
, immediately after setting the queue. Apparently the queue does not actually take effect until you do that.
你也说过(在评论中):
ideally I would like the song to finish first and then go onto the queue I have
好的,但也许您想要的是(iOS 11 中的新增功能)append
功能,它允许您修改队列而不完全替换它。