帖子

Java通过JNA&麦克风调离线语音唤醒

[复制链接]

该用户从未签到

1480 159****1928 发表于 2020-7-27 16:14:45 1#
放置资源(dll、jet、日志配置);
通过JNA加载dll资源;
登录MSPLogin;
开始会话QIVWSessionBegin;
注册回调QIVWRegisterNotify;
while(true){
        写入音频数据QIVWAudioWrite;
}
结束会话QIVWSessionEnd;
退出MSPLogout;

1.dll方法定义类:
  1. package com.day.iFlyInterface.commonUtil.dll.ivw;
  2. import java.util.Scanner;
  3. import javax.sound.sampled.AudioFormat;
  4. import javax.sound.sampled.AudioSystem;
  5. import javax.sound.sampled.DataLine;
  6. import javax.sound.sampled.TargetDataLine;
  7. import com.sun.jna.Library;
  8. import com.sun.jna.Native;
  9. import com.sun.jna.Pointer;
  10. import com.sun.jna.ptr.IntByReference;
  11. public class OfflineWindowsIvw {
  12.         /* char * 对应String ;;;int *对应IntByReference
  13.          * char * 对应String ;;;int 对应int;;;
  14.          * void * 对应Pointer;;;char *对应String ;;;int * 对应IntByReference;;;
  15.          * char * 对应String;;;
  16.          */
  17.         public interface MyDllInterface extends Library {
  18.                 //可以用绝对路径写
  19.                 MyDllInterface INSTANCE = (MyDllInterface)Native.loadLibrary("Ivw_x64", MyDllInterface.class);
  20.                 public int MSPLogin(String usr,String pwd,String params);
  21.                 //文档方法写错了,耽搁一段时间
  22.                 //开始
  23.                 public String QIVWSessionBegin(String grammarList,String params,IntByReference errorCode);
  24.                 //写音频
  25.                 public int QIVWAudioWrite(String sessionID, byte[] audioData,int audioLen,int audioStatus);
  26.                 //结束
  27.                 public int QIVWSessionEnd(String sessionID,String hints);
  28.                 //获取结果
  29.                 public int QIVWRegisterNotify(String sessionID,Ivw_ntf_handler msgProcCb,Pointer userData);
  30.                 //退出
  31.                 public int MSPLogout();
  32.         }
  33.         //录音相关参数
  34.         static AudioFormat audioFormat;
  35.         public static TargetDataLine targetDataLine;
  36.         private static final int CHUNCKED_SIZE = 1280;
  37.         public static void main(String[] args) throws Exception {
  38.                 System.out.println("y开始体验唤醒,n结束唤醒");
  39.                 Scanner input = new Scanner(System.in);
  40.                 String Sinput = input.next();
  41.                 long testtime = System.currentTimeMillis();
  42.                 if(Sinput.equals("y")){
  43.                         audioFormat = getAudioFormat(audioFormat);//构造具有线性 PCM 编码和给定参数的 AudioFormat。
  44.                         DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
  45.                         targetDataLine = (TargetDataLine) AudioSystem.getLine(dataLineInfo);
  46.                         OfflineWindowsIvw awakeDll=new OfflineWindowsIvw();
  47.                         IvwThread myThread=new IvwThread(awakeDll);
  48.                         myThread.start();
  49.                         Scanner input_2 = new Scanner(System.in);
  50.                         String Sinput_2 = input_2.next();
  51.                         if(Sinput_2.equals("n")){
  52.                                 OfflineWindowsIvw.targetDataLine.stop();
  53.                                 OfflineWindowsIvw.targetDataLine.close();
  54.                         }
  55.                         System.out.println("唤醒机器人"+(System.currentTimeMillis()-testtime)/1000+"秒!");
  56.                         System.exit(0);
  57.                 }
  58.         }
  59.         //构造线程参数
  60.         private static AudioFormat getAudioFormat(AudioFormat audioFormat) {
  61.                 audioFormat=new AudioFormat(16000F, 16, 1,true,false);
  62.                 // true,false 指示是以 big-endian 顺序还是以 little-endian 顺序存储音频数据。
  63.                 return audioFormat;//构造具有线性 PCM 编码和给定参数的 AudioFormat。
  64.         }
  65. }
复制代码



