aboutsummaryrefslogtreecommitdiffstats
path: root/src/output
diff options
context:
space:
mode:
Diffstat (limited to 'src/output')
-rw-r--r--src/output/alsa_plugin.c50
-rw-r--r--src/output/fifo_output_plugin.c4
-rw-r--r--src/output/httpd_client.c1
-rw-r--r--src/output/mvp_plugin.c4
-rw-r--r--src/output/oss_plugin.c4
-rw-r--r--src/output/recorder_output_plugin.c3
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(&params);
+ 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",