工作中,遇到了需要从微信中获取录音文件,然而高音质的音频文件不能直接使用,需要转成wav才能正常使用,这里记录下调研后的结果
通过微信录音获取音频文件的方式的有两种
一种是amr 低质量音频 通过https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID获取
一种是speex 高质量音频 通过https://api.weixin.qq.com/cgi-bin/media/get/jssdk?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
获取
然而高质量speex音频文件 往往无法直接使用,需要还换成其他的格式才能够使用
首先,由于安装的speex生成的可执行文件默认在/usr/local/lib/下 但是默认的path依赖是usr/lib/下,所以需要配置etc/bashrc文件最后一行加一行:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
注:修改过的配置文件,需要使用 source /etc/bashrc命令使配置文件生效
第一步,我们需要安装speex环境
根据微信提示,我们从https://www.speex.org/downloads/ 下载speex-1.2.0.tar.gz,进行以下步骤
tar -zxvf speex-1.2.0.tar.gz
cd speex-1.2.0
./configure
sudo make install
这里需要注意的是执行完操作后,要去/usr/local/lib下,是否有speex文件生成,如果没有,很有可能是最开始的配置文件没有更改
第二步:从https://github.com/ppninja/wechat-speex-declib下载speex_decode转码工具
到bin目录下 可以看到生成的speex_decode可执行文件 如果不存在,很有可能是因为上面的path路径问题
转码只需要到bin目录下 执行./speex_decode 音频.speex 音频.wav即可
以下附上代码,具体说明请看代码注释,涉及到一些其他工具类不影响主要逻辑,可以删除改成固定值测试
import java.text.MessageFormat;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.stereotype.Service;
import com.common.utils.logback.LogUtil;
import com.common.utils.uuid.GuidUtil;
import com.common.FileUtil;
import com.common.PropertiesDef;
@Service
public class SpeexToWavService {
private ExecutorService pool = Executors.newCachedThreadPool();
public byte[] speexToWav(byte[] data) {
byte[] body = null;
String speexName = GuidUtil.getUUID() + ".speex";
String wavName = GuidUtil.getUUID() + ".wav";
try {
if (FileUtil.save(PropertiesDef.ORIGIN_PATH, speexName, data)) {
// SPEEX_DECODE_PATH : speex_decode所在路径
// ORIGIN_PATH : 微信录音音频文件下拉位置
String command = MessageFormat.format("{0}speex_decode {1} {2}", PropertiesDef.SPEEX_DECODE_PATH,
PropertiesDef.ORIGIN_PATH + speexName, PropertiesDef.ORIGIN_PATH + wavName);
int n = execCommand(command, 10000);
// 获取文件流
if (n == 0) {
body = FileUtil.getFile(PropertiesDef.ORIGIN_PATH, wavName);
}
}
} catch (Exception e) {
LogUtil.logError("speex转wav失败", ExceptionUtils.getStackTrace(e));
} finally {
// 执行完毕,删除下拉音频文件
FileUtil.deleteFile(PropertiesDef.ORIGIN_PATH + speexName);
FileUtil.deleteFile(PropertiesDef.ORIGIN_PATH + wavName);
}
return body;
}
public int execCommand(String command, long timeout) {
Process process = null;
Future executeFuture = null;
try {
process = Runtime.getRuntime().exec(command);
final Process p = process;
Callable call = new Callable() {
@Override
public Integer call() throws Exception {
p.waitFor();
return p.exitValue();
}
};
//使用线程池防止Process阻塞
executeFuture = pool.submit(call);
return executeFuture.get(timeout, TimeUnit.MILLISECONDS);
} catch (Exception e) {
LogUtil.logError("speex转wav:execCommand 执行命令失败,command:{},错误原因:{}", command,
ExceptionUtils.getStackTrace(e));
return 1;
}finally {
if (executeFuture != null) {
try {
executeFuture.cancel(true);
} catch (Exception ignore) {
}
}
if (process != null) {
process.destroy();
}
}
}
}
FileUtil 工具类
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.commons.lang.exception.ExceptionUtils;
import com.common.utils.logback.LogUtil;
public class FileUtil {
public static boolean save(String filePath, String fileName, byte[] content) {
try {
File filedir = new File(filePath);
if (!filedir.exists()) {
filedir.mkdirs();
}
File file = new File(filedir, fileName);
OutputStream os = new FileOutputStream(file);
os.write(content, 0, content.length);
os.flush();
os.close();
} catch (FileNotFoundException e) {
LogUtil.logError(
"保存文件流异常,函数名称:save,fileName:{},filePath:{},异常原因:{}",
fileName, filePath, ExceptionUtils.getStackTrace(e));
return false;
} catch (IOException e) {
LogUtil.logError(
"保存文件流异常,函数名称:save,fileName:{},filePath:{},异常原因:{}",
fileName, filePath, ExceptionUtils.getStackTrace(e));
return false;
}
return true;
}
public static byte[] getFile(String filePath, String fileName){
byte[] buffer = null;
try {
File file = new File(filePath,fileName);
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024 * 4];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
buffer = bos.toByteArray();
fis.close();
bos.close();
} catch (Exception e) {
LogUtil.logError(
"获取文件流异常,函数名称:getFile,fileName:{},filePath:{},异常原因:{}",
fileName, filePath, ExceptionUtils.getStackTrace(e));
}
return buffer;
}
}