AudioQueue code from SpeakHere fails on iPad
I've using the SpeakHere audio classes in an App I'm creating that must Play & Record simultaneously.
I'm using the newest SDK with a 3.2 device target in a universal app build (targeting iPad & iPhone).
The app plays streaming movies using MPMoviePlayerController and Records audio simultaneously.
This works 100% perfectly on an iPhone.
However, it fails 100% on my clients iPad. Logs show !act errors that the AudioSession simply is refusing to active! And every log file I've received from him contains numerous Interruptions & Route Changes (namely Category) being returned to the callback functions. **On an iPhone I do NOT see anything like this at all. The logs show only that teh record was create, and recorded to the specified file. No interruptions, no route changes, no nonsense.
Here's the relevant logs:
Jul 10 07:15:21 iPad mediaserverd[15502] <Error>: [07:15:21.464 <0x1207000>] AudioSessionSetClientPlayState: Error adding running client - session not active
Sat Jul 10 07:15:21 iPad mediaserverd[15502] <Error>: [07:15:21.464 <AudioQueueServer>] AudioQueue: Error '!act' from AudioSessionSetClientPlayState(15642)
I've stubbed out both my callback functions to merely log the occurrences of interruptions and route changes (with reasons). So I won't bother posting the code, since it does literally nothing. I see these logs numerous times during a single attempt to start recording on the iPad though.
I've read virtually every post I can find in the Apple Dev forum and StackOverflow, but cannot seem to find someone with the same problem or any relevant notes in the Apple Docs that explain the difference in iPad behavior. --Note: The iPad did display some other defective behaviors that were remedied, such as the mismatched Begin Interruption calls that never ended (so I never deactivate the session).
I never receive any logs indicating any failed initialization or activation calls from the AudioQueue or AudioSession code. It simply fails when I attempt to start recording. --I even attempted forcing AudioSessionSetActive(true); calls before every attempted use of the sound system and I still receive these errors.
Here's the relevant code for the initialization calls:
//Initialize the Sound System
OSStatus error = AudioSessionInitialize(NULL, NULL, interruptionListener, self);
if (error){ printf("ERROR INITIALIZING AUDIO SESSION! %d\n", (int)error); }
else {
//must set the session active first according to devs talking about some defect....
error = AudioSessionSetActive(true);
if (error) NSLog(@"AudioSessionSetActive (true) failed");
UInt32 category = kAudioSessionCategory_PlayAndRecord;
error = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);
if (error) printf("couldn't set audio category!\n");
error = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, self);
if (error) printf("ERROR ADDING AUDIO SESSION PROP LISTENER! %d\n", (int)error);
//Force mixing!
UInt32 allowMixing = true;
error = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof (allowMixing), &allowMixing );
if (error) printf("ERROR ENABLING MIXING PROPS! %d\n", (int)error);
UInt32 inputAvailable = 0;
UInt32 size = sizeof(inputAvailable);
// we do not want to allow recording if input is not available
error = AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &size, &inputAvailable);
if (error) printf("ERROR GETTING开发者_如何学运维 INPUT AVAILABILITY! %d\n", (int)error);
isInputAvailable = (inputAvailable) ? YES : NO;
//iPad doesn't require the routing changes, branched to help isolate iPad behavioral issues
if(! [Utils GetMainVC].usingiPad){
//redirect to speaker? //this only resets on a category change!
UInt32 doChangeDefaultRoute = 1;
error = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker, sizeof (doChangeDefaultRoute), &doChangeDefaultRoute);
if (error) printf("ERROR CHANGING DEFAULT ROUTE PROPS! %d\n", (int)error);
//this resets with interruption and/or route changes
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
error = AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute,sizeof (audioRouteOverride),&audioRouteOverride);
if (error) printf("ERROR SPEAKER ROUTE PROPS! %d\n", (int)error);
}
// we also need to listen to see if input availability changes
error = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioInputAvailable, propListener, self);
if (error) printf("ERROR ADDING AUDIO SESSION PROP LISTENER! %d\n", (int)error);
error = AudioSessionSetActive(true);
if (error) NSLog(@"AudioSessionSetActive (true) failed");
}
// Allocate our singleton instance for the recorder & player object
myRecorder = new AQRecorder();
myPlayer = new AQPlayer();
Later on in the loadstate callback for the video I merely attempt to start the recording to a predetermined filepath:
myRecorder->StartRecord((CFStringRef)myPathStr);
And audio recording completely fails.
Thanks for your time and help on this.
Turns out this is an odd issue.
1) Use only sound recording and play back and the code runs perfectly on iPad.
2) Add the movie playback and DO NOT call any routing changes and things work fine on iPad.
Somehow the presence of the Movie Player playback is enough to change the AudioSession in some way that forcing any route changes (like to use the device speaker instead of headphones) causes the AudioSession to become inactive.
精彩评论