4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2 of the License,
12 or (at your option) any later version.
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
35 #include <pulse/sample.h>
36 #include <pulse/timeval.h>
37 #include <pulse/utf8.h>
38 #include <pulse/xmalloc.h>
40 #include <pulsecore/esound.h>
41 #include <pulsecore/memblock.h>
42 #include <pulsecore/client.h>
43 #include <pulsecore/sink-input.h>
44 #include <pulsecore/sink.h>
45 #include <pulsecore/source-output.h>
46 #include <pulsecore/source.h>
47 #include <pulsecore/core-scache.h>
48 #include <pulsecore/sample-util.h>
49 #include <pulsecore/authkey.h>
50 #include <pulsecore/namereg.h>
51 #include <pulsecore/log.h>
52 #include <pulsecore/core-util.h>
53 #include <pulsecore/core-error.h>
54 #include <pulsecore/ipacl.h>
55 #include <pulsecore/macro.h>
56 #include <pulsecore/thread-mq.h>
58 #include "endianmacros.h"
60 #include "protocol-esound.h"
62 /* Don't accept more connection than this */
63 #define MAX_CONNECTIONS 64
65 /* Kick a client if it doesn't authenticate within this time */
66 #define AUTH_TIMEOUT 5
68 #define DEFAULT_COOKIE_FILE ".esd_auth"
70 #define PLAYBACK_BUFFER_SECONDS (.25)
71 #define PLAYBACK_BUFFER_FRAGMENTS (10)
72 #define RECORD_BUFFER_SECONDS (5)
73 #define RECORD_BUFFER_FRAGMENTS (100)
75 #define MAX_CACHE_SAMPLE_SIZE (1024000)
77 #define SCACHE_PREFIX "esound."
79 /* This is heavily based on esound's code */
81 typedef struct connection
{
86 pa_protocol_esound
*protocol
;
89 pa_bool_t authorized
, swap_byte_order
;
91 size_t write_data_alloc
, write_data_index
, write_data_length
;
93 size_t read_data_alloc
, read_data_length
;
95 esd_client_state_t state
;
96 pa_sink_input
*sink_input
;
97 pa_source_output
*source_output
;
98 pa_memblockq
*input_memblockq
, *output_memblockq
;
99 pa_defer_event
*defer_event
;
104 pa_memblock
*current_memblock
;
105 size_t memblock_index
, fragment_size
;
110 pa_memchunk memchunk
;
112 pa_sample_spec sample_spec
;
115 pa_time_event
*auth_timeout_event
;
118 PA_DECLARE_CLASS(connection
);
119 #define CONNECTION(o) (connection_cast(o))
120 static PA_DEFINE_CHECK_TYPE(connection
, pa_msgobject
);
122 struct pa_protocol_esound
{
126 pa_socket_server
*server
;
127 pa_idxset
*connections
;
129 char *sink_name
, *source_name
;
131 uint8_t esd_key
[ESD_KEY_LEN
];
132 pa_ip_acl
*auth_ip_acl
;
136 SINK_INPUT_MESSAGE_POST_DATA
= PA_SINK_INPUT_MESSAGE_MAX
, /* data from main loop to sink input */
137 SINK_INPUT_MESSAGE_DISABLE_PREBUF
141 CONNECTION_MESSAGE_REQUEST_DATA
,
142 CONNECTION_MESSAGE_POST_DATA
,
143 CONNECTION_MESSAGE_UNLINK_CONNECTION
146 typedef struct proto_handler
{
148 int (*proc
)(connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
149 const char *description
;
150 } esd_proto_handler_info_t
;
152 static int sink_input_pop_cb(pa_sink_input
*i
, size_t length
, pa_memchunk
*chunk
);
153 static void sink_input_kill_cb(pa_sink_input
*i
);
154 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
);
155 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
);
157 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
);
158 static void source_output_kill_cb(pa_source_output
*o
);
160 static int esd_proto_connect(connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
161 static int esd_proto_stream_play(connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
162 static int esd_proto_stream_record(connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
163 static int esd_proto_get_latency(connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
164 static int esd_proto_server_info(connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
165 static int esd_proto_all_info(connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
166 static int esd_proto_stream_pan(connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
167 static int esd_proto_sample_cache(connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
168 static int esd_proto_sample_free_or_play(connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
169 static int esd_proto_sample_get_id(connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
170 static int esd_proto_standby_or_resume(connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
172 /* the big map of protocol handler info */
173 static struct proto_handler proto_map
[ESD_PROTO_MAX
] = {
174 { ESD_KEY_LEN
+ sizeof(int), esd_proto_connect
, "connect" },
175 { ESD_KEY_LEN
+ sizeof(int), NULL
, "lock" },
176 { ESD_KEY_LEN
+ sizeof(int), NULL
, "unlock" },
178 { ESD_NAME_MAX
+ 2 * sizeof(int), esd_proto_stream_play
, "stream play" },
179 { ESD_NAME_MAX
+ 2 * sizeof(int), esd_proto_stream_record
, "stream rec" },
180 { ESD_NAME_MAX
+ 2 * sizeof(int), esd_proto_stream_record
, "stream mon" },
182 { ESD_NAME_MAX
+ 3 * sizeof(int), esd_proto_sample_cache
, "sample cache" }, /* 6 */
183 { sizeof(int), esd_proto_sample_free_or_play
, "sample free" },
184 { sizeof(int), esd_proto_sample_free_or_play
, "sample play" }, /* 8 */
185 { sizeof(int), NULL
, "sample loop" },
186 { sizeof(int), NULL
, "sample stop" },
187 { -1, NULL
, "TODO: sample kill" },
189 { ESD_KEY_LEN
+ sizeof(int), esd_proto_standby_or_resume
, "standby" }, /* NOOP! */
190 { ESD_KEY_LEN
+ sizeof(int), esd_proto_standby_or_resume
, "resume" }, /* NOOP! */ /* 13 */
192 { ESD_NAME_MAX
, esd_proto_sample_get_id
, "sample getid" }, /* 14 */
193 { ESD_NAME_MAX
+ 2 * sizeof(int), NULL
, "stream filter" },
195 { sizeof(int), esd_proto_server_info
, "server info" },
196 { sizeof(int), esd_proto_all_info
, "all info" },
197 { -1, NULL
, "TODO: subscribe" },
198 { -1, NULL
, "TODO: unsubscribe" },
200 { 3 * sizeof(int), esd_proto_stream_pan
, "stream pan"},
201 { 3 * sizeof(int), NULL
, "sample pan" },
203 { sizeof(int), NULL
, "standby mode" },
204 { 0, esd_proto_get_latency
, "get latency" }
207 static void connection_unlink(connection
*c
) {
214 pa_sink_input_unlink(c
->sink_input
);
215 pa_sink_input_unref(c
->sink_input
);
216 c
->sink_input
= NULL
;
219 if (c
->source_output
) {
220 pa_source_output_unlink(c
->source_output
);
221 pa_source_output_unref(c
->source_output
);
222 c
->source_output
= NULL
;
226 pa_client_free(c
->client
);
230 if (c
->state
== ESD_STREAMING_DATA
)
231 c
->protocol
->n_player
--;
234 pa_iochannel_free(c
->io
);
238 if (c
->defer_event
) {
239 c
->protocol
->core
->mainloop
->defer_free(c
->defer_event
);
240 c
->defer_event
= NULL
;
243 if (c
->auth_timeout_event
) {
244 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
245 c
->auth_timeout_event
= NULL
;
248 pa_assert_se(pa_idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
) == c
);
253 static void connection_free(pa_object
*obj
) {
254 connection
*c
= CONNECTION(obj
);
257 if (c
->input_memblockq
)
258 pa_memblockq_free(c
->input_memblockq
);
259 if (c
->output_memblockq
)
260 pa_memblockq_free(c
->output_memblockq
);
262 if (c
->playback
.current_memblock
)
263 pa_memblock_unref(c
->playback
.current_memblock
);
265 pa_xfree(c
->read_data
);
266 pa_xfree(c
->write_data
);
268 if (c
->scache
.memchunk
.memblock
)
269 pa_memblock_unref(c
->scache
.memchunk
.memblock
);
270 pa_xfree(c
->scache
.name
);
272 pa_xfree(c
->original_name
);
276 static void connection_write_prepare(connection
*c
, size_t length
) {
280 t
= c
->write_data_length
+length
;
282 if (c
->write_data_alloc
< t
)
283 c
->write_data
= pa_xrealloc(c
->write_data
, c
->write_data_alloc
= t
);
285 pa_assert(c
->write_data
);
288 static void connection_write(connection
*c
, const void *data
, size_t length
) {
292 c
->protocol
->core
->mainloop
->defer_enable(c
->defer_event
, 1);
294 connection_write_prepare(c
, length
);
296 pa_assert(c
->write_data
);
298 i
= c
->write_data_length
;
299 c
->write_data_length
+= length
;
301 memcpy((uint8_t*) c
->write_data
+ i
, data
, length
);
304 static void format_esd2native(int format
, pa_bool_t swap_bytes
, pa_sample_spec
*ss
) {
307 ss
->channels
= ((format
& ESD_MASK_CHAN
) == ESD_STEREO
) ? 2 : 1;
308 if ((format
& ESD_MASK_BITS
) == ESD_BITS16
)
309 ss
->format
= swap_bytes
? PA_SAMPLE_S16RE
: PA_SAMPLE_S16NE
;
311 ss
->format
= PA_SAMPLE_U8
;
314 static int format_native2esd(pa_sample_spec
*ss
) {
317 format
= (ss
->format
== PA_SAMPLE_U8
) ? ESD_BITS8
: ESD_BITS16
;
318 format
|= (ss
->channels
>= 2) ? ESD_STEREO
: ESD_MONO
;
323 #define CHECK_VALIDITY(expression, ...) do { \
324 if (!(expression)) { \
325 pa_log_warn(__FILE__ ": " __VA_ARGS__); \
330 /*** esound commands ***/
332 static int esd_proto_connect(connection
*c
, PA_GCC_UNUSED esd_proto_t request
, const void *data
, size_t length
) {
336 connection_assert_ref(c
);
338 pa_assert(length
== (ESD_KEY_LEN
+ sizeof(uint32_t)));
340 if (!c
->authorized
) {
341 if (memcmp(data
, c
->protocol
->esd_key
, ESD_KEY_LEN
) != 0) {
342 pa_log("kicked client with invalid authorization key.");
346 c
->authorized
= TRUE
;
347 if (c
->auth_timeout_event
) {
348 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
349 c
->auth_timeout_event
= NULL
;
353 data
= (const char*)data
+ ESD_KEY_LEN
;
355 memcpy(&ekey
, data
, sizeof(uint32_t));
356 if (ekey
== ESD_ENDIAN_KEY
)
357 c
->swap_byte_order
= FALSE
;
358 else if (ekey
== ESD_SWAP_ENDIAN_KEY
)
359 c
->swap_byte_order
= TRUE
;
361 pa_log_warn("Client sent invalid endian key");
366 connection_write(c
, &ok
, sizeof(int));
370 static int esd_proto_stream_play(connection
*c
, PA_GCC_UNUSED esd_proto_t request
, const void *data
, size_t length
) {
371 char name
[ESD_NAME_MAX
], *utf8_name
;
372 int32_t format
, rate
;
375 pa_sink
*sink
= NULL
;
376 pa_sink_input_new_data sdata
;
378 connection_assert_ref(c
);
380 pa_assert(length
== (sizeof(int32_t)*2+ESD_NAME_MAX
));
382 memcpy(&format
, data
, sizeof(int32_t));
383 format
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, format
);
384 data
= (const char*) data
+ sizeof(int32_t);
386 memcpy(&rate
, data
, sizeof(int32_t));
387 rate
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, rate
);
388 data
= (const char*) data
+ sizeof(int32_t);
391 format_esd2native(format
, c
->swap_byte_order
, &ss
);
393 CHECK_VALIDITY(pa_sample_spec_valid(&ss
), "Invalid sample specification");
395 if (c
->protocol
->sink_name
) {
396 sink
= pa_namereg_get(c
->protocol
->core
, c
->protocol
->sink_name
, PA_NAMEREG_SINK
, 1);
397 CHECK_VALIDITY(sink
, "No such sink: %s", c
->protocol
->sink_name
);
400 strncpy(name
, data
, sizeof(name
));
401 name
[sizeof(name
)-1] = 0;
403 utf8_name
= pa_utf8_filter(name
);
404 pa_client_set_name(c
->client
, utf8_name
);
407 c
->original_name
= pa_xstrdup(name
);
409 pa_assert(!c
->sink_input
&& !c
->input_memblockq
);
411 pa_sink_input_new_data_init(&sdata
);
412 sdata
.driver
= __FILE__
;
413 sdata
.module
= c
->protocol
->module
;
414 sdata
.client
= c
->client
;
416 pa_proplist_update(sdata
.proplist
, PA_UPDATE_MERGE
, c
->client
->proplist
);
417 pa_sink_input_new_data_set_sample_spec(&sdata
, &ss
);
419 c
->sink_input
= pa_sink_input_new(c
->protocol
->core
, &sdata
, 0);
420 pa_sink_input_new_data_done(&sdata
);
422 CHECK_VALIDITY(c
->sink_input
, "Failed to create sink input.");
424 l
= (size_t) (pa_bytes_per_second(&ss
)*PLAYBACK_BUFFER_SECONDS
);
425 c
->input_memblockq
= pa_memblockq_new(
431 l
/PLAYBACK_BUFFER_FRAGMENTS
,
434 pa_iochannel_socket_set_rcvbuf(c
->io
, l
/PLAYBACK_BUFFER_FRAGMENTS
*2);
435 c
->playback
.fragment_size
= l
/PLAYBACK_BUFFER_FRAGMENTS
;
437 c
->sink_input
->parent
.process_msg
= sink_input_process_msg
;
438 c
->sink_input
->pop
= sink_input_pop_cb
;
439 c
->sink_input
->kill
= sink_input_kill_cb
;
440 c
->sink_input
->userdata
= c
;
442 c
->state
= ESD_STREAMING_DATA
;
444 c
->protocol
->n_player
++;
446 pa_atomic_store(&c
->playback
.missing
, pa_memblockq_missing(c
->input_memblockq
));
448 pa_sink_input_put(c
->sink_input
);
453 static int esd_proto_stream_record(connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
454 char name
[ESD_NAME_MAX
], *utf8_name
;
455 int32_t format
, rate
;
456 pa_source
*source
= NULL
;
459 pa_source_output_new_data sdata
;
461 connection_assert_ref(c
);
463 pa_assert(length
== (sizeof(int32_t)*2+ESD_NAME_MAX
));
465 memcpy(&format
, data
, sizeof(int32_t));
466 format
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, format
);
467 data
= (const char*) data
+ sizeof(int32_t);
469 memcpy(&rate
, data
, sizeof(int32_t));
470 rate
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, rate
);
471 data
= (const char*) data
+ sizeof(int32_t);
474 format_esd2native(format
, c
->swap_byte_order
, &ss
);
476 CHECK_VALIDITY(pa_sample_spec_valid(&ss
), "Invalid sample specification.");
478 if (request
== ESD_PROTO_STREAM_MON
) {
481 if (!(sink
= pa_namereg_get(c
->protocol
->core
, c
->protocol
->sink_name
, PA_NAMEREG_SINK
, 1))) {
482 pa_log("no such sink.");
486 if (!(source
= sink
->monitor_source
)) {
487 pa_log("no such monitor source.");
491 pa_assert(request
== ESD_PROTO_STREAM_REC
);
493 if (c
->protocol
->source_name
) {
494 if (!(source
= pa_namereg_get(c
->protocol
->core
, c
->protocol
->source_name
, PA_NAMEREG_SOURCE
, 1))) {
495 pa_log("no such source.");
501 strncpy(name
, data
, sizeof(name
));
502 name
[sizeof(name
)-1] = 0;
504 utf8_name
= pa_utf8_filter(name
);
505 pa_client_set_name(c
->client
, utf8_name
);
508 c
->original_name
= pa_xstrdup(name
);
510 pa_assert(!c
->output_memblockq
&& !c
->source_output
);
512 pa_source_output_new_data_init(&sdata
);
513 sdata
.driver
= __FILE__
;
514 sdata
.module
= c
->protocol
->module
;
515 sdata
.client
= c
->client
;
516 sdata
.source
= source
;
517 pa_proplist_update(sdata
.proplist
, PA_UPDATE_MERGE
, c
->client
->proplist
);
518 pa_source_output_new_data_set_sample_spec(&sdata
, &ss
);
520 c
->source_output
= pa_source_output_new(c
->protocol
->core
, &sdata
, 0);
521 pa_source_output_new_data_done(&sdata
);
523 CHECK_VALIDITY(c
->source_output
, "Failed to create source_output.");
525 l
= (size_t) (pa_bytes_per_second(&ss
)*RECORD_BUFFER_SECONDS
);
526 c
->output_memblockq
= pa_memblockq_new(
535 pa_iochannel_socket_set_sndbuf(c
->io
, l
/RECORD_BUFFER_FRAGMENTS
*2);
537 c
->source_output
->push
= source_output_push_cb
;
538 c
->source_output
->kill
= source_output_kill_cb
;
539 c
->source_output
->get_latency
= source_output_get_latency_cb
;
540 c
->source_output
->userdata
= c
;
542 c
->state
= ESD_STREAMING_DATA
;
544 c
->protocol
->n_player
++;
546 pa_source_output_put(c
->source_output
);
551 static int esd_proto_get_latency(connection
*c
, PA_GCC_UNUSED esd_proto_t request
, const void *data
, size_t length
) {
557 pa_assert(length
== 0);
559 if (!(sink
= pa_namereg_get(c
->protocol
->core
, c
->protocol
->sink_name
, PA_NAMEREG_SINK
, 1)))
562 double usec
= pa_sink_get_latency(sink
);
563 latency
= (int) ((usec
*44100)/1000000);
566 latency
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, latency
);
567 connection_write(c
, &latency
, sizeof(int32_t));
571 static int esd_proto_server_info(connection
*c
, PA_GCC_UNUSED esd_proto_t request
, const void *data
, size_t length
) {
572 int32_t rate
= 44100, format
= ESD_STEREO
|ESD_BITS16
;
578 pa_assert(length
== sizeof(int32_t));
580 if ((sink
= pa_namereg_get(c
->protocol
->core
, c
->protocol
->sink_name
, PA_NAMEREG_SINK
, 1))) {
581 rate
= sink
->sample_spec
.rate
;
582 format
= format_native2esd(&sink
->sample_spec
);
585 connection_write_prepare(c
, sizeof(int32_t) * 3);
588 connection_write(c
, &response
, sizeof(int32_t));
589 rate
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, rate
);
590 connection_write(c
, &rate
, sizeof(int32_t));
591 format
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, format
);
592 connection_write(c
, &format
, sizeof(int32_t));
597 static int esd_proto_all_info(connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
600 uint32_t idx
= PA_IDXSET_INVALID
;
602 char terminator
[sizeof(int32_t)*6+ESD_NAME_MAX
];
606 pa_assert(length
== sizeof(int32_t));
608 if (esd_proto_server_info(c
, request
, data
, length
) < 0)
611 k
= sizeof(int32_t)*5+ESD_NAME_MAX
;
612 s
= sizeof(int32_t)*6+ESD_NAME_MAX
;
613 nsamples
= c
->protocol
->core
->scache
? pa_idxset_size(c
->protocol
->core
->scache
) : 0;
614 t
= s
*(nsamples
+1) + k
*(c
->protocol
->n_player
+1);
616 connection_write_prepare(c
, t
);
618 memset(terminator
, 0, sizeof(terminator
));
620 for (conn
= pa_idxset_first(c
->protocol
->connections
, &idx
); conn
; conn
= pa_idxset_next(c
->protocol
->connections
, &idx
)) {
621 int32_t id
, format
= ESD_BITS16
| ESD_STEREO
, rate
= 44100, lvolume
= ESD_VOLUME_BASE
, rvolume
= ESD_VOLUME_BASE
;
622 char name
[ESD_NAME_MAX
];
624 if (conn
->state
!= ESD_STREAMING_DATA
)
627 pa_assert(t
>= k
*2+s
);
629 if (conn
->sink_input
) {
630 pa_cvolume volume
= *pa_sink_input_get_volume(conn
->sink_input
);
631 rate
= conn
->sink_input
->sample_spec
.rate
;
632 lvolume
= (volume
.values
[0]*ESD_VOLUME_BASE
)/PA_VOLUME_NORM
;
633 rvolume
= (volume
.values
[1]*ESD_VOLUME_BASE
)/PA_VOLUME_NORM
;
634 format
= format_native2esd(&conn
->sink_input
->sample_spec
);
638 id
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, (int32_t) (conn
->index
+1));
639 connection_write(c
, &id
, sizeof(int32_t));
642 memset(name
, 0, ESD_NAME_MAX
); /* don't leak old data */
643 if (conn
->original_name
)
644 strncpy(name
, conn
->original_name
, ESD_NAME_MAX
);
645 else if (conn
->client
&& pa_proplist_gets(conn
->client
->proplist
, PA_PROP_APPLICATION_NAME
))
646 strncpy(name
, pa_proplist_gets(conn
->client
->proplist
, PA_PROP_APPLICATION_NAME
), ESD_NAME_MAX
);
647 connection_write(c
, name
, ESD_NAME_MAX
);
650 rate
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, rate
);
651 connection_write(c
, &rate
, sizeof(int32_t));
654 lvolume
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, lvolume
);
655 connection_write(c
, &lvolume
, sizeof(int32_t));
658 rvolume
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, rvolume
);
659 connection_write(c
, &rvolume
, sizeof(int32_t));
662 format
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, format
);
663 connection_write(c
, &format
, sizeof(int32_t));
668 pa_assert(t
== s
*(nsamples
+1)+k
);
671 connection_write(c
, terminator
, k
);
676 idx
= PA_IDXSET_INVALID
;
677 for (ce
= pa_idxset_first(c
->protocol
->core
->scache
, &idx
); ce
; ce
= pa_idxset_next(c
->protocol
->core
->scache
, &idx
)) {
678 int32_t id
, rate
, lvolume
, rvolume
, format
, len
;
679 char name
[ESD_NAME_MAX
];
684 id
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, (int) (ce
->index
+1));
685 connection_write(c
, &id
, sizeof(int32_t));
688 memset(name
, 0, ESD_NAME_MAX
); /* don't leak old data */
689 if (strncmp(ce
->name
, SCACHE_PREFIX
, sizeof(SCACHE_PREFIX
)-1) == 0)
690 strncpy(name
, ce
->name
+sizeof(SCACHE_PREFIX
)-1, ESD_NAME_MAX
);
692 pa_snprintf(name
, ESD_NAME_MAX
, "native.%s", ce
->name
);
693 connection_write(c
, name
, ESD_NAME_MAX
);
696 rate
= PA_MAYBE_UINT32_SWAP(c
->swap_byte_order
, ce
->sample_spec
.rate
);
697 connection_write(c
, &rate
, sizeof(int32_t));
700 lvolume
= PA_MAYBE_UINT32_SWAP(c
->swap_byte_order
, (ce
->volume
.values
[0]*ESD_VOLUME_BASE
)/PA_VOLUME_NORM
);
701 connection_write(c
, &lvolume
, sizeof(int32_t));
704 rvolume
= PA_MAYBE_UINT32_SWAP(c
->swap_byte_order
, (ce
->volume
.values
[0]*ESD_VOLUME_BASE
)/PA_VOLUME_NORM
);
705 connection_write(c
, &rvolume
, sizeof(int32_t));
708 format
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, format_native2esd(&ce
->sample_spec
));
709 connection_write(c
, &format
, sizeof(int32_t));
712 len
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, (int) ce
->memchunk
.length
);
713 connection_write(c
, &len
, sizeof(int32_t));
721 connection_write(c
, terminator
, s
);
726 static int esd_proto_stream_pan(connection
*c
, PA_GCC_UNUSED esd_proto_t request
, const void *data
, size_t length
) {
728 uint32_t idx
, lvolume
, rvolume
;
731 connection_assert_ref(c
);
733 pa_assert(length
== sizeof(int32_t)*3);
735 memcpy(&idx
, data
, sizeof(uint32_t));
736 idx
= PA_MAYBE_UINT32_SWAP(c
->swap_byte_order
, idx
) - 1;
737 data
= (const char*)data
+ sizeof(uint32_t);
739 memcpy(&lvolume
, data
, sizeof(uint32_t));
740 lvolume
= PA_MAYBE_UINT32_SWAP(c
->swap_byte_order
, lvolume
);
741 data
= (const char*)data
+ sizeof(uint32_t);
743 memcpy(&rvolume
, data
, sizeof(uint32_t));
744 rvolume
= PA_MAYBE_UINT32_SWAP(c
->swap_byte_order
, rvolume
);
745 data
= (const char*)data
+ sizeof(uint32_t);
747 if ((conn
= pa_idxset_get_by_index(c
->protocol
->connections
, idx
)) && conn
->sink_input
) {
749 volume
.values
[0] = (lvolume
*PA_VOLUME_NORM
)/ESD_VOLUME_BASE
;
750 volume
.values
[1] = (rvolume
*PA_VOLUME_NORM
)/ESD_VOLUME_BASE
;
752 pa_sink_input_set_volume(conn
->sink_input
, &volume
);
757 connection_write(c
, &ok
, sizeof(int32_t));
762 static int esd_proto_sample_cache(connection
*c
, PA_GCC_UNUSED esd_proto_t request
, const void *data
, size_t length
) {
764 int32_t format
, rate
, sc_length
;
766 char name
[ESD_NAME_MAX
+sizeof(SCACHE_PREFIX
)-1];
768 connection_assert_ref(c
);
770 pa_assert(length
== (ESD_NAME_MAX
+3*sizeof(int32_t)));
772 memcpy(&format
, data
, sizeof(int32_t));
773 format
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, format
);
774 data
= (const char*)data
+ sizeof(int32_t);
776 memcpy(&rate
, data
, sizeof(int32_t));
777 rate
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, rate
);
778 data
= (const char*)data
+ sizeof(int32_t);
781 format_esd2native(format
, c
->swap_byte_order
, &ss
);
783 CHECK_VALIDITY(pa_sample_spec_valid(&ss
), "Invalid sample specification.");
785 memcpy(&sc_length
, data
, sizeof(int32_t));
786 sc_length
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, sc_length
);
787 data
= (const char*)data
+ sizeof(int32_t);
789 CHECK_VALIDITY(sc_length
<= MAX_CACHE_SAMPLE_SIZE
, "Sample too large (%d bytes).", (int)sc_length
);
791 strcpy(name
, SCACHE_PREFIX
);
792 strncpy(name
+sizeof(SCACHE_PREFIX
)-1, data
, ESD_NAME_MAX
);
793 name
[sizeof(name
)-1] = 0;
795 CHECK_VALIDITY(pa_utf8_valid(name
), "Invalid UTF8 in sample name.");
797 pa_assert(!c
->scache
.memchunk
.memblock
);
798 c
->scache
.memchunk
.memblock
= pa_memblock_new(c
->protocol
->core
->mempool
, sc_length
);
799 c
->scache
.memchunk
.index
= 0;
800 c
->scache
.memchunk
.length
= sc_length
;
801 c
->scache
.sample_spec
= ss
;
802 pa_assert(!c
->scache
.name
);
803 c
->scache
.name
= pa_xstrdup(name
);
805 c
->state
= ESD_CACHING_SAMPLE
;
807 pa_scache_add_item(c
->protocol
->core
, c
->scache
.name
, NULL
, NULL
, NULL
, c
->client
->proplist
, &idx
);
810 connection_write(c
, &idx
, sizeof(uint32_t));
815 static int esd_proto_sample_get_id(connection
*c
, PA_GCC_UNUSED esd_proto_t request
, const void *data
, size_t length
) {
818 char name
[ESD_NAME_MAX
+sizeof(SCACHE_PREFIX
)-1];
820 connection_assert_ref(c
);
822 pa_assert(length
== ESD_NAME_MAX
);
824 strcpy(name
, SCACHE_PREFIX
);
825 strncpy(name
+sizeof(SCACHE_PREFIX
)-1, data
, ESD_NAME_MAX
);
826 name
[sizeof(name
)-1] = 0;
828 CHECK_VALIDITY(pa_utf8_valid(name
), "Invalid UTF8 in sample name.");
831 if ((idx
= pa_scache_get_id_by_name(c
->protocol
->core
, name
)) != PA_IDXSET_INVALID
)
834 connection_write(c
, &ok
, sizeof(int32_t));
839 static int esd_proto_sample_free_or_play(connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
844 connection_assert_ref(c
);
846 pa_assert(length
== sizeof(int32_t));
848 memcpy(&idx
, data
, sizeof(uint32_t));
849 idx
= PA_MAYBE_UINT32_SWAP(c
->swap_byte_order
, idx
) - 1;
853 if ((name
= pa_scache_get_name_by_id(c
->protocol
->core
, idx
))) {
854 if (request
== ESD_PROTO_SAMPLE_PLAY
) {
857 if ((sink
= pa_namereg_get(c
->protocol
->core
, c
->protocol
->sink_name
, PA_NAMEREG_SINK
, 1)))
858 if (pa_scache_play_item(c
->protocol
->core
, name
, sink
, PA_VOLUME_NORM
, c
->client
->proplist
, NULL
) >= 0)
861 pa_assert(request
== ESD_PROTO_SAMPLE_FREE
);
863 if (pa_scache_remove_item(c
->protocol
->core
, name
) >= 0)
868 connection_write(c
, &ok
, sizeof(int32_t));
873 static int esd_proto_standby_or_resume(connection
*c
, PA_GCC_UNUSED esd_proto_t request
, PA_GCC_UNUSED
const void *data
, PA_GCC_UNUSED
size_t length
) {
876 connection_assert_ref(c
);
878 connection_write_prepare(c
, sizeof(int32_t) * 2);
881 connection_write(c
, &ok
, sizeof(int32_t));
882 connection_write(c
, &ok
, sizeof(int32_t));
887 /*** client callbacks ***/
889 static void client_kill_cb(pa_client
*c
) {
892 connection_unlink(CONNECTION(c
->userdata
));
895 /*** pa_iochannel callbacks ***/
897 static int do_read(connection
*c
) {
898 connection_assert_ref(c
);
900 /* pa_log("READ"); */
902 if (c
->state
== ESD_NEXT_REQUEST
) {
904 pa_assert(c
->read_data_length
< sizeof(c
->request
));
906 if ((r
= pa_iochannel_read(c
->io
, ((uint8_t*) &c
->request
) + c
->read_data_length
, sizeof(c
->request
) - c
->read_data_length
)) <= 0) {
907 pa_log_debug("read(): %s", r
< 0 ? pa_cstrerror(errno
) : "EOF");
911 if ((c
->read_data_length
+= r
) >= sizeof(c
->request
)) {
912 struct proto_handler
*handler
;
914 c
->request
= PA_MAYBE_INT32_SWAP(c
->swap_byte_order
, c
->request
);
916 if (c
->request
< ESD_PROTO_CONNECT
|| c
->request
> ESD_PROTO_MAX
) {
917 pa_log("recieved invalid request.");
921 handler
= proto_map
+c
->request
;
923 /* pa_log("executing request #%u", c->request); */
925 if (!handler
->proc
) {
926 pa_log("recieved unimplemented request #%u.", c
->request
);
930 if (handler
->data_length
== 0) {
931 c
->read_data_length
= 0;
933 if (handler
->proc(c
, c
->request
, NULL
, 0) < 0)
937 if (c
->read_data_alloc
< handler
->data_length
)
938 c
->read_data
= pa_xrealloc(c
->read_data
, c
->read_data_alloc
= handler
->data_length
);
939 pa_assert(c
->read_data
);
941 c
->state
= ESD_NEEDS_REQDATA
;
942 c
->read_data_length
= 0;
946 } else if (c
->state
== ESD_NEEDS_REQDATA
) {
948 struct proto_handler
*handler
= proto_map
+c
->request
;
950 pa_assert(handler
->proc
);
952 pa_assert(c
->read_data
&& c
->read_data_length
< handler
->data_length
);
954 if ((r
= pa_iochannel_read(c
->io
, (uint8_t*) c
->read_data
+ c
->read_data_length
, handler
->data_length
- c
->read_data_length
)) <= 0) {
955 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
958 pa_log_debug("read(): %s", r
< 0 ? pa_cstrerror(errno
) : "EOF");
962 if ((c
->read_data_length
+= r
) >= handler
->data_length
) {
963 size_t l
= c
->read_data_length
;
964 pa_assert(handler
->proc
);
966 c
->state
= ESD_NEXT_REQUEST
;
967 c
->read_data_length
= 0;
969 if (handler
->proc(c
, c
->request
, c
->read_data
, l
) < 0)
972 } else if (c
->state
== ESD_CACHING_SAMPLE
) {
976 pa_assert(c
->scache
.memchunk
.memblock
);
977 pa_assert(c
->scache
.name
);
978 pa_assert(c
->scache
.memchunk
.index
< c
->scache
.memchunk
.length
);
980 p
= pa_memblock_acquire(c
->scache
.memchunk
.memblock
);
981 r
= pa_iochannel_read(c
->io
, (uint8_t*) p
+c
->scache
.memchunk
.index
, c
->scache
.memchunk
.length
-c
->scache
.memchunk
.index
);
982 pa_memblock_release(c
->scache
.memchunk
.memblock
);
985 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
988 pa_log_debug("read(): %s", r
< 0 ? pa_cstrerror(errno
) : "EOF");
992 c
->scache
.memchunk
.index
+= r
;
993 pa_assert(c
->scache
.memchunk
.index
<= c
->scache
.memchunk
.length
);
995 if (c
->scache
.memchunk
.index
== c
->scache
.memchunk
.length
) {
998 c
->scache
.memchunk
.index
= 0;
999 pa_scache_add_item(c
->protocol
->core
, c
->scache
.name
, &c
->scache
.sample_spec
, NULL
, &c
->scache
.memchunk
, c
->client
->proplist
, &idx
);
1001 pa_memblock_unref(c
->scache
.memchunk
.memblock
);
1002 c
->scache
.memchunk
.memblock
= NULL
;
1003 c
->scache
.memchunk
.index
= c
->scache
.memchunk
.length
= 0;
1005 pa_xfree(c
->scache
.name
);
1006 c
->scache
.name
= NULL
;
1008 c
->state
= ESD_NEXT_REQUEST
;
1011 connection_write(c
, &idx
, sizeof(uint32_t));
1014 } else if (c
->state
== ESD_STREAMING_DATA
&& c
->sink_input
) {
1020 pa_assert(c
->input_memblockq
);
1022 /* pa_log("STREAMING_DATA"); */
1024 if (!(l
= pa_atomic_load(&c
->playback
.missing
)))
1027 if (l
> c
->playback
.fragment_size
)
1028 l
= c
->playback
.fragment_size
;
1030 if (c
->playback
.current_memblock
)
1031 if (pa_memblock_get_length(c
->playback
.current_memblock
) - c
->playback
.memblock_index
< l
) {
1032 pa_memblock_unref(c
->playback
.current_memblock
);
1033 c
->playback
.current_memblock
= NULL
;
1034 c
->playback
.memblock_index
= 0;
1037 if (!c
->playback
.current_memblock
) {
1038 pa_assert_se(c
->playback
.current_memblock
= pa_memblock_new(c
->protocol
->core
->mempool
, c
->playback
.fragment_size
*2));
1039 c
->playback
.memblock_index
= 0;
1042 p
= pa_memblock_acquire(c
->playback
.current_memblock
);
1043 r
= pa_iochannel_read(c
->io
, (uint8_t*) p
+c
->playback
.memblock_index
, l
);
1044 pa_memblock_release(c
->playback
.current_memblock
);
1048 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
1051 pa_log_debug("read(): %s", r
< 0 ? pa_cstrerror(errno
) : "EOF");
1055 chunk
.memblock
= c
->playback
.current_memblock
;
1056 chunk
.index
= c
->playback
.memblock_index
;
1059 c
->playback
.memblock_index
+= r
;
1061 pa_asyncmsgq_post(c
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(c
->sink_input
), SINK_INPUT_MESSAGE_POST_DATA
, NULL
, 0, &chunk
, NULL
);
1062 pa_atomic_sub(&c
->playback
.missing
, r
);
1068 static int do_write(connection
*c
) {
1069 connection_assert_ref(c
);
1071 /* pa_log("WRITE"); */
1073 if (c
->write_data_length
) {
1076 pa_assert(c
->write_data_index
< c
->write_data_length
);
1077 if ((r
= pa_iochannel_write(c
->io
, (uint8_t*) c
->write_data
+c
->write_data_index
, c
->write_data_length
-c
->write_data_index
)) < 0) {
1079 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
1082 pa_log("write(): %s", pa_cstrerror(errno
));
1086 if ((c
->write_data_index
+=r
) >= c
->write_data_length
)
1087 c
->write_data_length
= c
->write_data_index
= 0;
1089 } else if (c
->state
== ESD_STREAMING_DATA
&& c
->source_output
) {
1094 if (pa_memblockq_peek(c
->output_memblockq
, &chunk
) < 0)
1097 pa_assert(chunk
.memblock
);
1098 pa_assert(chunk
.length
);
1100 p
= pa_memblock_acquire(chunk
.memblock
);
1101 r
= pa_iochannel_write(c
->io
, (uint8_t*) p
+chunk
.index
, chunk
.length
);
1102 pa_memblock_release(chunk
.memblock
);
1104 pa_memblock_unref(chunk
.memblock
);
1108 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
1111 pa_log("write(): %s", pa_cstrerror(errno
));
1115 pa_memblockq_drop(c
->output_memblockq
, r
);
1121 static void do_work(connection
*c
) {
1122 connection_assert_ref(c
);
1124 c
->protocol
->core
->mainloop
->defer_enable(c
->defer_event
, 0);
1129 if (pa_iochannel_is_readable(c
->io
)) {
1134 if (c
->state
== ESD_STREAMING_DATA
&& c
->source_output
&& pa_iochannel_is_hungup(c
->io
))
1135 /* In case we are in capture mode we will never call read()
1136 * on the socket, hence we need to detect the hangup manually
1137 * here, instead of simply waiting for read() to return 0. */
1140 if (pa_iochannel_is_writable(c
->io
))
1141 if (do_write(c
) < 0)
1148 if (c
->state
== ESD_STREAMING_DATA
&& c
->sink_input
) {
1151 pa_iochannel_free(c
->io
);
1154 pa_asyncmsgq_post(c
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(c
->sink_input
), SINK_INPUT_MESSAGE_DISABLE_PREBUF
, NULL
, 0, NULL
, NULL
);
1156 connection_unlink(c
);
1159 static void io_callback(pa_iochannel
*io
, void *userdata
) {
1160 connection
*c
= CONNECTION(userdata
);
1162 connection_assert_ref(c
);
1168 static void defer_callback(pa_mainloop_api
*a
, pa_defer_event
*e
, void *userdata
) {
1169 connection
*c
= CONNECTION(userdata
);
1171 connection_assert_ref(c
);
1177 static int connection_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1178 connection
*c
= CONNECTION(o
);
1179 connection_assert_ref(c
);
1182 case CONNECTION_MESSAGE_REQUEST_DATA
:
1186 case CONNECTION_MESSAGE_POST_DATA
:
1187 /* pa_log("got data %u", chunk->length); */
1188 pa_memblockq_push_align(c
->output_memblockq
, chunk
);
1192 case CONNECTION_MESSAGE_UNLINK_CONNECTION
:
1193 connection_unlink(c
);
1200 /*** sink_input callbacks ***/
1202 /* Called from thread context */
1203 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1204 pa_sink_input
*i
= PA_SINK_INPUT(o
);
1207 pa_sink_input_assert_ref(i
);
1208 c
= CONNECTION(i
->userdata
);
1209 connection_assert_ref(c
);
1213 case SINK_INPUT_MESSAGE_POST_DATA
: {
1216 /* New data from the main loop */
1217 pa_memblockq_push_align(c
->input_memblockq
, chunk
);
1219 /* pa_log("got data, %u", pa_memblockq_get_length(c->input_memblockq)); */
1224 case SINK_INPUT_MESSAGE_DISABLE_PREBUF
: {
1225 pa_memblockq_prebuf_disable(c
->input_memblockq
);
1229 case PA_SINK_INPUT_MESSAGE_GET_LATENCY
: {
1230 pa_usec_t
*r
= userdata
;
1232 *r
= pa_bytes_to_usec(pa_memblockq_get_length(c
->input_memblockq
), &c
->sink_input
->sample_spec
);
1234 /* Fall through, the default handler will add in the extra
1235 * latency added by the resampler */
1239 return pa_sink_input_process_msg(o
, code
, userdata
, offset
, chunk
);
1243 /* Called from thread context */
1244 static int sink_input_pop_cb(pa_sink_input
*i
, size_t length
, pa_memchunk
*chunk
) {
1249 c
= CONNECTION(i
->userdata
);
1250 connection_assert_ref(c
);
1253 if ((r
= pa_memblockq_peek(c
->input_memblockq
, chunk
)) < 0) {
1256 if (c
->dead
&& pa_sink_input_safe_to_remove(i
))
1257 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(c
), CONNECTION_MESSAGE_UNLINK_CONNECTION
, NULL
, 0, NULL
, NULL
);
1261 old
= pa_memblockq_missing(c
->input_memblockq
);
1262 pa_memblockq_drop(c
->input_memblockq
, chunk
->length
);
1263 new = pa_memblockq_missing(c
->input_memblockq
);
1266 if (pa_atomic_add(&c
->playback
.missing
, new - old
) <= 0)
1267 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(c
), CONNECTION_MESSAGE_REQUEST_DATA
, NULL
, 0, NULL
, NULL
);
1274 static void sink_input_kill_cb(pa_sink_input
*i
) {
1275 pa_sink_input_assert_ref(i
);
1277 connection_unlink(CONNECTION(i
->userdata
));
1280 /*** source_output callbacks ***/
1282 /* Called from thread context */
1283 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
1287 c
= CONNECTION(o
->userdata
);
1291 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(c
), CONNECTION_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
1294 static void source_output_kill_cb(pa_source_output
*o
) {
1295 pa_source_output_assert_ref(o
);
1297 connection_unlink(CONNECTION(o
->userdata
));
1300 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
) {
1304 c
= CONNECTION(o
->userdata
);
1307 return pa_bytes_to_usec(pa_memblockq_get_length(c
->output_memblockq
), &c
->source_output
->sample_spec
);
1310 /*** socket server callback ***/
1312 static void auth_timeout(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*tv
, void *userdata
) {
1313 connection
*c
= CONNECTION(userdata
);
1317 connection_assert_ref(c
);
1318 pa_assert(c
->auth_timeout_event
== e
);
1321 connection_unlink(c
);
1324 static void on_connection(pa_socket_server
*s
, pa_iochannel
*io
, void *userdata
) {
1326 pa_protocol_esound
*p
= userdata
;
1327 char cname
[256], pname
[128];
1333 if (pa_idxset_size(p
->connections
)+1 > MAX_CONNECTIONS
) {
1334 pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS
);
1335 pa_iochannel_free(io
);
1339 c
= pa_msgobject_new(connection
);
1340 c
->parent
.parent
.free
= connection_free
;
1341 c
->parent
.process_msg
= connection_process_msg
;
1344 pa_iochannel_set_callback(c
->io
, io_callback
, c
);
1346 pa_iochannel_socket_peer_to_string(io
, pname
, sizeof(pname
));
1347 pa_snprintf(cname
, sizeof(cname
), "EsounD client (%s)", pname
);
1348 c
->client
= pa_client_new(p
->core
, __FILE__
, cname
);
1349 c
->client
->module
= p
->module
;
1350 c
->client
->kill
= client_kill_cb
;
1351 c
->client
->userdata
= c
;
1353 c
->authorized
= !!p
->public;
1354 c
->swap_byte_order
= FALSE
;
1357 c
->read_data_length
= 0;
1358 c
->read_data
= pa_xmalloc(c
->read_data_alloc
= proto_map
[ESD_PROTO_CONNECT
].data_length
);
1360 c
->write_data_length
= c
->write_data_index
= c
->write_data_alloc
= 0;
1361 c
->write_data
= NULL
;
1363 c
->state
= ESD_NEEDS_REQDATA
;
1364 c
->request
= ESD_PROTO_CONNECT
;
1366 c
->sink_input
= NULL
;
1367 c
->input_memblockq
= NULL
;
1369 c
->source_output
= NULL
;
1370 c
->output_memblockq
= NULL
;
1372 c
->playback
.current_memblock
= NULL
;
1373 c
->playback
.memblock_index
= 0;
1374 c
->playback
.fragment_size
= 0;
1375 pa_atomic_store(&c
->playback
.missing
, 0);
1377 c
->scache
.memchunk
.length
= c
->scache
.memchunk
.index
= 0;
1378 c
->scache
.memchunk
.memblock
= NULL
;
1379 c
->scache
.name
= NULL
;
1381 c
->original_name
= NULL
;
1383 if (!c
->authorized
&& p
->auth_ip_acl
&& pa_ip_acl_check(p
->auth_ip_acl
, pa_iochannel_get_recv_fd(io
)) > 0) {
1384 pa_log_info("Client authenticated by IP ACL.");
1385 c
->authorized
= TRUE
;
1388 if (!c
->authorized
) {
1390 pa_gettimeofday(&tv
);
1391 tv
.tv_sec
+= AUTH_TIMEOUT
;
1392 c
->auth_timeout_event
= p
->core
->mainloop
->time_new(p
->core
->mainloop
, &tv
, auth_timeout
, c
);
1394 c
->auth_timeout_event
= NULL
;
1396 c
->defer_event
= p
->core
->mainloop
->defer_new(p
->core
->mainloop
, defer_callback
, c
);
1397 p
->core
->mainloop
->defer_enable(c
->defer_event
, 0);
1399 pa_idxset_put(p
->connections
, c
, &c
->index
);
1402 /*** entry points ***/
1404 pa_protocol_esound
* pa_protocol_esound_new(pa_core
*core
, pa_socket_server
*server
, pa_module
*m
, pa_modargs
*ma
) {
1405 pa_protocol_esound
*p
= NULL
;
1406 pa_bool_t
public = FALSE
;
1414 if (pa_modargs_get_value_boolean(ma
, "auth-anonymous", &public) < 0) {
1415 pa_log("auth-anonymous= expects a boolean argument.");
1419 p
= pa_xnew(pa_protocol_esound
, 1);
1421 if (pa_authkey_load_auto(pa_modargs_get_value(ma
, "cookie", DEFAULT_COOKIE_FILE
), p
->esd_key
, sizeof(p
->esd_key
)) < 0)
1424 if ((acl
= pa_modargs_get_value(ma
, "auth-ip-acl", NULL
))) {
1426 if (!(p
->auth_ip_acl
= pa_ip_acl_new(acl
))) {
1427 pa_log("Failed to parse IP ACL '%s'", acl
);
1431 p
->auth_ip_acl
= NULL
;
1437 pa_socket_server_set_callback(p
->server
, on_connection
, p
);
1438 p
->connections
= pa_idxset_new(NULL
, NULL
);
1440 p
->sink_name
= pa_xstrdup(pa_modargs_get_value(ma
, "sink", NULL
));
1441 p
->source_name
= pa_xstrdup(pa_modargs_get_value(ma
, "source", NULL
));
1451 void pa_protocol_esound_free(pa_protocol_esound
*p
) {
1455 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
1456 connection_unlink(c
);
1457 pa_idxset_free(p
->connections
, NULL
, NULL
);
1459 pa_socket_server_unref(p
->server
);
1462 pa_ip_acl_free(p
->auth_ip_acl
);
1464 pa_xfree(p
->sink_name
);
1465 pa_xfree(p
->source_name
);