├── .gitignore
├── audio_play
├── .gitignore
├── mainpage.dox
├── CMakeLists.txt
├── launch
│ ├── record_to_file.launch
│ └── play.launch
├── package.xml
├── src
│ └── audio_play.cpp
└── CHANGELOG.rst
├── audio_capture
├── .gitignore
├── mainpage.dox
├── CMakeLists.txt
├── launch
│ ├── capture_wave.launch
│ ├── capture_to_file.launch
│ └── capture.launch
├── package.xml
├── CHANGELOG.rst
└── src
│ └── audio_capture.cpp
├── audio_common_msgs
├── .gitignore
├── msg
│ ├── AudioData.msg
│ ├── AudioDataStamped.msg
│ └── AudioInfo.msg
├── mainpage.dox
├── CMakeLists.txt
├── package.xml
└── CHANGELOG.rst
├── sound_play
├── resources
│ └── flitevox
│ │ └── .gitignore
├── sounds
│ ├── BACKINGUP.ogg
│ ├── say-beep.wav
│ ├── NEEDS_PLUGGING.ogg
│ ├── NEEDS_UNPLUGGING.ogg
│ ├── NEEDS_PLUGGING_BADLY.ogg
│ └── NEEDS_UNPLUGGING_BADLY.ogg
├── action
│ └── SoundRequest.action
├── sound_play_plugin.yaml
├── setup.py
├── test
│ ├── CMakeLists.txt
│ └── test.cpp
├── test.launch
├── scripts
│ ├── test
│ │ └── test_sound_client.py
│ ├── is_speaking.py
│ ├── test_actionlib_client.py
│ ├── shutup.py
│ ├── play.py
│ ├── playbuiltin.py
│ ├── playpackage.py
│ ├── say.py
│ ├── soundclient_example.py
│ ├── test.py
│ └── soundplay_node.py
├── mainpage.dox
├── msg
│ └── SoundRequest.msg
├── src
│ └── sound_play
│ │ ├── sound_play_plugin.py
│ │ ├── __init__.py
│ │ ├── flite_plugin.py
│ │ ├── festival_plugin.py
│ │ ├── sound_type.py
│ │ └── libsoundplay.py
├── soundplay_node.launch
├── CMakeLists.txt
├── README.md
├── package.xml
├── include
│ └── sound_play
│ │ └── sound_play.h
└── CHANGELOG.rst
├── audio_common
├── CMakeLists.txt
├── package.xml
└── CHANGELOG.rst
├── .github
├── labeler.yml
└── workflows
│ ├── labeler.yml
│ └── main.yml
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 |
--------------------------------------------------------------------------------
/audio_play/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 |
--------------------------------------------------------------------------------
/audio_capture/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 |
--------------------------------------------------------------------------------
/audio_common_msgs/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 |
--------------------------------------------------------------------------------
/audio_common_msgs/msg/AudioData.msg:
--------------------------------------------------------------------------------
1 | uint8[] data
2 |
--------------------------------------------------------------------------------
/sound_play/resources/flitevox/.gitignore:
--------------------------------------------------------------------------------
1 | *.flitevox
2 |
--------------------------------------------------------------------------------
/audio_common_msgs/msg/AudioDataStamped.msg:
--------------------------------------------------------------------------------
1 | std_msgs/Header header
2 | audio_common_msgs/AudioData audio
3 |
--------------------------------------------------------------------------------
/sound_play/sounds/BACKINGUP.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ros-drivers/audio_common/HEAD/sound_play/sounds/BACKINGUP.ogg
--------------------------------------------------------------------------------
/sound_play/sounds/say-beep.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ros-drivers/audio_common/HEAD/sound_play/sounds/say-beep.wav
--------------------------------------------------------------------------------
/sound_play/sounds/NEEDS_PLUGGING.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ros-drivers/audio_common/HEAD/sound_play/sounds/NEEDS_PLUGGING.ogg
--------------------------------------------------------------------------------
/sound_play/sounds/NEEDS_UNPLUGGING.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ros-drivers/audio_common/HEAD/sound_play/sounds/NEEDS_UNPLUGGING.ogg
--------------------------------------------------------------------------------
/sound_play/action/SoundRequest.action:
--------------------------------------------------------------------------------
1 | SoundRequest sound_request
2 | ---
3 | bool playing
4 | time stamp
5 | ---
6 | bool playing
7 | time stamp
--------------------------------------------------------------------------------
/sound_play/sounds/NEEDS_PLUGGING_BADLY.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ros-drivers/audio_common/HEAD/sound_play/sounds/NEEDS_PLUGGING_BADLY.ogg
--------------------------------------------------------------------------------
/sound_play/sounds/NEEDS_UNPLUGGING_BADLY.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ros-drivers/audio_common/HEAD/sound_play/sounds/NEEDS_UNPLUGGING_BADLY.ogg
--------------------------------------------------------------------------------
/audio_common/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(audio_common)
3 | find_package(catkin REQUIRED)
4 | catkin_metapackage()
5 |
--------------------------------------------------------------------------------
/sound_play/sound_play_plugin.yaml:
--------------------------------------------------------------------------------
1 | - name: sound_play/festival_plugin
2 | module: sound_play.festival_plugin.FestivalPlugin
3 | - name: sound_play/flite_plugin
4 | module: sound_play.flite_plugin.FlitePlugin
5 |
--------------------------------------------------------------------------------
/audio_common_msgs/mainpage.dox:
--------------------------------------------------------------------------------
1 | /**
2 | \mainpage
3 | \htmlinclude manifest.html
4 |
5 | \b audio_common_msgs contain messages for transimitting audio via ROS.
6 |
7 |
8 | \section codeapi Code API
9 |
10 |
11 | */
12 |
--------------------------------------------------------------------------------
/sound_play/setup.py:
--------------------------------------------------------------------------------
1 | from catkin_pkg.python_setup import generate_distutils_setup
2 | from setuptools import setup
3 |
4 | d = generate_distutils_setup(
5 | packages=['sound_play'],
6 | package_dir={'': 'src'}
7 | )
8 |
9 | setup(**d)
10 |
--------------------------------------------------------------------------------
/sound_play/test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_executable(test_sound_play test.cpp)
2 | target_link_libraries(test_sound_play ${catkin_LIBRARIES})
3 | add_dependencies(test_sound_play sound_play_gencpp)
4 | set_target_properties(test_sound_play PROPERTIES OUTPUT_NAME test)
5 |
--------------------------------------------------------------------------------
/.github/labeler.yml:
--------------------------------------------------------------------------------
1 | github-action:
2 | - .github/**/*
3 | audio_capture:
4 | - audio_capture/**/*
5 | audio_common:
6 | - audio_common/**/*
7 | audio_common_msgs:
8 | - audio_common_msgs/**/*
9 | audio_play:
10 | - audio_play/**/*
11 | sound_play:
12 | - sound_play/**/*
13 | readme:
14 | - REAEME.md
15 |
--------------------------------------------------------------------------------
/sound_play/test.launch:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/audio_common_msgs/msg/AudioInfo.msg:
--------------------------------------------------------------------------------
1 | # This message contains the audio meta data
2 |
3 | # Number of channels
4 | uint8 channels
5 | # Sampling rate [Hz]
6 | uint32 sample_rate
7 | # Audio format (e.g. S16LE)
8 | string sample_format
9 | # Amount of audio data per second [bits/s]
10 | uint32 bitrate
11 | # Audio coding format (e.g. WAVE, MP3)
12 | string coding_format
13 |
--------------------------------------------------------------------------------
/.github/workflows/labeler.yml:
--------------------------------------------------------------------------------
1 | name: "Pull Request Labeler"
2 | on:
3 | - pull_request_target
4 |
5 | permissions:
6 | contents: read
7 |
8 | jobs:
9 | triage:
10 | permissions:
11 | contents: read
12 | pull-requests: write
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/labeler@v3
16 | with:
17 | repo-token: "${{ secrets.GITHUB_TOKEN }}"
18 |
--------------------------------------------------------------------------------
/audio_common_msgs/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 |
3 | project(audio_common_msgs)
4 |
5 | find_package(catkin REQUIRED
6 | COMPONENTS
7 | message_generation
8 | std_msgs
9 | )
10 |
11 | add_message_files(DIRECTORY msg FILES
12 | AudioData.msg
13 | AudioDataStamped.msg
14 | AudioInfo.msg
15 | )
16 |
17 | generate_messages(
18 | DEPENDENCIES
19 | std_msgs
20 | )
21 |
22 | catkin_package(CATKIN_DEPENDS message_runtime)
23 |
--------------------------------------------------------------------------------
/sound_play/scripts/test/test_sound_client.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import unittest
4 |
5 | import rospy
6 | import rostest
7 | from sound_play.libsoundplay import SoundClient
8 |
9 | class TestCase(unittest.TestCase):
10 | def test_soundclient_constructor(self):
11 | s = SoundClient()
12 | self.assertIsNotNone(s)
13 |
14 | if __name__ == '__main__':
15 | rostest.rosrun('sound_play', 'test_sound_client', TestCase)
16 |
17 | __author__ = 'Felix Duvallet'
18 |
--------------------------------------------------------------------------------
/sound_play/mainpage.dox:
--------------------------------------------------------------------------------
1 | /**
2 |
3 | \mainpage
4 | \htmlinclude manifest.html
5 |
6 | The \b sound_play package provides a way to say strings,
7 | play WAV or OGG files and to play builtin sounds. Documentation for the
8 | package can be found here at http://www.ros.org/wiki/sound_play
9 |
10 | Multiple sounds can be played concurrently (up to 4 currently because of
11 | limitations in pygame).
12 |
13 | Python and C++ client classes are provide for ease of use:
14 |
15 | - sound_play::SoundClient and sound_play::SoundClient::Sound for C++
16 | - libsoundplay::SoundClient and libsoundplay::SoundClient::Sound for Python
17 |
18 | Example uses are in:
19 |
20 | - test.cpp
21 | - test.py
22 |
23 | */
24 |
--------------------------------------------------------------------------------
/audio_capture/mainpage.dox:
--------------------------------------------------------------------------------
1 | /**
2 | \mainpage
3 | \htmlinclude manifest.html
4 |
5 | \b audio_capture is a package that records audio from a microphone and makes it available to other ROS nodes.
6 |
7 | \section codeapi Code API
8 |
9 |
19 |
20 |
21 | */
22 |
--------------------------------------------------------------------------------
/audio_play/mainpage.dox:
--------------------------------------------------------------------------------
1 | /**
2 | \mainpage
3 | \htmlinclude manifest.html
4 |
5 | \b audio_play is a package that listens to a node that produces audio_msgs, and plays them through a connected speaker.
6 |
7 |
8 | \section codeapi Code API
9 |
10 |
20 |
21 |
22 | */
23 |
--------------------------------------------------------------------------------
/audio_play/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 |
3 | project(audio_play)
4 |
5 | find_package(catkin REQUIRED COMPONENTS roscpp audio_common_msgs)
6 |
7 | find_package(PkgConfig)
8 | pkg_check_modules(GST1.0 gstreamer-1.0 REQUIRED)
9 |
10 | find_package(Boost REQUIRED COMPONENTS thread)
11 |
12 | include_directories(${catkin_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${GST1.0_INCLUDE_DIRS})
13 |
14 | catkin_package()
15 |
16 | add_executable(audio_play src/audio_play.cpp)
17 | target_link_libraries(audio_play ${catkin_LIBRARIES} ${GST1.0_LIBRARIES} ${Boost_LIBRARIES})
18 | add_dependencies(audio_play ${catkin_EXPORTED_TARGETS})
19 |
20 | install(TARGETS audio_play
21 | DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
22 |
23 | install(DIRECTORY launch
24 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
25 |
--------------------------------------------------------------------------------
/audio_capture/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 |
3 | project(audio_capture)
4 |
5 | find_package(catkin REQUIRED COMPONENTS roscpp audio_common_msgs)
6 |
7 | find_package(PkgConfig)
8 | pkg_check_modules(GST1.0 gstreamer-1.0 REQUIRED)
9 |
10 | find_package(Boost REQUIRED COMPONENTS thread)
11 |
12 | include_directories(${catkin_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${GST1.0_INCLUDE_DIRS})
13 |
14 | catkin_package()
15 |
16 | add_executable(audio_capture src/audio_capture.cpp)
17 | target_link_libraries(audio_capture ${catkin_LIBRARIES} ${GST1.0_LIBRARIES} ${Boost_LIBRARIES})
18 | add_dependencies(audio_capture ${catkin_EXPORTED_TARGETS})
19 |
20 | install(TARGETS audio_capture
21 | DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
22 |
23 | install(DIRECTORY launch
24 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
25 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: ROS1 CI
2 | on:
3 | push:
4 | pull_request:
5 | schedule:
6 | - cron: "0 0 * * *"
7 | jobs:
8 | industrial_ci:
9 | strategy:
10 | matrix:
11 | env:
12 | - ROS_DISTRO: melodic
13 | ROS_REPO: testing
14 | CMAKE_ARGS: '-DCMAKE_BUILD_TYPE=Debug'
15 | - ROS_DISTRO: melodic
16 | ROS_REPO: testing
17 | CMAKE_ARGS: '-DCMAKE_BUILD_TYPE=Release'
18 | - ROS_DISTRO: noetic
19 | ROS_REPO: testing
20 | CMAKE_ARGS: '-DCMAKE_BUILD_TYPE=Debug'
21 | - ROS_DISTRO: noetic
22 | ROS_REPO: testing
23 | CMAKE_ARGS: '-DCMAKE_BUILD_TYPE=Release'
24 | runs-on: ubuntu-latest
25 | steps:
26 | - uses: actions/checkout@v1
27 | - uses: 'ros-industrial/industrial_ci@master'
28 | env: ${{matrix.env}}
29 |
--------------------------------------------------------------------------------
/audio_common_msgs/package.xml:
--------------------------------------------------------------------------------
1 |
2 | audio_common_msgs
3 | 0.3.18
4 |
5 | Messages for transmitting audio via ROS
6 |
7 | Austin Hendrix
8 | Shingo Kitagawa
9 | Nate Koenig
10 | BSD
11 | http://ros.org/wiki/audio_common_msgs
12 | https://github.com/ros-drivers/audio_common
13 | https://github.com/ros-drivers/audio_common/issues
14 |
15 | catkin
16 |
17 | message_generation
18 | std_msgs
19 |
20 | message_runtime
21 | std_msgs
22 |
23 |
--------------------------------------------------------------------------------
/audio_common/package.xml:
--------------------------------------------------------------------------------
1 |
2 | audio_common
3 | 0.3.18
4 |
5 | Common code for working with audio in ROS
6 |
7 | Austin Hendrix
8 | Shingo Kitagawa
9 | Blaise Gassend
10 | BSD
11 | http://ros.org/wiki/audio_common
12 | https://github.com/ros-drivers/audio_common
13 | https://github.com/ros-drivers/audio_common/issues
14 |
15 | catkin
16 |
17 | audio_capture
18 | audio_common_msgs
19 | audio_play
20 | sound_play
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/sound_play/msg/SoundRequest.msg:
--------------------------------------------------------------------------------
1 | # IMPORTANT: You should never have to generate this message yourself.
2 | # Use the sound_play::SoundClient C++ helper or the
3 | # sound_play.libsoundplay.SoundClient Python helper.
4 |
5 | # Sounds
6 | int8 BACKINGUP = 1
7 | int8 NEEDS_UNPLUGGING = 2
8 | int8 NEEDS_PLUGGING = 3
9 | int8 NEEDS_UNPLUGGING_BADLY = 4
10 | int8 NEEDS_PLUGGING_BADLY = 5
11 |
12 | # Sound identifiers that have special meaning
13 | int8 ALL = -1 # Only legal with PLAY_STOP
14 | int8 PLAY_FILE = -2
15 | int8 SAY = -3
16 |
17 | int8 sound # Selects which sound to play (see above)
18 |
19 | # Commands
20 | int8 PLAY_STOP = 0 # Stop this sound from playing
21 | int8 PLAY_ONCE = 1 # Play the sound once
22 | int8 PLAY_START = 2 # Play the sound in a loop until a stop request occurs
23 |
24 | int8 command # Indicates what to do with the sound
25 |
26 | # Volume at which to play the sound, with 0 as mute and 1.0 as 100%.
27 | float32 volume
28 |
29 | string arg # file name or text to say
30 | string arg2 # other arguments
31 |
--------------------------------------------------------------------------------
/sound_play/src/sound_play/sound_play_plugin.py:
--------------------------------------------------------------------------------
1 | class SoundPlayPlugin(object):
2 |
3 | """Base class for sound_play plugin
4 |
5 | This is a base class for sound_play plugin.
6 | sound_play plugin has one method; sound_play_say_plugin.
7 | sound_play_start_plugin run when command is SAY.
8 |
9 | sound_play plugin is defined in yaml format as below;
10 | - name: sound_play/festival_plugin # plugin name
11 | module: sound_play.festival_plugin.FestivalPlugin
12 | # plugin module name
13 |
14 | Also, sound_play plugin yaml file is exported in package.xml as below;
15 |
16 |
17 |
18 | """
19 |
20 | def __init__(self):
21 | pass
22 |
23 | def sound_play_say_plugin(self, text, voice):
24 | """Start plugin for sound_play
25 |
26 | Args:
27 | text (string): speech text
28 | voice (string): speech voice
29 | """
30 | return None
31 |
--------------------------------------------------------------------------------
/sound_play/soundplay_node.launch:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/audio_capture/launch/capture_wave.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/audio_capture/launch/capture_to_file.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/audio_play/launch/record_to_file.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/audio_play/package.xml:
--------------------------------------------------------------------------------
1 |
2 | audio_play
3 | 0.3.18
4 |
5 | Outputs audio to a speaker from a source node.
6 |
7 | Austin Hendrix
8 | Shingo Kitagawa
9 | Nate Koenig
10 | BSD
11 | http://ros.org/wiki/audio_play
12 | https://github.com/ros-drivers/audio_common
13 | https://github.com/ros-drivers/audio_common/issues
14 |
15 | catkin
16 |
17 | roscpp
18 | audio_common_msgs
19 | libgstreamer1.0-dev
20 | libgstreamer-plugins-base1.0-dev
21 |
22 | roscpp
23 | audio_common_msgs
24 | gstreamer1.0
25 | gstreamer1.0-alsa
26 | gstreamer1.0-plugins-base
27 | gstreamer1.0-plugins-ugly
28 | gstreamer1.0-plugins-good
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/audio_capture/launch/capture.launch:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/audio_play/launch/play.launch:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/sound_play/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 |
3 | project(sound_play)
4 |
5 | find_package(catkin REQUIRED COMPONENTS message_generation roscpp actionlib_msgs)
6 |
7 | add_action_files(DIRECTORY action FILES SoundRequest.action)
8 | add_message_files(DIRECTORY msg FILES SoundRequest.msg)
9 |
10 | include_directories(include ${catkin_INCLUDE_DIRS})
11 |
12 | catkin_python_setup()
13 |
14 | generate_messages(DEPENDENCIES actionlib_msgs)
15 |
16 | catkin_package(CATKIN_DEPENDS message_runtime actionlib_msgs
17 | INCLUDE_DIRS include)
18 |
19 | catkin_install_python(PROGRAMS
20 | scripts/is_speaking.py
21 | scripts/playbuiltin.py
22 | scripts/play.py
23 | scripts/say.py
24 | scripts/shutup.py
25 | scripts/soundplay_node.py
26 | scripts/test.py
27 | scripts/test_actionlib_client.py
28 | DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
29 |
30 | install(FILES
31 | soundplay_node.launch
32 | sound_play_plugin.yaml
33 | test.launch
34 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
35 |
36 | install(DIRECTORY include/${PROJECT_NAME}/
37 | DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION})
38 |
39 | install(DIRECTORY sounds
40 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
41 |
42 | # if(CATKIN_ENABLE_TESTING)
43 | # catkin_add_nosetests(scripts/test)
44 | # add_subdirectory(test)
45 | # endif()
46 |
--------------------------------------------------------------------------------
/audio_capture/package.xml:
--------------------------------------------------------------------------------
1 |
2 | audio_capture
3 | 0.3.18
4 |
5 | Transports audio from a source to a destination. Audio sources can come
6 | from a microphone or file. The destination can play the audio or save it
7 | to an mp3 file.
8 |
9 | Austin Hendrix
10 | Shingo Kitagawa
11 | Nate Koenig
12 | BSD
13 | http://ros.org/wiki/audio_capture
14 | https://github.com/ros-drivers/audio_common
15 | https://github.com/ros-drivers/audio_common/issues
16 |
17 | catkin
18 |
19 | roscpp
20 | audio_common_msgs
21 | libgstreamer1.0-dev
22 | libgstreamer-plugins-base1.0-dev
23 |
24 | roscpp
25 | audio_common_msgs
26 | gstreamer1.0
27 | gstreamer1.0-alsa
28 | gstreamer1.0-plugins-base
29 | gstreamer1.0-plugins-good
30 | gstreamer1.0-plugins-ugly
31 |
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2009, Willow Garage, Inc.
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/sound_play/scripts/is_speaking.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import rospy
4 |
5 | from actionlib_msgs.msg import GoalStatus
6 | from actionlib_msgs.msg import GoalStatusArray
7 | import std_msgs.msg
8 |
9 |
10 | class IsSpeaking(object):
11 |
12 | def __init__(self):
13 | super(IsSpeaking, self).__init__()
14 |
15 | self.sub = rospy.Subscriber(
16 | '~robotsound',
17 | GoalStatusArray,
18 | callback=self.callback,
19 | queue_size=1)
20 |
21 | self.is_speaking = False
22 | self.pub_speech_flag = rospy.Publisher(
23 | '~output/is_speaking',
24 | std_msgs.msg.Bool, queue_size=1)
25 |
26 | self.timer = rospy.Timer(rospy.Duration(0.01), self.speech_timer_cb)
27 |
28 | def check_speak_status(self, status_msg):
29 | """Returns True when speaking.
30 |
31 | """
32 | # If it is not included in the terminal state,
33 | # it is determined as a speaking state.
34 | if status_msg.status in [GoalStatus.ACTIVE,
35 | GoalStatus.PREEMPTING,
36 | GoalStatus.RECALLING]:
37 | return True
38 | return False
39 |
40 | def callback(self, msg):
41 | for status in msg.status_list:
42 | if self.check_speak_status(status):
43 | self.is_speaking = True
44 | return
45 | self.is_speaking = False
46 |
47 | def speech_timer_cb(self, timer):
48 | self.pub_speech_flag.publish(
49 | std_msgs.msg.Bool(self.is_speaking))
50 |
51 |
52 | if __name__ == '__main__':
53 | rospy.init_node('is_speaking')
54 | app = IsSpeaking()
55 | rospy.spin()
56 |
--------------------------------------------------------------------------------
/sound_play/src/sound_play/__init__.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2013, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | from sound_play.festival_plugin import FestivalPlugin
34 | from sound_play.flite_plugin import FlitePlugin
35 | import sound_play.libsoundplay as libsoundplay
36 | from sound_play.sound_play_plugin import SoundPlayPlugin
37 |
--------------------------------------------------------------------------------
/sound_play/README.md:
--------------------------------------------------------------------------------
1 | sound_play
2 | =========
3 |
4 | ## Dependencies
5 |
6 | - python-pygame
7 | - festival
8 | - festvox-don
9 | - alsa-base
10 | - alsa-tools
11 |
12 | ## Checking that the speaker/sound card is recognized by the kernel
13 |
14 | `cat /proc/asound/cards`
15 |
16 | Your card should be in the list. Make note of the number in front of the
17 | card, it will be used to tell alsa where to play sound from.
18 |
19 | If your sound device does not show up, your kernel may not support it, or
20 | the module may not be loaded. For usb speakers, you may want to try:
21 |
22 | `modprobe snd-usb-audio`
23 |
24 | (not sure if this list is exhaustive)
25 |
26 | ## Telling alsa which sound card/speaker to use
27 |
28 | Run (replace 75 with the number of the sound device to use):
29 |
30 | `asoundconf set-default-card 75`
31 |
32 | This will create .asoundrc.asoundconf in your home directory.
33 | To make alsa use these settings, add the following line to `~/.asoundrc`
34 |
35 | `include ".asoundrc.asoundconf"`
36 |
37 | To set this default to all users, copy this to the system-wide alsa
38 | configuration file:
39 |
40 | `mv ~/.asoundrc.asoundconf /etc/asound.conf`
41 |
42 | ## Getting started
43 |
44 | Start the sound play node, and have a look at the scripts in the scripts
45 | directory that exercise the node's functionality.
46 |
47 | ## Specify Device via ROS Param
48 |
49 | Besides setting default device as system wide settings, you can also specify audio device via `rosparam`:
50 |
51 | ``` xml
52 |
53 |
54 |
55 |
56 |
57 | ```
58 |
59 | or simply run: `rosrun sound_play soundplay_node.py _device:="hw:1,0"`
60 |
61 | In the launch file above, `~device` parameter is set to `hw:1,0`, which tells `soundplay_node` to use audio device No. `0` connected to audio card No.`1`.
62 | To find card/device number which you want to use, execute:
63 |
64 | ``` bash
65 | sudo aplay -l
66 | ```
67 |
68 |
--------------------------------------------------------------------------------
/sound_play/src/sound_play/flite_plugin.py:
--------------------------------------------------------------------------------
1 | import os
2 | import tempfile
3 |
4 | import resource_retriever
5 | import rospkg
6 | import rospy
7 |
8 | from sound_play.sound_play_plugin import SoundPlayPlugin
9 |
10 |
11 | class FlitePlugin(SoundPlayPlugin):
12 |
13 | _default_voice = 'kal'
14 |
15 | def __init__(self):
16 | super(FlitePlugin, self).__init__()
17 | self._default_voice_path = None
18 |
19 | def get_default_voice_path(self):
20 | if self._default_voice_path is None:
21 | self._default_voice_path = os.path.join(
22 | rospkg.RosPack().get_path('sound_play'),
23 | 'resources/flitevox')
24 | return self._default_voice_path
25 |
26 | def sound_play_say_plugin(self, text, voice):
27 | if voice is None or voice == '':
28 | voice = self._default_voice
29 | if voice.endswith('.flitevox'):
30 | if voice.startswith('package://'):
31 | voice = resource_retriever.get(voice)
32 | elif voice.startswith('/'):
33 | voice = voice
34 | else:
35 | voice = os.path.join(
36 | self.get_default_voice_path(), voice)
37 | (wavfile, wavfilename) = tempfile.mkstemp(
38 | prefix='sound_play', suffix='.wav')
39 | os.close(wavfile)
40 | cmd = "flite -voice {0} -t \"{1}\" -o {2}".format(
41 | voice, text, wavfilename)
42 | os.system(cmd)
43 | try:
44 | if os.stat(wavfilename).st_size == 0:
45 | # So we hit the same catch block
46 | raise OSError
47 | except OSError:
48 | rospy.logerr(
49 | 'Sound synthesis failed.'
50 | 'Is flite installed?'
51 | 'Is a flite voice installed?'
52 | 'Try running "rosdep satisfy sound_play|sh".'
53 | 'Refer to http://wiki.ros.org/'
54 | 'sound_play/Troubleshooting'
55 | )
56 | return None
57 | return wavfilename
58 |
--------------------------------------------------------------------------------
/sound_play/scripts/test_actionlib_client.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 |
3 | import roslib; roslib.load_manifest('sound_play')
4 | import rospy
5 | import actionlib
6 | from sound_play.msg import SoundRequest, SoundRequestAction, SoundRequestGoal
7 |
8 | import os
9 |
10 | def sound_play_client(volume=1.0):
11 | client = actionlib.SimpleActionClient('sound_play', SoundRequestAction)
12 |
13 | client.wait_for_server()
14 |
15 | rospy.loginfo("Need Unplugging")
16 | goal = SoundRequestGoal()
17 | goal.sound_request.sound = SoundRequest.NEEDS_UNPLUGGING
18 | goal.sound_request.command = SoundRequest.PLAY_ONCE
19 | goal.sound_request.volume = volume
20 |
21 | client.send_goal(goal)
22 | client.wait_for_result()
23 | # print client.get_result()
24 | rospy.loginfo("End Need Unplugging")
25 |
26 | rospy.loginfo("Need Plugging")
27 | goal = SoundRequestGoal()
28 | goal.sound_request.sound = SoundRequest.NEEDS_PLUGGING
29 | goal.sound_request.command = SoundRequest.PLAY_ONCE
30 | goal.sound_request.volume = volume
31 | client.send_goal(goal)
32 | client.wait_for_result()
33 | # print client.get_result()
34 | rospy.loginfo("End Need Plugging")
35 |
36 | rospy.loginfo("Say")
37 | goal = SoundRequestGoal()
38 | goal.sound_request.sound = SoundRequest.SAY
39 | goal.sound_request.command = SoundRequest.PLAY_ONCE
40 | goal.sound_request.arg = "Testing the actionlib interface A P I"
41 | goal.sound_request.volume = volume
42 | client.send_goal(goal)
43 | client.wait_for_result()
44 | # print client.get_result()
45 | rospy.loginfo("End Say")
46 |
47 | rospy.loginfo("Wav")
48 | goal = SoundRequestGoal()
49 | goal.sound_request.sound = SoundRequest.PLAY_FILE
50 | goal.sound_request.command = SoundRequest.PLAY_ONCE
51 | goal.sound_request.arg = os.path.join(roslib.packages.get_pkg_dir('sound_play'),'sounds') + "/say-beep.wav"
52 | goal.sound_request.volume = volume
53 | client.send_goal(goal)
54 | client.wait_for_result()
55 | # print client.get_result()
56 | rospy.loginfo("End wav")
57 |
58 | if __name__ == '__main__':
59 | rospy.init_node('soundplay_client_test')
60 | sound_play_client()
61 |
--------------------------------------------------------------------------------
/sound_play/src/sound_play/festival_plugin.py:
--------------------------------------------------------------------------------
1 | import os
2 | import tempfile
3 |
4 | import rospy
5 |
6 | from sound_play.sound_play_plugin import SoundPlayPlugin
7 |
8 |
9 | class FestivalPlugin(SoundPlayPlugin):
10 |
11 | _default_voice = 'voice_kal_diphone'
12 |
13 | def __init__(self):
14 | super(FestivalPlugin, self).__init__()
15 |
16 | def sound_play_say_plugin(self, text, voice):
17 | if voice is None or voice == '':
18 | voice = self._default_voice
19 | encoding = 'ISO-8859-15'
20 | if ':' in voice:
21 | voice, encoding = voice.split(':', maxsplit=1)
22 | txtfile = tempfile.NamedTemporaryFile(
23 | prefix='sound_play', suffix='.txt')
24 | (wavfile, wavfilename) = tempfile.mkstemp(
25 | prefix='sound_play', suffix='.wav')
26 | txtfilename = txtfile.name
27 | os.close(wavfile)
28 | try:
29 | try:
30 | if hasattr(text, 'decode'):
31 | txtfile.write(
32 | text.decode('UTF-8').encode(encoding))
33 | else:
34 | txtfile.write(
35 | text.encode(encoding))
36 | except UnicodeEncodeError:
37 | if hasattr(text, 'decode'):
38 | txtfile.write(text)
39 | else:
40 | txtfile.write(text.encode('UTF-8'))
41 | txtfile.flush()
42 | cmd = "text2wave -eval '({0})' {1} -o {2}".format(
43 | voice, txtfilename, wavfilename)
44 | os.system(cmd)
45 | try:
46 | if os.stat(wavfilename).st_size == 0:
47 | # So we hit the same catch block
48 | raise OSError
49 | except OSError:
50 | rospy.logerr(
51 | 'Sound synthesis failed.'
52 | 'Is festival installed?'
53 | 'Is a festival voice installed?'
54 | 'Try running "rosdep satisfy sound_play|sh".'
55 | 'Refer to http://wiki.ros.org/'
56 | 'sound_play/Troubleshooting'
57 | )
58 | return None
59 | finally:
60 | txtfile.close()
61 | return wavfilename
62 |
--------------------------------------------------------------------------------
/sound_play/scripts/shutup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | #***********************************************************
4 | #* Software License Agreement (BSD License)
5 | #*
6 | #* Copyright (c) 2009, Willow Garage, Inc.
7 | #* All rights reserved.
8 | #*
9 | #* Redistribution and use in source and binary forms, with or without
10 | #* modification, are permitted provided that the following conditions
11 | #* are met:
12 | #*
13 | #* * Redistributions of source code must retain the above copyright
14 | #* notice, this list of conditions and the following disclaimer.
15 | #* * Redistributions in binary form must reproduce the above
16 | #* copyright notice, this list of conditions and the following
17 | #* disclaimer in the documentation and/or other materials provided
18 | #* with the distribution.
19 | #* * Neither the name of the Willow Garage nor the names of its
20 | #* contributors may be used to endorse or promote products derived
21 | #* from this software without specific prior written permission.
22 | #*
23 | #* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | #* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | #* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | #* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | #* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 | #* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 | #* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 | #* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 | #* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 | #* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 | #* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 | #* POSSIBILITY OF SUCH DAMAGE.
35 | #***********************************************************
36 |
37 | # Author: Blaise Gassend
38 |
39 | import rospy
40 | from sound_play.msg import SoundRequest
41 | from sound_play.libsoundplay import SoundClient
42 |
43 | if __name__ == '__main__':
44 | rospy.init_node('shutup', anonymous=True)
45 |
46 | soundhandle = SoundClient()
47 | rospy.sleep(0.5) # let ROS get started...
48 |
49 | rospy.loginfo("Sending stopAll commande every 100 ms.")
50 | rospy.loginfo("Note: This will not prevent a node that is continuing to issue commands")
51 | rospy.loginfo("from producing sound.")
52 | rospy.loginfo("Press Ctrl+C to exit.")
53 |
54 | while not rospy.is_shutdown():
55 | soundhandle.stopAll()
56 | try:
57 | rospy.sleep(.1)
58 | except:
59 | pass
60 |
--------------------------------------------------------------------------------
/audio_common/CHANGELOG.rst:
--------------------------------------------------------------------------------
1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 | Changelog for package audio_common
3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4 |
5 | 0.3.18 (2024-08-13)
6 | -------------------
7 |
8 | 0.3.17 (2023-06-08)
9 | -------------------
10 |
11 | 0.3.16 (2022-12-23)
12 | -------------------
13 |
14 | 0.3.15 (2022-08-29)
15 | -------------------
16 |
17 | 0.3.14 (2022-08-18)
18 | -------------------
19 |
20 | 0.3.13 (2022-04-07)
21 | -------------------
22 |
23 | 0.3.12 (2021-09-01)
24 | -------------------
25 | * Merge branch 'master' into master
26 | * Contributors: Shingo Kitagawa
27 |
28 | 0.3.11 (2021-04-08)
29 | -------------------
30 |
31 | 0.3.10 (2021-01-07)
32 | -------------------
33 |
34 | 0.3.9 (2020-10-22)
35 | ------------------
36 |
37 | 0.3.8 (2020-09-13)
38 | ------------------
39 |
40 | 0.3.7 (2020-08-08)
41 | ------------------
42 |
43 | 0.3.6 (2020-05-29)
44 | ------------------
45 | * Merge pull request `#141 `_ from knorth55/add-maintainer
46 | add maintainer
47 | * add maintainer
48 | * Contributors: Shingo Kitagawa
49 |
50 | 0.3.5 (2020-04-28)
51 | ------------------
52 |
53 | 0.3.4 (2020-04-02)
54 | ------------------
55 | * Merge branch 'master' of github.com:ros-drivers/audio_common
56 | * Contributors: Gerard Canal
57 |
58 | 0.3.3 (2018-05-22)
59 | ------------------
60 |
61 | 0.3.2 (2018-05-02)
62 | ------------------
63 |
64 | 0.3.1 (2016-08-28)
65 | ------------------
66 | * Add changelogs
67 | * Update maintainer email
68 | * Contributors: trainman419
69 |
70 | 0.2.11 (2016-02-16)
71 | -------------------
72 | * Add changelogs
73 | * Contributors: trainman419
74 |
75 | 0.2.10 (2016-01-21)
76 | -------------------
77 | * Add changelogs
78 | * Contributors: trainman419
79 |
80 | 0.2.9 (2015-12-02)
81 | ------------------
82 | * Add changelogs
83 | * Contributors: trainman419
84 |
85 | 0.2.8 (2015-10-02)
86 | ------------------
87 | * Update maintainer email
88 | * Contributors: trainman419
89 |
90 | 0.2.7 (2014-07-25)
91 | ------------------
92 |
93 | 0.2.6 (2014-02-26)
94 | ------------------
95 |
96 | 0.2.5 (2014-01-23)
97 | ------------------
98 | * "0.2.5"
99 | * Contributors: trainman419
100 |
101 | 0.2.4 (2013-09-10)
102 | ------------------
103 |
104 | 0.2.3 (2013-07-15)
105 | ------------------
106 |
107 | 0.2.2 (2013-04-10)
108 | ------------------
109 |
110 | 0.2.1 (2013-04-08 13:59)
111 | ------------------------
112 | * Fix metapackage for REP 127.
113 | * Contributors: Austin Hendrix
114 |
115 | 0.2.0 (2013-04-08 13:49)
116 | ------------------------
117 | * Versions and more URLs.
118 | * Convert stack.xml to metapackage package.xml
119 | * Start catkinizing.
120 | * Contributors: Austin Hendrix
121 |
--------------------------------------------------------------------------------
/sound_play/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | sound_play
7 | 0.3.18
8 |
9 | sound_play provides a ROS node that translates commands on a ROS topic (robotsound) into sounds. The node supports built-in sounds, playing OGG/WAV files, and doing speech synthesis via festival. C++ and Python bindings allow this node to be used without understanding the details of the message format, allowing faster development and resilience to message format changes.
10 |
11 | Austin Hendrix
12 | Shingo Kitagawa
13 | Blaise Gassend
14 | BSD
15 | http://ros.org/wiki/sound_play
16 | https://github.com/ros-drivers/audio_common
17 | https://github.com/ros-drivers/audio_common/issues
18 |
19 | catkin
20 | python-setuptools
21 | python3-setuptools
22 |
23 | roscpp
24 | roslib
25 | actionlib_msgs
26 | actionlib
27 | audio_common_msgs
28 | diagnostic_msgs
29 | message_generation
30 |
31 | roscpp
32 | roslib
33 | actionlib_msgs
34 | audio_common_msgs
35 | diagnostic_msgs
36 |
37 | python-gi
38 | python3-gi
39 | gstreamer1.0
40 | gstreamer1.0-alsa
41 | gstreamer1.0-plugins-base
42 | gstreamer1.0-plugins-ugly
43 | gstreamer1.0-plugins-good
44 |
45 | rospy
46 | festival
47 | flite
48 | message_runtime
49 | resource_retriever
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/sound_play/scripts/play.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | #***********************************************************
4 | #* Software License Agreement (BSD License)
5 | #*
6 | #* Copyright (c) 2009, Willow Garage, Inc.
7 | #* All rights reserved.
8 | #*
9 | #* Redistribution and use in source and binary forms, with or without
10 | #* modification, are permitted provided that the following conditions
11 | #* are met:
12 | #*
13 | #* * Redistributions of source code must retain the above copyright
14 | #* notice, this list of conditions and the following disclaimer.
15 | #* * Redistributions in binary form must reproduce the above
16 | #* copyright notice, this list of conditions and the following
17 | #* disclaimer in the documentation and/or other materials provided
18 | #* with the distribution.
19 | #* * Neither the name of the Willow Garage nor the names of its
20 | #* contributors may be used to endorse or promote products derived
21 | #* from this software without specific prior written permission.
22 | #*
23 | #* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | #* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | #* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | #* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | #* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 | #* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 | #* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 | #* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 | #* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 | #* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 | #* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 | #* POSSIBILITY OF SUCH DAMAGE.
35 | #***********************************************************
36 |
37 | # Author: Blaise Gassend
38 |
39 |
40 | if __name__ == '__main__':
41 | import rospy
42 | rospy.init_node('play', anonymous=True)
43 | argv = rospy.myargv()
44 | if len(argv) < 2 or len(argv) > 3 or argv[1] == '--help':
45 | print('Usage: %s sound_to_play.(ogg|wav) [volume]' % argv[0])
46 | print()
47 | print('Plays an .OGG or .WAV file. The path to the file should be absolute, and be valid on the computer on which sound_play is running.\n The (optional) second parameter sets the volume for the sound as a value between 0 and 1.0, where 0 is mute.')
48 | exit(1)
49 |
50 | # Import after printing usage for speed.
51 | from sound_play.msg import SoundRequest
52 | from sound_play.libsoundplay import SoundClient
53 |
54 | soundhandle = SoundClient()
55 |
56 | rospy.sleep(1)
57 | rospy.loginfo('Playing "%s".' % argv[1])
58 |
59 | volume = float(argv[2]) if len(argv) == 3 else 1.0
60 |
61 | soundhandle.playWave(argv[1], volume)
62 | rospy.sleep(1)
63 |
--------------------------------------------------------------------------------
/sound_play/scripts/playbuiltin.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | #***********************************************************
4 | #* Software License Agreement (BSD License)
5 | #*
6 | #* Copyright (c) 2009, Willow Garage, Inc.
7 | #* All rights reserved.
8 | #*
9 | #* Redistribution and use in source and binary forms, with or without
10 | #* modification, are permitted provided that the following conditions
11 | #* are met:
12 | #*
13 | #* * Redistributions of source code must retain the above copyright
14 | #* notice, this list of conditions and the following disclaimer.
15 | #* * Redistributions in binary form must reproduce the above
16 | #* copyright notice, this list of conditions and the following
17 | #* disclaimer in the documentation and/or other materials provided
18 | #* with the distribution.
19 | #* * Neither the name of the Willow Garage nor the names of its
20 | #* contributors may be used to endorse or promote products derived
21 | #* from this software without specific prior written permission.
22 | #*
23 | #* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | #* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | #* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | #* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | #* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 | #* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 | #* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 | #* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 | #* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 | #* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 | #* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 | #* POSSIBILITY OF SUCH DAMAGE.
35 | #***********************************************************
36 |
37 | # Author: Blaise Gassend
38 |
39 | import sys
40 |
41 | if __name__ == '__main__':
42 | import rospy
43 | argv = rospy.myargv()
44 | if len(argv) < 2 or len(argv) > 3 or argv[1] == '--help':
45 | print('Usage: %s [volume]' % argv[0])
46 | print()
47 | print('Plays one of the built-in sounds based on its integer ID. Look at the sound_play/SoundRequest message definition for IDs.\n The (optional) volume parameter sets the volume for the sound as a value between 0 and 1.0, where 0 is mute.')
48 | exit(1)
49 |
50 | # Import here so that usage is fast.
51 | from sound_play.msg import SoundRequest
52 | from sound_play.libsoundplay import SoundClient
53 |
54 | rospy.init_node('play', anonymous=True)
55 |
56 | soundhandle = SoundClient()
57 | rospy.sleep(1)
58 |
59 | num = int(argv[1])
60 | volume = float(argv[2]) if len(argv) == 3 else 1.0
61 |
62 | rospy.loginfo('Playing sound %i.' % num)
63 |
64 | soundhandle.play(num, volume)
65 |
66 | rospy.sleep(1)
67 |
--------------------------------------------------------------------------------
/sound_play/scripts/playpackage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | #***********************************************************
4 | #* Software License Agreement (BSD License)
5 | #*
6 | #* Copyright (c) 2009, Willow Garage, Inc.
7 | #* All rights reserved.
8 | #*
9 | #* Redistribution and use in source and binary forms, with or without
10 | #* modification, are permitted provided that the following conditions
11 | #* are met:
12 | #*
13 | #* * Redistributions of source code must retain the above copyright
14 | #* notice, this list of conditions and the following disclaimer.
15 | #* * Redistributions in binary form must reproduce the above
16 | #* copyright notice, this list of conditions and the following
17 | #* disclaimer in the documentation and/or other materials provided
18 | #* with the distribution.
19 | #* * Neither the name of the Willow Garage nor the names of its
20 | #* contributors may be used to endorse or promote products derived
21 | #* from this software without specific prior written permission.
22 | #*
23 | #* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | #* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | #* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | #* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | #* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 | #* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 | #* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 | #* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 | #* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 | #* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 | #* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 | #* POSSIBILITY OF SUCH DAMAGE.
35 | #***********************************************************
36 |
37 | # Author: Matthias Nieuwenhuisen, Blaise Gassend
38 |
39 |
40 | import sys
41 |
42 | if __name__ == '__main__':
43 | import rospy
44 | argv = rospy.myargv()
45 | if len(argv) < 3 or len(argv) > 4 or argv[1] == '--help':
46 | print('Usage: %s package sound_to_play.(ogg|wav) [volume]' % argv[0])
47 | print()
48 | print('Plays an .OGG or .WAV file. The path to the file should be relative to the package, and be valid on the computer on which sound_play is running. \n The (optional) volume parameter sets the volume for the sound as a value between 0 and 1.0, where 0 is mute.')
49 | exit(1)
50 |
51 | # Import after printing usage for speed.
52 | from sound_play.msg import SoundRequest
53 | from sound_play.libsoundplay import SoundClient
54 |
55 | rospy.init_node('play', anonymous=True)
56 | soundhandle = SoundClient()
57 |
58 | volume = float(argv[3]) if len(argv) == 4 else 1.0
59 |
60 | rospy.sleep(1)
61 | rospy.loginfo('Playing "%s" from pkg "%s".' % (argv[2], argv[1]))
62 | soundhandle.playWaveFromPkg(argv[1], argv[2], volume)
63 | rospy.sleep(1)
64 |
--------------------------------------------------------------------------------
/audio_common_msgs/CHANGELOG.rst:
--------------------------------------------------------------------------------
1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 | Changelog for package audio_common_msgs
3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4 |
5 | 0.3.18 (2024-08-13)
6 | -------------------
7 |
8 | 0.3.17 (2023-06-08)
9 | -------------------
10 |
11 | 0.3.16 (2022-12-23)
12 | -------------------
13 | * Merge pull request `#202 `_ from knorth55/audio-stamped-msg
14 | * add AudioDataStamped.msg
15 | * Contributors: Shingo Kitagawa
16 |
17 | 0.3.15 (2022-08-29)
18 | -------------------
19 |
20 | 0.3.14 (2022-08-18)
21 | -------------------
22 |
23 | 0.3.13 (2022-04-07)
24 | -------------------
25 |
26 | 0.3.12 (2021-09-01)
27 | -------------------
28 | * Merge branch 'master' into master
29 | * Contributors: Shingo Kitagawa
30 |
31 | 0.3.11 (2021-04-08)
32 | -------------------
33 |
34 | 0.3.10 (2021-01-07)
35 | -------------------
36 | * Change comment style in AudioInfo.msg
37 | * [audio_common_msgs] AudioInfo.msg to add audio meta data
38 | * Contributors: Naoya Yamaguchi
39 |
40 | 0.3.9 (2020-10-22)
41 | ------------------
42 |
43 | 0.3.8 (2020-09-13)
44 | ------------------
45 |
46 | 0.3.7 (2020-08-08)
47 | ------------------
48 |
49 | 0.3.6 (2020-05-29)
50 | ------------------
51 | * Merge pull request `#141 `_ from knorth55/add-maintainer
52 | add maintainer
53 | * add maintainer
54 | * Contributors: Shingo Kitagawa
55 |
56 | 0.3.5 (2020-04-28)
57 | ------------------
58 |
59 | 0.3.4 (2020-04-02)
60 | ------------------
61 | * Merge branch 'master' of github.com:ros-drivers/audio_common
62 | * Contributors: Gerard Canal
63 |
64 | 0.3.3 (2018-05-22)
65 | ------------------
66 |
67 | 0.3.2 (2018-05-02)
68 | ------------------
69 |
70 | 0.3.1 (2016-08-28)
71 | ------------------
72 | * Add changelogs
73 | * Update maintainer email
74 | * Contributors: trainman419
75 |
76 | 0.2.11 (2016-02-16)
77 | -------------------
78 | * Add changelogs
79 | * Contributors: trainman419
80 |
81 | 0.2.10 (2016-01-21)
82 | -------------------
83 | * Add changelogs
84 | * Contributors: trainman419
85 |
86 | 0.2.9 (2015-12-02)
87 | ------------------
88 | * Add changelogs
89 | * Contributors: trainman419
90 |
91 | 0.2.8 (2015-10-02)
92 | ------------------
93 | * Update maintainer email
94 | * Contributors: trainman419
95 |
96 | 0.2.7 (2014-07-25)
97 | ------------------
98 |
99 | 0.2.6 (2014-02-26)
100 | ------------------
101 |
102 | 0.2.5 (2014-01-23)
103 | ------------------
104 | * "0.2.5"
105 | * Contributors: trainman419
106 |
107 | 0.2.4 (2013-09-10)
108 | ------------------
109 |
110 | 0.2.3 (2013-07-15)
111 | ------------------
112 |
113 | 0.2.2 (2013-04-10)
114 | ------------------
115 |
116 | 0.2.1 (2013-04-08 13:59)
117 | ------------------------
118 |
119 | 0.2.0 (2013-04-08 13:49)
120 | ------------------------
121 | * Catkinize audio_common_msgs.
122 | * Versions and more URLs.
123 | * Convert manifests to package.xml
124 | * Ditch old makefiles.
125 | * Fixed audio_msgs names to audio_common_msgs
126 | * Renamed audio_msgs to audio_common_msgs
127 | * Contributors: Austin Hendrix, Nate Koenig
128 |
--------------------------------------------------------------------------------
/sound_play/scripts/say.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | #***********************************************************
4 | #* Software License Agreement (BSD License)
5 | #*
6 | #* Copyright (c) 2009, Willow Garage, Inc.
7 | #* All rights reserved.
8 | #*
9 | #* Redistribution and use in source and binary forms, with or without
10 | #* modification, are permitted provided that the following conditions
11 | #* are met:
12 | #*
13 | #* * Redistributions of source code must retain the above copyright
14 | #* notice, this list of conditions and the following disclaimer.
15 | #* * Redistributions in binary form must reproduce the above
16 | #* copyright notice, this list of conditions and the following
17 | #* disclaimer in the documentation and/or other materials provided
18 | #* with the distribution.
19 | #* * Neither the name of the Willow Garage nor the names of its
20 | #* contributors may be used to endorse or promote products derived
21 | #* from this software without specific prior written permission.
22 | #*
23 | #* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | #* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | #* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | #* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | #* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 | #* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 | #* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 | #* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 | #* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 | #* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 | #* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 | #* POSSIBILITY OF SUCH DAMAGE.
35 | #***********************************************************
36 |
37 | # Author: Blaise Gassend
38 |
39 |
40 | import sys
41 |
42 | if __name__ == '__main__':
43 | import rospy
44 | argv = rospy.myargv()
45 | if len(argv) > 1 and argv[1] == '--help':
46 | print('Usage: %s \'String to say.\'' % argv[0])
47 | print(' %s < file_to_say.txt' % argv[0])
48 | print()
49 | print('Says a string. For a string on the command line, you must use quotes as')
50 | print('appropriate. For a string on standard input, the command will wait for')
51 | print('EOF before saying anything.')
52 | exit(-1)
53 |
54 | # Import after printing usage for speed.
55 | from sound_play.msg import SoundRequest
56 | from sound_play.libsoundplay import SoundClient
57 |
58 | if len(argv) == 1:
59 | print('Awaiting something to say on standard input.')
60 |
61 | # Ordered this way to minimize wait time.
62 | rospy.init_node('say', anonymous=True)
63 | soundhandle = SoundClient()
64 | rospy.sleep(1)
65 |
66 | voice = 'voice_kal_diphone'
67 | volume = 1.0
68 |
69 | if len(argv) == 1:
70 | s = sys.stdin.read()
71 | else:
72 | s = argv[1]
73 |
74 | if len(argv) > 2:
75 | voice = argv[2]
76 | if len(argv) > 3:
77 | volume = float(argv[3])
78 |
79 | rospy.loginfo('Saying: %s' % s)
80 | rospy.loginfo('Voice: %s' % voice)
81 | rospy.loginfo('Volume: %s' % volume)
82 |
83 | soundhandle.say(s, voice, volume)
84 | rospy.sleep(1)
85 |
--------------------------------------------------------------------------------
/sound_play/scripts/soundclient_example.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """
4 | Simple example showing how to use the SoundClient provided by libsoundplay,
5 | in blocking, non-blocking, and explicit usage.
6 | """
7 |
8 | import rospy
9 | from sound_play.libsoundplay import SoundClient
10 | from sound_play.msg import SoundRequest
11 |
12 |
13 | def play_explicit():
14 | rospy.loginfo('Example: SoundClient play methods can take in an explicit'
15 | ' blocking parameter')
16 | soundhandle = SoundClient() # blocking = False by default
17 | rospy.sleep(0.5) # Ensure publisher connection is successful.
18 |
19 | sound_beep = soundhandle.waveSound("say-beep.wav", volume=0.5)
20 | # Play the same sound twice, once blocking and once not. The first call is
21 | # blocking (explicitly specified).
22 | sound_beep.play(blocking=True)
23 | # This call is not blocking (uses the SoundClient's setting).
24 | sound_beep.play()
25 | rospy.sleep(0.5) # Let sound complete.
26 |
27 | # Play a blocking sound.
28 | soundhandle.play(SoundRequest.NEEDS_UNPLUGGING, blocking=True)
29 |
30 | # Create a new SoundClient where the default behavior *is* to block.
31 | soundhandle = SoundClient(blocking=True)
32 | soundhandle.say('Say-ing stuff while block-ing')
33 | soundhandle.say('Say-ing stuff without block-ing', blocking=False)
34 | rospy.sleep(1)
35 |
36 |
37 | def play_blocking():
38 | """
39 | Play various sounds, blocking until each is completed before going to the
40 | next.
41 | """
42 | rospy.loginfo('Example: Playing sounds in *blocking* mode.')
43 | soundhandle = SoundClient(blocking=True)
44 |
45 | rospy.loginfo('Playing say-beep at full volume.')
46 | soundhandle.playWave('say-beep.wav')
47 |
48 | rospy.loginfo('Playing say-beep at volume 0.3.')
49 | soundhandle.playWave('say-beep.wav', volume=0.3)
50 |
51 | rospy.loginfo('Playing sound for NEEDS_PLUGGING.')
52 | soundhandle.play(SoundRequest.NEEDS_PLUGGING)
53 |
54 | rospy.loginfo('Speaking some long string.')
55 | soundhandle.say('It was the best of times, it was the worst of times.')
56 |
57 |
58 | def play_nonblocking():
59 | """
60 | Play the same sounds with manual pauses between them.
61 | """
62 | rospy.loginfo('Example: Playing sounds in *non-blocking* mode.')
63 | # NOTE: you must sleep at the beginning to let the SoundClient publisher
64 | # establish a connection to the soundplay_node.
65 | soundhandle = SoundClient(blocking=False)
66 | rospy.sleep(1)
67 |
68 | # In the non-blocking version you need to sleep between calls.
69 | rospy.loginfo('Playing say-beep at full volume.')
70 | soundhandle.playWave('say-beep.wav')
71 | rospy.sleep(1)
72 |
73 | rospy.loginfo('Playing say-beep at volume 0.3.')
74 | soundhandle.playWave('say-beep.wav', volume=0.3)
75 | rospy.sleep(1)
76 |
77 | rospy.loginfo('Playing sound for NEEDS_PLUGGING.')
78 | soundhandle.play(SoundRequest.NEEDS_PLUGGING)
79 | rospy.sleep(1)
80 |
81 | rospy.loginfo('Speaking some long string.')
82 | soundhandle.say('It was the best of times, it was the worst of times.')
83 | # Note we will return before the string has finished playing.
84 |
85 |
86 | if __name__ == '__main__':
87 | rospy.init_node('soundclient_example', anonymous=False)
88 | play_explicit()
89 | play_blocking()
90 | play_nonblocking()
91 | rospy.loginfo('Finished')
92 |
--------------------------------------------------------------------------------
/sound_play/scripts/test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | #***********************************************************
4 | #* Software License Agreement (BSD License)
5 | #*
6 | #* Copyright (c) 2009, Willow Garage, Inc.
7 | #* All rights reserved.
8 | #*
9 | #* Redistribution and use in source and binary forms, with or without
10 | #* modification, are permitted provided that the following conditions
11 | #* are met:
12 | #*
13 | #* * Redistributions of source code must retain the above copyright
14 | #* notice, this list of conditions and the following disclaimer.
15 | #* * Redistributions in binary form must reproduce the above
16 | #* copyright notice, this list of conditions and the following
17 | #* disclaimer in the documentation and/or other materials provided
18 | #* with the distribution.
19 | #* * Neither the name of the Willow Garage nor the names of its
20 | #* contributors may be used to endorse or promote products derived
21 | #* from this software without specific prior written permission.
22 | #*
23 | #* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | #* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | #* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | #* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | #* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 | #* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 | #* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 | #* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 | #* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 | #* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 | #* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 | #* POSSIBILITY OF SUCH DAMAGE.
35 | #***********************************************************
36 |
37 | # Author: Blaise Gassend
38 |
39 | import rospy, os, sys
40 | from sound_play.msg import SoundRequest
41 |
42 | from sound_play.libsoundplay import SoundClient
43 |
44 | def sleep(t):
45 | try:
46 | rospy.sleep(t)
47 | except:
48 | pass
49 |
50 | if __name__ == '__main__':
51 | rospy.init_node('soundplay_test', anonymous = True)
52 | soundhandle = SoundClient()
53 |
54 | rospy.sleep(1)
55 |
56 | soundhandle.stopAll()
57 |
58 | rospy.loginfo("This script will run continuously until you hit CTRL+C, testing various sound_node sound types.")
59 |
60 | #print 'Try to play wave files that do not exist.'
61 | #soundhandle.playWave('17')
62 | #soundhandle.playWave('dummy')
63 |
64 | # print 'say'
65 | # soundhandle.say('Hello world!')
66 | # sleep(3)
67 |
68 | rospy.loginfo('wave')
69 | soundhandle.playWave('say-beep.wav')
70 | sleep(2)
71 |
72 | rospy.loginfo('quiet wave')
73 | soundhandle.playWave('say-beep.wav', 0.3)
74 | sleep(2)
75 |
76 | rospy.loginfo('plugging')
77 | soundhandle.play(SoundRequest.NEEDS_PLUGGING)
78 | sleep(2)
79 |
80 | rospy.loginfo('quiet plugging')
81 | soundhandle.play(SoundRequest.NEEDS_PLUGGING, 0.3)
82 | sleep(2)
83 |
84 | rospy.loginfo('unplugging')
85 | soundhandle.play(SoundRequest.NEEDS_UNPLUGGING)
86 | sleep(2)
87 |
88 | rospy.loginfo('plugging badly')
89 | soundhandle.play(SoundRequest.NEEDS_PLUGGING_BADLY)
90 | sleep(2)
91 |
92 | rospy.loginfo('unplugging badly')
93 | soundhandle.play(SoundRequest.NEEDS_UNPLUGGING_BADLY)
94 | sleep(2)
95 |
96 | s1 = soundhandle.builtinSound(SoundRequest.NEEDS_UNPLUGGING_BADLY)
97 | s2 = soundhandle.waveSound("say-beep.wav")
98 | s3 = soundhandle.voiceSound("Testing the new A P I")
99 | s4 = soundhandle.builtinSound(SoundRequest.NEEDS_UNPLUGGING_BADLY, 0.3)
100 | s5 = soundhandle.waveSound("say-beep.wav", 0.3)
101 | s6 = soundhandle.voiceSound("Testing the new A P I", 0.3)
102 |
103 | rospy.loginfo("New API start voice")
104 | s3.repeat()
105 | sleep(3)
106 |
107 | rospy.loginfo("New API start voice quiet")
108 | s6.play()
109 | sleep(3)
110 |
111 | rospy.loginfo("New API wave")
112 | s2.repeat()
113 | sleep(2)
114 |
115 | rospy.loginfo("New API wave quiet")
116 | s5.play()
117 | sleep(2)
118 |
119 | rospy.loginfo("New API builtin")
120 | s1.play()
121 | sleep(2)
122 |
123 | rospy.loginfo("New API builtin quiet")
124 | s4.play()
125 | sleep(2)
126 |
127 | rospy.loginfo("New API stop")
128 | s3.stop()
129 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ROS audio\_common Package
2 |
3 | [](https://github.com/ros-drivers/audio_common/actions/workflows/main.yml)
4 | [](https://github.com/ros-drivers/audio_common/actions/workflows/ros2.yml)
5 |
6 | This repository contains the ROS audio\_common package.
7 |
8 | For user documentation, please refer to the [ROS Wiki page for audio\_common](http://wiki.ros.org/audio_common)
9 |
10 | ## Deb Build Status
11 |
12 | | Package | Melodic (Bionic) | Noetic (Focal) | Noetic (Buster) |
13 | |:---------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
14 | | audio_common (arm64) | [](http://build.ros.org/job/Mbin_ubv8_uBv8__audio_common__ubuntu_bionic_arm64__binary) | [](http://build.ros.org/job/Nbin_ufv8_uFv8__audio_common__ubuntu_focal_arm64__binary) | [](http://build.ros.org/job/Nbin_dbv8_dBv8__audio_common__debian_buster_arm64__binary) |
15 | | audio_common (armhf) | [](http://build.ros.org/job/Mbin_ubhf_uBhf__audio_common__ubuntu_bionic_armhf__binary) | [](http://build.ros.org/job/Nbin_ufhf_uFhf__audio_common__ubuntu_focal_armhf__binary) | --- |
16 | | audio_common (i386) | --- | --- | --- |
17 | | audio_common (amd64) | [](http://build.ros.org/job/Mbin_uB64__audio_common__ubuntu_bionic_amd64__binary) | [](http://build.ros.org/job/Nbin_uF64__audio_common__ubuntu_focal_amd64__binary) | [](http://build.ros.org/job/Nbin_db_dB64__audio_common__debian_buster_amd64__binary) |
18 |
19 | ## ROS1 source build
20 |
21 | On ROS Kinetic, Melodic and Noetic, the [master](https://github.com/ros-drivers/audio_common/tree/master) branch is recommended.
22 |
23 | ## ROS2 source build
24 |
25 | On ROS2, the [ros2](https://github.com/ros-drivers/audio_common/tree/ros2) branch is recommended
26 |
27 | ## Development, Branch and Release Policy
28 |
29 | The `master` branch is currently considered the development branch, and is released into ROS Kinetic, Melodic and Noetic with version numbers in the 0.3.x range.
30 | `master` is accepting new, non-breaking features and bug fixes.
31 |
32 | Large, breaking changes such as changes to dependencies or the package API will be considered,
33 | but they will probably be staged into a development branch for release into the next major release of ROS (ROS L)
34 |
35 | ## Support
36 |
37 | Please ask support questions on [ROS Answers](http://answers.ros.org/questions/).
38 |
--------------------------------------------------------------------------------
/sound_play/src/sound_play/sound_type.py:
--------------------------------------------------------------------------------
1 | import os
2 | import threading
3 |
4 | import rospy
5 |
6 | from sound_play.msg import SoundRequest
7 |
8 | try:
9 | import gi
10 | gi.require_version('Gst', '1.0')
11 | from gi.repository import Gst as Gst
12 | except Exception:
13 | str = """
14 | **************************************************************
15 | Error opening pygst. Is gstreamer installed?
16 | **************************************************************
17 | """
18 | rospy.logfatal(str)
19 | # print str
20 | exit(1)
21 |
22 |
23 | class SoundType(object):
24 | STOPPED = 0
25 | LOOPING = 1
26 | COUNTING = 2
27 |
28 | def __init__(self, file, device, volume=1.0):
29 | self.lock = threading.RLock()
30 | self.state = self.STOPPED
31 | self.sound = Gst.ElementFactory.make("playbin", None)
32 | if self.sound is None:
33 | raise Exception("Could not create sound player")
34 |
35 | if device:
36 | self.sink = Gst.ElementFactory.make("alsasink", "sink")
37 | self.sink.set_property("device", device)
38 | self.sound.set_property("audio-sink", self.sink)
39 |
40 | if (":" in file):
41 | uri = file
42 | elif os.path.isfile(file):
43 | uri = "file://" + os.path.abspath(file)
44 | else:
45 | rospy.logerr('Error: URI is invalid: %s' % file)
46 |
47 | self.uri = uri
48 | self.volume = volume
49 | self.sound.set_property('uri', uri)
50 | self.sound.set_property("volume", volume)
51 | self.staleness = 1
52 | self.file = file
53 |
54 | self.bus = self.sound.get_bus()
55 | self.bus.add_signal_watch()
56 | self.bus_conn_id = self.bus.connect("message", self.on_stream_end)
57 |
58 | def on_stream_end(self, bus, message):
59 | if message.type == Gst.MessageType.EOS:
60 | if (self.state == self.LOOPING):
61 | self.sound.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, 0)
62 | else:
63 | self.stop()
64 |
65 | def __del__(self):
66 | # stop our GST object so that it gets garbage-collected
67 | self.dispose()
68 |
69 | def update(self):
70 | if self.bus is not None:
71 | self.bus.poll(Gst.MessageType.ERROR, 10)
72 |
73 | def loop(self):
74 | self.lock.acquire()
75 | try:
76 | self.staleness = 0
77 | if self.state == self.COUNTING:
78 | self.stop()
79 |
80 | if self.state == self.STOPPED:
81 | self.sound.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, 0)
82 | self.sound.set_state(Gst.State.PLAYING)
83 | self.state = self.LOOPING
84 | finally:
85 | self.lock.release()
86 |
87 | def dispose(self):
88 | self.lock.acquire()
89 | try:
90 | if self.bus is not None:
91 | self.sound.set_state(Gst.State.NULL)
92 | self.bus.disconnect(self.bus_conn_id)
93 | self.bus.remove_signal_watch()
94 | self.bus = None
95 | self.sound = None
96 | self.sink = None
97 | self.state = self.STOPPED
98 | except Exception as e:
99 | rospy.logerr('Exception in dispose: %s' % str(e))
100 | finally:
101 | self.lock.release()
102 |
103 | def stop(self):
104 | if self.state != self.STOPPED:
105 | self.lock.acquire()
106 | try:
107 | self.sound.set_state(Gst.State.NULL)
108 | self.state = self.STOPPED
109 | finally:
110 | self.lock.release()
111 |
112 | def single(self):
113 | self.lock.acquire()
114 | try:
115 | rospy.logdebug("Playing %s" % self.uri)
116 | self.staleness = 0
117 | if self.state == self.LOOPING:
118 | self.stop()
119 |
120 | self.sound.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, 0)
121 | self.sound.set_state(Gst.State.PLAYING)
122 | self.state = self.COUNTING
123 | finally:
124 | self.lock.release()
125 |
126 | def command(self, cmd):
127 | if cmd == SoundRequest.PLAY_STOP:
128 | self.stop()
129 | elif cmd == SoundRequest.PLAY_ONCE:
130 | self.single()
131 | elif cmd == SoundRequest.PLAY_START:
132 | self.loop()
133 |
134 | def get_staleness(self):
135 | self.lock.acquire()
136 | position = 0
137 | duration = 0
138 | try:
139 | position = self.sound.query_position(Gst.Format.TIME)[1]
140 | duration = self.sound.query_duration(Gst.Format.TIME)[1]
141 | except Exception:
142 | position = 0
143 | duration = 0
144 | finally:
145 | self.lock.release()
146 |
147 | if position != duration:
148 | self.staleness = 0
149 | else:
150 | self.staleness = self.staleness + 1
151 | return self.staleness
152 |
153 | def get_playing(self):
154 | return self.state == self.COUNTING
155 |
--------------------------------------------------------------------------------
/sound_play/test/test.cpp:
--------------------------------------------------------------------------------
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 | #include
36 | #include
37 |
38 | void sleepok(int t, ros::NodeHandle &nh)
39 | {
40 | if (nh.ok())
41 | sleep(t);
42 | }
43 |
44 | int main(int argc, char **argv)
45 | {
46 | ros::init(argc, argv, "sound_play_test");
47 |
48 | ros::NodeHandle nh;
49 | sound_play::SoundClient sc;
50 | sound_play::SoundClient quiet_sc;
51 |
52 | sleepok(1, nh);
53 |
54 | while(nh.ok())
55 | {
56 | sc.say("Hello world!");
57 | sleepok(2, nh);
58 | quiet_sc.say("Hello world!");
59 | sleepok(2, nh);
60 |
61 | const char *str1 = "I am annoying.";
62 | sc.repeat(str1);
63 | sleepok(4, nh);
64 | sc.stopSaying(str1);
65 | quiet_sc.repeat(str1);
66 | sleepok(4, nh);
67 | quiet_sc.stopSaying(str1);
68 |
69 | sc.playWave("/usr/share/xemacs21/xemacs-packages/etc/sounds/boing.wav");
70 | sleepok(2, nh);
71 | quiet_sc.playWave("/usr/share/xemacs21/xemacs-packages/etc/sounds/boing.wav");
72 | sleepok(2, nh);
73 |
74 | const char *str2 = "/usr/share/xemacs21/xemacs-packages/etc/sounds/piano-beep.wav";
75 | sc.startWave(str2);
76 | sleepok(4, nh);
77 | sc.stopWave(str2);
78 | quiet_sc.startWave(str2);
79 | sleepok(4, nh);
80 | quiet_sc.stopWave(str2);
81 |
82 | sc.play(sound_play::SoundRequest::NEEDS_UNPLUGGING);
83 | sleepok(2, nh);
84 | quiet_sc.play(sound_play::SoundRequest::NEEDS_UNPLUGGING);
85 | sleepok(2, nh);
86 |
87 | sc.play(sound_play::SoundRequest::NEEDS_UNPLUGGING);
88 | sleepok(2, nh);
89 | quiet_sc.play(sound_play::SoundRequest::NEEDS_UNPLUGGING);
90 | sleepok(2, nh);
91 |
92 | sc.start(sound_play::SoundRequest::BACKINGUP);
93 | sleepok(4, nh);
94 | sc.stop(sound_play::SoundRequest::BACKINGUP);
95 | quiet_sc.start(sound_play::SoundRequest::BACKINGUP);
96 | sleepok(4, nh);
97 | quiet_sc.stop(sound_play::SoundRequest::BACKINGUP);
98 |
99 | sleepok(2, nh);
100 | sound_play::Sound s1 = sc.waveSound("/usr/share/xemacs21/xemacs-packages/etc/sounds/boing.wav");
101 | s1.repeat();
102 | sleepok(1, nh);
103 | s1.stop();
104 |
105 | sleepok(2, nh);
106 | sound_play::Sound s2 = quiet_sc.waveSound("/usr/share/xemacs21/xemacs-packages/etc/sounds/boing.wav");
107 | s2.repeat();
108 | sleepok(1, nh);
109 | s2.stop();
110 |
111 | sleepok(2, nh);
112 | sound_play::Sound s3 = sc.voiceSound("This is a really long sentence that will get cut off.");
113 | s3.play();
114 | sleepok(1, nh);
115 | s3.stop();
116 |
117 | sleepok(2, nh);
118 | sound_play::Sound s4 = quiet_sc.voiceSound("This is a really long sentence that will get cut off.");
119 | s4.play();
120 | sleepok(1, nh);
121 | s4.stop();
122 |
123 | sleepok(2, nh);
124 | sound_play::Sound s5 = sc.builtinSound(sound_play::SoundRequest::NEEDS_UNPLUGGING_BADLY);
125 | s5.play();
126 | sleepok(1, nh);
127 | s5.stop();
128 |
129 | sleepok(2, nh);
130 | sound_play::Sound s6 = quiet_sc.builtinSound(sound_play::SoundRequest::NEEDS_UNPLUGGING_BADLY);
131 | s6.play();
132 | sleepok(1, nh);
133 | s6.stop();
134 |
135 | sleepok(2, nh);
136 | sound_play::Sound s7 = sc.waveSoundFromPkg("sound_play", "sounds/BACKINGUP.ogg");
137 | s7.play();
138 | sleepok(1, nh);
139 | s7.stop();
140 |
141 | sleepok(2, nh);
142 | sound_play::Sound s8 = quiet_sc.waveSoundFromPkg("sound_play", "sounds/BACKINGUP.ogg");
143 | s8.play();
144 | sleepok(1, nh);
145 | s8.stop();
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/audio_play/src/audio_play.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "audio_common_msgs/AudioData.h"
7 |
8 | namespace audio_transport
9 | {
10 | class RosGstPlay
11 | {
12 | public:
13 | RosGstPlay()
14 | {
15 | GstPad *audiopad;
16 | GstCaps *caps;
17 |
18 | std::string dst_type;
19 | std::string device;
20 | bool do_timestamp;
21 | std::string format;
22 | int channels;
23 | int depth;
24 | int sample_rate;
25 | std::string sample_format;
26 |
27 | // The destination of the audio
28 | ros::param::param("~dst", dst_type, "alsasink");
29 | ros::param::param("~device", device, std::string());
30 | ros::param::param("~do_timestamp", do_timestamp, true);
31 | ros::param::param("~format", format, "mp3");
32 | ros::param::param("~channels", channels, 1);
33 | ros::param::param("~depth", depth, 16);
34 | ros::param::param("~sample_rate", sample_rate, 16000);
35 | ros::param::param("~sample_format", sample_format, "S16LE");
36 |
37 | _sub = _nh.subscribe("audio", 10, &RosGstPlay::onAudio, this);
38 |
39 | _loop = g_main_loop_new(NULL, false);
40 |
41 | _pipeline = gst_pipeline_new("app_pipeline");
42 | _source = gst_element_factory_make("appsrc", "app_source");
43 | g_object_set(G_OBJECT(_source), "do-timestamp", (do_timestamp) ? TRUE : FALSE, NULL);
44 |
45 | //_playbin = gst_element_factory_make("playbin2", "uri_play");
46 | //g_object_set( G_OBJECT(_playbin), "uri", "file:///home/test/test.mp3", NULL);
47 | caps = gst_caps_new_simple(
48 | "audio/x-raw",
49 | "format", G_TYPE_STRING, sample_format.c_str(),
50 | "rate", G_TYPE_INT, sample_rate,
51 | "channels", G_TYPE_INT, channels,
52 | "width", G_TYPE_INT, depth,
53 | "depth", G_TYPE_INT, depth,
54 | "signed", G_TYPE_BOOLEAN, TRUE,
55 | "layout", G_TYPE_STRING, "interleaved",
56 | NULL);
57 |
58 | if (dst_type == "alsasink")
59 | {
60 | _audio = gst_bin_new("audiobin");
61 | _convert = gst_element_factory_make("audioconvert", "convert");
62 | audiopad = gst_element_get_static_pad(_convert, "sink");
63 | _resample = gst_element_factory_make("audioresample", "resample");
64 |
65 | _sink = gst_element_factory_make("alsasink", "sink");
66 | g_object_set(G_OBJECT(_sink), "sync", FALSE, NULL);
67 | if (!device.empty()) {
68 | g_object_set(G_OBJECT(_sink), "device", device.c_str(), NULL);
69 | }
70 | gst_bin_add_many( GST_BIN(_audio), _convert, _resample, _sink, NULL);
71 | gst_element_link_many(_convert, _resample, _sink, NULL);
72 | gst_element_add_pad(_audio, gst_ghost_pad_new("sink", audiopad));
73 | }
74 | else
75 | {
76 | ROS_INFO("file sink to %s", dst_type.c_str());
77 | _sink = gst_element_factory_make("filesink", "sink");
78 | g_object_set(G_OBJECT(_sink), "location", dst_type.c_str(), NULL);
79 | }
80 |
81 | if (format == "mp3")
82 | {
83 | if (dst_type == "alsasink")
84 | {
85 | _decoder = gst_element_factory_make("decodebin", "decoder");
86 | g_signal_connect(_decoder, "pad-added", G_CALLBACK(cb_newpad),this);
87 |
88 | _filter = gst_element_factory_make("capsfilter", "filter");
89 | g_object_set( G_OBJECT(_filter), "caps", caps, NULL);
90 |
91 | gst_bin_add_many(GST_BIN(_pipeline), _source, _decoder, _filter, _audio, NULL);
92 | gst_element_link_many(_source, _decoder, _filter, _audio, NULL);
93 | gst_object_unref(audiopad);
94 | gst_caps_unref(caps);
95 | }
96 | else
97 | {
98 | gst_bin_add_many(GST_BIN(_pipeline), _source, _sink, NULL);
99 | gst_element_link(_source, _sink);
100 | }
101 | }
102 | else if (format == "wave")
103 | {
104 | g_object_set( G_OBJECT(_source), "caps", caps, NULL);
105 | g_object_set (G_OBJECT (_source), "format", GST_FORMAT_TIME, NULL);
106 | if (dst_type == "alsasink")
107 | {
108 | gst_bin_add_many( GST_BIN(_pipeline), _source, _audio, NULL);
109 | gst_element_link_many( _source, _audio, NULL);
110 | gst_object_unref(audiopad);
111 | }
112 | else
113 | {
114 | _filter = gst_element_factory_make("wavenc", "filter");
115 | gst_bin_add_many(GST_BIN(_pipeline), _source, _filter, _sink, NULL);
116 | gst_element_link_many( _source, _filter, _sink, NULL);
117 | }
118 | gst_caps_unref(caps);
119 | }
120 | else
121 | {
122 | ROS_ERROR("Unsupported format: %s", format.c_str());
123 | }
124 |
125 | gst_element_set_state(GST_ELEMENT(_pipeline), GST_STATE_PLAYING);
126 | //gst_element_set_state(GST_ELEMENT(_playbin), GST_STATE_PLAYING);
127 |
128 | _gst_thread = boost::thread( boost::bind(g_main_loop_run, _loop) );
129 | }
130 |
131 | private:
132 |
133 | void onAudio(const audio_common_msgs::AudioDataConstPtr &msg)
134 | {
135 | GstBuffer *buffer = gst_buffer_new_and_alloc(msg->data.size());
136 | gst_buffer_fill(buffer, 0, &msg->data[0], msg->data.size());
137 | GstFlowReturn ret;
138 |
139 | g_signal_emit_by_name(_source, "push-buffer", buffer, &ret);
140 | gst_buffer_unref(buffer);
141 | }
142 |
143 | static void cb_newpad (GstElement *decodebin, GstPad *pad,
144 | gpointer data)
145 | {
146 | RosGstPlay *client = reinterpret_cast(data);
147 |
148 | GstCaps *caps;
149 | GstStructure *str;
150 | GstPad *audiopad;
151 |
152 | /* only link once */
153 | audiopad = gst_element_get_static_pad (client->_audio, "sink");
154 | if (GST_PAD_IS_LINKED (audiopad))
155 | {
156 | g_object_unref (audiopad);
157 | return;
158 | }
159 |
160 | /* check media type */
161 | caps = gst_pad_query_caps (pad, NULL);
162 | str = gst_caps_get_structure (caps, 0);
163 | if (!g_strrstr (gst_structure_get_name (str), "audio")) {
164 | gst_caps_unref (caps);
165 | gst_object_unref (audiopad);
166 | return;
167 | }
168 |
169 | gst_caps_unref (caps);
170 |
171 | /* link'n'play */
172 | gst_pad_link (pad, audiopad);
173 |
174 | g_object_unref (audiopad);
175 | }
176 |
177 | ros::NodeHandle _nh;
178 | ros::Subscriber _sub;
179 | boost::thread _gst_thread;
180 |
181 | GstElement *_pipeline, *_source, *_sink, *_decoder, *_convert, *_audio, *_resample, *_filter;
182 | GstElement *_playbin;
183 | GMainLoop *_loop;
184 | };
185 | }
186 |
187 |
188 | int main (int argc, char **argv)
189 | {
190 | ros::init(argc, argv, "audio_play");
191 | gst_init(&argc, &argv);
192 |
193 | audio_transport::RosGstPlay client;
194 |
195 | ros::spin();
196 | }
197 |
--------------------------------------------------------------------------------
/audio_capture/CHANGELOG.rst:
--------------------------------------------------------------------------------
1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 | Changelog for package audio_capture
3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4 |
5 | 0.3.18 (2024-08-13)
6 | -------------------
7 |
8 | 0.3.17 (2023-06-08)
9 | -------------------
10 | * Merge pull request `#220 `_ from v4hn/master
11 | * on real systems publish system clock time in capture node
12 | * The capture node is hard-coded to alsasrc
13 | * Contributors: Shingo Kitagawa, v4hn
14 |
15 | 0.3.16 (2022-12-23)
16 | -------------------
17 | * Merge pull request `#204 `_ from knorth55/audio-capture-stamped
18 | * add todo comment
19 | * publish audio stamped in audio_capture.cpp
20 | * Merge pull request `#216 `_ from knorth55/launch-update
21 | * update audio_capture launch
22 | * Contributors: Shingo Kitagawa
23 |
24 | 0.3.15 (2022-08-29)
25 | -------------------
26 |
27 | 0.3.14 (2022-08-18)
28 | -------------------
29 |
30 | 0.3.13 (2022-04-07)
31 | -------------------
32 |
33 | 0.3.12 (2021-09-01)
34 | -------------------
35 | * Merge branch 'master' into master
36 | * Contributors: Shingo Kitagawa
37 |
38 | 0.3.11 (2021-04-08)
39 | -------------------
40 |
41 | 0.3.10 (2021-01-07)
42 | -------------------
43 | * add bitrate in capture launch
44 | * [audio_capture] Publish audio info once before publishing /audio
45 | * Contributors: Naoya Yamaguchi, Shingo Kitagawa
46 |
47 | 0.3.9 (2020-10-22)
48 | ------------------
49 | * Merge pull request `#160 `_ from knorth55/add-device-play
50 | * use ROS_INFO instead of printf
51 | * Contributors: Shingo Kitagawa
52 |
53 | 0.3.8 (2020-09-13)
54 | ------------------
55 |
56 | 0.3.7 (2020-08-08)
57 | ------------------
58 | * Merge pull request `#150 `_ from sktometometo/fix_mp3_options
59 | Fix property of lamemp3enc element in audio_capture so that the bitrate parameter work properly.
60 | * fix property of lamemp3enc element so that it will use the specified bitrate
61 | * Merge pull request `#146 `_ from knorth55/mp3-support
62 | * use space instead of tab
63 | * use same caps
64 | * support channls for mp3
65 | * Merge pull request `#145 `_ from knorth55/mp3-channel-rate
66 | [audio_capture] add sample_format in audio_capture
67 | * Merge pull request `#147 `_ from knorth55/fix-filesink
68 | [audio_capture] fix filesink for wave format
69 | * add sample_format arg in capture_to_file.launch
70 | * fix filesink for wave format
71 | * add sample_format in audio_capture
72 | * Contributors: Koki Shinjo, Shingo Kitagawa
73 |
74 | 0.3.6 (2020-05-29)
75 | ------------------
76 | * Merge pull request `#141 `_ from knorth55/add-maintainer
77 | add maintainer
78 | * add maintainer
79 | * Contributors: Shingo Kitagawa
80 |
81 | 0.3.5 (2020-04-28)
82 | ------------------
83 |
84 | 0.3.4 (2020-04-02)
85 | ------------------
86 | * Merge branch 'master' of github.com:ros-drivers/audio_common
87 | * Contributors: Gerard Canal
88 |
89 | 0.3.3 (2018-05-22)
90 | ------------------
91 |
92 | 0.3.2 (2018-05-02)
93 | ------------------
94 | * [sound_play] add option to select audio device to play / record (`#87 `_)
95 | * [sound_play] add option to select audio device to play
96 | * [sound_play] reformat README to markdown; add usage to set device via rosparam
97 | * audio_capture: add option for selecting device to use
98 | * audio_play: add option to select device for playing audio
99 | * add device argument to launch files
100 | Conflicts:
101 | audio_capture/launch/capture.launch
102 | audio_capture/launch/capture_to_file.launch
103 | audio_capture/src/audio_capture.cpp
104 | audio_play/launch/play.launch
105 | sound_play/scripts/soundplay_node.py
106 | * Merge pull request `#102 `_ from EndPointCorp/fix_capture_leak
107 | Fix audio_capture leak
108 | * Fix audio_capture sample/buffer leak
109 | * Merge pull request `#90 `_ from prarobo/master
110 | Error checking code and improvements to launch files
111 | * Bug fix
112 | * fix(audio_capture): capturing wave using gst1.0
113 | 0.10-style raw audio caps were being created, according to GStreamer warning. Should be audio/x-raw,format=(string).. now.
114 | * Merge pull request `#1 `_ from prarobo/fixes
115 | Error checking code and improvements to launch files
116 | * Removed default device
117 | * Added error checking code
118 | * Added parameters to launch files
119 | * Contributors: Austin, Matt Vollrath, Prasanna Kannappan, Rokus, Yuki Furuta, prarobo
120 |
121 | 0.3.1 (2016-08-28)
122 | ------------------
123 | * Update to new gstreamer rosdeps
124 | * #70 can launch these in different namespaces with different microphones, and both are operating.
125 | * #70 can switch between different microphones, but the first microphone doesn't like the hw:1, it only works with device:="" - so must be doing something wrong still.
126 | * Add changelogs
127 | * [audio_capture] add error handler
128 | * [audio_capture] add option to publish captured audio data as wav format
129 | Conflicts:
130 | audio_capture/src/audio_capture.cpp
131 | * Fixed memory leak (see #18).
132 | * Removed trailing whitespace.
133 | * Fixed problem that CMake uses gstreamer-0.1 instead of gstreamer-1.0
134 | * Added gstreamer 1.0 dependecies
135 | * Ported to gstreamer 1.0
136 | package.xml dependencies still missing
137 | * Update maintainer email
138 | * Contributors: Benny, Felix Duvallet, Furushchev, Lucas Walter, trainman419
139 |
140 | 0.2.11 (2016-02-16)
141 | -------------------
142 | * Add changelogs
143 | * Contributors: trainman419
144 |
145 | 0.2.10 (2016-01-21)
146 | -------------------
147 | * Add changelogs
148 | * Contributors: trainman419
149 |
150 | 0.2.9 (2015-12-02)
151 | ------------------
152 | * Add changelogs
153 | * [audio_capture] add error handler
154 | * [audio_capture] add option to publish captured audio data as wav format
155 | * Fixed memory leak (see `#18 `_).
156 | * Removed trailing whitespace.
157 | * Contributors: Felix Duvallet, Furushchev, trainman419
158 |
159 | 0.2.8 (2015-10-02)
160 | ------------------
161 | * Update maintainer email
162 | * Contributors: trainman419
163 |
164 | 0.2.7 (2014-07-25)
165 | ------------------
166 | * audio_capture.cpp has to wait for generated AudioData headers
167 | * Contributors: v4hn
168 |
169 | 0.2.6 (2014-02-26)
170 | ------------------
171 | * audio_capture and play _require\_ gstreamer, it's not optional
172 | * Contributors: v4hn
173 |
174 | 0.2.5 (2014-01-23)
175 | ------------------
176 | * "0.2.5"
177 | * Contributors: trainman419
178 |
179 | 0.2.4 (2013-09-10)
180 | ------------------
181 | * Update CMakeLists.txt
182 | * audio_capture: install launchfiles
183 | * Contributors: David Gossow
184 |
185 | 0.2.3 (2013-07-15)
186 | ------------------
187 | * Fix install rule for audio_capture.
188 | * Contributors: Austin Hendrix
189 |
190 | 0.2.2 (2013-04-10)
191 | ------------------
192 |
193 | 0.2.1 (2013-04-08 13:59)
194 | ------------------------
195 |
196 | 0.2.0 (2013-04-08 13:49)
197 | ------------------------
198 | * Finish catkinizing audio_common.
199 | * Catkinize audio_play.
200 | * Catkinize audio_capture.
201 | * Fix typo in package.xml
202 | * Versions and more URLs.
203 | * Convert manifests to package.xml
204 | * Convert audio_capture manifest to package.xml
205 | * Ditch old makefiles.
206 | * Updates manifest
207 | * Updated manifests for rodep2
208 | * oneiric build fixes, bump version to 0.1.6
209 | * Removed redundant thread::thread
210 | * Added a rosdep.yaml file
211 | * Fixed to use audio_common_msgs
212 | * Added ability to use different festival voices
213 | * Updated documentation
214 | * Added ability to capture to file
215 | * Fixed ignore files
216 | * Added hgignore files
217 | * Audio_capture and audio_play working
218 | * Making separate audio_capture and audio_play packages
219 | * Moved audio_transport to audio_capture
220 | * Contributors: Austin Hendrix, Brian Gerkey, Nate Koenig, nkoenig
221 |
--------------------------------------------------------------------------------
/audio_play/CHANGELOG.rst:
--------------------------------------------------------------------------------
1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 | Changelog for package audio_play
3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4 |
5 | 0.3.18 (2024-08-13)
6 | -------------------
7 | * Merge pull request `#238 `_ from Kanazawanaoaki/add-record-to-file-launch
8 | * Add record to file launch
9 | * Contributors: Kanazawanaoaki, Shingo Kitagawa
10 |
11 | 0.3.17 (2023-06-08)
12 | -------------------
13 |
14 | 0.3.16 (2022-12-23)
15 | -------------------
16 | * Merge pull request `#216 `_ from knorth55/launch-update
17 | * update play.launch
18 | * Merge pull request `#206 `_ from knorth55/fix-205
19 | * unref buffer in audio_play to avoid memory leak
20 | * Contributors: Shingo Kitagawa
21 |
22 | 0.3.15 (2022-08-29)
23 | -------------------
24 |
25 | 0.3.14 (2022-08-18)
26 | -------------------
27 |
28 | 0.3.13 (2022-04-07)
29 | -------------------
30 | * Merge pull request `#179 `_ from tkmtnt7000/PR-remap-audio-topic
31 | * audio_play: add audio_topic option
32 | * Contributors: Naoto Tsukamoto, Shingo Kitagawa
33 |
34 | 0.3.12 (2021-09-01)
35 | -------------------
36 | * Merge branch 'master' into master
37 | * Contributors: Shingo Kitagawa
38 |
39 | 0.3.11 (2021-04-08)
40 | -------------------
41 |
42 | 0.3.10 (2021-01-07)
43 | -------------------
44 |
45 | 0.3.9 (2020-10-22)
46 | ------------------
47 | * Merge pull request `#160 `_ from knorth55/add-device-play
48 | * refactor audio_play to use same code
49 | * add audioresample in audio_play
50 | * apply caps for both formats
51 | * add device for wave format
52 | * add sync false for alsasink
53 | * use alsasink
54 | * add depth rosparam
55 | * add device arg in play.launch
56 | * fix audio_play to save file
57 | * Contributors: Shingo Kitagawa
58 |
59 | 0.3.8 (2020-09-13)
60 | ------------------
61 | * Merge pull request `#151 `_ from knorth55/do-timestamp-false
62 | [audio_play] set do_timestamp false
63 | * set do_timestamp false
64 | * Contributors: Shingo Kitagawa
65 |
66 | 0.3.7 (2020-08-08)
67 | ------------------
68 | * Merge pull request `#146 `_ from knorth55/mp3-support
69 | * support format, rate, channels in mp3
70 | * Merge pull request `#127 `_ from knorth55/audio-play-wave
71 | [audio_play] support wave format
72 | * add sample_format param in audio_play
73 | * add channels and sample_rate in audio_play/play.launch
74 | * add channels and sample_rate in audio_play.cpp
75 | * add format arg in play.launch
76 | * support wave in audio_play
77 | * Merge pull request `#144 `_ from ros-drivers/knorth55-patch-1
78 | * add gstreamer1.0-alsa for run_depend in audio_play
79 | * Contributors: Shingo Kitagawa
80 |
81 | 0.3.6 (2020-05-29)
82 | ------------------
83 | * Merge pull request `#141 `_ from knorth55/add-maintainer
84 | add maintainer
85 | * add maintainer
86 | * Contributors: Shingo Kitagawa
87 |
88 | 0.3.5 (2020-04-28)
89 | ------------------
90 |
91 | 0.3.4 (2020-04-02)
92 | ------------------
93 | * audio_play fix for reproducing livestream sound (`#122 `_)
94 | * Added capability to read from a udpsrc. To generalize it, possibly similarly to gscam.
95 | * Added parameter to control do-timestamp, as this fixes the problem with audio_play not being able to play livestream sound.
96 | * Aligning with the base master, removing the changes from the branch that included the udpsrc.
97 | Co-authored-by: Alberto Quattrini Li
98 | * Merge branch 'master' of github.com:ros-drivers/audio_common
99 | * Contributors: Alberto Quattrini Li, Gerard Canal
100 |
101 | 0.3.3 (2018-05-22)
102 | ------------------
103 |
104 | 0.3.2 (2018-05-02)
105 | ------------------
106 | * [sound_play] add option to select audio device to play / record (`#87 `_)
107 | * [sound_play] add option to select audio device to play
108 | * [sound_play] reformat README to markdown; add usage to set device via rosparam
109 | * audio_capture: add option for selecting device to use
110 | * audio_play: add option to select device for playing audio
111 | * add device argument to launch files
112 | Conflicts:
113 | audio_capture/launch/capture.launch
114 | audio_capture/launch/capture_to_file.launch
115 | audio_capture/src/audio_capture.cpp
116 | audio_play/launch/play.launch
117 | sound_play/scripts/soundplay_node.py
118 | * Merge pull request `#101 `_ from EndPointCorp/audio_play_dont_pause_pipeline
119 | audio_play: Fix mp3 clip overlap by never pausing the pipeline
120 | * audio_play: Don't pause the pipeline
121 | This prevents glitches when playing short mp3 clips.
122 | * Merge pull request `#90 `_ from prarobo/master
123 | Error checking code and improvements to launch files
124 | * Merge pull request `#1 `_ from prarobo/fixes
125 | Error checking code and improvements to launch files
126 | * Added parameters to launch files
127 | * Contributors: Austin, Matt Vollrath, Prasanna Kannappan, Yuki Furuta, prarobo
128 |
129 | 0.3.1 (2016-08-28)
130 | ------------------
131 | * Update to new gstreamer rosdeps
132 | * #70 can launch these in different namespaces with different microphones, and both are operating.
133 | * Add changelogs
134 | * Changed message level to warning
135 | * Fixed problem that CMake uses gstreamer-0.1 instead of gstreamer-1.0
136 | * Fixed underflow.
137 | Before the sink buffer underflows the pipeline is paused. When data is received again the pipeline is set to playing again.
138 | * Added gstreamer 1.0 dependecies
139 | * Ported to gstreamer 1.0
140 | package.xml dependencies still missing
141 | * Change audio sink to autoaudiosink
142 | * Update maintainer email
143 | * Contributors: Benny, Hans Gaiser, Lucas Walter, trainman419
144 |
145 | 0.2.11 (2016-02-16)
146 | -------------------
147 | * Add changelogs
148 | * Contributors: trainman419
149 |
150 | 0.2.10 (2016-01-21)
151 | -------------------
152 | * Add changelogs
153 | * Contributors: trainman419
154 |
155 | 0.2.9 (2015-12-02)
156 | ------------------
157 | * Add changelogs
158 | * Contributors: trainman419
159 |
160 | 0.2.8 (2015-10-02)
161 | ------------------
162 | * Changed message level to warning
163 | * Fixed underflow.
164 | Before the sink buffer underflows the pipeline is paused. When data is received again the pipeline is set to playing again.
165 | * Change audio sink to autoaudiosink
166 | * Update maintainer email
167 | * Contributors: Benny, Hans Gaiser, trainman419
168 |
169 | 0.2.7 (2014-07-25)
170 | ------------------
171 |
172 | 0.2.6 (2014-02-26)
173 | ------------------
174 | * audio_capture and play _require\_ gstreamer, it's not optional
175 | * Contributors: v4hn
176 |
177 | 0.2.5 (2014-01-23)
178 | ------------------
179 | * "0.2.5"
180 | * Contributors: trainman419
181 |
182 | 0.2.4 (2013-09-10)
183 | ------------------
184 |
185 | 0.2.3 (2013-07-15)
186 | ------------------
187 | * Fix dependencies and install rules.
188 | * Contributors: Austin Hendrix
189 |
190 | 0.2.2 (2013-04-10)
191 | ------------------
192 |
193 | 0.2.1 (2013-04-08 13:59)
194 | ------------------------
195 |
196 | 0.2.0 (2013-04-08 13:49)
197 | ------------------------
198 | * Finish catkinizing audio_common.
199 | * Catkinize audio_play.
200 | * Fix typo in package.xml
201 | * Versions and more URLs.
202 | * Convert manifests to package.xml
203 | * Ditch old makefiles.
204 | * Updates manifest
205 | * Updated manifests for rodep2
206 | * oneiric build fixes, bump version to 0.1.6
207 | * Removed another duplicate thread::thread
208 | * Added a rosdep.yaml file
209 | * Fixed to use audio_common_msgs
210 | * Added ability to use different festival voices
211 | * Updated documentation
212 | * Update to audio_play
213 | * Fixed ignore files
214 | * Added hgignore files
215 | * Audio_capture and audio_play working
216 | * Making separate audio_capture and audio_play packages
217 | * Contributors: Austin Hendrix, Brian Gerkey, Nate Koenig, nkoenig
218 |
--------------------------------------------------------------------------------
/audio_capture/src/audio_capture.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include
7 |
8 | #include "audio_common_msgs/AudioData.h"
9 | #include "audio_common_msgs/AudioDataStamped.h"
10 | #include "audio_common_msgs/AudioInfo.h"
11 |
12 | namespace audio_transport
13 | {
14 | class RosGstCapture
15 | {
16 | public:
17 | RosGstCapture()
18 | {
19 | _bitrate = 192;
20 |
21 | std::string dst_type;
22 |
23 | // Need to encoding or publish raw wave data
24 | ros::param::param("~format", _format, "mp3");
25 | ros::param::param("~sample_format", _sample_format, "S16LE");
26 |
27 | // The bitrate at which to encode the audio
28 | ros::param::param("~bitrate", _bitrate, 192);
29 |
30 | // only available for raw data
31 | ros::param::param("~channels", _channels, 1);
32 | ros::param::param("~depth", _depth, 16);
33 | ros::param::param("~sample_rate", _sample_rate, 16000);
34 |
35 | // The destination of the audio
36 | ros::param::param("~dst", dst_type, "appsink");
37 |
38 | // The source of the audio
39 | //ros::param::param("~src", source_type, "alsasrc");
40 | std::string device;
41 | ros::param::param("~device", device, "");
42 |
43 | _pub = _nh.advertise("audio", 10, true);
44 | _pub_stamped = _nh.advertise("audio_stamped", 10, true);
45 | _pub_info = _nh.advertise("audio_info", 1, true);
46 |
47 | _loop = g_main_loop_new(NULL, false);
48 | _pipeline = gst_pipeline_new("ros_pipeline");
49 | GstClock *clock = gst_system_clock_obtain();
50 | g_object_set(clock, "clock-type", GST_CLOCK_TYPE_REALTIME, NULL);
51 | gst_pipeline_use_clock(GST_PIPELINE_CAST(_pipeline), clock);
52 | gst_object_unref(clock);
53 |
54 | _bus = gst_pipeline_get_bus(GST_PIPELINE(_pipeline));
55 | gst_bus_add_signal_watch(_bus);
56 | g_signal_connect(_bus, "message::error",
57 | G_CALLBACK(onMessage), this);
58 | g_object_unref(_bus);
59 |
60 | // We create the sink first, just for convenience
61 | if (dst_type == "appsink")
62 | {
63 | _sink = gst_element_factory_make("appsink", "sink");
64 | g_object_set(G_OBJECT(_sink), "emit-signals", true, NULL);
65 | g_object_set(G_OBJECT(_sink), "max-buffers", 100, NULL);
66 | g_signal_connect( G_OBJECT(_sink), "new-sample",
67 | G_CALLBACK(onNewBuffer), this);
68 | }
69 | else
70 | {
71 | ROS_INFO("file sink to %s", dst_type.c_str());
72 | _sink = gst_element_factory_make("filesink", "sink");
73 | g_object_set( G_OBJECT(_sink), "location", dst_type.c_str(), NULL);
74 | }
75 |
76 | _source = gst_element_factory_make("alsasrc", "source");
77 | // if device isn't specified, it will use the default which is
78 | // the alsa default source.
79 | // A valid device will be of the foram hw:0,0 with other numbers
80 | // than 0 and 0 as are available.
81 | if (device != "")
82 | {
83 | // ghcar *gst_device = device.c_str();
84 | g_object_set(G_OBJECT(_source), "device", device.c_str(), NULL);
85 | }
86 |
87 | GstCaps *caps;
88 | caps = gst_caps_new_simple("audio/x-raw",
89 | "format", G_TYPE_STRING, _sample_format.c_str(),
90 | "channels", G_TYPE_INT, _channels,
91 | "width", G_TYPE_INT, _depth,
92 | "depth", G_TYPE_INT, _depth,
93 | "rate", G_TYPE_INT, _sample_rate,
94 | "signed", G_TYPE_BOOLEAN, TRUE,
95 | NULL);
96 |
97 | gboolean link_ok;
98 | if (_format == "mp3"){
99 | _filter = gst_element_factory_make("capsfilter", "filter");
100 | g_object_set( G_OBJECT(_filter), "caps", caps, NULL);
101 | gst_caps_unref(caps);
102 |
103 | _convert = gst_element_factory_make("audioconvert", "convert");
104 | if (!_convert) {
105 | ROS_ERROR_STREAM("Failed to create audioconvert element");
106 | exitOnMainThread(1);
107 | }
108 |
109 | _encode = gst_element_factory_make("lamemp3enc", "encoder");
110 | if (!_encode) {
111 | ROS_ERROR_STREAM("Failed to create encoder element");
112 | exitOnMainThread(1);
113 | }
114 | g_object_set( G_OBJECT(_encode), "target", 1, NULL);
115 | g_object_set( G_OBJECT(_encode), "bitrate", _bitrate, NULL);
116 |
117 | gst_bin_add_many( GST_BIN(_pipeline), _source, _filter, _convert, _encode, _sink, NULL);
118 | link_ok = gst_element_link_many(_source, _filter, _convert, _encode, _sink, NULL);
119 | } else if (_format == "wave") {
120 | if (dst_type == "appsink") {
121 | g_object_set( G_OBJECT(_sink), "caps", caps, NULL);
122 | gst_caps_unref(caps);
123 | gst_bin_add_many( GST_BIN(_pipeline), _source, _sink, NULL);
124 | link_ok = gst_element_link_many( _source, _sink, NULL);
125 | } else {
126 | _filter = gst_element_factory_make("wavenc", "filter");
127 | gst_bin_add_many( GST_BIN(_pipeline), _source, _filter, _sink, NULL);
128 | link_ok = gst_element_link_many( _source, _filter, _sink, NULL);
129 | }
130 | } else {
131 | ROS_ERROR_STREAM("format must be \"wave\" or \"mp3\"");
132 | exitOnMainThread(1);
133 | }
134 | /*}
135 | else
136 | {
137 | _sleep_time = 10000;
138 | _source = gst_element_factory_make("filesrc", "source");
139 | g_object_set(G_OBJECT(_source), "location", source_type.c_str(), NULL);
140 |
141 | gst_bin_add_many( GST_BIN(_pipeline), _source, _sink, NULL);
142 | gst_element_link_many(_source, _sink, NULL);
143 | }
144 | */
145 |
146 | if (!link_ok) {
147 | ROS_ERROR_STREAM("Unsupported media type.");
148 | exitOnMainThread(1);
149 | }
150 |
151 | gst_element_set_state(GST_ELEMENT(_pipeline), GST_STATE_PLAYING);
152 |
153 | _gst_thread = boost::thread( boost::bind(g_main_loop_run, _loop) );
154 |
155 | audio_common_msgs::AudioInfo info_msg;
156 | info_msg.channels = _channels;
157 | info_msg.sample_rate = _sample_rate;
158 | info_msg.sample_format = _sample_format;
159 | info_msg.bitrate = _bitrate;
160 | info_msg.coding_format = _format;
161 | _pub_info.publish(info_msg);
162 | }
163 |
164 | ~RosGstCapture()
165 | {
166 | g_main_loop_quit(_loop);
167 | gst_element_set_state(_pipeline, GST_STATE_NULL);
168 | gst_object_unref(_pipeline);
169 | g_main_loop_unref(_loop);
170 | }
171 |
172 | void exitOnMainThread(int code)
173 | {
174 | exit(code);
175 | }
176 |
177 | void publish( const audio_common_msgs::AudioData &msg )
178 | {
179 | _pub.publish(msg);
180 | }
181 |
182 | void publishStamped( const audio_common_msgs::AudioDataStamped &msg )
183 | {
184 | _pub_stamped.publish(msg);
185 | }
186 |
187 | static GstFlowReturn onNewBuffer (GstAppSink *appsink, gpointer userData)
188 | {
189 | audio_common_msgs::AudioData msg;
190 | audio_common_msgs::AudioDataStamped stamped_msg;
191 |
192 | RosGstCapture *server = reinterpret_cast(userData);
193 | GstMapInfo map;
194 |
195 | GstSample *sample;
196 | g_signal_emit_by_name(appsink, "pull-sample", &sample);
197 |
198 | GstBuffer *buffer = gst_sample_get_buffer(sample);
199 |
200 | if( ros::Time::isSimTime() )
201 | {
202 | stamped_msg.header.stamp = ros::Time::now();
203 | }
204 | else
205 | {
206 | GstClockTime buffer_time = gst_element_get_base_time(server->_source)+GST_BUFFER_PTS(buffer);
207 | stamped_msg.header.stamp.fromNSec(buffer_time);
208 | }
209 |
210 | gst_buffer_map(buffer, &map, GST_MAP_READ);
211 | msg.data.resize( map.size );
212 |
213 | memcpy( &msg.data[0], map.data, map.size );
214 | stamped_msg.audio = msg;
215 |
216 | gst_buffer_unmap(buffer, &map);
217 | gst_sample_unref(sample);
218 |
219 | server->publish(msg);
220 | server->publishStamped(stamped_msg);
221 |
222 | return GST_FLOW_OK;
223 | }
224 |
225 | static gboolean onMessage (GstBus *bus, GstMessage *message, gpointer userData)
226 | {
227 | RosGstCapture *server = reinterpret_cast(userData);
228 | GError *err;
229 | gchar *debug;
230 |
231 | gst_message_parse_error(message, &err, &debug);
232 | ROS_ERROR_STREAM("gstreamer: " << err->message);
233 | g_error_free(err);
234 | g_free(debug);
235 | g_main_loop_quit(server->_loop);
236 | server->exitOnMainThread(1);
237 | return FALSE;
238 | }
239 |
240 | private:
241 | ros::NodeHandle _nh;
242 | ros::Publisher _pub;
243 | ros::Publisher _pub_stamped;
244 | ros::Publisher _pub_info;
245 |
246 | boost::thread _gst_thread;
247 |
248 | GstElement *_pipeline, *_source, *_filter, *_sink, *_convert, *_encode;
249 | GstBus *_bus;
250 | int _bitrate, _channels, _depth, _sample_rate;
251 | GMainLoop *_loop;
252 | std::string _format, _sample_format;
253 | };
254 | }
255 |
256 | int main (int argc, char **argv)
257 | {
258 | ros::init(argc, argv, "audio_capture");
259 | gst_init(&argc, &argv);
260 |
261 | audio_transport::RosGstCapture server;
262 | ros::spin();
263 | }
264 |
--------------------------------------------------------------------------------
/sound_play/include/sound_play/sound_play.h:
--------------------------------------------------------------------------------
1 | /*
2 | ***********************************************************
3 | * Software License Agreement (BSD License)
4 | *
5 | * Copyright (c) 2009, Willow Garage, Inc.
6 | * All rights reserved.
7 | *
8 | * Redistribution and use in source and binary forms, with or without
9 | * modification, are permitted provided that the following conditions
10 | * are met:
11 | *
12 | * * Redistributions of source code must retain the above copyright
13 | * notice, this list of conditions and the following disclaimer.
14 | * * Redistributions in binary form must reproduce the above
15 | * copyright notice, this list of conditions and the following
16 | * disclaimer in the documentation and/or other materials provided
17 | * with the distribution.
18 | * * Neither the name of the Willow Garage nor the names of its
19 | * contributors may be used to endorse or promote products derived
20 | * from this software without specific prior written permission.
21 | *
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 | * POSSIBILITY OF SUCH DAMAGE.
34 | ***********************************************************
35 | */
36 |
37 | #ifndef __SOUND_PLAY__SOUND_PLAY__H__
38 | #define __SOUND_PLAY__SOUND_PLAY__H__
39 |
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 |
46 | namespace sound_play
47 | {
48 |
49 | /** \brief Class that publishes messages to the sound_play node.
50 | *
51 | * This class is a helper class for communicating with the sound_play node
52 | * via the \ref sound_play::SoundRequest message. It has two ways of being used:
53 | *
54 | * - It can create Sound classes that represent a particular sound which
55 | * can be played, repeated or stopped.
56 | *
57 | * - It provides methods for each way in which the sound_play::SoundRequest
58 | * message can be invoked.
59 | */
60 |
61 | class SoundClient
62 | {
63 | public:
64 | class Sound
65 | {
66 | friend class SoundClient;
67 | private:
68 | int snd_;
69 | float vol_;
70 | std::string arg_;
71 | std::string arg2_;
72 | SoundClient *client_;
73 |
74 | Sound(SoundClient *sc, int snd, const std::string &arg, const std::string arg2 = std::string(), const float vol = 1.0f)
75 | {
76 | client_ = sc;
77 | snd_ = snd;
78 | arg_ = arg;
79 | arg2_ = arg2;
80 | vol_ = vol;
81 | }
82 |
83 | public:
84 | /** \brief Play the Sound.
85 | *
86 | * This method causes the Sound to be played once.
87 | */
88 | void play()
89 | {
90 | client_->sendMsg(snd_, SoundRequest::PLAY_ONCE, arg_, arg2_, vol_);
91 | }
92 |
93 | /** \brief Play the Sound repeatedly.
94 | *
95 | * This method causes the Sound to be played repeatedly until stop() is
96 | * called.
97 | */
98 | void repeat()
99 | {
100 | client_->sendMsg(snd_, SoundRequest::PLAY_START, arg_, arg2_, vol_);
101 | }
102 |
103 | /** \brief Stop Sound playback.
104 | *
105 | * This method causes the Sound to stop playing.
106 | */
107 | void stop()
108 | {
109 | client_->sendMsg(snd_, SoundRequest::PLAY_STOP, arg_, arg2_, vol_);
110 | }
111 | };
112 |
113 | /** \brief Create a SoundClient that publishes on the given topic
114 | *
115 | * Creates a SoundClient that publishes to the given topic relative to the
116 | * given NodeHandle.
117 | *
118 | * \param nh Node handle to use when creating the topic.
119 | *
120 | * \param topic Topic to publish to.
121 | */
122 | SoundClient(ros::NodeHandle &nh, const std::string &topic)
123 | {
124 | init(nh, topic);
125 | }
126 |
127 | /** \brief Create a SoundClient with the default topic
128 | *
129 | * Creates a SoundClient that publishes to "robotsound".
130 | */
131 | SoundClient()
132 | {
133 | init(ros::NodeHandle(), "robotsound");
134 | }
135 |
136 | /** \brief Create a voice Sound.
137 | *
138 | * Creates a Sound corresponding to saying the indicated text.
139 | *
140 | * \param s Text to say
141 | * \param volume Volume at which to play the sound. 0 is mute, 1.0 is 100%.
142 | */
143 | Sound voiceSound(const std::string &s, float volume = 1.0f)
144 | {
145 | return Sound(this, SoundRequest::SAY, s, "", volume);
146 | }
147 |
148 | /** \brief Create a wave Sound.
149 | *
150 | * Creates a Sound corresponding to indicated file.
151 | *
152 | * \param s File to play. Should be an absolute path that exists on the
153 | * machine running the sound_play node.
154 | * \param volume Volume at which to play the sound. 0 is mute, 1.0 is 100%.
155 | */
156 | Sound waveSound(const std::string &s, float volume = 1.0f)
157 | {
158 | return Sound(this, SoundRequest::PLAY_FILE, s, "", volume);
159 | }
160 |
161 | /** \brief Create a wave Sound from a package.
162 | *
163 | * Creates a Sound corresponding to indicated file.
164 | *
165 | * \param p Package containing the sound file.
166 | * \param s Filename of the WAV or OGG file. Must be an path relative to the package valid
167 | * on the computer on which the sound_play node is running
168 | * \param volume Volume at which to play the sound. 0 is mute, 1.0 is 100%.
169 | */
170 | Sound waveSoundFromPkg(const std::string &p, const std::string &s, float volume = 1.0f)
171 | {
172 | return Sound(this, SoundRequest::PLAY_FILE, s, p, volume);
173 | }
174 |
175 | /** \brief Create a builtin Sound.
176 | *
177 | * Creates a Sound corresponding to indicated builtin wave.
178 | *
179 | * \param id Identifier of the sound to play.
180 | * \param volume Volume at which to play the sound. 0 is mute, 1.0 is 100%.
181 | */
182 | Sound builtinSound(int id, float volume = 1.0f)
183 | {
184 | return Sound(this, id, "", "", volume);
185 | }
186 |
187 | /** \brief Say a string
188 | *
189 | * Send a string to be said by the sound_node. The vocalization can be
190 | * stopped using stopSaying or stopAll.
191 | *
192 | * \param s String to say
193 | * \param volume Volume at which to play the sound. 0 is mute, 1.0 is 100%.
194 | */
195 | void say(const std::string &s, const std::string &voice="voice_kal_diphone", float volume = 1.0f)
196 | {
197 | sendMsg(SoundRequest::SAY, SoundRequest::PLAY_ONCE, s, voice, volume);
198 | }
199 |
200 | /** \brief Say a string repeatedly
201 | *
202 | * The string is said repeatedly until stopSaying or stopAll is used.
203 | *
204 | * \param s String to say repeatedly
205 | * \param volume Volume at which to play the sound. 0 is mute, 1.0 is 100%.
206 | */
207 | void repeat(const std::string &s, float volume = 1.0f)
208 | {
209 | sendMsg(SoundRequest::SAY, SoundRequest::PLAY_START, s, "", volume);
210 | }
211 |
212 | /** \brief Stop saying a string
213 | *
214 | * Stops saying a string that was previously started by say or repeat. The
215 | * argument indicates which string to stop saying.
216 | *
217 | * \param s Same string as in the say or repeat command
218 | */
219 | void stopSaying(const std::string &s)
220 | {
221 | sendMsg(SoundRequest::SAY, SoundRequest::PLAY_STOP, s, "");
222 | }
223 |
224 | /** \brief Plays a WAV or OGG file
225 | *
226 | * Plays a WAV or OGG file once. The playback can be stopped by stopWave or
227 | * stopAll.
228 | *
229 | * \param s Filename of the WAV or OGG file. Must be an absolute path valid
230 | * on the computer on which the sound_play node is running
231 | * \param volume Volume at which to play the sound. 0 is mute, 1.0 is 100%.
232 | */
233 | void playWave(const std::string &s, float volume = 1.0f)
234 | {
235 | sendMsg(SoundRequest::PLAY_FILE, SoundRequest::PLAY_ONCE, s, "", volume);
236 | }
237 |
238 | /** \brief Plays a WAV or OGG file repeatedly
239 | *
240 | * Plays a WAV or OGG file repeatedly until stopWave or stopAll is used.
241 | *
242 | * \param s Filename of the WAV or OGG file. Must be an absolute path valid
243 | * on the computer on which the sound_play node is running.
244 | * \param volume Volume at which to play the sound. 0 is mute, 1.0 is 100%.
245 | */
246 | void startWave(const std::string &s, float volume = 1.0f)
247 | {
248 | sendMsg(SoundRequest::PLAY_FILE, SoundRequest::PLAY_START, s, "", volume);
249 | }
250 |
251 | /** \brief Stop playing a WAV or OGG file
252 | *
253 | * Stops playing a file that was previously started by playWave or
254 | * startWave.
255 | *
256 | * \param s Same string as in the playWave or startWave command
257 | */
258 | void stopWave(const std::string &s)
259 | {
260 | sendMsg(SoundRequest::PLAY_FILE, SoundRequest::PLAY_STOP, s);
261 | }
262 |
263 | /** \brief Plays a WAV or OGG file from a package
264 | *
265 | * Plays a WAV or OGG file once. The playback can be stopped by stopWaveFromPkg or
266 | * stopAll.
267 | *
268 | * \param p Package name containing the sound file.
269 | * \param s Filename of the WAV or OGG file. Must be an path relative to the package valid
270 | * on the computer on which the sound_play node is running
271 | * \param volume Volume at which to play the sound. 0 is mute, 1.0 is 100%.
272 | */
273 | void playWaveFromPkg(const std::string &p, const std::string &s, float volume = 1.0f)
274 | {
275 | sendMsg(SoundRequest::PLAY_FILE, SoundRequest::PLAY_ONCE, s, p, volume);
276 | }
277 |
278 | /** \brief Plays a WAV or OGG file repeatedly
279 | *
280 | * Plays a WAV or OGG file repeatedly until stopWaveFromPkg or stopAll is used.
281 | *
282 | * \param p Package name containing the sound file.
283 | * \param s Filename of the WAV or OGG file. Must be an path relative to the package valid
284 | * on the computer on which the sound_play node is running
285 | * \param volume Volume at which to play the sound. 0 is mute, 1.0 is 100%.
286 | */
287 | void startWaveFromPkg(const std::string &p, const std::string &s, float volume = 1.0f)
288 | {
289 | sendMsg(SoundRequest::PLAY_FILE, SoundRequest::PLAY_START, s, p, volume);
290 | }
291 |
292 | /** \brief Stop playing a WAV or OGG file
293 | *
294 | * Stops playing a file that was previously started by playWaveFromPkg or
295 | * startWaveFromPkg.
296 | *
297 | * \param p Package name containing the sound file.
298 | * \param s Filename of the WAV or OGG file. Must be an path relative to the package valid
299 | * on the computer on which the sound_play node is running
300 | */
301 | void stopWaveFromPkg(const std::string &p, const std::string &s)
302 | {
303 | sendMsg(SoundRequest::PLAY_FILE, SoundRequest::PLAY_STOP, s, p);
304 | }
305 |
306 | /** \brief Play a buildin sound
307 | *
308 | * Starts playing one of the built-in sounds. built-ing sounds are documented
309 | * in \ref SoundRequest.msg. Playback can be stopped by stopAll.
310 | *
311 | * \param sound Identifier of the sound to play.
312 | * \param volume Volume at which to play the sound. 0 is mute, 1.0 is 100%.
313 | */
314 | void play(int sound, float volume = 1.0f)
315 | {
316 | sendMsg(sound, SoundRequest::PLAY_ONCE, "", "", volume);
317 | }
318 |
319 | /** \brief Play a buildin sound repeatedly
320 | *
321 | * Starts playing one of the built-in sounds repeatedly until stop or stopAll
322 | * is used. Built-in sounds are documented in \ref SoundRequest.msg.
323 | *
324 | * \param sound Identifier of the sound to play.
325 | * \param volume Volume at which to play the sound. 0 is mute, 1.0 is 100%.
326 | */
327 | void start(int sound, float volume = 1.0f)
328 | {
329 | sendMsg(sound, SoundRequest::PLAY_START, "", "", volume);
330 | }
331 |
332 | /** \brief Stop playing a built-in sound
333 | *
334 | * Stops playing a built-in sound started with play or start.
335 | *
336 | * \param sound Same sound that was used to start playback.
337 | */
338 | void stop(int sound)
339 | {
340 | sendMsg(sound, SoundRequest::PLAY_STOP);
341 | }
342 |
343 | /** \brief Stop all currently playing sounds
344 | *
345 | * This method stops all speech, wave file, and built-in sound playback.
346 | */
347 | void stopAll()
348 | {
349 | stop(SoundRequest::ALL);
350 | }
351 |
352 | /** \brief Turns warning messages on or off.
353 | *
354 | * If a message is sent when no node is subscribed to the topic, a
355 | * warning message is printed. This method can be used to enable or
356 | * disable warnings.
357 | *
358 | * \param state True to turn off messages, false to turn them on.
359 | */
360 | void setQuiet(bool state)
361 | {
362 | quiet_ = state;
363 | }
364 |
365 | private:
366 | void init(ros::NodeHandle nh, const std::string &topic)
367 | {
368 | nh_ = nh;
369 | pub_ = nh.advertise(topic, 5);
370 | quiet_ = false;
371 | }
372 |
373 | void sendMsg(int snd, int cmd, const std::string &s = "", const std::string &arg2 = "", const float &vol = 1.0f)
374 | {
375 | boost::mutex::scoped_lock lock(mutex_);
376 |
377 | if (!nh_.ok())
378 | return;
379 |
380 | SoundRequest msg;
381 | msg.sound = snd;
382 | msg.command = cmd;
383 | msg.arg = s;
384 | msg.arg2 = arg2;
385 |
386 | // ensure volume is in the correct range
387 | if (vol < 0)
388 | msg.volume = 0;
389 | else if (vol > 1.0)
390 | msg.volume = 1.0f;
391 | else
392 | msg.volume = vol;
393 |
394 | pub_.publish(msg);
395 |
396 | if (pub_.getNumSubscribers() == 0 && !quiet_)
397 | ROS_WARN("Sound command issued, but no node is subscribed to the topic. Perhaps you forgot to run soundplay_node.py");
398 | }
399 |
400 | bool quiet_;
401 | ros::NodeHandle nh_;
402 | ros::Publisher pub_;
403 | boost::mutex mutex_;
404 | };
405 |
406 | typedef SoundClient::Sound Sound;
407 |
408 | };
409 |
410 | #endif
411 |
--------------------------------------------------------------------------------
/sound_play/src/sound_play/libsoundplay.py:
--------------------------------------------------------------------------------
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 | ## \brief Class that publishes messages to the sound_play node.
47 | ##
48 | ## This class is a helper class for communicating with the sound_play node
49 | ## via the \ref sound_play.SoundRequest message. It has two ways of being used:
50 | ##
51 | ## - It can create Sound classes that represent a particular sound which
52 | ## can be played, repeated or stopped.
53 | ##
54 | ## - It provides methods for each way in which the sound_play.SoundRequest
55 | ## message can be invoked.
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 | ## \brief Play the Sound.
65 | ##
66 | ## This method causes the Sound to be played once.
67 |
68 | def play(self, **kwargs):
69 | self.client.sendMsg(self.snd, SoundRequest.PLAY_ONCE, self.arg,
70 | vol=self.vol, **kwargs)
71 |
72 | ## \brief Play the Sound repeatedly.
73 | ##
74 | ## This method causes the Sound to be played repeatedly until stop() is
75 | ## called.
76 |
77 | def repeat(self, **kwargs):
78 | self.client.sendMsg(self.snd, SoundRequest.PLAY_START, self.arg,
79 | vol=self.vol, **kwargs)
80 |
81 | ## \brief Stop Sound playback.
82 | ##
83 | ## This method causes the Sound to stop playing.
84 |
85 | def stop(self):
86 | self.client.sendMsg(self.snd, SoundRequest.PLAY_STOP, self.arg)
87 |
88 | ## This class is a helper class for communicating with the sound_play node
89 | ## via the \ref sound_play.SoundRequest message. There is a one-to-one mapping
90 | ## between methods and invocations of the \ref sound_play.SoundRequest message.
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.
123 | self.actionclient = actionlib.SimpleActionClient(
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 | ## \brief Create a voice Sound.
130 | ##
131 | ## Creates a Sound corresponding to saying the indicated text.
132 | ##
133 | ## \param s Text to say
134 |
135 | def voiceSound(self, s, volume=1.0):
136 | return Sound(self, SoundRequest.SAY, s, volume=volume)
137 |
138 | ## \brief Create a wave Sound.
139 | ##
140 | ## Creates a Sound corresponding to indicated file.
141 | ##
142 | ## \param s File to play. Should be an absolute path that exists on the
143 | ## machine running the sound_play node.
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 | ## \brief Create a builtin Sound.
151 | ##
152 | ## Creates a Sound corresponding to indicated builtin wave.
153 | ##
154 | ## \param id Identifier of the sound to play.
155 |
156 | def builtinSound(self, id, volume=1.0):
157 | return Sound(self, id, "", volume)
158 |
159 | ## \brief Say a string
160 | ##
161 | ## Send a string to be said by the sound_node. The vocalization can be
162 | ## stopped using stopSaying or stopAll.
163 | ##
164 | ## \param text String to say
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 | ## \brief Say a string repeatedly
171 | ##
172 | ## The string is said repeatedly until stopSaying or stopAll is used.
173 | ##
174 | ## \param text String to say repeatedly
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 | ## \brief Stop saying a string
181 | ##
182 | ## Stops saying a string that was previously started by say or repeat. The
183 | ## argument indicates which string to stop saying.
184 | ##
185 | ## \param text Same string as in the say or repeat command
186 |
187 | def stopSaying(self,text):
188 | self.sendMsg(SoundRequest.SAY, SoundRequest.PLAY_STOP, text)
189 |
190 | ## \brief Plays a WAV or OGG file
191 | ##
192 | ## Plays a WAV or OGG file once. The playback can be stopped by stopWave or
193 | ## stopAll.
194 | ##
195 | ## \param sound Filename of the WAV or OGG file. Must be an absolute path valid
196 | ## on the computer on which the sound_play node is running
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 | ## \brief Plays a WAV or OGG file repeatedly
206 | ##
207 | ## Plays a WAV or OGG file repeatedly until stopWave or stopAll is used.
208 | ##
209 | ## \param sound Filename of the WAV or OGG file. Must be an absolute path valid
210 | ## on the computer on which the sound_play node is running.
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 | ## \brief Stop playing a WAV or OGG file
220 | ##
221 | ## Stops playing a file that was previously started by playWave or
222 | ## startWave.
223 | ##
224 | ## \param sound Same string as in the playWave or startWave command
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 | ## \brief Plays a WAV or OGG file
233 | ##
234 | ## Plays a WAV or OGG file once. The playback can be stopped by stopWaveFromPkg or
235 | ## stopAll.
236 | ##
237 | ## \param package Package name containing the sound file.
238 | ## \param sound Filename of the WAV or OGG file. Must be an path relative to the package valid
239 | ## on the computer on which the sound_play node is running
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 | ## \brief Plays a WAV or OGG file repeatedly
246 | ##
247 | ## Plays a WAV or OGG file repeatedly until stopWaveFromPkg or stopAll is used.
248 | ##
249 | ## \param package Package name containing the sound file.
250 | ## \param sound Filename of the WAV or OGG file. Must be an path relative to the package valid
251 | ## on the computer on which the sound_play node is running
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 | ## \brief Stop playing a WAV or OGG file
258 | ##
259 | ## Stops playing a file that was previously started by playWaveFromPkg or
260 | ## startWaveFromPkg.
261 | ##
262 | ## \param package Package name containing the sound file.
263 | ## \param sound Filename of the WAV or OGG file. Must be an path relative to the package valid
264 | ## on the computer on which the sound_play node is running
265 |
266 | def stopWaveFromPkg(self,sound, package):
267 | self.sendMsg(SoundRequest.PLAY_FILE, SoundRequest.PLAY_STOP, sound, package)
268 |
269 | ## \brief Play a buildin sound
270 | ##
271 | ## Starts playing one of the built-in sounds. built-ing sounds are documented
272 | ## in \ref SoundRequest.msg. Playback can be stopped by stopall.
273 | ##
274 | ## \param sound Identifier of the sound to play.
275 |
276 | def play(self,sound, volume=1.0, **kwargs):
277 | self.sendMsg(sound, SoundRequest.PLAY_ONCE, "", vol=volume, **kwargs)
278 |
279 | ## \brief Play a buildin sound repeatedly
280 | ##
281 | ## Starts playing one of the built-in sounds repeatedly until stop or
282 | ## stopall is used. Built-in sounds are documented in \ref SoundRequest.msg.
283 | ##
284 | ## \param sound Identifier of the sound to play.
285 |
286 | def start(self,sound, volume=1.0, **kwargs):
287 | self.sendMsg(sound, SoundRequest.PLAY_START, "", vol=volume, **kwargs)
288 |
289 | ## \brief Stop playing a built-in sound
290 | ##
291 | ## Stops playing a built-in sound started with play or start.
292 | ##
293 | ## \param sound Same sound that was used to start playback
294 |
295 | def stop(self,sound):
296 | self.sendMsg(sound, SoundRequest.PLAY_STOP, "")
297 |
298 | ## \brief Stop all currently playing sounds
299 | ##
300 | ## This method stops all speech, wave file, and built-in sound playback.
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
375 |
--------------------------------------------------------------------------------
/sound_play/scripts/soundplay_node.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # ***********************************************************
4 | # * Software License Agreement (BSD License)
5 | # *
6 | # * Copyright (c) 2009, Willow Garage, Inc.
7 | # * All rights reserved.
8 | # *
9 | # * Redistribution and use in source and binary forms, with or without
10 | # * modification, are permitted provided that the following conditions
11 | # * are met:
12 | # *
13 | # * * Redistributions of source code must retain the above copyright
14 | # * notice, this list of conditions and the following disclaimer.
15 | # * * Redistributions in binary form must reproduce the above
16 | # * copyright notice, this list of conditions and the following
17 | # * disclaimer in the documentation and/or other materials provided
18 | # * with the distribution.
19 | # * * Neither the name of the Willow Garage nor the names of its
20 | # * contributors may be used to endorse or promote products derived
21 | # * from this software without specific prior written permission.
22 | # *
23 | # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | # * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 | # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 | # * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 | # * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 | # * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 | # * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 | # * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 | # * POSSIBILITY OF SUCH DAMAGE.
35 | # ***********************************************************
36 |
37 | import os
38 | import sys
39 | import threading
40 | import traceback
41 | import yaml
42 |
43 | import actionlib
44 | import roslib
45 | import rospkg
46 | import rospy
47 |
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
55 | from sound_play.sound_type import SoundType
56 |
57 | try:
58 | import gi
59 | gi.require_version('Gst', '1.0')
60 | from gi.repository import GObject as GObject
61 | from gi.repository import Gst as Gst
62 | except Exception:
63 | str = """
64 | **************************************************************
65 | Error opening pygst. Is gstreamer installed?
66 | **************************************************************
67 | """
68 | rospy.logfatal(str)
69 | # print str
70 | exit(1)
71 |
72 |
73 | class SoundPlayNode(object):
74 | _feedback = SoundRequestFeedback()
75 | _result = SoundRequestResult()
76 |
77 | def stopdict(self, dict):
78 | for sound in dict.values():
79 | sound.stop()
80 |
81 | def stopall(self):
82 | self.stopdict(self.builtinsounds)
83 | self.stopdict(self.filesounds)
84 | self.stopdict(self.voicesounds)
85 |
86 | def select_sound(self, data):
87 | if data.sound == SoundRequest.PLAY_FILE:
88 | if not data.arg2:
89 | if data.arg not in self.filesounds.keys():
90 | rospy.logdebug(
91 | 'command for uncached wave: "%s"' % data.arg)
92 | try:
93 | self.filesounds[data.arg] = SoundType(
94 | data.arg, self.device, data.volume)
95 | except Exception:
96 | rospy.logerr(
97 | 'Error setting up to play "%s".'
98 | 'Does this file exist on the machine'
99 | 'on which sound_play is running?' % data.arg)
100 | return
101 | else:
102 | rospy.logdebug('command for cached wave: "%s"' % data.arg)
103 | filesound = self.filesounds[data.arg]
104 | if filesound.sound.get_property('volume') != data.volume:
105 | rospy.logdebug(
106 | 'volume for cached wave has changed,'
107 | 'resetting volume')
108 | filesound.sound.set_property('volume', data.volume)
109 | sound = self.filesounds[data.arg]
110 | else:
111 | absfilename = os.path.join(
112 | roslib.packages.get_pkg_dir(data.arg2), data.arg)
113 | if absfilename not in self.filesounds.keys():
114 | rospy.logdebug(
115 | 'command for uncached wave: "%s"' % absfilename)
116 | try:
117 | self.filesounds[absfilename] = SoundType(
118 | absfilename, self.device, data.volume)
119 | except Exception:
120 | rospy.logerr(
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))
125 | return
126 | else:
127 | rospy.logdebug(
128 | 'command for cached wave: "%s"' % absfilename)
129 | filesound = self.filesounds[absfilename]
130 | if filesound.sound.get_property('volume') != data.volume:
131 | rospy.logdebug(
132 | 'volume for cached wave has changed,'
133 | 'resetting volume')
134 | filesound.sound.set_property('volume', data.volume)
135 | sound = self.filesounds[absfilename]
136 | elif data.sound == SoundRequest.SAY:
137 | voice_key = data.arg + '---' + data.arg2
138 | if voice_key not in self.voicesounds.keys():
139 | rospy.logdebug('command for uncached text: "%s"' % voice_key)
140 | if self.plugin is None:
141 | rospy.logerr(
142 | 'Plugin is not found {}.'.format(self.plugin_name))
143 | else:
144 | if data.arg2 == '':
145 | voice = self.default_voice
146 | else:
147 | voice = data.arg2
148 | wavfilename = self.plugin.sound_play_say_plugin(
149 | data.arg, voice)
150 | if wavfilename is None:
151 | rospy.logerr('Failed to generate wavfile.')
152 | else:
153 | self.voicesounds[voice_key] = SoundType(
154 | wavfilename, self.device, data.volume)
155 | else:
156 | rospy.logdebug('command for cached text: "%s"' % voice_key)
157 | voicesound = self.voicesounds[voice_key]
158 | if voicesound.sound.get_property('volume') != data.volume:
159 | rospy.logdebug(
160 | 'volume for cached text has changed, resetting volume')
161 | voicesound.sound.set_property('volume', data.volume)
162 | sound = self.voicesounds[voice_key]
163 | else:
164 | rospy.logdebug('command for builtin wave: %i' % data.sound)
165 | if ((data.sound in self.builtinsounds and
166 | data.volume != self.builtinsounds[data.sound].volume)
167 | or data.sound not in self.builtinsounds):
168 | params = self.builtinsoundparams[data.sound]
169 | volume = data.volume
170 | # use the second param as a scaling for the input volume
171 | if params[1] != 1:
172 | volume = (volume + params[1])/2
173 | self.builtinsounds[data.sound] = SoundType(
174 | params[0], self.device, volume)
175 | sound = self.builtinsounds[data.sound]
176 | if sound.staleness != 0 and data.command != SoundRequest.PLAY_STOP:
177 | # This sound isn't counted in active_sounds
178 | rospy.logdebug("activating %i %s" % (data.sound, data.arg))
179 | self.active_sounds = self.active_sounds + 1
180 | sound.staleness = 0
181 | return sound
182 |
183 | def callback(self, data):
184 | if not self.initialized:
185 | return
186 | self.mutex.acquire()
187 | try:
188 | if (data.sound == SoundRequest.ALL
189 | and data.command == SoundRequest.PLAY_STOP):
190 | self.stopall()
191 | else:
192 | sound = self.select_sound(data)
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())
197 | finally:
198 | self.mutex.release()
199 | rospy.logdebug("done callback")
200 |
201 | # Purge sounds that haven't been played in a while.
202 | def cleanupdict(self, dict):
203 | purgelist = []
204 | for key, sound in iter(dict.items()):
205 | try:
206 | staleness = sound.get_staleness()
207 | except Exception as e:
208 | rospy.logerr(
209 | 'Exception in cleanupdict for sound (%s): %s'
210 | % (str(key), str(e)))
211 | # Something is wrong. Let's purge and try again.
212 | staleness = 100
213 | # print "%s %i"%(key, staleness)
214 | if staleness >= 10:
215 | purgelist.append(key)
216 | # Sound is playing
217 | if staleness == 0:
218 | self.active_sounds = self.active_sounds + 1
219 | for key in purgelist:
220 | rospy.logdebug('Purging %s from cache' % key)
221 | # clean up resources
222 | dict[key].dispose()
223 | del dict[key]
224 |
225 | def cleanup(self):
226 | self.mutex.acquire()
227 | try:
228 | self.active_sounds = 0
229 | self.cleanupdict(self.filesounds)
230 | self.cleanupdict(self.voicesounds)
231 | self.cleanupdict(self.builtinsounds)
232 | except Exception:
233 | rospy.loginfo(
234 | 'Exception in cleanup: %s' % sys.exc_info()[0])
235 | finally:
236 | self.mutex.release()
237 |
238 | def diagnostics(self, state):
239 | try:
240 | da = DiagnosticArray()
241 | ds = DiagnosticStatus()
242 | ds.name = rospy.get_caller_id().lstrip('/') + ": Node State"
243 | if state == 0:
244 | ds.level = DiagnosticStatus.OK
245 | ds.message = "%i sounds playing" % self.active_sounds
246 | ds.values.append(
247 | KeyValue("Active sounds", str(self.active_sounds)))
248 | ds.values.append(
249 | KeyValue(
250 | "Allocated sound channels",
251 | str(self.num_channels)))
252 | ds.values.append(
253 | KeyValue(
254 | "Buffered builtin sounds",
255 | str(len(self.builtinsounds))))
256 | ds.values.append(
257 | KeyValue(
258 | "Buffered wave sounds",
259 | str(len(self.filesounds))))
260 | ds.values.append(
261 | KeyValue(
262 | "Buffered voice sounds",
263 | str(len(self.voicesounds))))
264 | elif state == 1:
265 | ds.level = DiagnosticStatus.WARN
266 | ds.message = "Sound device not open yet."
267 | else:
268 | ds.level = DiagnosticStatus.ERROR
269 | ds.message = "Can't open sound device." +\
270 | "See http://wiki.ros.org/sound_play/Troubleshooting"
271 | da.status.append(ds)
272 | da.header.stamp = rospy.get_rostime()
273 | self.diagnostic_pub.publish(da)
274 | except Exception as e:
275 | rospy.loginfo('Exception in diagnostics: %s' % str(e))
276 |
277 | def execute_cb(self, data):
278 | data = data.sound_request
279 | if not self.initialized:
280 | rospy.logerr('soundplay_node is not initialized yet.')
281 | self._as.set_aborted()
282 | return
283 | self.mutex.acquire()
284 | # Force only one sound at a time
285 | self.stopall()
286 | try:
287 | if (data.sound == SoundRequest.ALL
288 | and data.command == SoundRequest.PLAY_STOP):
289 | self.stopall()
290 | else:
291 | sound = self.select_sound(data)
292 | sound.command(data.command)
293 |
294 | r = rospy.Rate(self.loop_rate)
295 | start_time = rospy.get_rostime()
296 | success = True
297 | while sound.get_playing():
298 | sound.update()
299 | if self._as.is_preempt_requested():
300 | rospy.loginfo('sound_play action: Preempted')
301 | sound.stop()
302 | self._as.set_preempted()
303 | success = False
304 | break
305 |
306 | self._feedback.playing = sound.get_playing()
307 | self._feedback.stamp = rospy.get_rostime() - start_time
308 | self._as.publish_feedback(self._feedback)
309 | r.sleep()
310 |
311 | if success:
312 | self._result.playing = self._feedback.playing
313 | self._result.stamp = self._feedback.stamp
314 | rospy.loginfo('sound_play action: Succeeded')
315 | self._as.set_succeeded(self._result)
316 |
317 | except Exception as e:
318 | self._as.set_aborted()
319 | rospy.logerr(
320 | 'Exception in actionlib callback: %s' % str(e))
321 | rospy.loginfo(traceback.format_exc())
322 | finally:
323 | self.mutex.release()
324 | rospy.logdebug("done actionlib callback")
325 |
326 | def __init__(self):
327 | Gst.init(None)
328 |
329 | # Start gobject thread to receive gstreamer messages
330 | GObject.threads_init()
331 | self.g_loop = threading.Thread(target=GObject.MainLoop().run)
332 | self.g_loop.daemon = True
333 | self.g_loop.start()
334 |
335 | rospy.init_node('sound_play')
336 | self.loop_rate = rospy.get_param('~loop_rate', 100)
337 | self.device = rospy.get_param("~device", "default")
338 | self.default_voice = rospy.get_param('~default_voice', None)
339 | self.plugin_name = rospy.get_param(
340 | '~plugin', 'sound_play/festival_plugin')
341 | self.diagnostic_pub = rospy.Publisher(
342 | "/diagnostics", DiagnosticArray, queue_size=1)
343 | rootdir = os.path.join(
344 | roslib.packages.get_pkg_dir('sound_play'), 'sounds')
345 |
346 | # load plugin
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")
351 | plugin_yamls = []
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))
359 | plugin_dict = {}
360 | for plugin_yaml in plugin_yamls:
361 | if not os.path.exists(plugin_yaml):
362 | rospy.logerr(
363 | 'Failed to load plugin yaml: {}'.format(plugin_yaml))
364 | rospy.logerr(
365 | 'Missing plugin yaml: {}'.format(plugin_yaml))
366 | continue
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']
371 |
372 | self.plugin = None
373 | if self.plugin_name in plugin_dict.keys():
374 | plugin_module = plugin_dict[self.plugin_name]
375 | mod = __import__(plugin_module.split('.')[0])
376 | for sub_mod in plugin_module.split('.')[1:]:
377 | mod = getattr(mod, sub_mod)
378 | self.plugin = mod()
379 |
380 | self.builtinsoundparams = {
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),
391 | }
392 |
393 | self.no_error = True
394 | self.initialized = False
395 | self.active_sounds = 0
396 |
397 | self.mutex = threading.Lock()
398 | self.sub = rospy.Subscriber("robotsound", SoundRequest, self.callback)
399 | self._as = actionlib.SimpleActionServer(
400 | 'sound_play', SoundRequestAction,
401 | execute_cb=self.execute_cb, auto_start=False)
402 |
403 | self.mutex.acquire()
404 | # For ros startup race condition
405 | self.sleep(0.5)
406 | self.diagnostics(1)
407 |
408 | while not rospy.is_shutdown():
409 | while not rospy.is_shutdown():
410 | self.init_vars()
411 | self.no_error = True
412 | self.initialized = True
413 | self.mutex.release()
414 | if not self._as.action_server.started:
415 | self._as.start()
416 | try:
417 | self.idle_loop()
418 | # Returns after inactive period to test device availability
419 | # print "Exiting idle"
420 | except Exception:
421 | rospy.loginfo(
422 | 'Exception in idle_loop: %s' % sys.exc_info()[0])
423 | finally:
424 | self.mutex.acquire()
425 |
426 | self.diagnostics(2)
427 | self.mutex.release()
428 |
429 | def init_vars(self):
430 | self.num_channels = 10
431 | self.builtinsounds = {}
432 | self.filesounds = {}
433 | self.voicesounds = {}
434 | self.hotlist = []
435 | if not self.initialized:
436 | rospy.loginfo('sound_play node is ready to play sound')
437 |
438 | def sleep(self, duration):
439 | try:
440 | rospy.sleep(duration)
441 | except rospy.exceptions.ROSInterruptException:
442 | pass
443 |
444 | def get_sound_length(self):
445 | sound_length = len(self.builtinsounds) +\
446 | len(self.voicesounds) + len(self.filesounds)
447 | return sound_length
448 |
449 | def idle_loop(self):
450 | self.last_activity_time = rospy.get_time()
451 | while (not rospy.is_shutdown()
452 | and (rospy.get_time() - self.last_activity_time < 10
453 | or self.get_sound_length() > 0)):
454 | # print("idle_loop")
455 | self.diagnostics(0)
456 | self.sleep(1)
457 | self.cleanup()
458 | # print("idle_exiting")
459 |
460 |
461 | if __name__ == '__main__':
462 | SoundPlayNode()
463 |
--------------------------------------------------------------------------------
/sound_play/CHANGELOG.rst:
--------------------------------------------------------------------------------
1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 | Changelog for package sound_play
3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4 |
5 | 0.3.18 (2024-08-13)
6 | -------------------
7 | * Merge pull request `#249 `_ from peci1/patch-1
8 | festival_plugin: add support for different encodings
9 | * festival_plugin: add support for different encodings
10 | * Contributors: Martin Pecka, Shingo Kitagawa
11 |
12 | 0.3.17 (2023-06-08)
13 | -------------------
14 | * Merge pull request `#231 `_ from knorth55/no-wait-mode
15 | * dont wait when rospy.Duration(0) is set for timeout
16 | * Merge pull request `#229 `_ from furushchev/flite-plugin-lazy-load
17 | FlitePlugin: Lazy loading default voice path
18 | * FlitePlugin: Lazy loading default voice path
19 | * Contributors: Shingo Kitagawa, Yuki Furuta
20 |
21 | 0.3.16 (2022-12-23)
22 | -------------------
23 | * Merge pull request `#203 `_ from nakane11/timeout
24 | * refactor libsoundplay.py
25 | * Add timeout to wait_for_server and wait_for_result
26 | * Contributors: Aoi Nakane, Shingo Kitagawa
27 |
28 | 0.3.15 (2022-08-29)
29 | -------------------
30 | * Merge pull request `#200 `_ from knorth55/yaml-missing
31 | * show error and skip loading when plugin yaml is missing
32 | * Merge pull request `#199 `_ from knorth55/install-plugin-yaml
33 | * fix missing install in CMakeLists.txt
34 | * Contributors: Shingo Kitagawa
35 |
36 | 0.3.14 (2022-08-18)
37 | -------------------
38 | * Merge pull request `#193 `_ from knorth55/refactor-soundplay-node
39 | * refactor soundplay_node.py
40 | * Merge pull request `#192 `_ from knorth55/fix-file-open-issue
41 | * fix typo causing file open issue
42 | * Merge pull request `#191 `_ from knorth55/flite-default-voice-dir
43 | * add default voice dir for flite_plugin
44 | * Merge pull request `#190 `_ from ros-drivers/knorth55-patch-1
45 | * Update soundplay_node.py
46 | * Merge pull request `#187 `_ from knorth55/fix-typo
47 | * fix typo in soundplay_node.py
48 | * Merge pull request `#185 `_ from knorth55/sound-play-flite-plugin
49 | add flite plugin for sound_play
50 | * Merge pull request `#183 `_ from knorth55/sound-play-plugin
51 | add soundplay plugin feature
52 | * add flite in sound_play dependency
53 | * refactor FestivalPlugin
54 | * add flite plugin
55 | * change default_voice to None
56 | * add plugin arg in soundplay_node.launch
57 | * refactor codes
58 | * add output screen in soundplay_node.launch
59 | * add soundplay plugin attribute
60 | * Merge pull request `#184 `_ from knorth55/default-voice
61 | * add default_voice in soundplay_node.launch
62 | * Merge pull request `#182 `_ from iory/is-speaking
63 | * Improve is_speaking by checking goal status
64 | * Merge pull request `#181 `_ from knorth55/refactor-is-speaking
65 | * refactor is_speaking.py
66 | * Contributors: JSK fetch user, Shingo Kitagawa, iory
67 |
68 | 0.3.13 (2022-04-07)
69 | -------------------
70 | * Merge pull request `#176 `_ from iory/is-speeching
71 | * Add is_speaking.py to catkin_install_python
72 | * Fixed name speeching to speaking
73 | * Add is_speeching node for checking robot is speaking
74 | * Contributors: Shingo Kitagawa, iory
75 |
76 | 0.3.12 (2021-09-01)
77 | -------------------
78 | * Merge pull request `#175 `_ from iory/rate
79 | Modified loop rate for action execution
80 | * Modified loop rate for action execution
81 | * Merge pull request `#131 `_ from yann-bourrigault/master
82 | Handle playing sound in loop
83 | * import GObject in try section
84 | * Merge pull request `#174 `_ from iory/cache
85 | Add arg2 information for cache
86 | * Add arg2 information for cache
87 | * Merge pull request `#173 `_ from knorth55/replace-sound-client
88 | * Merge pull request `#172 `_ from knorth55/start-action-after-init
89 | [sound_play] start ActionServer after initialize in soundplay_node.py
90 | * Merge pull request `#171 `_ from knorth55/set-aborted
91 | [sound_play] add proper set_aborted in soundplay_node.py
92 | * add replace in sendMsg
93 | * start actionserver after initialize in soundplay_node.py
94 | * add proper set_aborted in soundplay_node.py
95 | * Merge branch 'master' into master
96 | * Handle playing sound repeatedly
97 | * Contributors: Shingo Kitagawa, Yann BOURRIGAULT, iory
98 |
99 | 0.3.11 (2021-04-08)
100 | -------------------
101 | * Merge pull request `#167 `_ from k-okada/fix_155
102 | * Use rospy.myargv() instead of sys.argv to support remapping
103 | * Contributors: Kei Okada, Shingo Kitagawa
104 |
105 | 0.3.10 (2021-01-07)
106 | -------------------
107 |
108 | 0.3.9 (2020-10-22)
109 | ------------------
110 |
111 | 0.3.8 (2020-09-13)
112 | ------------------
113 | * Merge pull request `#155 `_ from garaemon/use-myargv
114 | Use rospy.myargv() instead of sys.argv to support remapping
115 | * Use rospy.myargv() instead of sys.argv to support remapping
116 | * Merge pull request `#154 `_ from mikaelarguedas/fix_say_python3
117 | * update to support no iso-8859-15 language (`#1 `_)
118 | * support non iso-8859-15 language
119 | * encode only for python2
120 | * convert items to an iterator
121 | * make cleanup compatible with Python 3
122 | * catch AttributeError to handle python3 strings
123 | * Contributors: Mikael Arguedas, Ryohei Ueda, Shingo Kitagawa
124 |
125 | 0.3.7 (2020-08-08)
126 | ------------------
127 | * Merge pull request `#149 `_ from garaemon/specify-topic-to-play-sound
128 | Support use different topic and actionlib to play sound
129 | * Support use different topic and actionlib to play sound
130 | * Add two keywords to the constructor of SoundClient class in order to
131 | specify actionlib namespace and topic name to play sound.
132 | * See `#119 `_.
133 | * Merge pull request `#144 `_ from ros-drivers/knorth55-patch-1
134 | * add gstreamer1.0-alsa exec_depend in sound_play
135 | * Contributors: Ryohei Ueda, Shingo Kitagawa
136 |
137 | 0.3.6 (2020-05-29)
138 | ------------------
139 | * Merge pull request `#140 `_ from knorth55/support-python3
140 | fix syntax for python3
141 | * Merge pull request `#141 `_ from knorth55/add-maintainer
142 | add maintainer
143 | * add maintainer
144 | * fix syntax for python3
145 | * Contributors: Shingo Kitagawa
146 |
147 | 0.3.5 (2020-04-28)
148 | ------------------
149 | * Merge pull request `#133 `_ from knorth55/noetic-build
150 | * remove unnecessary shebang
151 | * use setuptools instead of distutils.core
152 | * use package format=3 for python3
153 | * refactor CMakeLists.txt
154 | * use catkin_install_python for python shebang
155 | * Merge pull request `#135 `_ from knorth55/add-travis
156 | * disable sound_play test
157 | * Contributors: Shingo Kitagawa
158 |
159 | 0.3.4 (2020-04-02)
160 | ------------------
161 | * Merge pull request `#126 `_ from itohdak/fix-Gstreamer-memory-leak
162 | [sound_play/scripts/soundplay_node.py] fix Gstreamer memory leak
163 | * Merge pull request `#123 `_ from 708yamaguchi/fix-encode
164 | Do not encode text when using langages which ISO-8859-15 does not support
165 | * [sound_play/scripts/soundplay_node.py] fix Gstreamer memory leak
166 | * do not encode text when using langages which ISO-8859-15 does not support
167 | * Merge pull request `#118 `_ from v4hn/patch-1
168 | use default audio output by default
169 | * use default audio output by default
170 | Not specifying a sound device defaults to *the first* sound device starting from Ubuntu 16.04., not to the one configured as default.
171 | The change is backward compatible and tested on ROS indigo and kinetic on a PR2 robot.
172 | * Merge pull request `#110 `_ from gerardcanal/master
173 | Encoded text to be said in ISO-8859-15
174 | * Merge branch 'master' of github.com:ros-drivers/audio_common
175 | * Sound play: Encoded file to be said in ISO-8859-15 so that accents in languages such as Spanish, Catalan or French are correctly pronounced (based on http://festcat.talp.cat/en/usage.php which says festival expects ISO-8859-15 encoding)
176 | * Contributors: Austin, Gerard Canal, Michael Görner, Naoya Yamaguchi, Shingo Kitagawa, itohdak
177 |
178 | 0.3.3 (2018-05-22)
179 | ------------------
180 | * Fix gstreamer errors. Fixes `#108 `_
181 | * Contributors: trainman419
182 |
183 | 0.3.2 (2018-05-02)
184 | ------------------
185 | * [sound_play] add option to select audio device to play / record (`#87 `_)
186 | * [sound_play] add option to select audio device to play
187 | * [sound_play] reformat README to markdown; add usage to set device via rosparam
188 | * audio_capture: add option for selecting device to use
189 | * audio_play: add option to select device for playing audio
190 | * add device argument to launch files
191 | Conflicts:
192 | audio_capture/launch/capture.launch
193 | audio_capture/launch/capture_to_file.launch
194 | audio_capture/src/audio_capture.cpp
195 | audio_play/launch/play.launch
196 | sound_play/scripts/soundplay_node.py
197 | * Merge pull request `#95 `_ from yujinrobot/volume_check
198 | [sound_play] volume check for cached sounds
199 | * [sound_play] checks if sound's Gst instance's volume has changed and resets it
200 | * Contributors: Austin, Naveed Usmani, Yuki Furuta
201 |
202 | 0.3.1 (2016-08-28)
203 | ------------------
204 | * Update to new gstreamer rosdeps
205 | * Update sound_play to gstreamer 1.0
206 | * remove chance of uninitialised variable being called in a subscriber callback.
207 | * Add changelogs
208 | * Issue: The error checks for missing publisher/action client in sendMsg were inverted.
209 | The non-blocking brach tested the action client while the blocking branch
210 | tested the publisher.
211 | Fix: Inverted the blocking boolean for both branchs.
212 | * sound_play: Fix build with -DCATKIN_ENABLE_TESTING=OFF.
213 | https://bugs.gentoo.org/show_bug.cgi?id=567466
214 | * [soundplay_node] fix resources not being released on dict cleanup
215 | This was resulting in the number of sink inputs reaching the maximum threshold,
216 | (32 on ubuntu 14.04 with pulseaudio 4.0) after which no more sounds could be
217 | played by the node. It would only happen if the rate of sounds being played was
218 | slower than the dictionary cleanup.
219 | * depend on actionlib.
220 | * Introduce unit test to ensure soundclient is started correctly.
221 | * Example of using the explicit blocking parameter to override the class setting.
222 | * SoundClient can also explicitly specify whether or not to block while playing the sound.
223 | Each play/repeat/say/... method can take an option blocking=True|False argument (using **kwargs), which over-rides the class-wide setting.
224 | * Merge pull request #62 from felixduvallet/set_queue_size
225 | Set queue_size in soundplay_node Publisher
226 | * do both in same script.
227 | * Added script showing the various blocking/non-blocking ways of using SoundClient.
228 | * removed trailing whitespace only
229 | * loginfo -> logdebug.
230 | * Slightly more condensed version of thresholding.
231 | * Enable blocking calls inside libsoundplay's SoundClient.
232 | This makes use of the actionlib interface provided by soundplay_node, by ensuring SoundClient receives a response before returning.
233 | Turn this on by: SoundClient(blocking=true).
234 | * Use new-style python classes (inherits from object).
235 | * removed trailing whitespace.
236 | * Set the volume in each of the sound_play actionlib tests.
237 | This makes the script actually play the sounds it requests.
238 | * Specify queue size explicitly.
239 | Removed warning message printed each time soundplay_node was started.
240 | * remove trailing whitespace only.
241 | * Change wiki urls
242 | * Fix test target name collision. Fixes #49
243 | * sound_play: cpp header conforms to the style guide
244 | * sound_play: update scripts to allow volume to be set
245 | * sound_play: updated tests to include volume changes
246 | * sound_play: add ability to specify volume at which to play sounds
247 | Also changed error to warning as per todo
248 | * sound_play: fix indentation and comment inconsistencies
249 | * sound_play: remove some raw prints cluttering output
250 | * sound_play: added queue_size to SoundClient init
251 | Should prevent warning being displayed whenever the client is created.
252 | Fixes issue #43
253 | * add simple-actionlib functionality to sound_play
254 | * sound_play: Added functions to play files relative to a package path
255 | * Update maintainer email
256 | * Contributors: Alexis Ballier, Austin, Daniel Stonier, David V. Lu, Felix Duvallet, Matthias Nieuwenhuisen, Michal Staniaszek, Neowizard, aginika, trainman419
257 |
258 | 0.2.11 (2016-02-16)
259 | -------------------
260 | * Add changelogs
261 | * Fix bug in say.py. Fixes `#72 `_
262 | * Contributors: trainman419
263 |
264 | 0.2.10 (2016-01-21)
265 | -------------------
266 | * Add changelogs
267 | * Issue: The error checks for missing publisher/action client in sendMsg were inverted.
268 | The non-blocking brach tested the action client while the blocking branch
269 | tested the publisher.
270 | Fix: Inverted the blocking boolean for both branchs.
271 | * sound_play: Fix build with -DCATKIN_ENABLE_TESTING=OFF.
272 | https://bugs.gentoo.org/show_bug.cgi?id=567466
273 | * Contributors: Alexis Ballier, Neowizard, trainman419
274 |
275 | 0.2.9 (2015-12-02)
276 | ------------------
277 | * Add changelogs
278 | * [soundplay_node] fix resources not being released on dict cleanup
279 | This was resulting in the number of sink inputs reaching the maximum threshold,
280 | (32 on ubuntu 14.04 with pulseaudio 4.0) after which no more sounds could be
281 | played by the node. It would only happen if the rate of sounds being played was
282 | slower than the dictionary cleanup.
283 | * depend on actionlib.
284 | * Introduce unit test to ensure soundclient is started correctly.
285 | * Example of using the explicit blocking parameter to override the class setting.
286 | * SoundClient can also explicitly specify whether or not to block while playing the sound.
287 | Each play/repeat/say/... method can take an option blocking=True|False argument (using **kwargs), which over-rides the class-wide setting.
288 | Conflicts:
289 | sound_play/src/sound_play/libsoundplay.py
290 | * do both in same script.
291 | * Added script showing the various blocking/non-blocking ways of using SoundClient.
292 | * removed trailing whitespace only
293 | Conflicts:
294 | sound_play/scripts/say.py
295 | * loginfo -> logdebug.
296 | * Enable blocking calls inside libsoundplay's SoundClient.
297 | This makes use of the actionlib interface provided by soundplay_node, by ensuring SoundClient receives a response before returning.
298 | Turn this on by: SoundClient(blocking=true).
299 | Conflicts:
300 | sound_play/src/sound_play/libsoundplay.py
301 | * Use new-style python classes (inherits from object).
302 | Conflicts:
303 | sound_play/src/sound_play/libsoundplay.py
304 | * removed trailing whitespace.
305 | Conflicts:
306 | sound_play/src/sound_play/libsoundplay.py
307 | * Revert "Set the volume in each of the sound_play actionlib tests."
308 | This reverts commit 55ab08c882809fc6d21affb849a7dac9f1901867.
309 | Indigo-devel does not have the volume API
310 | * Set the volume in each of the sound_play actionlib tests.
311 | This makes the script actually play the sounds it requests.
312 | * Specify queue size explicitly.
313 | Removed warning message printed each time soundplay_node was started.
314 | * remove trailing whitespace only.
315 | * Fix wiki links
316 | * Contributors: David V. Lu, Felix Duvallet, Michal Staniaszek, trainman419
317 |
318 | 0.2.8 (2015-10-02)
319 | ------------------
320 | * Fix test target name collision. Fixes `#49 `_
321 | * sound_play: remove some raw prints cluttering output
322 | * sound_play: added queue_size to SoundClient init
323 | Should prevent warning being displayed whenever the client is created.
324 | Fixes issue `#43 `_
325 | * add simple-actionlib functionality to sound_play
326 | * sound_play: Added functions to play files relative to a package path
327 | * Update maintainer email
328 | * Contributors: Matthias Nieuwenhuisen, Michal Staniaszek, aginika, trainman419
329 |
330 | 0.2.7 (2014-07-25)
331 | ------------------
332 |
333 | 0.2.6 (2014-02-26)
334 | ------------------
335 | * Fix path resolution in python soundplay lib.
336 | * now importing roslib. closes `#33 `_
337 | * Contributors: Piyush Khandelwal, trainman419
338 |
339 | 0.2.5 (2014-01-23)
340 | ------------------
341 | * "0.2.5"
342 | * Install sounds. Fixes `#29 `_.
343 | * install sound_play.h and export include folder
344 | * Contributors: ahendrix, trainman419, v4hn
345 |
346 | 0.2.4 (2013-09-10)
347 | ------------------
348 | * Fix cmake ordering.
349 | * Contributors: Austin Hendrix
350 |
351 | 0.2.3 (2013-07-15)
352 | ------------------
353 | * Fix python.
354 | * Contributors: Austin Hendrix
355 |
356 | 0.2.2 (2013-04-10)
357 | ------------------
358 | * Actually add proper dependency on message generation.
359 | * Reorder CMakeLists.txt.
360 | * Contributors: Austin Hendrix
361 |
362 | 0.2.1 (2013-04-08 13:59)
363 | ------------------------
364 |
365 | 0.2.0 (2013-04-08 13:49)
366 | ------------------------
367 | * Finish catkinizing audio_common.
368 | * Start catkinizing sound_play.
369 | * Fix typo in package.xml
370 | * Versions and more URLs.
371 | * Convert manifests to package.xml
372 | * Ditch old makefiles.
373 | * Use festival default voice from libsoundplay.
374 | * Set myself as the maintainer.
375 | * Fix filehandle leak and add debug statements.
376 | * Updates manifest
377 | * Updated manifests for rodep2
378 | * Fixed sound_play
379 | * Added test wave
380 | * Cleaned up the test script
381 | * Added default voice to say command
382 | * Updated the gstreamer rosdeps
383 | * Removed comment
384 | * Added diagnostic_msgs to sound_play
385 | * Added a rosdep.yaml file
386 | * Added ability to use different festival voices
387 | * Added exit(1) when import of pygame fails. This makes the error message easier to notice.
388 | * Added Ubuntu platform tags to manifest
389 | * Added a link to the troubleshooting wiki page in the diagnostic message as requested by `#4070 `_.
390 | * Took out the deprecated API.
391 | * Sound play now publishes header timestamp in message. `#3822 `_
392 | * Cleaned up temp file generation when doing text to speach. Now uses the tempfile module.
393 | * Adding missing export of headers for sound_play C++ API
394 | * Changing node name for sound play diagnostics, `#3599 `_
395 | * Added test.launch to run sound server and a test client.
396 | * Remove use of deprecated rosbuild macros
397 | * Replaced review tag with standardized message
398 | * Updated review status
399 | * Added a launch file to start soundplay_node.py
400 | * Made the sound_play client libraries be more explicit about what to do when the node is not running.
401 | * Updated manifest description
402 | * Updated copyright year
403 | * fixed XML typo
404 | * updated package description
405 | * Added a copyright message.
406 | * Removed debugging message from sound_play node.
407 | * Added tests for new sound_play python API and fixed a few bugs.
408 | * Fixed missing self arguments in sound_play libsoundplay.py
409 | * Upgraded the python sound_play API
410 | * Converted non-camelCase methods to camelCase in sound_play C++ API
411 | * Changed Lock to RLock to fix `#2801 `_
412 | * Made the deprecation of SoundHandle into a warning.
413 | * Added debug messages
414 | * Updated soundplay_node to publish diagnostics and increased the number of active channels.
415 | * Added diagnostic_msgs dependency to sound_play
416 | * sound_play: Renamed SoundHandle to SoundClient. Added Sound-centric C++ API. Changed byte to int8 in msg file. Updated documentation.
417 | * migration part 1
418 | * Contributors: Austin Hendrix, Nate Koenig, blaise, blaisegassend, eitan, gerkey, kwc, nkoenig, watts, wheeler
419 |
--------------------------------------------------------------------------------