8 #include "protocol-esound.h"
9 #include "esound-spec.h"
12 #include "sinkinput.h"
14 #include "sourceoutput.h"
20 #define COOKIE_FILE ".esd_auth"
22 #define PLAYBACK_BUFFER_SECONDS (.5)
23 #define PLAYBACK_BUFFER_FRAGMENTS (10)
24 #define RECORD_BUFFER_SECONDS (5)
25 #define RECORD_BUFFER_FRAGMENTS (100)
27 /* This is heavily based on esound's code */
31 struct pa_protocol_esound
*protocol
;
32 struct pa_iochannel
*io
;
33 struct pa_client
*client
;
34 int authorized
, swap_byte_order
;
36 size_t write_data_alloc
, write_data_index
, write_data_length
;
38 size_t read_data_alloc
, read_data_length
;
40 esd_client_state_t state
;
41 struct pa_sink_input
*sink_input
;
42 struct pa_source_output
*source_output
;
43 struct pa_memblockq
*input_memblockq
, *output_memblockq
;
46 struct pa_memblock
*current_memblock
;
47 size_t memblock_index
, fragment_size
;
51 struct pa_protocol_esound
{
53 struct pa_module
*module
;
55 struct pa_socket_server
*server
;
56 struct pa_idxset
*connections
;
57 uint32_t sink_index
, source_index
;
59 uint8_t esd_key
[ESD_KEY_LEN
];
62 typedef struct proto_handler
{
64 int (*proc
)(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
65 const char *description
;
66 } esd_proto_handler_info_t
;
68 static void sink_input_drop_cb(struct pa_sink_input
*i
, size_t length
);
69 static int sink_input_peek_cb(struct pa_sink_input
*i
, struct pa_memchunk
*chunk
);
70 static void sink_input_kill_cb(struct pa_sink_input
*i
);
71 static uint32_t sink_input_get_latency_cb(struct pa_sink_input
*i
);
73 static void source_output_push_cb(struct pa_source_output
*o
, const struct pa_memchunk
*chunk
);
74 static void source_output_kill_cb(struct pa_source_output
*o
);
76 static int esd_proto_connect(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
77 static int esd_proto_stream_play(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
78 static int esd_proto_stream_record(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
79 static int esd_proto_get_latency(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
80 static int esd_proto_server_info(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
81 static int esd_proto_all_info(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
82 static int esd_proto_stream_pan(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
84 /* the big map of protocol handler info */
85 static struct proto_handler proto_map
[ESD_PROTO_MAX
] = {
86 { ESD_KEY_LEN
+ sizeof(int), esd_proto_connect
, "connect" },
87 { ESD_KEY_LEN
+ sizeof(int), NULL
, "lock" },
88 { ESD_KEY_LEN
+ sizeof(int), NULL
, "unlock" },
90 { ESD_NAME_MAX
+ 2 * sizeof(int), esd_proto_stream_play
, "stream play" },
91 { ESD_NAME_MAX
+ 2 * sizeof(int), esd_proto_stream_record
, "stream rec" },
92 { ESD_NAME_MAX
+ 2 * sizeof(int), esd_proto_stream_record
, "stream mon" },
94 { ESD_NAME_MAX
+ 3 * sizeof(int), NULL
, "sample cache" },
95 { sizeof(int), NULL
, "sample free" },
96 { sizeof(int), NULL
, "sample play" },
97 { sizeof(int), NULL
, "sample loop" },
98 { sizeof(int), NULL
, "sample stop" },
99 { -1, NULL
, "TODO: sample kill" },
101 { ESD_KEY_LEN
+ sizeof(int), NULL
, "standby" },
102 { ESD_KEY_LEN
+ sizeof(int), NULL
, "resume" },
104 { ESD_NAME_MAX
, NULL
, "sample getid" },
105 { ESD_NAME_MAX
+ 2 * sizeof(int), NULL
, "stream filter" },
107 { sizeof(int), esd_proto_server_info
, "server info" },
108 { sizeof(int), esd_proto_all_info
, "all info" },
109 { -1, NULL
, "TODO: subscribe" },
110 { -1, NULL
, "TODO: unsubscribe" },
112 { 3 * sizeof(int), esd_proto_stream_pan
, "stream pan"},
113 { 3 * sizeof(int), NULL
, "sample pan" },
115 { sizeof(int), NULL
, "standby mode" },
116 { 0, esd_proto_get_latency
, "get latency" }
120 static void connection_free(struct connection
*c
) {
122 pa_idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
);
124 if (c
->state
== ESD_STREAMING_DATA
)
125 c
->protocol
->n_player
--;
127 pa_client_free(c
->client
);
130 pa_sink_input_free(c
->sink_input
);
131 if (c
->source_output
)
132 pa_source_output_free(c
->source_output
);
133 if (c
->input_memblockq
)
134 pa_memblockq_free(c
->input_memblockq
);
135 if (c
->output_memblockq
)
136 pa_memblockq_free(c
->output_memblockq
);
138 if (c
->playback
.current_memblock
)
139 pa_memblock_unref(c
->playback
.current_memblock
);
144 pa_iochannel_free(c
->io
);
147 c
->protocol
->core
->mainloop
->cancel_fixed(c
->protocol
->core
->mainloop
, c
->fixed_source
);
152 static struct pa_sink
* get_output_sink(struct pa_protocol_esound
*p
) {
156 if (!(s
= pa_idxset_get_by_index(p
->core
->sinks
, p
->sink_index
)))
157 s
= pa_sink_get_default(p
->core
);
159 p
->sink_index
= s
? s
->index
: PA_IDXSET_INVALID
;
163 static struct pa_source
* get_input_source(struct pa_protocol_esound
*p
) {
167 if (!(s
= pa_idxset_get_by_index(p
->core
->sources
, p
->sink_index
)))
168 s
= pa_source_get_default(p
->core
);
170 p
->source_index
= s
? s
->index
: PA_IDXSET_INVALID
;
174 static void* connection_write(struct connection
*c
, size_t length
) {
178 assert(c
->protocol
&& c
->protocol
->core
&& c
->protocol
->core
->mainloop
&& c
->protocol
->core
->mainloop
->enable_fixed
);
179 c
->protocol
->core
->mainloop
->enable_fixed(c
->protocol
->core
->mainloop
, c
->fixed_source
, 1);
181 t
= c
->write_data_length
+length
;
183 if (c
->write_data_alloc
< t
)
184 c
->write_data
= realloc(c
->write_data
, c
->write_data_alloc
= t
);
186 assert(c
->write_data
);
188 i
= c
->write_data_length
;
189 c
->write_data_length
+= length
;
191 return c
->write_data
+i
;
194 /*** esound commands ***/
196 static int esd_proto_connect(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
199 assert(length
== (ESD_KEY_LEN
+ sizeof(uint32_t)));
201 if (!c
->authorized
) {
202 if (memcmp(data
, c
->protocol
->esd_key
, ESD_KEY_LEN
) != 0) {
203 fprintf(stderr
, __FILE__
": kicked client with invalid authorization key.\n");
210 ekey
= *(uint32_t*)(data
+ESD_KEY_LEN
);
211 if (ekey
== ESD_ENDIAN_KEY
)
212 c
->swap_byte_order
= 0;
213 else if (ekey
== ESD_SWAP_ENDIAN_KEY
)
214 c
->swap_byte_order
= 1;
216 fprintf(stderr
, __FILE__
": client sent invalid endian key\n");
220 ok
= connection_write(c
, sizeof(int));
226 static int esd_proto_stream_play(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
227 char name
[ESD_NAME_MAX
];
229 struct pa_sink
*sink
;
230 struct pa_sample_spec ss
;
232 assert(c
&& length
== (sizeof(int)*2+ESD_NAME_MAX
));
234 format
= maybe_swap_endian_32(c
->swap_byte_order
, *(int*)data
);
235 rate
= maybe_swap_endian_32(c
->swap_byte_order
, *((int*)data
+ 1));
238 ss
.channels
= ((format
& ESD_MASK_CHAN
) == ESD_STEREO
) ? 2 : 1;
239 ss
.format
= ((format
& ESD_MASK_BITS
) == ESD_BITS16
) ? PA_SAMPLE_S16NE
: PA_SAMPLE_U8
;
241 if (!pa_sample_spec_valid(&ss
))
244 if (!(sink
= get_output_sink(c
->protocol
)))
247 strncpy(name
, data
+ sizeof(int)*2, sizeof(name
));
248 name
[sizeof(name
)-1] = 0;
250 pa_client_rename(c
->client
, name
);
252 assert(!c
->input_memblockq
);
254 l
= (size_t) (pa_bytes_per_second(&ss
)*PLAYBACK_BUFFER_SECONDS
);
255 c
->input_memblockq
= pa_memblockq_new(l
, 0, pa_sample_size(&ss
), l
/2, l
/PLAYBACK_BUFFER_FRAGMENTS
);
256 assert(c
->input_memblockq
);
257 pa_iochannel_socket_set_rcvbuf(c
->io
, l
/PLAYBACK_BUFFER_FRAGMENTS
*5);
258 c
->playback
.fragment_size
= l
/10;
260 assert(!c
->sink_input
);
261 c
->sink_input
= pa_sink_input_new(sink
, name
, &ss
);
262 assert(c
->sink_input
);
264 c
->sink_input
->owner
= c
->protocol
->module
;
265 c
->sink_input
->client
= c
->client
;
266 c
->sink_input
->peek
= sink_input_peek_cb
;
267 c
->sink_input
->drop
= sink_input_drop_cb
;
268 c
->sink_input
->kill
= sink_input_kill_cb
;
269 c
->sink_input
->get_latency
= sink_input_get_latency_cb
;
270 c
->sink_input
->userdata
= c
;
272 c
->state
= ESD_STREAMING_DATA
;
274 c
->protocol
->n_player
++;
279 static int esd_proto_stream_record(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
280 char name
[ESD_NAME_MAX
];
282 struct pa_source
*source
;
283 struct pa_sample_spec ss
;
285 assert(c
&& length
== (sizeof(int)*2+ESD_NAME_MAX
));
287 format
= maybe_swap_endian_32(c
->swap_byte_order
, *(int*)data
);
288 rate
= maybe_swap_endian_32(c
->swap_byte_order
, *((int*)data
+ 1));
291 ss
.channels
= ((format
& ESD_MASK_CHAN
) == ESD_STEREO
) ? 2 : 1;
292 ss
.format
= ((format
& ESD_MASK_BITS
) == ESD_BITS16
) ? PA_SAMPLE_S16NE
: PA_SAMPLE_U8
;
294 if (!pa_sample_spec_valid(&ss
))
297 if (request
== ESD_PROTO_STREAM_MON
) {
298 struct pa_sink
* sink
;
300 if (!(sink
= get_output_sink(c
->protocol
)))
303 if (!(source
= sink
->monitor_source
))
306 assert(request
== ESD_PROTO_STREAM_REC
);
308 if (!(source
= get_input_source(c
->protocol
)))
312 strncpy(name
, data
+ sizeof(int)*2, sizeof(name
));
313 name
[sizeof(name
)-1] = 0;
315 pa_client_rename(c
->client
, name
);
317 assert(!c
->output_memblockq
);
319 l
= (size_t) (pa_bytes_per_second(&ss
)*RECORD_BUFFER_SECONDS
);
320 c
->output_memblockq
= pa_memblockq_new(l
, 0, pa_sample_size(&ss
), 0, 0);
321 assert(c
->output_memblockq
);
322 pa_iochannel_socket_set_sndbuf(c
->io
, l
/RECORD_BUFFER_FRAGMENTS
*2);
324 assert(!c
->source_output
);
325 c
->source_output
= pa_source_output_new(source
, name
, &ss
);
326 assert(c
->source_output
);
328 c
->source_output
->owner
= c
->protocol
->module
;
329 c
->source_output
->client
= c
->client
;
330 c
->source_output
->push
= source_output_push_cb
;
331 c
->source_output
->kill
= source_output_kill_cb
;
332 c
->source_output
->userdata
= c
;
334 c
->state
= ESD_STREAMING_DATA
;
336 c
->protocol
->n_player
++;
341 static int esd_proto_get_latency(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
342 struct pa_sink
*sink
;
344 assert(c
&& !data
&& length
== 0);
346 if (!(sink
= get_output_sink(c
->protocol
)))
349 float usec
= pa_sink_get_latency(sink
);
350 usec
+= PLAYBACK_BUFFER_SECONDS
*1000000*.9; /* A better estimation would be a good idea! */
351 latency
= (int) ((usec
*44100)/1000000);
354 lag
= connection_write(c
, sizeof(int));
356 *lag
= c
->swap_byte_order
? swap_endian_32(latency
) : latency
;
360 static int esd_proto_server_info(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
361 int rate
= 44100, format
= ESD_STEREO
|ESD_BITS16
;
363 struct pa_sink
*sink
;
364 assert(c
&& data
&& length
== sizeof(int));
366 if ((sink
= get_output_sink(c
->protocol
))) {
367 rate
= sink
->sample_spec
.rate
;
368 format
= (sink
->sample_spec
.format
== PA_SAMPLE_U8
) ? ESD_BITS8
: ESD_BITS16
;
369 format
|= (sink
->sample_spec
.channels
>= 2) ? ESD_STEREO
: ESD_MONO
;
372 response
= connection_write(c
, sizeof(int)*3);
375 *(response
++) = maybe_swap_endian_32(c
->swap_byte_order
, rate
);
376 *(response
++) = maybe_swap_endian_32(c
->swap_byte_order
, format
);
380 static int esd_proto_all_info(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
383 struct connection
*conn
;
384 size_t index
= PA_IDXSET_INVALID
;
385 assert(c
&& data
&& length
== sizeof(int));
387 if (esd_proto_server_info(c
, request
, data
, length
) < 0)
390 k
= sizeof(int)*5+ESD_NAME_MAX
;
391 s
= sizeof(int)*6+ESD_NAME_MAX
;
392 response
= connection_write(c
, (t
= s
+k
*(c
->protocol
->n_player
+1)));
395 for (conn
= pa_idxset_first(c
->protocol
->connections
, &index
); conn
; conn
= pa_idxset_next(c
->protocol
->connections
, &index
)) {
396 int format
= ESD_BITS16
| ESD_STEREO
, rate
= 44100, volume
= 0xFF;
398 if (conn
->state
!= ESD_STREAMING_DATA
)
403 if (conn
->sink_input
) {
404 rate
= conn
->sink_input
->sample_spec
.rate
;
405 volume
= (conn
->sink_input
->volume
*0xFF)/0x100;
406 format
= (conn
->sink_input
->sample_spec
.format
== PA_SAMPLE_U8
) ? ESD_BITS8
: ESD_BITS16
;
407 format
|= (conn
->sink_input
->sample_spec
.channels
>= 2) ? ESD_STEREO
: ESD_MONO
;
411 *((int*) response
) = maybe_swap_endian_32(c
->swap_byte_order
, (int) conn
->index
);
412 response
+= sizeof(int);
415 assert(conn
->client
);
416 strncpy(response
, conn
->client
->name
, ESD_NAME_MAX
);
417 response
+= ESD_NAME_MAX
;
420 *((int*) response
) = maybe_swap_endian_32(c
->swap_byte_order
, rate
);
421 response
+= sizeof(int);
424 *((int*) response
) = maybe_swap_endian_32(c
->swap_byte_order
, volume
);
425 response
+= sizeof(int);
428 *((int*) response
) = maybe_swap_endian_32(c
->swap_byte_order
, volume
);
429 response
+= sizeof(int);
432 *((int*) response
) = maybe_swap_endian_32(c
->swap_byte_order
, format
);
433 response
+= sizeof(int);
439 memset(response
, 0, t
);
443 static int esd_proto_stream_pan(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
445 uint32_t index
, volume
;
446 struct connection
*conn
;
447 assert(c
&& data
&& length
== sizeof(int)*3);
449 index
= (uint32_t) maybe_swap_endian_32(c
->swap_byte_order
, *(int*)data
);
450 volume
= (uint32_t) maybe_swap_endian_32(c
->swap_byte_order
, *((int*)data
+ 1));
451 volume
= (volume
*0x100)/0xFF;
453 ok
= connection_write(c
, sizeof(int));
456 if ((conn
= pa_idxset_get_by_index(c
->protocol
->connections
, index
))) {
457 assert(conn
->sink_input
);
458 conn
->sink_input
->volume
= volume
;
466 /*** client callbacks ***/
468 static void client_kill_cb(struct pa_client
*c
) {
469 assert(c
&& c
->userdata
);
470 connection_free(c
->userdata
);
473 /*** pa_iochannel callbacks ***/
475 static int do_read(struct connection
*c
) {
478 if (c
->state
== ESD_NEXT_REQUEST
) {
480 assert(c
->read_data_length
< sizeof(c
->request
));
482 if ((r
= pa_iochannel_read(c
->io
, ((void*) &c
->request
) + c
->read_data_length
, sizeof(c
->request
) - c
->read_data_length
)) <= 0) {
483 fprintf(stderr
, "protocol-esound.c: read() failed: %s\n", r
== 0 ? "EOF" : strerror(errno
));
487 if ((c
->read_data_length
+= r
) >= sizeof(c
->request
)) {
488 struct proto_handler
*handler
;
490 if (c
->swap_byte_order
)
491 c
->request
= swap_endian_32(c
->request
);
493 if (c
->request
< ESD_PROTO_CONNECT
|| c
->request
> ESD_PROTO_MAX
) {
494 fprintf(stderr
, "protocol-esound.c: recieved invalid request.\n");
498 handler
= proto_map
+c
->request
;
500 if (!handler
->proc
) {
501 fprintf(stderr
, "protocol-sound.c: recieved unimplemented request.\n");
505 if (handler
->data_length
== 0) {
506 c
->read_data_length
= 0;
508 if (handler
->proc(c
, c
->request
, NULL
, 0) < 0)
512 if (c
->read_data_alloc
< handler
->data_length
)
513 c
->read_data
= realloc(c
->read_data
, c
->read_data_alloc
= handler
->data_length
);
514 assert(c
->read_data
);
516 c
->state
= ESD_NEEDS_REQDATA
;
517 c
->read_data_length
= 0;
521 } else if (c
->state
== ESD_NEEDS_REQDATA
) {
523 struct proto_handler
*handler
= proto_map
+c
->request
;
525 assert(handler
->proc
);
527 assert(c
->read_data
&& c
->read_data_length
< handler
->data_length
);
529 if ((r
= pa_iochannel_read(c
->io
, c
->read_data
+ c
->read_data_length
, handler
->data_length
- c
->read_data_length
)) <= 0) {
530 fprintf(stderr
, "protocol-esound.c: read() failed: %s\n", r
== 0 ? "EOF" : strerror(errno
));
534 if ((c
->read_data_length
+= r
) >= handler
->data_length
) {
535 size_t l
= c
->read_data_length
;
536 assert(handler
->proc
);
538 c
->state
= ESD_NEXT_REQUEST
;
539 c
->read_data_length
= 0;
541 if (handler
->proc(c
, c
->request
, c
->read_data
, l
) < 0)
544 } else if (c
->state
== ESD_STREAMING_DATA
&& c
->sink_input
) {
545 struct pa_memchunk chunk
;
549 assert(c
->input_memblockq
);
551 if (!(l
= pa_memblockq_missing(c
->input_memblockq
)))
554 if (l
> c
->playback
.fragment_size
)
555 l
= c
->playback
.fragment_size
;
557 if (c
->playback
.current_memblock
)
558 if (c
->playback
.current_memblock
->length
- c
->playback
.memblock_index
< l
) {
559 pa_memblock_unref(c
->playback
.current_memblock
);
560 c
->playback
.current_memblock
= NULL
;
561 c
->playback
.memblock_index
= 0;
565 if (!c
->playback
.current_memblock
) {
566 c
->playback
.current_memblock
= pa_memblock_new(c
->playback
.fragment_size
*2);
567 assert(c
->playback
.current_memblock
&& c
->playback
.current_memblock
->length
>= l
);
568 c
->playback
.memblock_index
= 0;
571 if ((r
= pa_iochannel_read(c
->io
, c
->playback
.current_memblock
->data
+c
->playback
.memblock_index
, l
)) <= 0) {
572 fprintf(stderr
, __FILE__
": read() failed: %s\n", r
== 0 ? "EOF" : strerror(errno
));
576 chunk
.memblock
= c
->playback
.current_memblock
;
577 chunk
.index
= c
->playback
.memblock_index
;
579 assert(chunk
.memblock
);
581 c
->playback
.memblock_index
+= r
;
583 assert(c
->input_memblockq
);
584 pa_memblockq_push_align(c
->input_memblockq
, &chunk
, 0);
585 assert(c
->sink_input
);
586 pa_sink_notify(c
->sink_input
->sink
);
593 static int do_write(struct connection
*c
) {
596 if (c
->write_data_length
) {
599 assert(c
->write_data_index
< c
->write_data_length
);
600 if ((r
= pa_iochannel_write(c
->io
, c
->write_data
+c
->write_data_index
, c
->write_data_length
-c
->write_data_index
)) < 0) {
601 fprintf(stderr
, __FILE__
": write() failed: %s\n", strerror(errno
));
605 if ((c
->write_data_index
+=r
) >= c
->write_data_length
)
606 c
->write_data_length
= c
->write_data_index
= 0;
608 } else if (c
->state
== ESD_STREAMING_DATA
&& c
->source_output
) {
609 struct pa_memchunk chunk
;
612 assert(c
->output_memblockq
);
613 if (pa_memblockq_peek(c
->output_memblockq
, &chunk
) < 0)
616 assert(chunk
.memblock
&& chunk
.length
);
618 if ((r
= pa_iochannel_write(c
->io
, chunk
.memblock
->data
+chunk
.index
, chunk
.length
)) < 0) {
619 pa_memblock_unref(chunk
.memblock
);
620 fprintf(stderr
, __FILE__
": write(): %s\n", strerror(errno
));
624 pa_memblockq_drop(c
->output_memblockq
, r
);
625 pa_memblock_unref(chunk
.memblock
);
631 static void do_work(struct connection
*c
) {
634 assert(c
->protocol
&& c
->protocol
->core
&& c
->protocol
->core
->mainloop
&& c
->protocol
->core
->mainloop
->enable_fixed
);
635 c
->protocol
->core
->mainloop
->enable_fixed(c
->protocol
->core
->mainloop
, c
->fixed_source
, 0);
637 if (pa_iochannel_is_hungup(c
->io
))
640 if (pa_iochannel_is_writable(c
->io
))
644 if (pa_iochannel_is_readable(c
->io
))
654 static void io_callback(struct pa_iochannel
*io
, void *userdata
) {
655 struct connection
*c
= userdata
;
656 assert(io
&& c
&& c
->io
== io
);
661 /*** fixed callback ***/
663 void fixed_callback(struct pa_mainloop_api
*a
, void *id
, void *userdata
) {
664 struct connection
*c
= userdata
;
665 assert(a
&& c
&& c
->fixed_source
== id
);
670 /*** sink_input callbacks ***/
672 static int sink_input_peek_cb(struct pa_sink_input
*i
, struct pa_memchunk
*chunk
) {
674 assert(i
&& i
->userdata
&& chunk
);
677 if (pa_memblockq_peek(c
->input_memblockq
, chunk
) < 0)
683 static void sink_input_drop_cb(struct pa_sink_input
*i
, size_t length
) {
684 struct connection
*c
= i
->userdata
;
685 assert(i
&& c
&& length
);
687 pa_memblockq_drop(c
->input_memblockq
, length
);
690 assert(c
->protocol
&& c
->protocol
->core
&& c
->protocol
->core
->mainloop
&& c
->protocol
->core
->mainloop
->enable_fixed
);
691 c
->protocol
->core
->mainloop
->enable_fixed(c
->protocol
->core
->mainloop
, c
->fixed_source
, 1);
694 static void sink_input_kill_cb(struct pa_sink_input
*i
) {
695 assert(i
&& i
->userdata
);
696 connection_free((struct connection
*) i
->userdata
);
700 static uint32_t sink_input_get_latency_cb(struct pa_sink_input
*i
) {
701 struct connection
*c
= i
->userdata
;
703 return pa_samples_usec(pa_memblockq_get_length(c
->input_memblockq
), &c
->sink_input
->sample_spec
);
706 /*** source_output callbacks ***/
708 static void source_output_push_cb(struct pa_source_output
*o
, const struct pa_memchunk
*chunk
) {
709 struct connection
*c
= o
->userdata
;
710 assert(o
&& c
&& chunk
);
712 pa_memblockq_push(c
->output_memblockq
, chunk
, 0);
715 assert(c
->protocol
&& c
->protocol
->core
&& c
->protocol
->core
->mainloop
&& c
->protocol
->core
->mainloop
->enable_fixed
);
716 c
->protocol
->core
->mainloop
->enable_fixed(c
->protocol
->core
->mainloop
, c
->fixed_source
, 1);
719 static void source_output_kill_cb(struct pa_source_output
*o
) {
720 assert(o
&& o
->userdata
);
721 connection_free((struct connection
*) o
->userdata
);
724 /*** socket server callback ***/
726 static void on_connection(struct pa_socket_server
*s
, struct pa_iochannel
*io
, void *userdata
) {
727 struct connection
*c
;
729 assert(s
&& io
&& userdata
);
731 c
= malloc(sizeof(struct connection
));
733 c
->protocol
= userdata
;
735 pa_iochannel_set_callback(c
->io
, io_callback
, c
);
737 pa_iochannel_socket_peer_to_string(io
, cname
, sizeof(cname
));
738 assert(c
->protocol
->core
);
739 c
->client
= pa_client_new(c
->protocol
->core
, "ESOUND", cname
);
741 c
->client
->owner
= c
->protocol
->module
;
742 c
->client
->kill
= client_kill_cb
;
743 c
->client
->userdata
= c
;
745 c
->authorized
= c
->protocol
->public;
746 c
->swap_byte_order
= 0;
748 c
->read_data_length
= 0;
749 c
->read_data
= malloc(c
->read_data_alloc
= proto_map
[ESD_PROTO_CONNECT
].data_length
);
750 assert(c
->read_data
);
752 c
->write_data_length
= c
->write_data_index
= c
->write_data_alloc
= 0;
753 c
->write_data
= NULL
;
755 c
->state
= ESD_NEEDS_REQDATA
;
756 c
->request
= ESD_PROTO_CONNECT
;
758 c
->sink_input
= NULL
;
759 c
->input_memblockq
= NULL
;
761 c
->source_output
= NULL
;
762 c
->output_memblockq
= NULL
;
764 c
->playback
.current_memblock
= NULL
;
765 c
->playback
.memblock_index
= 0;
766 c
->playback
.fragment_size
= 0;
768 c
->fixed_source
= c
->protocol
->core
->mainloop
->source_fixed(c
->protocol
->core
->mainloop
, fixed_callback
, c
);
769 assert(c
->fixed_source
);
770 c
->protocol
->core
->mainloop
->enable_fixed(c
->protocol
->core
->mainloop
, c
->fixed_source
, 0);
772 pa_idxset_put(c
->protocol
->connections
, c
, &c
->index
);
775 /*** entry points ***/
777 struct pa_protocol_esound
* pa_protocol_esound_new(struct pa_core
*core
, struct pa_socket_server
*server
, struct pa_module
*m
) {
778 struct pa_protocol_esound
*p
;
779 assert(core
&& server
);
781 p
= malloc(sizeof(struct pa_protocol_esound
));
784 if (pa_authkey_load_from_home(COOKIE_FILE
, p
->esd_key
, sizeof(p
->esd_key
)) < 0) {
792 pa_socket_server_set_callback(p
->server
, on_connection
, p
);
794 p
->connections
= pa_idxset_new(NULL
, NULL
);
795 assert(p
->connections
);
796 p
->sink_index
= p
->source_index
= PA_IDXSET_INVALID
;
802 void pa_protocol_esound_free(struct pa_protocol_esound
*p
) {
803 struct connection
*c
;
806 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
809 pa_idxset_free(p
->connections
, NULL
, NULL
);
810 pa_socket_server_free(p
->server
);