ios 语音合成小结及遇到的一些问题

前言

最近在开发过程中,有语音播放的需求,其实之前项目集成了科大讯飞的语音,但在开发过程中遇到了一问题,特此总结一下

需求

APP 收到推送消息,然后语音播报一下内容,类似支付宝和微信的收付款语音提醒,没说后台必须也可以播放,但有一点是:收到多少推送消息,就播多少条!!!也没见过支付宝、微信的一次多人同时支付是怎么播报的,反正最终是体验了我们自己的APP的这个功能。

先说一下科大讯飞的简单使用

科大讯飞集成播放识别等,其实并没有什么难点,集成完 SDK,在需要的地方实例化一下,播放对象是一个单例对象,所以只需要实例化一次即可:

/**
 * 初始化讯飞语音合成对象
 */
-(void)creatVoice
{
     // 合成对象的单例
    _iFlySpeechSynthesizer = [IFlySpeechSynthesizer sharedInstance];
    //设置协议委托对象
    _iFlySpeechSynthesizer.delegate = self;
    //设置合成参数
    //设置在线工作方式
    [_iFlySpeechSynthesizer setParameter:[IFlySpeechConstant TYPE_CLOUD]
                                  forKey:[IFlySpeechConstant ENGINE_TYPE]];
    //设置音量,取值范围 0~100
    [_iFlySpeechSynthesizer setParameter:@"100"
                                  forKey: [IFlySpeechConstant VOLUME]];
    //发音人,默认为”xiaoyan”,可以设置的参数列表可参考“合成发音人列表”
    [_iFlySpeechSynthesizer setParameter:@"xiaoyan"
                                  forKey: [IFlySpeechConstant VOICE_NAME]];
    //保存合成文件名,如不再需要,设置为nil或者为空表示取消,默认目录位于library/cache下
//    [_iFlySpeechSynthesizer setParameter:@"tts.pcm"
//                                  forKey: [IFlySpeechConstant TTS_AUDIO_PATH]];    
}

还有一些其他的设置参数,根据需要设置,也可以动态来设置:

    // 科大讯飞
    //发音人,默认为”xiaoyan”,可以设置的参数列表可参考“合成发音人列表”
//    https://doc.xfyun.cn/msc_ios/语音合成.html
    // @"xiaofeng"---@"xiaomei"---@"xiaoyan"---@"kaiselin"
    [_iFlySpeechSynthesizer setParameter:voiceName?voiceName:@"xiaoyan"
                                  forKey: [IFlySpeechConstant VOICE_NAME]];
    //设置音量,取值范围 0~100
    [_iFlySpeechSynthesizer setParameter:volume?volume:@"100"
                                  forKey: [IFlySpeechConstant VOLUME]];
    //设置语速,取值范围 0~100
    [_iFlySpeechSynthesizer setParameter:speed?speed:@"100"
                                  forKey: [IFlySpeechConstant SPEED]];
    // 调用此函数进行合成,如果发生错误会回调错误`onCompleted`
    [_iFlySpeechSynthesizer startSpeaking:voiceContent];

so easy ! 就连科大讯飞的文档也极其简单,可以看一下:

科大讯飞语音合成的文档

科大讯飞的帮助说明文档

到这里其实已经 OK 了,基本的语音播放功能已经实现了,单条消息可以无障碍播放了,但是距离需求还有一点距离。

同时收到多条消息播放的问题

遇见这个需求,本来想简便一点,省一点事,看看讯飞有没有类似这样的处理,同时给多条内容,调用播放,然并卵,每次调用都会从头开始重新播放新的一条消息,并没有什么处理,没办法啊,只能自己想办法了

解决办法,思路:

每次收到推送消息,都存到数组中,监听这个数组元素的变化,在监听到变化后,就调用 讯飞的播放语音播放。

这时就涉及到了一个数组监听的问题,可以移步刚写的另一篇文章

iOS KVO监听数组元素的变化

具体代码如下:

  1. 在收到推送消息的时候:
#pragma mark -- 处理推送消息
- (void)handleUserInfo:(NSDictionary *)dic
{
    NSString *voiceContent = [NSString stringWithFormat:@"%@",[dic objectForKey:@"voice"]];
    // 注意这里不要用[array addObject:]这种方法要用下面的方法
    [[obserVer mutableArrayValueForKeyPath:@"dataArray"] addObject:voiceContent];
}
  1. 监听消息处理:
#pragma mark -- 监听调用方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"dataArray"]) {
        //
        if (obserVer.dataArray.count > 0) {
//            if (!_iFlySpeechSynthesizer.isSpeaking) {
                curVoice = obserVer.dataArray.firstObject;
                [_iFlySpeechSynthesizer startSpeaking:curVoice];
//            }
        }
    }
}
  1. 科大讯飞语音播放结束回调方法监听处理:

#pragma mark -- IFlySpeechSynthesizerDelegate
// 结束回调
- (void)onCompleted:(IFlySpeechError*) error
{
//    [[obserVer mutableArrayValueForKeyPath:@"dataArray"] removeObject:curVoice];
    // 删除,添加都会出发监听方法
    [[obserVer mutableArrayValueForKeyPath:@"dataArray"] removeObjectAtIndex:0];
    [_iFlySpeechSynthesizer stopSpeaking];
// 删除,添加都会出发监听方法,所以不能在这里播放
//    if (obserVer.dataArray.count > 0) {
//        NSString *voiceContent = [obserVer.dataArray objectAtIndex:0];
//        [_iFlySpeechSynthesizer startSpeaking:voiceContent];
//    }
//    [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:NULL];
}

//合成开始
- (void) onSpeakBegin
{
    
}
//合成缓冲进度
- (void) onBufferProgress:(int) progress message:(NSString *)msg {
    
}
//合成播放进度
- (void) onSpeakProgress:(int) progress beginPos:(int)beginPos endPos:(int)endPos
{

}

小结

这里多条消息播放的思路大概是:每次收到推送消息,都存到数组中,监听这个数组元素的变化,在监听到变化后,就调用 讯飞的播放语音播放,同时监听讯飞播放的回调,播放完成以后,删除数组中的第一个元素,这时又会触发数组的监听方法,接着在获取到监听的方法中判断一下数组的数量,继续播放第一条,删一个播一个。

你可能感兴趣的:(ios 语音合成小结及遇到的一些问题)