A customer recently got in touch with me with an odd problem — Talkie for iPhone was going silent on him. After a little diagnosis, it turned out the audio system was throwing up an undocumented error — -12986 — while starting up on his iPod Touch.
Some googling turned up [this thread](http://stackoverflow.com/questions/1540078/iphone-sdk-audio-session-error-12986-after-upgrade-to-3-1) on Stack Overflow, which presented a solution for the AVAudioSession
framework: It turns out, on recent SDKs (somewhere equal to or above 3.0), the audio system will refuse to start up if the session is set to a recording mode, with no input device available, spitting out this error. Alas, the error isn’t listed anywhere that I could find.
So, the way to fix it is to check whether there’s an input device available, then choose an audio category accordingly:
OSStatus status; UInt32 inputAvailable=0; UInt32 size = sizeof(inputAvailable); AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &size, &inputAvailable); UInt32 sessionCategory; if ( inputAvailable ) { // Set the audio session category for simultaneous play and record sessionCategory = kAudioSessionCategory_PlayAndRecord; } else { // Just playback sessionCategory = kAudioSessionCategory_MediaPlayback; } status = AudioSessionSetProperty (kAudioSessionProperty_AudioCategory, sizeof (sessionCategory), &sessionCategory); checkStatus(status); |
It’s probably a good idea to respond when input becomes available or goes away, so add a property listener too:
void inputAvailablePropertyListener (void *inClientData, AudioSessionPropertyID inID, UInt32 inDataSize, const void *inData) { if ( inID = kAudioSessionProperty_AudioInputAvailable ) { UInt32 *inputAvailable = (UInt32*)inData; UInt32 sessionCategory; if ( *inputAvailable ) { // Set the audio session category for simultaneous play and record sessionCategory = kAudioSessionCategory_PlayAndRecord; } else { // Just playback sessionCategory = kAudioSessionCategory_MediaPlayback; } OSStatus status = AudioSessionSetProperty (kAudioSessionProperty_AudioCategory, sizeof (sessionCategory), &sessionCategory); checkStatus(status); } } |
then:
// Listen for audio input availability status = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioInputAvailable, inputAvailablePropertyListener, NULL); |
Funny, this one got me too.