aboutsummaryrefslogtreecommitdiff
path: root/audio/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/audio.c')
-rw-r--r--audio/audio.c348
1 files changed, 61 insertions, 287 deletions
diff --git a/audio/audio.c b/audio/audio.c
index eba4fdb121..7634535230 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -96,7 +96,7 @@ static struct {
{ 0 }, /* period */
0, /* plive */
- 0
+ 0 /* log_to_monitor */
};
static AudioState glob_audio_state;
@@ -623,25 +623,6 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
/*
* Hard voice (capture)
*/
-static void audio_pcm_hw_free_resources_in (HWVoiceIn *hw)
-{
- if (hw->conv_buf) {
- qemu_free (hw->conv_buf);
- }
- hw->conv_buf = NULL;
-}
-
-static int audio_pcm_hw_alloc_resources_in (HWVoiceIn *hw)
-{
- hw->conv_buf = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t));
- if (!hw->conv_buf) {
- dolog ("Could not allocate ADC conversion buffer (%d samples)\n",
- hw->samples);
- return -1;
- }
- return 0;
-}
-
static int audio_pcm_hw_find_min_in (HWVoiceIn *hw)
{
SWVoiceIn *sw;
@@ -668,64 +649,6 @@ int audio_pcm_hw_get_live_in (HWVoiceIn *hw)
/*
* Soft voice (capture)
*/
-static void audio_pcm_sw_free_resources_in (SWVoiceIn *sw)
-{
- if (sw->conv_buf) {
- qemu_free (sw->conv_buf);
- }
-
- if (sw->rate) {
- st_rate_stop (sw->rate);
- }
-
- sw->conv_buf = NULL;
- sw->rate = NULL;
-}
-
-static int audio_pcm_sw_alloc_resources_in (SWVoiceIn *sw)
-{
- int samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
- sw->conv_buf = audio_calloc (AUDIO_FUNC, samples, sizeof (st_sample_t));
- if (!sw->conv_buf) {
- dolog ("Could not allocate buffer for `%s' (%d samples)\n",
- SW_NAME (sw), samples);
- return -1;
- }
-
- sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
- if (!sw->rate) {
- qemu_free (sw->conv_buf);
- sw->conv_buf = NULL;
- return -1;
- }
- return 0;
-}
-
-static int audio_pcm_sw_init_in (
- SWVoiceIn *sw,
- HWVoiceIn *hw,
- const char *name,
- audsettings_t *as
- )
-{
- /* None of the cards emulated by QEMU are big-endian
- hence following shortcut */
- audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (0));
- sw->hw = hw;
- sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
-
- sw->clip =
- mixeng_clip
- [sw->info.nchannels == 2]
- [sw->info.sign]
- [sw->info.swap_endian]
- [sw->info.bits == 16];
-
- sw->name = qemu_strdup (name);
- audio_pcm_sw_free_resources_in (sw);
- return audio_pcm_sw_alloc_resources_in (sw);
-}
-
static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw)
{
HWVoiceIn *hw = sw->hw;
@@ -750,7 +673,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
{
HWVoiceIn *hw = sw->hw;
int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
- st_sample_t *src, *dst = sw->conv_buf;
+ st_sample_t *src, *dst = sw->buf;
rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
@@ -794,7 +717,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
total += isamp;
}
- sw->clip (buf, sw->conv_buf, ret);
+ sw->clip (buf, sw->buf, ret);
sw->total_hw_samples_acquired += total;
return ret << sw->info.shift;
}
@@ -802,27 +725,6 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
/*
* Hard voice (playback)
*/
-static void audio_pcm_hw_free_resources_out (HWVoiceOut *hw)
-{
- if (hw->mix_buf) {
- qemu_free (hw->mix_buf);
- }
-
- hw->mix_buf = NULL;
-}
-
-static int audio_pcm_hw_alloc_resources_out (HWVoiceOut *hw)
-{
- hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t));
- if (!hw->mix_buf) {
- dolog ("Could not allocate DAC mixing buffer (%d samples)\n",
- hw->samples);
- return -1;
- }
-
- return 0;
-}
-
static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep)
{
SWVoiceOut *sw;
@@ -876,66 +778,6 @@ int audio_pcm_hw_get_live_out (HWVoiceOut *hw)
/*
* Soft voice (playback)
*/
-static void audio_pcm_sw_free_resources_out (SWVoiceOut *sw)
-{
- if (sw->buf) {
- qemu_free (sw->buf);
- }
-
- if (sw->rate) {
- st_rate_stop (sw->rate);
- }
-
- sw->buf = NULL;
- sw->rate = NULL;
-}
-
-static int audio_pcm_sw_alloc_resources_out (SWVoiceOut *sw)
-{
- sw->buf = audio_calloc (AUDIO_FUNC, sw->hw->samples, sizeof (st_sample_t));
- if (!sw->buf) {
- dolog ("Could not allocate buffer for `%s' (%d samples)\n",
- SW_NAME (sw), sw->hw->samples);
- return -1;
- }
-
- sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
- if (!sw->rate) {
- qemu_free (sw->buf);
- sw->buf = NULL;
- return -1;
- }
- return 0;
-}
-
-static int audio_pcm_sw_init_out (
- SWVoiceOut *sw,
- HWVoiceOut *hw,
- const char *name,
- audsettings_t *as
- )
-{
- /* None of the cards emulated by QEMU are big-endian
- hence following shortcut */
- audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (0));
- sw->hw = hw;
- sw->empty = 1;
- sw->active = 0;
- sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
- sw->total_hw_samples_mixed = 0;
-
- sw->conv =
- mixeng_conv
- [sw->info.nchannels == 2]
- [sw->info.sign]
- [sw->info.swap_endian]
- [sw->info.bits == 16];
- sw->name = qemu_strdup (name);
-
- audio_pcm_sw_free_resources_out (sw);
- return audio_pcm_sw_alloc_resources_out (sw);
-}
-
int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
{
int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
@@ -1316,6 +1158,16 @@ static void audio_run_in (AudioState *s)
}
}
+static void audio_timer (void *opaque)
+{
+ AudioState *s = opaque;
+
+ audio_run_out (s);
+ audio_run_in (s);
+
+ qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
+}
+
static struct audio_option audio_options[] = {
/* DAC */
{"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_out.enabled,
@@ -1356,13 +1208,31 @@ static struct audio_option audio_options[] = {
{"PLIVE", AUD_OPT_BOOL, &conf.plive,
"(undocumented)", NULL, 0},
-
{"LOG_TO_MONITOR", AUD_OPT_BOOL, &conf.log_to_monitor,
"print logging messages to montior instead of stderr", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
+static void audio_pp_nb_voices (const char *typ, int nb)
+{
+ switch (nb) {
+ case 0:
+ printf ("Does not support %s\n", typ);
+ break;
+ case 1:
+ printf ("One %s voice\n", typ);
+ break;
+ case INT_MAX:
+ printf ("Theoretically supports many %s voices\n", typ);
+ break;
+ default:
+ printf ("Theoretically supports upto %d %s voices\n", nb, typ);
+ break;
+ }
+
+}
+
void AUD_help (void)
{
size_t i;
@@ -1387,37 +1257,8 @@ void AUD_help (void)
printf ("Name: %s\n", d->name);
printf ("Description: %s\n", d->descr);
- switch (d->max_voices_out) {
- case 0:
- printf ("Does not support DAC\n");
- break;
- case 1:
- printf ("One DAC voice\n");
- break;
- case INT_MAX:
- printf ("Theoretically supports many DAC voices\n");
- break;
- default:
- printf ("Theoretically supports upto %d DAC voices\n",
- d->max_voices_out);
- break;
- }
-
- switch (d->max_voices_in) {
- case 0:
- printf ("Does not support ADC\n");
- break;
- case 1:
- printf ("One ADC voice\n");
- break;
- case INT_MAX:
- printf ("Theoretically supports many ADC voices\n");
- break;
- default:
- printf ("Theoretically supports upto %d ADC voices\n",
- d->max_voices_in);
- break;
- }
+ audio_pp_nb_voices ("playback", d->max_voices_out);
+ audio_pp_nb_voices ("capture", d->max_voices_in);
if (d->options) {
printf ("Options:\n");
@@ -1434,7 +1275,7 @@ void AUD_help (void)
"Example:\n"
#ifdef _WIN32
" set QEMU_AUDIO_DRV=wav\n"
- " set QEMU_WAV_PATH=c:/tune.wav\n"
+ " set QEMU_WAV_PATH=c:\\tune.wav\n"
#else
" export QEMU_AUDIO_DRV=wav\n"
" export QEMU_WAV_PATH=$HOME/tune.wav\n"
@@ -1444,16 +1285,6 @@ void AUD_help (void)
);
}
-void audio_timer (void *opaque)
-{
- AudioState *s = opaque;
-
- audio_run_out (s);
- audio_run_in (s);
-
- qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
-}
-
static int audio_driver_init (AudioState *s, struct audio_driver *drv)
{
if (drv->options) {
@@ -1462,62 +1293,8 @@ static int audio_driver_init (AudioState *s, struct audio_driver *drv)
s->drv_opaque = drv->init ();
if (s->drv_opaque) {
- if (s->nb_hw_voices_out > drv->max_voices_out) {
- if (!drv->max_voices_out) {
- dolog ("`%s' does not support DAC\n", drv->name);
- }
- else {
- dolog (
- "`%s' does not support %d multiple DAC voicess\n"
- "Resetting to %d\n",
- drv->name,
- s->nb_hw_voices_out,
- drv->max_voices_out
- );
- }
- s->nb_hw_voices_out = drv->max_voices_out;
- }
-
-
- if (!drv->voice_size_in && drv->max_voices_in) {
- ldebug ("warning: No ADC voice size defined for `%s'\n",
- drv->name);
- drv->max_voices_in = 0;
- }
-
- if (!drv->voice_size_out && drv->max_voices_out) {
- ldebug ("warning: No DAC voice size defined for `%s'\n",
- drv->name);
- }
-
- if (drv->voice_size_in && !drv->max_voices_in) {
- ldebug ("warning: `%s' ADC voice size %d, zero voices \n",
- drv->name, drv->voice_size_out);
- }
-
- if (drv->voice_size_out && !drv->max_voices_out) {
- ldebug ("warning: `%s' DAC voice size %d, zero voices \n",
- drv->name, drv->voice_size_in);
- }
-
- if (s->nb_hw_voices_in > drv->max_voices_in) {
- if (!drv->max_voices_in) {
- ldebug ("`%s' does not support ADC\n", drv->name);
- }
- else {
- dolog (
- "`%s' does not support %d multiple ADC voices\n"
- "Resetting to %d\n",
- drv->name,
- s->nb_hw_voices_in,
- drv->max_voices_in
- );
- }
- s->nb_hw_voices_in = drv->max_voices_in;
- }
-
- LIST_INIT (&s->hw_head_out);
- LIST_INIT (&s->hw_head_in);
+ audio_init_nb_voices_out (s, drv);
+ audio_init_nb_voices_in (s, drv);
s->drv = drv;
return 0;
}
@@ -1549,25 +1326,13 @@ static void audio_atexit (void)
HWVoiceOut *hwo = NULL;
HWVoiceIn *hwi = NULL;
- while ((hwo = audio_pcm_hw_find_any_out (s, hwo))) {
- if (!hwo->pcm_ops) {
- continue;
- }
-
- if (hwo->enabled) {
- hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
- }
+ while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
+ hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
hwo->pcm_ops->fini_out (hwo);
}
- while ((hwi = audio_pcm_hw_find_any_in (s, hwi))) {
- if (!hwi->pcm_ops) {
- continue;
- }
-
- if (hwi->enabled) {
- hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
- }
+ while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
+ hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
hwi->pcm_ops->fini_in (hwi);
}
@@ -1616,21 +1381,31 @@ AudioState *AUD_init (void)
const char *drvname;
AudioState *s = &glob_audio_state;
+ LIST_INIT (&s->hw_head_out);
+ LIST_INIT (&s->hw_head_in);
+ atexit (audio_atexit);
+
+ s->ts = qemu_new_timer (vm_clock, audio_timer, s);
+ if (!s->ts) {
+ dolog ("Could not create audio timer\n");
+ return NULL;
+ }
+
audio_process_options ("AUDIO", audio_options);
s->nb_hw_voices_out = conf.fixed_out.nb_voices;
s->nb_hw_voices_in = conf.fixed_in.nb_voices;
if (s->nb_hw_voices_out <= 0) {
- dolog ("Bogus number of DAC voices %d\n",
+ dolog ("Bogus number of playback voices %d, setting to 1\n",
s->nb_hw_voices_out);
s->nb_hw_voices_out = 1;
}
if (s->nb_hw_voices_in <= 0) {
- dolog ("Bogus number of ADC voices %d\n",
+ dolog ("Bogus number of capture voices %d, setting to 0\n",
s->nb_hw_voices_in);
- s->nb_hw_voices_in = 1;
+ s->nb_hw_voices_in = 0;
}
{
@@ -1638,12 +1413,6 @@ AudioState *AUD_init (void)
drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def);
}
- s->ts = qemu_new_timer (vm_clock, audio_timer, s);
- if (!s->ts) {
- dolog ("Could not create audio timer\n");
- return NULL;
- }
-
if (drvname) {
int found = 0;
@@ -1680,6 +1449,8 @@ AudioState *AUD_init (void)
}
if (done) {
+ VMChangeStateEntry *e;
+
if (conf.period.hz <= 0) {
if (conf.period.hz < 0) {
dolog ("warning: Timer period is negative - %d "
@@ -1692,7 +1463,11 @@ AudioState *AUD_init (void)
conf.period.ticks = ticks_per_sec / conf.period.hz;
}
- qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
+ e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
+ if (!e) {
+ dolog ("warning: Could not register change state handler\n"
+ "(Audio can continue looping even after stopping the VM)\n");
+ }
}
else {
qemu_del_timer (s->ts);
@@ -1701,7 +1476,6 @@ AudioState *AUD_init (void)
LIST_INIT (&s->card_head);
register_savevm ("audio", 0, 1, audio_save, audio_load, s);
- atexit (audio_atexit);
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
return s;
}