diff options
Diffstat (limited to 'src/output')
-rw-r--r-- | src/output/alsa_plugin.c | 50 | ||||
-rw-r--r-- | src/output/fifo_output_plugin.c | 4 | ||||
-rw-r--r-- | src/output/httpd_client.c | 1 | ||||
-rw-r--r-- | src/output/mvp_plugin.c | 4 | ||||
-rw-r--r-- | src/output/oss_plugin.c | 4 | ||||
-rw-r--r-- | src/output/recorder_output_plugin.c | 3 |
6 files changed, 56 insertions, 10 deletions
diff --git a/src/output/alsa_plugin.c b/src/output/alsa_plugin.c index 48a40fb9b..64a8127ba 100644 --- a/src/output/alsa_plugin.c +++ b/src/output/alsa_plugin.c @@ -69,6 +69,16 @@ struct alsa_data { /** the size of one audio frame */ size_t frame_size; + + /** + * The size of one period, in number of frames. + */ + snd_pcm_uframes_t period_frames; + + /** + * The number of frames written in the current period. + */ + snd_pcm_uframes_t period_position; }; /** @@ -413,6 +423,9 @@ configure_hw: g_debug("buffer_size=%u period_size=%u", (unsigned)alsa_buffer_size, (unsigned)alsa_period_size); + ad->period_frames = alsa_period_size; + ad->period_position = 0; + return true; error: @@ -479,6 +492,7 @@ alsa_recover(struct alsa_data *ad, int err) /* fall-through to snd_pcm_prepare: */ case SND_PCM_STATE_SETUP: case SND_PCM_STATE_XRUN: + ad->period_position = 0; err = snd_pcm_prepare(ad->pcm); break; case SND_PCM_STATE_DISCONNECTED: @@ -500,8 +514,33 @@ alsa_drain(void *data) { struct alsa_data *ad = data; - if (snd_pcm_state(ad->pcm) == SND_PCM_STATE_RUNNING) - snd_pcm_drain(ad->pcm); + if (snd_pcm_state(ad->pcm) != SND_PCM_STATE_RUNNING) + return; + + if (ad->period_position > 0) { + /* generate some silence to finish the partial + period */ + snd_pcm_uframes_t nframes = + ad->period_frames - ad->period_position; + size_t nbytes = nframes * ad->frame_size; + void *buffer = g_malloc(nbytes); + snd_pcm_hw_params_t *params; + snd_pcm_format_t format; + unsigned channels; + + snd_pcm_hw_params_alloca(¶ms); + snd_pcm_hw_params_current(ad->pcm, params); + snd_pcm_hw_params_get_format(params, &format); + snd_pcm_hw_params_get_channels(params, &channels); + + snd_pcm_format_set_silence(format, buffer, nframes * channels); + ad->writei(ad->pcm, buffer, nframes); + g_free(buffer); + } + + snd_pcm_drain(ad->pcm); + + ad->period_position = 0; } static void @@ -509,6 +548,8 @@ alsa_cancel(void *data) { struct alsa_data *ad = data; + ad->period_position = 0; + snd_pcm_drop(ad->pcm); } @@ -529,8 +570,11 @@ alsa_play(void *data, const void *chunk, size_t size, GError **error) while (true) { snd_pcm_sframes_t ret = ad->writei(ad->pcm, chunk, size); - if (ret > 0) + if (ret > 0) { + ad->period_position = (ad->period_position + ret) + % ad->period_frames; return ret * ad->frame_size; + } if (ret < 0 && ret != -EAGAIN && ret != -EINTR && alsa_recover(ad, ret) < 0) { diff --git a/src/output/fifo_output_plugin.c b/src/output/fifo_output_plugin.c index 0217c2675..b5e6f5314 100644 --- a/src/output/fifo_output_plugin.c +++ b/src/output/fifo_output_plugin.c @@ -153,7 +153,7 @@ fifo_open(struct fifo_data *fd, GError **error) if (!fifo_check(fd, error)) return false; - fd->input = open_cloexec(fd->path, O_RDONLY|O_NONBLOCK); + fd->input = open_cloexec(fd->path, O_RDONLY|O_NONBLOCK, 0); if (fd->input < 0) { g_set_error(error, fifo_output_quark(), errno, "Could not open FIFO \"%s\" for reading: %s", @@ -162,7 +162,7 @@ fifo_open(struct fifo_data *fd, GError **error) return false; } - fd->output = open_cloexec(fd->path, O_WRONLY|O_NONBLOCK); + fd->output = open_cloexec(fd->path, O_WRONLY|O_NONBLOCK, 0); if (fd->output < 0) { g_set_error(error, fifo_output_quark(), errno, "Could not open FIFO \"%s\" for writing: %s", diff --git a/src/output/httpd_client.c b/src/output/httpd_client.c index 8157ebb44..62ede81be 100644 --- a/src/output/httpd_client.c +++ b/src/output/httpd_client.c @@ -22,6 +22,7 @@ #include "fifo_buffer.h" #include "page.h" #include "icy_server.h" +#include "glib_compat.h" #include <stdbool.h> #include <assert.h> diff --git a/src/output/mvp_plugin.c b/src/output/mvp_plugin.c index f5fbadbee..7e6dd6d31 100644 --- a/src/output/mvp_plugin.c +++ b/src/output/mvp_plugin.c @@ -116,7 +116,7 @@ mvp_output_test_default_device(void) { int fd; - fd = open_cloexec("/dev/adec_pcm", O_WRONLY); + fd = open_cloexec("/dev/adec_pcm", O_WRONLY, 0); if (fd >= 0) { close(fd); @@ -231,7 +231,7 @@ mvp_output_open(void *data, struct audio_format *audio_format, GError **error) int mix[5] = { 0, 2, 7, 1, 0 }; bool success; - md->fd = open_cloexec("/dev/adec_pcm", O_RDWR | O_NONBLOCK); + md->fd = open_cloexec("/dev/adec_pcm", O_RDWR | O_NONBLOCK, 0); if (md->fd < 0) { g_set_error(error, mvp_output_quark(), errno, "Error opening /dev/adec_pcm: %s", diff --git a/src/output/oss_plugin.c b/src/output/oss_plugin.c index f308c293e..6518c3f49 100644 --- a/src/output/oss_plugin.c +++ b/src/output/oss_plugin.c @@ -344,7 +344,7 @@ oss_output_test_default_device(void) int fd, i; for (i = G_N_ELEMENTS(default_devices); --i >= 0; ) { - fd = open_cloexec(default_devices[i], O_WRONLY); + fd = open_cloexec(default_devices[i], O_WRONLY, 0); if (fd >= 0) { close(fd); @@ -519,7 +519,7 @@ oss_open(struct oss_data *od, GError **error) { bool success; - od->fd = open_cloexec(od->device, O_WRONLY); + od->fd = open_cloexec(od->device, O_WRONLY, 0); if (od->fd < 0) { g_set_error(error, oss_output_quark(), errno, "Error opening OSS device \"%s\": %s", diff --git a/src/output/recorder_output_plugin.c b/src/output/recorder_output_plugin.c index 202b56073..11dd6c041 100644 --- a/src/output/recorder_output_plugin.c +++ b/src/output/recorder_output_plugin.c @@ -157,7 +157,8 @@ recorder_output_open(void *data, struct audio_format *audio_format, /* create the output file */ - recorder->fd = creat_cloexec(recorder->path, 0666); + recorder->fd = open_cloexec(recorder->path, O_CREAT|O_WRONLY|O_TRUNC, + 0666); if (recorder->fd < 0) { g_set_error(error_r, recorder_output_quark(), 0, "Failed to create '%s': %s", |