当前位置: 首页 > 知识库问答 >
问题:

如何在AVSpeechUtterance后持续停止AVAudio会话

隗俊誉
2023-03-14

我想做的是允许我的应用程序在后台音频应用程序播放音频时使用AVSpeechSynthesizer说话。当我的应用程序正在讲话时,我希望后台应用程序的音频“变暗”,然后在我的应用程序结束讲话后返回其原始音量。

在我的AudioFeedback类中,我初始化我设置的AVAudio会话像这样:

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

每当我想说一个新的话语时,我都会做以下事情。我遵循了AVSpeechSynthesizer问题的建议,有解决办法吗?每次创建一个新的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和当前AvSpeechEutrance与上一个已知的合成器和声音匹配,是否应该停止音频会话以将背景音频恢复到正常音量。

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

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

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

我不知道如何保证我可以停止播放。我已尝试继续调用[[AVAudioSession sharedInstance]设置活动:无错误:


共有2个答案

华锦
2023-03-14

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

测试

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

我找到的唯一解决办法是把这个短语改长。

邢法
2023-03-14

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

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

从文档中:

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

我想这句话需要一段时间才能从队列中清除出来。

 类似资料:
  • Since 10.0.18 stopContinuousLocation stopContinuousLocation 停止持续获取当前设备的经纬度信息 支持版本:从10.0.18开始 使用方法 和startContinuousLocation 配对使用, 单独使用没有效果, 且一定要先点击 启动持续定位,在点击停止持续定位才有效果。 测试地址:startContinuousLocation Al

  • 我很难理解以下代码示例的行为; 代码正常工作,直到调用观察到128项。发射和观察是平行的。但在那之后,Flowable继续发射项目(显然在某处排队),但直到所有1000个项目发射完毕,才观察到任何项目。发射完所有1000个项目后,剩下的项目( 这看起来与128的背压缓冲区大小有关,但我仍然希望发射和观察在整个1000个项目中是平行的,因为观察者显然不比发射者慢。我有什么遗漏吗?我应该怎么做来修复代

  • 问题内容: 我在停止“供稿”时遇到问题;cancel参数似乎对after方法没有任何影响。尽管“进纸停止”已打印到控制台。 我尝试使用一个按钮将启动供稿,而另一个按钮将停止供稿。 随着输出: 问题答案: 问题是,即使你打电话与停止循环,已经有等待消防挂起的工作。按下停止按钮不会触发新的作业,但是旧的作业仍然存在,并且当它自己调用时,它将传入False,这将导致循环继续。 您需要取消待处理的作业,以

  • 问题内容: 每当我在searchview中进行搜索时,我一直在努力阻止索引超出范围异常崩溃。我尝试了网上列出的几件事: 在搜索中使数组脱离索引绑定异常 https://www.codeproject.com/Questions/1040119/Android-app-is-crashing-with- Index-out-of-range-is 但到目前为止没有任何帮助。这个问题是我的代码特有的,

  • 我正在使用exoplayer,我注意到当我在一个活动中播放视频,然后通过按下按钮切换到另一个活动时,视频本身会停止播放以切换到新活动,但音频会继续播放。如果我返回旧活动并再次播放视频,音频仍然会继续播放我再次播放视频时听到的音频,现在在歌曲的不同时间同时听到两次音频。 这是我正在使用的代码有人知道这个问题的解决方案吗?

  • 问题内容: 我正在使用我的应用程序拨打电话。 一段时间后有什么办法可以终止通话?还是在ACTION_CALL开始之前设置一个计时器? 我正在使用Prasanta博客中的以下代码,但由于某些原因,导致出现以下错误。有什么建议? 无法解决 问题答案: 您的问题已被问过很多次了。简短的答案是,没有官方的方法可以做到这一点。 在一个问题中,有人建议打开飞行模式(应用程序当然需要权限才能执行此操作)。这很粗