I was googling this problem for many days but I didn't find a solution for my simple problem.
I'm trying to play a video while recording sound. Recording sound works fine without the video. And the video works fine without the recording.
As soon as I put both together, the recording throws values which do not react on sound and the video is not playing anymore. By the way this happens only on my device (iPhone 4 / iOS5). In the simulator everything works fine.
This is a reduced version of my code which is in a ViewController.
// Audio Recorder
NSURL *nullUrl = [NSURL fileURLWithPath:@"/dev/null"];
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat:44100.0], AVSampleRateKey,
[NSNumber numberWithInt:kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt:1], AVNumberOfChannelsKey,
[NSNumber numberWithInt:AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
NSError *recorderError;
_recorder = [[AVAudioRecorder alloc] initWithURL:nullUrl settings:settings error:&recorderError];
if (_recorder)
{
[_recorder prepareToRecord];
_recorder.meteringEnabled = YES;
[_recorder record];
_levelTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(levelTimerCallback:) userInfo:nil repeats:YES];
}
// Video Player
NSURL *url = [[NSBundle mainBundle] URLForResource:@"Video"
withExtension:@"mp4"
subdirectory:nil];
_avPlayer = [[AVPlayer playerWithURL:url] retain];
_avPlayerLayer = [[AVPlayerLayer playerLayerWithPlayer:_avPlayer] retain];
_avPlayerLayer.frame = self.view.layer.bounds;
[self.view.layer addSublayer:_avPlayerLayer];
[_avPlayer play];
The recorder simply outputs a value which is read in the levelTimerCallback method. The video simply plays a short video.
I figured out that I have to set a category for the AVAudioSession. If I implement this code after app start, the video is playing but the recorder still outputs the same values without reacting to sound.
NSError *error = nil;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
[audioSession setActive:YES error:&error];
I could imagine that I might have to do something with AudioSessionSetProperty
UInt32 sessionCategory = kAudioSessionCategory_PlayAndRecord;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(sessionCategory), &sessionCategory);
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,sizeof (audioRouteOverride),&audioRouteOverride);
But that doesn't change anything. Do you have an idea what I am missing or how to set up the AudioSession properly?
Thank you for every hint on that!
Cheers, Raphael ;)
I had the same problem (except I'm using the AVPlayer to play audio and not video though). I suggest you start listening for audio routing changes and you will see the route change multiple times when the AVPlayer and AVAudioRecorder are started at the same time.
In the callback print out the category and route (kAudioSessionProperty_AudioRoute). The only way I could get the audio playback and record to work simultaneously was if:
The audio session was AVAudioSessionCategoryPlayAndRecord and kAudioSessionProperty_OverrideCategoryMixWithOthers property was true.
I initiated the playback before the recording. After AVAudioRecorder prepareToRecord is called, don't start recording until you get the audio route change. Even though it does not fail if you start recording earlier, the audio route change seems to make the recording fail.
I tried other combinations, but this is the only one that works every time.