最近有需求要把微信小程序里面的语音进行语音识别,然后搜搜,微信小程序的语音格式是silk
1、上传silk文件
2、下载silk-v3-decoder,通过名称把silk转换成讯飞可识别的wav文件
3、获取讯飞转换后的文字信息
/**
* 获取wav文件 并返回路径
* @param wavFileName
* @return
* @throws Exception
*/
public String getWav(String wavFileName) throws Exception {//之前别人写的代码,可以改为java直接执行shell脚本的方式
StringBuilder command = new StringBuilder(Constant.FFMPEG);
command.append(Constant.CONVERTER);
command.append(Constant.OXM_VOICE_UPLOAD_BASE_PTAH);
command.append(wavFileName);
command.append(" wav ");
Session session = jschSessionService.getSession();
jschSessionService.getChannelAndExec(session, command.toString());
Thread.sleep(2000);
String name = wavFileName.replace("silk", "wav");
return name;
}
public static final String FFMPEG = " export PATH=/usr/local/ffmpeg/bin/:$PATH; source /etc/profile;";
public static final String CONVERTER = " sh /home/deployer/silk-v3-decoder-master/converter.sh ";
public static final String OXM_VOICE_UPLOAD_BASE_PTAH = "/home/deployer/tomcat7/webapps/xxxx/";
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Properties;
import org.springframework.stereotype.Service;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.shanjin.oxm.common.util.Constant;
/**
* java ssh 服务
*
*/
@Service("JschSessionService")
public class JschSessionService {
public Session getSession() throws JSchException {
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
JSch jsch = new JSch();
Session session = jsch.getSession(Constant.SSH_USER,Constant.SSH_IP,Constant.SSH_PORT);
session.setPassword(Constant.SSH_PASSWORD);
session.setConfig(sshConfig);
session.connect();
return session;
}
public void closeSession(Session session) {
if (session.isConnected()) {
session.disconnect();
}
}
public String getChannelAndExec(Session session, String command) throws JSchException, IOException {
Channel channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(command);
channel.setInputStream(null);
((ChannelExec) channel).setErrStream(System.err);
channel.connect();
int state = channel.getExitStatus();
/*if (state != 0) {
return "exec is error ,exit code is :" + state;
}*/
((ChannelExec) channel).setErrStream(System.err);
//String msg = getExitMessage(channel);
closeChannel(channel);
closeSession(session);
return state + "";
}
public void closeChannel(Channel channel){
if(channel.isConnected()){
channel.disconnect();
}
}
public String getExitMessage(Channel channel) throws IOException {
StringBuilder message = new StringBuilder("exit message is : ");
InputStream in = channel.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in,
Charset.forName("utf-8")));
String buf = null;
while ((buf = reader.readLine()) != null) {
message.append(buf);
}
return message.toString();
}
}
/** * 获取语音信息 */ public String getVoiceText(String filePath,String wavName) throws Exception { IflyTekServiceImpl iflytekService = new IflyTekServiceImpl();//TODO 注解方式,会产生缓存,一直都是第一次识别的语音 File ff = null; String text = null; File file = new File(filePath+wavName); InputStream in = new FileInputStream(file); byte[] bb = VoiceSplitUtil.getbytes(in); System.out.println(bb); text = iflytekService.RecognizePcmfileByte(bb);// text = this.getText(fly); in.close(); return text; } public String getText(IflyTekServiceImpl fly) { StringBuilder text = new StringBuilder(); JSONObject json = null; JSONArray wss = null; JSONObject ws = null; JSONArray cw = null; JSONObject c = null; long begin = System.currentTimeMillis(); while (true) { long end = System.currentTimeMillis(); if((end - begin) >3000){ break; } if (fly.recognizer.isListening() && fly.mIsEndOfSpeech == true) {System.out.println(fly.sn); json = JSONObject.fromObject(fly.sn.toString()); wss = json.getJSONArray("ws"); text = new StringBuilder(); for (int i = 0; i < wss.size(); i++) { ws = wss.getJSONObject(i); cw = ws.getJSONArray("cw"); c = cw.getJSONObject(0); text.append(c.getString("w")); } break; } } if(text.length() <= 0){ text.append("对不起,我没听清您在说什么"); } return text.toString(); }
用到了讯飞的jar:json-jena-1.0-1.0.jar、Msc-1.0.jar
讯飞的插件:libmsc32.so、libmsc64.so、msc32.dll、msc64.dll,插件我全部放在了工程的根目录下
后来又要求文字需要转换成,一个痛苦的过程啊,各种文件格式转换
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.Properties;
public class ShellExec {
public static void execShell(String command) {
InputStreamReader stdISR = null;
InputStreamReader errISR = null;
Process process = null;
// String command = "/home/Lance/workspace/someTest/testbash.sh";
long timeout = 10 * 1000;
try {
process = Runtime.getRuntime().exec(command);
// CommandStreamGobbler errorGobbler = new CommandStreamGobbler(
// process.getErrorStream(), command, "ERR");
// CommandStreamGobbler outputGobbler = new CommandStreamGobbler(
// process.getInputStream(), command, "STD");
// errorGobbler.start();
// 必须先等待错误输出ready再建立标准输出
// while (!errorGobbler.isReady()) {
// Thread.sleep(10);
// }
// outputGobbler.start();
// while (!outputGobbler.isReady()) {
// Thread.sleep(10);
// }
CommandWaitForThread commandThread = new CommandWaitForThread(
process);
commandThread.start();
long commandTime = new Date().getTime();
long nowTime = new Date().getTime();
boolean timeoutFlag = false;
while (!commandThread.isFinish()) {
if (nowTime - commandTime > timeout) {
timeoutFlag = true;
break;
} else {
Thread.sleep(1000);
nowTime = new Date().getTime();
}
}
if (timeoutFlag) {
// 命令超时
// errorGobbler.setTimeout(1);
// outputGobbler.setTimeout(1);
System.out.println("正式执行命令:" + command + "超时");
}
// while (true) {
// if (errorGobbler.isReadFinish() && outputGobbler.isReadFinish()) {
// break;
// }
// Thread.sleep(10);
// }
} catch (IOException | InterruptedException e) {
e.printStackTrace();
} finally {
if (process != null) {
process.destroy();
}
}
}
public static void convertAudio(String sourcePath,int sourceHZ,String targetPath,int targetHZ){//ffmpeg参数设置的坑好大啊
Properties props=System.getProperties(); //获得系统属性集
String osName = props.getProperty("os.name"); //操作系统名称
String command = null;
if(osName.contains("Windows")){
// ffmpeg -y -f s16le -ar 24000 -ac 1 -i "$1.pcm" -f wav -ar 16000 -b:a 16 -ac 1 "${1%.*}.$2"
command = "C:\\ffmpeg.exe -y -f s16le -ar "+sourceHZ+" -i "+sourcePath+" -f wav -ar "+targetHZ+" -b:a 8 -ac 1 "+targetPath;
}else{
command = "/usr/local/ffmpeg/bin/ffmpeg -y -f s16le -ar "+sourceHZ+" -ac 1 -i "+sourcePath+" -f wav -ar "+targetHZ+" -b:a 8 -ac 1 "+targetPath;
}
System.out.println("格式转换:"+command);
ShellExec.execShell(command);
}
public static void pcmToSilk(String pcmPath,String silkPath) throws InterruptedException{
//首先 pcm转换成8000的wav,然后wav转成silk
// ShellExec.convertAudio(pcmPath, 16000, pcmPath+".wav", 16000);
// Thread.sleep(1000);
// ShellExec.convertAudio(pcmPath+".wav", 16000, silkPath, 8000);
ShellExec.convertAudio(pcmPath, 16000, silkPath, 8000);
}
public static void pcmToWav(String pcmPath,String wavPath){
Properties props=System.getProperties(); //获得系统属性集
String osName = props.getProperty("os.name"); //操作系统名称
String command = null;
if(osName.contains("Windows")){
command = "C:\\ffmpeg.exe -f s16le -ar 16000 -i "+pcmPath+" -f wav -ar 16000 -b:a 8 -ac 1 "+wavPath;
}else{
command = "/usr/local/ffmpeg/bin/ffmpeg -f s16le -ar 16000 -i "+pcmPath+" -f wav -ar 16000 -b:a 16 -ac 1 "+wavPath;
}
System.out.println("格式转换:"+command);
ShellExec.execShell(command);
}
public static void silkToWav(String silkPath,String wavPath){
Properties props=System.getProperties(); //获得系统属性集
String osName = props.getProperty("os.name"); //操作系统名称
String command = null;
if(osName.contains("Windows")){
// ffmpeg -y -f s16le -ar 24000 -ac 1 -i "$1.pcm" -f wav -ar 16000 -b:a 16 -ac 1 "${1%.*}.$2"
command = "C:\\ffmpeg.exe -y -f s16le -ar 8000 -ac 1 -i "+silkPath+" -f wav -ar 16000 -b:a 16 -ac 1 "+wavPath;
}else{
command = "/usr/local/ffmpeg/bin/ffmpeg -y -f s16le -ar 8000 -ac 1 -i "+silkPath+" -f wav -ar 16000 -b:a 16 -ac 1 "+wavPath;
}
System.out.println("格式转换:"+command);
ShellExec.execShell(command);
}
public static void main(String[] args) throws Exception{
ShellExec.pcmToSilk("/home/deployer/tomcat7/webapps/omoFile/gc3e72fbe-1a27-479f-ae4f-d3aacc6276ed.pcm", "/home/deployer/tomcat7/webapps/omoFile/gc3e72fbe-1a27-479f-ae4f-d3aacc6276ed.pcm.silk");
// ShellExec.pcmToWav("/home/deployer/tomcat7/webapps/omoFile/gdd68fe07-35b3-46f1-af08-97100caba179.pcm", "/home/deployer/tomcat7/webapps/omoFile/gdd68fe07-35b3-46f1-af08-97100caba179.pcm.wav");
}
public class CommandWaitForThread extends Thread { private Process process; private boolean finish = false; private int exitValue = -1; public CommandWaitForThread(Process process) { this.process = process; } public void run() { try { this.exitValue = process.waitFor(); } catch (InterruptedException e) { e.printStackTrace(); } finally { finish = true; } } public boolean isFinish() { return finish; } public void setFinish(boolean finish) { this.finish = finish; } public int getExitValue() { return exitValue; }
最终得到了微信小程序需要的silk格式,然而,他喵的我不知道微信小程序需要什么频率什么规格的silk文件,电脑能够播放我转换了的silk,但是小程序并不能播放,好蛋疼啊。继续蛋疼中........
附两份资料
linux安装ffmpeg
http://blog.csdn.net/wh8_2011/article/details/50666745
ffmpeg命令及案例
http://blog.csdn.net/c910511/article/details/54849048 案例
http://www.cuplayer.com/player/PlayerCode/FFmpeg/2014/0706/1399.html 命令