Using Swift to display title of currently playing .MP3
Asked Answered
H

2

6

I was wondering if there was a straight forward way of displaying the image and title of the currently playing MP3 file my music player is playing. My code is as follows and is very simple for this example. I am only wanting to test using one .MP3 that I've included in my project.

class ViewController: UIViewController {
    let audioPath:NSURL! = NSBundle.mainBundle().URLForResource("SippinOnFire", withExtension: "mp3")

    @IBOutlet var sliderValue: UISlider!
    var player:AVAudioPlayer = AVAudioPlayer()


    @IBAction func play(sender: AnyObject) {

        player.play()
        //println("Playing \(audioPath)")
    }
    @IBAction func pause(sender: AnyObject) {

        player.pause()
    }
    @IBAction func stop(sender: AnyObject) {

        player.stop()
        player.currentTime = 0;
    }
    @IBAction func sliderChanged(sender: AnyObject) {

        player.volume = sliderValue.value

    }

    override func viewDidLoad() {
        super.viewDidLoad()

                 var error:NSError? = nil

        player = AVAudioPlayer(contentsOfURL: audioPath!, error: &error)

        player.volume = 0.5;

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

So far I am able to println the full path to the MP3 file but have not been able to use the display the image that is showing as the cover art for my MP3 in the project or to display only the title of the track playing. Could someone help me out with this?

Halstead answered 13/5, 2015 at 13:15 Comment(2)
Can you add some code or links on how to do it in Objective C? There are many here that could convert it easily to Swift for you.Geralyngeraniaceous
Here is a link addressing the issues in the other language. I figured it cleaner to do it this way than to try to post code all over the place. #14031246Halstead
C
11

you need to add the import statement for Media player and set the General Media Item Property Keys for nowPlayingInfo property. For the MPMediaItemPropertyArtwork you need to take a look at this MPMediaItemArtwork

import MediaPlayer

let audioInfo = MPNowPlayingInfoCenter.defaultCenter()
let audioName = audioPath.lastPathComponent!.stringByDeletingPathExtension
audioInfo.nowPlayingInfo = [ MPMediaItemPropertyTitle: audioName, MPMediaItemPropertyArtist:"artistName"]

To extract the metadata from your mp3 you need to create an AVPlayerItem and access its asset commonMetadata property

let playerItem = AVPlayerItem(URL: audioPath)
let metadataList = playerItem.asset.commonMetadata as! [AVMetadataItem]
for item in metadataList {
    if item.commonKey == "title" {
        println("Title = " + item.stringValue)
    }
    if item.commonKey == "artist" {
        println("Artist = " + item.stringValue)
    }
}       

Note: You will have to invoke beginReceivingRemoteControlEvents() otherwise it will not work on the actual device.

override func viewDidLoad() {
    super.viewDidLoad()
    UIApplication.sharedApplication().beginReceivingRemoteControlEvents()
}
Cordelia answered 13/5, 2015 at 13:31 Comment(11)
Thank you. I've used your code from you answer yet when I println("nowPlayingInfo") the result I get is :[title: songName, artist: artistName]. I am confused as to how I can use your code to display the track artwork and the title still. Do I need to create variables holding the title and call it with the nowPlayingInfo code?Halstead
I was able to find this example but it isn't in Swift. Could you help me translate it so I could apply it in my Swift project? ios-blog.co.uk/tutorials/how-to-play-music-in-your-appHalstead
audioPath.lastPathComponent!.stringByDeletingPathExtensionCordelia
That works beautifully for grabbing the filename of the MP3. Thanks for that. I am, however, more interested in grabbing the actual "Title" of the track from it's ID3 tag data stored within the file. This would also include the Album name, producer info. etc. Is there a way to access this through code?Halstead
You would probably have to create an asset from your media url developer.apple.com/library/ios/documentation/AVFoundation/…:Cordelia
developer.apple.com/library/ios/documentation/AVFoundation/…Cordelia
Thanks alot! I found this (#7708013). Of course, this is not in Swift but looks like it accomplishes what I am trying to do. This is a bit frustrating because it seems as though Swift isn't often used in alot of these scenarios, making this difficult to try to translate. If there is anyone out there up to the challenge you would be my hero!Halstead
OH! This is SO close! This gives me the complete metadata for the track. If I, for example, only wanted to add specific fields to labels (title and artist) on the player, how would I specifically select each one of these? This prints the entire metadata info, which is probably more than I need. I really appreciate your help!Halstead
kkkkk This is not like hold my hand and walk with me all the way. I showed the path you should at least do that little part picking the info you want from there. Anyway I will show it for you when I get back to my Mac Pro if you don't figure out it by yourself before I get back.Cordelia
I understand your frustration with me. I don't have a wealth of experience in Swift or debugging it with this and am trying hard to solve the rest of it on my own. I've managed to see that there is a property called "commonKey" that holds the "title" identifier that I am trying to retrieve, but when I try to debug "item" as it iterates through your code before println each items value it doesn't show me a whole lot to go on. Sorry if I've been annoying, but know that I am doing my best to learn this. Thanks again for your helpHalstead
Thanks so much for your help Leonardo!! I managed to accomplish is by looking inside the item.commonkey == "title" and then printing the value to my label. I couldn't have done it without your assistance! Cheers!Halstead
H
1

With Leonardo's help I was able to accomplish this using the following code:

@IBAction func play(sender: AnyObject) {


    let audioInfo = MPNowPlayingInfoCenter.defaultCenter()
println(audioInfo)


    player.play()
    //println("Playing \(audioPath)")


    let playerItem = AVPlayerItem(URL: audioPath)
    let metadataList = playerItem.asset.commonMetadata as! [AVMetadataItem]


    for item in metadataList {
        if let stringValue = item.value as? String {
           println(item.commonKey)
            if item.commonKey == "title" {
                trackLabel.text = stringValue
            }
            if item.commonKey == "artist" {
                artistLabel.text = stringValue
            }

        }
    }
}

You can selectively pick which commonkeys you would like to use with if statements like these and print the text to the labels like this:

            if item.commonKey == "title" {
                trackLabel.text = stringValue
            }
            if item.commonKey == "artist" {
                artistLabel.text = stringValue
            }

Thank you Leonardo for your assistance!

Halstead answered 14/5, 2015 at 17:43 Comment(2)
I have edited my answer AVMetadataItem has already a stringValue property, so no need to cast the value as StringCordelia
developer.apple.com/library/prerelease/ios/documentation/…Cordelia

© 2022 - 2024 — McMap. All rights reserved.