]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/protocol-esound.c
remap: build sse code only on x86
[pulseaudio] / src / pulsecore / protocol-esound.c
index 840f4581118cd259b977f08fd191e615d960b157..480af6d562609d1b325d4387909a0f974ee43631 100644 (file)
@@ -6,7 +6,7 @@
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
-  by the Free Software Foundation; either version 2 of the License,
+  by the Free Software Foundation; either version 2.1 of the License,
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
 #include <stdlib.h>
 #include <limits.h>
 
 #include <stdlib.h>
 #include <limits.h>
 
+#include <pulse/rtclock.h>
 #include <pulse/sample.h>
 #include <pulse/timeval.h>
 #include <pulse/utf8.h>
 #include <pulse/xmalloc.h>
 #include <pulse/sample.h>
 #include <pulse/timeval.h>
 #include <pulse/utf8.h>
 #include <pulse/xmalloc.h>
+#include <pulse/proplist.h>
 
 #include <pulsecore/esound.h>
 #include <pulsecore/memblock.h>
 
 #include <pulsecore/esound.h>
 #include <pulsecore/memblock.h>
@@ -62,7 +64,7 @@
 #define MAX_CONNECTIONS 64
 
 /* Kick a client if it doesn't authenticate within this time */
 #define MAX_CONNECTIONS 64
 
 /* Kick a client if it doesn't authenticate within this time */
-#define AUTH_TIMEOUT 5
+#define AUTH_TIMEOUT (5*PA_USEC_PER_SEC)
 
 #define DEFAULT_COOKIE_FILE ".esd_auth"
 
 
 #define DEFAULT_COOKIE_FILE ".esd_auth"
 
@@ -118,9 +120,8 @@ typedef struct connection {
     pa_time_event *auth_timeout_event;
 } connection;
 
     pa_time_event *auth_timeout_event;
 } connection;
 
-PA_DECLARE_CLASS(connection);
+PA_DEFINE_PRIVATE_CLASS(connection, pa_msgobject);
 #define CONNECTION(o) (connection_cast(o))
 #define CONNECTION(o) (connection_cast(o))
