libsoundplay.py
Go to the documentation of this file.
1 #***********************************************************
2 #* Software License Agreement (BSD License)
3 #*
4 #* Copyright (c) 2009, Willow Garage, Inc.
5 #* All rights reserved.
6 #*
7 #* Redistribution and use in source and binary forms, with or without
8 #* modification, are permitted provided that the following conditions
9 #* are met:
10 #*
11 #* * Redistributions of source code must retain the above copyright
12 #* notice, this list of conditions and the following disclaimer.
13 #* * Redistributions in binary form must reproduce the above
14 #* copyright notice, this list of conditions and the following
15 #* disclaimer in the documentation and/or other materials provided
16 #* with the distribution.
17 #* * Neither the name of the Willow Garage nor the names of its
18 #* contributors may be used to endorse or promote products derived
19 #* from this software without specific prior written permission.
20 #*
21 #* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 #* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 #* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 #* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 #* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 #* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 #* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 #* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 #* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 #* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 #* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 #* POSSIBILITY OF SUCH DAMAGE.
33 #***********************************************************
34 
35 # Author: Blaise Gassend
36 
37 import rospy
38 import roslib
39 import actionlib
40 import os, sys
41 from actionlib_msgs.msg import GoalStatusArray
42 from sound_play.msg import SoundRequest
43 from sound_play.msg import SoundRequestGoal
44 from sound_play.msg import SoundRequestAction
45 
46 
56 
57 class Sound(object):
58  def __init__(self, client, snd, arg, volume=1.0):
59  self.client = client
60  self.snd = snd
61  self.arg = arg
62  self.vol = volume
63 
64 
67 
68  def play(self, **kwargs):
69  self.client.sendMsg(self.snd, SoundRequest.PLAY_ONCE, self.arg,
70  vol=self.vol, **kwargs)
71 
72 
76 
77  def repeat(self, **kwargs):
78  self.client.sendMsg(self.snd, SoundRequest.PLAY_START, self.arg,
79  vol=self.vol, **kwargs)
80 
81 
84 
85  def stop(self):
86  self.client.sendMsg(self.snd, SoundRequest.PLAY_STOP, self.arg)
87 
88 
91 
92 class SoundClient(object):
93 
94  def __init__(self, blocking=False, sound_action='sound_play', sound_topic='robotsound'):
95  """
96 
97  The SoundClient can send SoundRequests in two modes: non-blocking mode
98  (by publishing a message to the soundplay_node directly) which will
99  return as soon as the sound request has been sent, or blocking mode (by
100  using the actionlib interface) which will wait until the sound has
101  finished playing completely.
102 
103  The blocking parameter here is the standard behavior, but can be
104  over-ridden. Each say/play/start/repeat method can take in an optional
105  `blocking=True|False` argument that will over-ride the class-wide
106  behavior. See soundclient_example.py for an example of this behavior.
107 
108  :param blocking: Used as the default behavior unless over-ridden,
109  (default = false)
110 
111  :param sound_action: Namespace of actionlib to play sound. The actionlib interface is used
112  only if blocking parameter is True. (default='sound_play')
113 
114  :param sound_topic: Topic name to play sound. The topic interface is used only if blocking
115  parameter is False. (default='robotsound')
116  """
117 
118  self._blocking = blocking
119  self._playing = False
120 
121  # NOTE: only one of these will be used at once, but we need to create
122  # both the publisher and actionlib client here.
124  sound_action, SoundRequestAction)
125  self.pub = rospy.Publisher(sound_topic, SoundRequest, queue_size=5)
126  self.sub = rospy.Subscriber(
127  '{}/status'.format(sound_action), GoalStatusArray, self._action_status_cb)
128 
129 
134 
135  def voiceSound(self, s, volume=1.0):
136  return Sound(self, SoundRequest.SAY, s, volume=volume)
137 
138 
144  def waveSound(self, sound, volume=1.0):
145  if sound[0] != "/":
146  rootdir = os.path.join(roslib.packages.get_pkg_dir('sound_play'),'sounds')
147  sound = rootdir + "/" + sound
148  return Sound(self, SoundRequest.PLAY_FILE, sound, volume=volume)
149 
150 
155 
156  def builtinSound(self, id, volume=1.0):
157  return Sound(self, id, "", volume)
158 
159 
165 
166  def say(self,text, voice='', volume=1.0, **kwargs):
167  self.sendMsg(SoundRequest.SAY, SoundRequest.PLAY_ONCE, text, voice,
168  volume, **kwargs)
169 
170 
175 
176  def repeat(self,text, volume=1.0, **kwargs):
177  self.sendMsg(SoundRequest.SAY, SoundRequest.PLAY_START, text,
178  vol=volume, **kwargs)
179 
180 
186 
187  def stopSaying(self,text):
188  self.sendMsg(SoundRequest.SAY, SoundRequest.PLAY_STOP, text)
189 
190 
197 
198  def playWave(self, sound, volume=1.0, **kwargs):
199  if sound[0] != "/":
200  rootdir = os.path.join(roslib.packages.get_pkg_dir('sound_play'),'sounds')
201  sound = rootdir + "/" + sound
202  self.sendMsg(SoundRequest.PLAY_FILE, SoundRequest.PLAY_ONCE, sound,
203  vol=volume, **kwargs)
204 
205 
211 
212  def startWave(self, sound, volume=1.0, **kwargs):
213  if sound[0] != "/":
214  rootdir = os.path.join(roslib.packages.get_pkg_dir('sound_play'),'sounds')
215  sound = rootdir + "/" + sound
216  self.sendMsg(SoundRequest.PLAY_FILE, SoundRequest.PLAY_START, sound,
217  vol=volume, **kwargs)
218 
219 
225 
226  def stopWave(self,sound):
227  if sound[0] != "/":
228  rootdir = os.path.join(roslib.package.get_pkg_dir('sound_play'),'sounds')
229  sound = rootdir + "/" + sound
230  self.sendMsg(SoundRequest.PLAY_FILE, SoundRequest.PLAY_STOP, sound)
231 
232 
240 
241  def playWaveFromPkg(self, package, sound, volume=1.0, **kwargs):
242  self.sendMsg(SoundRequest.PLAY_FILE, SoundRequest.PLAY_ONCE, sound, package,
243  volume, **kwargs)
244 
245 
252 
253  def startWaveFromPkg(self, package, sound, volume=1.0, **kwargs):
254  self.sendMsg(SoundRequest.PLAY_FILE, SoundRequest.PLAY_START, sound,
255  package, volume, **kwargs)
256 
257 
265 
266  def stopWaveFromPkg(self,sound, package):
267  self.sendMsg(SoundRequest.PLAY_FILE, SoundRequest.PLAY_STOP, sound, package)
268 
269 
275 
276  def play(self,sound, volume=1.0, **kwargs):
277  self.sendMsg(sound, SoundRequest.PLAY_ONCE, "", vol=volume, **kwargs)
278 
279 
285 
286  def start(self,sound, volume=1.0, **kwargs):
287  self.sendMsg(sound, SoundRequest.PLAY_START, "", vol=volume, **kwargs)
288 
289 
294 
295  def stop(self,sound):
296  self.sendMsg(sound, SoundRequest.PLAY_STOP, "")
297 
298 
301 
302  def stopAll(self):
303  self.stop(SoundRequest.ALL)
304 
305  def sendMsg(
306  self, snd, cmd, s, arg2="", vol=1.0, replace=True,
307  server_timeout=None, result_timeout=None,
308  **kwargs
309  ):
310  """
311  Internal method that publishes the sound request, either directly as a
312  SoundRequest to the soundplay_node or through the actionlib interface
313  (which blocks until the sound has finished playing).
314 
315  The blocking behavior is nominally the class-wide setting unless it has
316  been explicitly specified in the play call.
317  """
318 
319  # Use the passed-in argument if it exists, otherwise fall back to the
320  # class-wide setting.
321  blocking = kwargs.get('blocking', self._blocking)
322 
323  msg = SoundRequest()
324  msg.sound = snd
325  # Threshold volume between 0 and 1.
326  msg.volume = max(0, min(1, vol))
327  msg.command = cmd
328  msg.arg = s
329  msg.arg2 = arg2
330 
331  rospy.logdebug('Sending sound request with volume = {}'
332  ' and blocking = {}'.format(msg.volume, blocking))
333 
334  # Defensive check for the existence of the correct communicator.
335  if not blocking and not self.pub:
336  rospy.logerr('Publisher for SoundRequest must exist')
337  return
338  if blocking and not self.actionclient:
339  rospy.logerr('Action client for SoundRequest does not exist.')
340  return
341 
342  if not blocking: # Publish message directly and return immediately
343  self.pub.publish(msg)
344  if self.pub.get_num_connections() < 1:
345  rospy.logwarn("Sound command issued, but no node is subscribed"
346  " to the topic. Perhaps you forgot to run"
347  " soundplay_node.py?")
348  else: # Block until result comes back.
349  assert self.actionclient, 'Actionclient must exist'
350  rospy.logdebug('Sending action client sound request [blocking]')
351 
352  if server_timeout is None or server_timeout > rospy.Duration(0):
353  if server_timeout is None:
354  server_timeout = rospy.Duration()
355  if not self.actionclient.wait_for_server(timeout=server_timeout):
356  return
357 
358  goal = SoundRequestGoal()
359  goal.sound_request = msg
360  while not replace and self._playing:
361  rospy.sleep(0.1)
362  self.actionclient.send_goal(goal)
363  if result_timeout is None or result_timeout > rospy.Duration(0):
364  if result_timeout is None:
365  result_timeout = rospy.Duration()
366  if self.actionclient.wait_for_result(timeout=result_timeout):
367  rospy.logdebug('sound request response received')
368  return
369 
370  def _action_status_cb(self, msg):
371  if 1 in [s.status for s in msg.status_list]:
372  self._playing = True
373  else:
374  self._playing = False
def start(self, sound, volume=1.0, kwargs)
Play a buildin sound repeatedly.
def repeat(self, kwargs)
Play the Sound repeatedly.
Definition: libsoundplay.py:77
def waveSound(self, sound, volume=1.0)
Create a wave Sound.
def say(self, text, voice='', volume=1.0, kwargs)
Say a string.
def startWave(self, sound, volume=1.0, kwargs)
Plays a WAV or OGG file repeatedly.
def stopWave(self, sound)
Stop playing a WAV or OGG file.
def stopWaveFromPkg(self, sound, package)
Stop playing a WAV or OGG file.
def __init__(self, client, snd, arg, volume=1.0)
Definition: libsoundplay.py:58
def startWaveFromPkg(self, package, sound, volume=1.0, kwargs)
Plays a WAV or OGG file repeatedly.
def stop(self)
Stop Sound playback.
Definition: libsoundplay.py:85
def __init__(self, blocking=False, sound_action='sound_play', sound_topic='robotsound')
Definition: libsoundplay.py:94
def voiceSound(self, s, volume=1.0)
Create a voice Sound.
def builtinSound(self, id, volume=1.0)
Create a builtin Sound.
def stopAll(self)
Stop all currently playing sounds.
def playWaveFromPkg(self, package, sound, volume=1.0, kwargs)
Plays a WAV or OGG file.
def play(self, kwargs)
Play the Sound.
Definition: libsoundplay.py:68
def _action_status_cb(self, msg)
def playWave(self, sound, volume=1.0, kwargs)
Plays a WAV or OGG file.
def sendMsg(self, snd, cmd, s, arg2="", vol=1.0, replace=True, server_timeout=None, result_timeout=None, kwargs)
def stopSaying(self, text)
Stop saying a string.
This class is a helper class for communicating with the sound_play node via the sound_play.SoundRequest message.
Definition: libsoundplay.py:92
Class that publishes messages to the sound_play node.
Definition: libsoundplay.py:57


sound_play
Author(s): Blaise Gassend
autogenerated on Fri Jun 9 2023 02:47:15