如何在AVSpeechUtterance之后始终停止AVAudioSession [英] How to consistently stop AVAudioSession after AVSpeechUtterance

查看:168
本文介绍了如何在AVSpeechUtterance之后始终停止AVAudioSession的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想做的是让我的应用使用 AVSpeechSynthesizer 说话,同时背景音频应用播放音频。当我的应用发言时,我希望后台应用的音频昏暗,然后在我的应用完成发言后返回原始音量。

What I want to do is allow my app to speak an utterance using AVSpeechSynthesizer while background audio apps are playing audio. While my app is speaking, I'd like the background apps' audio to "dim" and then return to their original volume after my app has finished speaking.

在我的 AudioFeedback 类,我初始化我设置 AVAudioSessions ,如下所示:

In my AudioFeedback class, I initialize I setup the AVAudioSessions like so:

    self.session = [AVAudioSession sharedInstance];
    NSError *error;
    [self.session setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDuckOthers error:&error];

每当我想说一个新的话语时,我会做以下事情。我按照 AVSpeechSynthesizer的问题,任何解决方法?的建议来创建一个新的AVSpeechSynthesizer每次确保总是收到取消(它似乎工作,我不知道为什么)。

Whenever I want to speak a new utterance, I do the following. I followed the suggestion from An issue with AVSpeechSynthesizer, Any workarounds? to create a new AVSpeechSynthesizer every time to "make sure" that cancelations are always received (it just 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;
    }

    // Keep track of the final utterance, we'll use this to determine whether or not we should stop the audio session
    self.finalUtterance = [self utteranceWithString:string];
    [self.voice speakUtterance:self.finalUtterance];
}

在我的AVSpeechSynthesizer委托方法中,我检查是否应该停止音频如果当前AVSpeechSynthesizer和当前AVSpeechUtterance匹配最后一个已知的合成器和话语,则会话背景音频返回正常音量。

In my AVSpeechSynthesizer delegate method, I check to see if I should stop the audio session to return the background audio to normal volume if the current AVSpeechSynthesizer and the current AVSpeechUtterance match the last known synthesizer and utterance.

-(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'm having is that sometimes, the audio session will stop without issues, and other times, the audio session will fail to stop with the following error:


错误域= NSOSStatusErrorDomain代码= 2003329396操作无法完成。(OSStatus错误2003329396。)

Error Domain=NSOSStatusErrorDomain Code=2003329396 "The operation couldn’t be completed. (OSStatus error 2003329396.)"

我不确定如何保证我可以停止AVAudioSession。我试图继续调用 [[AVAudioSession sharedInstance] setActive:NO er​​ror:& error] ,只要我无法停止音频会话,但那只是似乎没有用。任何帮助将不胜感激。谢谢!

I am not sure how to guarantee that I can stop the AVAudioSession. I've tried to keep calling [[AVAudioSession sharedInstance] setActive:NO error:&error] for as long as I am unable to stop the audio session, but that just doesn't seem to work. Any help would be greatly appreciated. Thank you!

推荐答案

我发现如果我在几秒钟内再试一次它会起作用。我正在使用此代码。

I've found if I try again in a couple of seconds it will work. I'm using this code.

-(void)configureAVAudioSession:(bool)active {

    AVAudioSession *audioSession = [AVAudioSession sharedInstance];

    if (deactivationAttempt < 3) {  // This doesn't always work first time, but don't want to keep trying forever if it decides not to work ever.

        NSError *activationError = nil;
        success = [audioSession setActive:active error:&activationError];

        if (!success) {
            NSLog(@"(de)activation ERROR");
            ++deactivationAttempt;
            [self performSelector:@selector(configureAVAudioSession:) withObject:false afterDelay:2.0];
        }
        else {  // Success!
            deactivationAttempt = 0;
        }
    }
    else {  // Failed, but reset the counter in case we have more luck next time
        deactivationAttempt = 0;
    }
}

来自文档:


如果当前正在运行任何关联的音频对象(如队列,转换器,播放器或录像机),则取消激活会话将失败。

Deactivating your session will fail if any associated audio objects (such as queues, converters, players or recorders) are currently running.

我想从队列中清除话语需要一段时间。

I guess it takes a while for the utterance to be cleared from the queue.

这篇关于如何在AVSpeechUtterance之后始终停止AVAudioSession的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