AVAudioSession永远不会停止

4

我试图将我的AVAudioSession设置为非活动状态,以恢复正常状态。

我的语音函数:

class SSpeech : NSObject, AVSpeechSynthesizerDelegate {

    var group = DispatchGroup();
    var queue = DispatchQueue(label: "co.xxxx.speech", attributes: [])

    class var sharedInstance: SSpeech {
        struct Static {
            static var instance: SSpeech?
        }
        if !(Static.instance != nil) {
            Static.instance = SSpeech()
        }
       return Static.instance!
    }

   required override init() {
       super.init();
       self.speechsynt.delegate = self;
   }

   deinit {
      print("deinit SSpeech")
   }

   let audioSession = AVAudioSession.sharedInstance();
   var speechsynt: AVSpeechSynthesizer = AVSpeechSynthesizer()
   var queueTalks = SQueue<String>();

   func pause() {
        speechsynt.pauseSpeaking(at: .word)
   }

   func talk(_ sentence: String, languageCode code:String = SUtils.selectedLanguage.code, withEndPausing: Bool = false) {
       if SUser.sharedInstance.currentUser.value!.speechOn != 1 {
           return
        }

        queue.async{            
            self.queueTalks.enQueue(sentence)
            do {
                let category = AVAudioSessionCategoryPlayback;
                var categoryOptions = AVAudioSessionCategoryOptions.duckOthers
                if #available(iOS 9.0, *) {
                    categoryOptions.formUnion(AVAudioSessionCategoryOptions.interruptSpokenAudioAndMixWithOthers)
                 }
                try self.audioSession.setCategory(category, with: categoryOptions)
                try self.audioSession.setActive(true);
            } catch _ {
                return;
            }

            self.utteranceTalk(sentence, initSentence: false, speechsynt: self.speechsynt, languageCode:code, withEndPausing: withEndPausing)

            do {
                try self.audioSession.setCategory(AVAudioSessionCategoryPlayback, with: AVAudioSessionCategoryOptions.mixWithOthers)
            } catch _ {
                return;
            }
        }
    }

    func utteranceTalk(_ sentence: String, initSentence: Bool, speechsynt: AVSpeechSynthesizer, languageCode:String = "en-US", withEndPausing: Bool = false){
        if SUser.sharedInstance.currentUser.value!.speechOn != 1 {
            return
        }

        let nextSpeech:AVSpeechUtterance = AVSpeechUtterance(string: sentence)
        nextSpeech.voice = AVSpeechSynthesisVoice(language: languageCode)
        if !initSentence {
            nextSpeech.rate = 0.4;
        }

        if(withEndPausing){
            nextSpeech.postUtteranceDelay = 0.2;
        }
        speechsynt.speak(nextSpeech)
    }


    func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance:AVSpeechUtterance) {
        print("Speaker has finished to talk")

        queue.async {
               do {
                   try self.audioSession.setActive(false, with: AVAudioSessionSetActiveOptions.notifyOthersOnDeactivation)
               }
               catch {}
           }
       }
    }
}

我的方法被正确地调用,但是当utterance结束时,我的audioSession仍然处于活动状态。我尝试了很多方法但都没有起作用 :(。


也许可以看一下这篇文章:https://dev59.com/xnzaa4cB1Zd3GeqPTbMe?rq=1 - GCBenson
@arunjos007 我不确定我理解你的意思。你想知道我如何知道我的音频会话仍然处于活动状态吗? - Makaille
@Makaille 是的,就是这样。 - arunjos007
@arunjos007 只是一种假设,因为就像我说的那样,音乐仍然以低质量和低音量在背景中播放,从未回到旧状态。 - Makaille
@Makaille,你看过我的建议了吗? - NeverHopeless
显示剩余4条评论
3个回答

1

您无法停止或取消激活AudioSession,该会话在启动时由您的应用程序获取。文档:

音频会话是您的应用程序与iOS之间的中介,用于配置您的应用程序的音频行为。在启动时,您的应用程序自动获取单例音频会话。

因此,方法-setActive:不会使您的AudioSession处于“活动”状态,它只是将其类别和模式配置付诸实践。要回到“正常状态”,您可以设置默认设置或只需调用setActive(false, with:.notifyOthersOnDeactivation),这就足够了。


正如您所看到的,这就是我正在做的事情,我正在尝试找出为什么期望的结果不存在。我调用了 setActive(false, with:.notifyOthersOnDeactivation) 但它没有改变任何东西。 - Makaille
我说你做得很好 :) 你期望什么样的结果?方法 setActive(false) 不应该改变任何东西,它只是告诉系统媒体服务,你的应用程序不需要之前的音频设置。如果你想重置一些设置,你需要停用音频会话,将设置更改为默认值,然后重新激活它。 - Asya
目前,我正在使用耳机从Spotify听音乐(例如),我的应用程序会说“您正在跑步10公里……”。因此,在讲话期间,我的音乐声音会变低。当讲话结束时,来自Spotify的音乐不会恢复到先前的音量。 - Makaille
好的。为了打断背景声音并恢复,您需要设置适当的类别(在您的情况下为AVAudioSessionCategoryPlayback),不使用任何选项(其他音频中断默认情况下已启用),激活AudioSession并在播放完成后停用它。 - Asya
我在这里加入讨论,因为我遇到了类似的问题。实例化一个AudioSession确实会影响应用程序的其他部分。例如,如果在实例化AudioSession之前,AVPlayer将无法开始播放... 我无法找出如何解决这个问题。 - gundrabur

1
我建议使用AvAudioPlayer。它们有非常简单的开始和停止命令。
首先将音频播放器声明为变量。
var SoundEffect: AVAudioPlayer!

然后选择您需要的文件

    let path = Bundle.main.path(forResource: "Untitled2.wav", ofType:nil)!
                    let url = URL(fileURLWithPath: path)
    let sound = try AVAudioPlayer(contentsOf: url)
                        SoundEffect = sound
                        sound.numberOfLoops = -1
                        sound.play()

并停止音频播放器

if SoundEffect != nil {
            SoundEffect.stop()
            SoundEffect = nil
        }

谢谢您的回答,但我没有使用播放器和任何wav或其他声音文件。我通过字符串创建声音,这就是为什么我正在使用speechSynthetizer。 - Makaille

1

除了 AVAudioSession 文档中的一部分:

讨论

如果另一个优先级比你的音频会话更高(例如,电话呼叫),并且两个音频会话都不允许混合,则尝试激活您的音频会话将失败。如果任何相关的音频对象(例如队列、转换器、播放器或记录器)正在运行,则停用会话也将失败。

我猜测停用会话失败的原因是你在文档引用中突出显示的 queue 的运行进程。

也许你应该将停用过程变为同步而不是异步,或者确保你的 queue 下的所有运行操作都已处理完毕

试一试这个:

func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance:AVSpeechUtterance) {
        print("Speaker has finished to talk")

        queue.sync { // <---- `async` changed to `sync`
               do {
                   try self.audioSession.setActive(false, with: AVAudioSessionSetActiveOptions.notifyOthersOnDeactivation)
               }
               catch {}
           }
       }
    }

你好,我回来了。这里说的是同步问题。我进行了不同的测试,在使用蓝牙设备连接音频时出现了错误行为。 - Makaille
暂时可以尝试添加一个10-15秒的延迟,然后尝试停用声音进行测试。由于队列中可能存在一些未完成的操作,因此可能会失败。 - NeverHopeless

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接