From b7f435b50e591ca2c485e13c06c426b64ecd4090 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 23 Aug 2011 17:51:28 +0200 Subject: output/httpd: don't warn on client disconnect This warning should only be logged when we really received something. When the client disconnects, G_IO_IN is triggered, and the read returns G_IO_STATUS_EOF. --- src/output/httpd_client.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/output') diff --git a/src/output/httpd_client.c b/src/output/httpd_client.c index f5e14925b..df2f2a9e6 100644 --- a/src/output/httpd_client.c +++ b/src/output/httpd_client.c @@ -370,7 +370,14 @@ httpd_client_read(struct httpd_client *client) if (client->state == RESPONSE) { /* the client has already sent the request, and he must not send more */ - g_warning("unexpected input from client"); + char buffer[1]; + + status = g_io_channel_read_chars(client->channel, buffer, + sizeof(buffer), &bytes_read, + NULL); + if (status == G_IO_STATUS_NORMAL) + g_warning("unexpected input from client"); + return false; } -- cgit v1.2.3 From 7c887af1ea26cba22826475412a8ce437f87961f Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 23 Aug 2011 18:14:39 +0200 Subject: output/httpd: add assertions --- src/output/httpd_client.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'src/output') diff --git a/src/output/httpd_client.c b/src/output/httpd_client.c index df2f2a9e6..1119a7834 100644 --- a/src/output/httpd_client.c +++ b/src/output/httpd_client.c @@ -143,6 +143,8 @@ httpd_client_unref_page(gpointer data, G_GNUC_UNUSED gpointer user_data) void httpd_client_free(struct httpd_client *client) { + assert(client != NULL); + if (client->state == RESPONSE) { if (client->write_source_id != 0) g_source_remove(client->write_source_id); @@ -169,6 +171,8 @@ httpd_client_free(struct httpd_client *client) static void httpd_client_close(struct httpd_client *client) { + assert(client != NULL); + httpd_output_remove_client(client->httpd, client); httpd_client_free(client); } @@ -179,6 +183,9 @@ httpd_client_close(struct httpd_client *client) static void httpd_client_begin_response(struct httpd_client *client) { + assert(client != NULL); + assert(client->state != RESPONSE); + client->state = RESPONSE; client->write_source_id = 0; client->pages = g_queue_new(); @@ -239,6 +246,9 @@ httpd_client_handle_line(struct httpd_client *client, const char *line) static char * httpd_client_read_line(struct httpd_client *client) { + assert(client != NULL); + assert(client->state != RESPONSE); + const char *p, *newline; size_t length; char *line; @@ -271,6 +281,7 @@ httpd_client_send_response(struct httpd_client *client) GIOStatus status; gsize bytes_written; + assert(client != NULL); assert(client->state == RESPONSE); if (!client->metadata_requested) { @@ -334,14 +345,19 @@ httpd_client_send_response(struct httpd_client *client) static bool httpd_client_received(struct httpd_client *client) { + assert(client != NULL); + assert(client->state != RESPONSE); + char *line; bool success; while ((line = httpd_client_read_line(client)) != NULL) { success = httpd_client_handle_line(client, line); g_free(line); - if (!success) + if (!success) { + assert(client->state != RESPONSE); return false; + } if (client->state == RESPONSE) { if (!fifo_buffer_is_empty(client->input)) { -- cgit v1.2.3 From 25686e5bcee030a1e17f797f75258f26594bab39 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 23 Aug 2011 22:44:43 +0200 Subject: pulse/output: fix deadlock when resuming the stream Unlock the mainloop in all code paths. --- src/output/pulse_output_plugin.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/output') diff --git a/src/output/pulse_output_plugin.c b/src/output/pulse_output_plugin.c index d29fbd705..2635ed149 100644 --- a/src/output/pulse_output_plugin.c +++ b/src/output/pulse_output_plugin.c @@ -683,8 +683,10 @@ pulse_output_play(void *data, const void *chunk, size_t size, GError **error_r) /* unpause if previously paused */ if (pulse_output_stream_is_paused(po) && - !pulse_output_stream_pause(po, false, error_r)) + !pulse_output_stream_pause(po, false, error_r)) { + pa_threaded_mainloop_unlock(po->mainloop); return 0; + } /* wait until the server allows us to write */ -- cgit v1.2.3 From 2dc3acc5f06bf6ef83229278119a96337211e22a Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 23 Aug 2011 22:48:15 +0200 Subject: output/pulse: return 0 on error Not a bool. --- src/output/pulse_output_plugin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/output') diff --git a/src/output/pulse_output_plugin.c b/src/output/pulse_output_plugin.c index 2635ed149..79e79095e 100644 --- a/src/output/pulse_output_plugin.c +++ b/src/output/pulse_output_plugin.c @@ -697,7 +697,7 @@ pulse_output_play(void *data, const void *chunk, size_t size, GError **error_r) pa_threaded_mainloop_unlock(po->mainloop); g_set_error(error_r, pulse_output_quark(), 0, "disconnected"); - return false; + return 0; } } -- cgit v1.2.3 From 3db9ab82ea792fbfa398d0d631f976fa33a564fe Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 23 Aug 2011 22:03:24 +0200 Subject: output/pulse: add assertions --- src/output/pulse_output_plugin.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'src/output') diff --git a/src/output/pulse_output_plugin.c b/src/output/pulse_output_plugin.c index 79e79095e..c0633b9fb 100644 --- a/src/output/pulse_output_plugin.c +++ b/src/output/pulse_output_plugin.c @@ -207,6 +207,9 @@ pulse_output_subscribe_cb(pa_context *context, static bool pulse_output_connect(struct pulse_output *po, GError **error_r) { + assert(po != NULL); + assert(po->context != NULL); + int error; error = pa_context_connect(po->context, po->server, @@ -229,6 +232,9 @@ pulse_output_connect(struct pulse_output *po, GError **error_r) static bool pulse_output_setup_context(struct pulse_output *po, GError **error_r) { + assert(po != NULL); + assert(po->mainloop != NULL); + po->context = pa_context_new(pa_threaded_mainloop_get_api(po->mainloop), MPD_PULSE_NAME); if (po->context == NULL) { @@ -257,6 +263,9 @@ pulse_output_setup_context(struct pulse_output *po, GError **error_r) static void pulse_output_delete_context(struct pulse_output *po) { + assert(po != NULL); + assert(po->context != NULL); + pa_context_disconnect(po->context); pa_context_unref(po->context); po->context = NULL; @@ -347,6 +356,8 @@ pulse_output_disable(void *data) { struct pulse_output *po = data; + assert(po->mainloop != NULL); + pa_threaded_mainloop_stop(po->mainloop); if (po->context != NULL) pulse_output_delete_context(po); @@ -363,6 +374,8 @@ pulse_output_disable(void *data) static bool pulse_output_wait_connection(struct pulse_output *po, GError **error_r) { + assert(po->mainloop != NULL); + pa_context_state_t state; pa_threaded_mainloop_lock(po->mainloop); @@ -404,6 +417,10 @@ pulse_output_stream_state_cb(pa_stream *stream, void *userdata) { struct pulse_output *po = userdata; + assert(stream == po->stream || po->stream == NULL); + assert(po->mainloop != NULL); + assert(po->context != NULL); + switch (pa_stream_get_state(stream)) { case PA_STREAM_READY: if (po->mixer != NULL) @@ -432,6 +449,8 @@ pulse_output_stream_write_cb(G_GNUC_UNUSED pa_stream *stream, size_t nbytes, { struct pulse_output *po = userdata; + assert(po->mainloop != NULL); + po->writable = nbytes; pa_threaded_mainloop_signal(po->mainloop, 0); } @@ -444,6 +463,8 @@ pulse_output_open(void *data, struct audio_format *audio_format, pa_sample_spec ss; int error; + assert(po->mainloop != NULL); + if (po->context != NULL) { switch (pa_context_get_state(po->context)) { case PA_CONTEXT_UNCONNECTED: @@ -522,6 +543,8 @@ pulse_output_close(void *data) struct pulse_output *po = data; pa_operation *o; + assert(po->mainloop != NULL); + pa_threaded_mainloop_lock(po->mainloop); if (pa_stream_get_state(po->stream) == PA_STREAM_READY) { @@ -556,6 +579,8 @@ 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: @@ -637,6 +662,8 @@ pulse_output_stream_pause(struct pulse_output *po, bool pause, { pa_operation *o; + assert(po->mainloop != NULL); + assert(po->context != NULL); assert(po->stream != NULL); o = pa_stream_cork(po->stream, pause, @@ -667,6 +694,7 @@ pulse_output_play(void *data, const void *chunk, size_t size, GError **error_r) struct pulse_output *po = data; int error; + assert(po->mainloop != NULL); assert(po->stream != NULL); pa_threaded_mainloop_lock(po->mainloop); @@ -727,6 +755,7 @@ pulse_output_cancel(void *data) struct pulse_output *po = data; pa_operation *o; + assert(po->mainloop != NULL); assert(po->stream != NULL); pa_threaded_mainloop_lock(po->mainloop); @@ -758,6 +787,7 @@ pulse_output_pause(void *data) struct pulse_output *po = data; GError *error = NULL; + assert(po->mainloop != NULL); assert(po->stream != NULL); pa_threaded_mainloop_lock(po->mainloop); -- cgit v1.2.3 From b3df4dc2c92d27034eaf9cef52e97a6e39c77d2e Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 23 Aug 2011 22:43:08 +0200 Subject: output/pulse: fix deadlock when the stream was suspended Check if the stream is suspended; wake up the main loop when it becomes suspended. --- src/output/pulse_output_plugin.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'src/output') diff --git a/src/output/pulse_output_plugin.c b/src/output/pulse_output_plugin.c index c0633b9fb..babb8e221 100644 --- a/src/output/pulse_output_plugin.c +++ b/src/output/pulse_output_plugin.c @@ -412,6 +412,23 @@ pulse_output_wait_connection(struct pulse_output *po, GError **error_r) } } +#if PA_CHECK_VERSION(0,9,8) + +static void +pulse_output_stream_suspended_cb(G_GNUC_UNUSED pa_stream *stream, void *userdata) +{ + struct pulse_output *po = userdata; + + assert(stream == po->stream || po->stream == NULL); + assert(po->mainloop != NULL); + + /* wake up the main loop to break out of the loop in + pulse_output_play() */ + pa_threaded_mainloop_signal(po->mainloop, 0); +} + +#endif + static void pulse_output_stream_state_cb(pa_stream *stream, void *userdata) { @@ -508,6 +525,11 @@ pulse_output_open(void *data, struct audio_format *audio_format, return false; } +#if PA_CHECK_VERSION(0,9,8) + pa_stream_set_suspended_callback(po->stream, + pulse_output_stream_suspended_cb, po); +#endif + pa_stream_set_state_callback(po->stream, pulse_output_stream_state_cb, po); pa_stream_set_write_callback(po->stream, @@ -719,6 +741,15 @@ pulse_output_play(void *data, const void *chunk, size_t size, GError **error_r) /* wait until the server allows us to write */ while (po->writable == 0) { +#if PA_CHECK_VERSION(0,9,8) + if (pa_stream_is_suspended(po->stream)) { + pa_threaded_mainloop_unlock(po->mainloop); + g_set_error(error_r, pulse_output_quark(), 0, + "suspended"); + return 0; + } +#endif + pa_threaded_mainloop_wait(po->mainloop); if (pa_stream_get_state(po->stream) != PA_STREAM_READY) { -- cgit v1.2.3