-static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject);
 
 struct pa_esound_protocol {
     PA_REFCNT_DECLARE;
 
 struct pa_esound_protocol {
     PA_REFCNT_DECLARE;
@@ -164,10 +165,12 @@ static int esd_proto_get_latency(connection *c, esd_proto_t request, const void
 static int esd_proto_server_info(connection *c, esd_proto_t request, const void *data, size_t length);
 static int esd_proto_all_info(connection *c, esd_proto_t request, const void *data, size_t length);
 static int esd_proto_stream_pan(connection *c, esd_proto_t request, const void *data, size_t length);
 static int esd_proto_server_info(connection *c, esd_proto_t request, const void *data, size_t length);
 static int esd_proto_all_info(connection *c, esd_proto_t request, const void *data, size_t length);
 static int esd_proto_stream_pan(connection *c, esd_proto_t request, const void *data, size_t length);
+static int esd_proto_sample_pan(connection *c, esd_proto_t request, const void *data, size_t length);
 static int esd_proto_sample_cache(connection *c, esd_proto_t request, const void *data, size_t length);
 static int esd_proto_sample_free_or_play(connection *c, esd_proto_t request, const void *data, size_t length);
 static int esd_proto_sample_get_id(connection *c, esd_proto_t request, const void *data, size_t length);
 static int esd_proto_standby_or_resume(connection *c, esd_proto_t request, const void *data, size_t length);
 static int esd_proto_sample_cache(connection *c, esd_proto_t request, const void *data, size_t length);
 static int esd_proto_sample_free_or_play(connection *c, esd_proto_t request, const void *data, size_t length);
 static int esd_proto_sample_get_id(connection *c, esd_proto_t request, const void *data, size_t length);
 static int esd_proto_standby_or_resume(connection *c, esd_proto_t request, const void *data, size_t length);
+static int esd_proto_standby_mode(connection *c, esd_proto_t request, const void *data, size_t length);
 
 /* the big map of protocol handler info */
 static struct proto_handler proto_map[ESD_PROTO_MAX] = {
 
 /* the big map of protocol handler info */
 static struct proto_handler proto_map[ESD_PROTO_MAX] = {
@@ -186,8 +189,8 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = {
     { sizeof(int),                    NULL, "sample stop" },
     { (size_t) -1,                    NULL, "TODO: sample kill" },
 
     { sizeof(int),                    NULL, "sample stop" },
     { (size_t) -1,                    NULL, "TODO: sample kill" },
 
-    { ESD_KEY_LEN + sizeof(int),      esd_proto_standby_or_resume, "standby" },  /* NOOP! */
-    { ESD_KEY_LEN + sizeof(int),      esd_proto_standby_or_resume, "resume" },   /* NOOP! */         /* 13 */
+    { ESD_KEY_LEN + sizeof(int),      esd_proto_standby_or_resume, "standby" },
+    { ESD_KEY_LEN + sizeof(int),      esd_proto_standby_or_resume, "resume" },                       /* 13 */
 
     { ESD_NAME_MAX,                   esd_proto_sample_get_id, "sample getid" },                     /* 14 */
     { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" },
 
     { ESD_NAME_MAX,                   esd_proto_sample_get_id, "sample getid" },                     /* 14 */
     { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" },
@@ -198,9 +201,9 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = {
     { (size_t) -1,                    NULL, "TODO: unsubscribe" },
 
     { 3 * sizeof(int),                esd_proto_stream_pan, "stream pan"},
     { (size_t) -1,                    NULL, "TODO: unsubscribe" },
 
     { 3 * sizeof(int),                esd_proto_stream_pan, "stream pan"},
-    { 3 * sizeof(int),                NULL, "sample pan" },
+    { 3 * sizeof(int),                esd_proto_sample_pan, "sample pan" },
 
 
-    { sizeof(int),                    NULL, "standby mode" },
+    { sizeof(int),                    esd_proto_standby_mode, "standby mode" },
     { 0,                              esd_proto_get_latency, "get latency" }
 };
 
     { 0,                              esd_proto_get_latency, "get latency" }
 };
 
@@ -372,6 +375,8 @@ static int esd_proto_connect(connection *c, esd_proto_t request, const void *dat
         return -1;
     }
 
         return -1;
     }
 
+    pa_proplist_sets(c->client->proplist, "esound.byte_order", c->swap_byte_order ? "reverse" : "native");
+
     ok = 1;
     connection_write(c, &ok, sizeof(int));
     return 0;
     ok = 1;
     connection_write(c, &ok, sizeof(int));
     return 0;
@@ -404,7 +409,7 @@ static int esd_proto_stream_play(connection *c, esd_proto_t request, const void
 
     if (c->options->default_sink) {
         sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK);
 
     if (c->options->default_sink) {
         sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK);
-        CHECK_VALIDITY(sink, "No such sink: %s", c->options->default_sink);
+        CHECK_VALIDITY(sink, "No such sink: %s", pa_strnull(c->options->default_sink));
     }
 
     pa_strlcpy(name, data, sizeof(name));
     }
 
     pa_strlcpy(name, data, sizeof(name));
@@ -424,7 +429,7 @@ static int esd_proto_stream_play(connection *c, esd_proto_t request, const void
     sdata.sink = sink;
     pa_sink_input_new_data_set_sample_spec(&sdata, &ss);
 
     sdata.sink = sink;
     pa_sink_input_new_data_set_sample_spec(&sdata, &ss);
 
-    pa_sink_input_new(&c->sink_input, c->protocol->core, &sdata, 0);
+    pa_sink_input_new(&c->sink_input, c->protocol->core, &sdata);
     pa_sink_input_new_data_done(&sdata);
 
     CHECK_VALIDITY(c->sink_input, "Failed to create sink input.");
     pa_sink_input_new_data_done(&sdata);
 
     CHECK_VALIDITY(c->sink_input, "Failed to create sink input.");
@@ -489,23 +494,17 @@ static int esd_proto_stream_record(connection *c, esd_proto_t request, const voi
     if (request == ESD_PROTO_STREAM_MON) {
         pa_sink* sink;
 
     if (request == ESD_PROTO_STREAM_MON) {
         pa_sink* sink;
 
-        if (!(sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK))) {
-            pa_log("no such sink.");
-            return -1;
-        }
+        sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK);
+        CHECK_VALIDITY(sink, "No such sink: %s", pa_strnull(c->options->default_sink));
 
 
-        if (!(source = sink->monitor_source)) {
-            pa_log("no such monitor source.");
-            return -1;
-        }
+        source = sink->monitor_source;
+        CHECK_VALIDITY(source, "No such source.");
     } else {
         pa_assert(request == ESD_PROTO_STREAM_REC);
 
         if (c->options->default_source) {
     } else {
         pa_assert(request == ESD_PROTO_STREAM_REC);
 
         if (c->options->default_source) {
-            if (!(source = pa_namereg_get(c->protocol->core, c->options->default_source, PA_NAMEREG_SOURCE))) {
-                pa_log("no such source.");
-                return -1;
-            }
+            source = pa_namereg_get(c->protocol->core, c->options->default_source, PA_NAMEREG_SOURCE);
+            CHECK_VALIDITY(source, "No such source: %s", pa_strnull(c->options->default_source));
         }
     }
 
         }
     }
 
@@ -526,7 +525,7 @@ static int esd_proto_stream_record(connection *c, esd_proto_t request, const voi
     sdata.source = source;
     pa_source_output_new_data_set_sample_spec(&sdata, &ss);
 
     sdata.source = source;
     pa_source_output_new_data_set_sample_spec(&sdata, &ss);
 
-    pa_source_output_new(&c->source_output, c->protocol->core, &sdata, 0);
+    pa_source_output_new(&c->source_output, c->protocol->core, &sdata);
     pa_source_output_new_data_done(&sdata);
 
     CHECK_VALIDITY(c->source_output, "Failed to create source output.");
     pa_source_output_new_data_done(&sdata);
 
     CHECK_VALIDITY(c->source_output, "Failed to create source output.");
@@ -563,19 +562,20 @@ static int esd_proto_get_latency(connection *c, esd_proto_t request, const void
     pa_sink *sink;
     int32_t latency;
 
     pa_sink *sink;
     int32_t latency;
 
-    connection_ref(c);
+    connection_assert_ref(c);
     pa_assert(!data);
     pa_assert(length == 0);
 
     if (!(sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK)))
         latency = 0;
     else {
     pa_assert(!data);
     pa_assert(length == 0);
 
     if (!(sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK)))
         latency = 0;
     else {
-        double usec = (double) pa_sink_get_latency(sink);
+        double usec = (double) pa_sink_get_requested_latency(sink);
         latency = (int) ((usec*44100)/1000000);
     }
 
     latency = PA_MAYBE_INT32_SWAP(c->swap_byte_order, latency);
     connection_write(c, &latency, sizeof(int32_t));
         latency = (int) ((usec*44100)/1000000);
     }
 
     latency = PA_MAYBE_INT32_SWAP(c->swap_byte_order, latency);
     connection_write(c, &latency, sizeof(int32_t));
+
     return 0;
 }
 
     return 0;
 }
 
@@ -584,7 +584,7 @@ static int esd_proto_server_info(connection *c, esd_proto_t request, const void
     int32_t response;
     pa_sink *sink;
 
     int32_t response;
     pa_sink *sink;
 
-    connection_ref(c);
+    connection_assert_ref(c);
     pa_assert(data);
     pa_assert(length == sizeof(int32_t));
 
     pa_assert(data);
     pa_assert(length == sizeof(int32_t));
 
@@ -612,7 +612,7 @@ static int esd_proto_all_info(connection *c, esd_proto_t request, const void *da
     unsigned nsamples;
     char terminator[sizeof(int32_t)*6+ESD_NAME_MAX];
 
     unsigned nsamples;
     char terminator[sizeof(int32_t)*6+ESD_NAME_MAX];
 
-    connection_ref(c);
+    connection_assert_ref(c);
     pa_assert(data);
     pa_assert(length == sizeof(int32_t));
 
     pa_assert(data);
     pa_assert(length == sizeof(int32_t));
 
@@ -621,7 +621,7 @@ static int esd_proto_all_info(connection *c, esd_proto_t request, const void *da
 
     k = sizeof(int32_t)*5+ESD_NAME_MAX;
     s = sizeof(int32_t)*6+ESD_NAME_MAX;
 
     k = sizeof(int32_t)*5+ESD_NAME_MAX;
     s = sizeof(int32_t)*6+ESD_NAME_MAX;
-    nsamples = c->protocol->core->scache ? pa_idxset_size(c->protocol->core->scache) : 0;
+    nsamples = pa_idxset_size(c->protocol->core->scache);
     t = s*(nsamples+1) + k*(c->protocol->n_player+1);
 
     connection_write_prepare(c, t);
     t = s*(nsamples+1) + k*(c->protocol->n_player+1);
 
     connection_write_prepare(c, t);
@@ -638,10 +638,11 @@ static int esd_proto_all_info(connection *c, esd_proto_t request, const void *da
         pa_assert(t >= k*2+s);
 
         if (conn->sink_input) {
         pa_assert(t >= k*2+s);
 
         if (conn->sink_input) {
-            pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input);
+            pa_cvolume volume;
+            pa_sink_input_get_volume(conn->sink_input, &volume, TRUE);
             rate = (int32_t) conn->sink_input->sample_spec.rate;
             lvolume = (int32_t) ((volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM);
             rate = (int32_t) conn->sink_input->sample_spec.rate;
             lvolume = (int32_t) ((volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM);
-            rvolume = (int32_t) ((volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM);
+            rvolume = (int32_t) ((volume.values[volume.channels == 2 ? 1 : 0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM);
             format = format_native2esd(&conn->sink_input->sample_spec);
         }
 
             format = format_native2esd(&conn->sink_input->sample_spec);
         }
 
@@ -688,9 +689,26 @@ static int esd_proto_all_info(connection *c, esd_proto_t request, const void *da
         for (ce = pa_idxset_first(c->protocol->core->scache, &idx); ce; ce = pa_idxset_next(c->protocol->core->scache, &idx)) {
             int32_t id, rate, lvolume, rvolume, format, len;
             char name[ESD_NAME_MAX];
         for (ce = pa_idxset_first(c->protocol->core->scache, &idx); ce; ce = pa_idxset_next(c->protocol->core->scache, &idx)) {
             int32_t id, rate, lvolume, rvolume, format, len;
             char name[ESD_NAME_MAX];
+            pa_channel_map stereo = { .channels = 2, .map = { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT } };
+            pa_cvolume volume;
+            pa_sample_spec ss;
 
             pa_assert(t >= s*2);
 
 
             pa_assert(t >= s*2);
 
+            if (ce->volume_is_set) {
+                volume = ce->volume;
+                pa_cvolume_remap(&volume, &ce->channel_map, &stereo);
+            } else
+                pa_cvolume_reset(&volume, 2);
+
+            if (ce->memchunk.memblock)
+                ss = ce->sample_spec;
+            else {
+                ss.format = PA_SAMPLE_S16NE;
+                ss.rate = 44100;
+                ss.channels = 2;
+            }
+
             /* id */
             id = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1));
             connection_write(c, &id, sizeof(int32_t));
             /* id */
             id = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1));
             connection_write(c, &id, sizeof(int32_t));
@@ -704,19 +722,19 @@ static int esd_proto_all_info(connection *c, esd_proto_t request, const void *da
             connection_write(c, name, ESD_NAME_MAX);
 
             /* rate */
             connection_write(c, name, ESD_NAME_MAX);
 
             /* rate */
-            rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) ce->sample_spec.rate);
+            rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) ss.rate);
             connection_write(c, &rate, sizeof(int32_t));
 
             /* left */
             connection_write(c, &rate, sizeof(int32_t));
 
             /* left */
-            lvolume = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) ((ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM));
+            lvolume = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) ((volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM));
             connection_write(c, &lvolume, sizeof(int32_t));
 
             /*right*/
             connection_write(c, &lvolume, sizeof(int32_t));
 
             /*right*/
-            rvolume = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) ((ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM));
+            rvolume = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) ((volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM));
             connection_write(c, &rvolume, sizeof(int32_t));
 
             /*format*/
             connection_write(c, &rvolume, sizeof(int32_t));
 
             /*format*/
-            format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec));
+            format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ss));
             connection_write(c, &format, sizeof(int32_t));
 
             /*length*/
             connection_write(c, &format, sizeof(int32_t));
 
             /*length*/
