source: roaraudio/plugins/roard/protocol-rplay.c @ 5739:2a1671d592b9

Last change on this file since 5739:2a1671d592b9 was 5739:2a1671d592b9, checked in by phi, 11 years ago

commit 0: make protocol emulations for esd, gopher and rplay more independed so they can be moved into plugins easily (See: #311)

File size: 16.2 KB
Line 
1//emul_rplay.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2012
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 {
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 int 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 if ( emul_rplay_on_status(client, NULL, vio, NULL, 0) == -1 )
140  return -1;
141
142 return 0;
143}
144
145static 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) {
146 char buf[1024];
147 ssize_t len;
148
149 if ( client == -1 )
150  return -1;
151
152 if ( (len = roar_vio_read(vio, buf, sizeof(buf)-1)) <= 0 ) {
153  // really bad protocol error
154  return -1;
155 }
156
157 for (; buf[len-1] == '\r' || buf[len-1] == '\n'; len--);
158
159 buf[len] = 0;
160
161 return emul_rplay_exec_command(client, vio, buf);
162}
163
164int emul_rplay_exec_command  (int client, struct roar_vio_calls * vio, char * command) {
165 struct emul_rplay_command * cmd;
166 struct roar_keyval * kv;
167 ssize_t kvlen;
168 char * para = NULL;
169 char * c;
170 int last_was_space = 0;
171
172 for (c = command; *c != 0; c++) {
173  if ( *c == ' ' || *c == '\t' ) {
174   last_was_space = 1;
175   *c = 0;
176  } else {
177   if ( last_was_space ) {
178    para = c;
179    break;
180   }
181  }
182 }
183
184 if ( para == NULL ) {
185  kv = NULL;
186  kvlen = 0;
187 } else {
188  kvlen = roar_keyval_split(&kv, para, " \t", "=", 0);
189  if ( kvlen == -1 )
190   return emul_rplay_send_error(client, NULL, vio, NULL, 0, "Can not parse parameter list");
191 }
192
193 for (cmd = emul_rplay_commands; cmd->name != NULL; cmd++) {
194  if ( !strcasecmp(cmd->name, command) )
195   break;
196 }
197
198 if ( cmd->name == NULL )
199  return emul_rplay_send_error(client, NULL, vio, kv, kvlen, "unknown command");
200
201 if ( cmd->handler == NULL )
202  return emul_rplay_send_error(client, cmd, vio, kv, kvlen, "unsupported command");
203
204 return cmd->handler(client, cmd, vio, kv, kvlen);
205}
206
207int 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) {
208 struct roar_keyval * kvr;
209 const char * command;
210 const char * cd = NULL;
211
212 if ( cmd != NULL ) {
213  command = cmd->name;
214 } else {
215  command = "(unknown)";
216 }
217
218 if ( kv != NULL ) {
219  kvr = roar_keyval_lookup(kv, "client-data", kvlen, 0);
220  if ( kvr != NULL )
221   cd = kvr->value;
222 }
223
224 if ( cd == NULL )
225  cd = "";
226
227 return roar_vio_printf(vio, "-error=\"%s\" command=\"%s\" client-data=\"%s\"\n", msg, command, cd) <= 0 ? -1 : 0;
228}
229
230
231int emul_rplay_on_status(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
232 const char * hostname  = "localhost";
233 const char * version   = "RoarAudio";
234       char   uptime[16];
235 const char * byteorder = "native";
236       int    fragsize  = ROAR_OUTPUT_CALC_OUTBUFSIZE(g_sa);
237       int    h, m, s;
238
239 s  = g_pos / g_sa->rate / g_sa->channels;
240 h  = s / 3600;
241 s -= h * 3600;
242 m  = s / 60;
243 s -= m * 60;
244
245 snprintf(uptime, sizeof(uptime)-1, "%.2i:%.2i:%.2i", h, m, s);
246 uptime[sizeof(uptime)-1] = 0;
247
248 switch (ROAR_CODEC_BYTE_ORDER(g_sa->codec)) {
249  case ROAR_CODEC_LE:
250    byteorder = "little-endian";
251   break;
252  case ROAR_CODEC_BE:
253    byteorder = "big-endian";
254   break;
255  case ROAR_CODEC_PDP:
256    byteorder = "pdp-endian";
257   break;
258 }
259
260 roar_vio_printf(vio,
261                 "+host=%s version=%s uptime=%s "
262                 "audio-bits=%i audio-byte-order=%s audio-channels=%i "
263                 "audio-device=internal-mixer "
264                 "audio-format=linear-%i "
265                 "audio-fragsize=%i "
266                 "audio-port=speaker,headphone,lineout audio-rate=10 "
267                 "audio-sample-rate=%i "
268                 "volume=254 "
269                 "curr-rate=10 priority-threshold=0 audio-close=0 audio-device-status=open"
270                 "\n",
271                      hostname, version, uptime,
272                      g_sa->bits, byteorder, g_sa->channels,
273                      g_sa->bits,
274                      fragsize,
275                      g_sa->rate
276                );
277
278 return 0;
279}
280
281
282static int emul_rplay_on_quit(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
283 return -1;
284}
285
286static int emul_rplay_on_help(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
287 struct emul_rplay_command * c;
288
289 roar_vio_printf(vio, "+message=\"command summary\" command=help\n");
290
291 for (c = emul_rplay_commands; c->name != NULL; c++) {
292  roar_vio_printf(vio, "%-8s %s\n", c->name, c->usage == NULL ? "" : c->usage);
293 }
294
295 roar_vio_printf(vio, ".\n");
296
297 return -1;
298}
299
300
301static int emul_rplay_on_play(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
302 struct roar_keyval        * kvr, * rate, * bits, * channels, * format, * byteorder;
303 struct roar_audio_info      info;
304 struct roar_stream_server * ss;
305 struct roar_stream        *  s;
306 int stream;
307 int bo = -1;
308 char * cd = NULL;
309
310 if ( (kvr = roar_keyval_lookup(kv, "input", kvlen, 0)) == NULL ) {
311  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no input parameter");
312  return -1;
313 }
314
315 if ( !!strcasecmp(kvr->value, "flow") ) {
316  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "non-flow input not supported");
317  return -1;
318 }
319
320/*
321               "input-format=%s input-sample-rate=%d input-bits=%d "
322               "input-channels=%d input-byte-order=%s",
323*/
324
325 rate      = roar_keyval_lookup(kv, "input-sample-rate", kvlen, 0);
326 bits      = roar_keyval_lookup(kv, "input-bits",        kvlen, 0);
327 channels  = roar_keyval_lookup(kv, "input-channels",    kvlen, 0);
328 format    = roar_keyval_lookup(kv, "input-format",      kvlen, 0);
329 byteorder = roar_keyval_lookup(kv, "input-byte-order",  kvlen, 0);
330
331 if ( rate == NULL || bits == NULL || channels == NULL || format == NULL || byteorder == NULL ) {
332  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "missing audio parameter");
333  return -1;
334 }
335
336 info.rate     = atoi(rate->value);
337 info.bits     = atoi(bits->value);
338 info.channels = atoi(channels->value);
339
340 if ( !strcasecmp(byteorder->value, "big-endian") || !strcasecmp(byteorder->value, "big") ) {
341  bo = ROAR_BYTEORDER_BE;
342 } else if ( !strcasecmp(byteorder->value, "little-endian") || !strcasecmp(byteorder->value, "little") ) {
343  bo = ROAR_BYTEORDER_LE;
344 } else if ( !strcasecmp(byteorder->value, "pdp-endian") || !strcasecmp(byteorder->value, "pdp") ) {
345  bo = ROAR_BYTEORDER_PDP;
346 } else {
347  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "unknown byte order");
348  return -1;
349 }
350
351 info.codec = format_to_codec(format->value, bo);
352
353 if ((stream = streams_new()) == -1 ) {
354  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not create new stream");
355  return -1;
356 }
357
358 if ( streams_get(stream, &ss) == -1 ) {
359  streams_delete(stream);
360  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not get stream object");
361  return -1;
362 }
363
364 s = ROAR_STREAM(ss);
365
366 if ( client_stream_add(client, stream) == -1 ) {
367  streams_delete(stream);
368  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not add stream to client");
369  return -1;
370 }
371
372 memcpy(&(s->info), &info, sizeof(info));
373 ss->codec_orgi = s->info.codec;
374
375 if ( streams_set_dir(stream, ROAR_DIR_PLAY, 1) == -1 ) {
376  streams_delete(stream);
377  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not set dir on stream");
378  return -1;
379 }
380
381 if ( (kvr = roar_keyval_lookup(kv, "client-data", kvlen, 0)) != NULL ) {
382  cd = kvr->value;
383 }
384
385 if ( cd == NULL )
386  cd = "";
387
388//        connection_reply(c, "%cid=#%d sound=\"%s\" command=%s client-data=\"%s\" list-name=\"%s\"",
389// roar_vio_printf(vio, "+id=#%i sound=\"%s\" command=%s client-data=\"%s\" list-name=\"%s\"");
390 roar_vio_printf(vio, "+id=#%i command=%s client-data=\"%s\"\n", stream, "play", cd);
391
392 return 0;
393}
394
395static int emul_rplay_on_put(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
396 struct roar_keyval * kvr;
397 int stream;
398 size_t len;
399 char * cd = NULL;
400
401//23:00 < ph3-der-loewe>   rptp_putline(flow_fd, "put id=#%d size=0", spool_id);
402 if ( (kvr = roar_keyval_lookup(kv, "id", kvlen, 0)) == NULL ) {
403  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no id parameter");
404  return -1;
405 }
406
407 stream = atoi(kvr->value+1);
408
409 if ( (kvr = roar_keyval_lookup(kv, "size", kvlen, 0)) == NULL ) {
410  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no size parameter");
411  return -1;
412 }
413
414 len = atoi(kvr->value);
415
416 if ( len != 0 ) {
417  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "currently only zero size put supported");
418  return -1;
419 }
420
421 if ( client_stream_exec(client, stream) == -1 ) {
422  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not exec stream");
423  return -1;
424 }
425
426
427 if ( (kvr = roar_keyval_lookup(kv, "client-data", kvlen, 0)) != NULL ) {
428  cd = kvr->value;
429 }
430
431 if ( cd == NULL )
432  cd = "";
433
434/*
435        connection_reply(c, "%cid=#%d size=%d command=put client-data=\"%s\"",
436                         RPTP_OK, spool_id, sound_size, client_data);
437*/
438 roar_vio_printf(vio, "+id=#%i command=%s client-data=\"%s\"\n", stream, "put", cd);
439
440 return 0;
441}
442
443//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);
444//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);
445
446static int emul_rplay_on_pause(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
447 struct roar_keyval * kvr;
448 int stream;
449 char * cd = NULL;
450
451 if ( kvlen < 1 ) {
452  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no id parameter");
453  return -1;
454 }
455
456 stream = atoi(kv->key+1);
457
458 if ( streams_set_flag(stream, ROAR_FLAG_PAUSE) == -1 ) {
459  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not set pause flag");
460  return -1;
461 }
462
463 if ( (kvr = roar_keyval_lookup(kv, "client-data", kvlen, 0)) != NULL ) {
464  cd = kvr->value;
465 }
466
467 if ( cd == NULL )
468  cd = "";
469
470 roar_vio_printf(vio, "+id=#%i command=%s client-data=\"%s\"\n", stream, "pause", cd);
471
472 return 0;
473}
474
475static int emul_rplay_on_continue(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
476 struct roar_keyval * kvr;
477 int stream;
478 char * cd = NULL;
479
480 if ( kvlen < 1 ) {
481  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no id parameter");
482  return -1;
483 }
484
485 stream = atoi(kv->key+1);
486
487 if ( streams_reset_flag(stream, ROAR_FLAG_PAUSE) == -1 ) {
488  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not reset pause flag");
489  return -1;
490 }
491
492 if ( (kvr = roar_keyval_lookup(kv, "client-data", kvlen, 0)) != NULL ) {
493  cd = kvr->value;
494 }
495
496 if ( cd == NULL )
497  cd = "";
498
499 roar_vio_printf(vio, "+id=#%i command=%s client-data=\"%s\"\n", stream, "coninue", cd);
500
501 return 0;
502}
503
504//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);
505
506struct roar_dl_proto __proto_common_rplay = {
507 .proto = ROAR_PROTO_RPLAY,
508 .description = "RPlay emulation",
509 .flags = ROAR_DL_PROTO_FLAGS_NONE,
510 .set_proto = emul_rplay_set_proto,
511 .handle = emul_rplay_check_client
512};
513
514#endif
515
516//ll
Note: See TracBrowser for help on using the repository browser.