离线语音唤醒 node调用科大讯飞dll动态链接库

使用科大讯飞语音唤起离线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 运行你的代码即可

资料

科大讯飞错误码查询

坑点很多,前置工作会劝退绝大部分小白

相关推荐

  1. 实现动态DLL)注入的C++编程

    2024-06-14 12:48:05       65 阅读
  2. C++由动态dll生成lib文件

    2024-06-14 12:48:05       39 阅读
  3. Windows DLL动态)的用处

    2024-06-14 12:48:05       41 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-14 12:48:05       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-14 12:48:05       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-14 12:48:05       82 阅读
  4. Python语言-面向对象

    2024-06-14 12:48:05       91 阅读

热门阅读

  1. 面试题(常见)

    2024-06-14 12:48:05       34 阅读
  2. Webrtc支持FFMPEG硬解码之NVIDA(二)

    2024-06-14 12:48:05       35 阅读
  3. 字节一面(年前)测开—飞书

    2024-06-14 12:48:05       30 阅读
  4. 代码详解工厂设计模式【2】

    2024-06-14 12:48:05       29 阅读
  5. NumPy 字节交换

    2024-06-14 12:48:05       27 阅读
  6. 未来展望:超越现实的边界

    2024-06-14 12:48:05       20 阅读
  7. 2024-03 GESP C++ 六级试题及答案

    2024-06-14 12:48:05       24 阅读
  8. 14、C++中代码重用

    2024-06-14 12:48:05       25 阅读
  9. 【Avoid std::endl!】

    2024-06-14 12:48:05       28 阅读