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?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Unconquered82
  • 523
  • 1
  • 8
  • 17
  • 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. – pteofil May 13 '15 at 13:29
  • 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. http://stackoverflow.com/questions/14030746/ios-avfoundation-how-do-i-fetch-artwork-from-an-mp3-file – Unconquered82 May 13 '15 at 14:30

2 Answers2

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()
}
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • 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? – Unconquered82 May 14 '15 at 13:54
  • 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? http://ios-blog.co.uk/tutorials/how-to-play-music-in-your-app/ – Unconquered82 May 14 '15 at 14:01
  • 1
    audioPath.lastPathComponent!.stringByDeletingPathExtension – Leo Dabus May 14 '15 at 14:15
  • 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? – Unconquered82 May 14 '15 at 14:29
  • You would probably have to create an asset from your media url https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVAsset_Class/index.html#//apple_ref/occ/clm/AVAsset/assetWithURL: – Leo Dabus May 14 '15 at 14:45
  • https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVAsset_Class/index.html#//apple_ref/occ/instp/AVAsset/availableMetadataFormats – Leo Dabus May 14 '15 at 14:46
  • Thanks alot! I found this (http://stackoverflow.com/questions/7707513/getting-metadata-from-an-audio-stream). 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! – Unconquered82 May 14 '15 at 14:51
  • 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! – Unconquered82 May 14 '15 at 15:24
  • 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. – Leo Dabus May 14 '15 at 15:29
  • 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 help – Unconquered82 May 14 '15 at 16:15
  • 1
    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! – Unconquered82 May 14 '15 at 16:25
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!

Unconquered82
  • 523
  • 1
  • 8
  • 17
  • 1
    I have edited my answer AVMetadataItem has already a stringValue property, so no need to cast the value as String – Leo Dabus May 14 '15 at 18:27
  • https://developer.apple.com/library/prerelease/ios/documentation/AVFoundation/Reference/AVMetadataItem_Class/index.html#//apple_ref/occ/instp/AVMetadataItem/stringValue – Leo Dabus May 14 '15 at 18:28