Revision c0fe3827
b/Makefile.target | ||
---|---|---|
453 | 453 |
include .depend |
454 | 454 |
endif |
455 | 455 |
|
456 |
ifeq (0, 1)
|
|
456 |
ifeq (1, 0)
|
|
457 | 457 |
audio.o sdlaudio.o dsoundaudio.o ossaudio.o wavaudio.o noaudio.o \ |
458 |
fmodaudio.o alsaaudio.o mixeng.o: \ |
|
458 |
fmodaudio.o alsaaudio.o mixeng.o sb16.o es1370.o gus.o adlib.o: \
|
|
459 | 459 |
CFLAGS := $(CFLAGS) -Wall -Werror -W -Wsign-compare |
460 | 460 |
endif |
b/audio/alsaaudio.c | ||
---|---|---|
98 | 98 |
audfmt_e fmt; |
99 | 99 |
int nchannels; |
100 | 100 |
int can_pause; |
101 |
snd_pcm_uframes_t buffer_size;
|
|
101 |
snd_pcm_uframes_t samples;
|
|
102 | 102 |
}; |
103 | 103 |
|
104 | 104 |
static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...) |
... | ... | |
121 | 121 |
{ |
122 | 122 |
va_list ap; |
123 | 123 |
|
124 |
AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ);
|
|
124 |
AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
|
|
125 | 125 |
|
126 | 126 |
va_start (ap, fmt); |
127 | 127 |
AUD_vlog (AUDIO_CAP, fmt, ap); |
... | ... | |
209 | 209 |
return 0; |
210 | 210 |
} |
211 | 211 |
|
212 |
#ifdef DEBUG_MISMATCHES
|
|
212 |
#if defined DEBUG_MISMATCHES || defined DEBUG
|
|
213 | 213 |
static void alsa_dump_info (struct alsa_params_req *req, |
214 | 214 |
struct alsa_params_obt *obt) |
215 | 215 |
{ |
... | ... | |
221 | 221 |
dolog ("============================================\n"); |
222 | 222 |
dolog ("requested: buffer size %d period size %d\n", |
223 | 223 |
req->buffer_size, req->period_size); |
224 |
dolog ("obtained: buffer size %ld\n", obt->buffer_size);
|
|
224 |
dolog ("obtained: samples %ld\n", obt->samples);
|
|
225 | 225 |
} |
226 | 226 |
#endif |
227 | 227 |
|
... | ... | |
234 | 234 |
|
235 | 235 |
err = snd_pcm_sw_params_current (handle, sw_params); |
236 | 236 |
if (err < 0) { |
237 |
dolog ("Can not fully initialize DAC\n");
|
|
237 |
dolog ("Could not fully initialize DAC\n");
|
|
238 | 238 |
alsa_logerr (err, "Failed to get current software parameters\n"); |
239 | 239 |
return; |
240 | 240 |
} |
241 | 241 |
|
242 | 242 |
err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold); |
243 | 243 |
if (err < 0) { |
244 |
dolog ("Can not fully initialize DAC\n");
|
|
244 |
dolog ("Could not fully initialize DAC\n");
|
|
245 | 245 |
alsa_logerr (err, "Failed to set software threshold to %ld\n", |
246 | 246 |
threshold); |
247 | 247 |
return; |
... | ... | |
249 | 249 |
|
250 | 250 |
err = snd_pcm_sw_params (handle, sw_params); |
251 | 251 |
if (err < 0) { |
252 |
dolog ("Can not fully initialize DAC\n");
|
|
252 |
dolog ("Could not fully initialize DAC\n");
|
|
253 | 253 |
alsa_logerr (err, "Failed to set software parameters\n"); |
254 | 254 |
return; |
255 | 255 |
} |
... | ... | |
344 | 344 |
handle, |
345 | 345 |
hw_params, |
346 | 346 |
&period_size, |
347 |
0); |
|
347 |
0 |
|
348 |
); |
|
348 | 349 |
if (err < 0) { |
349 | 350 |
alsa_logerr2 (err, typ, |
350 | 351 |
"Failed to set period time %d\n", |
... | ... | |
357 | 358 |
handle, |
358 | 359 |
hw_params, |
359 | 360 |
&buffer_size, |
360 |
0); |
|
361 |
0 |
|
362 |
); |
|
361 | 363 |
|
362 | 364 |
if (err < 0) { |
363 | 365 |
alsa_logerr2 (err, typ, |
... | ... | |
382 | 384 |
if (err < 0) { |
383 | 385 |
alsa_logerr ( |
384 | 386 |
err, |
385 |
"Can not get minmal period size for %s\n",
|
|
387 |
"Could not get minmal period size for %s\n",
|
|
386 | 388 |
typ |
387 | 389 |
); |
388 | 390 |
} |
... | ... | |
419 | 421 |
&minval |
420 | 422 |
); |
421 | 423 |
if (err < 0) { |
422 |
alsa_logerr (err, "Can not get minmal buffer size for %s\n",
|
|
424 |
alsa_logerr (err, "Could not get minmal buffer size for %s\n",
|
|
423 | 425 |
typ); |
424 | 426 |
} |
425 | 427 |
else { |
... | ... | |
451 | 453 |
} |
452 | 454 |
} |
453 | 455 |
else { |
454 |
dolog ("warning: buffer size is not set\n");
|
|
456 |
dolog ("warning: Buffer size is not set\n");
|
|
455 | 457 |
} |
456 | 458 |
|
457 | 459 |
err = snd_pcm_hw_params (handle, hw_params); |
... | ... | |
468 | 470 |
|
469 | 471 |
err = snd_pcm_prepare (handle); |
470 | 472 |
if (err < 0) { |
471 |
alsa_logerr2 (err, typ, "Can not prepare handle %p\n", handle);
|
|
473 |
alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
|
|
472 | 474 |
goto err; |
473 | 475 |
} |
474 | 476 |
|
475 | 477 |
obt->can_pause = snd_pcm_hw_params_can_pause (hw_params); |
476 | 478 |
if (obt->can_pause < 0) { |
477 |
alsa_logerr (err, "Can not get pause capability for %s\n", typ);
|
|
479 |
alsa_logerr (err, "Could not get pause capability for %s\n", typ);
|
|
478 | 480 |
obt->can_pause = 0; |
479 | 481 |
} |
480 | 482 |
|
... | ... | |
493 | 495 |
obt->fmt = req->fmt; |
494 | 496 |
obt->nchannels = nchannels; |
495 | 497 |
obt->freq = freq; |
496 |
obt->buffer_size = snd_pcm_frames_to_bytes (handle, obt_buffer_size);
|
|
498 |
obt->samples = obt_buffer_size;
|
|
497 | 499 |
*handlep = handle; |
498 | 500 |
|
501 |
#if defined DEBUG_MISMATCHES || defined DEBUG |
|
499 | 502 |
if (obt->fmt != req->fmt || |
500 | 503 |
obt->nchannels != req->nchannels || |
501 | 504 |
obt->freq != req->freq) { |
502 |
#ifdef DEBUG_MISMATCHES |
|
503 | 505 |
dolog ("Audio paramters mismatch for %s\n", typ); |
504 | 506 |
alsa_dump_info (req, obt); |
505 |
#endif |
|
506 | 507 |
} |
508 |
#endif |
|
507 | 509 |
|
508 | 510 |
#ifdef DEBUG |
509 | 511 |
alsa_dump_info (req, obt); |
... | ... | |
550 | 552 |
} |
551 | 553 |
} |
552 | 554 |
|
553 |
alsa_logerr (avail, "Can not get amount free space\n");
|
|
555 |
alsa_logerr (avail, "Could not get amount free space\n");
|
|
554 | 556 |
return 0; |
555 | 557 |
} |
556 | 558 |
|
... | ... | |
618 | 620 |
} |
619 | 621 |
} |
620 | 622 |
|
621 |
static int alsa_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt)
|
|
623 |
static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
|
|
622 | 624 |
{ |
623 | 625 |
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; |
624 | 626 |
struct alsa_params_req req; |
... | ... | |
627 | 629 |
int endianness; |
628 | 630 |
int err; |
629 | 631 |
snd_pcm_t *handle; |
632 |
audsettings_t obt_as; |
|
630 | 633 |
|
631 |
req.fmt = aud_to_alsafmt (fmt); |
|
632 |
req.freq = freq; |
|
633 |
req.nchannels = nchannels; |
|
634 |
req.fmt = aud_to_alsafmt (as->fmt);
|
|
635 |
req.freq = as->freq;
|
|
636 |
req.nchannels = as->nchannels;
|
|
634 | 637 |
req.period_size = conf.period_size_out; |
635 | 638 |
req.buffer_size = conf.buffer_size_out; |
636 | 639 |
|
... | ... | |
644 | 647 |
return -1; |
645 | 648 |
} |
646 | 649 |
|
650 |
obt_as.freq = obt.freq; |
|
651 |
obt_as.nchannels = obt.nchannels; |
|
652 |
obt_as.fmt = effective_fmt; |
|
653 |
|
|
647 | 654 |
audio_pcm_init_info ( |
648 | 655 |
&hw->info, |
649 |
obt.freq, |
|
650 |
obt.nchannels, |
|
651 |
effective_fmt, |
|
656 |
&obt_as, |
|
652 | 657 |
audio_need_to_swap_endian (endianness) |
653 | 658 |
); |
654 | 659 |
alsa->can_pause = obt.can_pause; |
655 |
hw->bufsize = obt.buffer_size;
|
|
660 |
hw->samples = obt.samples;
|
|
656 | 661 |
|
657 |
alsa->pcm_buf = qemu_mallocz (hw->bufsize);
|
|
662 |
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
|
|
658 | 663 |
if (!alsa->pcm_buf) { |
664 |
dolog ("Could not allocate DAC buffer (%d bytes)\n", |
|
665 |
hw->samples << hw->info.shift); |
|
659 | 666 |
alsa_anal_close (&handle); |
660 | 667 |
return -1; |
661 | 668 |
} |
... | ... | |
703 | 710 |
return 0; |
704 | 711 |
} |
705 | 712 |
|
706 |
static int alsa_init_in (HWVoiceIn *hw, |
|
707 |
int freq, int nchannels, audfmt_e fmt) |
|
713 |
static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as) |
|
708 | 714 |
{ |
709 | 715 |
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; |
710 | 716 |
struct alsa_params_req req; |
... | ... | |
713 | 719 |
int err; |
714 | 720 |
audfmt_e effective_fmt; |
715 | 721 |
snd_pcm_t *handle; |
722 |
audsettings_t obt_as; |
|
716 | 723 |
|
717 |
req.fmt = aud_to_alsafmt (fmt); |
|
718 |
req.freq = freq; |
|
719 |
req.nchannels = nchannels; |
|
724 |
req.fmt = aud_to_alsafmt (as->fmt);
|
|
725 |
req.freq = as->freq;
|
|
726 |
req.nchannels = as->nchannels;
|
|
720 | 727 |
req.period_size = conf.period_size_in; |
721 | 728 |
req.buffer_size = conf.buffer_size_in; |
722 | 729 |
|
... | ... | |
730 | 737 |
return -1; |
731 | 738 |
} |
732 | 739 |
|
740 |
obt_as.freq = obt.freq; |
|
741 |
obt_as.nchannels = obt.nchannels; |
|
742 |
obt_as.fmt = effective_fmt; |
|
743 |
|
|
733 | 744 |
audio_pcm_init_info ( |
734 | 745 |
&hw->info, |
735 |
obt.freq, |
|
736 |
obt.nchannels, |
|
737 |
effective_fmt, |
|
746 |
&obt_as, |
|
738 | 747 |
audio_need_to_swap_endian (endianness) |
739 | 748 |
); |
740 | 749 |
alsa->can_pause = obt.can_pause; |
741 |
hw->bufsize = obt.buffer_size; |
|
742 |
alsa->pcm_buf = qemu_mallocz (hw->bufsize); |
|
750 |
hw->samples = obt.samples; |
|
751 |
|
|
752 |
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); |
|
743 | 753 |
if (!alsa->pcm_buf) { |
754 |
dolog ("Could not allocate ADC buffer (%d bytes)\n", |
|
755 |
hw->samples << hw->info.shift); |
|
744 | 756 |
alsa_anal_close (&handle); |
745 | 757 |
return -1; |
746 | 758 |
} |
b/audio/audio.c | ||
---|---|---|
26 | 26 |
#define AUDIO_CAP "audio" |
27 | 27 |
#include "audio_int.h" |
28 | 28 |
|
29 |
static void audio_pcm_hw_fini_in (HWVoiceIn *hw); |
|
30 |
static void audio_pcm_hw_fini_out (HWVoiceOut *hw); |
|
31 |
|
|
32 |
static LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in; |
|
33 |
static LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out; |
|
34 |
|
|
35 | 29 |
/* #define DEBUG_PLIVE */ |
36 | 30 |
/* #define DEBUG_LIVE */ |
37 | 31 |
/* #define DEBUG_OUT */ |
38 | 32 |
|
33 |
#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown" |
|
34 |
|
|
39 | 35 |
static struct audio_driver *drvtab[] = { |
40 | 36 |
#ifdef CONFIG_OSS |
41 | 37 |
&oss_audio_driver, |
... | ... | |
59 | 55 |
&wav_audio_driver |
60 | 56 |
}; |
61 | 57 |
|
62 |
AudioState audio_state = { |
|
63 |
/* Out */ |
|
64 |
1, /* use fixed settings */ |
|
65 |
44100, /* fixed frequency */ |
|
66 |
2, /* fixed channels */ |
|
67 |
AUD_FMT_S16, /* fixed format */ |
|
68 |
1, /* number of hw voices */ |
|
69 |
1, /* greedy */ |
|
70 |
|
|
71 |
/* In */ |
|
72 |
1, /* use fixed settings */ |
|
73 |
44100, /* fixed frequency */ |
|
74 |
2, /* fixed channels */ |
|
75 |
AUD_FMT_S16, /* fixed format */ |
|
76 |
1, /* number of hw voices */ |
|
77 |
1, /* greedy */ |
|
78 |
|
|
79 |
NULL, /* driver opaque */ |
|
80 |
NULL, /* driver */ |
|
81 |
|
|
82 |
NULL, /* timer handle */ |
|
58 |
struct fixed_settings { |
|
59 |
int enabled; |
|
60 |
int nb_voices; |
|
61 |
int greedy; |
|
62 |
audsettings_t settings; |
|
63 |
}; |
|
64 |
|
|
65 |
static struct { |
|
66 |
struct fixed_settings fixed_out; |
|
67 |
struct fixed_settings fixed_in; |
|
68 |
union { |
|
69 |
int hz; |
|
70 |
int64_t ticks; |
|
71 |
} period; |
|
72 |
int plive; |
|
73 |
} conf = { |
|
74 |
{ /* DAC fixed settings */ |
|
75 |
1, /* enabled */ |
|
76 |
1, /* nb_voices */ |
|
77 |
1, /* greedy */ |
|
78 |
{ |
|
79 |
44100, /* freq */ |
|
80 |
2, /* nchannels */ |
|
81 |
AUD_FMT_S16 /* fmt */ |
|
82 |
} |
|
83 |
}, |
|
84 |
|
|
85 |
{ /* ADC fixed settings */ |
|
86 |
1, /* enabled */ |
|
87 |
1, /* nb_voices */ |
|
88 |
1, /* greedy */ |
|
89 |
{ |
|
90 |
44100, /* freq */ |
|
91 |
2, /* nchannels */ |
|
92 |
AUD_FMT_S16 /* fmt */ |
|
93 |
} |
|
94 |
}, |
|
95 |
|
|
83 | 96 |
{ 0 }, /* period */ |
84 | 97 |
0 /* plive */ |
85 | 98 |
}; |
86 | 99 |
|
100 |
static AudioState glob_audio_state; |
|
101 |
|
|
87 | 102 |
volume_t nominal_volume = { |
88 | 103 |
0, |
89 | 104 |
#ifdef FLOAT_MIXENG |
... | ... | |
148 | 163 |
} |
149 | 164 |
#endif |
150 | 165 |
|
166 |
void *audio_calloc (const char *funcname, int nmemb, size_t size) |
|
167 |
{ |
|
168 |
int cond; |
|
169 |
size_t len; |
|
170 |
|
|
171 |
len = nmemb * size; |
|
172 |
cond = !nmemb || !size; |
|
173 |
cond |= nmemb < 0; |
|
174 |
cond |= len < size; |
|
175 |
|
|
176 |
if (audio_bug ("audio_calloc", cond)) { |
|
177 |
AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n", |
|
178 |
funcname); |
|
179 |
AUD_log (NULL, "nmemb=%d size=%d (len=%d)\n", nmemb, size, len); |
|
180 |
return NULL; |
|
181 |
} |
|
182 |
|
|
183 |
return qemu_mallocz (len); |
|
184 |
} |
|
185 |
|
|
151 | 186 |
static char *audio_alloc_prefix (const char *s) |
152 | 187 |
{ |
153 | 188 |
const char qemu_prefix[] = "QEMU_"; |
... | ... | |
386 | 421 |
} |
387 | 422 |
|
388 | 423 |
len = strlen (opt->name); |
424 |
/* len of opt->name + len of prefix + size of qemu_prefix |
|
425 |
* (includes trailing zero) + zero + underscore (on behalf of |
|
426 |
* sizeof) */ |
|
389 | 427 |
optname = qemu_malloc (len + preflen + sizeof (qemu_prefix) + 1); |
390 | 428 |
if (!optname) { |
391 |
dolog ("Can not allocate memory for option name `%s'\n",
|
|
429 |
dolog ("Could not allocate memory for option name `%s'\n",
|
|
392 | 430 |
opt->name); |
393 | 431 |
continue; |
394 | 432 |
} |
395 | 433 |
|
396 | 434 |
strcpy (optname, qemu_prefix); |
435 |
|
|
436 |
/* copy while upper-casing, including trailing zero */ |
|
397 | 437 |
for (i = 0; i <= preflen; ++i) { |
398 | 438 |
optname[i + sizeof (qemu_prefix) - 1] = toupper (prefix[i]); |
399 | 439 |
} |
... | ... | |
438 | 478 |
} |
439 | 479 |
} |
440 | 480 |
|
441 |
static int audio_pcm_info_eq (struct audio_pcm_info *info, int freq, |
|
442 |
int nchannels, audfmt_e fmt) |
|
481 |
static void audio_print_settings (audsettings_t *as) |
|
482 |
{ |
|
483 |
dolog ("frequency=%d nchannels=%d fmt=", as->freq, as->nchannels); |
|
484 |
|
|
485 |
switch (as->fmt) { |
|
486 |
case AUD_FMT_S8: |
|
487 |
AUD_log (NULL, "S8"); |
|
488 |
break; |
|
489 |
case AUD_FMT_U8: |
|
490 |
AUD_log (NULL, "U8"); |
|
491 |
break; |
|
492 |
case AUD_FMT_S16: |
|
493 |
AUD_log (NULL, "S16"); |
|
494 |
break; |
|
495 |
case AUD_FMT_U16: |
|
496 |
AUD_log (NULL, "U16"); |
|
497 |
break; |
|
498 |
default: |
|
499 |
AUD_log (NULL, "invalid(%d)", as->fmt); |
|
500 |
break; |
|
501 |
} |
|
502 |
AUD_log (NULL, "\n"); |
|
503 |
} |
|
504 |
|
|
505 |
static int audio_validate_settigs (audsettings_t *as) |
|
506 |
{ |
|
507 |
int invalid; |
|
508 |
|
|
509 |
invalid = as->nchannels != 1 && as->nchannels != 2; |
|
510 |
|
|
511 |
switch (as->fmt) { |
|
512 |
case AUD_FMT_S8: |
|
513 |
case AUD_FMT_U8: |
|
514 |
case AUD_FMT_S16: |
|
515 |
case AUD_FMT_U16: |
|
516 |
break; |
|
517 |
default: |
|
518 |
invalid = 1; |
|
519 |
break; |
|
520 |
} |
|
521 |
|
|
522 |
invalid |= as->freq <= 0; |
|
523 |
|
|
524 |
if (invalid) { |
|
525 |
return -1; |
|
526 |
} |
|
527 |
return 0; |
|
528 |
} |
|
529 |
|
|
530 |
static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as) |
|
443 | 531 |
{ |
444 | 532 |
int bits = 8, sign = 0; |
445 | 533 |
|
446 |
switch (fmt) { |
|
534 |
switch (as->fmt) {
|
|
447 | 535 |
case AUD_FMT_S8: |
448 | 536 |
sign = 1; |
449 | 537 |
case AUD_FMT_U8: |
... | ... | |
455 | 543 |
bits = 16; |
456 | 544 |
break; |
457 | 545 |
} |
458 |
return info->freq == freq |
|
459 |
&& info->nchannels == nchannels |
|
546 |
return info->freq == as->freq
|
|
547 |
&& info->nchannels == as->nchannels
|
|
460 | 548 |
&& info->sign == sign |
461 | 549 |
&& info->bits == bits; |
462 | 550 |
} |
463 | 551 |
|
464 |
void audio_pcm_init_info (struct audio_pcm_info *info, int freq, |
|
465 |
int nchannels, audfmt_e fmt, int swap_endian) |
|
552 |
void audio_pcm_init_info ( |
|
553 |
struct audio_pcm_info *info, |
|
554 |
audsettings_t *as, |
|
555 |
int swap_endian |
|
556 |
) |
|
466 | 557 |
{ |
467 | 558 |
int bits = 8, sign = 0; |
468 | 559 |
|
469 |
switch (fmt) { |
|
560 |
switch (as->fmt) {
|
|
470 | 561 |
case AUD_FMT_S8: |
471 | 562 |
sign = 1; |
472 | 563 |
case AUD_FMT_U8: |
... | ... | |
479 | 570 |
break; |
480 | 571 |
} |
481 | 572 |
|
482 |
info->freq = freq; |
|
573 |
info->freq = as->freq;
|
|
483 | 574 |
info->bits = bits; |
484 | 575 |
info->sign = sign; |
485 |
info->nchannels = nchannels; |
|
486 |
info->shift = (nchannels == 2) + (bits == 16); |
|
576 |
info->nchannels = as->nchannels;
|
|
577 |
info->shift = (as->nchannels == 2) + (bits == 16);
|
|
487 | 578 |
info->align = (1 << info->shift) - 1; |
488 | 579 |
info->bytes_per_second = info->freq << info->shift; |
489 | 580 |
info->swap_endian = swap_endian; |
... | ... | |
532 | 623 |
|
533 | 624 |
static int audio_pcm_hw_alloc_resources_in (HWVoiceIn *hw) |
534 | 625 |
{ |
535 |
hw->conv_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t));
|
|
626 |
hw->conv_buf = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t));
|
|
536 | 627 |
if (!hw->conv_buf) { |
628 |
dolog ("Could not allocate ADC conversion buffer (%d bytes)\n", |
|
629 |
hw->samples * sizeof (st_sample_t)); |
|
537 | 630 |
return -1; |
538 | 631 |
} |
539 | 632 |
return 0; |
540 | 633 |
} |
541 | 634 |
|
542 |
static int audio_pcm_hw_init_in (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt) |
|
543 |
{ |
|
544 |
audio_pcm_hw_fini_in (hw); |
|
545 |
|
|
546 |
if (hw->pcm_ops->init_in (hw, freq, nchannels, fmt)) { |
|
547 |
memset (hw, 0, audio_state.drv->voice_size_in); |
|
548 |
return -1; |
|
549 |
} |
|
550 |
LIST_INIT (&hw->sw_head); |
|
551 |
hw->active = 1; |
|
552 |
hw->samples = hw->bufsize >> hw->info.shift; |
|
553 |
hw->conv = |
|
554 |
mixeng_conv |
|
555 |
[nchannels == 2] |
|
556 |
[hw->info.sign] |
|
557 |
[hw->info.swap_endian] |
|
558 |
[hw->info.bits == 16]; |
|
559 |
if (audio_pcm_hw_alloc_resources_in (hw)) { |
|
560 |
audio_pcm_hw_free_resources_in (hw); |
|
561 |
return -1; |
|
562 |
} |
|
563 |
return 0; |
|
564 |
} |
|
565 |
|
|
566 |
static uint64_t audio_pcm_hw_find_min_in (HWVoiceIn *hw) |
|
635 |
static int audio_pcm_hw_find_min_in (HWVoiceIn *hw) |
|
567 | 636 |
{ |
568 | 637 |
SWVoiceIn *sw; |
569 | 638 |
int m = hw->total_samples_captured; |
... | ... | |
606 | 675 |
static int audio_pcm_sw_alloc_resources_in (SWVoiceIn *sw) |
607 | 676 |
{ |
608 | 677 |
int samples = ((int64_t) sw->hw->samples << 32) / sw->ratio; |
609 |
sw->conv_buf = qemu_mallocz (samples * sizeof (st_sample_t));
|
|
678 |
sw->conv_buf = audio_calloc (AUDIO_FUNC, samples, sizeof (st_sample_t));
|
|
610 | 679 |
if (!sw->conv_buf) { |
680 |
dolog ("Could not allocate buffer for `%s' (%d bytes)\n", |
|
681 |
SW_NAME (sw), samples * sizeof (st_sample_t)); |
|
611 | 682 |
return -1; |
612 | 683 |
} |
613 | 684 |
|
... | ... | |
620 | 691 |
return 0; |
621 | 692 |
} |
622 | 693 |
|
623 |
static int audio_pcm_sw_init_in (SWVoiceIn *sw, HWVoiceIn *hw, const char *name, |
|
624 |
int freq, int nchannels, audfmt_e fmt) |
|
694 |
static int audio_pcm_sw_init_in ( |
|
695 |
SWVoiceIn *sw, |
|
696 |
HWVoiceIn *hw, |
|
697 |
const char *name, |
|
698 |
audsettings_t *as |
|
699 |
) |
|
625 | 700 |
{ |
626 |
audio_pcm_init_info (&sw->info, freq, nchannels, fmt, |
|
627 |
/* None of the cards emulated by QEMU are big-endian |
|
628 |
hence following shortcut */ |
|
629 |
audio_need_to_swap_endian (0)); |
|
701 |
/* None of the cards emulated by QEMU are big-endian |
|
702 |
hence following shortcut */ |
|
703 |
audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (0)); |
|
630 | 704 |
sw->hw = hw; |
631 | 705 |
sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq; |
632 | 706 |
|
633 | 707 |
sw->clip = |
634 | 708 |
mixeng_clip |
635 |
[nchannels == 2] |
|
709 |
[sw->info.nchannels == 2]
|
|
636 | 710 |
[sw->info.sign] |
637 | 711 |
[sw->info.swap_endian] |
638 | 712 |
[sw->info.bits == 16]; |
... | ... | |
699 | 773 |
|
700 | 774 |
if (audio_bug (AUDIO_FUNC, osamp < 0)) { |
701 | 775 |
dolog ("osamp=%d\n", osamp); |
776 |
return 0; |
|
702 | 777 |
} |
703 | 778 |
|
704 | 779 |
st_rate_flow (sw->rate, src, dst, &isamp, &osamp); |
... | ... | |
717 | 792 |
/* |
718 | 793 |
* Hard voice (playback) |
719 | 794 |
*/ |
720 |
static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep) |
|
721 |
{ |
|
722 |
SWVoiceOut *sw; |
|
723 |
int m = INT_MAX; |
|
724 |
int nb_live = 0; |
|
725 |
|
|
726 |
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { |
|
727 |
if (sw->active || !sw->empty) { |
|
728 |
m = audio_MIN (m, sw->total_hw_samples_mixed); |
|
729 |
nb_live += 1; |
|
730 |
} |
|
731 |
} |
|
732 |
|
|
733 |
*nb_livep = nb_live; |
|
734 |
return m; |
|
735 |
} |
|
736 |
|
|
737 | 795 |
static void audio_pcm_hw_free_resources_out (HWVoiceOut *hw) |
738 | 796 |
{ |
739 | 797 |
if (hw->mix_buf) { |
... | ... | |
745 | 803 |
|
746 | 804 |
static int audio_pcm_hw_alloc_resources_out (HWVoiceOut *hw) |
747 | 805 |
{ |
748 |
hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t));
|
|
806 |
hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t));
|
|
749 | 807 |
if (!hw->mix_buf) { |
808 |
dolog ("Could not allocate DAC mixing buffer (%d bytes)\n", |
|
809 |
hw->samples * sizeof (st_sample_t)); |
|
750 | 810 |
return -1; |
751 | 811 |
} |
752 | 812 |
|
753 | 813 |
return 0; |
754 | 814 |
} |
755 | 815 |
|
756 |
static int audio_pcm_hw_init_out (HWVoiceOut *hw, int freq, |
|
757 |
int nchannels, audfmt_e fmt) |
|
816 |
static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep) |
|
758 | 817 |
{ |
759 |
audio_pcm_hw_fini_out (hw); |
|
760 |
if (hw->pcm_ops->init_out (hw, freq, nchannels, fmt)) { |
|
761 |
memset (hw, 0, audio_state.drv->voice_size_out); |
|
762 |
return -1; |
|
763 |
} |
|
818 |
SWVoiceOut *sw; |
|
819 |
int m = INT_MAX; |
|
820 |
int nb_live = 0; |
|
764 | 821 |
|
765 |
LIST_INIT (&hw->sw_head); |
|
766 |
hw->active = 1; |
|
767 |
hw->samples = hw->bufsize >> hw->info.shift; |
|
768 |
hw->clip = |
|
769 |
mixeng_clip |
|
770 |
[nchannels == 2] |
|
771 |
[hw->info.sign] |
|
772 |
[hw->info.swap_endian] |
|
773 |
[hw->info.bits == 16]; |
|
774 |
if (audio_pcm_hw_alloc_resources_out (hw)) { |
|
775 |
audio_pcm_hw_fini_out (hw); |
|
776 |
return -1; |
|
822 |
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { |
|
823 |
if (sw->active || !sw->empty) { |
|
824 |
m = audio_MIN (m, sw->total_hw_samples_mixed); |
|
825 |
nb_live += 1; |
|
826 |
} |
|
777 | 827 |
} |
778 |
return 0; |
|
828 |
|
|
829 |
*nb_livep = nb_live; |
|
830 |
return m; |
|
779 | 831 |
} |
780 | 832 |
|
781 | 833 |
int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live) |
... | ... | |
830 | 882 |
|
831 | 883 |
static int audio_pcm_sw_alloc_resources_out (SWVoiceOut *sw) |
832 | 884 |
{ |
833 |
sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t));
|
|
885 |
sw->buf = audio_calloc (AUDIO_FUNC, sw->hw->samples, sizeof (st_sample_t));
|
|
834 | 886 |
if (!sw->buf) { |
887 |
dolog ("Could not allocate buffer for `%s' (%d bytes)\n", |
|
888 |
SW_NAME (sw), sw->hw->samples * sizeof (st_sample_t)); |
|
835 | 889 |
return -1; |
836 | 890 |
} |
837 | 891 |
|
... | ... | |
844 | 898 |
return 0; |
845 | 899 |
} |
846 | 900 |
|
847 |
static int audio_pcm_sw_init_out (SWVoiceOut *sw, HWVoiceOut *hw, |
|
848 |
const char *name, int freq, |
|
849 |
int nchannels, audfmt_e fmt) |
|
901 |
static int audio_pcm_sw_init_out ( |
|
902 |
SWVoiceOut *sw, |
|
903 |
HWVoiceOut *hw, |
|
904 |
const char *name, |
|
905 |
audsettings_t *as |
|
906 |
) |
|
850 | 907 |
{ |
851 |
audio_pcm_init_info (&sw->info, freq, nchannels, fmt, |
|
852 |
/* None of the cards emulated by QEMU are big-endian |
|
853 |
hence following shortcut */ |
|
854 |
audio_need_to_swap_endian (0)); |
|
908 |
/* None of the cards emulated by QEMU are big-endian |
|
909 |
hence following shortcut */ |
|
910 |
audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (0)); |
|
855 | 911 |
sw->hw = hw; |
856 | 912 |
sw->empty = 1; |
857 | 913 |
sw->active = 0; |
... | ... | |
860 | 916 |
|
861 | 917 |
sw->conv = |
862 | 918 |
mixeng_conv |
863 |
[nchannels == 2] |
|
919 |
[sw->info.nchannels == 2]
|
|
864 | 920 |
[sw->info.sign] |
865 | 921 |
[sw->info.swap_endian] |
866 | 922 |
[sw->info.bits == 16]; |
... | ... | |
930 | 986 |
|
931 | 987 |
#ifdef DEBUG_OUT |
932 | 988 |
dolog ( |
933 |
"%s: write size %d ret %d total sw %d, hw %d\n",
|
|
934 |
sw->name,
|
|
989 |
"%s: write size %d ret %d total sw %d\n", |
|
990 |
SW_NAME (sw),
|
|
935 | 991 |
size >> sw->info.shift, |
936 | 992 |
ret, |
937 |
sw->total_hw_samples_mixed, |
|
938 |
sw->hw->total_samples_played |
|
993 |
sw->total_hw_samples_mixed |
|
939 | 994 |
); |
940 | 995 |
#endif |
941 | 996 |
|
... | ... | |
965 | 1020 |
} |
966 | 1021 |
|
967 | 1022 |
if (!sw->hw->enabled) { |
968 |
dolog ("Writing to disabled voice %s\n", sw->name);
|
|
1023 |
dolog ("Writing to disabled voice %s\n", SW_NAME (sw));
|
|
969 | 1024 |
return 0; |
970 | 1025 |
} |
971 | 1026 |
|
... | ... | |
983 | 1038 |
} |
984 | 1039 |
|
985 | 1040 |
if (!sw->hw->enabled) { |
986 |
dolog ("Reading from disabled voice %s\n", sw->name);
|
|
1041 |
dolog ("Reading from disabled voice %s\n", SW_NAME (sw));
|
|
987 | 1042 |
return 0; |
988 | 1043 |
} |
989 | 1044 |
|
... | ... | |
993 | 1048 |
|
994 | 1049 |
int AUD_get_buffer_size_out (SWVoiceOut *sw) |
995 | 1050 |
{ |
996 |
return sw->hw->bufsize;
|
|
1051 |
return sw->hw->samples << sw->hw->info.shift;
|
|
997 | 1052 |
} |
998 | 1053 |
|
999 | 1054 |
void AUD_set_active_out (SWVoiceOut *sw, int on) |
... | ... | |
1091 | 1146 |
|
1092 | 1147 |
ldebug ( |
1093 | 1148 |
"%s: get_avail live %d ret %lld\n", |
1094 |
sw->name,
|
|
1149 |
SW_NAME (sw),
|
|
1095 | 1150 |
live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift |
1096 | 1151 |
); |
1097 | 1152 |
|
... | ... | |
1110 | 1165 |
|
1111 | 1166 |
if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) { |
1112 | 1167 |
dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples); |
1168 |
return 0; |
|
1113 | 1169 |
} |
1114 | 1170 |
|
1115 | 1171 |
dead = sw->hw->samples - live; |
1116 | 1172 |
|
1117 | 1173 |
#ifdef DEBUG_OUT |
1118 | 1174 |
dolog ("%s: get_free live %d dead %d ret %lld\n", |
1119 |
sw->name,
|
|
1175 |
SW_NAME (sw),
|
|
1120 | 1176 |
live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift); |
1121 | 1177 |
#endif |
1122 | 1178 |
|
1123 | 1179 |
return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift; |
1124 | 1180 |
} |
1125 | 1181 |
|
1126 |
static void audio_run_out (void)
|
|
1182 |
static void audio_run_out (AudioState *s)
|
|
1127 | 1183 |
{ |
1128 | 1184 |
HWVoiceOut *hw = NULL; |
1129 | 1185 |
SWVoiceOut *sw; |
1130 | 1186 |
|
1131 |
while ((hw = audio_pcm_hw_find_any_active_enabled_out (hw))) {
|
|
1187 |
while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) {
|
|
1132 | 1188 |
int played; |
1133 |
int live, free, nb_live; |
|
1189 |
int live, free, nb_live, cleanup_required;
|
|
1134 | 1190 |
|
1135 | 1191 |
live = audio_pcm_hw_get_live_out2 (hw, &nb_live); |
1136 | 1192 |
if (!nb_live) { |
1137 | 1193 |
live = 0; |
1138 | 1194 |
} |
1195 |
|
|
1139 | 1196 |
if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { |
1140 | 1197 |
dolog ("live=%d hw->samples=%d\n", live, hw->samples); |
1198 |
continue; |
|
1141 | 1199 |
} |
1142 | 1200 |
|
1143 | 1201 |
if (hw->pending_disable && !nb_live) { |
... | ... | |
1170 | 1228 |
} |
1171 | 1229 |
|
1172 | 1230 |
#ifdef DEBUG_OUT |
1173 |
dolog ("played = %d total %d\n", played, hw->total_samples_played);
|
|
1231 |
dolog ("played=%d\n", played);
|
|
1174 | 1232 |
#endif |
1175 | 1233 |
|
1176 | 1234 |
if (played) { |
1177 | 1235 |
hw->ts_helper += played; |
1178 | 1236 |
} |
1179 | 1237 |
|
1238 |
cleanup_required = 0; |
|
1180 | 1239 |
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { |
1181 |
again: |
|
1182 | 1240 |
if (!sw->active && sw->empty) { |
1183 | 1241 |
continue; |
1184 | 1242 |
} |
... | ... | |
1193 | 1251 |
|
1194 | 1252 |
if (!sw->total_hw_samples_mixed) { |
1195 | 1253 |
sw->empty = 1; |
1196 |
|
|
1197 |
if (!sw->active && !sw->callback.fn) { |
|
1198 |
SWVoiceOut *temp = sw->entries.le_next; |
|
1199 |
|
|
1200 |
#ifdef DEBUG_PLIVE |
|
1201 |
dolog ("Finishing with old voice\n"); |
|
1202 |
#endif |
|
1203 |
AUD_close_out (sw); |
|
1204 |
sw = temp; |
|
1205 |
if (sw) { |
|
1206 |
goto again; |
|
1207 |
} |
|
1208 |
else { |
|
1209 |
break; |
|
1210 |
} |
|
1211 |
} |
|
1254 |
cleanup_required |= !sw->active && !sw->callback.fn; |
|
1212 | 1255 |
} |
1213 | 1256 |
|
1214 | 1257 |
if (sw->active) { |
... | ... | |
1218 | 1261 |
} |
1219 | 1262 |
} |
1220 | 1263 |
} |
1264 |
|
|
1265 |
if (cleanup_required) { |
|
1266 |
restart: |
|
1267 |
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { |
|
1268 |
if (!sw->active && !sw->callback.fn) { |
|
1269 |
#ifdef DEBUG_PLIVE |
|
1270 |
dolog ("Finishing with old voice\n"); |
|
1271 |
#endif |
|
1272 |
audio_close_out (s, sw); |
|
1273 |
goto restart; /* play it safe */ |
|
1274 |
} |
|
1275 |
} |
|
1276 |
} |
|
1221 | 1277 |
} |
1222 | 1278 |
} |
1223 | 1279 |
|
1224 |
static void audio_run_in (void)
|
|
1280 |
static void audio_run_in (AudioState *s)
|
|
1225 | 1281 |
{ |
1226 | 1282 |
HWVoiceIn *hw = NULL; |
1227 | 1283 |
|
1228 |
while ((hw = audio_pcm_hw_find_any_active_enabled_in (hw))) {
|
|
1284 |
while ((hw = audio_pcm_hw_find_any_enabled_in (s, hw))) {
|
|
1229 | 1285 |
SWVoiceIn *sw; |
1230 | 1286 |
int captured, min; |
1231 | 1287 |
|
... | ... | |
1252 | 1308 |
|
1253 | 1309 |
static struct audio_option audio_options[] = { |
1254 | 1310 |
/* DAC */ |
1255 |
{"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &audio_state.fixed_settings_out,
|
|
1311 |
{"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_out.enabled,
|
|
1256 | 1312 |
"Use fixed settings for host DAC", NULL, 0}, |
1257 | 1313 |
|
1258 |
{"DAC_FIXED_FREQ", AUD_OPT_INT, &audio_state.fixed_freq_out,
|
|
1314 |
{"DAC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_out.settings.freq,
|
|
1259 | 1315 |
"Frequency for fixed host DAC", NULL, 0}, |
1260 | 1316 |
|
1261 |
{"DAC_FIXED_FMT", AUD_OPT_FMT, &audio_state.fixed_fmt_out,
|
|
1317 |
{"DAC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_out.settings.fmt,
|
|
1262 | 1318 |
"Format for fixed host DAC", NULL, 0}, |
1263 | 1319 |
|
1264 |
{"DAC_FIXED_CHANNELS", AUD_OPT_INT, &audio_state.fixed_channels_out,
|
|
1320 |
{"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_out.settings.nchannels,
|
|
1265 | 1321 |
"Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0}, |
1266 | 1322 |
|
1267 |
{"DAC_VOICES", AUD_OPT_INT, &audio_state.nb_hw_voices_out,
|
|
1323 |
{"DAC_VOICES", AUD_OPT_INT, &conf.fixed_out.nb_voices,
|
|
1268 | 1324 |
"Number of voices for DAC", NULL, 0}, |
1269 | 1325 |
|
1270 | 1326 |
/* ADC */ |
1271 |
{"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &audio_state.fixed_settings_out,
|
|
1327 |
{"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_in.enabled,
|
|
1272 | 1328 |
"Use fixed settings for host ADC", NULL, 0}, |
1273 | 1329 |
|
1274 |
{"ADC_FIXED_FREQ", AUD_OPT_INT, &audio_state.fixed_freq_out,
|
|
1275 |
"Frequency for fixed ADC", NULL, 0}, |
|
1330 |
{"ADC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_in.settings.freq,
|
|
1331 |
"Frequency for fixed host ADC", NULL, 0},
|
|
1276 | 1332 |
|
1277 |
{"ADC_FIXED_FMT", AUD_OPT_FMT, &audio_state.fixed_fmt_out,
|
|
1278 |
"Format for fixed ADC", NULL, 0}, |
|
1333 |
{"ADC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_in.settings.fmt,
|
|
1334 |
"Format for fixed host ADC", NULL, 0},
|
|
1279 | 1335 |
|
1280 |
{"ADC_FIXED_CHANNELS", AUD_OPT_INT, &audio_state.fixed_channels_in,
|
|
1336 |
{"ADC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_in.settings.nchannels,
|
|
1281 | 1337 |
"Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0}, |
1282 | 1338 |
|
1283 |
{"ADC_VOICES", AUD_OPT_INT, &audio_state.nb_hw_voices_out,
|
|
1339 |
{"ADC_VOICES", AUD_OPT_INT, &conf.fixed_in.nb_voices,
|
|
1284 | 1340 |
"Number of voices for ADC", NULL, 0}, |
1285 | 1341 |
|
1286 | 1342 |
/* Misc */ |
1287 |
{"TIMER_PERIOD", AUD_OPT_INT, &audio_state.period.usec,
|
|
1288 |
"Timer period in microseconds (0 - try lowest possible)", NULL, 0},
|
|
1343 |
{"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hz,
|
|
1344 |
"Timer period in HZ (0 - use lowest possible)", NULL, 0},
|
|
1289 | 1345 |
|
1290 |
{"PLIVE", AUD_OPT_BOOL, &audio_state.plive,
|
|
1346 |
{"PLIVE", AUD_OPT_BOOL, &conf.plive,
|
|
1291 | 1347 |
"(undocumented)", NULL, 0}, |
1292 | 1348 |
|
1293 | 1349 |
{NULL, 0, NULL, NULL, NULL, 0} |
... | ... | |
1378 | 1434 |
{ |
1379 | 1435 |
AudioState *s = opaque; |
1380 | 1436 |
|
1381 |
audio_run_out (); |
|
1382 |
audio_run_in (); |
|
1437 |
audio_run_out (s);
|
|
1438 |
audio_run_in (s);
|
|
1383 | 1439 |
|
1384 |
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + s->period.ticks);
|
|
1440 |
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
|
|
1385 | 1441 |
} |
1386 | 1442 |
|
1387 |
static int audio_driver_init (struct audio_driver *drv) |
|
1443 |
static int audio_driver_init (AudioState *s, struct audio_driver *drv)
|
|
1388 | 1444 |
{ |
1389 | 1445 |
if (drv->options) { |
1390 | 1446 |
audio_process_options (drv->name, drv->options); |
1391 | 1447 |
} |
1392 |
audio_state.opaque = drv->init ();
|
|
1448 |
s->drv_opaque = drv->init ();
|
|
1393 | 1449 |
|
1394 |
if (audio_state.opaque) { |
|
1395 |
int i; |
|
1396 |
HWVoiceOut *hwo; |
|
1397 |
HWVoiceIn *hwi; |
|
1398 |
|
|
1399 |
if (audio_state.nb_hw_voices_out > drv->max_voices_out) { |
|
1450 |
if (s->drv_opaque) { |
|
1451 |
if (s->nb_hw_voices_out > drv->max_voices_out) { |
|
1400 | 1452 |
if (!drv->max_voices_out) { |
1401 | 1453 |
dolog ("`%s' does not support DAC\n", drv->name); |
1402 | 1454 |
} |
... | ... | |
1405 | 1457 |
"`%s' does not support %d multiple DAC voicess\n" |
1406 | 1458 |
"Resetting to %d\n", |
1407 | 1459 |
drv->name, |
1408 |
audio_state.nb_hw_voices_out,
|
|
1460 |
s->nb_hw_voices_out,
|
|
1409 | 1461 |
drv->max_voices_out |
1410 | 1462 |
); |
1411 | 1463 |
} |
1412 |
audio_state.nb_hw_voices_out = drv->max_voices_out; |
|
1413 |
} |
|
1414 |
|
|
1415 |
LIST_INIT (&hw_head_out); |
|
1416 |
hwo = qemu_mallocz (audio_state.nb_hw_voices_out * drv->voice_size_out); |
|
1417 |
if (!hwo) { |
|
1418 |
dolog ( |
|
1419 |
"Not enough memory for %d `%s' DAC voices (each %d bytes)\n", |
|
1420 |
audio_state.nb_hw_voices_out, |
|
1421 |
drv->name, |
|
1422 |
drv->voice_size_out |
|
1423 |
); |
|
1424 |
drv->fini (audio_state.opaque); |
|
1425 |
return -1; |
|
1464 |
s->nb_hw_voices_out = drv->max_voices_out; |
|
1426 | 1465 |
} |
1427 | 1466 |
|
1428 |
for (i = 0; i < audio_state.nb_hw_voices_out; ++i) { |
|
1429 |
LIST_INSERT_HEAD (&hw_head_out, hwo, entries); |
|
1430 |
hwo = advance (hwo, drv->voice_size_out); |
|
1431 |
} |
|
1432 | 1467 |
|
1433 | 1468 |
if (!drv->voice_size_in && drv->max_voices_in) { |
1434 | 1469 |
ldebug ("warning: No ADC voice size defined for `%s'\n", |
... | ... | |
1442 | 1477 |
} |
1443 | 1478 |
|
1444 | 1479 |
if (drv->voice_size_in && !drv->max_voices_in) { |
1445 |
ldebug ("warning: ADC voice size is %d for ADC less driver `%s'\n",
|
|
1446 |
drv->voice_size_out, drv->name);
|
|
1480 |
ldebug ("warning: `%s' ADC voice size %d, zero voices \n",
|
|
1481 |
drv->name, drv->voice_size_out);
|
|
1447 | 1482 |
} |
1448 | 1483 |
|
1449 | 1484 |
if (drv->voice_size_out && !drv->max_voices_out) { |
1450 |
ldebug ("warning: DAC voice size is %d for DAC less driver `%s'\n",
|
|
1451 |
drv->voice_size_in, drv->name);
|
|
1485 |
ldebug ("warning: `%s' DAC voice size %d, zero voices \n",
|
|
1486 |
drv->name, drv->voice_size_in);
|
|
1452 | 1487 |
} |
1453 | 1488 |
|
1454 |
if (audio_state.nb_hw_voices_in > drv->max_voices_in) {
|
|
1489 |
if (s->nb_hw_voices_in > drv->max_voices_in) {
|
|
1455 | 1490 |
if (!drv->max_voices_in) { |
1456 | 1491 |
ldebug ("`%s' does not support ADC\n", drv->name); |
1457 | 1492 |
} |
... | ... | |
1460 | 1495 |
"`%s' does not support %d multiple ADC voices\n" |
1461 | 1496 |
"Resetting to %d\n", |
1462 | 1497 |
drv->name, |
1463 |
audio_state.nb_hw_voices_in,
|
|
1498 |
s->nb_hw_voices_in,
|
|
1464 | 1499 |
drv->max_voices_in |
1465 | 1500 |
); |
1466 | 1501 |
} |
1467 |
audio_state.nb_hw_voices_in = drv->max_voices_in;
|
|
1502 |
s->nb_hw_voices_in = drv->max_voices_in;
|
|
1468 | 1503 |
} |
1469 | 1504 |
|
1470 |
LIST_INIT (&hw_head_in); |
|
1471 |
hwi = qemu_mallocz (audio_state.nb_hw_voices_in * drv->voice_size_in); |
|
1472 |
if (!hwi) { |
|
1473 |
dolog ( |
|
1474 |
"Not enough memory for %d `%s' ADC voices (each %d bytes)\n", |
|
1475 |
audio_state.nb_hw_voices_in, |
|
1476 |
drv->name, |
|
1477 |
drv->voice_size_in |
|
1478 |
); |
|
1479 |
qemu_free (hwo); |
|
1480 |
drv->fini (audio_state.opaque); |
|
1481 |
return -1; |
|
1482 |
} |
|
1483 |
|
|
1484 |
for (i = 0; i < audio_state.nb_hw_voices_in; ++i) { |
|
1485 |
LIST_INSERT_HEAD (&hw_head_in, hwi, entries); |
|
1486 |
hwi = advance (hwi, drv->voice_size_in); |
|
1487 |
} |
|
1488 |
|
|
1489 |
audio_state.drv = drv; |
|
1505 |
LIST_INIT (&s->hw_head_out); |
|
1506 |
LIST_INIT (&s->hw_head_in); |
|
1507 |
s->drv = drv; |
|
1490 | 1508 |
return 0; |
1491 | 1509 |
} |
1492 | 1510 |
else { |
... | ... | |
1497 | 1515 |
|
1498 | 1516 |
static void audio_vm_stop_handler (void *opaque, int reason) |
1499 | 1517 |
{ |
1518 |
AudioState *s = opaque; |
|
1500 | 1519 |
HWVoiceOut *hwo = NULL; |
1501 | 1520 |
HWVoiceIn *hwi = NULL; |
1502 | 1521 |
int op = reason ? VOICE_ENABLE : VOICE_DISABLE; |
1503 | 1522 |
|
1504 |
(void) opaque; |
|
1505 |
while ((hwo = audio_pcm_hw_find_any_out (hwo))) { |
|
1523 |
while ((hwo = audio_pcm_hw_find_any_out (s, hwo))) { |
|
1506 | 1524 |
if (!hwo->pcm_ops) { |
1507 | 1525 |
continue; |
1508 | 1526 |
} |
... | ... | |
1512 | 1530 |
} |
1513 | 1531 |
} |
1514 | 1532 |
|
1515 |
while ((hwi = audio_pcm_hw_find_any_in (hwi))) { |
|
1533 |
while ((hwi = audio_pcm_hw_find_any_in (s, hwi))) {
|
|
1516 | 1534 |
if (!hwi->pcm_ops) { |
1517 | 1535 |
continue; |
1518 | 1536 |
} |
... | ... | |
1525 | 1543 |
|
1526 | 1544 |
static void audio_atexit (void) |
1527 | 1545 |
{ |
1546 |
AudioState *s = &glob_audio_state; |
|
1528 | 1547 |
HWVoiceOut *hwo = NULL; |
1529 | 1548 |
HWVoiceIn *hwi = NULL; |
1530 | 1549 |
|
1531 |
while ((hwo = audio_pcm_hw_find_any_out (hwo))) { |
|
1550 |
while ((hwo = audio_pcm_hw_find_any_out (s, hwo))) {
|
|
1532 | 1551 |
if (!hwo->pcm_ops) { |
1533 | 1552 |
continue; |
1534 | 1553 |
} |
... | ... | |
1539 | 1558 |
hwo->pcm_ops->fini_out (hwo); |
1540 | 1559 |
} |
1541 | 1560 |
|
1542 |
while ((hwi = audio_pcm_hw_find_any_in (hwi))) { |
|
1561 |
while ((hwi = audio_pcm_hw_find_any_in (s, hwi))) {
|
|
1543 | 1562 |
if (!hwi->pcm_ops) { |
1544 | 1563 |
continue; |
1545 | 1564 |
} |
... | ... | |
1549 | 1568 |
} |
1550 | 1569 |
hwi->pcm_ops->fini_in (hwi); |
1551 | 1570 |
} |
1552 |
audio_state.drv->fini (audio_state.opaque); |
|
1571 |
|
|
1572 |
if (s->drv) { |
|
1573 |
s->drv->fini (s->drv_opaque); |
|
1574 |
} |
|
1553 | 1575 |
} |
1554 | 1576 |
|
1555 | 1577 |
static void audio_save (QEMUFile *f, void *opaque) |
... | ... | |
1570 | 1592 |
return 0; |
1571 | 1593 |
} |
1572 | 1594 |
|
1573 |
void AUD_init (void) |
|
1595 |
void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card) |
|
1596 |
{ |
|
1597 |
card->audio = s; |
|
1598 |
card->name = qemu_strdup (name); |
|
1599 |
memset (&card->entries, 0, sizeof (card->entries)); |
|
1600 |
LIST_INSERT_HEAD (&s->card_head, card, entries); |
|
1601 |
} |
|
1602 |
|
|
1603 |
void AUD_remove_card (QEMUSoundCard *card) |
|
1604 |
{ |
|
1605 |
LIST_REMOVE (card, entries); |
|
1606 |
card->audio = NULL; |
|
1607 |
qemu_free (card->name); |
|
1608 |
} |
|
1609 |
|
|
1610 |
AudioState *AUD_init (void) |
|
1574 | 1611 |
{ |
1575 | 1612 |
size_t i; |
1576 | 1613 |
int done = 0; |
1577 | 1614 |
const char *drvname; |
1578 |
AudioState *s = &audio_state; |
|
1615 |
AudioState *s = &glob_audio_state;
|
|
1579 | 1616 |
|
1580 | 1617 |
audio_process_options ("AUDIO", audio_options); |
1581 | 1618 |
|
1619 |
s->nb_hw_voices_out = conf.fixed_out.nb_voices; |
|
1620 |
s->nb_hw_voices_in = conf.fixed_in.nb_voices; |
|
1621 |
|
|
1582 | 1622 |
if (s->nb_hw_voices_out <= 0) { |
1583 | 1623 |
dolog ("Bogus number of DAC voices %d\n", |
1584 | 1624 |
s->nb_hw_voices_out); |
... | ... | |
1598 | 1638 |
|
1599 | 1639 |
s->ts = qemu_new_timer (vm_clock, audio_timer, s); |
1600 | 1640 |
if (!s->ts) { |
1601 |
dolog ("Can not create audio timer\n");
|
|
1602 |
return; |
|
1641 |
dolog ("Could not create audio timer\n");
|
|
1642 |
return NULL;
|
|
1603 | 1643 |
} |
1604 | 1644 |
|
1605 | 1645 |
if (drvname) { |
... | ... | |
1607 | 1647 |
|
1608 | 1648 |
for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { |
1609 | 1649 |
if (!strcmp (drvname, drvtab[i]->name)) { |
1610 |
done = !audio_driver_init (drvtab[i]); |
|
1650 |
done = !audio_driver_init (s, drvtab[i]);
|
|
1611 | 1651 |
found = 1; |
1612 | 1652 |
break; |
1613 | 1653 |
} |
... | ... | |
1619 | 1659 |
} |
1620 | 1660 |
} |
1621 | 1661 |
|
1622 |
qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL); |
|
1623 |
atexit (audio_atexit); |
|
1624 |
|
|
1625 | 1662 |
if (!done) { |
1626 | 1663 |
for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { |
1627 | 1664 |
if (drvtab[i]->can_be_default) { |
1628 |
done = !audio_driver_init (drvtab[i]); |
|
1665 |
done = !audio_driver_init (s, drvtab[i]);
|
|
1629 | 1666 |
} |
1630 | 1667 |
} |
1631 | 1668 |
} |
1632 | 1669 |
|
1633 |
register_savevm ("audio", 0, 1, audio_save, audio_load, NULL); |
|
1634 | 1670 |
if (!done) { |
1635 |
if (audio_driver_init (&no_audio_driver)) { |
|
1636 |
dolog ("Can not initialize audio subsystem\n"); |
|
1671 |
done = !audio_driver_init (s, &no_audio_driver); |
|
1672 |
if (!done) { |
|
1673 |
dolog ("Could not initialize audio subsystem\n"); |
|
1637 | 1674 |
} |
1638 | 1675 |
else { |
1639 |
dolog ("warning: using timer based audio emulation\n");
|
|
1676 |
dolog ("warning: Using timer based audio emulation\n");
|
|
1640 | 1677 |
} |
1641 | 1678 |
} |
1642 | 1679 |
|
1643 |
if (s->period.usec <= 0) { |
|
1644 |
if (s->period.usec < 0) { |
|
1645 |
dolog ("warning: timer period is negative - %d treating as zero\n", |
|
1646 |
s->period.usec); |
|
1680 |
if (done) { |
|
1681 |
if (conf.period.hz <= 0) { |
|
1682 |
if (conf.period.hz < 0) { |
|
1683 |
dolog ("warning: Timer period is negative - %d " |
|
1684 |
"treating as zero\n", |
|
1685 |
conf.period.hz); |
|
1686 |
} |
|
1687 |
conf.period.ticks = 1; |
|
1647 | 1688 |
} |
1648 |
s->period.ticks = 1; |
|
1689 |
else { |
|
1690 |
conf.period.ticks = ticks_per_sec / conf.period.hz; |
|
1691 |
} |
|
1692 |
|
|
1693 |
qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL); |
|
1649 | 1694 |
} |
1650 | 1695 |
else { |
1651 |
s->period.ticks = (ticks_per_sec * s->period.usec) / 1000000; |
|
1696 |
qemu_del_timer (s->ts); |
|
1697 |
return NULL; |
|
1652 | 1698 |
} |
1653 | 1699 |
|
1654 |
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + s->period.ticks); |
|
1700 |
LIST_INIT (&s->card_head); |
|
1701 |
register_savevm ("audio", 0, 1, audio_save, audio_load, s); |
|
1702 |
atexit (audio_atexit); |
|
1703 |
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); |
|
1704 |
return s; |
|
1655 | 1705 |
} |
b/audio/audio.h | ||
---|---|---|
24 | 24 |
#ifndef QEMU_AUDIO_H |
25 | 25 |
#define QEMU_AUDIO_H |
26 | 26 |
|
27 |
#include "sys-queue.h" |
|
28 |
|
|
27 | 29 |
typedef void (*audio_callback_fn_t) (void *opaque, int avail); |
28 | 30 |
|
29 | 31 |
typedef enum { |
30 |
AUD_FMT_U8, |
|
31 |
AUD_FMT_S8, |
|
32 |
AUD_FMT_U16, |
|
33 |
AUD_FMT_S16 |
|
32 |
AUD_FMT_U8,
|
|
33 |
AUD_FMT_S8,
|
|
34 |
AUD_FMT_U16,
|
|
35 |
AUD_FMT_S16
|
|
34 | 36 |
} audfmt_e; |
35 | 37 |
|
38 |
typedef struct { |
|
39 |
int freq; |
|
40 |
int nchannels; |
|
41 |
audfmt_e fmt; |
|
42 |
} audsettings_t; |
|
43 |
|
|
44 |
typedef struct AudioState AudioState; |
|
36 | 45 |
typedef struct SWVoiceOut SWVoiceOut; |
37 | 46 |
typedef struct SWVoiceIn SWVoiceIn; |
38 | 47 |
|
48 |
typedef struct QEMUSoundCard { |
|
49 |
AudioState *audio; |
|
50 |
char *name; |
|
51 |
LIST_ENTRY (QEMUSoundCard) entries; |
|
52 |
} QEMUSoundCard; |
|
53 |
|
|
39 | 54 |
typedef struct QEMUAudioTimeStamp { |
40 | 55 |
uint64_t old_ts; |
41 | 56 |
} QEMUAudioTimeStamp; |
... | ... | |
47 | 62 |
#endif |
48 | 63 |
; |
49 | 64 |
|
50 |
void AUD_init (void);
|
|
65 |
AudioState *AUD_init (void);
|
|
51 | 66 |
void AUD_help (void); |
67 |
void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card); |
|
68 |
void AUD_remove_card (QEMUSoundCard *card); |
|
52 | 69 |
|
53 |
SWVoiceOut *AUD_open_out ( |
|
70 |
SWVoiceOut *AUD_open_out ( |
|
71 |
QEMUSoundCard *card, |
|
54 | 72 |
SWVoiceOut *sw, |
55 | 73 |
const char *name, |
56 | 74 |
void *callback_opaque, |
57 | 75 |
audio_callback_fn_t callback_fn, |
58 |
int freq, |
|
59 |
int nchannels, |
|
60 |
audfmt_e fmt |
|
76 |
audsettings_t *settings |
|
61 | 77 |
); |
62 |
void AUD_close_out (SWVoiceOut *sw); |
|
63 |
int AUD_write (SWVoiceOut *sw, void *pcm_buf, int size); |
|
64 |
int AUD_get_buffer_size_out (SWVoiceOut *sw); |
|
65 |
void AUD_set_active_out (SWVoiceOut *sw, int on); |
|
66 |
int AUD_is_active_out (SWVoiceOut *sw); |
|
67 |
void AUD_init_time_stamp_out (SWVoiceOut *sw, |
|
68 |
QEMUAudioTimeStamp *ts); |
|
69 |
uint64_t AUD_time_stamp_get_elapsed_usec_out (SWVoiceOut *sw, |
|
70 |
QEMUAudioTimeStamp *ts); |
|
71 |
|
|
72 |
SWVoiceIn *AUD_open_in ( |
|
78 |
|
|
79 |
void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw); |
|
80 |
int AUD_write (SWVoiceOut *sw, void *pcm_buf, int size); |
|
81 |
int AUD_get_buffer_size_out (SWVoiceOut *sw); |
|
82 |
void AUD_set_active_out (SWVoiceOut *sw, int on); |
|
83 |
int AUD_is_active_out (SWVoiceOut *sw); |
|
84 |
|
|
85 |
void AUD_init_time_stamp_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts); |
|
86 |
uint64_t AUD_get_elapsed_usec_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts); |
|
87 |
|
|
88 |
SWVoiceIn *AUD_open_in ( |
|
89 |
QEMUSoundCard *card, |
|
73 | 90 |
SWVoiceIn *sw, |
74 | 91 |
const char *name, |
75 | 92 |
void *callback_opaque, |
76 | 93 |
audio_callback_fn_t callback_fn, |
77 |
int freq, |
|
78 |
int nchannels, |
|
79 |
audfmt_e fmt |
|
94 |
audsettings_t *settings |
|
80 | 95 |
); |
81 |
void AUD_close_in (SWVoiceIn *sw); |
|
82 |
int AUD_read (SWVoiceIn *sw, void *pcm_buf, int size); |
|
83 |
void AUD_adjust_in (SWVoiceIn *sw, int leftover); |
|
84 |
void AUD_set_active_in (SWVoiceIn *sw, int on); |
|
85 |
int AUD_is_active_in (SWVoiceIn *sw); |
|
86 |
void AUD_init_time_stamp_in (SWVoiceIn *sw, |
|
87 |
QEMUAudioTimeStamp *ts); |
|
88 |
uint64_t AUD_time_stamp_get_elapsed_usec_in (SWVoiceIn *sw, |
|
89 |
QEMUAudioTimeStamp *ts); |
|
96 |
|
|
97 |
void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw); |
|
98 |
int AUD_read (SWVoiceIn *sw, void *pcm_buf, int size); |
|
99 |
void AUD_set_active_in (SWVoiceIn *sw, int on); |
|
100 |
int AUD_is_active_in (SWVoiceIn *sw); |
|
101 |
|
|
102 |
void AUD_init_time_stamp_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts); |
|
103 |
uint64_t AUD_get_elapsed_usec_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts); |
|
90 | 104 |
|
91 | 105 |
static inline void *advance (void *p, int incr) |
92 | 106 |
{ |
b/audio/audio_int.h | ||
---|---|---|
24 | 24 |
#ifndef QEMU_AUDIO_INT_H |
25 | 25 |
#define QEMU_AUDIO_INT_H |
26 | 26 |
|
27 |
#include "sys-queue.h" |
|
28 |
|
|
29 | 27 |
#ifdef CONFIG_COREAUDIO |
30 | 28 |
#define FLOAT_MIXENG |
31 | 29 |
/* #define RECIPROCAL */ |
32 | 30 |
#endif |
33 | 31 |
#include "mixeng.h" |
34 | 32 |
|
35 |
int audio_bug (const char *funcname, int cond); |
|
36 |
|
|
37 | 33 |
struct audio_pcm_ops; |
38 | 34 |
|
39 | 35 |
typedef enum { |
... | ... | |
69 | 65 |
}; |
70 | 66 |
|
71 | 67 |
typedef struct HWVoiceOut { |
72 |
int active; |
|
73 | 68 |
int enabled; |
74 | 69 |
int pending_disable; |
75 | 70 |
int valid; |
... | ... | |
78 | 73 |
f_sample *clip; |
79 | 74 |
|
80 | 75 |
int rpos; |
81 |
int bufsize; |
|
82 | 76 |
uint64_t ts_helper; |
83 | 77 |
|
84 | 78 |
st_sample_t *mix_buf; |
... | ... | |
91 | 85 |
|
92 | 86 |
typedef struct HWVoiceIn { |
93 | 87 |
int enabled; |
94 |
int active; |
|
95 | 88 |
struct audio_pcm_info info; |
96 | 89 |
|
97 | 90 |
t_sample *conv; |
98 | 91 |
|
99 | 92 |
int wpos; |
100 |
int bufsize; |
|
101 | 93 |
int total_samples_captured; |
102 | 94 |
uint64_t ts_helper; |
103 | 95 |
|
... | ... | |
109 | 101 |
LIST_ENTRY (HWVoiceIn) entries; |
110 | 102 |
} HWVoiceIn; |
111 | 103 |
|
112 |
extern struct audio_driver no_audio_driver; |
|
113 |
extern struct audio_driver oss_audio_driver; |
|
114 |
extern struct audio_driver sdl_audio_driver; |
|
115 |
extern struct audio_driver wav_audio_driver; |
|
116 |
extern struct audio_driver fmod_audio_driver; |
|
117 |
extern struct audio_driver alsa_audio_driver; |
|
118 |
extern struct audio_driver coreaudio_audio_driver; |
|
119 |
extern struct audio_driver dsound_audio_driver; |
|
120 |
extern volume_t nominal_volume; |
|
121 |
|
|
122 |
struct audio_driver { |
|
123 |
const char *name; |
|
124 |
const char *descr; |
|
125 |
struct audio_option *options; |
|
126 |
void *(*init) (void); |
|
127 |
void (*fini) (void *); |
|
128 |
struct audio_pcm_ops *pcm_ops; |
|
129 |
int can_be_default; |
|
130 |
int max_voices_out; |
|
131 |
int max_voices_in; |
|
132 |
int voice_size_out; |
|
133 |
int voice_size_in; |
|
134 |
}; |
|
135 |
|
|
136 |
typedef struct AudioState { |
|
137 |
int fixed_settings_out; |
|
138 |
int fixed_freq_out; |
|
139 |
int fixed_channels_out; |
|
140 |
int fixed_fmt_out; |
|
141 |
int nb_hw_voices_out; |
|
142 |
int greedy_out; |
|
143 |
|
|
144 |
int fixed_settings_in; |
|
145 |
int fixed_freq_in; |
|
146 |
int fixed_channels_in; |
|
147 |
int fixed_fmt_in; |
|
148 |
int nb_hw_voices_in; |
|
149 |
int greedy_in; |
|
150 |
|
|
151 |
void *opaque; |
|
152 |
struct audio_driver *drv; |
|
153 |
|
|
154 |
QEMUTimer *ts; |
|
155 |
union { |
|
156 |
int usec; |
|
157 |
int64_t ticks; |
|
158 |
} period; |
|
159 |
|
|
160 |
int plive; |
|
161 |
} AudioState; |
Also available in: Unified diff