aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-09-24 13:51:51 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-09-24 13:51:51 +0100
commit860d9048c78ce59c5903c3d5209df56f38400986 (patch)
treebf8e0e0b752cdeee65e762c6a7d1800813b5310b
parent8dc57281b80f1de11a7c114a0acb6f192b3e1a9a (diff)
parent571a8c522e0095239598347ac0add93337c1e0bf (diff)
Merge remote-tracking branch 'remotes/kraxel/tags/audio-20190924-pull-request' into staging
audio: documentation fixes. audio: new backend api (first part of the surround sound patch series). # gpg: Signature made Tue 24 Sep 2019 07:19:31 BST # gpg: using RSA key 4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full] # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full] # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full] # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/audio-20190924-pull-request: audio: split ctl_* functions into enable_* and volume_* audio: common rate control code for timer based outputs audio: unify input and output mixeng buffer management audio: remove remains of the old backend api wavaudio: port to the new audio backend api spiceaudio: port to the new audio backend api sdlaudio: port to the new audio backend api paaudio: port to the new audio backend api ossaudio: port to the new audio backend api noaudio: port to the new audio backend api dsoundaudio: port to the new audio backend api coreaudio: port to the new audio backend api alsaaudio: port to the new audio backend api audio: api for mixeng code free backends audio: fix ALSA period-length typo in documentation audio: fix buffer-length typo in documentation Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--audio/Makefile.objs1
-rw-r--r--audio/alsaaudio.c364
-rw-r--r--audio/audio.c383
-rw-r--r--audio/audio_int.h78
-rw-r--r--audio/audio_pt_int.c173
-rw-r--r--audio/audio_pt_int.h22
-rw-r--r--audio/audio_template.h21
-rw-r--r--audio/coreaudio.c143
-rw-r--r--audio/dsound_template.h47
-rw-r--r--audio/dsoundaudio.c355
-rw-r--r--audio/noaudio.c78
-rw-r--r--audio/ossaudio.c348
-rw-r--r--audio/paaudio.c511
-rw-r--r--audio/sdlaudio.c104
-rw-r--r--audio/spiceaudio.c253
-rw-r--r--audio/wavaudio.c76
-rwxr-xr-xconfigure5
-rw-r--r--qemu-options.hx8
18 files changed, 1066 insertions, 1904 deletions
diff --git a/audio/Makefile.objs b/audio/Makefile.objs
index dca87f6347..d7490a379f 100644
--- a/audio/Makefile.objs
+++ b/audio/Makefile.objs
@@ -2,7 +2,6 @@ common-obj-y = audio.o audio_legacy.o noaudio.o wavaudio.o mixeng.o
common-obj-$(CONFIG_SPICE) += spiceaudio.o
common-obj-$(CONFIG_AUDIO_COREAUDIO) += coreaudio.o
common-obj-$(CONFIG_AUDIO_DSOUND) += dsoundaudio.o
-common-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o
common-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
common-obj-y += wavcapture.o
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 591344dccd..cfe42284a6 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -44,9 +44,6 @@ struct pollhlp {
typedef struct ALSAVoiceOut {
HWVoiceOut hw;
- int wpos;
- int pending;
- void *pcm_buf;
snd_pcm_t *handle;
struct pollhlp pollhlp;
Audiodev *dev;
@@ -55,7 +52,6 @@ typedef struct ALSAVoiceOut {
typedef struct ALSAVoiceIn {
HWVoiceIn hw;
snd_pcm_t *handle;
- void *pcm_buf;
struct pollhlp pollhlp;
Audiodev *dev;
} ALSAVoiceIn;
@@ -602,102 +598,64 @@ static int alsa_open(bool in, struct alsa_params_req *req,
return -1;
}
-static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
+static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len)
{
- snd_pcm_sframes_t avail;
-
- avail = snd_pcm_avail_update (handle);
- if (avail < 0) {
- if (avail == -EPIPE) {
- if (!alsa_recover (handle)) {
- avail = snd_pcm_avail_update (handle);
- }
- }
-
- if (avail < 0) {
- alsa_logerr (avail,
- "Could not obtain number of available frames\n");
- return -1;
- }
- }
+ ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+ size_t pos = 0;
+ size_t len_frames = len >> hw->info.shift;
+
+ while (len_frames) {
+ char *src = advance(buf, pos);
+ snd_pcm_sframes_t written;
+
+ written = snd_pcm_writei(alsa->handle, src, len_frames);
+
+ if (written <= 0) {
+ switch (written) {
+ case 0:
+ trace_alsa_wrote_zero(len_frames);
+ return pos;
+
+ case -EPIPE:
+ if (alsa_recover(alsa->handle)) {
+ alsa_logerr(written, "Failed to write %zu frames\n",
+ len_frames);
+ return pos;
+ }
+ trace_alsa_xrun_out();
+ continue;
+
+ case -ESTRPIPE:
+ /*
+ * stream is suspended and waiting for an application
+ * recovery
+ */
+ if (alsa_resume(alsa->handle)) {
+ alsa_logerr(written, "Failed to write %zu frames\n",
+ len_frames);
+ return pos;
+ }
+ trace_alsa_resume_out();
+ continue;
- return avail;
-}
+ case -EAGAIN:
+ return pos;
-static void alsa_write_pending (ALSAVoiceOut *alsa)
-{
- HWVoiceOut *hw = &alsa->hw;
-
- while (alsa->pending) {
- int left_till_end_samples = hw->samples - alsa->wpos;
- int len = MIN (alsa->pending, left_till_end_samples);
- char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
-
- while (len) {
- snd_pcm_sframes_t written;
-
- written = snd_pcm_writei (alsa->handle, src, len);
-
- if (written <= 0) {
- switch (written) {
- case 0:
- trace_alsa_wrote_zero(len);
- return;
-
- case -EPIPE:
- if (alsa_recover (alsa->handle)) {
- alsa_logerr (written, "Failed to write %d frames\n",
- len);
- return;
- }
- trace_alsa_xrun_out();
- continue;
-
- case -ESTRPIPE:
- /* stream is suspended and waiting for an
- application recovery */
- if (alsa_resume (alsa->handle)) {
- alsa_logerr (written, "Failed to write %d frames\n",
- len);
- return;
- }
- trace_alsa_resume_out();
- continue;
-
- case -EAGAIN:
- return;
-
- default:
- alsa_logerr (written, "Failed to write %d frames from %p\n",
- len, src);
- return;
- }
+ default:
+ alsa_logerr(written, "Failed to write %zu frames from %p\n",
+ len, src);
+ return pos;
}
-
- alsa->wpos = (alsa->wpos + written) % hw->samples;
- alsa->pending -= written;
- len -= written;
}
- }
-}
-
-static size_t alsa_run_out(HWVoiceOut *hw, size_t live)
-{
- ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
- size_t decr;
- snd_pcm_sframes_t avail;
- avail = alsa_get_avail (alsa->handle);
- if (avail < 0) {
- dolog ("Could not get number of available playback frames\n");
- return 0;
+ pos += written << hw->info.shift;
+ if (written < len_frames) {
+ break;
+ }
+ len_frames -= written;
}
- decr = MIN (live, avail);
- decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
- alsa->pending += decr;
- alsa_write_pending (alsa);
- return decr;
+ return pos;
}
static void alsa_fini_out (HWVoiceOut *hw)
@@ -706,9 +664,6 @@ static void alsa_fini_out (HWVoiceOut *hw)
ldebug ("alsa_fini\n");
alsa_anal_close (&alsa->handle, &alsa->pollhlp);
-
- g_free(alsa->pcm_buf);
- alsa->pcm_buf = NULL;
}
static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
@@ -737,14 +692,6 @@ static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
- alsa->pcm_buf = audio_calloc(__func__, obt.samples, 1 << hw->info.shift);
- if (!alsa->pcm_buf) {
- dolog("Could not allocate DAC buffer (%zu samples, each %d bytes)\n",
- hw->samples, 1 << hw->info.shift);
- alsa_anal_close1 (&handle);
- return -1;
- }
-
alsa->pollhlp.s = hw->s;
alsa->handle = handle;
alsa->dev = dev;
@@ -784,34 +731,28 @@ static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
return 0;
}
-static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
+static void alsa_enable_out(HWVoiceOut *hw, bool enable)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.out;
- switch (cmd) {
- case VOICE_ENABLE:
- {
- bool poll_mode = apdo->try_poll;
+ if (enable) {
+ bool poll_mode = apdo->try_poll;
- ldebug ("enabling voice\n");
- if (poll_mode && alsa_poll_out (hw)) {
- poll_mode = 0;
- }
- hw->poll_mode = poll_mode;
- return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PREPARE);
+ ldebug("enabling voice\n");
+ if (poll_mode && alsa_poll_out(hw)) {
+ poll_mode = 0;
}
-
- case VOICE_DISABLE:
- ldebug ("disabling voice\n");
+ hw->poll_mode = poll_mode;
+ alsa_voice_ctl(alsa->handle, "playback", VOICE_CTL_PREPARE);
+ } else {
+ ldebug("disabling voice\n");
if (hw->poll_mode) {
hw->poll_mode = 0;
- alsa_fini_poll (&alsa->pollhlp);
+ alsa_fini_poll(&alsa->pollhlp);
}
- return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PAUSE);
+ alsa_voice_ctl(alsa->handle, "playback", VOICE_CTL_PAUSE);
}
-
- return -1;
}
static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
@@ -839,14 +780,6 @@ static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
- alsa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
- if (!alsa->pcm_buf) {
- dolog("Could not allocate ADC buffer (%zu samples, each %d bytes)\n",
- hw->samples, 1 << hw->info.shift);
- alsa_anal_close1 (&handle);
- return -1;
- }
-
alsa->pollhlp.s = hw->s;
alsa->handle = handle;
alsa->dev = dev;
@@ -858,160 +791,73 @@ static void alsa_fini_in (HWVoiceIn *hw)
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
alsa_anal_close (&alsa->handle, &alsa->pollhlp);
-
- g_free(alsa->pcm_buf);
- alsa->pcm_buf = NULL;
}
-static size_t alsa_run_in(HWVoiceIn *hw)
+static size_t alsa_read(HWVoiceIn *hw, void *buf, size_t len)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
- int hwshift = hw->info.shift;
- int i;
- size_t live = audio_pcm_hw_get_live_in (hw);
- size_t dead = hw->samples - live;
- size_t decr;
- struct {
- size_t add;
- size_t len;
- } bufs[2] = {
- { .add = hw->wpos, .len = 0 },
- { .add = 0, .len = 0 }
- };
- snd_pcm_sframes_t avail;
- snd_pcm_uframes_t read_samples = 0;
-
- if (!dead) {
- return 0;
- }
+ size_t pos = 0;
- avail = alsa_get_avail (alsa->handle);
- if (avail < 0) {
- dolog ("Could not get number of captured frames\n");
- return 0;
- }
-
- if (!avail) {
- snd_pcm_state_t state;
-
- state = snd_pcm_state (alsa->handle);
- switch (state) {
- case SND_PCM_STATE_PREPARED:
- avail = hw->samples;
- break;
- case SND_PCM_STATE_SUSPENDED:
- /* stream is suspended and waiting for an application recovery */
- if (alsa_resume (alsa->handle)) {
- dolog ("Failed to resume suspended input stream\n");
- return 0;
- }
- trace_alsa_resume_in();
- break;
- default:
- trace_alsa_no_frames(state);
- return 0;
- }
- }
+ while (len) {
+ void *dst = advance(buf, pos);
+ snd_pcm_sframes_t nread;
- decr = MIN(dead, avail);
- if (!decr) {
- return 0;
- }
+ nread = snd_pcm_readi(alsa->handle, dst, len >> hw->info.shift);
- if (hw->wpos + decr > hw->samples) {
- bufs[0].len = (hw->samples - hw->wpos);
- bufs[1].len = (decr - (hw->samples - hw->wpos));
- }
- else {
- bufs[0].len = decr;
- }
+ if (nread <= 0) {
+ switch (nread) {
+ case 0:
+ trace_alsa_read_zero(len);
+ return pos;;
- for (i = 0; i < 2; ++i) {
- void *src;
- struct st_sample *dst;
- snd_pcm_sframes_t nread;
- snd_pcm_uframes_t len;
-
- len = bufs[i].len;
-
- src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
- dst = hw->conv_buf + bufs[i].add;
-
- while (len) {
- nread = snd_pcm_readi (alsa->handle, src, len);
-
- if (nread <= 0) {
- switch (nread) {
- case 0:
- trace_alsa_read_zero(len);
- goto exit;
-
- case -EPIPE:
- if (alsa_recover (alsa->handle)) {
- alsa_logerr (nread, "Failed to read %ld frames\n", len);
- goto exit;
- }
- trace_alsa_xrun_in();
- continue;
-
- case -EAGAIN:
- goto exit;
-
- default:
- alsa_logerr (
- nread,
- "Failed to read %ld frames from %p\n",
- len,
- src
- );
- goto exit;
+ case -EPIPE:
+ if (alsa_recover(alsa->handle)) {
+ alsa_logerr(nread, "Failed to read %zu frames\n", len);
+ return pos;
}
- }
+ trace_alsa_xrun_in();
+ continue;
- hw->conv (dst, src, nread);
+ case -EAGAIN:
+ return pos;
- src = advance (src, nread << hwshift);
- dst += nread;
-
- read_samples += nread;
- len -= nread;
+ default:
+ alsa_logerr(nread, "Failed to read %zu frames to %p\n",
+ len, dst);
+ return pos;;
+ }
}
+
+ pos += nread << hw->info.shift;
+ len -= nread << hw->info.shift;
}
- exit:
- hw->wpos = (hw->wpos + read_samples) % hw->samples;
- return read_samples;
+ return pos;
}
-static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
+static void alsa_enable_in(HWVoiceIn *hw, bool enable)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.in;
- switch (cmd) {
- case VOICE_ENABLE:
- {
- bool poll_mode = apdo->try_poll;
+ if (enable) {
+ bool poll_mode = apdo->try_poll;
- ldebug ("enabling voice\n");
- if (poll_mode && alsa_poll_in (hw)) {
- poll_mode = 0;
- }
- hw->poll_mode = poll_mode;
-
- return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_START);
+ ldebug("enabling voice\n");
+ if (poll_mode && alsa_poll_in(hw)) {
+ poll_mode = 0;
}
+ hw->poll_mode = poll_mode;
- case VOICE_DISABLE:
+ alsa_voice_ctl(alsa->handle, "capture", VOICE_CTL_START);
+ } else {
ldebug ("disabling voice\n");
if (hw->poll_mode) {
hw->poll_mode = 0;
- alsa_fini_poll (&alsa->pollhlp);
+ alsa_fini_poll(&alsa->pollhlp);
}
- return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_PAUSE);
+ alsa_voice_ctl(alsa->handle, "capture", VOICE_CTL_PAUSE);
}
-
- return -1;
}
static void alsa_init_per_direction(AudiodevAlsaPerDirectionOptions *apdo)
@@ -1065,13 +911,13 @@ static void alsa_audio_fini (void *opaque)
static struct audio_pcm_ops alsa_pcm_ops = {
.init_out = alsa_init_out,
.fini_out = alsa_fini_out,
- .run_out = alsa_run_out,
- .ctl_out = alsa_ctl_out,
+ .write = alsa_write,
+ .enable_out = alsa_enable_out,
.init_in = alsa_init_in,
.fini_in = alsa_fini_in,
- .run_in = alsa_run_in,
- .ctl_in = alsa_ctl_in,
+ .read = alsa_read,
+ .enable_in = alsa_enable_in,
};
static struct audio_driver alsa_audio_driver = {
diff --git a/audio/audio.c b/audio/audio.c
index e99fcd0694..7128ee98dc 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -541,36 +541,33 @@ static size_t audio_pcm_hw_find_min_in (HWVoiceIn *hw)
return m;
}
-size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
+static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
{
size_t live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
- if (audio_bug(__func__, live > hw->samples)) {
- dolog("live=%zu hw->samples=%zu\n", live, hw->samples);
+ if (audio_bug(__func__, live > hw->conv_buf->size)) {
+ dolog("live=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
return 0;
}
return live;
}
-size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf,
- size_t live, size_t pending)
+static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
{
- size_t left = hw->samples - pending;
- size_t len = MIN (left, live);
size_t clipped = 0;
+ size_t pos = hw->mix_buf->pos;
while (len) {
- struct st_sample *src = hw->mix_buf + hw->rpos;
- uint8_t *dst = advance (pcm_buf, hw->rpos << hw->info.shift);
- size_t samples_till_end_of_buf = hw->samples - hw->rpos;
- size_t samples_to_clip = MIN (len, samples_till_end_of_buf);
+ st_sample *src = hw->mix_buf->samples + pos;
+ uint8_t *dst = advance(pcm_buf, clipped << hw->info.shift);
+ size_t samples_till_end_of_buf = hw->mix_buf->size - pos;
+ size_t samples_to_clip = MIN(len, samples_till_end_of_buf);
- hw->clip (dst, src, samples_to_clip);
+ hw->clip(dst, src, samples_to_clip);
- hw->rpos = (hw->rpos + samples_to_clip) % hw->samples;
+ pos = (pos + samples_to_clip) % hw->mix_buf->size;
len -= samples_to_clip;
clipped += samples_to_clip;
}
- return clipped;
}
/*
@@ -582,17 +579,17 @@ static size_t audio_pcm_sw_get_rpos_in(SWVoiceIn *sw)
ssize_t live = hw->total_samples_captured - sw->total_hw_samples_acquired;
ssize_t rpos;
- if (audio_bug(__func__, live < 0 || live > hw->samples)) {
- dolog("live=%zu hw->samples=%zu\n", live, hw->samples);
+ if (audio_bug(__func__, live < 0 || live > hw->conv_buf->size)) {
+ dolog("live=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
return 0;
}
- rpos = hw->wpos - live;
+ rpos = hw->conv_buf->pos - live;
if (rpos >= 0) {
return rpos;
}
else {
- return hw->samples + rpos;
+ return hw->conv_buf->size + rpos;
}
}
@@ -602,11 +599,11 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
size_t samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
struct st_sample *src, *dst = sw->buf;
- rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
+ rpos = audio_pcm_sw_get_rpos_in(sw) % hw->conv_buf->size;
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
- if (audio_bug(__func__, live > hw->samples)) {
- dolog("live_in=%zu hw->samples=%zu\n", live, hw->samples);
+ if (audio_bug(__func__, live > hw->conv_buf->size)) {
+ dolog("live_in=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
return 0;
}
@@ -619,11 +616,11 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
swlim = MIN (swlim, samples);
while (swlim) {
- src = hw->conv_buf + rpos;
- if (hw->wpos > rpos) {
- isamp = hw->wpos - rpos;
+ src = hw->conv_buf->samples + rpos;
+ if (hw->conv_buf->pos > rpos) {
+ isamp = hw->conv_buf->pos - rpos;
} else {
- isamp = hw->samples - rpos;
+ isamp = hw->conv_buf->size - rpos;
}
if (!isamp) {
@@ -633,13 +630,13 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
swlim -= osamp;
- rpos = (rpos + isamp) % hw->samples;
+ rpos = (rpos + isamp) % hw->conv_buf->size;
dst += osamp;
ret += osamp;
total += isamp;
}
- if (!(hw->ctl_caps & VOICE_VOLUME_CAP)) {
+ if (!hw->pcm_ops->volume_in) {
mixeng_volume (sw->buf, ret, &sw->vol);
}
@@ -681,8 +678,8 @@ static size_t audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
if (nb_live1) {
size_t live = smin;
- if (audio_bug(__func__, live > hw->samples)) {
- dolog("live=%zu hw->samples=%zu\n", live, hw->samples);
+ if (audio_bug(__func__, live > hw->mix_buf->size)) {
+ dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size);
return 0;
}
return live;
@@ -702,11 +699,11 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
return size;
}
- hwsamples = sw->hw->samples;
+ hwsamples = sw->hw->mix_buf->size;
live = sw->total_hw_samples_mixed;
if (audio_bug(__func__, live > hwsamples)) {
- dolog("live=%zu hw->samples=%zu\n", live, hwsamples);
+ dolog("live=%zu hw->mix_buf->size=%zu\n", live, hwsamples);
return 0;
}
@@ -717,7 +714,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
return 0;
}
- wpos = (sw->hw->rpos + live) % hwsamples;
+ wpos = (sw->hw->mix_buf->pos + live) % hwsamples;
samples = size >> sw->info.shift;
dead = hwsamples - live;
@@ -726,7 +723,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
if (swlim) {
sw->conv (sw->buf, buf, swlim);
- if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) {
+ if (!sw->hw->pcm_ops->volume_out) {
mixeng_volume (sw->buf, swlim, &sw->vol);
}
}
@@ -743,7 +740,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
st_rate_flow_mix (
sw->rate,
sw->buf + pos,
- sw->hw->mix_buf + wpos,
+ sw->hw->mix_buf->samples + wpos,
&isamp,
&osamp
);
@@ -871,7 +868,7 @@ size_t AUD_read(SWVoiceIn *sw, void *buf, size_t size)
int AUD_get_buffer_size_out (SWVoiceOut *sw)
{
- return sw->hw->samples << sw->hw->info.shift;
+ return sw->hw->mix_buf->size << sw->hw->info.shift;
}
void AUD_set_active_out (SWVoiceOut *sw, int on)
@@ -893,7 +890,9 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
if (!hw->enabled) {
hw->enabled = 1;
if (s->vm_running) {
- hw->pcm_ops->ctl_out(hw, VOICE_ENABLE);
+ if (hw->pcm_ops->enable_out) {
+ hw->pcm_ops->enable_out(hw, true);
+ }
audio_reset_timer (s);
}
}
@@ -938,7 +937,9 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
if (!hw->enabled) {
hw->enabled = 1;
if (s->vm_running) {
- hw->pcm_ops->ctl_in(hw, VOICE_ENABLE);
+ if (hw->pcm_ops->enable_in) {
+ hw->pcm_ops->enable_in(hw, true);
+ }
audio_reset_timer (s);
}
}
@@ -955,7 +956,9 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
if (nb_active == 1) {
hw->enabled = 0;
- hw->pcm_ops->ctl_in (hw, VOICE_DISABLE);
+ if (hw->pcm_ops->enable_in) {
+ hw->pcm_ops->enable_in(hw, false);
+ }
}
}
}
@@ -972,8 +975,9 @@ static size_t audio_get_avail (SWVoiceIn *sw)
}
live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
- if (audio_bug(__func__, live > sw->hw->samples)) {
- dolog("live=%zu sw->hw->samples=%zu\n", live, sw->hw->samples);
+ if (audio_bug(__func__, live > sw->hw->conv_buf->size)) {
+ dolog("live=%zu sw->hw->conv_buf->size=%zu\n", live,
+ sw->hw->conv_buf->size);
return 0;
}
@@ -996,12 +1000,13 @@ static size_t audio_get_free(SWVoiceOut *sw)
live = sw->total_hw_samples_mixed;
- if (audio_bug(__func__, live > sw->hw->samples)) {
- dolog("live=%zu sw->hw->samples=%zu\n", live, sw->hw->samples);
+ if (audio_bug(__func__, live > sw->hw->mix_buf->size)) {
+ dolog("live=%zu sw->hw->mix_buf->size=%zu\n", live,
+ sw->hw->mix_buf->size);
return 0;
}
- dead = sw->hw->samples - live;
+ dead = sw->hw->mix_buf->size - live;
#ifdef DEBUG_OUT
dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n",
@@ -1026,12 +1031,12 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
n = samples;
while (n) {
- size_t till_end_of_hw = hw->samples - rpos2;
+ size_t till_end_of_hw = hw->mix_buf->size - rpos2;
size_t to_write = MIN(till_end_of_hw, n);
size_t bytes = to_write << hw->info.shift;
size_t written;
- sw->buf = hw->mix_buf + rpos2;
+ sw->buf = hw->mix_buf->samples + rpos2;
written = audio_pcm_sw_write (sw, NULL, bytes);
if (written - bytes) {
dolog("Could not mix %zu bytes into a capture "
@@ -1040,14 +1045,44 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
break;
}
n -= to_write;
- rpos2 = (rpos2 + to_write) % hw->samples;
+ rpos2 = (rpos2 + to_write) % hw->mix_buf->size;
}
}
}
- n = MIN(samples, hw->samples - rpos);
- mixeng_clear(hw->mix_buf + rpos, n);
- mixeng_clear(hw->mix_buf, samples - n);
+ n = MIN(samples, hw->mix_buf->size - rpos);
+ mixeng_clear(hw->mix_buf->samples + rpos, n);
+ mixeng_clear(hw->mix_buf->samples, samples - n);
+}
+
+static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
+{
+ size_t clipped = 0;
+
+ while (live) {
+ size_t size, decr, proc;
+ void *buf = hw->pcm_ops->get_buffer_out(hw, &size);
+ if (!buf) {
+ /* retrying will likely won't help, drop everything. */
+ hw->mix_buf->pos = (hw->mix_buf->pos + live) % hw->mix_buf->size;
+ return clipped + live;
+ }
+
+ decr = MIN(size >> hw->info.shift, live);
+ audio_pcm_hw_clip_out(hw, buf, decr);
+ proc = hw->pcm_ops->put_buffer_out(hw, buf, decr << hw->info.shift) >>
+ hw->info.shift;
+
+ live -= proc;
+ clipped += proc;
+ hw->mix_buf->pos = (hw->mix_buf->pos + proc) % hw->mix_buf->size;
+
+ if (proc == 0 || proc < decr) {
+ break;
+ }
+ }
+
+ return clipped;
}
static void audio_run_out (AudioState *s)
@@ -1064,8 +1099,8 @@ static void audio_run_out (AudioState *s)
live = 0;
}
- if (audio_bug(__func__, live > hw->samples)) {
- dolog ("live=%zu hw->samples=%zu\n", live, hw->samples);
+ if (audio_bug(__func__, live > hw->mix_buf->size)) {
+ dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size);
continue;
}
@@ -1076,7 +1111,9 @@ static void audio_run_out (AudioState *s)
#endif
hw->enabled = 0;
hw->pending_disable = 0;
- hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
+ if (hw->pcm_ops->enable_out) {
+ hw->pcm_ops->enable_out(hw, false);
+ }
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
sc->sw.active = 0;
audio_recalc_and_notify_capture (sc->cap);
@@ -1096,13 +1133,13 @@ static void audio_run_out (AudioState *s)
continue;
}
- prev_rpos = hw->rpos;
- played = hw->pcm_ops->run_out (hw, live);
+ prev_rpos = hw->mix_buf->pos;
+ played = audio_pcm_hw_run_out(hw, live);
replay_audio_out(&played);
- if (audio_bug(__func__, hw->rpos >= hw->samples)) {
- dolog("hw->rpos=%zu hw->samples=%zu played=%zu\n",
- hw->rpos, hw->samples, played);
- hw->rpos = 0;
+ if (audio_bug(__func__, hw->mix_buf->pos >= hw->mix_buf->size)) {
+ dolog("hw->mix_buf->pos=%zu hw->mix_buf->size=%zu played=%zu\n",
+ hw->mix_buf->pos, hw->mix_buf->size, played);
+ hw->mix_buf->pos = 0;
}
#ifdef DEBUG_OUT
@@ -1156,6 +1193,36 @@ static void audio_run_out (AudioState *s)
}
}
+static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)
+{
+ size_t conv = 0;
+ STSampleBuffer *conv_buf = hw->conv_buf;
+
+ while (samples) {
+ size_t proc;
+ size_t size = samples << hw->info.shift;
+ void *buf = hw->pcm_ops->get_buffer_in(hw, &size);
+
+ assert((size & hw->info.align) == 0);
+ if (size == 0) {
+ hw->pcm_ops->put_buffer_in(hw, buf, size);
+ break;
+ }
+
+ proc = MIN(size >> hw->info.shift,
+ conv_buf->size - conv_buf->pos);
+
+ hw->conv(conv_buf->samples + conv_buf->pos, buf, proc);
+ conv_buf->pos = (conv_buf->pos + proc) % conv_buf->size;
+
+ samples -= proc;
+ conv += proc;
+ hw->pcm_ops->put_buffer_in(hw, buf, proc << hw->info.shift);
+ }
+
+ return conv;
+}
+
static void audio_run_in (AudioState *s)
{
HWVoiceIn *hw = NULL;
@@ -1165,9 +1232,11 @@ static void audio_run_in (AudioState *s)
size_t captured = 0, min;
if (replay_mode != REPLAY_MODE_PLAY) {
- captured = hw->pcm_ops->run_in(hw);
+ captured = audio_pcm_hw_run_in(
+ hw, hw->conv_buf->size - audio_pcm_hw_get_live_in(hw));
}
- replay_audio_in(&captured, hw->conv_buf, &hw->wpos, hw->samples);
+ replay_audio_in(&captured, hw->conv_buf->samples, &hw->conv_buf->pos,
+ hw->conv_buf->size);
min = audio_pcm_hw_find_min_in (hw);
hw->total_samples_captured += captured - min;
@@ -1198,14 +1267,14 @@ static void audio_run_capture (AudioState *s)
SWVoiceOut *sw;
captured = live = audio_pcm_hw_get_live_out (hw, NULL);
- rpos = hw->rpos;
+ rpos = hw->mix_buf->pos;
while (live) {
- size_t left = hw->samples - rpos;
+ size_t left = hw->mix_buf->size - rpos;
size_t to_capture = MIN(live, left);
struct st_sample *src;
struct capture_callback *cb;
- src = hw->mix_buf + rpos;
+ src = hw->mix_buf->samples + rpos;
hw->clip (cap->buf, src, to_capture);
mixeng_clear (src, to_capture);
@@ -1213,10 +1282,10 @@ static void audio_run_capture (AudioState *s)
cb->ops.capture (cb->opaque, cap->buf,
to_capture << hw->info.shift);
}
- rpos = (rpos + to_capture) % hw->samples;
+ rpos = (rpos + to_capture) % hw->mix_buf->size;
live -= to_capture;
}
- hw->rpos = rpos;
+ hw->mix_buf->pos = rpos;
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
if (!sw->active && sw->empty) {
@@ -1259,12 +1328,137 @@ void audio_run(AudioState *s, const char *msg)
#endif
}
+void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
+{
+ ssize_t start;
+
+ if (unlikely(!hw->buf_emul)) {
+ size_t calc_size = hw->conv_buf->size << hw->info.shift;
+ hw->buf_emul = g_malloc(calc_size);
+ hw->size_emul = calc_size;
+ hw->pos_emul = hw->pending_emul = 0;
+ }
+
+ while (hw->pending_emul < hw->size_emul) {
+ size_t read_len = MIN(hw->size_emul - hw->pos_emul,
+ hw->size_emul - hw->pending_emul);
+ size_t read = hw->pcm_ops->read(hw, hw->buf_emul + hw->pos_emul,
+ read_len);
+ hw->pending_emul += read;
+ if (read < read_len) {
+ break;
+ }
+ }
+
+ start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
+ if (start < 0) {
+ start += hw->size_emul;
+ }
+ assert(start >= 0 && start < hw->size_emul);
+
+ *size = MIN(hw->pending_emul, hw->size_emul - start);
+ return hw->buf_emul + start;
+}
+
+void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
+{
+ assert(size <= hw->pending_emul);
+ hw->pending_emul -= size;
+}
+
+void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
+{
+ if (unlikely(!hw->buf_emul)) {
+ size_t calc_size = hw->mix_buf->size << hw->info.shift;
+
+ hw->buf_emul = g_malloc(calc_size);
+ hw->size_emul = calc_size;
+ hw->pos_emul = hw->pending_emul = 0;
+ }
+
+ *size = MIN(hw->size_emul - hw->pending_emul,
+ hw->size_emul - hw->pos_emul);
+ return hw->buf_emul + hw->pos_emul;
+}
+
+size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
+ size_t size)
+{
+ assert(buf == hw->buf_emul + hw->pos_emul &&
+ size + hw->pending_emul <= hw->size_emul);
+
+ hw->pending_emul += size;
+ hw->pos_emul = (hw->pos_emul + size) % hw->size_emul;
+
+ return size;
+}
+
+size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
+{
+ audio_generic_put_buffer_out_nowrite(hw, buf, size);
+
+ while (hw->pending_emul) {
+ size_t write_len, written;
+ ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
+ if (start < 0) {
+ start += hw->size_emul;
+ }
+ assert(start >= 0 && start < hw->size_emul);
+
+ write_len = MIN(hw->pending_emul, hw->size_emul - start);
+
+ written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len);
+ hw->pending_emul -= written;
+
+ if (written < write_len) {
+ break;
+ }
+ }
+
+ /*
+ * fake we have written everything. non-written data remain in pending_emul,
+ * so we do not have to clip them multiple times
+ */
+ return size;
+}
+
+size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
+{
+ size_t dst_size, copy_size;
+ void *dst = hw->pcm_ops->get_buffer_out(hw, &dst_size);
+ copy_size = MIN(size, dst_size);
+
+ memcpy(dst, buf, copy_size);
+ return hw->pcm_ops->put_buffer_out(hw, buf, copy_size);
+}
+
+size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
+{
+ size_t dst_size, copy_size;
+ void *dst = hw->pcm_ops->get_buffer_in(hw, &dst_size);
+ copy_size = MIN(size, dst_size);
+
+ memcpy(dst, buf, copy_size);
+ hw->pcm_ops->put_buffer_in(hw, buf, copy_size);
+ return copy_size;
+}
+
+
static int audio_driver_init(AudioState *s, struct audio_driver *drv,
bool msg, Audiodev *dev)
{
s->drv_opaque = drv->init(dev);
if (s->drv_opaque) {
+ if (!drv->pcm_ops->get_buffer_in) {
+ drv->pcm_ops->get_buffer_in = audio_generic_get_buffer_in;
+ drv->pcm_ops->put_buffer_in = audio_generic_put_buffer_in;
+ }
+ if (!drv->pcm_ops->get_buffer_out) {
+ drv->pcm_ops->get_buffer_out = audio_generic_get_buffer_out;
+ drv->pcm_ops->put_buffer_out = audio_generic_put_buffer_out;
+ }
+
audio_init_nb_voices_out(s, drv);
audio_init_nb_voices_in(s, drv);
s->drv = drv;
@@ -1284,15 +1478,18 @@ static void audio_vm_change_state_handler (void *opaque, int running,
AudioState *s = opaque;
HWVoiceOut *hwo = NULL;
HWVoiceIn *hwi = NULL;
- int op = running ? VOICE_ENABLE : VOICE_DISABLE;
s->vm_running = running;
while ((hwo = audio_pcm_hw_find_any_enabled_out(s, hwo))) {
- hwo->pcm_ops->ctl_out(hwo, op);
+ if (hwo->pcm_ops->enable_out) {
+ hwo->pcm_ops->enable_out(hwo, running);
+ }
}
while ((hwi = audio_pcm_hw_find_any_enabled_in(s, hwi))) {
- hwi->pcm_ops->ctl_in(hwi, op);
+ if (hwi->pcm_ops->enable_in) {
+ hwi->pcm_ops->enable_in(hwi, running);
+ }
}
audio_reset_timer (s);
}
@@ -1312,8 +1509,8 @@ static void free_audio_state(AudioState *s)
QLIST_FOREACH_SAFE(hwo, &s->hw_head_out, entries, hwon) {
SWVoiceCap *sc;
- if (hwo->enabled) {
- hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
+ if (hwo->enabled && hwo->pcm_ops->enable_out) {
+ hwo->pcm_ops->enable_out(hwo, false);
}
hwo->pcm_ops->fini_out (hwo);
@@ -1329,8 +1526,8 @@ static void free_audio_state(AudioState *s)
}
QLIST_FOREACH_SAFE(hwi, &s->hw_head_in, entries, hwin) {
- if (hwi->enabled) {
- hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
+ if (hwi->enabled && hwi->pcm_ops->enable_in) {
+ hwi->pcm_ops->enable_in(hwi, false);
}
hwi->pcm_ops->fini_in (hwi);
QLIST_REMOVE(hwi, entries);
@@ -1582,11 +1779,11 @@ CaptureVoiceOut *AUD_add_capture(
/* XXX find a more elegant way */
hw->samples = 4096 * 4;
- hw->mix_buf = g_new0(struct st_sample, hw->samples);
+ audio_pcm_hw_alloc_resources_out(hw);
audio_pcm_init_info (&hw->info, as);
- cap->buf = g_malloc0_n(hw->samples, 1 << hw->info.shift);
+ cap->buf = g_malloc0_n(hw->mix_buf->size, 1 << hw->info.shift);
hw->clip = mixeng_clip
[hw->info.nchannels == 2]
@@ -1652,8 +1849,8 @@ void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol)
sw->vol.l = nominal_volume.l * lvol / 255;
sw->vol.r = nominal_volume.r * rvol / 255;
- if (hw->pcm_ops->ctl_out) {
- hw->pcm_ops->ctl_out (hw, VOICE_VOLUME, sw);
+ if (hw->pcm_ops->volume_out) {
+ hw->pcm_ops->volume_out(hw, &sw->vol);
}
}
}
@@ -1667,8 +1864,8 @@ void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol)
sw->vol.l = nominal_volume.l * lvol / 255;
sw->vol.r = nominal_volume.r * rvol / 255;
- if (hw->pcm_ops->ctl_in) {
- hw->pcm_ops->ctl_in (hw, VOICE_VOLUME, sw);
+ if (hw->pcm_ops->volume_in) {
+ hw->pcm_ops->volume_in(hw, &sw->vol);
}
}
}
@@ -1865,3 +2062,33 @@ const char *audio_get_id(QEMUSoundCard *card)
return "";
}
}
+
+void audio_rate_start(RateCtl *rate)
+{
+ memset(rate, 0, sizeof(RateCtl));
+ rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+}
+
+size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate,
+ size_t bytes_avail)
+{
+ int64_t now;
+ int64_t ticks;
+ int64_t bytes;
+ int64_t samples;
+ size_t ret;
+
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ ticks = now - rate->start_ticks;
+ bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND);
+ samples = (bytes - rate->bytes_sent) >> info->shift;
+ if (samples < 0 || samples > 65536) {
+ AUD_log(NULL, "Resetting rate control (%" PRId64 " samples)\n", samples);
+ audio_rate_start(rate);
+ samples = 0;
+ }
+
+ ret = MIN(samples << info->shift, bytes_avail);
+ rate->bytes_sent += ret;
+ return ret;
+}
diff --git a/audio/audio_int.h b/audio/audio_int.h
index a674c5374a..22a703c13e 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -52,6 +52,11 @@ struct audio_pcm_info {
typedef struct AudioState AudioState;
typedef struct SWVoiceCap SWVoiceCap;
+typedef struct STSampleBuffer {
+ size_t pos, size;
+ st_sample samples[];
+} STSampleBuffer;
+
typedef struct HWVoiceOut {
AudioState *s;
int enabled;
@@ -60,16 +65,15 @@ typedef struct HWVoiceOut {
struct audio_pcm_info info;
f_sample *clip;
-
- size_t rpos;
uint64_t ts_helper;
- struct st_sample *mix_buf;
+ STSampleBuffer *mix_buf;
+ void *buf_emul;
+ size_t pos_emul, pending_emul, size_emul;
size_t samples;
QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
- int ctl_caps;
struct audio_pcm_ops *pcm_ops;
QLIST_ENTRY (HWVoiceOut) entries;
} HWVoiceOut;
@@ -82,15 +86,15 @@ typedef struct HWVoiceIn {
t_sample *conv;
- size_t wpos;
size_t total_samples_captured;
uint64_t ts_helper;
- struct st_sample *conv_buf;
+ STSampleBuffer *conv_buf;
+ void *buf_emul;
+ size_t pos_emul, pending_emul, size_emul;
size_t samples;
QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
- int ctl_caps;
struct audio_pcm_ops *pcm_ops;
QLIST_ENTRY (HWVoiceIn) entries;
} HWVoiceIn;
@@ -142,22 +146,46 @@ struct audio_driver {
int max_voices_in;
int voice_size_out;
int voice_size_in;
- int ctl_caps;
QLIST_ENTRY(audio_driver) next;
};
struct audio_pcm_ops {
- int (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque);
- void (*fini_out)(HWVoiceOut *hw);
- size_t (*run_out)(HWVoiceOut *hw, size_t live);
- int (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
-
- int (*init_in) (HWVoiceIn *hw, struct audsettings *as, void *drv_opaque);
- void (*fini_in) (HWVoiceIn *hw);
- size_t (*run_in)(HWVoiceIn *hw);
- int (*ctl_in) (HWVoiceIn *hw, int cmd, ...);
+ int (*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque);
+ void (*fini_out)(HWVoiceOut *hw);
+ size_t (*write) (HWVoiceOut *hw, void *buf, size_t size);
+ /*
+ * get a buffer that after later can be passed to put_buffer_out; optional
+ * returns the buffer, and writes it's size to size (in bytes)
+ * this is unrelated to the above buffer_size_out function
+ */
+ void *(*get_buffer_out)(HWVoiceOut *hw, size_t *size);
+ /*
+ * put back the buffer returned by get_buffer_out; optional
+ * buf must be equal the pointer returned by get_buffer_out,
+ * size may be smaller
+ */
+ size_t (*put_buffer_out)(HWVoiceOut *hw, void *buf, size_t size);
+ void (*enable_out)(HWVoiceOut *hw, bool enable);
+ void (*volume_out)(HWVoiceOut *hw, struct mixeng_volume *vol);
+
+ int (*init_in) (HWVoiceIn *hw, audsettings *as, void *drv_opaque);
+ void (*fini_in) (HWVoiceIn *hw);
+ size_t (*read) (HWVoiceIn *hw, void *buf, size_t size);
+ void *(*get_buffer_in)(HWVoiceIn *hw, size_t *size);
+ void (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size);
+ void (*enable_in)(HWVoiceIn *hw, bool enable);
+ void (*volume_in)(HWVoiceIn *hw, struct mixeng_volume *vol);
};
+void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
+void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size);
+void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
+size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size);
+size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
+ size_t size);
+size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size);
+size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size);
+
struct capture_callback {
struct audio_capture_ops ops;
void *opaque;
@@ -208,21 +236,19 @@ audio_driver *audio_driver_lookup(const char *name);
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
-size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw);
-
-size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf,
- size_t live, size_t pending);
-
int audio_bug (const char *funcname, int cond);
void *audio_calloc (const char *funcname, int nmemb, size_t size);
void audio_run(AudioState *s, const char *msg);
-#define VOICE_ENABLE 1
-#define VOICE_DISABLE 2
-#define VOICE_VOLUME 3
+typedef struct RateCtl {
+ int64_t start_ticks;
+ int64_t bytes_sent;
+} RateCtl;
-#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME)
+void audio_rate_start(RateCtl *rate);
+size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate,
+ size_t bytes_avail);
static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len)
{
diff --git a/audio/audio_pt_int.c b/audio/audio_pt_int.c
deleted file mode 100644
index 9f9d44ad4a..0000000000
--- a/audio/audio_pt_int.c
+++ /dev/null
@@ -1,173 +0,0 @@
-#include "qemu/osdep.h"
-#include "audio.h"
-
-#define AUDIO_CAP "audio-pt"
-
-#include "audio_int.h"
-#include "audio_pt_int.h"
-
-static void GCC_FMT_ATTR(3, 4) logerr (struct audio_pt *pt, int err,
- const char *fmt, ...)
-{
- va_list ap;
-
- va_start (ap, fmt);
- AUD_vlog (pt->drv, fmt, ap);
- va_end (ap);
-
- AUD_log (NULL, "\n");
- AUD_log (pt->drv, "Reason: %s\n", strerror (err));
-}
-
-int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
- void *opaque, const char *drv, const char *cap)
-{
- int err, err2;
- const char *efunc;
- sigset_t set, old_set;
-
- p->drv = drv;
-
- err = sigfillset (&set);
- if (err) {
- logerr(p, errno, "%s(%s): sigfillset failed", cap, __func__);
- return -1;
- }
-
- err = pthread_mutex_init (&p->mutex, NULL);
- if (err) {
- efunc = "pthread_mutex_init";
- goto err0;
- }
-
- err = pthread_cond_init (&p->cond, NULL);
- if (err) {
- efunc = "pthread_cond_init";
- goto err1;
- }
-
- err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
- if (err) {
- efunc = "pthread_sigmask";
- goto err2;
- }
-
- err = pthread_create (&p->thread, NULL, func, opaque);
-
- err2 = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
- if (err2) {
- logerr(p, err2, "%s(%s): pthread_sigmask (restore) failed",
- cap, __func__);
- /* We have failed to restore original signal mask, all bets are off,
- so terminate the process */
- exit (EXIT_FAILURE);
- }
-
- if (err) {
- efunc = "pthread_create";
- goto err2;
- }
-
- return 0;
-
- err2:
- err2 = pthread_cond_destroy (&p->cond);
- if (err2) {
- logerr(p, err2, "%s(%s): pthread_cond_destroy failed", cap, __func__);
- }
-
- err1:
- err2 = pthread_mutex_destroy (&p->mutex);
- if (err2) {
- logerr(p, err2, "%s(%s): pthread_mutex_destroy failed", cap, __func__);
- }
-
- err0:
- logerr(p, err, "%s(%s): %s failed", cap, __func__, efunc);
- return -1;
-}
-
-int audio_pt_fini (struct audio_pt *p, const char *cap)
-{
- int err, ret = 0;
-
- err = pthread_cond_destroy (&p->cond);
- if (err) {
- logerr(p, err, "%s(%s): pthread_cond_destroy failed", cap, __func__);
- ret = -1;
- }
-
- err = pthread_mutex_destroy (&p->mutex);
- if (err) {
- logerr(p, err, "%s(%s): pthread_mutex_destroy failed", cap, __func__);
- ret = -1;
- }
- return ret;
-}
-
-int audio_pt_lock (struct audio_pt *p, const char *cap)
-{
- int err;
-
- err = pthread_mutex_lock (&p->mutex);
- if (err) {
- logerr(p, err, "%s(%s): pthread_mutex_lock failed", cap, __func__);
- return -1;
- }
- return 0;
-}
-
-int audio_pt_unlock (struct audio_pt *p, const char *cap)
-{
- int err;
-
- err = pthread_mutex_unlock (&p->mutex);
- if (err) {
- logerr(p, err, "%s(%s): pthread_mutex_unlock failed", cap, __func__);
- return -1;
- }
- return 0;
-}
-
-int audio_pt_wait (struct audio_pt *p, const char *cap)
-{
- int err;
-
- err = pthread_cond_wait (&p->cond, &p->mutex);
- if (err) {
- logerr(p, err, "%s(%s): pthread_cond_wait failed", cap, __func__);
- return -1;
- }
- return 0;
-}
-
-int audio_pt_unlock_and_signal (struct audio_pt *p, const char *cap)
-{
- int err;
-
- err = pthread_mutex_unlock (&p->mutex);
- if (err) {
- logerr(p, err, "%s(%s): pthread_mutex_unlock failed", cap, __func__);
- return -1;
- }
- err = pthread_cond_signal (&p->cond);
- if (err) {
- logerr(p, err, "%s(%s): pthread_cond_signal failed", cap, __func__);
- return -1;
- }
- return 0;
-}
-
-int audio_pt_join (struct audio_pt *p, void **arg, const char *cap)
-{
- int err;
- void *ret;
-
- err = pthread_join (p->thread, &ret);
- if (err) {
- logerr(p, err, "%s(%s): pthread_join failed", cap, __func__);
- return -1;
- }
- *arg = ret;
- return 0;
-}
diff --git a/audio/audio_pt_int.h b/audio/audio_pt_int.h
deleted file mode 100644
index 4c0c15b9af..0000000000
--- a/audio/audio_pt_int.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef QEMU_AUDIO_PT_INT_H
-#define QEMU_AUDIO_PT_INT_H
-
-#include <pthread.h>
-
-struct audio_pt {
- const char *drv;
- pthread_t thread;
- pthread_cond_t cond;
- pthread_mutex_t mutex;
-};
-
-int audio_pt_init (struct audio_pt *, void *(*) (void *), void *,
- const char *, const char *);
-int audio_pt_fini (struct audio_pt *, const char *);
-int audio_pt_lock (struct audio_pt *, const char *);
-int audio_pt_unlock (struct audio_pt *, const char *);
-int audio_pt_wait (struct audio_pt *, const char *);
-int audio_pt_unlock_and_signal (struct audio_pt *, const char *);
-int audio_pt_join (struct audio_pt *, void **, const char *);
-
-#endif /* QEMU_AUDIO_PT_INT_H */
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 2562bf5f00..235d1acbbe 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -71,20 +71,20 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
{
+ g_free(hw->buf_emul);
g_free (HWBUF);
HWBUF = NULL;
}
-static bool glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
+static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
{
- HWBUF = audio_calloc(__func__, hw->samples, sizeof(struct st_sample));
- if (!HWBUF) {
- dolog("Could not allocate " NAME " buffer (%zu samples)\n",
- hw->samples);
- return false;
+ size_t samples = hw->samples;
+ if (audio_bug(__func__, samples == 0)) {
+ dolog("Attempted to allocate empty buffer\n");
}
- return true;
+ HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * samples);
+ HWBUF->size = samples;
}
static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
@@ -103,7 +103,7 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
{
int samples;
- samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
+ samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample));
if (!sw->buf) {
@@ -254,7 +254,6 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
hw->s = s;
hw->pcm_ops = drv->pcm_ops;
- hw->ctl_caps = drv->ctl_caps;
QLIST_INIT (&hw->sw_head);
#ifdef DAC
@@ -279,9 +278,7 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
[hw->info.swap_endianness]
[audio_bits_to_index (hw->info.bits)];
- if (!glue(audio_pcm_hw_alloc_resources_, TYPE)(hw)) {
- goto err1;
- }
+ glue(audio_pcm_hw_alloc_resources_, TYPE)(hw);
QLIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
glue (s->nb_hw_voices_, TYPE) -= 1;
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index d1be58b40a..1427c9f622 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -43,9 +43,6 @@ typedef struct coreaudioVoiceOut {
UInt32 audioDevicePropertyBufferFrameSize;
AudioStreamBasicDescription outputStreamBasicDescription;
AudioDeviceIOProcID ioprocid;
- size_t live;
- size_t decr;
- size_t rpos;
} coreaudioVoiceOut;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
@@ -397,31 +394,29 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
return 0;
}
-static size_t coreaudio_run_out(HWVoiceOut *hw, size_t live)
-{
- size_t decr;
- coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
-
- if (coreaudio_lock (core, "coreaudio_run_out")) {
- return 0;
+#define COREAUDIO_WRAPPER_FUNC(name, ret_type, args_decl, args) \
+ static ret_type glue(coreaudio_, name)args_decl \
+ { \
+ coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; \
+ ret_type ret; \
+ \
+ if (coreaudio_lock(core, "coreaudio_" #name)) { \
+ return 0; \
+ } \
+ \
+ ret = glue(audio_generic_, name)args; \
+ \
+ coreaudio_unlock(core, "coreaudio_" #name); \
+ return ret; \
}
-
- if (core->decr > live) {
- ldebug ("core->decr %d live %d core->live %d\n",
- core->decr,
- live,
- core->live);
- }
-
- decr = MIN (core->decr, live);
- core->decr -= decr;
-
- core->live = live - decr;
- hw->rpos = core->rpos;
-
- coreaudio_unlock (core, "coreaudio_run_out");
- return decr;
-}
+COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
+ (hw, size))
+COREAUDIO_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
+ (HWVoiceOut *hw, void *buf, size_t size),
+ (hw, buf, size))
+COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
+ (hw, buf, size))
+#undef COREAUDIO_WRAPPER_FUNC
/* callback to feed audiooutput buffer */
static OSStatus audioDeviceIOProc(
@@ -433,19 +428,11 @@ static OSStatus audioDeviceIOProc(
const AudioTimeStamp* inOutputTime,
void* hwptr)
{
- UInt32 frame, frameCount;
- float *out = outOutputData->mBuffers[0].mData;
+ UInt32 frameCount, pending_frames;
+ void *out = outOutputData->mBuffers[0].mData;
HWVoiceOut *hw = hwptr;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
- int rpos, live;
- struct st_sample *src;
-#ifndef FLOAT_MIXENG
-#ifdef RECIPROCAL
- const float scale = 1.f / UINT_MAX;
-#else
- const float scale = UINT_MAX;
-#endif
-#endif
+ size_t len;
if (coreaudio_lock (core, "audioDeviceIOProc")) {
inInputTime = 0;
@@ -453,42 +440,51 @@ static OSStatus audioDeviceIOProc(
}
frameCount = core->audioDevicePropertyBufferFrameSize;
- live = core->live;
+ pending_frames = hw->pending_emul >> hw->info.shift;
/* if there are not enough samples, set signal and return */
- if (live < frameCount) {
+ if (pending_frames < frameCount) {
inInputTime = 0;
coreaudio_unlock (core, "audioDeviceIOProc(empty)");
return 0;
}
- rpos = core->rpos;
- src = hw->mix_buf + rpos;
+ len = frameCount << hw->info.shift;
+ while (len) {
+ size_t write_len;
+ ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
+ if (start < 0) {
+ start += hw->size_emul;
+ }
+ assert(start >= 0 && start < hw->size_emul);
- /* fill buffer */
- for (frame = 0; frame < frameCount; frame++) {
-#ifdef FLOAT_MIXENG
- *out++ = src[frame].l; /* left channel */
- *out++ = src[frame].r; /* right channel */
-#else
-#ifdef RECIPROCAL
- *out++ = src[frame].l * scale; /* left channel */
- *out++ = src[frame].r * scale; /* right channel */
-#else
- *out++ = src[frame].l / scale; /* left channel */
- *out++ = src[frame].r / scale; /* right channel */
-#endif
-#endif
- }
+ write_len = MIN(MIN(hw->pending_emul, len),
+ hw->size_emul - start);
- rpos = (rpos + frameCount) % hw->samples;
- core->decr += frameCount;
- core->rpos = rpos;
+ memcpy(out, hw->buf_emul + start, write_len);
+ hw->pending_emul -= write_len;
+ len -= write_len;
+ out += write_len;
+ }
coreaudio_unlock (core, "audioDeviceIOProc");
return 0;
}
+static UInt32 coreaudio_get_flags(struct audio_pcm_info *info,
+ struct audsettings *as)
+{
+ UInt32 flags = info->sign ? kAudioFormatFlagIsSignedInteger : 0;
+ if (as->endianness) { /* 0 = little, 1 = big */
+ flags |= kAudioFormatFlagIsBigEndian;
+ }
+
+ if (flags == 0) { /* must not be 0 */
+ flags = kAudioFormatFlagsAreAllClear;
+ }
+ return flags;
+}
+
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
void *drv_opaque)
{
@@ -576,6 +572,16 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
/* set Samplerate */
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
+ core->outputStreamBasicDescription.mFormatID = kAudioFormatLinearPCM;
+ core->outputStreamBasicDescription.mFormatFlags =
+ coreaudio_get_flags(&hw->info, as);
+ core->outputStreamBasicDescription.mBytesPerPacket =
+ core->outputStreamBasicDescription.mBytesPerFrame =
+ hw->info.nchannels * hw->info.bits / 8;
+ core->outputStreamBasicDescription.mFramesPerPacket = 1;
+ core->outputStreamBasicDescription.mChannelsPerFrame = hw->info.nchannels;
+ core->outputStreamBasicDescription.mBitsPerChannel = hw->info.bits;
+
status = coreaudio_set_streamformat(core->outputDeviceID,
&core->outputStreamBasicDescription);
if (status != kAudioHardwareNoError) {
@@ -642,13 +648,12 @@ static void coreaudio_fini_out (HWVoiceOut *hw)
}
}
-static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
+static void coreaudio_enable_out(HWVoiceOut *hw, bool enable)
{
OSStatus status;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
- switch (cmd) {
- case VOICE_ENABLE:
+ if (enable) {
/* start playback */
if (!isPlaying(core->outputDeviceID)) {
status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
@@ -656,9 +661,7 @@ static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
coreaudio_logerr (status, "Could not resume playback\n");
}
}
- break;
-
- case VOICE_DISABLE:
+ } else {
/* stop playback */
if (!audio_is_cleaning_up()) {
if (isPlaying(core->outputDeviceID)) {
@@ -669,9 +672,7 @@ static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
}
}
}
- break;
}
- return 0;
}
static void *coreaudio_audio_init(Audiodev *dev)
@@ -686,8 +687,10 @@ static void coreaudio_audio_fini (void *opaque)
static struct audio_pcm_ops coreaudio_pcm_ops = {
.init_out = coreaudio_init_out,
.fini_out = coreaudio_fini_out,
- .run_out = coreaudio_run_out,
- .ctl_out = coreaudio_ctl_out
+ .write = coreaudio_write,
+ .get_buffer_out = coreaudio_get_buffer_out,
+ .put_buffer_out = coreaudio_put_buffer_out_nowrite,
+ .enable_out = coreaudio_enable_out
};
static struct audio_driver coreaudio_audio_driver = {
diff --git a/audio/dsound_template.h b/audio/dsound_template.h
index 8ece870c9e..9f10b688df 100644
--- a/audio/dsound_template.h
+++ b/audio/dsound_template.h
@@ -29,6 +29,8 @@
#define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER
#define FIELD dsound_capture_buffer
#define FIELD2 dsound_capture
+#define HWVOICE HWVoiceIn
+#define DSOUNDVOICE DSoundVoiceIn
#else
#define NAME "playback buffer"
#define NAME2 "DirectSound"
@@ -37,6 +39,8 @@
#define BUFPTR LPDIRECTSOUNDBUFFER
#define FIELD dsound_buffer
#define FIELD2 dsound
+#define HWVOICE HWVoiceOut
+#define DSOUNDVOICE DSoundVoiceOut
#endif
static int glue (dsound_unlock_, TYPE) (
@@ -72,8 +76,6 @@ static int glue (dsound_lock_, TYPE) (
)
{
HRESULT hr;
- LPVOID p1 = NULL, p2 = NULL;
- DWORD blen1 = 0, blen2 = 0;
DWORD flag;
#ifdef DSBTYPE_IN
@@ -81,7 +83,7 @@ static int glue (dsound_lock_, TYPE) (
#else
flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
#endif
- hr = glue(IFACE, _Lock)(buf, pos, len, &p1, &blen1, &p2, &blen2, flag);
+ hr = glue(IFACE, _Lock)(buf, pos, len, p1p, blen1p, p2p, blen2p, flag);
if (FAILED (hr)) {
#ifndef DSBTYPE_IN
@@ -96,34 +98,34 @@ static int glue (dsound_lock_, TYPE) (
goto fail;
}
- if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) {
- dolog ("DirectSound returned misaligned buffer %ld %ld\n",
- blen1, blen2);
- glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2);
+ if ((p1p && *p1p && (*blen1p & info->align)) ||
+ (p2p && *p2p && (*blen2p & info->align))) {
+ dolog("DirectSound returned misaligned buffer %ld %ld\n",
+ *blen1p, *blen2p);
+ glue(dsound_unlock_, TYPE)(buf, *p1p, p2p ? *p2p : NULL, *blen1p,
+ blen2p ? *blen2p : 0);
goto fail;
}
- if (!p1 && blen1) {
- dolog ("warning: !p1 && blen1=%ld\n", blen1);
- blen1 = 0;
+ if (p1p && !*p1p && *blen1p) {
+ dolog("warning: !p1 && blen1=%ld\n", *blen1p);
+ *blen1p = 0;
}
- if (!p2 && blen2) {
- dolog ("warning: !p2 && blen2=%ld\n", blen2);
- blen2 = 0;
+ if (p2p && !*p2p && *blen2p) {
+ dolog("warning: !p2 && blen2=%ld\n", *blen2p);
+ *blen2p = 0;
}
- *p1p = p1;
- *p2p = p2;
- *blen1p = blen1;
- *blen2p = blen2;
return 0;
fail:
*p1p = NULL - 1;
- *p2p = NULL - 1;
*blen1p = -1;
- *blen2p = -1;
+ if (p2p) {
+ *p2p = NULL - 1;
+ *blen2p = -1;
+ }
return -1;
}
@@ -242,7 +244,6 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
goto fail0;
}
- ds->first_time = 1;
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
@@ -252,15 +253,13 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
bc.dwBufferBytes, hw->info.align + 1
);
}
+ hw->size_emul = bc.dwBufferBytes;
hw->samples = bc.dwBufferBytes >> hw->info.shift;
ds->s = s;
#ifdef DEBUG_DSOUND
dolog ("caps %ld, desc %ld\n",
bc.dwBufferBytes, bd.dwBufferBytes);
-
- dolog ("bufsize %d, freq %d, chan %d, fmt %d\n",
- hw->bufsize, settings.freq, settings.nchannels, settings.fmt);
#endif
return 0;
@@ -276,3 +275,5 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
#undef BUFPTR
#undef FIELD
#undef FIELD2
+#undef HWVOICE
+#undef DSOUNDVOICE
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index 2fc118b795..d4a4757445 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -53,19 +53,11 @@ typedef struct {
typedef struct {
HWVoiceOut hw;
LPDIRECTSOUNDBUFFER dsound_buffer;
- DWORD old_pos;
- int first_time;
dsound *s;
-#ifdef DEBUG_DSOUND
- DWORD old_ppos;
- DWORD played;
- DWORD mixed;
-#endif
} DSoundVoiceOut;
typedef struct {
HWVoiceIn hw;
- int first_time;
LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
dsound *s;
} DSoundVoiceIn;
@@ -243,11 +235,6 @@ static void GCC_FMT_ATTR (3, 4) dsound_logerr2 (
dsound_log_hresult (hr);
}
-static uint64_t usecs_to_bytes(struct audio_pcm_info *info, uint32_t usecs)
-{
- return muldiv64(usecs, info->bytes_per_second, 1000000);
-}
-
#ifdef DEBUG_DSOUND
static void print_wave_format (WAVEFORMATEX *wfx)
{
@@ -312,33 +299,6 @@ static int dsound_get_status_in (LPDIRECTSOUNDCAPTUREBUFFER dscb,
return 0;
}
-static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
-{
- int src_len1 = dst_len;
- int src_len2 = 0;
- int pos = hw->rpos + dst_len;
- struct st_sample *src1 = hw->mix_buf + hw->rpos;
- struct st_sample *src2 = NULL;
-
- if (pos > hw->samples) {
- src_len1 = hw->samples - hw->rpos;
- src2 = hw->mix_buf;
- src_len2 = dst_len - src_len1;
- pos = src_len2;
- }
-
- if (src_len1) {
- hw->clip (dst, src1, src_len1);
- }
-
- if (src_len2) {
- dst = advance (dst, src_len1 << hw->info.shift);
- hw->clip (dst, src2, src_len2);
- }
-
- hw->rpos = pos % hw->samples;
-}
-
static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb,
dsound *s)
{
@@ -350,7 +310,7 @@ static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb,
dsb,
&hw->info,
0,
- hw->samples << hw->info.shift,
+ hw->size_emul,
&p1, &p2,
&blen1, &blen2,
1,
@@ -401,7 +361,7 @@ static int dsound_open (dsound *s)
return 0;
}
-static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
+static void dsound_enable_out(HWVoiceOut *hw, bool enable)
{
HRESULT hr;
DWORD status;
@@ -411,18 +371,17 @@ static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
if (!dsb) {
dolog ("Attempt to control voice without a buffer\n");
- return 0;
+ return;
}
- switch (cmd) {
- case VOICE_ENABLE:
+ if (enable) {
if (dsound_get_status_out (dsb, &status, s)) {
- return -1;
+ return;
}
if (status & DSBSTATUS_PLAYING) {
dolog ("warning: Voice is already playing\n");
- return 0;
+ return;
}
dsound_clear_sample (hw, dsb, s);
@@ -430,166 +389,74 @@ static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not start playing buffer\n");
- return -1;
+ return;
}
- break;
-
- case VOICE_DISABLE:
+ } else {
if (dsound_get_status_out (dsb, &status, s)) {
- return -1;
+ return;
}
if (status & DSBSTATUS_PLAYING) {
hr = IDirectSoundBuffer_Stop (dsb);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not stop playing buffer\n");
- return -1;
+ return;
}
}
else {
dolog ("warning: Voice is not playing\n");
}
- break;
}
- return 0;
}
-static size_t dsound_run_out(HWVoiceOut *hw, size_t live)
+static void *dsound_get_buffer_out(HWVoiceOut *hw, size_t *size)
{
- int err;
- HRESULT hr;
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
- size_t len;
- int hwshift;
- DWORD blen1, blen2;
- DWORD len1, len2;
- DWORD decr;
- DWORD wpos, ppos, old_pos;
- LPVOID p1, p2;
- size_t bufsize;
- dsound *s = ds->s;
- AudiodevDsoundOptions *dso = &s->dev->u.dsound;
-
- if (!dsb) {
- dolog ("Attempt to run empty with playback buffer\n");
- return 0;
- }
-
- hwshift = hw->info.shift;
- bufsize = hw->samples << hwshift;
-
- hr = IDirectSoundBuffer_GetCurrentPosition (
- dsb,
- &ppos,
- ds->first_time ? &wpos : NULL
- );
- if (FAILED (hr)) {
- dsound_logerr (hr, "Could not get playback buffer position\n");
- return 0;
- }
-
- len = live << hwshift;
-
- if (ds->first_time) {
- if (dso->latency) {
- DWORD cur_blat;
+ HRESULT hr;
+ DWORD ppos, act_size;
+ size_t req_size;
+ int err;
+ void *ret;
- cur_blat = audio_ring_dist (wpos, ppos, bufsize);
- ds->first_time = 0;
- old_pos = wpos;
- old_pos +=
- usecs_to_bytes(&hw->info, dso->latency) - cur_blat;
- old_pos %= bufsize;
- old_pos &= ~hw->info.align;
- }
- else {
- old_pos = wpos;
- }
-#ifdef DEBUG_DSOUND
- ds->played = 0;
- ds->mixed = 0;
-#endif
+ hr = IDirectSoundBuffer_GetCurrentPosition(dsb, &ppos, NULL);
+ if (FAILED(hr)) {
+ dsound_logerr(hr, "Could not get playback buffer position\n");
+ *size = 0;
+ return NULL;
}
- else {
- if (ds->old_pos == ppos) {
-#ifdef DEBUG_DSOUND
- dolog ("old_pos == ppos\n");
-#endif
- return 0;
- }
-#ifdef DEBUG_DSOUND
- ds->played += audio_ring_dist (ds->old_pos, ppos, hw->bufsize);
-#endif
- old_pos = ds->old_pos;
- }
+ req_size = audio_ring_dist(ppos, hw->pos_emul, hw->size_emul);
+ req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
- if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
- len = ppos - old_pos;
- }
- else {
- if ((old_pos > ppos) && ((old_pos + len) > (ppos + bufsize))) {
- len = bufsize - old_pos + ppos;
- }
+ err = dsound_lock_out(dsb, &hw->info, hw->pos_emul, req_size, &ret, NULL,
+ &act_size, NULL, false, ds->s);
+ if (err) {
+ dolog("Failed to lock buffer\n");
+ *size = 0;
+ return NULL;
}
- if (audio_bug(__func__, len > bufsize)) {
- dolog("len=%zu bufsize=%zu old_pos=%ld ppos=%ld\n",
- len, bufsize, old_pos, ppos);
- return 0;
- }
+ *size = act_size;
+ return ret;
+}
- len &= ~hw->info.align;
- if (!len) {
- return 0;
- }
+static size_t dsound_put_buffer_out(HWVoiceOut *hw, void *buf, size_t len)
+{
+ DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
+ LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
+ int err = dsound_unlock_out(dsb, buf, NULL, len, 0);
-#ifdef DEBUG_DSOUND
- ds->old_ppos = ppos;
-#endif
- err = dsound_lock_out (
- dsb,
- &hw->info,
- old_pos,
- len,
- &p1, &p2,
- &blen1, &blen2,
- 0,
- s
- );
if (err) {
+ dolog("Failed to unlock buffer!!\n");
return 0;
}
+ hw->pos_emul = (hw->pos_emul + len) % hw->size_emul;
- len1 = blen1 >> hwshift;
- len2 = blen2 >> hwshift;
- decr = len1 + len2;
-
- if (p1 && len1) {
- dsound_write_sample (hw, p1, len1);
- }
-
- if (p2 && len2) {
- dsound_write_sample (hw, p2, len2);
- }
-
- dsound_unlock_out (dsb, p1, p2, blen1, blen2);
- ds->old_pos = (old_pos + (decr << hwshift)) % bufsize;
-
-#ifdef DEBUG_DSOUND
- ds->mixed += decr << hwshift;
-
- dolog ("played %lu mixed %lu diff %ld sec %f\n",
- ds->played,
- ds->mixed,
- ds->mixed - ds->played,
- abs (ds->mixed - ds->played) / (double) hw->info.bytes_per_second);
-#endif
- return decr;
+ return len;
}
-static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...)
+static void dsound_enable_in(HWVoiceIn *hw, bool enable)
{
HRESULT hr;
DWORD status;
@@ -598,18 +465,17 @@ static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...)
if (!dscb) {
dolog ("Attempt to control capture voice without a buffer\n");
- return -1;
+ return;
}
- switch (cmd) {
- case VOICE_ENABLE:
+ if (enable) {
if (dsound_get_status_in (dscb, &status)) {
- return -1;
+ return;
}
if (status & DSCBSTATUS_CAPTURING) {
dolog ("warning: Voice is already capturing\n");
- return 0;
+ return;
}
/* clear ?? */
@@ -617,120 +483,69 @@ static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...)
hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not start capturing\n");
- return -1;
+ return;
}
- break;
-
- case VOICE_DISABLE:
+ } else {
if (dsound_get_status_in (dscb, &status)) {
- return -1;
+ return;
}
if (status & DSCBSTATUS_CAPTURING) {
hr = IDirectSoundCaptureBuffer_Stop (dscb);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not stop capturing\n");
- return -1;
+ return;
}
}
else {
dolog ("warning: Voice is not capturing\n");
}
- break;
}
- return 0;
}
-static size_t dsound_run_in(HWVoiceIn *hw)
+static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size)
{
- int err;
- HRESULT hr;
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
- size_t live, len, dead;
- DWORD blen1, blen2;
- DWORD len1, len2;
- DWORD decr;
- DWORD cpos, rpos;
- LPVOID p1, p2;
- int hwshift;
- dsound *s = ds->s;
-
- if (!dscb) {
- dolog ("Attempt to run without capture buffer\n");
- return 0;
- }
-
- hwshift = hw->info.shift;
-
- live = audio_pcm_hw_get_live_in (hw);
- dead = hw->samples - live;
- if (!dead) {
- return 0;
- }
-
- hr = IDirectSoundCaptureBuffer_GetCurrentPosition (
- dscb,
- &cpos,
- ds->first_time ? &rpos : NULL
- );
- if (FAILED (hr)) {
- dsound_logerr (hr, "Could not get capture buffer position\n");
- return 0;
- }
-
- if (ds->first_time) {
- ds->first_time = 0;
- if (rpos & hw->info.align) {
- ldebug ("warning: Misaligned capture read position %ld(%d)\n",
- rpos, hw->info.align);
- }
- hw->wpos = rpos >> hwshift;
- }
+ HRESULT hr;
+ DWORD cpos, act_size;
+ size_t req_size;
+ int err;
+ void *ret;
- if (cpos & hw->info.align) {
- ldebug ("warning: Misaligned capture position %ld(%d)\n",
- cpos, hw->info.align);
+ hr = IDirectSoundCaptureBuffer_GetCurrentPosition(dscb, &cpos, NULL);
+ if (FAILED(hr)) {
+ dsound_logerr(hr, "Could not get capture buffer position\n");
+ *size = 0;
+ return NULL;
}
- cpos >>= hwshift;
- len = audio_ring_dist (cpos, hw->wpos, hw->samples);
- if (!len) {
- return 0;
- }
- len = MIN (len, dead);
+ req_size = audio_ring_dist(cpos, hw->pos_emul, hw->size_emul);
+ req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
- err = dsound_lock_in (
- dscb,
- &hw->info,
- hw->wpos << hwshift,
- len << hwshift,
- &p1,
- &p2,
- &blen1,
- &blen2,
- 0,
- s
- );
+ err = dsound_lock_in(dscb, &hw->info, hw->pos_emul, req_size, &ret, NULL,
+ &act_size, NULL, false, ds->s);
if (err) {
- return 0;
+ dolog("Failed to lock buffer\n");
+ *size = 0;
+ return NULL;
}
- len1 = blen1 >> hwshift;
- len2 = blen2 >> hwshift;
- decr = len1 + len2;
+ *size = act_size;
+ return ret;
+}
- if (p1 && len1) {
- hw->conv (hw->conv_buf + hw->wpos, p1, len1);
- }
+static void dsound_put_buffer_in(HWVoiceIn *hw, void *buf, size_t len)
+{
+ DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
+ LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
+ int err = dsound_unlock_in(dscb, buf, NULL, len, 0);
- if (p2 && len2) {
- hw->conv (hw->conv_buf, p2, len2);
+ if (err) {
+ dolog("Failed to unlock buffer!!\n");
+ return;
}
-
- dsound_unlock_in (dscb, p1, p2, blen1, blen2);
- hw->wpos = (hw->wpos + decr) % hw->samples;
- return decr;
+ hw->pos_emul = (hw->pos_emul + len) % hw->size_emul;
}
static void dsound_audio_fini (void *opaque)
@@ -846,13 +661,17 @@ static void *dsound_audio_init(Audiodev *dev)
static struct audio_pcm_ops dsound_pcm_ops = {
.init_out = dsound_init_out,
.fini_out = dsound_fini_out,
- .run_out = dsound_run_out,
- .ctl_out = dsound_ctl_out,
+ .write = audio_generic_write,
+ .get_buffer_out = dsound_get_buffer_out,
+ .put_buffer_out = dsound_put_buffer_out,
+ .enable_out = dsound_enable_out,
.init_in = dsound_init_in,
.fini_in = dsound_fini_in,
- .run_in = dsound_run_in,
- .ctl_in = dsound_ctl_in
+ .read = audio_generic_read,
+ .get_buffer_in = dsound_get_buffer_in,
+ .put_buffer_in = dsound_put_buffer_in,
+ .enable_in = dsound_enable_in,
};
static struct audio_driver dsound_audio_driver = {
diff --git a/audio/noaudio.c b/audio/noaudio.c
index 0fb2629cf2..ec8a287f36 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -33,38 +33,27 @@
typedef struct NoVoiceOut {
HWVoiceOut hw;
- int64_t old_ticks;
+ RateCtl rate;
} NoVoiceOut;
typedef struct NoVoiceIn {
HWVoiceIn hw;
- int64_t old_ticks;
+ RateCtl rate;
} NoVoiceIn;
-static size_t no_run_out(HWVoiceOut *hw, size_t live)
+static size_t no_write(HWVoiceOut *hw, void *buf, size_t len)
{
NoVoiceOut *no = (NoVoiceOut *) hw;
- size_t decr, samples;
- int64_t now;
- int64_t ticks;
- int64_t bytes;
-
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ticks = now - no->old_ticks;
- bytes = muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
- bytes = MIN(bytes, SIZE_MAX);
- samples = bytes >> hw->info.shift;
-
- no->old_ticks = now;
- decr = MIN (live, samples);
- hw->rpos = (hw->rpos + decr) % hw->samples;
- return decr;
+ return audio_rate_get_bytes(&hw->info, &no->rate, len);
}
static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
{
+ NoVoiceOut *no = (NoVoiceOut *) hw;
+
audio_pcm_init_info (&hw->info, as);
hw->samples = 1024;
+ audio_rate_start(&no->rate);
return 0;
}
@@ -73,17 +62,22 @@ static void no_fini_out (HWVoiceOut *hw)
(void) hw;
}
-static int no_ctl_out (HWVoiceOut *hw, int cmd, ...)
+static void no_enable_out(HWVoiceOut *hw, bool enable)
{
- (void) hw;
- (void) cmd;
- return 0;
+ NoVoiceOut *no = (NoVoiceOut *) hw;
+
+ if (enable) {
+ audio_rate_start(&no->rate);
+ }
}
static int no_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
{
+ NoVoiceIn *no = (NoVoiceIn *) hw;
+
audio_pcm_init_info (&hw->info, as);
hw->samples = 1024;
+ audio_rate_start(&no->rate);
return 0;
}
@@ -92,32 +86,22 @@ static void no_fini_in (HWVoiceIn *hw)
(void) hw;
}
-static size_t no_run_in(HWVoiceIn *hw)
+static size_t no_read(HWVoiceIn *hw, void *buf, size_t size)
{
NoVoiceIn *no = (NoVoiceIn *) hw;
- size_t live = audio_pcm_hw_get_live_in(hw);
- size_t dead = hw->samples - live;
- size_t samples = 0;
-
- if (dead) {
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- int64_t ticks = now - no->old_ticks;
- int64_t bytes =
- muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
-
- no->old_ticks = now;
- bytes = MIN (bytes, SIZE_MAX);
- samples = bytes >> hw->info.shift;
- samples = MIN (samples, dead);
- }
- return samples;
+ int64_t bytes = audio_rate_get_bytes(&hw->info, &no->rate, size);
+
+ audio_pcm_info_clear_buf(&hw->info, buf, bytes >> hw->info.shift);
+ return bytes;
}
-static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
+static void no_enable_in(HWVoiceIn *hw, bool enable)
{
- (void) hw;
- (void) cmd;
- return 0;
+ NoVoiceIn *no = (NoVoiceIn *) hw;
+
+ if (enable) {
+ audio_rate_start(&no->rate);
+ }
}
static void *no_audio_init(Audiodev *dev)
@@ -133,13 +117,13 @@ static void no_audio_fini (void *opaque)
static struct audio_pcm_ops no_pcm_ops = {
.init_out = no_init_out,
.fini_out = no_fini_out,
- .run_out = no_run_out,
- .ctl_out = no_ctl_out,
+ .write = no_write,
+ .enable_out = no_enable_out,
.init_in = no_init_in,
.fini_in = no_fini_in,
- .run_in = no_run_in,
- .ctl_in = no_ctl_in
+ .read = no_read,
+ .enable_in = no_enable_in
};
static struct audio_driver no_audio_driver = {
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index 1696933688..0c4451e972 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -40,19 +40,15 @@
typedef struct OSSVoiceOut {
HWVoiceOut hw;
- void *pcm_buf;
int fd;
- int wpos;
int nfrags;
int fragsize;
int mmapped;
- int pending;
Audiodev *dev;
} OSSVoiceOut;
typedef struct OSSVoiceIn {
HWVoiceIn hw;
- void *pcm_buf;
int fd;
int nfrags;
int fragsize;
@@ -371,98 +367,87 @@ static int oss_open(int in, struct oss_params *req, audsettings *as,
return -1;
}
-static void oss_write_pending (OSSVoiceOut *oss)
+static size_t oss_get_available_bytes(OSSVoiceOut *oss)
{
- HWVoiceOut *hw = &oss->hw;
+ int err;
+ struct count_info cntinfo;
+ assert(oss->mmapped);
- if (oss->mmapped) {
- return;
+ err = ioctl(oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
+ if (err < 0) {
+ oss_logerr(errno, "SNDCTL_DSP_GETOPTR failed\n");
+ return 0;
}
- while (oss->pending) {
- int samples_written;
- ssize_t bytes_written;
- int samples_till_end = hw->samples - oss->wpos;
- int samples_to_write = MIN (oss->pending, samples_till_end);
- int bytes_to_write = samples_to_write << hw->info.shift;
- void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift);
+ return audio_ring_dist(cntinfo.ptr, oss->hw.pos_emul, oss->hw.size_emul);
+}
- bytes_written = write (oss->fd, pcm, bytes_to_write);
- if (bytes_written < 0) {
- if (errno != EAGAIN) {
- oss_logerr (errno, "failed to write %d bytes\n",
- bytes_to_write);
- }
- break;
- }
+static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
+{
+ OSSVoiceOut *oss = (OSSVoiceOut *) hw;
+ if (oss->mmapped) {
+ *size = MIN(oss_get_available_bytes(oss), hw->size_emul - hw->pos_emul);
+ return hw->buf_emul + hw->pos_emul;
+ } else {
+ return audio_generic_get_buffer_out(hw, size);
+ }
+}
- if (bytes_written & hw->info.align) {
- dolog ("misaligned write asked for %d, but got %zd\n",
- bytes_to_write, bytes_written);
- return;
- }
+static size_t oss_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
+{
+ OSSVoiceOut *oss = (OSSVoiceOut *) hw;
+ if (oss->mmapped) {
+ assert(buf == hw->buf_emul + hw->pos_emul && size < hw->size_emul);
- samples_written = bytes_written >> hw->info.shift;
- oss->pending -= samples_written;
- oss->wpos = (oss->wpos + samples_written) % hw->samples;
- if (bytes_written - bytes_to_write) {
- break;
- }
+ hw->pos_emul = (hw->pos_emul + size) % hw->size_emul;
+ return size;
+ } else {
+ return audio_generic_put_buffer_out(hw, buf, size);
}
}
-static size_t oss_run_out(HWVoiceOut *hw, size_t live)
+static size_t oss_write(HWVoiceOut *hw, void *buf, size_t len)
{
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
- int err;
- size_t decr;
- struct audio_buf_info abinfo;
- struct count_info cntinfo;
- size_t bufsize;
-
- bufsize = hw->samples << hw->info.shift;
+ size_t pos;
if (oss->mmapped) {
- int bytes, pos;
+ size_t total_len;
+ len = MIN(len, oss_get_available_bytes(oss));
- err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
- if (err < 0) {
- oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
- return 0;
- }
+ total_len = len;
+ while (len) {
+ size_t to_copy = MIN(len, hw->size_emul - hw->pos_emul);
+ memcpy(hw->buf_emul + hw->pos_emul, buf, to_copy);
- pos = hw->rpos << hw->info.shift;
- bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
- decr = MIN (bytes >> hw->info.shift, live);
- }
- else {
- err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
- if (err < 0) {
- oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
- return 0;
+ hw->pos_emul = (hw->pos_emul + to_copy) % hw->pos_emul;
+ buf += to_copy;
+ len -= to_copy;
}
+ return total_len;
+ }
- if (abinfo.bytes > bufsize) {
- trace_oss_invalid_available_size(abinfo.bytes, bufsize);
- abinfo.bytes = bufsize;
- }
+ pos = 0;
+ while (len) {
+ ssize_t bytes_written;
+ void *pcm = advance(buf, pos);
- if (abinfo.bytes < 0) {
- trace_oss_invalid_available_size(abinfo.bytes, bufsize);
- return 0;
+ bytes_written = write(oss->fd, pcm, len);
+ if (bytes_written < 0) {
+ if (errno != EAGAIN) {
+ oss_logerr(errno, "failed to write %zu bytes\n",
+ len);
+ }
+ return pos;
}
- decr = MIN (abinfo.bytes >> hw->info.shift, live);
- if (!decr) {
- return 0;
+ pos += bytes_written;
+ if (bytes_written < len) {
+ break;
}
+ len -= bytes_written;
}
-
- decr = audio_pcm_hw_clip_out (hw, oss->pcm_buf, decr, oss->pending);
- oss->pending += decr;
- oss_write_pending (oss);
-
- return decr;
+ return pos;
}
static void oss_fini_out (HWVoiceOut *hw)
@@ -473,18 +458,13 @@ static void oss_fini_out (HWVoiceOut *hw)
ldebug ("oss_fini\n");
oss_anal_close (&oss->fd);
- if (oss->pcm_buf) {
- if (oss->mmapped) {
- err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
- if (err) {
- oss_logerr(errno, "Failed to unmap buffer %p, size %zu\n",
- oss->pcm_buf, hw->samples << hw->info.shift);
- }
+ if (oss->mmapped && hw->buf_emul) {
+ err = munmap(hw->buf_emul, hw->size_emul);
+ if (err) {
+ oss_logerr(errno, "Failed to unmap buffer %p, size %zu\n",
+ hw->buf_emul, hw->size_emul);
}
- else {
- g_free (oss->pcm_buf);
- }
- oss->pcm_buf = NULL;
+ hw->buf_emul = NULL;
}
}
@@ -535,19 +515,20 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
oss->mmapped = 0;
if (oopts->has_try_mmap && oopts->try_mmap) {
- oss->pcm_buf = mmap (
+ hw->size_emul = hw->samples << hw->info.shift;
+ hw->buf_emul = mmap(
NULL,
- hw->samples << hw->info.shift,
+ hw->size_emul,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0
);
- if (oss->pcm_buf == MAP_FAILED) {
+ if (hw->buf_emul == MAP_FAILED) {
oss_logerr(errno, "Failed to map %zu bytes of DAC\n",
- hw->samples << hw->info.shift);
- }
- else {
+ hw->size_emul);
+ hw->buf_emul = NULL;
+ } else {
int err;
int trig = 0;
if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
@@ -567,88 +548,65 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
}
if (!oss->mmapped) {
- err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
+ err = munmap(hw->buf_emul, hw->size_emul);
if (err) {
oss_logerr(errno, "Failed to unmap buffer %p size %zu\n",
- oss->pcm_buf, hw->samples << hw->info.shift);
+ hw->buf_emul, hw->size_emul);
}
+ hw->buf_emul = NULL;
}
}
}
- if (!oss->mmapped) {
- oss->pcm_buf = audio_calloc(__func__,
- hw->samples,
- 1 << hw->info.shift);
- if (!oss->pcm_buf) {
- dolog (
- "Could not allocate DAC buffer (%zu samples, each %d bytes)\n",
- hw->samples,
- 1 << hw->info.shift
- );
- oss_anal_close (&fd);
- return -1;
- }
- }
-
oss->fd = fd;
oss->dev = dev;
return 0;
}
-static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
+static void oss_enable_out(HWVoiceOut *hw, bool enable)
{
int trig;
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
- switch (cmd) {
- case VOICE_ENABLE:
- {
- bool poll_mode = opdo->try_poll;
+ if (enable) {
+ bool poll_mode = opdo->try_poll;
- ldebug ("enabling voice\n");
- if (poll_mode) {
- oss_poll_out (hw);
- poll_mode = 0;
- }
- hw->poll_mode = poll_mode;
-
- if (!oss->mmapped) {
- return 0;
- }
+ ldebug("enabling voice\n");
+ if (poll_mode) {
+ oss_poll_out(hw);
+ poll_mode = 0;
+ }
+ hw->poll_mode = poll_mode;
- audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
- trig = PCM_ENABLE_OUTPUT;
- if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
- oss_logerr (
- errno,
- "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
- );
- return -1;
- }
+ if (!oss->mmapped) {
+ return;
}
- break;
- case VOICE_DISABLE:
+ audio_pcm_info_clear_buf(&hw->info, hw->buf_emul, hw->mix_buf->size);
+ trig = PCM_ENABLE_OUTPUT;
+ if (ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
+ oss_logerr(errno,
+ "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n");
+ return;
+ }
+ } else {
if (hw->poll_mode) {
qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
hw->poll_mode = 0;
}
if (!oss->mmapped) {
- return 0;
+ return;
}
ldebug ("disabling voice\n");
trig = 0;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
- return -1;
+ return;
}
- break;
}
- return 0;
}
static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
@@ -692,13 +650,6 @@ static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
}
hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
- oss->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
- if (!oss->pcm_buf) {
- dolog("Could not allocate ADC buffer (%zu samples, each %d bytes)\n",
- hw->samples, 1 << hw->info.shift);
- oss_anal_close (&fd);
- return -1;
- }
oss->fd = fd;
oss->dev = dev;
@@ -710,106 +661,57 @@ static void oss_fini_in (HWVoiceIn *hw)
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
oss_anal_close (&oss->fd);
-
- g_free(oss->pcm_buf);
- oss->pcm_buf = NULL;
}
-static size_t oss_run_in(HWVoiceIn *hw)
+static size_t oss_read(HWVoiceIn *hw, void *buf, size_t len)
{
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
- int hwshift = hw->info.shift;
- int i;
- size_t live = audio_pcm_hw_get_live_in (hw);
- size_t dead = hw->samples - live;
- size_t read_samples = 0;
- struct {
- size_t add;
- size_t len;
- } bufs[2] = {
- { .add = hw->wpos, .len = 0 },
- { .add = 0, .len = 0 }
- };
-
- if (!dead) {
- return 0;
- }
+ size_t pos = 0;
- if (hw->wpos + dead > hw->samples) {
- bufs[0].len = (hw->samples - hw->wpos) << hwshift;
- bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
- }
- else {
- bufs[0].len = dead << hwshift;
- }
-
- for (i = 0; i < 2; ++i) {
+ while (len) {
ssize_t nread;
- if (bufs[i].len) {
- void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
- nread = read (oss->fd, p, bufs[i].len);
+ void *dst = advance(buf, pos);
+ nread = read(oss->fd, dst, len);
- if (nread > 0) {
- if (nread & hw->info.align) {
- dolog("warning: Misaligned read %zd (requested %zu), "
- "alignment %d\n", nread, bufs[i].add << hwshift,
- hw->info.align + 1);
- }
- read_samples += nread >> hwshift;
- hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift);
- }
-
- if (bufs[i].len - nread) {
- if (nread == -1) {
- switch (errno) {
- case EINTR:
- case EAGAIN:
- break;
- default:
- oss_logerr(
- errno,
- "Failed to read %zu bytes of audio (to %p)\n",
- bufs[i].len, p
- );
- break;
- }
- }
+ if (nread == -1) {
+ switch (errno) {
+ case EINTR:
+ case EAGAIN:
+ break;
+ default:
+ oss_logerr(errno, "Failed to read %zu bytes of audio (to %p)\n",
+ len, dst);
break;
}
}
+
+ pos += nread;
+ len -= nread;
}
- hw->wpos = (hw->wpos + read_samples) % hw->samples;
- return read_samples;
+ return pos;
}
-static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
+static void oss_enable_in(HWVoiceIn *hw, bool enable)
{
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
- switch (cmd) {
- case VOICE_ENABLE:
- {
- bool poll_mode = opdo->try_poll;
+ if (enable) {
+ bool poll_mode = opdo->try_poll;
- if (poll_mode) {
- oss_poll_in (hw);
- poll_mode = 0;
- }
- hw->poll_mode = poll_mode;
+ if (poll_mode) {
+ oss_poll_in(hw);
+ poll_mode = 0;
}
- break;
-
- case VOICE_DISABLE:
+ hw->poll_mode = poll_mode;
+ } else {
if (hw->poll_mode) {
hw->poll_mode = 0;
qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
}
- break;
}
- return 0;
}
static void oss_init_per_direction(AudiodevOssPerDirectionOptions *opdo)
@@ -845,13 +747,15 @@ static void oss_audio_fini (void *opaque)
static struct audio_pcm_ops oss_pcm_ops = {
.init_out = oss_init_out,
.fini_out = oss_fini_out,
- .run_out = oss_run_out,
- .ctl_out = oss_ctl_out,
+ .write = oss_write,
+ .get_buffer_out = oss_get_buffer_out,
+ .put_buffer_out = oss_put_buffer_out,
+ .enable_out = oss_enable_out,
.init_in = oss_init_in,
.fini_in = oss_fini_in,
- .run_in = oss_run_in,
- .ctl_in = oss_ctl_in
+ .read = oss_read,
+ .enable_in = oss_enable_in
};
static struct audio_driver oss_audio_driver = {
diff --git a/audio/paaudio.c b/audio/paaudio.c
index bfef9acaad..ed31f863f7 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -9,7 +9,6 @@
#define AUDIO_CAP "pulseaudio"
#include "audio_int.h"
-#include "audio_pt_int.h"
typedef struct PAConnection {
char *server;
@@ -30,28 +29,16 @@ typedef struct {
typedef struct {
HWVoiceOut hw;
- size_t done;
- size_t live;
- size_t decr;
- size_t rpos;
pa_stream *stream;
- void *pcm_buf;
- struct audio_pt pt;
paaudio *g;
size_t samples;
} PAVoiceOut;
typedef struct {
HWVoiceIn hw;
- size_t done;
- size_t dead;
- size_t incr;
- size_t wpos;
pa_stream *stream;
- void *pcm_buf;
- struct audio_pt pt;
const void *read_data;
- size_t read_index, read_length;
+ size_t read_length;
paaudio *g;
size_t samples;
} PAVoiceIn;
@@ -89,298 +76,96 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
}
#endif
-#define CHECK_SUCCESS_GOTO(c, rerror, expression, label) \
+#define CHECK_SUCCESS_GOTO(c, expression, label, msg) \
do { \
if (!(expression)) { \
- if (rerror) { \
- *(rerror) = pa_context_errno ((c)->context); \
- } \
+ qpa_logerr(pa_context_errno((c)->context), msg); \
goto label; \
} \
} while (0)
-#define CHECK_DEAD_GOTO(c, stream, rerror, label) \
+#define CHECK_DEAD_GOTO(c, stream, label, msg) \
do { \
if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \
!(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \
if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \
((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \
- if (rerror) { \
- *(rerror) = pa_context_errno ((c)->context); \
- } \
+ qpa_logerr(pa_context_errno((c)->context), msg); \
} else { \
- if (rerror) { \
- *(rerror) = PA_ERR_BADSTATE; \
- } \
+ qpa_logerr(PA_ERR_BADSTATE, msg); \
} \
goto label; \
} \
} while (0)
-static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror)
+static size_t qpa_read(HWVoiceIn *hw, void *data, size_t length)
{
+ PAVoiceIn *p = (PAVoiceIn *) hw;
PAConnection *c = p->g->conn;
+ size_t l;
+ int r;
pa_threaded_mainloop_lock(c->mainloop);
- CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
-
- while (length > 0) {
- size_t l;
-
- while (!p->read_data) {
- int r;
+ CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
+ "pa_threaded_mainloop_lock failed\n");
- r = pa_stream_peek (p->stream, &p->read_data, &p->read_length);
- CHECK_SUCCESS_GOTO(c, rerror, r == 0, unlock_and_fail);
-
- if (!p->read_data) {
- pa_threaded_mainloop_wait(c->mainloop);
- CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
- } else {
- p->read_index = 0;
- }
- }
-
- l = p->read_length < length ? p->read_length : length;
- memcpy (data, (const uint8_t *) p->read_data+p->read_index, l);
-
- data = (uint8_t *) data + l;
- length -= l;
-
- p->read_index += l;
- p->read_length -= l;
+ if (!p->read_length) {
+ r = pa_stream_peek(p->stream, &p->read_data, &p->read_length);
+ CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
+ "pa_stream_peek failed\n");
+ }
- if (!p->read_length) {
- int r;
+ l = MIN(p->read_length, length);
+ memcpy(data, p->read_data, l);
- r = pa_stream_drop (p->stream);
- p->read_data = NULL;
- p->read_length = 0;
- p->read_index = 0;
+ p->read_data += l;
+ p->read_length -= l;
- CHECK_SUCCESS_GOTO(c, rerror, r == 0, unlock_and_fail);
- }
+ if (!p->read_length) {
+ r = pa_stream_drop(p->stream);
+ CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
+ "pa_stream_drop failed\n");
}
pa_threaded_mainloop_unlock(c->mainloop);
- return 0;
+ return l;
unlock_and_fail:
pa_threaded_mainloop_unlock(c->mainloop);
- return -1;
+ return 0;
}
-static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
+static size_t qpa_write(HWVoiceOut *hw, void *data, size_t length)
{
+ PAVoiceOut *p = (PAVoiceOut *) hw;
PAConnection *c = p->g->conn;
+ size_t l;
+ int r;
pa_threaded_mainloop_lock(c->mainloop);
- CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
-
- while (length > 0) {
- size_t l;
- int r;
-
- while (!(l = pa_stream_writable_size (p->stream))) {
- pa_threaded_mainloop_wait(c->mainloop);
- CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
- }
-
- CHECK_SUCCESS_GOTO(c, rerror, l != (size_t) -1, unlock_and_fail);
+ CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
+ "pa_threaded_mainloop_lock failed\n");
- if (l > length) {
- l = length;
- }
+ l = pa_stream_writable_size(p->stream);
- r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
- CHECK_SUCCESS_GOTO(c, rerror, r >= 0, unlock_and_fail);
+ CHECK_SUCCESS_GOTO(c, l != (size_t) -1, unlock_and_fail,
+ "pa_stream_writable_size failed\n");
- data = (const uint8_t *) data + l;
- length -= l;
+ if (l > length) {
+ l = length;
}
+ r = pa_stream_write(p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
+ CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail, "pa_stream_write failed\n");
+
pa_threaded_mainloop_unlock(c->mainloop);
- return 0;
+ return l;
unlock_and_fail:
pa_threaded_mainloop_unlock(c->mainloop);
- return -1;
-}
-
-static void *qpa_thread_out (void *arg)
-{
- PAVoiceOut *pa = arg;
- HWVoiceOut *hw = &pa->hw;
-
- if (audio_pt_lock(&pa->pt, __func__)) {
- return NULL;
- }
-
- for (;;) {
- size_t decr, to_mix, rpos;
-
- for (;;) {
- if (pa->done) {
- goto exit;
- }
-
- if (pa->live > 0) {
- break;
- }
-
- if (audio_pt_wait(&pa->pt, __func__)) {
- goto exit;
- }
- }
-
- decr = to_mix = MIN(pa->live, pa->samples >> 5);
- rpos = pa->rpos;
-
- if (audio_pt_unlock(&pa->pt, __func__)) {
- return NULL;
- }
-
- while (to_mix) {
- int error;
- size_t chunk = MIN (to_mix, hw->samples - rpos);
- struct st_sample *src = hw->mix_buf + rpos;
-
- hw->clip (pa->pcm_buf, src, chunk);
-
- if (qpa_simple_write (pa, pa->pcm_buf,
- chunk << hw->info.shift, &error) < 0) {
- qpa_logerr (error, "pa_simple_write failed\n");
- return NULL;
- }
-
- rpos = (rpos + chunk) % hw->samples;
- to_mix -= chunk;
- }
-
- if (audio_pt_lock(&pa->pt, __func__)) {
- return NULL;
- }
-
- pa->rpos = rpos;
- pa->live -= decr;
- pa->decr += decr;
- }
-
- exit:
- audio_pt_unlock(&pa->pt, __func__);
- return NULL;
-}
-
-static size_t qpa_run_out(HWVoiceOut *hw, size_t live)
-{
- size_t decr;
- PAVoiceOut *pa = (PAVoiceOut *) hw;
-
- if (audio_pt_lock(&pa->pt, __func__)) {
- return 0;
- }
-
- decr = MIN (live, pa->decr);
- pa->decr -= decr;
- pa->live = live - decr;
- hw->rpos = pa->rpos;
- if (pa->live > 0) {
- audio_pt_unlock_and_signal(&pa->pt, __func__);
- }
- else {
- audio_pt_unlock(&pa->pt, __func__);
- }
- return decr;
-}
-
-/* capture */
-static void *qpa_thread_in (void *arg)
-{
- PAVoiceIn *pa = arg;
- HWVoiceIn *hw = &pa->hw;
-
- if (audio_pt_lock(&pa->pt, __func__)) {
- return NULL;
- }
-
- for (;;) {
- size_t incr, to_grab, wpos;
-
- for (;;) {
- if (pa->done) {
- goto exit;
- }
-
- if (pa->dead > 0) {
- break;
- }
-
- if (audio_pt_wait(&pa->pt, __func__)) {
- goto exit;
- }
- }
-
- incr = to_grab = MIN(pa->dead, pa->samples >> 5);
- wpos = pa->wpos;
-
- if (audio_pt_unlock(&pa->pt, __func__)) {
- return NULL;
- }
-
- while (to_grab) {
- int error;
- size_t chunk = MIN (to_grab, hw->samples - wpos);
- void *buf = advance (pa->pcm_buf, wpos);
-
- if (qpa_simple_read (pa, buf,
- chunk << hw->info.shift, &error) < 0) {
- qpa_logerr (error, "pa_simple_read failed\n");
- return NULL;
- }
-
- hw->conv (hw->conv_buf + wpos, buf, chunk);
- wpos = (wpos + chunk) % hw->samples;
- to_grab -= chunk;
- }
-
- if (audio_pt_lock(&pa->pt, __func__)) {
- return NULL;
- }
-
- pa->wpos = wpos;
- pa->dead -= incr;
- pa->incr += incr;
- }
-
- exit:
- audio_pt_unlock(&pa->pt, __func__);
- return NULL;
-}
-
-static size_t qpa_run_in(HWVoiceIn *hw)
-{
- size_t live, incr, dead;
- PAVoiceIn *pa = (PAVoiceIn *) hw;
-
- if (audio_pt_lock(&pa->pt, __func__)) {
- return 0;
- }
-
- live = audio_pcm_hw_get_live_in (hw);
- dead = hw->samples - live;
- incr = MIN (dead, pa->incr);
- pa->incr -= incr;
- pa->dead = dead - incr;
- hw->wpos = pa->wpos;
- if (pa->dead > 0) {
- audio_pt_unlock_and_signal(&pa->pt, __func__);
- }
- else {
- audio_pt_unlock(&pa->pt, __func__);
- }
- return incr;
+ return 0;
}
static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness)
@@ -468,13 +253,6 @@ static void stream_state_cb (pa_stream *s, void * userdata)
}
}
-static void stream_request_cb (pa_stream *s, size_t length, void *userdata)
-{
- PAConnection *c = userdata;
-
- pa_threaded_mainloop_signal(c->mainloop, 0);
-}
-
static pa_stream *qpa_simple_new (
PAConnection *c,
const char *name,
@@ -497,8 +275,6 @@ static pa_stream *qpa_simple_new (
}
pa_stream_set_state_callback(stream, stream_state_cb, c);
- pa_stream_set_read_callback(stream, stream_request_cb, c);
- pa_stream_set_write_callback(stream, stream_request_cb, c);
flags =
PA_STREAM_INTERPOLATE_TIMING
@@ -579,28 +355,9 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
hw->samples = pa->samples = audio_buffer_samples(
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
&obt_as, ppdo->buffer_length);
- pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
- pa->rpos = hw->rpos;
- if (!pa->pcm_buf) {
- dolog("Could not allocate buffer (%zu bytes)\n",
- hw->samples << hw->info.shift);
- goto fail2;
- }
-
- if (audio_pt_init(&pa->pt, qpa_thread_out, hw, AUDIO_CAP, __func__)) {
- goto fail3;
- }
return 0;
- fail3:
- g_free (pa->pcm_buf);
- pa->pcm_buf = NULL;
- fail2:
- if (pa->stream) {
- pa_stream_unref (pa->stream);
- pa->stream = NULL;
- }
fail1:
return -1;
}
@@ -647,28 +404,9 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
hw->samples = pa->samples = audio_buffer_samples(
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
&obt_as, ppdo->buffer_length);
- pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
- pa->wpos = hw->wpos;
- if (!pa->pcm_buf) {
- dolog("Could not allocate buffer (%zu bytes)\n",
- hw->samples << hw->info.shift);
- goto fail2;
- }
-
- if (audio_pt_init(&pa->pt, qpa_thread_in, hw, AUDIO_CAP, __func__)) {
- goto fail3;
- }
return 0;
- fail3:
- g_free (pa->pcm_buf);
- pa->pcm_buf = NULL;
- fail2:
- if (pa->stream) {
- pa_stream_unref (pa->stream);
- pa->stream = NULL;
- }
fail1:
return -1;
}
@@ -696,45 +434,25 @@ static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream)
static void qpa_fini_out (HWVoiceOut *hw)
{
- void *ret;
PAVoiceOut *pa = (PAVoiceOut *) hw;
- audio_pt_lock(&pa->pt, __func__);
- pa->done = 1;
- audio_pt_unlock_and_signal(&pa->pt, __func__);
- audio_pt_join(&pa->pt, &ret, __func__);
-
if (pa->stream) {
qpa_simple_disconnect(pa->g->conn, pa->stream);
pa->stream = NULL;
}
-
- audio_pt_fini(&pa->pt, __func__);
- g_free (pa->pcm_buf);
- pa->pcm_buf = NULL;
}
static void qpa_fini_in (HWVoiceIn *hw)
{
- void *ret;
PAVoiceIn *pa = (PAVoiceIn *) hw;
- audio_pt_lock(&pa->pt, __func__);
- pa->done = 1;
- audio_pt_unlock_and_signal(&pa->pt, __func__);
- audio_pt_join(&pa->pt, &ret, __func__);
-
if (pa->stream) {
qpa_simple_disconnect(pa->g->conn, pa->stream);
pa->stream = NULL;
}
-
- audio_pt_fini(&pa->pt, __func__);
- g_free (pa->pcm_buf);
- pa->pcm_buf = NULL;
}
-static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
+static void qpa_volume_out(HWVoiceOut *hw, struct mixeng_volume *vol)
{
PAVoiceOut *pa = (PAVoiceOut *) hw;
pa_operation *op;
@@ -745,49 +463,36 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
pa_cvolume_init (&v); /* function is present in 0.9.13+ */
#endif
- switch (cmd) {
- case VOICE_VOLUME:
- {
- SWVoiceOut *sw;
- va_list ap;
-
- va_start (ap, cmd);
- sw = va_arg (ap, SWVoiceOut *);
- va_end (ap);
-
- v.channels = 2;
- v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
- v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
-
- pa_threaded_mainloop_lock(c->mainloop);
-
- op = pa_context_set_sink_input_volume(c->context,
- pa_stream_get_index (pa->stream),
- &v, NULL, NULL);
- if (!op) {
- qpa_logerr(pa_context_errno(c->context),
- "set_sink_input_volume() failed\n");
- } else {
- pa_operation_unref(op);
- }
-
- op = pa_context_set_sink_input_mute(c->context,
- pa_stream_get_index (pa->stream),
- sw->vol.mute, NULL, NULL);
- if (!op) {
- qpa_logerr(pa_context_errno(c->context),
- "set_sink_input_mute() failed\n");
- } else {
- pa_operation_unref(op);
- }
-
- pa_threaded_mainloop_unlock(c->mainloop);
- }
+ v.channels = 2;
+ v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->l) / UINT32_MAX;
+ v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->r) / UINT32_MAX;
+
+ pa_threaded_mainloop_lock(c->mainloop);
+
+ op = pa_context_set_sink_input_volume(c->context,
+ pa_stream_get_index(pa->stream),
+ &v, NULL, NULL);
+ if (!op) {
+ qpa_logerr(pa_context_errno(c->context),
+ "set_sink_input_volume() failed\n");
+ } else {
+ pa_operation_unref(op);
}
- return 0;
+
+ op = pa_context_set_sink_input_mute(c->context,
+ pa_stream_get_index(pa->stream),
+ vol->mute, NULL, NULL);
+ if (!op) {
+ qpa_logerr(pa_context_errno(c->context),
+ "set_sink_input_mute() failed\n");
+ } else {
+ pa_operation_unref(op);
+ }
+
+ pa_threaded_mainloop_unlock(c->mainloop);
}
-static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
+static void qpa_volume_in(HWVoiceIn *hw, struct mixeng_volume *vol)
{
PAVoiceIn *pa = (PAVoiceIn *) hw;
pa_operation *op;
@@ -798,46 +503,33 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
pa_cvolume_init (&v);
#endif
- switch (cmd) {
- case VOICE_VOLUME:
- {
- SWVoiceIn *sw;
- va_list ap;
-
- va_start (ap, cmd);
- sw = va_arg (ap, SWVoiceIn *);
- va_end (ap);
-
- v.channels = 2;
- v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
- v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
-
- pa_threaded_mainloop_lock(c->mainloop);
-
- op = pa_context_set_source_output_volume(c->context,
- pa_stream_get_index(pa->stream),
- &v, NULL, NULL);
- if (!op) {
- qpa_logerr(pa_context_errno(c->context),
- "set_source_output_volume() failed\n");
- } else {
- pa_operation_unref(op);
- }
-
- op = pa_context_set_source_output_mute(c->context,
- pa_stream_get_index (pa->stream),
- sw->vol.mute, NULL, NULL);
- if (!op) {
- qpa_logerr(pa_context_errno(c->context),
- "set_source_output_mute() failed\n");
- } else {
- pa_operation_unref (op);
- }
-
- pa_threaded_mainloop_unlock(c->mainloop);
- }
+ v.channels = 2;
+ v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->l) / UINT32_MAX;
+ v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->r) / UINT32_MAX;
+
+ pa_threaded_mainloop_lock(c->mainloop);
+
+ op = pa_context_set_source_output_volume(c->context,
+ pa_stream_get_index(pa->stream),
+ &v, NULL, NULL);
+ if (!op) {
+ qpa_logerr(pa_context_errno(c->context),
+ "set_source_output_volume() failed\n");
+ } else {
+ pa_operation_unref(op);
}
- return 0;
+
+ op = pa_context_set_source_output_mute(c->context,
+ pa_stream_get_index(pa->stream),
+ vol->mute, NULL, NULL);
+ if (!op) {
+ qpa_logerr(pa_context_errno(c->context),
+ "set_source_output_mute() failed\n");
+ } else {
+ pa_operation_unref(op);
+ }
+
+ pa_threaded_mainloop_unlock(c->mainloop);
}
static int qpa_validate_per_direction_opts(Audiodev *dev,
@@ -1005,13 +697,13 @@ static void qpa_audio_fini (void *opaque)
static struct audio_pcm_ops qpa_pcm_ops = {
.init_out = qpa_init_out,
.fini_out = qpa_fini_out,
- .run_out = qpa_run_out,
- .ctl_out = qpa_ctl_out,
+ .write = qpa_write,
+ .volume_out = qpa_volume_out,
.init_in = qpa_init_in,
.fini_in = qpa_fini_in,
- .run_in = qpa_run_in,
- .ctl_in = qpa_ctl_in
+ .read = qpa_read,
+ .volume_in = qpa_volume_in
};
static struct audio_driver pa_audio_driver = {
@@ -1025,7 +717,6 @@ static struct audio_driver pa_audio_driver = {
.max_voices_in = INT_MAX,
.voice_size_out = sizeof (PAVoiceOut),
.voice_size_in = sizeof (PAVoiceIn),
- .ctl_caps = VOICE_VOLUME_CAP
};
static void register_audio_pa(void)
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index 14b11f0335..5c6bcfcb3e 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -41,8 +41,6 @@
typedef struct SDLVoiceOut {
HWVoiceOut hw;
- size_t live;
- size_t decr;
} SDLVoiceOut;
static struct SDLAudioState {
@@ -184,62 +182,59 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
SDLVoiceOut *sdl = opaque;
SDLAudioState *s = &glob_sdl;
HWVoiceOut *hw = &sdl->hw;
- size_t samples = len >> hw->info.shift;
- size_t to_mix, decr;
- if (s->exit || !sdl->live) {
+ if (s->exit) {
return;
}
/* dolog ("in callback samples=%zu live=%zu\n", samples, sdl->live); */
- to_mix = MIN(samples, sdl->live);
- decr = to_mix;
- while (to_mix) {
- size_t chunk = MIN(to_mix, hw->samples - hw->rpos);
- struct st_sample *src = hw->mix_buf + hw->rpos;
-
- /* dolog ("in callback to_mix %zu, chunk %zu\n", to_mix, chunk); */
- hw->clip(buf, src, chunk);
- hw->rpos = (hw->rpos + chunk) % hw->samples;
- to_mix -= chunk;
- buf += chunk << hw->info.shift;
+ while (hw->pending_emul && len) {
+ size_t write_len;
+ ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
+ if (start < 0) {
+ start += hw->size_emul;
+ }
+ assert(start >= 0 && start < hw->size_emul);
+
+ write_len = MIN(MIN(hw->pending_emul, len),
+ hw->size_emul - start);
+
+ memcpy(buf, hw->buf_emul + start, write_len);
+ hw->pending_emul -= write_len;
+ len -= write_len;
+ buf += write_len;
}
- samples -= decr;
- sdl->live -= decr;
- sdl->decr += decr;
- /* dolog ("done len=%zu\n", len); */
-
- /* SDL2 does not clear the remaining buffer for us, so do it on our own */
- if (samples) {
- memset(buf, 0, samples << hw->info.shift);
+ /* clear remaining buffer that we couldn't fill with data */
+ if (len) {
+ memset(buf, 0, len);
}
}
-static size_t sdl_run_out(HWVoiceOut *hw, size_t live)
-{
- size_t decr;
- SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
-
- SDL_LockAudio();
-
- if (sdl->decr > live) {
- ldebug ("sdl->decr %d live %d sdl->live %d\n",
- sdl->decr,
- live,
- sdl->live);
+#define SDL_WRAPPER_FUNC(name, ret_type, args_decl, args, fail, unlock) \
+ static ret_type glue(sdl_, name)args_decl \
+ { \
+ ret_type ret; \
+ \
+ SDL_LockAudio(); \
+ \
+ ret = glue(audio_generic_, name)args; \
+ \
+ SDL_UnlockAudio(); \
+ return ret; \
}
- decr = MIN (sdl->decr, live);
- sdl->decr -= decr;
-
- sdl->live = live;
+SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
+ (hw, size), *size = 0, sdl_unlock)
+SDL_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
+ (HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size),
+ /*nothing*/, sdl_unlock_and_post)
+SDL_WRAPPER_FUNC(write, size_t,
+ (HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size),
+ /*nothing*/, sdl_unlock_and_post)
- SDL_UnlockAudio();
-
- return decr;
-}
+#undef SDL_WRAPPER_FUNC
static void sdl_fini_out (HWVoiceOut *hw)
{
@@ -290,20 +285,9 @@ static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as,
return 0;
}
-static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
+static void sdl_enable_out(HWVoiceOut *hw, bool enable)
{
- (void) hw;
-
- switch (cmd) {
- case VOICE_ENABLE:
- SDL_PauseAudio (0);
- break;
-
- case VOICE_DISABLE:
- SDL_PauseAudio (1);
- break;
- }
- return 0;
+ SDL_PauseAudio(!enable);
}
static void *sdl_audio_init(Audiodev *dev)
@@ -336,8 +320,10 @@ static void sdl_audio_fini (void *opaque)
static struct audio_pcm_ops sdl_pcm_ops = {
.init_out = sdl_init_out,
.fini_out = sdl_fini_out,
- .run_out = sdl_run_out,
- .ctl_out = sdl_ctl_out,
+ .write = sdl_write,
+ .get_buffer_out = sdl_get_buffer_out,
+ .put_buffer_out = sdl_put_buffer_out_nowrite,
+ .enable_out = sdl_enable_out,
};
static struct audio_driver sdl_audio_driver = {
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index 26873c7f22..9860f9c5e1 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -40,27 +40,21 @@
#define LINE_IN_SAMPLES (256 * 4)
#endif
-typedef struct SpiceRateCtl {
- int64_t start_ticks;
- int64_t bytes_sent;
-} SpiceRateCtl;
-
typedef struct SpiceVoiceOut {
HWVoiceOut hw;
SpicePlaybackInstance sin;
- SpiceRateCtl rate;
+ RateCtl rate;
int active;
uint32_t *frame;
- uint32_t *fpos;
+ uint32_t fpos;
uint32_t fsize;
} SpiceVoiceOut;
typedef struct SpiceVoiceIn {
HWVoiceIn hw;
SpiceRecordInstance sin;
- SpiceRateCtl rate;
+ RateCtl rate;
int active;
- uint32_t samples[LINE_IN_SAMPLES];
} SpiceVoiceIn;
static const SpicePlaybackInterface playback_sif = {
@@ -90,32 +84,6 @@ static void spice_audio_fini (void *opaque)
/* nothing */
}
-static void rate_start (SpiceRateCtl *rate)
-{
- memset (rate, 0, sizeof (*rate));
- rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-}
-
-static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate)
-{
- int64_t now;
- int64_t ticks;
- int64_t bytes;
- int64_t samples;
-
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ticks = now - rate->start_ticks;
- bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND);
- samples = (bytes - rate->bytes_sent) >> info->shift;
- if (samples < 0 || samples > 65536) {
- error_report("Resetting rate control (%" PRId64 " samples)", samples);
- rate_start(rate);
- samples = 0;
- }
- rate->bytes_sent += samples << info->shift;
- return samples;
-}
-
/* playback */
static int line_out_init(HWVoiceOut *hw, struct audsettings *as,
@@ -152,93 +120,76 @@ static void line_out_fini (HWVoiceOut *hw)
spice_server_remove_interface (&out->sin.base);
}
-static size_t line_out_run (HWVoiceOut *hw, size_t live)
+static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size)
{
- SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
- size_t rpos, decr;
- size_t samples;
+ SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
- if (!live) {
- return 0;
+ if (!out->frame) {
+ spice_server_playback_get_buffer(&out->sin, &out->frame, &out->fsize);
+ out->fpos = 0;
}
- decr = rate_get_samples (&hw->info, &out->rate);
- decr = MIN (live, decr);
+ if (out->frame) {
+ *size = audio_rate_get_bytes(
+ &hw->info, &out->rate, (out->fsize - out->fpos) << hw->info.shift);
+ } else {
+ audio_rate_start(&out->rate);
+ }
+ return out->frame + out->fpos;
+}
- samples = decr;
- rpos = hw->rpos;
- while (samples) {
- int left_till_end_samples = hw->samples - rpos;
- int len = MIN (samples, left_till_end_samples);
+static size_t line_out_put_buffer(HWVoiceOut *hw, void *buf, size_t size)
+{
+ SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
- if (!out->frame) {
- spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize);
- out->fpos = out->frame;
- }
- if (out->frame) {
- len = MIN (len, out->fsize);
- hw->clip (out->fpos, hw->mix_buf + rpos, len);
- out->fsize -= len;
- out->fpos += len;
- if (out->fsize == 0) {
- spice_server_playback_put_samples (&out->sin, out->frame);
- out->frame = out->fpos = NULL;
- }
- }
- rpos = (rpos + len) % hw->samples;
- samples -= len;
+ assert(buf == out->frame + out->fpos && out->fpos <= out->fsize);
+ out->fpos += size >> 2;
+
+ if (out->fpos == out->fsize) { /* buffer full */
+ spice_server_playback_put_samples(&out->sin, out->frame);
+ out->frame = NULL;
}
- hw->rpos = rpos;
- return decr;
+
+ return size;
}
-static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
+static void line_out_enable(HWVoiceOut *hw, bool enable)
{
SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
- switch (cmd) {
- case VOICE_ENABLE:
+ if (enable) {
if (out->active) {
- break;
+ return;
}
out->active = 1;
- rate_start (&out->rate);
+ audio_rate_start(&out->rate);
spice_server_playback_start (&out->sin);
- break;
- case VOICE_DISABLE:
+ } else {
if (!out->active) {
- break;
+ return;
}
out->active = 0;
if (out->frame) {
- memset (out->fpos, 0, out->fsize << 2);
+ memset(out->frame + out->fpos, 0, (out->fsize - out->fpos) << 2);
spice_server_playback_put_samples (&out->sin, out->frame);
- out->frame = out->fpos = NULL;
+ out->frame = NULL;
}
spice_server_playback_stop (&out->sin);
- break;
- case VOICE_VOLUME:
- {
-#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
- SWVoiceOut *sw;
- va_list ap;
- uint16_t vol[2];
-
- va_start (ap, cmd);
- sw = va_arg (ap, SWVoiceOut *);
- va_end (ap);
-
- vol[0] = sw->vol.l / ((1ULL << 16) + 1);
- vol[1] = sw->vol.r / ((1ULL << 16) + 1);
- spice_server_playback_set_volume (&out->sin, 2, vol);
- spice_server_playback_set_mute (&out->sin, sw->vol.mute);
-#endif
- break;
- }
}
+}
- return 0;
+#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
+static void line_out_volume(HWVoiceOut *hw, struct mixeng_volume *vol)
+{
+ SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
+ uint16_t svol[2];
+
+ svol[0] = vol->l / ((1ULL << 16) + 1);
+ svol[1] = vol->r / ((1ULL << 16) + 1);
+ spice_server_playback_set_volume(&out->sin, 2, svol);
+ spice_server_playback_set_mute(&out->sin, vol->mute);
}
+#endif
/* record */
@@ -275,104 +226,73 @@ static void line_in_fini (HWVoiceIn *hw)
spice_server_remove_interface (&in->sin.base);
}
-static size_t line_in_run(HWVoiceIn *hw)
+static size_t line_in_read(HWVoiceIn *hw, void *buf, size_t len)
{
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
- size_t num_samples;
- int ready;
- size_t len[2];
- uint64_t delta_samp;
- const uint32_t *samples;
-
- if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in (hw))) {
- return 0;
- }
+ uint64_t to_read = audio_rate_get_bytes(&hw->info, &in->rate, len) >> 2;
+ size_t ready = spice_server_record_get_samples(&in->sin, buf, to_read);
- delta_samp = rate_get_samples (&hw->info, &in->rate);
- num_samples = MIN (num_samples, delta_samp);
-
- ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples);
- samples = in->samples;
+ /* XXX: do we need this? */
if (ready == 0) {
- static const uint32_t silence[LINE_IN_SAMPLES];
- samples = silence;
- ready = LINE_IN_SAMPLES;
- }
-
- num_samples = MIN (ready, num_samples);
-
- if (hw->wpos + num_samples > hw->samples) {
- len[0] = hw->samples - hw->wpos;
- len[1] = num_samples - len[0];
- } else {
- len[0] = num_samples;
- len[1] = 0;
+ memset(buf, 0, to_read << 2);
+ ready = to_read;
}
- hw->conv (hw->conv_buf + hw->wpos, samples, len[0]);
-
- if (len[1]) {
- hw->conv (hw->conv_buf, samples + len[0], len[1]);
- }
-
- hw->wpos = (hw->wpos + num_samples) % hw->samples;
-
- return num_samples;
+ return ready << 2;
}
-static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
+static void line_in_enable(HWVoiceIn *hw, bool enable)
{
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
- switch (cmd) {
- case VOICE_ENABLE:
+ if (enable) {
if (in->active) {
- break;
+ return;
}
in->active = 1;
- rate_start (&in->rate);
+ audio_rate_start(&in->rate);
spice_server_record_start (&in->sin);
- break;
- case VOICE_DISABLE:
+ } else {
if (!in->active) {
- break;
+ return;
}
in->active = 0;
spice_server_record_stop (&in->sin);
- break;
- case VOICE_VOLUME:
- {
-#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2))
- SWVoiceIn *sw;
- va_list ap;
- uint16_t vol[2];
-
- va_start (ap, cmd);
- sw = va_arg (ap, SWVoiceIn *);
- va_end (ap);
-
- vol[0] = sw->vol.l / ((1ULL << 16) + 1);
- vol[1] = sw->vol.r / ((1ULL << 16) + 1);
- spice_server_record_set_volume (&in->sin, 2, vol);
- spice_server_record_set_mute (&in->sin, sw->vol.mute);
-#endif
- break;
- }
}
+}
- return 0;
+#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2))
+static void line_in_volume(HWVoiceIn *hw, struct mixeng_volume *vol)
+{
+ SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw);
+ uint16_t svol[2];
+
+ svol[0] = vol->l / ((1ULL << 16) + 1);
+ svol[1] = vol->r / ((1ULL << 16) + 1);
+ spice_server_record_set_volume(&in->sin, 2, svol);
+ spice_server_record_set_mute(&in->sin, vol->mute);
}
+#endif
static struct audio_pcm_ops audio_callbacks = {
.init_out = line_out_init,
.fini_out = line_out_fini,
- .run_out = line_out_run,
- .ctl_out = line_out_ctl,
+ .write = audio_generic_write,
+ .get_buffer_out = line_out_get_buffer,
+ .put_buffer_out = line_out_put_buffer,
+ .enable_out = line_out_enable,
+#if (SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && \
+ (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)
+ .volume_out = line_out_volume,
+#endif
.init_in = line_in_init,
.fini_in = line_in_fini,
- .run_in = line_in_run,
- .ctl_in = line_in_ctl,
+ .read = line_in_read,
+ .enable_in = line_in_enable,
+#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2))
+ .volume_in = line_in_volume,
+#endif
};
static struct audio_driver spice_audio_driver = {
@@ -385,9 +305,6 @@ static struct audio_driver spice_audio_driver = {
.max_voices_in = 1,
.voice_size_out = sizeof (SpiceVoiceOut),
.voice_size_in = sizeof (SpiceVoiceIn),
-#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
- .ctl_caps = VOICE_VOLUME_CAP
-#endif
};
void qemu_spice_audio_init (void)
diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index b6eeeb4e26..47efdc1b1e 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -35,53 +35,23 @@
typedef struct WAVVoiceOut {
HWVoiceOut hw;
FILE *f;
- int64_t old_ticks;
- void *pcm_buf;
+ RateCtl rate;
int total_samples;
} WAVVoiceOut;
-static size_t wav_run_out(HWVoiceOut *hw, size_t live)
+static size_t wav_write_out(HWVoiceOut *hw, void *buf, size_t len)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
- size_t rpos, decr, samples;
- uint8_t *dst;
- struct st_sample *src;
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- int64_t ticks = now - wav->old_ticks;
- int64_t bytes =
- muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
+ int64_t bytes = audio_rate_get_bytes(&hw->info, &wav->rate, len);
+ assert(bytes >> hw->info.shift << hw->info.shift == bytes);
- if (bytes > INT_MAX) {
- samples = INT_MAX >> hw->info.shift;
+ if (bytes && fwrite(buf, bytes, 1, wav->f) != 1) {
+ dolog("wav_write_out: fwrite of %" PRId64 " bytes failed\nReason: %s\n",
+ bytes, strerror(errno));
}
- else {
- samples = bytes >> hw->info.shift;
- }
-
- wav->old_ticks = now;
- decr = MIN (live, samples);
- samples = decr;
- rpos = hw->rpos;
- while (samples) {
- int left_till_end_samples = hw->samples - rpos;
- int convert_samples = MIN (samples, left_till_end_samples);
-
- src = hw->mix_buf + rpos;
- dst = advance (wav->pcm_buf, rpos << hw->info.shift);
-
- hw->clip (dst, src, convert_samples);
- if (fwrite (dst, convert_samples << hw->info.shift, 1, wav->f) != 1) {
- dolog ("wav_run_out: fwrite of %d bytes failed\nReaons: %s\n",
- convert_samples << hw->info.shift, strerror (errno));
- }
- rpos = (rpos + convert_samples) % hw->samples;
- samples -= convert_samples;
- wav->total_samples += convert_samples;
- }
-
- hw->rpos = rpos;
- return decr;
+ wav->total_samples += bytes >> hw->info.shift;
+ return bytes;
}
/* VICE code: Store number as little endian. */
@@ -137,13 +107,6 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as,
audio_pcm_init_info (&hw->info, &wav_as);
hw->samples = 1024;
- wav->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
- if (!wav->pcm_buf) {
- dolog("Could not allocate buffer (%zu bytes)\n",
- hw->samples << hw->info.shift);
- return -1;
- }
-
le_store (hdr + 22, hw->info.nchannels, 2);
le_store (hdr + 24, hw->info.freq, 4);
le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
@@ -153,8 +116,6 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as,
if (!wav->f) {
dolog ("Failed to open wave file `%s'\nReason: %s\n",
wav_path, strerror(errno));
- g_free (wav->pcm_buf);
- wav->pcm_buf = NULL;
return -1;
}
@@ -163,6 +124,8 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as,
strerror(errno));
return -1;
}
+
+ audio_rate_start(&wav->rate);
return 0;
}
@@ -208,16 +171,15 @@ static void wav_fini_out (HWVoiceOut *hw)
wav->f, strerror (errno));
}
wav->f = NULL;
-
- g_free (wav->pcm_buf);
- wav->pcm_buf = NULL;
}
-static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
+static void wav_enable_out(HWVoiceOut *hw, bool enable)
{
- (void) hw;
- (void) cmd;
- return 0;
+ WAVVoiceOut *wav = (WAVVoiceOut *) hw;
+
+ if (enable) {
+ audio_rate_start(&wav->rate);
+ }
}
static void *wav_audio_init(Audiodev *dev)
@@ -234,8 +196,8 @@ static void wav_audio_fini (void *opaque)
static struct audio_pcm_ops wav_pcm_ops = {
.init_out = wav_init_out,
.fini_out = wav_fini_out,
- .run_out = wav_run_out,
- .ctl_out = wav_ctl_out,
+ .write = wav_write_out,
+ .enable_out = wav_enable_out,
};
static struct audio_driver wav_audio_driver = {
diff --git a/configure b/configure
index 30544f52e6..397bb476e1 100755
--- a/configure
+++ b/configure
@@ -297,7 +297,6 @@ host_cc="cc"
libs_cpu=""
libs_softmmu=""
libs_tools=""
-audio_pt_int=""
audio_win_int=""
libs_qga=""
debug_info="yes"
@@ -3388,7 +3387,6 @@ for drv in $audio_drv_list; do
pa | try-pa)
if $pkg_config libpulse --exists; then
pulse_libs=$($pkg_config libpulse --libs)
- audio_pt_int="yes"
if test "$drv" = "try-pa"; then
audio_drv_list=$(echo "$audio_drv_list" | sed -e 's/try-pa/pa/')
fi
@@ -6611,9 +6609,6 @@ echo "PULSE_LIBS=$pulse_libs" >> $config_host_mak
echo "COREAUDIO_LIBS=$coreaudio_libs" >> $config_host_mak
echo "DSOUND_LIBS=$dsound_libs" >> $config_host_mak
echo "OSS_LIBS=$oss_libs" >> $config_host_mak
-if test "$audio_pt_int" = "yes" ; then
- echo "CONFIG_AUDIO_PT_INT=y" >> $config_host_mak
-fi
if test "$audio_win_int" = "yes" ; then
echo "CONFIG_AUDIO_WIN_INT=y" >> $config_host_mak
fi
diff --git a/qemu-options.hx b/qemu-options.hx
index 618a57d409..2a04ca6ac5 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -439,13 +439,13 @@ DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev,
" in|out.format= sample format to use with fixed settings\n"
" valid values: s8, s16, s32, u8, u16, u32\n"
" in|out.voices= number of voices to use\n"
- " in|out.buffer-len= length of buffer in microseconds\n"
+ " in|out.buffer-length= length of buffer in microseconds\n"
"-audiodev none,id=id,[,prop[=value][,...]]\n"
" dummy driver that discards all output\n"
#ifdef CONFIG_AUDIO_ALSA
"-audiodev alsa,id=id[,prop[=value][,...]]\n"
" in|out.dev= name of the audio device to use\n"
- " in|out.period-len= length of period in microseconds\n"
+ " in|out.period-length= length of period in microseconds\n"
" in|out.try-poll= attempt to use poll mode\n"
" threshold= threshold (in microseconds) when playback starts\n"
#endif
@@ -524,7 +524,7 @@ Valid values are: @code{s8}, @code{s16}, @code{s32}, @code{u8},
@item in|out.voices=@var{voices}
Specify the number of @var{voices} to use. Default is 1.
-@item in|out.buffer=@var{usecs}
+@item in|out.buffer-length=@var{usecs}
Sets the size of the buffer in microseconds.
@end table
@@ -545,7 +545,7 @@ ALSA specific options are:
Specify the ALSA @var{device} to use for input and/or output. Default
is @code{default}.
-@item in|out.period-len=@var{usecs}
+@item in|out.period-length=@var{usecs}
Sets the period length in microseconds.
@item in|out.try-poll=on|off