33
votes

I've done my homework... been reading here, the docs, googling, stackoverflowing... but still no luck in making my sound stick when the user makes the app go into the background.

What I have done so far: Added the UIBackgroundModes, audio to the plist-file.

First this code:

radioAudio = [[AVAudioSession alloc] init];
[radioAudio setCategory:AVAudioSessionCategoryPlayback error:nil];
[radioAudio setActive:YES error:nil];

Then this:

NSString *radioURL = @"http://xxx.xxx.xxx/radio.m3u";
radioPlayer = [[AVPlayer playerWithURL:[NSURL URLWithString:radioURL]] retain];

But as soon as the user hits the home-button, my sound dies.

I also found this, but not added yet cuase some stuff I've read says it is not needed;

newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
     if (newTaskId != UIBackgroundTaskInvalid && bgTaskId != UIBackgroundTaskInvalid)
        [[UIApplication sharedApplication] endBackgroundTask: bgTaskId];
bgTaskId = newTaskId;

Right now I have no idea where I should go to make my AVPlayer let the radio sing while the user does other stuff on the phone. I am testing this on an iPhone 4 with 4.2. Building it for 4.0.

Anyone have any suggestions what I should do?

6
See My answer in this Que, you will find the your solution [Click Here to View the Answer][1] [1]: stackoverflow.com/questions/15470452/…Vishal Khatri

6 Answers

42
votes

Had the same problem, but found a solution for this..

Look here: https://devforums.apple.com/message/395049#395049

The content of the above link:


Replace APPNAME with your own app name!

Im on iOS 4.2.1

EDIT: Working with iOS5 + 6 + 7 beta so far

Add UIBackgroundModes in the APPNAME-Info.plist, with the selection App plays audio

Then add the AudioToolBox framework to the folder frameworks.

In the APPNAMEAppDelegate.h add:

#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>

so it look like this:

...
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
...

In the APPNAMEAppDelegate.m add the following:

// Set AudioSession
NSError *sessionError = nil;
[[AVAudioSession sharedInstance] setDelegate:self];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];

/* Pick any one of them */
// 1. Overriding the output audio route
//UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
//AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);

// 2. Changing the default output audio route
UInt32 doChangeDefaultRoute = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker, sizeof(doChangeDefaultRoute), &doChangeDefaultRoute);

into the

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

but before the two lines:

[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];

Build your project and see if theres any error, If not, try debug on Device insted of the Simulator, it CAN bug on simulator.

Hope this helps others with same problem..

50
votes

UPDATE IOS 11.2 with Swift 4:

Now if you are using AVPlayer to play music files you should also configure MPNowPlayingInfoCenter.default() to show now playing info on the lock screen.

Below code will show now playing controls on the screen but it won't be able to respond any commands.

If you also want to controls to work you should check apple's sample project here: https://developer.apple.com/library/content/samplecode/MPRemoteCommandSample/Introduction/Intro.html#//apple_ref/doc/uid/TP40017322

Apple sample code covers all but i find it confusing.

If you want to play sound and show controls on the lock screen these steps will do just fine.

IMPORTANT NOTE: If you are NOT using AVPlayer to play sound. If you are using some third party libraries to generate sound or playback a sound file you should read comments inside the code. Also if you are using ios simulator 11.2 you won't be able to see any controls on lock screen. You should use a device to see it work.


1- Select project -> capabilites -> set background modes ON -> tick Audio, AirPlay and Picture in Picture

ios 11 background audio setting

2- AppDelegate.swift file should look like this :

import UIKit

import AVFoundation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
{

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
    {
        // Override point for customization after application launch.

        do
        {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
            try AVAudioSession.sharedInstance().setActive(true)

         //!! IMPORTANT !!
         /*
         If you're using 3rd party libraries to play sound or generate sound you should
         set sample rate manually here.
         Otherwise you wont be able to hear any sound when you lock screen
         */
            //try AVAudioSession.sharedInstance().setPreferredSampleRate(4096)
        }
        catch
        {
            print(error)
        }
        // This will enable to show nowplaying controls on lock screen
        application.beginReceivingRemoteControlEvents()

        return true
    }
}

3- ViewController.swift should look like this:

import UIKit

import AVFoundation
import MediaPlayer

class ViewController: UIViewController
{

    var player : AVPlayer = AVPlayer()

    override func viewDidLoad()
    {
        super.viewDidLoad()


        let path = Bundle.main.path(forResource: "music", ofType: "mp3")
        let url = URL(fileURLWithPath: path!)

        // !! IMPORTANT !!
        /*
            If you are using 3rd party libraries to play sound 
            or generate sound you should always setNowPlayingInfo 
            before you create your player object.

            right:
            self.setNowPlayingInfo()
            let notAVPlayer = SomePlayer()

            wrong(You won't be able to see any controls on lock screen.):
            let notAVPlayer = SomePlayer()
            self.setNowPlayingInfo()
         */

        self.setNowPlayingInfo()
        self.player = AVPlayer(url: url)

    }


    func setNowPlayingInfo()
    {
        let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
        var nowPlayingInfo = nowPlayingInfoCenter.nowPlayingInfo ?? [String: Any]()

        let title = "title"
        let album = "album"
        let artworkData = Data()
        let image = UIImage(data: artworkData) ?? UIImage()
        let artwork = MPMediaItemArtwork(boundsSize: image.size, requestHandler: {  (_) -> UIImage in
            return image
        })

        nowPlayingInfo[MPMediaItemPropertyTitle] = title
        nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = album
        nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork

        nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo
    }

    @IBAction func startPlayingButtonPressed(_ sender: Any)
    {
        self.player.play()
    }

OLD ANSWER IOS 8.2:

Patrick's answer is totally right.

But i'm gonna write what i do for ios 8.2:

I add my app's info.plist required background modes like below:

enter image description here

And in my AppDelegate.h i add these imports:

#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>

Then in my AppDelegate.m i wrote application didFinishLaunchingWithOptionsthis exactly like below:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];

    return YES;
}

Now App keeps playing music even if screen is locked :)

10
votes

I have successfully made audio run in the background by adding the following to my applicationDidFinishLaunching

// Registers this class as the delegate of the audio session.
[[AVAudioSession sharedInstance] setDelegate: self];    
// Allow the app sound to continue to play when the screen is locked.
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
6
votes

iOS 9 Swift

All you should need is add the following to your didFinishLaunchingWithOptions

do  {
    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
} catch {
    //TODO
}
1
votes

You have a good example of a GPS background app that plays sounds even when in background :

http://www.informit.com/articles/article.aspx?p=1646438&seqNum=5

In this example, AudioToolbox is used.

I did a test myself and it works : create a simple project that monitors the GPS post (UIBackgroundModes location) , and every x received position, play a sound using

AudioServicesPlaySystemSound(soundId);

Then if you put audio as part of your UIBackgroundModes and the sounds will be played, even if the application isn't in foreground anymore.

I've made such a test and it works ok !

(I didn't manage to get it working with AVPlayer so I fallbacked to AudioToolbox)

0
votes

I've the same problem and I found solution in Apple Docs:https://developer.apple.com/library/ios/qa/qa1668/_index.html

Q: How do I ensure my media will continue playing when using AV Foundation while my application is in the background?

A: You must declare your app plays audible content while in the background, and assign an appropriate category to your audio session. See also Special Considerations for Video Media.