Calling Android's TextToSpeech functionality from Qt
Hello all,
First of all, I apologize if this thread is not in the right place, and ask the moderators to kindly re-direct it appropriately.
With the advent of Qt 5.2 beta, we have access to QtAndroidExtras, which is very nice. I want to use this to invoke Android's text to speech functionality, and it appears that the class for doing this is android.speech.tts.TextToSpeech.
On the Qt side, I have this:
Code:
void TTSClient
::speak(const QString &msg
) { QAndroidJniObject myTtsObj("org.qtproject.qt5.android.bindings.MyTextToSpeech");
if (myTtsObj.isValid())
myTtsObj.callMethod<void>("speak", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(msg).object<jstring>());
else
qDebug() << "TTSClient::speak() - Failed: invalid QAndroidJniObject!";
}
While on the Java side, I have this:
Code:
package org.qtproject.qt5.android.bindings;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
public class MyTextToSpeech implements OnInitListener {
private TextToSpeech tts;
public MyTextToSpeech() {
// tts = new TextToSpeech(<something that is-a android.content.Context>, this);
}
@Override
public void onInit(int status) {
System.out.println("MyTextToSpeech.onInit() - Got status: " + status);
}
@Override
public void finalize() throws Throwable {
if (tts != null) {
tts.stop();
tts.shutdown();
}
super.finalize();
}
public void speak(String msg) {
System.out.println("MyTextToSpeech.speak() - " + msg);
// rest to be implemented once TextToSpeech constructor is sorted out!
}
}
My Java class has-a TextToSpeech. The TextToSpeech class does not expose a default constructor, and at minimum requires two things: a Context, and an OnInitListener. The second part is easy. The first is giving me a terrible headache! At first I thought I could simply pass in an instance of android.app.Application, which is-a Context. So, I altered my Java constructor accordingly, and created an Application in Qt:
Code:
QAndroidJniEnvironment jniEnv;
jclass appClass = jniEnv->FindClass("android/app/Application");
jmethodID appCtor = jniEnv->GetMethodID(appClass, "<init>", "()V");
jobject appObj = jniEnv->NewObject(appClass, appCtor);
QAndroidJniObject myTtsObj("org.qtproject.qt5.android.bindings.MyTextToSpeech", "(Landroid/app/Application;)V", appObj);
But the MyTextToSpeechClass constructor call would seemingly hang when it tried to initialize the TextToSpeech member, and on any subsequent attempt to call TTSClient::speak() would crash with a NullPointerException:
Code:
E/AndroidRuntime(11258): FATAL EXCEPTION: Thread-579
E/AndroidRuntime(11258): java.lang.NullPointerException
E/AndroidRuntime(11258): at android.content.ContextWrapper.getPackageName(ContextWrapper.java:135)
E/AndroidRuntime(11258): at android.speech.tts.TextToSpeech.<init>(TextToSpeech.java:606)
E/AndroidRuntime(11258): at android.speech.tts.TextToSpeech.<init>(TextToSpeech.java:582)
E/AndroidRuntime(11258): at android.speech.tts.TextToSpeech.<init>(TextToSpeech.java:567)
E/AndroidRuntime(11258): at org.qtproject.qt5.android.bindings.MyTextToSpeech.<init>(MyTextToSpeech.java:13)
E/AndroidRuntime(11258): at dalvik.system.NativeStart.run(Native Method)
I/Process (11258): Sending signal. PID: 11258 SIG: 9
Then I thought to try using an instance of QtApplication (which is placed by Qt in android\src\org\qtproject\qt5\android\bindings) but this crashed without even having the decency to say much about it:
Code:
F/libc (13574): Fatal signal 11 (SIGSEGV) at 0x0000002c (code=1), thread 13589 (.MyProjectName)
Finally, I thought to make my Java class extend android.app.Activity, which is-a Context as well. But, this crashed too:
Code:
W/dalvikvm(11794): threadid=12: thread exiting with uncaught exception (group=0x416aa700)
E/AndroidRuntime(11794): FATAL EXCEPTION: Thread-583
E/AndroidRuntime(11794): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
E/AndroidRuntime(11794): at android.os.Handler.<init>(Handler.java:197)
E/AndroidRuntime(11794): at android.os.Handler.<init>(Handler.java:111)
E/AndroidRuntime(11794): at android.app.Activity.<init>(Activity.java:759)
E/AndroidRuntime(11794): at org.qtproject.qt5.android.bindings.MyTextToSpeech.<init>(MyTextToSpeech.java:11)
E/AndroidRuntime(11794): at dalvik.system.NativeStart.run(Native Method)
I guess my over-arching question is: how do I supply the requisite Context to my TextToSpeech member variable?
Any guidance is very appreciated. I think I must be missing some crucial concepts.
Thank you for your time.
Re: Calling Android's TextToSpeech functionality from Qt
Update: for a working (if not necessarily optimal/recommended!) solution, see the following links:
1) Including QPlatformNativeInterface: http://stackoverflow.com/questions/1...rface-and-hwnd
2) Using QPlatformNativeInterface to get a QtActivity jobject: http://qt-project.org/forums/viewthread/33771
Re: Calling Android's TextToSpeech functionality from Qt
Hi,
I had the same problem trying to use TextToSpeech class through Qt Android Extras. Finally I have a working code here
and some explanations in this post
regards