赞
踩
希望大家收藏:
本文持续更新地址:https://haoqchen.site/2018/04/26/iflytek-awaken-asr/
- int main(int argc, char **argv)//这只是主体程序
- {
- //init iflytek
- int ret = 0 ;
- ret = MSPLogin(NULL, NULL, lgi_param);
-
- memset(&asr_data, 0, sizeof(UserData));
- ret = build_grammar(&asr_data); //第一次使用某语法进行识别,需要先构建语法网络,获取语法ID,之后使用此语法进行识别,无需再次构建
-
- while (1)
- {
- run_ivw(NULL, ssb_param);
-
- if(g_is_awaken_succeed){
- run_asr(&asr_data);
- g_is_awaken_succeed = FALSE;
- }
-
- if(g_is_order_publiced == FALSE){
- if(g_order==ORDER_BACK_TO_CHARGE){
- play_wav((char*)concat(PACKAGE_PATH, "audios/back_to_charge.wav"));
- }
- if(g_order == ORDER_FACE_DETECTION){
- play_wav((char*)concat(PACKAGE_PATH, "audios/operating_face_rec.wav"));
- }
- g_is_order_publiced = TRUE;
- }
-
- }
- exit:
- MSPLogout();
- }
上面是main函数的主体部分
登录->构建语法->进入while(1)循环
在while(1)循环中,运行run_ivw(NULL, ssb_param); 开启录音,创建一个新的线程接收录音并上传至服务器等待唤醒结果。此时run_ivw处于阻塞状态,一直持续到收到唤醒结果,然后停止录音退出唤醒服务。
- void run_ivw(const char *grammar_list , const char* session_begin_params)//这只是主题
- {
- //start QIVW
- session_id=QIVWSessionBegin(grammar_list, session_begin_params, &err_code);
- err_code = QIVWRegisterNotify(session_id, cb_ivw_msg_proc,NULL);
- //start record
- err_code = create_recorder(&recorder, iat_cb, (void*)session_id);
- err_code = open_recorder(recorder, get_default_input_dev(), &wavfmt);
- err_code = start_record(recorder);
-
- record_state = MSP_AUDIO_SAMPLE_FIRST;
-
- while(record_state != MSP_AUDIO_SAMPLE_LAST)
- {
- sleep_ms(200); //阻塞直到唤醒结果出现
- printf("waiting for awaken%d\n", record_state);
- }
-
- exit:
- if (recorder) {
- if(!is_record_stopped(recorder))
- stop_record(recorder);
- close_recorder(recorder);
- destroy_recorder(recorder);
- recorder = NULL;
- }
- if (NULL != session_id)
- {
- QIVWSessionEnd(session_id, sse_hints);
- }
- }
只有当唤醒结果是成功的才运行run_asr(&asr_data),该函数构建离线命令词识别参数,调用demo_mic函数。该函数的作用与run_ivw函数基本相似,初始化语音识别、开始识别、等待15秒或者识别完成之后关闭录音
- static void demo_mic(const char* session_begin_params)//这只是主体程序
- {
- struct speech_rec_notifier recnotifier = {
- on_result,
- on_speech_begin,
- on_speech_end
- };
-
- errcode = sr_init(&iat, session_begin_params, SR_MIC, &recnotifier);
- errcode = sr_start_listening(&iat);
- /* demo 15 seconds recording */
- while(i++ < 15 && iat.session_id != NULL)
- sleep(1);
- errcode = sr_stop_listening(&iat);
- sr_uninit(&iat);
- }
语音唤醒的回调函数为:
- int cb_ivw_msg_proc( const char *sessionID, int msg, int param1, int param2, const void *info, void *userData )//这只是主体部分程序
- {
- if (MSP_IVW_MSG_ERROR == msg) //唤醒出错消息
- {
- g_is_awaken_succeed = FALSE;
- record_state = MSP_AUDIO_SAMPLE_LAST;
- }else if (MSP_IVW_MSG_WAKEUP == msg) //唤醒成功消息
- {
- g_is_awaken_succeed = TRUE;
- record_state = MSP_AUDIO_SAMPLE_LAST;
- }
- int ret = stop_record(recorder);
- return 0;
- }
该函数通过服务器返回的消息判断唤醒结果,这里我们通过全局变量向主函数以及录音线程传递结果,以及时做出该有的反应。
离线命令词识别的回调函数:
- void on_result(const char *result, char is_last)
- {
- if (result) {
- size_t left = g_buffersize - 1 - strlen(g_result);
- size_t size = strlen(result);
- if (left < size) {
- g_result = (char*)realloc(g_result, g_buffersize + BUFFER_SIZE);
- if (g_result)
- g_buffersize += BUFFER_SIZE;
- else {
- printf("mem alloc failed\n");
- return;
- }
- }
- strncat(g_result, result, size);
- show_result(g_result, is_last);
- g_order = get_order(g_result);
- if(g_order > ORDER_NONE){
- g_is_order_publiced = FALSE;
- }
- }
- }
持续获取结果,然后调用get_order函数获取结果并返回到全局变量g_order中。这个get_order函数是我根据自己的语法特性编写的。各位看官可以根据自己的情况做更改。我的语法特性请看下图:
主要就是todo+order的形式,其中21300-21399是todo的id,21400-21499是order的id。这样就可以在获取结果时很明显地区分开todo和order,进而识别出语义。
这个语音唤醒与命令词识别一开始也主要想用在ROS系统进行机器人语音控制。这里给出了indigo版本的实现。
在这个包中,我定义了一个sr_order的msg,然后定义一个awaken_asr节点,当获取到识别结果时就发布消息。同时给出了一个listener接收消息的例子。熟悉ROS的朋友应该都知道我在说啥,就不细说了,具体看我github中ROS的分支程序。
SDK文档
科大讯飞工作人员的态度真的很棒,之前调试发现了一个bug,向他们反馈,虽然还没解决,但是一直在积极跟进。
另外希望科大讯飞可以降低起购量。学生党真的想用,但是不需要这么多的装机量。最后在他们官方群哭诉了挺久,他们的工作人员建议我实名制学生身份,然后向他们服务申请了几个学术用途的装机量。他们做支持的小姐姐不辞劳苦地忙了很久,最后终于给我申请到了。在此感谢科大讯飞给了我这个机会学习到这些知识。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。