48 from diagnostic_msgs.msg
import DiagnosticArray
49 from diagnostic_msgs.msg
import DiagnosticStatus
50 from diagnostic_msgs.msg
import KeyValue
51 from sound_play.msg
import SoundRequest
52 from sound_play.msg
import SoundRequestAction
53 from sound_play.msg
import SoundRequestFeedback
54 from sound_play.msg
import SoundRequestResult
59 gi.require_version(
'Gst',
'1.0')
60 from gi.repository
import GObject
as GObject
61 from gi.repository
import Gst
as Gst
64 **************************************************************
65 Error opening pygst. Is gstreamer installed?
66 **************************************************************
74 _feedback = SoundRequestFeedback()
75 _result = SoundRequestResult()
78 for sound
in dict.values():
87 if data.sound == SoundRequest.PLAY_FILE:
91 'command for uncached wave: "%s"' % data.arg)
94 data.arg, self.
device, data.volume)
97 'Error setting up to play "%s".'
98 'Does this file exist on the machine'
99 'on which sound_play is running?' % data.arg)
102 rospy.logdebug(
'command for cached wave: "%s"' % data.arg)
104 if filesound.sound.get_property(
'volume') != data.volume:
106 'volume for cached wave has changed,'
108 filesound.sound.set_property(
'volume', data.volume)
111 absfilename = os.path.join(
112 roslib.packages.get_pkg_dir(data.arg2), data.arg)
115 'command for uncached wave: "%s"' % absfilename)
118 absfilename, self.
device, data.volume)
121 'Error setting up to play "%s" from package "%s".'
122 'Does this file exist on the machine '
123 'on which sound_play is running?'
124 % (data.arg, data.arg2))
128 'command for cached wave: "%s"' % absfilename)
130 if filesound.sound.get_property(
'volume') != data.volume:
132 'volume for cached wave has changed,'
134 filesound.sound.set_property(
'volume', data.volume)
136 elif data.sound == SoundRequest.SAY:
137 voice_key = data.arg +
'---' + data.arg2
139 rospy.logdebug(
'command for uncached text: "%s"' % voice_key)
142 'Plugin is not found {}.'.format(self.
plugin_name))
148 wavfilename = self.
plugin.sound_play_say_plugin(
150 if wavfilename
is None:
151 rospy.logerr(
'Failed to generate wavfile.')
154 wavfilename, self.
device, data.volume)
156 rospy.logdebug(
'command for cached text: "%s"' % voice_key)
158 if voicesound.sound.get_property(
'volume') != data.volume:
160 'volume for cached text has changed, resetting volume')
161 voicesound.sound.set_property(
'volume', data.volume)
164 rospy.logdebug(
'command for builtin wave: %i' % data.sound)
172 volume = (volume + params[1])/2
174 params[0], self.
device, volume)
176 if sound.staleness != 0
and data.command != SoundRequest.PLAY_STOP:
178 rospy.logdebug(
"activating %i %s" % (data.sound, data.arg))
188 if (data.sound == SoundRequest.ALL
189 and data.command == SoundRequest.PLAY_STOP):
193 sound.command(data.command)
194 except Exception
as e:
195 rospy.logerr(
'Exception in callback: %s' %
str(e))
196 rospy.loginfo(traceback.format_exc())
199 rospy.logdebug(
"done callback")
204 for key, sound
in iter(dict.items()):
206 staleness = sound.get_staleness()
207 except Exception
as e:
209 'Exception in cleanupdict for sound (%s): %s'
215 purgelist.append(key)
219 for key
in purgelist:
220 rospy.logdebug(
'Purging %s from cache' % key)
234 'Exception in cleanup: %s' % sys.exc_info()[0])
240 da = DiagnosticArray()
241 ds = DiagnosticStatus()
242 ds.name = rospy.get_caller_id().lstrip(
'/') +
": Node State"
244 ds.level = DiagnosticStatus.OK
250 "Allocated sound channels",
254 "Buffered builtin sounds",
258 "Buffered wave sounds",
262 "Buffered voice sounds",
265 ds.level = DiagnosticStatus.WARN
266 ds.message =
"Sound device not open yet."
268 ds.level = DiagnosticStatus.ERROR
269 ds.message =
"Can't open sound device." +\
270 "See http://wiki.ros.org/sound_play/Troubleshooting"
272 da.header.stamp = rospy.get_rostime()
274 except Exception
as e:
275 rospy.loginfo(
'Exception in diagnostics: %s' %
str(e))
278 data = data.sound_request
280 rospy.logerr(
'soundplay_node is not initialized yet.')
281 self.
_as.set_aborted()
287 if (data.sound == SoundRequest.ALL
288 and data.command == SoundRequest.PLAY_STOP):
292 sound.command(data.command)
295 start_time = rospy.get_rostime()
297 while sound.get_playing():
299 if self.
_as.is_preempt_requested():
300 rospy.loginfo(
'sound_play action: Preempted')
302 self.
_as.set_preempted()
306 self.
_feedback.playing = sound.get_playing()
307 self.
_feedback.stamp = rospy.get_rostime() - start_time
314 rospy.loginfo(
'sound_play action: Succeeded')
317 except Exception
as e:
318 self.
_as.set_aborted()
320 'Exception in actionlib callback: %s' %
str(e))
321 rospy.loginfo(traceback.format_exc())
324 rospy.logdebug(
"done actionlib callback")
330 GObject.threads_init()
331 self.
g_loop = threading.Thread(target=GObject.MainLoop().run)
335 rospy.init_node(
'sound_play')
337 self.
device = rospy.get_param(
"~device",
"default")
340 '~plugin',
'sound_play/festival_plugin')
342 "/diagnostics", DiagnosticArray, queue_size=1)
343 rootdir = os.path.join(
344 roslib.packages.get_pkg_dir(
'sound_play'),
'sounds')
347 rospack = rospkg.RosPack()
348 depend_pkgs = rospack.get_depends_on(
'sound_play', implicit=
False)
349 depend_pkgs = [
'sound_play'] + depend_pkgs
350 rospy.loginfo(
"Loading from plugin definitions")
352 for depend_pkg
in depend_pkgs:
353 manifest = rospack.get_manifest(depend_pkg)
354 plugin_yaml = manifest.get_export(
'sound_play',
'plugin')
355 if len(plugin_yaml) != 0:
356 plugin_yamls += plugin_yaml
357 for plugin_y
in plugin_yaml:
358 rospy.logdebug(
'Loading plugin in {}'.format(plugin_y))
360 for plugin_yaml
in plugin_yamls:
361 if not os.path.exists(plugin_yaml):
363 'Failed to load plugin yaml: {}'.format(plugin_yaml))
365 'Missing plugin yaml: {}'.format(plugin_yaml))
367 with open(plugin_yaml)
as f:
368 plugin_descs = yaml.safe_load(f)
369 for plugin_desc
in plugin_descs:
370 plugin_dict[plugin_desc[
'name']] = plugin_desc[
'module']
375 mod = __import__(plugin_module.split(
'.')[0])
376 for sub_mod
in plugin_module.split(
'.')[1:]:
377 mod = getattr(mod, sub_mod)
381 SoundRequest.BACKINGUP: (
382 os.path.join(rootdir,
'BACKINGUP.ogg'), 0.1),
383 SoundRequest.NEEDS_UNPLUGGING: (
384 os.path.join(rootdir,
'NEEDS_UNPLUGGING.ogg'), 1),
385 SoundRequest.NEEDS_PLUGGING: (
386 os.path.join(rootdir,
'NEEDS_PLUGGING.ogg'), 1),
387 SoundRequest.NEEDS_UNPLUGGING_BADLY: (
388 os.path.join(rootdir,
'NEEDS_UNPLUGGING_BADLY.ogg'), 1),
389 SoundRequest.NEEDS_PLUGGING_BADLY: (
390 os.path.join(rootdir,
'NEEDS_PLUGGING_BADLY.ogg'), 1),
398 self.
sub = rospy.Subscriber(
"robotsound", SoundRequest, self.
callback)
400 'sound_play', SoundRequestAction,
408 while not rospy.is_shutdown():
409 while not rospy.is_shutdown():
414 if not self.
_as.action_server.started:
422 'Exception in idle_loop: %s' % sys.exc_info()[0])
436 rospy.loginfo(
'sound_play node is ready to play sound')
440 rospy.sleep(duration)
441 except rospy.exceptions.ROSInterruptException:
451 while (
not rospy.is_shutdown()
461 if __name__ ==
'__main__':