Android TTS(TextToSpeech)实践

一、介绍   

        TextToSpeech:将文本合成语音,立即播放或创建声音文件。

        最简单的流程如下:

        1.创建TextToSpeech后,它会找到一个适合的Engine进行连接,然后回调onInit,如果status不为0,则没有找到引擎。

        2.在初始化成功后,调用speak就可以进行语音播报了。播报过程中,引擎会调用UtteranceProgressListener的回调函数,它是个抽象类,可以覆盖其他函数,如onRangeStart(String utteranceId, int start, int end, int frame) 可以在播报过程中可以拿到实时返回的读取字符位置,但它是在api 26以后才开始支持。

        简单的TTS语音播报代码如下: 

if (textToSpeech == null) {
    textToSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
        @Override
        public void onInit(int status) {
            textToSpeech.speak("你好,测试语音播报功能", TextToSpeech.QUEUE_ADD, null);
            textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
                @Override
                public void onStart(String utteranceId) {
                }

                @Override
                public void onDone(String utteranceId) {
                }

                @Override
                public void onError(String utteranceId) {
                }
            });
        }
    });
}

在实际场景中,可能会遇到以下问题需要抉择(尤其是在做海外市场)

        1.支持引擎(引擎查询和设置) 

        2.支持语言(语言支持和下载)

        3.版本兼容问题(回调版本支持)

        接下来分别进行介绍。

二、实践-引擎

        1.引擎是TTS核心部分,主要用于加载语言语音包,将文本转换为音频,及执行回调的部分。引擎的实现,需要继承TextToSpeechService,并且需要对以下方法进行实现:

protected abstract int onIsLanguageAvailable(String lang, String country, String variant)

protected abstract String[] onGetLanguage()

protected abstract int onLoadLanguage(String lang, String country, String variant)

protected abstract void onStop()

protected abstract void onSynthesizeText(SynthesisRequest request, SynthesisCallback callback)

 详细的原理这里不进行讲解,可以参考下面两篇文章,讲的很详细:

        https://blog.csdn.net/qq_30359699/article/details/105388575        

        https://blog.csdn.net/zhupumao/article/details/78960456

首先,虽然列出了要实现TextToSpeechService的方法,但我们如果只使用系统提供的引擎,则不需要自己继承TextToSpeechService并实现以上方法,但需要知道的是:

        1.是否支持语言,支持语言列表及加载语言包:分别是onIsLanguageAvailable,onGetLanguage和onLoadLanguage

        2.进行文本合成语音,需要在onSynthesizeText中实现,对应的回调也需要在方法中调用SynthesisCallback的方法

        3.onStop停止语音合成

        4.因为引擎是自定义实现的,所以会有自己的语言语音包来支持不同的国家语言(如果做海外市场要注意,引擎是否支持对应国家的语言),这些语言语音包依赖于引擎提供方是否提供

        5.需要在AndroidManifest中,在自己的Service中,加入如下配置:

<intent-filter>

    <action android:name="android.intent.action.TTS_SERVICE" />

    <category android:name="android.intent.category.DEFAULT" />

</intent-filter>

 说了这么多,如果使用系统的引擎,则可以忽略这部分内容,但对理解有帮助。

        2.引擎支持,通常在不同品牌设备上,语音引擎可能有多个,并且都是系统级别的,如三星有GoogleTTSService和SamsungTTSService等,这个时候不选择引擎时,很有可能使用的是SamsungTTSService。这里我写了个获取引擎列表的方法如下:

public List<String> getEngines() {
    if (mContext == null) {
        throw new IllegalArgumentException("Please set mContext first!!");
    }
    ArrayList<String> engines = new ArrayList<>();
    PackageManager pm = mContext.getPackageManager();
    Intent intent = new Intent(TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE);
    List<ResolveInfo> resolveInfo =     pm.queryIntentServices(intent,PackageManager.MATCH_DEFAULT_ONLY);
    for (ResolveInfo info: resolveInfo) {
        engines.add(info.serviceInfo.packageName);
    }
    return engines;
}

         可以看到,主要是通过action:TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE来进行查询(自定义引擎的Service也必须设置action为TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE)。

        而最终得到的,是所有继承TextToSpeechService实现引擎的包名列表,当使用指定引擎时,TextToSpeech会通过包名和action绑定到Service上。

        好,不出意外的话,会包含google系统引擎的包名,“com.google.android.tts”,后面说到引擎时,都是继承了TextToSpeechService并实现了语音合成的包名。

        3.有了引擎,我们在使用TextToSpeech的时候,就可以使用TextToSpeech(Context context, OnInitListener listener, String engine) 来连接到指定引擎了。

三、实践-Locale

        Locale包含了语言,国家和多样性等信息,但并不全包含这些信息,如果使TextToSpeech播放不同国家的语言时,这时需要设置Locale给它。但TextToSpeech一定会播放吗,不一定,需要看引擎是否支持,必定真正工作的是引擎对应的Service。那么看下图:

文本输入给引擎之前,引擎需要加载语言语音包,如果支持指定的语言,则可以输出音频数据进行播放或写入文件,同时会执行回调。那么问题来了,如何知道引擎是否支持语言音乐包,如果不支持,如何下载?

那么问题可以总结如下:

        1.查询引擎目前支持的语言语音包(引擎和语言音乐包是绑定的)

        2.判断指定Locale是否支持

        3.下载语言语音包

        接下来分别介绍。

