YARP
Yet Another Robot Platform
fakeMicrophone.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * All rights reserved.
4  *
5  * This software may be modified and distributed under the terms of the
6  * BSD-3-Clause license. See the accompanying LICENSE file for details.
7  */
8 
9 #include "fakeMicrophone.h"
10 
11 #include <yarp/os/Thread.h>
12 #include <yarp/os/Time.h>
13 #include <yarp/os/Semaphore.h>
14 #include <yarp/os/Stamp.h>
15 #include <yarp/os/LogComponent.h>
16 #include <yarp/os/LogStream.h>
17 
18 #include <mutex>
19 #include <string>
20 
21 
22 using namespace yarp::os;
23 using namespace yarp::dev;
24 using namespace yarp::sig;
25 
26 #define HW_CHANNELS 2
27 #define SAMPLING_RATE 44100
28 #define CHUNK_SIZE 512
29 #define SLEEP_TIME 0.005
30 #define SAMPLES_TO_BE_COPIED 512
31 
32 namespace {
33 YARP_LOG_COMPONENT(FAKEMICROPHONE, "yarp.device.fakeMicrophone")
34 }
35 
36 typedef unsigned short int audio_sample_16t;
37 
40  m_isRecording(false),
41  m_cfg_numSamples(0),
42  m_cfg_numChannels(0),
43  m_cfg_frequency(0),
44  m_cfg_bytesPerSample(0),
45  m_audio_filename("audio.wav"),
46  m_bpnt(0),
47  m_inputBuffer(nullptr),
48  m_getSoundIsNotBlocking(false)
49 {
50 }
51 
53 {
54  close();
55 }
56 
58 {
59  //sets the thread period
60  if(config.check("period"))
61  {
62  double period = config.find("period").asFloat64();
63  setPeriod(period);
64  yCInfo(FAKEMICROPHONE) << "Using chosen period of " << period << " s";
65  }
66  else
67  {
68  yCInfo(FAKEMICROPHONE) << "Using default period of " << DEFAULT_PERIOD << " s";
69  }
70 
71  //sets the filename
72  if (config.check("audio_file"))
73  {
74  m_audio_filename = config.find("audio_file").asString();
75  }
76  else
77  {
78  yCInfo(FAKEMICROPHONE) << "--audio_file option not found. Using default:" << m_audio_filename;
79  }
80 
81  //opens the file
82  bool ret = yarp::sig::file::read(m_audioFile, m_audio_filename.c_str());
83  if (ret == false)
84  {
85  yCError(FAKEMICROPHONE) << "Unable to open file" << m_audio_filename.c_str();
86  return false;
87  }
88 
89  //sets the fake mic configuration equal to the audio file
90  m_cfg_numSamples = m_audioFile.getSamples();
91  m_cfg_numChannels = m_audioFile.getChannels();
92  m_cfg_frequency = m_audioFile.getFrequency();
93  m_cfg_bytesPerSample = m_audioFile.getBytesPerSample();
94  const size_t EXTRA_SPACE = 2;
95  AudioBufferSize buffer_size(m_cfg_numSamples*EXTRA_SPACE, m_cfg_numChannels, m_cfg_bytesPerSample);
96  m_inputBuffer = new yarp::dev::CircularAudioBuffer_16t("fake_mic_buffer", buffer_size);
97 
98  //start the capture thread
99  start();
100  return true;
101 }
102 
104 {
106  if (m_inputBuffer)
107  {
108  delete m_inputBuffer;
109  m_inputBuffer = 0;
110  }
111  return true;
112 }
113 
114 
115 bool fakeMicrophone::threadInit()
116 {
117  return true;
118 }
119 
120 
121 void fakeMicrophone::run()
122 {
123  // when not recording, do nothing
124  if (!m_isRecording)
125  {
126  return;
127  }
128 
129  // Just acquire raw data and put them in the buffer
130  auto p = m_audioFile.getInterleavedAudioRawData();
131  size_t fsize_in_samples = m_audioFile.getSamples();
132 // size_t bps = m_audioFile.getBytesPerSample();
133 
134  //each iteration, which occurs every xxx ms, I copy a bunch of samples in the buffer.
135  //When the pointer reaches the end of the sound (audioFile), just restart from the beginning in an endless loop
136  for (size_t i = 0; i < SAMPLES_TO_BE_COPIED; i++)
137  {
138  if (m_bpnt >= fsize_in_samples)
139  {
140  m_bpnt = 0;
141  }
142  m_inputBuffer->write((unsigned short)(p.at(m_bpnt).get()));
143  m_bpnt++;
144  }
145 #ifdef ADVANCED_DEBUG
146  yCDebug(FAKEMICROPHONE) << "b_pnt" << m_bpnt << "/" << fsize_in_bytes << " bytes";
147 #endif
148 }
149 
151 {
152  std::lock_guard<std::mutex> lock(m_mutex);
153  m_isRecording = true;
154 #ifdef BUFFER_AUTOCLEAR
155  this->m_recDataBuffer->clear();
156 #endif
157  yCInfo(FAKEMICROPHONE) << "Recording started";
158  return true;
159 }
160 
161 
163 {
164  std::lock_guard<std::mutex> lock(m_mutex);
165  m_isRecording = false;
166 #ifdef BUFFER_AUTOCLEAR
167  this->m_recDataBuffer->clear();
168 #endif
169  yCInfo(FAKEMICROPHONE) << "Recording stopped";
170  return true;
171 }
172 
173 
175 {
176  //no lock guard is needed here
177  size = this->m_inputBuffer->getMaxSize();
178  return true;
179 }
180 
181 
183 {
184  //no lock guard is needed here
185  size = this->m_inputBuffer->size();
186  return true;
187 }
188 
189 
191 {
192  std::lock_guard<std::mutex> lock(m_mutex);
193  m_inputBuffer->clear();
194  yCDebug(FAKEMICROPHONE) << "resetRecordingAudioBuffer";
195  return true;
196 }
197 
198 bool fakeMicrophone::getSound(yarp::sig::Sound& sound, size_t min_number_of_samples, size_t max_number_of_samples, double max_samples_timeout_s)
199 {
200  //check for something_to_record
201  {
202 #ifdef AUTOMATIC_REC_START
203  if (m_isRecording == false)
204  {
205  this->startRecording();
206  }
207 #else
208  double debug_time = yarp::os::Time::now();
209  while (m_isRecording == false)
210  {
211  if (yarp::os::Time::now() - debug_time > 5.0)
212  {
213  yCInfo(FAKEMICROPHONE) << "getSound() is currently waiting. Use startRecording() to start the audio stream";
214  debug_time = yarp::os::Time::now();
215  }
217  }
218 #endif
219  }
220 
221  //prevents simultaneous start/stop/reset etc.
222  //std::lock_guard<std::mutex> lock(m_mutex); //This must be used carefully
223 
224  //check on input parameters
225  if (max_number_of_samples < min_number_of_samples)
226  {
227  yCError(FAKEMICROPHONE) << "max_number_of_samples must be greater than min_number_of_samples!";
228  return false;
229  }
230  if (max_number_of_samples > this->m_cfg_numSamples)
231  {
232  yCWarning(FAKEMICROPHONE) << "max_number_of_samples bigger than the internal audio buffer! It will be truncated to:" << this->m_cfg_numSamples;
233  max_number_of_samples = this->m_cfg_numSamples;
234  }
235 
236  //wait until the desired number of samples are obtained
237  size_t buff_size = 0;
238  double start_time = yarp::os::Time::now();
239  double debug_time = yarp::os::Time::now();
240  do
241  {
242  buff_size = m_inputBuffer->size().getSamples();
243  if (buff_size >= max_number_of_samples) { break; }
244  if (buff_size >= min_number_of_samples && yarp::os::Time::now() - start_time > max_samples_timeout_s) { break; }
245  if (m_isRecording == false) { break; }
246 
247  if (yarp::os::Time::now() - debug_time > 1.0)
248  {
249  debug_time = yarp::os::Time::now();
250  yCDebug(FAKEMICROPHONE) << "getSound() Buffer size is " << buff_size << "/" << max_number_of_samples << " after 1s";
251  }
252 
254  }
255  while (true);
256 
257  //prepare the sound data struct
258  size_t samples_to_be_copied = buff_size;
259  if (samples_to_be_copied > max_number_of_samples) samples_to_be_copied = max_number_of_samples;
260  if (sound.getChannels() != this->m_cfg_numChannels && sound.getSamples() != samples_to_be_copied)
261  {
262  sound.resize(samples_to_be_copied, this->m_cfg_numChannels);
263  }
264  sound.setFrequency(this->m_cfg_frequency);
265 
266  //fill the sound data struct, reading samples from the circular buffer
267 #ifdef DEBUG_TIME_SPENT
268  double ct1 = yarp::os::Time::now();
269 #endif
270  for (size_t i = 0; i< samples_to_be_copied; i++)
271  for (size_t j = 0; j<this->m_cfg_numChannels; j++)
272  {
273  int16_t s = (int16_t)(m_inputBuffer->read());
274  sound.set(s, i, j);
275  }
276 
277  auto debug_p = sound.getInterleavedAudioRawData();
278 #ifdef DEBUG_TIME_SPENT
279  double ct2 = yarp::os::Time::now();
280  yCDebug(FAKEMICROPHONE) << ct2 - ct1;
281 #endif
282  return true;
283 }
bool ret
virtual bool getSound(yarp::sig::Sound &sound, size_t min_number_of_samples, size_t max_number_of_samples, double max_samples_timeout_s) override
Get a sound from a device.
virtual bool resetRecordingAudioBuffer() override
virtual bool startRecording() override
Start the recording.
bool close() override
Close the DeviceDriver.
virtual bool getRecordingAudioBufferCurrentSize(yarp::dev::AudioBufferSize &size) override
virtual bool stopRecording() override
Stop the recording.
virtual bool getRecordingAudioBufferMaxSize(yarp::dev::AudioBufferSize &size) override
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
~fakeMicrophone() override
yarp::dev::AudioBufferSize getMaxSize()
An abstraction for a periodic thread.
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...
A base class for nested structures that can be searched.
Definition: Searchable.h:69
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
static void delaySystem(double seconds)
Definition: SystemClock.cpp:32
virtual yarp::conf::float64_t asFloat64() const
Get 64-bit floating point value.
Definition: Value.cpp:225
virtual std::string asString() const
Get string value.
Definition: Value.cpp:237
Class for storing sounds.
Definition: Sound.h:28
void setFrequency(int freq)
Set the frequency of the sound (i.e.
Definition: Sound.cpp:226
size_t getBytesPerSample() const
Get the number of bytes per sample.
Definition: Sound.cpp:399
std::vector< std::reference_wrapper< audio_sample > > getInterleavedAudioRawData() const
Returns a serialized version of the sound, in interleaved format, e.g.
Definition: Sound.cpp:343
size_t getChannels() const
Get the number of channels of the sound.
Definition: Sound.cpp:409
void resize(size_t samples, size_t channels=1)
Set the sound size.
Definition: Sound.cpp:167
int getFrequency() const
Get the frequency of the sound (i.e.
Definition: Sound.cpp:221
void set(audio_sample value, size_t sample, size_t channel=0)
Definition: Sound.cpp:206
size_t getSamples() const
Get the number of samples contained in the sound.
Definition: Sound.cpp:404
#define SAMPLES_TO_BE_COPIED
#define SLEEP_TIME
unsigned short int audio_sample_16t
#define DEFAULT_PERIOD
#define yCInfo(component,...)
Definition: LogComponent.h:135
#define yCError(component,...)
Definition: LogComponent.h:157
#define yCWarning(component,...)
Definition: LogComponent.h:146
#define yCDebug(component,...)
Definition: LogComponent.h:112
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:80
An interface for the device drivers.
yarp::dev::CircularAudioBuffer< unsigned short int > CircularAudioBuffer_16t
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition: Time.cpp:124
An interface to the operating system, including Port based communication.
bool read(ImageOf< PixelRgb > &dest, const std::string &src, image_fileformat format=FORMAT_ANY)
Definition: ImageFile.cpp:656
Signal processing.
Definition: Image.h:25