forked from zuizuihao/xfyun-node
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxfyun.cc
252 lines (217 loc) · 7.15 KB
/
xfyun.cc
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
/*
* 语音识别(Automatic Speech Recognition)技术能够从语音中识别出特定的命令词或语句模式。
*/
#include <node.h>
#include <nan.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "qisr.h"
#include "msp_cmn.h"
#include "msp_errors.h"
#define BUFFER_SIZE 4096
#define HINTS_SIZE 100
#define GRAMID_LEN 128
#define FRAME_LEN 640
namespace xfy
{
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Null;
using v8::Object;
using v8::String;
using v8::Value;
void Iat(const Nan::FunctionCallbackInfo<v8::Value> &info)
{
// printf("%s", info[0] -> ToString());
if (info.Length() != 6)
{
Nan::ThrowTypeError("Wrong number of arguments");
}
String::Utf8Value username(info[0]->ToString());
String::Utf8Value password(info[1]->ToString());
String::Utf8Value login_params(info[2]->ToString());
String::Utf8Value session_params(info[3]->ToString());
String::Utf8Value audio_file(info[4]->ToString());
// printlog
printf("(xfyun.cc)>>>> username [%s].\n", (const char *)(*username));
printf("(xfyun.cc)>>>> password [%s].\n", (const char *)(*password));
printf("(xfyun.cc)>>>> login_params [%s].\n", (const char *)(*login_params));
printf("(xfyun.cc)>>>> session_params [%s].\n", (const char *)(*session_params));
printf("(xfyun.cc)>>>> audio_file [%s].\n", (const char *)(*audio_file));
int ret = MSP_SUCCESS;
char *grammar_id = NULL;
/* 用户登录 */
ret = MSPLogin(NULL, NULL, (const char *)(*login_params)); //第一个参数是用户名,第二个参数是密码,均传NULL即可,第三个参数是登录参数
if (MSP_SUCCESS != ret)
{
printf("MSPLogin failed, error code: %d.\n", ret);
Nan::ThrowError("MSPLogin failed. Check out error code in consolelog.");
}
else
{
printf("MSPLogin succ.\n");
}
// else logined succ.
// char rec_result = run_iat((const char *)(*audio_file), (const char *)(*session_params));
// process rec_result
const char *session_id = NULL;
char rec_result[BUFFER_SIZE] = {NULL};
char *rec_error = "";
char hints[HINTS_SIZE] = {NULL}; //hints为结束本次会话的原因描述,由用户自定义
unsigned int total_len = 0;
int aud_stat = MSP_AUDIO_SAMPLE_CONTINUE; //音频状态
int ep_stat = MSP_EP_LOOKING_FOR_SPEECH; //端点检测
int rec_stat = MSP_REC_STATUS_SUCCESS; //识别状态
int errcode = MSP_SUCCESS;
FILE *f_pcm = NULL;
char *p_pcm = NULL;
long pcm_count = 0;
long pcm_size = 0;
long read_size = 0;
if (NULL == (const char *)(*audio_file))
Nan::ThrowError("audio_file does not exist.");
f_pcm = fopen((const char *)(*audio_file), "rb");
if (NULL == f_pcm)
{
// printf("\nopen [%s] failed! \n", (const char *)(*audio_file));
Nan::ThrowError("open audio_file error.");
}
fseek(f_pcm, 0, SEEK_END);
pcm_size = ftell(f_pcm); //获取音频文件大小
fseek(f_pcm, 0, SEEK_SET);
p_pcm = (char *)malloc(pcm_size);
if (NULL == p_pcm)
{
printf("\nout of memory! \n");
rec_error = "filebuffer out of memory.";
}
read_size = fread((void *)p_pcm, 1, pcm_size, f_pcm); //读取音频文件内容
if (read_size != pcm_size)
{
printf("\nread [%s] error!\n", (const char *)(*audio_file));
rec_error = "read audio file error.";
}
printf("(xfyun.cc)>>>>Start iat session ...\n");
session_id = QISRSessionBegin(NULL, (const char *)(*session_params), &errcode); //听写不需要语法,第一个参数为NULL
if (MSP_SUCCESS != errcode)
{
printf("\nQISRSessionBegin failed! error code:%d\n", errcode);
rec_error = "QISRSessionBegin failed! error code";
}
if ("" == rec_error)
{
while (1)
{
unsigned int len = 10 * FRAME_LEN; // 每次写入200ms音频(16k,16bit):1帧音频20ms,10帧=200ms。16k采样率的16位音频,一帧的大小为640Byte
int ret = 0;
if (pcm_size < 2 * len)
len = pcm_size;
if (len <= 0)
break;
aud_stat = MSP_AUDIO_SAMPLE_CONTINUE;
if (0 == pcm_count)
aud_stat = MSP_AUDIO_SAMPLE_FIRST;
ret = QISRAudioWrite(session_id, (const void *)&p_pcm[pcm_count], len, aud_stat, &ep_stat, &rec_stat);
if (MSP_SUCCESS != ret)
{
printf("\nQISRAudioWrite failed! error code:%d\n", ret);
rec_error = "QISRAudioWrite failed! error code";
}
pcm_count += (long)len;
pcm_size -= (long)len;
if (MSP_REC_STATUS_SUCCESS == rec_stat) //已经有部分听写结果
{
const char *rslt = QISRGetResult(session_id, &rec_stat, 0, &errcode);
if (MSP_SUCCESS != errcode)
{
printf("\nQISRGetResult failed! error code: %d\n", errcode);
rec_error = "QISRGetResult failed! error code";
}
if (NULL != rslt)
{
unsigned int rslt_len = strlen(rslt);
total_len += rslt_len;
if (total_len >= BUFFER_SIZE)
{
printf("\nno enough buffer for rec_result !\n");
rec_error = "no enough buffer for rec_result !";
}
strncat(rec_result, rslt, rslt_len);
}
}
if (MSP_EP_AFTER_SPEECH == ep_stat)
break;
// usleep(200 * 1000); //模拟人说话时间间隙。200ms对应10帧的音频
}
errcode = QISRAudioWrite(session_id, NULL, 0, MSP_AUDIO_SAMPLE_LAST, &ep_stat, &rec_stat);
if (MSP_SUCCESS != errcode)
{
printf("\nQISRAudioWrite failed! error code:%d \n", errcode);
}
while (MSP_REC_STATUS_COMPLETE != rec_stat)
{
const char *rslt = QISRGetResult(session_id, &rec_stat, 0, &errcode);
if (MSP_SUCCESS != errcode)
{
printf("\nQISRGetResult failed, error code: %d\n", errcode);
}
if (NULL != rslt)
{
unsigned int rslt_len = strlen(rslt);
total_len += rslt_len;
if (total_len >= BUFFER_SIZE)
{
printf("\nno enough buffer for rec_result !\n");
rec_error = "enough buffer for rec_result";
}
strncat(rec_result, rslt, rslt_len);
}
// usleep(150 * 1000); //防止频繁占用CPU
}
// end session
QISRSessionEnd(session_id, hints);
printf("(xfyun.cc)>>>>End iat session by id %d.\n", session_id);
printf("(xfyun.cc)>>>>Result:\n");
printf("(xfyun.cc)>>>>%s\n", rec_result);
}
else
{
printf("(xfyun.cc)>>>>Can not start Session: %s", rec_error);
}
ret = MSPLogout();
if (MSP_SUCCESS != ret)
{
printf("(xfyun.cc)>>>>MSPLogout failed, error code is: %d", ret);
}
if (NULL != f_pcm)
{
fclose(f_pcm);
f_pcm = NULL;
}
if (NULL != p_pcm)
{
free(p_pcm);
p_pcm = NULL;
}
/**
* return callback
*/
Isolate *isolate = info.GetIsolate();
// callback fn
Local<Function> cb = Local<Function>::Cast(info[5]);
const unsigned argc = 2;
Local<Value> argv[argc] = {String::NewFromUtf8(isolate, rec_error), String::NewFromUtf8(isolate, rec_result)};
cb->Call(Null(isolate), argc, argv);
}
void Init(Local<Object> exports, Local<Object> module)
{
exports->Set(Nan::New("iat").ToLocalChecked(),
Nan::New<v8::FunctionTemplate>(Iat)->GetFunction());
}
NODE_MODULE(xfyun, Init)
} // namespace xfy