8 #include "protocol-esound.h"
9 #include "esound-spec.h"
12 #include "sinkinput.h"
16 /* This is heavily based on esound's code */
19 struct protocol_esound
*protocol
;
21 struct client
*client
;
22 int authorized
, swap_byte_order
;
24 size_t read_data_alloc
, read_data_length
;
26 size_t write_data_alloc
, write_data_index
, write_data_length
;
28 esd_client_state_t state
;
29 struct sink_input
*sink_input
;
30 struct memblockq
*input_memblockq
;
33 struct protocol_esound
{
36 struct socket_server
*server
;
37 struct idxset
*connections
;
40 typedef struct proto_handler
{
42 int (*proc
)(struct connection
*c
, const void *data
, size_t length
);
43 const char *description
;
44 } esd_proto_handler_info_t
;
46 #define BUFSIZE PIPE_BUF
48 static void sink_input_drop_cb(struct sink_input
*i
, size_t length
);
49 static int sink_input_peek_cb(struct sink_input
*i
, struct memchunk
*chunk
);
50 static void sink_input_kill_cb(struct sink_input
*i
);
51 static uint32_t sink_input_get_latency_cb(struct sink_input
*i
);
53 static int esd_proto_connect(struct connection
*c
, const void *data
, size_t length
);
54 static int esd_proto_stream_play(struct connection
*c
, const void *data
, size_t length
);
55 static int esd_proto_stream_record(struct connection
*c
, const void *data
, size_t length
);
57 static int do_write(struct connection
*c
);
59 /* the big map of protocol handler info */
60 static struct proto_handler proto_map
[ESD_PROTO_MAX
] = {
61 { ESD_KEY_LEN
+ sizeof(int), &esd_proto_connect
, "connect" },
62 { ESD_KEY_LEN
+ sizeof(int), NULL
, "lock" },
63 { ESD_KEY_LEN
+ sizeof(int), NULL
, "unlock" },
65 { ESD_NAME_MAX
+ 2 * sizeof(int), &esd_proto_stream_play
, "stream play" },
66 { ESD_NAME_MAX
+ 2 * sizeof(int), &esd_proto_stream_record
, "stream rec" },
67 { ESD_NAME_MAX
+ 2 * sizeof(int), NULL
, "stream mon" },
69 { ESD_NAME_MAX
+ 3 * sizeof(int), NULL
, "sample cache" },
70 { sizeof(int), NULL
, "sample free" },
71 { sizeof(int), NULL
, "sample play" },
72 { sizeof(int), NULL
, "sample loop" },
73 { sizeof(int), NULL
, "sample stop" },
74 { -1, NULL
, "TODO: sample kill" },
76 { ESD_KEY_LEN
+ sizeof(int), NULL
, "standby" },
77 { ESD_KEY_LEN
+ sizeof(int), NULL
, "resume" },
79 { ESD_NAME_MAX
, NULL
, "sample getid" },
80 { ESD_NAME_MAX
+ 2 * sizeof(int), NULL
, "stream filter" },
82 { sizeof(int), NULL
, "server info" },
83 { sizeof(int), NULL
, "all info" },
84 { -1, NULL
, "TODO: subscribe" },
85 { -1, NULL
, "TODO: unsubscribe" },
87 { 3 * sizeof(int), NULL
, "stream pan"},
88 { 3 * sizeof(int), NULL
, "sample pan" },
90 { sizeof(int), NULL
, "standby mode" },
91 { 0, NULL
, "get latency" }
95 static void connection_free(struct connection
*c
) {
97 idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
);
99 client_free(c
->client
);
102 sink_input_free(c
->sink_input
);
103 if (c
->input_memblockq
)
104 memblockq_free(c
->input_memblockq
);
109 iochannel_free(c
->io
);
113 static struct sink
* get_output_sink(struct protocol_esound
*p
) {
115 return sink_get_default(p
->core
);
118 static void* connection_write(struct connection
*c
, size_t length
) {
122 t
= c
->write_data_length
+length
;
124 if (c
->write_data_alloc
< t
)
125 c
->write_data
= realloc(c
->write_data
, c
->write_data_alloc
= t
);
127 assert(c
->write_data
);
129 i
= c
->write_data_length
;
130 c
->write_data_length
+= length
;
132 return c
->write_data
+i
;
135 /*** esound commands ***/
137 static int esd_proto_connect(struct connection
*c
, const void *data
, size_t length
) {
140 assert(length
== (ESD_KEY_LEN
+ sizeof(uint32_t)));
144 ekey
= *(uint32_t*)(data
+ESD_KEY_LEN
);
145 if (ekey
== ESD_ENDIAN_KEY
)
146 c
->swap_byte_order
= 0;
147 else if (ekey
== ESD_SWAP_ENDIAN_KEY
)
148 c
->swap_byte_order
= 1;
150 fprintf(stderr
, "protocol-esound.c: client sent invalid endian key\n");
154 ok
= connection_write(c
, sizeof(int));
163 static int esd_proto_stream_play(struct connection
*c
, const void *data
, size_t length
) {
164 char name
[ESD_NAME_MAX
];
167 struct pa_sample_spec ss
;
168 assert(length
== (sizeof(int)*2+ESD_NAME_MAX
));
170 format
= *(int*)data
;
171 rate
= *((int*)data
+ 1);
173 if (c
->swap_byte_order
)
174 format
= swap_endian_32(format
);
175 if (c
->swap_byte_order
)
176 rate
= swap_endian_32(rate
);
179 ss
.channels
= ((format
& ESD_MASK_CHAN
) == ESD_STEREO
) ? 2 : 1;
180 ss
.format
= ((format
& ESD_MASK_BITS
) == ESD_BITS16
) ? PA_SAMPLE_S16NE
: PA_SAMPLE_U8
;
182 if (!pa_sample_spec_valid(&ss
))
185 if (!(sink
= get_output_sink(c
->protocol
)))
188 strncpy(name
, data
+ sizeof(int)*2, sizeof(name
));
189 name
[sizeof(name
)-1] = 0;
191 client_rename(c
->client
, name
);
193 assert(!c
->input_memblockq
);
194 c
->input_memblockq
= memblockq_new(1024*10, pa_sample_size(&ss
), 1024*2);
195 assert(c
->input_memblockq
);
197 assert(!c
->sink_input
);
198 c
->sink_input
= sink_input_new(sink
, &ss
, name
);
199 assert(c
->sink_input
);
201 c
->sink_input
->peek
= sink_input_peek_cb
;
202 c
->sink_input
->drop
= sink_input_drop_cb
;
203 c
->sink_input
->kill
= sink_input_kill_cb
;
204 c
->sink_input
->get_latency
= sink_input_get_latency_cb
;
205 c
->sink_input
->userdata
= c
;
207 c
->state
= ESD_STREAMING_DATA
;
212 static int esd_proto_stream_record(struct connection
*c
, const void *data
, size_t length
) {
216 /*** client callbacks ***/
218 static void client_kill_cb(struct client
*c
) {
219 assert(c
&& c
->userdata
);
220 connection_free(c
->userdata
);
223 /*** iochannel callbacks ***/
225 static int do_read(struct connection
*c
) {
228 if (!iochannel_is_readable(c
->io
))
231 if (c
->state
== ESD_NEXT_REQUEST
) {
233 assert(c
->read_data_length
< sizeof(c
->request
));
235 if ((r
= iochannel_read(c
->io
, ((void*) &c
->request
) + c
->read_data_length
, sizeof(c
->request
) - c
->read_data_length
)) <= 0) {
236 fprintf(stderr
, "protocol-esound.c: read() failed: %s\n", r
== 0 ? "EOF" : strerror(errno
));
240 if ((c
->read_data_length
+= r
) >= sizeof(c
->request
)) {
241 struct proto_handler
*handler
;
243 if (c
->swap_byte_order
)
244 c
->request
= swap_endian_32(c
->request
);
246 if (c
->request
< ESD_PROTO_CONNECT
|| c
->request
> ESD_PROTO_MAX
) {
247 fprintf(stderr
, "protocol-esound.c: recieved invalid request.\n");
251 handler
= proto_map
+c
->request
;
253 if (!handler
->proc
) {
254 fprintf(stderr
, "protocol-sound.c: recieved unimplemented request.\n");
258 if (handler
->data_length
== 0) {
259 c
->read_data_length
= 0;
261 if (handler
->proc(c
, NULL
, 0) < 0)
265 if (c
->read_data_alloc
< handler
->data_length
)
266 c
->read_data
= realloc(c
->read_data
, c
->read_data_alloc
= handler
->data_length
);
267 assert(c
->read_data
);
269 c
->state
= ESD_NEEDS_REQDATA
;
270 c
->read_data_length
= 0;
274 } else if (c
->state
== ESD_NEEDS_REQDATA
) {
276 struct proto_handler
*handler
= proto_map
+c
->request
;
278 assert(handler
->proc
);
280 assert(c
->read_data
&& c
->read_data_length
< handler
->data_length
);
282 if ((r
= iochannel_read(c
->io
, c
->read_data
+ c
->read_data_length
, handler
->data_length
- c
->read_data_length
)) <= 0) {
283 fprintf(stderr
, "protocol-esound.c: read() failed: %s\n", r
== 0 ? "EOF" : strerror(errno
));
287 if ((c
->read_data_length
+= r
) >= handler
->data_length
) {
288 size_t l
= c
->read_data_length
;
289 assert(handler
->proc
);
291 c
->state
= ESD_NEXT_REQUEST
;
292 c
->read_data_length
= 0;
294 if (handler
->proc(c
, c
->read_data
, l
) < 0)
297 } else if (c
->state
== ESD_STREAMING_DATA
) {
298 struct memchunk chunk
;
301 assert(c
->input_memblockq
);
303 if (!memblockq_is_writable(c
->input_memblockq
, BUFSIZE
))
306 chunk
.memblock
= memblock_new(BUFSIZE
);
307 assert(chunk
.memblock
&& chunk
.memblock
->data
);
309 if ((r
= iochannel_read(c
->io
, chunk
.memblock
->data
, BUFSIZE
)) <= 0) {
310 fprintf(stderr
, "protocol-esound.c: read() failed: %s\n", r
== 0 ? "EOF" : strerror(errno
));
311 memblock_unref(chunk
.memblock
);
315 chunk
.memblock
->length
= chunk
.length
= r
;
318 assert(c
->input_memblockq
);
319 memblockq_push(c
->input_memblockq
, &chunk
, 0);
320 memblock_unref(chunk
.memblock
);
321 assert(c
->sink_input
);
322 sink_notify(c
->sink_input
->sink
);
329 static int do_write(struct connection
*c
) {
333 if (!iochannel_is_writable(c
->io
))
336 if (!c
->write_data_length
)
339 assert(c
->write_data_index
< c
->write_data_length
);
340 if ((r
= iochannel_write(c
->io
, c
->write_data
+c
->write_data_index
, c
->write_data_length
-c
->write_data_index
)) < 0) {
341 fprintf(stderr
, "protocol-esound.c: write() failed: %s\n", strerror(errno
));
345 if ((c
->write_data_index
+=r
) >= c
->write_data_length
)
346 c
->write_data_length
= c
->write_data_index
= 0;
351 static void io_callback(struct iochannel
*io
, void *userdata
) {
352 struct connection
*c
= userdata
;
353 assert(io
&& c
&& c
->io
== io
);
355 if (do_read(c
) < 0 || do_write(c
) < 0)
359 /*** sink_input callbacks ***/
361 static int sink_input_peek_cb(struct sink_input
*i
, struct memchunk
*chunk
) {
363 assert(i
&& i
->userdata
&& chunk
);
366 if (memblockq_peek(c
->input_memblockq
, chunk
) < 0)
372 static void sink_input_drop_cb(struct sink_input
*i
, size_t length
) {
373 struct connection
*c
= i
->userdata
;
374 assert(i
&& c
&& length
);
376 memblockq_drop(c
->input_memblockq
, length
);
382 static void sink_input_kill_cb(struct sink_input
*i
) {
383 assert(i
&& i
->userdata
);
384 connection_free((struct connection
*) i
->userdata
);
388 static uint32_t sink_input_get_latency_cb(struct sink_input
*i
) {
389 struct connection
*c
= i
->userdata
;
391 return pa_samples_usec(memblockq_get_length(c
->input_memblockq
), &c
->sink_input
->sample_spec
);
394 /*** socket server callback ***/
396 static void on_connection(struct socket_server
*s
, struct iochannel
*io
, void *userdata
) {
397 struct connection
*c
;
399 assert(s
&& io
&& userdata
);
401 c
= malloc(sizeof(struct connection
));
403 c
->protocol
= userdata
;
405 iochannel_set_callback(c
->io
, io_callback
, c
);
407 iochannel_peer_to_string(io
, cname
, sizeof(cname
));
408 assert(c
->protocol
->core
);
409 c
->client
= client_new(c
->protocol
->core
, "ESOUND", cname
);
411 c
->client
->kill
= client_kill_cb
;
412 c
->client
->userdata
= c
;
414 c
->authorized
= c
->protocol
->public;
415 c
->swap_byte_order
= 0;
417 c
->read_data_length
= 0;
418 c
->read_data
= malloc(c
->read_data_alloc
= proto_map
[ESD_PROTO_CONNECT
].data_length
);
419 assert(c
->read_data
);
421 c
->write_data_length
= c
->write_data_index
= c
->write_data_alloc
= 0;
422 c
->write_data
= NULL
;
424 c
->state
= ESD_NEEDS_REQDATA
;
425 c
->request
= ESD_PROTO_CONNECT
;
427 c
->sink_input
= NULL
;
428 c
->input_memblockq
= NULL
;
430 idxset_put(c
->protocol
->connections
, c
, NULL
);
433 /*** entry points ***/
435 struct protocol_esound
* protocol_esound_new(struct core
*core
, struct socket_server
*server
) {
436 struct protocol_esound
*p
;
437 assert(core
&& server
);
439 p
= malloc(sizeof(struct protocol_esound
));
444 p
->connections
= idxset_new(NULL
, NULL
);
445 assert(p
->connections
);
447 socket_server_set_callback(p
->server
, on_connection
, p
);
452 void protocol_esound_free(struct protocol_esound
*p
) {
453 struct connection
*c
;
456 while ((c
= idxset_first(p
->connections
, NULL
)))
459 idxset_free(p
->connections
, NULL
, NULL
);
460 socket_server_free(p
->server
);