aboutsummaryrefslogtreecommitdiff
path: root/audio
diff options
context:
space:
mode:
Diffstat (limited to 'audio')
-rw-r--r--audio/alsaaudio.c1
-rw-r--r--audio/audio.c194
-rw-r--r--audio/audio_int.h20
-rw-r--r--audio/coreaudio.c15
-rw-r--r--audio/dsoundaudio.c30
-rw-r--r--audio/jackaudio.c5
-rw-r--r--audio/noaudio.c1
-rw-r--r--audio/ossaudio.c17
-rw-r--r--audio/paaudio.c49
-rw-r--r--audio/sdlaudio.c21
-rw-r--r--audio/wavaudio.c1
11 files changed, 212 insertions, 142 deletions
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 2b9789e647..b04716a6cc 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -916,6 +916,7 @@ static struct audio_pcm_ops alsa_pcm_ops = {
.init_out = alsa_init_out,
.fini_out = alsa_fini_out,
.write = alsa_write,
+ .buffer_get_free = audio_generic_buffer_get_free,
.run_buffer_out = audio_generic_run_buffer_out,
.enable_out = alsa_enable_out,
diff --git a/audio/audio.c b/audio/audio.c
index dc28685d22..a88572e713 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -548,65 +548,45 @@ static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
return live;
}
-static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
+static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
{
- size_t clipped = 0;
- size_t pos = hw->mix_buf->pos;
-
- while (len) {
- st_sample *src = hw->mix_buf->samples + pos;
- uint8_t *dst = advance(pcm_buf, clipped * hw->info.bytes_per_frame);
- size_t samples_till_end_of_buf = hw->mix_buf->size - pos;
- size_t samples_to_clip = MIN(len, samples_till_end_of_buf);
+ size_t conv = 0;
+ STSampleBuffer *conv_buf = hw->conv_buf;
- hw->clip(dst, src, samples_to_clip);
+ while (samples) {
+ uint8_t *src = advance(pcm_buf, conv * hw->info.bytes_per_frame);
+ size_t proc = MIN(samples, conv_buf->size - conv_buf->pos);
- pos = (pos + samples_to_clip) % hw->mix_buf->size;
- len -= samples_to_clip;
- clipped += samples_to_clip;
+ hw->conv(conv_buf->samples + conv_buf->pos, src, proc);
+ conv_buf->pos = (conv_buf->pos + proc) % conv_buf->size;
+ samples -= proc;
+ conv += proc;
}
+
+ return conv;
}
/*
* Soft voice (capture)
*/
-static size_t audio_pcm_sw_get_rpos_in(SWVoiceIn *sw)
-{
- HWVoiceIn *hw = sw->hw;
- ssize_t live = hw->total_samples_captured - sw->total_hw_samples_acquired;
- ssize_t rpos;
-
- 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->conv_buf->pos - live;
- if (rpos >= 0) {
- return rpos;
- } else {
- return hw->conv_buf->size + rpos;
- }
-}
-
static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
{
HWVoiceIn *hw = sw->hw;
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->conv_buf->size;
-
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
+ if (!live) {
+ return 0;
+ }
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;
}
+ rpos = audio_ring_posb(hw->conv_buf->pos, live, hw->conv_buf->size);
+
samples = size / sw->info.bytes_per_frame;
- if (!live) {
- return 0;
- }
swlim = (live * sw->ratio) >> 32;
swlim = MIN (swlim, samples);
@@ -632,7 +612,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
total += isamp;
}
- if (hw->pcm_ops && !hw->pcm_ops->volume_in) {
+ if (!hw->pcm_ops->volume_in) {
mixeng_volume (sw->buf, ret, &sw->vol);
}
@@ -683,12 +663,38 @@ static size_t audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
return 0;
}
+static size_t audio_pcm_hw_get_free(HWVoiceOut *hw)
+{
+ return (hw->pcm_ops->buffer_get_free ? hw->pcm_ops->buffer_get_free(hw) :
+ INT_MAX) / hw->info.bytes_per_frame;
+}
+
+static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
+{
+ size_t clipped = 0;
+ size_t pos = hw->mix_buf->pos;
+
+ while (len) {
+ st_sample *src = hw->mix_buf->samples + pos;
+ uint8_t *dst = advance(pcm_buf, clipped * hw->info.bytes_per_frame);
+ 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);
+
+ pos = (pos + samples_to_clip) % hw->mix_buf->size;
+ len -= samples_to_clip;
+ clipped += samples_to_clip;
+ }
+}
+
/*
* Soft voice (playback)
*/
static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
{
- size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
+ size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, blck;
+ size_t hw_free;
size_t ret = 0, pos = 0, total = 0;
if (!sw) {
@@ -711,27 +717,28 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
}
wpos = (sw->hw->mix_buf->pos + live) % hwsamples;
- samples = size / sw->info.bytes_per_frame;
dead = hwsamples - live;
- swlim = ((int64_t) dead << 32) / sw->ratio;
- swlim = MIN (swlim, samples);
- if (swlim) {
- sw->conv (sw->buf, buf, swlim);
+ hw_free = audio_pcm_hw_get_free(sw->hw);
+ hw_free = hw_free > live ? hw_free - live : 0;
+ samples = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
+ samples = MIN(samples, size / sw->info.bytes_per_frame);
+ if (samples) {
+ sw->conv(sw->buf, buf, samples);
- if (sw->hw->pcm_ops && !sw->hw->pcm_ops->volume_out) {
- mixeng_volume (sw->buf, swlim, &sw->vol);
+ if (!sw->hw->pcm_ops->volume_out) {
+ mixeng_volume(sw->buf, samples, &sw->vol);
}
}
- while (swlim) {
+ while (samples) {
dead = hwsamples - live;
left = hwsamples - wpos;
blck = MIN (dead, left);
if (!blck) {
break;
}
- isamp = swlim;
+ isamp = samples;
osamp = blck;
st_rate_flow_mix (
sw->rate,
@@ -741,7 +748,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
&osamp
);
ret += isamp;
- swlim -= isamp;
+ samples -= isamp;
pos += isamp;
live += osamp;
wpos = (wpos + osamp) % hwsamples;
@@ -1003,6 +1010,11 @@ static size_t audio_get_avail (SWVoiceIn *sw)
return (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame;
}
+static size_t audio_sw_bytes_free(SWVoiceOut *sw, size_t free)
+{
+ return (((int64_t)free << 32) / sw->ratio) * sw->info.bytes_per_frame;
+}
+
static size_t audio_get_free(SWVoiceOut *sw)
{
size_t live, dead;
@@ -1022,13 +1034,11 @@ static size_t audio_get_free(SWVoiceOut *sw)
dead = sw->hw->mix_buf->size - live;
#ifdef DEBUG_OUT
- dolog ("%s: get_free live %zu dead %zu ret %" PRId64 "\n",
- SW_NAME (sw),
- live, dead, (((int64_t) dead << 32) / sw->ratio) *
- sw->info.bytes_per_frame);
+ dolog("%s: get_free live %zu dead %zu sw_bytes %zu\n",
+ SW_NAME(sw), live, dead, audio_sw_bytes_free(sw, dead));
#endif
- return (((int64_t) dead << 32) / sw->ratio) * sw->info.bytes_per_frame;
+ return dead;
}
static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
@@ -1132,9 +1142,27 @@ static void audio_run_out (AudioState *s)
}
while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
- size_t played, live, prev_rpos, free;
+ size_t played, live, prev_rpos;
+ size_t hw_free = audio_pcm_hw_get_free(hw);
int nb_live;
+ for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+ if (sw->active) {
+ size_t sw_free = audio_get_free(sw);
+ size_t free;
+
+ if (hw_free > sw->total_hw_samples_mixed) {
+ free = audio_sw_bytes_free(sw,
+ MIN(sw_free, hw_free - sw->total_hw_samples_mixed));
+ } else {
+ free = 0;
+ }
+ if (free > 0) {
+ sw->callback.fn(sw->callback.opaque, free);
+ }
+ }
+ }
+
live = audio_pcm_hw_get_live_out (hw, &nb_live);
if (!nb_live) {
live = 0;
@@ -1163,14 +1191,6 @@ static void audio_run_out (AudioState *s)
}
if (!live) {
- for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
- if (sw->active) {
- free = audio_get_free (sw);
- if (free > 0) {
- sw->callback.fn (sw->callback.opaque, free);
- }
- }
- }
if (hw->pcm_ops->run_buffer_out) {
hw->pcm_ops->run_buffer_out(hw);
}
@@ -1211,13 +1231,6 @@ static void audio_run_out (AudioState *s)
if (!sw->total_hw_samples_mixed) {
sw->empty = 1;
}
-
- if (sw->active) {
- free = audio_get_free (sw);
- if (free > 0) {
- sw->callback.fn (sw->callback.opaque, free);
- }
- }
}
}
}
@@ -1225,7 +1238,6 @@ 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;
if (hw->pcm_ops->run_buffer_in) {
hw->pcm_ops->run_buffer_in(hw);
@@ -1241,11 +1253,7 @@ static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)
break;
}
- proc = MIN(size / hw->info.bytes_per_frame,
- 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;
+ proc = audio_pcm_hw_conv_in(hw, buf, size / hw->info.bytes_per_frame);
samples -= proc;
conv += proc;
@@ -1394,12 +1402,10 @@ void audio_generic_run_buffer_in(HWVoiceIn *hw)
void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
{
- ssize_t start = (ssize_t)hw->pos_emul - hw->pending_emul;
+ size_t start;
- if (start < 0) {
- start += hw->size_emul;
- }
- assert(start >= 0 && start < hw->size_emul);
+ start = audio_ring_posb(hw->pos_emul, hw->pending_emul, hw->size_emul);
+ assert(start < hw->size_emul);
*size = MIN(*size, hw->pending_emul);
*size = MIN(*size, hw->size_emul - start);
@@ -1412,16 +1418,22 @@ void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
hw->pending_emul -= size;
}
+size_t audio_generic_buffer_get_free(HWVoiceOut *hw)
+{
+ if (hw->buf_emul) {
+ return hw->size_emul - hw->pending_emul;
+ } else {
+ return hw->samples * hw->info.bytes_per_frame;
+ }
+}
+
void audio_generic_run_buffer_out(HWVoiceOut *hw)
{
while (hw->pending_emul) {
- size_t write_len, written;
- ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
+ size_t write_len, written, start;
- if (start < 0) {
- start += hw->size_emul;
- }
- assert(start >= 0 && start < hw->size_emul);
+ start = audio_ring_posb(hw->pos_emul, hw->pending_emul, hw->size_emul);
+ assert(start < hw->size_emul);
write_len = MIN(hw->pending_emul, hw->size_emul - start);
@@ -1462,6 +1474,12 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
{
size_t total = 0;
+ if (hw->pcm_ops->buffer_get_free) {
+ size_t free = hw->pcm_ops->buffer_get_free(hw);
+
+ size = MIN(size, free);
+ }
+
while (total < size) {
size_t dst_size = size - total;
size_t copy_size, proc;
@@ -1821,6 +1839,7 @@ void AUD_remove_card (QEMUSoundCard *card)
g_free (card->name);
}
+static struct audio_pcm_ops capture_pcm_ops;
CaptureVoiceOut *AUD_add_capture(
AudioState *s,
@@ -1866,6 +1885,7 @@ CaptureVoiceOut *AUD_add_capture(
hw = &cap->hw;
hw->s = s;
+ hw->pcm_ops = &capture_pcm_ops;
QLIST_INIT (&hw->sw_head);
QLIST_INIT (&cap->cb_head);
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 428a091d05..2a6914d2aa 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -162,9 +162,13 @@ struct audio_pcm_ops {
size_t (*write) (HWVoiceOut *hw, void *buf, size_t size);
void (*run_buffer_out)(HWVoiceOut *hw);
/*
+ * Get the free output buffer size. This is an upper limit. The size
+ * returned by function get_buffer_out may be smaller.
+ */
+ size_t (*buffer_get_free)(HWVoiceOut *hw);
+ /*
* 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);
/*
@@ -190,6 +194,7 @@ void audio_generic_run_buffer_in(HWVoiceIn *hw);
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_run_buffer_out(HWVoiceOut *hw);
+size_t audio_generic_buffer_get_free(HWVoiceOut *hw);
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_write(HWVoiceOut *hw, void *buf, size_t size);
@@ -266,6 +271,19 @@ static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len)
return (dst >= src) ? (dst - src) : (len - src + dst);
}
+/**
+ * audio_ring_posb() - returns new position in ringbuffer in backward
+ * direction at given distance
+ *
+ * @pos: current position in ringbuffer
+ * @dist: distance in ringbuffer to walk in reverse direction
+ * @len: size of ringbuffer
+ */
+static inline size_t audio_ring_posb(size_t pos, size_t dist, size_t len)
+{
+ return pos >= dist ? pos - dist : len - dist + pos;
+}
+
#define dolog(fmt, ...) AUD_log(AUDIO_CAP, fmt, ## __VA_ARGS__)
#ifdef DEBUG
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index d8a21d3e50..0f19d0ce01 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -283,6 +283,7 @@ static int coreaudio_buf_unlock (coreaudioVoiceOut *core, const char *fn_name)
coreaudio_buf_unlock(core, "coreaudio_" #name); \
return ret; \
}
+COREAUDIO_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw))
COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
(hw, size))
COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t,
@@ -333,12 +334,10 @@ static OSStatus audioDeviceIOProc(
len = frameCount * hw->info.bytes_per_frame;
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);
+ size_t write_len, start;
+
+ start = audio_ring_posb(hw->pos_emul, hw->pending_emul, hw->size_emul);
+ assert(start < hw->size_emul);
write_len = MIN(MIN(hw->pending_emul, len),
hw->size_emul - start);
@@ -604,6 +603,8 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
coreaudio_playback_logerr(status,
"Could not remove voice property change listener\n");
}
+
+ return -1;
}
return 0;
@@ -654,6 +655,8 @@ static struct audio_pcm_ops coreaudio_pcm_ops = {
.fini_out = coreaudio_fini_out,
/* wrapper for audio_generic_write */
.write = coreaudio_write,
+ /* wrapper for audio_generic_buffer_get_free */
+ .buffer_get_free = coreaudio_buffer_get_free,
/* wrapper for audio_generic_get_buffer_out */
.get_buffer_out = coreaudio_get_buffer_out,
/* wrapper for audio_generic_put_buffer_out */
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index 3dd2c4d4a6..231f3e65b3 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -427,22 +427,18 @@ static void dsound_enable_out(HWVoiceOut *hw, bool enable)
}
}
-static void *dsound_get_buffer_out(HWVoiceOut *hw, size_t *size)
+static size_t dsound_buffer_get_free(HWVoiceOut *hw)
{
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
HRESULT hr;
- DWORD ppos, wpos, act_size;
- size_t req_size;
- int err;
- void *ret;
+ DWORD ppos, wpos;
hr = IDirectSoundBuffer_GetCurrentPosition(
dsb, &ppos, ds->first_time ? &wpos : NULL);
if (FAILED(hr)) {
dsound_logerr(hr, "Could not get playback buffer position\n");
- *size = 0;
- return NULL;
+ return 0;
}
if (ds->first_time) {
@@ -450,13 +446,20 @@ static void *dsound_get_buffer_out(HWVoiceOut *hw, size_t *size)
ds->first_time = false;
}
- req_size = audio_ring_dist(ppos, hw->pos_emul, hw->size_emul);
- req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
+ return audio_ring_dist(ppos, hw->pos_emul, hw->size_emul);
+}
- if (req_size == 0) {
- *size = 0;
- return NULL;
- }
+static void *dsound_get_buffer_out(HWVoiceOut *hw, size_t *size)
+{
+ DSoundVoiceOut *ds = (DSoundVoiceOut *)hw;
+ LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
+ DWORD act_size;
+ size_t req_size;
+ int err;
+ void *ret;
+
+ req_size = MIN(*size, hw->size_emul - hw->pos_emul);
+ assert(req_size > 0);
err = dsound_lock_out(dsb, &hw->info, hw->pos_emul, req_size, &ret, NULL,
&act_size, NULL, false, ds->s);
@@ -699,6 +702,7 @@ static struct audio_pcm_ops dsound_pcm_ops = {
.init_out = dsound_init_out,
.fini_out = dsound_fini_out,
.write = audio_generic_write,
+ .buffer_get_free = dsound_buffer_get_free,
.get_buffer_out = dsound_get_buffer_out,
.put_buffer_out = dsound_put_buffer_out,
.enable_out = dsound_enable_out,
diff --git a/audio/jackaudio.c b/audio/jackaudio.c
index 317009e936..bf757250b5 100644
--- a/audio/jackaudio.c
+++ b/audio/jackaudio.c
@@ -483,8 +483,8 @@ static int qjack_client_init(QJackClient *c)
c->buffersize = 512;
}
- /* create a 2 period buffer */
- qjack_buffer_create(&c->fifo, c->nchannels, c->buffersize * 2);
+ /* create a 3 period buffer */
+ qjack_buffer_create(&c->fifo, c->nchannels, c->buffersize * 3);
qjack_client_connect_ports(c);
c->state = QJACK_STATE_RUNNING;
@@ -652,6 +652,7 @@ static struct audio_pcm_ops jack_pcm_ops = {
.init_out = qjack_init_out,
.fini_out = qjack_fini_out,
.write = qjack_write,
+ .buffer_get_free = audio_generic_buffer_get_free,
.run_buffer_out = audio_generic_run_buffer_out,
.enable_out = qjack_enable_out,
diff --git a/audio/noaudio.c b/audio/noaudio.c
index aac87dbc93..84a6bfbb1c 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -118,6 +118,7 @@ static struct audio_pcm_ops no_pcm_ops = {
.init_out = no_init_out,
.fini_out = no_fini_out,
.write = no_write,
+ .buffer_get_free = audio_generic_buffer_get_free,
.run_buffer_out = audio_generic_run_buffer_out,
.enable_out = no_enable_out,
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index 60eff66424..da9c232222 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -389,11 +389,23 @@ static void oss_run_buffer_out(HWVoiceOut *hw)
}
}
+static size_t oss_buffer_get_free(HWVoiceOut *hw)
+{
+ OSSVoiceOut *oss = (OSSVoiceOut *)hw;
+
+ if (oss->mmapped) {
+ return oss_get_available_bytes(oss);
+ } else {
+ return audio_generic_buffer_get_free(hw);
+ }
+}
+
static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
{
- OSSVoiceOut *oss = (OSSVoiceOut *) hw;
+ OSSVoiceOut *oss = (OSSVoiceOut *)hw;
+
if (oss->mmapped) {
- *size = MIN(oss_get_available_bytes(oss), hw->size_emul - hw->pos_emul);
+ *size = hw->size_emul - hw->pos_emul;
return hw->buf_emul + hw->pos_emul;
} else {
return audio_generic_get_buffer_out(hw, size);
@@ -750,6 +762,7 @@ static struct audio_pcm_ops oss_pcm_ops = {
.init_out = oss_init_out,
.fini_out = oss_fini_out,
.write = oss_write,
+ .buffer_get_free = oss_buffer_get_free,
.run_buffer_out = oss_run_buffer_out,
.get_buffer_out = oss_get_buffer_out,
.put_buffer_out = oss_put_buffer_out,
diff --git a/audio/paaudio.c b/audio/paaudio.c
index 75401d5391..a53ed85e0b 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -201,13 +201,11 @@ unlock_and_fail:
return 0;
}
-static void *qpa_get_buffer_out(HWVoiceOut *hw, size_t *size)
+static size_t qpa_buffer_get_free(HWVoiceOut *hw)
{
- PAVoiceOut *p = (PAVoiceOut *) hw;
+ PAVoiceOut *p = (PAVoiceOut *)hw;
PAConnection *c = p->g->conn;
- void *ret;
size_t l;
- int r;
pa_threaded_mainloop_lock(c->mainloop);
@@ -216,7 +214,6 @@ static void *qpa_get_buffer_out(HWVoiceOut *hw, size_t *size)
if (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
/* wait for stream to become ready */
l = 0;
- ret = NULL;
goto unlock;
}
@@ -224,16 +221,33 @@ static void *qpa_get_buffer_out(HWVoiceOut *hw, size_t *size)
CHECK_SUCCESS_GOTO(c, l != (size_t) -1, unlock_and_fail,
"pa_stream_writable_size failed\n");
+unlock:
+ pa_threaded_mainloop_unlock(c->mainloop);
+ return l;
+
+unlock_and_fail:
+ pa_threaded_mainloop_unlock(c->mainloop);
+ return 0;
+}
+
+static void *qpa_get_buffer_out(HWVoiceOut *hw, size_t *size)
+{
+ PAVoiceOut *p = (PAVoiceOut *)hw;
+ PAConnection *c = p->g->conn;
+ void *ret;
+ int r;
+
+ pa_threaded_mainloop_lock(c->mainloop);
+
+ CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
+ "pa_threaded_mainloop_lock failed\n");
+
*size = -1;
r = pa_stream_begin_write(p->stream, &ret, size);
CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail,
"pa_stream_begin_write failed\n");
-unlock:
pa_threaded_mainloop_unlock(c->mainloop);
- if (*size > l) {
- *size = l;
- }
return ret;
unlock_and_fail:
@@ -535,11 +549,8 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
}
audio_pcm_init_info (&hw->info, &obt_as);
- /*
- * This is wrong. hw->samples counts in frames. hw->samples will be
- * number of channels times larger than expected.
- */
- hw->samples = audio_buffer_samples(
+ /* hw->samples counts in frames */
+ hw->samples = audio_buffer_frames(
qapi_AudiodevPaPerDirectionOptions_base(ppdo), &obt_as, 46440);
return 0;
@@ -587,11 +598,8 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
}
audio_pcm_init_info (&hw->info, &obt_as);
- /*
- * This is wrong. hw->samples counts in frames. hw->samples will be
- * number of channels times larger than expected.
- */
- hw->samples = audio_buffer_samples(
+ /* hw->samples counts in frames */
+ hw->samples = audio_buffer_frames(
qapi_AudiodevPaPerDirectionOptions_base(ppdo), &obt_as, 46440);
return 0;
@@ -744,7 +752,7 @@ static int qpa_validate_per_direction_opts(Audiodev *dev,
{
if (!pdo->has_latency) {
pdo->has_latency = true;
- pdo->latency = 15000;
+ pdo->latency = 46440;
}
return 1;
}
@@ -901,6 +909,7 @@ static struct audio_pcm_ops qpa_pcm_ops = {
.init_out = qpa_init_out,
.fini_out = qpa_fini_out,
.write = qpa_write,
+ .buffer_get_free = qpa_buffer_get_free,
.get_buffer_out = qpa_get_buffer_out,
.put_buffer_out = qpa_put_buffer_out,
.volume_out = qpa_volume_out,
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index c68c62a3e4..797b47bbdd 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -224,12 +224,11 @@ static void sdl_callback_out(void *opaque, Uint8 *buf, int len)
/* dolog("callback_out: len=%d avail=%zu\n", len, hw->pending_emul); */
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);
+ size_t write_len, start;
+
+ start = audio_ring_posb(hw->pos_emul, hw->pending_emul,
+ hw->size_emul);
+ assert(start < hw->size_emul);
write_len = MIN(MIN(hw->pending_emul, len),
hw->size_emul - start);
@@ -310,6 +309,7 @@ static void sdl_callback_in(void *opaque, Uint8 *buf, int len)
SDL_UnlockAudioDevice(sdl->devid); \
}
+SDL_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw), Out)
SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
(hw, size), Out)
SDL_WRAPPER_FUNC(put_buffer_out, size_t,
@@ -347,11 +347,8 @@ static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as,
req.freq = as->freq;
req.format = aud_to_sdlfmt (as->fmt);
req.channels = as->nchannels;
- /*
- * This is wrong. SDL samples are QEMU frames. The buffer size will be
- * the requested buffer size multiplied by the number of channels.
- */
- req.samples = audio_buffer_samples(
+ /* SDL samples are QEMU frames */
+ req.samples = audio_buffer_frames(
qapi_AudiodevSdlPerDirectionOptions_base(spdo), as, 11610);
req.callback = sdl_callback_out;
req.userdata = sdl;
@@ -472,6 +469,8 @@ static struct audio_pcm_ops sdl_pcm_ops = {
.fini_out = sdl_fini_out,
/* wrapper for audio_generic_write */
.write = sdl_write,
+ /* wrapper for audio_generic_buffer_get_free */
+ .buffer_get_free = sdl_buffer_get_free,
/* wrapper for audio_generic_get_buffer_out */
.get_buffer_out = sdl_get_buffer_out,
/* wrapper for audio_generic_put_buffer_out */
diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index 20e6853f85..ac666335c7 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -197,6 +197,7 @@ static struct audio_pcm_ops wav_pcm_ops = {
.init_out = wav_init_out,
.fini_out = wav_fini_out,
.write = wav_write_out,
+ .buffer_get_free = audio_generic_buffer_get_free,
.run_buffer_out = audio_generic_run_buffer_out,
.enable_out = wav_enable_out,
};