]> git.proxmox.com Git - qemu.git/blame - audio/winwaveaudio.c
qom: improve documentation of cast functions
[qemu.git] / audio / winwaveaudio.c
CommitLineData
d5631638 1/* public domain */
2
3#include "qemu-common.h"
9c17d615 4#include "sysemu/sysemu.h"
d5631638 5#include "audio.h"
6
7#define AUDIO_CAP "winwave"
8#include "audio_int.h"
9
10#include <windows.h>
11#include <mmsystem.h>
12
13#include "audio_win_int.h"
14
15static struct {
16 int dac_headers;
17 int dac_samples;
a58c16dc 18 int adc_headers;
19 int adc_samples;
d5631638 20} conf = {
21 .dac_headers = 4,
a58c16dc 22 .dac_samples = 1024,
23 .adc_headers = 4,
24 .adc_samples = 1024
d5631638 25};
26
27typedef struct {
28 HWVoiceOut hw;
29 HWAVEOUT hwo;
30 WAVEHDR *hdrs;
e0bda367 31 HANDLE event;
d5631638 32 void *pcm_buf;
33 int avail;
34 int pending;
35 int curhdr;
6165a426 36 int paused;
d5631638 37 CRITICAL_SECTION crit_sect;
38} WaveVoiceOut;
39
a58c16dc 40typedef struct {
41 HWVoiceIn hw;
42 HWAVEIN hwi;
43 WAVEHDR *hdrs;
44 HANDLE event;
45 void *pcm_buf;
46 int curhdr;
47 int paused;
48 int rpos;
49 int avail;
50 CRITICAL_SECTION crit_sect;
51} WaveVoiceIn;
52
d5631638 53static void winwave_log_mmresult (MMRESULT mr)
54{
55 const char *str = "BUG";
56
57 switch (mr) {
58 case MMSYSERR_NOERROR:
59 str = "Success";
60 break;
61
62 case MMSYSERR_INVALHANDLE:
63 str = "Specified device handle is invalid";
64 break;
65
66 case MMSYSERR_BADDEVICEID:
67 str = "Specified device id is out of range";
68 break;
69
70 case MMSYSERR_NODRIVER:
71 str = "No device driver is present";
72 break;
73
74 case MMSYSERR_NOMEM:
eb2aeacf 75 str = "Unable to allocate or lock memory";
d5631638 76 break;
77
78 case WAVERR_SYNC:
79 str = "Device is synchronous but waveOutOpen was called "
80 "without using the WINWAVE_ALLOWSYNC flag";
81 break;
82
83 case WAVERR_UNPREPARED:
84 str = "The data block pointed to by the pwh parameter "
85 "hasn't been prepared";
86 break;
87
2a117d40 88 case WAVERR_STILLPLAYING:
89 str = "There are still buffers in the queue";
90 break;
91
d5631638 92 default:
a58c16dc 93 dolog ("Reason: Unknown (MMRESULT %#x)\n", mr);
d5631638 94 return;
95 }
96
a58c16dc 97 dolog ("Reason: %s\n", str);
d5631638 98}
99
100static void GCC_FMT_ATTR (2, 3) winwave_logerr (
101 MMRESULT mr,
102 const char *fmt,
103 ...
104 )
105{
106 va_list ap;
107
108 va_start (ap, fmt);
109 AUD_vlog (AUDIO_CAP, fmt, ap);
110 va_end (ap);
111
bc578fe0 112 AUD_log (NULL, " failed\n");
d5631638 113 winwave_log_mmresult (mr);
114}
115
116static void winwave_anal_close_out (WaveVoiceOut *wave)
117{
118 MMRESULT mr;
119
120 mr = waveOutClose (wave->hwo);
121 if (mr != MMSYSERR_NOERROR) {
bc578fe0 122 winwave_logerr (mr, "waveOutClose");
d5631638 123 }
124 wave->hwo = NULL;
125}
126
a58c16dc 127static void CALLBACK winwave_callback_out (
d5631638 128 HWAVEOUT hwo,
129 UINT msg,
130 DWORD_PTR dwInstance,
131 DWORD_PTR dwParam1,
132 DWORD_PTR dwParam2
133 )
134{
135 WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance;
136
137 switch (msg) {
138 case WOM_DONE:
139 {
140 WAVEHDR *h = (WAVEHDR *) dwParam1;
141 if (!h->dwUser) {
142 h->dwUser = 1;
143 EnterCriticalSection (&wave->crit_sect);
144 {
145 wave->avail += conf.dac_samples;
146 }
147 LeaveCriticalSection (&wave->crit_sect);
e0bda367 148 if (wave->hw.poll_mode) {
149 if (!SetEvent (wave->event)) {
a58c16dc 150 dolog ("DAC SetEvent failed %lx\n", GetLastError ());
e0bda367 151 }
152 }
d5631638 153 }
154 }
155 break;
156
157 case WOM_CLOSE:
158 case WOM_OPEN:
159 break;
160
161 default:
a58c16dc 162 dolog ("unknown wave out callback msg %x\n", msg);
d5631638 163 }
164}
165
166static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
167{
168 int i;
169 int err;
170 MMRESULT mr;
171 WAVEFORMATEX wfx;
172 WaveVoiceOut *wave;
173
174 wave = (WaveVoiceOut *) hw;
175
176 InitializeCriticalSection (&wave->crit_sect);
177
a58c16dc 178 err = waveformat_from_audio_settings (&wfx, as);
d5631638 179 if (err) {
180 goto err0;
181 }
182
183 mr = waveOutOpen (&wave->hwo, WAVE_MAPPER, &wfx,
a58c16dc 184 (DWORD_PTR) winwave_callback_out,
d5631638 185 (DWORD_PTR) wave, CALLBACK_FUNCTION);
186 if (mr != MMSYSERR_NOERROR) {
bc578fe0 187 winwave_logerr (mr, "waveOutOpen");
d5631638 188 goto err1;
189 }
190
191 wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
192 sizeof (*wave->hdrs));
193 if (!wave->hdrs) {
194 goto err2;
195 }
196
197 audio_pcm_init_info (&hw->info, as);
198 hw->samples = conf.dac_samples * conf.dac_headers;
199 wave->avail = hw->samples;
200
201 wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.dac_samples,
202 conf.dac_headers << hw->info.shift);
203 if (!wave->pcm_buf) {
204 goto err3;
205 }
206
207 for (i = 0; i < conf.dac_headers; ++i) {
208 WAVEHDR *h = &wave->hdrs[i];
209
210 h->dwUser = 0;
211 h->dwBufferLength = conf.dac_samples << hw->info.shift;
212 h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
213 h->dwFlags = 0;
214
215 mr = waveOutPrepareHeader (wave->hwo, h, sizeof (*h));
216 if (mr != MMSYSERR_NOERROR) {
a58c16dc 217 winwave_logerr (mr, "waveOutPrepareHeader(%d)", i);
d5631638 218 goto err4;
219 }
220 }
221
222 return 0;
223
224 err4:
7267c094 225 g_free (wave->pcm_buf);
d5631638 226 err3:
7267c094 227 g_free (wave->hdrs);
d5631638 228 err2:
229 winwave_anal_close_out (wave);
230 err1:
231 err0:
232 return -1;
233}
234
235static int winwave_write (SWVoiceOut *sw, void *buf, int len)
236{
237 return audio_pcm_sw_write (sw, buf, len);
238}
239
240static int winwave_run_out (HWVoiceOut *hw, int live)
241{
242 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
243 int decr;
e0bda367 244 int doreset;
d5631638 245
246 EnterCriticalSection (&wave->crit_sect);
247 {
248 decr = audio_MIN (live, wave->avail);
249 decr = audio_pcm_hw_clip_out (hw, wave->pcm_buf, decr, wave->pending);
250 wave->pending += decr;
251 wave->avail -= decr;
252 }
253 LeaveCriticalSection (&wave->crit_sect);
254
e0bda367 255 doreset = hw->poll_mode && (wave->pending >= conf.dac_samples);
256 if (doreset && !ResetEvent (wave->event)) {
a58c16dc 257 dolog ("DAC ResetEvent failed %lx\n", GetLastError ());
e0bda367 258 }
259
d5631638 260 while (wave->pending >= conf.dac_samples) {
261 MMRESULT mr;
262 WAVEHDR *h = &wave->hdrs[wave->curhdr];
263
264 h->dwUser = 0;
265 mr = waveOutWrite (wave->hwo, h, sizeof (*h));
266 if (mr != MMSYSERR_NOERROR) {
bc578fe0 267 winwave_logerr (mr, "waveOutWrite(%d)", wave->curhdr);
d5631638 268 break;
269 }
270
271 wave->pending -= conf.dac_samples;
272 wave->curhdr = (wave->curhdr + 1) % conf.dac_headers;
273 }
e0bda367 274
d5631638 275 return decr;
276}
277
a58c16dc 278static void winwave_poll (void *opaque)
f4e8d0b7 279{
280 (void) opaque;
a58c16dc 281 audio_run ("winwave_poll");
f4e8d0b7 282}
283
d5631638 284static void winwave_fini_out (HWVoiceOut *hw)
285{
2a117d40 286 int i;
287 MMRESULT mr;
d5631638 288 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
289
2a117d40 290 mr = waveOutReset (wave->hwo);
291 if (mr != MMSYSERR_NOERROR) {
bc578fe0 292 winwave_logerr (mr, "waveOutReset");
2a117d40 293 }
294
295 for (i = 0; i < conf.dac_headers; ++i) {
296 mr = waveOutUnprepareHeader (wave->hwo, &wave->hdrs[i],
297 sizeof (wave->hdrs[i]));
298 if (mr != MMSYSERR_NOERROR) {
bc578fe0 299 winwave_logerr (mr, "waveOutUnprepareHeader(%d)", i);
2a117d40 300 }
301 }
302
875ef647 303 winwave_anal_close_out (wave);
304
e0bda367 305 if (wave->event) {
a58c16dc 306 qemu_del_wait_object (wave->event, winwave_poll, wave);
e0bda367 307 if (!CloseHandle (wave->event)) {
a58c16dc 308 dolog ("DAC CloseHandle failed %lx\n", GetLastError ());
e0bda367 309 }
310 wave->event = NULL;
311 }
e0bda367 312
7267c094 313 g_free (wave->pcm_buf);
f4e8d0b7 314 wave->pcm_buf = NULL;
315
7267c094 316 g_free (wave->hdrs);
f4e8d0b7 317 wave->hdrs = NULL;
d5631638 318}
319
320static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
321{
6165a426 322 MMRESULT mr;
e0bda367 323 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
324
d5631638 325 switch (cmd) {
326 case VOICE_ENABLE:
e0bda367 327 {
328 va_list ap;
329 int poll_mode;
330
331 va_start (ap, cmd);
332 poll_mode = va_arg (ap, int);
333 va_end (ap);
334
335 if (poll_mode && !wave->event) {
336 wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
337 if (!wave->event) {
a58c16dc 338 dolog ("DAC CreateEvent: %lx, poll mode will be disabled\n",
339 GetLastError ());
e0bda367 340 }
341 }
342
343 if (wave->event) {
344 int ret;
345
a58c16dc 346 ret = qemu_add_wait_object (wave->event, winwave_poll, wave);
e0bda367 347 hw->poll_mode = (ret == 0);
348 }
349 else {
350 hw->poll_mode = 0;
351 }
13ef70f6 352 wave->paused = 0;
e0bda367 353 }
d5631638 354 return 0;
355
356 case VOICE_DISABLE:
6165a426 357 if (!wave->paused) {
13ef70f6 358 mr = waveOutReset (wave->hwo);
6165a426 359 if (mr != MMSYSERR_NOERROR) {
13ef70f6 360 winwave_logerr (mr, "waveOutReset");
6165a426 361 }
362 else {
363 wave->paused = 1;
364 }
365 }
e0bda367 366 if (wave->event) {
a58c16dc 367 qemu_del_wait_object (wave->event, winwave_poll, wave);
e0bda367 368 }
d5631638 369 return 0;
370 }
371 return -1;
372}
373
a58c16dc 374static void winwave_anal_close_in (WaveVoiceIn *wave)
375{
376 MMRESULT mr;
377
378 mr = waveInClose (wave->hwi);
379 if (mr != MMSYSERR_NOERROR) {
380 winwave_logerr (mr, "waveInClose");
381 }
382 wave->hwi = NULL;
383}
384
385static void CALLBACK winwave_callback_in (
386 HWAVEIN *hwi,
387 UINT msg,
388 DWORD_PTR dwInstance,
389 DWORD_PTR dwParam1,
390 DWORD_PTR dwParam2
391 )
392{
393 WaveVoiceIn *wave = (WaveVoiceIn *) dwInstance;
394
395 switch (msg) {
396 case WIM_DATA:
397 {
398 WAVEHDR *h = (WAVEHDR *) dwParam1;
399 if (!h->dwUser) {
400 h->dwUser = 1;
401 EnterCriticalSection (&wave->crit_sect);
402 {
403 wave->avail += conf.adc_samples;
404 }
405 LeaveCriticalSection (&wave->crit_sect);
406 if (wave->hw.poll_mode) {
407 if (!SetEvent (wave->event)) {
408 dolog ("ADC SetEvent failed %lx\n", GetLastError ());
409 }
410 }
411 }
412 }
413 break;
414
415 case WIM_CLOSE:
416 case WIM_OPEN:
417 break;
418
419 default:
420 dolog ("unknown wave in callback msg %x\n", msg);
421 }
422}
423
424static void winwave_add_buffers (WaveVoiceIn *wave, int samples)
425{
426 int doreset;
427
428 doreset = wave->hw.poll_mode && (samples >= conf.adc_samples);
429 if (doreset && !ResetEvent (wave->event)) {
430 dolog ("ADC ResetEvent failed %lx\n", GetLastError ());
431 }
432
433 while (samples >= conf.adc_samples) {
434 MMRESULT mr;
435 WAVEHDR *h = &wave->hdrs[wave->curhdr];
436
437 h->dwUser = 0;
438 mr = waveInAddBuffer (wave->hwi, h, sizeof (*h));
439 if (mr != MMSYSERR_NOERROR) {
440 winwave_logerr (mr, "waveInAddBuffer(%d)", wave->curhdr);
441 }
442 wave->curhdr = (wave->curhdr + 1) % conf.adc_headers;
443 samples -= conf.adc_samples;
444 }
445}
446
447static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as)
448{
449 int i;
450 int err;
451 MMRESULT mr;
452 WAVEFORMATEX wfx;
453 WaveVoiceIn *wave;
454
455 wave = (WaveVoiceIn *) hw;
456
457 InitializeCriticalSection (&wave->crit_sect);
458
459 err = waveformat_from_audio_settings (&wfx, as);
460 if (err) {
461 goto err0;
462 }
463
464 mr = waveInOpen (&wave->hwi, WAVE_MAPPER, &wfx,
465 (DWORD_PTR) winwave_callback_in,
466 (DWORD_PTR) wave, CALLBACK_FUNCTION);
467 if (mr != MMSYSERR_NOERROR) {
468 winwave_logerr (mr, "waveInOpen");
469 goto err1;
470 }
471
472 wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
473 sizeof (*wave->hdrs));
474 if (!wave->hdrs) {
475 goto err2;
476 }
477
478 audio_pcm_init_info (&hw->info, as);
479 hw->samples = conf.adc_samples * conf.adc_headers;
480 wave->avail = 0;
481
482 wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.adc_samples,
483 conf.adc_headers << hw->info.shift);
484 if (!wave->pcm_buf) {
485 goto err3;
486 }
487
488 for (i = 0; i < conf.adc_headers; ++i) {
489 WAVEHDR *h = &wave->hdrs[i];
490
491 h->dwUser = 0;
492 h->dwBufferLength = conf.adc_samples << hw->info.shift;
493 h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
494 h->dwFlags = 0;
495
496 mr = waveInPrepareHeader (wave->hwi, h, sizeof (*h));
497 if (mr != MMSYSERR_NOERROR) {
498 winwave_logerr (mr, "waveInPrepareHeader(%d)", i);
499 goto err4;
500 }
501 }
502
503 wave->paused = 1;
504 winwave_add_buffers (wave, hw->samples);
505 return 0;
506
507 err4:
7267c094 508 g_free (wave->pcm_buf);
a58c16dc 509 err3:
7267c094 510 g_free (wave->hdrs);
a58c16dc 511 err2:
512 winwave_anal_close_in (wave);
513 err1:
514 err0:
515 return -1;
516}
517
518static void winwave_fini_in (HWVoiceIn *hw)
519{
520 int i;
521 MMRESULT mr;
522 WaveVoiceIn *wave = (WaveVoiceIn *) hw;
523
524 mr = waveInReset (wave->hwi);
525 if (mr != MMSYSERR_NOERROR) {
526 winwave_logerr (mr, "waveInReset");
527 }
528
529 for (i = 0; i < conf.adc_headers; ++i) {
530 mr = waveInUnprepareHeader (wave->hwi, &wave->hdrs[i],
531 sizeof (wave->hdrs[i]));
532 if (mr != MMSYSERR_NOERROR) {
533 winwave_logerr (mr, "waveInUnprepareHeader(%d)", i);
534 }
535 }
536
537 winwave_anal_close_in (wave);
538
539 if (wave->event) {
540 qemu_del_wait_object (wave->event, winwave_poll, wave);
541 if (!CloseHandle (wave->event)) {
542 dolog ("ADC CloseHandle failed %lx\n", GetLastError ());
543 }
544 wave->event = NULL;
545 }
546
7267c094 547 g_free (wave->pcm_buf);
a58c16dc 548 wave->pcm_buf = NULL;
549
7267c094 550 g_free (wave->hdrs);
a58c16dc 551 wave->hdrs = NULL;
552}
553
554static int winwave_run_in (HWVoiceIn *hw)
555{
556 WaveVoiceIn *wave = (WaveVoiceIn *) hw;
557 int live = audio_pcm_hw_get_live_in (hw);
558 int dead = hw->samples - live;
559 int decr, ret;
560
561 if (!dead) {
562 return 0;
563 }
564
565 EnterCriticalSection (&wave->crit_sect);
566 {
567 decr = audio_MIN (dead, wave->avail);
568 wave->avail -= decr;
569 }
570 LeaveCriticalSection (&wave->crit_sect);
571
572 ret = decr;
573 while (decr) {
574 int left = hw->samples - hw->wpos;
575 int conv = audio_MIN (left, decr);
576 hw->conv (hw->conv_buf + hw->wpos,
577 advance (wave->pcm_buf, wave->rpos << hw->info.shift),
00e07679 578 conv);
a58c16dc 579
580 wave->rpos = (wave->rpos + conv) % hw->samples;
581 hw->wpos = (hw->wpos + conv) % hw->samples;
582 decr -= conv;
583 }
584
585 winwave_add_buffers (wave, ret);
586 return ret;
587}
588
589static int winwave_read (SWVoiceIn *sw, void *buf, int size)
590{
591 return audio_pcm_sw_read (sw, buf, size);
592}
593
594static int winwave_ctl_in (HWVoiceIn *hw, int cmd, ...)
595{
596 MMRESULT mr;
597 WaveVoiceIn *wave = (WaveVoiceIn *) hw;
598
599 switch (cmd) {
600 case VOICE_ENABLE:
601 {
602 va_list ap;
603 int poll_mode;
604
605 va_start (ap, cmd);
606 poll_mode = va_arg (ap, int);
607 va_end (ap);
608
609 if (poll_mode && !wave->event) {
610 wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
611 if (!wave->event) {
612 dolog ("ADC CreateEvent: %lx, poll mode will be disabled\n",
613 GetLastError ());
614 }
615 }
616
617 if (wave->event) {
618 int ret;
619
620 ret = qemu_add_wait_object (wave->event, winwave_poll, wave);
621 hw->poll_mode = (ret == 0);
622 }
623 else {
624 hw->poll_mode = 0;
625 }
626 if (wave->paused) {
627 mr = waveInStart (wave->hwi);
628 if (mr != MMSYSERR_NOERROR) {
629 winwave_logerr (mr, "waveInStart");
630 }
631 wave->paused = 0;
632 }
633 }
634 return 0;
635
636 case VOICE_DISABLE:
637 if (!wave->paused) {
638 mr = waveInStop (wave->hwi);
639 if (mr != MMSYSERR_NOERROR) {
640 winwave_logerr (mr, "waveInStop");
641 }
642 else {
643 wave->paused = 1;
644 }
645 }
646 if (wave->event) {
647 qemu_del_wait_object (wave->event, winwave_poll, wave);
648 }
649 return 0;
650 }
651 return 0;
652}
653
d5631638 654static void *winwave_audio_init (void)
655{
656 return &conf;
657}
658
659static void winwave_audio_fini (void *opaque)
660{
661 (void) opaque;
662}
663
664static struct audio_option winwave_options[] = {
665 {
666 .name = "DAC_HEADERS",
667 .tag = AUD_OPT_INT,
668 .valp = &conf.dac_headers,
669 .descr = "DAC number of headers",
670 },
671 {
672 .name = "DAC_SAMPLES",
673 .tag = AUD_OPT_INT,
674 .valp = &conf.dac_samples,
675 .descr = "DAC number of samples per header",
676 },
a58c16dc 677 {
678 .name = "ADC_HEADERS",
679 .tag = AUD_OPT_INT,
680 .valp = &conf.adc_headers,
681 .descr = "ADC number of headers",
682 },
683 {
684 .name = "ADC_SAMPLES",
685 .tag = AUD_OPT_INT,
686 .valp = &conf.adc_samples,
687 .descr = "ADC number of samples per header",
688 },
d5631638 689 { /* End of list */ }
690};
691
692static struct audio_pcm_ops winwave_pcm_ops = {
693 .init_out = winwave_init_out,
694 .fini_out = winwave_fini_out,
695 .run_out = winwave_run_out,
696 .write = winwave_write,
a58c16dc 697 .ctl_out = winwave_ctl_out,
698 .init_in = winwave_init_in,
699 .fini_in = winwave_fini_in,
700 .run_in = winwave_run_in,
701 .read = winwave_read,
702 .ctl_in = winwave_ctl_in
d5631638 703};
704
705struct audio_driver winwave_audio_driver = {
706 .name = "winwave",
707 .descr = "Windows Waveform Audio http://msdn.microsoft.com",
708 .options = winwave_options,
709 .init = winwave_audio_init,
710 .fini = winwave_audio_fini,
711 .pcm_ops = &winwave_pcm_ops,
712 .can_be_default = 1,
713 .max_voices_out = INT_MAX,
a58c16dc 714 .max_voices_in = INT_MAX,
d5631638 715 .voice_size_out = sizeof (WaveVoiceOut),
a58c16dc 716 .voice_size_in = sizeof (WaveVoiceIn)
d5631638 717};