Play audio while app in background not working

481 views Asked by At

I've searched all over but cannot get this to work consistently. I want to play audio when a remote push notification arrives while the app is in the background or lock screen and the ringer is off.

Steps I've followed:

1) Set Required Background Modes to "App plays audio" into info.plist.

2) In application:didFinishLaunchingWithOptions: a) set Audio Session category to Playback b) make Audio Session active. c) make app receive remote control events and become first responder

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

  // https://developer.apple.com/library/ios/qa/qa1668/_index.html
  // For playback to continue when the screen locks, or when the Ring/Silent switch is set to silent, use the AVAudioSessionCategoryPlayback
  BOOL result = [audioSession setCategory:AVAudioSessionCategoryPlayback error:&sessionError]; // TODO AVAudioSessionCategorySoloAmbient

  if (!result && sessionError) {
    NSLog(@"AppDelegate error setting session category. error %@", sessionError);
  }
  else {
    NSLog(@"AppDelegate setting session category is successful");
  }

  result = [audioSession setActive:YES error:&sessionError];

  if (!result && sessionError) {
    NSLog(@"AppDelegate error activating audio session. error %@", sessionError);
  }
  else {
    NSLog(@"AppDelegate setting session active is successful");
  }

  [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
  [self becomeFirstResponder];
}

3) In applicationDidEnterBackground: a) begin background task b) receive remote control events

- (void)applicationDidEnterBackground:(UIApplication *)application {
  NSLog(@"AppDelegate applicationDidEnterBackground: called");

  NSLog(@"AppDelegate applicationDidEnterBackground: is calling beginBackgroundTaskWithExpirationHandler:");
  [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];

  NSLog(@"AppDelegate applicationDidEnterBackground: is calling beginReceivingRemoteControlEvents");
  [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}

4) When the remote notification comes in, play an audio file

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {

  _currentItem = [AVPlayerItem playerItemWithURL:[[NSBundle mainBundle] URLForResource:@"Audio" withExtension:@"wav"]];
  _audioPlayer = [AVPlayer playerWithPlayerItem:_currentItem];

  [_currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
  [_audioPlayer addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];

  NSLog(@"playAudio: calling [_audioPlayer play] on audioPlayer %@", _audioPlayer);
  [_audioPlayer play];
}

It works sometimes, but not always. Any ideas how to make this work consistently?

1

There are 1 answers

0
malhal On

I think that you can't start playing background audio while already in the background, even starting in applicationDidEnterBackground is too late. A work around you could do is play silent audio or pause audio maybe. You could use the queue player to achieve this by looping the silent audio and seeking to the beginning when it ends, then enqueue the audio you'd like to play after it.