YARP
Yet Another Robot Platform
AudioRecorderWrapper.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include "AudioRecorderWrapper.h"
20 #include <yarp/os/LogStream.h>
21 
22 using namespace yarp::dev;
23 
24 namespace {
25 YARP_LOG_COMPONENT(AUDIORECORDERWRAPPER, "yarp.device.AudioRecorderWrapper")
26 constexpr double DEFAULT_THREAD_PERIOD = 0.02; // seconds
27 constexpr size_t DEFAULT_MIN_NUMBER_OF_SAMPLES_OVER_NETWORK = 11250;
28 constexpr size_t DEFAULT_MAX_NUMBER_OF_SAMPLES_OVER_NETWORK = 11250;
29 constexpr double DEFAULT_GETSOUND_TIMEOUT = 1.0;
30 
31 #ifdef DEBUG_TIME_SPENT
32 double last_time;
33 #endif
34 }
35 
36 
38  PeriodicThread(DEFAULT_THREAD_PERIOD),
39  m_mic(nullptr),
40  m_period(DEFAULT_THREAD_PERIOD),
41  m_min_number_of_samples_over_network(DEFAULT_MIN_NUMBER_OF_SAMPLES_OVER_NETWORK),
42  m_max_number_of_samples_over_network(DEFAULT_MAX_NUMBER_OF_SAMPLES_OVER_NETWORK),
43  m_getSound_timeout(DEFAULT_GETSOUND_TIMEOUT),
44  m_isDeviceOwned(false)
45 #ifdef DEBUG_TIME_SPENT
46  , last_time(yarp::os::Time::now()),
47 #endif
48 {
49  m_stamp.update();
50 }
51 
53 {
54  if (m_mic != nullptr)
55  {
56  close();
57  }
58 }
59 
61 {
62  if (config.check("period"))
63  {
64  m_period = config.find("period").asFloat64();
65  }
66 
67  if (config.check("subdevice"))
68  {
70  PolyDriverList driverlist;
71  p.fromString(config.toString(), false);
72  p.put("device", config.find("subdevice").asString());
73 
74  if (!m_driver.open(p) || !m_driver.isValid())
75  {
76  yCError(AUDIORECORDERWRAPPER) << "Failed to open subdevice.. check params";
77  return false;
78  }
79 
80  driverlist.push(&m_driver, "1");
81  if (!attachAll(driverlist))
82  {
83  yCError(AUDIORECORDERWRAPPER) << "Failed to open subdevice.. check params";
84  return false;
85  }
86  m_isDeviceOwned = true;
87  }
88 
89  if (m_mic == nullptr)
90  {
91  yCError(AUDIORECORDERWRAPPER, "Failed to open IAudioGrabberSound interface");
92  return false;
93  }
94 
95  // Get parameter samples_over_network
96  if (config.check("min_samples_over_network"))
97  {
98  m_min_number_of_samples_over_network = config.find("min_samples_over_network").asInt64();
99  }
100  if (config.check("max_samples_over_network"))
101  {
102  m_max_number_of_samples_over_network = config.find("max_samples_over_network").asInt64();
103  }
104  yCInfo(AUDIORECORDERWRAPPER) << "Wrapper configured to produce packets with the following size (in samples): " <<
105  m_min_number_of_samples_over_network << " < samples < " << m_max_number_of_samples_over_network;
106 
107 
108  // Get parameter samples_over_network
109  if (config.check("max_samples_timeout"))
110  {
111  m_getSound_timeout = config.find("max_samples_timeout").asFloat64();
112  }
113  yCInfo(AUDIORECORDERWRAPPER) << "Wrapper configured with max_samples_timeout: " << m_getSound_timeout << "s";
114 
115  // Set the streaming port
116  std::string portname = "/audioRecorderWrapper";
117  if (config.check("name"))
118  {
119  portname= config.find("name").asString();
120  }
121  if (m_streamingPort.open(portname + "/audio:o") == false)
122  {
123  yCError(AUDIORECORDERWRAPPER) << "Unable to open port" << portname;
124  return false;
125  }
126 
127  // Set the RPC port
128  if (m_rpcPort.open(portname + "/rpc") == false)
129  {
130  yCError(AUDIORECORDERWRAPPER) << "Unable to open port" << portname + "/rpc";
131  return false;
132  }
133  m_rpcPort.setReader(*this);
134 
135  // Wait a little and then start if requested
136  if (config.check("start")) {
138  m_mic->startRecording();
139  }
140 
141  return true;
142 }
143 
145 {
146  if (m_mic != nullptr)
147  {
148  PeriodicThread::stop();
149  m_mic->stopRecording();
150  m_mic = nullptr;
151 
152  m_streamingPort.interrupt();
153  m_streamingPort.close();
154  m_rpcPort.interrupt();
155  m_rpcPort.close();
156 
157  return true;
158  }
159  return false;
160 }
161 
163 {
164 #ifdef DEBUG_TIME_SPENT
165  double current_time = yarp::os::Time::now();
166  yCDebug(AUDIORECORDERWRAPPER) << current_time - m_last_time;
167  m_last_time = current_time;
168 #endif
169 
170  if (m_mic == nullptr)
171  {
172  yCError(AUDIORECORDERWRAPPER) << "The IAudioGrabberSound interface is not available yet!";
173  return;
174  }
175 
176 #ifdef PRINT_DEBUG_MESSAGES
177  {
178  audio_buffer_size buf_max;
179  audio_buffer_size buf_cur;
180  mic->getRecordingAudioBufferMaxSize(buf_max);
181  mic->getRecordingAudioBufferCurrentSize(buf_cur);
182  yCDebug(AUDIORECORDERWRAPPER) << "BEFORE Buffer status:" << buf_cur.getBytes() << "/" << buf_max.getBytes() << "bytes";
183  }
184 #endif
185 
186  yarp::sig::Sound snd;
187  m_mic->getSound(snd, m_min_number_of_samples_over_network, m_max_number_of_samples_over_network, m_getSound_timeout);
188 
189  if (snd.getSamples() < m_min_number_of_samples_over_network ||
190  snd.getSamples() < m_max_number_of_samples_over_network)
191  {
192  yCWarning(AUDIORECORDERWRAPPER) << "subdevice->getSound() is not producing sounds of the requested size ("
193  << m_min_number_of_samples_over_network << "<"
194  << snd.getSamples() << "<"
195  << m_max_number_of_samples_over_network << ") failed";
196  }
197 
198 #ifdef PRINT_DEBUG_MESSAGES
199  {
200  audio_buffer_size buf_max;
201  audio_buffer_size buf_cur;
202  mic->getRecordingAudioBufferMaxSize(buf_max);
203  mic->getRecordingAudioBufferCurrentSize(buf_cur);
204  yCDebug(AUDIORECORDERWRAPPER) << "AFTER Buffer status:" << buf_cur.getBytes() << "/" << buf_max.getBytes() << "bytes";
205  }
206 #endif
207 #ifdef PRINT_DEBUG_MESSAGES
208  yCDebug(AUDIORECORDERWRAPPER) << "Sound size:" << snd.getSamples()*snd.getChannels()*snd.getBytesPerSample() << " bytes";
209  yCDebug(AUDIORECORDERWRAPPER);
210 #endif
211 
212  //prepare the timestamp
213  m_stamp.update();
214  m_streamingPort.setEnvelope(m_stamp);
215 
216  //check before sending data
217  if (snd.getSamples() == 0)
218  {
219  yCError(AUDIORECORDERWRAPPER) << "Subdevice produced sound of 0 samples!";
220  return;
221  }
222  if (snd.getChannels() == 0)
223  {
224  yCError(AUDIORECORDERWRAPPER) << "Subdevice produced sound of 0 channels!";
225  return;
226  }
227  if (snd.getFrequency() == 0)
228  {
229  yCError(AUDIORECORDERWRAPPER) << "Subdevice produced sound with 0 frequency!";
230  return;
231  }
232 
233  //send data
234  m_streamingPort.write(snd);
235 }
236 
238 {
239  yarp::os::Bottle command;
240  yarp::os::Bottle reply;
241  bool ok = command.read(connection);
242  if (!ok) return false;
243  reply.clear();
244 
245  if (command.get(0).asString()=="start")
246  {
247  m_mic->startRecording();
248  reply.addVocab(VOCAB_OK);
249  }
250  else if (command.get(0).asString() == "stop")
251  {
252  m_mic->stopRecording();
253  reply.addVocab(VOCAB_OK);
254  }
255  else if (command.get(0).asString() == "clear")
256  {
257  m_mic->resetRecordingAudioBuffer();
258  reply.addVocab(VOCAB_OK);
259  }
260  else if (command.get(0).asString() == "help")
261  {
262  reply.addVocab(yarp::os::Vocab::encode("many"));
263  reply.addString("start");
264  reply.addString("stop");
265  reply.addString("clear");
266  }
267  else
268  {
269  yCError(AUDIORECORDERWRAPPER) << "Invalid command";
270  reply.addVocab(VOCAB_ERR);
271  }
272 
273  yarp::os::ConnectionWriter *returnToSender = connection.getWriter();
274  if (returnToSender != nullptr)
275  {
276  reply.write(*returnToSender);
277  }
278  return true;
279 }
280 
282 {
283  if (device2attach.size() != 1)
284  {
285  yCError(AUDIORECORDERWRAPPER, "Cannot attach more than one device");
286  return false;
287  }
288 
289  yarp::dev::PolyDriver * Idevice2attach = device2attach[0]->poly;
290 
291  if (Idevice2attach->isValid())
292  {
293  Idevice2attach->view(m_mic);
294  }
295 
296  if (nullptr == m_mic)
297  {
298  yCError(AUDIORECORDERWRAPPER, "Subdevice passed to attach method is invalid");
299  return false;
300  }
301  attach(m_mic);
302 
303  PeriodicThread::setPeriod(m_period);
304  return PeriodicThread::start();
305 }
306 
308 {
309  if (PeriodicThread::isRunning())
310  {
311  PeriodicThread::stop();
312  }
313  m_mic = nullptr;
314  return true;
315 }
316 
318 {
319  m_mic = igrab;
320 }
321 
323 {
324  if (PeriodicThread::isRunning())
325  {
326  PeriodicThread::stop();
327  }
328  m_mic = nullptr;
329 }
330 
332 {
333  return true;
334 }
335 
337 {
338 /* m_audioInPort.interrupt();
339  m_audioInPort.close();
340  m_rpcPort.interrupt();
341  m_rpcPort.close();
342  m_statusPort.interrupt();
343  m_statusPort.close();*/
344 }
yarp::os::Port::close
void close() override
Stop port activity.
Definition: Port.cpp:357
LogStream.h
std_msgs::Time
yarp::rosmsg::std_msgs::Time Time
Definition: Time.h:24
yarp::os::Bottle
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:73
yarp::os::Property::put
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition: Property.cpp:998
AudioRecorderWrapper::read
bool read(yarp::os::ConnectionReader &connection) override
Read this object from a network connection.
Definition: AudioRecorderWrapper.cpp:237
AudioRecorderWrapper.h
yarp::os::Bottle::clear
void clear()
Empties the bottle of any objects it contains.
Definition: Bottle.cpp:124
yarp::os::Searchable
A base class for nested structures that can be searched.
Definition: Searchable.h:69
yarp::sig::Sound::getFrequency
int getFrequency() const
Get the frequency of the sound (i.e.
Definition: Sound.cpp:221
yCWarning
#define yCWarning(component,...)
Definition: LogComponent.h:146
yarp::sig::Sound::getSamples
size_t getSamples() const
Get the number of samples contained in the sound.
Definition: Sound.cpp:404
yarp::os::Searchable::toString
virtual std::string toString() const =0
Return a standard text representation of the content of the object.
yarp::os::Property::fromString
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
Definition: Property.cpp:1046
yarp::dev::PolyDriverList::size
int size() const
Definition: PolyDriverList.cpp:39
yarp::dev::PolyDriver::isValid
bool isValid() const
Check if device is valid.
Definition: PolyDriver.cpp:199
YARP_LOG_COMPONENT
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:80
AudioRecorderWrapper::attachAll
bool attachAll(const yarp::dev::PolyDriverList &p) override
Attach to a list of objects.
Definition: AudioRecorderWrapper.cpp:281
yarp::dev::DeviceDriver::view
bool view(T *&x)
Get an interface to the device driver.
Definition: DeviceDriver.h:77
yarp::sig::Sound::getChannels
size_t getChannels() const
Get the number of channels of the sound.
Definition: Sound.cpp:409
yarp::os::Port::open
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
Definition: Port.cpp:82
AudioRecorderWrapper::close
bool close() override
Close the DeviceDriver.
Definition: AudioRecorderWrapper.cpp:144
yarp::dev::PolyDriverList
Definition: PolyDriverList.h:22
yarp::dev::IAudioGrabberSound::startRecording
virtual bool startRecording()=0
Start the recording.
yarp::dev::PolyDriver::open
bool open(const std::string &txt)
Construct and configure a device by its common name.
Definition: PolyDriver.cpp:143
yarp::os::Time::now
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition: Time.cpp:124
yarp::dev
An interface for the device drivers.
Definition: audioBufferSizeData.cpp:17
AudioRecorderWrapper::detachAll
bool detachAll() override
Detach the object (you must have first called attach).
Definition: AudioRecorderWrapper.cpp:307
yarp::os::Port::setEnvelope
bool setEnvelope(PortWriter &envelope) override
Set an envelope (e.g., a timestamp) to the next message which will be sent.
Definition: Port.cpp:541
yarp::dev::PolyDriverList::push
void push(PolyDriver *p, const char *k)
Definition: PolyDriverList.cpp:44
yarp::dev::IAudioGrabberSound
Read a YARP-format sound block from a device.
Definition: IAudioGrabberSound.h:26
yarp::os::Bottle::get
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:249
yarp::os::Bottle::write
bool write(ConnectionWriter &writer) const override
Output a representation of the bottle to a network connection.
Definition: Bottle.cpp:233
yarp::os::ConnectionWriter
An interface for writing to a network connection.
Definition: ConnectionWriter.h:40
AudioRecorderWrapper::attach
void attach(yarp::dev::IAudioGrabberSound *igrab)
Definition: AudioRecorderWrapper.cpp:317
yarp::os::SystemClock::delaySystem
static void delaySystem(double seconds)
Definition: SystemClock.cpp:32
yarp::os::Value::asString
virtual std::string asString() const
Get string value.
Definition: Value.cpp:237
yarp::dev::PolyDriver
A container for a device driver.
Definition: PolyDriver.h:27
AudioRecorderWrapper::threadInit
bool threadInit() override
Initialization method.
Definition: AudioRecorderWrapper.cpp:331
yarp::os::Searchable::check
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
yarp::os::Searchable::find
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
yarp::os::Vocab::encode
NetInt32 encode(const std::string &str)
Convert a string into a vocabulary identifier.
Definition: Vocab.cpp:14
AudioRecorderWrapper::~AudioRecorderWrapper
~AudioRecorderWrapper() override
Definition: AudioRecorderWrapper.cpp:52
yarp::os::ConnectionReader::getWriter
virtual ConnectionWriter * getWriter()=0
Gets a way to reply to the message, if possible.
yarp::dev::IAudioGrabberSound::resetRecordingAudioBuffer
virtual bool resetRecordingAudioBuffer()=0
DEBUG_TIME_SPENT
#define DEBUG_TIME_SPENT
Definition: AudioRecorderDeviceBase.cpp:32
yarp::os::Bottle::addString
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition: Bottle.cpp:173
yarp::os::Port::setReader
void setReader(PortReader &reader) override
Set an external reader for port data.
Definition: Port.cpp:505
AudioRecorderWrapper::detach
void detach()
Definition: AudioRecorderWrapper.cpp:322
yarp::os::Bottle::addVocab
void addVocab(int x)
Places a vocabulary item in the bottle, at the end of the list.
Definition: Bottle.cpp:167
VOCAB_ERR
constexpr yarp::conf::vocab32_t VOCAB_ERR
Definition: GenericVocabs.h:20
yarp::os::ConnectionReader
An interface for reading from a network connection.
Definition: ConnectionReader.h:40
yCError
#define yCError(component,...)
Definition: LogComponent.h:157
yarp::os::Port::write
bool write(const PortWriter &writer, const PortWriter *callback=nullptr) const override
Write an object to the port.
Definition: Port.cpp:430
yarp::os::Stamp::update
void update()
Set the timestamp to the current time, and increment the sequence number (wrapping to 0 if the sequen...
Definition: Stamp.cpp:113
AudioRecorderWrapper::open
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
Definition: AudioRecorderWrapper.cpp:60
yCInfo
#define yCInfo(component,...)
Definition: LogComponent.h:135
yCDebug
#define yCDebug(component,...)
Definition: LogComponent.h:112
yarp::sig::Sound
Class for storing sounds.
Definition: Sound.h:28
DEFAULT_THREAD_PERIOD
#define DEFAULT_THREAD_PERIOD
Definition: AnalogWrapper.h:45
yarp::dev::IAudioGrabberSound::getSound
virtual bool 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.
yarp
The main, catch-all namespace for YARP.
Definition: environment.h:18
AudioRecorderWrapper::run
void run() override
Loop function.
Definition: AudioRecorderWrapper.cpp:162
AudioRecorderWrapper::threadRelease
void threadRelease() override
Release method.
Definition: AudioRecorderWrapper.cpp:336
yarp::os::Bottle::read
bool read(ConnectionReader &reader) override
Set the bottle's value based on input from a network connection.
Definition: Bottle.cpp:243
yarp::os::Port::interrupt
void interrupt() override
Interrupt any current reads or writes attached to the port.
Definition: Port.cpp:377
yarp::dev::IAudioGrabberSound::stopRecording
virtual bool stopRecording()=0
Stop the recording.
yarp::sig::Sound::getBytesPerSample
size_t getBytesPerSample() const
Get the number of bytes per sample.
Definition: Sound.cpp:399
AudioRecorderWrapper::AudioRecorderWrapper
AudioRecorderWrapper()
Constructor.
Definition: AudioRecorderWrapper.cpp:37
yarp::os::Value::asFloat64
virtual yarp::conf::float64_t asFloat64() const
Get 64-bit floating point value.
Definition: Value.cpp:225
yarp::os::Value::asInt64
virtual std::int64_t asInt64() const
Get 64-bit integer value.
Definition: Value.cpp:213
VOCAB_OK
constexpr yarp::conf::vocab32_t VOCAB_OK
Definition: GenericVocabs.h:18
yarp::os::Property
A class for storing options and configuration information.
Definition: Property.h:37