Trying to identify problem with core audio vs iPhone background execution
I have an audio app in the store. It works fine with versions of the iPhone OS before iOS 4.0. I am working on a new version, starting by bringing the app into compliance with the new iOS multitasking capabilities. (I have iOS 4.0 on my iPhone, and have upgraded to the latest xCode and SDK.)
The result has been a show-stopper.
o When I install the app on the iPhone and run in the debugger, or start the app after the iPhone was powered down, the app acts just fine - playing audio as I push buttons, or restarting audio from "state" that was saved the previous time the app was run.
o If I try to push the Home button and then restart the app from the background, the audio - a and mix of 1-n audio streams - comes out with a stuttering sound that only I could recognize.
o If - while the audio is cleanly - I call the iPhone, I can either answer or decline the call. In both cases the app comes back cleanly, playing as it should.
Note that I am not trying to play anything while in background mode. I simply want to shut things off and bring them back when asked.
Technology: All of the audio logic uses RemoteIO. (I have plans for someday doing some fairly sophisticated signal processing.)
Please excuse the pseudo code narrative - some of the real code is pretty extensive.
MainViewController:
o viewDidLoad - nothing special
o didBecomeActive set self as audio session delegate; set the AudioSessionCategory to MediaPlayback; set the AudioSessionActive; create a Player (see below); restart any sounds that were previ开发者_开发百科ously playing;
o willResignActive save the state of what was playing; stopAllSounds; stop the player; set the audio session inactive;
o didEnterBackground - nothing (method is registered, but no content.)
o willEnterForeground - nothing (method is registered, but no content.)
Overview of Player - my class: The Player is a singleton. I make sure that the singleton instance is destroyed, and a new one created, in didBecomeActive. Instantiating the singleton actually starts the AudioUnit.
constructor setupRemoteIO; start AudioOutputUnitStart; stop AudioOutputUnitStop; player callback the usual stuff;
>
Here are some methods from my MainViewController:
(void)willResignActive:(NSNotification *)note {
[ self saveState ];
[ [ NaturePlayer getInstance ] stopAllSounds ];
[ [ NaturePlayer getInstance ] stop ];
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: NO error: &activationError];
[NaturePlayer destroy];
}
- (void)didBecomeActive:(NSNotification *)note {
[ self setupAudioSession ];
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
[ self restartSounds ];
[ self setViewState ];
}
- (void)didEnterBackground:(NSNotification *)note {
int xxx = 1;
}
- (void)willEnterForeground:(NSNotification *)note {
int xxx = 1;
}
- (void) applicationWillTerminate: (NSNotification*) notification {
int xxx = 1;
}
Here is a method from the NaturePlayer:
/**
* Stop the playback process.
*/
void NaturePlayerDelegate::stop() {
if (isPlaying_) {
AudioOutputUnitStop(outputUnit_);
isPlaying_ = FALSE ;
}
}
I checked: stop() is being called, and in turn calls AudioOutputUnitStop(); Also checked: The doc on AudioOutputUnitStop says it blocks until all activity has completed.
Hard to say without more details on the audio code. But I suggest you might want to examine your Player object teardown code to make sure the audio unit and the audio session are completely stopped (buffer callback thread drained) before releasing stuff.
Are you initializing and un-initializing AudioUnits within your code? I have recently found an issue that AudioUnits being created and destroyed then leaving and returning to your App will cause stuttering.
I was able to fix this in my application by never uninitializing the AudioUnits.
More info on my problem and my AudioUnit code.
I had the same problem in a project of mine. I found that if I called AudioOutputUnitStop() from a button click before suspending the app, then called AudioOutputUnitStart() when the app resumed, I had no problems. But if I called AudioOutputUnitStop() automatically from the viewDidUnload handler or as a response to the UIApplicationWillResignActiveNotification, I had the stuttering, feedback-like sound described above.
I also noticed that if I stopped the audio unit manually, then suspended the app, the interruption listener was called. But if I suspended the app while the audio unit was still running, the interruption listener was not called. The interruption listener is supposed to stop the audio unit, so that's not doing me much good.
After several hours of tracing this, I found a way to finish my task without audio units, and took them out of my app. So I'm afraid I don't have a complete answer. But hopefully these clues will help someone. I may need to do this again in the future, so I'll check back here to see if someone else has figured it out.
精彩评论