最近项目需要实现语音播报收款金额,本来要使用百度AL开发平台的语音合成进行语音播报,虽然这个是可以完美实现,但是这个在免费的情况下有这播放条数的限制,所以最终决定使用播放本地语音的方式进行实现。不多说,直接贴代码,代码也都进行了注释:

一、FileUtils文件读取工具类

public class FileUtils {public static AssetFileDescriptor getAssetFileDescription(String filename) throws IOException {AssetManager manager = CardDoctorApplication.getContext().getAssets();return manager.openFd(filename);}
}

CardDoctorApplication是自己的application类,就不贴出来了。

二、音频播放类

import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** 音频播放类* Created by Administrator on 2018/10/9.*/public class VoiceSpeaker {private static VoiceSpeaker sInstance;private ExecutorService service;//线程池private VoiceSpeaker() {service = Executors.newCachedThreadPool();}/*** 获取音频播放对象* @return*/public static synchronized VoiceSpeaker getInstance() {if (sInstance == null) {sInstance = new VoiceSpeaker();}return sInstance;}/*** 播放前检查* @param list*/public void speak(final List<String> list){if (service != null){service.execute(new Runnable() {@Overridepublic void run() {start(list);}});}}/*** 开始播放* @param list*/private void start(final List<String> list) {synchronized (this) {final CountDownLatch latch = new CountDownLatch(1);//并发MediaPlayer player = new MediaPlayer();/*** 遍历音频模板集合,按顺序播放音频文件*/if (list != null && list.size() > 0) {final int[] counter = {0};/*** format方法使用占位符进行格式化* %s中的 s 代表 字符串类型** path是音频文件的路径,通过格式化之后匹配到对应的音频文件*/String path = String.format("sound/tts_%s.mp3", list.get(counter[0]));AssetFileDescriptor fd = null;try {fd = FileUtils.getAssetFileDescription(path);/*** 设置要使用的数据源(FileDescriptor)。FileDescriptor必须是可搜索的(注意,LocalSocket不可搜索)。调用者有责任关闭文件描述符。* 参数说明:* 第一个参数:FileDescriptor:您要播放的文件的FileDescriptor* 第二个参数:long:要播放的数据开始的文件的偏移量,以字节为单位* 第三个参数:long:要播放的数据的字节长度*/player.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(),fd.getLength());/*** 准备播放器以异步方式播放。设置数据源和显示表面后,您需要调用prepare()或prepareAsync()。* 对于流,您应该调用prepareAsync(),它会立即返回,而不是阻塞,直到缓冲了足够的数据。*/player.prepareAsync();/*** 注册媒体源准备播放时要调用的回调。*/player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mp) {mp.start();}});/*** 注册在回放期间到达媒体源末尾时要调用的回调。*/player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {/*** 将MediaPlayer重置为未初始化状态。调用此方法后,您必须通过设置数据源并调用prepare()再次初始化它。*/mp.reset();counter[0]++;if (counter[0] < list.size()) {try {AssetFileDescriptor fileDescriptor = FileUtils.getAssetFileDescription(String.format("sound/tts_%s.mp3", list.get(counter[0])));mp.setDataSource(fileDescriptor.getFileDescriptor(), fileDescriptor.getStartOffset(), fileDescriptor.getLength());mp.prepare();} catch (IOException e) {e.printStackTrace();latch.countDown();//完成预期工作,发出完成信号...}} else {/*** 是否MediaPlayer资源*/mp.release();latch.countDown();//完成预期工作,发出完成信号...}}});} catch (IOException e) {e.printStackTrace();latch.countDown();//完成预期工作,发出完成信号...}finally {if (fd != null){try {fd.close();//关闭文件操作} catch (IOException e) {e.printStackTrace();}}}}try {latch.await();等待主线程执行完毕,获得开始执行信号...this.notifyAll();} catch (InterruptedException e) {e.printStackTrace();}}}
}

三、音频播放模板处理类

