I'm trying to set my AVAudioSession
to inactive to get back to normal state.
My utterance function:
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 {}
}
}
}
}
My method is correctly called, but my audioSession
still active when the utterance
is finished. i've tried lot of thing but nothing work :(.
A part from documentation of AVAudioSession:
Discussion
If another active audio session has higher priority than yours (for example, a phone call), and neither audio session allows mixing, attempting to activate your audio session fails. Deactivating your session will fail if any associated audio objects (such as queues, converters, players, or recorders) are currently running.
My guess is that the failure to deactivate the session is the running process(es) of your queue
as I highlighted in the document quote.
Probably you should make the deactivation process synchronous instead of asynchronous OR make sure that all the running actions under your queue
has been processed.
Give this a try:
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 {}
}
}
}
I would suggest using an AvAudioPlayer. They have very easy start and stop commands.
first declare the audio player as a variable
var SoundEffect: AVAudioPlayer!
then select the file you need
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()
and to stop the audio player
if SoundEffect != nil {
SoundEffect.stop()
SoundEffect = nil
}
You cannot stop or deactive AudioSession
, your app gets it upon launching. Documentation:
An audio session is the intermediary between your app and iOS used to configure your app’s audio behavior. Upon launch, your app automatically gets a singleton audio session.
So method -setActive:
does not make your AudioSession
"active", it just puts its category and mode configuration into action. For getting back to the "normal state", you could set default settings or just call setActive(false, with:.notifyOthersOnDeactivation)
, that will be enough.
来源:https://stackoverflow.com/questions/43373486/avaudiosession-never-stopped