GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/audiosources.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 0 587 0.0%
Functions: 0 42 0.0%
Branches: 0 300 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_bool_t format_defined = false;
526
527 if (impl->output != NULL)
528 {
529 /* output stream */
530 /* not supported/do nothing */
531 }
532
533 if (impl->input != NULL)
534 {
535 /* input stream */
536
537 format_defined = gate_atomic_int_set(&impl->format_defined, 1);
538 if (!format_defined)
539 {
540 do
541 {
542 char hdr_buffer[36];
543 gate_size_t bytes_returned = 0;
544 gate_result_t result = gate_stream_read_block(impl->input, hdr_buffer, sizeof(hdr_buffer), &bytes_returned);
545 GATE_BREAK_IF_FAILED(result);
546
547 if (bytes_returned < sizeof(hdr_buffer))
548 {
549 gate_atomic_int_set(&impl->format_defined, 0);
550 break;
551 }
552
553 if (!gate_audio_riff_check_format(hdr_buffer, &impl->format, &impl->data_length))
554 {
555 gate_atomic_int_set(&impl->format_defined, 0);
556 break;
557 }
558 format_defined = true;
559 } while (0);
560 }
561 }
562
563 if (format_defined)
564 {
565 if ((format_buffer_count != 0) && (format_buffer != NULL))
566 {
567 format_buffer[0] = impl->format;
568 ret = 1;
569 }
570 }
571 return ret;
572 }
573
574 static gate_result_t gate_audio_device_wave_stream_open(void* device, gate_audio_format_t const* format, gate_size_t sample_count)
575 {
576 gate_audio_wave_stream_impl_t* const impl = (gate_audio_wave_stream_impl_t*)device;
577 gate_result_t ret = GATE_RESULT_FAILED;
578
579 GATE_UNUSED_ARG(sample_count);
580
581 do
582 {
583 if (impl->opened)
584 {
585 ret = GATE_RESULT_INVALIDSTATE;
586 break;
587 }
588
589 if (impl->input != NULL)
590 {
591 gate_audio_device_wave_stream_get_supported_formats(device, NULL, 0);
592 if (0 == gate_atomic_int_get(&impl->format_defined))
593 {
594 ret = GATE_RESULT_INVALIDHEADER;
595 break;
596 }
597 impl->opened = true;
598 ret = GATE_RESULT_OK;
599 }
600
601 if (impl->output != NULL)
602 {
603 char riff_hdrs[36];
604 char data_hdrs[8];
605 gate_size_t bytes_written;
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 do
639 {
640 if (!impl->opened)
641 {
642 /* is already closed */
643 break;
644 }
645
646 if (impl->output != NULL)
647 {
648 gate_int64_t cur_pos = 0;
649 gate_uint32_t data_len = 0;
650 char buffer[4];
651 gate_size_t len_written = 0;
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 GATE_DEBUG_TRACE_FAILED(ret, "gate_stream_seek(END) failed");
682
683 ret = gate_stream_flush(impl->output);
684 GATE_BREAK_IF_FAILED(ret);
685 }
686 } while (0);
687
688 return ret;
689 }
690
691 static gate_result_t gate_audio_device_wave_stream_read(void* device, gate_audio_sample_t* sample)
692 {
693 gate_audio_wave_stream_impl_t* impl = (gate_audio_wave_stream_impl_t*)device;
694 gate_result_t result = GATE_RESULT_OK;
695
696 do
697 {
698 gate_bool_t data_found = false;
699
700 if (!impl->opened)
701 {
702 result = GATE_RESULT_INVALIDSTATE;
703 break;
704 }
705
706 if (impl->input == NULL)
707 {
708 result = GATE_RESULT_NOTSUPPORTED;
709 break;
710 }
711 gate_mem_clear(sample, sizeof(gate_audio_sample_t));
712
713 while (!data_found)
714 {
715 char riff_hdr[8];
716 gate_size_t bytes_received;
717 gate_uint32_t data_len;
718
719 result = gate_stream_read_block(impl->input, riff_hdr, sizeof(riff_hdr), &bytes_received);
720 GATE_BREAK_IF_FAILED(result);
721 if (bytes_received == 0)
722 {
723 result = GATE_RESULT_ENDOFSTREAM;
724 break;
725 }
726 if (bytes_received != sizeof(riff_hdr))
727 {
728 result = GATE_RESULT_INVALIDHEADER;
729 break;
730 }
731
732 gate_deserialize_uint32_l(&riff_hdr[4], 4, &data_len);
733 if (0 == gate_str_comp_range(riff_hdr, "data", 4))
734 {
735 char* sample_data = NULL;
736
737 sample->format = impl->format;
738 sample->record_time = 0;
739 sample->meta_data = NULL;
740 sample->data = gate_memoryblock_create(data_len);
741 if (sample->data == NULL)
742 {
743 result = GATE_RESULT_OUTOFMEMORY;
744 break;
745 }
746 sample_data = gate_memoryblock_get_content(sample->data);
747 result = gate_stream_read_block(impl->input, sample_data, data_len, &bytes_received);
748 GATE_BREAK_IF_FAILED(result);
749
750 sample->sample_count = (gate_uint32_t)(bytes_received / ((gate_size_t)impl->format.channels * ((gate_size_t)impl->format.bits_per_sample / 8)));
751 data_found = true;
752 }
753 else
754 {
755 result = gate_stream_skip(impl->input, data_len, NULL);
756 GATE_BREAK_IF_FAILED(result);
757 }
758 }
759 } while (0);
760 return result;
761 }
762 static gate_result_t gate_audio_device_wave_stream_read_async(void* device, gate_delegate_t const* completion)
763 {
764 (void)device;
765 (void)completion;
766 return GATE_RESULT_NOTSUPPORTED;
767 }
768 static gate_result_t gate_audio_device_wave_stream_write(void* device, gate_audio_sample_t const* sample)
769 {
770 gate_audio_wave_stream_impl_t* impl = (gate_audio_wave_stream_impl_t*)device;
771 gate_result_t result = GATE_RESULT_FAILED;
772 do
773 {
774 //char hdr[8] = "data";
775 gate_uint32_t memsize;
776 char const* memdata;
777 gate_size_t data_written;
778
779 if (!impl->opened)
780 {
781 result = GATE_RESULT_INVALIDSTATE;
782 break;
783 }
784 if (impl->output == NULL)
785 {
786 result = GATE_RESULT_NOTSUPPORTED;
787 break;
788 }
789 memsize = (gate_uint32_t)gate_memoryblock_get_size(sample->data);
790 memdata = (char*)gate_memoryblock_get_content(sample->data);
791
792 /*gate_serialize_uint32_l(&hdr[4], 4, &memsize);
793 result = gate_stream_write_block((gate_stream_t*)impl->output, hdr, sizeof(hdr), &data_written);
794 GATE_BREAK_IF_FAILED(result);
795 */
796
797 result = gate_stream_write_block((gate_stream_t*)impl->output, memdata, memsize, &data_written);
798 } while (0);
799
800 return result;
801 }
802 static gate_result_t gate_audio_device_wave_stream_write_async(void* device, gate_audio_sample_t const* sample, gate_delegate_t const* completion)
803 {
804 (void)device;
805 (void)sample;
806 (void)completion;
807 return GATE_RESULT_NOTSUPPORTED;
808 }
809
810
811 gate_result_t gate_audio_create_wave_reader(gate_stream_t* input, gate_audio_device_t** ptr_reader)
812 {
813 gate_result_t ret;
814 do
815 {
816 gate_audio_wave_stream_impl_t* impl;
817
818 if ((input == NULL) || (ptr_reader == NULL))
819 {
820 ret = GATE_RESULT_INVALIDARG;
821 break;
822 }
823 impl = (gate_audio_wave_stream_impl_t*)gate_mem_alloc(sizeof(gate_audio_wave_stream_impl_t));
824 if (impl == NULL)
825 {
826 ret = GATE_RESULT_OUTOFMEMORY;
827 break;
828 }
829 gate_mem_clear(impl, sizeof(gate_audio_wave_stream_impl_t));
830 gate_init_audio_device_vtbl_wave_stream();
831 impl->vtbl = &gate_audio_device_vtbl_wave_stream;
832 impl->input = input;
833 gate_object_retain(impl->input);
834 gate_atomic_int_init(&impl->ref_counter, 1);
835 gate_atomic_int_set(&impl->format_defined, 0);
836 ret = GATE_RESULT_OK;
837 *ptr_reader = (gate_audio_device_t*)impl;
838 } while (0);
839 return ret;
840 }
841
842
843 gate_result_t gate_audio_create_wave_writer(gate_controlstream_t* output, gate_audio_device_t** ptr_writer)
844 {
845 gate_result_t ret;
846 do
847 {
848 gate_audio_wave_stream_impl_t* impl;
849
850 if ((output == NULL) || (ptr_writer == NULL))
851 {
852 ret = GATE_RESULT_INVALIDARG;
853 break;
854 }
855 impl = (gate_audio_wave_stream_impl_t*)gate_mem_alloc(sizeof(gate_audio_wave_stream_impl_t));
856 if (impl == NULL)
857 {
858 ret = GATE_RESULT_OUTOFMEMORY;
859 break;
860 }
861 gate_mem_clear(impl, sizeof(gate_audio_wave_stream_impl_t));
862 gate_init_audio_device_vtbl_wave_stream();
863 impl->vtbl = &gate_audio_device_vtbl_wave_stream;
864 impl->output = output;
865 gate_object_retain(impl->output);
866 gate_atomic_int_init(&impl->ref_counter, 1);
867 gate_atomic_int_set(&impl->format_defined, 0);
868 ret = GATE_RESULT_OK;
869 *ptr_writer = (gate_audio_device_t*)impl;
870 } while (0);
871 return ret;
872 }
873
874
875
876 #if defined(GATE_IO_AUDIO_WINAPI)
877
878 # if defined(UNICODE) || defined(_UNICODE)
879 # include <winsock2.h>
880 # else
881 # include <winsock.h>
882 # endif
883 # include <windows.h>
884 # include "gate/platforms.h"
885
886 struct gate_win32_format_mapping
887 {
888 DWORD win_format;
889 gate_audio_format_t gate_format;
890 };
891
892 static struct gate_win32_format_mapping gate_win32_all_formats[] =
893 {
894 #if defined(WAVE_FORMAT_48M08)
895 { WAVE_FORMAT_48M08, { 1, 48000, 1, 8 } },
896 #endif
897 #if defined(WAVE_FORMAT_48M16)
898 { WAVE_FORMAT_48M16, { 1, 48000, 1, 16 } },
899 #endif
900 #if defined(WAVE_FORMAT_48S08)
901 { WAVE_FORMAT_48S08, { 1, 48000, 2, 8 } },
902 #endif
903 #if defined(WAVE_FORMAT_48S16)
904 { WAVE_FORMAT_48S16, { 1, 48000, 2, 16 } },
905 #endif
906 #if defined(WAVE_FORMAT_96M08)
907 { WAVE_FORMAT_96M08, { 1, 96000, 1, 8 } },
908 #endif
909 #if defined(WAVE_FORMAT_96M16)
910 { WAVE_FORMAT_96M16, { 1, 96000, 1, 16 } },
911 #endif
912 #if defined(WAVE_FORMAT_96S08)
913 { WAVE_FORMAT_96S08, { 1, 96000, 2, 8 } },
914 #endif
915 #if defined(WAVE_FORMAT_96S16)
916 { WAVE_FORMAT_96S16, { 1, 96000, 2, 16 } },
917 #endif
918 { WAVE_FORMAT_1M08, { 1, 11025, 1, 8 } },
919 { WAVE_FORMAT_1M16, { 1, 11025, 1, 16 } },
920 { WAVE_FORMAT_1S08, { 1, 11025, 2, 8 } },
921 { WAVE_FORMAT_1S16, { 1, 11025, 2, 16 } },
922 { WAVE_FORMAT_2M08, { 1, 22050, 1, 8 } },
923 { WAVE_FORMAT_2M16, { 1, 22050, 1, 16 } },
924 { WAVE_FORMAT_2S08, { 1, 22050, 2, 8 } },
925 { WAVE_FORMAT_2S16, { 1, 22050, 2, 16 } },
926 { WAVE_FORMAT_4M08, { 1, 44100, 1, 8 } },
927 { WAVE_FORMAT_4M16, { 1, 44100, 1, 16 } },
928 { WAVE_FORMAT_4S08, { 1, 44100, 2, 8 } },
929 { WAVE_FORMAT_4S16, { 1, 44100, 2, 16 } },
930 };
931
932 typedef struct
933 {
934 UINT(WINAPI* MMwaveInGetNumDevs) (VOID);
935 MMRESULT(WINAPI* MMwaveInGetDevCaps) (UINT uDeviceID, LPWAVEINCAPS pwic, UINT cbwic);
936 MMRESULT(WINAPI* MMwaveInPrepareHeader) (HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
937 MMRESULT(WINAPI* MMwaveInUnprepareHeader) (HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
938 MMRESULT(WINAPI* MMwaveInAddBuffer) (HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
939 MMRESULT(WINAPI* MMwaveInOpen) (LPHWAVEIN phwi, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
940 MMRESULT(WINAPI* MMwaveInStart) (HWAVEIN hwi);
941 MMRESULT(WINAPI* MMwaveInReset) (HWAVEIN hwi);
942 MMRESULT(WINAPI* MMwaveInStop) (HWAVEIN hwi);
943 MMRESULT(WINAPI* MMwaveInClose) (HWAVEIN hwi);
944
945 UINT(WINAPI* MMwaveOutGetNumDevs) (VOID);
946 MMRESULT(WINAPI* MMwaveOutGetDevCaps) (UINT uDeviceID, LPWAVEOUTCAPS pwoc, UINT cbwoc);
947 MMRESULT(WINAPI* MMwaveOutPrepareHeader) (HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
948 MMRESULT(WINAPI* MMwaveOutUnprepareHeader) (HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
949 MMRESULT(WINAPI* MMwaveOutOpen) (LPHWAVEOUT phwo, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
950 MMRESULT(WINAPI* MMwaveOutWrite) (HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
951 MMRESULT(WINAPI* MMwaveOutReset) (HWAVEOUT hwo);
952 MMRESULT(WINAPI* MMwaveOutClose) (HWAVEOUT hwo);
953 } win32_audio_functions_t;
954
955 static win32_audio_functions_t win32_audio = GATE_INIT_EMPTY;
956 static volatile gate_bool_t win32_audio_functions_loaded = false;
957
958 static gate_bool_t load_winmm_functions()
959 {
960 static volatile HMODULE hmod_winmm = NULL;
961
962 do
963 {
964 if (win32_audio_functions_loaded)
965 {
966 break;
967 }
968
969 if (hmod_winmm == NULL)
970 {
971 hmod_winmm = LoadLibrary(_T("winmm.dll"));
972 if (hmod_winmm == NULL)
973 {
974 break;
975 }
976 }
977 //gate_win32_get_proc_address(hmod_winmm, "", &win32_audio.);
978
979 if (!gate_win32_get_proc_address(hmod_winmm, "waveInGetNumDevs", &win32_audio.MMwaveInGetNumDevs)) break;
980 if (!gate_win32_get_proc_address(hmod_winmm, GATE_WIN32_DUAL_NAME("waveInGetDevCaps"), &win32_audio.MMwaveInGetDevCaps)) break;
981 if (!gate_win32_get_proc_address(hmod_winmm, "waveInPrepareHeader", &win32_audio.MMwaveInPrepareHeader)) break;
982 if (!gate_win32_get_proc_address(hmod_winmm, "waveInUnprepareHeader", &win32_audio.MMwaveInUnprepareHeader)) break;
983 if (!gate_win32_get_proc_address(hmod_winmm, "waveInAddBuffer", &win32_audio.MMwaveInAddBuffer)) break;
984 if (!gate_win32_get_proc_address(hmod_winmm, "waveInOpen", &win32_audio.MMwaveInOpen)) break;
985 if (!gate_win32_get_proc_address(hmod_winmm, "waveInStart", &win32_audio.MMwaveInStart)) break;
986 if (!gate_win32_get_proc_address(hmod_winmm, "waveInReset", &win32_audio.MMwaveInReset)) break;
987 if (!gate_win32_get_proc_address(hmod_winmm, "waveInStop", &win32_audio.MMwaveInStop)) break;
988 if (!gate_win32_get_proc_address(hmod_winmm, "waveInClose", &win32_audio.MMwaveInClose)) break;
989
990 if (!gate_win32_get_proc_address(hmod_winmm, "waveOutGetNumDevs", &win32_audio.MMwaveOutGetNumDevs)) break;
991 if (!gate_win32_get_proc_address(hmod_winmm, GATE_WIN32_DUAL_NAME("waveOutGetDevCaps"), &win32_audio.MMwaveOutGetDevCaps)) break;
992 if (!gate_win32_get_proc_address(hmod_winmm, "waveOutPrepareHeader", &win32_audio.MMwaveOutPrepareHeader)) break;
993 if (!gate_win32_get_proc_address(hmod_winmm, "waveOutUnprepareHeader", &win32_audio.MMwaveOutUnprepareHeader)) break;
994 if (!gate_win32_get_proc_address(hmod_winmm, "waveOutOpen", &win32_audio.MMwaveOutOpen)) break;
995 if (!gate_win32_get_proc_address(hmod_winmm, "waveOutWrite", &win32_audio.MMwaveOutWrite)) break;
996 if (!gate_win32_get_proc_address(hmod_winmm, "waveOutReset", &win32_audio.MMwaveOutReset)) break;
997 if (!gate_win32_get_proc_address(hmod_winmm, "waveOutClose", &win32_audio.MMwaveOutClose)) break;
998
999 win32_audio_functions_loaded = true;
1000
1001 } while (0);
1002
1003 return win32_audio_functions_loaded;
1004 }
1005
1006 static gate_size_t gate_win32_get_formats(DWORD win_formats, gate_audio_format_t* formats, gate_size_t format_count)
1007 {
1008 static gate_size_t gate_win32_all_format_count = sizeof(gate_win32_all_formats) / sizeof(gate_win32_all_formats[0]);
1009 gate_size_t ret = 0;
1010 gate_size_t index;
1011
1012 for (index = 0; index != gate_win32_all_format_count; ++index)
1013 {
1014 if (win_formats & gate_win32_all_formats[index].win_format)
1015 {
1016 *formats = gate_win32_all_formats[index].gate_format;
1017 ++ret;
1018 ++formats;
1019 if (ret >= format_count)
1020 {
1021 break;
1022 }
1023 }
1024 }
1025 return ret;
1026 }
1027
1028 typedef struct gate_audio_device_impl
1029 {
1030 GATE_INTERFACE_VTBL(gate_audio_device) const* vtbl;
1031
1032 gate_atomic_int_t ref_counter;
1033 UINT device_id;
1034 char device_id_text[32];
1035 char device_name[128];
1036 gate_enumint_t device_type;
1037 HWAVEIN wave_in_handle;
1038 HWAVEOUT wave_out_handle;
1039 HANDLE event_handle;
1040 gate_audio_format_t supported_formats[32];
1041 gate_size_t supported_formats_count;
1042 gate_audio_format_t selected_format;
1043 gate_size_t default_sample_count;
1044
1045 gate_atomic_flag_t exequeue_running;
1046 gate_exequeue_t exequeue;
1047
1048 } gate_audio_device_impl_t;
1049
1050 static void gate_audio_device_impl_release(void* device)
1051 {
1052 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1053 if (gate_atomic_int_dec(&impl->ref_counter) == 0)
1054 {
1055 gate_audio_device_impl_close(device);
1056
1057 if (impl->event_handle != NULL)
1058 {
1059 CloseHandle(impl->event_handle);
1060 impl->event_handle = NULL;
1061 }
1062
1063 gate_mem_dealloc(impl);
1064 }
1065 }
1066 static int gate_audio_device_impl_retain(void* device)
1067 {
1068 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1069 return gate_atomic_int_inc(&impl->ref_counter);
1070 }
1071
1072 static char const* gate_audio_device_impl_get_id(void* device)
1073 {
1074 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1075 return impl->device_id_text;
1076 }
1077 static char const* gate_audio_device_impl_get_name(void* device)
1078 {
1079 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1080 return impl->device_name;
1081 }
1082 static gate_intptr_t gate_audio_device_impl_get_handle(void* device)
1083 {
1084 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1085 return (gate_intptr_t)impl->device_id;
1086 }
1087 static gate_enumint_t gate_audio_device_impl_get_device_type(void* device)
1088 {
1089 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1090 return impl->device_type;
1091 }
1092 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)
1093 {
1094 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1095 gate_size_t count = format_buffer_count > impl->supported_formats_count ? impl->supported_formats_count : format_buffer_count;
1096 gate_mem_copy(format_buffer, &impl->supported_formats[0], sizeof(gate_audio_format_t) * count);
1097 return count;
1098 }
1099
1100 static gate_result_t gate_audio_device_impl_open(void* device, gate_audio_format_t const* format, gate_size_t sample_count)
1101 {
1102 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
1103 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1104 WAVEFORMATEX format_ex;
1105 MMRESULT mm_result;
1106
1107 do
1108 {
1109 if (sample_count == 0)
1110 {
1111 sample_count = format->samples_per_second;
1112 }
1113
1114 impl->selected_format = *format;
1115 if (impl->event_handle == NULL)
1116 {
1117 impl->event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
1118 if (NULL == impl->event_handle)
1119 {
1120 ret = GATE_RESULT_OUTOFRESOURCES;
1121 break;
1122 }
1123 }
1124 impl->default_sample_count = sample_count;
1125
1126 format_ex.wFormatTag = (WORD)format->encoding_id;
1127 format_ex.nChannels = format->channels;
1128 format_ex.nSamplesPerSec = format->samples_per_second;
1129 format_ex.wBitsPerSample = format->bits_per_sample;
1130 format_ex.nBlockAlign = (format_ex.nChannels * format_ex.wBitsPerSample) >> 3;
1131 format_ex.nAvgBytesPerSec = (format_ex.nBlockAlign * format_ex.nSamplesPerSec);
1132 format_ex.cbSize = 0;
1133
1134 if (impl->device_type == gate_audio_device_input)
1135 {
1136 if (impl->wave_in_handle != NULL)
1137 {
1138 ret = GATE_RESULT_INVALIDSTATE;
1139 break;
1140 }
1141
1142 mm_result = win32_audio.MMwaveInOpen(&impl->wave_in_handle, impl->device_id, &format_ex,
1143 (DWORD_PTR)impl->event_handle, (DWORD_PTR)device, CALLBACK_EVENT);
1144 if (MMSYSERR_NOERROR != mm_result)
1145 {
1146 ret = GATE_RESULT_FAILED;
1147 impl->wave_in_handle = NULL;
1148 break;
1149 }
1150
1151 mm_result = win32_audio.MMwaveInStart(impl->wave_in_handle);
1152 if (MMSYSERR_NOERROR != mm_result)
1153 {
1154 ret = GATE_RESULT_FAILED;
1155 win32_audio.MMwaveInClose(impl->wave_in_handle);
1156 impl->wave_in_handle = NULL;
1157 break;
1158 }
1159
1160 ResetEvent(impl->event_handle);
1161 ret = GATE_RESULT_OK;
1162 }
1163 else if (impl->device_type == gate_audio_device_output)
1164 {
1165 if (impl->wave_out_handle != NULL)
1166 {
1167 ret = GATE_RESULT_INVALIDSTATE;
1168 break;
1169 }
1170
1171 mm_result = win32_audio.MMwaveOutOpen(&impl->wave_out_handle, impl->device_id, &format_ex,
1172 (DWORD_PTR)impl->event_handle, (DWORD_PTR)device, CALLBACK_EVENT);
1173 if (MMSYSERR_NOERROR != mm_result)
1174 {
1175 impl->wave_out_handle = NULL;
1176 ret = GATE_RESULT_FAILED;
1177 break;
1178 }
1179
1180 ResetEvent(impl->event_handle);
1181 ret = GATE_RESULT_OK;
1182 }
1183
1184 } while (0);
1185 return ret;
1186 }
1187 static gate_result_t gate_audio_device_impl_close(void* device)
1188 {
1189 gate_result_t ret = GATE_RESULT_OK;
1190 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1191
1192 if (impl->wave_in_handle != NULL)
1193 {
1194 win32_audio.MMwaveInStop(impl->wave_in_handle);
1195 win32_audio.MMwaveInReset(impl->wave_in_handle);
1196 win32_audio.MMwaveInClose(impl->wave_in_handle);
1197 impl->wave_in_handle = NULL;
1198 }
1199
1200 if (impl->wave_out_handle != NULL)
1201 {
1202 win32_audio.MMwaveOutReset(impl->wave_out_handle);
1203 win32_audio.MMwaveOutClose(impl->wave_out_handle);
1204 impl->wave_out_handle = NULL;
1205 }
1206
1207 return ret;
1208 }
1209
1210 static gate_result_t gate_audio_device_impl_read(void* device, gate_audio_sample_t* sample)
1211 {
1212 gate_result_t ret = GATE_RESULT_FAILED;
1213 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1214
1215 WAVEHDR wavehdr;
1216 char* ptr_buffer = NULL;
1217 MMRESULT mm_result;
1218
1219 gate_size_t buffersize;
1220
1221 do
1222 {
1223 if (impl->wave_in_handle == NULL)
1224 {
1225 ret = GATE_RESULT_INVALIDSTATE;
1226 break;
1227 }
1228
1229 gate_mem_clear(sample, sizeof(gate_audio_sample_t));
1230
1231 buffersize = impl->default_sample_count
1232 * impl->selected_format.channels
1233 * impl->selected_format.bits_per_sample
1234 / 8
1235 ;
1236
1237 if (buffersize == 0)
1238 {
1239 ret = GATE_RESULT_INVALIDARG;
1240 break;
1241 }
1242
1243 sample->sample_count = (gate_uint32_t)impl->default_sample_count;
1244 sample->format = impl->selected_format;
1245 sample->record_time = 0;
1246 sample->data = gate_memoryblock_create(buffersize);
1247 if (sample->data == NULL)
1248 {
1249 ret = GATE_RESULT_OUTOFMEMORY;
1250 break;
1251 }
1252 ptr_buffer = (char*)gate_memoryblock_get_content(sample->data);
1253
1254 gate_mem_clear(&wavehdr, sizeof(wavehdr));
1255 wavehdr.dwBufferLength = (DWORD)buffersize;
1256 wavehdr.lpData = ptr_buffer;
1257
1258 mm_result = win32_audio.MMwaveInPrepareHeader(impl->wave_in_handle, &wavehdr, sizeof(wavehdr));
1259 if (MMSYSERR_NOERROR != mm_result)
1260 {
1261 ret = GATE_RESULT_FAILED;
1262 break;
1263 }
1264
1265 mm_result = win32_audio.MMwaveInAddBuffer(impl->wave_in_handle, &wavehdr, sizeof(wavehdr));
1266 if (MMSYSERR_NOERROR != mm_result)
1267 {
1268 mm_result = win32_audio.MMwaveInUnprepareHeader(impl->wave_in_handle, &wavehdr, sizeof(wavehdr));
1269 ret = GATE_RESULT_FAILED;
1270 break;
1271 }
1272
1273 WaitForSingleObject(impl->event_handle, INFINITE);
1274 mm_result = win32_audio.MMwaveInUnprepareHeader(impl->wave_in_handle, &wavehdr, sizeof(wavehdr));
1275 sample->sample_count = wavehdr.dwBytesRecorded * 8
1276 / impl->selected_format.bits_per_sample
1277 / impl->selected_format.channels;
1278 sample->format = impl->selected_format;
1279 ret = GATE_RESULT_OK;
1280
1281 } while (0);
1282
1283 if (GATE_FAILED(ret))
1284 {
1285 if (sample->data != NULL)
1286 {
1287 gate_object_release(sample->data);
1288 }
1289 if (sample->meta_data != NULL)
1290 {
1291 gate_object_release(sample->meta_data);
1292 }
1293 gate_mem_clear(sample, sizeof(gate_audio_sample_t));
1294 }
1295 return ret;
1296 }
1297 static gate_result_t gate_audio_device_impl_write(void* device, gate_audio_sample_t const* sample)
1298 {
1299 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1300 gate_result_t ret = GATE_RESULT_OK;
1301
1302 WAVEHDR wavehdr;
1303 MMRESULT mm_result;
1304
1305 do
1306 {
1307 if (impl->wave_out_handle == NULL)
1308 {
1309 ret = GATE_RESULT_INVALIDSTATE;
1310 break;
1311 }
1312 gate_mem_clear(&wavehdr, sizeof(wavehdr));
1313
1314 wavehdr.dwBufferLength = (DWORD)gate_memoryblock_get_size(sample->data);
1315 wavehdr.lpData = (char*)gate_memoryblock_get_content(sample->data);
1316
1317 if ((wavehdr.lpData == NULL) || (wavehdr.dwBufferLength == 0))
1318 {
1319 ret = GATE_RESULT_INVALIDARG;
1320 break;
1321 }
1322
1323 mm_result = win32_audio.MMwaveOutPrepareHeader(impl->wave_out_handle, &wavehdr, (UINT)sizeof(wavehdr));
1324 if (mm_result != MMSYSERR_NOERROR)
1325 {
1326 ret = GATE_RESULT_FAILED;
1327 break;
1328 }
1329 mm_result = win32_audio.MMwaveOutWrite(impl->wave_out_handle, &wavehdr, (UINT)sizeof(wavehdr));
1330 if (mm_result != MMSYSERR_NOERROR)
1331 {
1332 ret = GATE_RESULT_FAILED;
1333 mm_result = win32_audio.MMwaveOutUnprepareHeader(impl->wave_out_handle, &wavehdr, (UINT)sizeof(wavehdr));
1334 break;
1335 }
1336
1337 WaitForSingleObject(impl->event_handle, INFINITE);
1338 mm_result = win32_audio.MMwaveOutUnprepareHeader(impl->wave_out_handle, &wavehdr, (UINT)sizeof(wavehdr));
1339 ret = GATE_RESULT_OK;
1340 } while (0);
1341
1342 return ret;
1343 }
1344
1345 //static gate_result_t /
1346
1347 static gate_result_t gate_audio_device_impl_read_async(void* device, gate_delegate_t const* completion)
1348 {
1349 gate_audio_device_impl_t* impl = (gate_audio_device_impl_t*)device;
1350 gate_result_t result = GATE_RESULT_FAILED;
1351
1352 do
1353 {
1354 if (gate_atomic_flag_set(&impl->exequeue_running) == false)
1355 {
1356 result = gate_exequeue_create(&impl->exequeue, NULL, NULL, NULL);
1357 GATE_BREAK_IF_FAILED(result);
1358 }
1359 /*TODO*/
1360 //gate_exequeue_push(impl->exequeue, )
1361
1362 } while (0);
1363
1364 return result;
1365 }
1366
1367 static gate_result_t gate_audio_device_impl_write_async(void* device, gate_audio_sample_t const* sample, gate_delegate_t const* completion)
1368 {
1369 gate_result_t result = GATE_RESULT_OK;
1370 /* gate_audio_device_impl_t* const impl = (gate_audio_device_impl_t*)device; */
1371
1372 /*TODO*/
1373
1374 return result;
1375 }
1376
1377
1378 gate_result_t gate_audio_devices_enum(gate_enumint_t type, gate_delegate_t const* callback, void* param)
1379 {
1380 gate_result_t ret = GATE_RESULT_OK;
1381 UINT num_devs;
1382 UINT dev_index;
1383 WAVEINCAPS incaps;
1384 WAVEOUTCAPS outcaps;
1385 MMRESULT mmresult;
1386
1387 if (!load_winmm_functions())
1388 {
1389 return GATE_RESULT_NOTSUPPORTED;
1390 }
1391
1392 num_devs = win32_audio.MMwaveInGetNumDevs();
1393
1394 if ((type == gate_audio_device_unknown) || (type == gate_audio_device_input))
1395 {
1396 for (dev_index = 0; dev_index < num_devs; dev_index++)
1397 {
1398 mmresult = win32_audio.MMwaveInGetDevCaps(dev_index, &incaps, sizeof(incaps));
1399 if (MMSYSERR_NOERROR == mmresult)
1400 {
1401 gate_audio_device_impl_t* impl = gate_mem_alloc(sizeof(gate_audio_device_impl_t));
1402 if (impl != NULL)
1403 {
1404 gate_mem_clear(impl, sizeof(gate_audio_device_impl_t));
1405 gate_init_audio_device_vtbl_impl();
1406 impl->vtbl = &gate_audio_device_vtbl_impl;
1407
1408 gate_atomic_int_init(&impl->ref_counter, 1);
1409
1410 impl->device_id = dev_index;
1411 impl->device_type = gate_audio_device_input;
1412
1413 gate_str_print_uint(&impl->device_id_text[1], sizeof(impl->device_id_text) - 1, dev_index, 0);
1414 impl->device_id_text[0] = 'I';
1415
1416 gate_win32_winstr_2_utf8(incaps.szPname, sizeof(incaps.szPname) / sizeof(incaps.szPname[0]),
1417 impl->device_name, sizeof(impl->device_name));
1418
1419 impl->wave_in_handle = NULL;
1420 impl->wave_out_handle = NULL;
1421 impl->event_handle = NULL;
1422
1423 impl->supported_formats_count = gate_win32_get_formats(
1424 incaps.dwFormats, impl->supported_formats,
1425 sizeof(impl->supported_formats) / sizeof(impl->supported_formats[0]));
1426
1427 ret = gate_delegate_invoke(callback, (gate_audio_device_t*)impl, param);
1428 }
1429
1430 if (impl != NULL)
1431 {
1432 gate_object_release(impl);
1433 }
1434
1435 GATE_BREAK_IF_FAILED(ret);
1436 }
1437 }
1438
1439 }
1440
1441 if ((type == gate_audio_device_unknown) || (type == gate_audio_device_output))
1442 {
1443 if (GATE_SUCCEEDED(ret))
1444 {
1445 num_devs = win32_audio.MMwaveOutGetNumDevs();
1446
1447 for (dev_index = 0; dev_index < num_devs; dev_index++)
1448 {
1449 mmresult = win32_audio.MMwaveOutGetDevCaps(dev_index, &outcaps, sizeof(outcaps));
1450 if (MMSYSERR_NOERROR == mmresult)
1451 {
1452 gate_audio_device_impl_t* impl = gate_mem_alloc(sizeof(gate_audio_device_impl_t));
1453 if (impl != NULL)
1454 {
1455 gate_mem_clear(impl, sizeof(gate_audio_device_impl_t));
1456 gate_init_audio_device_vtbl_impl();
1457 impl->vtbl = &gate_audio_device_vtbl_impl;
1458
1459 gate_atomic_int_init(&impl->ref_counter, 1);
1460
1461 impl->device_id = dev_index;
1462 impl->device_type = gate_audio_device_output;
1463
1464 gate_str_print_uint(&impl->device_id_text[1], sizeof(impl->device_id_text) - 1, dev_index, 0);
1465 impl->device_id_text[0] = 'O';
1466
1467 gate_win32_winstr_2_utf8(outcaps.szPname, sizeof(outcaps.szPname) / sizeof(outcaps.szPname[0]),
1468 impl->device_name, sizeof(impl->device_name));
1469
1470 impl->wave_in_handle = NULL;
1471 impl->wave_out_handle = NULL;
1472 impl->event_handle = NULL;
1473
1474 impl->supported_formats_count = gate_win32_get_formats(
1475 outcaps.dwFormats, impl->supported_formats,
1476 sizeof(impl->supported_formats) / sizeof(impl->supported_formats[0]));
1477
1478 ret = gate_delegate_invoke(callback, impl, param);
1479 }
1480
1481 if (impl != NULL)
1482 {
1483 gate_object_release(impl);
1484 }
1485
1486 GATE_BREAK_IF_FAILED(ret);
1487 }
1488 }
1489 }
1490 }
1491 return ret;
1492 }
1493
1494 #endif /* GATE_IO_AUDIO_WINAPI */
1495
1496
1497
1498 #if defined(GATE_IO_AUDIO_ALSA)
1499
1500 #include <alsa/asoundlib.h> /*libasound2-dev*/
1501
1502 struct gate_audio_alsa_snd_code
1503 {
1504 int (*pcm_open) (snd_pcm_t** pcm, const char* name, snd_pcm_stream_t stream, int mode);
1505 int (*pcm_close) (snd_pcm_t* pcm);
1506 int (*pcm_hw_params_malloc) (snd_pcm_hw_params_t** ptr);
1507 int (*pcm_hw_params_any) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params);
1508 int (*pcm_hw_params_set_access) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params, snd_pcm_access_t access);
1509 int (*pcm_hw_params_set_format) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params, snd_pcm_format_t format);
1510 int (*pcm_hw_params_set_rate_near) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params, unsigned int* val, int* dir);
1511 int (*pcm_hw_params_set_channels) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params, unsigned int val);
1512 void(*pcm_hw_params_free) (snd_pcm_hw_params_t* obj);
1513 int (*pcm_hw_params) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params);
1514 int (*pcm_prepare) (snd_pcm_t* pcm);
1515 snd_pcm_sframes_t(*pcm_readi) (snd_pcm_t* pcm, void* buffer, snd_pcm_uframes_t size);
1516 snd_pcm_sframes_t(*pcm_writei) (snd_pcm_t* pcm, const void* buffer, snd_pcm_uframes_t size);
1517 snd_pcm_sframes_t(*pcm_avail) (snd_pcm_t* pcm);
1518 snd_pcm_state_t(*pcm_state) (snd_pcm_t* pcm);
1519 };
1520
1521 static struct gate_audio_alsa_snd_code alsa_snd = GATE_INIT_EMPTY;
1522
1523 static gate_result_t gate_audio_alsa_init()
1524 {
1525 static gate_string_t alsa_lib_name = GATE_STRING_INIT_STATIC("libasound.so");
1526 static gate_library_t alsa_library = NULL;
1527
1528 gate_library_t tmp_lib = NULL;
1529 gate_result_t result = GATE_RESULT_FAILED;
1530
1531 if (alsa_library == NULL)
1532 {
1533 do
1534 {
1535 GATE_BREAK_IF_FAILED(result = gate_library_open(&alsa_lib_name, &tmp_lib, GATE_LIBRARY_FLAG_DEFAULT));
1536
1537 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_open", &alsa_snd.pcm_open));
1538 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_close", &alsa_snd.pcm_close));
1539 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params_malloc", &alsa_snd.pcm_hw_params_malloc));
1540 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params_any", &alsa_snd.pcm_hw_params_any));
1541 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));
1542 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));
1543 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));
1544 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));
1545 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params_free", &alsa_snd.pcm_hw_params_free));
1546 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params", &alsa_snd.pcm_hw_params));
1547 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_prepare", &alsa_snd.pcm_prepare));
1548 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_readi", &alsa_snd.pcm_readi));
1549 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_open", &alsa_snd.pcm_open));
1550 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_writei", &alsa_snd.pcm_writei));
1551 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_avail", &alsa_snd.pcm_avail));
1552 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_state", &alsa_snd.pcm_state));
1553
1554 alsa_library = tmp_lib;
1555 tmp_lib = NULL;
1556 result = GATE_RESULT_OK;
1557 } while (0);
1558
1559 if (tmp_lib != NULL)
1560 {
1561 gate_library_close(tmp_lib);
1562 }
1563 }
1564 else
1565 {
1566 result = GATE_RESULT_OK;
1567 }
1568 return result;
1569 }
1570
1571
1572 typedef struct gate_audio_alsa_impl
1573 {
1574 GATE_INTERFACE_VTBL(gate_audio_device) const* vtbl;
1575
1576 gate_atomic_int_t ref_counter;
1577 char id[256];
1578 char name[256];
1579 snd_pcm_t* handle;
1580 gate_enumint_t type;
1581
1582 gate_audio_format_t format;
1583 gate_atomic_int_t format_defined;
1584 gate_uint32_t sample_count;
1585
1586 } gate_audio_alsa_impl_t;
1587
1588
1589 static void gate_audio_device_impl_release(void* device)
1590 {
1591 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1592 if (0 == gate_atomic_int_dec(&impl->ref_counter))
1593 {
1594 gate_audio_device_impl_close(impl);
1595 gate_mem_dealloc(impl);
1596 }
1597 }
1598 static int gate_audio_device_impl_retain(void* device)
1599 {
1600 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1601 return gate_atomic_int_inc(&impl->ref_counter);
1602 }
1603
1604 static char const* gate_audio_device_impl_get_id(void* device)
1605 {
1606 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1607 return impl->id;
1608 }
1609 static char const* gate_audio_device_impl_get_name(void* device)
1610 {
1611 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1612 return impl->name;
1613 }
1614 static gate_intptr_t gate_audio_device_impl_get_handle(void* device)
1615 {
1616 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1617 return (gate_intptr_t)(void*)impl->handle;
1618 }
1619 static gate_enumint_t gate_audio_device_impl_get_device_type(void* device)
1620 {
1621 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1622 return impl->type;
1623 }
1624
1625 static gate_audio_format_t const alsa_all_formats[] =
1626 {
1627 { 1, 44100, 2, 16 },
1628 { 1, 44100, 1, 16 },
1629 { 1, 44100, 2, 8 },
1630 { 1, 44100, 1, 8 },
1631
1632 { 1, 22050, 2, 16 },
1633 { 1, 22050, 1, 16 },
1634 { 1, 22050, 2, 8 },
1635 { 1, 22050, 1, 8 },
1636
1637 { 1, 11025, 2, 16 },
1638 { 1, 11025, 1, 16 },
1639 { 1, 11025, 2, 8 },
1640 { 1, 11025, 1, 8 }
1641 };
1642
1643 static gate_size_t gate_audio_device_impl_get_supported_formats(
1644 void* device, gate_audio_format_t* format_buffer, gate_size_t format_buffer_count)
1645 {
1646 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1647 static gate_size_t const alsa_all_formats_count = sizeof(alsa_all_formats) / sizeof(alsa_all_formats[0]);
1648 gate_size_t ret = format_buffer_count < alsa_all_formats_count ? format_buffer_count : alsa_all_formats_count;
1649 gate_size_t index;
1650
1651 for (index = 0; index != ret; ++index)
1652 {
1653 format_buffer[index] = alsa_all_formats[index];
1654 }
1655 return ret;
1656 }
1657
1658 static gate_result_t gate_audio_device_impl_open(void* device, gate_audio_format_t const* format, gate_size_t sample_count)
1659 {
1660 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1661 gate_result_t result = GATE_RESULT_FAILED;
1662 int pcm_code;
1663 snd_pcm_t* handle = NULL;
1664 snd_pcm_hw_params_t* hw_params = NULL;
1665 int pcm_format;
1666 unsigned int pcm_rate = format->samples_per_second;
1667
1668 do
1669 {
1670 result = gate_audio_alsa_init();
1671 GATE_BREAK_IF_FAILED(result);
1672
1673 if (sample_count == 0)
1674 {
1675 impl->sample_count = format->samples_per_second;
1676 }
1677 else
1678 {
1679 impl->sample_count = sample_count;
1680 }
1681
1682 if (format->bits_per_sample == 8)
1683 {
1684 pcm_format = SND_PCM_FORMAT_U8;
1685 }
1686 else if (format->bits_per_sample == 16)
1687 {
1688 pcm_format = SND_PCM_FORMAT_S16_LE;
1689 }
1690 else
1691 {
1692 result = GATE_RESULT_INVALIDINPUT;
1693 break;
1694 }
1695
1696
1697 switch (impl->type)
1698 {
1699 case gate_audio_device_input:
1700 {
1701 if (impl->handle != NULL)
1702 {
1703 result = GATE_RESULT_INVALIDSTATE;
1704 break;
1705 }
1706
1707 /* assume failure until all functions return success */
1708 result = GATE_RESULT_FAILED;
1709
1710 pcm_code = alsa_snd.pcm_open(&handle, impl->id, SND_PCM_STREAM_CAPTURE, 0);
1711 if (pcm_code < 0)
1712 {
1713 GATE_DEBUG_TRACE("pcm_open() failed");
1714 break;
1715 }
1716
1717 pcm_code = alsa_snd.pcm_hw_params_malloc(&hw_params);
1718 if (pcm_code < 0)
1719 {
1720 GATE_DEBUG_TRACE("pcm_hw_params_malloc() failed");
1721 break;
1722 }
1723
1724 pcm_code = alsa_snd.pcm_hw_params_any(handle, hw_params);
1725 if (pcm_code < 0)
1726 {
1727 GATE_DEBUG_TRACE("pcm_hw_params_any() failed");
1728 break;
1729 }
1730
1731 pcm_code = alsa_snd.pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
1732 if (pcm_code < 0)
1733 {
1734 GATE_DEBUG_TRACE("pcm_hw_params_set_access() failed");
1735 break;
1736 }
1737
1738 pcm_code = alsa_snd.pcm_hw_params_set_format(handle, hw_params, pcm_format);
1739 if (pcm_code < 0)
1740 {
1741 GATE_DEBUG_TRACE("pcm_hw_params_set_format() failed");
1742 break;
1743 }
1744
1745 pcm_code = alsa_snd.pcm_hw_params_set_rate_near(handle, hw_params, &pcm_rate, NULL);
1746 if (pcm_code < 0)
1747 {
1748 GATE_DEBUG_TRACE("pcm_hw_params_set_rate_near() failed");
1749 break;
1750 }
1751
1752 pcm_code = alsa_snd.pcm_hw_params_set_channels(handle, hw_params, format->channels);
1753 if (pcm_code < 0)
1754 {
1755 GATE_DEBUG_TRACE("pcm_hw_params_set_channels() failed");
1756 break;
1757 }
1758
1759 pcm_code = alsa_snd.pcm_hw_params(handle, hw_params);
1760 if (pcm_code < 0)
1761 {
1762 GATE_DEBUG_TRACE("pcm_hw_params() failed");
1763 break;
1764 }
1765
1766 impl->format = *format;
1767 gate_atomic_int_set(&impl->format_defined, 1);
1768 impl->handle = handle;
1769 handle = NULL;
1770 result = GATE_RESULT_OK;
1771 break;
1772 }
1773 case gate_audio_device_output:
1774 {
1775 pcm_code = alsa_snd.pcm_open(&handle, impl->id, SND_PCM_STREAM_PLAYBACK, 0);
1776 if (pcm_code < 0)
1777 {
1778 GATE_DEBUG_TRACE("pcm_open() failed");
1779 break;
1780 }
1781
1782 pcm_code = alsa_snd.pcm_hw_params_malloc(&hw_params);
1783 if (pcm_code < 0)
1784 {
1785 GATE_DEBUG_TRACE("pcm_hw_params_malloc() failed");
1786 break;
1787 }
1788
1789 pcm_code = alsa_snd.pcm_hw_params_any(handle, hw_params);
1790 if (pcm_code < 0)
1791 {
1792 GATE_DEBUG_TRACE("pcm_hw_params_any() failed");
1793 break;
1794 }
1795
1796 pcm_code = alsa_snd.pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
1797 if (pcm_code < 0)
1798 {
1799 GATE_DEBUG_TRACE("pcm_hw_params_set_access() failed");
1800 break;
1801 }
1802
1803 pcm_code = alsa_snd.pcm_hw_params_set_format(handle, hw_params, pcm_format);
1804 if (pcm_code < 0)
1805 {
1806 GATE_DEBUG_TRACE("pcm_hw_params_set_format() failed");
1807 break;
1808 }
1809
1810 pcm_code = alsa_snd.pcm_hw_params_set_rate_near(handle, hw_params, &pcm_rate, NULL);
1811 if (pcm_code < 0)
1812 {
1813 GATE_DEBUG_TRACE("pcm_hw_params_set_rate_near() failed");
1814 break;
1815 }
1816
1817 pcm_code = alsa_snd.pcm_hw_params_set_channels(handle, hw_params, format->channels);
1818 if (pcm_code < 0)
1819 {
1820 GATE_DEBUG_TRACE("pcm_hw_params_set_channels() failed");
1821 break;
1822 }
1823
1824 pcm_code = alsa_snd.pcm_hw_params(handle, hw_params);
1825 if (pcm_code < 0)
1826 {
1827 GATE_DEBUG_TRACE("pcm_hw_params() failed");
1828 break;
1829 }
1830
1831 pcm_code = alsa_snd.pcm_prepare(handle);
1832 if (pcm_code < 0)
1833 {
1834 GATE_DEBUG_TRACE("pcm_prepare() failed");
1835 break;
1836 }
1837
1838 impl->format = *format;
1839 gate_atomic_int_set(&impl->format_defined, 1);
1840 impl->handle = handle;
1841 handle = NULL;
1842 result = GATE_RESULT_OK;
1843 break;
1844 }
1845 case gate_audio_device_unknown:
1846 {
1847 result = GATE_RESULT_NOTSUPPORTED;
1848 break;
1849 }
1850 }
1851 } while (0);
1852
1853 if (hw_params != NULL)
1854 {
1855 alsa_snd.pcm_hw_params_free(hw_params);
1856 }
1857 if (handle != NULL)
1858 {
1859 alsa_snd.pcm_close(handle);
1860 }
1861 return result;
1862 }
1863 static gate_result_t gate_audio_device_impl_close(void* device)
1864 {
1865 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1866 gate_result_t result = GATE_RESULT_OK;
1867
1868 if (impl->handle != NULL)
1869 {
1870 alsa_snd.pcm_close(impl->handle);
1871 impl->handle = NULL;
1872 }
1873 return result;
1874 }
1875
1876 static gate_result_t gate_audio_device_impl_read(void* device, gate_audio_sample_t* sample)
1877 {
1878 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1879 gate_result_t result = GATE_RESULT_FAILED;
1880 gate_size_t buffer_size;
1881 int pcm_code;
1882 char* buffer;
1883
1884 do
1885 {
1886 buffer_size = impl->sample_count * impl->format.channels * impl->format.bits_per_sample / 8;
1887 sample->format = impl->format;
1888 sample->data = gate_memoryblock_create(buffer_size);
1889 sample->meta_data = NULL;
1890 sample->record_time = 0;
1891 buffer = gate_memoryblock_get_content(sample->data);
1892
1893 pcm_code = alsa_snd.pcm_readi(impl->handle, buffer, buffer_size * 8 / impl->format.bits_per_sample);
1894 if (pcm_code < 0)
1895 {
1896 result = GATE_RESULT_FAILED;
1897 }
1898 else
1899 {
1900 sample->sample_count = pcm_code / impl->format.channels;
1901 result = GATE_RESULT_OK;
1902 }
1903 } while (0);
1904
1905 return result;
1906 }
1907 static gate_result_t gate_audio_device_impl_read_async(void* device, gate_delegate_t const* completion)
1908 {
1909 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1910 gate_result_t result = GATE_RESULT_NOTIMPLEMENTED;
1911
1912 return result;
1913 }
1914 static gate_result_t gate_audio_device_impl_write(void* device, gate_audio_sample_t const* sample)
1915 {
1916 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
1917 gate_result_t result = GATE_RESULT_FAILED;
1918 int pcm_code;
1919 char* buffer;
1920 gate_size_t bufferlen;
1921 snd_pcm_sframes_t available_frames;
1922
1923 do
1924 {
1925 if (0 != gate_compare_audio_format(&sample->format, &impl->format))
1926 {
1927 result = GATE_RESULT_INVALIDINPUT;
1928 break;
1929 }
1930
1931 buffer = gate_memoryblock_get_content(sample->data);
1932 bufferlen = gate_memoryblock_get_size(sample->data);
1933
1934 pcm_code = alsa_snd.pcm_writei(impl->handle, buffer, sample->sample_count * sample->format.channels);
1935 if (pcm_code < 0)
1936 {
1937 result = GATE_RESULT_FAILED;
1938 break;
1939 }
1940
1941 available_frames = alsa_snd.pcm_avail(impl->handle);
1942 while (available_frames > 0)
1943 {
1944 gate_thread_sleep(1);
1945 available_frames = alsa_snd.pcm_avail(impl->handle);
1946 }
1947
1948 result = GATE_RESULT_OK;
1949 } while (0);
1950
1951 return result;
1952 }
1953
1954 static gate_result_t gate_audio_device_impl_write_async(
1955 void* device, gate_audio_sample_t const* sample, gate_delegate_t const* completion)
1956 {
1957 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)impl;
1958 gate_result_t result = GATE_RESULT_NOTIMPLEMENTED;
1959
1960 return result;
1961 }
1962
1963
1964 gate_result_t gate_audio_devices_enum(gate_enumint_t type, gate_delegate_t const* callback, void* param)
1965 {
1966 gate_result_t result = GATE_RESULT_OK;
1967 gate_audio_alsa_impl_t* device;
1968
1969 if ((type == gate_audio_device_unknown) || (type == gate_audio_device_input))
1970 {
1971 gate_audio_alsa_impl_t* impl = gate_mem_alloc(sizeof(gate_audio_alsa_impl_t));
1972 gate_mem_clear(impl, sizeof(gate_audio_alsa_impl_t));
1973 gate_init_audio_device_vtbl_impl();
1974 impl->vtbl = &gate_audio_device_vtbl_impl;
1975
1976 gate_atomic_int_init(&impl->ref_counter, 1);
1977
1978 gate_str_print_text(impl->id, sizeof(impl->id), "default", 7);
1979 gate_str_print_text(impl->name, sizeof(impl->name), "Default Audio Input", 19);
1980 impl->type = gate_audio_device_input;
1981
1982 result = gate_delegate_invoke(callback, (gate_audio_device_t*)impl, param);
1983 }
1984
1985 if ((type == gate_audio_device_unknown) || (type == gate_audio_device_output))
1986 {
1987 gate_audio_alsa_impl_t* impl = gate_mem_alloc(sizeof(gate_audio_alsa_impl_t));
1988 gate_mem_clear(impl, sizeof(gate_audio_alsa_impl_t));
1989 gate_init_audio_device_vtbl_impl();
1990 impl->vtbl = &gate_audio_device_vtbl_impl;
1991
1992 gate_atomic_int_init(&impl->ref_counter, 1);
1993
1994 gate_str_print_text(impl->id, sizeof(impl->id), "default", 7);
1995 gate_str_print_text(impl->name, sizeof(impl->name), "Default Audio Output", 20);
1996 impl->type = gate_audio_device_output;
1997
1998 result = gate_delegate_invoke(callback, (gate_audio_device_t*)impl, param);
1999 }
2000
2001 return result;
2002 }
2003
2004
2005
2006 #endif /* GATE_IO_AUDIO_ALSA */
2007
2008
2009
2010
2011 #if defined(GATE_IO_AUDIO_NO_IMPL)
2012
2013 gate_result_t gate_audio_devices_enum(gate_enumint_t type, gate_delegate_t const* callback, void* param)
2014 {
2015 GATE_UNUSED_ARG(type);
2016 GATE_UNUSED_ARG(callback);
2017 GATE_UNUSED_ARG(param);
2018 return GATE_RESULT_NOTIMPLEMENTED;
2019 }
2020
2021 #endif /* GATE_IO_AUDIO_NO_IMPL */
2022