Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5e11a6ad authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

Prevent the setLanguage() method in TextToSpeech to change the language

for all current TextToSpeech instances by only caching the language
value so it is used with each subsequent utterance for this instance.
Synchronize calls to the engine around a global mutex since the engine
isn't thread-safe, except for the stop() call which is meant to interrupt
the synthesis loop.
parent 5f6133a1
Loading
Loading
Loading
Loading
+17 −11
Original line number Original line Diff line number Diff line
@@ -820,14 +820,14 @@ public class TextToSpeech {
                if (speechRate > 0) {
                if (speechRate > 0) {
                    int rate = (int)(speechRate*100);
                    int rate = (int)(speechRate*100);
                    mCachedParams[Engine.TTS_PARAM_POSITION_RATE + 1] = String.valueOf(rate);
                    mCachedParams[Engine.TTS_PARAM_POSITION_RATE + 1] = String.valueOf(rate);
                    result = mITts.setSpeechRate(mPackageName, rate);
                    // the rate is not set here, instead it is cached so it will be associated
                    // with all upcoming utterances.
                    if (speechRate > 0.0f) {
                        result = TTS_SUCCESS;
                    } else {
                        result = TTS_ERROR;
                    }
                }
                }
            } catch (RemoteException e) {
                // TTS died; restart it.
                Log.e("TextToSpeech.java - setSpeechRate", "RemoteException");
                e.printStackTrace();
                mStarted = false;
                initTts();
            } catch (NullPointerException e) {
            } catch (NullPointerException e) {
                // TTS died; restart it.
                // TTS died; restart it.
                Log.e("TextToSpeech.java - setSpeechRate", "NullPointerException");
                Log.e("TextToSpeech.java - setSpeechRate", "NullPointerException");
@@ -907,7 +907,9 @@ public class TextToSpeech {
     * @param loc
     * @param loc
     *            The locale describing the language to be used.
     *            The locale describing the language to be used.
     *
     *
     * @return Code indicating the support status for the locale. See the TTS_LANG_ codes.
     * @return code indicating the support status for the locale. See {@link #TTS_LANG_AVAILABLE},
     *         {@link #TTS_LANG_COUNTRY_AVAILABLE}, {@link #TTS_LANG_COUNTRY_VAR_AVAILABLE},
     *         {@link #TTS_LANG_MISSING_DATA} and {@link #TTS_LANG_NOT_SUPPORTED}.
     */
     */
    public int setLanguage(Locale loc) {
    public int setLanguage(Locale loc) {
        synchronized (mStartLock) {
        synchronized (mStartLock) {
@@ -919,7 +921,10 @@ public class TextToSpeech {
                mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1] = loc.getISO3Language();
                mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1] = loc.getISO3Language();
                mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1] = loc.getISO3Country();
                mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1] = loc.getISO3Country();
                mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] = loc.getVariant();
                mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] = loc.getVariant();
                result = mITts.setLanguage(mPackageName,
                // the language is not set here, instead it is cached so it will be associated
                // with all upcoming utterances. But we still need to change the language support,
                // which is achieved by calling isLanguageAvailable()
                result = mITts.isLanguageAvailable(
                        mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1],
                        mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1],
                        mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1],
                        mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1],
                        mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] );
                        mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] );
