30 #include "speaker.moc"
35 #include <QtCore/QFile>
36 #include <QtCore/QDir>
37 #include <QtGui/QApplication>
38 #include <QtDBus/QtDBus>
39 #include <QtXml/QDomDocument>
42 #include <kconfiggroup.h>
45 #include <kstandarddirs.h>
46 #include <ktemporaryfile.h>
47 #include <kservicetypetrader.h>
103 SpeakerPrivate(
Speaker *parent) :
106 config(new KConfig(QLatin1String(
"kttsdrc" ))),
114 spd_close(connection);
127 foreach (
AppData* applicationData, appData)
128 delete applicationData;
136 bool ConnectToSpeechd()
139 connection = spd_open(
"jovie",
"main", NULL, SPD_MODE_THREADED);
140 if (connection != NULL)
142 kDebug() <<
"successfully opened connection to speech dispatcher";
143 connection->callback_begin = connection->callback_end =
144 connection->callback_cancel = connection->callback_pause =
147 spd_set_notification_on(connection, SPD_BEGIN);
148 spd_set_notification_on(connection, SPD_END);
149 spd_set_notification_on(connection, SPD_CANCEL);
150 spd_set_notification_on(connection, SPD_PAUSE);
151 spd_set_notification_on(connection, SPD_RESUME);
152 char ** modulenames = spd_list_modules(connection);
153 while (modulenames != NULL && modulenames[0] != NULL)
170 spd_close(connection);
171 return ConnectToSpeechd();
174 void readTalkerData()
176 config->reparseConfiguration();
178 KConfigGroup ttsconfig(config,
"General");
179 QStringList talkerIDsList = ttsconfig.readEntry(
"TalkerIDs", QStringList());
181 if (!talkerIDsList.isEmpty())
183 QStringList::ConstIterator itEnd = talkerIDsList.constEnd();
184 for (QStringList::ConstIterator it = talkerIDsList.constBegin(); it != itEnd; ++it)
186 QString talkerID = *it;
187 kDebug() <<
"TalkerListWidget::loadTalkerCodes: talkerID = " << talkerID;
188 KConfigGroup talkGroup(config,
"Talkers");
189 QString talkerCode = talkGroup.readEntry(talkerID);
191 if (defaultTalker.name().isEmpty())
193 kDebug() <<
"TalkerCodeWidget::loadTalkerCodes: talkerCode = " << talkerCode;
197 currentTalker = defaultTalker;
200 q->setLanguage(defaultTalker.language());
201 q->setVoiceType(defaultTalker.voiceType());
202 q->setVolume(defaultTalker.volume());
203 q->setPitch(defaultTalker.pitch());
204 q->setSpeed(defaultTalker.rate());
213 SPDConnection * connection;
218 mutable QMap<QString, AppData*> appData;
247 Speaker * Speaker::m_instance = NULL;
251 if (m_instance == NULL)
260 kDebug() <<
"speechdCallback called with messageid: " << msg_id <<
" and type: " << type;
284 d(new SpeakerPrivate(this))
286 if (!d->ConnectToSpeechd())
288 kDebug() <<
"connection: " << d->connection;
289 kError() <<
"could not get a connection to speech-dispatcher"<< endl;
293 connect (QDBusConnection::sessionBus().interface(), SIGNAL(serviceUnregistered(QString)),
294 this, SLOT(slotServiceUnregistered(QString)));
298 kDebug() <<
"Running: Speaker::~Speaker()";
306 kDebug() <<
"Running: Speaker::init()";
309 d->filterMgr->init();
317 if (!d->appData.contains(appId))
318 d->appData.insert(appId,
new AppData(appId));
319 return d->appData[appId];
322 bool Speaker::isSsml(
const QString &text)
326 ssml.setContent(text,
false);
328 QDomElement root = ssml.documentElement();
329 return (root.tagName() == QLatin1String(
"speak" ));
332 QStringList Speaker::parseText(
const QString &text,
const QString &appId )
337 QStringList tempList(text);
341 QRegExp sentenceDelimiter(
getAppData(appId)->sentenceDelimiter());
344 temp.replace(QRegExp(QLatin1String(
"[ \\t\\f]+") ), QLatin1String(
" " ));
346 temp.replace(sentenceDelimiter, QLatin1String(
"\\1\t" ));
348 temp.replace(QLatin1Char(
'\n' ),QLatin1Char(
' ' ));
349 temp.replace(QLatin1Char(
'\r' ),QLatin1Char(
' ' ));
351 temp.replace(QRegExp(QLatin1String(
"\\t +" )), QLatin1String(
"\t" ));
353 temp.replace(QRegExp(QLatin1String(
" +\\t" )), QLatin1String(
"\t" ));
355 temp.replace(QRegExp(QLatin1String(
"\t\t+" )),QLatin1String(
"\t" ));
357 QStringList tempList = temp.split( QLatin1Char(
'\t' ), QString::SkipEmptyParts);
365 int Speaker::say(
const QString& appId,
const QString& text,
int sayOptions)
367 QString filteredText = text;
377 SPDPriority spdpriority = SPD_PROGRESS;
380 case KSpeech::jpScreenReaderOutput:
381 spdpriority = SPD_IMPORTANT;
383 case KSpeech::jpWarning:
384 spdpriority = SPD_NOTIFICATION;
386 case KSpeech::jpMessage:
387 spdpriority = SPD_MESSAGE;
389 case KSpeech::jpText:
390 spdpriority = SPD_TEXT;
392 case KSpeech::jpProgress:
393 spdpriority = SPD_PROGRESS;
398 filteredText = d->filterMgr->convert(text, &talkerCode, appId);
402 if (talkerCode != d->currentTalker)
404 kDebug() <<
"Changing language from " << d->currentTalker.getTranslatedDescription() <<
423 while (jobNum == -1 && d->connection != NULL)
427 case KSpeech::soNone:
428 jobNum = spd_say(d->connection, spdpriority, filteredText.toUtf8().data());
430 case KSpeech::soPlainText:
431 jobNum = spd_say(d->connection, spdpriority, filteredText.toUtf8().data());
433 case KSpeech::soHtml:
434 jobNum = spd_say(d->connection, spdpriority, filteredText.toUtf8().data());
436 case KSpeech::soSsml:
437 spd_set_data_mode(d->connection, SPD_DATA_SSML);
438 jobNum = spd_say(d->connection, spdpriority, filteredText.toUtf8().data());
439 spd_set_data_mode(d->connection, SPD_DATA_TEXT);
441 case KSpeech::soChar:
442 spd_set_spelling(d->connection, SPD_SPELL_ON);
443 jobNum = spd_say(d->connection, spdpriority, filteredText.toUtf8().data());
444 spd_set_spelling(d->connection, SPD_SPELL_OFF);
447 jobNum = spd_key(d->connection, spdpriority, filteredText.toUtf8().data());
449 case KSpeech::soSoundIcon:
450 jobNum = spd_sound_icon(d->connection, spdpriority, filteredText.toUtf8().data());
453 if (jobNum == -1 && d->connection != NULL)
457 kDebug() <<
"trying to reconnect to speech dispatcher";
461 kDebug() <<
"could not connect to speech dispatcher";
468 kDebug() <<
"incoming job with text: " << text;
469 kDebug() <<
"saying post filtered text: " << filteredText;
473 appData->
jobList()->append(jobNum);
498 kDebug() <<
"Speaker::setTalker this is not implemented yet in speech-dispatcher";
503 return d->outputModules;
508 QStringList languages;
509 if (d->connection && module != QLatin1String(
"dummy") &&
510 spd_set_output_module(d->connection, module.toUtf8().data()) == 0)
512 SPDVoice ** voices = spd_list_synthesis_voices(d->connection);
513 while (voices != NULL && voices[0] != NULL)
515 if (!languages.contains(QLatin1String( voices[0]->
language) ))
516 languages << QLatin1String( voices[0]->
language );
527 foreach (
const QString &module, d->outputModules)
530 spd_set_output_module(d->connection, module.toUtf8().data()) == 0)
532 SPDVoice ** voices = spd_list_synthesis_voices(d->connection);
533 kDebug() <<
"Got voices for output module " << module;
534 while (voices != NULL && voices[0] != NULL)
552 spd_set_voice_rate(d->connection, speed);
553 d->currentTalker.setRate(speed);
559 return d->currentTalker.rate();
565 spd_set_voice_pitch(d->connection, pitch);
566 d->currentTalker.setPitch(pitch);
572 return d->currentTalker.pitch();
578 spd_set_volume(d->connection, volume);
579 d->currentTalker.setVolume(volume);
585 return d->currentTalker.volume();
591 int result = spd_set_output_module(d->connection, module.toUtf8().data());
592 d->currentTalker.setOutputModule(module);
599 return d->currentTalker.outputModule();
605 int result = spd_set_synthesis_voice(d->connection, voiceName.toUtf8().data());
606 d->currentTalker.setVoiceName(voiceName);
612 return d->currentTalker.voiceName();
618 int result = spd_set_language(d->connection, language.toUtf8().data());
619 d->currentTalker.setLanguage(language);
626 return d->currentTalker.language();
632 int result = spd_set_voice_type(d->connection, SPDVoiceType(voiceType));
633 d->currentTalker.setVoiceType(voiceType);
640 return d->currentTalker.voiceType();
646 spd_stop(d->connection);
648 kDebug() <<
"unable to stop as there's no connection to speech-dispatcher";
654 spd_cancel(d->connection);
656 kDebug() <<
"unable to cancel as there's no connection to speech-dispatcher";
662 spd_pause(d->connection);
664 kDebug() <<
"unable to pause as there's no connection to speech-dispatcher";
670 spd_resume(d->connection);
672 kDebug() <<
"unable to resume as there's no connection to speech-dispatcher";
680 void Speaker::slotServiceUnregistered(
const QString& serviceName)
682 if (d->appData.contains(serviceName))
683 d->appData[serviceName]->setUnregistered(
true);
void requestExit()
Tells the thread to exit.
void setLanguage(const QString &language)
AppData * getAppData(const QString &appId) const
Get application data.
QString getTranslatedDescription() const
The Talker Code translated for display.
bool filteringOn() const
Returns the applications's current filtering enabled flag.
bool isApplicationPaused() const
Returns whether the jobs of the application are currently paused.
int findJobNumByAppId(const QString &appId) const
Given an appId, returns the last (most recently queued) Job Number with that appId, or if no such job, the Job Number of the last (most recent) job in the queue.
void setOutputModule(const QString &moduleName)
bool isApplicationPaused(const QString &appId)
Return true if the application is paused.
QString voiceName() const
void setOutputModule(const QString &module)
void cancel()
Stops the currently spoken message from this connection (if there is any) and discards all the queued...
void resume()
Resumes the speech.
int lastJobNum() const
Return the JobNum of the last job queued by the application.
void setVolume(int volume)
void setVoiceName(const QString &voiceName)
QString getTalkerCode() const
static Speaker * Instance()
singleton accessor
static QString languageCodeToLanguage(const QString &languageCode)
Converts a language code plus optional country code to language description.
void newJobFiltered(const QString &prefilterText, const QString &postfilterText)
This signal is emitted when a new job coming in is filtered (or not filtered if no filters are on)...
int say(const QString &appId, const QString &text, int sayOptions)
Queue and start a speech job.
KSpeech::JobPriority defaultPriority() const
Returns the default priority (job type) for the application.
bool isSpeaking()
Determine if kttsd is currently speaking any jobs.
QStringList languagesByModule(const QString &module)
void init()
(re)initializes the filtermgr
void stop()
Stops the message currently being spoken on a given connection.
QStringList outputModules()
Get the output modules available from speech-dispatcher.
void pause()
Pauses the speech.
QString outputModule() const
void setVoiceName(const QString &voiceName)
void setLanguage(const QString &language)
TJobListPtr jobList() const
List of jobs for this app.
void setTalker(int jobNum, const QString &talker)
Change the talker for a job.
QStringList getPossibleTalkers()
static void speechdCallback(size_t msg_id, size_t client_id, SPDNotificationType type)
void setVoiceType(int voiceType)