4 This file is part of polypaudio.
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
33 #include "protocol-esound.h"
37 #include "sink-input.h"
39 #include "source-output.h"
43 #include "sample-util.h"
49 #include "endianmacros.h"
51 /* Don't accept more connection than this */
52 #define MAX_CONNECTIONS 10
54 /* Kick a client if it doesn't authenticate within this time */
55 #define AUTH_TIMEOUT 5
57 #define DEFAULT_COOKIE_FILE ".esd_auth"
59 #define PLAYBACK_BUFFER_SECONDS (.5)
60 #define PLAYBACK_BUFFER_FRAGMENTS (10)
61 #define RECORD_BUFFER_SECONDS (5)
62 #define RECORD_BUFFER_FRAGMENTS (100)
64 #define MAX_CACHE_SAMPLE_SIZE (1024000)
66 #define SCACHE_PREFIX "esound."
68 /* This is heavily based on esound's code */
73 pa_protocol_esound
*protocol
;
76 int authorized
, swap_byte_order
;
78 size_t write_data_alloc
, write_data_index
, write_data_length
;
80 size_t read_data_alloc
, read_data_length
;
82 esd_client_state_t state
;
83 pa_sink_input
*sink_input
;
84 pa_source_output
*source_output
;
85 pa_memblockq
*input_memblockq
, *output_memblockq
;
86 pa_defer_event
*defer_event
;
89 pa_memblock
*current_memblock
;
90 size_t memblock_index
, fragment_size
;
96 pa_sample_spec sample_spec
;
99 pa_time_event
*auth_timeout_event
;
102 struct pa_protocol_esound
{
106 pa_socket_server
*server
;
107 pa_idxset
*connections
;
108 char *sink_name
, *source_name
;
110 uint8_t esd_key
[ESD_KEY_LEN
];
113 typedef struct proto_handler
{
115 int (*proc
)(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
116 const char *description
;
117 } esd_proto_handler_info_t
;
119 static void sink_input_drop_cb(pa_sink_input
*i
, const pa_memchunk
*chunk
, size_t length
);
120 static int sink_input_peek_cb(pa_sink_input
*i
, pa_memchunk
*chunk
);
121 static void sink_input_kill_cb(pa_sink_input
*i
);
122 static pa_usec_t
sink_input_get_latency_cb(pa_sink_input
*i
);
123 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
);
125 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
);
126 static void source_output_kill_cb(pa_source_output
*o
);
128 static int esd_proto_connect(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
129 static int esd_proto_stream_play(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
130 static int esd_proto_stream_record(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
131 static int esd_proto_get_latency(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
132 static int esd_proto_server_info(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
133 static int esd_proto_all_info(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
134 static int esd_proto_stream_pan(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
135 static int esd_proto_sample_cache(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
136 static int esd_proto_sample_free_or_play(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
137 static int esd_proto_sample_get_id(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
138 static int esd_proto_standby_or_resume(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
140 /* the big map of protocol handler info */
141 static struct proto_handler proto_map
[ESD_PROTO_MAX
] = {
142 { ESD_KEY_LEN
+ sizeof(int), esd_proto_connect
, "connect" },
143 { ESD_KEY_LEN
+ sizeof(int), NULL
, "lock" },
144 { ESD_KEY_LEN
+ sizeof(int), NULL
, "unlock" },
146 { ESD_NAME_MAX
+ 2 * sizeof(int), esd_proto_stream_play
, "stream play" },
147 { ESD_NAME_MAX
+ 2 * sizeof(int), esd_proto_stream_record
, "stream rec" },
148 { ESD_NAME_MAX
+ 2 * sizeof(int), esd_proto_stream_record
, "stream mon" },
150 { ESD_NAME_MAX
+ 3 * sizeof(int), esd_proto_sample_cache
, "sample cache" }, /* 6 */
151 { sizeof(int), esd_proto_sample_free_or_play
, "sample free" },
152 { sizeof(int), esd_proto_sample_free_or_play
, "sample play" }, /* 8 */
153 { sizeof(int), NULL
, "sample loop" },
154 { sizeof(int), NULL
, "sample stop" },
155 { -1, NULL
, "TODO: sample kill" },
157 { ESD_KEY_LEN
+ sizeof(int), esd_proto_standby_or_resume
, "standby" }, /* NOOP! */
158 { ESD_KEY_LEN
+ sizeof(int), esd_proto_standby_or_resume
, "resume" }, /* NOOP! */ /* 13 */
160 { ESD_NAME_MAX
, esd_proto_sample_get_id
, "sample getid" }, /* 14 */
161 { ESD_NAME_MAX
+ 2 * sizeof(int), NULL
, "stream filter" },
163 { sizeof(int), esd_proto_server_info
, "server info" },
164 { sizeof(int), esd_proto_all_info
, "all info" },
165 { -1, NULL
, "TODO: subscribe" },
166 { -1, NULL
, "TODO: unsubscribe" },
168 { 3 * sizeof(int), esd_proto_stream_pan
, "stream pan"},
169 { 3 * sizeof(int), NULL
, "sample pan" },
171 { sizeof(int), NULL
, "standby mode" },
172 { 0, esd_proto_get_latency
, "get latency" }
176 static void connection_free(struct connection
*c
) {
178 pa_idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
);
180 if (c
->state
== ESD_STREAMING_DATA
)
181 c
->protocol
->n_player
--;
183 pa_client_free(c
->client
);
186 pa_sink_input_disconnect(c
->sink_input
);
187 pa_sink_input_unref(c
->sink_input
);
190 if (c
->source_output
) {
191 pa_source_output_disconnect(c
->source_output
);
192 pa_source_output_unref(c
->source_output
);
195 if (c
->input_memblockq
)
196 pa_memblockq_free(c
->input_memblockq
);
197 if (c
->output_memblockq
)
198 pa_memblockq_free(c
->output_memblockq
);
200 if (c
->playback
.current_memblock
)
201 pa_memblock_unref(c
->playback
.current_memblock
);
203 pa_xfree(c
->read_data
);
204 pa_xfree(c
->write_data
);
207 pa_iochannel_free(c
->io
);
210 c
->protocol
->core
->mainloop
->defer_free(c
->defer_event
);
212 if (c
->scache
.memchunk
.memblock
)
213 pa_memblock_unref(c
->scache
.memchunk
.memblock
);
214 pa_xfree(c
->scache
.name
);
216 if (c
->auth_timeout_event
)
217 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
222 static void* connection_write(struct connection
*c
, size_t length
) {
226 assert(c
->protocol
&& c
->protocol
->core
&& c
->protocol
->core
->mainloop
&& c
->protocol
->core
->mainloop
->defer_enable
);
227 c
->protocol
->core
->mainloop
->defer_enable(c
->defer_event
, 1);
229 t
= c
->write_data_length
+length
;
231 if (c
->write_data_alloc
< t
)
232 c
->write_data
= pa_xrealloc(c
->write_data
, c
->write_data_alloc
= t
);
234 assert(c
->write_data
);
236 i
= c
->write_data_length
;
237 c
->write_data_length
+= length
;
239 return (uint8_t*) c
->write_data
+i
;
242 static void format_esd2native(int format
, int swap_bytes
, pa_sample_spec
*ss
) {
245 ss
->channels
= ((format
& ESD_MASK_CHAN
) == ESD_STEREO
) ? 2 : 1;
246 if ((format
& ESD_MASK_BITS
) == ESD_BITS16
)
247 ss
->format
= swap_bytes
? PA_SAMPLE_S16RE
: PA_SAMPLE_S16NE
;
249 ss
->format
= PA_SAMPLE_U8
;
252 static int format_native2esd(pa_sample_spec
*ss
) {
255 format
= (ss
->format
== PA_SAMPLE_U8
) ? ESD_BITS8
: ESD_BITS16
;
256 format
|= (ss
->channels
>= 2) ? ESD_STEREO
: ESD_MONO
;
261 /*** esound commands ***/
263 static int esd_proto_connect(struct connection
*c
, PA_GCC_UNUSED esd_proto_t request
, const void *data
, size_t length
) {
266 assert(length
== (ESD_KEY_LEN
+ sizeof(uint32_t)));
268 if (!c
->authorized
) {
269 if (memcmp(data
, c
->protocol
->esd_key
, ESD_KEY_LEN
) != 0) {
270 pa_log(__FILE__
": kicked client with invalid authorization key.\n");
275 if (c
->auth_timeout_event
) {
276 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
277 c
->auth_timeout_event
= NULL
;
281 ekey
= *(const uint32_t*)((const uint8_t*) data
+ESD_KEY_LEN
);
282 if (ekey
== ESD_ENDIAN_KEY
)
283 c
->swap_byte_order
= 0;
284 else if (ekey
== ESD_SWAP_ENDIAN_KEY
)
285 c
->swap_byte_order
= 1;
287 pa_log(__FILE__
": client sent invalid endian key\n");
291 ok
= connection_write(c
, sizeof(int));
297 static int esd_proto_stream_play(struct connection
*c
, PA_GCC_UNUSED esd_proto_t request
, const void *data
, size_t length
) {
298 char name
[ESD_NAME_MAX
];
303 assert(c
&& length
== (sizeof(int)*2+ESD_NAME_MAX
));
305 format
= MAYBE_INT32_SWAP(c
->swap_byte_order
, *(const int*)data
);
306 rate
= MAYBE_INT32_SWAP(c
->swap_byte_order
, *((const int*)data
+ 1));
309 format_esd2native(format
, c
->swap_byte_order
, &ss
);
311 if (!pa_sample_spec_valid(&ss
)) {
312 pa_log(__FILE__
": invalid sample specification\n");
316 if (!(sink
= pa_namereg_get(c
->protocol
->core
, c
->protocol
->sink_name
, PA_NAMEREG_SINK
, 1))) {
317 pa_log(__FILE__
": no such sink\n");
321 strncpy(name
, (const char*) data
+ sizeof(int)*2, sizeof(name
));
322 name
[sizeof(name
)-1] = 0;
324 pa_client_set_name(c
->client
, name
);
326 assert(!c
->sink_input
&& !c
->input_memblockq
);
328 if (!(c
->sink_input
= pa_sink_input_new(sink
, __FILE__
, name
, &ss
, NULL
, 0, -1))) {
329 pa_log(__FILE__
": failed to create sink input.\n");
333 l
= (size_t) (pa_bytes_per_second(&ss
)*PLAYBACK_BUFFER_SECONDS
);
334 c
->input_memblockq
= pa_memblockq_new(l
, 0, pa_frame_size(&ss
), l
/2, l
/PLAYBACK_BUFFER_FRAGMENTS
, c
->protocol
->core
->memblock_stat
);
335 pa_iochannel_socket_set_rcvbuf(c
->io
, l
/PLAYBACK_BUFFER_FRAGMENTS
*2);
336 c
->playback
.fragment_size
= l
/10;
338 c
->sink_input
->owner
= c
->protocol
->module
;
339 c
->sink_input
->client
= c
->client
;
340 c
->sink_input
->peek
= sink_input_peek_cb
;
341 c
->sink_input
->drop
= sink_input_drop_cb
;
342 c
->sink_input
->kill
= sink_input_kill_cb
;
343 c
->sink_input
->get_latency
= sink_input_get_latency_cb
;
344 c
->sink_input
->userdata
= c
;
346 c
->state
= ESD_STREAMING_DATA
;
348 c
->protocol
->n_player
++;
353 static int esd_proto_stream_record(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
354 char name
[ESD_NAME_MAX
];
359 assert(c
&& length
== (sizeof(int)*2+ESD_NAME_MAX
));
361 format
= MAYBE_INT32_SWAP(c
->swap_byte_order
, *(const int*)data
);
362 rate
= MAYBE_INT32_SWAP(c
->swap_byte_order
, *((const int*)data
+ 1));
365 format_esd2native(format
, c
->swap_byte_order
, &ss
);
367 if (!pa_sample_spec_valid(&ss
)) {
368 pa_log(__FILE__
": invalid sample specification.\n");
372 if (request
== ESD_PROTO_STREAM_MON
) {
375 if (!(sink
= pa_namereg_get(c
->protocol
->core
, c
->protocol
->sink_name
, PA_NAMEREG_SINK
, 1))) {
376 pa_log(__FILE__
": no such sink.\n");
380 if (!(source
= sink
->monitor_source
)) {
381 pa_log(__FILE__
": no such monitor source.\n");
385 assert(request
== ESD_PROTO_STREAM_REC
);
387 if (!(source
= pa_namereg_get(c
->protocol
->core
, c
->protocol
->source_name
, PA_NAMEREG_SOURCE
, 1))) {
388 pa_log(__FILE__
": no such source.\n");
393 strncpy(name
, (const char*) data
+ sizeof(int)*2, sizeof(name
));
394 name
[sizeof(name
)-1] = 0;
396 pa_client_set_name(c
->client
, name
);
398 assert(!c
->output_memblockq
&& !c
->source_output
);
400 if (!(c
->source_output
= pa_source_output_new(source
, __FILE__
, name
, &ss
, NULL
, -1))) {
401 pa_log(__FILE__
": failed to create source output\n");
405 l
= (size_t) (pa_bytes_per_second(&ss
)*RECORD_BUFFER_SECONDS
);
406 c
->output_memblockq
= pa_memblockq_new(l
, 0, pa_frame_size(&ss
), 0, 0, c
->protocol
->core
->memblock_stat
);
407 pa_iochannel_socket_set_sndbuf(c
->io
, l
/RECORD_BUFFER_FRAGMENTS
*2);
409 c
->source_output
->owner
= c
->protocol
->module
;
410 c
->source_output
->client
= c
->client
;
411 c
->source_output
->push
= source_output_push_cb
;
412 c
->source_output
->kill
= source_output_kill_cb
;
413 c
->source_output
->get_latency
= source_output_get_latency_cb
;
414 c
->source_output
->userdata
= c
;
416 c
->state
= ESD_STREAMING_DATA
;
418 c
->protocol
->n_player
++;
423 static int esd_proto_get_latency(struct connection
*c
, PA_GCC_UNUSED esd_proto_t request
, const void *data
, size_t length
) {
426 assert(c
&& !data
&& length
== 0);
428 if (!(sink
= pa_namereg_get(c
->protocol
->core
, c
->protocol
->sink_name
, PA_NAMEREG_SINK
, 1)))
431 double usec
= pa_sink_get_latency(sink
);
432 latency
= (int) ((usec
*44100)/1000000);
435 lag
= connection_write(c
, sizeof(int));
437 *lag
= MAYBE_INT32_SWAP(c
->swap_byte_order
, latency
);
441 static int esd_proto_server_info(struct connection
*c
, PA_GCC_UNUSED esd_proto_t request
, const void *data
, size_t length
) {
442 int rate
= 44100, format
= ESD_STEREO
|ESD_BITS16
;
445 assert(c
&& data
&& length
== sizeof(int));
447 if ((sink
= pa_namereg_get(c
->protocol
->core
, c
->protocol
->sink_name
, PA_NAMEREG_SINK
, 1))) {
448 rate
= sink
->sample_spec
.rate
;
449 format
= format_native2esd(&sink
->sample_spec
);
452 response
= connection_write(c
, sizeof(int)*3);
455 *(response
++) = MAYBE_INT32_SWAP(c
->swap_byte_order
, rate
);
456 *(response
++) = MAYBE_INT32_SWAP(c
->swap_byte_order
, format
);
460 static int esd_proto_all_info(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
463 struct connection
*conn
;
464 size_t idx
= PA_IDXSET_INVALID
;
466 assert(c
&& data
&& length
== sizeof(int));
468 if (esd_proto_server_info(c
, request
, data
, length
) < 0)
471 k
= sizeof(int)*5+ESD_NAME_MAX
;
472 s
= sizeof(int)*6+ESD_NAME_MAX
;
473 nsamples
= c
->protocol
->core
->scache
? pa_idxset_size(c
->protocol
->core
->scache
) : 0;
474 response
= connection_write(c
, (t
= s
*(nsamples
+1) + k
*(c
->protocol
->n_player
+1)));
477 for (conn
= pa_idxset_first(c
->protocol
->connections
, &idx
); conn
; conn
= pa_idxset_next(c
->protocol
->connections
, &idx
)) {
478 int format
= ESD_BITS16
| ESD_STEREO
, rate
= 44100, lvolume
= ESD_VOLUME_BASE
, rvolume
= ESD_VOLUME_BASE
;
480 if (conn
->state
!= ESD_STREAMING_DATA
)
485 if (conn
->sink_input
) {
486 rate
= conn
->sink_input
->sample_spec
.rate
;
487 lvolume
= (conn
->sink_input
->volume
.values
[0]*ESD_VOLUME_BASE
)/PA_VOLUME_NORM
;
488 rvolume
= (conn
->sink_input
->volume
.values
[1]*ESD_VOLUME_BASE
)/PA_VOLUME_NORM
;
489 format
= format_native2esd(&conn
->sink_input
->sample_spec
);
493 *((int*) response
) = MAYBE_INT32_SWAP(c
->swap_byte_order
, (int) (conn
->index
+1));
494 response
+= sizeof(int);
497 assert(conn
->client
);
498 strncpy((char*) response
, conn
->client
->name
, ESD_NAME_MAX
);
499 response
+= ESD_NAME_MAX
;
502 *((int*) response
) = MAYBE_INT32_SWAP(c
->swap_byte_order
, rate
);
503 response
+= sizeof(int);
506 *((int*) response
) = MAYBE_INT32_SWAP(c
->swap_byte_order
, lvolume
);
507 response
+= sizeof(int);
510 *((int*) response
) = MAYBE_INT32_SWAP(c
->swap_byte_order
, rvolume
);
511 response
+= sizeof(int);
514 *((int*) response
) = MAYBE_INT32_SWAP(c
->swap_byte_order
, format
);
515 response
+= sizeof(int);
520 assert(t
== s
*(nsamples
+1)+k
);
521 memset(response
, 0, k
);
528 idx
= PA_IDXSET_INVALID
;
529 for (ce
= pa_idxset_first(c
->protocol
->core
->scache
, &idx
); ce
; ce
= pa_idxset_next(c
->protocol
->core
->scache
, &idx
)) {
533 *((int*) response
) = MAYBE_INT32_SWAP(c
->swap_byte_order
, (int) (ce
->index
+1));
534 response
+= sizeof(int);
537 if (strncmp(ce
->name
, SCACHE_PREFIX
, sizeof(SCACHE_PREFIX
)-1) == 0)
538 strncpy((char*) response
, ce
->name
+sizeof(SCACHE_PREFIX
)-1, ESD_NAME_MAX
);
540 snprintf((char*) response
, ESD_NAME_MAX
, "native.%s", ce
->name
);
541 response
+= ESD_NAME_MAX
;
544 *((int*) response
) = MAYBE_INT32_SWAP(c
->swap_byte_order
, ce
->sample_spec
.rate
);
545 response
+= sizeof(int);
548 *((int*) response
) = MAYBE_INT32_SWAP(c
->swap_byte_order
, (ce
->volume
.values
[0]*ESD_VOLUME_BASE
)/PA_VOLUME_NORM
);
549 response
+= sizeof(int);
552 *((int*) response
) = MAYBE_INT32_SWAP(c
->swap_byte_order
, (ce
->volume
.values
[0]*ESD_VOLUME_BASE
)/PA_VOLUME_NORM
);
553 response
+= sizeof(int);
556 *((int*) response
) = MAYBE_INT32_SWAP(c
->swap_byte_order
, format_native2esd(&ce
->sample_spec
));
557 response
+= sizeof(int);
560 *((int*) response
) = MAYBE_INT32_SWAP(c
->swap_byte_order
, (int) ce
->memchunk
.length
);
561 response
+= sizeof(int);
568 memset(response
, 0, s
);
573 static int esd_proto_stream_pan(struct connection
*c
, PA_GCC_UNUSED esd_proto_t request
, const void *data
, size_t length
) {
576 pa_volume_t lvolume
, rvolume
;
577 struct connection
*conn
;
578 assert(c
&& data
&& length
== sizeof(int)*3);
580 idx
= MAYBE_UINT32_SWAP(c
->swap_byte_order
, *(const int*)data
)-1;
581 lvolume
= MAYBE_UINT32_SWAP(c
->swap_byte_order
, *((const int*)data
+ 1));
582 lvolume
= (lvolume
*PA_VOLUME_NORM
)/ESD_VOLUME_BASE
;
583 rvolume
= MAYBE_UINT32_SWAP(c
->swap_byte_order
, *((const int*)data
+ 2));
584 rvolume
= (rvolume
*PA_VOLUME_NORM
)/ESD_VOLUME_BASE
;
586 ok
= connection_write(c
, sizeof(int));
589 if ((conn
= pa_idxset_get_by_index(c
->protocol
->connections
, idx
))) {
590 assert(conn
->sink_input
);
591 conn
->sink_input
->volume
.values
[0] = lvolume
;
592 conn
->sink_input
->volume
.values
[1] = rvolume
;
593 conn
->sink_input
->volume
.channels
= 2;
601 static int esd_proto_sample_cache(struct connection
*c
, PA_GCC_UNUSED esd_proto_t request
, const void *data
, size_t length
) {
607 char name
[ESD_NAME_MAX
+sizeof(SCACHE_PREFIX
)-1];
608 assert(c
&& data
&& length
== (ESD_NAME_MAX
+3*sizeof(int)));
610 format
= MAYBE_INT32_SWAP(c
->swap_byte_order
, *(const int*)data
);
611 rate
= MAYBE_INT32_SWAP(c
->swap_byte_order
, *((const int*)data
+ 1));
614 format_esd2native(format
, c
->swap_byte_order
, &ss
);
616 sc_length
= (size_t) MAYBE_INT32_SWAP(c
->swap_byte_order
, (*((const int*)data
+ 2)));
618 if (sc_length
>= MAX_CACHE_SAMPLE_SIZE
)
621 strcpy(name
, SCACHE_PREFIX
);
622 strncpy(name
+sizeof(SCACHE_PREFIX
)-1, (const char*) data
+3*sizeof(int), ESD_NAME_MAX
);
623 name
[sizeof(name
)-1] = 0;
625 assert(!c
->scache
.memchunk
.memblock
);
626 c
->scache
.memchunk
.memblock
= pa_memblock_new(sc_length
, c
->protocol
->core
->memblock_stat
);
627 c
->scache
.memchunk
.index
= 0;
628 c
->scache
.memchunk
.length
= sc_length
;
629 c
->scache
.sample_spec
= ss
;
630 assert(!c
->scache
.name
);
631 c
->scache
.name
= pa_xstrdup(name
);
633 c
->state
= ESD_CACHING_SAMPLE
;
635 pa_scache_add_item(c
->protocol
->core
, c
->scache
.name
, NULL
, NULL
, NULL
, &idx
);
637 ok
= connection_write(c
, sizeof(int));
645 static int esd_proto_sample_get_id(struct connection
*c
, PA_GCC_UNUSED esd_proto_t request
, const void *data
, size_t length
) {
648 char name
[ESD_NAME_MAX
+sizeof(SCACHE_PREFIX
)-1];
649 assert(c
&& data
&& length
== ESD_NAME_MAX
);
651 ok
= connection_write(c
, sizeof(int));
656 strcpy(name
, SCACHE_PREFIX
);
657 strncpy(name
+sizeof(SCACHE_PREFIX
)-1, data
, ESD_NAME_MAX
);
658 name
[sizeof(name
)-1] = 0;
660 if ((idx
= pa_scache_get_id_by_name(c
->protocol
->core
, name
)) != PA_IDXSET_INVALID
)
666 static int esd_proto_sample_free_or_play(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
670 assert(c
&& data
&& length
== sizeof(int));
672 idx
= (uint32_t) MAYBE_INT32_SWAP(c
->swap_byte_order
, *(const int*)data
)-1;
674 ok
= connection_write(c
, sizeof(int));
679 if ((name
= pa_scache_get_name_by_id(c
->protocol
->core
, idx
))) {
680 if (request
== ESD_PROTO_SAMPLE_PLAY
) {
683 if ((sink
= pa_namereg_get(c
->protocol
->core
, c
->protocol
->sink_name
, PA_NAMEREG_SINK
, 1)))
684 if (pa_scache_play_item(c
->protocol
->core
, name
, sink
, NULL
) >= 0)
687 assert(request
== ESD_PROTO_SAMPLE_FREE
);
689 if (pa_scache_remove_item(c
->protocol
->core
, name
) >= 0)
697 static int esd_proto_standby_or_resume(struct connection
*c
, PA_GCC_UNUSED esd_proto_t request
, PA_GCC_UNUSED
const void *data
, PA_GCC_UNUSED
size_t length
) {
699 ok
= connection_write(c
, sizeof(int)*2);
706 /*** client callbacks ***/
708 static void client_kill_cb(pa_client
*c
) {
709 assert(c
&& c
->userdata
);
710 connection_free(c
->userdata
);
713 /*** pa_iochannel callbacks ***/
715 static int do_read(struct connection
*c
) {
718 /* pa_log("READ\n"); */
720 if (c
->state
== ESD_NEXT_REQUEST
) {
722 assert(c
->read_data_length
< sizeof(c
->request
));
724 if ((r
= pa_iochannel_read(c
->io
, ((uint8_t*) &c
->request
) + c
->read_data_length
, sizeof(c
->request
) - c
->read_data_length
)) <= 0) {
726 pa_log_warn(__FILE__
": read() failed: %s\n", strerror(errno
));
730 if ((c
->read_data_length
+= r
) >= sizeof(c
->request
)) {
731 struct proto_handler
*handler
;
733 c
->request
= MAYBE_INT32_SWAP(c
->swap_byte_order
, c
->request
);
735 if (c
->request
< ESD_PROTO_CONNECT
|| c
->request
> ESD_PROTO_MAX
) {
736 pa_log(__FILE__
": recieved invalid request.\n");
740 handler
= proto_map
+c
->request
;
742 /* pa_log(__FILE__": executing request #%u\n", c->request); */
744 if (!handler
->proc
) {
745 pa_log(__FILE__
": recieved unimplemented request #%u.\n", c
->request
);
749 if (handler
->data_length
== 0) {
750 c
->read_data_length
= 0;
752 if (handler
->proc(c
, c
->request
, NULL
, 0) < 0)
756 if (c
->read_data_alloc
< handler
->data_length
)
757 c
->read_data
= pa_xrealloc(c
->read_data
, c
->read_data_alloc
= handler
->data_length
);
758 assert(c
->read_data
);
760 c
->state
= ESD_NEEDS_REQDATA
;
761 c
->read_data_length
= 0;
765 } else if (c
->state
== ESD_NEEDS_REQDATA
) {
767 struct proto_handler
*handler
= proto_map
+c
->request
;
769 assert(handler
->proc
);
771 assert(c
->read_data
&& c
->read_data_length
< handler
->data_length
);
773 if ((r
= pa_iochannel_read(c
->io
, (uint8_t*) c
->read_data
+ c
->read_data_length
, handler
->data_length
- c
->read_data_length
)) <= 0) {
775 pa_log_warn(__FILE__
": read() failed: %s\n", strerror(errno
));
779 if ((c
->read_data_length
+= r
) >= handler
->data_length
) {
780 size_t l
= c
->read_data_length
;
781 assert(handler
->proc
);
783 c
->state
= ESD_NEXT_REQUEST
;
784 c
->read_data_length
= 0;
786 if (handler
->proc(c
, c
->request
, c
->read_data
, l
) < 0)
789 } else if (c
->state
== ESD_CACHING_SAMPLE
) {
792 assert(c
->scache
.memchunk
.memblock
&& c
->scache
.name
&& c
->scache
.memchunk
.index
< c
->scache
.memchunk
.length
);
794 if ((r
= pa_iochannel_read(c
->io
, (uint8_t*) c
->scache
.memchunk
.memblock
->data
+c
->scache
.memchunk
.index
, c
->scache
.memchunk
.length
-c
->scache
.memchunk
.index
)) <= 0) {
796 pa_log_warn(__FILE__
": read() failed: %s\n", strerror(errno
));
800 c
->scache
.memchunk
.index
+= r
;
801 assert(c
->scache
.memchunk
.index
<= c
->scache
.memchunk
.length
);
803 if (c
->scache
.memchunk
.index
== c
->scache
.memchunk
.length
) {
807 c
->scache
.memchunk
.index
= 0;
808 pa_scache_add_item(c
->protocol
->core
, c
->scache
.name
, &c
->scache
.sample_spec
, NULL
, &c
->scache
.memchunk
, &idx
);
810 pa_memblock_unref(c
->scache
.memchunk
.memblock
);
811 c
->scache
.memchunk
.memblock
= NULL
;
812 c
->scache
.memchunk
.index
= c
->scache
.memchunk
.length
= 0;
814 pa_xfree(c
->scache
.name
);
815 c
->scache
.name
= NULL
;
817 c
->state
= ESD_NEXT_REQUEST
;
819 ok
= connection_write(c
, sizeof(int));
824 } else if (c
->state
== ESD_STREAMING_DATA
&& c
->sink_input
) {
829 assert(c
->input_memblockq
);
831 /* pa_log("STREAMING_DATA\n"); */
833 if (!(l
= pa_memblockq_missing(c
->input_memblockq
)))
836 if (l
> c
->playback
.fragment_size
)
837 l
= c
->playback
.fragment_size
;
839 if (c
->playback
.current_memblock
)
840 if (c
->playback
.current_memblock
->length
- c
->playback
.memblock_index
< l
) {
841 pa_memblock_unref(c
->playback
.current_memblock
);
842 c
->playback
.current_memblock
= NULL
;
843 c
->playback
.memblock_index
= 0;
846 if (!c
->playback
.current_memblock
) {
847 c
->playback
.current_memblock
= pa_memblock_new(c
->playback
.fragment_size
*2, c
->protocol
->core
->memblock_stat
);
848 assert(c
->playback
.current_memblock
&& c
->playback
.current_memblock
->length
>= l
);
849 c
->playback
.memblock_index
= 0;
852 if ((r
= pa_iochannel_read(c
->io
, (uint8_t*) c
->playback
.current_memblock
->data
+c
->playback
.memblock_index
, l
)) <= 0) {
854 pa_log(__FILE__
": read() failed: %s\n", strerror(errno
));
858 /* pa_log(__FILE__": read %u\n", r); */
860 chunk
.memblock
= c
->playback
.current_memblock
;
861 chunk
.index
= c
->playback
.memblock_index
;
863 assert(chunk
.memblock
);
865 c
->playback
.memblock_index
+= r
;
867 assert(c
->input_memblockq
);
868 pa_memblockq_push_align(c
->input_memblockq
, &chunk
, 0);
869 assert(c
->sink_input
);
870 pa_sink_notify(c
->sink_input
->sink
);
876 static int do_write(struct connection
*c
) {
879 /* pa_log("WRITE\n"); */
881 if (c
->write_data_length
) {
884 assert(c
->write_data_index
< c
->write_data_length
);
885 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) {
886 pa_log(__FILE__
": write() failed: %s\n", strerror(errno
));
890 if ((c
->write_data_index
+=r
) >= c
->write_data_length
)
891 c
->write_data_length
= c
->write_data_index
= 0;
893 } else if (c
->state
== ESD_STREAMING_DATA
&& c
->source_output
) {
897 assert(c
->output_memblockq
);
898 if (pa_memblockq_peek(c
->output_memblockq
, &chunk
) < 0)
901 assert(chunk
.memblock
&& chunk
.length
);
903 if ((r
= pa_iochannel_write(c
->io
, (uint8_t*) chunk
.memblock
->data
+chunk
.index
, chunk
.length
)) < 0) {
904 pa_memblock_unref(chunk
.memblock
);
905 pa_log(__FILE__
": write(): %s\n", strerror(errno
));
909 pa_memblockq_drop(c
->output_memblockq
, &chunk
, r
);
910 pa_memblock_unref(chunk
.memblock
);
916 static void do_work(struct connection
*c
) {
919 assert(c
->protocol
&& c
->protocol
->core
&& c
->protocol
->core
->mainloop
&& c
->protocol
->core
->mainloop
->defer_enable
);
920 c
->protocol
->core
->mainloop
->defer_enable(c
->defer_event
, 0);
922 /* pa_log("DOWORK %i\n", pa_iochannel_is_hungup(c->io)); */
924 if (!c
->dead
&& pa_iochannel_is_readable(c
->io
))
928 if (!c
->dead
&& pa_iochannel_is_writable(c
->io
))
932 /* In case the line was hungup, make sure to rerun this function
933 as soon as possible, until all data has been read. */
935 if (!c
->dead
&& pa_iochannel_is_hungup(c
->io
))
936 c
->protocol
->core
->mainloop
->defer_enable(c
->defer_event
, 1);
942 if (c
->state
== ESD_STREAMING_DATA
&& c
->sink_input
) {
944 pa_memblockq_prebuf_disable(c
->input_memblockq
);
946 pa_iochannel_free(c
->io
);
953 static void io_callback(pa_iochannel
*io
, void *userdata
) {
954 struct connection
*c
= userdata
;
955 assert(io
&& c
&& c
->io
== io
);
957 /* pa_log("IO\n"); */
962 /*** defer callback ***/
964 static void defer_callback(pa_mainloop_api
*a
, pa_defer_event
*e
, void *userdata
) {
965 struct connection
*c
= userdata
;
966 assert(a
&& c
&& c
->defer_event
== e
);
968 /* pa_log("DEFER\n"); */
973 /*** sink_input callbacks ***/
975 static int sink_input_peek_cb(pa_sink_input
*i
, pa_memchunk
*chunk
) {
977 assert(i
&& i
->userdata
&& chunk
);
980 if (pa_memblockq_peek(c
->input_memblockq
, chunk
) < 0) {
991 static void sink_input_drop_cb(pa_sink_input
*i
, const pa_memchunk
*chunk
, size_t length
) {
992 struct connection
*c
= i
->userdata
;
993 assert(i
&& c
&& length
);
995 /* pa_log("DROP\n"); */
997 pa_memblockq_drop(c
->input_memblockq
, chunk
, length
);
1000 assert(c
->protocol
&& c
->protocol
->core
&& c
->protocol
->core
->mainloop
&& c
->protocol
->core
->mainloop
->defer_enable
);
1003 c
->protocol
->core
->mainloop
->defer_enable(c
->defer_event
, 1);
1005 /* assert(pa_memblockq_get_length(c->input_memblockq) > 2048); */
1008 static void sink_input_kill_cb(pa_sink_input
*i
) {
1009 assert(i
&& i
->userdata
);
1010 connection_free((struct connection
*) i
->userdata
);
1013 static pa_usec_t
sink_input_get_latency_cb(pa_sink_input
*i
) {
1014 struct connection
*c
= i
->userdata
;
1016 return pa_bytes_to_usec(pa_memblockq_get_length(c
->input_memblockq
), &c
->sink_input
->sample_spec
);
1019 /*** source_output callbacks ***/
1021 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
1022 struct connection
*c
= o
->userdata
;
1023 assert(o
&& c
&& chunk
);
1025 pa_memblockq_push(c
->output_memblockq
, chunk
, 0);
1028 assert(c
->protocol
&& c
->protocol
->core
&& c
->protocol
->core
->mainloop
&& c
->protocol
->core
->mainloop
->defer_enable
);
1031 c
->protocol
->core
->mainloop
->defer_enable(c
->defer_event
, 1);
1034 static void source_output_kill_cb(pa_source_output
*o
) {
1035 assert(o
&& o
->userdata
);
1036 connection_free((struct connection
*) o
->userdata
);
1039 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
) {
1040 struct connection
*c
= o
->userdata
;
1042 return pa_bytes_to_usec(pa_memblockq_get_length(c
->output_memblockq
), &c
->source_output
->sample_spec
);
1045 /*** socket server callback ***/
1047 static void auth_timeout(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*tv
, void *userdata
) {
1048 struct connection
*c
= userdata
;
1049 assert(m
&& tv
&& c
&& c
->auth_timeout_event
== e
);
1055 static void on_connection(pa_socket_server
*s
, pa_iochannel
*io
, void *userdata
) {
1056 struct connection
*c
;
1057 pa_protocol_esound
*p
= userdata
;
1059 assert(s
&& io
&& p
);
1061 if (pa_idxset_size(p
->connections
)+1 > MAX_CONNECTIONS
) {
1062 pa_log(__FILE__
": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS
);
1063 pa_iochannel_free(io
);
1067 c
= pa_xmalloc(sizeof(struct connection
));
1070 pa_iochannel_set_callback(c
->io
, io_callback
, c
);
1072 pa_iochannel_socket_peer_to_string(io
, cname
, sizeof(cname
));
1074 c
->client
= pa_client_new(p
->core
, __FILE__
, cname
);
1076 c
->client
->owner
= p
->module
;
1077 c
->client
->kill
= client_kill_cb
;
1078 c
->client
->userdata
= c
;
1080 c
->authorized
= p
->public;
1081 c
->swap_byte_order
= 0;
1084 c
->read_data_length
= 0;
1085 c
->read_data
= pa_xmalloc(c
->read_data_alloc
= proto_map
[ESD_PROTO_CONNECT
].data_length
);
1087 c
->write_data_length
= c
->write_data_index
= c
->write_data_alloc
= 0;
1088 c
->write_data
= NULL
;
1090 c
->state
= ESD_NEEDS_REQDATA
;
1091 c
->request
= ESD_PROTO_CONNECT
;
1093 c
->sink_input
= NULL
;
1094 c
->input_memblockq
= NULL
;
1096 c
->source_output
= NULL
;
1097 c
->output_memblockq
= NULL
;
1099 c
->playback
.current_memblock
= NULL
;
1100 c
->playback
.memblock_index
= 0;
1101 c
->playback
.fragment_size
= 0;
1103 c
->scache
.memchunk
.length
= c
->scache
.memchunk
.index
= 0;
1104 c
->scache
.memchunk
.memblock
= NULL
;
1105 c
->scache
.name
= NULL
;
1107 if (!c
->authorized
) {
1109 pa_gettimeofday(&tv
);
1110 tv
.tv_sec
+= AUTH_TIMEOUT
;
1111 c
->auth_timeout_event
= p
->core
->mainloop
->time_new(p
->core
->mainloop
, &tv
, auth_timeout
, c
);
1113 c
->auth_timeout_event
= NULL
;
1115 c
->defer_event
= p
->core
->mainloop
->defer_new(p
->core
->mainloop
, defer_callback
, c
);
1116 assert(c
->defer_event
);
1117 p
->core
->mainloop
->defer_enable(c
->defer_event
, 0);
1119 pa_idxset_put(p
->connections
, c
, &c
->index
);
1122 /*** entry points ***/
1124 pa_protocol_esound
* pa_protocol_esound_new(pa_core
*core
, pa_socket_server
*server
, pa_module
*m
, pa_modargs
*ma
) {
1125 pa_protocol_esound
*p
;
1127 assert(core
&& server
&& ma
);
1129 p
= pa_xmalloc(sizeof(pa_protocol_esound
));
1131 if (pa_modargs_get_value_boolean(ma
, "public", &public) < 0) {
1132 pa_log(__FILE__
": public= expects a boolean argument.\n");
1136 if (pa_authkey_load_auto(pa_modargs_get_value(ma
, "cookie", DEFAULT_COOKIE_FILE
), p
->esd_key
, sizeof(p
->esd_key
)) < 0) {
1144 pa_socket_server_set_callback(p
->server
, on_connection
, p
);
1146 p
->connections
= pa_idxset_new(NULL
, NULL
);
1147 assert(p
->connections
);
1149 p
->sink_name
= pa_xstrdup(pa_modargs_get_value(ma
, "sink", NULL
));
1150 p
->source_name
= pa_xstrdup(pa_modargs_get_value(ma
, "source", NULL
));
1156 void pa_protocol_esound_free(pa_protocol_esound
*p
) {
1157 struct connection
*c
;
1160 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
1163 pa_idxset_free(p
->connections
, NULL
, NULL
);
1164 pa_socket_server_unref(p
->server
);