source: roaraudio/plugins/roard/protocol-rplay.c @ 5306:8f1d1d2d3ca9

Last change on this file since 5306:8f1d1d2d3ca9 was 4708:c9d40761088a, checked in by phi, 13 years ago

updated copyright statements

File size: 13.7 KB
Line 
1//emul_rplay.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011
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, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 */
25
26#include "roard.h"
27
28#ifndef ROAR_WITHOUT_DCOMP_EMUL_RPLAY
29
30struct emul_rplay_command emul_rplay_commands[] = {
31 {"access",      NULL, -1, -1, NULL},
32 {"application", NULL,  1, -1, NULL},
33 {"continue",    NULL,  1, -1, emul_rplay_on_continue},
34 {"die",         NULL,  1, -1, NULL},
35 {"done",        NULL,  1, -1, NULL}, // #ifdef DEBUG
36 {"find",        NULL,  1,  1, NULL},
37 {"get",         NULL,  1,  1, NULL},
38 {"help",        NULL, -1, -1, emul_rplay_on_help},
39 {"info",        NULL,  1,  1, NULL},
40 {"list",        NULL,  0,  1, NULL},
41 {"modify",      NULL,  2, -1, NULL},
42 {"monitor",     NULL,  1, -1, NULL},
43 {"pause",       NULL,  1, -1, emul_rplay_on_pause},
44 {"play",        NULL,  1, -1, emul_rplay_on_play},
45 {"put",         NULL,  2, -1, emul_rplay_on_put},
46 {"quit",        NULL,  0,  0, emul_rplay_on_quit},
47 {"reset",       NULL,  0,  0, NULL},
48 {"set",         NULL,  1, -1, NULL},
49 {"skip",        NULL,  1,  1, NULL},
50 {"status",      NULL,  0,  0, emul_rplay_on_status},
51 {"stop",        NULL,  1, -1, NULL},
52 {"version",     NULL,  0,  0, NULL},
53 {"volume",      NULL,  0,  1, NULL},
54 {"wait",        NULL, -1, -1, NULL},
55 {NULL, NULL, -1, -1, NULL}
56};
57
58static inline int is_true(const char * str) {
59 const char * ts[] = {"true", "t", "1", "yes", "y", "on"};
60 int i;
61
62 for (i = 0; i < sizeof(ts)/sizeof(*ts); i++)
63  if ( !strcasecmp(str, ts[i]) )
64   return 1;
65
66 return 0;
67}
68
69static inline int is_false(const char * str) {
70 return !is_true(str);
71}
72
73static int format_to_codec(const char * str, const int bo) {
74
75 if ( !strcasecmp(str, "ulaw") || !strcasecmp(str, "u_law") || !strcasecmp(str, "u-law") )
76  return ROAR_CODEC_MULAW;
77
78 if ( !strncasecmp(str, "ulinear", 7) ) {
79  switch (bo) {
80   case ROAR_BYTEORDER_LE:
81     return ROAR_CODEC_PCM_U_LE;
82    break;
83   case ROAR_BYTEORDER_BE:
84     return ROAR_CODEC_PCM_U_BE;
85    break;
86   case ROAR_BYTEORDER_PDP:
87     return ROAR_CODEC_PCM_U_PDP;
88    break;
89   default:
90     return -1;
91    break;
92  }
93 } else if ( !strncasecmp(str, "linear", 6) ) {
94  switch (bo) {
95   case ROAR_BYTEORDER_LE:
96     return ROAR_CODEC_PCM_S_LE;
97    break;
98   case ROAR_BYTEORDER_BE:
99     return ROAR_CODEC_PCM_S_BE;
100    break;
101   case ROAR_BYTEORDER_PDP:
102     return ROAR_CODEC_PCM_S_PDP;
103    break;
104   default:
105     return -1;
106    break;
107  }
108 }
109
110 return -1;
111}
112
113int emul_rplay_check_client  (int client, struct roar_vio_calls * vio) {
114 struct roar_vio_calls calls;
115 char buf[1024];
116 ssize_t len;
117
118 if ( client == -1 )
119  return -1;
120
121 if ( vio == NULL ) {
122  vio = &calls;
123  if ( roar_vio_open_fh_socket(vio, clients_get_fh(client)) == -1 )
124   return -1;
125 }
126
127 if ( (len = roar_vio_read(vio, buf, sizeof(buf)-1)) <= 0 ) {
128  // really bad protocol error
129  clients_delete(client);
130  return -1;
131 }
132
133 for (; buf[len-1] == '\r' || buf[len-1] == '\n'; len--);
134
135 buf[len] = 0;
136
137 return emul_rplay_exec_command(client, vio, buf);
138}
139
140int emul_rplay_exec_command  (int client, struct roar_vio_calls * vio, char * command) {
141 struct emul_rplay_command * cmd;
142 struct roar_keyval * kv;
143 ssize_t kvlen;
144 char * para = NULL;
145 char * c;
146 int last_was_space = 0;
147
148 for (c = command; *c != 0; c++) {
149  if ( *c == ' ' || *c == '\t' ) {
150   last_was_space = 1;
151   *c = 0;
152  } else {
153   if ( last_was_space ) {
154    para = c;
155    break;
156   }
157  }
158 }
159
160 if ( para == NULL ) {
161  kv = NULL;
162  kvlen = 0;
163 } else {
164  kvlen = roar_keyval_split(&kv, para, " \t", "=", 0);
165  if ( kvlen == -1 )
166   return emul_rplay_send_error(client, NULL, vio, NULL, 0, "Can not parse parameter list");
167 }
168
169 for (cmd = emul_rplay_commands; cmd->name != NULL; cmd++) {
170  if ( !strcasecmp(cmd->name, command) )
171   break;
172 }
173
174 if ( cmd->name == NULL )
175  return emul_rplay_send_error(client, NULL, vio, kv, kvlen, "unknown command");
176
177 if ( cmd->handler == NULL )
178  return emul_rplay_send_error(client, cmd, vio, kv, kvlen, "unsupported command");
179
180 return cmd->handler(client, cmd, vio, kv, kvlen);
181}
182
183int emul_rplay_send_error    (int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen, const char * msg) {
184 struct roar_keyval * kvr;
185 const char * command;
186 const char * cd = NULL;
187
188 if ( cmd != NULL ) {
189  command = cmd->name;
190 } else {
191  command = "(unknown)";
192 }
193
194 if ( kv != NULL ) {
195  kvr = roar_keyval_lookup(kv, "client-data", kvlen, 0);
196  if ( kvr != NULL )
197   cd = kvr->value;
198 }
199
200 if ( cd == NULL )
201  cd = "";
202
203 return roar_vio_printf(vio, "-error=\"%s\" command=\"%s\" client-data=\"%s\"\n", msg, command, cd) <= 0 ? -1 : 0;
204}
205
206
207int emul_rplay_on_status(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
208 const char * hostname  = "localhost";
209 const char * version   = "RoarAudio";
210       char   uptime[16];
211 const char * byteorder = "native";
212       int    fragsize  = ROAR_OUTPUT_CALC_OUTBUFSIZE(g_sa);
213       int    h, m, s;
214
215 s  = g_pos / g_sa->rate / g_sa->channels;
216 h  = s / 3600;
217 s -= h * 3600;
218 m  = s / 60;
219 s -= m * 60;
220
221 snprintf(uptime, sizeof(uptime)-1, "%.2i:%.2i:%.2i", h, m, s);
222 uptime[sizeof(uptime)-1] = 0;
223
224 switch (ROAR_CODEC_BYTE_ORDER(g_sa->codec)) {
225  case ROAR_CODEC_LE:
226    byteorder = "little-endian";
227   break;
228  case ROAR_CODEC_BE:
229    byteorder = "big-endian";
230   break;
231  case ROAR_CODEC_PDP:
232    byteorder = "pdp-endian";
233   break;
234 }
235
236 roar_vio_printf(vio,
237                 "+host=%s version=%s uptime=%s "
238                 "audio-bits=%i audio-byte-order=%s audio-channels=%i "
239                 "audio-device=internal-mixer "
240                 "audio-format=linear-%i "
241                 "audio-fragsize=%i "
242                 "audio-port=speaker,headphone,lineout audio-rate=10 "
243                 "audio-sample-rate=%i "
244                 "volume=254 "
245                 "curr-rate=10 priority-threshold=0 audio-close=0 audio-device-status=open"
246                 "\n",
247                      hostname, version, uptime,
248                      g_sa->bits, byteorder, g_sa->channels,
249                      g_sa->bits,
250                      fragsize,
251                      g_sa->rate
252                );
253
254 return 0;
255}
256
257
258int emul_rplay_on_quit(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
259 clients_delete(client);
260 return -1;
261}
262
263int emul_rplay_on_help(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
264 struct emul_rplay_command * c;
265
266 roar_vio_printf(vio, "+message=\"command summary\" command=help\n");
267
268 for (c = emul_rplay_commands; c->name != NULL; c++) {
269  roar_vio_printf(vio, "%-8s %s\n", c->name, c->usage == NULL ? "" : c->usage);
270 }
271
272 roar_vio_printf(vio, ".\n");
273
274 return -1;
275}
276
277
278int emul_rplay_on_play(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
279 struct roar_keyval        * kvr, * rate, * bits, * channels, * format, * byteorder;
280 struct roar_audio_info      info;
281 struct roar_stream_server * ss;
282 struct roar_stream        *  s;
283 int stream;
284 int bo = -1;
285 char * cd = NULL;
286
287 if ( (kvr = roar_keyval_lookup(kv, "input", kvlen, 0)) == NULL ) {
288  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no input parameter");
289  return -1;
290 }
291
292 if ( !!strcasecmp(kvr->value, "flow") ) {
293  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "non-flow input not supported");
294  return -1;
295 }
296
297/*
298               "input-format=%s input-sample-rate=%d input-bits=%d "
299               "input-channels=%d input-byte-order=%s",
300*/
301
302 rate      = roar_keyval_lookup(kv, "input-sample-rate", kvlen, 0);
303 bits      = roar_keyval_lookup(kv, "input-bits",        kvlen, 0);
304 channels  = roar_keyval_lookup(kv, "input-channels",    kvlen, 0);
305 format    = roar_keyval_lookup(kv, "input-format",      kvlen, 0);
306 byteorder = roar_keyval_lookup(kv, "input-byte-order",  kvlen, 0);
307
308 if ( rate == NULL || bits == NULL || channels == NULL || format == NULL || byteorder == NULL ) {
309  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "missing audio parameter");
310  return -1;
311 }
312
313 info.rate     = atoi(rate->value);
314 info.bits     = atoi(bits->value);
315 info.channels = atoi(channels->value);
316
317 if ( !strcasecmp(byteorder->value, "big-endian") || !strcasecmp(byteorder->value, "big") ) {
318  bo = ROAR_BYTEORDER_BE;
319 } else if ( !strcasecmp(byteorder->value, "little-endian") || !strcasecmp(byteorder->value, "little") ) {
320  bo = ROAR_BYTEORDER_LE;
321 } else if ( !strcasecmp(byteorder->value, "pdp-endian") || !strcasecmp(byteorder->value, "pdp") ) {
322  bo = ROAR_BYTEORDER_PDP;
323 } else {
324  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "unknown byte order");
325  return -1;
326 }
327
328 info.codec = format_to_codec(format->value, bo);
329
330 if ((stream = streams_new()) == -1 ) {
331  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not create new stream");
332  return -1;
333 }
334
335 if ( streams_get(stream, &ss) == -1 ) {
336  streams_delete(stream);
337  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not get stream object");
338  return -1;
339 }
340
341 s = ROAR_STREAM(ss);
342
343 if ( client_stream_add(client, stream) == -1 ) {
344  streams_delete(stream);
345  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not add stream to client");
346  return -1;
347 }
348
349 memcpy(&(s->info), &info, sizeof(info));
350 ss->codec_orgi = s->info.codec;
351
352 if ( streams_set_dir(stream, ROAR_DIR_PLAY, 1) == -1 ) {
353  streams_delete(stream);
354  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not set dir on stream");
355  return -1;
356 }
357
358 if ( (kvr = roar_keyval_lookup(kv, "client-data", kvlen, 0)) != NULL ) {
359  cd = kvr->value;
360 }
361
362 if ( cd == NULL )
363  cd = "";
364
365//        connection_reply(c, "%cid=#%d sound=\"%s\" command=%s client-data=\"%s\" list-name=\"%s\"",
366// roar_vio_printf(vio, "+id=#%i sound=\"%s\" command=%s client-data=\"%s\" list-name=\"%s\"");
367 roar_vio_printf(vio, "+id=#%i command=%s client-data=\"%s\"\n", stream, "play", cd);
368
369 return 0;
370}
371
372int emul_rplay_on_put(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
373 struct roar_keyval * kvr;
374 int stream;
375 size_t len;
376 char * cd = NULL;
377
378//23:00 < ph3-der-loewe>   rptp_putline(flow_fd, "put id=#%d size=0", spool_id);
379 if ( (kvr = roar_keyval_lookup(kv, "id", kvlen, 0)) == NULL ) {
380  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no id parameter");
381  return -1;
382 }
383
384 stream = atoi(kvr->value+1);
385
386 if ( (kvr = roar_keyval_lookup(kv, "size", kvlen, 0)) == NULL ) {
387  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no size parameter");
388  return -1;
389 }
390
391 len = atoi(kvr->value);
392
393 if ( len != 0 ) {
394  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "currently only zero size put supported");
395  return -1;
396 }
397
398 if ( client_stream_exec(client, stream) == -1 ) {
399  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not exec stream");
400  return -1;
401 }
402
403
404 if ( (kvr = roar_keyval_lookup(kv, "client-data", kvlen, 0)) != NULL ) {
405  cd = kvr->value;
406 }
407
408 if ( cd == NULL )
409  cd = "";
410
411/*
412        connection_reply(c, "%cid=#%d size=%d command=put client-data=\"%s\"",
413                         RPTP_OK, spool_id, sound_size, client_data);
414*/
415 roar_vio_printf(vio, "+id=#%i command=%s client-data=\"%s\"\n", stream, "put", cd);
416
417 return 0;
418}
419
420int emul_rplay_on_set(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen);
421int emul_rplay_on_modify(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen);
422
423int emul_rplay_on_pause(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
424 struct roar_keyval * kvr;
425 int stream;
426 char * cd = NULL;
427
428 if ( kvlen < 1 ) {
429  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no id parameter");
430  return -1;
431 }
432
433 stream = atoi(kv->key+1);
434
435 if ( streams_set_flag(stream, ROAR_FLAG_PAUSE) == -1 ) {
436  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not set pause flag");
437  return -1;
438 }
439
440 if ( (kvr = roar_keyval_lookup(kv, "client-data", kvlen, 0)) != NULL ) {
441  cd = kvr->value;
442 }
443
444 if ( cd == NULL )
445  cd = "";
446
447 roar_vio_printf(vio, "+id=#%i command=%s client-data=\"%s\"\n", stream, "pause", cd);
448
449 return 0;
450}
451
452int emul_rplay_on_continue(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
453 struct roar_keyval * kvr;
454 int stream;
455 char * cd = NULL;
456
457 if ( kvlen < 1 ) {
458  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no id parameter");
459  return -1;
460 }
461
462 stream = atoi(kv->key+1);
463
464 if ( streams_reset_flag(stream, ROAR_FLAG_PAUSE) == -1 ) {
465  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not reset pause flag");
466  return -1;
467 }
468
469 if ( (kvr = roar_keyval_lookup(kv, "client-data", kvlen, 0)) != NULL ) {
470  cd = kvr->value;
471 }
472
473 if ( cd == NULL )
474  cd = "";
475
476 roar_vio_printf(vio, "+id=#%i command=%s client-data=\"%s\"\n", stream, "coninue", cd);
477
478 return 0;
479}
480
481int emul_rplay_on_stop(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen);
482
483#endif
484
485//ll
Note: See TracBrowser for help on using the repository browser.