java 多条语音顺序合并及播放 + amr转wav播放控制(业务场景:语音顺序广播及紧急口播)

业务场景

从数据库中获取配置好的语音文件信息数组,然后播放,播放中如果有紧急广播,则终止当前的,播放紧急的;

实现大致方式

在此,将语音数组进行合并成一条语音,否则不好控制,另外没有使用线程阻塞和多线程,一方面是不好控制,另一方面是效果很不好,所以在这里加了一个文件结束日期,当播放语音开始时,获取文件时长,然后得到该文件播放完的结束日期,如果在结束日期之前再来广播,则不播放(可在此配置队列进行排队机制,我没加^_^),如果来了紧急广播,则终止当前正在播放的,来播放紧急语音,所以在每次广播之前都要先判断一下,当前时间是否在结束日期之前;

说明

将amr转为wav的过程中,可能有报错,但是不影响使用,报错说时长等属性为空,但是我设置后还是为提示空,暂时没管这个错;

代码实现
import it.sauronsoftware.jave.AudioAttributes;
import it.sauronsoftware.jave.Encoder;
import it.sauronsoftware.jave.EncoderException;
import it.sauronsoftware.jave.EncodingAttributes;
import it.sauronsoftware.jave.InputFormatException;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ljy.common.shcedule.ScheduledJob;
import com.ljy.entity.TB_YYK_VO;
import com.ljy.util.PropertiesUtil;


import sun.audio.AudioPlayer;
import sun.audio.AudioStream;


@RestController
@RequestMapping("/radio")
public class ReadWav {
    private  FileInputStream fileau = null; 
    private  String stop_date = getNowTime(); //文件播放的结束时间,初始化为当前时间
    private  static String allWav_name = "allWav_playing.wav"; //合并后的语音文件名称
    private  static String talk_name = "talking.wav"; //紧急口播生成的文件名称
    private  static String loop_num = "2"; //默认循环
    private  static boolean is_replace = false; //是否下次语音覆盖正在播放的语音
    private final static Logger logger = LoggerFactory.getLogger(ScheduledJob.class);


