@@ -38,9 +38,14 @@ bool TTS_Android::initialized = false;
3838jobject TTS_Android::tts = nullptr ;
3939jclass TTS_Android::cls = nullptr ;
4040
41+ Thread TTS_Android::init_thread;
42+ SafeFlag TTS_Android::quit_request;
43+ SafeFlag TTS_Android::init_done;
44+
4145jmethodID TTS_Android::_init = nullptr ;
4246jmethodID TTS_Android::_is_speaking = nullptr ;
4347jmethodID TTS_Android::_is_paused = nullptr ;
48+ jmethodID TTS_Android::_get_state = nullptr ;
4449jmethodID TTS_Android::_get_voices = nullptr ;
4550jmethodID TTS_Android::_speak = nullptr ;
4651jmethodID TTS_Android::_pause_speaking = nullptr ;
@@ -49,12 +54,49 @@ jmethodID TTS_Android::_stop_speaking = nullptr;
4954
5055HashMap<int , Char16String> TTS_Android::ids;
5156
52- void TTS_Android::initialize_tts () {
57+ void TTS_Android::_thread_function (void *self) {
58+ JNIEnv *env = get_jni_env ();
59+ ERR_FAIL_NULL (env);
60+
61+ env->CallVoidMethod (tts, _init);
62+
63+ uint64_t sleep = 200 ;
64+ while (env->CallIntMethod (tts, _get_state) == INIT_STATE_UNKNOWN && !quit_request.is_set ()) {
65+ OS::get_singleton ()->delay_usec (1000 * sleep);
66+ }
67+ init_done.set ();
68+ }
69+
70+ void TTS_Android::initialize_tts (bool p_wait) {
71+ if (!_init || !_get_state || !tts) {
72+ return ;
73+ }
5374 JNIEnv *env = get_jni_env ();
5475 ERR_FAIL_NULL (env);
5576
56- if (_init) {
57- env->CallVoidMethod (tts, _init);
77+ if (!init_thread.is_started () && !init_done.is_set ()) {
78+ init_thread.start (TTS_Android::_thread_function, nullptr );
79+ }
80+
81+ if (env->CallIntMethod (tts, _get_state) == INIT_STATE_SUCCESS) {
82+ initialized = true ;
83+ return ;
84+ }
85+
86+ // If it's not initialized at launch wait for 1 second for TTS init.
87+ if (p_wait) {
88+ uint64_t sleep = 200 ;
89+ uint64_t wait = 1000000 ;
90+ uint64_t time = OS::get_singleton ()->get_ticks_usec ();
91+ while (OS::get_singleton ()->get_ticks_usec () - time < wait) {
92+ OS::get_singleton ()->delay_usec (1000 * sleep);
93+ if (init_done.is_set ()) {
94+ break ;
95+ }
96+ }
97+ }
98+
99+ if (env->CallIntMethod (tts, _get_state) == INIT_STATE_SUCCESS) {
58100 initialized = true ;
59101 }
60102}
@@ -64,13 +106,16 @@ void TTS_Android::setup(jobject p_tts) {
64106 ERR_FAIL_NULL (env);
65107
66108 tts = env->NewGlobalRef (p_tts);
109+ quit_request.clear ();
110+ init_done.clear ();
67111
68112 jclass c = env->GetObjectClass (tts);
69113 cls = (jclass)env->NewGlobalRef (c);
70114
71115 _init = env->GetMethodID (cls, " init" , " ()V" );
72116 _is_speaking = env->GetMethodID (cls, " isSpeaking" , " ()Z" );
73117 _is_paused = env->GetMethodID (cls, " isPaused" , " ()Z" );
118+ _get_state = env->GetMethodID (cls, " getState" , " ()I" );
74119 _get_voices = env->GetMethodID (cls, " getVoices" , " ()[Ljava/lang/String;" );
75120 _speak = env->GetMethodID (cls, " speak" , " (Ljava/lang/String;Ljava/lang/String;IFFIZ)V" );
76121 _pause_speaking = env->GetMethodID (cls, " pauseSpeaking" , " ()V" );
@@ -79,14 +124,19 @@ void TTS_Android::setup(jobject p_tts) {
79124
80125 bool tts_enabled = GLOBAL_GET (" audio/general/text_to_speech" );
81126 if (tts_enabled) {
82- initialize_tts ();
127+ initialize_tts (false );
83128 }
84129}
85130
86131void TTS_Android::terminate () {
87132 JNIEnv *env = get_jni_env ();
88133 ERR_FAIL_NULL (env);
89134
135+ if (init_thread.is_started ()) {
136+ quit_request.set ();
137+ init_thread.wait_to_finish ();
138+ }
139+
90140 if (cls) {
91141 env->DeleteGlobalRef (cls);
92142 }
@@ -99,7 +149,7 @@ void TTS_Android::_java_utterance_callback(int p_event, int p_id, int p_pos) {
99149 if (unlikely (!initialized)) {
100150 initialize_tts ();
101151 }
102- ERR_FAIL_NULL ( tts);
152+ ERR_FAIL_COND_MSG (!initialized || tts == nullptr , " Text to Speech not initialized. " );
103153 if (ids.has (p_id)) {
104154 int pos = 0 ;
105155 if ((DisplayServer::TTSUtteranceEvent)p_event == DisplayServer::TTS_UTTERANCE_BOUNDARY) {
@@ -123,7 +173,7 @@ bool TTS_Android::is_speaking() {
123173 if (unlikely (!initialized)) {
124174 initialize_tts ();
125175 }
126- ERR_FAIL_NULL_V ( tts, false );
176+ ERR_FAIL_COND_V_MSG (!initialized || tts == nullptr , false , " Text to Speech not initialized. " );
127177 if (_is_speaking) {
128178 JNIEnv *env = get_jni_env ();
129179
@@ -138,7 +188,7 @@ bool TTS_Android::is_paused() {
138188 if (unlikely (!initialized)) {
139189 initialize_tts ();
140190 }
141- ERR_FAIL_NULL_V ( tts, false );
191+ ERR_FAIL_COND_V_MSG (!initialized || tts == nullptr , false , " Text to Speech not initialized. " );
142192 if (_is_paused) {
143193 JNIEnv *env = get_jni_env ();
144194
@@ -153,7 +203,7 @@ Array TTS_Android::get_voices() {
153203 if (unlikely (!initialized)) {
154204 initialize_tts ();
155205 }
156- ERR_FAIL_NULL_V ( tts, Array ());
206+ ERR_FAIL_COND_V_MSG (!initialized || tts == nullptr , Array (), " Text to Speech not initialized. " );
157207 Array list;
158208 if (_get_voices) {
159209 JNIEnv *env = get_jni_env ();
@@ -184,7 +234,7 @@ void TTS_Android::speak(const String &p_text, const String &p_voice, int p_volum
184234 if (unlikely (!initialized)) {
185235 initialize_tts ();
186236 }
187- ERR_FAIL_NULL ( tts);
237+ ERR_FAIL_COND_MSG (!initialized || tts == nullptr , " Text to Speech not initialized. " );
188238 if (p_interrupt) {
189239 stop ();
190240 }
@@ -212,7 +262,7 @@ void TTS_Android::pause() {
212262 if (unlikely (!initialized)) {
213263 initialize_tts ();
214264 }
215- ERR_FAIL_NULL ( tts);
265+ ERR_FAIL_COND_MSG (!initialized || tts == nullptr , " Text to Speech not initialized. " );
216266 if (_pause_speaking) {
217267 JNIEnv *env = get_jni_env ();
218268
@@ -225,7 +275,7 @@ void TTS_Android::resume() {
225275 if (unlikely (!initialized)) {
226276 initialize_tts ();
227277 }
228- ERR_FAIL_NULL ( tts);
278+ ERR_FAIL_COND_MSG (!initialized || tts == nullptr , " Text to Speech not initialized. " );
229279 if (_resume_speaking) {
230280 JNIEnv *env = get_jni_env ();
231281
@@ -238,7 +288,7 @@ void TTS_Android::stop() {
238288 if (unlikely (!initialized)) {
239289 initialize_tts ();
240290 }
241- ERR_FAIL_NULL ( tts);
291+ ERR_FAIL_COND_MSG (!initialized || tts == nullptr , " Text to Speech not initialized. " );
242292 for (const KeyValue<int , Char16String> &E : ids) {
243293 DisplayServer::get_singleton ()->tts_post_utterance_event (DisplayServer::TTS_UTTERANCE_CANCELED, E.key );
244294 }
0 commit comments