美文网首页
ios 语音合成小结及遇到的一些问题

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

作者: Superman168 | 来源:发表于2018-10-29 19:58 被阅读0次

    前言

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

    需求

    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 语音合成小结及遇到的一些问题

          本文链接:https://www.haomeiwen.com/subject/weybtqtx.html