YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
AudioRecorderWrapper.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
7#include <yarp/os/LogStream.h>
9
10using namespace yarp::dev;
11using namespace yarp::os;
12
13namespace {
14YARP_LOG_COMPONENT(AUDIORECORDERWRAPPER, "yarp.device.AudioRecorderWrapper")
15constexpr double DEFAULT_THREAD_PERIOD = 0.02; // seconds
19
20}
21
22
24 m_period(DEFAULT_THREAD_PERIOD),
25 m_min_number_of_samples_over_network(DEFAULT_MIN_NUMBER_OF_SAMPLES_OVER_NETWORK),
26 m_max_number_of_samples_over_network(DEFAULT_MAX_NUMBER_OF_SAMPLES_OVER_NETWORK),
27 m_getSound_timeout(DEFAULT_GETSOUND_TIMEOUT)
28{
29 m_stamp.update();
30}
31
36
38{
39 yCWarning(AUDIORECORDERWRAPPER) << "The 'AudioRecorderWrapper' device is deprecated in favour of 'audioRecorder_nws_yarp'.";
40 yCWarning(AUDIORECORDERWRAPPER) << "The old device is no longer supported, and it will be removed in next YARP releases.";
41 yCWarning(AUDIORECORDERWRAPPER) << "Please update your scripts.";
42
43 m_config.fromString(config.toString());
44
45 if (config.check("period"))
46 {
47 m_period = config.find("period").asFloat64();
48 }
49
50 // Get parameter samples_over_network
51 if (config.check("min_samples_over_network"))
52 {
53 m_min_number_of_samples_over_network = config.find("min_samples_over_network").asInt64();
54 }
55 if (config.check("max_samples_over_network"))
56 {
57 m_max_number_of_samples_over_network = config.find("max_samples_over_network").asInt64();
58 }
59 yCInfo(AUDIORECORDERWRAPPER) << "Wrapper configured to produce packets with the following size (in samples): " <<
60 m_min_number_of_samples_over_network << " < samples < " << m_max_number_of_samples_over_network;
61
62 // Get parameter samples_over_network
63 if (config.check("max_samples_timeout"))
64 {
65 m_getSound_timeout = config.find("max_samples_timeout").asFloat64();
66 }
67 yCInfo(AUDIORECORDERWRAPPER) << "Wrapper configured with max_samples_timeout: " << m_getSound_timeout << "s";
68
69 // Set the streaming port
70 std::string portname = "/audioRecorderWrapper";
71 if (config.check("name"))
72 {
73 portname= config.find("name").asString();
74 }
75 if (m_streamingPort.open(portname + "/audio:o") == false)
76 {
77 yCError(AUDIORECORDERWRAPPER) << "Unable to open port" << portname + "/audio:o";
78 return false;
79 }
80 if (m_statusPort.open(portname + "/status:o") == false)
81 {
82 yCError(AUDIORECORDERWRAPPER) << "Unable to open port" << portname + "/status:o";
83 return false;
84 }
85 // Set the RPC port
86 if (m_rpcPort.open(portname + "/rpc") == false)
87 {
88 yCError(AUDIORECORDERWRAPPER) << "Unable to open port" << portname + "/rpc";
89 return false;
90 }
91 m_rpcPort.setReader(*this);
92
93 return true;
94}
95
97{
98 detach();
99
100 m_streamingPort.interrupt();
101 m_streamingPort.close();
102 m_rpcPort.interrupt();
103 m_rpcPort.close();
104 m_statusPort.interrupt();
105 m_statusPort.close();
106
107 if (m_dataThread)
108 {
109 delete m_dataThread;
110 m_dataThread = nullptr;
111 }
112 if (m_statusThread)
113 {
114 delete m_statusThread;
115 m_statusThread = nullptr;
116 }
117 return true;
118}
119
121{
122 yarp::os::Bottle command;
123 yarp::os::Bottle reply;
124 bool ok = command.read(connection);
125 if (!ok) {
126 return false;
127 }
128 reply.clear();
129
130 if (command.get(0).asString()=="start")
131 {
132 m_mic->startRecording();
133 m_mic->isRecording(m_isRecording);
134 reply.addVocab32(VOCAB_OK);
135 }
136 else if (command.get(0).asString() == "stop")
137 {
138 m_mic->stopRecording();
139 m_mic->isRecording(m_isRecording);
140 reply.addVocab32(VOCAB_OK);
141 }
142 else if (command.get(0).asString() == "sw_audio_gain")
143 {
144 double val = command.get(1).asFloat64();
145 if (val >= 0)
146 {
147 m_mic->setSWGain(val);
148 reply.addVocab32(VOCAB_OK);
149 }
150 else
151 {
152 yCError(AUDIORECORDERWRAPPER) << "Invalid audio gain";
153 reply.addVocab32(VOCAB_ERR);
154 }
155 }
156 else if (command.get(0).asString() == "hw_audio_gain")
157 {
158 double val = command.get(1).asFloat64();
159 if (val >= 0)
160 {
161 m_mic->setHWGain(val);
162 reply.addVocab32(VOCAB_OK);
163 }
164 else
165 {
166 yCError(AUDIORECORDERWRAPPER) << "Invalid audio gain";
167 reply.addVocab32(VOCAB_ERR);
168 }
169 }
170 else if (command.get(0).asString() == "clear")
171 {
173 reply.addVocab32(VOCAB_OK);
174 }
175 else if (command.get(0).asString() == "help")
176 {
177 reply.addVocab32("many");
178 reply.addString("start");
179 reply.addString("stop");
180 reply.addString("clear");
181 reply.addString("sw_audio_gain <gain>");
182 reply.addString("hw_audio_gain <gain>");
183 }
184 else
185 {
186 yCError(AUDIORECORDERWRAPPER) << "Invalid command";
187 reply.addVocab32(VOCAB_ERR);
188 }
189
191 if (returnToSender != nullptr)
192 {
193 reply.write(*returnToSender);
194 }
195 return true;
196}
197
199{
200 if (driver->isValid())
201 {
202 driver->view(m_mic);
203 }
204
205 if (nullptr == m_mic)
206 {
207 yCError(AUDIORECORDERWRAPPER, "Subdevice passed to attach method is invalid");
208 return false;
209 }
210
211 m_dataThread = new AudioRecorderDataThread(this);
212 m_statusThread = new AudioRecorderStatusThread(this);
213 m_dataThread->setPeriod(m_period);
214 m_dataThread->start();
215 m_statusThread->start();
216
217 // Wait a little and then start if requested
218 if (m_config.check("start")) {
219 yCDebug(AUDIORECORDERWRAPPER) << "Auto start requested";
221 m_mic->startRecording();
222 m_mic->isRecording(m_isRecording);
223 }
224
225 return true;
226}
227
229{
230 if (m_dataThread)
231 {
232 m_dataThread->stop();
233 }
234 if (m_statusThread)
235 {
236 m_statusThread->stop();
237 }
238
239 if (m_mic)
240 {
241 m_mic->stopRecording();
242 m_mic = nullptr;
243 }
244 return true;
245}
246
248{
253
254 if (m_ARW->m_debug_enabled)
255 {
256 static double printer_wdt = yarp::os::Time::now();
257 if (yarp::os::Time::now() - printer_wdt > 1.0)
258 {
259 yCDebug(AUDIORECORDERWRAPPER) << device_buffer_current_size.getSamples() << "/" << device_buffer_max_size.getSamples() << "samples";
261 }
262 }
263
264
265 m_ARW->m_mic->isRecording(m_ARW->m_isRecording);
266
267 //status port
269 status.enabled = m_ARW->m_isRecording;
271 status.max_buffer_size = device_buffer_max_size.getSamples();
272 m_ARW->m_statusPort.write(status);
273}
274
276{
277 if (0)
278 {
279 //debug: print the duration of the thread
281 yCDebug(AUDIORECORDERWRAPPER) << (current_time - m_ARW->m_debug_last_time);
282 m_ARW->m_debug_last_time = current_time;
283 }
284
285 if (m_ARW->m_mic == nullptr)
286 {
287 yCError(AUDIORECORDERWRAPPER) << "The IAudioGrabberSound interface is not available yet!";
288 return;
289 }
290
291#ifdef PRINT_DEBUG_MESSAGES
292 {
295 mic->getRecordingAudioBufferMaxSize(buf_max);
296 mic->getRecordingAudioBufferCurrentSize(buf_cur);
297 yCDebug(AUDIORECORDERWRAPPER) << "BEFORE Buffer status:" << buf_cur.getBytes() << "/" << buf_max.getBytes() << "bytes";
298 }
299#endif
300
302 m_ARW->m_mic->getSound(snd, m_ARW->m_min_number_of_samples_over_network, m_ARW->m_max_number_of_samples_over_network, m_ARW->m_getSound_timeout);
303
304 if (snd.getSamples() < m_ARW->m_min_number_of_samples_over_network ||
305 snd.getSamples() < m_ARW->m_max_number_of_samples_over_network)
306 {
307 yCWarning(AUDIORECORDERWRAPPER) << "subdevice->getSound() is not producing sounds of the requested size ("
308 << m_ARW->m_min_number_of_samples_over_network << "<"
309 << snd.getSamples() << "<"
310 << m_ARW->m_max_number_of_samples_over_network << ") failed";
311 }
312
313#ifdef PRINT_DEBUG_MESSAGES
314 {
317 mic->getRecordingAudioBufferMaxSize(buf_max);
318 mic->getRecordingAudioBufferCurrentSize(buf_cur);
319 yCDebug(AUDIORECORDERWRAPPER) << "AFTER Buffer status:" << buf_cur.getBytes() << "/" << buf_max.getBytes() << "bytes";
320 }
321#endif
322#ifdef PRINT_DEBUG_MESSAGES
323 yCDebug(AUDIORECORDERWRAPPER) << "Sound size:" << snd.getSamples() * snd.getChannels() * snd.getBytesPerSample() << " bytes";
325#endif
326
327 //prepare the timestamp
328 m_ARW->m_stamp.update();
329 m_ARW->m_streamingPort.setEnvelope(m_ARW->m_stamp);
330
331 //check before sending data
332 if (snd.getSamples() == 0)
333 {
334 yCError(AUDIORECORDERWRAPPER) << "Subdevice produced sound of 0 samples!";
335 return;
336 }
337 if (snd.getChannels() == 0)
338 {
339 yCError(AUDIORECORDERWRAPPER) << "Subdevice produced sound of 0 channels!";
340 return;
341 }
342 if (snd.getFrequency() == 0)
343 {
344 yCError(AUDIORECORDERWRAPPER) << "Subdevice produced sound with 0 frequency!";
345 return;
346 }
347
348 //send data
349 m_ARW->m_streamingPort.write(snd);
350}
#define DEFAULT_THREAD_PERIOD
constexpr yarp::conf::vocab32_t VOCAB_OK
constexpr yarp::conf::vocab32_t VOCAB_ERR
void run() override
Loop function.
AudioRecorderWrapper * m_ARW
AudioRecorderWrapper * m_ARW
void run() override
Loop function.
AudioRecorderWrapper: A Wrapper which streams audio over the network, after grabbing it from a device
bool attach(yarp::dev::PolyDriver *driver) override
Attach to another object.
friend class AudioRecorderDataThread
bool close() override
Close the DeviceDriver.
friend class AudioRecorderStatusThread
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
bool read(yarp::os::ConnectionReader &connection) override
Read this object from a network connection.
bool detach() override
Detach the object (you must have first called attach).
bool view(T *&x)
Get an interface to the device driver.
virtual yarp::dev::ReturnValue getRecordingAudioBufferCurrentSize(yarp::sig::AudioBufferSize &size)=0
virtual yarp::dev::ReturnValue getSound(yarp::sig::Sound &sound, size_t min_number_of_samples, size_t max_number_of_samples, double max_samples_timeout_s)=0
Get a sound from a device.
virtual yarp::dev::ReturnValue stopRecording()=0
Stop the recording.
virtual yarp::dev::ReturnValue resetRecordingAudioBuffer()=0
virtual yarp::dev::ReturnValue isRecording(bool &recording_enabled)=0
Check if the recording has been enabled (e.g.
virtual yarp::dev::ReturnValue setHWGain(double gain)=0
Sets the hardware gain of the grabbing device (if supported by the hardware)
virtual yarp::dev::ReturnValue startRecording()=0
Start the recording.
virtual yarp::dev::ReturnValue setSWGain(double gain)=0
Sets a software gain for the grabbed audio.
virtual yarp::dev::ReturnValue getRecordingAudioBufferMaxSize(yarp::sig::AudioBufferSize &size)=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.
An interface for reading from a network connection.
An interface for writing to a network connection.
bool setPeriod(double period)
Set the (new) period of the thread.
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
bool setEnvelope(PortWriter &envelope) override
Set an envelope (e.g., a timestamp) to the next message which will be sent.
Definition Port.cpp:547
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
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
bool check(const std::string &key) const override
Check if there exists a property of the given name.
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.
virtual std::string toString() const =0
Return a standard text representation of the content of the object.
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
void update()
Set the timestamp to the current time, and increment the sequence number (wrapping to 0 if the sequen...
Definition Stamp.cpp:124
static void delaySystem(double seconds)
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
AudioRecorderStatus: A class used to describe the status of an audio recorder device.
size_t current_buffer_size
the size of the audio buffer [samples]
size_t max_buffer_size
the max_size of the audio buffer [samples]
bool enabled
true if the playback is currently enabled
Class for storing sounds See Audio in YARP for additional documentation on YARP audio.
Definition Sound.h:25
size_t getBytesPerSample() const
Get the number of bytes per sample.
Definition Sound.cpp:593
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
size_t getSamples() const
Get the number of samples contained in the sound.
Definition Sound.cpp:598
#define yCInfo(component,...)
#define yCError(component,...)
#define yCWarning(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.