Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Q
qgroundcontrol
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Valentin Platzgummer
qgroundcontrol
Commits
7abe60d1
Commit
7abe60d1
authored
Oct 21, 2015
by
Gus Grubba
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2070 from dogmaphobic/textToSpeech
Text to Speech Work
parents
fec16350
dd587ce2
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
261 additions
and
174 deletions
+261
-174
QGCExternalLibs.pri
QGCExternalLibs.pri
+85
-80
UsbDeviceJNI.java
android/src/org/qgroundcontrol/qgchelper/UsbDeviceJNI.java
+33
-1
GAudioOutput.cc
src/GAudioOutput.cc
+34
-11
GAudioOutput.h
src/GAudioOutput.h
+7
-4
QGCAudioWorker.cpp
src/audio/QGCAudioWorker.cpp
+66
-32
QGCAudioWorker.h
src/audio/QGCAudioWorker.h
+3
-9
UAS.cc
src/uas/UAS.cc
+33
-37
No files found.
QGCExternalLibs.pri
View file @
7abe60d1
...
@@ -270,6 +270,11 @@ else:WindowsBuild {
...
@@ -270,6 +270,11 @@ else:WindowsBuild {
DEFINES += QGC_SPEECH_ENABLED
DEFINES += QGC_SPEECH_ENABLED
LIBS += -lOle32
LIBS += -lOle32
}
}
# Android supports speech through native (Java) API.
else:AndroidBuild {
message("Including support for speech output")
DEFINES += QGC_SPEECH_ENABLED
}
#
#
# [OPTIONAL] Zeroconf for UDP links
# [OPTIONAL] Zeroconf for UDP links
...
...
android/src/org/qgroundcontrol/qgchelper/UsbDeviceJNI.java
View file @
7abe60d1
...
@@ -43,12 +43,15 @@ import android.content.IntentFilter;
...
@@ -43,12 +43,15 @@ import android.content.IntentFilter;
import
android.hardware.usb.*
;
import
android.hardware.usb.*
;
import
android.widget.Toast
;
import
android.widget.Toast
;
import
android.util.Log
;
import
android.util.Log
;
//-- Text To Speech
import
android.os.Bundle
;
import
android.speech.tts.TextToSpeech
;
import
com.hoho.android.usbserial.driver.*
;
import
com.hoho.android.usbserial.driver.*
;
import
org.qtproject.qt5.android.bindings.QtActivity
;
import
org.qtproject.qt5.android.bindings.QtActivity
;
import
org.qtproject.qt5.android.bindings.QtApplication
;
import
org.qtproject.qt5.android.bindings.QtApplication
;
public
class
UsbDeviceJNI
extends
QtActivity
public
class
UsbDeviceJNI
extends
QtActivity
implements
TextToSpeech
.
OnInitListener
{
{
public
static
int
BAD_PORT
=
0
;
public
static
int
BAD_PORT
=
0
;
private
static
UsbDeviceJNI
m_instance
;
private
static
UsbDeviceJNI
m_instance
;
...
@@ -61,6 +64,7 @@ public class UsbDeviceJNI extends QtActivity
...
@@ -61,6 +64,7 @@ public class UsbDeviceJNI extends QtActivity
private
BroadcastReceiver
m_UsbReceiver
=
null
;
private
BroadcastReceiver
m_UsbReceiver
=
null
;
private
final
static
ExecutorService
m_Executor
=
Executors
.
newSingleThreadExecutor
();
private
final
static
ExecutorService
m_Executor
=
Executors
.
newSingleThreadExecutor
();
private
static
final
String
TAG
=
"QGC_UsbDeviceJNI"
;
private
static
final
String
TAG
=
"QGC_UsbDeviceJNI"
;
private
static
TextToSpeech
m_tts
;
private
final
static
UsbIoManager
.
Listener
m_Listener
=
private
final
static
UsbIoManager
.
Listener
m_Listener
=
new
UsbIoManager
.
Listener
()
new
UsbIoManager
.
Listener
()
...
@@ -98,6 +102,34 @@ public class UsbDeviceJNI extends QtActivity
...
@@ -98,6 +102,34 @@ public class UsbDeviceJNI extends QtActivity
Log
.
i
(
TAG
,
"Instance created"
);
Log
.
i
(
TAG
,
"Instance created"
);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Text To Speech
// Pigback a ride for providing TTS to QGC
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
public
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
m_tts
=
new
TextToSpeech
(
this
,
this
);
}
@Override
protected
void
onDestroy
()
{
super
.
onDestroy
();
m_tts
.
shutdown
();
}
public
void
onInit
(
int
status
)
{
}
public
static
void
say
(
String
msg
)
{
Log
.
i
(
TAG
,
"Say: "
+
msg
);
m_tts
.
speak
(
msg
,
TextToSpeech
.
QUEUE_FLUSH
,
null
);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Find all current devices that match the device filter described in the androidmanifest.xml and the
// Find all current devices that match the device filter described in the androidmanifest.xml and the
...
...
src/GAudioOutput.cc
View file @
7abe60d1
...
@@ -38,42 +38,51 @@ This file is part of the QGROUNDCONTROL project
...
@@ -38,42 +38,51 @@ This file is part of the QGROUNDCONTROL project
#include "QGCApplication.h"
#include "QGCApplication.h"
#include "QGC.h"
#include "QGC.h"
#if defined __android__
#include <QtAndroidExtras/QtAndroidExtras>
#include <QtAndroidExtras/QAndroidJniObject>
#endif
IMPLEMENT_QGC_SINGLETON
(
GAudioOutput
,
GAudioOutput
)
IMPLEMENT_QGC_SINGLETON
(
GAudioOutput
,
GAudioOutput
)
const
char
*
GAudioOutput
::
_mutedKey
=
"AudioMuted"
;
const
char
*
GAudioOutput
::
_mutedKey
=
"AudioMuted"
;
GAudioOutput
::
GAudioOutput
(
QObject
*
parent
)
:
GAudioOutput
::
GAudioOutput
(
QObject
*
parent
)
QGCSingleton
(
parent
),
:
QGCSingleton
(
parent
)
muted
(
false
),
,
muted
(
false
)
thread
(
new
QThread
()),
#ifndef __android__
worker
(
new
QGCAudioWorker
())
,
thread
(
new
QThread
())
,
worker
(
new
QGCAudioWorker
())
#endif
{
{
QSettings
settings
;
QSettings
settings
;
muted
=
settings
.
value
(
_mutedKey
,
false
).
toBool
();
muted
=
settings
.
value
(
_mutedKey
,
false
).
toBool
();
muted
|=
qgcApp
()
->
runningUnitTests
();
muted
|=
qgcApp
()
->
runningUnitTests
();
#ifndef __android__
worker
->
moveToThread
(
thread
);
worker
->
moveToThread
(
thread
);
connect
(
this
,
&
GAudioOutput
::
textToSpeak
,
worker
,
&
QGCAudioWorker
::
say
);
connect
(
this
,
&
GAudioOutput
::
textToSpeak
,
worker
,
&
QGCAudioWorker
::
say
);
connect
(
thread
,
&
QThread
::
finished
,
thread
,
&
QObject
::
deleteLater
);
connect
(
thread
,
&
QThread
::
finished
,
thread
,
&
QObject
::
deleteLater
);
connect
(
thread
,
&
QThread
::
finished
,
worker
,
&
QObject
::
deleteLater
);
connect
(
thread
,
&
QThread
::
finished
,
worker
,
&
QObject
::
deleteLater
);
thread
->
start
();
thread
->
start
();
#endif
}
}
GAudioOutput
::~
GAudioOutput
()
GAudioOutput
::~
GAudioOutput
()
{
{
#ifndef __android__
thread
->
quit
();
thread
->
quit
();
#endif
}
}
void
GAudioOutput
::
mute
(
bool
mute
)
void
GAudioOutput
::
mute
(
bool
mute
)
{
{
QSettings
settings
;
QSettings
settings
;
muted
=
mute
;
muted
=
mute
;
settings
.
setValue
(
_mutedKey
,
mute
);
settings
.
setValue
(
_mutedKey
,
mute
);
#ifndef __android__
emit
mutedChanged
(
mute
);
emit
mutedChanged
(
mute
);
#endif
}
}
bool
GAudioOutput
::
isMuted
()
bool
GAudioOutput
::
isMuted
()
...
@@ -81,10 +90,24 @@ bool GAudioOutput::isMuted()
...
@@ -81,10 +90,24 @@ bool GAudioOutput::isMuted()
return
muted
;
return
muted
;
}
}
bool
GAudioOutput
::
say
(
const
QString
&
t
ext
,
int
severity
)
bool
GAudioOutput
::
say
(
const
QString
&
inT
ext
,
int
severity
)
{
{
if
(
!
muted
)
{
if
(
!
muted
)
{
emit
textToSpeak
(
text
,
severity
);
#if defined __android__
#if defined QGC_SPEECH_ENABLED
static
const
char
V_jniClassName
[]
{
"org/qgroundcontrol/qgchelper/UsbDeviceJNI"
};
QAndroidJniEnvironment
env
;
if
(
env
->
ExceptionCheck
())
{
env
->
ExceptionDescribe
();
env
->
ExceptionClear
();
}
QString
text
=
QGCAudioWorker
::
fixTextMessageForAudio
(
inText
);
QAndroidJniObject
javaMessage
=
QAndroidJniObject
::
fromString
(
text
);
QAndroidJniObject
::
callStaticMethod
<
void
>
(
V_jniClassName
,
"say"
,
"(Ljava/lang/String;)V"
,
javaMessage
.
object
<
jstring
>
());
#endif
#else
emit
textToSpeak
(
inText
,
severity
);
#endif
}
}
return
true
;
return
true
;
}
}
src/GAudioOutput.h
View file @
7abe60d1
...
@@ -88,8 +88,11 @@ signals:
...
@@ -88,8 +88,11 @@ signals:
protected:
protected:
bool
muted
;
bool
muted
;
#if !defined __android__
QThread
*
thread
;
QThread
*
thread
;
QGCAudioWorker
*
worker
;
QGCAudioWorker
*
worker
;
#endif
private:
private:
GAudioOutput
(
QObject
*
parent
=
NULL
);
GAudioOutput
(
QObject
*
parent
=
NULL
);
...
...
src/audio/QGCAudioWorker.cpp
View file @
7abe60d1
...
@@ -10,6 +10,47 @@
...
@@ -10,6 +10,47 @@
#if defined Q_OS_MAC && defined QGC_SPEECH_ENABLED
#if defined Q_OS_MAC && defined QGC_SPEECH_ENABLED
#include <ApplicationServices/ApplicationServices.h>
#include <ApplicationServices/ApplicationServices.h>
static
SpeechChannel
sc
;
static
Fixed
volume
;
static
void
speechDone
(
SpeechChannel
sc2
,
void
*
)
{
if
(
sc2
==
sc
)
{
DisposeSpeechChannel
(
sc
);
}
}
class
MacSpeech
{
public:
MacSpeech
()
{
setVolume
(
100
);
}
~
MacSpeech
()
{
}
void
say
(
const
char
*
words
)
{
while
(
SpeechBusy
())
{
QGC
::
SLEEP
::
msleep
(
100
);
}
NewSpeechChannel
(
NULL
,
&
sc
);
SetSpeechInfo
(
sc
,
soVolume
,
&
volume
);
SetSpeechInfo
(
sc
,
soSpeechDoneCallBack
,
reinterpret_cast
<
void
*>
(
speechDone
));
CFStringRef
cfstr
=
CFStringCreateWithCString
(
NULL
,
words
,
kCFStringEncodingUTF8
);
SpeakCFString
(
sc
,
cfstr
,
NULL
);
}
void
setVolume
(
int
v
)
{
volume
=
FixRatio
(
v
,
100
);
}
};
//-- Singleton
MacSpeech
macSpeech
;
#endif
#endif
// Speech synthesis is only supported with MSVC compiler
// Speech synthesis is only supported with MSVC compiler
...
@@ -18,7 +59,7 @@
...
@@ -18,7 +59,7 @@
#include <sapi.h>
#include <sapi.h>
#endif
#endif
#if defined Q_OS_LINUX && defined QGC_SPEECH_ENABLED
#if defined Q_OS_LINUX &&
!defined __android__ &&
defined QGC_SPEECH_ENABLED
// Using eSpeak for speech synthesis: following https://github.com/mondhs/espeak-sample/blob/master/sampleSpeak.cpp
// Using eSpeak for speech synthesis: following https://github.com/mondhs/espeak-sample/blob/master/sampleSpeak.cpp
#include <espeak/speak_lib.h>
#include <espeak/speak_lib.h>
#endif
#endif
...
@@ -48,7 +89,7 @@ void QGCAudioWorker::init()
...
@@ -48,7 +89,7 @@ void QGCAudioWorker::init()
sound
=
new
QSound
(
":/res/Alert"
);
sound
=
new
QSound
(
":/res/Alert"
);
#endif
#endif
#if defined Q_OS_LINUX && defined QGC_SPEECH_ENABLED
#if defined Q_OS_LINUX &&
!defined __android__ &&
defined QGC_SPEECH_ENABLED
espeak_Initialize
(
AUDIO_OUTPUT_SYNCH_PLAYBACK
,
500
,
NULL
,
0
);
// initialize for playback with 500ms buffer and no options (see speak_lib.h)
espeak_Initialize
(
AUDIO_OUTPUT_SYNCH_PLAYBACK
,
500
,
NULL
,
0
);
// initialize for playback with 500ms buffer and no options (see speak_lib.h)
espeak_VOICE
*
espeak_voice
=
espeak_GetCurrentVoice
();
espeak_VOICE
*
espeak_voice
=
espeak_GetCurrentVoice
();
espeak_voice
->
languages
=
"en-uk"
;
// Default to British English
espeak_voice
->
languages
=
"en-uk"
;
// Default to British English
...
@@ -92,6 +133,10 @@ QGCAudioWorker::~QGCAudioWorker()
...
@@ -92,6 +133,10 @@ QGCAudioWorker::~QGCAudioWorker()
void
QGCAudioWorker
::
say
(
QString
inText
,
int
severity
)
void
QGCAudioWorker
::
say
(
QString
inText
,
int
severity
)
{
{
#ifdef __android__
Q_UNUSED
(
inText
);
Q_UNUSED
(
severity
);
#else
static
bool
threadInit
=
false
;
static
bool
threadInit
=
false
;
if
(
!
threadInit
)
{
if
(
!
threadInit
)
{
threadInit
=
true
;
threadInit
=
true
;
...
@@ -100,7 +145,7 @@ void QGCAudioWorker::say(QString inText, int severity)
...
@@ -100,7 +145,7 @@ void QGCAudioWorker::say(QString inText, int severity)
if
(
!
muted
)
if
(
!
muted
)
{
{
QString
text
=
_
fixTextMessageForAudio
(
inText
);
QString
text
=
fixTextMessageForAudio
(
inText
);
// Prepend high priority text with alert beep
// Prepend high priority text with alert beep
if
(
severity
<
GAudioOutput
::
AUDIO_SEVERITY_CRITICAL
)
{
if
(
severity
<
GAudioOutput
::
AUDIO_SEVERITY_CRITICAL
)
{
beep
();
beep
();
...
@@ -124,26 +169,13 @@ void QGCAudioWorker::say(QString inText, int severity)
...
@@ -124,26 +169,13 @@ void QGCAudioWorker::say(QString inText, int severity)
espeak_Synth
(
text
.
toStdString
().
c_str
(),
espeak_size
,
0
,
POS_CHARACTER
,
0
,
espeakCHARS_AUTO
,
NULL
,
NULL
);
espeak_Synth
(
text
.
toStdString
().
c_str
(),
espeak_size
,
0
,
POS_CHARACTER
,
0
,
espeakCHARS_AUTO
,
NULL
,
NULL
);
#elif defined Q_OS_MAC && defined QGC_SPEECH_ENABLED
#elif defined Q_OS_MAC && defined QGC_SPEECH_ENABLED
// Slashes necessary to have the right start to the sentence
macSpeech
.
say
(
text
.
toStdString
().
c_str
());
// copying data prevents SpeakString from reading additional chars
text
=
"
\\
"
+
text
;
std
::
wstring
str
=
text
.
toStdWString
();
unsigned
char
str2
[
1024
]
=
{};
memcpy
(
str2
,
text
.
toLatin1
().
data
(),
str
.
length
());
SpeakString
(
str2
);
// Block the thread while busy
// because we run in our own thread, this doesn't
// halt the main application
while
(
SpeechBusy
())
{
QGC
::
SLEEP
::
msleep
(
100
);
}
#else
#else
// Make sure there isn't an unused variable warning when speech output is disabled
// Make sure there isn't an unused variable warning when speech output is disabled
Q_UNUSED
(
inText
);
Q_UNUSED
(
inText
);
#endif
#endif
}
}
#endif // __android__
}
}
void
QGCAudioWorker
::
mute
(
bool
mute
)
void
QGCAudioWorker
::
mute
(
bool
mute
)
...
@@ -187,7 +219,7 @@ bool QGCAudioWorker::_getMillisecondString(const QString& string, QString& match
...
@@ -187,7 +219,7 @@ bool QGCAudioWorker::_getMillisecondString(const QString& string, QString& match
return
false
;
return
false
;
}
}
QString
QGCAudioWorker
::
_
fixTextMessageForAudio
(
const
QString
&
string
)
{
QString
QGCAudioWorker
::
fixTextMessageForAudio
(
const
QString
&
string
)
{
QString
match
;
QString
match
;
QString
newNumber
;
QString
newNumber
;
QString
result
=
string
;
QString
result
=
string
;
...
@@ -204,7 +236,9 @@ QString QGCAudioWorker::_fixTextMessageForAudio(const QString& string) {
...
@@ -204,7 +236,9 @@ QString QGCAudioWorker::_fixTextMessageForAudio(const QString& string) {
if
(
result
.
contains
(
"ALTCTL"
,
Qt
::
CaseInsensitive
))
{
if
(
result
.
contains
(
"ALTCTL"
,
Qt
::
CaseInsensitive
))
{
result
.
replace
(
"ALTCTL"
,
"Altitude Control"
,
Qt
::
CaseInsensitive
);
result
.
replace
(
"ALTCTL"
,
"Altitude Control"
,
Qt
::
CaseInsensitive
);
}
}
if
(
result
.
contains
(
"RTL"
,
Qt
::
CaseInsensitive
))
{
if
(
result
.
contains
(
"AUTO_RTL"
,
Qt
::
CaseInsensitive
))
{
result
.
replace
(
"AUTO_RTL"
,
"auto Return To Land"
,
Qt
::
CaseInsensitive
);
}
else
if
(
result
.
contains
(
"RTL"
,
Qt
::
CaseInsensitive
))
{
result
.
replace
(
"RTL"
,
"Return To Land"
,
Qt
::
CaseInsensitive
);
result
.
replace
(
"RTL"
,
"Return To Land"
,
Qt
::
CaseInsensitive
);
}
}
if
(
result
.
contains
(
"ACCEL "
,
Qt
::
CaseInsensitive
))
{
if
(
result
.
contains
(
"ACCEL "
,
Qt
::
CaseInsensitive
))
{
...
...
src/audio/QGCAudioWorker.h
View file @
7abe60d1
...
@@ -7,13 +7,6 @@
...
@@ -7,13 +7,6 @@
#include <QSound>
#include <QSound>
#endif
#endif
/* For Snow leopard and later
#if defined Q_OS_MAC & defined QGC_SPEECH_ENABLED
#include <NSSpeechSynthesizer.h>
#endif
*/
#if defined _MSC_VER && defined QGC_SPEECH_ENABLED
#if defined _MSC_VER && defined QGC_SPEECH_ENABLED
// Documentation: http://msdn.microsoft.com/en-us/library/ee125082%28v=VS.85%29.aspx
// Documentation: http://msdn.microsoft.com/en-us/library/ee125082%28v=VS.85%29.aspx
#include <basetyps.h>
#include <basetyps.h>
...
@@ -31,6 +24,8 @@ public:
...
@@ -31,6 +24,8 @@ public:
bool
isMuted
();
bool
isMuted
();
void
init
();
void
init
();
static
QString
fixTextMessageForAudio
(
const
QString
&
string
);
signals:
signals:
public
slots
:
public
slots
:
...
@@ -52,8 +47,7 @@ protected:
...
@@ -52,8 +47,7 @@ protected:
QTimer
*
emergencyTimer
;
QTimer
*
emergencyTimer
;
bool
muted
;
bool
muted
;
private:
private:
QString
_fixTextMessageForAudio
(
const
QString
&
string
);
static
bool
_getMillisecondString
(
const
QString
&
string
,
QString
&
match
,
int
&
number
);
bool
_getMillisecondString
(
const
QString
&
string
,
QString
&
match
,
int
&
number
);
};
};
#endif // QGCAUDIOWORKER_H
#endif // QGCAUDIOWORKER_H
src/uas/UAS.cc
View file @
7abe60d1
...
@@ -422,7 +422,7 @@ void UAS::receiveMessage(mavlink_message_t message)
...
@@ -422,7 +422,7 @@ void UAS::receiveMessage(mavlink_message_t message)
modechanged
=
true
;
modechanged
=
true
;
this
->
base_mode
=
state
.
base_mode
;
this
->
base_mode
=
state
.
base_mode
;
this
->
custom_mode
=
state
.
custom_mode
;
this
->
custom_mode
=
state
.
custom_mode
;
modeAudio
=
" is now in "
+
audiomodeText
+
"flight mode"
;
modeAudio
=
" is now in "
+
audiomodeText
+
"
flight mode"
;
}
}
// We got the mode
// We got the mode
...
@@ -2470,10 +2470,6 @@ void UAS::unsetRCToParameterMap()
...
@@ -2470,10 +2470,6 @@ void UAS::unsetRCToParameterMap()
void
UAS
::
_say
(
const
QString
&
text
,
int
severity
)
void
UAS
::
_say
(
const
QString
&
text
,
int
severity
)
{
{
#ifndef UNITTEST_BUILD
if
(
!
qgcApp
()
->
runningUnitTests
())
GAudioOutput
::
instance
()
->
say
(
text
,
severity
);
GAudioOutput
::
instance
()
->
say
(
text
,
severity
);
#else
Q_UNUSED
(
text
)
Q_UNUSED
(
severity
)
#endif
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment