1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 package com.android.tts.compat; 17 18 import android.database.Cursor; 19 import android.net.Uri; 20 import android.speech.tts.SynthesisCallback; 21 import android.speech.tts.SynthesisRequest; 22 import android.speech.tts.TextToSpeech; 23 import android.speech.tts.TextToSpeechService; 24 import android.util.Log; 25 26 import java.io.File; 27 28 public abstract class CompatTtsService extends TextToSpeechService { 29 30 private static final boolean DBG = false; 31 private static final String TAG = "CompatTtsService"; 32 33 private SynthProxy mNativeSynth = null; 34 35 protected abstract String getSoFilename(); 36 37 @Override 38 public void onCreate() { 39 if (DBG) Log.d(TAG, "onCreate()"); 40 super.onCreate(); 41 42 String soFilename = getSoFilename(); 43 44 File f = new File(soFilename); 45 if (!f.exists()) { 46 Log.e(TAG, "Invalid TTS Binary: " + soFilename); 47 return; 48 } 49 50 if (mNativeSynth != null) { 51 mNativeSynth.stopSync(); 52 mNativeSynth.shutdown(); 53 mNativeSynth = null; 54 } 55 56 // Load the engineConfig from the plugin if it has any special configuration 57 // to be loaded. By convention, if an engine wants the TTS framework to pass 58 // in any configuration, it must put it into its content provider which has the URI: 59 // content://<packageName>.providers.SettingsProvider 60 // That content provider must provide a Cursor which returns the String that 61 // is to be passed back to the native .so file for the plugin when getString(0) is 62 // called on it. 63 // Note that the TTS framework does not care what this String data is: it is something 64 // that comes from the engine plugin and is consumed only by the engine plugin itself. 65 String engineConfig = ""; 66 Cursor c = getContentResolver().query(Uri.parse("content://" + getPackageName() 67 + ".providers.SettingsProvider"), null, null, null, null); 68 if (c != null){ 69 c.moveToFirst(); 70 engineConfig = c.getString(0); 71 c.close(); 72 } 73 mNativeSynth = new SynthProxy(soFilename, engineConfig); 74 } 75 76 @Override 77 public void onDestroy() { 78 if (DBG) Log.d(TAG, "onDestroy()"); 79 super.onDestroy(); 80 81 if (mNativeSynth != null) { 82 mNativeSynth.shutdown(); 83 } 84 mNativeSynth = null; 85 } 86 87 @Override 88 protected String[] onGetLanguage() { 89 if (mNativeSynth == null) return null; 90 return mNativeSynth.getLanguage(); 91 } 92 93 @Override 94 protected int onIsLanguageAvailable(String lang, String country, String variant) { 95 if (DBG) Log.d(TAG, "onIsLanguageAvailable(" + lang + "," + country + "," + variant + ")"); 96 if (mNativeSynth == null) return TextToSpeech.ERROR; 97 return mNativeSynth.isLanguageAvailable(lang, country, variant); 98 } 99 100 @Override 101 protected int onLoadLanguage(String lang, String country, String variant) { 102 if (DBG) Log.d(TAG, "onLoadLanguage(" + lang + "," + country + "," + variant + ")"); 103 int result = onIsLanguageAvailable(lang, country, variant); 104 // TODO: actually load language 105 return result; 106 } 107 108 @Override 109 protected void onSynthesizeText(SynthesisRequest request, SynthesisCallback callback) { 110 if (mNativeSynth == null) { 111 callback.error(); 112 return; 113 } 114 115 // Set language 116 String lang = request.getLanguage(); 117 String country = request.getCountry(); 118 String variant = request.getVariant(); 119 if (mNativeSynth.setLanguage(lang, country, variant) != TextToSpeech.SUCCESS) { 120 Log.e(TAG, "setLanguage(" + lang + "," + country + "," + variant + ") failed"); 121 callback.error(); 122 return; 123 } 124 125 // Set speech rate 126 int speechRate = request.getSpeechRate(); 127 if (mNativeSynth.setSpeechRate(speechRate) != TextToSpeech.SUCCESS) { 128 Log.e(TAG, "setSpeechRate(" + speechRate + ") failed"); 129 callback.error(); 130 return; 131 } 132 133 // Set speech 134 int pitch = request.getPitch(); 135 if (mNativeSynth.setPitch(pitch) != TextToSpeech.SUCCESS) { 136 Log.e(TAG, "setPitch(" + pitch + ") failed"); 137 callback.error(); 138 return; 139 } 140 141 // Synthesize 142 if (mNativeSynth.speak(request, callback) != TextToSpeech.SUCCESS) { 143 callback.error(); 144 return; 145 } 146 } 147 148 @Override 149 protected void onStop() { 150 if (DBG) Log.d(TAG, "onStop()"); 151 if (mNativeSynth == null) return; 152 mNativeSynth.stop(); 153 } 154 155 } 156