-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathmod_baidu_asr.cpp
551 lines (463 loc) · 27.7 KB
/
mod_baidu_asr.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
#include <iostream>
#include <unistd.h>
#include <cstring>
#include <cstdio>
#include <ctime>
#include <typeinfo>
#include <switch.h>
#include <atomic>
//引入语音识别模块
#include "BDSpeechSDK.hpp"
#include "bds_ASRDefines.hpp"
#include "bds_asr_key_definitions.hpp"
using namespace std;
//下面的代码是调用一个带参数的宏,这此宏定义在switch_type.h中,替换后如下一行 1
//switch_status_t mod_baidu_asr_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool);
//SWITCH_MODULE_LOAD_FUNCTION(加载模块时执行的函数)
SWITCH_MODULE_LOAD_FUNCTION(mod_baidu_asr_load);
//下面的代码是调用一个带参数的宏,这此宏定义在switch_type.h中,替换后如下一行
//switch_status_t mod_baidu_asr_shutdown (void)
//SWITCH_MODULE_SHUTDOWN_FUNCTION(卸载时执行的函数)
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_baidu_asr_shutdown);
/*下面的代码是调用一个带参数的宏,这此宏定义在switch_type.h中,替换后如下一行
static const char modname[] = #mod_baidu_asr;
SWITCH_MOD_DECLARE_DATA switch_loadable_module_function_table_t mod_baidu_asr##_module_interface = {SWITCH_API_VERSION, mod_baidu_asr_load, mod_baidu_asr_shutdown, NULL, SMODF_NONE}
SWITCH_MODULE_DEFINITION(模块名,加载时执行的函数,卸载时执行的函数,runtime不知道干啥的)*/
SWITCH_MODULE_DEFINITION(mod_baidu_asr, mod_baidu_asr_load, mod_baidu_asr_shutdown, NULL);
SWITCH_MODULE_RUNTIME_FUNCTION(mod_baidu_asr_runtime);
// bds::BDSSDKMessage push_params;
// push_params.name = bds::ASR_CMD_PUSH_AUDIO;
struct switch_da_t {
int stop;
char *app_name;
char *app_id;
char *chunk_key;
char *secret_key;
char *product_id;
bool asr_finish_tags;//线程是否结束识别 true已结束 未結束false
float vad_pause_frames = 30; //设置vad语句静音切分门限(帧), 30帧 = 300ms
bds::BDSpeechSDK *sdk; //百度sdk
bds::BDSSDKMessage *push_params; //传输方式
switch_channel_t *channel; //freeswitch channels
switch_core_session_t *session; //channels 包含 session
switch_media_bug_t *bug;
};
//原子操作记录当前并发
std::atomic_int curr_concurrent(0);
//原子操作记录识别总次数
std::atomic_int count_concurrent(0);
#ifdef _BDS_EASR_MFE_DNN
#else
#define _BDS_EASR_MFE_DNN ""
#define _BDS_EASR_MFE_CMVN ""
#endif
/**
* 请根据文档说明设置参数
*/
void asr_set_config_params(bds::BDSSDKMessage &cfg_params, switch_da_t *user_data) {
//const bds::TBDVoiceRecognitionDebugLogLevel sdk_log_level = bds::EVRDebugLogLevelTrace;
const bds::TBDVoiceRecognitionDebugLogLevel sdk_log_level = bds::EVRDebugLogLevelTrace; // 关闭详细日志
// app_id app_key app_secret 请测试成功后替换为您在网页上申请的appId appKey和appSecret
const std::string app_id = user_data->app_id;
const std::string chunk_key = user_data->chunk_key;
const std::string secret_key = user_data->secret_key;
const std::string product_id = user_data->product_id; // 普通话搜索模型:1536,普通话搜索模型+语义理解 15361, 普通话输入法模型(有逗号) 1537 , 8001 8002
float vad_pause_frames = user_data->vad_pause_frames; //设置vad语句静音切分门限(帧), 30帧 = 300ms
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "app_id %s\n", user_data->app_id);
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "chunk_key %s\n", user_data->chunk_key);
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "secret_key %s\n", user_data->secret_key);
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "product_id %s\n", user_data->product_id);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s %s %s %s %s %s %f curr_concurrent=%d count_concurrent=%d\n",
switch_channel_get_name(user_data->channel), user_data->app_name, user_data->app_id, user_data->chunk_key,
user_data->secret_key, user_data->product_id, user_data->vad_pause_frames,
curr_concurrent.operator int(), count_concurrent.operator int());
cfg_params.name = bds::ASR_CMD_CONFIG;
cfg_params.set_parameter(bds::ASR_PARAM_KEY_APP_ID, app_id);
// 自训练平台上线模型的调用参数,与product_id 8001 或 8002连用。
// cfg_params.set_parameter(bds::ASR_PARAM_KEY_LMID, 1068); // 设为 product_id = 8002
cfg_params.set_parameter(bds::ASR_PARAM_KEY_CHUNK_KEY, chunk_key);
cfg_params.set_parameter(bds::ASR_PARAM_KEY_PRODUCT_ID, product_id);
cfg_params.set_parameter(bds::COMMON_PARAM_KEY_DEBUG_LOG_LEVEL, sdk_log_level);
cfg_params.set_parameter(bds::ASR_PARAM_KEY_MAX_SPEECH_PAUSE, vad_pause_frames);
// cfg_params.set_parameter(bds::ASR_PARAM_KEY_SAVE_AUDIO_ENABLE, 1); //是否存识别的音频
// cfg_params.set_parameter(bds::ASR_PARAM_KEY_SAVE_AUDIO_PATH, "sdk_save_audio.d"); //存音频的路径
cfg_params.set_parameter(bds::ASR_PARAM_KEY_ENABLE_LONG_SPEECH, 1); // 强制固定值
cfg_params.set_parameter(bds::ASR_PARAM_KEY_CHUNK_ENABLE, 1); // 强制固定值
const std::string mfe_dnn_file_path = _BDS_EASR_MFE_DNN; // bds_easr_mfe_dnn.dat文件路径
const std::string mfe_cmvn_file_path = _BDS_EASR_MFE_CMVN; // bds_easr_mfe_cmvn.dat文件路径
cfg_params.set_parameter(bds::ASR_PARAM_KEY_MFE_DNN_DAT_FILE, mfe_dnn_file_path); // 强制固定值
cfg_params.set_parameter(bds::ASR_PARAM_KEY_MFE_CMVN_DAT_FILE, mfe_cmvn_file_path); // 强制固定值
cfg_params.set_parameter(bds::ASR_PARAM_KEY_COMPRESSION_TYPE, bds::EVR_AUDIO_COMPRESSION_PCM);
// cfg_params.set_parameter(bds::ASR_PARAM_KEY_COMPRESSION_TYPE, bds::EVR_AUDIO_COMPRESSION_BV32); // 有损压缩, 可能遇见音频压缩问题
//设置录音采样率 EVoiceRecognitionRecordSampleRate8K|EVoiceRecognitionRecordSampleRate16K
cfg_params.set_parameter(bds::ASR_PARAM_KEY_SAMPLE_RATE, bds::EVoiceRecognitionRecordSampleRate8K);
}
// 设置启动参数
void asr_set_start_params(bds::BDSSDKMessage &start_params, char *app_name) {
const std::string app = app_name;
start_params.name = bds::ASR_CMD_START;
start_params.set_parameter(bds::ASR_PARAM_KEY_APP, app);
start_params.set_parameter(bds::ASR_PARAM_KEY_PLATFORM, "linux"); //固定值
start_params.set_parameter(bds::ASR_PARAM_KEY_SDK_VERSION, "LINUX TEST"); //固定值
}
/**
* SDK 识别过程中的回调,注意回调产生在SDK内部的线程中,并非调用线程。
* @param message IN SDK的回调信息
* @param user_arg IN 用户设置set_event_listener的第二个参数
* {"results_recognition":["今"],"origin_result":{"corpus_no":6704127917118906481,"err_no":0,"result":{"word":["今"]},"sn":"5FC0A526-64E9-4DB8-AF7F-A959666166A8"},"sn_start_time":"00:00.340","sn_end_time":"00:01.700"}
* {"results_recognition":["今天"],"origin_result":{"corpus_no":6704127917118906481,"err_no":0,"result":{"word":["今天"]},"sn":"5FC0A526-64E9-4DB8-AF7F-A959666166A8"},"sn_start_time":"00:00.340","sn_end_time":"00:01.209"}
* {"results_recognition":["今天天"],"origin_result":{"corpus_no":6704127917118906481,"err_no":0,"result":{"word":["今天天"]},"sn":"5FC0A526-64E9-4DB8-AF7F-A959666166A8"},"sn_start_time":"00:00.340","sn_end_time":"00:01.550"}
* {"results_recognition":["今天天气"],"origin_result":{"corpus_no":6704127917118906481,"err_no":0,"result":{"word":["今天天气"]},"sn":"5FC0A526-64E9-4DB8-AF7F-A959666166A8"},"sn_start_time":"00:00.340","sn_end_time":"00:01.840"}
* {"results_recognition":["今天天气怎"],"origin_result":{"corpus_no":6704127917118906481,"err_no":0,"result":{"word":["今天天气怎"]},"sn":"5FC0A526-64E9-4DB8-AF7F-A959666166A8"},"sn_start_time":"00:00.340","sn_end_time":"00:02.200"}
* {"results_recognition":["今天天气怎样?"],"origin_result":{"corpus_no":6704127917118906481,"err_no":0,"result":{"word":["今天天气怎样?"]},"sn":"5FC0A526-64E9-4DB8-AF7F-A959666166A8","voice_energy":26029.9433593750},"sn_start_time":"00:00.340","sn_end_time":"00:02.509"}
*
*/
void asr_output_callback(bds::BDSSDKMessage &message, void *user_arg) {
// FILE *err_output_file = stderr;
switch_da_t *user_data = (switch_da_t *) user_arg;
const char *channel_name = switch_channel_get_name(user_data->channel);
if (message.name != bds::asr_callback_name) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s shouldn't call\n", channel_name);
return;
}
int status = 0;
if (!message.get_parameter(bds::CALLBACK_ASR_STATUS, status)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s get status failed\n", channel_name);
return;
}
switch (status) {
// 识别工作开始,开始采集及处理数据
case bds::EVoiceRecognitionClientWorkStatusStartWorkIng: {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s 识别工作开始\n", channel_name);
break;
}
// 检测到用户开始说话
case bds::EVoiceRecognitionClientWorkStatusStart: {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s 检测到用户开始说话\n", channel_name);
break;
}
// 本地声音采集结束,等待识别结果返回并结束录音
case bds::EVoiceRecognitionClientWorkStatusEnd: {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s 本地声音采集结束,等待识别结果返回并结束录音\n", channel_name);
break;
}
// 连续上屏,中间结果
case bds::EVoiceRecognitionClientWorkStatusFlushData: {
std::string json_result;
message.get_parameter(bds::CALLBACK_ASR_RESULT, json_result);
switch_event_t *event = nullptr;
if (switch_event_create(&event, SWITCH_EVENT_CUSTOM) == SWITCH_STATUS_SUCCESS) {
event->subclass_name = strdup("baidu_asr_flush_data");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Event-Subclass", event->subclass_name); //事件名
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "ASR-Response", json_result.c_str()); //一句话识别结果
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_channel_get_uuid(user_data->channel)); //通道uuid
switch_event_fire(&event); //发送事件
}
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s patial result: %s\n", switch_channel_get_name(user_data->channel), json_result.c_str());
break;
}
//一句话的最终结果
case bds::EVoiceRecognitionClientWorkStatusFinish: {
std::string json_result;
message.get_parameter(bds::CALLBACK_ASR_RESULT, json_result);
switch_event_t *event = nullptr;
if (switch_event_create(&event, SWITCH_EVENT_CUSTOM) == SWITCH_STATUS_SUCCESS) {
event->subclass_name = strdup("baidu_asr_finish");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Event-Subclass", event->subclass_name); //事件名
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "ASR-Response", json_result.c_str()); //一句话识别结果
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_channel_get_uuid(user_data->channel)); //通道uuid
switch_event_fire(&event); //发送事件
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s final result: %s\n",
switch_channel_get_name(user_data->channel), json_result.c_str());
break;
}
//语义解析
case bds::EVoiceRecognitionClientWorkStatusChunkNlu: {
const char *buf;
int len = 0;
message.get_parameter(bds::DATA_CHUNK, buf, len);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s nlu result:", channel_name);
for (int i = 0; i < len; ++i) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%c", buf[i]);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "\n");
break;
}
// 长语音结束状态 该实例处于空闲状态
case bds::EVoiceRecognitionClientWorkStatusLongSpeechEnd: {
user_data->asr_finish_tags = true;//标记为识别结束
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s 识别完成\n", channel_name);
break;
}
// 产生错误 该实例处于空闲状态
case bds::EVoiceRecognitionClientWorkStatusError: {
int err_code = 0;
int err_domain = 0;
std::string err_desc;
message.get_parameter(bds::CALLBACK_ERROR_CODE, err_code);
message.get_parameter(bds::CALLBACK_ERROR_DOMAIN, err_domain);
message.get_parameter(bds::CALLBACK_ERROR_DESC, err_desc);
std::string sn;
message.get_parameter(bds::CALLBACK_ERROR_SERIAL_NUM, sn);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
"%s 识别出错, err_code: %d, err_domain: %d,err_desc: %s, sn: %s\n",
channel_name, err_code, err_domain, err_desc.c_str(),
sn.c_str());
user_data->asr_finish_tags = true;//标记为识别结束
break;
}
// 用户取消 该实例处于空闲状态
case bds::EVoiceRecognitionClientWorkStatusCancel: {
user_data->asr_finish_tags = true;//标记为识别结束
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s 用户取消\n", channel_name);
break;
}
//录音数据回调 每次上传录音都会执行这里
case bds::EVoiceRecognitionClientWorkStatusNewRecordData: {
break;
}
//当前音量回调 6
case bds::EVoiceRecognitionClientWorkStatusMeterLevel: {
break;
}
//CHUNK: 识别结果中的第三方数据
// case bds::EVoiceRecognitionClientWorkStatusChunkThirdData:
// {
// const char *buf;
// int len = 0;
// message.get_parameter(bds::DATA_CHUNK, buf, len);
// //第三方结果未必是文本字符串,所以以%s打印未必有意义
// fprintf(result_output_file, "third final result len[%d]\n", len);
// //for (int i = 0; i < len; ++i) fprintf(result_output_file, "%c", buf[i]);
// fprintf(result_output_file, "\n");
// break;
// }
// CHUNK: 识别过程结束 应该就一句话结束
case bds::EVoiceRecognitionClientWorkStatusChunkEnd: {
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s CHUNK: 识别过程结束%d\n", switch_channel_get_name(user_data->channel), status);
break;
}
//默认
default: {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s 其它状态%d\n", channel_name, status);
break;
}
}
}
/**
* 释放SDK
*/
void asr_online_release(bds::BDSpeechSDK *sdk) {
bds::BDSpeechSDK::release_instance(sdk);
curr_concurrent--;
}
/**
* 发送停止命令
*/
int asr_online_stop(bds::BDSpeechSDK *sdk) {
FILE *err_output_file = stderr;
std::string err_msg;
bds::BDSSDKMessage stop_params;
stop_params.name = bds::ASR_CMD_STOP;
if (!sdk->post(stop_params, err_msg)) {
fprintf(err_output_file, "stop sdk failed for %s\n", err_msg.c_str());
return 1;
}
return 0;
}
//switch_core_media_bug_add()的回调函数
static switch_bool_t baidu_asr_callback(switch_media_bug_t *bug, void *user_arg, switch_abc_type_t type) {
switch_da_t *user_data = (switch_da_t *) user_arg;
std::string err_msg;
const char *channel_name = switch_channel_get_name(user_data->channel);
switch (type) {
case SWITCH_ABC_TYPE_INIT: {//媒体bug设置成功
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s SWITCH_ABC_TYPE_INIT\n", channel_name);
break;
}
case SWITCH_ABC_TYPE_CLOSE: { //媒体流关闭 资源回收
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s SWITCH_ABC_TYPE_CLOSE\n", channel_name);
//告诉sdk,后续不会再post音频数据 , 注意这个调用之后需要紧接着调用asr_online_stop
user_data->push_params->set_parameter(bds::DATA_CHUNK, NULL, 0);
/* 6 发送停止传输音频数据标记 */
asr_online_stop(user_data->sdk);
/* 7 等待识别结束 */
while (!user_data->asr_finish_tags) {
usleep(10000);//微秒
}
/* 8 关闭日志 ,如果之前调用过 open_log_file */
// bds::BDSpeechSDK::close_log_file();
/* 8 释放sdk 与get_instance 对应 SDK不是处于空闲状态(见下面的空闲状态定义),调用 bds::BDSpeechSDK::release_instance可能引起程序出core。 */
asr_online_release(user_data->sdk);
//内存清理
delete user_data->push_params;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s 释放语音识别通道成功\n", channel_name);
break;
}
case SWITCH_ABC_TYPE_READ_REPLACE: {//读取到音频流
switch_frame_t *frame;
if (user_data->asr_finish_tags == true) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s 识别通道提前结束,挂机\n", channel_name);
switch_channel_hangup(user_data->channel, SWITCH_CAUSE_NORMAL_CLEARING);
} else if ((frame = switch_core_media_bug_get_read_replace_frame(bug))) {
int frame_len = frame->datalen; //语音流长度
char *frame_data = (char *) frame->data; //语音流内容
switch_core_media_bug_set_read_replace_frame(bug, frame);
if (frame->channels != 1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "%s nonsupport channels: %d!\n", channel_name, frame->channels);
return SWITCH_FALSE;
}
user_data->push_params->set_parameter(bds::DATA_CHUNK, frame_data, frame_len);
if (!user_data->sdk->post(*user_data->push_params, err_msg)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s push audio data failed for %s\n", channel_name, err_msg.c_str());
}
// else
// {
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s 发送数据成功 %s", frame_data, switch_channel_get_name(user_data->channel));
// }
}
break;
}
default: {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "default type=%s", to_string(type).c_str());
break;
}
}
return SWITCH_TRUE;
}
//执行这个app时的回调函数-下面的宏替换后如下
//static void start_baidu_asr_session_function (switch_core_session_t *session, 调用app时传的参数)
//static void start_baidu_asr_session_function (switch_core_session_t *session, const char *data)
SWITCH_STANDARD_APP(start_baidu_asr_session_function) {
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_da_t *pvt; //自定义参数
switch_status_t status; //调用 switch_core_media_bug_add()的状态,用来判断断是否调用成功
switch_codec_implementation_t read_impl;
const char *channel_name = switch_channel_get_name(channel);
//函数是内存赋值函数,用来给某一块内存空间进行赋值的
memset(&read_impl, 0, sizeof(switch_codec_implementation_t));
int argc; //调用app时传参个数
char *argv[6] = {0}; //调用app时传的参数 数组
char *lbuf = nullptr; //调用app时传的参数 字符串 会话内存池中的地址
//zstr()//如果字符串为空或长度为零,则返回真值
if (zstr(data)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s 调用 baidu_asr 参数不能为空\n", channel_name);
return;
}
//switch_core_session_strdup() 使用会话池中的内存分配简要复制字符串 返回指向新复制字符串的指针
if (!(lbuf = switch_core_session_strdup(session, data))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s 调用 baidu_asr 获取参数失败1\n", channel_name);
return;
}
//switch_separate_string(要分割的字符串,分割符,拆分后的数组,数组中元素的最大数目) 将字符串分隔为数组,反回分割后数组的元素个数
argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < 6) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s 调用 baidu_asr 获取参数个数不能小于6个\n", channel_name);
return;
}
switch_core_session_get_read_impl(session, &read_impl);
//为自定义数据从会话内存池分配内存
//申请内存通道关闭后会自动释放
//所以不需要手动释放
if (!(pvt = (switch_da_t *) switch_core_session_alloc(session, sizeof(switch_da_t)))) {
return;
}
pvt->stop = 0;
pvt->app_name = argv[0]; //应用名称
pvt->app_id = argv[1]; //识别系统Id
pvt->chunk_key = argv[2]; //chunk_key
pvt->secret_key = argv[3]; //secret_key
pvt->product_id = argv[4]; //识别模型
pvt->asr_finish_tags = false; //线程是否结束识别 true已结束 未結束false
pvt->vad_pause_frames = atof(argv[5]); //设置vad语句静音切分门限(帧), 30帧 = 300ms
pvt->session = session;
pvt->channel = channel;
/* 1 获取sdk实例 */
std::string err_msg;
bds::BDSpeechSDK *sdk = bds::BDSpeechSDK::get_instance(bds::SDK_TYPE_ASR, err_msg);
if (!sdk) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s get sdk failed for %s\n", channel_name, err_msg.c_str());
return;
} else {
curr_concurrent++;
count_concurrent++;
}
/* 2 设置输出回调 */
sdk->set_event_listener(&asr_output_callback, pvt);
/* 3 设置并发送sdk配置参数 */
bds::BDSSDKMessage cfg_params;
asr_set_config_params(cfg_params, pvt);
if (!sdk->post(cfg_params, err_msg)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s init sdk failed for %s\n", channel_name, err_msg.c_str());
bds::BDSpeechSDK::release_instance(sdk);
curr_concurrent--;
return;
}
/* 4 设置并发送sdk启动参数 */
bds::BDSSDKMessage start_params;
asr_set_start_params(start_params, pvt->app_name);
if (!sdk->post(start_params, err_msg)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s start sdk failed for %s\n", channel_name, err_msg.c_str());
bds::BDSpeechSDK::release_instance(sdk);
curr_concurrent--;
return;
}
//自定义数据
pvt->sdk = sdk; //百度sdk对像
pvt->push_params = new bds::BDSSDKMessage(bds::ASR_CMD_PUSH_AUDIO); //传输方式 二进制 及其长度 new的类需要用delete释放内存
switch_media_bug_flag_t flags = SMBF_READ_REPLACE | SMBF_NO_PAUSE | SMBF_ONE_ONLY;
//添加一个media bug到 session
// switch_core_media_bug_add(session, "app名", NULL,switch_media_bug_callback_t callback,用户数据,停止时间,_In_ switch_media_bug_flag_t flags,_Out_ switch_media_bug_t **new_bug)
if ((status = switch_core_media_bug_add(session, "baidu_asr", NULL, baidu_asr_callback, pvt, 0, flags, &(pvt->bug))) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Start baidu_asr media bug fail \n", channel_name);
return;
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "%s Start baidu_asr media bug success \n", channel_name);
switch_channel_set_private(channel, "baidu_asr", pvt);
}
}
//模块加载时执行 宏替换后如下
//switch_status_t mod_baidu_asr_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool)
SWITCH_MODULE_LOAD_FUNCTION(mod_baidu_asr_load) {
switch_application_interface_t *app_interface;
//load时一定要先执行这一行
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
//SWITCH_ADD_APP(app_interface,"模块名","短描述","长描述",调用模块时执行的回调函数,"看源码像是调用出错时的字符串")
SWITCH_ADD_APP(app_interface, "baidu_asr", "baidu_asr_1", "baidu_asr_2", start_baidu_asr_session_function, "baidu_asr调用出错7777777", SAF_MEDIA_TAP);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "_BDS_EASR_MFE_DNN=%s \n", _BDS_EASR_MFE_DNN);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "_BDS_EASR_MFE_CMVN=%s \n", _BDS_EASR_MFE_CMVN);
return SWITCH_STATUS_SUCCESS;
}
//下面的代码是调用一个带参数的宏,这此宏定义在switch_type.h中,替换后如下一行
//switch_status_t mod_baidu_asr_shutdown (void)
//SWITCH_MODULE_LOAD_FUNCTION(卸载时执行的函数)
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_baidu_asr_shutdown) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "baidu_asr_shutdown curr_concurrent=%d count_concurrent=%d \n", curr_concurrent.operator int(), count_concurrent.operator int());
if (curr_concurrent > 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "有未释放的识别请求,不能释放线程池,不能unload模块\n");
return SWITCH_STATUS_NOUNLOAD;
} else if (curr_concurrent == 0 && count_concurrent > 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "清理线程池\n");
bds::BDSpeechSDK::do_cleanup();
return SWITCH_STATUS_SUCCESS;
} else if (count_concurrent <= 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "未使用不需要清理线程池\n");
return SWITCH_STATUS_SUCCESS;
} else {
return SWITCH_STATUS_SUCCESS;
}
}
//如果runtime函数存在,则系统核心会启动一个新线程来调用该函数。
//在这里,可以是一个无限循环(如第67行,当然要记住给无限循环终止条件,否则该模块就不能卸载了),
//也可以在执行一段时间后返回一个状态值,只要返回值不是 SWITCH_STATUS_TERM ,该函数就会被再次调用。
SWITCH_MODULE_RUNTIME_FUNCTION(mod_baidu_asr_runtime) {
if (curr_concurrent > 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "mod_baidu_asr_runtime SWITCH_STATUS_NOUNLOAD\n");
switch_yield(200000);//延时2秒
return SWITCH_STATUS_NOUNLOAD;//阻止被卸载
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "mod_baidu_asr_runtime SWITCH_STATUS_TERM\n");
return SWITCH_STATUS_TERM;
}
}