|
|
1.1 root 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:
1.1.1.3 ! root 225: g_free (wave->pcm_buf);
1.1 root 226: err3:
1.1.1.3 ! root 227: g_free (wave->hdrs);
1.1 root 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:
1.1.1.3 ! root 313: g_free (wave->pcm_buf);
1.1 root 314: wave->pcm_buf = NULL;
315:
1.1.1.3 ! root 316: g_free (wave->hdrs);
1.1 root 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:
1.1.1.3 ! root 514: g_free (wave->pcm_buf);
1.1 root 515: err3:
1.1.1.3 ! root 516: g_free (wave->hdrs);
1.1 root 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:
1.1.1.3 ! root 553: g_free (wave->pcm_buf);
1.1 root 554: wave->pcm_buf = NULL;
555:
1.1.1.3 ! root 556: g_free (wave->hdrs);
1.1 root 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),
1.1.1.2 root 584: conv);
1.1 root 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: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.