29 #include <yarp/os/BufferedPort.h>
30 #include <yarp/os/ResourceFinder.h>
31 #include <yarp/os/RFModule.h>
32 #include <yarp/os/Network.h>
33 #include <yarp/os/Time.h>
34 #include <yarp/os/Log.h>
35 #include <yarp/os/LogStream.h>
36 #include <yarp/os/Semaphore.h>
37 #include <yarp/sig/SoundFile.h>
38 #include <yarp/dev/PolyDriver.h>
40 #include <grpc++/grpc++.h>
41 #include "google/cloud/language/v1/language_service.grpc.pb.h"
42 #include "google/cloud/texttospeech/v1/cloud_tts.grpc.pb.h"
44 #include "googleSynthesis_IDL.h"
46 using namespace google::cloud::language::v1;
47 using namespace google::cloud::texttospeech::v1;
52 static const std::map<grpc::StatusCode, std::string> status_code_to_string {
54 {grpc::CANCELLED,
"cancelled"},
55 {grpc::UNKNOWN,
"unknown"},
56 {grpc::INVALID_ARGUMENT,
"invalid_argument"},
57 {grpc::DEADLINE_EXCEEDED,
"deadline_exceeded"},
58 {grpc::NOT_FOUND,
"not_found"},
59 {grpc::ALREADY_EXISTS,
"already_exists"},
60 {grpc::PERMISSION_DENIED,
"permission_denied"},
61 {grpc::UNAUTHENTICATED,
"unauthenticated"},
62 {grpc::RESOURCE_EXHAUSTED ,
"resource_exhausted"},
63 {grpc::FAILED_PRECONDITION,
"failed_precondition"},
64 {grpc::ABORTED,
"aborted"},
65 {grpc::OUT_OF_RANGE,
"out_of_range"},
66 {grpc::UNIMPLEMENTED,
"unimplemented"},
67 {grpc::INTERNAL,
"internal"},
68 {grpc::UNAVAILABLE,
"unavailable"},
69 {grpc::DATA_LOSS,
"data_loss"},
70 {grpc::DO_NOT_USE,
"do_not_use"}
73 class Processing :
public yarp::os::BufferedPort<yarp::os::Bottle>
75 std::string moduleName;
81 yarp::os::RpcServer handlerPort;
82 yarp::os::Port syncPort;
83 yarp::os::Port soundOutputPort;
87 sendToPort_compressed=1,
88 sendToPort_uncompressed=2
94 Processing(
const std::string &moduleName,
const std::string &language,
const std::string &voice,
const double &speed,
const double &pitch, std::string &state,
string playmode ): state(state)
96 this->moduleName = moduleName;
97 this->language = language;
101 if (playmode==
"playFromDisk") {playbackmode=playbackmode_t::playFromDisk;}
102 else if (playmode==
"sendToPort_compressed") {playbackmode=playbackmode_t::sendToPort_compressed;}
103 else if (playmode==
"sendToPort_uncompressed") {playbackmode=playbackmode_t::sendToPort_uncompressed;}
116 yarp::os::BufferedPort<yarp::os::Bottle >::open(
"/" + moduleName +
"/text:i" );
117 syncPort.open(
"/" + moduleName +
"/sync:o" );
119 if (playbackmode==playbackmode_t::sendToPort_compressed ||
120 playbackmode==playbackmode_t::sendToPort_uncompressed)
122 soundOutputPort.open(
"/"+moduleName+
"/sound:o");
131 yarp::os::BufferedPort<yarp::os::Bottle >::close();
133 if (playbackmode==playbackmode_t::sendToPort_compressed ||
134 playbackmode==playbackmode_t::sendToPort_uncompressed)
136 soundOutputPort.close();
143 yarp::os::Bottle syncBot;
144 syncBot.addString(
"done");
145 syncPort.write(syncBot);
146 yDebug() <<
"done querying google";
149 void onRead( yarp::os::Bottle &bot )
151 queryGoogleSynthesis(bot);
156 void queryGoogleSynthesis(yarp::os::Bottle& text)
158 yDebug() <<
"in queryGoogleSynthesis";
160 yDebug() <<
"Phrase is " << text.toString().c_str();
162 std::string tmp = text.toString();
164 tmp.erase(std::remove(tmp.begin(),tmp.end(),
'\"'),tmp.end());
166 yDebug() <<
"Phrase is now " << tmp.c_str();
168 std::string content = tmp;
170 if (content.size()>0)
172 SynthesizeSpeechRequest request;
173 SynthesizeSpeechResponse response;
176 grpc::ClientContext context;
178 auto creds = grpc::GoogleDefaultCredentials();
179 auto channel = grpc::CreateChannel(
"texttospeech.googleapis.com", creds);
180 std::unique_ptr<TextToSpeech::Stub> tts(TextToSpeech::NewStub(channel));
182 AudioConfig audio_config;
183 VoiceSelectionParams params;
185 SynthesisInput input;
186 input.set_text(content);
188 audio_config.set_audio_encoding(MP3);
189 params.set_language_code(language);
190 params.set_ssml_gender(NEUTRAL);
191 params.set_name(voice);
192 audio_config.set_speaking_rate(speed);
193 audio_config.set_pitch(pitch);
195 request.set_allocated_input(&input);
196 request.set_allocated_voice(¶ms);
197 request.set_allocated_audio_config(&audio_config);
200 yarp::os::Time::delay(0.2);
201 grpc::Status tts_status = tts->SynthesizeSpeech(&context, request, &response);
202 std::string status_string = status_code_to_string.at(tts_status.error_code());
203 yInfo() <<
"Status string:" << status_string;
206 if ( tts_status.ok() )
208 yInfo() <<
"Status returned OK";
209 yInfo() <<
"\n------Response------\n";
211 if (playbackmode==playbackmode_t::playFromDisk)
213 std::string file =
"test.mp3";
214 std::ofstream mp3File(file, std::ios::out | std::ios::binary);
216 mp3File.write( response.audio_content().data(), response.audio_content().size());
218 std::string command =
"play test.mp3";
220 system(command.c_str());
222 else if (playbackmode==playbackmode_t::sendToPort_compressed)
224 yarp::os::Value v (response.audio_content().data(), response.audio_content().size());
225 yarp::os::Bottle bot; bot.add(v);
226 soundOutputPort.write(bot);
228 else if (playbackmode==playbackmode_t::sendToPort_uncompressed)
230 yarp::sig::Sound snd;
231 yarp::sig::file::read_bytestream(snd, response.audio_content().data(), response.audio_content().size(),
".mp3");
232 soundOutputPort.write(snd);
236 yError() <<
"Invalid playbackmode";
241 yError() <<
"Status Returned Cancelled";
242 checkState(
"Failure_" + status_string);
243 yInfo() << tts_status.error_message();
246 request.release_input();
247 request.release_voice();
248 request.release_audio_config();
250 yInfo() <<
"\n------finished google query------\n";
252 else if (content.size()==0)
254 checkState(
"Empty_input");
258 bool start_acquisition()
264 bool stop_acquisition()
271 bool setLanguageCode(
const std::string &languageCode)
273 language = languageCode;
278 bool setVoiceCode(
const std::string &voiceCode)
285 bool setPitch(
const double pitchVal)
292 bool setSpeed(
const double speedVal)
298 std::string getLanguageCode()
304 std::string getVoiceCode()
322 bool checkState(std::string new_state)
324 if(new_state!=state){
336 class Module :
public yarp::os::RFModule,
public googleSynthesis_IDL
338 yarp::os::ResourceFinder *rf;
339 yarp::os::RpcServer rpcPort;
340 yarp::os::BufferedPort<yarp::os::Bottle> statePort;
343 Processing *processing;
344 friend class processing;
348 std::vector<std::string> allLanguageCodes;
349 std::vector<std::string> allVoiceCodes;
356 bool configure(yarp::os::ResourceFinder &rf)
360 std::string moduleName = rf.check(
"name", yarp::os::Value(
"googleSynthesis"),
"module name (string)").asString();
362 std::string language = rf.check(
"language", yarp::os::Value(
"en-US"),
"language to use (string)").asString();
363 std::string voice = rf.check(
"voice", yarp::os::Value(
"en-US-Wavenet-D"),
"voice to use (string)").asString();
365 double speed = rf.check(
"speed", yarp::os::Value(1.0),
"speed to use (double)").asFloat64();
366 double pitch = rf.check(
"pitch", yarp::os::Value(0.0),
"pitch to use (double)").asFloat64();
368 string playmode_string = rf.check(
"playbackmode", yarp::os::Value(
"playFromDisk"),
"can be one of the following: `playFromDisk`(default), `sendToPort_compressed`, `sendToPort_uncompressed`").asString();
370 if (rf.check(
"languageCodes",
"Getting language codes"))
372 yarp::os::Bottle &grp=rf.findGroup(
"languageCodes");
375 for (
int i=0; i<sz; i++)
376 allLanguageCodes.push_back(grp.get(1+i).asString());
379 if (rf.check(
"voiceCodes",
"Getting voice codes"))
381 yarp::os::Bottle &grp=rf.findGroup(
"voiceCodes");
384 for (
int i=0; i<sz; i++)
385 allVoiceCodes.push_back(grp.get(1+i).asString());
388 setName(moduleName.c_str());
390 rpcPort.open((
"/"+getName(
"/rpc")).c_str());
391 statePort.open(
"/"+ moduleName +
"/state:o");
395 processing =
new Processing( moduleName, language, voice, speed, pitch, state, playmode_string);
400 if(!attach(rpcPort)) {
401 yError()<<
"Cannot attach to rpc port";
409 bool attach(yarp::os::RpcServer &source)
411 return this->yarp().attachAsServer(source);
430 bool say(
const std::string& phrase)
432 yarp::os::Bottle bot;
433 bot.addString(phrase);
434 processing->queryGoogleSynthesis(bot);
435 processing->sendDone();
440 std::string setLanguage(
const std::string& languageCode,
const std::string& voiceCode)
442 std::string returnVal =
"Error, wrong language or voice code (eg: en-US en-US-Wavenet-A)";
444 std::string language, voice;
446 for (
int i = 0; i < allLanguageCodes.size(); i++)
448 if (languageCode == allLanguageCodes[i])
450 for (
int v = 0; v < allVoiceCodes.size(); v++)
452 if (voiceCode == allVoiceCodes[v])
454 language = languageCode;
464 if(returnVal ==
"[ok]")
466 processing->setLanguageCode(languageCode);
467 processing->setVoiceCode(voiceCode);
473 bool setPitch(
const double pitchVal)
475 processing->setPitch(pitchVal);
480 bool setSpeed(
const double speedVal)
482 processing->setSpeed(speedVal);
487 std::string getLanguageCode()
489 return processing->getLanguageCode();
493 std::string getVoiceCode()
495 return processing->getVoiceCode();
501 return processing->getPitch();
507 return processing->getSpeed();
522 yarp::os::Bottle &outTargets = statePort.prepare();
524 outTargets.addString(state);
525 yDebug() <<
"outTarget:" << outTargets.toString().c_str();
533 int main(
int argc,
char *argv[])
535 yarp::os::Network::init();
537 yarp::os::Network yarp;
538 if (!yarp.checkNetwork())
540 yError(
"YARP server not available!");
545 yarp::os::ResourceFinder rf;
547 rf.setVerbose(
true );
548 rf.setDefaultContext(
"googleSynthesis" );
549 rf.setDefaultConfigFile(
"config.ini" );
550 rf.setDefault(
"name",
"googleSynthesis");
551 rf.configure(argc,argv);
553 return module.runModule(rf);