使用科大讯飞语音唤起离线SDK 结合electron来实现效果
先看运行效果。前置条件还是比较苛刻的,没有充足的时间还是选择其他方案比较好
准备工作
1.登录科大讯飞开发者平台
2.下载离线sdk
3.node 版本 17.6.0
4.下载依赖
npm i windows-build-tools -g 会下载一个c++编辑器和Python27,如果下载失败手动下载到本地即可,Python记得设环境变量
npm i ffi-napi
npm i ref-napi
npm i node-record-lpcm16
下载sox到本地 并且设置path环境变量 C:\Program Files (x86)\sox-14-4-1
代码目录
创建一个libs目录吧离线sdk的bin目录复制过来
代码
const ffi = require("ffi-napi");
const ref = require("ref-napi");
const record = require('node-record-lpcm16');
// DLL 文件路径 绝对路径 记得修改为你的
let libPath = "C:/Users/12747/Desktop/dev/web3d/libs/bin/msc_x64.dll";
const libm = ffi.Library(libPath, {
MSPLogin: [ref.types.int, ["string", "string", "string"]],
MSPLogout: [ref.types.int, []],
QIVWSessionBegin: ["string", ["string", "string", ref.refType(ref.types.int)]],
QIVWSessionEnd: [ref.types.int, ["string", "string"]],
QIVWAudioWrite: [ref.types.int, ["string", ref.refType(ref.types.void), ref.types.uint, ref.types.int]],
QIVWRegisterNotify: [ref.types.int, ["string", "pointer", ref.refType(ref.types.void)]],
});
// 登录SDK
function loginSDK(appId) {
const loginStr = `appid = ${appId}, engine_start = ivw, work_dir = .`;
const loginRes = libm.MSPLogin(null, null, loginStr);
if (loginRes === 0) {
console.log("登录成功");
} else {
console.error("登录错误", loginRes);
}
return loginRes;
}
// 登出SDK
function logoutSDK() {
const logoutRes = libm.MSPLogout();
if (logoutRes === 0) {
console.log("登出成功");
} else {
console.error("登出失败,错误码:", logoutRes);
}
return logoutRes;
}
// 开启语音唤醒会话
function startWakeupSession() {
let errorCode = ref.alloc(ref.types.int);
// 注意:这里为相对路径
const jetPath = "../libs/bin/msc/res/ivw/wakeupresource.jet";
const sessionParams = `ivw_threshold=0:-30,sst=wakeup,ivw_res_path=fo|${jetPath}`;
const sessionID = libm.QIVWSessionBegin(null, sessionParams, errorCode);
if (!sessionID) {
console.error("语音唤醒会话开始失败,错误码:", errorCode.deref());
return null;
}
console.log("语音唤醒会话开始成功,Session ID:", sessionID);
return sessionID;
}
// 结束语音唤醒会话
function endWakeupSession(sessionID) {
const endRes = libm.QIVWSessionEnd(sessionID, "正常结束");
if (endRes === 0) {
console.log("语音唤醒会话结束成功");
} else {
console.error("语音唤醒会话结束失败,错误码:", endRes);
}
return endRes;
}
// 注册唤醒回调
function registerWakeupCallback(sessionID, callback) {
const notifyUserData = ref.alloc(ref.types.void);
const notifyRes = libm.QIVWRegisterNotify(sessionID, callback, notifyUserData);
if (notifyRes === 0) {
console.log("回调函数注册成功");
} else {
console.error("回调函数注册失败,错误码:", notifyRes);
}
return notifyRes;
}
// 写入音频数据
function writeAudioData(sessionID, audioData) {
const audioRes = libm.QIVWAudioWrite(sessionID, audioData, audioData.length, 2); // 2表示音频结束标志
if (audioRes === 0) {
// console.log("音频数据写入成功");
} else {
console.error("音频数据写入失败,错误码:", audioRes);
}
return audioRes;
}
// 获取音频数据
function getAudioData(callback) {
const mic = record.record({
sampleRate: 16000, // 音频采样率
channels: 1, // 通道数
threshold: 0.5, // 静音阈值(仅录音)
recordProgram: 'sox', // 选择你所使用的录音程序,'rec', 'sox', 'arecord' 等
silence: '10.0', // 结束前的静音秒数
});
mic.stream().on('data', data => {
callback(data);
});
mic.stream().on('error', (err) => {
console.error("录音错误:", err);
});
mic.stream().on('end', () => {
console.log("录音结束");
});
mic.stream().on('close', () => {
console.log("录音流关闭");
});
// 停止录音的条件可以根据实际需要调整
// setTimeout(() => {
// mic.stop();
// }, 5000);
}
// 登录SDK,开启语音唤醒,注册回调,写入音频数据,然后登出SDK
const appId = "你的应用appid";
// 登录SDK
if (loginSDK(appId) === 0) {
// 开启语音唤醒会话
const sessionID = startWakeupSession();
if (sessionID) {
// 注册唤醒回调
let wakeupCallback = ffi.Callback('void', ['string', ref.refType(ref.types.void), ref.types.uint, ref.refType(ref.types.void)], (sessionID, userData, audioLen, param) => {
console.log("唤醒成功,Session ID:", sessionID);
// 处理唤醒事件,比如播放提示音等
console.log("wakeup : ivw param =", param);
global.sharedObj = wakeupCallback;// 确保不会被回收
});
if (registerWakeupCallback(sessionID, wakeupCallback) === 0) {
// 获取音频数据并写入
getAudioData((audioData) => {
writeAudioData(sessionID, audioData);
});
// 录音过程中的其他逻辑,如需要,可以加入更多处理
} else {
// 结束会话
// endWakeupSession(sessionID);
// 登出SDK
// logoutSDK();
}
} else {
// 登出SDK
// logoutSDK();
}
} else {
console.error("SDK登录失败,无法继续");
}
修改代码中 libPath appId jetPath 为自己的实际情况。
node index.js 运行你的代码即可
资料
坑点很多,前置工作会劝退绝大部分小白