package com.bot.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 音频格式转换
*
* @author sqd233
*/
@Component
public class AudioUtils {
static Logger logger = LoggerFactory.getLogger(AudioUtils.class);
/**
* 工具地址
**/
public static String path = "lib\\silk_converter\\";
/**
* MP3/WAV转SILk格式
* @param filePath 例:D:\\file\\audio.mp3
* @param isSource isSource 是否清空原文件
* @return
*/
public static String toSilk(String filePath, boolean isSource){
Integer index = filePath.lastIndexOf("\\") + 1;
return toSilk(filePath.substring(0, index), filePath.substring(index, filePath.length()), isSource);
}
/**
* MP3/WAV转SILk格式
*
* @param path 文件路径 例:D:\\file\\
* @param name 文件名称 例:audio.mp3/audio.wav
* @param isSource 是否清空原文件
* @return silk文件路径
* @throws Exception
*/
public static String toSilk(String path, String name, boolean isSource) {
try {
// 判断后缀格式
String suffix = name.split("\\.")[1];
if (!suffix.toLowerCase().equals("mp3") && !suffix.toLowerCase().equals("wav")) {
throw new Exception("文件格式必须是mp3/wav");
}
String filePath = path + name;
File file = new File(filePath);
if (!file.exists()) {
throw new Exception("文件不存在!");
}
// 文件名时拼接
SimpleDateFormat ttime = new SimpleDateFormat("yyyyMMddhhMMSS");
String time = ttime.format(new Date());
// 导出的pcm格式路径
String pcmPath = path + "PCM_" + time + ".pcm";
// 先将mp3/wav转换成pcm格式
toPcm(filePath, pcmPath);
// 导出的silk格式路径
String silkPath = path + "SILK_" + time + ".silk";
// 转换成silk格式
pcmToSilk(pcmPath, silkPath);
// 删除pcm文件
File pcmFile = new File(pcmPath);
if (pcmFile.exists()) {
pcmFile.delete();
}
if (isSource) {
File audioFile = new File(filePath);
if (audioFile.exists()) {
audioFile.delete();
}
}
return silkPath;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 调用ffmpeg,wav转 pcm
*
* @param wavPath wav文件地址
* @param target 转后文件地址
*/
public static void wavToPcm (String wavPath, String target) {
// ffmpeg -i input.wav -f s16le -ar 44100 -acodec pcm_s16le output.raw
toPcm(wavPath, target);
}
/**
* 调用ffmpeg,mp3转 pcm
*
* @param mp3Path mp3文件地址
* @param target 转后文件地址
*/
public static void mp3ToPcm(String mp3Path, String target) {
//ffmpeg -y -i 源文件 -f s16le -ar 24000 -ac 1 转换后文件位置
toPcm(mp3Path, target);
}
/**
* mp3/wav 通用
* @param fpath
* @param target
*/
private static void toPcm(String fpath, String target) {
List<String> commend = new ArrayList<String>();
commend.add(path + "ffmpeg.exe");
commend.add("-y");
commend.add("-i");
commend.add(fpath);
commend.add("-f");
commend.add("s16le");
commend.add("-ar");
commend.add("24000");
commend.add("-ac");
commend.add("-2");
commend.add(target);
Process p = null;
try {
ProcessBuilder builder = new ProcessBuilder();
builder.command(commend);
p = builder.start();
p.waitFor();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (p != null) {
p.destroy();
}
}
}
/**
* silk_v3_encoder.exe,转成Silk格式
* @param pcmPath pcm 文件地址
* @param target 转换后的silk地址
* silk_v3_encoder.exe 路径
* pcm文件地址
* silk输出地址
* -Fs_API <Hz> : API sampling rate in Hz, default: 24000
* -Fs_maxInternal <Hz> : Maximum internal sampling rate in Hz, default: 24000
* -packetlength <ms> : Packet interval in ms, default: 20
* -rate <bps> : Target bitrate; default: 25000
* -loss <perc> : Uplink loss estimate, in percent (0-100); default: 0
* -complexity <comp> : Set complexity, 0: low, 1: medium, 2: high; default: 2
* -DTX <flag> : Enable DTX (0/1); default: 0
* -quiet : Print only some basic values
* -tencent : Compatible with QQ/Wechat
*/
public static void pcmToSilk(String pcmPath, String target) {
Process process = null;
try {
process = Runtime.getRuntime().exec("cmd /c start " + path + "silk_v3_encoder.exe " + pcmPath + " " + target + " -tencent");
process.waitFor();
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (process != null) {
process.destroy();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* mp3转amr(低质量qq语音)
* @param mp3Path MP3文件地址
* @param target 转换后文件地址
* return
*/
public static void mp3ToAmr(String mp3Path, String target) {
// 被转换文件地址
File source = new File(path);
try {
if (!source.exists()) {
throw new Exception("文件不存在!");
}
List<String> commend = new ArrayList<String>();
commend.add(path + "ffmpeg.exe");
commend.add("-y");
commend.add("-i");
commend.add(mp3Path);
commend.add("-ac");
commend.add("1");
commend.add("-ar");
commend.add("8000");
commend.add(target);
try {
ProcessBuilder builder = new ProcessBuilder();
builder.command(commend);
Process p = builder.start();
p.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
logger.error("mp3转amr异常-{}", e);
}
}
/**
* 一个音频转byte类型的方法
* @param filePath
* @return
*/
public static byte[] byteAudio(String filePath) {
try {
InputStream inStream = new FileInputStream(filePath);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = inStream.read(buffer)) > 0) {
baos.write(buffer, 0, bytesRead);
}
inStream.close();
baos.close();
return baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}