3.1查询引擎目前支持的语言语音包:

        1).系统方式

        2).使用TextToSpeech方式(指定引擎)

3.1.1系统方式:

分为两部,1.发送Intent给系统 2.在当前activity中接收和解析结果

        发送Intent给系统        

    Intent checkIntent = new Intent();
	checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
	checkIntent.setPackage(engine);
	activity.startActivityForResult(checkIntent, CHECK_REQUEST_CODE);

        在当前activity中接收和解析结果(在onActivityResult中调用下面的方法获取Locale列表)

	public List<Locale> checkSupportTTSLocale(int requestCode,  int resultCode, Intent data) {
        ArrayList<Locale> locales = new ArrayList<>();
        if (requestCode == CHECK_REQUEST_CODE && resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS && data != null) {
            ArrayList<String> availableVoices = data.getStringArrayListExtra(TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES);
            if (availableVoices != null && availableVoices.size() > 0) {
                for (String voice: availableVoices) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        String[] split = voice.split("-");
                        if (split.length > 0) {
                            Locale locale = split.length == 1 ? new Locale(split[0]) : (split.length == 2 ? new Locale(split[0], split[1]): new Locale(split[0], split[1], split[2]));
                            locales.add(locale);
                        }
                    }
                }
            }
        }
        return locales;
    }

3.1.2使用TextToSpeech方式

	public List<Locale> getSupportLocales() {
        ArrayList<Locale> locales = new ArrayList<>();
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            Set<Voice> voiceSet = textToSpeech.getVoices();
            for (Voice voice: voiceSet) {
                locales.add(voice.getLocale());
            }
        }
        return locales;
    }

       

        重要:前提是textToSpeech指定了引擎,如textToSpeech = new TextToSpeech(context, listener, “com.google.android.tts”),查询到是“com.google.android.tts”支持的语音语音包对应的Locale列表。

3.2 判断指定Locale是否支持

        通过之前的描述应该了解,Locale在不同引擎支持的情况不一样,且对应的语言语音包和引擎是绑定的,所以判断是否支持Locale可以通过TextToSpeech进行判断,通过下面两个方法都可以判断:        

	TextToSpeech.setLanguage(Locale)
	TextToSpeech.isLanguageAvailable(Locale)

3.3 下载语言语音包

        当引擎暂不支持指定语言音乐包时,可以通过下载语言音乐包进行支持(若没有语言语音包就没办法了,不过google支持还是挺全的,其它引擎就不一定了)。

使用google系统引擎下载语言音乐包实现如下:

    Intent installIntent = new Intent();
    installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
    installIntent.setPackage(engine);
    activity.startActivityForResult(installIntent, INSTALL_REQUEST_CODE);

        在系统页面下载完成之后,返回当前activity后,在onActivityResult中并不能查询到安装结果,还是需要3.1方式进行查询。

四、回调和部分方法

1.TextToSpeech.setOnUtteranceProgressListener(UtteranceProgressListener listener)

UtteranceProgressListener
	//API 15
	-public abstract void onStart(String utteranceId)
	//API 15		
	-public abstract void onDone(String utteranceId)
	//API 15		
	-public abstract void onError(String utteranceId)	
	//API 23	
	-public void onStop(String utteranceId, boolean interrupted)	
	//API 24	
	-public void onBeginSynthesis(String utteranceId, int sampleRateInHz, int audioFormat, int channelCount)
	//API 24		
	-public void onAudioAvailable(String utteranceId, byte[] audio)		
	//API 26
	-public void onRangeStart(String utteranceId, int start, int end, int frame)

        虽然回调方法不少,但如果是使用google引擎则注意兼容版本(国内实现的引擎应该比较完善,目前看到华为是支持类似onRangeStart的方法,这个方法能够实现实时单词高亮效果等)

2.设置语音属性

    //设置音调高低,函数没有明确说明范围,我测试的范围0.5-3.0
    setPitch(float pitch) 
    //设置语速,函数没有明确说明范围,我测试的范围0.5-3.0
    setSpeechRate(float speechRate)

        这两个方法调用并不是实时生效,下次调用speak时才会生效

3.周期方法

    //设置文本给引擎进行播报		
	speek	
	//停止语音播报
	stop
	//关闭引擎
	shutdown

        没有pause和resume,如果自己实现,建议在speek时进行分句操作。

五、总结

下面对调用进行总结:

        1.查询引擎列表,使用需要的引擎实例化TextToSpeech

        2.查询语言语音列表,如果不支持,可以通过系统方法(三方实现的调用三方下载语言语音包方法)进行安装

        3.设置语言语音包给引擎

        4.使用speak进行语音播报,可以在对应的回调中处理逻辑,但要注意支持API版本

        5.使用完成时候记得shutdown释放资源

赋大概的时序图如下:

下面是参考的文档和可以参考的资源:

参考:

Android Speech之TTS(文本到语音)源码及流程分析_奔腾的小马-CSDN博客

TTS源码解析_zhupumao的博客-CSDN博客_tts文件解析错误

google例子:

https://android.googlesource.com/platform/development/+/master/samples/TtsEngine?autodive=0

github上高星地址:

https://github.com/ak1394/react-native-tts

https://github.com/gotev/android-speech

https://github.com/HMS-Core/hms-ml-demo

https://github.com/happyalu/Flite-TTS-Engine-for-Android

 

 注:如有错误或探讨的地方,欢迎大家留言哈。

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值