source: roaraudio/plugins/roard/protocol-esound.c @ 2828:ea6c979c9cab

Last change on this file since 2828:ea6c979c9cab was 2828:ea6c979c9cab, checked in by phi, 13 years ago

esd emulation code does check for byte order

File size: 14.7 KB
Line 
1//emul_esd.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2009
5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25#include "roard.h"
26
27#ifndef ROAR_WITHOUT_DCOMP_EMUL_ESD
28#ifdef ROAR_HAVE_H_ESD
29
30#if !defined(ROAR_TARGET_MICROCONTROLLER) && !defined(ROAR_MINIMAL)
31#define _NAME(x) (x)
32#else
33#define _NAME(x) ((char*)NULL)
34#endif
35
36#define _cmd_t   int
37#define _INTSIZE sizeof(_cmd_t)
38
39#define _NOT_TO_IMPLEMENT    NULL
40#define _UNIMPLEMNTED_IN_ESD NULL
41#define _NEED_SAMPLE_SUPPORT NULL
42
43#define _ROAR2ESD(x) ((x)+1)
44#define _ESD2ROAR(x) ((x)-1)
45
46struct emul_esd_command g_emul_esd_commands[] = {
47 {ESD_PROTO_CONNECT,      ESD_KEY_LEN  +     _INTSIZE, _NAME("CONNECT"),      emul_esd_on_connect},
48 {ESD_PROTO_LOCK,         ESD_KEY_LEN  +     _INTSIZE, _NAME("LOCK"),         NULL},
49 {ESD_PROTO_UNLOCK,       ESD_KEY_LEN  +     _INTSIZE, _NAME("UNLOCK"),       NULL},
50 {ESD_PROTO_STREAM_PLAY,  ESD_NAME_MAX + 2 * _INTSIZE, _NAME("STREAM_PLAY"),  emul_esd_on_stream},
51 {ESD_PROTO_STREAM_REC,   ESD_NAME_MAX + 2 * _INTSIZE, _NAME("STREAM_REC"),   emul_esd_on_stream},
52 {ESD_PROTO_STREAM_MON,   ESD_NAME_MAX + 2 * _INTSIZE, _NAME("STREAM_MON"),   emul_esd_on_stream},
53 {ESD_PROTO_SAMPLE_CACHE, ESD_NAME_MAX + 3 * _INTSIZE, _NAME("SAMPLE_CACHE"), _NEED_SAMPLE_SUPPORT},
54 {ESD_PROTO_SAMPLE_FREE,                     _INTSIZE, _NAME("SAMPLE_FREE"),  _NEED_SAMPLE_SUPPORT},
55 {ESD_PROTO_SAMPLE_PLAY,                     _INTSIZE, _NAME("SAMPLE_PLAY"),  _NEED_SAMPLE_SUPPORT},
56 {ESD_PROTO_SAMPLE_LOOP,                     _INTSIZE, _NAME("SAMPLE_LOOP"),  _NEED_SAMPLE_SUPPORT},
57 {ESD_PROTO_SAMPLE_STOP,                     _INTSIZE, _NAME("SAMPLE_STOP"),  _NEED_SAMPLE_SUPPORT},
58 {ESD_PROTO_SAMPLE_KILL,  0                          , _NAME("SAMPLE_KILL"),  _NEED_SAMPLE_SUPPORT},
59 {ESD_PROTO_STANDBY,      ESD_KEY_LEN +      _INTSIZE, _NAME("STANDBY"),      emul_esd_on_standby},
60 {ESD_PROTO_RESUME,       ESD_KEY_LEN +      _INTSIZE, _NAME("RESUME"),       emul_esd_on_standby},
61 {ESD_PROTO_SAMPLE_GETID, ESD_NAME_MAX               , _NAME("SAMPLE_GETID"), _NEED_SAMPLE_SUPPORT},
62 {ESD_PROTO_STREAM_FILT,  ESD_NAME_MAX + 2 * _INTSIZE, _NAME("STREAM_FILT"),  emul_esd_on_stream},
63 {ESD_PROTO_SERVER_INFO,                     _INTSIZE, _NAME("SERVER_INFO"),  emul_esd_on_server_info},
64 {ESD_PROTO_ALL_INFO,                        _INTSIZE, _NAME("ALL_INFO"),     emul_esd_on_all_info},
65 {ESD_PROTO_SUBSCRIBE,    0                          , _NAME("SUBSCRIBE"),    _UNIMPLEMNTED_IN_ESD},
66 {ESD_PROTO_UNSUBSCRIBE,  0                          , _NAME("UNSUBSCRIBE"),  _UNIMPLEMNTED_IN_ESD},
67 {ESD_PROTO_STREAM_PAN,                  3 * _INTSIZE, _NAME("STREAM_PAN"),   emul_esd_on_stream_pan},
68 {ESD_PROTO_SAMPLE_PAN,                  3 * _INTSIZE, _NAME("SAMPLE_PAN"),   _NEED_SAMPLE_SUPPORT},
69 {ESD_PROTO_STANDBY_MODE,                    _INTSIZE, _NAME("STANDBY_MODE"), emul_esd_on_standbymode},
70 {ESD_PROTO_LATENCY,      0                          , _NAME("LATENCY"),      emul_esd_on_latency},
71 {ESD_PROTO_MAX,          0                          , _NAME("MAX"),          _NOT_TO_IMPLEMENT},
72 {-1, 0, _NAME("END OF LIST"), _NOT_TO_IMPLEMENT}
73};
74
75// command handling:
76int emul_esd_exec_command(int client, int cmd, struct roar_vio_calls * vio) {
77 struct emul_esd_command * cur;
78 void * data = NULL;
79 ssize_t ret;
80 size_t  done = 0;
81 int r;
82 int i;
83
84 ROAR_DBG("emul_esd_exec_command(*) = ?");
85
86 if ( client == -1 || cmd < ESD_PROTO_CONNECT || cmd > ESD_PROTO_MAX || vio == NULL )
87  return -1;
88
89 ROAR_DBG("emul_esd_exec_command(*) = ?");
90
91 for (i = 0; (cur = &(g_emul_esd_commands[i]))->cmd != -1; i++) {
92  if ( cur->cmd == cmd ) {
93   if ( cur->datalen > 0 ) {
94    if ( (data = malloc(cur->datalen)) == NULL ) {
95     // we will do a protocol error in case we do not drop the client
96     clients_delete(client);
97     return -1;
98    }
99
100    while ( done < cur->datalen ) {
101     ret = roar_vio_read(vio, data+done, cur->datalen-done);
102
103     if ( ret < 1 ) {
104      free(data);
105      clients_delete(client);
106      return -1;
107     } else {
108      done += ret;
109     }
110    }
111   }
112
113   if ( cur->handler == NULL ) {
114    ROAR_WARN("emul_esd_exec_command(client=%i, cmd=%s(%i), vio=%p): client uses unimplemted command",
115               client, cur->name, cmd, vio
116             );
117    clients_delete(client);
118    r = -1;
119   } else {
120    r = cur->handler(client, cur, data, vio);
121   }
122
123   if ( data != NULL )
124    free(data);
125
126   return r;
127  }
128 }
129
130 return -1;
131}
132
133int emul_esd_check_client(int client, struct roar_vio_calls * vio) {
134 struct roar_vio_calls calls;
135 _cmd_t cmd;
136
137 if ( client == -1 )
138  return -1;
139
140 if ( vio == NULL ) {
141  vio = &calls;
142  if ( roar_vio_open_fh_socket(vio, clients_get_fh(client)) == -1 )
143   return -1;
144 }
145
146 if ( roar_vio_read(vio, &cmd, _INTSIZE) != _INTSIZE ) {
147  // really bad protocol error
148  clients_delete(client);
149  return -1;
150 }
151
152 return emul_esd_exec_command(client, cmd, vio);
153}
154
155// porto lib:
156int emul_esd_int_read_buf  (int client, int * data, void * buf) {
157 _cmd_t d;
158
159 if ( data == NULL || buf == NULL )
160  return -1;
161
162 d = *(_cmd_t*)buf;
163
164 *data = d;
165
166 return 0;
167}
168int emul_esd_int_read      (int client, int * data, struct roar_vio_calls * vio) {
169 _cmd_t d;
170
171 if ( data == NULL )
172  return -1;
173
174 if ( roar_vio_read(vio, &d, _INTSIZE) != _INTSIZE )
175  return -1;
176
177 *data = d;
178
179 return 0;
180}
181
182int emul_esd_int_write     (int client, int   data, struct roar_vio_calls * vio) {
183 _cmd_t d = data;
184
185 return roar_vio_write(vio, &d, _INTSIZE) == _INTSIZE ? 0 : -1;
186}
187
188int emul_esd_test_auth     (int client, void * data, struct roar_vio_calls * vio) {
189 // accept all clients for the moment.
190 return emul_esd_int_write(client, 1, vio);
191}
192
193int emul_esd_test_byteorder(int client, void * data) {
194 struct roar_client * c;
195
196 if ( clients_get(client, &c) == -1 )
197  return -1;
198
199// "NDNE";
200
201 if ( !memcmp(data, "NDNE", 4) ) {
202  c->byteorder = ROAR_BYTEORDER_LE;
203 } else if ( !memcmp(data, "ENDE", 4) ) {
204  c->byteorder = ROAR_BYTEORDER_BE;
205 } else if ( !memcmp(data, "NEED", 4) ) {
206  c->byteorder = ROAR_BYTEORDER_PDP;
207 } else {
208  return -1;
209 }
210
211 return 0;
212}
213
214// handler:
215int emul_esd_on_connect    (int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
216
217 ROAR_DBG("emul_esd_on_connect(client=%i, cmd=%p, data=%p, vio=%p) = ?", client, cmd, data, vio);
218
219 if ( client == -1 || data == NULL || vio == NULL )
220  return -1;
221
222 ROAR_DBG("emul_esd_on_connect(client=%i, cmd=%p, data=%p, vio=%p) = ?", client, cmd, data, vio);
223
224 if ( emul_esd_test_auth(client, data, vio) == -1 )
225  return -1;
226
227 ROAR_DBG("emul_esd_on_connect(client=%i, cmd=%p, data=%p, vio=%p) = ?", client, cmd, data, vio);
228
229 if ( emul_esd_test_byteorder(client, data+ESD_KEY_LEN) == -1 )
230  return -1;
231
232 ROAR_DBG("emul_esd_on_connect(client=%i, cmd=%p, data=%p, vio=%p) = ?", client, cmd, data, vio);
233
234 return 0;
235}
236
237int emul_esd_on_stream     (int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
238 struct roar_stream_server * ss;
239 struct roar_stream        *  s;
240 struct roar_client        *  c;
241 int stream;
242 int dir = -1;
243 int esdformat;
244 int rate;
245
246 if ( client == -1 || cmd == NULL || data == NULL || vio == NULL )
247  return -1;
248
249 switch (cmd->cmd) {
250  case ESD_PROTO_STREAM_PLAY: dir = ROAR_DIR_PLAY;    break;
251  case ESD_PROTO_STREAM_REC:  dir = ROAR_DIR_RECORD;  break;
252  case ESD_PROTO_STREAM_MON:  dir = ROAR_DIR_MONITOR; break;
253  case ESD_PROTO_STREAM_FILT: dir = ROAR_DIR_FILTER;  break;
254  default:
255    clients_delete(client);
256    return -1;
257 }
258
259 if ( clients_get(client, &c) == -1 ) {
260  return -1;
261 }
262
263 ROAR_DBG("emul_esd_on_stream(client=%i, ...): creating stream...", client);
264 if ((stream = streams_new()) == -1 ) {
265  clients_delete(client);
266  return -1;
267 }
268
269 ROAR_DBG("emul_esd_on_stream(client=%i, ...): getting stream...", client);
270 if ( streams_get(stream, &ss) == -1 ) {
271  streams_delete(stream);
272  clients_delete(client);
273  return -1;
274 }
275
276 s = ROAR_STREAM(ss);
277
278 ROAR_DBG("emul_esd_on_stream(client=%i, ...): set client of stream...", client);
279 if ( client_stream_add(client, stream) == -1 ) {
280  streams_delete(stream);
281  clients_delete(client);
282  return -1;
283 }
284
285 emul_esd_int_read_buf(client, &esdformat, data);
286 emul_esd_int_read_buf(client, &rate,      data+_INTSIZE);
287
288 strncpy(c->name, data + 2*_INTSIZE, ROAR_BUFFER_NAME > ESD_NAME_MAX ? ESD_NAME_MAX : ROAR_BUFFER_NAME);
289 c->name[ROAR_BUFFER_NAME-1] = 0;
290
291 ROAR_DBG("emul_esd_on_stream(*): esdformat=0x%.8X, rate=%i", esdformat, rate);
292
293 s->info.rate = rate;
294
295 switch (esdformat & ESD_MASK_BITS) {
296  case ESD_BITS8:  s->info.bits =  8; s->info.codec = ROAR_CODEC_PCM_U_LE; break;
297  case ESD_BITS16: s->info.bits = 16; s->info.codec = ROAR_CODEC_DEFAULT;  break;
298  default:
299    streams_delete(stream);
300    clients_delete(client);
301    return -1;
302 }
303
304 switch (esdformat & ESD_MASK_CHAN) {
305  case ESD_MONO:   s->info.channels = 1; break;
306  case ESD_STEREO: s->info.channels = 2; break;
307  default:
308    streams_delete(stream);
309    clients_delete(client);
310    return -1;
311 }
312
313 ss->codec_orgi = s->info.codec;
314
315 ROAR_DBG("emul_esd_on_stream(*): s->info = {.rate=%i, .bits=%i, .channels=%i, .codec=%i}", s->info.rate, s->info.bits, s->info.channels, s->info.codec);
316
317 if ( streams_set_dir(stream, dir, 1) == -1 ) {
318  clients_delete(client);
319  return -1;
320 }
321
322 if ( client_stream_exec(client, stream) == -1 ) {
323  clients_delete(client);
324  return -1;
325 }
326
327 return 0;
328}
329
330int emul_esd_on_latency    (int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
331 int lag = ROAR_OUTPUT_CFREQ;
332
333 lag *= 2.0 * 44100.0 / (float)g_sa->rate;
334 
335 return emul_esd_int_write(client, lag, vio);
336}
337
338int emul_esd_on_standby    (int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
339 int ok = 0;
340
341 if ( emul_esd_test_auth(client, data, vio) == -1 ) {
342  return emul_esd_int_write(client, ok, vio);
343 }
344
345 ok = 1;
346
347 if (cmd->cmd == ESD_PROTO_STANDBY) {
348  g_standby = 1;
349 } else {
350  g_standby = 0;
351 }
352
353
354 return emul_esd_int_write(client, ok, vio);
355}
356
357int emul_esd_on_standbymode(int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
358 int mode = ESM_ERROR;
359
360 if ( g_standby ) {
361  if ( g_autostandby ) {
362   mode = ESM_ON_AUTOSTANDBY;
363  } else {
364   mode = ESM_ON_STANDBY;
365  }
366 } else {
367  mode = ESM_RUNNING;
368 }
369
370 return emul_esd_int_write(client, mode, vio);
371}
372
373int emul_esd_on_stream_pan (int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
374 struct roar_stream_server * ss;
375 int stream;
376 int left, right;
377 int ok = 0;
378
379 emul_esd_int_read_buf(client, &stream, data + 0*_INTSIZE);
380 emul_esd_int_read_buf(client, &left,   data + 1*_INTSIZE);
381 emul_esd_int_read_buf(client, &right,  data + 2*_INTSIZE);
382
383 stream = _ESD2ROAR(stream);
384
385 if ( streams_get(stream, &ss) != -1 ) {
386  ss->mixer.mixer[0] = left  == 256 ? 65535 : left  * 256;
387  ss->mixer.mixer[1] = right == 256 ? 65535 : right * 256;
388  if ( streams_set_mixer(stream) != -1 )
389   ok = 1;
390 }
391
392 return emul_esd_int_write(client, ok, vio);
393}
394
395int emul_esd_on_server_info(int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
396 int version = 0;
397 int rate    = g_sa->rate;
398 int format  = 0;
399
400 switch (g_sa->bits) {
401  case  8: format |= ESD_BITS8;  break;
402  case 16: format |= ESD_BITS16; break;
403 }
404
405 switch (g_sa->channels) {
406  case  1: format |= ESD_MONO;   break;
407  case  2: format |= ESD_STEREO; break;
408 }
409
410 if ( emul_esd_int_write(client, version, vio) == -1 )
411  return -1;
412
413 if ( emul_esd_int_write(client, rate, vio) == -1 )
414  return -1;
415
416 if ( emul_esd_int_write(client, format, vio) == -1 )
417  return -1;
418
419 return 0;
420}
421
422int emul_esd_on_all_info   (int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
423 struct roar_stream_server *   ss;
424 struct roar_audio_info    * info;
425 struct roar_client        *    c;
426 char name[ESD_NAME_MAX];
427 char * sname;
428 int id, rate, left, right, format;
429 int i;
430
431 if ( emul_esd_on_server_info(client, cmd, data, vio) == -1 )
432  return -1;
433
434 for (i = 0; i < (ROAR_STREAMS_MAX+2); i++) {
435  memset(name, 0, sizeof(name));
436
437  id   = rate  = format = 0;
438  left = right = 0;
439
440  if ( i >= ROAR_STREAMS_MAX ) {
441   id = -1;
442  } else {
443   if ( streams_get(i, &ss) == -1 )
444    continue;
445
446   switch (streams_get_dir(i)) {
447    case ROAR_DIR_PLAY:    format |= ESD_PLAY;    break;
448    case ROAR_DIR_MONITOR: format |= ESD_MONITOR; break;
449    case ROAR_DIR_RECORD:  format |= ESD_RECORD;  break;
450    default:               continue;              break;
451   }
452
453   info = &(ROAR_STREAM(ss)->info);
454
455   id = i;
456   rate = info->rate;
457
458   switch (info->bits) {
459    case  8: format |= ESD_BITS8;  break;
460    case 16: format |= ESD_BITS16; break;
461   }
462
463   switch (info->channels) {
464    case  1:
465      if ( ss->mixer.mixer[0] == ss->mixer.scale ) {
466       left = right = 256;
467      } else {
468       left = right = ss->mixer.mixer[0] / 256;
469      }
470      format |= ESD_MONO;
471     break;
472    case  2:
473      if ( ss->mixer.mixer[0] == ss->mixer.scale ) {
474       left = 256;
475      } else {
476       left = ss->mixer.mixer[0] / 256;
477      }
478
479      if ( ss->mixer.mixer[1] == ss->mixer.scale ) {
480       right = 256;
481      } else {
482       right = ss->mixer.mixer[1] / 256;
483      }
484
485      format |= ESD_STEREO;
486     break;
487    default:
488      left = right = 0;
489   }
490
491   sname = streams_get_name(id);
492
493   if ( sname == NULL || sname[0] == 0 ) {
494    if ( clients_get(streams_get_client(id), &c) != -1 ) {
495     sname = c->name;
496    }
497   }
498
499   if ( sname == NULL || sname[0] == 0 )
500    sname = "(unknown)";
501
502   strncpy(name, sname, sizeof(name) > ROAR_BUFFER_NAME ? ROAR_BUFFER_NAME : sizeof(name));
503   name[sizeof(name)-1] = 0;
504
505  }
506
507  id = _ROAR2ESD(id);
508
509  if ( emul_esd_int_write(client, id, vio) == -1 )
510   return -1;
511  if ( roar_vio_write(vio, name, sizeof(name)) != sizeof(name) )
512   return -1;
513  if ( emul_esd_int_write(client, rate, vio) == -1 )
514   return -1;
515  if ( emul_esd_int_write(client, left, vio) == -1 )
516   return -1;
517  if ( emul_esd_int_write(client, right, vio) == -1 )
518   return -1;
519  if ( emul_esd_int_write(client, format, vio) == -1 )
520   return -1;
521
522  if ( i == ROAR_STREAMS_MAX+1) {
523   // write 'length'...
524   if ( emul_esd_int_write(client, id, vio) == -1 )
525    return -1;
526  }
527 }
528
529 return 0;
530}
531
532#endif
533#endif
534
535//ll
Note: See TracBrowser for help on using the repository browser.