]> git.proxmox.com Git - qemu.git/blob - audio/winwaveaudio.c
Wrap recv to avoid warnings
[qemu.git] / audio / winwaveaudio.c
1 /* public domain */
2
3 #include "qemu-common.h"
4 #include "sysemu.h"
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
15 static struct {
16 int dac_headers;
17 int dac_samples;
18 int adc_headers;
19 int adc_samples;
20 } conf = {
21 .dac_headers = 4,
22 .dac_samples = 1024,
23 .adc_headers = 4,
24 .adc_samples = 1024
25 };
26
27 typedef struct {
28 HWVoiceOut hw;
29 HWAVEOUT hwo;
30 WAVEHDR *hdrs;
31 HANDLE event;
32 void *pcm_buf;
33 int avail;
34 int pending;
35 int curhdr;
36 int paused;
37 CRITICAL_SECTION crit_sect;
38 } WaveVoiceOut;
39
40 typedef 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
53 static 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:
75 str = "Unable to allocate or locl memory";
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
88 case WAVERR_STILLPLAYING:
89 str = "There are still buffers in the queue";
90 break;
91
92 default:
93 dolog ("Reason: Unknown (MMRESULT %#x)\n", mr);
94 return;
95 }
96
97 dolog ("Reason: %s\n", str);
98 }
99
100 static 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
112 AUD_log (NULL, " failed\n");
113 winwave_log_mmresult (mr);
114 }
115
116 static void winwave_anal_close_out (WaveVoiceOut *wave)
117 {
118 MMRESULT mr;
119
120 mr = waveOutClose (wave->hwo);
121 if (mr != MMSYSERR_NOERROR) {
122 winwave_logerr (mr, "waveOutClose");
123 }
124 wave->hwo = NULL;
125 }
126
127 static void CALLBACK winwave_callback_out (
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);
148 if (wave->hw.poll_mode) {
149 if (!SetEvent (wave->event)) {
150 dolog ("DAC SetEvent failed %lx\n", GetLastError ());
151 }
152 }
153 }
154 }
155 break;
156
157 case WOM_CLOSE:
158 case WOM_OPEN:
159 break;
160
161 default:
162 dolog ("unknown wave out callback msg %x\n", msg);
163 }
164 }
165
166 static 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
178 err = waveformat_from_audio_settings (&wfx, as);
179 if (err) {
180 goto err0;
181 }
182
183 mr = waveOutOpen (&wave->hwo, WAVE_MAPPER, &wfx,
184 (DWORD_PTR) winwave_callback_out,
185 (DWORD_PTR) wave, CALLBACK_FUNCTION);
186 if (mr != MMSYSERR_NOERROR) {
187 winwave_logerr (mr, "waveOutOpen");
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) {
217 winwave_logerr (mr, "waveOutPrepareHeader(%d)", i);
218 goto err4;
219 }
220 }
221
222 return 0;
223
224 err4:
225 qemu_free (wave->pcm_buf);
226 err3:
227 qemu_free (wave->hdrs);
228 err2:
229 winwave_anal_close_out (wave);
230 err1:
231 err0:
232 return -1;
233 }
234
235 static int winwave_write (SWVoiceOut *sw, void *buf, int len)
236 {
237 return audio_pcm_sw_write (sw, buf, len);
238 }
239
240 static int winwave_run_out (HWVoiceOut *hw, int live)
241 {
242 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
243 int decr;
244 int doreset;
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
255 doreset = hw->poll_mode && (wave->pending >= conf.dac_samples);
256 if (doreset && !ResetEvent (wave->event)) {
257 dolog ("DAC ResetEvent failed %lx\n", GetLastError ());
258 }
259
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) {
267 winwave_logerr (mr, "waveOutWrite(%d)", wave->curhdr);
268 break;
269 }
270
271 wave->pending -= conf.dac_samples;
272 wave->curhdr = (wave->curhdr + 1) % conf.dac_headers;
273 }
274
275 return decr;
276 }
277
278 static void winwave_poll (void *opaque)
279 {
280 (void) opaque;
281 audio_run ("winwave_poll");
282 }
283
284 static void winwave_fini_out (HWVoiceOut *hw)
285 {
286 int i;
287 MMRESULT mr;
288 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
289
290 mr = waveOutReset (wave->hwo);
291 if (mr != MMSYSERR_NOERROR) {
292 winwave_logerr (mr, "waveOutReset");
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) {
299 winwave_logerr (mr, "waveOutUnprepareHeader(%d)", i);
300 }
301 }
302
303 winwave_anal_close_out (wave);
304
305 if (wave->event) {
306 qemu_del_wait_object (wave->event, winwave_poll, wave);
307 if (!CloseHandle (wave->event)) {
308 dolog ("DAC CloseHandle failed %lx\n", GetLastError ());
309 }
310 wave->event = NULL;
311 }
312
313 qemu_free (wave->pcm_buf);
314 wave->pcm_buf = NULL;
315
316 qemu_free (wave->hdrs);
317 wave->hdrs = NULL;
318 }
319
320 static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
321 {
322 MMRESULT mr;
323 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
324
325 switch (cmd) {
326 case VOICE_ENABLE:
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) {
338 dolog ("DAC CreateEvent: %lx, poll mode will be disabled\n",
339 GetLastError ());
340 }
341 }
342
343 if (wave->event) {
344 int ret;
345
346 ret = qemu_add_wait_object (wave->event, winwave_poll, wave);
347 hw->poll_mode = (ret == 0);
348 }
349 else {
350 hw->poll_mode = 0;
351 }
352 if (wave->paused) {
353 mr = waveOutRestart (wave->hwo);
354 if (mr != MMSYSERR_NOERROR) {
355 winwave_logerr (mr, "waveOutRestart");
356 }
357 wave->paused = 0;
358 }
359 }
360 return 0;
361
362 case VOICE_DISABLE:
363 if (!wave->paused) {
364 mr = waveOutPause (wave->hwo);
365 if (mr != MMSYSERR_NOERROR) {
366 winwave_logerr (mr, "waveOutPause");
367 }
368 else {
369 wave->paused = 1;
370 }
371 }
372 if (wave->event) {
373 qemu_del_wait_object (wave->event, winwave_poll, wave);
374 }
375 return 0;
376 }
377 return -1;
378 }
379
380 static void winwave_anal_close_in (WaveVoiceIn *wave)
381 {
382 MMRESULT mr;
383
384 mr = waveInClose (wave->hwi);
385 if (mr != MMSYSERR_NOERROR) {
386 winwave_logerr (mr, "waveInClose");
387 }
388 wave->hwi = NULL;
389 }
390
391 static void CALLBACK winwave_callback_in (
392 HWAVEIN *hwi,
393 UINT msg,
394 DWORD_PTR dwInstance,
395 DWORD_PTR dwParam1,
396 DWORD_PTR dwParam2
397 )
398 {
399 WaveVoiceIn *wave = (WaveVoiceIn *) dwInstance;
400
401 switch (msg) {
402 case WIM_DATA:
403 {
404 WAVEHDR *h = (WAVEHDR *) dwParam1;
405 if (!h->dwUser) {
406 h->dwUser = 1;
407 EnterCriticalSection (&wave->crit_sect);
408 {
409 wave->avail += conf.adc_samples;
410 }
411 LeaveCriticalSection (&wave->crit_sect);
412 if (wave->hw.poll_mode) {
413 if (!SetEvent (wave->event)) {
414 dolog ("ADC SetEvent failed %lx\n", GetLastError ());
415 }
416 }
417 }
418 }
419 break;
420
421 case WIM_CLOSE:
422 case WIM_OPEN:
423 break;
424
425 default:
426 dolog ("unknown wave in callback msg %x\n", msg);
427 }
428 }
429
430 static void winwave_add_buffers (WaveVoiceIn *wave, int samples)
431 {
432 int doreset;
433
434 doreset = wave->hw.poll_mode && (samples >= conf.adc_samples);
435 if (doreset && !ResetEvent (wave->event)) {
436 dolog ("ADC ResetEvent failed %lx\n", GetLastError ());
437 }
438
439 while (samples >= conf.adc_samples) {
440 MMRESULT mr;
441 WAVEHDR *h = &wave->hdrs[wave->curhdr];
442
443 h->dwUser = 0;
444 mr = waveInAddBuffer (wave->hwi, h, sizeof (*h));
445 if (mr != MMSYSERR_NOERROR) {
446 winwave_logerr (mr, "waveInAddBuffer(%d)", wave->curhdr);
447 }
448 wave->curhdr = (wave->curhdr + 1) % conf.adc_headers;
449 samples -= conf.adc_samples;
450 }
451 }
452
453 static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as)
454 {
455 int i;
456 int err;
457 MMRESULT mr;
458 WAVEFORMATEX wfx;
459 WaveVoiceIn *wave;
460
461 wave = (WaveVoiceIn *) hw;
462
463 InitializeCriticalSection (&wave->crit_sect);
464
465 err = waveformat_from_audio_settings (&wfx, as);
466 if (err) {
467 goto err0;
468 }
469
470 mr = waveInOpen (&wave->hwi, WAVE_MAPPER, &wfx,
471 (DWORD_PTR) winwave_callback_in,
472 (DWORD_PTR) wave, CALLBACK_FUNCTION);
473 if (mr != MMSYSERR_NOERROR) {
474 winwave_logerr (mr, "waveInOpen");
475 goto err1;
476 }
477
478 wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
479 sizeof (*wave->hdrs));
480 if (!wave->hdrs) {
481 goto err2;
482 }
483
484 audio_pcm_init_info (&hw->info, as);
485 hw->samples = conf.adc_samples * conf.adc_headers;
486 wave->avail = 0;
487
488 wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.adc_samples,
489 conf.adc_headers << hw->info.shift);
490 if (!wave->pcm_buf) {
491 goto err3;
492 }
493
494 for (i = 0; i < conf.adc_headers; ++i) {
495 WAVEHDR *h = &wave->hdrs[i];
496
497 h->dwUser = 0;
498 h->dwBufferLength = conf.adc_samples << hw->info.shift;
499 h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
500 h->dwFlags = 0;
501
502 mr = waveInPrepareHeader (wave->hwi, h, sizeof (*h));
503 if (mr != MMSYSERR_NOERROR) {
504 winwave_logerr (mr, "waveInPrepareHeader(%d)", i);
505 goto err4;
506 }
507 }
508
509 wave->paused = 1;
510 winwave_add_buffers (wave, hw->samples);
511 return 0;
512
513 err4:
514 qemu_free (wave->pcm_buf);
515 err3:
516 qemu_free (wave->hdrs);
517 err2:
518 winwave_anal_close_in (wave);
519 err1:
520 err0:
521 return -1;
522 }
523
524 static void winwave_fini_in (HWVoiceIn *hw)
525 {
526 int i;
527 MMRESULT mr;
528 WaveVoiceIn *wave = (WaveVoiceIn *) hw;
529
530 mr = waveInReset (wave->hwi);
531 if (mr != MMSYSERR_NOERROR) {
532 winwave_logerr (mr, "waveInReset");
533 }
534
535 for (i = 0; i < conf.adc_headers; ++i) {
536 mr = waveInUnprepareHeader (wave->hwi, &wave->hdrs[i],
537 sizeof (wave->hdrs[i]));
538 if (mr != MMSYSERR_NOERROR) {
539 winwave_logerr (mr, "waveInUnprepareHeader(%d)", i);
540 }
541 }
542
543 winwave_anal_close_in (wave);
544
545 if (wave->event) {
546 qemu_del_wait_object (wave->event, winwave_poll, wave);
547 if (!CloseHandle (wave->event)) {
548 dolog ("ADC CloseHandle failed %lx\n", GetLastError ());
549 }
550 wave->event = NULL;
551 }
552
553 qemu_free (wave->pcm_buf);
554 wave->pcm_buf = NULL;
555
556 qemu_free (wave->hdrs);
557 wave->hdrs = NULL;
558 }
559
560 static int winwave_run_in (HWVoiceIn *hw)
561 {
562 WaveVoiceIn *wave = (WaveVoiceIn *) hw;
563 int live = audio_pcm_hw_get_live_in (hw);
564 int dead = hw->samples - live;
565 int decr, ret;
566
567 if (!dead) {
568 return 0;
569 }
570
571 EnterCriticalSection (&wave->crit_sect);
572 {
573 decr = audio_MIN (dead, wave->avail);
574 wave->avail -= decr;
575 }
576 LeaveCriticalSection (&wave->crit_sect);
577
578 ret = decr;
579 while (decr) {
580 int left = hw->samples - hw->wpos;
581 int conv = audio_MIN (left, decr);
582 hw->conv (hw->conv_buf + hw->wpos,
583 advance (wave->pcm_buf, wave->rpos << hw->info.shift),
584 conv);
585
586 wave->rpos = (wave->rpos + conv) % hw->samples;
587 hw->wpos = (hw->wpos + conv) % hw->samples;
588 decr -= conv;
589 }
590
591 winwave_add_buffers (wave, ret);
592 return ret;
593 }
594
595 static int winwave_read (SWVoiceIn *sw, void *buf, int size)
596 {
597 return audio_pcm_sw_read (sw, buf, size);
598 }
599
600 static int winwave_ctl_in (HWVoiceIn *hw, int cmd, ...)
601 {
602 MMRESULT mr;
603 WaveVoiceIn *wave = (WaveVoiceIn *) hw;
604
605 switch (cmd) {
606 case VOICE_ENABLE:
607 {
608 va_list ap;
609 int poll_mode;
610
611 va_start (ap, cmd);
612 poll_mode = va_arg (ap, int);
613 va_end (ap);
614
615 if (poll_mode && !wave->event) {
616 wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
617 if (!wave->event) {
618 dolog ("ADC CreateEvent: %lx, poll mode will be disabled\n",
619 GetLastError ());
620 }
621 }
622
623 if (wave->event) {
624 int ret;
625
626 ret = qemu_add_wait_object (wave->event, winwave_poll, wave);
627 hw->poll_mode = (ret == 0);
628 }
629 else {
630 hw->poll_mode = 0;
631 }
632 if (wave->paused) {
633 mr = waveInStart (wave->hwi);
634 if (mr != MMSYSERR_NOERROR) {
635 winwave_logerr (mr, "waveInStart");
636 }
637 wave->paused = 0;
638 }
639 }
640 return 0;
641
642 case VOICE_DISABLE:
643 if (!wave->paused) {
644 mr = waveInStop (wave->hwi);
645 if (mr != MMSYSERR_NOERROR) {
646 winwave_logerr (mr, "waveInStop");
647 }
648 else {
649 wave->paused = 1;
650 }
651 }
652 if (wave->event) {
653 qemu_del_wait_object (wave->event, winwave_poll, wave);
654 }
655 return 0;
656 }
657 return 0;
658 }
659
660 static void *winwave_audio_init (void)
661 {
662 return &conf;
663 }
664
665 static void winwave_audio_fini (void *opaque)
666 {
667 (void) opaque;
668 }
669
670 static struct audio_option winwave_options[] = {
671 {
672 .name = "DAC_HEADERS",
673 .tag = AUD_OPT_INT,
674 .valp = &conf.dac_headers,
675 .descr = "DAC number of headers",
676 },
677 {
678 .name = "DAC_SAMPLES",
679 .tag = AUD_OPT_INT,
680 .valp = &conf.dac_samples,
681 .descr = "DAC number of samples per header",
682 },
683 {
684 .name = "ADC_HEADERS",
685 .tag = AUD_OPT_INT,
686 .valp = &conf.adc_headers,
687 .descr = "ADC number of headers",
688 },
689 {
690 .name = "ADC_SAMPLES",
691 .tag = AUD_OPT_INT,
692 .valp = &conf.adc_samples,
693 .descr = "ADC number of samples per header",
694 },
695 { /* End of list */ }
696 };
697
698 static struct audio_pcm_ops winwave_pcm_ops = {
699 .init_out = winwave_init_out,
700 .fini_out = winwave_fini_out,
701 .run_out = winwave_run_out,
702 .write = winwave_write,
703 .ctl_out = winwave_ctl_out,
704 .init_in = winwave_init_in,
705 .fini_in = winwave_fini_in,
706 .run_in = winwave_run_in,
707 .read = winwave_read,
708 .ctl_in = winwave_ctl_in
709 };
710
711 struct audio_driver winwave_audio_driver = {
712 .name = "winwave",
713 .descr = "Windows Waveform Audio http://msdn.microsoft.com",
714 .options = winwave_options,
715 .init = winwave_audio_init,
716 .fini = winwave_audio_fini,
717 .pcm_ops = &winwave_pcm_ops,
718 .can_be_default = 1,
719 .max_voices_out = INT_MAX,
720 .max_voices_in = INT_MAX,
721 .voice_size_out = sizeof (WaveVoiceOut),
722 .voice_size_in = sizeof (WaveVoiceIn)
723 };