2.通过麦克风传音频流线程
  1. package com.day.iFlyInterface.commonUtil.dll.ivw;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileNotFoundException;
  5. import java.io.IOException;
  6. import java.util.Arrays;
  7. import javax.sound.sampled.AudioInputStream;
  8. import javax.sound.sampled.LineUnavailableException;
  9. import com.day.iFlyInterface.commonUtil.dll.ivw.OfflineWindowsIvw.MyDllInterface;
  10. import com.sun.jna.Memory;
  11. import com.sun.jna.Pointer;
  12. import com.sun.jna.ptr.IntByReference;
  13. public class IvwThread extends Thread{
  14.         OfflineWindowsIvw offlineWindowsIvw=null;
  15.         IvwThread(OfflineWindowsIvw offlineWindowsIvw){
  16.                 this.offlineWindowsIvw=offlineWindowsIvw;
  17.         }
  18.         public void run(){
  19.                 //登录参数
  20.                 String lgi_param = "appid = 填写您自己的, work_dir = ./dllLib/ivw";//注意路径放置
  21.                 String ssb_param = "ivw_threshold=0:1450,sst=wakeup,ivw_shot_word=1,ivw_res_path =fo|res/ivw/wakeupresource.jet";
  22.                 //登录成功标志ret为0  MSP_SUCCESS = 0,
  23.                 int ret=MyDllInterface.INSTANCE.MSPLogin(null, null, lgi_param);
  24.                 if (ret!=0){
  25.                         System.out.println("登录失败...请检查");
  26.                         System.exit(1);
  27.                 }else{
  28.                         System.out.println("请注意,唤醒语音需要根据唤醒词内容自行录制并重命名为宏IVW_AUDIO_FILE_NAME所指定名称");
  29.                 }
  30.                 IntByReference intByReference = new IntByReference(-1);
  31.                 String session_id=MyDllInterface.INSTANCE.QIVWSessionBegin(null,ssb_param,intByReference);
  32.                 System.out.println("本次会话id为:"+session_id);
  33.                 //指定唤醒音频文件读取
  34.                 File file=new File("./zMusic/pcm/Ivw/awake.pcm");
  35.                 int frameSize = 10*640; //每次发送音频大小
  36.                 int intervel = 200;
  37.                 int MSP_AUDIO_SAMPLE_INIT = 0x00;//初始化帧
  38.                 int SP_AUDIO_SAMPLE_FIRST = 0x01;//第一帧
  39.                 int MSP_AUDIO_SAMPLE_CONTINUE  = 0x02;//中间帧
  40.                 int MSP_AUDIO_SAMPLE_LAST  = 0x04;//最后帧
  41.                 int sendStage=0x01;
  42.                 Ivw_ntf_handler msgProcCb = new Ivw_ntf_handlerImpl();//回调函数实例
  43.                 int err_code = MyDllInterface.INSTANCE.QIVWRegisterNotify(session_id,msgProcCb,null);
  44.                 System.out.println("注册函数返回的错误码"+err_code);
  45.                 System.out.println("csid="+session_id+",错误码"+err_code);
  46.                 Pointer audioDataPointer = new Memory(9600000);
  47.                 try (FileInputStream fs = new FileInputStream(file)) {
  48.                         while(true){
  49.                                 //System.err.println(fs.available());
  50.                                 byte[] byteArrayAudioData = new byte[frameSize];
  51.                                 offlineWindowsIvw.targetDataLine.open(offlineWindowsIvw.audioFormat);
  52.                                 offlineWindowsIvw.targetDataLine.start();
  53.                                 int len = new AudioInputStream(offlineWindowsIvw.targetDataLine).read(byteArrayAudioData);
  54.                                 if(len!=-1){
  55.                                         /*String sendData=Base64.getEncoder().encodeToString(Arrays.copyOf(buffer, len));
  56.                                 audioDataPointer.setString(indexFlag, sendData);
  57.                                 System.err.println(indexFlag);*/
  58.                                         //byte[] temp=Arrays.copyOf(buffer, len);
  59.                                         /*for(long z=0;z<buffer.length;z++){
  60.                                                 audioDataPointer.setByte(z, buffer[(int) z]);
  61.                                         }*/
  62.                                         //System.out.print(sendStage);
  63.                                         //直接写byte[] 数组数据也可以的
  64.                                         err_code = MyDllInterface.INSTANCE.QIVWAudioWrite(session_id,byteArrayAudioData,len,sendStage);
  65.                                         //System.err.println(sendData);
  66.                                         //System.out.println("csid="+session_id+",错误码"+err_code+",长度"+len+",aus="+sendStage);
  67.                                 }
  68.                                 //调用麦克风时候,这段将不会被执行...
  69.                                 sendStage=0x02;
  70.                                 if (len == -1) {
  71.                                         //System.err.println("空帧....");
  72.                                         byte b='b';
  73.                                         sendStage=0x04;
  74.                                         audioDataPointer=new Memory(100000);
  75.                                         audioDataPointer.setByte(0, b);
  76.                                         err_code = MyDllInterface.INSTANCE.QIVWAudioWrite(session_id,"".getBytes(),0,sendStage);
  77.                                         //System.out.println("csid="+session_id+",错误码"+err_code+",长度"+len+",aus="+sendStage);
  78.                                         System.out.println("最后一帧返回的错误码:"+err_code+",即将执行退出...");
  79.                                         break;  //文件读完,跳出循环
  80.                                 }
  81.                                 if(err_code!=0){
  82.                                         System.out.println("出错了...");
  83.                                 }
  84.                                 Thread.sleep(200); //模拟人说话时间间隙,10帧的音频时长为200ms
  85.                         }
  86.                 } catch (FileNotFoundException e) {
  87.                         e.printStackTrace();
  88.                 } catch (IOException e) {
  89.                         e.printStackTrace();
  90.                 } catch (InterruptedException e) {
  91.                         e.printStackTrace();
  92.                 } catch (LineUnavailableException e) {
  93.                         e.printStackTrace();
  94.                 }
  95.                 //Thread.sleep(500);
  96.                 MyDllInterface.INSTANCE.QIVWSessionEnd(session_id, "正常终止");
  97.                 int tempCode=MyDllInterface.INSTANCE.MSPLogout();
  98.                 System.out.println("最终的执行退出,返回的错误码:"+tempCode);
  99.         }
  100. }
