summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
Diffstat (limited to 'audio')
-rw-r--r--audio/alsaaudio.c1
-rw-r--r--audio/audio.c69
-rw-r--r--audio/audio_int.h7
-rw-r--r--audio/coreaudio.c3
-rw-r--r--audio/jackaudio.c1
-rw-r--r--audio/noaudio.c1
-rw-r--r--audio/ossaudio.c12
-rw-r--r--audio/sdlaudio.c3
-rw-r--r--audio/wavaudio.c1
9 files changed, 80 insertions, 18 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 c420a8bd1c..a88572e713 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -663,6 +663,12 @@ 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;
@@ -687,7 +693,8 @@ static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
*/
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) {
@@ -710,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->volume_out) {
- mixeng_volume (sw->buf, swlim, &sw->vol);
+ 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,
@@ -740,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;
@@ -1002,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;
@@ -1021,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,
@@ -1131,12 +1142,21 @@ 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) {
- free = audio_get_free(sw);
+ 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);
}
@@ -1398,6 +1418,15 @@ 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) {
@@ -1445,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;
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 71be162271..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);
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index 1fdd1d4b14..91ea6ae975 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,
@@ -652,6 +653,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/jackaudio.c b/audio/jackaudio.c
index 26246c3a8b..bf757250b5 100644
--- a/audio/jackaudio.c
+++ b/audio/jackaudio.c
@@ -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..1bd6800840 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -389,6 +389,17 @@ 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 INT_MAX;
+ } else {
+ return audio_generic_buffer_get_free(hw);
+ }
+}
+
static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
{
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
@@ -750,6 +761,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/sdlaudio.c b/audio/sdlaudio.c
index d6f3aa1a9a..e605c787ba 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -309,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,
@@ -471,6 +472,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,
};