TTS源碼解析

TTS全稱爲“TextToSpeech”,是Android原生在文本轉語音服務。本文將從TTS使用過程,對TTS源碼進行分析。

主要涉及的源碼有:

framework\base\core\java\android\speech\tts\TextToSpeech.java

framework\base/core\java/android\speech\tts\TextToSpeechService.java

external\svox\pico\src\com\svox\pico\PicoService.java

external\svox\pico\compat\src\com\android\tts\compat\CompatTtsService.java

external\svox\pico\compat\src\com\android\tts\compat\SynthProxy.java

external\svox\pico\compat\jni\com_android_tts_compat_SynthProxy.cpp

external\svox\pico\tts\com_svox_picottsengine.cpp

1、TTS初始化

首先來看TextToSpeech的構造函數


緊接着執行initTts操作,初始化TTS:



首先連接到用戶請求的tts引擎服務,接着是默認引擎,最後是高性能引擎,從代碼可以看出高性能引擎優先級最高,默認引擎其次。連接代碼如下:



Engine.INTENT_ACTION_TTS_SERVICE的值爲"android.intent.action.TTS_SERVICE";其連接到的服務爲action爲"android.intent.action.TTS_SERVICE"的服務,在external\svox\pico目錄中的AndroidManifest.xml文件可以發現:


所以可以得到這裏連接到的服務就是PicoService,其具體代碼如下:其繼承於CompatTtsService。



我們再來看看CompatTtsService這個類,這個類爲抽象類,它的父類爲TextToSpeechService,其有一個成員SynthProxy類,該類負責調用TTS的C++層代碼。



我們來看看CompatTtsService的onCreate()方法,該方法中主要對SynthProxy進行了初始化



我們緊接着看看SynthProxy的構造函數都幹了什麼,我也不知道幹了什麼,但是裏面有個靜態代碼塊,其加載了ttscompat動態庫,所以它肯定只是一個代理,實際功能由C++本地方法實現

在構造函數中,調用了native_setup方法來初始化引擎,其實現在C++層(com_android_tts_compat_SynthProxy.cpp)。代碼如下:

上面紅線init方法在com_svox_picottsengine.cpp中:



至此,TTS引擎的初始化就完成了,接下來分析TTS的調用。

2、TTS的調用

我們在應用層一般調用TextToSpeech中的speak()方法,我們來看看其執行流程:


接着調用runAction():


然後調用mServiceConnection中的runAction方法,其具體代碼如下:


可以發現最後會回調action.run(mService)方法。接着執行service.playAudio();這裏的service爲PicoService,其繼承於抽象類CompatTtsService,而CompatTtsService繼承於抽象類TextToSpeechService.所以會執行TextToSpeechService中的playAudio(),該方法位於TextToSpeechService中mBinder中。該方法如下:



接着執行mSynthHandler.enqueueSpeechItem(queueMode, item),其代碼如下:



我們主要看speechItem.play()該方法在Speechitem類中,其爲TextToSpeechService內部類



在TextToSpeechService中的playAudio()中代碼可以知道這裏的speechitem爲SynthesisSpeechItemV1。因此在play中執行的playimpl()方法爲SynthesisSpeechItemV1類中的playimpl()方法,其代碼如下:



在playImpl方法中會執行onSynthesizeText方法,這是個抽象方法,記住其傳遞了一個synthesisCallback,後面會講到。哪該方法具體實現是在哪裏呢,沒錯,就是在TextToSpeechService的子類CompatTtsService中。來看看它怎麼實現的:


mNativeSynth爲SynthProxy的一個對象,之前說了他是一個代理類,他的speak方法如下:



看到沒?什麼都沒做,就是調用native_speak方法,看它的名字就知道是一個本地方法,那麼該方法又是在哪實現呢?就是在com_android_tts_compat_SynthProxy.cpp中,該文件中有下面的映射數組(只截取了一部分):

java中對應的native_speak方法對應的C++層代碼方法爲com_android_tts_compat_SynthProxy_speak方法,接下來來看看該方法是怎麼實現的:


該方法中調用了TTS引擎中的synthesizeText方法,那麼該方法是怎麼實現的呢?該方法位於com_svox_picottsengine.cpp中,主要代碼(代碼太長,只貼部分)如下:



其中picoSynthDoneCBPtr()爲回調函數,其爲TTS初始化過程傳入的:


而TTS的init初始化在native_setup中被調用


那麼__ttsSynthDoneCB又是什麼呢?其實現如下:


callRequestAudioAvailable()方法如下:


這個地方調用env->CallIntMethod()方法,在C++層調用java方法,那麼這個方法在哪呢?這裏的env就是之前說的synthesisCallback,synthesisCallback爲PlaybackSynthesisCallback類的對象,那麼將會執行PlaybackSynthesisCallback中的audioAvailable()


至此,TTS的調用就結束了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章