]> code.delx.au - pulseaudio/blob - src/protocol-esound.c
esound protocol
[pulseaudio] / src / protocol-esound.c
1 #include <errno.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include <assert.h>
5 #include <stdlib.h>
6 #include <limits.h>
7
8 #include "protocol-esound.h"
9 #include "esound-spec.h"
10 #include "memblock.h"
11 #include "client.h"
12 #include "sinkinput.h"
13 #include "sink.h"
14 #include "sample.h"
15
16 /* This is heavily based on esound's code */
17
18 struct connection {
19 struct protocol_esound *protocol;
20 struct iochannel *io;
21 struct client *client;
22 int authorized, swap_byte_order;
23 void *read_data;
24 size_t read_data_alloc, read_data_length;
25 void *write_data;
26 size_t write_data_alloc, write_data_index, write_data_length;
27 esd_proto_t request;
28 esd_client_state_t state;
29 struct sink_input *sink_input;
30 struct memblockq *input_memblockq;
31 };
32
33 struct protocol_esound {
34 int public;
35 struct core *core;
36 struct socket_server *server;
37 struct idxset *connections;
38 };
39
40 typedef struct proto_handler {
41 size_t data_length;
42 int (*proc)(struct connection *c, const void *data, size_t length);
43 const char *description;
44 } esd_proto_handler_info_t;
45
46 #define BUFSIZE PIPE_BUF
47
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);
52
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);
56
57 static int do_write(struct connection *c);
58
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" },
64
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" },
68
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" },
75
76 { ESD_KEY_LEN + sizeof(int), NULL, "standby" },
77 { ESD_KEY_LEN + sizeof(int), NULL, "resume" },
78
79 { ESD_NAME_MAX, NULL, "sample getid" },
80 { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" },
81
82 { sizeof(int), NULL, "server info" },
83 { sizeof(int), NULL, "all info" },
84 { -1, NULL, "TODO: subscribe" },
85 { -1, NULL, "TODO: unsubscribe" },
86
87 { 3 * sizeof(int), NULL, "stream pan"},
88 { 3 * sizeof(int), NULL, "sample pan" },
89
90 { sizeof(int), NULL, "standby mode" },
91 { 0, NULL, "get latency" }
92 };
93
94
95 static void connection_free(struct connection *c) {
96 assert(c);
97 idxset_remove_by_data(c->protocol->connections, c, NULL);
98
99 client_free(c->client);
100
101 if (c->sink_input)
102 sink_input_free(c->sink_input);
103 if (c->input_memblockq)
104 memblockq_free(c->input_memblockq);
105
106 free(c->read_data);
107 free(c->write_data);
108
109 iochannel_free(c->io);
110 free(c);
111 }
112
113 static struct sink* get_output_sink(struct protocol_esound *p) {
114 assert(p);
115 return sink_get_default(p->core);
116 }
117
118 static void* connection_write(struct connection *c, size_t length) {
119 size_t t, i;
120 assert(c);
121
122 t = c->write_data_length+length;
123
124 if (c->write_data_alloc < t)
125 c->write_data = realloc(c->write_data, c->write_data_alloc = t);
126
127 assert(c->write_data);
128
129 i = c->write_data_length;
130 c->write_data_length += length;
131
132 return c->write_data+i;
133 }
134
135 /*** esound commands ***/
136
137 static int esd_proto_connect(struct connection *c, const void *data, size_t length) {
138 uint32_t ekey;
139 int *ok;
140 assert(length == (ESD_KEY_LEN + sizeof(uint32_t)));
141
142 c->authorized = 1;
143
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;
149 else {
150 fprintf(stderr, "protocol-esound.c: client sent invalid endian key\n");
151 return -1;
152 }
153
154 ok = connection_write(c, sizeof(int));
155 assert(ok);
156 *ok = 1;
157
158 do_write(c);
159
160 return 0;
161 }
162
163 static int esd_proto_stream_play(struct connection *c, const void *data, size_t length) {
164 char name[ESD_NAME_MAX];
165 int format, rate;
166 struct sink *sink;
167 struct pa_sample_spec ss;
168 assert(length == (sizeof(int)*2+ESD_NAME_MAX));
169
170 format = *(int*)data;
171 rate = *((int*)data + 1);
172
173 if (c->swap_byte_order)
174 format = swap_endian_32(format);
175 if (c->swap_byte_order)
176 rate = swap_endian_32(rate);
177
178 ss.rate = 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;
181
182 if (!pa_sample_spec_valid(&ss))
183 return -1;
184
185 if (!(sink = get_output_sink(c->protocol)))
186 return -1;
187
188 strncpy(name, data + sizeof(int)*2, sizeof(name));
189 name[sizeof(name)-1] = 0;
190
191 client_rename(c->client, name);
192
193 assert(!c->input_memblockq);
194 c->input_memblockq = memblockq_new(1024*10, pa_sample_size(&ss), 1024*2);
195 assert(c->input_memblockq);
196
197 assert(!c->sink_input);
198 c->sink_input = sink_input_new(sink, &ss, name);
199 assert(c->sink_input);
200
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;
206
207 c->state = ESD_STREAMING_DATA;
208
209 return 0;
210 }
211
212 static int esd_proto_stream_record(struct connection *c, const void *data, size_t length) {
213 assert(0);
214 }
215
216 /*** client callbacks ***/
217
218 static void client_kill_cb(struct client *c) {
219 assert(c && c->userdata);
220 connection_free(c->userdata);
221 }
222
223 /*** iochannel callbacks ***/
224
225 static int do_read(struct connection *c) {
226 assert(c && c->io);
227
228 if (!iochannel_is_readable(c->io))
229 return 0;
230
231 if (c->state == ESD_NEXT_REQUEST) {
232 ssize_t r;
233 assert(c->read_data_length < sizeof(c->request));
234
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));
237 return -1;
238 }
239
240 if ((c->read_data_length+= r) >= sizeof(c->request)) {
241 struct proto_handler *handler;
242
243 if (c->swap_byte_order)
244 c->request = swap_endian_32(c->request);
245
246 if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) {
247 fprintf(stderr, "protocol-esound.c: recieved invalid request.\n");
248 return -1;
249 }
250
251 handler = proto_map+c->request;
252
253 if (!handler->proc) {
254 fprintf(stderr, "protocol-sound.c: recieved unimplemented request.\n");
255 return -1;
256 }
257
258 if (handler->data_length == 0) {
259 c->read_data_length = 0;
260
261 if (handler->proc(c, NULL, 0) < 0)
262 return -1;
263
264 } else {
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);
268
269 c->state = ESD_NEEDS_REQDATA;
270 c->read_data_length = 0;
271 }
272 }
273
274 } else if (c->state == ESD_NEEDS_REQDATA) {
275 ssize_t r;
276 struct proto_handler *handler = proto_map+c->request;
277
278 assert(handler->proc);
279
280 assert(c->read_data && c->read_data_length < handler->data_length);
281
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));
284 return -1;
285 }
286
287 if ((c->read_data_length+= r) >= handler->data_length) {
288 size_t l = c->read_data_length;
289 assert(handler->proc);
290
291 c->state = ESD_NEXT_REQUEST;
292 c->read_data_length = 0;
293
294 if (handler->proc(c, c->read_data, l) < 0)
295 return -1;
296 }
297 } else if (c->state == ESD_STREAMING_DATA) {
298 struct memchunk chunk;
299 ssize_t r;
300
301 assert(c->input_memblockq);
302
303 if (!memblockq_is_writable(c->input_memblockq, BUFSIZE))
304 return 0;
305
306 chunk.memblock = memblock_new(BUFSIZE);
307 assert(chunk.memblock && chunk.memblock->data);
308
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);
312 return -1;
313 }
314
315 chunk.memblock->length = chunk.length = r;
316 chunk.index = 0;
317
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);
323 } else
324 assert(0);
325
326 return 0;
327 }
328
329 static int do_write(struct connection *c) {
330 ssize_t r;
331 assert(c && c->io);
332
333 if (!iochannel_is_writable(c->io))
334 return 0;
335
336 if (!c->write_data_length)
337 return 0;
338
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));
342 return -1;
343 }
344
345 if ((c->write_data_index +=r) >= c->write_data_length)
346 c->write_data_length = c->write_data_index = 0;
347
348 return 0;
349 }
350
351 static void io_callback(struct iochannel*io, void *userdata) {
352 struct connection *c = userdata;
353 assert(io && c && c->io == io);
354
355 if (do_read(c) < 0 || do_write(c) < 0)
356 connection_free(c);
357 }
358
359 /*** sink_input callbacks ***/
360
361 static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk) {
362 struct connection*c;
363 assert(i && i->userdata && chunk);
364 c = i->userdata;
365
366 if (memblockq_peek(c->input_memblockq, chunk) < 0)
367 return -1;
368
369 return 0;
370 }
371
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);
375
376 memblockq_drop(c->input_memblockq, length);
377
378 if (do_read(c) < 0)
379 connection_free(c);
380 }
381
382 static void sink_input_kill_cb(struct sink_input *i) {
383 assert(i && i->userdata);
384 connection_free((struct connection *) i->userdata);
385 }
386
387
388 static uint32_t sink_input_get_latency_cb(struct sink_input *i) {
389 struct connection*c = i->userdata;
390 assert(i && c);
391 return pa_samples_usec(memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec);
392 }
393
394 /*** socket server callback ***/
395
396 static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) {
397 struct connection *c;
398 char cname[256];
399 assert(s && io && userdata);
400
401 c = malloc(sizeof(struct connection));
402 assert(c);
403 c->protocol = userdata;
404 c->io = io;
405 iochannel_set_callback(c->io, io_callback, c);
406
407 iochannel_peer_to_string(io, cname, sizeof(cname));
408 assert(c->protocol->core);
409 c->client = client_new(c->protocol->core, "ESOUND", cname);
410 assert(c->client);
411 c->client->kill = client_kill_cb;
412 c->client->userdata = c;
413
414 c->authorized = c->protocol->public;
415 c->swap_byte_order = 0;
416
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);
420
421 c->write_data_length = c->write_data_index = c->write_data_alloc = 0;
422 c->write_data = NULL;
423
424 c->state = ESD_NEEDS_REQDATA;
425 c->request = ESD_PROTO_CONNECT;
426
427 c->sink_input = NULL;
428 c->input_memblockq = NULL;
429
430 idxset_put(c->protocol->connections, c, NULL);
431 }
432
433 /*** entry points ***/
434
435 struct protocol_esound* protocol_esound_new(struct core*core, struct socket_server *server) {
436 struct protocol_esound *p;
437 assert(core && server);
438
439 p = malloc(sizeof(struct protocol_esound));
440 assert(p);
441 p->public = 1;
442 p->server = server;
443 p->core = core;
444 p->connections = idxset_new(NULL, NULL);
445 assert(p->connections);
446
447 socket_server_set_callback(p->server, on_connection, p);
448
449 return p;
450 }
451
452 void protocol_esound_free(struct protocol_esound *p) {
453 struct connection *c;
454 assert(p);
455
456 while ((c = idxset_first(p->connections, NULL)))
457 connection_free(c);
458
459 idxset_free(p->connections, NULL, NULL);
460 socket_server_free(p->server);
461 free(p);
462 }