import android.text.TextUtils;import com.yunkahui.datacubeper.common.utils.LogUtils;import java.util.ArrayList;
import java.util.List;/*** 音频播放模板处理类* Created by Administrator on 2018/10/9.*/public class VoiceTemplate {private static final String DOT = ".";private String numString;private String prefix;//收款成功音频private String suffix;//元的音频public VoiceTemplate() {}/*** 获取播放的音频文件顺序集合** @param money* @return*/public static List<String> getDefaultTemplate(String money) {return new VoiceTemplate().prefix("success").numString(money).suffix("yuan").gen();}public String getPrefix() {return prefix;}public VoiceTemplate prefix(String prefix) {this.prefix = prefix;return this;}public String getSuffix() {return suffix;}public VoiceTemplate suffix(String suffix) {this.suffix = suffix;return this;}public String getNumString() {return numString;}public VoiceTemplate numString(String numString) {this.numString = numString;return this;}public List<String> gen() {return genVoiceList();}private List<String> createReadableNumList(String numString) {List<String> result = new ArrayList<>();if (!TextUtils.isEmpty(numString)) {int len = numString.length();for (int i = 0; i < len; i++) {if ('.' == numString.charAt(i)) {result.add("dot");} else {result.add(String.valueOf(numString.charAt(i)));}}}return result;}/*** 播放音频文件顺序** @return*/private List<String> genVoiceList() {List<String> result = new ArrayList<>();if (!TextUtils.isEmpty(prefix)) {result.add(prefix);}if (!TextUtils.isEmpty(numString)) {result.addAll(genReadableMoney(numString));}if (!TextUtils.isEmpty(suffix)) {result.add(suffix);}return result;}/*** 拆分金额成一个集合,以对应音频文件** @param numString* @return*/private List<String> genReadableMoney(String numString) {List<String> result = new ArrayList<>();if (!TextUtils.isEmpty(numString)) {/*** contains()返回TRUE时,该字符串中存在该字符* 此处判断字符串是否包含小数点*/if (numString.contains(DOT)) {String integerPart = numString.split("\\.")[0];String decimalPart = numString.split("\\.")[1];//整数部分List<String> intList = readIntPart(integerPart);//小数点之后的部分List<String> decimalList = readDecimalPart(decimalPart);result.addAll(intList);if (!decimalList.isEmpty()) {result.add("dot");result.addAll(decimalList);}} else {//intresult.addAll(readIntPart(numString));}}return result;}/*** 拆分小数点后面字符串** @param decimalPart* @return*/private List<String> readDecimalPart(String decimalPart) {List<String> result = new ArrayList<>();if (!"00".equals(decimalPart)) {char[] chars = decimalPart.toCharArray();for (char ch : chars) {result.add(String.valueOf(ch));}}return result;}/*** 当金额为整数时,直接拆分,拆分成** @param integerPart* @return*/private List<String> readIntPart(String integerPart) {List<String> result = new ArrayList<>();String intString = readLong(Long.parseLong(integerPart));int len = intString.length();for (int i = 0; i < len; i++) {char current = intString.charAt(i);if (current == '拾') {result.add("ten");} else if (current == '佰') {result.add("hundred");} else if (current == '仟') {result.add("thousand");} else if (current == '万') {result.add("ten_thousand");} else if (current == '亿') {result.add("ten_million");} else {result.add(String.valueOf(current));}}return result;}private static final char[] NUM = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};private static final char[] CHINESE_UNIT = {'元', '拾', '佰', '仟', '万', '拾', '佰', '仟', '亿', '拾', '佰', '仟'};/*** 返回关于钱的中文式大写数字,支仅持到亿,超过亿则需要使用长整型long*/public static String readLong(long moneyNum) {long mMoneyNum = moneyNum;String res = "";int i = 0;if (moneyNum == 0) {return "0";}if (moneyNum == 10) {return "拾";}if (moneyNum > 10 && moneyNum < 20) {return "拾" + moneyNum % 10;}while (moneyNum > 0) {res = CHINESE_UNIT[i++] + res;res = NUM[(int) (moneyNum % 10)] + res;moneyNum /= 10;}/*** replaceAll() 方法使用给定的参数 replacement 替换字符串所有匹配给定的正则表达式的子字符串。* 参数* 第一个参数:regex -- 匹配此字符串的正则表达式。* 第二个参数:newChar -- 用来替换每个匹配项的字符串。* 成功则返回替换的字符串,失败则返回原始字符串。*/if (mMoneyNum >= 100000000) {//整亿if (mMoneyNum % 100000000 == 0) {return res.replaceAll("0[拾佰仟万]", "0").replaceAll("0+亿", "亿").replaceAll("0+万", "万").replaceAll("0+元", "元").replaceAll("0+", "0").replace("元", "");} else {//非整亿,有万位或者千位(这里万位包括万、十万、百万、千万位)String a = String.valueOf(mMoneyNum);LogUtils.e("原始数据--》" + a);LogUtils.e("截取万位--》" + a.substring(a.length() - 8, a.length() - 4));if (Long.parseLong(String.valueOf(mMoneyNum).substring(String.valueOf(mMoneyNum).length() - 8, String.valueOf(mMoneyNum).length() - 4)) == 0) {//万位为全部为0的情况,例如 1500002000.00 此情况不需要读出 万,直接读一十五亿零二千元return res.replaceAll("0[拾佰仟]", "0").replaceAll("0+亿", "亿").replaceAll("0+万", "0").replaceAll("0+元", "元").replaceAll("0+", "0").replace("元", "");} else {//万位为不为0的情况,例如  1520002000.00 此情况需要读出 万,读一十五亿二千万二千元return res.replaceAll("0[拾佰仟]", "0").replaceAll("0+亿", "亿").replaceAll("0+万", "万").replaceAll("0+元", "元").replaceAll("0+", "0").replace("元", "");}}} else {//小于一亿return res.replaceAll("0[拾佰仟]", "0").replaceAll("0+亿", "亿").replaceAll("0+万", "万").replaceAll("0+元", "元").replaceAll("0+", "0").replace("元", "");}}}

四、新建assets文件夹,把音频文件放在assets目录下

此demo可支持到千亿播放,对播放的语序也进行了一些处理,但是可能还有些许情况没有考虑到,需要使用的朋友可以按自己的需求自行添加

新添加内容:

最近接到反馈,说语音播报的速度太慢,跟一个老大爷一样,所以在处方面做了优化。此处没有使用Android自带的播放器,而是使用Google支持的第三方的播放器ExoPlayer ,需要了解ExoPlayer 可到这个网址了解,https://google.github.io/ExoPlayer/

ExoPlayer gitgub地址https://github.com/google/ExoPlayer

下面直接贴出代码,新的代码只是一个方法,替换之前的播报方法即可,或者根据需求使用两者中的其中一个即可。

private ConcatenatingMediaSource mConcatenatingMediaSource;private List<MediaSource> mMediaSourceList;
private void exoPlayerStart(final List<String> list) {synchronized (this){if (mMediaSourceList == null) {mMediaSourceList = new ArrayList<>();}mMediaSourceList.clear();final CountDownLatch latch = new CountDownLatch(1);//并发DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(CardDoctorApplication.getInstance().getContext(),Util.getUserAgent(CardDoctorApplication.getInstance().getContext(), "CardDoctor"));final SimpleExoPlayer mPlayer = ExoPlayerFactory.newSimpleInstance(CardDoctorApplication.getInstance().getContext());for (int i = 0; i < list.size(); i++) {MediaSource mediaSource = new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(FileUtils.getAssetsPath(String.format("sound/tts_%s.mp3", list.get(i)))));mMediaSourceList.add(mediaSource);}switch (mMediaSourceList.size()) {case 1:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0));break;case 2:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1));break;case 3:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2));break;case 4:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3));break;case 5:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4));break;case 6:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5));break;case 7:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6));break;case 8:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7));break;case 9:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8));break;case 10:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9));break;case 11:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10));break;case 12:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11));break;case 13:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12));break;case 14:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13));break;case 15:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14));break;case 16:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15));break;case 17:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),mMediaSourceList.get(16));break;case 18:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),mMediaSourceList.get(16), mMediaSourceList.get(17));break;case 19:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18));break;case 20:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19));break;case 21:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19),mMediaSourceList.get(20));break;case 22:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19), mMediaSourceList.get(20),mMediaSourceList.get(21));break;case 23:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19), mMediaSourceList.get(20), mMediaSourceList.get(21),mMediaSourceList.get(22));break;case 24:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19),mMediaSourceList.get(20), mMediaSourceList.get(21),mMediaSourceList.get(22), mMediaSourceList.get(23));break;case 25:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19),mMediaSourceList.get(20), mMediaSourceList.get(21),mMediaSourceList.get(22), mMediaSourceList.get(23),mMediaSourceList.get(24));break;case 26:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19),mMediaSourceList.get(20), mMediaSourceList.get(21),mMediaSourceList.get(22), mMediaSourceList.get(23),mMediaSourceList.get(24),mMediaSourceList.get(25));break;case 27:mConcatenatingMediaSource = new ConcatenatingMediaSource(mMediaSourceList.get(0), mMediaSourceList.get(1), mMediaSourceList.get(2), mMediaSourceList.get(3),mMediaSourceList.get(4), mMediaSourceList.get(5), mMediaSourceList.get(6), mMediaSourceList.get(7), mMediaSourceList.get(8), mMediaSourceList.get(9),mMediaSourceList.get(10), mMediaSourceList.get(11), mMediaSourceList.get(12), mMediaSourceList.get(13), mMediaSourceList.get(14), mMediaSourceList.get(15),mMediaSourceList.get(16), mMediaSourceList.get(17), mMediaSourceList.get(18), mMediaSourceList.get(19),mMediaSourceList.get(20), mMediaSourceList.get(21),mMediaSourceList.get(22), mMediaSourceList.get(23),mMediaSourceList.get(24),mMediaSourceList.get(25),mMediaSourceList.get(26));break;default:break;}mPlayer.addListener(new Player.EventListener() {@Overridepublic void onPlayerStateChanged(boolean playWhenReady, int playbackState) {if (playbackState == 4) {mPlayer.release();latch.countDown();}}@Overridepublic void onPlayerError(ExoPlaybackException error) {mPlayer.release();latch.countDown();}});mPlayer.prepare(mConcatenatingMediaSource);mPlayer.setPlayWhenReady(true);try {latch.await();this.notifyAll();} catch (InterruptedException e) {e.printStackTrace();}}}

最后附上播放的音频文件与以上代码https://download.csdn.net/download/freak_csh/10786233

github 项目https://github.com/freakcsh/VoiceDemo.git 此项目还接入了百度语音的demo,还有极光推送,但是极光被我干掉了,使用不了。

语音播报(播报本地音频文件)实现收款金额的播报相关推荐

  1. TextToSpeech文字转语音、文字转音频文件并播放

    TextToSpeech文字转语音.文字转音频文件并播放 前段时间遇到了语音读网页的需求,特地在网上找了一些资料.学习完毕后跟大家分享一下.这里是我从项目中抽取出来的代码,大家应该也基本能看清楚流程了 ...

  2. iOS 用 AVPlayer 播放一个本地音频文件

    iOS 用 AVPlayer 播放一个本地音频文件 步骤 第一步:在 Project - TARGETS - Project名 - Build Phases - Link Binary With Li ...

  3. iOS Dev (21) 用 AVPlayer 播放一个本地音频文件

    iOS Dev (21) 用 AVPlayer 播放一个本地音频文件 作者:CSDN 大锐哥 博客:http://blog.csdn.net/prevention 前言 这篇文章与上一篇极其相似,要注 ...

  4. 语音转文字和音频文件转文字应该如何完成

    手机自带的语音转文字功能,目前只能支持实时语音转文字,app相对比较全面,还支持音频文件转文字.那么,音频转文字如果操作呢? 1) 首先我们在手机应用市场找到:录音转文字助手,部份手机需要在百度浏览器 ...

  5. android 微信播放语音文件,如何将微信语音导出为MP3音频文件-Android平台

    本文对于安卓用户,提供了一种相对快捷的方法. ---------以下为图文,请在本文最后点击"阅读原文"查看视频教程-------- ios平台下,导出微信语音只需要两个步骤:使用 ...

  6. Android播放本地音频文件

    准备 音频文件置于res/raw文件夹下: 实现 /** * 监听系统静音模式 * @param mContext */ private void modeIndicater(Context mCon ...

  7. 将本地音频文件上传到微信公众号服务器获得文件media_id

    第一步:获得微信的实时令牌token 我是通过spring cloud微服务通过注册中心映射到微信项目获得的token @FeignClient(value = "weixin-token- ...

  8. ajax上传本地音频文件,使用ajax将音频blob上传到文件夹中

    我正在构建一个录音项目,我想通过blob将音频上传到文件夹(上传). 这是我迄今取得的成就: var url = URL.createObjectURL(blob); var li = documen ...

  9. js处理本地.bin音频文件和node.js的fs模块处理本地.bin音频区别

    1.js处理本地.bin文件 <body><input type="file" name="" id="fileInput" ...

最新文章

  1. struts练习-表单提交
  2. linux ftp 怎么验证,Linux编译安装vsftpd服务器(本地用户验证方式)
  3. python插入排序_从Python看排序:插入排序
  4. C# 控件双缓冲控制 ControlStyles 枚举详解
  5. comsol 多物理场仿真流程-以开关柜为例
  6. java servlet 配置_servlet与javabean配置
  7. raft算法_学习分布式一致性协议:自己实现一个Raft算法
  8. 如何攻克 Android 调试难题?| 技术头条
  9. 嵌入式软件设计第11次实验报告
  10. 给model模型传数组参数
  11. 实例讲解木马的分析方法
  12. PCAN监测can总线状态设置
  13. JavaOOP项目 - 嗖嗖移动业务大厅
  14. 机器视觉1:图像预处理与瑕疵检测
  15. 查看电脑重启日志_win10中查看开关机时间及查看admin的RID的方法
  16. 当上技术领导以后才明白的事情
  17. 视频的编码与传输过程
  18. 如何配置SQL AgentMail与SQL Mail收发邮件
  19. java lang ClassCastException java lang Integer cannot be ca
  20. 阿里云对象存储OSS标准型(LRS)存储包详解

热门文章

  1. 贪吃蛇c语言经典程序下载,C语言实现贪吃蛇游戏(单人版)
  2. 项目中JS脚本的执行方式
  3. 佳能Canon PIXMA iP6000D 打印机驱动
  4. 关于STM32软硬件兼容性相关的知识
  5. 阿里妈妈技术质量再度重磅开源:国内首个智能化功能测试开源平台Markov
  6. YouTube图片幻灯片分享技巧
  7. java毕业设计软件源代码]springMVC+mysql实现进销存系统仓库管理系统
  8. bcd 初始化库系统卷失败_U盘多系统启动制作教程 教你做多U盘系统启动盘
  9. 关于S32K148LQFP144时钟配置的问题
  10. 微信内置浏览器的JsAPI(WeixinJSBridge续)