Technical Q&A QA1668

Playing media while in the background using AV Foundation on iOS

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.

Declare your app plays Audible Content while in the Background

First, declare your application provides specific background services and must be allowed to continue running while in the background. To do this, add the UIBackgroundModes key in your app's Info.plist file. Its value is an array that contains one or more strings that identify which background tasks your application supports. Specify the string value audio to indicate the application plays audible content to the user while in the background:

Figure 1  Declaring the app plays audible content in the background.

Before iOS 5.0, you needed to opt into AirPlay to enable your media to be to be streamed to high-definition displays and high-fidelity audio systems. The details for opting in and opting out of AirPlay vary depending on the method of media playback. For details, see the AirPlay Overview.

Setting the Audio Session Category

You must assign an appropriate category to your audio session to ensure your audio plays even with the screen locked and with the Ring/Silent switch set to silent. You cannot rely on the default audio session, whose category is AVAudioSessionCategorySoloAmbient (or equivalently, kAudioSessionCategory_SoloAmbientSound).

For playback to continue when the screen locks, or when the Ring/Silent switch is set to silent, use the AVAudioSessionCategoryPlayback (or the equivalent kAudioSessionCategory_MediaPlayback) category. Listing 1 demonstrates how to initialize your application's audio session with the AVAudioSessionCategoryPlayback category.

Listing 1  Setting the audio category to allow playback when the screen locks or when the Ring/Silent switch is set to silent.

#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
 
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
 
NSError *setCategoryError = nil;
BOOL success = [audioSession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
if (!success) { /* handle the error condition */ }
 
NSError *activationError = nil;
success = [audioSession setActive:YES error:&activationError];
if (!success) { /* handle the error condition */ }

See the Audio Session Programming Guide - Audio Session Categories for more information about the available audio session categories.

Special Considerations for Video Media

If the AVPlayer's current item is displaying video on the device's display, playback of the AVPlayer is automatically paused when the app is sent to the background. There are two ways to prevent this pause:

Listing 2  Disabling the video tracks in the player item.

#import <AVFoundation/AVFoundation.h>
 
AVPlayerItem *playerItem = <#Get your player item#>;
 
NSArray *tracks = [playerItem tracks];
for (AVPlayerItemTrack *playerItemTrack in tracks)
{
    // find video tracks
    if ([playerItemTrack.assetTrack hasMediaCharacteristic:AVMediaCharacteristicVisual])
    {
        playerItemTrack.enabled = NO; // disable the track
    }
}

Listing 3  Remove/Restore the AVPlayerLayer and its associated AVPlayer.

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
 
@interface MyPlayerLayerView : UIView
@end
 
@implementation MyPlayerLayerView
 
- (AVPlayerLayer *)playerLayer {
  return (AVPlayerLayer *)[self layer];
}
 
+ (Class)layerClass {
  return [AVPlayerLayer class];
}
 
@end
 
@interface MyAppDelegate : UIResponder <UIApplicationDelegate>
...
@end
 
@implementation MyAppDelegate
 
...
 
/* Remove the AVPlayerLayer from its associated AVPlayer
    once the app is in the background. */
- (void)applicationDidEnterBackground:(UIApplication *)application {
  MyPlayerLayerView *playerView = <#Get your player view#>;
  [[playerView playerLayer] setPlayer:nil]; // remove the player
}
 
/* Restore the AVPlayer when the app is active again. */
- (void)applicationDidBecomeActive:(UIApplication *)application {
  MyPlayerLayerView *playerView = <#Get your player view#>;
  [[playerView playerLayer] setPlayer:_player]; // restore the player
}
 
...
 
@end


Document Revision History


DateNotes
2014-02-12

Added code snippet showing how to remove an AVPlayer from an AVPlayerLayer. Specified use of app delegate applicationDidEnterBackground as the recommended method for adding code to prevent video pause. Reorganization of some of the Q&A material. Other miscellaneous changes.

2013-04-29

Updated special considerations for playback of HTTP Live Streams.

2013-04-11

Provided code snippets to show how to disable a player item's video tracks. Added special considerations for playback of HTTP Live Streams. Other miscellaneous changes.

2012-03-06

Updated to include AirPlay information.

2010-07-27

New document that discusses playing media while in the background using AV Foundation on iOS