root / audio / winwaveaudio.c @ 7267c094
History | View | Annotate | Download (17.4 kB)
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 |
g_free (wave->pcm_buf); |
226 |
err3:
|
227 |
g_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 |
g_free (wave->pcm_buf); |
314 |
wave->pcm_buf = NULL;
|
315 |
|
316 |
g_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 |
g_free (wave->pcm_buf); |
515 |
err3:
|
516 |
g_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 |
g_free (wave->pcm_buf); |
554 |
wave->pcm_buf = NULL;
|
555 |
|
556 |
g_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 |
}; |