start playing audio from a background task via AVAudioPlayer in Xcode

Viewed 8848

I am trying to start playing a sound from a background task via an AVAudioPlayer that is instantiated then, so here's what I've got.

For readability I cut out all user selected values.

- (void)restartHandler {
    bg = 0;
    bg = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [[UIApplication sharedApplication] endBackgroundTask:bg];
    }];
    tim = [NSTimer timerWithTimeInterval:.1 target:self selector:@selector(upd) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:tim forMode:NSRunLoopCommonModes];
}

- (void)upd {
    if ([[NSDate date] timeIntervalSinceDate:startDate] >= difference) {
        [self playSoundFile];
        [tim invalidate];
        [[UIApplication sharedApplication] endBackgroundTask:bg];
    }
}

- (void)playSoundFile {

    NSError *sessionError = nil;
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&sessionError];


    // new player object
    _player = [[AVQueuePlayer alloc] init];
    [_player insertItem:[AVPlayerItem playerItemWithURL:[[NSBundle mainBundle] URLForResource:@"Manamana" withExtension:@"m4a"]] afterItem:nil];

    [_player setVolume:.7];
    [_player play];

    NSLog(@"Testing");
}

Explanation: bg, tim, startDate, difference and _player are globally declared variables. I call - (void)restartHandler from a user-fired method and inside it start a 10Hz repeating timer for - (void)upd. When a pre-set difference is reached, - (void)playSoundFile gets called and initiates and starts the player. The testing NSLog at the end of the method gets called.

Now the strange thing is if I call - (void)playSoundFile when the app is active, everything works out just fine, but if I start it from the background task it just won't play any sound.

Edit

So I tried using different threads at runtime and as it seems, if the Player is not instantiated on the Main Thread this same problem will appear. I also tried using AVPlayer and AVAudioPlayer where the AVAudioPlayer's .playing property did return YES and still no sound was playing.

5 Answers

What fixed it for me was to start playing some audio just as application quits, so I added 1sec blank audio in applicationWillResignActive in the AppDelegate

func applicationWillResignActive(_ application: UIApplication) {

        self.backgroundUpdateTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
            self.endBackgroundUpdateTask(true)
        })


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

        do {
            audioPlayer = try AVAudioPlayer(contentsOf: secSilence)
        }
        catch {
            print("Error in loading sound file")
        }

        audioPlayer.prepareToPlay()
        audioPlayer.play()



}
Related