aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/output/alsa_plugin.c31
-rw-r--r--src/output/ao_plugin.c20
-rw-r--r--src/output/fifo_plugin.c17
-rw-r--r--src/output/jack_plugin.c33
-rw-r--r--src/output/mvp_plugin.c12
-rw-r--r--src/output/null_plugin.c6
-rw-r--r--src/output/oss_plugin.c17
-rw-r--r--src/output/osx_plugin.c45
-rw-r--r--src/output/pulse_plugin.c6
-rw-r--r--src/output/shout_plugin.c7
-rw-r--r--src/output_plugin.h6
-rw-r--r--src/output_thread.c22
12 files changed, 103 insertions, 119 deletions
diff --git a/src/output/alsa_plugin.c b/src/output/alsa_plugin.c
index bbb03e80b..05e097513 100644
--- a/src/output/alsa_plugin.c
+++ b/src/output/alsa_plugin.c
@@ -441,7 +441,7 @@ alsa_close(void *data)
mixer_close(ad->mixer);
}
-static bool
+static size_t
alsa_play(void *data, const char *chunk, size_t size)
{
struct alsa_data *ad = data;
@@ -449,28 +449,19 @@ alsa_play(void *data, const char *chunk, size_t size)
size /= ad->frame_size;
- while (size > 0) {
+ while (true) {
ret = ad->writei(ad->pcm, chunk, size);
-
- if (ret == -EAGAIN || ret == -EINTR)
- continue;
-
- if (ret < 0) {
- if (alsa_recover(ad, ret) < 0) {
- g_warning("closing ALSA device \"%s\" due to write "
- "error: %s\n",
- alsa_device(ad), snd_strerror(-errno));
- return false;
- }
-
- continue;
+ if (ret > 0)
+ return ret * ad->frame_size;
+
+ if (ret < 0 && ret != -EAGAIN && ret != -EINTR &&
+ alsa_recover(ad, ret) < 0) {
+ g_warning("closing ALSA device \"%s\" due to write "
+ "error: %s\n",
+ alsa_device(ad), snd_strerror(-errno));
+ return 0;
}
-
- chunk += ret * ad->frame_size;
- size -= ret;
}
-
- return true;
}
const struct audio_output_plugin alsaPlugin = {
diff --git a/src/output/ao_plugin.c b/src/output/ao_plugin.c
index b0662d7a1..c9d10174e 100644
--- a/src/output/ao_plugin.c
+++ b/src/output/ao_plugin.c
@@ -208,29 +208,23 @@ static int ao_play_deconst(ao_device *device, const void *output_samples,
return ao_play(device, u.out, num_bytes);
}
-static bool
+static size_t
audioOutputAo_play(void *data, const char *playChunk, size_t size)
{
AoData *ad = (AoData *)data;
- size_t chunk_size;
if (ad->device == NULL)
return false;
- while (size > 0) {
- chunk_size = ad->writeSize > size
- ? size : ad->writeSize;
-
- if (ao_play_deconst(ad->device, playChunk, chunk_size) == 0) {
- audioOutputAo_error("Closing libao device due to play error");
- return false;
- }
+ if (size > ad->writeSize)
+ size = ad->writeSize;
- playChunk += chunk_size;
- size -= chunk_size;
+ if (ao_play_deconst(ad->device, playChunk, size) == 0) {
+ audioOutputAo_error("Closing libao device due to play error");
+ return 0;
}
- return true;
+ return size;
}
const struct audio_output_plugin aoPlugin = {
diff --git a/src/output/fifo_plugin.c b/src/output/fifo_plugin.c
index b0c6d12f4..1be0f2a7d 100644
--- a/src/output/fifo_plugin.c
+++ b/src/output/fifo_plugin.c
@@ -237,11 +237,10 @@ static void fifo_dropBufferedAudio(void *data)
}
}
-static bool
+static size_t
fifo_playAudio(void *data, const char *playChunk, size_t size)
{
FifoData *fd = (FifoData *)data;
- size_t offset = 0;
ssize_t bytes;
if (!fd->timer->started)
@@ -251,8 +250,11 @@ fifo_playAudio(void *data, const char *playChunk, size_t size)
timer_add(fd->timer, size);
- while (size) {
- bytes = write(fd->output, playChunk + offset, size);
+ while (true) {
+ bytes = write(fd->output, playChunk, size);
+ if (bytes > 0)
+ return (size_t)bytes;
+
if (bytes < 0) {
switch (errno) {
case EAGAIN:
@@ -265,14 +267,9 @@ fifo_playAudio(void *data, const char *playChunk, size_t size)
g_warning("Closing FIFO output \"%s\" due to write error: %s",
fd->path, strerror(errno));
- return false;
+ return 0;
}
-
- size -= bytes;
- offset += bytes;
}
-
- return true;
}
const struct audio_output_plugin fifoPlugin = {
diff --git a/src/output/jack_plugin.c b/src/output/jack_plugin.c
index 2bcdf874f..22841f8ef 100644
--- a/src/output/jack_plugin.c
+++ b/src/output/jack_plugin.c
@@ -387,7 +387,7 @@ mpd_jack_write_samples(struct jack_data *jd, const void *src,
}
}
-static bool
+static size_t
mpd_jack_play(void *data, const char *buff, size_t size)
{
struct jack_data *jd = data;
@@ -396,36 +396,33 @@ mpd_jack_play(void *data, const char *buff, size_t size)
if (jd->shutdown) {
g_warning("Refusing to play, because there is no client thread.");
- return false;
+ return 0;
}
assert(size % frame_size == 0);
size /= frame_size;
- while (size > 0 && !jd->shutdown) {
+
+ while (!jd->shutdown) {
space = jack_ringbuffer_write_space(jd->ringbuffer[0]);
space1 = jack_ringbuffer_write_space(jd->ringbuffer[1]);
if (space > space1)
/* send data symmetrically */
space = space1;
- space /= sample_size;
- if (space > 0) {
- if (space > size)
- space = size;
-
- mpd_jack_write_samples(jd, buff, space);
-
- buff += space * frame_size;
- size -= space;
- } else {
- /* XXX do something more intelligent to
- synchronize */
- g_usleep(1000);
- }
+ if (space >= frame_size)
+ break;
+ /* XXX do something more intelligent to
+ synchronize */
+ g_usleep(1000);
}
- return true;
+ space /= sample_size;
+ if (space < size)
+ size = space;
+
+ mpd_jack_write_samples(jd, buff, size);
+ return size * frame_size;
}
const struct audio_output_plugin jackPlugin = {
diff --git a/src/output/mvp_plugin.c b/src/output/mvp_plugin.c
index cb570c8ee..840661ea7 100644
--- a/src/output/mvp_plugin.c
+++ b/src/output/mvp_plugin.c
@@ -248,7 +248,7 @@ static void mvp_dropBufferedAudio(void *data)
}
}
-static bool
+static size_t
mvp_playAudio(void *data, const char *playChunk, size_t size)
{
MvpData *md = data;
@@ -258,19 +258,19 @@ mvp_playAudio(void *data, const char *playChunk, size_t size)
if (md->fd < 0)
mvp_openDevice(md, &md->audio_format);
- while (size > 0) {
+ while (true) {
ret = write(md->fd, playChunk, size);
+ if (ret > 0)
+ return (size_t)ret;
+
if (ret < 0) {
if (errno == EINTR)
continue;
g_warning("closing mvp PCM device due to write error: "
"%s\n", strerror(errno));
- return false;
+ return 0;
}
- playChunk += ret;
- size -= ret;
}
- return true;
}
const struct audio_output_plugin mvpPlugin = {
diff --git a/src/output/null_plugin.c b/src/output/null_plugin.c
index 1ae55ca9b..2506feb74 100644
--- a/src/output/null_plugin.c
+++ b/src/output/null_plugin.c
@@ -74,14 +74,14 @@ null_close(void *data)
}
}
-static bool
+static size_t
null_play(void *data, G_GNUC_UNUSED const char *chunk, size_t size)
{
struct null_data *nd = data;
Timer *timer = nd->timer;
if (!nd->sync)
- return true;
+ return size;
if (!timer->started)
timer_start(timer);
@@ -90,7 +90,7 @@ null_play(void *data, G_GNUC_UNUSED const char *chunk, size_t size)
timer_add(timer, size);
- return true;
+ return size;
}
static void
diff --git a/src/output/oss_plugin.c b/src/output/oss_plugin.c
index 007d5bc84..eca6f9101 100644
--- a/src/output/oss_plugin.c
+++ b/src/output/oss_plugin.c
@@ -553,7 +553,7 @@ static void oss_dropBufferedAudio(void *data)
}
}
-static bool
+static size_t
oss_playAudio(void *data, const char *playChunk, size_t size)
{
OssData *od = data;
@@ -563,20 +563,17 @@ oss_playAudio(void *data, const char *playChunk, size_t size)
if (od->fd < 0 && !oss_open(od))
return false;
- while (size > 0) {
+ while (true) {
ret = write(od->fd, playChunk, size);
- if (ret < 0) {
- if (errno == EINTR)
- continue;
+ if (ret > 0)
+ return (size_t)ret;
+
+ if (ret < 0 && errno != EINTR) {
g_warning("closing oss device \"%s\" due to write error: "
"%s\n", od->device, strerror(errno));
- return false;
+ return 0;
}
- playChunk += ret;
- size -= ret;
}
-
- return true;
}
const struct audio_output_plugin ossPlugin = {
diff --git a/src/output/osx_plugin.c b/src/output/osx_plugin.c
index a97f56982..ffeb8cd5e 100644
--- a/src/output/osx_plugin.c
+++ b/src/output/osx_plugin.c
@@ -256,13 +256,11 @@ osx_openDevice(void *data, struct audio_format *audioFormat)
return true;
}
-static bool
+static size_t
osx_play(void *data, const char *playChunk, size_t size)
{
OsxData *od = data;
- size_t bytesToCopy;
- size_t bytes;
- size_t curpos;
+ size_t start, nbytes;
if (!od->started) {
int err;
@@ -270,42 +268,35 @@ osx_play(void *data, const char *playChunk, size_t size)
err = AudioOutputUnitStart(od->au);
if (err) {
g_warning("unable to start audio output: %i\n", err);
- return false;
+ return 0;
}
}
g_mutex_lock(od->mutex);
- while (size) {
- curpos = od->pos + od->len;
- if (curpos >= od->bufferSize)
- curpos -= od->bufferSize;
+ while (od->len >= od->bufferSize)
+ /* wait for some free space in the buffer */
+ g_cond_wait(od->condition, od->mutex);
- bytesToCopy = MIN(od->bufferSize, size);
+ start = od->pos + od->len;
+ if (start >= od->bufferSize)
+ start -= od->bufferSize;
- while (od->len > od->bufferSize - bytesToCopy) {
- g_cond_wait(od->condition, od->mutex);
- }
+ nbytes = start < od->pos
+ ? od->pos - start
+ : od->bufferSize - start;
- size -= bytesToCopy;
- od->len += bytesToCopy;
+ assert(nbytes > 0);
- bytes = od->bufferSize - curpos;
- if (bytesToCopy > bytes) {
- memcpy(od->buffer + curpos, playChunk, bytes);
- curpos = 0;
- playChunk += bytes;
- bytesToCopy -= bytes;
- }
-
- memcpy(od->buffer + curpos, playChunk, bytesToCopy);
- playChunk += bytesToCopy;
+ if (nbytes > size)
+ nbytes = size;
- }
+ memcpy(od->buffer + start, playChunk, nbytes);
+ od->len += nbytes;
g_mutex_unlock(od->mutex);
- return true;
+ return nbytes;
}
const struct audio_output_plugin osxPlugin = {
diff --git a/src/output/pulse_plugin.c b/src/output/pulse_plugin.c
index 559d2ee56..0203310e7 100644
--- a/src/output/pulse_plugin.c
+++ b/src/output/pulse_plugin.c
@@ -160,7 +160,7 @@ static void pulse_close(void *data)
}
}
-static bool
+static size_t
pulse_play(void *data, const char *playChunk, size_t size)
{
struct pulse_data *pd = data;
@@ -172,10 +172,10 @@ pulse_play(void *data, const char *playChunk, size_t size)
audio_output_get_name(pd->ao),
pa_strerror(error));
pulse_close(pd);
- return false;
+ return 0;
}
- return true;
+ return size;
}
const struct audio_output_plugin pulse_plugin = {
diff --git a/src/output/shout_plugin.c b/src/output/shout_plugin.c
index 7887e2922..2563e8092 100644
--- a/src/output/shout_plugin.c
+++ b/src/output/shout_plugin.c
@@ -413,7 +413,7 @@ my_shout_open_device(void *data, struct audio_format *audio_format)
return true;
}
-static bool
+static size_t
my_shout_play(void *data, const char *chunk, size_t size)
{
struct shout_data *sd = (struct shout_data *)data;
@@ -427,7 +427,10 @@ my_shout_play(void *data, const char *chunk, size_t size)
return false;
}
- return write_page(sd);
+ if (!write_page(sd))
+ return 0;
+
+ return size;
}
static bool
diff --git a/src/output_plugin.h b/src/output_plugin.h
index b652dc44e..8a2bcadac 100644
--- a/src/output_plugin.h
+++ b/src/output_plugin.h
@@ -92,8 +92,10 @@ struct audio_output_plugin {
/**
* Play a chunk of audio data.
+ *
+ * @return the number of bytes played, or 0 on error
*/
- bool (*play)(void *data, const char *playChunk, size_t size);
+ size_t (*play)(void *data, const char *chunk, size_t size);
/**
* Try to cancel data which may still be in the device's
@@ -167,7 +169,7 @@ ao_plugin_send_tag(const struct audio_output_plugin *plugin,
plugin->send_tag(data, tag);
}
-static inline bool
+static inline size_t
ao_plugin_play(const struct audio_output_plugin *plugin,
void *data, const void *chunk, size_t size)
{
diff --git a/src/output_thread.c b/src/output_thread.c
index 098e1b427..709d8d1a2 100644
--- a/src/output_thread.c
+++ b/src/output_thread.c
@@ -52,9 +52,9 @@ static void ao_play(struct audio_output *ao)
{
const char *data = ao->args.play.data;
size_t size = ao->args.play.size;
- bool ret;
assert(size > 0);
+ assert(size % audio_format_frame_size(&ao->out_audio_format) == 0);
if (!audio_format_equals(&ao->in_audio_format, &ao->out_audio_format)) {
data = pcm_convert(&ao->convert_state,
@@ -69,10 +69,22 @@ static void ao_play(struct audio_output *ao)
return;
}
- ret = ao_plugin_play(ao->plugin, ao->data, data, size);
- if (!ret) {
- ao_plugin_cancel(ao->plugin, ao->data);
- ao_close(ao);
+ while (size > 0) {
+ size_t nbytes;
+
+ nbytes = ao_plugin_play(ao->plugin, ao->data, data, size);
+ if (nbytes == 0) {
+ /* play()==0 means failure */
+ ao_plugin_cancel(ao->plugin, ao->data);
+ ao_close(ao);
+ break;
+ }
+
+ assert(nbytes <= size);
+ assert(nbytes % audio_format_frame_size(&ao->out_audio_format) == 0);
+
+ data += nbytes;
+ size -= nbytes;
}
ao_command_finished(ao);