source: roaraudio/plugins/roard/protocol-rplay.c @ 5823:f9f70dbaa376

Last change on this file since 5823:f9f70dbaa376 was 5823:f9f70dbaa376, checked in by phi, 11 years ago

updated copyright

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