MediaPlayer 实现金额的语音播报功能

来源:互联网 发布:linux udp端口禁用 编辑:程序博客网 时间:2024/05/18 13:08

作者 | qzh

地址 | https://github.com/javaexception

声明 | 本文是 qzh 原创,已获授权发布,未经原作者允许请勿转载



前言

最近写了一个金额的语音播报功能,已封装成依赖库到 Github,希望对大家有所帮助。


Github地址 :

https://github.com/javaexception


思路

(1).准备音频文件。

(2).把要播报的金额转换成大写的金额,比如"零壹贰叁肆伍陆柒捌玖,分角  拾佰仟万拾佰仟亿拾佰仟万"的组合。

(3).通过 MediaPlayer 播放音频。


一.准备音频文件

下面是我音频文件,里面是大写的数字,为播报金额组合做准备。

二.金额转换

public class PlaySound {

   /**
    * 截取字符串
    *
    * @param str  需要截取的字符串
    * @param idx1 开始位置
    * @param idx2 截止位置
    * @return 截取后的字符串
    */

   public static String subString(String str, int idx1, int idx2) {
       try {
           return str.substring(idx1, idx2);
       } catch (Exception ex) {
           return "";
       }
   }

   /**
    * 传递一个字符串参数,如果是null返回“”字符串,否则去除前后的空格。
    *
    * @param str 传入参数
    * @return 没有前后没有空格的字符串
    */

   public static final String trim(String str) {
       if (str == null) return "";
       else return str.trim();
   }

   /**
    * 把double类型数据转换成有格式的字符串
    *
    * @param d      需要转换的double类型数据
    * @param format 格式化方式
    * @return 有格式的字符串
    */

   public static String formatDoubleToString(double d, String format) {
       String doubleStr = String.valueOf(d);
       java.text.DecimalFormat decf = new java.text.DecimalFormat(format);
       String formatStr = decf.format(d);
       /**
        * 通过java保留小数了
        * 如果转换前的长度>转换后的长度,Java的转换就有可能出错
        */

       if (doubleStr.length() > formatStr.length()) {
           /**
            * 如果前面的都一致,但最后一位大于4就需要进位
            * 否则不进位
            */

           if (formatStr.equals(doubleStr.substring(0, formatStr.length()))) {
               /**
                * 取转换前的后一位,
                * 有可能是“.”
                */

               String followStr = doubleStr.substring(formatStr.length(), formatStr.length() + 1);
               if (".".equals(followStr)) {
                   followStr = doubleStr.substring(formatStr.length() + 1, formatStr.length() + 2);
               }

               if (Integer.valueOf(followStr).intValue() > 4) {
                   /**
                    * 这个时候Java没有进位
                    */

                   formatStr = decf.format(Double.valueOf(formatStr).doubleValue() + Double.valueOf(format.substring(0, format.length() - 1) + "1").
                           doubleValue());
               }
           }
       }

       return formatStr;
   }
   /**
    * 把一个都money转换成大写的money
    *
    * @param d 需要转换的money
    * @return 换成大写的money
    */

   public static String capitalValueOf(double d) {
       String lowStr;
       int strLen;
       String currentStr;
       String upperPart;
       String upperStr = "";
       int index = 0;
       int findCount;
       String chns = "零壹贰叁肆伍陆柒捌玖";
       String units = "分角  拾佰仟万拾佰仟亿拾佰仟万";

       if (d >= 100000000 || d < 0) {
           return "";
       }
       if (d == 0) {
           return "零元整";
       }
       lowStr = trim(formatDoubleToString(d, "0.00"));
       strLen = lowStr.length();
       if (strLen == 0) {
           return "";
       }
       while (index < strLen) {
           currentStr = subString(lowStr, strLen - index - 1, strLen - index);
           if (".".equals(currentStr)) {
               upperPart = "元";
           } else {
               upperPart = subString(chns, Integer.valueOf(currentStr).intValue(), Integer.valueOf(currentStr).intValue() + 1);
           }
           upperPart += trim(subString(units, index, index + 1));
           upperStr = upperPart + upperStr;
           index += 1;
       }
       for (; ; ) {
           findCount = 0;
           if (upperStr.indexOf("拾零万零仟") < 0) {
               if (upperStr.indexOf("拾零万") >= 0) {
                   if ("仟".equals(subString(upperStr, upperStr.indexOf("拾零万") + 4, upperStr.indexOf("拾零万") + 5))) {
                       findCount++;
                       upperStr = upperStr.replaceFirst("拾零万", "拾万零");
                   }
               }
           }
           if (upperStr.indexOf("零元") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("零元", "元");
           }
           if (upperStr.indexOf("零拾") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("零拾", "零");
           }
           if (upperStr.indexOf("零佰") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("零佰", "零");
           }
           if (upperStr.indexOf("零仟") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("零仟", "零");
           }
           if (upperStr.indexOf("零万") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("零万", "万");
           }
           if (upperStr.indexOf("零亿") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("零亿", "亿");
           }
           if (upperStr.indexOf("零零") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("零零", "零");
           }
           if (upperStr.indexOf("零角零分") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("零角零分", "整");
           }
           if (upperStr.indexOf("零分") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("零分", "整");
           }
           if (upperStr.indexOf("零角") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("零角", "零");
           }
           if (upperStr.indexOf("零亿零万零元") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("零亿零万零元", "亿元");
           }
           if (upperStr.indexOf("亿零万零元") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("亿零万零元", "亿元");
           }
           if (upperStr.indexOf("零亿零万") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("零亿零万", "亿");
           }
           if (upperStr.indexOf("零万零元") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("零万零元", "万元");
           }
           if (upperStr.indexOf("万零元") >= 0) {
               findCount++;
               upperStr = upperStr.replaceAll("万零元", "万元");
           }
           if (findCount == 0) {
               break;
           }
       }
       while ("元".equals(subString(upperStr, 0, 1)) || "零".equals(subString(upperStr, 0, 1)) || "角".equals(subString(upperStr, 0, 1)) || "分".equals(subString(upperStr, 0, 1)) || "整".equals(subString(upperStr, 0, 1))) {
           strLen = upperStr.length();
           upperStr = subString(upperStr, 1, strLen);
       }
       return upperStr;
   }
   public static void main(String[] args){
   }
}

