source: roaraudio/plugins/roard/protocol-esound.c @ 2539:616cc31e245a

Last change on this file since 2539:616cc31e245a was 2539:616cc31e245a, checked in by phi, 15 years ago

added emul_esd_on_server_info()

File size: 11.8 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_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"),     NULL},
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(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 // TODO: do a real test
195 return 0;
196}
197
198// handler:
199int emul_esd_on_connect    (int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
200
201 ROAR_DBG("emul_esd_on_connect(client=%i, cmd=%p, data=%p, vio=%p) = ?", client, cmd, data, vio);
202
203 if ( client == -1 || data == NULL || vio == NULL )
204  return -1;
205
206 ROAR_DBG("emul_esd_on_connect(client=%i, cmd=%p, data=%p, vio=%p) = ?", client, cmd, data, vio);
207
208 if ( emul_esd_test_auth(client, data, vio) == -1 )
209  return -1;
210
211 ROAR_DBG("emul_esd_on_connect(client=%i, cmd=%p, data=%p, vio=%p) = ?", client, cmd, data, vio);
212
213 if ( emul_esd_test_byteorder(client, data+ESD_KEY_LEN) == -1 )
214  return -1;
215
216 ROAR_DBG("emul_esd_on_connect(client=%i, cmd=%p, data=%p, vio=%p) = ?", client, cmd, data, vio);
217
218 return 0;
219}
220
221int emul_esd_on_stream     (int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
222 struct roar_stream_server * ss;
223 struct roar_stream        *  s;
224 struct roar_client        *  c;
225 int stream;
226 int dir = -1;
227 int esdformat;
228 int rate;
229
230 if ( client == -1 || cmd == NULL || data == NULL || vio == NULL )
231  return -1;
232
233 switch (cmd->cmd) {
234  case ESD_PROTO_STREAM_PLAY: dir = ROAR_DIR_PLAY;    break;
235  case ESD_PROTO_STREAM_REC:  dir = ROAR_DIR_RECORD;  break;
236  case ESD_PROTO_STREAM_MON:  dir = ROAR_DIR_MONITOR; break;
237  case ESD_PROTO_STREAM_FILT: dir = ROAR_DIR_FILTER;  break;
238  default:
239    clients_delete(client);
240    return -1;
241 }
242
243 if ( clients_get(client, &c) == -1 ) {
244  return -1;
245 }
246
247 ROAR_DBG("emul_esd_on_stream(client=%i, ...): creating stream...", client);
248 if ((stream = streams_new()) == -1 ) {
249  clients_delete(client);
250  return -1;
251 }
252
253 ROAR_DBG("emul_esd_on_stream(client=%i, ...): getting stream...", client);
254 if ( streams_get(stream, &ss) == -1 ) {
255  streams_delete(stream);
256  clients_delete(client);
257  return -1;
258 }
259
260 s = ROAR_STREAM(ss);
261
262 ROAR_DBG("emul_esd_on_stream(client=%i, ...): set client of stream...", client);
263 if ( client_stream_add(client, stream) == -1 ) {
264  streams_delete(stream);
265  clients_delete(client);
266  return -1;
267 }
268
269 emul_esd_int_read_buf(client, &esdformat, data);
270 emul_esd_int_read_buf(client, &rate,      data+_INTSIZE);
271
272 strncpy(c->name, data + 2*_INTSIZE, ROAR_BUFFER_NAME > ESD_NAME_MAX ? ESD_NAME_MAX : ROAR_BUFFER_NAME);
273 c->name[ROAR_BUFFER_NAME-1] = 0;
274
275 ROAR_DBG("emul_esd_on_stream(*): esdformat=0x%.8X, rate=%i", esdformat, rate);
276
277 s->info.rate = rate;
278
279 switch (esdformat & ESD_MASK_BITS) {
280  case ESD_BITS8:  s->info.bits =  8; s->info.codec = ROAR_CODEC_PCM_U_LE; break;
281  case ESD_BITS16: s->info.bits = 16; s->info.codec = ROAR_CODEC_DEFAULT;  break;
282  default:
283    streams_delete(stream);
284    clients_delete(client);
285    return -1;
286 }
287
288 switch (esdformat & ESD_MASK_CHAN) {
289  case ESD_MONO:   s->info.channels = 1; break;
290  case ESD_STEREO: s->info.channels = 2; break;
291  default:
292    streams_delete(stream);
293    clients_delete(client);
294    return -1;
295 }
296
297 ss->codec_orgi = s->info.codec;
298
299 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);
300
301 if ( streams_set_dir(stream, dir, 1) == -1 ) {
302  clients_delete(client);
303  return -1;
304 }
305
306 if ( client_stream_exec(client, stream) == -1 ) {
307  clients_delete(client);
308  return -1;
309 }
310
311 return 0;
312}
313
314int emul_esd_on_latency    (int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
315 int lag = ROAR_OUTPUT_CFREQ;
316
317 lag *= 2.0 * 44100.0 / (float)g_sa->rate;
318 
319 return emul_esd_int_write(client, lag, vio);
320}
321
322int emul_esd_on_standby    (int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
323 int ok = 0;
324
325 if ( emul_esd_test_auth(client, data, vio) == -1 ) {
326  return emul_esd_int_write(client, ok, vio);
327 }
328
329 ok = 1;
330
331 if (cmd->cmd == ESD_PROTO_STANDBY) {
332  g_standby = 1;
333 } else {
334  g_standby = 0;
335 }
336
337
338 return emul_esd_int_write(client, ok, vio);
339}
340
341int emul_esd_on_standbymode(int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
342 int mode = ESM_ERROR;
343
344 if ( g_standby ) {
345  if ( g_autostandby ) {
346   mode = ESM_ON_AUTOSTANDBY;
347  } else {
348   mode = ESM_ON_STANDBY;
349  }
350 } else {
351  mode = ESM_RUNNING;
352 }
353
354 return emul_esd_int_write(client, mode, vio);
355}
356
357int emul_esd_on_stream_pan (int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
358 struct roar_stream_server * ss;
359 int stream;
360 int left, right;
361 int ok = 0;
362
363 emul_esd_int_read_buf(client, &stream, data + 0*_INTSIZE);
364 emul_esd_int_read_buf(client, &left,   data + 1*_INTSIZE);
365 emul_esd_int_read_buf(client, &right,  data + 2*_INTSIZE);
366
367 stream = _ESD2ROAR(stream);
368
369 if ( streams_get(stream, &ss) != -1 ) {
370  ss->mixer.mixer[0] = left  == 256 ? 65535 : left  * 256;
371  ss->mixer.mixer[1] = right == 256 ? 65535 : right * 256;
372  if ( streams_set_mixer(stream) != -1 )
373   ok = 1;
374 }
375
376 return emul_esd_int_write(client, ok, vio);
377}
378
379int emul_esd_on_server_info(int client, struct emul_esd_command * cmd, void * data, struct roar_vio_calls * vio) {
380 int version = 0;
381 int rate    = g_sa->rate;
382 int format  = 0;
383
384 switch (g_sa->bits) {
385  case  8: format |= ESD_BITS8;  break;
386  case 16: format |= ESD_BITS16; break;
387 }
388
389 switch (g_sa->channels) {
390  case  1: format |= ESD_MONO;   break;
391  case  2: format |= ESD_STEREO; break;
392 }
393
394 if ( emul_esd_int_write(client, version, vio) == -1 )
395  return -1;
396
397 if ( emul_esd_int_write(client, rate, vio) == -1 )
398  return -1;
399
400 if ( emul_esd_int_write(client, format, vio) == -1 )
401  return -1;
402
403 return 0;
404}
405
406#endif
407#endif
408
409//ll
Note: See TracBrowser for help on using the repository browser.