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

时间:2019-01-13 22:54:22

标签: ios swift mpmusicplayercontroller

我真的很想找出解决办法,而且我在互联网上看了很多,却找不到答案。如您所知,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

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

1 个答案:

答案 0 :(得分:3)

MPMusicPlayerController(及其相关子类)使得很难无缝地管理这样的队列。如果我没记错的话,您甚至无法将重复的MPMediaItem对象添加到队列中,并且从Control Center中点击播放媒体实际上将启动Music应用程序,而不是您自己的应用程序。本质上,您的应用只能充当音乐播放体验的外壳,而音乐应用正在承担所有繁重的工作。

根据您的要求,尽管有一些折衷,您可能还有其他选择。 AVFoundation框架提供 AVPlayerAVQueuePlayer,这使得管理队列和提供更多高级播放选项更加容易。但是,您只能播放仅下载的,无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中一次或两次,这样就不必弄乱其用于插入/删除媒体的API。