source: roaraudio/plugins/roard/protocol-rplay.c @ 3988:2bba9fc40cb0

Last change on this file since 3988:2bba9fc40cb0 was 3988:2bba9fc40cb0, checked in by phi, 14 years ago

added support for pause and continue

File size: 13.6 KB
Line 
1//emul_rplay.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010
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 sprintf(uptime, "%.2i:%.2i:%.2i", h, m, s);
222
223 switch (ROAR_CODEC_BYTE_ORDER(g_sa->codec)) {
224  case ROAR_CODEC_LE:
225    byteorder = "little-endian";
226   break;
227  case ROAR_CODEC_BE:
228    byteorder = "big-endian";
229   break;
230  case ROAR_CODEC_PDP:
231    byteorder = "pdp-endian";
232   break;
233 }
234
235 roar_vio_printf(vio,
236                 "+host=%s version=%s uptime=%s "
237                 "audio-bits=%i audio-byte-order=%s audio-channels=%i "
238                 "audio-device=internal-mixer "
239                 "audio-format=linear-%i "
240                 "audio-fragsize=%i "
241                 "audio-port=speaker,headphone,lineout audio-rate=10 "
242                 "audio-sample-rate=%i "
243                 "volume=254 "
244                 "curr-rate=10 priority-threshold=0 audio-close=0 audio-device-status=open"
245                 "\n",
246                      hostname, version, uptime,
247                      g_sa->bits, byteorder, g_sa->channels,
248                      g_sa->bits,
249                      fragsize,
250                      g_sa->rate
251                );
252
253 return 0;
254}
255
256
257int emul_rplay_on_quit(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
258 clients_delete(client);
259 return -1;
260}
261
262int emul_rplay_on_help(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
263 struct emul_rplay_command * c;
264
265 roar_vio_printf(vio, "+message=\"command summary\" command=help\n");
266
267 for (c = emul_rplay_commands; c->name != NULL; c++) {
268  roar_vio_printf(vio, "%-8s %s\n", c->name, c->usage == NULL ? "" : c->usage);
269 }
270
271 roar_vio_printf(vio, ".\n");
272
273 return -1;
274}
275
276
277int emul_rplay_on_play(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
278 struct roar_keyval        * kvr, * rate, * bits, * channels, * format, * byteorder;
279 struct roar_audio_info      info;
280 struct roar_stream_server * ss;
281 struct roar_stream        *  s;
282 int stream;
283 int bo = -1;
284 char * cd = NULL;
285
286 if ( (kvr = roar_keyval_lookup(kv, "input", kvlen, 0)) == NULL ) {
287  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no input parameter");
288  return -1;
289 }
290
291 if ( !!strcasecmp(kvr->value, "flow") ) {
292  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "non-flow input not supported");
293  return -1;
294 }
295
296/*
297               "input-format=%s input-sample-rate=%d input-bits=%d "
298               "input-channels=%d input-byte-order=%s",
299*/
300
301 rate      = roar_keyval_lookup(kv, "input-sample-rate", kvlen, 0);
302 bits      = roar_keyval_lookup(kv, "input-bits",        kvlen, 0);
303 channels  = roar_keyval_lookup(kv, "input-channels",    kvlen, 0);
304 format    = roar_keyval_lookup(kv, "input-format",      kvlen, 0);
305 byteorder = roar_keyval_lookup(kv, "input-byte-order",  kvlen, 0);
306
307 if ( rate == NULL || bits == NULL || channels == NULL || format == NULL || byteorder == NULL ) {
308  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "missing audio parameter");
309  return -1;
310 }
311
312 info.rate     = atoi(rate->value);
313 info.bits     = atoi(bits->value);
314 info.channels = atoi(channels->value);
315
316 if ( !strcasecmp(byteorder->value, "big-endian") || !strcasecmp(byteorder->value, "big") ) {
317  bo = ROAR_BYTEORDER_BE;
318 } else if ( !strcasecmp(byteorder->value, "little-endian") || !strcasecmp(byteorder->value, "little") ) {
319  bo = ROAR_BYTEORDER_LE;
320 } else if ( !strcasecmp(byteorder->value, "pdp-endian") || !strcasecmp(byteorder->value, "pdp") ) {
321  bo = ROAR_BYTEORDER_PDP;
322 } else {
323  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "unknown byte order");
324  return -1;
325 }
326
327 info.codec = format_to_codec(format->value, bo);
328
329 if ((stream = streams_new()) == -1 ) {
330  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not create new stream");
331  return -1;
332 }
333
334 if ( streams_get(stream, &ss) == -1 ) {
335  streams_delete(stream);
336  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not get stream object");
337  return -1;
338 }
339
340 s = ROAR_STREAM(ss);
341
342 if ( client_stream_add(client, stream) == -1 ) {
343  streams_delete(stream);
344  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not add stream to client");
345  return -1;
346 }
347
348 memcpy(&(s->info), &info, sizeof(info));
349 ss->codec_orgi = s->info.codec;
350
351 if ( streams_set_dir(stream, ROAR_DIR_PLAY, 1) == -1 ) {
352  streams_delete(stream);
353  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not set dir on stream");
354  return -1;
355 }
356
357 if ( (kvr = roar_keyval_lookup(kv, "client-data", kvlen, 0)) != NULL ) {
358  cd = kvr->value;
359 }
360
361 if ( cd == NULL )
362  cd = "";
363
364//        connection_reply(c, "%cid=#%d sound=\"%s\" command=%s client-data=\"%s\" list-name=\"%s\"",
365// roar_vio_printf(vio, "+id=#%i sound=\"%s\" command=%s client-data=\"%s\" list-name=\"%s\"");
366 roar_vio_printf(vio, "+id=#%i command=%s client-data=\"%s\"\n", stream, "play", cd);
367
368 return 0;
369}
370
371int emul_rplay_on_put(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
372 struct roar_keyval * kvr;
373 int stream;
374 size_t len;
375 char * cd = NULL;
376
377//23:00 < ph3-der-loewe>   rptp_putline(flow_fd, "put id=#%d size=0", spool_id);
378 if ( (kvr = roar_keyval_lookup(kv, "id", kvlen, 0)) == NULL ) {
379  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no id parameter");
380  return -1;
381 }
382
383 stream = atoi(kvr->value+1);
384
385 if ( (kvr = roar_keyval_lookup(kv, "size", kvlen, 0)) == NULL ) {
386  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no size parameter");
387  return -1;
388 }
389
390 len = atoi(kvr->value);
391
392 if ( len != 0 ) {
393  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "currently only zero size put supported");
394  return -1;
395 }
396
397 if ( client_stream_exec(client, stream) == -1 ) {
398  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not exec stream");
399  return -1;
400 }
401
402
403 if ( (kvr = roar_keyval_lookup(kv, "client-data", kvlen, 0)) != NULL ) {
404  cd = kvr->value;
405 }
406
407 if ( cd == NULL )
408  cd = "";
409
410/*
411        connection_reply(c, "%cid=#%d size=%d command=put client-data=\"%s\"",
412                         RPTP_OK, spool_id, sound_size, client_data);
413*/
414 roar_vio_printf(vio, "+id=#%i command=%s client-data=\"%s\"\n", stream, "put", cd);
415
416 return 0;
417}
418
419int emul_rplay_on_set(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen);
420int emul_rplay_on_modify(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen);
421
422int emul_rplay_on_pause(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
423 struct roar_keyval * kvr;
424 int stream;
425 char * cd = NULL;
426
427 if ( kvlen < 1 ) {
428  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no id parameter");
429  return -1;
430 }
431
432 stream = atoi(kv->key+1);
433
434 if ( streams_set_flag(stream, ROAR_FLAG_PAUSE) == -1 ) {
435  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not set pause flag");
436  return -1;
437 }
438
439 if ( (kvr = roar_keyval_lookup(kv, "client-data", kvlen, 0)) != NULL ) {
440  cd = kvr->value;
441 }
442
443 if ( cd == NULL )
444  cd = "";
445
446 roar_vio_printf(vio, "+id=#%i command=%s client-data=\"%s\"\n", stream, "pause", cd);
447
448 return 0;
449}
450
451int emul_rplay_on_continue(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen) {
452 struct roar_keyval * kvr;
453 int stream;
454 char * cd = NULL;
455
456 if ( kvlen < 1 ) {
457  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "no id parameter");
458  return -1;
459 }
460
461 stream = atoi(kv->key+1);
462
463 if ( streams_reset_flag(stream, ROAR_FLAG_PAUSE) == -1 ) {
464  emul_rplay_send_error(client, cmd, vio, kv, kvlen, "can not reset pause flag");
465  return -1;
466 }
467
468 if ( (kvr = roar_keyval_lookup(kv, "client-data", kvlen, 0)) != NULL ) {
469  cd = kvr->value;
470 }
471
472 if ( cd == NULL )
473  cd = "";
474
475 roar_vio_printf(vio, "+id=#%i command=%s client-data=\"%s\"\n", stream, "coninue", cd);
476
477 return 0;
478}
479
480int emul_rplay_on_stop(int client, struct emul_rplay_command * cmd, struct roar_vio_calls * vio, struct roar_keyval * kv, size_t kvlen);
481
482#endif
483
484//ll
Note: See TracBrowser for help on using the repository browser.