java 微信小程序 语音识别成文字 音频格式转换 silk pcm wav

时间:2021-07-19 16:43:31

最近有需求要把微信小程序里面的语音进行语音识别,然后搜搜,微信小程序的语音格式是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 命令