@@ -994,8 +999,9 @@ public class TextToSpeech {
     * @param loc
     * @param loc
     *            The Locale describing the language to be used.
     *            The Locale describing the language to be used.
     *
     *
     * @return one of TTS_LANG_NOT_SUPPORTED, TTS_LANG_MISSING_DATA, TTS_LANG_AVAILABLE,
     * @return code indicating the support status for the locale. See {@link #TTS_LANG_AVAILABLE},
     *         TTS_LANG_COUNTRY_AVAILABLE, TTS_LANG_COUNTRY_VAR_AVAILABLE.
     *         {@link #TTS_LANG_COUNTRY_AVAILABLE}, {@link #TTS_LANG_COUNTRY_VAR_AVAILABLE},
     *         {@link #TTS_LANG_MISSING_DATA} and {@link #TTS_LANG_NOT_SUPPORTED}.
     */
     */
    public int isLanguageAvailable(Locale loc) {
    public int isLanguageAvailable(Locale loc) {
        synchronized (mStartLock) {
        synchronized (mStartLock) {
+16 −2
Original line number Original line Diff line number Diff line
@@ -59,6 +59,9 @@ struct afterSynthData_t {
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static fields_t javaTTSFields;
static fields_t javaTTSFields;


// TODO move to synth member once we have multiple simultaneous engines running
static Mutex engineMutex;

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
class SynthProxyJniStorage {
class SynthProxyJniStorage {
    public :
    public :
@@ -194,7 +197,6 @@ static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate,
        if (bufferSize > 0) {
        if (bufferSize > 0) {
            prepAudioTrack(pJniData, pForAfter->streamType, rate, format, channel);
            prepAudioTrack(pJniData, pForAfter->streamType, rate, format, channel);
            if (pJniData->mAudioOut) {
            if (pJniData->mAudioOut) {
                pJniData->mAudioOut->start();
                pJniData->mAudioOut->write(wav, bufferSize);
                pJniData->mAudioOut->write(wav, bufferSize);
                memset(wav, 0, bufferSize);
                memset(wav, 0, bufferSize);
                //LOGV("AudioTrack wrote: %d bytes", bufferSize);
                //LOGV("AudioTrack wrote: %d bytes", bufferSize);
@@ -331,6 +333,8 @@ android_tts_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData,
        return result;
        return result;
    }
    }


    Mutex::Autolock l(engineMutex);

    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
    const char *langNativeString = env->GetStringUTFChars(language, 0);
    const char *langNativeString = env->GetStringUTFChars(language, 0);
    const char *countryNativeString = env->GetStringUTFChars(country, 0);
    const char *countryNativeString = env->GetStringUTFChars(country, 0);
@@ -390,6 +394,8 @@ android_tts_SynthProxy_setSpeechRate(JNIEnv *env, jobject thiz, jint jniData,
    char buffer [bufSize];
    char buffer [bufSize];
    sprintf(buffer, "%d", speechRate);
    sprintf(buffer, "%d", speechRate);


    Mutex::Autolock l(engineMutex);

    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
    LOGI("setting speech rate to %d", speechRate);
    LOGI("setting speech rate to %d", speechRate);


@@ -412,6 +418,8 @@ android_tts_SynthProxy_setPitch(JNIEnv *env, jobject thiz, jint jniData,
        return result;
        return result;
    }
    }


    Mutex::Autolock l(engineMutex);

    int bufSize = 10;
    int bufSize = 10;
    char buffer [bufSize];
    char buffer [bufSize];
    sprintf(buffer, "%d", pitch);
    sprintf(buffer, "%d", pitch);
@@ -444,6 +452,8 @@ android_tts_SynthProxy_synthesizeToFile(JNIEnv *env, jobject thiz, jint jniData,
        return result;
        return result;
    }
    }


    Mutex::Autolock l(engineMutex);

    // Retrieve audio parameters before writing the file header
    // Retrieve audio parameters before writing the file header
    AudioSystem::audio_format encoding = DEFAULT_TTS_FORMAT;
    AudioSystem::audio_format encoding = DEFAULT_TTS_FORMAT;
    uint32_t rate = DEFAULT_TTS_RATE;
    uint32_t rate = DEFAULT_TTS_RATE;
@@ -546,10 +556,12 @@ android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData,
        return result;
        return result;
    }
    }


    Mutex::Autolock l(engineMutex);

    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;


    if (pSynthData->mAudioOut) {
    if (pSynthData->mAudioOut) {
        pSynthData->mAudioOut->stop();
        pSynthData->mAudioOut->start();
    }
    }


    afterSynthData_t* pForAfter = new (afterSynthData_t);
    afterSynthData_t* pForAfter = new (afterSynthData_t);
@@ -600,6 +612,8 @@ android_tts_SynthProxy_shutdown(JNIEnv *env, jobject thiz, jint jniData)
        return;
        return;
    }
    }


    Mutex::Autolock l(engineMutex);

    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
    if (pSynthData->mNativeSynthInterface) {
    if (pSynthData->mNativeSynthInterface) {
        pSynthData->mNativeSynthInterface->shutdown();
        pSynthData->mNativeSynthInterface->shutdown();
+4 −4
Original line number Original line Diff line number Diff line
@@ -546,7 +546,7 @@ public class TtsService extends Service implements OnCompletionListener {
                    if (!synthAvailable) {
                    if (!synthAvailable) {
                        Thread.sleep(100);
                        Thread.sleep(100);
                        Thread synth = (new Thread(new SynthThread()));
                        Thread synth = (new Thread(new SynthThread()));
                        synth.setPriority(Thread.MIN_PRIORITY);
                        //synth.setPriority(Thread.MIN_PRIORITY);
                        synth.start();
                        synth.start();
                        return;
                        return;
                    }
                    }
@@ -608,7 +608,7 @@ public class TtsService extends Service implements OnCompletionListener {
            }
            }
        }
        }
        Thread synth = (new Thread(new SynthThread()));
        Thread synth = (new Thread(new SynthThread()));
        synth.setPriority(Thread.MIN_PRIORITY);
        //synth.setPriority(Thread.MIN_PRIORITY);
        synth.start();
        synth.start();
    }
    }


@@ -623,7 +623,7 @@ public class TtsService extends Service implements OnCompletionListener {
                    if (!synthAvailable) {
                    if (!synthAvailable) {
                        Thread.sleep(100);
                        Thread.sleep(100);
                        Thread synth = (new Thread(new SynthThread()));
                        Thread synth = (new Thread(new SynthThread()));
                        synth.setPriority(Thread.MIN_PRIORITY);
                        //synth.setPriority(Thread.MIN_PRIORITY);
                        synth.start();
                        synth.start();
                        return;
                        return;
                    }
                    }
@@ -677,7 +677,7 @@ public class TtsService extends Service implements OnCompletionListener {
            }
            }
        }
        }
        Thread synth = (new Thread(new SynthThread()));
        Thread synth = (new Thread(new SynthThread()));
        synth.setPriority(Thread.MIN_PRIORITY);
        //synth.setPriority(Thread.MIN_PRIORITY);
        synth.start();
        synth.start();
    }
    }