package nliveroid.nlr.main; import java.util.HashMap; import java.util.Locale; import java.util.concurrent.ArrayBlockingQueue; import android.app.Activity; import android.content.Context; import android.os.AsyncTask; import android.speech.tts.TextToSpeech; import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener; import android.util.Log; public class TTSSpeech implements TextToSpeech.OnInitListener,Speechable{ private TextToSpeech tts;//これはnot static private Activity act; private boolean isInited; private int speed; private int pich; private boolean wait = false; private boolean ENDFLAG = true; private boolean isClearing = false; private String skip_word; private int maxBufferSize; private SpeechLoop loopThread; private ArrayBlockingQueue<String> readBuffer = new ArrayBlockingQueue<String>(10); private HashMap<String,String> noMean = new HashMap<String,String>(); private String nomeanStr = "0"; public TTSSpeech(String skip_word,int maxBufferSize){ // TextToSpeechオブジェクトの生成 this.skip_word = skip_word; this.maxBufferSize = maxBufferSize; } //Contextは何故かrebindみたくなってるっぽいのですぐnullになったから別ロジック public void setContext(Activity act,int speed,int pich){ this.act = act; tts = new TextToSpeech(((NLiveRoid)act.getApplicationContext()).getBaseContext(), this); // 再生速度の設定 this.speed = speed; // 再生ピッチの設定 initしてないと、設定されないのでinit後に設定 this.pich = pich; } public void destroy() { Log.d("NLiveRoid","TTS DESTROY ---------------- "); tts.stop(); readBuffer.clear(); if(loopThread != null&&loopThread.getStatus() != AsyncTask.Status.FINISHED)loopThread.cancel(true); loopThread = null; // TextToSpeechのリソースを解放する tts.shutdown(); } @Override public void onInit(final int status) { Log.d("NLiveRoid","TTS INIT ---------------- " + isInited + " status:"+status); if(isInited)return; if(loopThread != null&&loopThread.getStatus() != AsyncTask.Status.FINISHED)loopThread.cancel(true); loopThread = null; if (TextToSpeech.SUCCESS == status) { Locale locale1 = Locale.JAPANESE; Locale locale2 = Locale.JAPAN; if(act == null){ return; } if(tts == null){ tts = new TextToSpeech(act.getBaseContext(), this); } if (tts.isLanguageAvailable(locale1) >= TextToSpeech.LANG_AVAILABLE){ tts.setLanguage(locale1); }else if(tts.isLanguageAvailable(locale2) >= TextToSpeech.LANG_AVAILABLE) { tts.setLanguage(locale2); }else { act.runOnUiThread(new Runnable(){ @Override public void run() { MyToast.customToastShow(act, "読み上げの初期化に失敗しました\n日本語に非対応:000"); } }); return; } } else { act.runOnUiThread(new Runnable(){ @Override public void run() { MyToast.customToastShow(act, "読み上げの初期化に失敗しました:111 \nSTATUS:" + status); } }); return; } // 発話終了のListner tts.setOnUtteranceCompletedListener(new OnUtteranceCompletedListener() { public void onUtteranceCompleted(String utteranceId) { wait = false; if(isClearing){ isClearing = false; } } }); isInited = true; setSpeed(speed); setPich(pich); //初期化前にアドされていたら読まれない loopThread = new SpeechLoop(); loopThread.execute(); } @Override public void addSpeech(String sentence) throws InterruptedException { if(isInited&&0 < sentence.length()&&!isClearing) { //isClearingクリア中にアドされちゃうと、省略を何回も読んじゃうのでisClearingにして、それを読んだらfalse readBuffer.put(sentence); } } class SpeechLoop extends AsyncTask<Void,Void,Void>{ @Override public void onCancelled(){ super.onCancelled(); wait = false; ENDFLAG = false; } @Override protected Void doInBackground(Void... params) { try { noMean.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID ,nomeanStr); while(ENDFLAG){ // Log.d("Log","WHILE"); //常にADDされ続ける if(readBuffer.size() > 0){//無理だった場合、今あるのをクリアして省略を読む if(readBuffer.size() > maxBufferSize){ readBuffer.clear(); wait =true; if(skip_word == null||skip_word.equals("")){//ワードなしなら読み上げずにisClearingも変えない }else{ isClearing = true; tts.speak(skip_word, TextToSpeech.QUEUE_ADD, noMean);//クリアする場合、QUEUE_FLUSH } }else{ isClearing = false; wait = true; String read = readBuffer.poll();//clearのタイミングとかぶるとおかしくなるので一旦コピー if(read != null && !read.equals(""))tts.speak(read, TextToSpeech.QUEUE_ADD, noMean); } while(wait){ try{ Thread.sleep(100); }catch(Exception e){ Log.d("NLiveRoid","SPEACH SLEEP EXCEPTION"); } //読み上げ完了するまで待つ } } } } catch (IndexOutOfBoundsException e) {//途中キャンセル e.printStackTrace(); }catch(IllegalArgumentException e1){ e1.printStackTrace(); Log.d("NLiveRoid","IllegalArgumentException at SpeechLoop"); }catch (RuntimeException e) {//その他 e.printStackTrace(); } return null; } } @Override public void setSpeed(int speed) { if(tts != null){ if(speed == 0){ tts.setSpeechRate((float)0.1); }else{ tts.setSpeechRate((float) (speed*0.3)); } } } @Override public void setPich(int val){ if(tts != null){ if(val == 0){ tts.setPitch((float)0.1); }else{ tts.setPitch((float) (val*0.2)); } } } @Override public boolean isInitalized() {//Testのみで参照(0.8.80) return isInited; } @Override public Object[] getStatus() { return new Object[]{this.speed,this.pich,false,5,0}; } }