Home | History | Annotate | Download | only in compat
      1 /*
      2  * Copyright (C) 2011 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.speech.tts.SynthesisCallback;
     19 import android.speech.tts.SynthesisRequest;
     20 import android.util.Log;
     21 
     22 /**
     23  * The SpeechSynthesis class provides a high-level api to create and play
     24  * synthesized speech. This class is used internally to talk to a native
     25  * TTS library that implements the interface defined in
     26  * frameworks/base/include/tts/TtsEngine.h
     27  *
     28  */
     29 public class SynthProxy {
     30 
     31     static {
     32         System.loadLibrary("ttscompat");
     33     }
     34 
     35     private final static String TAG = "SynthProxy";
     36 
     37     // Default parameters of a filter to be applied when using the Pico engine.
     38     // Such a huge filter gain is justified by how much energy in the low frequencies is "wasted" at
     39     // the output of the synthesis. The low shelving filter removes it, leaving room for
     40     // amplification.
     41     private final static float PICO_FILTER_GAIN = 5.0f; // linear gain
     42     private final static float PICO_FILTER_LOWSHELF_ATTENUATION = -18.0f; // in dB
     43     private final static float PICO_FILTER_TRANSITION_FREQ = 1100.0f;     // in Hz
     44     private final static float PICO_FILTER_SHELF_SLOPE = 1.0f;            // Q
     45 
     46     private long mJniData = 0;
     47 
     48     /**
     49      * Constructor; pass the location of the native TTS .so to use.
     50      */
     51     public SynthProxy(String nativeSoLib, String engineConfig) {
     52         boolean applyFilter = shouldApplyAudioFilter(nativeSoLib);
     53         Log.v(TAG, "About to load "+ nativeSoLib + ", applyFilter=" + applyFilter);
     54         mJniData = native_setup(nativeSoLib, engineConfig);
     55         if (mJniData == 0) {
     56             throw new RuntimeException("Failed to load " + nativeSoLib);
     57         }
     58         native_setLowShelf(applyFilter, PICO_FILTER_GAIN, PICO_FILTER_LOWSHELF_ATTENUATION,
     59                 PICO_FILTER_TRANSITION_FREQ, PICO_FILTER_SHELF_SLOPE);
     60     }
     61 
     62     // HACK: Apply audio filter if the engine is pico
     63     private boolean shouldApplyAudioFilter(String nativeSoLib) {
     64         return nativeSoLib.toLowerCase().contains("pico");
     65     }
     66 
     67     /**
     68      * Stops and clears the AudioTrack.
     69      */
     70     public int stop() {
     71         return native_stop(mJniData);
     72     }
     73 
     74     /**
     75      * Synchronous stop of the synthesizer. This method returns when the synth
     76      * has completed the stop procedure and doesn't use any of the resources it
     77      * was using while synthesizing.
     78      *
     79      * @return {@link android.speech.tts.TextToSpeech#SUCCESS} or
     80      *         {@link android.speech.tts.TextToSpeech#ERROR}
     81      */
     82     public int stopSync() {
     83         return native_stopSync(mJniData);
     84     }
     85 
     86     public int speak(SynthesisRequest request, SynthesisCallback callback) {
     87         return native_speak(mJniData, request.getText(), callback);
     88     }
     89 
     90     /**
     91      * Queries for language support.
     92      * Return codes are defined in android.speech.tts.TextToSpeech
     93      */
     94     public int isLanguageAvailable(String language, String country, String variant) {
     95         return native_isLanguageAvailable(mJniData, language, country, variant);
     96     }
     97 
     98     /**
     99      * Updates the engine configuration.
    100      */
    101     public int setConfig(String engineConfig) {
    102         return native_setProperty(mJniData, "engineConfig", engineConfig);
    103     }
    104 
    105     /**
    106      * Sets the language.
    107      */
    108     public int setLanguage(String language, String country, String variant) {
    109         return native_setLanguage(mJniData, language, country, variant);
    110     }
    111 
    112     /**
    113      * Loads the language: it's not set, but prepared for use later.
    114      */
    115     public int loadLanguage(String language, String country, String variant) {
    116         return native_loadLanguage(mJniData, language, country, variant);
    117     }
    118 
    119     /**
    120      * Sets the speech rate.
    121      */
    122     public final int setSpeechRate(int speechRate) {
    123         return native_setProperty(mJniData, "rate", String.valueOf(speechRate));
    124     }
    125 
    126     /**
    127      * Sets the pitch of the synthesized voice.
    128      */
    129     public final int setPitch(int pitch) {
    130         return native_setProperty(mJniData, "pitch", String.valueOf(pitch));
    131     }
    132 
    133     /**
    134      * Returns the currently set language, country and variant information.
    135      */
    136     public String[] getLanguage() {
    137         return native_getLanguage(mJniData);
    138     }
    139 
    140     /**
    141      * Shuts down the native synthesizer.
    142      */
    143     public void shutdown() {
    144         native_shutdown(mJniData);
    145         mJniData = 0;
    146     }
    147 
    148     @Override
    149     protected void finalize() {
    150         if (mJniData != 0) {
    151             Log.w(TAG, "SynthProxy finalized without being shutdown");
    152             native_finalize(mJniData);
    153             mJniData = 0;
    154         }
    155     }
    156 
    157     private native final long native_setup(String nativeSoLib, String engineConfig);
    158 
    159     private native final int native_setLowShelf(boolean applyFilter, float filterGain,
    160             float attenuationInDb, float freqInHz, float slope);
    161 
    162     private native final void native_finalize(long jniData);
    163 
    164     private native final int native_stop(long jniData);
    165 
    166     private native final int native_stopSync(long jniData);
    167 
    168     private native final int native_speak(long jniData, String text, SynthesisCallback request);
    169 
    170     private native final int  native_isLanguageAvailable(long jniData, String language,
    171             String country, String variant);
    172 
    173     private native final int native_setLanguage(long jniData, String language, String country,
    174             String variant);
    175 
    176     private native final int native_loadLanguage(long jniData, String language, String country,
    177             String variant);
    178 
    179     private native final int native_setProperty(long jniData, String name, String value);
    180 
    181     private native final String[] native_getLanguage(long jniData);
    182 
    183     private native final void native_shutdown(long jniData);
    184 
    185 }
    186