重新排列 MediaPlayer 音乐队列 [iOS]

Rearrange MediaPlayer Music Queue [iOS]

我真的很难弄明白,我在网上找遍了,但找不到答案。如您所知,Spotify 和 Apple Music 等音乐应用程序本身允许用户重新排列下一个队列,即使用户正在收听歌曲。我一直无法弄清楚如何做同样的事情。我希望能够完全重新排列队列,包括添加、删除和移动下一队列中的歌曲。我尝试了各种方法,例如

musicPlayer.setQueue([queue])

但这需要我调用 musicPlayer.prepareToPlay() 后记来更新队列,这将结束当前歌曲并启动新队列。

我也试过使用

musicPlayer.perform(queueTransaction: { (currentQueue) in
    let oldItems = currentQueue.items

    var currentItem: MPMediaItem? = nil
    for (i, item) in oldItems.enumerated() {
        if i == musicPlayer.indexOfNowPlayingItem {
            currentItem = item
            continue
        }

        currentQueue.remove(item)
    }

    currentQueue.insert(queue, after: currentItem)
}, completionHandler: { (newQueue, error) in
    if let error = error {
        print("there was an error updating the queue", error)
        return
    }

    print("===  NEW QUEUE  ===")  //insert does not work
    for item in newQueue.items {
        print("  -", item.title ?? "[No Title]")
    }
})

但是你可能从这个问题中知道: MPMusicPlayerControllerMutableQueue insert an Apple Music song not working

队列的项目后插入功能似乎不起作用(我也尝试将项目设置为 nil,这有时会删除当前项目并将队列设置为空)。我也知道 musicPlayer.prepend([queue]) 它将在当前播放的项目之后添加新队列,但我还必须从内存中删除以前的队列,这样下一个队列最终不会超过 300 首歌曲。我也试过在队列事务中使用 prepend 函数,但有时歌曲会在中间停止,音乐播放器会将 nowPlayingItem 设置为 nil。我真的希望有人知道这个问题的答案,因为我已经遇到这个问题 4 天多了,而且我似乎找不到 100% 有效的解决方案。

MPMusicPlayerController(及其相关的子类)使得像这样无缝地管理队列变得非常困难。如果我没记错的话,你甚至无法将重复的 MPMediaItem 对象添加到队列中,并且从控制中心点击播放媒体实际上会启动音乐应用程序而不是你自己的应用程序。从本质上讲,您的应用程序只能充当音乐播放体验的 shell,而音乐应用程序正在完成所有繁重的工作。

根据您的要求,您可能还有其他选择,尽管会有一些妥协。 AVFoundation 框架提供 AVPlayer and AVQueuePlayer,可以更轻松地管理队列并提供更高级的播放选项。但是,您只能播放已下载的无 DRM 内容(即 Apple Music 中的歌曲将无法播放)。

设置您的播放器:

let audioPlayer = AVQueuePlayer()

// Play next song in queue.
NotificationCenter.default.addObserver(self, selector: #selector(didPlayToEndTime), name: .AVPlayerItemDidPlayToEndTime, object: nil)

// Recover from failed playback.
NotificationCenter.default.addObserver(self, selector: #selector(failedToPlayToEndTime(_:)), name: .AVPlayerItemFailedToPlayToEndTime, object: nil)

// Resume music after interruptions.
NotificationCenter.default.addObserver(self, selector: #selector(handleAudioSessionInterruption(_:)), name: .AVAudioSessionInterruption, object: AVAudioSession.sharedInstance())

在队列中插入新项目:

let media = MPMediaQuery.songs()
let mediaItem: MPMediaItem = media.items.first!

// MPMediaItem objects stored in iCloud or from Apple Music
// will not have a URL, therefore, they cannot be played.
guard let assetURL: URL = mediaItem.assetURL else { return }

let playerItem = AVPlayerItem(url: assetURL)
playerItem.seek(to: kCMTimeZero)
audioPlayer.insert(playerItem, after: nil)

在我的音乐播放器应用程序中,我保留了一个 Array 媒体以便重新排序、插入和删除媒体非常简单,还保留了一个索引来跟踪当前播放的曲目。然后,我一次将媒体传递给 AVQueuePlayer 一两个,这样我就不必为 inserting/removing 媒体弄乱它的 API。