语音转文字功能在安卓里面也是一个很可能用到的,虽然谷歌提供了系统自带的 TTS 功能,但是貌似很多手机厂商为了精简 ROM 把中文去掉了(以前),之前还能安装个什么讯飞语记(或其他)的软件支持一下,后面软件也不行了,并且原本免费的讯飞语音 sdk 也要付费了,很坑。

ps. 我又看了一眼手机,我的荣耀10居然只有讯飞语音引擎了,支持中文了,我记得以前还可以改成 PicoTTS 的 ,可能是手机厂商进步了,不需要控制 ROM 大小了,应该很多手机都可以默认使用系统的中文 TTS 了。

下面介绍我使用的几种办法:

系统自带 TTS

在 activity 中使用方法如下,记得销毁对象:

    private TextToSpeech mTextToSpeech;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//初始化mTextToSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() {@Overridepublic void onInit(int status) {if (status == TextToSpeech.SUCCESS) {//设置朗读语言int supported = mTextToSpeech.setLanguage(Locale.CHINESE);if ((supported != TextToSpeech.LANG_AVAILABLE)&&(supported != TextToSpeech.LANG_COUNTRY_AVAILABLE)) {Toast.makeText(sAppContext, "不支持当前语言!", Toast.LENGTH_SHORT).show();}}}});//播放语音mTextToSpeech.speak("hello world!", TextToSpeech.QUEUE_FLUSH, null);}@Overrideprotected void onDestroy() {if (mTextToSpeech != null) {mTextToSpeech.stop();mTextToSpeech.shutdown();mTextToSpeech = null;}super.onDestroy();}

下面是使用时的参数介绍:

