47 from diagnostic_msgs.msg
import DiagnosticStatus, KeyValue, DiagnosticArray
48 from sound_play.msg
import SoundRequest, SoundRequestAction, SoundRequestResult, SoundRequestFeedback
53 gi.require_version(
'Gst',
'1.0')
54 from gi.repository
import Gst
as Gst
57 ************************************************************** 58 Error opening pygst. Is gstreamer installed? 59 ************************************************************** 77 def __init__(self, file, device, volume = 1.0):
78 self.
lock = threading.RLock()
80 self.
sound = Gst.ElementFactory.make(
"playbin",
None)
81 if self.
sound is None:
82 raise Exception(
"Could not create sound player")
85 self.
sink = Gst.ElementFactory.make(
"alsasink",
"sink")
86 self.sink.set_property(
"device", device)
87 self.sound.set_property(
"audio-sink", self.
sink)
91 elif os.path.isfile(file):
92 uri =
"file://" + os.path.abspath(file)
94 rospy.logerr(
'Error: URI is invalid: %s'%file)
98 self.sound.set_property(
'uri', uri)
99 self.sound.set_property(
"volume",volume)
103 self.
bus = self.sound.get_bus()
104 self.bus.add_signal_watch()
108 if message.type == Gst.MessageType.EOS:
116 self.bus.poll(Gst.MessageType.ERROR, 10)
126 self.sound.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, 0)
127 self.sound.set_state(Gst.State.PLAYING)
136 self.sound.set_state(Gst.State.NULL)
144 rospy.logdebug(
"Playing %s"%self.
uri)
149 self.sound.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, 0)
150 self.sound.set_state(Gst.State.PLAYING)
156 if cmd == SoundRequest.PLAY_STOP:
158 elif cmd == SoundRequest.PLAY_ONCE:
160 elif cmd == SoundRequest.PLAY_START:
168 position = self.sound.query_position(Gst.Format.TIME)[0]
169 duration = self.sound.query_duration(Gst.Format.TIME)[0]
176 if position != duration:
186 _feedback = SoundRequestFeedback()
187 _result = SoundRequestResult()
190 for sound
in dict.values():
199 if data.sound == SoundRequest.PLAY_FILE:
201 if not data.arg
in self.filesounds.keys():
202 rospy.logdebug(
'command for uncached wave: "%s"'%data.arg)
206 rospy.logerr(
'Error setting up to play "%s". Does this file exist on the machine on which sound_play is running?'%data.arg)
209 rospy.logdebug(
'command for cached wave: "%s"'%data.arg)
210 if self.
filesounds[data.arg].sound.get_property(
'volume') != data.volume:
211 rospy.logdebug(
'volume for cached wave has changed, resetting volume')
212 self.
filesounds[data.arg].sound.set_property(
'volume', data.volume)
215 absfilename = os.path.join(roslib.packages.get_pkg_dir(data.arg2), data.arg)
216 if not absfilename
in self.filesounds.keys():
217 rospy.logdebug(
'command for uncached wave: "%s"'%absfilename)
221 rospy.logerr(
'Error setting up to play "%s" from package "%s". Does this file exist on the machine on which sound_play is running?'%(data.arg, data.arg2))
224 rospy.logdebug(
'command for cached wave: "%s"'%absfilename)
225 if self.
filesounds[absfilename].sound.get_property(
'volume') != data.volume:
226 rospy.logdebug(
'volume for cached wave has changed, resetting volume')
227 self.
filesounds[absfilename].sound.set_property(
'volume', data.volume)
229 elif data.sound == SoundRequest.SAY:
231 if not data.arg
in self.voicesounds.keys():
232 rospy.logdebug(
'command for uncached text: "%s"' % data.arg)
233 txtfile = tempfile.NamedTemporaryFile(prefix=
'sound_play', suffix=
'.txt')
234 (wavfile,wavfilename) = tempfile.mkstemp(prefix=
'sound_play', suffix=
'.wav')
235 txtfilename=txtfile.name
239 txtfile.write(data.arg.decode(
'UTF-8').encode(
'ISO-8859-15'))
241 os.system(
"text2wave -eval '("+voice+
")' "+txtfilename+
" -o "+wavfilename)
243 if os.stat(wavfilename).st_size == 0:
246 rospy.logerr(
'Sound synthesis failed. Is festival installed? Is a festival voice installed? Try running "rosdep satisfy sound_play|sh". Refer to http://wiki.ros.org/sound_play/Troubleshooting')
252 rospy.logdebug(
'command for cached text: "%s"'%data.arg)
253 if self.
voicesounds[data.arg].sound.get_property(
'volume') != data.volume:
254 rospy.logdebug(
'volume for cached text has changed, resetting volume')
255 self.
voicesounds[data.arg].sound.set_property(
'volume', data.volume)
258 rospy.logdebug(
'command for builtin wave: %i'%data.sound)
263 volume = (volume + params[1])/2
266 if sound.staleness != 0
and data.command != SoundRequest.PLAY_STOP:
268 rospy.logdebug(
"activating %i %s"%(data.sound,data.arg))
283 if data.sound == SoundRequest.ALL
and data.command == SoundRequest.PLAY_STOP:
287 sound.command(data.command)
289 rospy.logerr(
'Exception in callback: %s'%
str(e))
290 rospy.loginfo(traceback.format_exc())
293 rospy.logdebug(
"done callback")
298 for (key,sound)
in dict.iteritems():
300 staleness = sound.get_staleness()
302 rospy.logerr(
'Exception in cleanupdict for sound (%s): %s'%(
str(key),
str(e)))
306 purgelist.append(key)
309 for key
in purgelist:
310 rospy.logdebug(
'Purging %s from cache'%key)
322 rospy.loginfo(
'Exception in cleanup: %s'%sys.exc_info()[0])
328 da = DiagnosticArray()
329 ds = DiagnosticStatus()
330 ds.name = rospy.get_caller_id().lstrip(
'/') +
": Node State" 332 ds.level = DiagnosticStatus.OK
335 ds.values.append(KeyValue(
"Allocated sound channels",
str(self.
num_channels)))
336 ds.values.append(KeyValue(
"Buffered builtin sounds",
str(len(self.
builtinsounds))))
337 ds.values.append(KeyValue(
"Buffered wave sounds",
str(len(self.
filesounds))))
338 ds.values.append(KeyValue(
"Buffered voice sounds",
str(len(self.
voicesounds))))
340 ds.level = DiagnosticStatus.WARN
341 ds.message =
"Sound device not open yet." 343 ds.level = DiagnosticStatus.ERROR
344 ds.message =
"Can't open sound device. See http://wiki.ros.org/sound_play/Troubleshooting" 346 da.header.stamp = rospy.get_rostime()
347 self.diagnostic_pub.publish(da)
349 rospy.loginfo(
'Exception in diagnostics: %s'%
str(e))
352 data = data.sound_request
359 if data.sound == SoundRequest.ALL
and data.command == SoundRequest.PLAY_STOP:
363 sound.command(data.command)
366 start_time = rospy.get_rostime()
368 while sound.get_playing():
370 if self._as.is_preempt_requested():
371 rospy.loginfo(
'sound_play action: Preempted')
373 self._as.set_preempted()
377 self._feedback.playing = sound.get_playing()
378 self._feedback.stamp = rospy.get_rostime() - start_time
379 self._as.publish_feedback(self.
_feedback)
383 self._result.playing = self._feedback.playing
384 self._result.stamp = self._feedback.stamp
385 rospy.loginfo(
'sound_play action: Succeeded')
386 self._as.set_succeeded(self.
_result)
389 rospy.logerr(
'Exception in actionlib callback: %s'%
str(e))
390 rospy.loginfo(traceback.format_exc())
393 rospy.logdebug(
"done actionlib callback")
397 rospy.init_node(
'sound_play')
398 self.
device = rospy.get_param(
"~device",
"default")
399 self.
diagnostic_pub = rospy.Publisher(
"/diagnostics", DiagnosticArray, queue_size=1)
400 rootdir = os.path.join(roslib.packages.get_pkg_dir(
'sound_play'),
'sounds')
403 SoundRequest.BACKINGUP : (os.path.join(rootdir,
'BACKINGUP.ogg'), 0.1),
404 SoundRequest.NEEDS_UNPLUGGING : (os.path.join(rootdir,
'NEEDS_UNPLUGGING.ogg'), 1),
405 SoundRequest.NEEDS_PLUGGING : (os.path.join(rootdir,
'NEEDS_PLUGGING.ogg'), 1),
406 SoundRequest.NEEDS_UNPLUGGING_BADLY : (os.path.join(rootdir,
'NEEDS_UNPLUGGING_BADLY.ogg'), 1),
407 SoundRequest.NEEDS_PLUGGING_BADLY : (os.path.join(rootdir,
'NEEDS_PLUGGING_BADLY.ogg'), 1),
415 sub = rospy.Subscriber(
"robotsound", SoundRequest, self.
callback)
423 while not rospy.is_shutdown():
424 while not rospy.is_shutdown():
434 rospy.loginfo(
'Exception in idle_loop: %s'%sys.exc_info()[0])
448 rospy.loginfo(
'sound_play node is ready to play sound')
452 rospy.sleep(duration)
453 except rospy.exceptions.ROSInterruptException:
460 and not rospy.is_shutdown():
467 if __name__ ==
'__main__':
def __init__(self, file, device, volume=1.0)
def sleep(self, duration)
def on_stream_end(self, bus, message)
def cleanupdict(self, dict)
def stop(self)
Stop Sound playback.
def diagnostics(self, state)
def execute_cb(self, data)
def select_sound(self, data)