YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
AudioPlayerWrapper.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: LGPL-2.1-or-later
4 */
5
6#define _USE_MATH_DEFINES
7
9
11#include <yarp/os/LogStream.h>
12
15
16#include <cmath>
17#include <sstream>
18
19using namespace yarp::sig;
20using namespace yarp::dev;
21using namespace yarp::os;
22
23namespace {
24YARP_LOG_COMPONENT(AUDIOPLAYERWRAPPER, "yarp.device.AudioPlayerWrapper")
25constexpr double DEFAULT_THREAD_PERIOD = 0.02; // seconds
26}
27
32
34{
35 m_irender = nullptr;
36}
37
43{
44 if (driver->isValid())
45 {
46 driver->view(m_irender);
47 }
48
49 if (nullptr == m_irender)
50 {
51 yCError(AUDIOPLAYERWRAPPER, "Subdevice passed to attach method is invalid");
52 return false;
53 }
54
55 if (!m_irender->getPlaybackAudioBufferMaxSize(m_max_buffer_size))
56 {
57 yCError(AUDIOPLAYERWRAPPER, "getPlaybackAudioBufferMaxSize failed\n");
58 return false;
59 }
60
62 return PeriodicThread::start();
63}
64
66{
68 {
70 }
71 m_irender = nullptr;
72 return true;
73}
74
75bool AudioPlayerWrapper::read(yarp::os::ConnectionReader& connection)
76{
77 yarp::os::Bottle command;
78 yarp::os::Bottle reply;
79 bool ok = command.read(connection);
80 if (!ok) {
81 return false;
82 }
83 reply.clear();
84
85 if (command.get(0).asString() == "start")
86 {
87 m_irender->startPlayback();
88 m_irender->isPlaying(m_isPlaying);
89 reply.addVocab32(VOCAB_OK);
90 }
91 else if (command.get(0).asString() == "stop")
92 {
93 m_irender->stopPlayback();
94 m_irender->isPlaying(m_isPlaying);
95 reply.addVocab32(VOCAB_OK);
96 }
97 else if (command.get(0).asString() == "sw_audio_gain")
98 {
99 double val = command.get(1).asFloat64();
100 if (val>=0)
101 {
102 m_irender->setSWGain(val);
103 reply.addVocab32(VOCAB_OK);
104 }
105 else
106 {
107 yCError(AUDIOPLAYERWRAPPER) << "Invalid audio gain";
108 reply.addVocab32(VOCAB_ERR);
109 }
110 }
111 else if (command.get(0).asString() == "hw_audio_gain")
112 {
113 double val = command.get(1).asFloat64();
114 if (val >= 0)
115 {
116 m_irender->setHWGain(val);
117 reply.addVocab32(VOCAB_OK);
118 }
119 else
120 {
121 yCError(AUDIOPLAYERWRAPPER) << "Invalid audio gain";
122 reply.addVocab32(VOCAB_ERR);
123 }
124 }
125 else if (command.get(0).asString() == "clear")
126 {
127 m_irender->resetPlaybackAudioBuffer();
128 reply.addVocab32(VOCAB_OK);
129 }
130 else if (command.get(0).asString() == "help")
131 {
132 reply.addVocab32("many");
133 reply.addString("start");
134 reply.addString("stop");
135 reply.addString("clear");
136 reply.addString("sw_audio_gain <gain>");
137 reply.addString("hw_audio_gain <gain>");
138 }
139 else
140 {
141 yCError(AUDIOPLAYERWRAPPER) << "Invalid command";
142 reply.addVocab32(VOCAB_ERR);
143 }
144
146 if (returnToSender != nullptr)
147 {
148 reply.write(*returnToSender);
149 }
150 return true;
151}
152
154{
155 return true;
156}
157
159{
160 if (!parseParams(config)) { return false; }
161
162 std::string audioInPortName = m_name + "/audio:i";
163 std::string rpcPortName = m_name + "/rpc:i";
164 std::string statusPortName = m_name + "/status:o";
165
166 if (!m_audioInPort.open(audioInPortName))
167 {
168 yCError(AUDIOPLAYERWRAPPER, "Failed to open port %s", audioInPortName.c_str());
169 return false;
170 }
171 if (!m_statusPort.open(statusPortName))
172 {
173 yCError(AUDIOPLAYERWRAPPER, "Failed to open port %s", statusPortName.c_str());
174 return false;
175 }
176 if (!m_rpcPort.open(rpcPortName))
177 {
178 yCError(AUDIOPLAYERWRAPPER, "Failed to open port %s", rpcPortName.c_str());
179 return false;
180 }
181 m_rpcPort.setReader(*this);
182
183 yCInfo(AUDIOPLAYERWRAPPER) << "Using a 'playback_network_buffer_size' of" << m_playback_network_buffer_size << "s";
184 yCInfo(AUDIOPLAYERWRAPPER) << "Increase this value to robustify the real-time audio stream (it will increase latency too)";
185
186 return true;
187}
188
190{
191 m_audioInPort.interrupt();
192 m_audioInPort.close();
193 m_rpcPort.interrupt();
194 m_rpcPort.close();
195 m_statusPort.interrupt();
196 m_statusPort.close();
197}
198
200{
201 if(success)
202 {
203 if (m_start)
204 {
205 m_irender->startPlayback();
206 m_irender->isPlaying(m_isPlaying);
207 }
208 }
209}
210
212{
214
215 Sound* s = m_audioInPort.read(false);
216 if (s != nullptr)
217 {
218 if (m_debug)
219 {
220 yCDebug(AUDIOPLAYERWRAPPER) << "Received sound of:" << s->getSamples() << " samples";
221 }
222
223 scheduled_sound_type ss;
224#if 1
225 //This is simple, but we don't know how big the sound is...
227#elif 0
228 //This is ok, but it doesn't work if the sounds have different durations...
229 ss.scheduled_time = current_time + 5.0 * s.getDuration();
230#else
231 ss.scheduled_time = current_time + m_buffer_delay > 5.0 * s.getDuration() ? (m_buffer_delay) : (5.0 * s.getDuration());
232#endif
233 ss.sound_data = *s;
234 m_sound_buffer.push(ss);
235 }
236
237 if (!m_sound_buffer.empty() && current_time > m_sound_buffer.front().scheduled_time)
238 {
239 m_irender->renderSound(m_sound_buffer.front().sound_data);
240 m_sound_buffer.pop();
241 }
242
243 m_irender->getPlaybackAudioBufferCurrentSize(m_current_buffer_size);
244 if (m_debug)
245 {
246 static double printer_wdt = yarp::os::Time::now();
247 if (yarp::os::Time::now() - printer_wdt > 1.0)
248 {
249 yCDebug(AUDIOPLAYERWRAPPER) << m_current_buffer_size.getSamples() << "/" << m_max_buffer_size.getSamples() << "samples";
251 }
252 }
253
254 m_irender->isPlaying(m_isPlaying);
255
256 //status port
258 status.enabled = m_isPlaying;
259 status.current_buffer_size = m_current_buffer_size.getSamples();
260 status.max_buffer_size = m_max_buffer_size.getSamples();
261 m_statusPort.write(status);
262}
263
265{
266 yCTrace(AUDIOPLAYERWRAPPER, "AudioPlayerWrapper::Close");
268 {
270 }
271
272 return true;
273}
define control board standard interfaces
#define DEFAULT_THREAD_PERIOD
constexpr yarp::conf::vocab32_t VOCAB_OK
constexpr yarp::conf::vocab32_t VOCAB_ERR
bool parseParams(const yarp::os::Searchable &config) override
Parse the DeviceDriver parameters.
bool close() override
Close the DeviceDriver.
bool threadInit() override
Initialization method.
void run() override
Loop function.
void threadRelease() override
Release method.
void afterStart(bool success) override
Called just after a new thread starts (or fails to start), this is executed by the same thread that c...
bool detach() override
Detach the object (you must have first called attach).
bool open(yarp::os::Searchable &params) override
Open the DeviceDriver.
bool attach(yarp::dev::PolyDriver *driver) override
Specify which sensor this thread has to read from.
bool view(T *&x)
Get an interface to the device driver.
virtual yarp::dev::ReturnValue getPlaybackAudioBufferCurrentSize(yarp::sig::AudioBufferSize &size)=0
virtual yarp::dev::ReturnValue startPlayback()=0
Start the playback.
virtual yarp::dev::ReturnValue renderSound(const yarp::sig::Sound &sound)=0
Render a sound using a device (i.e.
virtual yarp::dev::ReturnValue stopPlayback()=0
Stop the playback.
virtual yarp::dev::ReturnValue setHWGain(double gain)=0
Sets the hardware gain of the playback device (if supported by the hardware)
virtual yarp::dev::ReturnValue isPlaying(bool &playback_enabled)=0
Check if the playback has been enabled (e.g.
virtual yarp::dev::ReturnValue setSWGain(double gain)=0
Sets a software gain for the played audio.
virtual yarp::dev::ReturnValue getPlaybackAudioBufferMaxSize(yarp::sig::AudioBufferSize &size)=0
virtual yarp::dev::ReturnValue resetPlaybackAudioBuffer()=0
A container for a device driver.
Definition PolyDriver.h:23
bool isValid() const
Check if device is valid.
A simple collection of objects that can be described and transmitted in a portable way.
Definition Bottle.h:64
void addVocab32(yarp::conf::vocab32_t x)
Places a vocabulary item in the bottle, at the end of the list.
Definition Bottle.cpp:164
bool read(ConnectionReader &reader) override
Set the bottle's value based on input from a network connection.
Definition Bottle.cpp:240
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition Bottle.cpp:246
void clear()
Empties the bottle of any objects it contains.
Definition Bottle.cpp:121
bool write(ConnectionWriter &writer) const override
Output a representation of the bottle to a network connection.
Definition Bottle.cpp:230
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition Bottle.cpp:170
A mini-server for performing network communication in the background.
void close() override
Stop port activity.
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
void interrupt() override
Interrupt any current reads or writes attached to the port.
T * read(bool shouldWait=true) override
Read an available object from the port.
An interface for reading from a network connection.
virtual ConnectionWriter * getWriter()=0
Gets a way to reply to the message, if possible.
An interface for writing to a network connection.
An abstraction for a periodic thread.
bool setPeriod(double period)
Set the (new) period of the thread.
bool isRunning() const
Returns true when the thread is started, false otherwise.
bool start()
Call this to start the thread.
void stop()
Call this to stop the thread, this call blocks until the thread is terminated (and releaseThread() ca...
bool write(const PortWriter &writer, const PortWriter *callback=nullptr) const override
Write an object to the port.
Definition Port.cpp:436
void setReader(PortReader &reader) override
Set an external reader for port data.
Definition Port.cpp:511
void interrupt() override
Interrupt any current reads or writes attached to the port.
Definition Port.cpp:383
void close() override
Stop port activity.
Definition Port.cpp:363
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
Definition Port.cpp:79
A base class for nested structures that can be searched.
Definition Searchable.h:31
virtual yarp::conf::float64_t asFloat64() const
Get 64-bit floating point value.
Definition Value.cpp:222
virtual std::string asString() const
Get string value.
Definition Value.cpp:234
AudioPlayerStatus: A class used to describe the status of an audio player device.
size_t max_buffer_size
the max_size of the audio buffer [samples]
bool enabled
true if the playback is currently enabled
size_t current_buffer_size
the size of the audio buffer [samples]
Class for storing sounds See Audio in YARP for additional documentation on YARP audio.
Definition Sound.h:25
double getDuration() const
Get the duration of sound in seconds.
Definition Sound.cpp:608
size_t getSamples() const
Get the number of samples contained in the sound.
Definition Sound.cpp:598
std::string current_time()
Definition utils.h:24
#define yCInfo(component,...)
#define yCError(component,...)
#define yCTrace(component,...)
#define yCDebug(component,...)
#define YARP_LOG_COMPONENT(name,...)
For streams capable of holding different kinds of content, check what they actually have.
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition Time.cpp:121
An interface to the operating system, including Port based communication.