user1541723
user1541723

Reputation: 36

AVAudioRecorder blocks AVSpeechSynthesizer

I'm using Cordova 3.2 for text to speech and speech to text. Under iOS 7, AVSpeechSynthesizer is available and works very well. Here is the critical bit of the plugin:

        self.synthesizer = [[AVSpeechSynthesizer alloc] init];
        self.synthesizer.delegate = self;
        NSString * toBeSpoken=[command.arguments objectAtIndex:0];
        NSNumber * rate=[command.arguments objectAtIndex:1];
        NSString * voice=[command.arguments objectAtIndex:2];
        NSNumber * volume=[command.arguments objectAtIndex:3];
        NSNumber * pitchMult=[command.arguments objectAtIndex:4];

        AVSpeechUtterance *utt =[[AVSpeechUtterance alloc] initWithString:toBeSpoken];

        utt.rate= [rate floatValue]/4;// this is to slow down the speech rate
        utt.volume=[volume floatValue];
        utt.pitchMultiplier=[pitchMult floatValue];
        utt.voice=[AVSpeechSynthesisVoice voiceWithLanguage:voice];

        [self.synthesizer speakUtterance:utt];

The problem occurs after the text is spoken. Using the Cordova Media call to record (AVAudioRecorder) the response for voice to text conversion does something to disrupt the synthesizer output.

Some things that I've noticed during my attempts to figure this out:

  1. Running in the simulator, there is no problem. In fact, I have to be careful to wait for the speech to end before recording, otherwise the record will pick the output through the microphone.

  2. On the iPad 3 w/ iOS 7+, starting the recording will pause the synthesizer output until the recorded file is played back. The media reference to the file is released after the successful recording.

  3. After recording, the synthesizer delegate receives responses:

    TTSPlugin did start speaking TTSPlugin will speak in range of speech string. TTSPlugin will speak in range of speech string. TTSPlugin will speak in range of speech string. TTSPlugin did cancel speaking

  4. Canceling the speech synthesize clears the utterance queue.

My goal is to be able to have a conversation with the app. I'm not able to find where the interference is. Help?

EDIT

I solved the problem. The culprit was AVAudioSession, which the Media plugin in Cordova was managing. I hadn't done multiple audio sources before so this was a stumper.

I added these to my TTS plugin to manage AVAudioSession and activate it as needed. Everything is fine now.

// returns whether or not audioSession is available - creates it if necessary
- (BOOL)hasAudioSession
{
    BOOL bSession = YES;

    if (!self.avSession) {
        NSError* error = nil;

        self.avSession = [AVAudioSession sharedInstance];
        if (error) {
                // is not fatal if can't get AVAudioSession , just log the error
            NSLog(@"error creating audio session: %@", [[error userInfo] description]);
            self.avSession = nil;
            bSession = NO;
        }
    }
    return bSession;
}

- (void)setAudioSession
{
    if ([self hasAudioSession]) {
        NSError* __autoreleasing err = nil;
        NSNumber* playAudioWhenScreenIsLocked = 0;
        BOOL bPlayAudioWhenScreenIsLocked = YES;
        if (playAudioWhenScreenIsLocked != nil) {
            bPlayAudioWhenScreenIsLocked = [playAudioWhenScreenIsLocked boolValue];
        }

        NSString* sessionCategory = bPlayAudioWhenScreenIsLocked ? AVAudioSessionCategoryPlayback : AVAudioSessionCategorySoloAmbient;
        [self.avSession setCategory:sessionCategory error:&err];
        if (![self.avSession setActive:YES error:&err]) {
                // other audio with higher priority that does not allow mixing could cause this to fail
            NSLog(@"Unable to play audio: %@", [err localizedFailureReason]);
        }
    }
}

Upvotes: 2

Views: 1195

Answers (1)

satohiro
satohiro

Reputation: 267

startRecordingAudio method in Media(CDVSound.m) set AVAudioSession as "AVAudioSessionCategoryRecord".

In my case, I just I added following 1 line, it works for me.

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[self.synthesizer speakUtterance:utt];

Upvotes: 0

Related Questions