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

最近写了一个金额的语音播报功能,已封装成依赖库到Github,希望对大家有所帮助。
Github地址 :
https://github.com/javaexception

思路:
(1).准备音频文件。
(2).把要播报的金额转换成大写的金额,比如”零壹贰叁肆伍陆柒捌玖,分角 拾佰仟万拾佰仟亿拾佰仟万”的组合。
(3).通过MediaPlayer播放音频。


###一.准备音频文件

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


###二.金额转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
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 start():开始或恢复播放。

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实现播报源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
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 添加代码:

1
2
3
4
5
6
allprojects {
repositories {
jcenter()
maven { url 'https://jitpack.io' }
}
}

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

1
2
3
dependencies {
compile 'com.github.javaexception:VoiceAnnouncements:v1.2'
}

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

1
      //普通用法        VoiceUtils.with(this).Play("111",true);

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private synchronized void Play(final String str) {
if (VoiceUtils.with(this).GetIsPlay()){
System.out.println("正在播放语音 ");
new Thread() {
@Override
public void run() {
super.run();
try {
Thread.sleep(100);//休眠0.1秒
Play(str);
} catch (InterruptedException e) {
e.printStackTrace();
}
/**
* 要执行的操作
*/
}
}.start();
}else {
System.out.println("不冲突");
VoiceUtils.with(this).Play(str,true);
}
}

播报语速的调控问题,现在因为只能支持Android6.0以上的,所以代码我没添加,等解决后一起更新。
如果有什么不清楚的可以加我公众号或者加微信,希望对大家有所帮助。

秦子帅 wechat
欢迎您扫一扫上面的微信公众号,带你走进Android、Python技术!
坚持原创技术分享,您的支持将鼓励我继续创作!