質問

Can't make AVQueuePlayer start playing sound queue when it's starting after the app went into the background.

The basic question is: how to start sound from newly created AVQueuePlayer instance from background?

It's for navi-like app that need to play couple of combined sounds with appropriate directions when the time comes. And most of the time the app works in background...

The details are below...

It plays just fine when I start it from active application, and finishes playing sound even after app went to background.

What I did so far:

In AppDelegate inside didFinishLaunchingWithOptions I added:

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

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

After the app started I clicked the home button so the app went into the background.

When the time came this code executes (the app is still in background, but note, that I have enabled Audio and AirPlay background mode):

-(void)playTrainingFinishedSound
{
    NSMutableArray *queue = [NSMutableArray array];
    [queue addObject:[AVPlayerItem playerItemWithURL:[[NSBundle mainBundle] URLForResource:@"alertkoniectreningu" withExtension:@"m4a"]]];
    [self initializeAudioPlayerWithQueue:queue];
    [self.appDelegate.audioPlayer play];
}

-(void)initializeAudioPlayerWithQueue:(NSArray *)queue
{
    self.appDelegate.audioPlayer = [[AVQueuePlayer alloc] initWithItems:queue];
    self.appDelegate.audioPlayer.actionAtItemEnd = AVPlayerActionAtItemEndAdvance;
}

Unfortunately this code doesn't make any sound, opposite to the situation when the app was in foreground.

役に立ちましたか?

解決

Oh God, there was just one line missing in the AppDelegate didFinishLaunchingWithOptions [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

so it looks now like:

    audioSession = [AVAudioSession sharedInstance];
    [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
    if (audioSession) [audioSession setActive:YES error:nil];
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

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

他のヒント

The reason the AVPlayer is failing is because you can't create/initialize an Audio Unit while an application is in the background, which is what the AVPlayer is attempting to do under the hood. The exception to this rule is of course audio-playing applications which can be started/resumed via the "Play" buttons built into the OS, while they are in the background. Thus, applications which subscribe to remote control events have the capability to start Audio Units in the background, which is why subscribing to these events appears to solve the problem.

It's unclear whether Apple is OK with using the API feature in this way.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top