【问题标题】:How to consistently stop AVAudioSession after AVSpeechUtterance如何在 AVSpeechUtterance 之后始终停止 AVAudioSession
【发布时间】:2014-03-20 12:32:24
【问题描述】:

我想要做的是让我的应用在后台音频应用正在播放音频时使用AVSpeechSynthesizer 说出话语。在我的应用说话时,我希望后台应用的音频“变暗”,然后在我的应用说完后恢复到原来的音量。

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

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

每当我想说出新的话语时,我都会执行以下操作。我遵循An issue with AVSpeechSynthesizer, Any workarounds? 的建议,每次都创建一个新的 AVSpeechSynthesizer 以“确保”始终收到取消(它似乎有效,我不知道为什么)。

- (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 与最后一个已知的合成器和话语匹配,我检查是否应该停止音频会话以将背景音频恢复到正常音量。

-(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);
        }
    }
}

我遇到的问题是,有时,音频会话会毫无问题地停止,而其他时候,音频会话将无法停止并出现以下错误:

Error Domain=NSOSStatusErrorDomain Code=2003329396 “操作无法完成。(OSStatus 错误 2003329396。)”

我不确定如何保证我可以停止 AVAudioSession。只要我无法停止音频会话,我就一直尝试拨打[[AVAudioSession sharedInstance] setActive:NO error:&error],但这似乎不起作用。任何帮助将不胜感激。谢谢!

【问题讨论】:

  • 对于那些关注的人,我已经联系了 Apple 技术支持,他们要求我提交关于该问题的错误。就解决方法而言,我已改用“AVAudioSessionCategoryOptionMixWithOthers”而不是“AVAudioSessionCategoryOptionDuckOthers”。 ShadowDES 似乎有一个有限的解决方法,这对我来说不可能,但可能对其他人有用。我自己没试过。

标签: ios ios7 avaudiosession avspeechsynthesizer


【解决方案1】:

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

-(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;
    }
}

来自文档:

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

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

【讨论】:

  • 当您尝试停用音频会话时,可能是合成器尚未完成讲话。您可以使用 协议。它对我来说一直有效,没有错误。
【解决方案2】:

我也遇到过同样的问题,我相信我已经找到了原因。对我来说,如果我说的短语太短,就会出错。如果它“足够长”,则没有错误。

我测试过

NSString *phraseToSay = [NSString stringWithFormat:@"One Two Three Four Five"]; // Gives the error
NSString *phraseToSay = [NSString stringWithFormat:@"One Two Three Four Five Six"]; // No error

我找到的唯一解决方案是让短语ToSay 更长。

【讨论】:

  • 太有趣了。不幸的是,这对我来说不是一个有用的工作,因为我的短语会有不同的长度并且通常很长。不过感谢分享!希望这对其他人有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-08
  • 2021-03-13
  • 2020-08-02
  • 2013-07-05
  • 1970-01-01
相关资源
最近更新 更多