    //也可以从配置文件中读取
    static{
        try {
            Properties pro = PropertiesUtil.getProperties("Config.properties");
            allWav_name = pro.getProperty("allWav_name");
            talk_name = pro.getProperty("talk_name");
            loop_num = pro.getProperty("loop_num");
            is_replace = Boolean.parseBoolean(pro.getProperty("is_replace"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //lujing:需要播放的语音文件路径数组JSON,按顺序排好,cs:播放次数
    @RequestMapping("/wav")
    public void ReadWavs(String lujing,String cs) throws IOException, LineUnavailableException, 
                    UnsupportedAudioFileException, InterruptedException{
        //如果在播放时间再次播放,则直接返回不播放
        if(!is_replace && compare_date(getNowTime(),stop_date) == -1){
            logger.info("当前有正在播放语音,本次播放禁止!");
            return ;
        }
        //JSON转为实体类 
        TB_YYK_VO[] lists = new ObjectMapper().readValue(lujing, TB_YYK_VO[].class);

        //如果没传次数,则使用默认
        if(cs == null || "".equals(cs)){
            cs = loop_num ;
        }
        int num = Integer.parseInt(cs);     
        AudioFormat format = null;
        AudioFileFormat aff = null ;
        AudioInputStream ais = null ;
        long frameLength = 0; //文件帧数
        ArrayList<AudioInputStream> c = new ArrayList<AudioInputStream>();  
        //播放次数
        for(int i=0;i<num;i++){
            //语音文件数组
            for(int j=0;j<lists.length;j++){
                String adress = lists[j].getLj();
                File ccy = new File(adress);
                ais = AudioSystem.getAudioInputStream(ccy); 
                //获取语音文件的属性信息,只获取一次即可
                if(j == 0){
                    aff = AudioSystem.getAudioFileFormat(ccy);
                    format = ais.getFormat();
                }
                //需要将长度相加,不然时长不对
                frameLength += ais.getFrameLength();
                c.add(ais);
            }
        }
        Enumeration<AudioInputStream> e = Collections.enumeration(c); 
        SequenceInputStream sis = new SequenceInputStream(e);

        AudioInputStream  all = new AudioInputStream(sis, format,frameLength) ;
        AudioSystem.write(all,aff.getType(), new File(allWav_name));
       //需要播放的语音文件流
        fileau = new FileInputStream(allWav_name);
        long wav_time = CalculationTime(allWav_name)*1000+10; //文件时长
        stop_date = getDateByAdd((int)wav_time); //文件播放完的日期
        AudioPlayer.player.start(fileau); 
    }

    //停止播放
    @RequestMapping("/stopWav")
    public void stopWav() throws Exception{
        logger.info("停止了当前播放语音");
        AudioPlayer.player.stop(fileau);
        stop_date = getNowTime() ; //结束播放后,将文件播放结束日期置为当前即可
    }

    //紧急口播 
    //filePath:生成的amr路径
    @RequestMapping("/playVideo")
    public void playVideo(String filePath,String duration) throws Exception{
        logger.info("口播语音filename:---"+filePath);
        //口播优先级最高,所以直接中断当前广播
        AudioPlayer.player.stop(fileau);
        changeToWav(filePath,talk_name,new Float(duration)); //格式转换
        fileau = new FileInputStream(talk_name);
        long wav_time = CalculationTime(talk_name)*1000+10; //文件时长
        stop_date = getDateByAdd((int)wav_time); //文件播放完的日期
        AudioPlayer.player.start(fileau);
    }


/**
 *
 * 下面是一些服务方法
 *------------------------------------------------------------------------------------------
 */


    /**
     * 
        * @Title: changeToWav
        * @Description: TODO(将语音文件转为wav格式)
        * @param @param sourcePath 源文件路径
        * @param @param targetPath    转换后的文件路径
        * @param @param duration  文件时长(这个从手机端传过来的参数值,但是使用了没效果)
        * @return void    返回类型
        * @throws
     */
     public static void changeToWav(String sourcePath, String targetPath,Float duration) {  
        try {
            File source = new File(sourcePath);  
            File target = new File(targetPath);  
            AudioAttributes audio = new AudioAttributes();  
            Encoder encoder = new Encoder();  

            audio.setCodec("pcm_s16le");
            audio.setBitRate(new Integer(705000));  
            audio.setChannels(new Integer(1));  
            audio.setSamplingRate(new Integer(44100)); 
            audio.setVolume(new Integer(500));
            EncodingAttributes attrs = new EncodingAttributes();  
            attrs.setFormat("wav");  
            attrs.setAudioAttributes(audio); 
            attrs.setDuration(duration);
            encoder.encode(source, target, attrs);  
        } catch (IllegalArgumentException e) {  
            e.printStackTrace();  
        } catch (InputFormatException e) {  
            e.printStackTrace();  
        } catch (EncoderException e) {  
            e.printStackTrace();  
        }  
     }
    //计算WAV文件时间
    public static long CalculationTime(String adress) throws LineUnavailableException, 
                                            UnsupportedAudioFileException, IOException{
        File file = new File(adress);
        Clip clip = AudioSystem.getClip();
        AudioInputStream ais = AudioSystem.getAudioInputStream(file);
        clip.open(ais);
        long times = (long) (clip.getMicrosecondLength() / 1000000D);
        return times;
    }

    //获取当前时间+给定秒之后的时间
    public static String getDateByAdd(long s){
        long currentTime = System.currentTimeMillis() ;
        currentTime += s;
        Date date = new Date(currentTime);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = sdf.format(date);
        return  dateStr ;
    }
    /**
     * 
        * @Title: compare_date
        * @Description: TODO(比较日期大小)
        * @param @param DATE1
        * @param @param DATE2
        * @param @return    参数
        * @return int    返回类型
        * @throws
     */
     public static int compare_date(String DATE1, String DATE2) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date dt1 = df.parse(DATE1);
            Date dt2 = df.parse(DATE2);
            if (dt1.getTime() > dt2.getTime()) {
                return 1 ;
            } else if (dt1.getTime() < dt2.getTime()) {
                return -1 ;
            } else {
                return 0;
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return 0;
    }
     /**
         * 
            * @Title: getNowTime
            * @Description: TODO(获取当前时间)
            * @param @return    参数
            * @return String    返回类型
            * @throws
         */
    public static String getNowTime(){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String now = sdf.format(new Date()) ;
        return now ;
    }

    public static void main(String[] args) throws ParseException {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm");
        Date dt1 = df.parse(null);
        System.out.println(dt1.getTime() );
    }
}
附jave jar包下载地址,请下载1.0.2的,2.0的我用了报错

jave 语音格式转换jar下载

猜你喜欢

转载自blog.csdn.net/qq_35564978/article/details/81665002