复制代码



3.回调接口定义
  1. package com.day.iFlyInterface.commonUtil.dll.ivw;
  2. import com.sun.jna.Pointer;
  3. import com.sun.jna.win32.StdCallLibrary.StdCallCallback;
  4. public interface Ivw_ntf_handler extends StdCallCallback{
  5.         public int cb_ivw_msg_proc(String sessionID, int msg, int param1, int param2,String info,String userData);
  6. }
复制代码




4.回调接口实现类
  1. package com.day.iFlyInterface.commonUtil.dll.ivw;
  2. import java.io.IOException;
  3. import javax.sound.sampled.LineUnavailableException;
  4. import javax.sound.sampled.UnsupportedAudioFileException;
  5. import com.sun.jna.Pointer;
  6. public class Ivw_ntf_handlerImpl implements Ivw_ntf_handler{
  7.         @Override
  8.         public int cb_ivw_msg_proc(String sessionID, int msg, int param1,
  9.                         int param2, String info, String userData) {
  10.                 /*监听唤醒人说话
  11.                 try {
  12.                         IatMicUtil.doIatWork();
  13.                 } catch (Exception e) {
  14.                         e.printStackTrace();
  15.                 }
  16.                 while(true){
  17.                         try {
  18.                                 if(!IatMicUtil.iatFlag){
  19.                                         System.out.println("监听说话中...");
  20.                                 }else{
  21.                                         break;
  22.                                 }
  23.                         } catch (Exception e) {
  24.                                 e.printStackTrace();
  25.                         }
  26.                 }
  27.                 try {
  28.                         Thread.sleep(1000);
  29.                 } catch (InterruptedException e1) {
  30.                         e1.printStackTrace();
  31.                 }*/
  32.                 //机器人随机答复结果
  33.                 /*String readResult=MyFileReader.MyRead("./zText/AnswerRobot.txt");
  34.                 String []robotAnswer=readResult.split("\n");
  35.                 System.out.println(robotAnswer.length);
  36.                 //int tempIndex=(int) (Math.random()*136)+1;
  37.                 //产生0-135的随机数
  38.                 int tempIndex=(int) (Math.random()*136);
  39.                 try {
  40.                         OfflineWindowsTts.doTts(robotAnswer[tempIndex]);
  41.                 } catch (Exception e) {
  42.                         e.printStackTrace();
  43.                 }*/
  44.                 //唤醒简单答复
  45.                 /*try {
  46.                         OfflineWindowsTts.doTts("主人,主人,我在呢");
  47.                 } catch (Exception e) {
  48.                         e.printStackTrace();
  49.                 }*/
  50.                 System.err.println("唤醒结果:.......................");
  51.                 System.err.println("唤醒结果:"+info);
  52.                 return 0;
  53.         }
  54. }



复制代码


评分

参与人数 1语点 +50 收起 理由
打豆豆 + 50 赞一个!

查看全部评分