00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <ros/ros.h>
00019 #include <actionlib/server/simple_action_server.h>
00020 #include <diagnostic_msgs/DiagnosticArray.h>
00021 #include <visualization_msgs/Marker.h>
00022 #include <std_msgs/String.h>
00023 #include <std_srvs/Trigger.h>
00024 #include <cob_sound/SayAction.h>
00025 #include <cob_sound/PlayAction.h>
00026 #include <cob_srvs/SetString.h>
00027
00028 #include <vlc/vlc.h>
00029 #include <boost/filesystem.hpp>
00030 #include <boost/lexical_cast.hpp>
00031
00032 class SoundAction
00033 {
00034 protected:
00035
00036 ros::NodeHandle nh_;
00037 actionlib::SimpleActionServer<cob_sound::SayAction> as_say_;
00038 actionlib::SimpleActionServer<cob_sound::PlayAction> as_play_;
00039 ros::ServiceServer srvServer_say_;
00040 ros::ServiceServer srvServer_play_;
00041 ros::ServiceServer srvServer_stop_;
00042 ros::ServiceServer srvServer_mute_;
00043 ros::ServiceServer srvServer_unmute_;
00044 ros::Subscriber sub_say_;
00045 ros::Subscriber sub_play_;
00046 ros::Timer play_feedback_timer_;
00047 bool mute_;
00048 double fade_duration_;
00049 bool fade_volume_;
00050
00051 libvlc_instance_t* vlc_inst_;
00052 libvlc_media_player_t* vlc_player_;
00053 libvlc_media_t* vlc_media_;
00054
00055 public:
00056 diagnostic_msgs::DiagnosticArray diagnostics_;
00057 ros::Publisher diagnostics_pub_;
00058 ros::Timer diagnostics_timer_;
00059 ros::Publisher pubMarker_;
00060
00061 SoundAction():
00062 as_say_(nh_, ros::this_node::getName() + "/say", boost::bind(&SoundAction::as_cb_say_, this, _1), false),
00063 as_play_(nh_, ros::this_node::getName() + "/play", false)
00064 {
00065 nh_ = ros::NodeHandle("~");
00066 }
00067
00068 ~SoundAction(void)
00069 {
00070 libvlc_media_player_stop(vlc_player_);
00071 libvlc_media_player_release(vlc_player_);
00072 libvlc_release(vlc_inst_);
00073 }
00074
00075 bool init()
00076 {
00077 vlc_inst_ = libvlc_new(0,NULL);
00078 if(!vlc_inst_){ROS_ERROR("failed to create libvlc instance"); return false;}
00079 vlc_player_ = libvlc_media_player_new(vlc_inst_);
00080 if(!vlc_player_){ROS_ERROR("failed to create vlc media player object"); return false;}
00081
00082 as_play_.registerGoalCallback(boost::bind(&SoundAction::as_goal_cb_play_, this));
00083 as_play_.registerPreemptCallback(boost::bind(&SoundAction::as_preempt_cb_play_, this));
00084 srvServer_say_ = nh_.advertiseService("say", &SoundAction::service_cb_say, this);
00085 srvServer_play_ = nh_.advertiseService("play", &SoundAction::service_cb_play, this);
00086 srvServer_stop_ = nh_.advertiseService("stop", &SoundAction::service_cb_stop, this);
00087 srvServer_mute_ = nh_.advertiseService("mute", &SoundAction::service_cb_mute, this);
00088 srvServer_unmute_ = nh_.advertiseService("unmute", &SoundAction::service_cb_unmute, this);
00089 sub_say_ = nh_.subscribe("say", 1, &SoundAction::topic_cb_say, this);
00090 sub_play_ = nh_.subscribe("play", 1, &SoundAction::topic_cb_play, this);
00091 diagnostics_pub_ = nh_.advertise<diagnostic_msgs::DiagnosticArray>("diagnostics", 1);
00092 diagnostics_timer_ = nh_.createTimer(ros::Duration(1.0), &SoundAction::timer_cb, this);
00093 play_feedback_timer_ = nh_.createTimer(ros::Duration(0.25), &SoundAction::timer_play_feedback_cb, this, false, false);
00094 pubMarker_ = nh_.advertise<visualization_msgs::Marker>("marker",1);
00095 fade_volume_ = nh_.param<bool>("fade_volume", true);
00096 fade_duration_ = nh_.param<double>("fade_duration", 0.5);
00097
00098 mute_ = false;
00099
00100 as_say_.start();
00101 as_play_.start();
00102 return true;
00103 }
00104
00105 void as_goal_cb_play_()
00106 {
00107 std::string filename = as_play_.acceptNewGoal()->filename;
00108 std::string message;
00109 if(play(filename, message))
00110 {
00111 play_feedback_timer_.start();
00112 }
00113 else
00114 {
00115 cob_sound::PlayResult result;
00116 result.success = false;
00117 result.message = message;
00118 as_play_.setAborted(result, message);
00119 }
00120 }
00121
00122 void as_preempt_cb_play_()
00123 {
00124 if(as_play_.isActive())
00125 {
00126 fade_out();
00127 play_feedback_timer_.stop();
00128 libvlc_media_player_stop(vlc_player_);
00129 }
00130 cob_sound::PlayResult result;
00131 result.success = false;
00132 result.message = "Action has been preempted";
00133 as_play_.setPreempted();
00134 }
00135
00136 void as_cb_say_(const cob_sound::SayGoalConstPtr &goal)
00137 {
00138 std::string message;
00139 bool ret = say(goal->text, message);
00140
00141 cob_sound::SayResult result;
00142 result.success = ret;
00143 result.message = message;
00144 if (ret)
00145 {
00146 as_say_.setSucceeded(result, message);
00147 }
00148 else
00149 {
00150 as_say_.setAborted(result, message);
00151 }
00152 }
00153
00154 bool service_cb_say(cob_srvs::SetString::Request &req,
00155 cob_srvs::SetString::Response &res )
00156 {
00157 res.success = say(req.data, res.message);
00158 return true;
00159 }
00160
00161 bool service_cb_play(cob_srvs::SetString::Request &req,
00162 cob_srvs::SetString::Response &res )
00163 {
00164 res.success = play(req.data, res.message);
00165 ros::Duration(0.1).sleep();
00166 while((libvlc_media_player_is_playing(vlc_player_) == 1))
00167 {
00168 ros::Duration(0.1).sleep();
00169 ROS_DEBUG("still playing %s", req.data.c_str());
00170 }
00171 return true;
00172 }
00173
00174 bool service_cb_stop(std_srvs::Trigger::Request &req,
00175 std_srvs::Trigger::Response &res )
00176 {
00177 fade_out();
00178 if(as_play_.isActive())
00179 {
00180 play_feedback_timer_.stop();
00181 cob_sound::PlayResult result;
00182 result.success = false;
00183 result.message = "Action has been aborted";
00184 as_play_.setAborted(result, result.message);
00185 libvlc_media_player_stop(vlc_player_);
00186 res.success = true;
00187 res.message = "aborted running action";
00188 }
00189 else
00190 {
00191 if(libvlc_media_player_is_playing(vlc_player_) == 1)
00192 {
00193 libvlc_media_player_stop(vlc_player_);
00194 res.success = true;
00195 res.message = "stopped sound play";
00196 }
00197 else
00198 {
00199 res.success = false;
00200 res.message = "nothing there to stop";
00201 }
00202 }
00203 return true;
00204 }
00205
00206 bool service_cb_mute(std_srvs::Trigger::Request &req,
00207 std_srvs::Trigger::Response &res )
00208 {
00209 mute_ = true;
00210 res.success = true;
00211 res.message = "Sound muted successfully";
00212 return true;
00213 }
00214
00215 bool service_cb_unmute(std_srvs::Trigger::Request &req,
00216 std_srvs::Trigger::Response &res )
00217 {
00218 mute_ = false;
00219 res.success = true;
00220 res.message = "Sound un-muted successfully";
00221 return true;
00222 }
00223
00224 void topic_cb_say(const std_msgs::String::ConstPtr& msg)
00225 {
00226 std::string message;
00227 say(msg->data.c_str(), message);
00228 }
00229
00230 void topic_cb_play(const std_msgs::String::ConstPtr& msg)
00231 {
00232 std::string message;
00233 play(msg->data.c_str(), message);
00234 }
00235
00236 bool say(std::string data, std::string& message)
00237 {
00238 if (mute_)
00239 {
00240 message = "Sound is set to mute. You will hear nothing.";
00241 ROS_WARN_STREAM(message);
00242 return true;
00243 }
00244
00245 ROS_INFO("Saying: %s", data.c_str());
00246
00247 publish_marker(data);
00248
00249 std::string mode;
00250 std::string command;
00251 std::string cepstral_voice;
00252 std::string cepstral_conf;
00253 nh_.param<std::string>("mode",mode,"festival");
00254 nh_.param<std::string>("cepstral_voice",cepstral_voice,"David");
00255 nh_.param<std::string>("cepstral_settings",cepstral_conf,"\"speech/rate=170\"");
00256 if (mode == "cepstral")
00257 {
00258 command = "aoss swift -p " + cepstral_conf + " -n " + cepstral_voice + " " + data;
00259 }
00260 else
00261 {
00262 command = "echo " + data + " | text2wave | aplay -q";
00263 }
00264
00265 int ret = system(command.c_str());
00266 if (ret != 0)
00267 {
00268 message = "Command say failed to say '" + data + "' using mode " + mode + " (system return value: " + boost::lexical_cast<std::string>(ret) + ")";
00269 ROS_ERROR_STREAM(message);
00270 publish_diagnostics(diagnostic_msgs::DiagnosticStatus::ERROR, message);
00271 return false;
00272 }
00273
00274 message = "Say successfull";
00275 return true;
00276 }
00277
00278 bool play(std::string filename, std::string &message)
00279 {
00280 if (mute_)
00281 {
00282 message = "Sound is set to mute. You will hear nothing.";
00283 ROS_WARN_STREAM(message);
00284 return false;
00285 }
00286
00287 if (filename.empty())
00288 {
00289 message = "Cannot play because filename is empty.";
00290 ROS_WARN_STREAM(message);
00291 return false;
00292 }
00293
00294 if ( !boost::filesystem::exists(filename) )
00295 {
00296 message = "Cannot play '" + filename +"' because file does not exist.";
00297 ROS_WARN_STREAM(message);
00298 return false;
00299 }
00300
00301 vlc_media_ = libvlc_media_new_path(vlc_inst_, filename.c_str());
00302 if(!vlc_media_)
00303 {
00304 message = "failed to create media for filepath %s", filename.c_str();
00305 ROS_WARN_STREAM(message);
00306 return false;
00307 }
00308
00309 libvlc_media_player_set_media(vlc_player_, vlc_media_);
00310 libvlc_media_release(vlc_media_);
00311
00312 if(!fade_out())
00313 {
00314 message = "failed to fade out";
00315 ROS_WARN_STREAM(message);
00316 return false;
00317 }
00318
00319 if(!fade_in())
00320 {
00321 message = "failed to fade in";
00322 ROS_WARN_STREAM(message);
00323 return false;
00324 }
00325
00326 message = "Play successfull";
00327 return true;
00328 }
00329
00330 void timer_cb(const ros::TimerEvent&)
00331 {
00332 publish_diagnostics(diagnostic_msgs::DiagnosticStatus::OK, "sound controller running");
00333 }
00334
00335 void timer_play_feedback_cb(const ros::TimerEvent&)
00336 {
00337 if(as_play_.isActive())
00338 {
00339 if (libvlc_media_player_is_playing(vlc_player_) == 1)
00340 {
00341 float perc_done = libvlc_media_player_get_position(vlc_player_);
00342 int64_t t = libvlc_media_player_get_time(vlc_player_);
00343 cob_sound::PlayFeedback feedback;
00344 feedback.position = perc_done;
00345 feedback.time = t;
00346 as_play_.publishFeedback(feedback);
00347 }
00348 else
00349 {
00350 play_feedback_timer_.stop();
00351 cob_sound::PlayResult result;
00352 result.success = true;
00353 result.message = "Action succeeded";
00354 as_play_.setSucceeded();
00355 }
00356 }
00357 }
00358
00359 void publish_marker(std::string data)
00360 {
00361 visualization_msgs::Marker marker;
00362 marker.header.frame_id = "base_link";
00363 marker.header.stamp = ros::Time();
00364 marker.ns = "color";
00365 marker.id = 0;
00366 marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
00367 marker.action = visualization_msgs::Marker::ADD;
00368 marker.lifetime = ros::Duration(std::max(data.size()*0.15, 2.0));
00369 marker.text = data;
00370 marker.pose.position.x = 0.0;
00371 marker.pose.position.y = 0.0;
00372 marker.pose.position.z = 1.8;
00373 marker.pose.orientation.x = 0.0;
00374 marker.pose.orientation.y = 0.0;
00375 marker.pose.orientation.z = 0.0;
00376 marker.pose.orientation.w = 1.0;
00377 marker.scale.x = 0.1;
00378 marker.scale.y = 0.1;
00379 marker.scale.z = 0.1;
00380 marker.color.a = 1.0;
00381 marker.color.r = 1.0;
00382 marker.color.g = 1.0;
00383 marker.color.b = 1.0;
00384 pubMarker_.publish(marker);
00385 }
00386
00387 void publish_diagnostics(unsigned char level, std::string message)
00388 {
00389 diagnostic_msgs::DiagnosticStatus status;
00390 status.level = level;
00391 status.name = "sound";
00392 status.hardware_id = "sound";
00393 status.message = message;
00394 diagnostics_.status.push_back(status);
00395
00396 diagnostics_.header.stamp = ros::Time::now();
00397 diagnostics_pub_.publish(diagnostics_);
00398
00399 diagnostics_.status.resize(0);
00400 }
00401
00402 bool fade_in()
00403 {
00404 if(libvlc_media_player_play(vlc_player_) >= 0)
00405 {
00406 if(fade_volume_)
00407 {
00408 while(libvlc_audio_set_volume(vlc_player_,0) != 0)
00409 ros::Duration(0.05).sleep();
00410 for(int i = 0; i < 100; i+=5)
00411 {
00412 libvlc_audio_set_volume(vlc_player_,i);
00413 ros::Duration(fade_duration_/20.0).sleep();
00414 }
00415 }
00416 else
00417 {
00418 while(libvlc_audio_set_volume(vlc_player_,100) != 0)
00419 ros::Duration(0.05).sleep();
00420 }
00421 }
00422 else
00423 {
00424 return false;
00425 }
00426
00427 return true;
00428 }
00429
00430 bool fade_out()
00431 {
00432 int volume = libvlc_audio_get_volume(vlc_player_);
00433 if(libvlc_media_player_is_playing(vlc_player_))
00434 {
00435 if(fade_volume_)
00436 {
00437 for(int i = volume - (volume%5); i>=0; i-=5)
00438 {
00439 libvlc_audio_set_volume(vlc_player_,i);
00440 ros::Duration(fade_duration_/20.0).sleep();
00441 }
00442 }
00443 }
00444 return true;
00445 }
00446 };
00447
00448
00449 int main(int argc, char** argv)
00450 {
00451 ros::init(argc, argv, "cob_sound");
00452
00453 SoundAction sound;
00454 if(!sound.init())
00455 {
00456 ROS_ERROR("sound init failed");
00457 return 1;
00458 }
00459 else
00460 {
00461 ROS_INFO("sound node started");
00462 ros::spin();
00463 return 0;
00464 }
00465 }