Solving the mystery among AVAudioPlayer, AVAudioRecorder and AVAudioSession

Lately I’ve been heavily developing my thesis project – VirtualEar for some audio signal processing. One of its basic tasks is to be able to record a sound and play the sound back. However, such a task may not be so simple as you think. In fact, it could be so frustrating that it might be running happily in your simulator but crashing on your actual device, which is what happened to me.

Well, not exactly. I want to keep simple things simple, so I use AVAudioRecorder in one viewcontroller for recording and AVAudioPlayer in another viewcontroller for playing. Everything worked fine in the simulator until I installed it on my phone. My AVAudioPlayer won’t playback the recorded sound. And the worst part is, it didn’t crash and not even an error message!

At first, I thought it was something wrong with the phone. And it turned out to be not the case as I downloaded and installed the sample code avTouch from Apple and it worked fine on my phone. Then I thought will it be the file format? So I replaced the sound in the sample project with my sound and everything was fine again.

Hmmm, I really need some error message here. So I carefully read through Apple’s documentation and found this delegate method of AVAudioPlayer:

- (void)playerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error
	NSLog(@"ERROR IN DECODE: %@\n", error);

I quickly run the app again and this time it returns me with “audioPlayer couldn’t play the file /localhost/var/mobile/XXXX”. That’s not very helpful but we’re getting something. To make sure the file does exist, I sshed to the phone directory and it’s there.

Time to turn to our good friend Google again. I searched the keyword “avaudioplayer won’t play”. There were not many related links to it but I did find one post talking about the activity setting with AVAudioSession. I almost forget about AVAudioSession!

AVAudioSession is a singleton object that you employ to set the audio context for your application.

I recall using AVAudioSession in my recorder viewcontroller to create a context for my AVAudioRecorder but not for AVAudioPlayer.

It might be something wrong in my AVAudioSession settings. I scrutinized my code again for the setting part and there it was:

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:nil];

I didn’t tell it to be able to playback! No wonder it won’t play. So thrilled, I changed the line to this:

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];

Bingo! My phone is singing happily and I can finally go to bed peacefully.