最近项目需要实现语音播报收款金额,本来要使用百度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 list){
if (service != null){
service.execute(new Runnable() {
@Override
public void run() {
start(list);
}
});
}
}
/**
* 开始播放
* @param list
*/
private void start(final List 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() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
/**
* 注册在回放期间到达媒体源末尾时要调用的回调。
*/
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public 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 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 gen() {
return genVoiceList();
}
private List createReadableNumList(String numString) {
List 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 genVoiceList() {
List 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 genReadableMoney(String numString) {
List result = new ArrayList<>();
if (!TextUtils.isEmpty(numString)) {
/**
* contains()返回TRUE时,该字符串中存在该字符
* 此处判断字符串是否包含小数点
*/
if (numString.contains(DOT)) {
String integerPart = numString.split("\\.")[0];
String decimalPart = numString.split("\\.")[1];
//整数部分
List intList = readIntPart(integerPart);
//小数点之后的部分
List decimalList = readDecimalPart(decimalPart);
result.addAll(intList);
if (!decimalList.isEmpty()) {
result.add("dot");
result.addAll(decimalList);
}
} else {
//int
result.addAll(readIntPart(numString));
}
}
return result;
}
/**
* 拆分小数点后面字符串
*
* @param decimalPart
* @return
*/
private List readDecimalPart(String decimalPart) {
List 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 readIntPart(String integerPart) {
List 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 ListmMediaSourceList;
private void exoPlayerStart(final Listlist) { 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() { @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { if (playbackState == 4) { mPlayer.release(); latch.countDown(); } } @Override public 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,还有极光推送,但是极光被我干掉了,使用不了。