0

I am trying to play video in background.I follow so many tutorial but i did not get appropriate results.For that i am using AVPlayer.I am able to play my video whenever application state is active.But i want to play music in background for that i need to detach AVPlayerLayer from AVPlayer,If you have any alternate solution so that i can play my video in background.Please help me.

This is my code:

ViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    [self becomeFirstResponder];
    [[AVAudioSession sharedInstance] setDelegate: self];
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    [[AVAudioSession sharedInstance] setActive: YES error: nil];

    NSURL *url = [[NSBundle mainBundle] URLForResource:@"sample"
              withExtension:@"m4v" subdirectory:nil];
avPlayerItem = [AVPlayerItem playerItemWithURL:url];
    self.songPlayer = [AVPlayer playerWithPlayerItem:avPlayerItem];
    self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer: self.songPlayer];
    self.avPlayerLayer.frame = self.view.layer.bounds;
    UIView *newView = [[UIView alloc] initWithFrame:self.view.bounds];
    [newView.layer addSublayer:avPlayerLayer];
    [self.view addSubview:newView];
    [self.songPlayer play];
   }

AppDelegate.m

- (void)applicationWillResignActive:(UIApplication *)application
{
    ViewController *vc=[[ViewController alloc]init];
    vc.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:nil];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
    ViewController *vc=[[ViewController alloc]init];
    vc.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:vc.songPlayer];

}
user2182231
  • 111
  • 1
  • 1
  • 10

1 Answers1

0

You are creating a new view controller in both your application delegate methods, with a new player etc.. That will not change a thing. You must use the player and layer you created in the view controller's viewDidLoad method, and modify that one later in the delegate methods. For this, your application delegate could store the main view controller in it's properties, or you could implement the NSNotifications for application delegate in your view controller class, like so: (could be added to the view controller's viewDidLoad method)

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];

To detach the player layer from the player, as it's said in the documentation, is slightly incorrect, at least confusing. In fact you have to detach the player from the player layer. Add this code to the applicationDidEnterBackground (not applicationWillResignActive) method:

// Detach player from playerlayer to avoid pause while in background
if (self.playerLayer && self.player)
{
    [self.playerLayer setPlayer: nil];
}

In your applicationWillEnterForeground, store a flag to remember that when the application becomes active, it is due to entering the foreground, and not one of the other numerous reasons for which applicationDidBecomeActive may be called:

self.enteringForeground = true;

And then, in your applicationDidBecomeActive: method,

if (self.enteringForeground)
{
    // Re-attach player to playerlayer
    if (self.playerLayer && self.player)
    {
        if (self.playerLayer.player != self.player)
            [self.playerLayer setPlayer: self.player];
    }

    self.enteringForeground = false;
}

For this to work, you will need a new property in your application delegate .h file or view controller .h file, depending which implementation you chose:

@property (readwrite)           BOOL            enteringForeground;

Of course, you also need to add the entry UIBackgroundModes with value 'audio' to your application's info.plist file (or in the Info tab of your project, add the entry 'Required background modes' and then the value 'App plays audio or streams audio/video using AirPlay').

I hope this is helpful. I too struggled at first to implement background playback, and this method seems to work quite well.

Simon Tillson
  • 3,609
  • 1
  • 15
  • 23