8f53694e7142efaac82fbb37b138c5c2a7b21d0a
[profile/ivi/pulseaudio.git] / src / polypcore / protocol-esound.c
1 /* $Id$ */
2
3 /***
4   This file is part of polypaudio.
5  
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.
10  
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.
15  
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
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <assert.h>
30 #include <stdlib.h>
31 #include <limits.h>
32
33 #include <polyp/sample.h>
34 #include <polyp/utf8.h>
35 #include <polyp/xmalloc.h>
36
37 #include <polypcore/esound.h>
38 #include <polypcore/memblock.h>
39 #include <polypcore/client.h>
40 #include <polypcore/sink-input.h>
41 #include <polypcore/sink.h>
42 #include <polypcore/source-output.h>
43 #include <polypcore/source.h>
44 #include <polypcore/core-scache.h>
45 #include <polypcore/sample-util.h>
46 #include <polypcore/authkey.h>
47 #include <polypcore/namereg.h>
48 #include <polypcore/log.h>
49 #include <polypcore/util.h>
50
51 #include "endianmacros.h"
52
53 #include "protocol-esound.h"
54
55 /* Don't accept more connection than this */
56 #define MAX_CONNECTIONS 10
57
58 /* Kick a client if it doesn't authenticate within this time */
59 #define AUTH_TIMEOUT 5
60
61 #define DEFAULT_COOKIE_FILE ".esd_auth"
62
63 #define PLAYBACK_BUFFER_SECONDS (.25)
64 #define PLAYBACK_BUFFER_FRAGMENTS (10)
65 #define RECORD_BUFFER_SECONDS (5)
66 #define RECORD_BUFFER_FRAGMENTS (100)
67
68 #define MAX_CACHE_SAMPLE_SIZE (1024000)
69
70 #define SCACHE_PREFIX "esound."
71
72 /* This is heavily based on esound's code */
73
74 struct connection {
75     uint32_t index;
76     int dead;
77     pa_protocol_esound *protocol;
78     pa_iochannel *io;
79     pa_client *client;
80     int authorized, swap_byte_order;
81     void *write_data;
82     size_t write_data_alloc, write_data_index, write_data_length;
83     void *read_data;
84     size_t read_data_alloc, read_data_length;
85     esd_proto_t request;
86     esd_client_state_t state;
87     pa_sink_input *sink_input;
88     pa_source_output *source_output;
89     pa_memblockq *input_memblockq, *output_memblockq;
90     pa_defer_event *defer_event;
91
92     char *original_name;
93     
94     struct {
95         pa_memblock *current_memblock;
96         size_t memblock_index, fragment_size;
97     } playback;
98
99     struct {
100         pa_memchunk memchunk;
101         char *name;
102         pa_sample_spec sample_spec;
103     } scache;
104
105     pa_time_event *auth_timeout_event;
106 };
107
108 struct pa_protocol_esound {
109     int public;
110     pa_module *module;
111     pa_core *core;
112     pa_socket_server *server;
113     pa_idxset *connections;
114     char *sink_name, *source_name;
115     unsigned n_player;
116     uint8_t esd_key[ESD_KEY_LEN];
117 };
118
119 typedef struct proto_handler {
120     size_t data_length;
121     int (*proc)(struct connection *c, esd_proto_t request, const void *data, size_t length);
122     const char *description;
123 } esd_proto_handler_info_t;
124
125 static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length);
126 static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk);
127 static void sink_input_kill_cb(pa_sink_input *i);
128 static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i);
129 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
130
131 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
132 static void source_output_kill_cb(pa_source_output *o);
133
134 static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length);
135 static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length);
136 static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length);
137 static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length);
138 static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length);
139 static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length);
140 static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length);
141 static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length);
142 static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length);
143 static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length);
144 static int esd_proto_standby_or_resume(struct connection *c, esd_proto_t request, const void *data, size_t length);
145
146 /* the big map of protocol handler info */
147 static struct proto_handler proto_map[ESD_PROTO_MAX] = {
148     { ESD_KEY_LEN + sizeof(int),      esd_proto_connect, "connect" },
149     { ESD_KEY_LEN + sizeof(int),      NULL, "lock" },
150     { ESD_KEY_LEN + sizeof(int),      NULL, "unlock" },
151
152     { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_play, "stream play" },
153     { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream rec" },
154     { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream mon" },
155
156     { ESD_NAME_MAX + 3 * sizeof(int), esd_proto_sample_cache, "sample cache" },                      /* 6 */
157     { sizeof(int),                    esd_proto_sample_free_or_play, "sample free" },
158     { sizeof(int),                    esd_proto_sample_free_or_play, "sample play" },                /* 8 */
159     { sizeof(int),                    NULL, "sample loop" },
160     { sizeof(int),                    NULL, "sample stop" },
161     { -1,                             NULL, "TODO: sample kill" },
162
163     { ESD_KEY_LEN + sizeof(int),      esd_proto_standby_or_resume, "standby" },  /* NOOP! */
164     { ESD_KEY_LEN + sizeof(int),      esd_proto_standby_or_resume, "resume" },   /* NOOP! */         /* 13 */
165
166     { ESD_NAME_MAX,                   esd_proto_sample_get_id, "sample getid" },                     /* 14 */
167     { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" },
168
169     { sizeof(int),                    esd_proto_server_info, "server info" },
170     { sizeof(int),                    esd_proto_all_info, "all info" },
171     { -1,                             NULL, "TODO: subscribe" },
172     { -1,                             NULL, "TODO: unsubscribe" },
173
174     { 3 * sizeof(int),                esd_proto_stream_pan, "stream pan"},
175     { 3 * sizeof(int),                NULL, "sample pan" },
176      
177     { sizeof(int),                    NULL, "standby mode" },
178     { 0,                              esd_proto_get_latency, "get latency" }
179 };
180
181 static void connection_free(struct connection *c) {
182     assert(c);
183     pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
184
185     if (c->state == ESD_STREAMING_DATA)
186         c->protocol->n_player--;
187     
188     pa_client_free(c->client);
189
190     if (c->sink_input) {
191         pa_sink_input_disconnect(c->sink_input);
192         pa_sink_input_unref(c->sink_input);
193     }
194     
195     if (c->source_output) {
196         pa_source_output_disconnect(c->source_output);
197         pa_source_output_unref(c->source_output);
198     }
199     
200     if (c->input_memblockq)
201         pa_memblockq_free(c->input_memblockq);
202     if (c->output_memblockq)
203         pa_memblockq_free(c->output_memblockq);
204
205     if (c->playback.current_memblock)
206         pa_memblock_unref(c->playback.current_memblock);
207     
208     pa_xfree(c->read_data);
209     pa_xfree(c->write_data);
210
211     if (c->io)
212         pa_iochannel_free(c->io);
213     
214     if (c->defer_event)
215         c->protocol->core->mainloop->defer_free(c->defer_event);
216
217     if (c->scache.memchunk.memblock)
218         pa_memblock_unref(c->scache.memchunk.memblock);
219     pa_xfree(c->scache.name);
220
221     if (c->auth_timeout_event)
222         c->protocol->core->mainloop->time_free(c->auth_timeout_event);
223
224     pa_xfree(c->original_name);
225     pa_xfree(c);
226 }
227
228 static void connection_write_prepare(struct connection *c, size_t length) {
229     size_t t;
230     assert(c);
231
232     t = c->write_data_length+length;
233
234     if (c->write_data_alloc < t)
235         c->write_data = pa_xrealloc(c->write_data, c->write_data_alloc = t);
236
237     assert(c->write_data);
238 }
239
240 static void connection_write(struct connection *c, const void *data, size_t length) {
241     size_t i;
242     assert(c);
243
244     assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable);
245     c->protocol->core->mainloop->defer_enable(c->defer_event, 1);
246
247     connection_write_prepare(c, length);
248
249     assert(c->write_data);
250
251     i = c->write_data_length;
252     c->write_data_length += length;
253     
254     memcpy((char*)c->write_data + i, data, length);
255 }
256
257 static void format_esd2native(int format, int swap_bytes, pa_sample_spec *ss) {
258     assert(ss);
259
260     ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1;
261     if ((format & ESD_MASK_BITS) == ESD_BITS16)
262         ss->format = swap_bytes ? PA_SAMPLE_S16RE : PA_SAMPLE_S16NE;
263     else
264         ss->format = PA_SAMPLE_U8;
265 }
266
267 static int format_native2esd(pa_sample_spec *ss) {
268     int format = 0;
269     
270     format = (ss->format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16;
271     format |= (ss->channels >= 2) ? ESD_STEREO : ESD_MONO;
272
273     return format;
274 }
275
276 #define CHECK_VALIDITY(expression, string) do { \
277     if (!(expression)) { \
278         pa_log_warn(__FILE__ ": " string); \
279         return -1; \
280     } \
281 } while(0);
282
283 /*** esound commands ***/
284
285 static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
286     uint32_t ekey;
287     int ok;
288
289     assert(length == (ESD_KEY_LEN + sizeof(uint32_t)));
290
291     if (!c->authorized) {
292         if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) {
293             pa_log(__FILE__": kicked client with invalid authorization key.");
294             return -1;
295         }
296
297         c->authorized = 1;
298         if (c->auth_timeout_event) {
299             c->protocol->core->mainloop->time_free(c->auth_timeout_event);
300             c->auth_timeout_event = NULL;
301         }
302     }
303
304     data = (const char*)data + ESD_KEY_LEN;
305
306     memcpy(&ekey, data, sizeof(uint32_t));
307     if (ekey == ESD_ENDIAN_KEY)
308         c->swap_byte_order = 0;
309     else if (ekey == ESD_SWAP_ENDIAN_KEY)
310         c->swap_byte_order = 1;
311     else {
312         pa_log(__FILE__": client sent invalid endian key");
313         return -1;
314     }
315
316     ok = 1;
317     connection_write(c, &ok, sizeof(int));
318     return 0;
319 }
320
321 static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
322     char name[ESD_NAME_MAX], *utf8_name;
323     int32_t format, rate;
324     pa_sink *sink;
325     pa_sample_spec ss;
326     size_t l;
327
328     assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX));
329     
330     memcpy(&format, data, sizeof(int32_t));
331     format = MAYBE_INT32_SWAP(c->swap_byte_order, format);
332     data = (const char*)data + sizeof(int32_t);
333
334     memcpy(&rate, data, sizeof(int32_t));
335     rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate);
336     data = (const char*)data + sizeof(int32_t);
337
338     ss.rate = rate;
339     format_esd2native(format, c->swap_byte_order, &ss);
340
341     CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification");
342     sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1);
343     CHECK_VALIDITY(sink, "No such sink");
344
345     strncpy(name, data, sizeof(name));
346     name[sizeof(name)-1] = 0;
347     utf8_name = pa_utf8_filter(name);
348     
349     pa_client_set_name(c->client, utf8_name);
350     c->original_name = pa_xstrdup(name);
351
352     assert(!c->sink_input && !c->input_memblockq);
353
354     c->sink_input = pa_sink_input_new(sink, __FILE__, utf8_name, &ss, NULL, NULL, 0, -1);
355
356     pa_xfree(utf8_name);
357
358     CHECK_VALIDITY(c->sink_input, "Failed to create sink input.");
359
360     l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); 
361     c->input_memblockq = pa_memblockq_new(
362             0,
363             l,
364             0,
365             pa_frame_size(&ss),
366             (size_t) -1,
367             l/PLAYBACK_BUFFER_FRAGMENTS,
368             NULL,
369             c->protocol->core->memblock_stat);
370     pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2);
371     c->playback.fragment_size = l/10;
372
373     c->sink_input->owner = c->protocol->module;
374     c->sink_input->client = c->client;
375     c->sink_input->peek = sink_input_peek_cb;
376     c->sink_input->drop = sink_input_drop_cb;
377     c->sink_input->kill = sink_input_kill_cb;
378     c->sink_input->get_latency = sink_input_get_latency_cb;
379     c->sink_input->userdata = c;
380
381     c->state = ESD_STREAMING_DATA;
382
383     c->protocol->n_player++;
384     
385     return 0;
386 }
387
388 static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) {
389     char name[ESD_NAME_MAX], *utf8_name;
390     int32_t format, rate;
391     pa_source *source;
392     pa_sample_spec ss;
393     size_t l;
394
395     assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX));
396     
397     memcpy(&format, data, sizeof(int32_t));
398     format = MAYBE_INT32_SWAP(c->swap_byte_order, format);
399     data = (const char*)data + sizeof(int32_t);
400
401     memcpy(&rate, data, sizeof(int32_t));
402     rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate);
403     data = (const char*)data + sizeof(int32_t);
404
405     ss.rate = rate;
406     format_esd2native(format, c->swap_byte_order, &ss);
407
408     CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification.");
409
410     if (request == ESD_PROTO_STREAM_MON) {
411         pa_sink* sink;
412
413         if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) {
414             pa_log(__FILE__": no such sink.");
415             return -1;
416         }
417
418         if (!(source = sink->monitor_source)) {
419             pa_log(__FILE__": no such monitor source.");
420             return -1;
421         }
422     } else {
423         assert(request == ESD_PROTO_STREAM_REC);
424         
425         if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) {
426             pa_log(__FILE__": no such source.");
427             return -1;
428         }
429     }
430     
431     strncpy(name, data, sizeof(name));
432     name[sizeof(name)-1] = 0;
433
434     utf8_name = pa_utf8_filter(name);
435     pa_client_set_name(c->client, utf8_name);
436     pa_xfree(utf8_name);
437     
438     c->original_name = pa_xstrdup(name);
439
440     assert(!c->output_memblockq && !c->source_output);
441
442     if (!(c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &ss, NULL, -1))) {
443         pa_log(__FILE__": failed to create source output");
444         return -1;
445     }
446
447     l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); 
448     c->output_memblockq = pa_memblockq_new(
449             0,
450             l,
451             0,
452             pa_frame_size(&ss),
453             1,
454             0,
455             NULL,
456             c->protocol->core->memblock_stat);
457     pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2);
458     
459     c->source_output->owner = c->protocol->module;
460     c->source_output->client = c->client;
461     c->source_output->push = source_output_push_cb;
462     c->source_output->kill = source_output_kill_cb;
463     c->source_output->get_latency = source_output_get_latency_cb;
464     c->source_output->userdata = c;
465
466     c->state = ESD_STREAMING_DATA;
467
468     c->protocol->n_player++;
469     
470     return 0;
471 }
472
473 static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
474     pa_sink *sink;
475     int32_t latency;
476
477     assert(c && !data && length == 0);
478
479     if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1)))
480         latency = 0;
481     else {
482         double usec = pa_sink_get_latency(sink);
483         latency = (int) ((usec*44100)/1000000);
484     }
485     
486     latency = MAYBE_INT32_SWAP(c->swap_byte_order, latency);
487     connection_write(c, &latency, sizeof(int32_t));
488     return 0;
489 }
490
491 static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
492     int32_t rate = 44100, format = ESD_STEREO|ESD_BITS16;
493     int32_t response;
494     pa_sink *sink;
495
496     assert(c && data && length == sizeof(int32_t));
497
498     if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) {
499         rate = sink->sample_spec.rate;
500         format = format_native2esd(&sink->sample_spec);
501     }
502
503     connection_write_prepare(c, sizeof(int32_t) * 3);
504
505     response = 0;
506     connection_write(c, &response, sizeof(int32_t));
507     rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate);
508     connection_write(c, &rate, sizeof(int32_t));
509     format = MAYBE_INT32_SWAP(c->swap_byte_order, format);
510     connection_write(c, &format, sizeof(int32_t));
511
512     return 0;
513 }
514
515 static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) {
516     uint8_t *response;
517     size_t t, k, s;
518     struct connection *conn;
519     uint32_t idx = PA_IDXSET_INVALID;
520     unsigned nsamples;
521     char terminator[sizeof(int32_t)*6+ESD_NAME_MAX];
522
523     assert(c && data && length == sizeof(int32_t));
524     
525     if (esd_proto_server_info(c, request, data, length) < 0)
526         return -1;
527
528     k = sizeof(int32_t)*5+ESD_NAME_MAX;
529     s = sizeof(int32_t)*6+ESD_NAME_MAX;
530     nsamples = c->protocol->core->scache ? pa_idxset_size(c->protocol->core->scache) : 0;
531     t = s*(nsamples+1) + k*(c->protocol->n_player+1);
532
533     connection_write_prepare(c, t);
534
535     memset(terminator, 0, sizeof(terminator));
536
537     for (conn = pa_idxset_first(c->protocol->connections, &idx); conn; conn = pa_idxset_next(c->protocol->connections, &idx)) {
538         int32_t id, format = ESD_BITS16 | ESD_STEREO, rate = 44100, lvolume = ESD_VOLUME_BASE, rvolume = ESD_VOLUME_BASE;
539         char name[ESD_NAME_MAX];
540
541         if (conn->state != ESD_STREAMING_DATA)
542             continue;
543
544         assert(t >= k*2+s);
545         
546         if (conn->sink_input) {
547             pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input);
548             rate = conn->sink_input->sample_spec.rate;
549             lvolume = (volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM;
550             rvolume = (volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM;
551             format = format_native2esd(&conn->sink_input->sample_spec);
552         }
553         
554         /* id */
555         id = MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) (conn->index+1));
556         connection_write(c, &id, sizeof(int32_t));
557
558         /* name */
559         memset(name, 0, ESD_NAME_MAX); /* don't leak old data */
560         if (conn->original_name)
561             strncpy(name, conn->original_name, ESD_NAME_MAX);
562         else if (conn->client && conn->client->name)
563             strncpy(name, conn->client->name, ESD_NAME_MAX);
564         connection_write(c, name, ESD_NAME_MAX);
565
566         /* rate */
567         rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate);
568         connection_write(c, &rate, sizeof(int32_t));
569
570         /* left */
571         lvolume = MAYBE_INT32_SWAP(c->swap_byte_order, lvolume);
572         connection_write(c, &lvolume, sizeof(int32_t));
573
574         /*right*/
575         rvolume = MAYBE_INT32_SWAP(c->swap_byte_order, rvolume);
576         connection_write(c, &rvolume, sizeof(int32_t));
577
578         /*format*/
579         format = MAYBE_INT32_SWAP(c->swap_byte_order, format);
580         connection_write(c, &format, sizeof(int32_t));
581
582         t -= k;
583     }
584
585     assert(t == s*(nsamples+1)+k);
586     response += k;
587     t -= k;
588
589     connection_write(c, terminator, k);
590
591     if (nsamples) {
592         pa_scache_entry *ce;
593         
594         idx = PA_IDXSET_INVALID;
595         for (ce = pa_idxset_first(c->protocol->core->scache, &idx); ce; ce = pa_idxset_next(c->protocol->core->scache, &idx)) {
596             int32_t id, rate, lvolume, rvolume, format, len;
597             char name[ESD_NAME_MAX];
598
599             assert(t >= s*2);
600
601             /* id */
602             id = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1));
603             connection_write(c, &id, sizeof(int32_t));
604             
605             /* name */
606             memset(name, 0, ESD_NAME_MAX); /* don't leak old data */
607             if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0)
608                 strncpy(name, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX);
609             else
610                 snprintf(name, ESD_NAME_MAX, "native.%s", ce->name);
611             connection_write(c, name, ESD_NAME_MAX);
612             
613             /* rate */
614             rate = MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate);
615             connection_write(c, &rate, sizeof(int32_t));
616             
617             /* left */
618             lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM);
619             connection_write(c, &lvolume, sizeof(int32_t));
620             
621             /*right*/
622             rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM);
623             connection_write(c, &rvolume, sizeof(int32_t));
624             
625             /*format*/
626             format = MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec));
627             connection_write(c, &format, sizeof(int32_t));
628
629             /*length*/
630             len = MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length);
631             connection_write(c, &len, sizeof(int32_t));
632
633             t -= s;
634         }
635     }
636
637     assert(t == s);
638
639     connection_write(c, terminator, s);
640
641     return 0;
642 }
643
644 static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
645     int32_t ok;
646     uint32_t idx, lvolume, rvolume;
647     struct connection *conn;
648
649     assert(c && data && length == sizeof(int32_t)*3);
650     
651     memcpy(&idx, data, sizeof(uint32_t));
652     idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1;
653     data = (const char*)data + sizeof(uint32_t);
654
655     memcpy(&lvolume, data, sizeof(uint32_t));
656     lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, lvolume);
657     data = (const char*)data + sizeof(uint32_t);
658
659     memcpy(&rvolume, data, sizeof(uint32_t));
660     rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume);
661     data = (const char*)data + sizeof(uint32_t);
662
663     if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx)) && conn->sink_input) {
664         pa_cvolume volume;
665         volume.values[0] = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE;
666         volume.values[1] = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE;
667         volume.channels = 2;
668         pa_sink_input_set_volume(conn->sink_input, &volume);
669         ok = 1;
670     } else
671         ok = 0;
672
673     connection_write(c, &ok, sizeof(int32_t));
674     
675     return 0;
676 }
677
678 static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
679     pa_sample_spec ss;
680     int32_t format, rate, sc_length;
681     uint32_t idx;
682     char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1];
683
684     assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int32_t)));
685
686     memcpy(&format, data, sizeof(int32_t));
687     format = MAYBE_INT32_SWAP(c->swap_byte_order, format);
688     data = (const char*)data + sizeof(int32_t);
689
690     memcpy(&rate, data, sizeof(int32_t));
691     rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate);
692     data = (const char*)data + sizeof(int32_t);
693     
694     ss.rate = rate;
695     format_esd2native(format, c->swap_byte_order, &ss);
696
697     CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification.");
698
699     memcpy(&sc_length, data, sizeof(int32_t));
700     sc_length = MAYBE_INT32_SWAP(c->swap_byte_order, sc_length);
701     data = (const char*)data + sizeof(int32_t);
702
703     CHECK_VALIDITY(sc_length <= MAX_CACHE_SAMPLE_SIZE, "Sample too large.");
704
705     strcpy(name, SCACHE_PREFIX);
706     strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX);
707     name[sizeof(name)-1] = 0;
708
709     CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name.");
710     
711     assert(!c->scache.memchunk.memblock);
712     c->scache.memchunk.memblock = pa_memblock_new(sc_length, c->protocol->core->memblock_stat);
713     c->scache.memchunk.index = 0;
714     c->scache.memchunk.length = sc_length;
715     c->scache.sample_spec = ss;
716     assert(!c->scache.name);
717     c->scache.name = pa_xstrdup(name);
718     
719     c->state = ESD_CACHING_SAMPLE;
720
721     pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, NULL, &idx);
722
723     idx += 1;
724     connection_write(c, &idx, sizeof(uint32_t));
725     
726     return 0;
727 }
728
729 static int esd_proto_sample_get_id(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
730     int32_t ok;
731     uint32_t idx;
732     char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1];
733
734     assert(c && data && length == ESD_NAME_MAX);
735
736     strcpy(name, SCACHE_PREFIX);
737     strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX);
738     name[sizeof(name)-1] = 0;
739
740     CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name.");
741
742     ok = -1;
743     if ((idx = pa_scache_get_id_by_name(c->protocol->core, name)) != PA_IDXSET_INVALID)
744         ok = idx + 1;
745
746     connection_write(c, &ok, sizeof(int32_t));
747
748     return 0;
749 }
750
751 static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length) {
752     int32_t ok;
753     const char *name;
754     uint32_t idx;
755
756     assert(c && data && length == sizeof(int32_t));
757
758     memcpy(&idx, data, sizeof(uint32_t));
759     idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1;
760
761     ok = 0;
762     
763     if ((name = pa_scache_get_name_by_id(c->protocol->core, idx))) {
764         if (request == ESD_PROTO_SAMPLE_PLAY) {
765             pa_sink *sink;
766         
767             if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1)))
768                 if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0)
769                     ok = idx + 1;
770         } else {
771             assert(request == ESD_PROTO_SAMPLE_FREE);
772
773             if (pa_scache_remove_item(c->protocol->core, name) >= 0)
774                 ok = idx + 1;
775         }
776     }
777     
778     connection_write(c, &ok, sizeof(int32_t));
779
780     return 0;
781 }
782
783 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) {
784     int32_t ok;
785
786     connection_write_prepare(c, sizeof(int32_t) * 2);
787
788     ok = 1;
789     connection_write(c, &ok, sizeof(int32_t));
790     connection_write(c, &ok, sizeof(int32_t));
791
792     return 0;
793 }
794
795 /*** client callbacks ***/
796
797 static void client_kill_cb(pa_client *c) {
798     assert(c && c->userdata);
799     connection_free(c->userdata);
800 }
801
802 /*** pa_iochannel callbacks ***/
803
804 static int do_read(struct connection *c) {
805     assert(c && c->io);
806
807 /*      pa_log("READ");  */
808     
809     if (c->state == ESD_NEXT_REQUEST) {
810         ssize_t r;
811         assert(c->read_data_length < sizeof(c->request));
812
813         if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) {
814             pa_log_debug(__FILE__": read() failed: %s", r < 0 ? strerror(errno) : "EOF");
815             return -1;
816         }
817
818         if ((c->read_data_length+= r) >= sizeof(c->request)) {
819             struct proto_handler *handler;
820             
821             c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request);
822
823             if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) {
824                 pa_log(__FILE__": recieved invalid request.");
825                 return -1;
826             }
827
828             handler = proto_map+c->request;
829
830 /*             pa_log(__FILE__": executing request #%u", c->request); */
831
832             if (!handler->proc) {
833                 pa_log(__FILE__": recieved unimplemented request #%u.", c->request);
834                 return -1;
835             }
836             
837             if (handler->data_length == 0) {
838                 c->read_data_length = 0;
839
840                 if (handler->proc(c, c->request, NULL, 0) < 0)
841                     return -1;
842                 
843             } else {
844                 if (c->read_data_alloc < handler->data_length)
845                     c->read_data = pa_xrealloc(c->read_data, c->read_data_alloc = handler->data_length);
846                 assert(c->read_data);
847                 
848                 c->state = ESD_NEEDS_REQDATA;
849                 c->read_data_length = 0;
850             }
851         }
852
853     } else if (c->state == ESD_NEEDS_REQDATA) {
854         ssize_t r;
855         struct proto_handler *handler = proto_map+c->request;
856
857         assert(handler->proc);
858         
859         assert(c->read_data && c->read_data_length < handler->data_length);
860
861         if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) {
862             pa_log_debug(__FILE__": read() failed: %s", r < 0 ? strerror(errno) : "EOF");
863             return -1;
864         }
865
866         if ((c->read_data_length += r) >= handler->data_length) {
867             size_t l = c->read_data_length;
868             assert(handler->proc);
869
870             c->state = ESD_NEXT_REQUEST;
871             c->read_data_length = 0;
872             
873             if (handler->proc(c, c->request, c->read_data, l) < 0)
874                 return -1;
875         }
876     } else if (c->state == ESD_CACHING_SAMPLE) {
877         ssize_t r;
878
879         assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length);
880         
881         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) {
882             pa_log_debug(__FILE__": read() failed: %s", r < 0 ? strerror(errno) : "EOF");
883             return -1;
884         }
885
886         c->scache.memchunk.index += r;
887         assert(c->scache.memchunk.index <= c->scache.memchunk.length);
888         
889         if (c->scache.memchunk.index == c->scache.memchunk.length) {
890             uint32_t idx;
891             
892             c->scache.memchunk.index = 0;
893             pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, NULL, &c->scache.memchunk, &idx);
894
895             pa_memblock_unref(c->scache.memchunk.memblock);
896             c->scache.memchunk.memblock = NULL;
897             c->scache.memchunk.index = c->scache.memchunk.length = 0;
898
899             pa_xfree(c->scache.name);
900             c->scache.name = NULL;
901
902             c->state = ESD_NEXT_REQUEST;
903
904             idx += 1;
905             connection_write(c, &idx, sizeof(uint32_t));
906         }
907         
908     } else if (c->state == ESD_STREAMING_DATA && c->sink_input) {
909         pa_memchunk chunk;
910         ssize_t r;
911         size_t l;
912
913         assert(c->input_memblockq);
914
915 /*         pa_log("STREAMING_DATA"); */
916
917         if (!(l = pa_memblockq_missing(c->input_memblockq)))
918             return 0;
919
920         if (l > c->playback.fragment_size)
921             l = c->playback.fragment_size;
922
923         if (c->playback.current_memblock) 
924             if (c->playback.current_memblock->length - c->playback.memblock_index < l) {
925                 pa_memblock_unref(c->playback.current_memblock);
926                 c->playback.current_memblock = NULL;
927                 c->playback.memblock_index = 0;
928             }
929         
930         if (!c->playback.current_memblock) {
931             c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat);
932             assert(c->playback.current_memblock && c->playback.current_memblock->length >= l);
933             c->playback.memblock_index = 0;
934         }
935
936         if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) {
937             pa_log_debug(__FILE__": read() failed: %s", r < 0 ? strerror(errno) : "EOF");
938             return -1;
939         }
940         
941         chunk.memblock = c->playback.current_memblock;
942         chunk.index = c->playback.memblock_index;
943         chunk.length = r;
944         assert(chunk.memblock);
945
946         c->playback.memblock_index += r;
947         
948         assert(c->input_memblockq);
949         pa_memblockq_push_align(c->input_memblockq, &chunk);
950         assert(c->sink_input);
951         pa_sink_notify(c->sink_input->sink);
952     }
953     
954     return 0;
955 }
956
957 static int do_write(struct connection *c) {
958     assert(c && c->io);
959
960 /*     pa_log("WRITE"); */
961     
962     if (c->write_data_length) {
963         ssize_t r;
964         
965         assert(c->write_data_index < c->write_data_length);
966         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) {
967             pa_log(__FILE__": write() failed: %s", strerror(errno));
968             return -1;
969         }
970         
971         if ((c->write_data_index +=r) >= c->write_data_length)
972             c->write_data_length = c->write_data_index = 0;
973         
974     } else if (c->state == ESD_STREAMING_DATA && c->source_output) {
975         pa_memchunk chunk;
976         ssize_t r;
977
978         assert(c->output_memblockq);
979         if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0)
980             return 0;
981         
982         assert(chunk.memblock && chunk.length);
983         
984         if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) {
985             pa_memblock_unref(chunk.memblock);
986             pa_log(__FILE__": write(): %s", strerror(errno));
987             return -1;
988         }
989
990         pa_memblockq_drop(c->output_memblockq, &chunk, r);
991         pa_memblock_unref(chunk.memblock);
992
993         pa_source_notify(c->source_output->source);
994     }
995     
996     return 0;
997 }
998
999 static void do_work(struct connection *c) {
1000     assert(c);
1001
1002     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, 0);
1004
1005     if (c->dead)
1006         return;
1007
1008     if (pa_iochannel_is_readable(c->io)) {
1009         if (do_read(c) < 0)
1010             goto fail;
1011     }
1012
1013     if (c->state == ESD_STREAMING_DATA && c->source_output && pa_iochannel_is_hungup(c->io))
1014         /* In case we are in capture mode we will never call read()
1015          * on the socket, hence we need to detect the hangup manually
1016          * here, instead of simply waiting for read() to return 0. */
1017         goto fail;
1018
1019     if (pa_iochannel_is_writable(c->io))
1020         if (do_write(c) < 0)
1021             goto fail;
1022     
1023     return;
1024
1025 fail:
1026
1027     if (c->state == ESD_STREAMING_DATA && c->sink_input) {
1028         c->dead = 1;
1029
1030         pa_iochannel_free(c->io);
1031         c->io = NULL;
1032
1033         pa_memblockq_prebuf_disable(c->input_memblockq);
1034         pa_sink_notify(c->sink_input->sink);
1035     } else
1036         connection_free(c);
1037 }
1038
1039 static void io_callback(pa_iochannel*io, void *userdata) {
1040     struct connection *c = userdata;
1041     assert(io && c && c->io == io);
1042
1043     do_work(c);
1044 }
1045
1046 /*** defer callback ***/
1047
1048 static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) {
1049     struct connection *c = userdata;
1050     assert(a && c && c->defer_event == e);
1051
1052 /*     pa_log("DEFER"); */
1053     
1054     do_work(c);
1055 }
1056
1057 /*** sink_input callbacks ***/
1058
1059 static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
1060     struct connection*c;
1061     assert(i && i->userdata && chunk);
1062     c = i->userdata;
1063     
1064     if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) {
1065
1066         if (c->dead)
1067             connection_free(c);
1068         
1069         return -1;
1070     }
1071
1072     return 0;
1073 }
1074
1075 static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) {
1076     struct connection*c = i->userdata;
1077     assert(i && c && length);
1078
1079 /*     pa_log("DROP"); */
1080     
1081     pa_memblockq_drop(c->input_memblockq, chunk, length);
1082
1083     /* do something */
1084     assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable);
1085
1086     if (!c->dead)
1087         c->protocol->core->mainloop->defer_enable(c->defer_event, 1);
1088
1089 /*     assert(pa_memblockq_get_length(c->input_memblockq) > 2048); */
1090 }
1091
1092 static void sink_input_kill_cb(pa_sink_input *i) {
1093     assert(i && i->userdata);
1094     connection_free((struct connection *) i->userdata);
1095 }
1096
1097 static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) {
1098     struct connection*c = i->userdata;
1099     assert(i && c);
1100     return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec);
1101 }
1102
1103 /*** source_output callbacks ***/
1104
1105 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1106     struct connection *c = o->userdata;
1107     assert(o && c && chunk);
1108
1109     pa_memblockq_push(c->output_memblockq, chunk);
1110
1111     /* do something */
1112     assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable);
1113
1114     if (!c->dead)
1115         c->protocol->core->mainloop->defer_enable(c->defer_event, 1);
1116 }
1117
1118 static void source_output_kill_cb(pa_source_output *o) {
1119     assert(o && o->userdata);
1120     connection_free((struct connection *) o->userdata);
1121 }
1122
1123 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1124     struct connection*c = o->userdata;
1125     assert(o && c);
1126     return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec);
1127 }
1128
1129 /*** socket server callback ***/
1130
1131 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
1132     struct connection *c = userdata;
1133     assert(m && tv && c && c->auth_timeout_event == e);
1134
1135     if (!c->authorized)
1136         connection_free(c);
1137 }
1138
1139 static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) {
1140     struct connection *c;
1141     pa_protocol_esound *p = userdata;
1142     char cname[256];
1143     assert(s && io && p);
1144
1145     if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
1146         pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
1147         pa_iochannel_free(io);
1148         return;
1149     }
1150     
1151     c = pa_xnew(struct connection, 1);
1152     c->protocol = p;
1153     c->io = io;
1154     pa_iochannel_set_callback(c->io, io_callback, c);
1155
1156     pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname));
1157     assert(p->core);
1158     c->client = pa_client_new(p->core, __FILE__, cname);
1159     assert(c->client);
1160     c->client->owner = p->module;
1161     c->client->kill = client_kill_cb;
1162     c->client->userdata = c;
1163     
1164     c->authorized = p->public;
1165     c->swap_byte_order = 0;
1166     c->dead = 0;
1167
1168     c->read_data_length = 0;
1169     c->read_data = pa_xmalloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length);
1170
1171     c->write_data_length = c->write_data_index = c->write_data_alloc = 0;
1172     c->write_data = NULL;
1173
1174     c->state = ESD_NEEDS_REQDATA;
1175     c->request = ESD_PROTO_CONNECT;
1176
1177     c->sink_input = NULL;
1178     c->input_memblockq = NULL;
1179
1180     c->source_output = NULL;
1181     c->output_memblockq = NULL;
1182
1183     c->playback.current_memblock = NULL;
1184     c->playback.memblock_index = 0;
1185     c->playback.fragment_size = 0;
1186
1187     c->scache.memchunk.length = c->scache.memchunk.index = 0;
1188     c->scache.memchunk.memblock = NULL;
1189     c->scache.name = NULL;
1190
1191     c->original_name = NULL;
1192
1193     if (!c->authorized) {
1194         struct timeval tv;
1195         pa_gettimeofday(&tv);
1196         tv.tv_sec += AUTH_TIMEOUT;
1197         c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c);
1198     } else
1199         c->auth_timeout_event = NULL;
1200     
1201     c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c);
1202     assert(c->defer_event);
1203     p->core->mainloop->defer_enable(c->defer_event, 0);
1204
1205     pa_idxset_put(p->connections, c, &c->index);
1206 }
1207
1208 /*** entry points ***/
1209
1210 pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) {
1211     pa_protocol_esound *p;
1212     int public = 0;
1213     assert(core && server && ma);
1214
1215     p = pa_xnew(pa_protocol_esound, 1);
1216
1217     if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) {
1218         pa_log(__FILE__": auth-anonymous= expects a boolean argument.");
1219         return NULL;
1220     }
1221
1222     if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) {
1223         pa_xfree(p);
1224         return NULL;
1225     }
1226
1227     p->module = m;
1228     p->public = public;
1229     p->server = server;
1230     pa_socket_server_set_callback(p->server, on_connection, p);
1231     p->core = core;
1232     p->connections = pa_idxset_new(NULL, NULL);
1233     assert(p->connections);
1234
1235     p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
1236     p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));
1237     p->n_player = 0;
1238
1239     return p;
1240 }
1241
1242 void pa_protocol_esound_free(pa_protocol_esound *p) {
1243     struct connection *c;
1244     assert(p);
1245
1246     while ((c = pa_idxset_first(p->connections, NULL)))
1247         connection_free(c);
1248
1249     pa_idxset_free(p->connections, NULL, NULL);
1250     pa_socket_server_unref(p->server);
1251     pa_xfree(p);
1252 }