Nikita Zernov
Nikita Zernov

Reputation: 5635

iOS: Start playing sound from background

I need to start playing sound when user closes app. I use applicationDidEnterBackground method. Here it is:

func applicationDidEnterBackground(application: UIApplication) {
    let dispatchQueue =
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

    dispatch_async(dispatchQueue, {[weak self] in

        var audioSessionError: NSError?
        let audioSession = AVAudioSession.sharedInstance()
        NSNotificationCenter.defaultCenter().addObserver(self!,
            selector: "handleInterruption:",
            name: AVAudioSessionInterruptionNotification,
            object: nil)

        audioSession.setActive(true, error: nil)

        if audioSession.setCategory(AVAudioSessionCategoryPlayback,
            error: &audioSessionError){
                println("Successfully set the audio session")
        } else {
            println("Could not set the audio session")
        }

        let filePath = NSBundle.mainBundle().pathForResource("MySong",
            ofType:"mp3")

        let fileData = NSData(contentsOfFile: filePath!,
            options: .DataReadingMappedIfSafe,
            error: nil)

        var error:NSError?

        /* Start the audio player */
        self!.audioPlayer = AVAudioPlayer(data: fileData, error: &error)

        /* Did we get an instance of AVAudioPlayer? */
        if let theAudioPlayer = self!.audioPlayer{
            theAudioPlayer.delegate = self;
            if theAudioPlayer.prepareToPlay() &&
                theAudioPlayer.play(){
                    println("Successfully started playing")
            } else {
                println("Failed to play")
            }
        } else {
            /* Handle the failure of instantiating the audio player */
        }
        })

}
func handleInterruption(notification: NSNotification){
/* Audio Session is interrupted. The player will be paused here */

let interruptionTypeAsObject =
notification.userInfo![AVAudioSessionInterruptionTypeKey] as! NSNumber

let interruptionType = AVAudioSessionInterruptionType(rawValue:
  interruptionTypeAsObject.unsignedLongValue)

if let type = interruptionType{
  if type == .Ended{

    /* resume the audio if needed */

  }
}

}

func audioPlayerDidFinishPlaying(player: AVAudioPlayer!, successfully flag: Bool){

  println("Finished playing the song")

  /* The flag parameter tells us if the playback was successfully
  finished or not */
  if player == audioPlayer{
    audioPlayer = nil
  }
  }

It does not work. After debugging I see that theAudioPlayer.play() returns false. If I run this code for example in applicationDidFinishLaunching it plays sound. I added background mode App plays audio or streams audio/video using AirPlay to my Info.plist What's wrong here?

Upvotes: 3

Views: 2178

Answers (1)

Woodstock
Woodstock

Reputation: 22926

At a very basic level there are three prerequisites your app should satisfy to play audio in the background:

  • Music must be playing
  • Setup ‘Background Modes’ for Audio in your Target Capabilities.

  • For basic playback, initialise your audio session, and set your audio session category to AVAudioSessionCategoryPlayback. If you don’t, you’ll get the default behaviour.

You should also configure your app to respond to

  • changes in audio output
  • audio session interruptions (e.g. phone call)
  • remote control events (via control centre, or the lock screen)

Check out this Swift example.

Upvotes: 3

Related Questions