@@ -759,8 +777,9 @@ static int esd_proto_stream_pan(connection *c, esd_proto_t request, const void *
         pa_cvolume volume;
         volume.values[0] = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE;
         volume.values[1] = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE;
         pa_cvolume volume;
         volume.values[0] = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE;
         volume.values[1] = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE;
-        volume.channels = 2;
-        pa_sink_input_set_volume(conn->sink_input, &volume, TRUE);
+        volume.channels = conn->sink_input->sample_spec.channels;
+
+        pa_sink_input_set_volume(conn->sink_input, &volume, TRUE, TRUE);
         ok = 1;
     } else
         ok = 0;
         ok = 1;
     } else
         ok = 0;
@@ -770,6 +789,46 @@ static int esd_proto_stream_pan(connection *c, esd_proto_t request, const void *
     return 0;
 }
 
     return 0;
 }
 
+static int esd_proto_sample_pan(connection *c, esd_proto_t request, const void *data, size_t length) {
+    int32_t ok = 0;
+    uint32_t idx, lvolume, rvolume;
+    pa_cvolume volume;
+    pa_scache_entry *ce;
+
+    connection_assert_ref(c);
+    pa_assert(data);
+    pa_assert(length == sizeof(int32_t)*3);
+
+    memcpy(&idx, data, sizeof(uint32_t));
+    idx = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1;
+    data = (const char*)data + sizeof(uint32_t);
+
+    memcpy(&lvolume, data, sizeof(uint32_t));
+    lvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, lvolume);
+    data = (const char*)data + sizeof(uint32_t);
+
+    memcpy(&rvolume, data, sizeof(uint32_t));
+    rvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume);
+    data = (const char*)data + sizeof(uint32_t);
+
+    volume.values[0] = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE;
+    volume.values[1] = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE;
+    volume.channels = 2;
+
+    if ((ce = pa_idxset_get_by_index(c->protocol->core->scache, idx))) {
+        pa_channel_map stereo = { .channels = 2, .map = { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT } };
+
+        pa_cvolume_remap(&volume, &stereo, &ce->channel_map);
+        ce->volume = volume;
+        ce->volume_is_set = TRUE;
+        ok = 1;
+    }
+
+    connection_write(c, &ok, sizeof(int32_t));
+
+    return 0;
+}
+
 static int esd_proto_sample_cache(connection *c, esd_proto_t request, const void *data, size_t length) {
     pa_sample_spec ss;
     int32_t format, rate, sc_length;
 static int esd_proto_sample_cache(connection *c, esd_proto_t request, const void *data, size_t length) {
     pa_sample_spec ss;
     int32_t format, rate, sc_length;
@@ -880,19 +939,47 @@ static int esd_proto_sample_free_or_play(connection *c, esd_proto_t request, con
 }
 
 static int esd_proto_standby_or_resume(connection *c, esd_proto_t request, const void *data, size_t length) {
 }
 
 static int esd_proto_standby_or_resume(connection *c, esd_proto_t request, const void *data, size_t length) {
-    int32_t ok;
+    int32_t ok = 1;
 
     connection_assert_ref(c);
 
     connection_write_prepare(c, sizeof(int32_t) * 2);
 
     connection_assert_ref(c);
 
     connection_write_prepare(c, sizeof(int32_t) * 2);
-
-    ok = 1;
     connection_write(c, &ok, sizeof(int32_t));
     connection_write(c, &ok, sizeof(int32_t));
+
+    if (request == ESD_PROTO_STANDBY)
+        ok = pa_sink_suspend_all(c->protocol->core, TRUE, PA_SUSPEND_USER) >= 0;
+    else {
+        pa_assert(request == ESD_PROTO_RESUME);
+        ok = pa_sink_suspend_all(c->protocol->core, FALSE, PA_SUSPEND_USER) >= 0;
+    }
+
     connection_write(c, &ok, sizeof(int32_t));
 
     return 0;
 }
 
     connection_write(c, &ok, sizeof(int32_t));
 
     return 0;
 }
 
+static int esd_proto_standby_mode(connection *c, esd_proto_t request, const void *data, size_t length) {
+    int32_t mode;
+    pa_sink *sink, *source;
+
+    connection_assert_ref(c);
+
+    mode = ESM_RUNNING;
+
+    if ((sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK)))
+        if (pa_sink_get_state(sink) == PA_SINK_SUSPENDED)
+            mode = ESM_ON_STANDBY;
+
+    if ((source = pa_namereg_get(c->protocol->core, c->options->default_source, PA_NAMEREG_SOURCE)))
+        if (pa_source_get_state(source) == PA_SOURCE_SUSPENDED)
+            mode = ESM_ON_STANDBY;
+
+    mode = PA_MAYBE_INT32_SWAP(c->swap_byte_order, mode);
+
+    connection_write(c, &mode, sizeof(mode));
+    return 0;
+}
+
 /*** client callbacks ***/
 
 static void client_kill_cb(pa_client *c) {
 /*** client callbacks ***/
 
 static void client_kill_cb(pa_client *c) {
@@ -912,7 +999,13 @@ static int do_read(connection *c) {
         ssize_t r;
         pa_assert(c->read_data_length < sizeof(c->request));
 
         ssize_t r;
         pa_assert(c->read_data_length < sizeof(c->request));
 
-        if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) {
+        if ((r = pa_iochannel_read(c->io,
+                                   ((uint8_t*) &c->request) + c->read_data_length,
+                                   sizeof(c->request) - c->read_data_length)) <= 0) {
+
+            if (r < 0 && (errno == EINTR || errno == EAGAIN))
+                return 0;
+
             pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF");
             return -1;
         }
             pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF");
             return -1;
         }
@@ -962,7 +1055,10 @@ static int do_read(connection *c) {
 
         pa_assert(c->read_data && c->read_data_length < handler->data_length);
 
 
         pa_assert(c->read_data && c->read_data_length < handler->data_length);
 
-        if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) {
+        if ((r = pa_iochannel_read(c->io,
+                                   (uint8_t*) c->read_data + c->read_data_length,
+                                   handler->data_length - c->read_data_length)) <= 0) {
+
             if (r < 0 && (errno == EINTR || errno == EAGAIN))
                 return 0;
 
             if (r < 0 && (errno == EINTR || errno == EAGAIN))
                 return 0;
 
@@ -1011,8 +1107,7 @@ static int do_read(connection *c) {
             pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, NULL, &c->scache.memchunk, c->client->proplist, &idx);
 
             pa_memblock_unref(c->scache.memchunk.memblock);
             pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, NULL, &c->scache.memchunk, c->client->proplist, &idx);
 
             pa_memblock_unref(c->scache.memchunk.memblock);
-            c->scache.memchunk.memblock = NULL;
-            c->scache.memchunk.index = c->scache.memchunk.length = 0;
+            pa_memchunk_reset(&c->scache.memchunk);
 
             pa_xfree(c->scache.name);
             c->scache.name = NULL;
 
             pa_xfree(c->scache.name);
             c->scache.name = NULL;
@@ -1196,6 +1291,9 @@ static int connection_process_msg(pa_msgobject *o, int code, void*userdata, int6
     connection *c = CONNECTION(o);
     connection_assert_ref(c);
 
     connection *c = CONNECTION(o);
     connection_assert_ref(c);
 
+    if (!c->protocol)
+        return -1;
+
     switch (code) {
         case CONNECTION_MESSAGE_REQUEST_DATA:
             do_work(c);
     switch (code) {
         case CONNECTION_MESSAGE_REQUEST_DATA:
             do_work(c);
@@ -1361,11 +1459,10 @@ static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
 
 /*** entry points ***/
 
 
 /*** entry points ***/
 
-static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
+static void auth_timeout(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
     connection *c = CONNECTION(userdata);
 
     pa_assert(m);
     connection *c = CONNECTION(userdata);
 
     pa_assert(m);
-    pa_assert(tv);
     connection_assert_ref(c);
     pa_assert(c->auth_timeout_event == e);
 
     connection_assert_ref(c);
     pa_assert(c->auth_timeout_event == e);
 
@@ -1455,12 +1552,9 @@ void pa_esound_protocol_connect(pa_esound_protocol *p, pa_iochannel *io, pa_esou
         c->authorized = TRUE;
     }
 
         c->authorized = TRUE;
     }
 
-    if (!c->authorized) {
-        struct timeval tv;
-        pa_gettimeofday(&tv);
-        tv.tv_sec += AUTH_TIMEOUT;
-        c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c);
-    } else
+    if (!c->authorized)
+        c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
+    else
         c->auth_timeout_event = NULL;
 
     c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c);
         c->auth_timeout_event = NULL;
 
     c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c);