GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/audiosources.c
Date: 2025-09-14 13:10:38
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
1493
1494 /*
1495 class AudioReader : public IAsyncAudioInputStream, protected Lockable
1496 {
1497 public:
1498 friend class AudioStreamService;
1499
1500 typedef IAsyncAudioInputStream::AsyncReadDelegate AsyncReadDelegate;
1501 virtual result_t beginRead(intptr_t nLength, const AsyncReadDelegate & delRead, intptr_t nParam);
1502 virtual result_t endRead();
1503
1504 typedef IAudioStreamService::DeviceRef DeviceRef;
1505
1506 AudioReader(AudioStreamService& rService, IExecutionQueue* pQueue, DeviceRef refDevice, AudioFormat const & rFormat, intptr_t nHandle, dword_t dwDefaultSampleCount = 0);
1507
1508 AudioFormat const & Format() const;
1509 DeviceRef WaveDevice();
1510 intptr_t Handle();
1511
1512 void dispatchEvent(HWAVEIN hwi, UINT uMsg, LPWAVEHDR pHdr);
1513 void processEvent(HWAVEIN hwi, UINT uMsg, LPWAVEHDR pHdr);
1514 void processSample(AutoPtr<AudioSample> ptrSample);
1515
1516 result_t close();
1517
1518 protected:
1519 AudioStreamService* m_service;
1520 IExecutionQueue* m_queue;
1521 DeviceRef m_device;
1522 AudioFormat m_format;
1523 intptr_t m_handle;
1524 dword_t m_dwDefaultSampleCount;
1525 bool m_bStarted;
1526
1527 //intptr_t BufferSize;
1528 //LPWAVEHDR Buffer1;
1529 //LPWAVEHDR Buffer2;
1530 //AudioFormat RecordFormat;
1531 bool Closed;
1532
1533 struct ReadJob
1534 {
1535 AsyncReadDelegate ReadCallback;
1536 intptr_t Length;
1537 intptr_t Param;
1538 WAVEHDR Header;
1539 MemStream Buffer;
1540 };
1541
1542 typedef List<ReadJob> ReadJobList;
1543 ReadJobList m_listReadJobs;
1544
1545 private:
1546 AudioReader(const AudioReader & r);
1547 AudioReader& operator=(const AudioReader & r);
1548
1549 };
1550
1551
1552
1553 class AudioWriter : public IAsyncAudioOutputStream, protected Lockable
1554 {
1555 public:
1556 friend class AudioStreamService;
1557
1558 typedef IAsyncAudioOutputStream::AsyncWriteDelegate AsyncWriteDelegate;
1559 virtual result_t beginWrite(AudioSample const * atData, intptr_t nLength, const AsyncWriteDelegate & delWrite, intptr_t nParam);
1560 virtual result_t endWrite();
1561
1562 void dispatchEvent(HWAVEOUT hwo, UINT msg, LPWAVEHDR wavehdr);
1563 void processEvent(HWAVEOUT hwo, UINT msg, LPWAVEHDR wavehdr);
1564
1565 result_t close();
1566
1567
1568 typedef IAudioStreamService::DeviceRef DeviceRef;
1569
1570 protected:
1571 AudioWriter(AudioStreamService & rService, IExecutionQueue* pQueue, DeviceRef refDevice, AudioFormat const & rFormat, intptr_t nHandle);
1572
1573 AudioStreamService* m_pService;
1574 IExecutionQueue* m_queue;
1575 DeviceRef m_refDevice;
1576 AudioFormat m_format;
1577 intptr_t m_handle;
1578 bool m_started;
1579
1580 struct WriteJob
1581 {
1582 AsyncWriteDelegate WriteCallback;
1583 intptr_t Length;
1584 intptr_t Param;
1585 WAVEHDR Header;
1586 AudioSample Sample;
1587 };
1588
1589 typedef List<WriteJob> WriteJobList;
1590
1591 WriteJobList m_listWriteJobs;
1592
1593 result_t processSample(WriteJob & sample);
1594
1595 private:
1596 AudioWriter(const AudioWriter & r);
1597 AudioWriter& operator=(const AudioWriter & r);
1598 };
1599
1600
1601
1602
1603
1604 struct WaveInMetaData
1605 {
1606 AudioReader * Reader;
1607 intptr_t BufferSize;
1608 LPWAVEHDR Buffer1;
1609 LPWAVEHDR Buffer2;
1610 AudioFormat RecordFormat;
1611 bool Closed;
1612
1613 WaveInMetaData(AudioReader * poCtrl, intptr_t nBufferSize)
1614 : Reader(poCtrl), BufferSize(nBufferSize), Buffer1(0), Buffer2(0), Closed(false)
1615 {
1616 }
1617 };
1618
1619
1620
1621 void CALLBACK g_audiostream_waveInProc(HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD)
1622 {
1623 AudioReader * poReader = reinterpret_cast<AudioReader*>(DWORD_PTR(dwInstance));
1624 if (poReader)
1625 {
1626 LPWAVEHDR pwh = reinterpret_cast<LPWAVEHDR>(DWORD_PTR(dwParam1));
1627 poReader->dispatchEvent(hwi, uMsg, pwh);
1628 }
1629 }
1630
1631 void CALLBACK g_audiostream_waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, DWORD dwParam1, DWORD)
1632 {
1633 AudioWriter * poWriter = reinterpret_cast<AudioWriter*>(DWORD_PTR(dwInstance));
1634 if (poWriter)
1635 {
1636 LPWAVEHDR pwh = reinterpret_cast<LPWAVEHDR>(DWORD_PTR(dwParam1));
1637 poWriter->dispatchEvent(hwo, uMsg, pwh);
1638 }
1639 }
1640
1641
1642
1643 */
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657 ///////////////////////////////////////////////
1658 // //
1659 // class AudioStreamService implementation //
1660 // //
1661 ///////////////////////////////////////////////
1662
1663
1664 /*
1665
1666 AudioStreamService::AudioStreamService()
1667 {
1668 this->m_exequeue.create();
1669 this->m_queue = &*this->m_exequeue;
1670 }
1671
1672 AudioStreamService::AudioStreamService(IExecutionQueue* pQueue)
1673 : m_queue(pQueue)
1674 {
1675 }
1676
1677 AudioStreamService::~AudioStreamService() throw()
1678 {
1679 }
1680
1681 void AudioStreamService::run()
1682 {
1683 this->m_queue->run();
1684 }
1685
1686 result_t AudioStreamService::quit()
1687 {
1688 return this->m_queue->quit();
1689 }
1690
1691
1692 result_t AudioStreamService::getDevices(Array<DeviceRef>& raDevs)
1693 {
1694 result_t resReturn = AudioInputStream::getDevices(raDevs);
1695 if (resReturn != results::Ok) return resReturn;
1696 return AudioOutputStream::getDevices(raDevs);
1697 }
1698
1699 result_t AudioStreamService::open(DeviceRef refDev, AudioFormat const & rFormat, Ref<IAsyncAudioInputStream>& rrefReader)
1700 {
1701 HWAVEIN hwi = 0;
1702
1703 WAVEFORMATEX uFormatEx;
1704 uFormatEx.wFormatTag = WAVE_FORMAT_PCM;
1705 uFormatEx.nChannels = rFormat.Channels;
1706 uFormatEx.nSamplesPerSec = rFormat.SamplesPerSecond;
1707 uFormatEx.wBitsPerSample = rFormat.BitsPerSample;
1708 uFormatEx.nBlockAlign = (uFormatEx.nChannels * uFormatEx.wBitsPerSample) >> 3;
1709 uFormatEx.nAvgBytesPerSec = (uFormatEx.nBlockAlign * uFormatEx.nSamplesPerSec);
1710 uFormatEx.cbSize = 0;
1711
1712 Ref<AudioReader> refReader(new AudioReader(*this, this->m_queue, refDev, rFormat, 0));
1713
1714 MMRESULT iResult = ::waveInOpen(&hwi, UINT(refDev->Handle()), &uFormatEx, DWORD_PTR(&g_audiostream_waveInProc), DWORD_PTR(&*refReader), CALLBACK_FUNCTION);
1715 if (iResult == MMSYSERR_NOERROR)
1716 {
1717 Lock l(this);
1718 intptr_t nHandle = intptr_t(hwi);
1719 refReader->m_handle = nHandle;
1720 this->m_listReader.add(refReader);
1721 rrefReader = refReader;
1722 //this->m_mapHandles.add(nHandle, nHandle);
1723 //this->m_mapDevices.add(nHandle, roDev);
1724 //this->m_mapFormats.add(nHandle, roFormat);
1725 //this->m_mapSounds.add(nHandle, SoundList());
1726 //this->m_mapMeta.add(nHandle, poMeta);
1727 return results::Ok;
1728 }
1729 else
1730 {
1731 return result_t(iResult);
1732 }
1733 }
1734
1735 result_t AudioStreamService::open(DeviceRef refDev, AudioFormat const & rFormat, Ref<IAsyncAudioOutputStream>& rrefWriter)
1736 {
1737 HWAVEOUT hwo = 0;
1738
1739 WAVEFORMATEX uFormatEx;
1740 uFormatEx.wFormatTag = WAVE_FORMAT_PCM;
1741 uFormatEx.nChannels = rFormat.Channels;
1742 uFormatEx.nSamplesPerSec = rFormat.SamplesPerSecond;
1743 uFormatEx.wBitsPerSample = rFormat.BitsPerSample;
1744 uFormatEx.nBlockAlign = (uFormatEx.nChannels * uFormatEx.wBitsPerSample) >> 3;
1745 uFormatEx.nAvgBytesPerSec = (uFormatEx.nBlockAlign * uFormatEx.nSamplesPerSec);
1746 uFormatEx.cbSize = 0;
1747
1748 Ref<AudioWriter> refWriter(new AudioWriter(*this, this->m_queue, refDev, rFormat, 0));
1749
1750 MMRESULT iResult = ::waveOutOpen(&hwo, UINT(refDev->Handle()), &uFormatEx, DWORD_PTR(g_audiostream_waveOutProc), DWORD_PTR(&*refWriter), CALLBACK_FUNCTION); //DWORD_PTR(this->m_pvHandle), 0, CALLBACK_WINDOW);
1751 if (iResult == MMSYSERR_NOERROR)
1752 {
1753 Lock l(this);
1754 intptr_t nHandle = intptr_t(hwo);
1755 //Ref<AudioWriter> refWriter = new AudioWriter(*this, &this->m_queue, rFormat, nHandle);
1756 refWriter->m_handle = nHandle;
1757 this->m_listWriter.add(refWriter);
1758 rrefWriter = refWriter;
1759 //this->m_mapHandles.add(nHandle, nHandle);
1760 //this->m_mapDevices.add(nHandle, roDev);
1761 //this->m_mapFormats.add(nHandle, roFormat);
1762 //this->m_mapSounds.add(nHandle, SoundList());
1763
1764 //rnHandle = nHandle;
1765 return results::Ok;
1766 }
1767 else
1768 {
1769 return result_t(iResult);
1770 }
1771 }
1772
1773 result_t AudioStreamService::close(Ref<IAsyncAudioInputStream> refReader)
1774 {
1775 Ref<AudioReader> reader;
1776 Lock l(this);
1777 for (AudioInputList::Iterator iter(this->m_listReader); !!iter; ++iter)
1778 {
1779 if (static_cast<IAsyncAudioInputStream*>(iter->get()) == refReader.get())
1780 {
1781 reader = *iter;
1782 this->m_listReader.remove(iter);
1783 break;
1784 }
1785 }
1786 if (!reader) return results::NoMatch;
1787 return reader->close();
1788 }
1789
1790 result_t AudioStreamService::close(Ref<IAsyncAudioOutputStream> refWriter)
1791 {
1792 Ref<AudioWriter> writer;
1793 Lock l(this);
1794 for (AudioOutputList::Iterator iter(this->m_listWriter); !!iter; ++iter)
1795 {
1796 if (static_cast<IAsyncAudioOutputStream*>(iter->get()) == refWriter.get())
1797 {
1798 writer = *iter;
1799 this->m_listWriter.remove(iter);
1800 break;
1801 }
1802 }
1803 if (!writer) return results::NoMatch;
1804 return writer->close();
1805 }
1806
1807
1808 */
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820 ////////////////////////////////////////////////////////////
1821 // //
1822 // class AudioStreamService::AudioWriter implementation //
1823 // //
1824 ////////////////////////////////////////////////////////////
1825
1826 /*
1827 AudioWriter::AudioWriter(AudioStreamService & rService, IExecutionQueue* pQueue, DeviceRef refDevice, AudioFormat const & rFormat, intptr_t nHandle)
1828 : m_pService(&rService), m_queue(pQueue), m_refDevice(refDevice),
1829 m_format(rFormat), m_handle(nHandle), m_started(false)
1830 {
1831 }
1832
1833 result_t AudioWriter::beginWrite(AudioSample const * atData, intptr_t nLength, const AsyncWriteDelegate & delWrite, intptr_t nParam)
1834 {
1835 if (nLength <= 0) return results::InvalidParameter;
1836 for (intptr_t n = 1; n < nLength; ++n)
1837 {
1838 if (atData[n].Format != atData[0].Format)
1839 {
1840 return results::InvalidContent;
1841 }
1842 }
1843
1844 WriteJob * ptrJob = 0;
1845 {
1846 Lock l(this);
1847 WriteJobList::Iterator job = this->m_listWriteJobs.add(WriteJob());
1848 job->Sample.Format = atData[0].Format;
1849 job->Sample.MetaData = atData[0].MetaData;
1850 job->WriteCallback = delWrite;
1851 job->Length = 1;
1852 job->Param = nParam;
1853 for (intptr_t n = 0; n < nLength; ++n) job->Sample.Data.write(atData[n].Data);
1854 ptrJob = &*job;
1855 }
1856 return this->processSample(*ptrJob);
1857
1858 if (!this->m_started)
1859 {
1860 this->m_started = true;
1861 //::waveoutst
1862 }
1863 return results::Ok;
1864 }
1865
1866 result_t AudioWriter::endWrite()
1867 {
1868 return results::NotImplemented;
1869 }
1870
1871 result_t AudioWriter::processSample(WriteJob & job)
1872 {
1873 HWAVEOUT hwo = reinterpret_cast<HWAVEOUT>(this->m_handle);
1874 Mem::clear(&job.Header, sizeof(job.Header));
1875 job.Header.dwBufferLength = DWORD(job.Sample.Data.Length());
1876 job.Header.lpData = &job.Sample.Data[0];
1877 MMRESULT iResult = waveOutPrepareHeader(hwo, &job.Header, UINT(sizeof(job.Header)));
1878 if (MMSYSERR_NOERROR == iResult)
1879 {
1880 iResult = waveOutWrite(hwo, &job.Header, UINT(sizeof(job.Header)));
1881 }
1882 return result_t(iResult);
1883 }
1884
1885
1886 void AudioWriter::dispatchEvent(HWAVEOUT hwo, UINT msg, LPWAVEHDR wavehdr)
1887 {
1888 GTry
1889 {
1890 AutoPtr<IRunnable> ptrInvoke = new Executor3<void, HWAVEOUT, UINT, LPWAVEHDR>(&AudioWriter::processEvent, this, hwo, msg, wavehdr);
1891 this->m_queue->invoke(ptrInvoke);
1892 }
1893 GCatchAll()
1894 {
1895 }
1896 }
1897
1898 void AudioWriter::processEvent(HWAVEOUT hwo, UINT msg, LPWAVEHDR wavehdr)
1899 {
1900 switch (msg)
1901 {
1902 case WOM_CLOSE:
1903 {
1904 break;
1905 }
1906 case WOM_DONE:
1907 {
1908 ::waveOutUnprepareHeader(hwo, wavehdr, sizeof(WAVEHDR));
1909 OptionalVar<WriteJob> job;
1910 {
1911 Lock l(this);
1912 for (WriteJobList::Iterator iter(this->m_listWriteJobs); !!iter; ++iter)
1913 {
1914 if (&iter->Header == wavehdr)
1915 {
1916 job.create();
1917 job->WriteCallback = iter->WriteCallback;
1918 job->Header = iter->Header;
1919 job->Sample.swap(iter->Sample);
1920 job->Param = iter->Param;
1921 job->Length = iter->Length;
1922 this->m_listWriteJobs.remove(iter);
1923 break;
1924 }
1925 //iter->WriteCallback(this, results::Ok,
1926 }
1927 }
1928 if (!!job)
1929 {
1930 job->WriteCallback(this, results::Ok, &job->Sample, job->Length, 1, job->Param);
1931 }
1932 break;
1933 }
1934 case WOM_OPEN:
1935 {
1936 break;
1937 }
1938 }
1939 }
1940
1941 result_t AudioWriter::close()
1942 {
1943 HWAVEOUT hwo = reinterpret_cast<HWAVEOUT>(this->m_handle);
1944 waveOutReset(hwo);
1945 waveOutClose(hwo);
1946 return results::Ok;
1947 }
1948
1949 */
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959 ////////////////////////////////////////////////////////////
1960 // //
1961 // class AudioStreamService::AudioReader implementation //
1962 // //
1963 ////////////////////////////////////////////////////////////
1964
1965 /*
1966 AudioReader::AudioReader(AudioStreamService & rService, IExecutionQueue * pQueue, DeviceRef refDevice, AudioFormat const & rFormat, intptr_t nHandle, dword_t dwDefaultSampleCount)
1967 : m_service(&rService), m_queue(pQueue), m_device(refDevice),
1968 m_format(rFormat), m_handle(nHandle), m_dwDefaultSampleCount(dwDefaultSampleCount), m_bStarted(false)
1969 {
1970 if (!m_dwDefaultSampleCount) m_dwDefaultSampleCount = rFormat.SamplesPerSecond;
1971 }
1972
1973 result_t AudioReader::beginRead(intptr_t nLength, const AsyncReadDelegate & delRead, intptr_t nParam)
1974 {
1975 if (nLength <= 0) return results::InvalidParameter;
1976
1977 MMRESULT iResult = MMSYSERR_NOERROR;
1978 HWAVEIN hwi = reinterpret_cast<HWAVEIN>(this->m_handle);
1979 intptr_t nBufferSize = this->m_dwDefaultSampleCount
1980 * this->m_format.Channels
1981 * this->m_format.BitsPerSample
1982 * nLength
1983 / 8;
1984 {
1985 Lock l(this);
1986 ReadJobList::Iterator entry = this->m_listReadJobs.add(ReadJob());
1987 entry->ReadCallback = delRead;
1988 entry->Length = nLength;
1989 entry->Param = nParam;
1990 char * ptrBuffer = entry->Buffer.createContent(nBufferSize);
1991 LPWAVEHDR pwh = &entry->Header;
1992 Mem::clear(pwh, sizeof(entry->Header));
1993 pwh->dwFlags = 0;
1994 pwh->dwLoops = 0;
1995 pwh->dwUser = 1;
1996 pwh->lpNext = 0;
1997 pwh->reserved = 0;
1998 pwh->dwBufferLength = DWORD(nBufferSize);
1999 pwh->dwBytesRecorded = 0;
2000 pwh->lpData = ptrBuffer;
2001
2002 iResult = ::waveInPrepareHeader(hwi, pwh, sizeof(entry->Header));
2003 if (MMSYSERR_NOERROR == iResult)
2004 {
2005 iResult = ::waveInAddBuffer(hwi, pwh, sizeof(WAVEHDR));
2006 }
2007 }
2008
2009 if (iResult == MMSYSERR_NOERROR)
2010 {
2011 if (!m_bStarted)
2012 {
2013 m_bStarted = true;
2014 iResult = ::waveInStart(hwi);
2015 if (iResult != MMSYSERR_NOERROR)
2016 {
2017 m_bStarted = false;
2018 }
2019 }
2020 }
2021
2022 return result_t(iResult);
2023 }
2024
2025 result_t AudioReader::endRead()
2026 {
2027 HWAVEIN hwi = reinterpret_cast<HWAVEIN>(this->m_handle);
2028 MMRESULT iResult = ::waveInStop(hwi);
2029 if (iResult == MMSYSERR_NOERROR) iResult = ::waveInReset(hwi);
2030 return result_t(iResult);
2031 }
2032
2033 void AudioReader::processEvent(HWAVEIN hwi, UINT uMsg, LPWAVEHDR pwh)
2034 {
2035 switch (uMsg)
2036 {
2037 case WIM_OPEN:
2038 break;
2039 case WIM_DATA:
2040 {
2041 if (pwh)
2042 {
2043 //MMRESULT iResult =
2044 ::waveInUnprepareHeader(hwi, pwh, sizeof(WAVEHDR));
2045 //if(MMSYSERR_NOERROR == iResult)
2046 {
2047 AudioSample sample;
2048 AsyncReadDelegate delCallback;
2049 intptr_t nReqLength = 0;
2050 intptr_t nParam = 0;
2051 {
2052 Lock l(this);
2053 for (ReadJobList::Iterator iter(this->m_listReadJobs); !!iter; ++iter)
2054 {
2055 if (pwh == &iter->Header)
2056 {
2057 nParam = iter->Param;
2058 nReqLength = iter->Length;
2059 delCallback = iter->ReadCallback;
2060 sample.Format = this->m_format;
2061 sample.SampleCount = pwh->dwBytesRecorded * 8 / this->m_format.Channels / this->m_format.BitsPerSample;
2062 sample.Data.swap(iter->Buffer);
2063 this->m_listReadJobs.remove(iter);
2064 break;
2065 }
2066 }
2067 }
2068 if (!!delCallback)
2069 {
2070 delCallback(this, results::Ok, &sample, nReqLength, 1, nParam);
2071 }
2072
2073 }
2074 //else
2075 {
2076 // GATE_BREAKPOINT;
2077 }
2078 }
2079 break;
2080 }
2081 case WIM_CLOSE:
2082 {
2083 this->Closed = true;
2084 break;
2085 }
2086 }
2087 }
2088
2089 void AudioReader::processSample(AutoPtr<AudioSample> ptrSample)
2090 {
2091 ReadJob job;
2092 {
2093 Lock l(this);
2094 ReadJobList::Iterator iter(this->m_listReadJobs);
2095 if (iter)
2096 {
2097 job = *iter;
2098 this->m_listReadJobs.remove(iter);
2099 }
2100 }
2101 if (!!job.ReadCallback) job.ReadCallback(this, results::Ok, ptrSample.get(), job.Length, 1, job.Param);
2102 }
2103
2104 void AudioReader::dispatchEvent(HWAVEIN hwi, UINT uMsg, LPWAVEHDR pHdr)
2105 {
2106 GTry
2107 {
2108 AutoPtr<IRunnable> ptr = new Executor3<void, HWAVEIN, UINT, LPWAVEHDR>(&AudioReader::processEvent, this, hwi, uMsg, pHdr);
2109 this->m_queue->invoke(ptr);
2110 }
2111 GCatchAll()
2112 {
2113 }
2114 }
2115
2116 result_t AudioReader::close()
2117 {
2118 HWAVEIN hwi = reinterpret_cast<HWAVEIN>(this->m_handle);
2119 waveInReset(hwi);
2120 waveInClose(hwi);
2121 return results::Ok;
2122 }
2123
2124 */
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138 #if defined(GATE_IO_AUDIO_ALSA)
2139
2140 #include <alsa/asoundlib.h> /*libasound2-dev*/
2141
2142 struct gate_audio_alsa_snd_code
2143 {
2144 int (*pcm_open) (snd_pcm_t** pcm, const char* name, snd_pcm_stream_t stream, int mode);
2145 int (*pcm_close) (snd_pcm_t* pcm);
2146 int (*pcm_hw_params_malloc) (snd_pcm_hw_params_t** ptr);
2147 int (*pcm_hw_params_any) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params);
2148 int (*pcm_hw_params_set_access) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params, snd_pcm_access_t access);
2149 int (*pcm_hw_params_set_format) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params, snd_pcm_format_t format);
2150 int (*pcm_hw_params_set_rate_near) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params, unsigned int* val, int* dir);
2151 int (*pcm_hw_params_set_channels) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params, unsigned int val);
2152 void(*pcm_hw_params_free) (snd_pcm_hw_params_t* obj);
2153 int (*pcm_hw_params) (snd_pcm_t* pcm, snd_pcm_hw_params_t* params);
2154 int (*pcm_prepare) (snd_pcm_t* pcm);
2155 snd_pcm_sframes_t(*pcm_readi) (snd_pcm_t* pcm, void* buffer, snd_pcm_uframes_t size);
2156 snd_pcm_sframes_t(*pcm_writei) (snd_pcm_t* pcm, const void* buffer, snd_pcm_uframes_t size);
2157 snd_pcm_sframes_t(*pcm_avail) (snd_pcm_t* pcm);
2158 snd_pcm_state_t(*pcm_state) (snd_pcm_t* pcm);
2159 };
2160
2161 static struct gate_audio_alsa_snd_code alsa_snd = GATE_INIT_EMPTY;
2162
2163 static gate_result_t gate_audio_alsa_init()
2164 {
2165 static gate_string_t alsa_lib_name = GATE_STRING_INIT_STATIC("libasound.so");
2166 static gate_library_t alsa_library = NULL;
2167
2168 gate_library_t tmp_lib = NULL;
2169 gate_result_t result = GATE_RESULT_FAILED;
2170
2171 if (alsa_library == NULL)
2172 {
2173 do
2174 {
2175 GATE_BREAK_IF_FAILED(result = gate_library_open(&alsa_lib_name, &tmp_lib, GATE_LIBRARY_FLAG_DEFAULT));
2176
2177 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_open", &alsa_snd.pcm_open));
2178 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_close", &alsa_snd.pcm_close));
2179 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params_malloc", &alsa_snd.pcm_hw_params_malloc));
2180 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params_any", &alsa_snd.pcm_hw_params_any));
2181 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));
2182 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));
2183 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));
2184 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));
2185 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params_free", &alsa_snd.pcm_hw_params_free));
2186 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_hw_params", &alsa_snd.pcm_hw_params));
2187 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_prepare", &alsa_snd.pcm_prepare));
2188 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_readi", &alsa_snd.pcm_readi));
2189 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_open", &alsa_snd.pcm_open));
2190 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_writei", &alsa_snd.pcm_writei));
2191 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_avail", &alsa_snd.pcm_avail));
2192 GATE_BREAK_IF_FAILED(result = gate_library_get_function_name(tmp_lib, "snd_pcm_state", &alsa_snd.pcm_state));
2193
2194 alsa_library = tmp_lib;
2195 tmp_lib = NULL;
2196 result = GATE_RESULT_OK;
2197 } while (0);
2198
2199 if (tmp_lib != NULL)
2200 {
2201 gate_library_close(tmp_lib);
2202 }
2203 }
2204 else
2205 {
2206 result = GATE_RESULT_OK;
2207 }
2208 return result;
2209 }
2210
2211
2212 typedef struct gate_audio_alsa_impl
2213 {
2214 GATE_INTERFACE_VTBL(gate_audio_device) const* vtbl;
2215
2216 gate_atomic_int_t ref_counter;
2217 char id[256];
2218 char name[256];
2219 snd_pcm_t* handle;
2220 gate_enumint_t type;
2221
2222 gate_audio_format_t format;
2223 gate_atomic_int_t format_defined;
2224 gate_uint32_t sample_count;
2225
2226 } gate_audio_alsa_impl_t;
2227
2228
2229 static void gate_audio_device_impl_release(void* device)
2230 {
2231 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
2232 if (0 == gate_atomic_int_dec(&impl->ref_counter))
2233 {
2234 gate_audio_device_impl_close(impl);
2235 gate_mem_dealloc(impl);
2236 }
2237 }
2238 static int gate_audio_device_impl_retain(void* device)
2239 {
2240 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
2241 return gate_atomic_int_inc(&impl->ref_counter);
2242 }
2243
2244 static char const* gate_audio_device_impl_get_id(void* device)
2245 {
2246 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
2247 return impl->id;
2248 }
2249 static char const* gate_audio_device_impl_get_name(void* device)
2250 {
2251 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
2252 return impl->name;
2253 }
2254 static gate_intptr_t gate_audio_device_impl_get_handle(void* device)
2255 {
2256 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
2257 return (gate_intptr_t)(void*)impl->handle;
2258 }
2259 static gate_enumint_t gate_audio_device_impl_get_device_type(void* device)
2260 {
2261 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
2262 return impl->type;
2263 }
2264
2265 static gate_audio_format_t const alsa_all_formats[] =
2266 {
2267 { 1, 44100, 2, 16 },
2268 { 1, 44100, 1, 16 },
2269 { 1, 44100, 2, 8 },
2270 { 1, 44100, 1, 8 },
2271
2272 { 1, 22050, 2, 16 },
2273 { 1, 22050, 1, 16 },
2274 { 1, 22050, 2, 8 },
2275 { 1, 22050, 1, 8 },
2276
2277 { 1, 11025, 2, 16 },
2278 { 1, 11025, 1, 16 },
2279 { 1, 11025, 2, 8 },
2280 { 1, 11025, 1, 8 }
2281 };
2282
2283 static gate_size_t gate_audio_device_impl_get_supported_formats(
2284 void* device, gate_audio_format_t* format_buffer, gate_size_t format_buffer_count)
2285 {
2286 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
2287 static gate_size_t const alsa_all_formats_count = sizeof(alsa_all_formats) / sizeof(alsa_all_formats[0]);
2288 gate_size_t ret = format_buffer_count < alsa_all_formats_count ? format_buffer_count : alsa_all_formats_count;
2289 gate_size_t index;
2290
2291 for (index = 0; index != ret; ++index)
2292 {
2293 format_buffer[index] = alsa_all_formats[index];
2294 }
2295 return ret;
2296 }
2297
2298 static gate_result_t gate_audio_device_impl_open(void* device, gate_audio_format_t const* format, gate_size_t sample_count)
2299 {
2300 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
2301 gate_result_t result = GATE_RESULT_FAILED;
2302 int pcm_code;
2303 snd_pcm_t* handle = NULL;
2304 snd_pcm_hw_params_t* hw_params = NULL;
2305 int pcm_format;
2306 unsigned int pcm_rate = format->samples_per_second;
2307
2308 do
2309 {
2310 result = gate_audio_alsa_init();
2311 GATE_BREAK_IF_FAILED(result);
2312
2313 if (sample_count == 0)
2314 {
2315 impl->sample_count = format->samples_per_second;
2316 }
2317 else
2318 {
2319 impl->sample_count = sample_count;
2320 }
2321
2322 if (format->bits_per_sample == 8)
2323 {
2324 pcm_format = SND_PCM_FORMAT_U8;
2325 }
2326 else if (format->bits_per_sample == 16)
2327 {
2328 pcm_format = SND_PCM_FORMAT_S16_LE;
2329 }
2330 else
2331 {
2332 result = GATE_RESULT_INVALIDINPUT;
2333 break;
2334 }
2335
2336
2337 switch (impl->type)
2338 {
2339 case gate_audio_device_input:
2340 {
2341 if (impl->handle != NULL)
2342 {
2343 result = GATE_RESULT_INVALIDSTATE;
2344 break;
2345 }
2346
2347 /* assume failure until all functions return success */
2348 result = GATE_RESULT_FAILED;
2349
2350 pcm_code = alsa_snd.pcm_open(&handle, impl->id, SND_PCM_STREAM_CAPTURE, 0);
2351 if (pcm_code < 0)
2352 {
2353 GATE_DEBUG_TRACE("pcm_open() failed");
2354 break;
2355 }
2356
2357 pcm_code = alsa_snd.pcm_hw_params_malloc(&hw_params);
2358 if (pcm_code < 0)
2359 {
2360 GATE_DEBUG_TRACE("pcm_hw_params_malloc() failed");
2361 break;
2362 }
2363
2364 pcm_code = alsa_snd.pcm_hw_params_any(handle, hw_params);
2365 if (pcm_code < 0)
2366 {
2367 GATE_DEBUG_TRACE("pcm_hw_params_any() failed");
2368 break;
2369 }
2370
2371 pcm_code = alsa_snd.pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
2372 if (pcm_code < 0)
2373 {
2374 GATE_DEBUG_TRACE("pcm_hw_params_set_access() failed");
2375 break;
2376 }
2377
2378 pcm_code = alsa_snd.pcm_hw_params_set_format(handle, hw_params, pcm_format);
2379 if (pcm_code < 0)
2380 {
2381 GATE_DEBUG_TRACE("pcm_hw_params_set_format() failed");
2382 break;
2383 }
2384
2385 pcm_code = alsa_snd.pcm_hw_params_set_rate_near(handle, hw_params, &pcm_rate, NULL);
2386 if (pcm_code < 0)
2387 {
2388 GATE_DEBUG_TRACE("pcm_hw_params_set_rate_near() failed");
2389 break;
2390 }
2391
2392 pcm_code = alsa_snd.pcm_hw_params_set_channels(handle, hw_params, format->channels);
2393 if (pcm_code < 0)
2394 {
2395 GATE_DEBUG_TRACE("pcm_hw_params_set_channels() failed");
2396 break;
2397 }
2398
2399 pcm_code = alsa_snd.pcm_hw_params(handle, hw_params);
2400 if (pcm_code < 0)
2401 {
2402 GATE_DEBUG_TRACE("pcm_hw_params() failed");
2403 break;
2404 }
2405
2406 impl->format = *format;
2407 gate_atomic_int_set(&impl->format_defined, 1);
2408 impl->handle = handle;
2409 handle = NULL;
2410 result = GATE_RESULT_OK;
2411 break;
2412 }
2413 case gate_audio_device_output:
2414 {
2415 pcm_code = alsa_snd.pcm_open(&handle, impl->id, SND_PCM_STREAM_PLAYBACK, 0);
2416 if (pcm_code < 0)
2417 {
2418 GATE_DEBUG_TRACE("pcm_open() failed");
2419 break;
2420 }
2421
2422 pcm_code = alsa_snd.pcm_hw_params_malloc(&hw_params);
2423 if (pcm_code < 0)
2424 {
2425 GATE_DEBUG_TRACE("pcm_hw_params_malloc() failed");
2426 break;
2427 }
2428
2429 pcm_code = alsa_snd.pcm_hw_params_any(handle, hw_params);
2430 if (pcm_code < 0)
2431 {
2432 GATE_DEBUG_TRACE("pcm_hw_params_any() failed");
2433 break;
2434 }
2435
2436 pcm_code = alsa_snd.pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
2437 if (pcm_code < 0)
2438 {
2439 GATE_DEBUG_TRACE("pcm_hw_params_set_access() failed");
2440 break;
2441 }
2442
2443 pcm_code = alsa_snd.pcm_hw_params_set_format(handle, hw_params, pcm_format);
2444 if (pcm_code < 0)
2445 {
2446 GATE_DEBUG_TRACE("pcm_hw_params_set_format() failed");
2447 break;
2448 }
2449
2450 pcm_code = alsa_snd.pcm_hw_params_set_rate_near(handle, hw_params, &pcm_rate, NULL);
2451 if (pcm_code < 0)
2452 {
2453 GATE_DEBUG_TRACE("pcm_hw_params_set_rate_near() failed");
2454 break;
2455 }
2456
2457 pcm_code = alsa_snd.pcm_hw_params_set_channels(handle, hw_params, format->channels);
2458 if (pcm_code < 0)
2459 {
2460 GATE_DEBUG_TRACE("pcm_hw_params_set_channels() failed");
2461 break;
2462 }
2463
2464 pcm_code = alsa_snd.pcm_hw_params(handle, hw_params);
2465 if (pcm_code < 0)
2466 {
2467 GATE_DEBUG_TRACE("pcm_hw_params() failed");
2468 break;
2469 }
2470
2471 pcm_code = alsa_snd.pcm_prepare(handle);
2472 if (pcm_code < 0)
2473 {
2474 GATE_DEBUG_TRACE("pcm_prepare() failed");
2475 break;
2476 }
2477
2478 impl->format = *format;
2479 gate_atomic_int_set(&impl->format_defined, 1);
2480 impl->handle = handle;
2481 handle = NULL;
2482 result = GATE_RESULT_OK;
2483 break;
2484 }
2485 case gate_audio_device_unknown:
2486 {
2487 result = GATE_RESULT_NOTSUPPORTED;
2488 break;
2489 }
2490 }
2491 } while (0);
2492
2493 if (hw_params != NULL)
2494 {
2495 alsa_snd.pcm_hw_params_free(hw_params);
2496 }
2497 if (handle != NULL)
2498 {
2499 alsa_snd.pcm_close(handle);
2500 }
2501 return result;
2502 }
2503 static gate_result_t gate_audio_device_impl_close(void* device)
2504 {
2505 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
2506 gate_result_t result = GATE_RESULT_OK;
2507
2508 if (impl->handle != NULL)
2509 {
2510 alsa_snd.pcm_close(impl->handle);
2511 impl->handle = NULL;
2512 }
2513 return result;
2514 }
2515
2516 static gate_result_t gate_audio_device_impl_read(void* device, gate_audio_sample_t* sample)
2517 {
2518 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
2519 gate_result_t result = GATE_RESULT_FAILED;
2520 gate_size_t buffer_size;
2521 int pcm_code;
2522 char* buffer;
2523
2524 do
2525 {
2526 buffer_size = impl->sample_count * impl->format.channels * impl->format.bits_per_sample / 8;
2527 sample->format = impl->format;
2528 sample->data = gate_memoryblock_create(buffer_size);
2529 sample->meta_data = NULL;
2530 sample->record_time = 0;
2531 buffer = gate_memoryblock_get_content(sample->data);
2532
2533 pcm_code = alsa_snd.pcm_readi(impl->handle, buffer, buffer_size * 8 / impl->format.bits_per_sample);
2534 if (pcm_code < 0)
2535 {
2536 result = GATE_RESULT_FAILED;
2537 }
2538 else
2539 {
2540 sample->sample_count = pcm_code / impl->format.channels;
2541 result = GATE_RESULT_OK;
2542 }
2543 } while (0);
2544
2545 return result;
2546 }
2547 static gate_result_t gate_audio_device_impl_read_async(void* device, gate_delegate_t const* completion)
2548 {
2549 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
2550 gate_result_t result = GATE_RESULT_NOTIMPLEMENTED;
2551
2552 return result;
2553 }
2554 static gate_result_t gate_audio_device_impl_write(void* device, gate_audio_sample_t const* sample)
2555 {
2556 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)device;
2557 gate_result_t result = GATE_RESULT_FAILED;
2558 int pcm_code;
2559 char* buffer;
2560 gate_size_t bufferlen;
2561 snd_pcm_sframes_t available_frames;
2562
2563 do
2564 {
2565 if (0 != gate_compare_audio_format(&sample->format, &impl->format))
2566 {
2567 result = GATE_RESULT_INVALIDINPUT;
2568 break;
2569 }
2570
2571 buffer = gate_memoryblock_get_content(sample->data);
2572 bufferlen = gate_memoryblock_get_size(sample->data);
2573
2574 pcm_code = alsa_snd.pcm_writei(impl->handle, buffer, sample->sample_count * sample->format.channels);
2575 if (pcm_code < 0)
2576 {
2577 result = GATE_RESULT_FAILED;
2578 break;
2579 }
2580
2581 available_frames = alsa_snd.pcm_avail(impl->handle);
2582 while (available_frames > 0)
2583 {
2584 gate_thread_sleep(1);
2585 available_frames = alsa_snd.pcm_avail(impl->handle);
2586 }
2587
2588 result = GATE_RESULT_OK;
2589 } while (0);
2590
2591 return result;
2592 }
2593
2594 static gate_result_t gate_audio_device_impl_write_async(
2595 void* device, gate_audio_sample_t const* sample, gate_delegate_t const* completion)
2596 {
2597 gate_audio_alsa_impl_t* impl = (gate_audio_alsa_impl_t*)impl;
2598 gate_result_t result = GATE_RESULT_NOTIMPLEMENTED;
2599
2600 return result;
2601 }
2602
2603
2604 gate_result_t gate_audio_devices_enum(gate_enumint_t type, gate_delegate_t const* callback, void* param)
2605 {
2606 gate_result_t result = GATE_RESULT_OK;
2607 gate_audio_alsa_impl_t* device;
2608
2609 if ((type == gate_audio_device_unknown) || (type == gate_audio_device_input))
2610 {
2611 gate_audio_alsa_impl_t* impl = gate_mem_alloc(sizeof(gate_audio_alsa_impl_t));
2612 gate_mem_clear(impl, sizeof(gate_audio_alsa_impl_t));
2613 gate_init_audio_device_vtbl_impl();
2614 impl->vtbl = &gate_audio_device_vtbl_impl;
2615
2616 gate_atomic_int_init(&impl->ref_counter, 1);
2617
2618 gate_str_print_text(impl->id, sizeof(impl->id), "default", 7);
2619 gate_str_print_text(impl->name, sizeof(impl->name), "Default Audio Input", 19);
2620 impl->type = gate_audio_device_input;
2621
2622 result = gate_delegate_invoke(callback, (gate_audio_device_t*)impl, param);
2623 }
2624
2625 if ((type == gate_audio_device_unknown) || (type == gate_audio_device_output))
2626 {
2627 gate_audio_alsa_impl_t* impl = gate_mem_alloc(sizeof(gate_audio_alsa_impl_t));
2628 gate_mem_clear(impl, sizeof(gate_audio_alsa_impl_t));
2629 gate_init_audio_device_vtbl_impl();
2630 impl->vtbl = &gate_audio_device_vtbl_impl;
2631
2632 gate_atomic_int_init(&impl->ref_counter, 1);
2633
2634 gate_str_print_text(impl->id, sizeof(impl->id), "default", 7);
2635 gate_str_print_text(impl->name, sizeof(impl->name), "Default Audio Output", 20);
2636 impl->type = gate_audio_device_output;
2637
2638 result = gate_delegate_invoke(callback, (gate_audio_device_t*)impl, param);
2639 }
2640
2641 return result;
2642 }
2643
2644
2645
2646 #endif /* GATE_IO_AUDIO_ALSA */
2647
2648
2649
2650
2651 #if defined(GATE_IO_AUDIO_NO_IMPL)
2652
2653 gate_result_t gate_audio_devices_enum(gate_enumint_t type, gate_delegate_t const* callback, void* param)
2654 {
2655 GATE_UNUSED_ARG(type);
2656 GATE_UNUSED_ARG(callback);
2657 GATE_UNUSED_ARG(param);
2658 return GATE_RESULT_NOTIMPLEMENTED;
2659 }
2660
2661 #endif /* GATE_IO_AUDIO_NO_IMPL */
2662