public int speak(final String text, final int queueMode, final HashMap<String, String> params) {  return runAction(new Action<Integer>()
  • text 需要转成语音的文字
  • queueMode 队列方式:
    QUEUE_ADD:播放完之前的语音任务后才播报本次内容
    QUEUE_FLUSH:丢弃之前的播报任务,立即播报本次内容
  • params 设置TTS参数,可以是null。
    KEY_PARAM_STREAM:音频通道,可以是:STREAM_MUSIC、STREAM_NOTIFICATION、STREAM_RING等
    KEY_PARAM_VOLUME:音量大小,0-1f
  • 返回值:int SUCCESS = 0,int ERROR = -1。

讯飞语音集成

讯飞语音集成要钱了,有兴趣可以看看下面这篇文章或者官网介绍:

https://blog.csdn.net/ysc332606387/article/details/78917949

使用 SoundPool 播放音频文件

之前项目有个语音报值的功能,就是播放 0 - 100 的语音,本来是想用 TTS 的,可是客户的大部分手机没有中文没法用,想想要播放的语音也不多,还不如直接用文件播放算了。后面就随便找了个生成语音的 PC 软件(很不好意思前几天删除了,可以直接网上搜文字转语音软件),生成格式为 wav,质量选择还可以的,可以自己试试,有的可能没法再安卓上播放。

有了资源后,就是播放了,一开始用音乐播放器,真是傻了,后面换成 SoundPool,下面看封装的一个类:

public class AudioManager {@SuppressLint("StaticFieldLeak")private volatile static AudioManager mConnectManager = null;private final Context context;private SoundPool soundPool;private AudioManager(Context context) {this.context = context;initPoolVoice();}//DCLpublic static AudioManager getInstance(Context context) {if (mConnectManager == null) {synchronized (AudioManager.class) {if (mConnectManager == null) {mConnectManager = new AudioManager(context);}}}return mConnectManager;}//初始化private void initPoolVoice(){//sdk版本21是SoundPool 的一个分水岭if (Build.VERSION.SDK_INT >= 21) {SoundPool.Builder builder = new SoundPool.Builder();//传入最多播放音频数量,builder.setMaxStreams(1);//AudioAttributes是一个封装音频各种属性的方法AudioAttributes.Builder attrBuilder = new AudioAttributes.Builder();//设置音频流的合适的属性attrBuilder.setLegacyStreamType(android.media.AudioManager.STREAM_MUSIC);//加载一个AudioAttributesbuilder.setAudioAttributes(attrBuilder.build());soundPool = builder.build();} else {/*** 第一个参数:int maxStreams:SoundPool对象的最大并发流数* 第二个参数:int streamType:AudioManager中描述的音频流类型* 第三个参数:int srcQuality:采样率转换器的质量。 目前没有效果。 使用0作为默认值。*/soundPool = new SoundPool(1, android.media.AudioManager.STREAM_MUSIC, 0);}}//根据numb播放音频public void playPoolVoice(final int numb){try {//可以通过四种途径来记载一个音频资源://1.通过一个AssetFileDescriptor对象//int load(AssetFileDescriptor afd, int priority) //2.通过一个资源ID//int load(Context context, int resId, int priority) //3.通过指定的路径加载//int load(String path, int priority) //4.通过FileDescriptor加载//int load(FileDescriptor fd, long offset, long length, int priority) //声音ID 加载音频资源,这里用的是第二种,第三个参数为priority,声音的优先级*API中指出,priority参数目前没有效果,建议设置为1。final int voiceId = soundPool.load(context, getVoiceId(numb), 1);//异步需要等待加载完成,音频才能播放成功soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {@Overridepublic void onLoadComplete(SoundPool soundPool, int sampleId, int status) {if (status == 0) {//第一个参数soundID//第二个参数leftVolume为左侧音量值(范围= 0.0到1.0)//第三个参数rightVolume为右的音量值(范围= 0.0到1.0)//第四个参数priority 为流的优先级,值越大优先级高,影响当同时播放数量超出了最大支持数时SoundPool对该流的处理//第五个参数loop 为音频重复播放次数,0为值播放一次,-1为无限循环,其他值为播放loop+1次//第六个参数 rate为播放的速率,范围0.5-2.0(0.5为一半速率,1.0为正常速率,2.0为两倍速率)soundPool.play(voiceId, 1, 1, 1, 0, 1);}}});}catch (Exception e) {//很奇怪voiceId会错乱,可能是资源加载问题e.printStackTrace();}}//根据numb找到音频资源文件private int getVoiceId(int numb) {try {int id=0;ApplicationInfo appInfo = MyApplication.getContext().getApplicationInfo();id = MyApplication.getContext().getResources().getIdentifier("y" + numb, "raw", appInfo.packageName);return id;}catch (Exception e){return R.raw.y0;}}}

下面是使用:

AudioManager.getInstance(application).playPoolVoice(power);

注意一下我这里的文件保存在 raw 文件夹里面,格式是 y66.wav,因为不能以数字开头。

这里参考了这篇博客,下面是 SoundPool 相对于 MediaPlayer 的优点

  1. SoundPool 适合 短且对反应速度比较高 的情况(游戏音效或按键声等),文件大小一般控制在几十K到几百K,最好不超过1M,

  2. SoundPool 可以与 MediaPlayer 同时播放,SoundPool 可以同时播放多个声音;

  3. SoundPool 最终编解码实现与 MediaPlayer 相同;

  4. MediaPlayer 只能同时播放一个声音,加载文件有一定的时间,适合文件比较大,响应时间要是那种不是非常高的场景

结语

这里介绍了三种办法,其中讯飞 SDK 需要付费,但是功能会更多,系统自带的 TTS 可能无法支持中文,比较麻烦,最后通过 SoundPool 播放音频适合播放频率较高,但是文件不是很多的情况,看读者需要吧!

end

语音播报功能的几种实现办法(包含TTS)相关推荐

  1. 实现百度地图导航Demo的语音播报功能

    上文中实现了在本地导入百度地图导航Demo,那么在此基础上如何实现导航的语音播报呢? 一.为该应用申请语音播报(也叫注册) http://developer.baidu.com/map/index.p ...

  2. iOS 后台语音播报功能开发过程中的那些坑

      上个版本的开发计划中产品同学建议在我们的商家版App中做后台语音播报功能,在评审的时候我就在想,完全可以通过Push静默推送来实现后台播放音频来实现(后续事实证明,这是个大坑).   关于静默推送 ...

  3. php加入语音播报功能_PHP实现语音播报功能

    大家估计都知道现在很多AI音响能够给你播报天气,叫你起床...甚至能够接受语音指令!所谓的人工智能音响,听起来很高大上,都说PHP是最好的编程语言,今天我就带大家来实现一个语音播报功能!先大体说一个思 ...

  4. 前端实现语音播报功能

    近期接到需求,内容页中的文字要实现语音播报功能,语音生成已经存入数据库 var myAudio = new Audio(); //arr 中存放的是音频数据,数组的大小是不确定的 var arr = ...

  5. html5实现百度语音播报功能

    html5实现百度语音播报功能 总结 记录一下,html5调用百度语音接口实现语音播报功能,简单的完整案例 <!DOCTYPE html> <html> <head> ...

  6. APP收款语音播报功能讲解

    一.背景 比起主动扫码能确定收款多少与是否到账,扫二维码支付场景不能直接确认,需要核对客户付款截屏,目前微信.支付宝在扫二维码支付后,均支持收款方自动播报收款到账信息,为了秦丝APP有更好体验,也需要 ...

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

    推荐阅读: SurfaceView+MediaPlayer封装之路 Android学习资源分享合集(1) 最近写了一个金额的语音播报功能,已封装成依赖库到Github,希望对大家有所帮助. Githu ...

  8. 一定要了解的小常识:聚合支付有语音播报功能

    在大部分商机都是使用聚合支付收款,他们在营业收款时都十分需要语音播报,这样可以让他们的收款效率大大提高,那么聚合支付有语音播报功能吗?该怎么去开通呢? 聚合支付二维码:从一柜多码到一柜一码 以往,商家 ...

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

    推荐阅读: SurfaceView+MediaPlayer封装之路 Android学习资源分享合集(1) 最近写了一个金额的语音播报功能,已封装成依赖库到Github,希望对大家有所帮助. Githu ...

最新文章

  1. ChineseCalendar类[转]
  2. Qt 自定义信号与槽
  3. 区域链 信息存储的服务器,利用区块链储存明显优于传统的中心化服务器
  4. 【LeetCode】LeetCode之跳跃游戏Ⅱ——暴力解法+动态规划+贪婪算法
  5. 数据处理之判断值是否为nan(空值)记录
  6. PageHelper分页插件的原理是什么
  7. 不染用计算机数字,2013年计算机等级考试一级B知识预测题(6)
  8. 运行python嵌入式要求_在嵌入式IPython实例中运行配置文件启动文件
  9. centec交换机配置_盛科(Centec)交换机 SmartConfig 特性
  10. initrd in linux 2.6.32.27
  11. matlab读取adtx文件,求大家帮我看看下面中matlab中的程序问题出在哪里? - 计算模拟 - 小木虫 - 学术 科研 互动社区...
  12. chrome浏览器加载css、js等静态资源文件的坑
  13. Linux四剑客详解——grep
  14. 小爱mini改aux立体声_拆解报告:Redmi小爱音箱Play
  15. Java代码混淆技术选型
  16. 【嵌入式】基于SPI的M8266WIFI模块调试
  17. 【Android -- 技术周刊】第 021 期
  18. JavaScript 设计模式之模板方法模式
  19. 《畅玩NAS》 使用树莓派打造一个NAS服务器
  20. Vant_根据已有地址获取code

热门文章

  1. 用铸造涂料中的消泡剂消除泡沫能对生产能起到哪些作用?
  2. 计算机硬件系统 — 冯诺依曼体系结构运行原理解析
  3. 计算机可以不用电脑编程吗,围棋也能学编程?不用电脑就能玩的编程玩具!
  4. python 3.6 + robotFramework自动化框架 环境搭建、学习笔记
  5. 基于摄像头的车道线检测方法一览
  6. Linux根目录下的目录介绍
  7. 马克思主义基本原理期末复习
  8. 阿里P8推荐的10本Java实战书籍,Java开发进阶必备书单
  9. 2021-2027全球与中国混合聚合物电容器市场现状及未来发展趋势
  10. python打印数据时,出现省略号,解决办法