-2

I am trying to allow the user to pick a song from their library and play it across different view controllers. I am able to pick songs currently and play them, but I don't know how to play them in the background. Thanks!

class ViewController: UIViewController,
MPMediaPickerControllerDelegate, AVAudioPlayerDelegate {


    var myMusicPlayer: MPMusicPlayerController?
    var mediaPicker: MPMediaPickerController?
    var backgroundMusicPlayer:AVAudioPlayer = AVAudioPlayer()


    @IBAction func musicBtn(sender: AnyObject) {
        displayMediaPickerAndPlayItem()
    }


    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.

    }


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


    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */



    func musicPlayerStateChanged(notification: NSNotification){

        print("Player State Changed")

        /* Let's get the state of the player */
        let stateAsObject =
            notification.userInfo!["MPMusicPlayerControllerPlaybackStateKey"]
                as? NSNumber

        if let state = stateAsObject{

            /* Make your decision based on the state of the player */
            switch MPMusicPlaybackState(rawValue: state.integerValue)!{
            case .Stopped:
                /* Here the media player has stopped playing the queue. */
                print("Stopped")
            case .Playing:
                /* The media player is playing the queue. Perhaps you
                 can reduce some processing that your application
                 that is using to give more processing power
                 to the media player */
                print("Paused")
            case .Paused:
                /* The media playback is paused here. You might want
                 to indicate by showing graphics to the user */
                print("Paused")
            case .Interrupted:
                /* An interruption stopped the playback of the media queue */
                print("Interrupted")
            case .SeekingForward:
                /* The user is seeking forward in the queue */
                print("Seeking Forward")
            case .SeekingBackward:
                /* The user is seeking backward in the queue */
                print("Seeking Backward")
            }

        }
    }

    func nowPlayingItemIsChanged(notification: NSNotification){

        print("Playing Item Is Changed")

        let key = "MPMusicPlayerControllerNowPlayingItemPersistentIDKey"

        let persistentID =
            notification.userInfo![key] as? NSString

        if let id = persistentID{
            /* Do something with Persistent ID */
            print("Persistent ID = \(id)")
        }

    }

    func volumeIsChanged(notification: NSNotification){
        print("Volume Is Changed")
        /* The userInfo dictionary of this notification is normally empty */
    }

    func mediaPicker(mediaPicker: MPMediaPickerController,
                     didPickMediaItems mediaItemCollection: MPMediaItemCollection){

        print("Media Picker returned")

        /* Instantiate the music player */

        myMusicPlayer = MPMusicPlayerController()

        if let player = myMusicPlayer{

            player.beginGeneratingPlaybackNotifications()

            /* Get notified when the state of the playback changes */
            NSNotificationCenter.defaultCenter().addObserver(self,
                                                             selector: "musicPlayerStateChanged:",
                                                             name: MPMusicPlayerControllerPlaybackStateDidChangeNotification,
                                                             object: nil)

            /* Get notified when the playback moves from one item
             to the other. In this recipe, we are only going to allow
             our user to pick one music file */
            NSNotificationCenter.defaultCenter().addObserver(self,
                                                             selector: "nowPlayingItemIsChanged:",
                                                             name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification,
                                                             object: nil)

            /* And also get notified when the volume of the
             music player is changed */
            NSNotificationCenter.defaultCenter().addObserver(self,
                                                             selector: "volumeIsChanged:",
                                                             name: MPMusicPlayerControllerVolumeDidChangeNotification,
                                                             object: nil)

            /* Start playing the items in the collection */
            player.setQueueWithItemCollection(mediaItemCollection)
            player.play()

            /* Finally dismiss the media picker controller */
            mediaPicker.dismissViewControllerAnimated(true, completion: nil)

        }

    }

    func mediaPickerDidCancel(mediaPicker: MPMediaPickerController) {
        /* The media picker was cancelled */
        print("Media Picker was cancelled")
        mediaPicker.dismissViewControllerAnimated(true, completion: nil)
    }

    func stopPlayingAudio(){

        NSNotificationCenter.defaultCenter().removeObserver(self)

        if let player = myMusicPlayer{
            player.stop()
        }

    }

    func displayMediaPickerAndPlayItem(){

        mediaPicker = MPMediaPickerController(mediaTypes: .AnyAudio)

        if let picker = mediaPicker{


            print("Successfully instantiated a media picker")
            picker.delegate = self
            picker.allowsPickingMultipleItems = true
            picker.showsCloudItems = true
            picker.prompt = "Pick a song please..."
            view.addSubview(picker.view)

            presentViewController(picker, animated: true, completion: nil)

        } else {
            print("Could not instantiate a media picker")
        }

    }

}
Brandex07
  • 85
  • 1
  • 9

2 Answers2

2

If you want to play "across different view controllers" then do not put the AVAudioPlayer in one view controller. If you do that, it will be destroyed when you leave that view controller.

Put the audio player somewhere that will survive no matter what, like your App Delegate.

matt
  • 515,959
  • 87
  • 875
  • 1,141
0

You can use singleton to achieve it like this:

import AVFoundation

class MusicHelper {
    static let sharedHelper = MusicHelper()
    var audioPlayer: AVAudioPlayer?

    func playBackgroundMusic() {
        let pickedSong = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("userPickedSong", ofType: "mp3")!)
        do {
            audioPlayer = try AVAudioPlayer(contentsOfURL:aSound)
            audioPlayer!.numberOfLoops = -1
            audioPlayer!.prepareToPlay()
            audioPlayer!.play()
        } catch {
            print("Cannot play the file")
        }
    }
}

And you can use it like this:

MusicHelper.sharedHelper.playBackgroundMusic()

This is just one example how you can do it. Actually there are more and there are already answers on StackOverflow. But with the way I showed you can call it in any class.

Tarvo Mäesepp
  • 4,477
  • 3
  • 44
  • 92