I'm building an app that makes use of MPMusicPlayerApplicationController
to play music from a user's local music library.
The songs from the library are retrieved like so:
func retrieveMusic() {
mediaQueryQueue.async {
let songsQuery = MPMediaQuery.songs()
let songsCollections = songsQuery.collections
for songCollection in songsCollections ?? [] {
let songs = songCollection.items
self.retrievedSongs.append(contentsOf: songs)
}
DispatchQueue.main.async {
self.setLoadedSongsUIState()
self.setupTableView()
self.sortOrderDidChange()
}
}
}
These songs are then displayed in a table view:
func setTableViewItems(_ songs: [MPMediaItem]) {
let section = self.tableViewAdaptor!.sections[0] as! TableViewAdaptorSection<SongTableViewCell, MPMediaItem>
section.items = songs
tableViewAdaptor.tableView.reloadData()
}
I also have a segment control that will determine whether to display the songs in the order in which they were retrieved, or in the last played order; and then update the table view based on which choice was selected:
var retrievedSongs: [MPMediaItem] = []
var sortedSongs: [MPMediaItem] = []
private func sortOrderDidChange() {
switch sortOrder {
case .playDateDescending:
let unixDate = Date(timeIntervalSince1970: 1000)
sortedSongs = retrievedSongs.sorted {
$0.lastPlayedDate ?? unixDate > $1.lastPlayedDate ?? unixDate
}
default:
sortedSongs = retrievedSongs
}
setTableViewItems(sortedSongs)
let queueDescriptor = MPMusicPlayerMediaItemQueueDescriptor(itemCollection: MPMediaItemCollection(items: sortedSongs))
queueDescriptor.startItem = musicPlayer.nowPlayingItem
musicPlayer.setQueue(with: queueDescriptor)
selectPlayingItem(scrollToVisible: true)
}
The user is able to use buttons to play/pause, and go to the next or previous tracks:
@IBAction func forwardButtonPressed(_ sender: Any) {
musicPlayer.skipToNextItem()
selectPlayingItem(scrollToVisible: true)
}
@IBAction func backButtonPressed(_ sender: Any) {
musicPlayer.skipToPreviousItem()
selectPlayingItem(scrollToVisible: true)
}
Additionally, if you select a track in the table view, that track will be played:
tableViewAdaptor = TableViewAdaptor(
tableView: songTableView,
sections: [songsLibrarySection],
didChangeHandler: {
let selectedSongIndex = self.songTableView.indexPathForSelectedRow
if selectedSongIndex != nil {
let selectedSong = self.retrievedSongs[selectedSongIndex!.row]
self.musicPlayer.nowPlayingItem = selectedSong
self.musicPlayer.play()
self.updatePlaybackUI(scrollNowPlayingToVisible: true)
}
})
setTableViewItems(retrievedSongs)
When the songs are displayed in the order in which they were retrieved, everything works perfectly. If I click back or forwards, or select a song to play; the correct song will play in the next order.
Right now if you're in the "order retrieved" tab, and you go to the "ordered by date" tab and click backwards or forward, the next song will not be whatever is next that's displayed in the table view, but in the "retrieved" by order.
What I'm trying to do is change the code so that no matter whether the retrieved or ordered songs are displayed, the next or previous song will correspond to what's displayed.
from Displaying and Playing MPMediaItem songs in retrieved + last played order
No comments:
Post a Comment