summaryrefslogtreecommitdiffstats
path: root/audio/alsaaudio.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/alsaaudio.c')
-rw-r--r--audio/alsaaudio.c38
1 files changed, 37 insertions, 1 deletions
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 4a61378cd7..7a2a94cd42 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -602,6 +602,42 @@ static int alsa_open(bool in, struct alsa_params_req *req,
return -1;
}
+static size_t alsa_buffer_get_free(HWVoiceOut *hw)
+{
+ ALSAVoiceOut *alsa = (ALSAVoiceOut *)hw;
+ snd_pcm_sframes_t avail;
+ size_t alsa_free, generic_free, generic_in_use;
+
+ avail = snd_pcm_avail_update(alsa->handle);
+ if (avail < 0) {
+ if (avail == -EPIPE) {
+ if (!alsa_recover(alsa->handle)) {
+ avail = snd_pcm_avail_update(alsa->handle);
+ }
+ }
+ if (avail < 0) {
+ alsa_logerr(avail,
+ "Could not obtain number of available frames\n");
+ avail = 0;
+ }
+ }
+
+ alsa_free = avail * hw->info.bytes_per_frame;
+ generic_free = audio_generic_buffer_get_free(hw);
+ generic_in_use = hw->samples * hw->info.bytes_per_frame - generic_free;
+ if (generic_in_use) {
+ /*
+ * This code can only be reached in the unlikely case that
+ * snd_pcm_avail_update() returned a larger number of frames
+ * than snd_pcm_writei() could write. Make sure that all
+ * remaining bytes in the generic buffer can be written.
+ */
+ alsa_free = alsa_free > generic_in_use ? alsa_free - generic_in_use : 0;
+ }
+
+ return alsa_free;
+}
+
static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
@@ -916,7 +952,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,
+ .buffer_get_free = alsa_buffer_get_free,
.run_buffer_out = audio_generic_run_buffer_out,
.enable_out = alsa_enable_out,