三.MediaPlayer播放音频

1.MediaPlayer 简介

MediaPlayer 其实是一个封装的很好的音频、视频流媒体操作类,如果查看其源码,会发现其内部是调用的 native 方法,既然是一个流媒体操作类,那么必然涉及到,播放、暂停、停止等操作,实际上 MediaPlayer 也为我们提供了相应的方法来直接操作流媒体。

  • void statr():开始或恢复播放。

  • void stop():停止播放。

  • void pause():暂停播放。 


通过上面三个方法,只要设定好流媒体数据源,即可在应用中播放流媒体资源,为了更好的操作流媒体,MediaPlayer 还为我们提供了一些其他的方法,这里列出一些常用的,详细内容参阅官方文档。

  • int getDuration():获取流媒体的总播放时长,单位是毫秒。

  • int getCurrentPosition():获取当前流媒体的播放的位置,单位是毫秒。

  • void seekTo(int msec):设置当前MediaPlayer的播放位置,单位是毫秒。

  • void setLooping(boolean looping):设置是否循环播放。

  • boolean isLooping():判断是否循环播放。

  • boolean  isPlaying():判断是否正在播放。

  • void prepare():同步的方式装载流媒体文件。

  • void prepareAsync():异步的方式装载流媒体文件。

  • void release ():回收流媒体资源。 

  • void setAudioStreamType(int streamtype):设置播放流媒体类型。

  • void setWakeMode(Context context, int mode):设置CPU唤醒的状态。

  • setNextMediaPlayer(MediaPlayer next):设置当前流媒体播放完毕,下一个播放的MediaPlayer。


在使用 start() 播放流媒体之前,需要装载流媒体资源。


2.MediaPlayer实现播报源码

public class VoiceUtils {
   private static volatile VoiceUtils singleton = null;
   public    boolean IsPlaying;

     MediaPlayer mediaPlayer=null;
   private Context mContext;

   public VoiceUtils(Context context) {
       this.mContext = context.getApplicationContext();
   }

   /**
    * 单例
    * @param context
    * @return
    */

   public static VoiceUtils with(Context context){
       if (singleton == null) {
           synchronized (VoiceUtils.class) {
               if (singleton == null) {
                   singleton = new VoiceUtils(context);
               }
           }
       }
       return singleton;
   }

public void SetIsPlay( boolean IsPlaying){

   this.IsPlaying=IsPlaying;
}

