YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
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;
17using namespace yarp::sig;
18
19constexpr double c_sleep_time=0.005;
20
21YARP_LOG_COMPONENT(AUDIOPLAYER_BASE, "yarp.devices.AudioPlayerDeviceBase")
22
23//the following macros should never be modified and are used only for development purposes
24#define DEBUG_TIME_SPENT 0
25
26//Default device parameters
27#define DEFAULT_SAMPLE_RATE (44100)
28#define DEFAULT_NUM_CHANNELS (2)
29#define DEFAULT_SAMPLE_SIZE (2)
30
32{
33 if (m_outputBuffer == nullptr)
34 {
35 yCError(AUDIOPLAYER_BASE) << "getPlaybackAudioBufferCurrentSize() called, but no audio buffer is allocated yet";
37 }
38 //no lock guard is needed here
39 size = this->m_outputBuffer->size();
40 return ReturnValue_ok;
41}
42
44{
45 if (m_outputBuffer == nullptr)
46 {
47 yCError(AUDIOPLAYER_BASE) << "getPlaybackAudioBufferMaxSize() called, but no audio buffer is allocated yet";
49 }
50 //no lock guard is needed here
51 size = this->m_outputBuffer->getMaxSize();
52 return ReturnValue_ok;
53}
54
56{
57 if (m_outputBuffer != nullptr)
58 {
59 delete m_outputBuffer;
60 m_outputBuffer = nullptr;
61 }
62}
63
65{
66 std::lock_guard<std::recursive_mutex> lock(m_mutex);
67 if (gain>0)
68 {
69 m_sw_gain = gain;
70 return ReturnValue_ok;
71 }
72 //negative gain
74}
75
77{
78 std::lock_guard<std::recursive_mutex> lock(m_mutex);
79 m_playback_enabled = true;
81 {this->m_outputBuffer->clear();}
82 yCInfo(AUDIOPLAYER_BASE) << "Playback started";
83 return ReturnValue_ok;
84}
85
87{
88 std::lock_guard<std::recursive_mutex> lock(m_mutex);
89 m_playback_enabled = false;
91 {this->m_outputBuffer->clear();}
92 yCInfo(AUDIOPLAYER_BASE) << "Playback stopped";
93 return ReturnValue_ok;
94}
95
101
103{
104 if (m_outputBuffer == nullptr)
105 {
106 yCError(AUDIOPLAYER_BASE) << "resetPlaybackAudioBuffer() called, but no audio buffer is allocated yet";
108 }
109 std::lock_guard<std::recursive_mutex> lock(m_mutex);
110 this->m_outputBuffer->clear();
111 return ReturnValue_ok;
112}
113
115{
116 //Do I need a lockguard?
117 size_t num_channels = sound.getChannels();
118 size_t num_samples = sound.getSamples();
119
120 for (size_t i = 0; i < num_samples; i++) {
121 for (size_t j = 0; j < num_channels; j++) {
122 m_outputBuffer->write(sound.get(i, j));
123 }
124 }
125
126 return true;
127}
128
130{
131 //Do I need a lockguard?
133
134 size_t num_channels = sound.getChannels();
135 size_t num_samples = sound.getSamples();
136
137 for (size_t i = 0; i < num_samples; i++) {
138 for (size_t j = 0; j < num_channels; j++) {
139 m_outputBuffer->write(sound.get(i, j));
140 }
141 }
142
143 return true;
144}
145
147{
148 //prevents simultaneous start/stop/reset etc.
149 std::lock_guard<std::recursive_mutex> lock(m_mutex);
150
151 size_t freq = sound.getFrequency();
152 size_t chans = sound.getChannels();
153 if (freq == 0)
154 {
155 yCError(AUDIOPLAYER_BASE) << "received a bad audio sample of frequency 0";
157 }
158 if (chans == 0)
159 {
160 yCError(AUDIOPLAYER_BASE) << "received a bad audio sample with 0 channels";
162 }
163
164 //process the sound, if required
166 if (m_sw_gain != 1.0)
167 {
168 procsound.amplify(m_sw_gain);
169 }
170
171 if (freq != this->m_audioplayer_cfg.frequency ||
172 chans != this->m_audioplayer_cfg.numChannels)
173 {
174 //wait for current playback to finish
176
177 //reset the driver
178 yCInfo(AUDIOPLAYER_BASE, "***** audio driver configuration changed, resetting");
179 yCInfo(AUDIOPLAYER_BASE) << "changing from: " << this->m_audioplayer_cfg.numChannels << "channels, " << this->m_audioplayer_cfg.frequency << " Hz, ->" <<
180 chans << "channels, " << freq << " Hz";
181
182 bool was_playing = this->m_playback_enabled;
183 //close is called in order to destroy the buffer
185
186 //The device is re-opened with new configuration parameters
189 bool ok = configureDeviceAndStart();
190 if (ok == false)
191 {
192 yCError(AUDIOPLAYER_BASE, "error occurred during audio driver reconfiguration, aborting");
194 }
195 //restore the playback_enabled status before device reconfiguration
196 if (was_playing)
197 {
198 this->startPlayback();
199 }
200 }
201
203 {
204 if (immediateSound(procsound))
205 return ReturnValue_ok;
206 else
208 } else if (m_renderMode == RENDER_APPEND)
209 {
211 return ReturnValue_ok;
212 else
214 }
215
217}
218
220{
221 m_audioplayer_cfg.frequency = config.check("rate", Value(0), "audio sample rate (0=automatic)").asInt32();
222 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();
223 m_audioplayer_cfg.numChannels = config.check("channels", Value(0), "number of audio channels (0=automatic, max is 2)").asInt32();
224 m_hw_gain = config.check("hw_gain", Value(1.0), "HW gain").asFloat32();
225 m_sw_gain = config.check("sw_gain", Value(1.0), "SW gain").asFloat32();
226
229 }
230 if (m_audioplayer_cfg.frequency == 0) {
232 }
233 if (m_audioplayer_cfg.numSamples == 0) {
234 m_audioplayer_cfg.numSamples = m_audioplayer_cfg.frequency; // by default let's use chunks of 1 second
235 }
236
237 if (config.check("render_mode_append"))
238 {
240 }
241 if (config.check("render_mode_immediate"))
242 {
244 }
245
246 yCInfo(AUDIOPLAYER_BASE) << "Device configured with the following options:";
248 yCInfo(AUDIOPLAYER_BASE) << "Samples (buffer size):" << m_audioplayer_cfg.numSamples;
251 yCInfo(AUDIOPLAYER_BASE) << "HW gain:" << m_hw_gain;
252 yCInfo(AUDIOPLAYER_BASE) << "SW gain:" << m_sw_gain;
253 yCInfo(AUDIOPLAYER_BASE) << "Render mode:" << (m_renderMode==RENDER_APPEND?"append":"immediate");
254
255 //create the buffer
257 if (m_outputBuffer == nullptr)
258 {
259 m_outputBuffer = new yarp::dev::CircularAudioBuffer_16t(device_name, buffer_size);
260 }
261
262 //additional options
263 m_enable_buffer_autoclear = config.check("buffer_autoclear", Value(false), "Automatically clear the buffer every time the devices is started/stopped").asBool();
264 m_audiobase_debug = config.check("debug", Value(false), "Enable debug mode").asBool();
265
266 return true;
267}
268
270{
271 if (m_outputBuffer == nullptr)
272 {
273 yCError(AUDIOPLAYER_BASE) << "waitUntilPlaybackStreamIsComplete() called, but no audio buffer is allocated yet";
274 return;
275 }
276
277 while (m_outputBuffer->size().getSamples() != 0)
278 {
280 }
281}
const yarp::os::LogComponent & AUDIOPLAYER_BASE()
#define DEFAULT_NUM_CHANNELS
#define DEFAULT_SAMPLE_RATE
constexpr double c_sleep_time
#define ReturnValue_ok
Definition ReturnValue.h:77
virtual yarp::dev::ReturnValue getPlaybackAudioBufferMaxSize(yarp::sig::AudioBufferSize &size) override
virtual bool immediateSound(const yarp::sig::Sound &sound)
virtual bool configureDeviceAndStart()=0
virtual yarp::dev::ReturnValue renderSound(const yarp::sig::Sound &sound) override
Render a sound using a device (i.e.
virtual yarp::dev::ReturnValue stopPlayback() override
Stop the playback.
virtual yarp::dev::ReturnValue getPlaybackAudioBufferCurrentSize(yarp::sig::AudioBufferSize &size) override
virtual yarp::dev::ReturnValue isPlaying(bool &playback_enabled) override
Check if the playback has been enabled (e.g.
virtual yarp::dev::ReturnValue resetPlaybackAudioBuffer() override
virtual bool appendSound(const yarp::sig::Sound &sound)
enum yarp::dev::AudioPlayerDeviceBase::@87 m_renderMode
yarp::dev::CircularAudioBuffer_16t * m_outputBuffer
virtual yarp::dev::ReturnValue setSWGain(double gain) override
Sets a software gain for the played audio.
bool configurePlayerAudioDevice(yarp::os::Searchable &config, std::string device_name)
virtual bool interruptDeviceAndClose()=0
virtual yarp::dev::ReturnValue startPlayback() override
Start the playback.
AudioDeviceDriverSettings m_audioplayer_cfg
yarp::sig::AudioBufferSize size()
yarp::sig::AudioBufferSize getMaxSize()
@ return_value_error_not_ready
Method failed due to invalid internal status/invalid request.
@ return_value_error_method_failed
Method is deprecated.
A mini-server for performing network communication in the background.
A base class for nested structures that can be searched.
Definition Searchable.h:31
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:603
int getFrequency() const
Get the frequency of the sound (i.e.
Definition Sound.cpp:356
audio_sample get(size_t sample, size_t channel=0) const
Definition Sound.cpp:294
size_t getSamples() const
Get the number of samples contained in the sound.
Definition Sound.cpp:598
#define yCInfo(component,...)
#define yCError(component,...)
#define YARP_LOG_COMPONENT(name,...)
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.