porcupine/demo/c/pvrecorder/src/pv_recorder.c
Go to the documentation of this file.
1 /*
2  Copyright 2021 Picovoice Inc.
3 
4  You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE"
5  file accompanying this source.
6 
7  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8  an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9  specific language governing permissions and limitations under the License.
10 */
11 
12 #pragma GCC diagnostic push
13 
14 #pragma GCC diagnostic ignored "-Wunused-result"
15 
16 #define MINIAUDIO_IMPLEMENTATION
17 
18 #include "miniaudio.h"
19 
20 #pragma GCC diagnostic pop
21 
22 #include "pv_circular_buffer.h"
23 #include "pv_recorder.h"
24 
25 static const int32_t READ_RETRY_COUNT = 500;
26 static const int32_t READ_SLEEP_MILLI_SECONDS = 2;
27 
28 struct pv_recorder {
32  int32_t frame_length;
33  bool is_started;
36 };
37 
38 static void pv_recorder_ma_callback(ma_device *device, void *output, const void *input, ma_uint32 frame_count) {
39  (void) output;
40 
42 
43  ma_mutex_lock(&object->mutex);
44  pv_circular_buffer_status_t status = pv_circular_buffer_write(object->buffer, input, (int32_t) frame_count);
45  if ((status == PV_CIRCULAR_BUFFER_STATUS_WRITE_OVERFLOW) && (object->log_overflow)) {
46  fprintf(stdout, "Overflow - reader is not reading fast enough.\n");
47  }
48  ma_mutex_unlock(&object->mutex);
49 }
50 
52  int32_t device_index,
53  int32_t frame_length,
54  int32_t buffer_size_msec,
55  bool log_overflow,
56  pv_recorder_t **object) {
57  if (device_index < PV_RECORDER_DEFAULT_DEVICE_INDEX) {
59  }
60  if (frame_length <= 0) {
62  }
63  if (buffer_size_msec <= 0) {
65  }
66  if (!object) {
68  }
69 
70  // capacity = 16kHz * seconds
71  const int32_t capacity = (int32_t) ((16000 * buffer_size_msec) / 1000);
72  if (capacity < frame_length) {
74  }
75 
76  *object = NULL;
77 
78  pv_recorder_t *o = calloc(1, sizeof(pv_recorder_t));
79  if (!o) {
81  }
82 
83  ma_result result = ma_context_init(NULL, 0, NULL, &(o->context));
84  if (result != MA_SUCCESS) {
86  if ((result == MA_NO_BACKEND) || (result == MA_FAILED_TO_INIT_BACKEND)) {
88  } else if (result == MA_OUT_OF_MEMORY) {
90  } else {
92  }
93  }
94 
95  ma_device_config device_config;
97  device_config.capture.format = ma_format_s16;
98  device_config.capture.channels = 1;
100  device_config.dataCallback = pv_recorder_ma_callback;
101  device_config.pUserData = o;
102 
103  if (device_index != PV_RECORDER_DEFAULT_DEVICE_INDEX) {
104  ma_device_info *capture_info = NULL;
105  ma_uint32 count = 0;
106  result = ma_context_get_devices(&(o->context), NULL, NULL, &capture_info, &count);
107  if (result != MA_SUCCESS) {
109  if (result == MA_OUT_OF_MEMORY) {
111  } else {
113  }
114  }
115  if (device_index >= count) {
118  }
119  device_config.capture.pDeviceID = &capture_info[device_index].id;
120  }
121 
122  result = ma_device_init(&(o->context), &device_config, &(o->device));
123  if (result != MA_SUCCESS) {
125  if (result == MA_DEVICE_ALREADY_INITIALIZED) {
127  } else if (result == MA_OUT_OF_MEMORY) {
129  } else {
131  }
132  }
133 
134  result = ma_mutex_init(&(o->mutex));
135  if (result != MA_SUCCESS) {
137  if (result == MA_OUT_OF_MEMORY) {
139  } else {
141  }
142  }
143 
145  capacity,
146  sizeof(int16_t),
147  &(o->buffer));
148 
149  if (status != PV_CIRCULAR_BUFFER_STATUS_SUCCESS) {
152  }
153 
154  o->frame_length = frame_length;
155  o->log_overflow = log_overflow;
156 
157  *object = o;
158 
160 }
161 
163  if (object) {
164  ma_device_uninit(&(object->device));
165  ma_context_uninit(&(object->context));
166  ma_mutex_uninit(&(object->mutex));
168  free(object);
169  }
170 }
171 
173  if (!object) {
175  }
176 
177  ma_result result = ma_device_start(&(object->device));
178  if (result != MA_SUCCESS) {
179  if (result == MA_DEVICE_NOT_INITIALIZED) {
181  } else {
182  // device already started
184  }
185  }
186 
187  object->is_started = true;
188 
190 }
191 
193  if (!object) {
195  }
196 
197  ma_result result = ma_device_stop(&(object->device));
198  if (result != MA_SUCCESS) {
199  if (result == MA_DEVICE_NOT_INITIALIZED) {
201  } else {
202  // device already stopped
204  }
205  }
206 
208  object->is_started = false;
209 
211 }
212 
214  if (!object) {
216  }
217  if (!pcm) {
219  }
220  if (!(object->is_started)) {
222  }
223 
224  int16_t *read_ptr = pcm;
225  int32_t processed = 0;
226  int32_t remaining = object->frame_length;
227 
228  for (int32_t i = 0; i < READ_RETRY_COUNT; i++) {
229  ma_mutex_lock(&object->mutex);
230 
231  const int32_t length = pv_circular_buffer_read(object->buffer, read_ptr, remaining);
232  processed += length;
233 
234  if (processed == object->frame_length) {
235  ma_mutex_unlock(&object->mutex);
237  }
238 
239  ma_mutex_unlock(&object->mutex);
241 
242  read_ptr += length;
243  remaining = object->frame_length - processed;
244  }
245 
247 }
248 
250  if (!object) {
251  return NULL;
252  }
253  return object->device.capture.name;
254 }
255 
257  if (!count) {
259  }
260  if (!devices) {
262  }
263 
265  ma_result result = ma_context_init(NULL, 0, NULL, &context);
266  if (result != MA_SUCCESS) {
267  if ((result == MA_NO_BACKEND) || (result == MA_FAILED_TO_INIT_BACKEND)) {
269  } else if (result == MA_OUT_OF_MEMORY) {
271  } else {
273  }
274  }
275 
276  ma_device_info *capture_info;
277  ma_uint32 capture_count;
278  result = ma_context_get_devices(&context, NULL, NULL, &capture_info, &capture_count);
279  if (result != MA_SUCCESS) {
281  if (result == MA_OUT_OF_MEMORY) {
283  } else {
285  }
286  }
287 
288  char **d = calloc(capture_count, sizeof(char *));
289  if (!d) {
292  }
293 
294  for (int32_t i = 0; i < (int32_t) capture_count; i++) {
295  d[i] = strdup(capture_info[i].name);
296  if (!d[i]) {
297  for (int32_t j = i - 1; j >= 0; j--) {
298  free(d[j]);
299  }
300  free(d);
303  }
304  }
305 
307 
308  *count = (int32_t) capture_count;
309  *devices = d;
310 
312 }
313 
314 PV_API void pv_recorder_free_device_list(int32_t count, char **devices) {
315  if (devices && (count > 0)) {
316  for (int32_t i = 0; i < count; i++) {
317  free(devices[i]);
318  }
319  free(devices);
320  }
321 }
322 
324  static const char *const STRINGS[] = {
325  "SUCCESS",
326  "OUT_OF_MEMORY",
327  "INVALID_ARGUMENT",
328  "INVALID_STATE",
329  "BACKEND_ERROR",
330  "DEVICE_INITIALIZED",
331  "DEVICE_NOT_INITIALIZED",
332  "IO_ERROR",
333  "RUNTIME_ERROR"};
334 
335  int32_t size = sizeof(STRINGS) / sizeof(STRINGS[0]);
336  if (status < PV_RECORDER_STATUS_SUCCESS || status >= (PV_RECORDER_STATUS_SUCCESS + size)) {
337  return NULL;
338  }
339 
340  return STRINGS[status - PV_RECORDER_STATUS_SUCCESS];
341 }
342 
343 PV_API const char *pv_recorder_version(void) {
344  return "v1.0.0";
345 }
PV_RECORDER_STATUS_OUT_OF_MEMORY
@ PV_RECORDER_STATUS_OUT_OF_MEMORY
Definition: porcupine/demo/c/pvrecorder/include/pv_recorder.h:33
PV_CIRCULAR_BUFFER_STATUS_WRITE_OVERFLOW
@ PV_CIRCULAR_BUFFER_STATUS_WRITE_OVERFLOW
Definition: porcupine/demo/c/pvrecorder/include/pv_circular_buffer.h:30
ma_device_config::pDeviceID
ma_device_id * pDeviceID
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3127
pv_circular_buffer_read
int32_t pv_circular_buffer_read(pv_circular_buffer_t *object, void *buffer, int32_t length)
Definition: porcupine/demo/c/pvrecorder/src/pv_circular_buffer.c:68
MA_FAILED_TO_INIT_BACKEND
#define MA_FAILED_TO_INIT_BACKEND
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1730
ma_device_uninit
void ma_device_uninit(ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27425
READ_SLEEP_MILLI_SECONDS
static const int32_t READ_SLEEP_MILLI_SECONDS
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:26
ma_device_start
ma_result ma_device_start(ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27485
context
ma_context context
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/tests/test_deviceio/ma_test_deviceio.c:56
NULL
#define NULL
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/resample.c:92
ma_device_type_capture
@ ma_device_type_capture
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3013
pv_circular_buffer_status_t
pv_circular_buffer_status_t
Definition: porcupine/demo/c/pvrecorder/include/pv_circular_buffer.h:26
pv_recorder_stop
PV_API pv_recorder_status_t pv_recorder_stop(pv_recorder_t *object)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:192
ma_device_stop
ma_result ma_device_stop(ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27544
pv_recorder::log_overflow
bool log_overflow
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:34
pv_recorder::device
ma_device device
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:30
pv_recorder_start
PV_API pv_recorder_status_t pv_recorder_start(pv_recorder_t *object)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:172
PV_CIRCULAR_BUFFER_STATUS_SUCCESS
@ PV_CIRCULAR_BUFFER_STATUS_SUCCESS
Definition: porcupine/demo/c/pvrecorder/include/pv_circular_buffer.h:27
ma_device_config::dataCallback
ma_device_callback_proc dataCallback
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3110
PV_RECORDER_STATUS_IO_ERROR
@ PV_RECORDER_STATUS_IO_ERROR
Definition: porcupine/demo/c/pvrecorder/include/pv_recorder.h:39
PV_RECORDER_STATUS_INVALID_ARGUMENT
@ PV_RECORDER_STATUS_INVALID_ARGUMENT
Definition: porcupine/demo/c/pvrecorder/include/pv_recorder.h:34
device
ma_device device
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/tests/test_deviceio/ma_test_deviceio.c:57
pv_circular_buffer_delete
void pv_circular_buffer_delete(pv_circular_buffer_t *object)
Definition: porcupine/demo/c/pvrecorder/src/pv_circular_buffer.c:61
pv_recorder_ma_callback
static void pv_recorder_ma_callback(ma_device *device, void *output, const void *input, ma_uint32 frame_count)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:38
ma_device_config::capture
struct ma_device_config::@98 capture
python.setup.name
name
Definition: porcupine/binding/python/setup.py:69
pv_recorder_status_t
pv_recorder_status_t
Definition: porcupine/demo/c/pvrecorder/include/pv_recorder.h:31
ma_context_uninit
ma_result ma_context_uninit(ma_context *pContext)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26757
ma_result
int ma_result
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1658
pv_recorder_get_selected_device
const PV_API char * pv_recorder_get_selected_device(pv_recorder_t *object)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:249
ma_device_info::id
ma_device_id id
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3076
MA_DEVICE_NOT_INITIALIZED
#define MA_DEVICE_NOT_INITIALIZED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1724
ma_mutex_uninit
void ma_mutex_uninit(ma_mutex *pMutex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4784
pv_recorder::is_started
bool is_started
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:33
PV_RECORDER_DEFAULT_DEVICE_INDEX
#define PV_RECORDER_DEFAULT_DEVICE_INDEX
Definition: porcupine/demo/c/pvrecorder/include/pv_recorder.h:20
count
size_t count
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/tests/test_common/ma_test_common.c:31
pv_circular_buffer_init
pv_circular_buffer_status_t pv_circular_buffer_init(int32_t capacity, int32_t element_size, pv_circular_buffer_t **object)
Definition: porcupine/demo/c/pvrecorder/src/pv_circular_buffer.c:26
pv_circular_buffer
Definition: porcupine/demo/c/pvrecorder/src/pv_circular_buffer.c:17
pv_recorder::mutex
ma_mutex mutex
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:35
ma_format_s16
@ ma_format_s16
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1787
pv_recorder
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:28
ma_device_info
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3073
ma_device::pUserData
void * pUserData
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3592
d
d
MA_DEVICE_ALREADY_INITIALIZED
#define MA_DEVICE_ALREADY_INITIALIZED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1725
ma_mutex_init
ma_result ma_mutex_init(ma_context *pContext, ma_mutex *pMutex)
pv_recorder_init
PV_API pv_recorder_status_t pv_recorder_init(int32_t device_index, int32_t frame_length, int32_t buffer_size_msec, bool log_overflow, pv_recorder_t **object)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:51
MA_NO_BACKEND
#define MA_NO_BACKEND
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1718
ma_context_get_devices
ma_result ma_context_get_devices(ma_context *pContext, ma_device_info **ppPlaybackDeviceInfos, ma_uint32 *pPlaybackDeviceCount, ma_device_info **ppCaptureDeviceInfos, ma_uint32 *pCaptureDeviceCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26866
pv_recorder_status_to_string
const PV_API char * pv_recorder_status_to_string(pv_recorder_status_t status)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:323
pv_recorder_version
const PV_API char * pv_recorder_version(void)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:343
ma_uint32
uint32_t ma_uint32
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1503
ma_device_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3128
PV_RECORDER_STATUS_DEVICE_ALREADY_INITIALIZED
@ PV_RECORDER_STATUS_DEVICE_ALREADY_INITIALIZED
Definition: porcupine/demo/c/pvrecorder/include/pv_recorder.h:37
ma_device_config_init
ma_device_config ma_device_config_init(ma_device_type deviceType)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27034
pv_recorder_free_device_list
PV_API void pv_recorder_free_device_list(int32_t count, char **devices)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:314
ma_mutex
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2846
ma_device_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3129
pv_recorder_delete
PV_API void pv_recorder_delete(pv_recorder_t *object)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:162
pv_recorder_read
PV_API pv_recorder_status_t pv_recorder_read(pv_recorder_t *object, int16_t *pcm)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:213
READ_RETRY_COUNT
static const int32_t READ_RETRY_COUNT
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:25
ma_mutex_unlock
void ma_mutex_unlock(ma_mutex *pMutex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4813
pv_circular_buffer_reset
void pv_circular_buffer_reset(pv_circular_buffer_t *object)
Definition: porcupine/demo/c/pvrecorder/src/pv_circular_buffer.c:152
PV_API
#define PV_API
Definition: porcupine/demo/c/pvrecorder/include/pv_recorder.h:18
pv_recorder_get_audio_devices
PV_API pv_recorder_status_t pv_recorder_get_audio_devices(int32_t *count, char ***devices)
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:256
ma_context
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3210
pv_recorder::buffer
pv_circular_buffer_t * buffer
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:31
ma_device_init
ma_result ma_device_init(ma_context *pContext, const ma_device_config *pConfig, ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27048
ma_device
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3584
pv_recorder::frame_length
int32_t frame_length
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:32
ma_device_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3100
ma_device_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3103
ma_mutex_lock
void ma_mutex_lock(ma_mutex *pMutex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4798
PV_RECORDER_STATUS_DEVICE_NOT_INITIALIZED
@ PV_RECORDER_STATUS_DEVICE_NOT_INITIALIZED
Definition: porcupine/demo/c/pvrecorder/include/pv_recorder.h:38
PV_RECORDER_STATUS_RUNTIME_ERROR
@ PV_RECORDER_STATUS_RUNTIME_ERROR
Definition: porcupine/demo/c/pvrecorder/include/pv_recorder.h:40
ma_context_init
ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config *pConfig, ma_context *pContext)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26550
MA_SUCCESS
#define MA_SUCCESS
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1659
ma_standard_sample_rate_16000
@ ma_standard_sample_rate_16000
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:424
pv_recorder::context
ma_context context
Definition: porcupine/demo/c/pvrecorder/src/pv_recorder.c:29
PV_RECORDER_STATUS_BACKEND_ERROR
@ PV_RECORDER_STATUS_BACKEND_ERROR
Definition: porcupine/demo/c/pvrecorder/include/pv_recorder.h:36
PV_RECORDER_STATUS_SUCCESS
@ PV_RECORDER_STATUS_SUCCESS
Definition: porcupine/demo/c/pvrecorder/include/pv_recorder.h:32
ma_sleep
static void ma_sleep(ma_uint32 milliseconds)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:522
PV_RECORDER_STATUS_INVALID_STATE
@ PV_RECORDER_STATUS_INVALID_STATE
Definition: porcupine/demo/c/pvrecorder/include/pv_recorder.h:35
pv_circular_buffer_write
pv_circular_buffer_status_t pv_circular_buffer_write(pv_circular_buffer_t *object, const void *buffer, int32_t length)
Definition: porcupine/demo/c/pvrecorder/src/pv_circular_buffer.c:108
ma_device_config::pUserData
void * pUserData
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3112
MA_OUT_OF_MEMORY
#define MA_OUT_OF_MEMORY
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1663


picovoice_driver
Author(s):
autogenerated on Fri Apr 1 2022 02:14:50