YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
PortAudioRecorderDeviceDriver.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
8#include <cstdio>
9#include <cstdlib>
10#include <cstring>
11#include <yarp/dev/api.h>
12
13#include <yarp/os/Time.h>
15#include <yarp/os/LogStream.h>
16
17using namespace yarp::os;
18using namespace yarp::dev;
19
20#define SLEEP_TIME 0.005f
21
22#if 0
23#define PA_SAMPLE_TYPE paFloat32
24typedef float SAMPLE;
25#define SAMPLE_SILENCE (0.0f)
26#elif 1
27#define PA_SAMPLE_TYPE paInt16
28typedef short SAMPLE;
29#define SAMPLE_SILENCE (0)
30#elif 1
31#define PA_SAMPLE_TYPE paInt8
32typedef char SAMPLE;
33#define SAMPLE_SILENCE (0)
34#else
35#define PA_SAMPLE_TYPE paUInt8
36typedef unsigned char SAMPLE;
37#define SAMPLE_SILENCE (128)
38#define SAMPLE_UNSIGNED
39#endif
40
41namespace {
42YARP_LOG_COMPONENT(PORTAUDIORECORDER, "yarp.devices.portaudioRecorder")
43}
44
45#define DEFAULT_FRAMES_PER_BUFFER (512)
46
47/* This routine will be called by the PortAudio engine when audio is needed.
48** It may be called at interrupt level on some machines so don't do anything
49** that could mess up the system like calling malloc() or free().
50*/
51static int bufferIOCallback( const void *inputBuffer, void *outputBuffer,
52 unsigned long framesPerBuffer,
55 void *userData )
56{
58 size_t num_rec_channels = recdata->getMaxSize().getChannels();
59 int finished = paComplete;
60
61 if (1)
62 {
63 const auto* rptr = (const SAMPLE*)inputBuffer;
64 size_t framesToCalc;
65 size_t framesLeft = (recdata->getMaxSize().getSamples()* recdata->getMaxSize().getChannels()) -
66 (recdata->size().getSamples() * recdata->size().getChannels());
67
68 YARP_UNUSED(outputBuffer); // just to prevent unused variable warnings
72
74 {
76#ifdef STOP_REC_ON_EMPTY_BUFFER
77 //if we return paComplete, then the callback is not called anymore.
78 //method Pa_IsStreamActive() will return 1.
79 //user needs to call Pa_StopStream() before starting a new recording session
80 finished = paComplete;
81#else
82 finished = paContinue;
83#endif
84 }
85 else
86 {
88 //if we return paContinue, then the callback will be invoked again later
89 //method Pa_IsStreamActive() will return 0
90 finished = paContinue;
91 }
92
93 if( inputBuffer == nullptr )
94 {
95 for( size_t i=0; i<framesToCalc; i++ )
96 {
97 for (size_t j=0; j < num_rec_channels; j++)
98 {
99 recdata->write(0);
100 }
101 }
102 }
103 else
104 {
105 for( size_t i=0; i<framesToCalc; i++ )
106 {
107 for (size_t j = 0; j < num_rec_channels; j++)
108 {
109 recdata->write(*rptr++);
110 }
111 }
112 }
113 return finished;
114 }
115
116 yCError(PORTAUDIORECORDER, "No write operations requested, aborting");
117 return paAbort;
118}
119
121 m_stream(nullptr),
122 m_err(paNoError),
123 m_system_resource(nullptr)
124{
125 memset(&m_inputParameters, 0, sizeof(PaStreamParameters));
126}
127
132
133
135{
136 bool b = parseParams(config);
137 if (!b) { return false; }
138
139 b = configureRecorderAudioDevice(config.findGroup("AUDIO_BASE"),"portaudioRecorder");
140 if (!b) { return false; }
141
142 m_err = Pa_Initialize();
143 if(m_err != paNoError )
144 {
145 yCError(PORTAUDIORECORDER, "portaudio system failed to initialize");
146 return false;
147 }
148
149 m_inputParameters.device = (m_audio_device_id == -1) ? Pa_GetDefaultInputDevice() : m_audio_device_id;
150 m_inputParameters.channelCount = static_cast<int>(m_audiorecorder_cfg.numChannels);
151 m_inputParameters.sampleFormat = PA_SAMPLE_TYPE;
152 m_inputParameters.hostApiSpecificStreamInfo = nullptr;
153
154 const PaDeviceInfo* devinfo = Pa_GetDeviceInfo(m_inputParameters.device);
155 std::string devname = "unknown";
156 if (devinfo != nullptr)
157 {
158 m_inputParameters.suggestedLatency = devinfo->defaultLowInputLatency;
159 devname = devinfo->name;
160 }
161 yCInfo(PORTAUDIORECORDER, "Selected device: number: %d, name: %s", m_inputParameters.device, devname.c_str());
162
163 m_err = Pa_OpenStream(
164 &m_stream,
165 &m_inputParameters,
166 nullptr,
169 paClipOff,
172
173 if(m_err != paNoError )
174 {
175 yCError(PORTAUDIORECORDER, "An error occurred while using the portaudio stream" );
176 yCError(PORTAUDIORECORDER, "Error number: %d", m_err );
177 yCError(PORTAUDIORECORDER, "Error message: %s", Pa_GetErrorText(m_err ) );
178 }
179
180 //start the thread
181 bool ret = this->start();
182 YARP_UNUSED(ret);
183
184 return (m_err==paNoError);
185}
186
188{
189 //Pa_Terminate();
191
192 if(m_err != paNoError )
193 {
194 yCError(PORTAUDIORECORDER, "An error occurred while using the portaudio stream" );
195 yCError(PORTAUDIORECORDER, "Error number: %d", m_err );
196 yCError(PORTAUDIORECORDER, "Error message: %s", Pa_GetErrorText(m_err ) );
197 }
198}
199
201{
202 this->stop();
203 if (m_stream != nullptr)
204 {
205 m_err = Pa_CloseStream(m_stream );
206 if(m_err != paNoError )
207 {
208 yCError(PORTAUDIORECORDER, "An error occurred while closing the portaudio stream" );
209 yCError(PORTAUDIORECORDER, "Error number: %d", m_err );
210 yCError(PORTAUDIORECORDER, "Error message: %s", Pa_GetErrorText(m_err ) );
211 }
212 }
213
214 if (this->m_inputBuffer != nullptr)
215 {
216 delete this->m_inputBuffer;
217 this->m_inputBuffer = nullptr;
218 }
219
220 return (m_err==paNoError);
221}
222
224{
226 m_err = Pa_StartStream(m_stream );
227 if(m_err < 0 ) {handleError(); return ReturnValue::return_code::return_value_error_method_failed;}
228 yCInfo(PORTAUDIORECORDER) << "started recording";
229 return ReturnValue_ok;
230}
231
233{
234 yCInfo(PORTAUDIORECORDER) << "not yet implemented recording";
235 return ReturnValue::return_code::return_value_error_not_implemented_by_device;
236}
237
239{
241 m_err = Pa_StopStream(m_stream );
242 if(m_err < 0 ) {handleError(); return ReturnValue::return_code::return_value_error_method_failed;}
243 yCInfo(PORTAUDIORECORDER) << "stopped recording";
244 return ReturnValue_ok;
245}
246
250
252{
253 return true;
254}
255
257{
258 while(this->isStopping()==false)
259 {
260 //The status of the buffer (i.e. the return value of Pa_IsStreamActive() depends on the returned value
261 //of the callback function bufferIOCallback() which may return paContinue or paComplete.
263 {
264 m_err = Pa_IsStreamActive(m_stream);
265 if (m_err < 0)
266 {
267 handleError();
268 yCError(PORTAUDIORECORDER) << "Unhandled error. Calling abortSound()";
269 //abortSound();
270 continue;
271 }
272 if (m_err == 1)
273 {
274 //already doing something
275 }
276 else if (m_err == 0)
277 {
278 //the recording is stopped
279 }
280 }
281
283 }
284 return;
285}
bool ret
#define PA_SAMPLE_TYPE
static int bufferIOCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
#define SLEEP_TIME
static int bufferIOCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
#define ReturnValue_ok
Definition ReturnValue.h:77
bool parseParams(const yarp::os::Searchable &config) override
Parse the DeviceDriver parameters.
yarp::dev::ReturnValue setHWGain(double gain) override
Sets the hardware gain of the grabbing device (if supported by the hardware)
void run() override
Main body of the new thread.
bool threadInit() override
Initialization method.
yarp::dev::ReturnValue stopRecording() override
Stop the recording.
void threadRelease() override
Release method.
bool close() override
Close the DeviceDriver.
yarp::dev::ReturnValue startRecording() override
Start the recording.
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
yarp::dev::CircularAudioBuffer_16t * m_inputBuffer
virtual yarp::dev::ReturnValue startRecording() override
Start the recording.
virtual yarp::dev::ReturnValue stopRecording() override
Stop the recording.
bool configureRecorderAudioDevice(yarp::os::Searchable &config, std::string device_name)
AudioDeviceDriverSettings m_audiorecorder_cfg
A mini-server for performing network communication in the background.
void write(bool forceStrict=false)
Write the current object being returned by BufferedPort::prepare.
A base class for nested structures that can be searched.
Definition Searchable.h:31
virtual Bottle & findGroup(const std::string &key) const =0
Gets a list corresponding to a given keyword.
bool stop()
Stop the thread.
Definition Thread.cpp:81
bool isStopping()
Returns true if the thread is stopping (Thread::stop has been called).
Definition Thread.cpp:99
bool start()
Start the new thread running.
Definition Thread.cpp:93
#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.
Definition jointData.cpp:13
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.
#define YARP_UNUSED(var)
Definition api.h:162