1、写调用主函数
package com.iflytek;
import com.iflytek.util.Step3_ivw_thread;
import com.iflytek.util.Step4_audioFormat;
import java.util.Scanner;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.TargetDataLine;
/**
* 请注意!!!
* 1.首选到控制台https://console.xfyun.cn/services/awaken下载唤醒的Windows MSC。
* 2.下载的唤醒Windows MSC解压后,把bin目录下msc文件夹与dll文件拷贝到res目录下。
* 3.最后请替换Step3_ivw_thread中的appid值,appid值在下载页面控制台可以看到。
*/
public class OfflineIvwMain {
//录音相关参数
public static AudioFormat audioFormat;
public static TargetDataLine targetDataLine;
public static void main(String[] args) throws Exception {
System.out.println("y开始体验唤醒,n结束唤醒");
Scanner input = new Scanner(System.in);
String inputContent = input.next();
long startTime = System.currentTimeMillis();
if(inputContent.equals("y")){
audioFormat = Step4_audioFormat.getAudioFormat(audioFormat);//构造具有线性 PCM 编码和给定参数的 AudioFormat。
DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
targetDataLine = (TargetDataLine) AudioSystem.getLine(dataLineInfo);
Step3_ivw_thread myThread=new Step3_ivw_thread();
myThread.start();
Scanner input_2 = new Scanner(System.in);
String inputContent_2 = input_2.next();
if(inputContent_2.equals("n")){
targetDataLine.stop();
targetDataLine.close();
}
System.out.println("唤醒操作持续:"+(System.currentTimeMillis()-startTime)/1000+"秒!");
System.exit(0);
}
}
}
2、 根据文档用JAVA重写方法
package com.iflytek.service;
import com.iflytek.util.Step2_ivw_ntf_handler;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;
public interface Step1_ivw_dll extends Library {
/**
* 重点:
* 1.char * 对应 String
* 2.int * 对应 IntByReference
* 3.void * 对应 Pointer或byte[]
* 4.int 对应 int
* 5.无参 对应 无参
* 6.回调函数 对应 根据文档自定义回调函数,实现接口Callback
*/
//加载dll动态库并实例化,从而使用其内部的方法
Step1_ivw_dll INSTANCE = (Step1_ivw_dll) Native.loadLibrary
("res/msc_x64.dll", Step1_ivw_dll.class);
//定义登录方法 MSPLogin(const char *usr, const char *pwd, const char *params)
public int MSPLogin(String usr, String pwd, String params);
//定义开始方法 QIVWSessionbegin(const char *grammarList, const char *params, int *errorCode)
public String QIVWSessionBegin(String grammarList, String params, IntByReference errorCode);
//定义写音频方法 QIVWAudioWrite(const char *sessionID, const void *audioData, unsigned int audioLen, int audioStatus)
public int QIVWAudioWrite(String sessionID, byte[] audioData, int audioLen, int audioStatus);
//定义结束方法 QIVWSessionEnd(const char *sessionID, const char *hints)
public int QIVWSessionEnd(String sessionID, String hints);
//定义获取结果方法 QIVWRegisterNotify(const char *sessionID, ivw_ntf_handler msgProcCb, void *userData)
public int QIVWRegisterNotify(String sessionID, Step2_ivw_ntf_handler msgProcCb, byte[] userData);
//定义退出方法 MSPLogout()
public int MSPLogout();
}
3、根据文档写回调函数
package com.iflytek.util;
import com.sun.jna.Callback;
public class Step2_ivw_ntf_handler implements Callback {
//根据文档写回调方法
public int cb_ivw_msg_proc(String sessionID, int msg, int param1, int param2,
String info, String userData) {
System.out.println("..............................................");
System.out.println("回调函数返回的唤醒结果:"+info);
return 0;
}
}
4、把调用步骤依次写到线程类
package com.iflytek.util;
import com.iflytek.OfflineIvwMain;
import com.iflytek.service.Step1_ivw_dll;
import com.sun.jna.ptr.IntByReference;
import javax.sound.sampled.AudioInputStream;
public class Step3_ivw_thread extends Thread{
public void run() {
//登录参数
String lgi_param = "appid = 替换你的appid, work_dir = ./res";
String ssb_param = "ivw_threshold=0:1450,sst=wakeup,ivw_shot_word=1,ivw_res_path =fo|res/ivw/wakeupresource.jet";
int ret = Step1_ivw_dll.INSTANCE.MSPLogin(null, null, lgi_param);
if (ret != 0) {//登录成功标志ret为0
System.out.println("登录失败...请检查");
System.exit(1);
} else {
System.out.println("请注意,唤醒语音需要根据控制台定义的唤醒词来进行唤醒...");
}
//开启会话
IntByReference intByReference = new IntByReference(-100);
String sessionId = Step1_ivw_dll.INSTANCE.QIVWSessionBegin(null, ssb_param, intByReference);
if (intByReference.getValue() == 0) {//只有返回0为函数调用成功
System.out.println("本次会话开启成功...,会话id为:" + sessionId);
}
int frameSize = 6400; //一帧的大小为6400B,其他的可能导致无法长时间唤醒
int audioStatus = 1;//用来告知MSC音频发送是否完成
//注册回调
Step2_ivw_ntf_handler msgProcCb = new Step2_ivw_ntf_handler();//回调函数实例
ret = Step1_ivw_dll.INSTANCE.QIVWRegisterNotify(sessionId, msgProcCb, null);
if (ret == 0) {//返回为0则代表成功
System.out.println("注册回调函数成功...");
} else {
System.out.println("注册函数返回的错误码" + ret);
}
//反复调用QIVWAudioWrite写音频方法,直到音频写完为止
//long startTime=System.currentTimeMillis();
try {
while (true) {
byte[] audioDataByteArray = new byte[frameSize];
OfflineIvwMain.targetDataLine.open(OfflineIvwMain.audioFormat);
OfflineIvwMain.targetDataLine.start();
int len = new AudioInputStream(OfflineIvwMain.targetDataLine).read(audioDataByteArray);
//long endTime=System.currentTimeMillis();
if (len == -1) {//调用麦克风时候,这段将不会被执行...
//||(endTime-startTime>60*1000)
audioStatus = 4;//最后帧
ret = Step1_ivw_dll.INSTANCE.QIVWAudioWrite(sessionId, "".getBytes(), 0, audioStatus);
System.out.println("最后一帧返回的错误码:" + ret + ",即将执行退出...");
break; //文件读完,跳出循环
} else {
//反复调用
ret = Step1_ivw_dll.INSTANCE.QIVWAudioWrite(sessionId, audioDataByteArray, len, audioStatus);
}
audioStatus = 2;//中间帧
if (ret != 0) {
System.err.println("出错了:" + ret);
}
Thread.sleep(200); //模拟人说话时间间隙
}
} catch (Exception e) {
e.printStackTrace();
}
//终止会话
ret = Step1_ivw_dll.INSTANCE.QIVWSessionEnd(sessionId, "正常终止");
if (ret == 0) {
System.out.println("本次会话正常终止...");
}
//执行退出
ret = Step1_ivw_dll.INSTANCE.MSPLogout();
if (ret == 0) {
System.out.println("正常退出...");
}else{
System.out.println("异常退出...");
}
}
}
5、 录音生成16K、16BIT单声道的音频流
package com.iflytek.util;
import javax.sound.sampled.AudioFormat;
public class Step4_audioFormat {
//构造线程参数
//16k采样率的16bit音频,一帧的大小为640B, 时长20ms
/**
sampleRate - 每秒样品数
sampleSizeInBits - 每个样本中的位数
channels - 通道数(1为mono,2为立体声等)
signed - 表示数据是签名还是无符号
bigEndian - 指示单个样本的数据是否以大字节顺序存储( false表示小端)
*/
public static AudioFormat getAudioFormat(AudioFormat audioFormat) {
audioFormat=new AudioFormat(16000F, 16, 1,true,false);
// true,false 指示是以 big-endian 顺序还是以 little-endian 顺序存储音频数据。
return audioFormat;//构造具有线性 PCM 编码和给定参数的 AudioFormat。
}
}
6、放置讯飞开放平台下载Linux/Windows中所带的资源
7、 Linux代码基本类似,注意加载SO库就行和放置资源
package com.iflytek.service;
import com.iflytek.OfflineIvwMain;
import com.iflytek.util.Step2_ivw_ntf_handler;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
public interface Step1_ivw_so extends Library {
/**
* 重点:
* 1.char * 对应 String
* 2.int * 对应 IntByReference
* 3.void * 对应 Pointer
* 4.int 对应 int
* 5.无参 对应 无参
* 6.回调函数 对应 根据文档自定义回调函数,实现接口Callback
* 7.Linux设置程序共享库位置,否则会话时会报错25000
* export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/root/SoIvw/res
* 注意:每个版本都有两个so库,libmsc.so、libw_ivw.so
*/
//加载so动态库并实例化,从而使用其内部的方法
Step1_ivw_so INSTANCE = (Step1_ivw_so) Native.loadLibrary
(OfflineIvwMain.userPath+"res/libmsc.so", Step1_ivw_so.class);
//定义登录方法 MSPLogin(const char *usr, const char *pwd, const char *params)
public int MSPLogin(String usr, String pwd, String params);
//定义开始方法 QIVWSessionbegin(const char *grammarList, const char *params, int *errorCode)
public String QIVWSessionBegin(String grammarList, String params, IntByReference errorCode);
//定义写音频方法 QIVWAudioWrite(const char *sessionID, const void *audioData, unsigned int audioLen, int audioStatus)
public int QIVWAudioWrite(String sessionID, byte[] audioData, int audioLen, int audioStatus);
//定义获取结果方法 QIVWRegisterNotify(const char *sessionID, ivw_ntf_handler msgProcCb, void *userData)
public int QIVWRegisterNotify(String sessionID, Step2_ivw_ntf_handler msgProcCb, Pointer userData);
//定义结束方法 QIVWSessionEnd(const char *sessionID, const char *hints)
public int QIVWSessionEnd(String sessionID, String hints);
//定义退出方法 MSPLogout()
public int MSPLogout();
}