   public boolean GetIsPlay() {
       return IsPlaying;
   }
   public void Play(String stramount,boolean strsuccess)
   
{

       String str=null;
       //如果是TRUE  就播放“收款成功”这句话
       if (strsuccess){
    str  =    "$" + PlaySound.capitalValueOf(Double.valueOf(String.format("%.2f", Double.parseDouble(stramount))));
}else {
    str  = PlaySound.capitalValueOf(Double.valueOf(String.format("%.2f", Double.parseDouble(stramount))));

}
       System.out.println("金额的长度 "+str);
       String temp ="";

       try {
           Thread.sleep(1000);
       } catch (InterruptedException e1) {
           // TODO Auto-generated catch block
           e1.printStackTrace();
       }

       PlaySoundList(1,str,str.length());

   }
   public  void PlaySoundList( final int soundindex, final String soundString, final int soundcount)
   
{
       singleton.SetIsPlay(true);
       boolean createState=false;
       if(mediaPlayer==null) {
           mediaPlayer = null;
       }
       System.out.println("加载音频["+soundindex+"]");
       mediaPlayer = createSound(soundindex,soundString);
       createState=true;

       if(createState==true)
           System.out.println("加载音频成功["+soundindex+"]");
       else
           System.out.println("加载音频失败["+soundindex+"]");

       //播放完成触发此事件
       mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
           @Override
           public void onCompletion(MediaPlayer mp) {
               mp.release();//释放音频资源
               int newsoundindex =soundindex;
               System.out.println("释放资源[" +soundindex+"]");
               if(soundindex<soundcount) {
                   newsoundindex=newsoundindex+1;
                   PlaySoundList(newsoundindex, soundString,soundcount);
               }else {
                   singleton.SetIsPlay(false);
               }

           }
       });
       try {
           //在播放音频资源之前,必须调用Prepare方法完成些准备工作
           if(createState)
               mediaPlayer.prepare();
           else
               mediaPlayer.prepare();
           //开始播放音频
           mediaPlayer.start();

           System.out.println("播放音频["+soundindex+"]");
       } catch (IllegalStateException e) {
           e.printStackTrace();
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
   public  MediaPlayer createSound(int soundIndex, String soundString){
       MediaPlayer mp=null;

       String soundChar = soundString.substring(soundIndex-1,soundIndex);

       switch (soundChar)
       {
           case "零":
               mp=MediaPlayer.create(mContext,R.raw.sound0);
               break;
           case "壹":
               mp=MediaPlayer.create(mContext,R.raw.sound1);
               break;
           case "贰":
               mp=MediaPlayer.create(mContext,R.raw.sound2);
               break;
           case "叁":
               mp=MediaPlayer.create(mContext,R.raw.sound3);
               break;
           case "肆":
               mp=MediaPlayer.create(mContext,R.raw.sound4);
               break;
           case "伍":
               mp=MediaPlayer.create(mContext,R.raw.sound5);
               break;
           case "陆":
               mp=MediaPlayer.create(mContext,R.raw.sound6);
               break;
           case "柒":
               mp=MediaPlayer.create(mContext,R.raw.sound7);
               break;
           case "捌":
               mp=MediaPlayer.create(mContext,R.raw.sound8);
               break;
           case "玖":
               mp=MediaPlayer.create(mContext,R.raw.sound9);
               break;
           case "拾":
               mp=MediaPlayer.create(mContext,R.raw.soundshi);
               break;
           case "佰":
               mp=MediaPlayer.create(mContext,R.raw.soundbai);
               break;
           case "仟":
               mp=MediaPlayer.create(mContext,R.raw.soundqian);
               break;
           case "角":
               mp=MediaPlayer.create(mContext,R.raw.soundjiao);
               break;
           case "分":
               mp=MediaPlayer.create(mContext,R.raw.soundfen);
               break;
           case "元":
               mp=MediaPlayer.create(mContext,R.raw.soundyuan);
               break;
           case "整":
               mp=MediaPlayer.create(mContext,R.raw.soundzheng);
               break;
           case "万":
               mp=MediaPlayer.create(mContext,R.raw.soundwan);
               break;
           case "$":
               mp=MediaPlayer.create(mContext,R.raw.soundsuccess);
               break;

       }
       //下面这三句是控制语速,但是只适用于Android6.0 以上,以下的就会报错,所以这个功能下次更新时解决
//        PlaybackParams pbp = new PlaybackParams();
//        pbp.setSpeed(1.5F);
//        mp.setPlaybackParams(pbp);
       mp.stop();
       return mp;
   }

}


四.使用

Gradle依赖 -

1.最 app 外层的 build.gradle 添加代码:


2.在app 的 build.gradle 中添加:


使用方法 -

1.普通调用:
我想强调的是传入的金额最多精确到”分”,还有在调用的时候应该进行 try-catch 因为如果传入的不是金额,会出现异常的。 如果是 true 播报语音为”收款成功+收款金额”,如果是 false 只播报收款金额。


2.防止用户同时接收多条语音造成语音重叠的调用方法:



报语速的调控问题,现在因为只能支持 Android6.0 以上的,所以代码我没添加,等解决后一起更新。



与之相关

1 回炉再造,灵活的 YMenuView 2.0 诞生

2 给编程生涯充电的 10 本书



微信号:code-xiaosheng





公众号

「code小生」


原创粉丝点击