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
f5d2c570
Commit
f5d2c570
authored
Dec 08, 2014
by
Lorenz Meier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Put audio output into a worker thread.
parent
fa69b34c
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
244 additions
and
223 deletions
+244
-223
qgroundcontrol.pro
qgroundcontrol.pro
+5
-2
GAudioOutput.cc
src/GAudioOutput.cc
+35
-179
GAudioOutput.h
src/GAudioOutput.h
+10
-42
QGCAudioWorker.cpp
src/audio/QGCAudioWorker.cpp
+143
-0
QGCAudioWorker.h
src/audio/QGCAudioWorker.h
+51
-0
No files found.
qgroundcontrol.pro
View file @
f5d2c570
...
@@ -243,6 +243,7 @@ INCLUDEPATH += \
...
@@ -243,6 +243,7 @@ INCLUDEPATH += \
src
/
ui
/
map
\
src
/
ui
/
map
\
src
/
uas
\
src
/
uas
\
src
/
comm
\
src
/
comm
\
src
/
audio
\
include
/
ui
\
include
/
ui
\
src
/
input
\
src
/
input
\
src
/
lib
/
qmapcontrol
\
src
/
lib
/
qmapcontrol
\
...
@@ -479,7 +480,8 @@ HEADERS += \
...
@@ -479,7 +480,8 @@ HEADERS += \
src
/
QGCFileDialog
.
h
\
src
/
QGCFileDialog
.
h
\
src
/
QGCMessageBox
.
h
\
src
/
QGCMessageBox
.
h
\
src
/
QGCComboBox
.
h
\
src
/
QGCComboBox
.
h
\
src
/
QGCTemporaryFile
.
h
src
/
QGCTemporaryFile
.
h
\
src
/
audio
/
QGCAudioWorker
.
h
SOURCES
+=
\
SOURCES
+=
\
src
/
main
.
cc
\
src
/
main
.
cc
\
...
@@ -618,7 +620,8 @@ SOURCES += \
...
@@ -618,7 +620,8 @@ SOURCES += \
src
/
uas
/
QGXPX4UAS
.
cc
\
src
/
uas
/
QGXPX4UAS
.
cc
\
src
/
QGCFileDialog
.
cc
\
src
/
QGCFileDialog
.
cc
\
src
/
QGCComboBox
.
cc
\
src
/
QGCComboBox
.
cc
\
src
/
QGCTemporaryFile
.
cc
src
/
QGCTemporaryFile
.
cc
\
src
/
audio
/
QGCAudioWorker
.
cpp
#
#
...
...
src/GAudioOutput.cc
View file @
f5d2c570
...
@@ -33,28 +33,8 @@ This file is part of the QGROUNDCONTROL project
...
@@ -33,28 +33,8 @@ This file is part of the QGROUNDCONTROL project
#include <QApplication>
#include <QApplication>
#include <QSettings>
#include <QSettings>
#include "GAudioOutput.h"
#include "GAudioOutput.h"
#include "MG.h"
#include <QDebug>
#include <QDebug>
#include <QGC.h>
#if defined Q_OS_MAC && defined QGC_SPEECH_ENABLED
#include <ApplicationServices/ApplicationServices.h>
#endif
// Speech synthesis is only supported with MSVC compiler
#if defined _MSC_VER && defined QGC_SPEECH_ENABLED
// Documentation: http://msdn.microsoft.com/en-us/library/ee125082%28v=VS.85%29.aspx
#include <sapi.h>
#endif
#if defined Q_OS_LINUX && defined QGC_SPEECH_ENABLED
// Using eSpeak for speech synthesis: following https://github.com/mondhs/espeak-sample/blob/master/sampleSpeak.cpp
#include <espeak/speak_lib.h>
#endif
#if defined _MSC_VER && defined QGC_SPEECH_ENABLED
ISpVoice
*
GAudioOutput
::
pVoice
=
NULL
;
#endif
/**
/**
* This class follows the singleton design pattern
* This class follows the singleton design pattern
...
@@ -78,134 +58,44 @@ GAudioOutput *GAudioOutput::instance()
...
@@ -78,134 +58,44 @@ GAudioOutput *GAudioOutput::instance()
return
_instance
;
return
_instance
;
}
}
#define QGC_GAUDIOOUTPUT_KEY QString("QGC_AUDIOOUTPUT_")
GAudioOutput
::
GAudioOutput
(
QObject
*
parent
)
:
QObject
(
parent
),
GAudioOutput
::
GAudioOutput
(
QObject
*
parent
)
:
QObject
(
parent
),
voiceIndex
(
0
),
muted
(
false
),
emergency
(
false
),
thread
(
new
QThread
()
),
muted
(
false
)
worker
(
new
QGCAudioWorker
()
)
{
{
// Load settings
worker
->
moveToThread
(
thread
);
QSettings
settings
;
connect
(
this
,
SIGNAL
(
textToSpeak
(
QString
,
int
)),
worker
,
SLOT
(
say
(
QString
,
int
)));
muted
=
settings
.
value
(
QGC_GAUDIOOUTPUT_KEY
+
"muted"
,
muted
).
toBool
();
thread
->
start
();
#if defined Q_OS_LINUX && defined QGC_SPEECH_ENABLED
espeak_Initialize
(
AUDIO_OUTPUT_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
->
languages
=
"en-uk"
;
// Default to British English
espeak_voice
->
identifier
=
NULL
;
// no specific voice file specified
espeak_voice
->
name
=
"klatt"
;
// espeak voice name
espeak_voice
->
gender
=
2
;
// Female
espeak_voice
->
age
=
0
;
// age not specified
espeak_SetVoiceByProperties
(
espeak_voice
);
#endif
#if defined _MSC_VER && defined QGC_SPEECH_ENABLED
pVoice
=
NULL
;
if
(
FAILED
(
::
CoInitialize
(
NULL
)))
{
qDebug
()
<<
"ERROR: Creating COM object for audio output failed!"
;
}
else
{
HRESULT
hr
=
CoCreateInstance
(
CLSID_SpVoice
,
NULL
,
CLSCTX_ALL
,
IID_ISpVoice
,
(
void
**
)
&
pVoice
);
if
(
FAILED
(
hr
))
{
qDebug
()
<<
"ERROR: Initializing voice for audio output failed!"
;
}
}
#endif
// Prepare regular emergency signal, will be fired off on calling startEmergency()
emergencyTimer
=
new
QTimer
();
connect
(
emergencyTimer
,
SIGNAL
(
timeout
()),
this
,
SLOT
(
beep
()));
switch
(
voiceIndex
)
{
case
0
:
selectFemaleVoice
();
break
;
default:
selectMaleVoice
();
break
;
}
}
}
GAudioOutput
::~
GAudioOutput
()
GAudioOutput
::~
GAudioOutput
()
{
{
#if defined _MSC_VER && defined QGC_SPEECH_ENABLED
thread
->
quit
();
pVoice
->
Release
();
while
(
thread
->
isRunning
())
{
pVoice
=
NULL
;
QGC
::
SLEEP
::
usleep
(
100
);
::
CoUninitialize
();
}
#endif
worker
->
deleteLater
();
thread
->
deleteLater
();
worker
=
NULL
;
thread
=
NULL
;
}
}
void
GAudioOutput
::
mute
(
bool
mute
)
void
GAudioOutput
::
mute
(
bool
mute
)
{
{
if
(
mute
!=
muted
)
// XXX handle muting
{
this
->
muted
=
mute
;
QSettings
settings
;
settings
.
setValue
(
QGC_GAUDIOOUTPUT_KEY
+
"muted"
,
this
->
muted
);
emit
mutedChanged
(
muted
);
}
}
}
bool
GAudioOutput
::
isMuted
()
bool
GAudioOutput
::
isMuted
()
{
{
return
this
->
muted
;
// XXX return right stuff
return
false
;
}
}
bool
GAudioOutput
::
say
(
QString
text
,
int
severity
)
bool
GAudioOutput
::
say
(
QString
text
,
int
severity
)
{
{
if
(
!
muted
)
emit
textToSpeak
(
text
,
severity
);
{
return
true
;
// TODO Add severity filter
Q_UNUSED
(
severity
);
bool
res
=
false
;
if
(
!
emergency
)
{
#if defined _MSC_VER && defined QGC_SPEECH_ENABLED
pVoice
->
Speak
(
text
.
toStdWString
().
c_str
(),
SPF_ASYNC
,
NULL
);
#elif defined Q_OS_LINUX && defined QGC_SPEECH_ENABLED
// Set size of string for espeak: +1 for the null-character
unsigned
int
espeak_size
=
strlen
(
text
.
toStdString
().
c_str
())
+
1
;
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
// Slashes necessary to have the right start to the sentence
// 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
);
res
=
true
;
#else
// Make sure there isn't an unused variable warning when speech output is disabled
Q_UNUSED
(
text
);
#endif
}
return
res
;
}
else
{
return
false
;
}
}
}
/**
/**
...
@@ -213,19 +103,8 @@ bool GAudioOutput::say(QString text, int severity)
...
@@ -213,19 +103,8 @@ bool GAudioOutput::say(QString text, int severity)
*/
*/
bool
GAudioOutput
::
alert
(
QString
text
)
bool
GAudioOutput
::
alert
(
QString
text
)
{
{
if
(
!
emergency
||
!
muted
)
emit
textToSpeak
(
text
,
2
);
{
return
true
;
// Play alert sound
beep
();
// Say alert message
say
(
text
,
2
);
return
true
;
}
else
{
return
false
;
}
}
}
void
GAudioOutput
::
notifyPositive
()
void
GAudioOutput
::
notifyPositive
()
...
@@ -261,16 +140,16 @@ void GAudioOutput::notifyNegative()
...
@@ -261,16 +140,16 @@ void GAudioOutput::notifyNegative()
*/
*/
bool
GAudioOutput
::
startEmergency
()
bool
GAudioOutput
::
startEmergency
()
{
{
if
(
!
emergency
)
//
if (!emergency)
{
//
{
emergency
=
true
;
//
emergency = true;
// Beep immediately and then start timer
//
// Beep immediately and then start timer
if
(
!
muted
)
beep
();
//
if (!muted) beep();
emergencyTimer
->
start
(
1500
);
//
emergencyTimer->start(1500);
QTimer
::
singleShot
(
5000
,
this
,
SLOT
(
stopEmergency
()));
//
QTimer::singleShot(5000, this, SLOT(stopEmergency()));
}
//
}
return
true
;
return
true
;
}
}
...
@@ -283,11 +162,11 @@ bool GAudioOutput::startEmergency()
...
@@ -283,11 +162,11 @@ bool GAudioOutput::startEmergency()
*/
*/
bool
GAudioOutput
::
stopEmergency
()
bool
GAudioOutput
::
stopEmergency
()
{
{
if
(
emergency
)
//
if (emergency)
{
//
{
emergency
=
false
;
//
emergency = false;
emergencyTimer
->
stop
();
//
emergencyTimer->stop();
}
//
}
return
true
;
return
true
;
}
}
...
@@ -304,26 +183,3 @@ void GAudioOutput::beep()
...
@@ -304,26 +183,3 @@ void GAudioOutput::beep()
//m_media->play();
//m_media->play();
}
}
}
}
void
GAudioOutput
::
selectFemaleVoice
()
{
#if defined Q_OS_LINUX && defined QGC_SPEECH_ENABLED
// FIXME: Enable selecting a female voice on all platforms
//this->voice = register_cmu_us_slt(NULL);
#endif
}
void
GAudioOutput
::
selectMaleVoice
()
{
#if defined Q_OS_LINUX && defined QGC_SPEECH_ENABLED
// FIXME: Enable selecting a male voice on all platforms
//this->voice = register_cmu_us_rms(NULL);
#endif
}
QStringList
GAudioOutput
::
listVoices
(
void
)
{
// No voice selection is currently supported, so just return an empty list
QStringList
l
;
return
l
;
}
src/GAudioOutput.h
View file @
f5d2c570
...
@@ -34,31 +34,10 @@ This file is part of the PIXHAWK project
...
@@ -34,31 +34,10 @@ This file is part of the PIXHAWK project
#include <QObject>
#include <QObject>
#include <QTimer>
#include <QTimer>
#include <QThread>
#include <QStringList>
#include <QStringList>
#ifdef Q_OS_MAC
//#include <MediaObject>
#include <QGCAudioWorker.h>
//#include <AudioOutput>
#endif
#ifdef Q_OS_LINUX
//#include <phonon/MediaObject>
//#include <phonon/AudioOutput>
#endif
#ifdef Q_OS_WIN
//#include <Phonon/MediaObject>
//#include <Phonon/AudioOutput>
#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
// Documentation: http://msdn.microsoft.com/en-us/library/ee125082%28v=VS.85%29.aspx
#include <sapi.h>
#endif
/**
/**
* @brief Audio Output (speech synthesizer and "beep" output)
* @brief Audio Output (speech synthesizer and "beep" output)
...
@@ -91,10 +70,10 @@ public slots:
...
@@ -91,10 +70,10 @@ public slots:
bool
startEmergency
();
bool
startEmergency
();
/** @brief Stop emergency sound */
/** @brief Stop emergency sound */
bool
stopEmergency
();
bool
stopEmergency
();
/** @brief Select female voice */
//
/** @brief Select female voice */
void
selectFemaleVoice
();
//
void selectFemaleVoice();
/** @brief Select male voice */
//
/** @brief Select male voice */
void
selectMaleVoice
();
//
void selectMaleVoice();
/** @brief Play emergency sound once */
/** @brief Play emergency sound once */
void
beep
();
void
beep
();
/** @brief Notify about positive event */
/** @brief Notify about positive event */
...
@@ -106,23 +85,12 @@ public slots:
...
@@ -106,23 +85,12 @@ public slots:
signals:
signals:
void
mutedChanged
(
bool
);
void
mutedChanged
(
bool
);
bool
textToSpeak
(
QString
text
,
int
severity
=
1
);
protected:
protected:
#if defined Q_OS_MAC && defined QGC_SPEECH_ENABLED
//NSSpeechSynthesizer
#endif
#if defined Q_OS_LINUX && defined QGC_SPEECH_ENABLED
//cst_voice* voice; ///< The flite voice object
#endif
#if defined _MSC_VER && defined QGC_SPEECH_ENABLED
static
ISpVoice
*
pVoice
;
#endif
int
voiceIndex
;
///< The index of the flite voice to use (awb, slt, rms)
//Phonon::MediaObject *m_media; ///< The output object for audio
//Phonon::AudioOutput *m_audioOutput;
bool
emergency
;
///< Emergency status flag
QTimer
*
emergencyTimer
;
bool
muted
;
bool
muted
;
QThread
*
thread
;
QGCAudioWorker
*
worker
;
private:
private:
GAudioOutput
(
QObject
*
parent
=
NULL
);
GAudioOutput
(
QObject
*
parent
=
NULL
);
~
GAudioOutput
();
~
GAudioOutput
();
...
...
src/audio/QGCAudioWorker.cpp
0 → 100644
View file @
f5d2c570
#include <QSettings>
#include <QDebug>
#include "QGC.h"
#include "QGCAudioWorker.h"
#if defined Q_OS_MAC && defined QGC_SPEECH_ENABLED
#include <ApplicationServices/ApplicationServices.h>
#endif
// Speech synthesis is only supported with MSVC compiler
#if defined _MSC_VER && defined QGC_SPEECH_ENABLED
// Documentation: http://msdn.microsoft.com/en-us/library/ee125082%28v=VS.85%29.aspx
#include <sapi.h>
#endif
#if defined Q_OS_LINUX && defined QGC_SPEECH_ENABLED
// Using eSpeak for speech synthesis: following https://github.com/mondhs/espeak-sample/blob/master/sampleSpeak.cpp
#include <espeak/speak_lib.h>
#endif
#if defined _MSC_VER && defined QGC_SPEECH_ENABLED
ISpVoice
*
GAudioOutput
::
pVoice
=
NULL
;
#endif
#define QGC_GAUDIOOUTPUT_KEY QString("QGC_AUDIOOUTPUT_")
QGCAudioWorker
::
QGCAudioWorker
(
QObject
*
parent
)
:
QObject
(
parent
),
voiceIndex
(
0
),
emergency
(
false
),
muted
(
false
)
{
// Load settings
QSettings
settings
;
muted
=
settings
.
value
(
QGC_GAUDIOOUTPUT_KEY
+
"muted"
,
muted
).
toBool
();
#if defined Q_OS_LINUX && defined QGC_SPEECH_ENABLED
espeak_Initialize
(
AUDIO_OUTPUT_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
->
languages
=
"en-uk"
;
// Default to British English
espeak_voice
->
identifier
=
NULL
;
// no specific voice file specified
espeak_voice
->
name
=
"klatt"
;
// espeak voice name
espeak_voice
->
gender
=
2
;
// Female
espeak_voice
->
age
=
0
;
// age not specified
espeak_SetVoiceByProperties
(
espeak_voice
);
#endif
#if defined _MSC_VER && defined QGC_SPEECH_ENABLED
pVoice
=
NULL
;
if
(
FAILED
(
::
CoInitialize
(
NULL
)))
{
qDebug
()
<<
"ERROR: Creating COM object for audio output failed!"
;
}
else
{
HRESULT
hr
=
CoCreateInstance
(
CLSID_SpVoice
,
NULL
,
CLSCTX_ALL
,
IID_ISpVoice
,
(
void
**
)
&
pVoice
);
if
(
FAILED
(
hr
))
{
qDebug
()
<<
"ERROR: Initializing voice for audio output failed!"
;
}
}
#endif
// Prepare regular emergency signal, will be fired off on calling startEmergency()
emergencyTimer
=
new
QTimer
();
connect
(
emergencyTimer
,
SIGNAL
(
timeout
()),
this
,
SLOT
(
beep
()));
}
QGCAudioWorker
::~
QGCAudioWorker
()
{
#if defined _MSC_VER && defined QGC_SPEECH_ENABLED
pVoice
->
Release
();
pVoice
=
NULL
;
::
CoUninitialize
();
#endif
}
void
QGCAudioWorker
::
say
(
QString
text
,
int
severity
)
{
qDebug
()
<<
"TEXT"
<<
text
;
if
(
!
muted
)
{
// TODO Add severity filter
Q_UNUSED
(
severity
);
bool
res
=
false
;
if
(
!
emergency
)
{
#if defined _MSC_VER && defined QGC_SPEECH_ENABLED
pVoice
->
Speak
(
text
.
toStdWString
().
c_str
(),
SPF_ASYNC
,
NULL
);
#elif defined Q_OS_LINUX && defined QGC_SPEECH_ENABLED
// Set size of string for espeak: +1 for the null-character
unsigned
int
espeak_size
=
strlen
(
text
.
toStdString
().
c_str
())
+
1
;
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
// Slashes necessary to have the right start to the sentence
// 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
// Make sure there isn't an unused variable warning when speech output is disabled
Q_UNUSED
(
text
);
#endif
}
}
}
void
QGCAudioWorker
::
mute
(
bool
mute
)
{
if
(
mute
!=
muted
)
{
this
->
muted
=
mute
;
QSettings
settings
;
settings
.
setValue
(
QGC_GAUDIOOUTPUT_KEY
+
"muted"
,
this
->
muted
);
// emit mutedChanged(muted);
}
}
bool
QGCAudioWorker
::
isMuted
()
{
return
this
->
muted
;
}
src/audio/QGCAudioWorker.h
0 → 100644
View file @
f5d2c570
#ifndef QGCAUDIOWORKER_H
#define QGCAUDIOWORKER_H
#include <QObject>
#include <QTimer>
/* 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
// Documentation: http://msdn.microsoft.com/en-us/library/ee125082%28v=VS.85%29.aspx
#include <sapi.h>
#endif
class
QGCAudioWorker
:
public
QObject
{
Q_OBJECT
public:
explicit
QGCAudioWorker
(
QObject
*
parent
=
0
);
~
QGCAudioWorker
();
void
mute
(
bool
mute
);
bool
isMuted
();
signals:
public
slots
:
/** @brief Say this text if current output priority matches */
void
say
(
QString
text
,
int
severity
=
1
);
protected:
#if defined Q_OS_MAC && defined QGC_SPEECH_ENABLED
//NSSpeechSynthesizer
#endif
#if defined Q_OS_LINUX && defined QGC_SPEECH_ENABLED
//cst_voice* voice; ///< The flite voice object
#endif
#if defined _MSC_VER && defined QGC_SPEECH_ENABLED
static
ISpVoice
*
pVoice
;
#endif
int
voiceIndex
;
///< The index of the flite voice to use (awb, slt, rms)
bool
emergency
;
///< Emergency status flag
QTimer
*
emergencyTimer
;
bool
muted
;
};
#endif // QGCAUDIOWORKER_H
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