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 if self.
bus is not None:
117 self.bus.poll(Gst.MessageType.ERROR, 10)
127 self.sound.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, 0)
128 self.sound.set_state(Gst.State.PLAYING)
136 if self.
bus is not None:
137 self.sound.set_state(Gst.State.NULL)
139 self.bus.remove_signal_watch()
144 except Exception
as e:
145 rospy.logerr(
'Exception in dispose: %s'%
str(e))
153 self.sound.set_state(Gst.State.NULL)
161 rospy.logdebug(
"Playing %s"%self.
uri)
166 self.sound.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, 0)
167 self.sound.set_state(Gst.State.PLAYING)
173 if cmd == SoundRequest.PLAY_STOP:
175 elif cmd == SoundRequest.PLAY_ONCE:
177 elif cmd == SoundRequest.PLAY_START:
185 position = self.sound.query_position(Gst.Format.TIME)[0]
186 duration = self.sound.query_duration(Gst.Format.TIME)[0]
187 except Exception
as e:
193 if position != duration:
203 _feedback = SoundRequestFeedback()
204 _result = SoundRequestResult()
207 for sound
in dict.values():
216 if data.sound == SoundRequest.PLAY_FILE:
218 if not data.arg
in self.filesounds.keys():
219 rospy.logdebug(
'command for uncached wave: "%s"'%data.arg)
223 rospy.logerr(
'Error setting up to play "%s". Does this file exist on the machine on which sound_play is running?'%data.arg)
226 rospy.logdebug(
'command for cached wave: "%s"'%data.arg)
227 if self.
filesounds[data.arg].sound.get_property(
'volume') != data.volume:
228 rospy.logdebug(
'volume for cached wave has changed, resetting volume')
229 self.
filesounds[data.arg].sound.set_property(
'volume', data.volume)
232 absfilename = os.path.join(roslib.packages.get_pkg_dir(data.arg2), data.arg)
233 if not absfilename
in self.filesounds.keys():
234 rospy.logdebug(
'command for uncached wave: "%s"'%absfilename)
238 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))
241 rospy.logdebug(
'command for cached wave: "%s"'%absfilename)
242 if self.
filesounds[absfilename].sound.get_property(
'volume') != data.volume:
243 rospy.logdebug(
'volume for cached wave has changed, resetting volume')
244 self.
filesounds[absfilename].sound.set_property(
'volume', data.volume)
246 elif data.sound == SoundRequest.SAY:
248 if not data.arg
in self.voicesounds.keys():
249 rospy.logdebug(
'command for uncached text: "%s"' % data.arg)
250 txtfile = tempfile.NamedTemporaryFile(prefix=
'sound_play', suffix=
'.txt')
251 (wavfile,wavfilename) = tempfile.mkstemp(prefix=
'sound_play', suffix=
'.wav')
252 txtfilename=txtfile.name
257 if hasattr(data.arg,
'decode'):
258 txtfile.write(data.arg.decode(
'UTF-8').encode(
'ISO-8859-15'))
260 txtfile.write(data.arg.encode(
'ISO-8859-15'))
261 except UnicodeEncodeError:
262 if hasattr(data.arg,
'decode'):
263 txtfile.write(data.arg)
265 txtfile.write(data.arg.encode(
'UTF-8'))
267 os.system(
"text2wave -eval '("+voice+
")' "+txtfilename+
" -o "+wavfilename)
269 if os.stat(wavfilename).st_size == 0:
272 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')
278 rospy.logdebug(
'command for cached text: "%s"'%data.arg)
279 if self.
voicesounds[data.arg].sound.get_property(
'volume') != data.volume:
280 rospy.logdebug(
'volume for cached text has changed, resetting volume')
281 self.
voicesounds[data.arg].sound.set_property(
'volume', data.volume)
284 rospy.logdebug(
'command for builtin wave: %i'%data.sound)
289 volume = (volume + params[1])/2
292 if sound.staleness != 0
and data.command != SoundRequest.PLAY_STOP:
294 rospy.logdebug(
"activating %i %s"%(data.sound,data.arg))
309 if data.sound == SoundRequest.ALL
and data.command == SoundRequest.PLAY_STOP:
313 sound.command(data.command)
314 except Exception
as e:
315 rospy.logerr(
'Exception in callback: %s'%
str(e))
316 rospy.loginfo(traceback.format_exc())
319 rospy.logdebug(
"done callback")
324 for (key,sound)
in iter(dict.items()):
326 staleness = sound.get_staleness()
327 except Exception
as e:
328 rospy.logerr(
'Exception in cleanupdict for sound (%s): %s'%(
str(key),
str(e)))
332 purgelist.append(key)
335 for key
in purgelist:
336 rospy.logdebug(
'Purging %s from cache'%key)
348 rospy.loginfo(
'Exception in cleanup: %s'%sys.exc_info()[0])
354 da = DiagnosticArray()
355 ds = DiagnosticStatus()
356 ds.name = rospy.get_caller_id().lstrip(
'/') +
": Node State" 358 ds.level = DiagnosticStatus.OK
361 ds.values.append(KeyValue(
"Allocated sound channels",
str(self.
num_channels)))
362 ds.values.append(KeyValue(
"Buffered builtin sounds",
str(len(self.
builtinsounds))))
363 ds.values.append(KeyValue(
"Buffered wave sounds",
str(len(self.
filesounds))))
364 ds.values.append(KeyValue(
"Buffered voice sounds",
str(len(self.
voicesounds))))
366 ds.level = DiagnosticStatus.WARN
367 ds.message =
"Sound device not open yet." 369 ds.level = DiagnosticStatus.ERROR
370 ds.message =
"Can't open sound device. See http://wiki.ros.org/sound_play/Troubleshooting" 372 da.header.stamp = rospy.get_rostime()
373 self.diagnostic_pub.publish(da)
374 except Exception
as e:
375 rospy.loginfo(
'Exception in diagnostics: %s'%
str(e))
378 data = data.sound_request
385 if data.sound == SoundRequest.ALL
and data.command == SoundRequest.PLAY_STOP:
389 sound.command(data.command)
392 start_time = rospy.get_rostime()
394 while sound.get_playing():
396 if self._as.is_preempt_requested():
397 rospy.loginfo(
'sound_play action: Preempted')
399 self._as.set_preempted()
403 self._feedback.playing = sound.get_playing()
404 self._feedback.stamp = rospy.get_rostime() - start_time
405 self._as.publish_feedback(self.
_feedback)
409 self._result.playing = self._feedback.playing
410 self._result.stamp = self._feedback.stamp
411 rospy.loginfo(
'sound_play action: Succeeded')
412 self._as.set_succeeded(self.
_result)
414 except Exception
as e:
415 rospy.logerr(
'Exception in actionlib callback: %s'%
str(e))
416 rospy.loginfo(traceback.format_exc())
419 rospy.logdebug(
"done actionlib callback")
423 rospy.init_node(
'sound_play')
424 self.
device = rospy.get_param(
"~device",
"default")
425 self.
diagnostic_pub = rospy.Publisher(
"/diagnostics", DiagnosticArray, queue_size=1)
426 rootdir = os.path.join(roslib.packages.get_pkg_dir(
'sound_play'),
'sounds')
429 SoundRequest.BACKINGUP : (os.path.join(rootdir,
'BACKINGUP.ogg'), 0.1),
430 SoundRequest.NEEDS_UNPLUGGING : (os.path.join(rootdir,
'NEEDS_UNPLUGGING.ogg'), 1),
431 SoundRequest.NEEDS_PLUGGING : (os.path.join(rootdir,
'NEEDS_PLUGGING.ogg'), 1),
432 SoundRequest.NEEDS_UNPLUGGING_BADLY : (os.path.join(rootdir,
'NEEDS_UNPLUGGING_BADLY.ogg'), 1),
433 SoundRequest.NEEDS_PLUGGING_BADLY : (os.path.join(rootdir,
'NEEDS_PLUGGING_BADLY.ogg'), 1),
441 sub = rospy.Subscriber(
"robotsound", SoundRequest, self.
callback)
449 while not rospy.is_shutdown():
450 while not rospy.is_shutdown():
460 rospy.loginfo(
'Exception in idle_loop: %s'%sys.exc_info()[0])
474 rospy.loginfo(
'sound_play node is ready to play sound')
478 rospy.sleep(duration)
479 except rospy.exceptions.ROSInterruptException:
486 and not rospy.is_shutdown():
493 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 diagnostics(self, state)
def execute_cb(self, data)
def select_sound(self, data)