GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/audiosources.c
Date: 2025-09-22 22:57:09
Exec Total Coverage
Lines: 0 586 0.0%
Functions: 0 42 0.0%
Branches: 0 294 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28 #include "gate/io/audiosources.h"
29 #include "gate/results.h"
30 #include "gate/queues.h"
31 #include "gate/threading.h"
32 #include "gate/synchronization.h"
33 #include "gate/serializers.h"
34 #include "gate/mathematics.h"
35 #include "gate/libraries.h"
36 #include "gate/debugging.h"
37
38 #if defined(GATE_SYS_WIN16)
39 # define GATE_IO_AUDIO_NO_IMPL 1
40 #elif defined(GATE_SYS_WIN)
41 # if defined(GATE_SYS_WINSTORE)
42 # define GATE_IO_AUDIO_NO_IMPL 1
43 # else
44 # define GATE_IO_AUDIO_WINAPI 1
45 # endif
46 #elif defined(GATE_SYS_LINUX) && !defined(GATE_SYS_ANDROID)
47 # define GATE_IO_AUDIO_ALSA 1
48 #else
49 # define GATE_IO_AUDIO_NO_IMPL 1
50 #endif
51
52 #if !defined(GATE_IO_AUDIO_NO_IMPL)
53
54 static void gate_audio_device_impl_release(void* device);
55 static int gate_audio_device_impl_retain(void* device);
56 static char const* gate_audio_device_impl_get_interface_name(void* device);
57
58 static char const* gate_audio_device_impl_get_id(void* device);
59 static char const* gate_audio_device_impl_get_name(void* device);
60 static gate_intptr_t gate_audio_device_impl_get_handle(void* device);
61 static gate_enumint_t gate_audio_device_impl_get_device_type(void* device);
62 static gate_size_t gate_audio_device_impl_get_supported_formats(void* device, gate_audio_format_t* format_buffer, gate_size_t format_buffer_count);
63
64 static gate_result_t gate_audio_device_impl_open(void* device, gate_audio_format_t const* format, gate_size_t sample_count);
65 static gate_result_t gate_audio_device_impl_close(void* device);
66
67 static gate_result_t gate_audio_device_impl_read(void* device, gate_audio_sample_t* sample);
68 static gate_result_t gate_audio_device_impl_read_async(void* device, gate_delegate_t const* completion);
69 static gate_result_t gate_audio_device_impl_write(void* device, gate_audio_sample_t const* sample);
70 static gate_result_t gate_audio_device_impl_write_async(void* device, gate_audio_sample_t const* sample, gate_delegate_t const* completion);
71
72 static GATE_INTERFACE_VTBL(gate_audio_device) gate_audio_device_vtbl_impl;
73 ✗ static void gate_init_audio_device_vtbl_impl()
74 {
75 ✗ if (!gate_audio_device_vtbl_impl.get_interface_name)
76 {
77 GATE_INTERFACE_VTBL(gate_audio_device) const local_vtbl =
78 {
79 &gate_audio_device_impl_get_interface_name,
80 &gate_audio_device_impl_release,
81 &gate_audio_device_impl_retain,
82
83 &gate_audio_device_impl_get_id,
84 &gate_audio_device_impl_get_name,
85 &gate_audio_device_impl_get_handle,
86 &gate_audio_device_impl_get_device_type,
87 &gate_audio_device_impl_get_supported_formats,
88
89 &gate_audio_device_impl_open,
90 &gate_audio_device_impl_close,
91
92 &gate_audio_device_impl_read,
93 &gate_audio_device_impl_read_async,
94 &gate_audio_device_impl_write,
95 &gate_audio_device_impl_write_async
96 };
97 ✗ gate_audio_device_vtbl_impl = local_vtbl;
98 }
99 ✗ }
100
101 ✗ static char const* gate_audio_device_impl_get_interface_name(void* device)
102 {
103 GATE_UNUSED_ARG(device);
104 ✗ return GATE_INTERFACE_NAME_AUDIO_DEVICE;
105 }
106
107 #endif /* !defined(GATE_IO_AUDIO_NO_IMPL) */
108
109
110 ✗ gate_audio_sample_t* gate_audio_sample_create(
111 gate_audio_sample_t* new_sample,
112 gate_audio_format_t const* format,
113 void const* data, gate_size_t data_size,
114 void const* meta_data, gate_size_t meta_data_size,
115 gate_uint32_t sample_count,
116 gate_int64_t record_time)
117 {
118 ✗ gate_audio_sample_t* ret = NULL;
119 ✗ if (new_sample != NULL)
120 {
121 ✗ gate_mem_clear(new_sample, sizeof(gate_audio_sample_t));
122 do
123 {
124 ✗ gate_mem_copy(&new_sample->format, format, sizeof(gate_audio_format_t));
125
126 ✗ new_sample->sample_count = sample_count;
127 ✗ new_sample->record_time = record_time;
128
129 ✗ if (data_size != 0)
130 {
131 ✗ new_sample->data = gate_memoryblock_create(data_size);
132 ✗ if (new_sample->data == NULL)
133 {
134 // failed
135 ✗ break;
136 }
137 ✗ if (data != NULL)
138 {
139 ✗ gate_mem_copy(gate_memoryblock_get_content(new_sample->data), data, data_size);
140 }
141 }
142
143 ✗ if (meta_data_size != 0)
144 {
145 ✗ new_sample->meta_data = gate_memoryblock_create(meta_data_size);
146 ✗ if (new_sample->meta_data == NULL)
147 {
148 // failed
149 ✗ break;
150 }
151 ✗ if (meta_data != NULL)
152 {
153 ✗ gate_mem_copy(gate_memoryblock_get_content(new_sample->meta_data), meta_data, meta_data_size);
154 }
155 }
156
157 ✗ ret = new_sample;
158 } while (0);
159
160 ✗ if (ret == NULL)
161 {
162 // release resources, if something has failed
163 ✗ if (new_sample->data != NULL)
164 {
165 ✗ gate_object_release(new_sample->data);
166 ✗ new_sample->data = NULL;
167 }
168
169 ✗ if (new_sample->meta_data != NULL)
170 {
171 ✗ gate_object_release(new_sample->meta_data);
172 ✗ new_sample->meta_data = NULL;
173 }
174 }
175 }
176 ✗ return ret;
177 }
178
179
180 ✗ void gate_audio_sample_release(gate_audio_sample_t* sample)
181 {
182 ✗ if (sample != NULL)
183 {
184 ✗ if (sample->data != NULL)
185 {
186 ✗ gate_object_release(sample->data);
187 }
188 ✗ if (sample->meta_data != NULL)
189 {
190 ✗ gate_object_release(sample->meta_data);
191 }
192
193 ✗ gate_mem_clear(sample, sizeof(gate_audio_sample_t));
194 }
195 ✗ }
196
197 ✗ int gate_compare_audio_format(void const* item1, void const* item2)
198 {
199 ✗ gate_audio_format_t const* format1 = (gate_audio_format_t const*)item1;
200 ✗ gate_audio_format_t const* format2 = (gate_audio_format_t const*)item2;
201 ✗ if (format1->bits_per_sample < format2->bits_per_sample) return -1;
202 ✗ if (format1->bits_per_sample > format2->bits_per_sample) return 1;
203 ✗ if (format1->channels < format2->channels) return -1;
204 ✗ if (format1->channels > format2->channels) return 1;
205 ✗ if (format1->bits_per_sample < format2->bits_per_sample) return -1;
206 ✗ if (format1->bits_per_sample > format2->bits_per_sample) return 1;
207 ✗ if (format1->encoding_id < format2->encoding_id) return -1;
208 ✗ if (format1->encoding_id > format2->encoding_id) return 1;
209 ✗ return 0;
210 }
211
212 ✗ gate_audio_format_t const* gate_audio_format_choose(gate_audio_format_t const* formats, gate_size_t formats_count,
213 gate_uint32_t const* desired_samples_per_second,
214 gate_uint16_t const* desired_channels,
215 gate_uint16_t const* desired_bits_per_sample)
216 {
217 ✗ gate_audio_format_t const* ret = NULL;
218 gate_uint32_t scores[1024]; /* smaller is better */
219 gate_uint32_t qualities[1024]; /* greater is better */
220 gate_size_t index;
221 gate_audio_format_t const* format;
222 ✗ gate_uint32_t best_score = 0xffffffff;
223 ✗ gate_uint32_t best_quality = 0;
224 gate_int32_t diff;
225
226 ✗ if (formats_count > 1024) formats_count = 1024;
227 ✗ for (index = 0; index != formats_count; ++index)
228 {
229 ✗ format = &formats[index];
230 ✗ scores[index] = 0;
231 ✗ if (desired_samples_per_second != NULL)
232 {
233 ✗ diff = (gate_int32_t)*desired_samples_per_second - (gate_int32_t)format->samples_per_second;
234 ✗ scores[index] += (gate_uint32_t)gate_math_abs_i32(diff);
235 }
236 ✗ if (desired_channels != NULL)
237 {
238 ✗ diff = (gate_int32_t)*desired_channels - (gate_int32_t)format->channels;
239 ✗ scores[index] += (gate_uint32_t)gate_math_abs_i32(diff) * 100;
240 }
241 ✗ if (desired_bits_per_sample != NULL)
242 {
243 ✗ diff = (gate_int32_t)*desired_bits_per_sample - (gate_int32_t)format->bits_per_sample;
244 ✗ scores[index] += (gate_uint32_t)gate_math_abs_i32(diff);
245 }
246 ✗ qualities[index] = format->bits_per_sample * format->channels * format->samples_per_second;
247 }
248 ✗ for (index = 0; index != formats_count; ++index)
249 {
250 ✗ if (scores[index] < best_score ||
251 ✗ ((scores[index] == best_score) && (qualities[index] > best_quality))
252 )
253 {
254 ✗ ret = &formats[index];
255 ✗ best_score = scores[index];
256 ✗ best_quality = qualities[index];
257 }
258
259 }
260 ✗ if (ret == NULL)
261 {
262 /* choose best quality */
263 ✗ for (index = 0; index != formats_count; ++index)
264 {
265 ✗ if (qualities[index] > best_quality)
266 {
267 ✗ ret = &formats[index];
268 ✗ best_quality = qualities[index];
269 }
270 }
271 }
272 ✗ return ret;
273 }
274
275
276
277 struct gate_audio_device_by_id_helper
278 {
279 char const* id;
280 gate_audio_device_t* device;
281 };
282
283 ✗ static gate_result_t gate_audio_device_by_id_callback(gate_audio_device_t* device, void* param)
284 {
285 ✗ struct gate_audio_device_by_id_helper* ptr = (struct gate_audio_device_by_id_helper*)param;
286
287 ✗ char const* id = gate_audio_device_get_id(device);
288 ✗ if ((0 == gate_str_comp(id, ptr->id)) && (ptr->device == NULL))
289 {
290 ✗ ptr->device = device;
291 ✗ gate_object_retain(ptr->device);
292 }
293 ✗ return GATE_RESULT_OK;
294 }
295
296 ✗ gate_result_t gate_audio_device_by_id(gate_enumint_t dev_type, char const* id, gate_audio_device_t** ptr_device)
297 {
298 gate_result_t result;
299 struct gate_audio_device_by_id_helper param;
300 gate_delegate_t callback;
301
302 ✗ param.id = id;
303 ✗ param.device = NULL;
304
305 ✗ GATE_DELEGATE_BIND_FUNC(gate_audio_devices_enum, &callback, gate_audio_device_by_id_callback);
306
307 ✗ result = gate_audio_devices_enum(dev_type, &callback, &param);
308
309 ✗ if (GATE_SUCCEEDED(result))
310 {
311 ✗ if (param.device != NULL)
312 {
313 ✗ if (ptr_device != NULL)
314 {
315 /* return device */
316 ✗ *ptr_device = param.device;
317 ✗ param.device = NULL;
318 }
319 }
320 else
321 {
322 ✗ result = GATE_RESULT_NOMATCH;
323 }
324 }
325
326 ✗ if (param.device != NULL)
327 {
328 ✗ gate_object_release(param.device);
329 }
330
331 ✗ return result;
332 }
333
334
335
336 static void gate_audio_device_wave_stream_release(void* device);
337 static int gate_audio_device_wave_stream_retain(void* device);
338 static char const* gate_audio_device_wave_stream_get_interface_name(void* device);
339
340 static char const* gate_audio_device_wave_stream_get_id(void* device);
341 static char const* gate_audio_device_wave_stream_get_name(void* device);
342 static gate_intptr_t gate_audio_device_wave_stream_get_handle(void* device);
343 static gate_enumint_t gate_audio_device_wave_stream_get_device_type(void* device);
344 static gate_size_t gate_audio_device_wave_stream_get_supported_formats(void* device, gate_audio_format_t* format_buffer, gate_size_t format_buffer_count);
345
346 static gate_result_t gate_audio_device_wave_stream_open(void* device, gate_audio_format_t const* format, gate_size_t sample_count);
347 static gate_result_t gate_audio_device_wave_stream_close(void* device);
348
349 static gate_result_t gate_audio_device_wave_stream_read(void* device, gate_audio_sample_t* sample);
350 static gate_result_t gate_audio_device_wave_stream_read_async(void* device, gate_delegate_t const* completion);
351 static gate_result_t gate_audio_device_wave_stream_write(void* device, gate_audio_sample_t const* sample);
352 static gate_result_t gate_audio_device_wave_stream_write_async(void* device, gate_audio_sample_t const* sample, gate_delegate_t const* completion);
353
354 static GATE_INTERFACE_VTBL(gate_audio_device) gate_audio_device_vtbl_wave_stream;
355 ✗ static void gate_init_audio_device_vtbl_wave_stream()
356 {
357 ✗ if (!gate_audio_device_vtbl_wave_stream.get_interface_name)
358 {
359 GATE_INTERFACE_VTBL(gate_audio_device) const local_vtbl =
360 {
361 &gate_audio_device_wave_stream_get_interface_name,
362 &gate_audio_device_wave_stream_release,
363 &gate_audio_device_wave_stream_retain,
364
365 &gate_audio_device_wave_stream_get_id,
366 &gate_audio_device_wave_stream_get_name,
367 &gate_audio_device_wave_stream_get_handle,
368 &gate_audio_device_wave_stream_get_device_type,
369 &gate_audio_device_wave_stream_get_supported_formats,
370
371 &gate_audio_device_wave_stream_open,
372 &gate_audio_device_wave_stream_close,
373
374 &gate_audio_device_wave_stream_read,
375 &gate_audio_device_wave_stream_read_async,
376 &gate_audio_device_wave_stream_write,
377 &gate_audio_device_wave_stream_write_async
378 };
379 ✗ gate_audio_device_vtbl_wave_stream = local_vtbl;
380 }
381 ✗ }
382
383 typedef struct gate_audio_wave_stream_impl
384 {
385 GATE_INTERFACE_VTBL(gate_audio_device) const* vtbl;
386
387 gate_atomic_int_t ref_counter;
388 gate_stream_t* input;
389 gate_controlstream_t* output;
390 gate_bool_t opened;
391 gate_audio_format_t format;
392 gate_atomic_int_t format_defined;
393 gate_uint32_t data_length;
394 gate_int64_t write_start_position;
395 } gate_audio_wave_stream_impl_t;
396
397 ✗ static void gate_audio_device_wave_stream_release(void* device)
398 {
399 ✗ gate_audio_wave_stream_impl_t* impl = (gate_audio_wave_stream_impl_t*)device;
400 ✗ if (gate_atomic_int_dec(&impl->ref_counter) == 0)
401 {
402 ✗ if (impl->input)
403 {
404 ✗ gate_object_release(impl->input);
405 ✗ impl->input = NULL;
406 }
407 ✗ if (impl->output)
408 {
409 ✗ gate_object_release(impl->output);
410 ✗ impl->output = NULL;
411 }
412 }
413 ✗ gate_mem_dealloc(impl);
414 ✗ }
415 ✗ static int gate_audio_device_wave_stream_retain(void* device)
416 {
417 ✗ gate_audio_wave_stream_impl_t* impl = (gate_audio_wave_stream_impl_t*)device;
418 ✗ return gate_atomic_int_inc(&impl->ref_counter);
419 }
420 ✗ static char const* gate_audio_device_wave_stream_get_interface_name(void* device)
421 {
422 (void)device;
423 ✗ return GATE_INTERFACE_NAME_AUDIO_DEVICE;
424 }
425
426 ✗ static char const* gate_audio_device_wave_stream_get_id(void* device)
427 {
428 (void)device;
429 ✗ return "riff_stream";
430 }
431 ✗ static char const* gate_audio_device_wave_stream_get_name(void* device)
432 {
433 (void)device;
434 ✗ return "RIFF/WAVE Stream";
435 }
436 ✗ static gate_intptr_t gate_audio_device_wave_stream_get_handle(void* device)
437 {
438 (void)device;
439 ✗ return -1;
440 }
441 ✗ static gate_enumint_t gate_audio_device_wave_stream_get_device_type(void* device)
442 {
443 ✗ gate_audio_wave_stream_impl_t* impl = (gate_audio_wave_stream_impl_t*)device;
444 ✗ if (impl->input != NULL)
445 {
446 ✗ return gate_audio_device_input;
447 }
448 ✗ else if (impl->output != NULL)
449 {
450 ✗ return gate_audio_device_output;
451 }
452 else
453 {
454 ✗ return gate_audio_device_unknown;
455 }
456 }
457
458 ✗ static gate_bool_t gate_audio_riff_check_format(char const buffer[36], gate_audio_format_t* format, gate_uint32_t* ptr_datalen)
459 {
460 ✗ gate_bool_t ret = false;
461 gate_uint32_t format_len, sample_rate, bytes_per_sec;
462 gate_uint16_t format_tag, channels, block_align, bits_sample;
463
464 ✗ if ((0 == gate_str_comp_range(&buffer[0], "RIFF", 4))
465 ✗ && (0 == gate_str_comp_range(&buffer[8], "WAVE", 4))
466 ✗ && (0 == gate_str_comp_range(&buffer[12], "fmt ", 4))
467 )
468 {
469 /*
470 16 4 <fmt length> Length of remaining fmt header (16 Byte)
471 20 2 <format tag> Datenformat der Abtastwerte (siehe separate Tabelle weiter unten)
472 22 2 <channels> Count of channels: 1 = mono, 2 = stereo
473 24 4 <sample rate> Abtastrate pro Sekunde (z.B. 44100)
474 28 4 <bytes/second> Abtastrate * Block-Align
475 32 2 <block align> <channels> * (<bits/sample> / 8) (Division ohne Rest)
476 34 2 <bits/sample> 8, 16 oder 24
477 */
478 ✗ gate_deserialize_uint32_l(&buffer[4], 4, ptr_datalen);
479 ✗ gate_deserialize_uint32_l(&buffer[16], 4, &format_len);
480 ✗ gate_deserialize_uint16_l(&buffer[20], 2, &format_tag);
481 ✗ gate_deserialize_uint16_l(&buffer[22], 2, &channels);
482 ✗ gate_deserialize_uint32_l(&buffer[24], 4, &sample_rate);
483 ✗ gate_deserialize_uint32_l(&buffer[28], 4, &bytes_per_sec);
484 ✗ gate_deserialize_uint16_l(&buffer[32], 2, &block_align);
485 ✗ gate_deserialize_uint16_l(&buffer[34], 2, &bits_sample);
486
487 ✗ format->encoding_id = format_tag;
488 ✗ format->samples_per_second = sample_rate;
489 ✗ format->bits_per_sample = bits_sample;
490 ✗ format->channels = channels;
491
492 ✗ ret = true;
493 }
494 ✗ return ret;
495 }
496
497 ✗ static gate_bool_t gate_audio_riff_create_header(char buffer[36], gate_audio_format_t const* format)
498 {
499 static gate_uint32_t const format_len = 16;
500 static gate_uint32_t const datalen = 36 + 8; /* total file length = RIFF+WAVE+fmt+data headers */
501
502 ✗ gate_uint32_t const bytes_per_second = format->samples_per_second * format->channels * format->bits_per_sample / 8;
503 ✗ gate_uint16_t const block_align = format->channels * format->bits_per_sample / 8;
504 ✗ gate_uint16_t encoding_id = 0;
505 ✗ gate_mem_copy(&buffer[0], "RIFF", 4);
506 ✗ gate_serialize_uint32_l(&buffer[4], 4, &datalen);
507 ✗ gate_mem_copy(&buffer[8], "WAVE", 4);
508 ✗ gate_mem_copy(&buffer[12], "fmt ", 4);
509 ✗ gate_serialize_uint32_l(&buffer[16], 4, &format_len);
510 ✗ encoding_id = (gate_uint16_t)format->encoding_id;
511 ✗ gate_serialize_uint16_l(&buffer[20], 2, &encoding_id);
512 ✗ gate_serialize_uint16_l(&buffer[22], 2, &format->channels);
513 ✗ gate_serialize_uint32_l(&buffer[24], 4, &format->samples_per_second);
514 ✗ gate_serialize_uint32_l(&buffer[28], 4, &bytes_per_second);
515 ✗ gate_serialize_uint16_l(&buffer[32], 2, &block_align);
516 ✗ gate_serialize_uint16_l(&buffer[34], 2, &format->bits_per_sample);
517 ✗ return true;
518 }
519
520
521 ✗ static gate_size_t gate_audio_device_wave_stream_get_supported_formats(void* device, gate_audio_format_t* format_buffer, gate_size_t format_buffer_count)
522 {
523 ✗ gate_audio_wave_stream_impl_t* impl = (gate_audio_wave_stream_impl_t*)device;
524 ✗ gate_size_t ret = 0;
525 gate_result_t result;
526 char hdr_buffer[36];
527 ✗ gate_size_t bytes_returned = 0;
528 ✗ gate_bool_t format_defined = false;
529
530 ✗ if (impl->output != NULL)
531 {
532 /* output stream */
533 /* not supported/do nothing */
534 }
535
536 ✗ if (impl->input != NULL)
537 {
538 /* input stream */
539
540 ✗ format_defined = gate_atomic_int_set(&impl->format_defined, 1);
541 ✗ if (!format_defined)
542 {
543 do
544 {
545 ✗ result = gate_stream_read_block(impl->input, hdr_buffer, sizeof(hdr_buffer), &bytes_returned);
546 ✗ GATE_BREAK_IF_FAILED(result);
547
548 ✗ if (bytes_returned < sizeof(hdr_buffer))
549 {
550 ✗ gate_atomic_int_set(&impl->format_defined, 0);
551 ✗ break;
552 }
553
554 ✗ if (!gate_audio_riff_check_format(hdr_buffer, &impl->format, &impl->data_length))
555 {
556 ✗ gate_atomic_int_set(&impl->format_defined, 0);
557 ✗ break;
558 }
559 ✗ format_defined = true;
560 } while (0);
561 }
562 }
563
564 ✗ if (format_defined)
565 {
566 ✗ if ((format_buffer_count != 0) && (format_buffer != NULL))
567 {
568 ✗ format_buffer[0] = impl->format;
569 ✗ ret = 1;
570 }
571 }
572 ✗ return ret;
573 }
574
575 ✗ static gate_result_t gate_audio_device_wave_stream_open(void* device, gate_audio_format_t const* format, gate_size_t sample_count)
576 {
577 ✗ gate_audio_wave_stream_impl_t* const impl = (gate_audio_wave_stream_impl_t*)device;
578 ✗ gate_result_t ret = GATE_RESULT_FAILED;
579 char riff_hdrs[36];
580 char data_hdrs[8];
581 gate_size_t bytes_written;
582
583 GATE_UNUSED_ARG(sample_count);
584
585 do
586 {
587 ✗ if (impl->opened)
588 {
589 ✗ ret = GATE_RESULT_INVALIDSTATE;
590 ✗ break;
591 }
592
593 ✗ if (impl->input != NULL)
594 {
595 ✗ gate_audio_device_wave_stream_get_supported_formats(device, NULL, 0);
596 ✗ if (0 == gate_atomic_int_get(&impl->format_defined))
597 {
598 ✗ ret = GATE_RESULT_INVALIDHEADER;
599 ✗ break;
600 }
601 ✗ impl->opened = true;
602 ✗ ret = GATE_RESULT_OK;
603 }
604
605 ✗ if (impl->output != NULL)
606 {
607 ✗ if (format == NULL)
608 {
609 ✗ ret = GATE_RESULT_INVALIDARG;
610 ✗ break;
611 }
612 ✗ gate_mem_copy(&impl->format, format, sizeof(impl->format));
613 ✗ ret = gate_stream_get_position(impl->output, &impl->write_start_position);
614 ✗ GATE_BREAK_IF_FAILED(ret);
615
616 ✗ gate_audio_riff_create_header(riff_hdrs, &impl->format);
617 ✗ ret = gate_stream_write_block((gate_stream_t*)impl->output, riff_hdrs, sizeof(riff_hdrs), &bytes_written);
618 ✗ GATE_BREAK_IF_FAILED(ret);
619
620 ✗ gate_mem_copy(&data_hdrs[0], "data", 4);
621 ✗ gate_mem_clear(&data_hdrs[4], 4);
622 ✗ impl->data_length = 0;
623 ✗ ret = gate_stream_write_block((gate_stream_t*)impl->output, data_hdrs, sizeof(riff_hdrs), &bytes_written);
624 ✗ GATE_BREAK_IF_FAILED(ret);
625
626 ✗ impl->opened = true;
627 }
628
629 } while (0);
630
631 ✗ return ret;
632 }
633 ✗ static gate_result_t gate_audio_device_wave_stream_close(void* device)
634 {
635 ✗ gate_result_t ret = GATE_RESULT_OK;
636 ✗ gate_audio_wave_stream_impl_t* const impl = (gate_audio_wave_stream_impl_t*)device;
637
638 ✗ gate_int64_t cur_pos = 0;
639 ✗ gate_uint32_t data_len = 0;
640 char buffer[4];
641 ✗ gate_size_t len_written = 0;
642
643 do
644 {
645 ✗ if (!impl->opened)
646 {
647 /* is already closed */
648 ✗ break;
649 }
650
651 ✗ if (impl->output != NULL)
652 {
653 ✗ ret = gate_stream_get_position(impl->output, &cur_pos);
654 ✗ GATE_BREAK_IF_FAILED(ret);
655
656 /* total file_len - 8 is stored at offset 4 */
657 ✗ GATE_DEBUG_ASSERT(cur_pos >= (impl->write_start_position + 8));
658 ✗ data_len = (gate_uint32_t)(cur_pos - impl->write_start_position - 8);
659 ✗ gate_serialize_uint32_l(buffer, sizeof(buffer), &data_len);
660
661 ✗ ret = gate_stream_seek(impl->output, impl->write_start_position + 4, GATE_STREAM_SEEK_BEGIN, NULL);
662 ✗ GATE_BREAK_IF_FAILED(ret);
663
664 ✗ ret = gate_stream_write_block((gate_stream_t*)impl->output, buffer, 4, &len_written);
665 ✗ GATE_BREAK_IF_FAILED(ret);
666
667 /* samples_length is stored at offset 40 */
668 ✗ GATE_DEBUG_ASSERT(cur_pos >= (impl->write_start_position + 44));
669 ✗ data_len = (gate_uint32_t)(cur_pos - impl->write_start_position - 44);
670 ✗ gate_serialize_uint32_l(buffer, sizeof(buffer), &data_len);
671
672 ✗ ret = gate_stream_seek(impl->output, impl->write_start_position + 40, GATE_STREAM_SEEK_BEGIN, NULL);
673 ✗ GATE_BREAK_IF_FAILED(ret);
674
675 ✗ ret = gate_stream_write_block((gate_stream_t*)impl->output, buffer, 4, &len_written);
676 ✗ GATE_BREAK_IF_FAILED(ret);
677
678
679 /* go back to file end: */
680 ✗ ret = gate_stream_seek(impl->output, cur_pos, GATE_STREAM_SEEK_BEGIN, NULL);
681
682 ✗ ret = gate_stream_flush(impl->output);
683 ✗ GATE_BREAK_IF_FAILED(ret);
684 }
685 } while (0);
686
687 ✗ return ret;
688 }
689
690 ✗ static gate_result_t gate_audio_device_wave_stream_read(void* device, gate_audio_sample_t* sample)
691 {
692 ✗ gate_audio_wave_stream_impl_t* impl = (gate_audio_wave_stream_impl_t*)device;
693 ✗ gate_result_t result = GATE_RESULT_OK;
694 char riff_hdr[8];
695 gate_size_t bytes_received;
696 gate_uint32_t data_len;
697 ✗ gate_bool_t data_found = false;
698 ✗ char* sample_data = NULL;
699
700 do
701 {
702 ✗ if (!impl->opened)
703 {
704 ✗ result = GATE_RESULT_INVALIDSTATE;
705 ✗ break;
706 }
707
708 ✗ if (impl->input == NULL)
709 {
710 ✗ result = GATE_RESULT_NOTSUPPORTED;
711 ✗ break;
712 }
713 ✗ gate_mem_clear(sample, sizeof(gate_audio_sample_t));
714
715 ✗ while (!data_found)
716 {
717 ✗ result = gate_stream_read_block(impl->input, riff_hdr, sizeof(riff_hdr), &bytes_received);
718 ✗ GATE_BREAK_IF_FAILED(result);
719 ✗ if (bytes_received == 0)
720 {
721 ✗ result = GATE_RESULT_ENDOFSTREAM;
722 ✗ break;
723 }
724 ✗ if (bytes_received != sizeof(riff_hdr))
725 {
726 ✗ result = GATE_RESULT_INVALIDHEADER;
727 ✗ break;
728 }
729
730 ✗ gate_deserialize_uint32_l(&riff_hdr[4], 4, &data_len);
731 ✗ if (0 == gate_str_comp_range(riff_hdr, "data", 4))
732 {
733 ✗ sample->format = impl->format;
734 ✗ sample->record_time = 0;
735 ✗ sample->meta_data = NULL;
736 ✗ sample->data = gate_memoryblock_create(data_len);
737 ✗ if (sample->data == NULL)
738 {
739 ✗ result = GATE_RESULT_OUTOFMEMORY;
740 ✗ break;
741 }
742 ✗ sample_data = gate_memoryblock_get_content(sample->data);
743 ✗ result = gate_stream_read_block(impl->input, sample_data, data_len, &bytes_received);
744 ✗ GATE_BREAK_IF_FAILED(result);
745
746 ✗ sample->sample_count = (gate_uint32_t)(bytes_received / ((gate_size_t)impl->format.channels * ((gate_size_t)impl->format.bits_per_sample / 8)));
747 ✗ data_found = true;
748 }
749 else
750 {
751 ✗ result = gate_stream_skip(impl->input, data_len, NULL);
752 ✗ GATE_BREAK_IF_FAILED(result);
753 }
754 }
755 } while (0);
756 ✗ return result;
757 }
758 ✗ static gate_result_t gate_audio_device_wave_stream_read_async(void* device, gate_delegate_t const* completion)
759 {
760 (void)device;
761 (void)completion;
762 ✗ return GATE_RESULT_NOTSUPPORTED;
763 }
764 ✗ static gate_result_t gate_audio_device_wave_stream_write(void* device, gate_audio_sample_t const* sample)
765 {
766 ✗ gate_audio_wave_stream_impl_t* impl = (gate_audio_wave_stream_impl_t*)device;
767 ✗ gate_result_t result = GATE_RESULT_FAILED;
768 //char hdr[8] = "data";
769 gate_uint32_t memsize;
770 char const* memdata;
771 gate_size_t data_written;
772 do
773 {
774 ✗ if (!impl->opened)
775 {
776 ✗ result = GATE_RESULT_INVALIDSTATE;
777 ✗ break;
778 }
779 ✗ if (impl->output == NULL)
780 {
781 ✗ result = GATE_RESULT_NOTSUPPORTED;
782 ✗ break;
783 }
784 ✗ memsize = (gate_uint32_t)gate_memoryblock_get_size(sample->data);
785 ✗ memdata = (char*)gate_memoryblock_get_content(sample->data);
786
787 /*gate_serialize_uint32_l(&hdr[4], 4, &memsize);
788 result = gate_stream_write_block((gate_stream_t*)impl->output, hdr, sizeof(hdr), &data_written);
789 GATE_BREAK_IF_FAILED(result);
790 */
791
792 ✗ result = gate_stream_write_block((gate_stream_t*)impl->output, memdata, memsize, &data_written);
793 } while (0);
794
795 ✗ return result;
796 }
797 ✗ static gate_result_t gate_audio_device_wave_stream_write_async(void* device, gate_audio_sample_t const* sample, gate_delegate_t const* completion)
798 {
799 (void)device;
800 (void)sample;
801 (void)completion;
802 ✗ return GATE_RESULT_NOTSUPPORTED;
803 }
804
805
806 ✗ gate_result_t gate_audio_create_wave_reader(gate_stream_t* input, gate_audio_device_t** ptr_reader)
807 {
808 gate_result_t ret;
809 gate_audio_wave_stream_impl_t* impl;
810 do
811 {
812 ✗ if ((input == NULL) || (ptr_reader == NULL))
813 {
814 ✗ ret = GATE_RESULT_INVALIDARG;
815 ✗ break;
816 }
817 ✗ impl = (gate_audio_wave_stream_impl_t*)gate_mem_alloc(sizeof(gate_audio_wave_stream_impl_t));
818 ✗ if (impl == NULL)
819 {
820 ✗ ret = GATE_RESULT_OUTOFMEMORY;
821 ✗ break;
822 }
823 ✗ gate_mem_clear(impl, sizeof(gate_audio_wave_stream_impl_t));
824 ✗ gate_init_audio_device_vtbl_wave_stream();
825 ✗ impl->vtbl = &gate_audio_device_vtbl_wave_stream;
826 ✗ impl->input = input;
827 ✗ gate_object_retain(impl->input);
828 ✗ gate_atomic_int_init(&impl->ref_counter, 1);
829 ✗ gate_atomic_int_set(&impl->format_defined, 0);
830 ✗ ret = GATE_RESULT_OK;
831 ✗ *ptr_reader = (gate_audio_device_t*)impl;
832 } while (0);
833 ✗ return ret;
834 }
835
836
837 ✗ gate_result_t gate_audio_create_wave_writer(gate_controlstream_t* output, gate_audio_device_t** ptr_writer)
838 {
839 gate_result_t ret;
840 gate_audio_wave_stream_impl_t* impl;
841 do
842 {
843 ✗ if ((output == NULL) || (ptr_writer == NULL))
844 {
845 ✗ ret = GATE_RESULT_INVALIDARG;
846 ✗ break;
847 }
848 ✗ impl = (gate_audio_wave_stream_impl_t*)gate_mem_alloc(sizeof(gate_audio_wave_stream_impl_t));
849 ✗ if (impl == NULL)
850 {
851 ✗ ret = GATE_RESULT_OUTOFMEMORY;
852 ✗ break;
853 }
854 ✗ gate_mem_clear(impl, sizeof(gate_audio_wave_stream_impl_t));
855 ✗ gate_init_audio_device_vtbl_wave_stream();
856 ✗ impl->vtbl = &gate_audio_device_vtbl_wave_stream;
857 ✗ impl->output = output;
858 ✗ gate_object_retain(impl->output);
859 ✗ gate_atomic_int_init(&impl->ref_counter, 1);
860 ✗ gate_atomic_int_set(&impl->format_defined, 0);
861 ✗ ret = GATE_RESULT_OK;
862 ✗ *ptr_writer = (gate_audio_device_t*)impl;
863 } while (0);
864 ✗ return ret;
865 }
866
867
868
869
870 #if defined(GATE_IO_AUDIO_WINAPI)
871
872 # if defined(UNICODE) || defined(_UNICODE)
873 # include <winsock2.h>
874 # else
875 # include <winsock.h>
876 # endif
877 # include <windows.h>
878 # include "gate/platforms.h"
879
880 struct gate_win32_format_mapping
881 {
882 DWORD win_format;
883 gate_audio_format_t gate_format;
884 };
885
886 static struct gate_win32_format_mapping gate_win32_all_formats[] =
887 {
888 #if defined(WAVE_FORMAT_48M08)
889 { WAVE_FORMAT_48M08, { 1, 48000, 1, 8 } },
890 #endif
891 #if defined(WAVE_FORMAT_48M16)
892 { WAVE_FORMAT_48M16, { 1, 48000, 1, 16 } },
893 #endif
894 #if defined(WAVE_FORMAT_48S08)
895 { WAVE_FORMAT_48S08, { 1, 48000, 2, 8 } },
896 #endif
897 #if defined(WAVE_FORMAT_48S16)
898 { WAVE_FORMAT_48S16, { 1, 48000, 2, 16 } },
899 #endif
900 #if defined(WAVE_FORMAT_96M08)
901 { WAVE_FORMAT_96M08, { 1, 96000, 1, 8 } },
902 #endif
903 #if defined(WAVE_FORMAT_96M16)
904 { WAVE_FORMAT_96M16, { 1, 96000, 1, 16 } },
905 #endif
906 #if defined(WAVE_FORMAT_96S08)
907 { WAVE_FORMAT_96S08, { 1, 96000, 2, 8 } },
908 #endif
909 #if defined(WAVE_FORMAT_96S16)
910 { WAVE_FORMAT_96S16, { 1, 96000, 2, 16 } },
911 #endif
912 { WAVE_FORMAT_1M08, { 1, 11025, 1, 8 } },
913 { WAVE_FORMAT_1M16, { 1, 11025, 1, 16 } },
914 { WAVE_FORMAT_1S08, { 1, 11025, 2, 8 } },
915 { WAVE_FORMAT_1S16, { 1, 11025, 2, 16 } },
916 { WAVE_FORMAT_2M08, { 1, 22050, 1, 8 } },
917 { WAVE_FORMAT_2M16, { 1, 22050, 1, 16 } },
918 { WAVE_FORMAT_2S08, { 1, 22050, 2, 8 } },
919 { WAVE_FORMAT_2S16, { 1, 22050, 2, 16 } },
920 { WAVE_FORMAT_4M08, { 1, 44100, 1, 8 } },
921 { WAVE_FORMAT_4M16, { 1, 44100, 1, 16 } },
922 { WAVE_FORMAT_4S08, { 1, 44100, 2, 8 } },
923 { WAVE_FORMAT_4S16, { 1, 44100, 2, 16 } },
924 };
925
926 typedef struct
927 {
928 UINT(WINAPI* MMwaveInGetNumDevs) (VOID);
929 MMRESULT(WINAPI* MMwaveInGetDevCaps) (UINT uDeviceID, LPWAVEINCAPS pwic, UINT cbwic);
930 MMRESULT(WINAPI* MMwaveInPrepareHeader) (HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
931 MMRESULT(WINAPI* MMwaveInUnprepareHeader) (HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
932 MMRESULT(WINAPI* MMwaveInAddBuffer) (HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
933 MMRESULT(WINAPI* MMwaveInOpen) (LPHWAVEIN phwi, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
934 MMRESULT(WINAPI* MMwaveInStart) (HWAVEIN hwi);
935 MMRESULT(WINAPI* MMwaveInReset) (HWAVEIN hwi);
936 MMRESULT(WINAPI* MMwaveInStop) (HWAVEIN hwi);
937 MMRESULT(WINAPI* MMwaveInClose) (HWAVEIN hwi);
938
939 UINT(WINAPI* MMwaveOutGetNumDevs) (VOID);
940 MMRESULT(WINAPI* MMwaveOutGetDevCaps) (UINT uDeviceID, LPWAVEOUTCAPS pwoc, UINT cbwoc);
941 MMRESULT(WINAPI* MMwaveOutPrepareHeader) (HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
942 MMRESULT(WINAPI* MMwaveOutUnprepareHeader) (HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
943 MMRESULT(WINAPI* MMwaveOutOpen) (LPHWAVEOUT phwo, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
944 MMRESULT(WINAPI* MMwaveOutWrite) (HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
945 MMRESULT(WINAPI* MMwaveOutReset) (HWAVEOUT hwo);
946 MMRESULT(WINAPI* MMwaveOutClose) (HWAVEOUT hwo);
947 } win32_audio_functions_t;
948
949 static win32_audio_functions_t win32_audio = GATE_INIT_EMPTY;
950 static volatile gate_bool_t win32_audio_functions_loaded = false;
951
952 static gate_bool_t load_winmm_functions()
953 {
954 static volatile HMODULE hmod_winmm = NULL;
955
956 do
957 {
958 if (win32_audio_functions_loaded)
959 {
960 break;
961 }
962
963 if (hmod_winmm == NULL)
964 {
965 hmod_winmm = LoadLibrary(_T("winmm.dll"));
966 if (hmod_winmm == NULL)
967 {
968 break;
969 }
970 }
971 //gate_win32_get_proc_address(hmod_winmm, "", &win32_audio.);
972
973 if (!gate_win32_get_proc_address(hmod_winmm, "waveInGetNumDevs", &win32_audio.MMwaveInGetNumDevs)) break;
974 if (!gate_win32_get_proc_address(hmod_winmm, GATE_WIN32_DUAL_NAME("waveInGetDevCaps"), &win32_audio.MMwaveInGetDevCaps)) break;
975 if (!gate_win32_get_proc_address(hmod_winmm, "waveInPrepareHeader", &win32_audio.MMwaveInPrepareHeader)) break;
976 if (!gate_win32_get_proc_address(hmod_winmm, "waveInUnprepareHeader", &win32_audio.MMwaveInUnprepareHeader)) break;
977 if (!gate_win32_get_proc_address(hmod_winmm, "waveInAddBuffer", &win32_audio.MMwaveInAddBuffer)) break;
978 if (!gate_win32_get_proc_address(hmod_winmm, "waveInOpen", &win32_audio.MMwaveInOpen)) break;
979 if (!gate_win32_get_proc_address(hmod_winmm, "waveInStart", &win32_audio.MMwaveInStart)) break;
980 if (!gate_win32_get_proc_address(hmod_winmm, "waveInReset", &win32_audio.MMwaveInReset)) break;
981 if (!gate_win32_get_proc_address(hmod_winmm, "waveInStop", &win32_audio.MMwaveInStop)) break;
982 if (!gate_win32_get_proc_address(hmod_winmm, "waveInClose", &win32_audio.MMwaveInClose)) break;
983
984 if (!gate_win32_get_proc_address(hmod_winmm, "waveOutGetNumDevs", &win32_audio.MMwaveOutGetNumDevs)) break;
985 if (!gate_win32_get_proc_address(hmod_winmm, GATE_WIN32_DUAL_NAME("waveOutGetDevCaps"), &win32_audio.MMwaveOutGetDevCaps)) break;
986 if (!gate_win32_get_proc_address(hmod_winmm, "waveOutPrepareHeader", &win32_audio.MMwaveOutPrepareHeader)) break;
987 if (!gate_win32_get_proc_address(hmod_winmm, "waveOutUnprepareHeader", &win32_audio.MMwaveOutUnprepareHeader)) break;
988 if (!gate_win32_get_proc_address(hmod_winmm, "waveOutOpen", &win32_audio.MMwaveOutOpen)) break;
989 if (!gate_win32_get_proc_address(hmod_winmm, "waveOutWrite", &win32_audio.MMwaveOutWrite)) break;
990 if (!gate_win32_get_proc_address(hmod_winmm, "waveOutReset", &win32_audio.MMwaveOutReset)) break;
991 if (!gate_win32_get_proc_address(hmod_winmm, "waveOutClose", &win32_audio.MMwaveOutClose)) break;
992
993 win32_audio_functions_loaded = true;
994
995 } while (0);
996
997 return win32_audio_functions_loaded;
998 }
999
1000 static gate_size_t gate_win32_get_formats(DWORD win_formats, gate_audio_format_t* formats, gate_size_t format_count)
1001 {
1002 static gate_size_t gate_win32_all_format_count = sizeof(gate_win32_all_formats) / sizeof(gate_win32_all_formats[0]);
1003 gate_size_t ret = 0;
1004 gate_size_t index;
1005
1006 for (index = 0; index != gate_win32_all_format_count; ++index)
1007 {
1008 if (win_formats & gate_win32_all_formats[index].win_format)
1009 {
1010 *formats = gate_win32_all_formats[index].gate_format;
1011 ++ret;
1012 ++formats;
1013 if (ret >= format_count)
1014 {
1015 break;
1016 }
1017 }
1018 }
1019 return ret;
1020 }
1021
1022 typedef struct gate_audio_device_impl
1023 {
1024 GATE_INTERFACE_VTBL(gate_audio_device) const* vtbl;
1025
1026 gate_atomic_int_t ref_counter;
1027 UINT device_id;
1028 char device_id_text[32];
1029 char device_name[128];
1030 gate_enumint_t device_type;
1031 HWAVEIN wave_in_handle;
1032 HWAVEOUT wave_out_handle;
1033 HANDLE event_handle;
1034 gate_audio_format_t supported_formats[32];
1035 gate_size_t supported_formats_count;
1036 gate_audio_format_t selected_format;
1037 gate_size_t default_sample_count;
1038
1039 gate_atomic_flag_t exequeue_running;
1040 gate_exequeue_t exequeue;
1041
1042 } gate_audio_device_impl_t;
1043
1044 static void gate_audio_device_impl_release(void* device)
1045 {
1046 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1047 if (gate_atomic_int_dec(&impl->ref_counter) == 0)
1048 {
1049 gate_audio_device_impl_close(device);
1050
1051 if (impl->event_handle != NULL)
1052 {
1053 CloseHandle(impl->event_handle);
1054 impl->event_handle = NULL;
1055 }
1056
1057 gate_mem_dealloc(impl);
1058 }
1059 }
1060 static int gate_audio_device_impl_retain(void* device)
1061 {
1062 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1063 return gate_atomic_int_inc(&impl->ref_counter);
1064 }
1065
1066 static char const* gate_audio_device_impl_get_id(void* device)
1067 {
1068 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1069 return impl->device_id_text;
1070 }
1071 static char const* gate_audio_device_impl_get_name(void* device)
1072 {
1073 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1074 return impl->device_name;
1075 }
1076 static gate_intptr_t gate_audio_device_impl_get_handle(void* device)
1077 {
1078 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1079 return (gate_intptr_t)impl->device_id;
1080 }
1081 static gate_enumint_t gate_audio_device_impl_get_device_type(void* device)
1082 {
1083 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1084 return impl->device_type;
1085 }
1086 static gate_size_t gate_audio_device_impl_get_supported_formats(void* device, gate_audio_format_t* format_buffer, gate_size_t format_buffer_count)
1087 {
1088 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1089 gate_size_t count = format_buffer_count > impl->supported_formats_count ? impl->supported_formats_count : format_buffer_count;
1090 gate_mem_copy(format_buffer, &impl->supported_formats[0], sizeof(gate_audio_format_t) * count);
1091 return count;
1092 }
1093
1094 static gate_result_t gate_audio_device_impl_open(void* device, gate_audio_format_t const* format, gate_size_t sample_count)
1095 {
1096 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
1097 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1098 WAVEFORMATEX format_ex;
1099 MMRESULT mm_result;
1100
1101 do
1102 {
1103 if (sample_count == 0)
1104 {
1105 sample_count = format->samples_per_second;
1106 }
1107
1108 impl->selected_format = *format;
1109 if (impl->event_handle == NULL)
1110 {
1111 impl->event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
1112 if (NULL == impl->event_handle)
1113 {
1114 ret = GATE_RESULT_OUTOFRESOURCES;
1115 break;
1116 }
1117 }
1118 impl->default_sample_count = sample_count;
1119
1120 format_ex.wFormatTag = (WORD)format->encoding_id;
1121 format_ex.nChannels = format->channels;
1122 format_ex.nSamplesPerSec = format->samples_per_second;
1123 format_ex.wBitsPerSample = format->bits_per_sample;
1124 format_ex.nBlockAlign = (format_ex.nChannels * format_ex.wBitsPerSample) >> 3;
1125 format_ex.nAvgBytesPerSec = (format_ex.nBlockAlign * format_ex.nSamplesPerSec);
1126 format_ex.cbSize = 0;
1127
1128 if (impl->device_type == gate_audio_device_input)
1129 {
1130 if (impl->wave_in_handle != NULL)
1131 {
1132 ret = GATE_RESULT_INVALIDSTATE;
1133 break;
1134 }
1135
1136 mm_result = win32_audio.MMwaveInOpen(&impl->wave_in_handle, impl->device_id, &format_ex,
1137 (DWORD_PTR)impl->event_handle, (DWORD_PTR)device, CALLBACK_EVENT);
1138 if (MMSYSERR_NOERROR != mm_result)
1139 {
1140 ret = GATE_RESULT_FAILED;
1141 impl->wave_in_handle = NULL;
1142 break;
1143 }
1144
1145 mm_result = win32_audio.MMwaveInStart(impl->wave_in_handle);
1146 if (MMSYSERR_NOERROR != mm_result)
1147 {
1148 ret = GATE_RESULT_FAILED;
1149 win32_audio.MMwaveInClose(impl->wave_in_handle);
1150 impl->wave_in_handle = NULL;
1151 break;
1152 }
1153
1154 ResetEvent(impl->event_handle);
1155 ret = GATE_RESULT_OK;
1156 }
1157 else if (impl->device_type == gate_audio_device_output)
1158 {
1159 if (impl->wave_out_handle != NULL)
1160 {
1161 ret = GATE_RESULT_INVALIDSTATE;
1162 break;
1163 }
1164
1165 mm_result = win32_audio.MMwaveOutOpen(&impl->wave_out_handle, impl->device_id, &format_ex,
1166 (DWORD_PTR)impl->event_handle, (DWORD_PTR)device, CALLBACK_EVENT);
1167 if (MMSYSERR_NOERROR != mm_result)
1168 {
1169 impl->wave_out_handle = NULL;
1170 ret = GATE_RESULT_FAILED;
1171 break;
1172 }
1173
1174 ResetEvent(impl->event_handle);
1175 ret = GATE_RESULT_OK;
1176 }
1177
1178 } while (0);
1179 return ret;
1180 }
1181 static gate_result_t gate_audio_device_impl_close(void* device)
1182 {
1183 gate_result_t ret = GATE_RESULT_OK;
1184 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1185
1186 if (impl->wave_in_handle != NULL)
1187 {
1188 win32_audio.MMwaveInStop(impl->wave_in_handle);
1189 win32_audio.MMwaveInReset(impl->wave_in_handle);
1190 win32_audio.MMwaveInClose(impl->wave_in_handle);
1191 impl->wave_in_handle = NULL;
1192 }
1193
1194 if (impl->wave_out_handle != NULL)
1195 {
1196 win32_audio.MMwaveOutReset(impl->wave_out_handle);
1197 win32_audio.MMwaveOutClose(impl->wave_out_handle);
1198 impl->wave_out_handle = NULL;
1199 }
1200
1201 return ret;
1202 }
1203
1204 static gate_result_t gate_audio_device_impl_read(void* device, gate_audio_sample_t* sample)
1205 {
1206 gate_result_t ret = GATE_RESULT_FAILED;
1207 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1208
1209 WAVEHDR wavehdr;
1210 char* ptr_buffer = NULL;
1211 MMRESULT mm_result;
1212
1213 gate_size_t buffersize;
1214
1215 do
1216 {
1217 if (impl->wave_in_handle == NULL)
1218 {
1219 ret = GATE_RESULT_INVALIDSTATE;
1220 break;
1221 }
1222
1223 gate_mem_clear(sample, sizeof(gate_audio_sample_t));
1224
1225 buffersize = impl->default_sample_count
1226 * impl->selected_format.channels
1227 * impl->selected_format.bits_per_sample
1228 / 8
1229 ;
1230
1231 if (buffersize == 0)
1232 {
1233 ret = GATE_RESULT_INVALIDARG;
1234 break;
1235 }
1236
1237 sample->sample_count = (gate_uint32_t)impl->default_sample_count;
1238 sample->format = impl->selected_format;
1239 sample->record_time = 0;
1240 sample->data = gate_memoryblock_create(buffersize);
1241 if (sample->data == NULL)
1242 {
1243 ret = GATE_RESULT_OUTOFMEMORY;
1244 break;
1245 }
1246 ptr_buffer = (char*)gate_memoryblock_get_content(sample->data);
1247
1248 gate_mem_clear(&wavehdr, sizeof(wavehdr));
1249 wavehdr.dwBufferLength = (DWORD)buffersize;
1250 wavehdr.lpData = ptr_buffer;
1251
1252 mm_result = win32_audio.MMwaveInPrepareHeader(impl->wave_in_handle, &wavehdr, sizeof(wavehdr));
1253 if (MMSYSERR_NOERROR != mm_result)
1254 {
1255 ret = GATE_RESULT_FAILED;
1256 break;
1257 }
1258
1259 mm_result = win32_audio.MMwaveInAddBuffer(impl->wave_in_handle, &wavehdr, sizeof(wavehdr));
1260 if (MMSYSERR_NOERROR != mm_result)
1261 {
1262 mm_result = win32_audio.MMwaveInUnprepareHeader(impl->wave_in_handle, &wavehdr, sizeof(wavehdr));
1263 ret = GATE_RESULT_FAILED;
1264 break;
1265 }
1266
1267 WaitForSingleObject(impl->event_handle, INFINITE);
1268 mm_result = win32_audio.MMwaveInUnprepareHeader(impl->wave_in_handle, &wavehdr, sizeof(wavehdr));
1269 sample->sample_count = wavehdr.dwBytesRecorded * 8
1270 / impl->selected_format.bits_per_sample
1271 / impl->selected_format.channels;
1272 sample->format = impl->selected_format;
1273 ret = GATE_RESULT_OK;
1274
1275 } while (0);
1276
1277 if (GATE_FAILED(ret))
1278 {
1279 if (sample->data != NULL)
1280 {
1281 gate_object_release(sample->data);
1282 }
1283 if (sample->meta_data != NULL)
1284 {
1285 gate_object_release(sample->meta_data);
1286 }
1287 gate_mem_clear(sample, sizeof(gate_audio_sample_t));
1288 }
1289 return ret;
1290 }
1291 static gate_result_t gate_audio_device_impl_write(void* device, gate_audio_sample_t const* sample)
1292 {
1293 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1294 gate_result_t ret = GATE_RESULT_OK;
1295
1296 WAVEHDR wavehdr;
1297 MMRESULT mm_result;
1298
1299 do
1300 {
1301 if (impl->wave_out_handle == NULL)
1302 {
1303 ret = GATE_RESULT_INVALIDSTATE;
1304 break;
1305 }
1306 gate_mem_clear(&wavehdr, sizeof(wavehdr));
1307
1308 wavehdr.dwBufferLength = (DWORD)gate_memoryblock_get_size(sample->data);
1309 wavehdr.lpData = (char*)gate_memoryblock_get_content(sample->data);
1310
1311 if ((wavehdr.lpData == NULL) || (wavehdr.dwBufferLength == 0))
1312 {
1313 ret = GATE_RESULT_INVALIDARG;
1314 break;
1315 }
1316
1317 mm_result = win32_audio.MMwaveOutPrepareHeader(impl->wave_out_handle, &wavehdr, (UINT)sizeof(wavehdr));
1318 if (mm_result != MMSYSERR_NOERROR)
1319 {
1320 ret = GATE_RESULT_FAILED;
1321 break;
1322 }
1323 mm_result = win32_audio.MMwaveOutWrite(impl->wave_out_handle, &wavehdr, (UINT)sizeof(wavehdr));
1324 if (mm_result != MMSYSERR_NOERROR)
1325 {
1326 ret = GATE_RESULT_FAILED;
1327 mm_result = win32_audio.MMwaveOutUnprepareHeader(impl->wave_out_handle, &wavehdr, (UINT)sizeof(wavehdr));
1328 break;
1329 }
1330
1331 WaitForSingleObject(impl->event_handle, INFINITE);
1332 mm_result = win32_audio.MMwaveOutUnprepareHeader(impl->wave_out_handle, &wavehdr, (UINT)sizeof(wavehdr));
1333 ret = GATE_RESULT_OK;
1334 } while (0);
1335
1336 return ret;
1337 }
1338
1339 //static gate_result_t /
1340
1341 static gate_result_t gate_audio_device_impl_read_async(void* device, gate_delegate_t const* completion)
1342 {
1343 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1344 gate_result_t result = GATE_RESULT_FAILED;
1345
1346 do
1347 {
1348 if (gate_atomic_flag_set(&impl->exequeue_running) == false)
1349 {
1350 result = gate_exequeue_create(&impl->exequeue, NULL, NULL, NULL);
1351 GATE_BREAK_IF_FAILED(result);
1352 }
1353 /*TODO*/
1354 //gate_exequeue_push(impl->exequeue, )
1355
1356 } while (0);
1357
1358 return result;
1359 }
1360
1361 static gate_result_t gate_audio_device_impl_write_async(void* device, gate_audio_sample_t const* sample, gate_delegate_t const* completion)
1362 {
1363 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1364 gate_result_t result = GATE_RESULT_OK;
1365
1366 /*TODO*/
1367
1368 return result;
1369 }
1370
1371
1372 gate_result_t gate_audio_devices_enum(gate_enumint_t type, gate_delegate_t const* callback, void* param)
1373 {
1374 gate_result_t ret = GATE_RESULT_OK;
1375 UINT num_devs;
1376 UINT dev_index;
1377 WAVEINCAPS incaps;
1378 WAVEOUTCAPS outcaps;
1379 MMRESULT mmresult;
1380
1381 if (!load_winmm_functions())
1382 {
1383 return GATE_RESULT_NOTSUPPORTED;
1384 }
1385
1386 num_devs = win32_audio.MMwaveInGetNumDevs();
1387
1388 if ((type == gate_audio_device_unknown) || (type == gate_audio_device_input))
1389 {
1390 for (dev_index = 0; dev_index < num_devs; dev_index++)
1391 {
1392 mmresult = win32_audio.MMwaveInGetDevCaps(dev_index, &incaps, sizeof(incaps));
1393 if (MMSYSERR_NOERROR == mmresult)
1394 {
1395 gate_audio_device_impl_t* impl = gate_mem_alloc(sizeof(gate_audio_device_impl_t));
1396 if (impl != NULL)
1397 {
1398 gate_mem_clear(impl, sizeof(gate_audio_device_impl_t));
1399 gate_init_audio_device_vtbl_impl();
1400 impl->vtbl = &gate_audio_device_vtbl_impl;
1401
1402 gate_atomic_int_init(&impl->ref_counter, 1);
1403
1404 impl->device_id = dev_index;
1405 impl->device_type = gate_audio_device_input;
1406
1407 gate_str_print_uint(&impl->device_id_text[1], sizeof(impl->device_id_text) - 1, dev_index, 0);
1408 impl->device_id_text[0] = 'I';
1409
1410 gate_win32_winstr_2_utf8(incaps.szPname, sizeof(incaps.szPname) / sizeof(incaps.szPname[0]),
1411 impl->device_name, sizeof(impl->device_name));
1412
1413 impl->wave_in_handle = NULL;
1414 impl->wave_out_handle = NULL;
1415 impl->event_handle = NULL;
1416
1417 impl->supported_formats_count = gate_win32_get_formats(
1418 incaps.dwFormats, impl->supported_formats,
1419 sizeof(impl->supported_formats) / sizeof(impl->supported_formats[0]));
1420
1421 ret = gate_delegate_invoke(callback, (gate_audio_device_t*)impl, param);
1422 }
1423
1424 if (impl != NULL)
1425 {
1426 gate_object_release(impl);
1427 }
1428
1429 GATE_BREAK_IF_FAILED(ret);
1430 }
1431 }
1432
1433 }
1434
1435 if ((type == gate_audio_device_unknown) || (type == gate_audio_device_output))
1436 {
1437 if (GATE_SUCCEEDED(ret))
1438 {
1439 num_devs = win32_audio.MMwaveOutGetNumDevs();
1440
1441 for (dev_index = 0; dev_index < num_devs; dev_index++)
1442 {
1443 mmresult = win32_audio.MMwaveOutGetDevCaps(dev_index, &outcaps, sizeof(outcaps));
1444 if (MMSYSERR_NOERROR == mmresult)
1445 {
1446 gate_audio_device_impl_t* impl = gate_mem_alloc(sizeof(gate_audio_device_impl_t));
1447 if (impl != NULL)
1448 {
1449 gate_mem_clear(impl, sizeof(gate_audio_device_impl_t));
1450 gate_init_audio_device_vtbl_impl();
1451 impl->vtbl = &gate_audio_device_vtbl_impl;
1452
1453 gate_atomic_int_init(&impl->ref_counter, 1);
1454
1455 impl->device_id = dev_index;
1456 impl->device_type = gate_audio_device_output;
1457
1458 gate_str_print_uint(&impl->device_id_text[1], sizeof(impl->device_id_text) - 1, dev_index, 0);
1459 impl->device_id_text[0] = 'O';
1460
1461 gate_win32_winstr_2_utf8(outcaps.szPname, sizeof(outcaps.szPname) / sizeof(outcaps.szPname[0]),
1462 impl->device_name, sizeof(impl->device_name));
1463
1464 impl->wave_in_handle = NULL;
1465 impl->wave_out_handle = NULL;
1466 impl->event_handle = NULL;
1467
1468 impl->supported_formats_count = gate_win32_get_formats(
1469 outcaps.dwFormats, impl->supported_formats,
1470 sizeof(impl->supported_formats) / sizeof(impl->supported_formats[0]));
1471
1472 ret = gate_delegate_invoke(callback, impl, param);
1473 }
1474
1475 if (impl != NULL)
1476 {
1477 gate_object_release(impl);
1478 }
1479
1480 GATE_BREAK_IF_FAILED(ret);
1481 }
1482 }
1483 }
1484 }
1485 return ret;
1486 }
1487
1488 #endif /* GATE_IO_AUDIO_WINAPI */
1489
1490
1491
1492 #if defined(GATE_IO_AUDIO_ALSA)
1493
1494 #include <alsa/asoundlib.h> /*libasound2-dev*/
1495
1496 struct gate_audio_alsa_snd_code
1497 {
1498 int (*pcm_open) (snd_pcm_t** pcm, const char* name, snd_pcm_stream_t stream, int mode);
1499 int (*pcm_close) (snd_pcm_t* pcm);
1500 int (*pcm_hw_params_malloc) (snd_pcm_hw_params_t** ptr);
1501 int (*pcm_hw_params_any) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params);
1502 int (*pcm_hw_params_set_access) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params, snd_pcm_access_t access);
1503 int (*pcm_hw_params_set_format) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params, snd_pcm_format_t format);
1504 int (*pcm_hw_params_set_rate_near) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params, unsigned int* val, int* dir);
1505 int (*pcm_hw_params_set_channels) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params, unsigned int val);
1506 void(*pcm_hw_params_free) (snd_pcm_hw_params_t* obj);
1507 int (*pcm_hw_params) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params);
1508 int (*pcm_prepare) (snd_pcm_t* pcm);
1509 snd_pcm_sframes_t(*pcm_readi) (snd_pcm_t* pcm, void* buffer, snd_pcm_uframes_t size);
1510 snd_pcm_sframes_t(*pcm_writei) (snd_pcm_t* pcm, const void* buffer, snd_pcm_uframes_t size);
1511 snd_pcm_sframes_t(*pcm_avail) (snd_pcm_t* pcm);
1512 snd_pcm_state_t(*pcm_state) (snd_pcm_t* pcm);
1513 };
1514
1515 static struct gate_audio_alsa_snd_code alsa_snd = GATE_INIT_EMPTY;
1516
1517 ✗ static gate_result_t gate_audio_alsa_init()
1518 {
1519 static gate_string_t alsa_lib_name = GATE_STRING_INIT_STATIC("libasound.so");
1520 static gate_library_t alsa_library = NULL;
1521
1522 ✗ gate_library_t tmp_lib = NULL;
1523 ✗ gate_result_t result = GATE_RESULT_FAILED;
1524
1525 ✗ if (alsa_library == NULL)
1526 {
1527 do
1528 {
1529 ✗ GATE_BREAK_IF_FAILED(result = gate_library_open(&alsa_lib_name, &tmp_lib, GATE_LIBRARY_FLAG_DEFAULT));
1530
1531 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_open", &alsa_snd.pcm_open));
1532 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_close", &alsa_snd.pcm_close));
1533 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params_malloc", &alsa_snd.pcm_hw_params_malloc));
1534 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params_any", &alsa_snd.pcm_hw_params_any));
1535 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params_set_access", &alsa_snd.pcm_hw_params_set_access));
1536 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params_set_format", &alsa_snd.pcm_hw_params_set_format));
1537 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params_set_rate_near", &alsa_snd.pcm_hw_params_set_rate_near));
1538 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params_set_channels", &alsa_snd.pcm_hw_params_set_channels));
1539 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params_free", &alsa_snd.pcm_hw_params_free));
1540 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params", &alsa_snd.pcm_hw_params));
1541 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_prepare", &alsa_snd.pcm_prepare));
1542 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_readi", &alsa_snd.pcm_readi));
1543 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_open", &alsa_snd.pcm_open));
1544 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_writei", &alsa_snd.pcm_writei));
1545 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_avail", &alsa_snd.pcm_avail));
1546 ✗ GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_state", &alsa_snd.pcm_state));
1547
1548 ✗ alsa_library = tmp_lib;
1549 ✗ tmp_lib = NULL;
1550 ✗ result = GATE_RESULT_OK;
1551 } while (0);
1552
1553 ✗ if (tmp_lib != NULL)
1554 {
1555 ✗ gate_library_close(tmp_lib);
1556 }
1557 }
1558 else
1559 {
1560 ✗ result = GATE_RESULT_OK;
1561 }
1562 ✗ return result;
1563 }
1564
1565
1566 typedef struct gate_audio_alsa_impl
1567 {
1568 GATE_INTERFACE_VTBL(gate_audio_device) const* vtbl;
1569
1570 gate_atomic_int_t ref_counter;
1571 char id[256];
1572 char name[256];
1573 snd_pcm_t* handle;
1574 gate_enumint_t type;
1575
1576 gate_audio_format_t format;
1577 gate_atomic_int_t format_defined;
1578 gate_uint32_t sample_count;
1579
1580 } gate_audio_alsa_impl_t;
1581
1582
1583 ✗ static void gate_audio_device_impl_release(void* device)
1584 {
1585 ✗ gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1586 ✗ if (0 == gate_atomic_int_dec(&impl->ref_counter))
1587 {
1588 ✗ gate_audio_device_impl_close(impl);
1589 ✗ gate_mem_dealloc(impl);
1590 }
1591 ✗ }
1592 ✗ static int gate_audio_device_impl_retain(void* device)
1593 {
1594 ✗ gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1595 ✗ return gate_atomic_int_inc(&impl->ref_counter);
1596 }
1597
1598 ✗ static char const* gate_audio_device_impl_get_id(void* device)
1599 {
1600 ✗ gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1601 ✗ return impl->id;
1602 }
1603 ✗ static char const* gate_audio_device_impl_get_name(void* device)
1604 {
1605 ✗ gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1606 ✗ return impl->name;
1607 }
1608 ✗ static gate_intptr_t gate_audio_device_impl_get_handle(void* device)
1609 {
1610 ✗ gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1611 ✗ return (gate_intptr_t)(void*)impl->handle;
1612 }
1613 ✗ static gate_enumint_t gate_audio_device_impl_get_device_type(void* device)
1614 {
1615 ✗ gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1616 ✗ return impl->type;
1617 }
1618
1619 static gate_audio_format_t const alsa_all_formats[] =
1620 {
1621 { 1, 44100, 2, 16 },
1622 { 1, 44100, 1, 16 },
1623 { 1, 44100, 2, 8 },
1624 { 1, 44100, 1, 8 },
1625
1626 { 1, 22050, 2, 16 },
1627 { 1, 22050, 1, 16 },
1628 { 1, 22050, 2, 8 },
1629 { 1, 22050, 1, 8 },
1630
1631 { 1, 11025, 2, 16 },
1632 { 1, 11025, 1, 16 },
1633 { 1, 11025, 2, 8 },
1634 { 1, 11025, 1, 8 }
1635 };
1636
1637 ✗ static gate_size_t gate_audio_device_impl_get_supported_formats(
1638 void* device, gate_audio_format_t* format_buffer, gate_size_t format_buffer_count)
1639 {
1640 ✗ gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1641 static gate_size_t const alsa_all_formats_count = sizeof(alsa_all_formats) / sizeof(alsa_all_formats[0]);
1642 ✗ gate_size_t ret = format_buffer_count < alsa_all_formats_count ? format_buffer_count : alsa_all_formats_count;
1643 gate_size_t index;
1644
1645 ✗ for (index = 0; index != ret; ++index)
1646 {
1647 ✗ format_buffer[index] = alsa_all_formats[index];
1648 }
1649 ✗ return ret;
1650 }
1651
1652 ✗ static gate_result_t gate_audio_device_impl_open(void* device, gate_audio_format_t const* format, gate_size_t sample_count)
1653 {
1654 ✗ gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1655 ✗ gate_result_t result = GATE_RESULT_FAILED;
1656 int pcm_code;
1657 ✗ snd_pcm_t* handle = NULL;
1658 ✗ snd_pcm_hw_params_t* hw_params = NULL;
1659 int pcm_format;
1660 ✗ unsigned int pcm_rate = format->samples_per_second;
1661
1662 do
1663 {
1664 ✗ result = gate_audio_alsa_init();
1665 ✗ GATE_BREAK_IF_FAILED(result);
1666
1667 ✗ if (sample_count == 0)
1668 {
1669 ✗ impl->sample_count = format->samples_per_second;
1670 }
1671 else
1672 {
1673 ✗ impl->sample_count = sample_count;
1674 }
1675
1676 ✗ if (format->bits_per_sample == 8)
1677 {
1678 ✗ pcm_format = SND_PCM_FORMAT_U8;
1679 }
1680 ✗ else if (format->bits_per_sample == 16)
1681 {
1682 ✗ pcm_format = SND_PCM_FORMAT_S16_LE;
1683 }
1684 else
1685 {
1686 ✗ result = GATE_RESULT_INVALIDINPUT;
1687 ✗ break;
1688 }
1689
1690
1691 ✗ switch (impl->type)
1692 {
1693 ✗ case gate_audio_device_input:
1694 {
1695 ✗ if (impl->handle != NULL)
1696 {
1697 ✗ result = GATE_RESULT_INVALIDSTATE;
1698 ✗ break;
1699 }
1700
1701 /* assume failure until all functions return success */
1702 ✗ result = GATE_RESULT_FAILED;
1703
1704 ✗ pcm_code = alsa_snd.pcm_open(&handle, impl->id, SND_PCM_STREAM_CAPTURE, 0);
1705 ✗ if (pcm_code < 0)
1706 {
1707 ✗ GATE_DEBUG_TRACE("pcm_open() failed");
1708 ✗ break;
1709 }
1710
1711 ✗ pcm_code = alsa_snd.pcm_hw_params_malloc(&hw_params);
1712 ✗ if (pcm_code < 0)
1713 {
1714 ✗ GATE_DEBUG_TRACE("pcm_hw_params_malloc() failed");
1715 ✗ break;
1716 }
1717
1718 ✗ pcm_code = alsa_snd.pcm_hw_params_any(handle, hw_params);
1719 ✗ if (pcm_code < 0)
1720 {
1721 ✗ GATE_DEBUG_TRACE("pcm_hw_params_any() failed");
1722 ✗ break;
1723 }
1724
1725 ✗ pcm_code = alsa_snd.pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
1726 ✗ if (pcm_code < 0)
1727 {
1728 ✗ GATE_DEBUG_TRACE("pcm_hw_params_set_access() failed");
1729 ✗ break;
1730 }
1731
1732 ✗ pcm_code = alsa_snd.pcm_hw_params_set_format(handle, hw_params, pcm_format);
1733 ✗ if (pcm_code < 0)
1734 {
1735 ✗ GATE_DEBUG_TRACE("pcm_hw_params_set_format() failed");
1736 ✗ break;
1737 }
1738
1739 ✗ pcm_code = alsa_snd.pcm_hw_params_set_rate_near(handle, hw_params, &pcm_rate, NULL);
1740 ✗ if (pcm_code < 0)
1741 {
1742 ✗ GATE_DEBUG_TRACE("pcm_hw_params_set_rate_near() failed");
1743 ✗ break;
1744 }
1745
1746 ✗ pcm_code = alsa_snd.pcm_hw_params_set_channels(handle, hw_params, format->channels);
1747 ✗ if (pcm_code < 0)
1748 {
1749 ✗ GATE_DEBUG_TRACE("pcm_hw_params_set_channels() failed");
1750 ✗ break;
1751 }
1752
1753 ✗ pcm_code = alsa_snd.pcm_hw_params(handle, hw_params);
1754 ✗ if (pcm_code < 0)
1755 {
1756 ✗ GATE_DEBUG_TRACE("pcm_hw_params() failed");
1757 ✗ break;
1758 }
1759
1760 ✗ impl->format = *format;
1761 ✗ gate_atomic_int_set(&impl->format_defined, 1);
1762 ✗ impl->handle = handle;
1763 ✗ handle = NULL;
1764 ✗ result = GATE_RESULT_OK;
1765 ✗ break;
1766 }
1767 ✗ case gate_audio_device_output:
1768 {
1769 ✗ pcm_code = alsa_snd.pcm_open(&handle, impl->id, SND_PCM_STREAM_PLAYBACK, 0);
1770 ✗ if (pcm_code < 0)
1771 {
1772 ✗ GATE_DEBUG_TRACE("pcm_open() failed");
1773 ✗ break;
1774 }
1775
1776 ✗ pcm_code = alsa_snd.pcm_hw_params_malloc(&hw_params);
1777 ✗ if (pcm_code < 0)
1778 {
1779 ✗ GATE_DEBUG_TRACE("pcm_hw_params_malloc() failed");
1780 ✗ break;
1781 }
1782
1783 ✗ pcm_code = alsa_snd.pcm_hw_params_any(handle, hw_params);
1784 ✗ if (pcm_code < 0)
1785 {
1786 ✗ GATE_DEBUG_TRACE("pcm_hw_params_any() failed");
1787 ✗ break;
1788 }
1789
1790 ✗ pcm_code = alsa_snd.pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
1791 ✗ if (pcm_code < 0)
1792 {
1793 ✗ GATE_DEBUG_TRACE("pcm_hw_params_set_access() failed");
1794 ✗ break;
1795 }
1796
1797 ✗ pcm_code = alsa_snd.pcm_hw_params_set_format(handle, hw_params, pcm_format);
1798 ✗ if (pcm_code < 0)
1799 {
1800 ✗ GATE_DEBUG_TRACE("pcm_hw_params_set_format() failed");
1801 ✗ break;
1802 }
1803
1804 ✗ pcm_code = alsa_snd.pcm_hw_params_set_rate_near(handle, hw_params, &pcm_rate, NULL);
1805 ✗ if (pcm_code < 0)
1806 {
1807 ✗ GATE_DEBUG_TRACE("pcm_hw_params_set_rate_near() failed");
1808 ✗ break;
1809 }
1810
1811 ✗ pcm_code = alsa_snd.pcm_hw_params_set_channels(handle, hw_params, format->channels);
1812 ✗ if (pcm_code < 0)
1813 {
1814 ✗ GATE_DEBUG_TRACE("pcm_hw_params_set_channels() failed");
1815 ✗ break;
1816 }
1817
1818 ✗ pcm_code = alsa_snd.pcm_hw_params(handle, hw_params);
1819 ✗ if (pcm_code < 0)
1820 {
1821 ✗ GATE_DEBUG_TRACE("pcm_hw_params() failed");
1822 ✗ break;
1823 }
1824
1825 ✗ pcm_code = alsa_snd.pcm_prepare(handle);
1826 ✗ if (pcm_code < 0)
1827 {
1828 ✗ GATE_DEBUG_TRACE("pcm_prepare() failed");
1829 ✗ break;
1830 }
1831
1832 ✗ impl->format = *format;
1833 ✗ gate_atomic_int_set(&impl->format_defined, 1);
1834 ✗ impl->handle = handle;
1835 ✗ handle = NULL;
1836 ✗ result = GATE_RESULT_OK;
1837 ✗ break;
1838 }
1839 ✗ case gate_audio_device_unknown:
1840 {
1841 ✗ result = GATE_RESULT_NOTSUPPORTED;
1842 ✗ break;
1843 }
1844 }
1845 ✗ } while (0);
1846
1847 ✗ if (hw_params != NULL)
1848 {
1849 ✗ alsa_snd.pcm_hw_params_free(hw_params);
1850 }
1851 ✗ if (handle != NULL)
1852 {
1853 ✗ alsa_snd.pcm_close(handle);
1854 }
1855 ✗ return result;
1856 }
1857 ✗ static gate_result_t gate_audio_device_impl_close(void* device)
1858 {
1859 ✗ gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1860 ✗ gate_result_t result = GATE_RESULT_OK;
1861
1862 ✗ if (impl->handle != NULL)
1863 {
1864 ✗ alsa_snd.pcm_close(impl->handle);
1865 ✗ impl->handle = NULL;
1866 }
1867 ✗ return result;
1868 }
1869
1870 ✗ static gate_result_t gate_audio_device_impl_read(void* device, gate_audio_sample_t* sample)
1871 {
1872 ✗ gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1873 ✗ gate_result_t result = GATE_RESULT_FAILED;
1874 gate_size_t buffer_size;
1875 int pcm_code;
1876 char* buffer;
1877
1878 do
1879 {
1880 ✗ buffer_size = impl->sample_count * impl->format.channels * impl->format.bits_per_sample / 8;
1881 ✗ sample->format = impl->format;
1882 ✗ sample->data = gate_memoryblock_create(buffer_size);
1883 ✗ sample->meta_data = NULL;
1884 ✗ sample->record_time = 0;
1885 ✗ buffer = gate_memoryblock_get_content(sample->data);
1886
1887 ✗ pcm_code = alsa_snd.pcm_readi(impl->handle, buffer, buffer_size * 8 / impl->format.bits_per_sample);
1888 ✗ if (pcm_code < 0)
1889 {
1890 ✗ result = GATE_RESULT_FAILED;
1891 }
1892 else
1893 {
1894 ✗ sample->sample_count = pcm_code / impl->format.channels;
1895 ✗ result = GATE_RESULT_OK;
1896 }
1897 } while (0);
1898
1899 ✗ return result;
1900 }
1901 ✗ static gate_result_t gate_audio_device_impl_read_async(void* device, gate_delegate_t const* completion)
1902 {
1903 ✗ gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1904 ✗ gate_result_t result = GATE_RESULT_NOTIMPLEMENTED;
1905
1906 ✗ return result;
1907 }
1908 ✗ static gate_result_t gate_audio_device_impl_write(void* device, gate_audio_sample_t const* sample)
1909 {
1910 ✗ gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1911 ✗ gate_result_t result = GATE_RESULT_FAILED;
1912 int pcm_code;
1913 char* buffer;
1914 gate_size_t bufferlen;
1915 snd_pcm_sframes_t available_frames;
1916
1917 do
1918 {
1919 ✗ if (0 != gate_compare_audio_format(&sample->format, &impl->format))
1920 {
1921 ✗ result = GATE_RESULT_INVALIDINPUT;
1922 ✗ break;
1923 }
1924
1925 ✗ buffer = gate_memoryblock_get_content(sample->data);
1926 ✗ bufferlen = gate_memoryblock_get_size(sample->data);
1927
1928 ✗ pcm_code = alsa_snd.pcm_writei(impl->handle, buffer, sample->sample_count * sample->format.channels);
1929 ✗ if (pcm_code < 0)
1930 {
1931 ✗ result = GATE_RESULT_FAILED;
1932 ✗ break;
1933 }
1934
1935 ✗ available_frames = alsa_snd.pcm_avail(impl->handle);
1936 ✗ while (available_frames > 0)
1937 {
1938 ✗ gate_thread_sleep(1);
1939 ✗ available_frames = alsa_snd.pcm_avail(impl->handle);
1940 }
1941
1942 ✗ result = GATE_RESULT_OK;
1943 } while (0);
1944
1945 ✗ return result;
1946 }
1947
1948 ✗ static gate_result_t gate_audio_device_impl_write_async(
1949 void* device, gate_audio_sample_t const* sample, gate_delegate_t const* completion)
1950 {
1951 ✗ gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)impl;
1952 ✗ gate_result_t result = GATE_RESULT_NOTIMPLEMENTED;
1953
1954 ✗ return result;
1955 }
1956
1957
1958 ✗ gate_result_t gate_audio_devices_enum(gate_enumint_t type, gate_delegate_t const* callback, void* param)
1959 {
1960 ✗ gate_result_t result = GATE_RESULT_OK;
1961 gate_audio_alsa_impl_t* device;
1962
1963 ✗ if ((type == gate_audio_device_unknown) || (type == gate_audio_device_input))
1964 {
1965 ✗ gate_audio_alsa_impl_t* impl = gate_mem_alloc(sizeof(gate_audio_alsa_impl_t));
1966 ✗ gate_mem_clear(impl, sizeof(gate_audio_alsa_impl_t));
1967 ✗ gate_init_audio_device_vtbl_impl();
1968 ✗ impl->vtbl = &gate_audio_device_vtbl_impl;
1969
1970 ✗ gate_atomic_int_init(&impl->ref_counter, 1);
1971
1972 ✗ gate_str_print_text(impl->id, sizeof(impl->id), "default", 7);
1973 ✗ gate_str_print_text(impl->name, sizeof(impl->name), "Default Audio Input", 19);
1974 ✗ impl->type = gate_audio_device_input;
1975
1976 ✗ result = gate_delegate_invoke(callback, (gate_audio_device_t*)impl, param);
1977 }
1978
1979 ✗ if ((type == gate_audio_device_unknown) || (type == gate_audio_device_output))
1980 {
1981 ✗ gate_audio_alsa_impl_t* impl = gate_mem_alloc(sizeof(gate_audio_alsa_impl_t));
1982 ✗ gate_mem_clear(impl, sizeof(gate_audio_alsa_impl_t));
1983 ✗ gate_init_audio_device_vtbl_impl();
1984 ✗ impl->vtbl = &gate_audio_device_vtbl_impl;
1985
1986 ✗ gate_atomic_int_init(&impl->ref_counter, 1);
1987
1988 ✗ gate_str_print_text(impl->id, sizeof(impl->id), "default", 7);
1989 ✗ gate_str_print_text(impl->name, sizeof(impl->name), "Default Audio Output", 20);
1990 ✗ impl->type = gate_audio_device_output;
1991
1992 ✗ result = gate_delegate_invoke(callback, (gate_audio_device_t*)impl, param);
1993 }
1994
1995 ✗ return result;
1996 }
1997
1998
1999
2000 #endif /* GATE_IO_AUDIO_ALSA */
2001
2002
2003
2004
2005 #if defined(GATE_IO_AUDIO_NO_IMPL)
2006
2007 gate_result_t gate_audio_devices_enum(gate_enumint_t type, gate_delegate_t const* callback, void* param)
2008 {
2009 GATE_UNUSED_ARG(type);
2010 GATE_UNUSED_ARG(callback);
2011 GATE_UNUSED_ARG(param);
2012 return GATE_RESULT_NOTIMPLEMENTED;
2013 }
2014
2015 #endif /* GATE_IO_AUDIO_NO_IMPL */
2016