aboutsummaryrefslogtreecommitdiff
path: root/src/output
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2012-08-14 23:58:54 +0200
committerMax Kellermann <max@duempel.org>2012-08-14 23:58:54 +0200
commit7d27d2ea5e8b622a288c80518bc0daec53dbbc93 (patch)
treeb1b9e98369919d66869b3ff1626372bf16a38c23 /src/output
parent5cc3338267214eb050e39bc509d8b4258cec6afd (diff)
parentdc22846d58264bfae3b4516e2de1614b3b97a5ca (diff)
Merge branch 'v0.17.x'
Diffstat (limited to 'src/output')
-rw-r--r--src/output/httpd_output_plugin.c52
-rw-r--r--src/output/jack_output_plugin.c15
-rw-r--r--src/output/pulse_output_plugin.c99
3 files changed, 88 insertions, 78 deletions
diff --git a/src/output/httpd_output_plugin.c b/src/output/httpd_output_plugin.c
index e7344320..abef826b 100644
--- a/src/output/httpd_output_plugin.c
+++ b/src/output/httpd_output_plugin.c
@@ -53,6 +53,31 @@ httpd_output_quark(void)
return g_quark_from_static_string("httpd_output");
}
+/**
+ * Check whether there is at least one client.
+ *
+ * Caller must lock the mutex.
+ */
+G_GNUC_PURE
+static bool
+httpd_output_has_clients(const struct httpd_output *httpd)
+{
+ return httpd->clients != NULL;
+}
+
+/**
+ * Check whether there is at least one client.
+ */
+G_GNUC_PURE
+static bool
+httpd_output_lock_has_clients(const struct httpd_output *httpd)
+{
+ g_mutex_lock(httpd->mutex);
+ bool result = httpd_output_has_clients(httpd);
+ g_mutex_unlock(httpd->mutex);
+ return result;
+}
+
static void
httpd_listen_in_event(int fd, const struct sockaddr *address,
size_t address_length, int uid, void *ctx);
@@ -397,6 +422,19 @@ httpd_output_delay(struct audio_output *ao)
{
struct httpd_output *httpd = (struct httpd_output *)ao;
+ if (!httpd_output_lock_has_clients(httpd) && httpd->base.pause) {
+ /* if there's no client and this output is paused,
+ then httpd_output_pause() will not do anything, it
+ will not fill the buffer and it will not update the
+ timer; therefore, we reset the timer here */
+ timer_reset(httpd->timer);
+
+ /* some arbitrary delay that is long enough to avoid
+ consuming too much CPU, and short enough to notice
+ new clients quickly enough */
+ return 1000;
+ }
+
return httpd->timer->started
? timer_delay(httpd->timer)
: 0;
@@ -475,13 +513,8 @@ httpd_output_play(struct audio_output *ao, const void *chunk, size_t size,
GError **error)
{
struct httpd_output *httpd = (struct httpd_output *)ao;
- bool has_clients;
- g_mutex_lock(httpd->mutex);
- has_clients = httpd->clients != NULL;
- g_mutex_unlock(httpd->mutex);
-
- if (has_clients) {
+ if (httpd_output_lock_has_clients(httpd)) {
bool success;
success = httpd_output_encode_and_play(httpd, chunk, size,
@@ -502,16 +535,11 @@ httpd_output_pause(struct audio_output *ao)
{
struct httpd_output *httpd = (struct httpd_output *)ao;
- g_mutex_lock(httpd->mutex);
- bool has_clients = httpd->clients != NULL;
- g_mutex_unlock(httpd->mutex);
-
- if (has_clients) {
+ if (httpd_output_lock_has_clients(httpd)) {
static const char silence[1020];
return httpd_output_play(ao, silence, sizeof(silence),
NULL) > 0;
} else {
- g_usleep(100000);
return true;
}
}
diff --git a/src/output/jack_output_plugin.c b/src/output/jack_output_plugin.c
index a24cb855..d5c8ca41 100644
--- a/src/output/jack_output_plugin.c
+++ b/src/output/jack_output_plugin.c
@@ -608,6 +608,16 @@ mpd_jack_close(G_GNUC_UNUSED struct audio_output *ao)
mpd_jack_stop(jd);
}
+static unsigned
+mpd_jack_delay(struct audio_output *ao)
+{
+ struct jack_data *jd = (struct jack_data *)ao;
+
+ return jd->base.pause && jd->pause && !jd->shutdown
+ ? 1000
+ : 0;
+}
+
static inline jack_default_audio_sample_t
sample_16_to_jack(int16_t sample)
{
@@ -727,10 +737,6 @@ mpd_jack_pause(struct audio_output *ao)
jd->pause = true;
- /* due to a MPD API limitation, we have to sleep a little bit
- here, to avoid hogging the CPU */
- g_usleep(50000);
-
return true;
}
@@ -742,6 +748,7 @@ const struct audio_output_plugin jack_output_plugin = {
.enable = mpd_jack_enable,
.disable = mpd_jack_disable,
.open = mpd_jack_open,
+ .delay = mpd_jack_delay,
.play = mpd_jack_play,
.pause = mpd_jack_pause,
.close = mpd_jack_close,
diff --git a/src/output/pulse_output_plugin.c b/src/output/pulse_output_plugin.c
index 0dc9be0e..e267427d 100644
--- a/src/output/pulse_output_plugin.c
+++ b/src/output/pulse_output_plugin.c
@@ -682,35 +682,6 @@ pulse_output_close(struct audio_output *ao)
}
/**
- * Check if the stream is (already) connected, and waits for a signal
- * if not. The mainloop must be locked before calling this function.
- *
- * @return the current stream state
- */
-static pa_stream_state_t
-pulse_output_check_stream(struct pulse_output *po)
-{
- pa_stream_state_t state = pa_stream_get_state(po->stream);
-
- assert(po->mainloop != NULL);
-
- switch (state) {
- case PA_STREAM_READY:
- case PA_STREAM_FAILED:
- case PA_STREAM_TERMINATED:
- case PA_STREAM_UNCONNECTED:
- break;
-
- case PA_STREAM_CREATING:
- pa_threaded_mainloop_wait(po->mainloop);
- state = pa_stream_get_state(po->stream);
- break;
- }
-
- return state;
-}
-
-/**
* Check if the stream is (already) connected, and waits if not. The
* mainloop must be locked before calling this function.
*
@@ -719,35 +690,25 @@ pulse_output_check_stream(struct pulse_output *po)
static bool
pulse_output_wait_stream(struct pulse_output *po, GError **error_r)
{
- pa_stream_state_t state = pa_stream_get_state(po->stream);
-
- switch (state) {
- case PA_STREAM_READY:
- return true;
-
- case PA_STREAM_FAILED:
- case PA_STREAM_TERMINATED:
- case PA_STREAM_UNCONNECTED:
- g_set_error(error_r, pulse_output_quark(), 0,
- "disconnected");
- return false;
-
- case PA_STREAM_CREATING:
- break;
- }
+ while (true) {
+ switch (pa_stream_get_state(po->stream)) {
+ case PA_STREAM_READY:
+ return true;
- do {
- state = pulse_output_check_stream(po);
- } while (state == PA_STREAM_CREATING);
+ case PA_STREAM_FAILED:
+ case PA_STREAM_TERMINATED:
+ case PA_STREAM_UNCONNECTED:
+ g_set_error(error_r, pulse_output_quark(),
+ pa_context_errno(po->context),
+ "failed to connect the stream: %s",
+ pa_strerror(pa_context_errno(po->context)));
+ return false;
- if (state != PA_STREAM_READY) {
- g_set_error(error_r, pulse_output_quark(), 0,
- "failed to connect the stream: %s",
- pa_strerror(pa_context_errno(po->context)));
- return false;
+ case PA_STREAM_CREATING:
+ pa_threaded_mainloop_wait(po->mainloop);
+ break;
+ }
}
-
- return true;
}
/**
@@ -801,6 +762,24 @@ pulse_output_stream_pause(struct pulse_output *po, bool pause,
return true;
}
+static unsigned
+pulse_output_delay(struct audio_output *ao)
+{
+ struct pulse_output *po = (struct pulse_output *)ao;
+ unsigned result = 0;
+
+ pa_threaded_mainloop_lock(po->mainloop);
+
+ if (po->base.pause && pulse_output_stream_is_paused(po) &&
+ pa_stream_get_state(po->stream) == PA_STREAM_READY)
+ /* idle while paused */
+ result = 1000;
+
+ pa_threaded_mainloop_unlock(po->mainloop);
+
+ return result;
+}
+
static size_t
pulse_output_play(struct audio_output *ao, const void *chunk, size_t size,
GError **error_r)
@@ -928,13 +907,8 @@ pulse_output_pause(struct audio_output *ao)
/* cork the stream */
- if (pulse_output_stream_is_paused(po)) {
- /* already paused; due to a MPD API limitation, we
- have to sleep a little bit here, to avoid hogging
- the CPU */
-
- g_usleep(50000);
- } else if (!pulse_output_stream_pause(po, true, &error)) {
+ if (!pulse_output_stream_is_paused(po) &&
+ !pulse_output_stream_pause(po, true, &error)) {
pa_threaded_mainloop_unlock(po->mainloop);
g_warning("%s", error->message);
g_error_free(error);
@@ -971,6 +945,7 @@ const struct audio_output_plugin pulse_output_plugin = {
.enable = pulse_output_enable,
.disable = pulse_output_disable,
.open = pulse_output_open,
+ .delay = pulse_output_delay,
.play = pulse_output_play,
.cancel = pulse_output_cancel,
.pause = pulse_output_pause,