YARP
Yet Another Robot Platform
AudioPlayerDeviceBase.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
6#define _USE_MATH_DEFINES
7
9#include <yarp/os/LogStream.h>
10#include <mutex>
11#include <limits>
12#include <cmath>
13#include <functional>
14
15using namespace yarp::os;
16using namespace yarp::dev;
17
18constexpr double c_sleep_time=0.005;
19
20YARP_LOG_COMPONENT(AUDIOPLAYER_BASE, "yarp.devices.AudioPlayerDeviceBase")
21
22//the following macros should never be modified and are used only for development purposes
23#define DEBUG_TIME_SPENT 0
24
25//Default device parameters
26#define DEFAULT_SAMPLE_RATE (44100)
27#define DEFAULT_NUM_CHANNELS (2)
28#define DEFAULT_SAMPLE_SIZE (2)
29
30bool AudioPlayerDeviceBase::getPlaybackAudioBufferCurrentSize(yarp::dev::AudioBufferSize& size)
31{
32 if (m_outputBuffer == nullptr)
33 {
34 yCError(AUDIOPLAYER_BASE) << "getPlaybackAudioBufferCurrentSize() called, but no audio buffer is allocated yet";
35 return false;
36 }
37 //no lock guard is needed here
38 size = this->m_outputBuffer->size();
39 return true;
40}
41
43{
44 if (m_outputBuffer == nullptr)
45 {
46 yCError(AUDIOPLAYER_BASE) << "getPlaybackAudioBufferMaxSize() called, but no audio buffer is allocated yet";
47 return false;
48 }
49 //no lock guard is needed here
50 size = this->m_outputBuffer->getMaxSize();
51 return true;
52}
53
55{
56 delete m_outputBuffer;
57}
58
60{
61 std::lock_guard<std::recursive_mutex> lock(m_mutex);
62 if (gain>0)
63 {
64 m_sw_gain = gain;
65 return true;
66 }
67 return false;
68}
69
71{
72 std::lock_guard<std::recursive_mutex> lock(m_mutex);
73 m_playback_enabled = true;
75 {this->m_outputBuffer->clear();}
76 yCInfo(AUDIOPLAYER_BASE) << "Playback started";
77 return true;
78}
79
81{
82 std::lock_guard<std::recursive_mutex> lock(m_mutex);
83 m_playback_enabled = false;
85 {this->m_outputBuffer->clear();}
86 yCInfo(AUDIOPLAYER_BASE) << "Playback stopped";
87 return true;
88}
89
90bool AudioPlayerDeviceBase::isPlaying(bool& playback_enabled)
91{
92 playback_enabled = m_playback_enabled;
93 return true;
94}
95
97{
98 if (m_outputBuffer == nullptr)
99 {
100 yCError(AUDIOPLAYER_BASE) << "resetPlaybackAudioBuffer() called, but no audio buffer is allocated yet";
101 return false;
102 }
103 std::lock_guard<std::recursive_mutex> lock(m_mutex);
104 this->m_outputBuffer->clear();
105 return true;
106}
107
109{
110 //Do I need a lockguard?
111 size_t num_channels = sound.getChannels();
112 size_t num_samples = sound.getSamples();
113
114 for (size_t i = 0; i < num_samples; i++) {
115 for (size_t j = 0; j < num_channels; j++) {
116 m_outputBuffer->write(sound.get(i, j));
117 }
118 }
119
120 return true;
121}
122
124{
125 //Do I need a lockguard?
127
128 size_t num_channels = sound.getChannels();
129 size_t num_samples = sound.getSamples();
130
131 for (size_t i = 0; i < num_samples; i++) {
132 for (size_t j = 0; j < num_channels; j++) {
133 m_outputBuffer->write(sound.get(i, j));
134 }
135 }
136
137 return true;
138}
139
141{
142 //prevents simultaneous start/stop/reset etc.
143 std::lock_guard<std::recursive_mutex> lock(m_mutex);
144
145 size_t freq = sound.getFrequency();
146 size_t chans = sound.getChannels();
147 if (freq == 0)
148 {
149 yCError(AUDIOPLAYER_BASE) << "received a bad audio sample of frequency 0";
150 return false;
151 }
152 if (chans == 0)
153 {
154 yCError(AUDIOPLAYER_BASE) << "received a bad audio sample with 0 channels";
155 return false;
156 }
157
158 //process the sound, if required
159 yarp::sig::Sound procsound = sound;
160 if (m_sw_gain != 1.0)
161 {
162 procsound.amplify(m_sw_gain);
163 }
164
165 if (freq != this->m_audioplayer_cfg.frequency ||
166 chans != this->m_audioplayer_cfg.numChannels)
167 {
168 //wait for current playback to finish
170
171 //reset the driver
172 yCInfo(AUDIOPLAYER_BASE, "***** audio driver configuration changed, resetting");
173 yCInfo(AUDIOPLAYER_BASE) << "changing from: " << this->m_audioplayer_cfg.numChannels << "channels, " << this->m_audioplayer_cfg.frequency << " Hz, ->" <<
174 chans << "channels, " << freq << " Hz";
175
176 bool was_playing = this->m_playback_enabled;
177 //close is called in order to destroy the buffer
179
180 //The device is re-opened with new configuration parameters
181 m_audioplayer_cfg.numChannels = (int)(chans);
182 m_audioplayer_cfg.frequency = (int)(freq);
183 bool ok = configureDeviceAndStart();
184 if (ok == false)
185 {
186 yCError(AUDIOPLAYER_BASE, "error occurred during audio driver reconfiguration, aborting");
187 return false;
188 }
189 //restore the playback_enabled status before device reconfiguration
190 if (was_playing)
191 {
192 this->startPlayback();
193 }
194 }
195
197 return immediateSound(procsound);
198 } else if (m_renderMode == RENDER_APPEND) {
199 return appendSound(procsound);
200 }
201
202 return false;
203}
204
206{
207 m_audioplayer_cfg.frequency = config.check("rate", Value(0), "audio sample rate (0=automatic)").asInt32();
208 m_audioplayer_cfg.numSamples = config.check("samples", Value(0), "number of samples per network packet (0=automatic). For chunks of 1 second of recording set samples=rate. Channels number is handled internally.").asInt32();
209 m_audioplayer_cfg.numChannels = config.check("channels", Value(0), "number of audio channels (0=automatic, max is 2)").asInt32();
210 m_hw_gain = config.check("hw_gain", Value(1.0), "HW gain").asFloat32();
211 m_sw_gain = config.check("sw_gain", Value(1.0), "SW gain").asFloat32();
212
215 }
216 if (m_audioplayer_cfg.frequency == 0) {
218 }
219 if (m_audioplayer_cfg.numSamples == 0) {
220 m_audioplayer_cfg.numSamples = m_audioplayer_cfg.frequency; // by default let's use chunks of 1 second
221 }
222
223 if (config.check("render_mode_append"))
224 {
226 }
227 if (config.check("render_mode_immediate"))
228 {
230 }
231
232 yCInfo(AUDIOPLAYER_BASE) << "Device configured with the following options:";
234 yCInfo(AUDIOPLAYER_BASE) << "Samples (buffer size):" << m_audioplayer_cfg.numSamples;
237 yCInfo(AUDIOPLAYER_BASE) << "HW gain:" << m_hw_gain;
238 yCInfo(AUDIOPLAYER_BASE) << "SW gain:" << m_sw_gain;
239 yCInfo(AUDIOPLAYER_BASE) << "Render mode:" << (m_renderMode==RENDER_APPEND?"append":"immediate");
240
241 //create the buffer
243 if (m_outputBuffer == nullptr)
244 {
245 m_outputBuffer = new yarp::dev::CircularAudioBuffer_16t(device_name, buffer_size);
246 }
247
248 //additional options
249 m_enable_buffer_autoclear = config.check("buffer_autoclear", Value(false), "Automatically clear the buffer every time the devices is started/stopped").asBool();
250 m_audiobase_debug = config.check("debug", Value(false), "Enable debug mode").asBool();
251
252 return true;
253}
254
256{
257 if (m_outputBuffer == nullptr)
258 {
259 yCError(AUDIOPLAYER_BASE) << "waitUntilPlaybackStreamIsComplete() called, but no audio buffer is allocated yet";
260 return;
261 }
262
263 while (m_outputBuffer->size().getSamples() != 0)
264 {
266 }
267}
const yarp::os::LogComponent & AUDIOPLAYER_BASE()
#define DEFAULT_NUM_CHANNELS
#define DEFAULT_SAMPLE_RATE
constexpr double c_sleep_time
virtual bool immediateSound(const yarp::sig::Sound &sound)
virtual bool isPlaying(bool &playback_enabled) override
Check if the playback has been enabled (e.g.
virtual bool configureDeviceAndStart()=0
virtual bool renderSound(const yarp::sig::Sound &sound) override
Render a sound using a device (i.e.
virtual bool resetPlaybackAudioBuffer() override
virtual bool getPlaybackAudioBufferMaxSize(yarp::dev::AudioBufferSize &size) override
virtual bool setSWGain(double gain) override
Sets a software gain for the played audio.
virtual bool appendSound(const yarp::sig::Sound &sound)
enum yarp::dev::AudioPlayerDeviceBase::@87 m_renderMode
yarp::dev::CircularAudioBuffer_16t * m_outputBuffer
virtual bool startPlayback() override
Start the playback.
virtual bool stopPlayback() override
Stop the playback.
bool configurePlayerAudioDevice(yarp::os::Searchable &config, std::string device_name)
virtual bool interruptDeviceAndClose()=0
AudioDeviceDriverSettings m_audioplayer_cfg
yarp::dev::AudioBufferSize getMaxSize()
A base class for nested structures that can be searched.
Definition: Searchable.h:63
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
A single value (typically within a Bottle).
Definition: Value.h:43
Class for storing sounds See Audio in YARP for additional documentation on YARP audio.
Definition: Sound.h:25
size_t getChannels() const
Get the number of channels of the sound.
Definition: Sound.cpp:424
void amplify(double gain)
amplify a sound
Definition: Sound.cpp:466
int getFrequency() const
Get the frequency of the sound (i.e.
Definition: Sound.cpp:224
audio_sample get(size_t sample, size_t channel=0) const
Definition: Sound.cpp:175
size_t getSamples() const
Get the number of samples contained in the sound.
Definition: Sound.cpp:419
#define yCInfo(component,...)
Definition: LogComponent.h:171
#define yCError(component,...)
Definition: LogComponent.h:213
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:76
For streams capable of holding different kinds of content, check what they actually have.
yarp::dev::CircularAudioBuffer< unsigned short int > CircularAudioBuffer_16t
void delay(double seconds)
Wait for a certain number of seconds.
Definition: Time.cpp:111
An interface to the operating system, including Port based communication.