00001 #!/usr/bin/env python 00002 00003 #*********************************************************** 00004 #* Software License Agreement (BSD License) 00005 #* 00006 #* Copyright (c) 2009, Willow Garage, Inc. 00007 #* All rights reserved. 00008 #* 00009 #* Redistribution and use in source and binary forms, with or without 00010 #* modification, are permitted provided that the following conditions 00011 #* are met: 00012 #* 00013 #* * Redistributions of source code must retain the above copyright 00014 #* notice, this list of conditions and the following disclaimer. 00015 #* * Redistributions in binary form must reproduce the above 00016 #* copyright notice, this list of conditions and the following 00017 #* disclaimer in the documentation and/or other materials provided 00018 #* with the distribution. 00019 #* * Neither the name of the Willow Garage nor the names of its 00020 #* contributors may be used to endorse or promote products derived 00021 #* from this software without specific prior written permission. 00022 #* 00023 #* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00024 #* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00025 #* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00026 #* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00027 #* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00028 #* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00029 #* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00030 #* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00031 #* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00032 #* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00033 #* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00034 #* POSSIBILITY OF SUCH DAMAGE. 00035 #*********************************************************** 00036 00037 # Author: Blaise Gassend 00038 00039 import rospy 00040 from sound_play.msg import SoundRequest 00041 00042 ## \brief Class that publishes messages to the sound_play node. 00043 ## 00044 ## This class is a helper class for communicating with the sound_play node 00045 ## via the \ref sound_play.SoundRequest message. It has two ways of being used: 00046 ## 00047 ## - It can create Sound classes that represent a particular sound which 00048 ## can be played, repeated or stopped. 00049 ## 00050 ## - It provides methods for each way in which the sound_play.SoundRequest 00051 ## message can be invoked. 00052 00053 class Sound: 00054 def __init__(self, client, snd, arg): 00055 self.client = client 00056 self.snd = snd 00057 self.arg = arg 00058 00059 ## \brief Play the Sound. 00060 ## 00061 ## This method causes the Sound to be played once. 00062 00063 def play(self): 00064 self.client.sendMsg(self.snd, SoundRequest.PLAY_ONCE, self.arg) 00065 00066 ## \brief Play the Sound repeatedly. 00067 ## 00068 ## This method causes the Sound to be played repeatedly until stop() is 00069 ## called. 00070 00071 def repeat(self): 00072 self.client.sendMsg(self.snd, SoundRequest.PLAY_START, self.arg) 00073 00074 ## \brief Stop Sound playback. 00075 ## 00076 ## This method causes the Sound to stop playing. 00077 00078 def stop(self): 00079 self.client.sendMsg(self.snd, SoundRequest.PLAY_STOP, self.arg) 00080 00081 ## This class is a helper class for communicating with the sound_play node 00082 ## via the \ref sound_play.SoundRequest message. There is a one-to-one mapping 00083 ## between methods and invocations of the \ref sound_play.SoundRequest message. 00084 00085 class SoundClient: 00086 def __init__(self): 00087 self.pub = rospy.Publisher('robotsound', SoundRequest) 00088 00089 ## \brief Create a voice Sound. 00090 ## 00091 ## Creates a Sound corresponding to saying the indicated text. 00092 ## 00093 ## \param s Text to say 00094 00095 def voiceSound(self, s): 00096 return Sound(self, SoundRequest.SAY, s) 00097 00098 ## \brief Create a wave Sound. 00099 ## 00100 ## Creates a Sound corresponding to indicated file. 00101 ## 00102 ## \param s File to play. Should be an absolute path that exists on the 00103 ## machine running the sound_play node. 00104 def waveSound(self, s): 00105 return Sound(self, SoundRequest.PLAY_FILE, s) 00106 00107 ## \brief Create a builtin Sound. 00108 ## 00109 ## Creates a Sound corresponding to indicated builtin wave. 00110 ## 00111 ## \param id Identifier of the sound to play. 00112 00113 def builtinSound(self, id): 00114 return Sound(self, id, "") 00115 00116 ## \brief Say a string 00117 ## 00118 ## Send a string to be said by the sound_node. The vocalization can be 00119 ## stopped using stopSaying or stopAll. 00120 ## 00121 ## \param text String to say 00122 00123 def say(self,text): 00124 self.sendMsg(SoundRequest.SAY, SoundRequest.PLAY_ONCE, text) 00125 00126 ## \brief Say a string repeatedly 00127 ## 00128 ## The string is said repeatedly until stopSaying or stopAll is used. 00129 ## 00130 ## \param text String to say repeatedly 00131 00132 def repeat(self,text): 00133 self.sendMsg(SoundRequest.SAY, SoundRequest.PLAY_START, text) 00134 00135 ## \brief Stop saying a string 00136 ## 00137 ## Stops saying a string that was previously started by say or repeat. The 00138 ## argument indicates which string to stop saying. 00139 ## 00140 ## \param text Same string as in the say or repeat command 00141 00142 def stopSaying(self,text): 00143 self.sendMsg(SoundRequest.SAY, SoundRequest.PLAY_STOP, text) 00144 00145 ## \brief Plays a WAV or OGG file 00146 ## 00147 ## Plays a WAV or OGG file once. The playback can be stopped by stopWave or 00148 ## stopAll. 00149 ## 00150 ## \param sound Filename of the WAV or OGG file. Must be an absolute path valid 00151 ## on the computer on which the sound_play node is running 00152 00153 def playWave(self,sound): 00154 self.sendMsg(SoundRequest.PLAY_FILE, SoundRequest.PLAY_ONCE, sound) 00155 00156 ## \brief Plays a WAV or OGG file repeatedly 00157 ## 00158 ## Plays a WAV or OGG file repeatedly until stopWave or stopAll is used. 00159 ## 00160 ## \param sound Filename of the WAV or OGG file. Must be an absolute path valid 00161 ## on the computer on which the sound_play node is running. 00162 00163 def startWave(self,sound): 00164 self.sendMsg(SoundRequest.PLAY_FILE, SoundRequest.PLAY_START, sound) 00165 00166 ## \brief Stop playing a WAV or OGG file 00167 ## 00168 ## Stops playing a file that was previously started by playWave or 00169 ## startWave. 00170 ## 00171 ## \param sound Same string as in the playWave or startWave command 00172 00173 def stopWave(self,sound): 00174 self.sendMsg(SoundRequest.PLAY_FILE, SoundRequest.PLAY_STOP, sound) 00175 00176 ## \brief Play a buildin sound 00177 ## 00178 ## Starts playing one of the built-in sounds. built-ing sounds are documented 00179 ## in \ref SoundRequest.msg. Playback can be stopped by stopall. 00180 ## 00181 ## \param sound Identifier of the sound to play. 00182 00183 def play(self,sound): 00184 self.sendMsg(sound, SoundRequest.PLAY_ONCE, "") 00185 00186 ## \brief Play a buildin sound repeatedly 00187 ## 00188 ## Starts playing one of the built-in sounds repeatedly until stop or 00189 ## stopall is used. Built-in sounds are documented in \ref SoundRequest.msg. 00190 ## 00191 ## \param sound Identifier of the sound to play. 00192 00193 def start(self,sound): 00194 self.sendMsg(sound, SoundRequest.PLAY_START, "") 00195 00196 ## \brief Stop playing a built-in sound 00197 ## 00198 ## Stops playing a built-in sound started with play or start. 00199 ## 00200 ## \param sound Same sound that was used to start playback 00201 00202 def stop(self,sound): 00203 self.sendMsg(sound, SoundRequest.PLAY_STOP, "") 00204 00205 ## \brief Stop all currently playing sounds 00206 ## 00207 ## This method stops all speech, wave file, and built-in sound playback. 00208 00209 def stopAll(self): 00210 self.stop(SoundRequest.ALL) 00211 00212 def sendMsg(self, snd, cmd, s): 00213 msg = SoundRequest() 00214 msg.sound = snd 00215 msg.command = cmd 00216 msg.arg = s 00217 self.pub.publish(msg) 00218 ## @todo this should be a warn once warns become visible on the console. 00219 if self.pub.get_num_connections() < 1: 00220 rospy.logerr("Sound command issued, but no node is subscribed to the topic. Perhaps you forgot to run soundplay_node.py");