static struct {
int samples;
- int divisor;
char *server;
char *sink;
char *source;
} conf = {
- 1024,
- 2,
- NULL,
- NULL,
- NULL
+ .samples = 4096,
};
static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
{
PAVoiceOut *pa = arg;
HWVoiceOut *hw = &pa->hw;
- int threshold;
-
- threshold = conf.divisor ? hw->samples / conf.divisor : 0;
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
return NULL;
goto exit;
}
- if (pa->live > threshold) {
+ if (pa->live > 0) {
break;
}
}
}
- decr = to_mix = pa->live;
- rpos = hw->rpos;
+ decr = to_mix = audio_MIN (pa->live, conf.samples >> 2);
+ rpos = pa->rpos;
if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
return NULL;
while (to_mix) {
int error;
int chunk = audio_MIN (to_mix, hw->samples - rpos);
- st_sample_t *src = hw->mix_buf + rpos;
+ struct st_sample *src = hw->mix_buf + rpos;
hw->clip (pa->pcm_buf, src, chunk);
return NULL;
}
-static int qpa_run_out (HWVoiceOut *hw)
+static int qpa_run_out (HWVoiceOut *hw, int live)
{
- int live, decr;
+ int decr;
PAVoiceOut *pa = (PAVoiceOut *) hw;
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
return 0;
}
- live = audio_pcm_hw_get_live_out (hw);
decr = audio_MIN (live, pa->decr);
pa->decr -= decr;
pa->live = live - decr;
{
PAVoiceIn *pa = arg;
HWVoiceIn *hw = &pa->hw;
- int threshold;
-
- threshold = conf.divisor ? hw->samples / conf.divisor : 0;
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
return NULL;
goto exit;
}
- if (pa->dead > threshold) {
+ if (pa->dead > 0) {
break;
}
}
}
- incr = to_grab = pa->dead;
- wpos = hw->wpos;
+ incr = to_grab = audio_MIN (pa->dead, conf.samples >> 2);
+ wpos = pa->wpos;
if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
return NULL;
return NULL;
}
- hw->conv (hw->conv_buf + wpos, buf, chunk, &nominal_volume);
+ hw->conv (hw->conv_buf + wpos, buf, chunk);
wpos = (wpos + chunk) % hw->samples;
to_grab -= chunk;
}
}
}
-static int qpa_init_out (HWVoiceOut *hw, audsettings_t *as)
+static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
{
int error;
static pa_sample_spec ss;
- audsettings_t obt_as = *as;
+ static pa_buffer_attr ba;
+ struct audsettings obt_as = *as;
PAVoiceOut *pa = (PAVoiceOut *) hw;
ss.format = audfmt_to_pa (as->fmt, as->endianness);
ss.channels = as->nchannels;
ss.rate = as->freq;
+ /*
+ * qemu audio tick runs at 250 Hz (by default), so processing
+ * data chunks worth 4 ms of sound should be a good fit.
+ */
+ ba.tlength = pa_usec_to_bytes (4 * 1000, &ss);
+ ba.minreq = pa_usec_to_bytes (2 * 1000, &ss);
+ ba.maxlength = -1;
+ ba.prebuf = -1;
+
obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
pa->s = pa_simple_new (
"pcm.playback",
&ss,
NULL, /* channel map */
- NULL, /* buffering attributes */
+ &ba, /* buffering attributes */
&error
);
if (!pa->s) {
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = conf.samples;
pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+ pa->rpos = hw->rpos;
if (!pa->pcm_buf) {
dolog ("Could not allocate buffer (%d bytes)\n",
hw->samples << hw->info.shift);
return 0;
fail3:
- free (pa->pcm_buf);
+ g_free (pa->pcm_buf);
pa->pcm_buf = NULL;
fail2:
pa_simple_free (pa->s);
return -1;
}
-static int qpa_init_in (HWVoiceIn *hw, audsettings_t *as)
+static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
{
int error;
static pa_sample_spec ss;
- audsettings_t obt_as = *as;
+ struct audsettings obt_as = *as;
PAVoiceIn *pa = (PAVoiceIn *) hw;
ss.format = audfmt_to_pa (as->fmt, as->endianness);
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = conf.samples;
pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+ pa->wpos = hw->wpos;
if (!pa->pcm_buf) {
dolog ("Could not allocate buffer (%d bytes)\n",
hw->samples << hw->info.shift);
return 0;
fail3:
- free (pa->pcm_buf);
+ g_free (pa->pcm_buf);
pa->pcm_buf = NULL;
fail2:
pa_simple_free (pa->s);
}
audio_pt_fini (&pa->pt, AUDIO_FUNC);
- qemu_free (pa->pcm_buf);
+ g_free (pa->pcm_buf);
pa->pcm_buf = NULL;
}
}
audio_pt_fini (&pa->pt, AUDIO_FUNC);
- qemu_free (pa->pcm_buf);
+ g_free (pa->pcm_buf);
pa->pcm_buf = NULL;
}
}
struct audio_option qpa_options[] = {
- {"SAMPLES", AUD_OPT_INT, &conf.samples,
- "buffer size in samples", NULL, 0},
-
- {"DIVISOR", AUD_OPT_INT, &conf.divisor,
- "threshold divisor", NULL, 0},
-
- {"SERVER", AUD_OPT_STR, &conf.server,
- "server address", NULL, 0},
-
- {"SINK", AUD_OPT_STR, &conf.sink,
- "sink device name", NULL, 0},
-
- {"SOURCE", AUD_OPT_STR, &conf.source,
- "source device name", NULL, 0},
-
- {NULL, 0, NULL, NULL, NULL, 0}
+ {
+ .name = "SAMPLES",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.samples,
+ .descr = "buffer size in samples"
+ },
+ {
+ .name = "SERVER",
+ .tag = AUD_OPT_STR,
+ .valp = &conf.server,
+ .descr = "server address"
+ },
+ {
+ .name = "SINK",
+ .tag = AUD_OPT_STR,
+ .valp = &conf.sink,
+ .descr = "sink device name"
+ },
+ {
+ .name = "SOURCE",
+ .tag = AUD_OPT_STR,
+ .valp = &conf.source,
+ .descr = "source device name"
+ },
+ { /* End of list */ }
};
static struct audio_pcm_ops qpa_pcm_ops = {
- qpa_init_out,
- qpa_fini_out,
- qpa_run_out,
- qpa_write,
- qpa_ctl_out,
- qpa_init_in,
- qpa_fini_in,
- qpa_run_in,
- qpa_read,
- qpa_ctl_in
+ .init_out = qpa_init_out,
+ .fini_out = qpa_fini_out,
+ .run_out = qpa_run_out,
+ .write = qpa_write,
+ .ctl_out = qpa_ctl_out,
+
+ .init_in = qpa_init_in,
+ .fini_in = qpa_fini_in,
+ .run_in = qpa_run_in,
+ .read = qpa_read,
+ .ctl_in = qpa_ctl_in
};
struct audio_driver pa_audio_driver = {
- INIT_FIELD (name = ) "pa",
- INIT_FIELD (descr = ) "http://www.pulseaudio.org/",
- INIT_FIELD (options = ) qpa_options,
- INIT_FIELD (init = ) qpa_audio_init,
- INIT_FIELD (fini = ) qpa_audio_fini,
- INIT_FIELD (pcm_ops = ) &qpa_pcm_ops,
- INIT_FIELD (can_be_default = ) 0,
- INIT_FIELD (max_voices_out = ) INT_MAX,
- INIT_FIELD (max_voices_in = ) INT_MAX,
- INIT_FIELD (voice_size_out = ) sizeof (PAVoiceOut),
- INIT_FIELD (voice_size_in = ) sizeof (PAVoiceIn)
+ .name = "pa",
+ .descr = "http://www.pulseaudio.org/",
+ .options = qpa_options,
+ .init = qpa_audio_init,
+ .fini = qpa_audio_fini,
+ .pcm_ops = &qpa_pcm_ops,
+ .can_be_default = 1,
+ .max_voices_out = INT_MAX,
+ .max_voices_in = INT_MAX,
+ .voice_size_out = sizeof (PAVoiceOut),
+ .voice_size_in = sizeof (PAVoiceIn)
};