What I want to do is allow my application to make a statement using AVSpeechSynthesizer , while background audio applications produce sound. While my application is talking, I would like the sound of the background applications to "fade" and then return to the original volume after my application has finished speaking.
In my AudioFeedback class AudioFeedback I initialize the AVAudioSessions setting as follows:
self.session = [AVAudioSession sharedInstance]; NSError *error; [self.session setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDuckOthers error:&error];
When I want to make a new statement, I do the following. I followed the suggestion Problem with AVSpeechSynthesizer, any workarounds? to create a new AVSpeechSynthesizer each time to βmake sureβ that the cancellation is always accepted (this seems to work, I'm not sure why).
- (AVSpeechUtterance *) utteranceWithString: (NSString *) string { AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:string]; utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"en-ES"]; [utterance setRate:(AVSpeechUtteranceDefaultSpeechRate+AVSpeechUtteranceMinimumSpeechRate)/2.0]; return utterance; } - (void) sayString: (NSString *) string cancelPrevious: (BOOL) cancelPrevious { [self.session setActive:enabled error:nil]; if (cancelPrevious) { AVSpeechSynthesizer *oldSynthesizer = self.voice; self.voice = nil; [oldSynthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate]; self.voice = [[AVSpeechSynthesizer alloc] init]; self.voice.delegate = self; }
In my AVSpeechSynthesizer delegation method, I check if I should end the audio session in order to return the background sound to the normal volume if the current AVSpeechSynthesizer and the current AVSpeechUtterance match the last known synthesizer and pronunciation.
-(void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance { NSError *error; // Only stop the audio session if this is the last created synthesizer if (synthesizer == self.voice && self.finalUtterance == utterance) { if ([self.session setActive:enabled error:&error]]) { NSLog(@"Stopped the audio session: Speech synthesizer still speaking %d", synthesizer.speaking); } else { NSLog(@"ERROR failed to stop the audio session: %@. Speech synthesizer still speaking %d", error, synthesizer.speaking); } } }
The problem I am facing is that sometimes the audio session stops without problems, and in other cases the audio session does not stop with the following error:
Domain Error = NSOSStatusErrorDomain Code = 2003329396 "Operation could not be completed (OSStatus error 2003329396.)"
I am not sure how to guarantee that I can stop AVAudioSession. I tried to keep calling [[AVAudioSession sharedInstance] setActive:NO error:&error] until I can stop the audio session, but that just doesn't work. Any help would be greatly appreciated. Thanks!