0

此代码导致沉默:

let query = MPMediaQuery.songs()
let result = query.items
guard let items = result, items.count > 0 else {return}
let song = items[0]

let player = MPMusicPlayerController.applicationQueuePlayer

let coll = MPMediaItemCollection(items: [song])
let q = MPMusicPlayerMediaItemQueueDescriptor(itemCollection: coll)
player.setQueue(with: q)
player.play()

我已经浏览了代码,我们到达了player.play(). 我有一个 MPMediaItem 并且我已经正确地形成了一个 MPMediaItemCollection 和一个MPMusicPlayerMediaItemQueueDescriptor。那为什么我的播放器不玩了?

4

3 回答 3

2

斯威夫特 5

我参加演出有点晚了,但这就是我想出的。(我正在修剪歌曲以使用描述符播放)。

确保在主线程上使用音乐播放器运行所有内容。否则,您将遇到奇怪的错误。

通过 persistentId 获取歌曲:

/// Retrieves a song in the MPMediaItem format using the persistentId passed.
/// - Parameter persistentID: (UInt64) The songs persistentId.
/// - Returns: (MPMediaItem?) Nil if not found other wise the MPMediaItem (song).
private static func getSong(forId persistentID: UInt64) -> MPMediaItem? {
    let query = MPMediaQuery.songs()
    let predicate = MPMediaPropertyPredicate(value: persistentID, forProperty: MPMediaItemPropertyPersistentID)
    query.addFilterPredicate(predicate)
    return query.items?.first
}

通过 persistentId 播放歌曲:

private var startTime: Double = 0
private var endTime: Double = 0


/// Plays the song with the identifier.
/// - Note: Trims song to start and end time.
/// - Parameter persistentId: (UInt64) The song persistent identifier.
private func play(forId persistentId: UInt64) {
    DispatchQueue.main.async {
        if let song = Self.getSong(forId: persistentId) {
            let identifier = MPMediaItemPropertyPersistentID
            let predicate = MPMediaPropertyPredicate(value: persistentId, forProperty: identifier)
            let query = MPMediaQuery(filterPredicates: [predicate])
            let descriptor = MPMusicPlayerMediaItemQueueDescriptor(query: query)
            descriptor.setStartTime(self.startTime, for: song)
            descriptor.setEndTime(self.endTime, for: song)
            self.musicPlayer.setQueue(with: descriptor)
            self.musicPlayer.prepareToPlay()
            self.musicPlayer.repeatMode = .none
            self.musicPlayer.play()
        }
    }
}

我还发现初始化音乐控制器的方式很重要:

private lazy var musicPlayer: MPMusicPlayerController = { MPMusicPlayerController.applicationQueuePlayer }()

请注意:有些代码不是拖放的。您需要定义诸如开始和结束时间变量之类的东西。

于 2020-07-14T03:42:10.217 回答
1

你发现了一个错误。初始化程序似乎MPMusicPlayerMediaItemQueueDescriptor(itemCollection:)完全被破坏了:它导致了一个不可用的队列描述符。

在可能的情况下,解决方法是使用另一个初始化程序,即MPMusicPlayerMediaItemQueueDescriptor(query:).

例如,在这种情况下,您可以编写(从原始代码的最后四行开始):

let coll = MPMediaItemCollection(items: [song])
let predicate = MPMediaPropertyPredicate(
                value: song.persistentID,
                forProperty: MPMediaItemPropertyPersistentID)
let query = MPMediaQuery(filterPredicates: [predicate])
let q = MPMusicPlayerMediaItemQueueDescriptor(query: query)
player.setQueue(with: q)
player.play()

不幸的是,在许多情况下,您无法形成一个单一的查询来获得您真正想要的 MPMediaItemCollection。

在这个特定的示例中,您也可以通过直接使用 MPMediaItemCollection 而不是由 MPMediaItemCollection 生成的 MPMusicPlayerMediaItemQueueDescriptor 设置播放器的队列来解决这个问题。

但是很可惜,有些命令(例如append(_:)需要MPMusicPlayerMediaItemQueueDescriptor,而对于这样的事情,整个 API 基本上都被占用了。自 iOS 10.1 以来,它就一直在使用软管,并且在 iOS 11.1 中仍然保持软管状态。

于 2017-10-19T18:40:01.387 回答
1

“它自 iOS 10.1 以来就一直在使用软管,并且在 iOS 11.1 中仍然保持软管状态。” 借调。

我一直在进行一场旷日持久的战斗,只是试图 a)让 MPMusicPlayerController 简单地工作(最终管理它)和 b)让它从偏移量播放一首歌曲(仍然没有)。这是在 iOS 10 之前 100% 按预期运行的应用程序中。

现在,这是对我有用的代码(至少在播放歌曲方面):

let currentPlayer = MPMusicPlayerController.applicationQueuePlayer()
currentPlayer.repeatMode = .none

self.currentCollection = MPMediaItemCollection(items: [mediaItem])
currentPlayer.beginGeneratingPlaybackNotifications()

let query = MPMediaQuery.songs()
let pred = MPMediaPropertyPredicate(value: mediaItem.persistentID, forProperty: MPMediaItemPropertyPersistentID)
query.addFilterPredicate(pred)
let desc = MPMusicPlayerMediaItemQueueDescriptor(query: query)
currentPlayer.setQueueWith(desc)

currentPlayer.prepareToPlay(completionHandler: {[unowned self] (error) in
    MPMusicPlayerController.applicationQueuePlayer().play()
})

这有点令人费解,因为我不得不使用我认为基于可用 API 的最复杂的方法。但是其他几种方法会导致完成块永远不会被调用或得到一个完全无用的错误。现在我有 5 个关于 MPMusicPlayerController 的错误报告给苹果,所以我现在不是一个快乐的开发者。我将打开另一个与此代码相关的代码,因为 setStartTime 和 setEndTime 似乎并不比 currentPlaybackTime 更好地从指定的偏移量开始播放。

不过,此代码确实可以可靠地播放同步和下载的 Apple Music 项目。

于 2017-11-11T23:14:17.457 回答