iOS音频问题通用配置
[[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:NULL];
**场景一
**
场景说明:
应用A正在播放音乐,应用B启动语音合成,但不中断应用A播放。
解决步骤:
- 在应用B中设置AVAudioSession的Category属性:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:***AVAudioSessionCategoryOptionMixWithOthers ***error:nil]; - 启动语音合成:
[_iFlySpeechSynthesizer startSpeaking:str];
**场景二
**
场景说明:
应用A正在播放音乐,应用B启动语音合成,此时中断应用A播放,当合成结束后自动恢复应用A播放。
解决步骤:
- 在应用B中设置AVAudioSession的Category属性:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; - 启动语音合成:
[_iFlySpeechSynthesizerstartSpeaking:str]; - 合成结束后会调用回调方法:
-(void)onCompleted IFlySpeechError) error
在此回调方法中实现如下操作以恢复应用A的音乐播放:
[[AVAudioSession sharedInstance] setActive:NOwithOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation* error:NULL]; - 如果是调用stopSpeaking结束合成,则不会调用步骤3的回调方法。此时需要在调用stopSpeaking之后实现如下操作以恢复应用A的音乐播放:
[[AVAudioSession sharedInstance] setActive:NOwithOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivationerror:NULL];
**场景三
**
场景说明:
应用A正在播放音乐,应用B启动语音识别,但不中断应用A播放。
解决步骤:
- 在应用B中设置AVAudioSession的Category属性:
[[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionMixWithOtherserror:nil]; - 启动语音识别:
[_iFlySpeechRecognizerstartListening];
**场景四
**
场景说明:
应用A正在播放音乐,应用B启动语音识别,此时中断应用A播放,当识别结束后自动恢复应用A播放。
解决步骤:
- 在应用B中设置AVAudioSession的Category属性:
[[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil]; - 启动语音识别:
[_iFlySpeechRecognizerstartListening]; - 识别结束后会调用回调方法:
- (void)onError
IFlySpeechError ) error
在此回调方法中实现如下操作以恢复应用A的音乐播放:
[[AVAudioSession sharedInstance] setActive:NOwithOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation*error:NULL];
**场景五
**
场景说明:
应用A正在播放音乐,然后在应用A启动语音识别,但不中断之前的音乐播放。
解决步骤:
- 在应用A启动识别前设置AVAudioSession的Category属性:
[[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker
|
AVAudioSessionCategoryOptionAllowBluetooth|
AVAudioSessionCategoryOptionMixWithOtherserror:nil];
- 启动语音识别:
[_iFlySpeechRecognizerstartListening];
**场景六
**
场景说明:
应用A正在播放音乐,然后在应用A启动语音识别,此时中断之前的音乐播放。当识别结束后自动恢复音乐播放。
解决步骤:
- 在应用A启动识别前中断正在运行的音乐播放:
NSDictionary *userInfo = [NSDictionarydictionaryWithObjectsAndKeys:[NSNumbernumberWithInteger:1],AVAudioSessionInterruptionTypeKey, nil];
[[NSNotificationCenter defaultCenter]postNotificationName:AVAudioSessionInterruptionNotification object:niluserInfo:userInfo]; - 设置识别AVAudioSession的Category属性:
[[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryRecord withOptions: AVAudioSessionCategoryOptionAllowBluetootherror:nil]; - 启动语音识别:
[_iFlySpeechRecognizerstartListening]; - 识别结束后会调用回调方法:
- (void)onError
IFlySpeechError ) error
在此回调方法中先恢复设置启动识别之前的AVAudioSession的Category*属性。然后在此回调方法中恢复应用A之前的音乐播放:
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumbernumberWithInteger:0],AVAudioSessionInterruptionTypeKey, nil];
[[NSNotificationCenter defaultCenter]postNotificationName:AVAudioSessionInterruptionNotification object:niluserInfo:userInfo];
注意事项:
- 切不可在识别结束后直接调用:
[[AVAudioSession sharedInstance] setActive:NOwithOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivationerror:NULL];
因为应用中还有音频播放服务未结束,只有在应用中所有音频服务都结束后才可以调用。 - 应用A中被中断的音乐播放控件必须有系统中断通知处理。
**场景七
**
场景说明:
应用A正在播音或录音,然后在应用A启动语音合成,但不中断之前的播音或录音。
解决步骤:
- 在应用A启动合成前设置AVAudioSession的Category属性:
[[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionMixWithOtherserror:nil]; - 启动语音合成:
[_iFlySpeechSynthesizerstartSpeaking:str];
**场景八
**
场景说明:
应用A正在播音或录音,然后在应用A启动语音合成,此时中断之前的播音或录音。当合成结束后自动恢复播音或录音。
解决步骤:
-
在应用A启动合成前中断正在运行的播音或录音:
NSDictionary *userInfo = [NSDictionarydictionaryWithObjectsAndKeys:[NSNumbernumberWithInteger:1],AVAudioSessionInterruptionTypeKey, nil];
[[NSNotificationCenter defaultCenter]postNotificationName:AVAudioSessionInterruptionNotification object:niluserInfo:userInfo]; -
设置合成AVAudioSession的Category属性:
[[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryPlayback error:nil]; -
启动语音合成:
[_iFlySpeechSynthesizerstartSpeaking:str]; -
合成结束后会调用回调方法:
IFlySpeechError) error
-(void)onCompleted
在此回调方法中先恢复设置启动合成之前的AVAudioSession的Category*属性。然后在此回调方法中恢复应用A之前的播音或录音:
NSDictionary *userInfo = [NSDictionarydictionaryWithObjectsAndKeys:[NSNumber numberWithInteger:0],AVAudioSessionInterruptionTypeKey,nil];
[[NSNotificationCenter defaultCenter]postNotificationName:AVAudioSessionInterruptionNotification object:niluserInfo:userInfo]; -
如果是调用stopSpeaking结束合成,则不会调用步骤4的回调方法。此时需要在调用stopSpeaking之后先恢复设置启动合成之前的AVAudioSession的Category属性。然后在此回调方法中恢复应用A之前的播音或录音:
NSDictionary *userInfo = [NSDictionarydictionaryWithObjectsAndKeys:[NSNumber numberWithInteger:0],AVAudioSessionInterruptionTypeKey,nil];
[[NSNotificationCenter defaultCenter]postNotificationName:AVAudioSessionInterruptionNotification object:niluserInfo:userInfo];
注意事项: -
切不可在合成结束后直接调用:
[[AVAudioSession sharedInstance] setActive:NOwithOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivationerror:NULL];
因为应用中还有播放或录音服务未结束,只有在应用中所有音频服务都结束后才可以调用。 -
应用A中被中断的播音或录音控件必须有系统中断通知处理。
**特别说明
**
- 上面介绍的只是一些典型场景,还有很多其他复杂场景这里不再一一例举,但基本可以找到类似的解决方法;
- 以上各场景中有关AVAudioSession的Category属性设置并不唯一,可根据实际需要作适当更改;
- 激活AVAudioSession:
[[AVAudioSession sharedInstance] setActive:YESerror:NULL];
一般是系统默认启动的,可以不用调用。
**常见问题
**
-
合成开始播放声音时音量由小变大
问题说明:
在启动语音合成播放音频时,播放的音量刚开始由小逐渐变大最后正常。此现象目前只在iPhone 7上出现,其他机型没有出现。
出现机型:
iPhone 7 iOS10.1;
出现场景:
如果在启动语音合成前如此设置AVAudioSession的Category属性:
[[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryPlayAndRecordwithOptions:AVAudioSessionCategoryOptionDefaultToSpeaker|AVAudioSessionCategoryOptionAllowBluetootherror:nil];
a. 在合成播放过程中被其他音频服务中断后又恢复会出现此现象;
b. 在本次合成播放结束后如果没有设置:
[[AVAudioSession sharedInstance] setActive:NOwithOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivationerror:NULL];
则当重新启动新的合成服务时会出现此现象。
解决思路:
a. 在启动合成前将AVAudioSession的Category属性设置为AVAudioSessionCategoryPlayback,则可以完全避免上述问题。
b. 若启动合成前AVAudioSession的Category属性仍是AVAudioSessionCategoryPlayAndRecord,则以上场景a问题无法避免。
c. 若启动合成前AVAudioSession的Category属性仍是AVAudioSessionCategoryPlayAndRecord,则可以通过如下操作避免场景b问题。在每次启动合成服务前设置:
[[AVAudioSessionsharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivationerror:NULL];
初步怀疑这可能是iPhone 7 的bug,因为其他机型上并没有出现,如果大家有更好的解决方案,欢迎留言分享。 -
AVAudioSession警告
只有在应用中所有正在运行的音频服务都结束后才可以调用:
[[AVAudioSession sharedInstance] setActive:NOwithOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivationerror:NULL];
否则会出现如下警告:
[avas] AVAudioSession.mm:1074:-[AVAudioSessionsetActive:withOptions:error:]: Deactivating an audio session that has runningI/O. All I/O should be stopped or paused prior to deactivating the audiosession. -
蓝牙耳机无法录音
所使用的蓝牙耳机必须支持A2DP协议。 后台无法启动合成或识别
问题说明:
当应用A正在处于后台工作时,此时启动应用A音频服务(播放或者录音)或者恢复应用A中被中断的音频服务,音频启动会失败。
原因分析:
出现以上现象时系统会报AVAudioSessionErrorCodeCannotInterruptOthers
(错误码为560557684)。这是因为当启动后台应用的音频服务时不能影响前台应用的音频服务,因此后台应用的AVAudioSession的Category属性必须含有***AVAudioSessionCategoryOptionMixWithOthers
*** 选项。
解决方法:
在合成或者识别前如下设置AVAudioSession的Category属性:
[[AVAudioSessionsharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:
AVAudioSessionCategoryOptionMixWithOtherserror:nil];
或者
[[AVAudioSessionsharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:
AVAudioSessionCategoryOptionMixWithOtherserror:nil];