sound.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *   http://www.apache.org/licenses/LICENSE-2.0
00009 
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
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); //Advertise visualization marker topic
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 }


cob_sound
Author(s): Florian Weisshardt, Benjamin Maidel
autogenerated on Sat Jun 8 2019 21:02:24