import com.jdd.ai.digital.human.live.common.exception.error.CommonErrorCode; import com.jdd.ai.digital.human.live.constants.VideoMaterialTypeEnum; import com.jdd.ai.digital.human.live.exception.BaseException; import com.jdd.ai.robot.digital.human.service.system.oss.UuidUtils; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.MessageFormat; import java.util.Objects; 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 java.util.regex.Matcher; import java.util.regex.Pattern; import jodd.io.FileUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import ws.schild.jave.MultimediaInfo; import ws.schild.jave.MultimediaObject; /** * @author ext.huishanyu1 */ @Service @Slf4j public class AudioService { private final ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2); private final String ORIGIN_PATH = "/music/convert/"; private static final String MUSIC_SUFFIX = ".wav"; private final Pattern pattern = Pattern.compile("[\u4E00-\u9FA5|\\!|\\,|\\。|\\(|\\)|\\《|\\》|\\“|\\”|\\?|\\:|\\;|\\【|\\】]"); /** 判断是否为music类型 */ public boolean isMusicType(MultipartFile multipartFile) { return MaterialUtils.convert(Objects.requireNonNull(FilenameUtils.getExtension(multipartFile.getOriginalFilename()))).name().equals(VideoMaterialTypeEnum.music.name()); } /** 判断是否为中文 */ public boolean isChinese(String str) { if (StringUtils.isBlank(str)) { return false; } Matcher m = pattern.matcher(str); return m.find(); } /** 判断是否为wav格式 */ public boolean isWav(String suffix) { return MUSIC_SUFFIX.equalsIgnoreCase(suffix); } /** 获取新文件名 */ public String getNewBaseName(String fileName) { return String.format("%s%s", FilenameUtils.getBaseName(fileName), MUSIC_SUFFIX); } /** 生成新文件名 */ public String generateFileName(String suffix) { String newSuffix = StringUtils.isBlank(suffix) ? MUSIC_SUFFIX : String.format(".%s", suffix); return String.format("%s%s", UuidUtils.getUUID(), newSuffix); } /** 获取后缀 */ public String getNewSuffix() { return MUSIC_SUFFIX; } /** 获取语音文件播放时长 */ public String getDuration(MultipartFile multipartFile) { File file = new File(Objects.requireNonNull(multipartFile.getOriginalFilename())); try { FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file); MultimediaObject object = new MultimediaObject(file); MultimediaInfo info = object.getInfo(); return DateUtils.convertMillisecond2(info.getDuration()); } catch (Exception e) { e.printStackTrace(); log.error("<AudioUtil>.getDuration, music get duration fail, message:{}", ExceptionUtils.getStackTrace(e)); return "00:00"; } finally { // 删除文件 try { FileUtil.deleteFile(file); } catch (IOException e) { e.printStackTrace(); log.error("<AudioUtil>.getDuration, file delete fail, message:{}", ExceptionUtils.getStackTrace(e)); } } } /** 其他音乐类型转换为标准wav类型 */ public InputStream toWav(MultipartFile multipartFile) throws BaseException{ InputStream inputStream = null; // 录音文件下拉地址 String sourceName = multipartFile.getOriginalFilename(); String destName = String.format("%s%s", FilenameUtils.getBaseName(multipartFile.getOriginalFilename()), MUSIC_SUFFIX); // 文件中文检测 if(isChinese(sourceName)){ sourceName = generateFileName(FilenameUtils.getExtension(sourceName)); destName = generateFileName(null); } String sourcePath = String.format("%s%s", ORIGIN_PATH, sourceName); String destPath = String.format("%s%s", ORIGIN_PATH, destName); try { if (save(ORIGIN_PATH, sourceName, multipartFile.getBytes())) { String command; // 将原音频文件转换为 双声道(-ac 2)/采样率22050Hz(-ar 22050) 16bit/音频码率128kbps(-ab 128k)/声音编解码器16kbs(-acodec pcm_s16le)的wav音频文件 command = MessageFormat.format("ffmpeg -i {0} -ac 2 -ar 22050 -ab 128k -acodec pcm_s16le {1}", sourcePath, destPath); // command = MessageFormat.format("D:/software/ffmpeg/ffmpeg-5.0.1-essentials_build/bin/ffmpeg.exe -i {0} -ac 2 -ar 22050 -ab 128k -acodec pcm_s16le {1}", sourcePath, destPath); int n = execCommand(command, 30); // 获取文件流 if (n == 0) { byte[] body = getFileBytes(destName); // byte[] convert InputStream inputStream = new ByteArrayInputStream(body); } else { throw new BaseException(CommonErrorCode.FILE_FFMPEG_CONVERT_TYPE_ERROR.getDesc()); } } } catch (Exception e) { e.printStackTrace(); log.error("<AudioUtil>.toWav, source convert wav fail, message:{}", ExceptionUtils.getStackTrace(e)); } finally { // 执行完毕,删除下拉音频文件 try { FileUtil.deleteFile(sourcePath); FileUtil.deleteFile(destPath); } catch (IOException e) { e.printStackTrace(); log.error("<AudioUtil>.toWav, delete file fail, message:{}", ExceptionUtils.getStackTrace(e)); } } return inputStream; } /** 执行FFmpeg命令 */ public int execCommand(String command, long timeout) { Process process = null; Future<Integer> executeFuture = null; try { process = Runtime.getRuntime().exec(command); final Process p = process; Callable<Integer> call = () -> { p.waitFor(); return p.exitValue(); }; // 使用线程池防止Process阻塞 executeFuture = executorService.submit(call); return executeFuture.get(timeout, TimeUnit.SECONDS); } catch (Exception e) { e.printStackTrace(); log.error("<AudioUtil>.save, convert wav type error,execCommand fail, command:{}, message:{}", command, ExceptionUtils.getStackTrace(e)); return 1; } finally { if (executeFuture != null) { try { executeFuture.cancel(true); } catch (Exception e) { e.printStackTrace(); log.error("<AudioUtil>.save, convert wav type error,future cancel fail, message:{}", ExceptionUtils.getStackTrace(e)); } } if (process != null) { process.destroy(); } } } /** 保存文件 */ private 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 (IOException e) { e.printStackTrace(); log.error("<AudioUtil>.save, file save error, fileName:{}, filePath:{}, message:{}", fileName, filePath, ExceptionUtils.getStackTrace(e)); return false; } return true; } /** 获取文件byte[] */ private byte[] getFileBytes(String fileName) { byte[] buffer = null; FileInputStream fis = null; ByteArrayOutputStream bos = null; try { File file = new File(ORIGIN_PATH, fileName); fis = new FileInputStream(file); 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(); } catch (Exception e) { e.printStackTrace(); log.error("<AudioUtil>.getFile, get file bytes error, fileName:{}, filePath:{}, message:{}", fileName, ORIGIN_PATH, ExceptionUtils.getStackTrace(e)); } finally { try { if (Objects.nonNull(bos)) { bos.close(); } if (Objects.nonNull(fis)) { fis.close(); } } catch (IOException e) { e.printStackTrace(); log.error("<AudioUtil>.getFile, close stream error, message:{}", ExceptionUtils.getStackTrace(e)); } } return buffer; } }
因篇幅问题不能全部显示,请点此查看更多更全内容