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 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 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"
45 #define DEFAULT_COOKIE_FILE ".esd_auth"
47 #define PLAYBACK_BUFFER_SECONDS (.5)
48 #define PLAYBACK_BUFFER_FRAGMENTS (10)
49 #define RECORD_BUFFER_SECONDS (5)
50 #define RECORD_BUFFER_FRAGMENTS (100)
52 /* This is heavily based on esound's code */
56 struct pa_protocol_esound
*protocol
;
57 struct pa_iochannel
*io
;
58 struct pa_client
*client
;
59 int authorized
, swap_byte_order
;
61 size_t write_data_alloc
, write_data_index
, write_data_length
;
63 size_t read_data_alloc
, read_data_length
;
65 esd_client_state_t state
;
66 struct pa_sink_input
*sink_input
;
67 struct pa_source_output
*source_output
;
68 struct pa_memblockq
*input_memblockq
, *output_memblockq
;
71 struct pa_memblock
*current_memblock
;
72 size_t memblock_index
, fragment_size
;
76 struct pa_protocol_esound
{
78 struct pa_module
*module
;
80 struct pa_socket_server
*server
;
81 struct pa_idxset
*connections
;
82 uint32_t sink_index
, source_index
;
84 uint8_t esd_key
[ESD_KEY_LEN
];
87 typedef struct proto_handler
{
89 int (*proc
)(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
90 const char *description
;
91 } esd_proto_handler_info_t
;
93 static void sink_input_drop_cb(struct pa_sink_input
*i
, size_t length
);
94 static int sink_input_peek_cb(struct pa_sink_input
*i
, struct pa_memchunk
*chunk
);
95 static void sink_input_kill_cb(struct pa_sink_input
*i
);
96 static uint32_t sink_input_get_latency_cb(struct pa_sink_input
*i
);
98 static void source_output_push_cb(struct pa_source_output
*o
, const struct pa_memchunk
*chunk
);
99 static void source_output_kill_cb(struct pa_source_output
*o
);
101 static int esd_proto_connect(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
102 static int esd_proto_stream_play(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
103 static int esd_proto_stream_record(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
104 static int esd_proto_get_latency(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
105 static int esd_proto_server_info(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
106 static int esd_proto_all_info(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
107 static int esd_proto_stream_pan(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
);
109 /* the big map of protocol handler info */
110 static struct proto_handler proto_map
[ESD_PROTO_MAX
] = {
111 { ESD_KEY_LEN
+ sizeof(int), esd_proto_connect
, "connect" },
112 { ESD_KEY_LEN
+ sizeof(int), NULL
, "lock" },
113 { ESD_KEY_LEN
+ sizeof(int), NULL
, "unlock" },
115 { ESD_NAME_MAX
+ 2 * sizeof(int), esd_proto_stream_play
, "stream play" },
116 { ESD_NAME_MAX
+ 2 * sizeof(int), esd_proto_stream_record
, "stream rec" },
117 { ESD_NAME_MAX
+ 2 * sizeof(int), esd_proto_stream_record
, "stream mon" },
119 { ESD_NAME_MAX
+ 3 * sizeof(int), NULL
, "sample cache" },
120 { sizeof(int), NULL
, "sample free" },
121 { sizeof(int), NULL
, "sample play" },
122 { sizeof(int), NULL
, "sample loop" },
123 { sizeof(int), NULL
, "sample stop" },
124 { -1, NULL
, "TODO: sample kill" },
126 { ESD_KEY_LEN
+ sizeof(int), NULL
, "standby" },
127 { ESD_KEY_LEN
+ sizeof(int), NULL
, "resume" },
129 { ESD_NAME_MAX
, NULL
, "sample getid" },
130 { ESD_NAME_MAX
+ 2 * sizeof(int), NULL
, "stream filter" },
132 { sizeof(int), esd_proto_server_info
, "server info" },
133 { sizeof(int), esd_proto_all_info
, "all info" },
134 { -1, NULL
, "TODO: subscribe" },
135 { -1, NULL
, "TODO: unsubscribe" },
137 { 3 * sizeof(int), esd_proto_stream_pan
, "stream pan"},
138 { 3 * sizeof(int), NULL
, "sample pan" },
140 { sizeof(int), NULL
, "standby mode" },
141 { 0, esd_proto_get_latency
, "get latency" }
145 static void connection_free(struct connection
*c
) {
147 pa_idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
);
149 if (c
->state
== ESD_STREAMING_DATA
)
150 c
->protocol
->n_player
--;
152 pa_client_free(c
->client
);
155 pa_sink_input_free(c
->sink_input
);
156 if (c
->source_output
)
157 pa_source_output_free(c
->source_output
);
158 if (c
->input_memblockq
)
159 pa_memblockq_free(c
->input_memblockq
);
160 if (c
->output_memblockq
)
161 pa_memblockq_free(c
->output_memblockq
);
163 if (c
->playback
.current_memblock
)
164 pa_memblock_unref(c
->playback
.current_memblock
);
169 pa_iochannel_free(c
->io
);
172 c
->protocol
->core
->mainloop
->cancel_fixed(c
->protocol
->core
->mainloop
, c
->fixed_source
);
177 static struct pa_sink
* get_output_sink(struct pa_protocol_esound
*p
) {
181 if (!(s
= pa_idxset_get_by_index(p
->core
->sinks
, p
->sink_index
)))
182 s
= pa_sink_get_default(p
->core
);
184 p
->sink_index
= s
? s
->index
: PA_IDXSET_INVALID
;
188 static struct pa_source
* get_input_source(struct pa_protocol_esound
*p
) {
192 if (!(s
= pa_idxset_get_by_index(p
->core
->sources
, p
->sink_index
)))
193 s
= pa_source_get_default(p
->core
);
195 p
->source_index
= s
? s
->index
: PA_IDXSET_INVALID
;
199 static void* connection_write(struct connection
*c
, size_t length
) {
203 assert(c
->protocol
&& c
->protocol
->core
&& c
->protocol
->core
->mainloop
&& c
->protocol
->core
->mainloop
->enable_fixed
);
204 c
->protocol
->core
->mainloop
->enable_fixed(c
->protocol
->core
->mainloop
, c
->fixed_source
, 1);
206 t
= c
->write_data_length
+length
;
208 if (c
->write_data_alloc
< t
)
209 c
->write_data
= realloc(c
->write_data
, c
->write_data_alloc
= t
);
211 assert(c
->write_data
);
213 i
= c
->write_data_length
;
214 c
->write_data_length
+= length
;
216 return c
->write_data
+i
;
219 /*** esound commands ***/
221 static int esd_proto_connect(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
224 assert(length
== (ESD_KEY_LEN
+ sizeof(uint32_t)));
226 if (!c
->authorized
) {
227 if (memcmp(data
, c
->protocol
->esd_key
, ESD_KEY_LEN
) != 0) {
228 fprintf(stderr
, __FILE__
": kicked client with invalid authorization key.\n");
235 ekey
= *(uint32_t*)(data
+ESD_KEY_LEN
);
236 if (ekey
== ESD_ENDIAN_KEY
)
237 c
->swap_byte_order
= 0;
238 else if (ekey
== ESD_SWAP_ENDIAN_KEY
)
239 c
->swap_byte_order
= 1;
241 fprintf(stderr
, __FILE__
": client sent invalid endian key\n");
245 ok
= connection_write(c
, sizeof(int));
251 static int esd_proto_stream_play(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
252 char name
[ESD_NAME_MAX
];
254 struct pa_sink
*sink
;
255 struct pa_sample_spec ss
;
257 assert(c
&& length
== (sizeof(int)*2+ESD_NAME_MAX
));
259 format
= maybe_swap_endian_32(c
->swap_byte_order
, *(int*)data
);
260 rate
= maybe_swap_endian_32(c
->swap_byte_order
, *((int*)data
+ 1));
263 ss
.channels
= ((format
& ESD_MASK_CHAN
) == ESD_STEREO
) ? 2 : 1;
264 ss
.format
= ((format
& ESD_MASK_BITS
) == ESD_BITS16
) ? PA_SAMPLE_S16NE
: PA_SAMPLE_U8
;
266 if (!pa_sample_spec_valid(&ss
))
269 if (!(sink
= get_output_sink(c
->protocol
)))
272 strncpy(name
, data
+ sizeof(int)*2, sizeof(name
));
273 name
[sizeof(name
)-1] = 0;
275 pa_client_rename(c
->client
, name
);
277 assert(!c
->input_memblockq
);
279 l
= (size_t) (pa_bytes_per_second(&ss
)*PLAYBACK_BUFFER_SECONDS
);
280 c
->input_memblockq
= pa_memblockq_new(l
, 0, pa_sample_size(&ss
), l
/2, l
/PLAYBACK_BUFFER_FRAGMENTS
);
281 assert(c
->input_memblockq
);
282 pa_iochannel_socket_set_rcvbuf(c
->io
, l
/PLAYBACK_BUFFER_FRAGMENTS
*2);
283 c
->playback
.fragment_size
= l
/10;
285 assert(!c
->sink_input
);
286 c
->sink_input
= pa_sink_input_new(sink
, name
, &ss
);
287 assert(c
->sink_input
);
289 c
->sink_input
->owner
= c
->protocol
->module
;
290 c
->sink_input
->client
= c
->client
;
291 c
->sink_input
->peek
= sink_input_peek_cb
;
292 c
->sink_input
->drop
= sink_input_drop_cb
;
293 c
->sink_input
->kill
= sink_input_kill_cb
;
294 c
->sink_input
->get_latency
= sink_input_get_latency_cb
;
295 c
->sink_input
->userdata
= c
;
297 c
->state
= ESD_STREAMING_DATA
;
299 c
->protocol
->n_player
++;
304 static int esd_proto_stream_record(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
305 char name
[ESD_NAME_MAX
];
307 struct pa_source
*source
;
308 struct pa_sample_spec ss
;
310 assert(c
&& length
== (sizeof(int)*2+ESD_NAME_MAX
));
312 format
= maybe_swap_endian_32(c
->swap_byte_order
, *(int*)data
);
313 rate
= maybe_swap_endian_32(c
->swap_byte_order
, *((int*)data
+ 1));
316 ss
.channels
= ((format
& ESD_MASK_CHAN
) == ESD_STEREO
) ? 2 : 1;
317 ss
.format
= ((format
& ESD_MASK_BITS
) == ESD_BITS16
) ? PA_SAMPLE_S16NE
: PA_SAMPLE_U8
;
319 if (!pa_sample_spec_valid(&ss
))
322 if (request
== ESD_PROTO_STREAM_MON
) {
323 struct pa_sink
* sink
;
325 if (!(sink
= get_output_sink(c
->protocol
)))
328 if (!(source
= sink
->monitor_source
))
331 assert(request
== ESD_PROTO_STREAM_REC
);
333 if (!(source
= get_input_source(c
->protocol
)))
337 strncpy(name
, data
+ sizeof(int)*2, sizeof(name
));
338 name
[sizeof(name
)-1] = 0;
340 pa_client_rename(c
->client
, name
);
342 assert(!c
->output_memblockq
);
344 l
= (size_t) (pa_bytes_per_second(&ss
)*RECORD_BUFFER_SECONDS
);
345 c
->output_memblockq
= pa_memblockq_new(l
, 0, pa_sample_size(&ss
), 0, 0);
346 assert(c
->output_memblockq
);
347 pa_iochannel_socket_set_sndbuf(c
->io
, l
/RECORD_BUFFER_FRAGMENTS
*2);
349 assert(!c
->source_output
);
350 c
->source_output
= pa_source_output_new(source
, name
, &ss
);
351 assert(c
->source_output
);
353 c
->source_output
->owner
= c
->protocol
->module
;
354 c
->source_output
->client
= c
->client
;
355 c
->source_output
->push
= source_output_push_cb
;
356 c
->source_output
->kill
= source_output_kill_cb
;
357 c
->source_output
->userdata
= c
;
359 c
->state
= ESD_STREAMING_DATA
;
361 c
->protocol
->n_player
++;
366 static int esd_proto_get_latency(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
367 struct pa_sink
*sink
;
369 assert(c
&& !data
&& length
== 0);
371 if (!(sink
= get_output_sink(c
->protocol
)))
374 float usec
= pa_sink_get_latency(sink
);
375 usec
+= PLAYBACK_BUFFER_SECONDS
*1000000; /* A better estimation would be a good idea! */
376 latency
= (int) ((usec
*44100)/1000000);
379 lag
= connection_write(c
, sizeof(int));
381 *lag
= c
->swap_byte_order
? swap_endian_32(latency
) : latency
;
385 static int esd_proto_server_info(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
386 int rate
= 44100, format
= ESD_STEREO
|ESD_BITS16
;
388 struct pa_sink
*sink
;
389 assert(c
&& data
&& length
== sizeof(int));
391 if ((sink
= get_output_sink(c
->protocol
))) {
392 rate
= sink
->sample_spec
.rate
;
393 format
= (sink
->sample_spec
.format
== PA_SAMPLE_U8
) ? ESD_BITS8
: ESD_BITS16
;
394 format
|= (sink
->sample_spec
.channels
>= 2) ? ESD_STEREO
: ESD_MONO
;
397 response
= connection_write(c
, sizeof(int)*3);
400 *(response
++) = maybe_swap_endian_32(c
->swap_byte_order
, rate
);
401 *(response
++) = maybe_swap_endian_32(c
->swap_byte_order
, format
);
405 static int esd_proto_all_info(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
408 struct connection
*conn
;
409 size_t index
= PA_IDXSET_INVALID
;
410 assert(c
&& data
&& length
== sizeof(int));
412 if (esd_proto_server_info(c
, request
, data
, length
) < 0)
415 k
= sizeof(int)*5+ESD_NAME_MAX
;
416 s
= sizeof(int)*6+ESD_NAME_MAX
;
417 response
= connection_write(c
, (t
= s
+k
*(c
->protocol
->n_player
+1)));
420 for (conn
= pa_idxset_first(c
->protocol
->connections
, &index
); conn
; conn
= pa_idxset_next(c
->protocol
->connections
, &index
)) {
421 int format
= ESD_BITS16
| ESD_STEREO
, rate
= 44100, volume
= 0xFF;
423 if (conn
->state
!= ESD_STREAMING_DATA
)
428 if (conn
->sink_input
) {
429 rate
= conn
->sink_input
->sample_spec
.rate
;
430 volume
= (conn
->sink_input
->volume
*0xFF)/0x100;
431 format
= (conn
->sink_input
->sample_spec
.format
== PA_SAMPLE_U8
) ? ESD_BITS8
: ESD_BITS16
;
432 format
|= (conn
->sink_input
->sample_spec
.channels
>= 2) ? ESD_STEREO
: ESD_MONO
;
436 *((int*) response
) = maybe_swap_endian_32(c
->swap_byte_order
, (int) conn
->index
);
437 response
+= sizeof(int);
440 assert(conn
->client
);
441 strncpy(response
, conn
->client
->name
, ESD_NAME_MAX
);
442 response
+= ESD_NAME_MAX
;
445 *((int*) response
) = maybe_swap_endian_32(c
->swap_byte_order
, rate
);
446 response
+= sizeof(int);
449 *((int*) response
) = maybe_swap_endian_32(c
->swap_byte_order
, volume
);
450 response
+= sizeof(int);
453 *((int*) response
) = maybe_swap_endian_32(c
->swap_byte_order
, volume
);
454 response
+= sizeof(int);
457 *((int*) response
) = maybe_swap_endian_32(c
->swap_byte_order
, format
);
458 response
+= sizeof(int);
464 memset(response
, 0, t
);
468 static int esd_proto_stream_pan(struct connection
*c
, esd_proto_t request
, const void *data
, size_t length
) {
470 uint32_t index
, volume
;
471 struct connection
*conn
;
472 assert(c
&& data
&& length
== sizeof(int)*3);
474 index
= (uint32_t) maybe_swap_endian_32(c
->swap_byte_order
, *(int*)data
);
475 volume
= (uint32_t) maybe_swap_endian_32(c
->swap_byte_order
, *((int*)data
+ 1));
476 volume
= (volume
*0x100)/0xFF;
478 ok
= connection_write(c
, sizeof(int));
481 if ((conn
= pa_idxset_get_by_index(c
->protocol
->connections
, index
))) {
482 assert(conn
->sink_input
);
483 conn
->sink_input
->volume
= volume
;
491 /*** client callbacks ***/
493 static void client_kill_cb(struct pa_client
*c
) {
494 assert(c
&& c
->userdata
);
495 connection_free(c
->userdata
);
498 /*** pa_iochannel callbacks ***/
500 static int do_read(struct connection
*c
) {
503 if (c
->state
== ESD_NEXT_REQUEST
) {
505 assert(c
->read_data_length
< sizeof(c
->request
));
507 if ((r
= pa_iochannel_read(c
->io
, ((void*) &c
->request
) + c
->read_data_length
, sizeof(c
->request
) - c
->read_data_length
)) <= 0) {
508 fprintf(stderr
, "protocol-esound.c: read() failed: %s\n", r
== 0 ? "EOF" : strerror(errno
));
512 if ((c
->read_data_length
+= r
) >= sizeof(c
->request
)) {
513 struct proto_handler
*handler
;
515 if (c
->swap_byte_order
)
516 c
->request
= swap_endian_32(c
->request
);
518 if (c
->request
< ESD_PROTO_CONNECT
|| c
->request
> ESD_PROTO_MAX
) {
519 fprintf(stderr
, "protocol-esound.c: recieved invalid request.\n");
523 handler
= proto_map
+c
->request
;
525 if (!handler
->proc
) {
526 fprintf(stderr
, "protocol-sound.c: recieved unimplemented request.\n");
530 if (handler
->data_length
== 0) {
531 c
->read_data_length
= 0;
533 if (handler
->proc(c
, c
->request
, NULL
, 0) < 0)
537 if (c
->read_data_alloc
< handler
->data_length
)
538 c
->read_data
= realloc(c
->read_data
, c
->read_data_alloc
= handler
->data_length
);
539 assert(c
->read_data
);
541 c
->state
= ESD_NEEDS_REQDATA
;
542 c
->read_data_length
= 0;
546 } else if (c
->state
== ESD_NEEDS_REQDATA
) {
548 struct proto_handler
*handler
= proto_map
+c
->request
;
550 assert(handler
->proc
);
552 assert(c
->read_data
&& c
->read_data_length
< handler
->data_length
);
554 if ((r
= pa_iochannel_read(c
->io
, c
->read_data
+ c
->read_data_length
, handler
->data_length
- c
->read_data_length
)) <= 0) {
555 fprintf(stderr
, "protocol-esound.c: read() failed: %s\n", r
== 0 ? "EOF" : strerror(errno
));
559 if ((c
->read_data_length
+= r
) >= handler
->data_length
) {
560 size_t l
= c
->read_data_length
;
561 assert(handler
->proc
);
563 c
->state
= ESD_NEXT_REQUEST
;
564 c
->read_data_length
= 0;
566 if (handler
->proc(c
, c
->request
, c
->read_data
, l
) < 0)
569 } else if (c
->state
== ESD_STREAMING_DATA
&& c
->sink_input
) {
570 struct pa_memchunk chunk
;
574 assert(c
->input_memblockq
);
576 if (!(l
= pa_memblockq_missing(c
->input_memblockq
)))
579 if (l
> c
->playback
.fragment_size
)
580 l
= c
->playback
.fragment_size
;
582 if (c
->playback
.current_memblock
)
583 if (c
->playback
.current_memblock
->length
- c
->playback
.memblock_index
< l
) {
584 pa_memblock_unref(c
->playback
.current_memblock
);
585 c
->playback
.current_memblock
= NULL
;
586 c
->playback
.memblock_index
= 0;
589 if (!c
->playback
.current_memblock
) {
590 c
->playback
.current_memblock
= pa_memblock_new(c
->playback
.fragment_size
*2);
591 assert(c
->playback
.current_memblock
&& c
->playback
.current_memblock
->length
>= l
);
592 c
->playback
.memblock_index
= 0;
595 if ((r
= pa_iochannel_read(c
->io
, c
->playback
.current_memblock
->data
+c
->playback
.memblock_index
, l
)) <= 0) {
596 fprintf(stderr
, __FILE__
": read() failed: %s\n", r
== 0 ? "EOF" : strerror(errno
));
600 chunk
.memblock
= c
->playback
.current_memblock
;
601 chunk
.index
= c
->playback
.memblock_index
;
603 assert(chunk
.memblock
);
605 c
->playback
.memblock_index
+= r
;
607 assert(c
->input_memblockq
);
608 pa_memblockq_push_align(c
->input_memblockq
, &chunk
, 0);
609 assert(c
->sink_input
);
610 pa_sink_notify(c
->sink_input
->sink
);
617 static int do_write(struct connection
*c
) {
620 if (c
->write_data_length
) {
623 assert(c
->write_data_index
< c
->write_data_length
);
624 if ((r
= pa_iochannel_write(c
->io
, c
->write_data
+c
->write_data_index
, c
->write_data_length
-c
->write_data_index
)) < 0) {
625 fprintf(stderr
, __FILE__
": write() failed: %s\n", strerror(errno
));
629 if ((c
->write_data_index
+=r
) >= c
->write_data_length
)
630 c
->write_data_length
= c
->write_data_index
= 0;
632 } else if (c
->state
== ESD_STREAMING_DATA
&& c
->source_output
) {
633 struct pa_memchunk chunk
;
636 assert(c
->output_memblockq
);
637 if (pa_memblockq_peek(c
->output_memblockq
, &chunk
) < 0)
640 assert(chunk
.memblock
&& chunk
.length
);
642 if ((r
= pa_iochannel_write(c
->io
, chunk
.memblock
->data
+chunk
.index
, chunk
.length
)) < 0) {
643 pa_memblock_unref(chunk
.memblock
);
644 fprintf(stderr
, __FILE__
": write(): %s\n", strerror(errno
));
648 pa_memblockq_drop(c
->output_memblockq
, r
);
649 pa_memblock_unref(chunk
.memblock
);
655 static void do_work(struct connection
*c
) {
658 assert(c
->protocol
&& c
->protocol
->core
&& c
->protocol
->core
->mainloop
&& c
->protocol
->core
->mainloop
->enable_fixed
);
659 c
->protocol
->core
->mainloop
->enable_fixed(c
->protocol
->core
->mainloop
, c
->fixed_source
, 0);
661 if (pa_iochannel_is_hungup(c
->io
))
664 if (pa_iochannel_is_writable(c
->io
))
668 if (pa_iochannel_is_readable(c
->io
))
678 static void io_callback(struct pa_iochannel
*io
, void *userdata
) {
679 struct connection
*c
= userdata
;
680 assert(io
&& c
&& c
->io
== io
);
685 /*** fixed callback ***/
687 static void fixed_callback(struct pa_mainloop_api
*a
, void *id
, void *userdata
) {
688 struct connection
*c
= userdata
;
689 assert(a
&& c
&& c
->fixed_source
== id
);
694 /*** sink_input callbacks ***/
696 static int sink_input_peek_cb(struct pa_sink_input
*i
, struct pa_memchunk
*chunk
) {
698 assert(i
&& i
->userdata
&& chunk
);
701 if (pa_memblockq_peek(c
->input_memblockq
, chunk
) < 0)
707 static void sink_input_drop_cb(struct pa_sink_input
*i
, size_t length
) {
708 struct connection
*c
= i
->userdata
;
709 assert(i
&& c
&& length
);
711 pa_memblockq_drop(c
->input_memblockq
, length
);
714 assert(c
->protocol
&& c
->protocol
->core
&& c
->protocol
->core
->mainloop
&& c
->protocol
->core
->mainloop
->enable_fixed
);
715 c
->protocol
->core
->mainloop
->enable_fixed(c
->protocol
->core
->mainloop
, c
->fixed_source
, 1);
718 static void sink_input_kill_cb(struct pa_sink_input
*i
) {
719 assert(i
&& i
->userdata
);
720 connection_free((struct connection
*) i
->userdata
);
724 static uint32_t sink_input_get_latency_cb(struct pa_sink_input
*i
) {
725 struct connection
*c
= i
->userdata
;
727 return pa_samples_usec(pa_memblockq_get_length(c
->input_memblockq
), &c
->sink_input
->sample_spec
);
730 /*** source_output callbacks ***/
732 static void source_output_push_cb(struct pa_source_output
*o
, const struct pa_memchunk
*chunk
) {
733 struct connection
*c
= o
->userdata
;
734 assert(o
&& c
&& chunk
);
736 pa_memblockq_push(c
->output_memblockq
, chunk
, 0);
739 assert(c
->protocol
&& c
->protocol
->core
&& c
->protocol
->core
->mainloop
&& c
->protocol
->core
->mainloop
->enable_fixed
);
740 c
->protocol
->core
->mainloop
->enable_fixed(c
->protocol
->core
->mainloop
, c
->fixed_source
, 1);
743 static void source_output_kill_cb(struct pa_source_output
*o
) {
744 assert(o
&& o
->userdata
);
745 connection_free((struct connection
*) o
->userdata
);
748 /*** socket server callback ***/
750 static void on_connection(struct pa_socket_server
*s
, struct pa_iochannel
*io
, void *userdata
) {
751 struct connection
*c
;
753 assert(s
&& io
&& userdata
);
755 c
= malloc(sizeof(struct connection
));
757 c
->protocol
= userdata
;
759 pa_iochannel_set_callback(c
->io
, io_callback
, c
);
761 pa_iochannel_socket_peer_to_string(io
, cname
, sizeof(cname
));
762 assert(c
->protocol
->core
);
763 c
->client
= pa_client_new(c
->protocol
->core
, "ESOUND", cname
);
765 c
->client
->owner
= c
->protocol
->module
;
766 c
->client
->kill
= client_kill_cb
;
767 c
->client
->userdata
= c
;
769 c
->authorized
= c
->protocol
->public;
770 c
->swap_byte_order
= 0;
772 c
->read_data_length
= 0;
773 c
->read_data
= malloc(c
->read_data_alloc
= proto_map
[ESD_PROTO_CONNECT
].data_length
);
774 assert(c
->read_data
);
776 c
->write_data_length
= c
->write_data_index
= c
->write_data_alloc
= 0;
777 c
->write_data
= NULL
;
779 c
->state
= ESD_NEEDS_REQDATA
;
780 c
->request
= ESD_PROTO_CONNECT
;
782 c
->sink_input
= NULL
;
783 c
->input_memblockq
= NULL
;
785 c
->source_output
= NULL
;
786 c
->output_memblockq
= NULL
;
788 c
->playback
.current_memblock
= NULL
;
789 c
->playback
.memblock_index
= 0;
790 c
->playback
.fragment_size
= 0;
792 c
->fixed_source
= c
->protocol
->core
->mainloop
->source_fixed(c
->protocol
->core
->mainloop
, fixed_callback
, c
);
793 assert(c
->fixed_source
);
794 c
->protocol
->core
->mainloop
->enable_fixed(c
->protocol
->core
->mainloop
, c
->fixed_source
, 0);
796 pa_idxset_put(c
->protocol
->connections
, c
, &c
->index
);
799 /*** entry points ***/
801 struct pa_protocol_esound
* pa_protocol_esound_new(struct pa_core
*core
, struct pa_socket_server
*server
, struct pa_module
*m
, struct pa_modargs
*ma
) {
802 uint32_t source_index
, sink_index
;
803 struct pa_protocol_esound
*p
;
804 assert(core
&& server
&& ma
);
806 if (pa_modargs_get_source_index(ma
, core
, &source_index
) < 0) {
807 fprintf(stderr
, __FILE__
": source does not exist.\n");
811 if (pa_modargs_get_sink_index(ma
, core
, &sink_index
) < 0) {
812 fprintf(stderr
, __FILE__
": sink does not exist.\n");
815 p
= malloc(sizeof(struct pa_protocol_esound
));
818 if (pa_authkey_load_auto(pa_modargs_get_value(ma
, "cookie", DEFAULT_COOKIE_FILE
), p
->esd_key
, sizeof(p
->esd_key
)) < 0) {
826 pa_socket_server_set_callback(p
->server
, on_connection
, p
);
828 p
->connections
= pa_idxset_new(NULL
, NULL
);
829 assert(p
->connections
);
830 p
->sink_index
= sink_index
;
831 p
->source_index
= source_index
;
837 void pa_protocol_esound_free(struct pa_protocol_esound
*p
) {
838 struct connection
*c
;
841 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
844 pa_idxset_free(p
->connections
, NULL
, NULL
);
845 pa_socket_server_free(p
->server
);