TextToSpeech簡稱 TTS,是Android 1.6版本中比較重要的新功能。將所指定的文本轉成不一樣語言音頻輸出。它能夠方便的嵌入到遊戲或者應用程序中,加強用戶體驗。
在講解TTS API和將這項功能應用到你的實際項目中的方法以前,先對這套TTS引擎有個初步的瞭解。android
對TTS資源的大致瞭解:異步
TTS engine依託於當前Android Platform所支持的幾種主要的語言:English、French、German、Italian和Spanish五大語言(暫時沒有咱們偉大的中文,至少Google的科學家們尚未把中文玩到爐火純青的地步,先易後難也是理所固然。)TTS能夠將文本隨意的轉換成以上任意五種語言的語音輸出。與此同時,對於個別的語言版本將取決於不一樣的時區,例如:對於English,在TTS中能夠分別輸出美式和英式兩種不一樣的版本(由此看出Google的作事風格真夠細緻,而正由於如此估計Google不加入中文的另一種理由是中文的方言太多了)。electron
能支持如此龐大的數據量,TTS 引擎對於資源的優化採起預加載的方法。根據一系列的參數信息(參數的用法將在後邊有詳細的介紹)從庫中提取相應的資源,並加載到當前系統中。優化
儘管當前大部分加載有Android操做系統的設備都經過這套引擎來提供TTS功能,但因爲一些設備的存儲空間很是有限而影響到TTS沒法最大限度的發揮功能,算是當前的一個瓶頸。爲此,開發小組引入了檢測模塊,讓利用這項技術的應用程序或者遊戲針對於不一樣的設備能夠有相應的優化調整,從而避免因爲此項功能的限制,影響到整個應用程序的使用。比較穩妥的作法是讓用戶自行選擇是否有足夠的空間或者需求來加載此項資源,下邊給出一個標準的檢測方法:ui
Intent checkIntent = new Intent();
checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkIntent, MY_DATA_CHECK_CODE);
若是當前系統容許建立一個 「android.speech.tts.TextToSpeech」 的Object, 說明已經提供TTS功能的支持,將檢測返回結果中給出「 CHECK_VOICE_DATA_PASS 」 的標記。若是系統不支持這項功能,那麼用戶能夠選擇是否加載這項功能,從而讓設備支持輸出多國語言的語音功能「Multi-lingual Talking」。「ACTION_INSTALL_TTS_DATA」 intent將用戶引入Android market中的TTS下載界面。下載完成後將自動完成安裝,下邊是實現這一過程的完整代碼 (androidres.com) :this
private TextToSpeech mTts;
protected void onActivityResult(
int requestCode, int resultCode, Intent data) {
if (requestCode == MY_DATA_CHECK_CODE) {
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
// success, create the TTS instance
mTts = new TextToSpeech(this, this);
} else {
// missing data, install it
Intent installIntent = new Intent();
installIntent.setAction(
TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
}
}
}
TextToSpeech實體和OnInitListener都須要引用當前Activity的Context做爲構造參數。OnInitListener()的用處是通知系統當前TTS Engine已經加載完成,並處於可用狀態。spa
根據需求設置語言參數:操作系統
早在Google I/O大會上,官方給出了一段關於應用這項功能的鮮活體驗,將翻譯結果直接經過五種不一樣國家語言的語音輸出。加載語言的方法很是簡單:翻譯
mTts.setLanguage(Locale.US);
上邊代碼表示當前TTS實體加載美式英語。其參數並無指示某種語言的名稱,而是利用國家代碼來表示,這樣作的好處是不但能夠肯定語言的選擇,並且能夠根據地區的不一樣而有所區別。例如:英語做爲最普遍被應用的語種,在多個不一樣的地區都有必定的差異。判斷當前系統是否支持某個地區的語言資源,能夠經過調用isLanguageAvailable()方法的返回值,根據返回值的描述來選擇正確的處理方式。讓應用某些絢麗功能的應用程序更加健壯,這個是貫穿整個開發過程都要考慮的技術環節。下邊是一些應用實例 (androidres.com) :orm
mTts.isLanguageAvailable(Locale.UK))
mTts.isLanguageAvailable(Locale.FRANCE))
mTts.isLanguageAvailable(new Locale("spa", "ESP")))
若是返回值是 「 TextToSpeech.LANG_COUNTRY_AVAILABLE 」 說明所選擇的地區被包含在當前TTS系統中。若是系統中已經建立了TTS實體,那麼能夠利用isLanguageAvailable()方法來替代 Start 「ACTION_CHECK_TTS_DATA 」 intent 檢測。當沒法找到任何可用資源匹配所指定的參數時,將會返回 「 TextToSpeech.LANG_MISSING_DATA 」的結果。下邊給出另外兩個返回其它不一樣狀態信息的例子:
mTts.isLanguageAvailable(Locale.CANADA_FRENCH))
mTts.isLanguageAvailable(new Locale("spa"))
兩個語句的返回值均爲 「 TextToSpeech.LANG_AVAILABLE 」 。第一個是檢測當前系統是否支持加拿*****語,因爲系統在資源庫中沒法找到這個地區的法語分支,其含義是僅支持這項語言(法語),而不支持當前地區的語言分支。
另外,相比於上面強制用戶應用預約的語音設置,更加提倡利用Locale.getDefault()方法根據用戶默認的地區設置來選擇合適的語言庫。
執行Speak的具體方法:
根據上邊的介紹,基本實現了TextToSpeech的初始化和參數配置。下面是一個有關鬧鐘的應用實例,利用Speak()方法能夠直接在應用程序中發揮強大的語音功能。沒錯,用起來就是這麼簡單:
String myText1 = "This Translation is from androidRes.com";
String myText2 = "I hope so, because it's time to wake up.";
mTts.speak(myText1, TextToSpeech.QUEUE_FLUSH, null);
mTts.speak(myText2, TextToSpeech.QUEUE_ADD, null);
TTS Engine的工做原理:
每一個獨立的應用程序均可以單首創建一個TTS實體,而他們須要執行的語音消息列隊(Queue)都統一由TTS Engine管理和語音合成。
名詞解釋:
synthesize [ˈsɪnθəsaɪz] DJ ['sɪnθəˈsaɪz] KK:to produce sounds, music or speech using electronic equipment (音響)合成
utterances [ˈʌtərəns] DJ [ˈʌtərəns] KK :說話方式,語音/語調。
每一個獨立的TTS實例管理語音消息列隊請求的優先級和順序等。當引用 「TextToSpeech.QUEUE_FLUSH」 調用Speak()方法時,會中斷當前實例正在運行的任務(也能夠理解爲清除當前語音任務,轉而執行新的列隊任務)。引用 「TextToSpeech.QUEUE_ADD」標籤的發音任務將被添加到當前任務列隊以後。
爲語音任務關聯Stream Type:
在Android操做系統中全部的Audio Stream任務都是經過AudioManager類來實現,而它會針對不一樣的Stream Type來改變語音的播放模式。StreamType能夠理解爲語音的播放屬性,這個屬性是用戶根據本身的須要在系統中配置的應用方案。若是將語音任務都清楚的分門別類,能夠方便的統一管理相同類別任務的屬性。基於上一個Alarm Clock例子的基礎上,將Speak()方法的最後一個Null參數替換成具備實際含義的數值。這個參數的類型是HashMap,若是但願將當前的Stream Type設置爲系統中Alarm類型,對上一個例子稍做改動:
HashMap myHashAlarm = new HashMap();
myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_STREAM,
String.valueOf(AudioManager.STREAM_ALARM));
mTts.speak(myText1, TextToSpeech.QUEUE_FLUSH, myHashAlarm);
mTts.speak(myText2, TextToSpeech.QUEUE_ADD, myHashAlarm);
應用語音功能的Completion Callback:
TTS中的Speak()的是異步調用,不管應用QUEUE_FLUSH 或者QUEUE_ADD做爲參數均可以經過定義Listener監聽當前任務的完成狀態。能夠利用這個方法追加Speak()執行以後的一些額外操做。下接下來的例子中,當完成第二次Speak()方法調用以後,利用OnUtteranceCompletedListener接口來調用其它方法:
mTts.setOnUtteranceCompletedListener(this);
myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_STREAM,
String.valueOf(AudioManager.STREAM_ALARM));
mTts.speak(myText1, TextToSpeech.QUEUE_FLUSH, myHashAlarm);
myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,
"end of wakeup message ID");
// myHashAlarm now contains two optional parameters
mTts.speak(myText2, TextToSpeech.QUEUE_ADD, myHashAlarm);
下邊是定義Listener的代碼,相似與監聽按鈕或者其它View Events的方法。在這裏將會把Speak()中HashMap參數傳進Listener中,做爲條件的判斷依據:
public void onUtteranceCompleted(String uttId) {
if (uttId == "end of wakeup message ID") {
playAnnoyingMusic();
}
}
「烘焙」當前實時的語音數據:
看到烘焙兩個字,就會讓人聯想到香噴噴的麪包。軟件開發要關注因而否能夠最大限度的實現資源的複用,特別是針對資源有限的手機應用平臺。那麼對於TTS這麼奢侈的應用如何才能更高效的使用資源呢?此次一塊兒來體驗比烘焙麪包更加讓人激動的功能,將TTS Engine輸出的Audio Stream做爲永久的音頻文件保存在當前的存儲空間中(SDCard)。這樣能夠對須要重複播放的某些語音內容實現快速的回放功能,從而實現國際倡導的「減排」目的,能省就省吧!在下邊的例子用經過TTS的synthesizeToFile方法,將合成的語音Stream保存在參數所指定的地址中。
HashMap myHashRender = new HashMap();
String wakeUpText = "Are you up yet?";
String destFileName = "/sdcard/myAppCache/wakeUp.wav";
myHashRender.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, wakeUpText);
mTts.synthesizeToFile(wakuUpText, myHashRender, destFileName);
當完成以上操做以後會收到系統的完成通知,同時能夠像其它音頻資源同樣,經過android.media.MediaPlayer方法來播放。但這有悖於TextToSpeech的應用流程,能夠將剛剛輸出的語音資源經過addSpeech()的方法將其語音和文字描述一同存儲於TTS庫中。
mTts.addSpeech(wakeUpText, destFileName);
在當前的TTS Instance中,任何利用Speak()方法執行相同內容的調用都將複用剛剛所生成的音頻文件。若是資源丟失或者SDCard等存儲設備移除,那麼系統將再次經過TTS Engine合成所指定的語音內容。
mTts.speak(wakeUpText, TextToSpeech.QUEUE_ADD, myHashAlarm);
回收TTS:
當肯定應用程序再也不須要TTS的相關功能後,能夠在Activity的OnDestroy()方法中調用shutDown()釋放當前TTS實體所佔用的資源。