source: roaraudio/libroar/ctl.c @ 5608:584b36c566e2

Last change on this file since 5608:584b36c566e2 was 5608:584b36c566e2, checked in by phi, 12 years ago

Handle super long client names well (Closes: #286)

File size: 22.5 KB
Line 
1//ctl.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2012
5 *
6 *  This file is part of libroar 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 *  libroar 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 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "libroar.h"
37
38int roar_get_clientid  (struct roar_connection * con) {
39 struct roar_message mes;
40
41 memset(&mes, 0, sizeof(struct roar_message)); // make valgrind happy!
42
43 mes.cmd     = ROAR_CMD_WHOAMI;
44 mes.stream  = -1;
45 mes.datalen =  0;
46
47 if ( roar_req(con, &mes, NULL) == -1 )
48  return -1;
49
50 if ( mes.cmd != ROAR_CMD_OK )
51  return -1;
52
53 if ( mes.datalen != 1 )
54  return -1;
55
56 return mes.data[0];
57}
58
59int roar_server_oinfo  (struct roar_connection * con, struct roar_stream * s, int dir) {
60 struct roar_message mes;
61
62 memset(&mes, 0, sizeof(struct roar_message)); // make valgrind happy!
63
64 mes.cmd     = ROAR_CMD_SERVER_OINFO;
65
66 if ( dir == -1 ) {
67  mes.datalen = 0;
68 } else {
69  mes.datalen = 2;
70  mes.data[0] = 0;
71  mes.data[1] = dir;
72 }
73
74 if ( roar_req(con, &mes, NULL) == -1 )
75  return -1;
76
77 if ( mes.cmd != ROAR_CMD_OK )
78  return -1;
79
80 if ( roar_stream_m2s(s, &mes) == -1 )
81  return -1;
82
83 return 0;
84}
85
86int roar_get_standby   (struct roar_connection * con) {
87 struct roar_message mes;
88
89 memset(&mes, 0, sizeof(struct roar_message)); // make valgrind happy!
90
91 mes.cmd = ROAR_CMD_GET_STANDBY;
92 mes.stream  = -1;
93 mes.datalen =  0;
94
95 if ( roar_req(con, &mes, NULL) == -1 )
96  return -1;
97
98 if ( mes.cmd != ROAR_CMD_OK )
99  return -1;
100
101 return ROAR_NET2HOST16(*((uint16_t*)mes.data));
102}
103
104int roar_set_standby   (struct roar_connection * con, int state) {
105 struct roar_message mes;
106
107 memset(&mes, 0, sizeof(struct roar_message)); // make valgrind happy!
108
109 mes.cmd = ROAR_CMD_SET_STANDBY;
110 mes.stream  = -1;
111 mes.datalen =  2;
112
113 *((uint16_t*)mes.data) = ROAR_HOST2NET16((unsigned) state);
114
115 if ( roar_req(con, &mes, NULL) == -1 )
116  return -1;
117
118 if ( mes.cmd != ROAR_CMD_OK )
119  return -1;
120
121 return 0;
122}
123
124int roar_terminate (struct roar_connection * con, int terminate) {
125 struct roar_message mes;
126
127 memset(&mes, 0, sizeof(struct roar_message)); // make valgrind happy!
128
129 mes.cmd     = ROAR_CMD_EXIT;
130 mes.stream  = -1;
131 mes.datalen =  1;
132 mes.data[0] = terminate;
133
134 if ( roar_req(con, &mes, NULL) == -1 )
135  return -1;
136
137 if ( mes.cmd != ROAR_CMD_OK )
138  return -1;
139
140 return 0;
141}
142
143int roar_list_filtered(struct roar_connection * con, int * items,   int max, int cmd, unsigned char filter, unsigned char cmp, uint32_t id) {
144 struct roar_message m;
145
146 memset(&m, 0, sizeof(struct roar_message)); // make valgrind happy!
147
148 roar_ctl_f2m(&m, filter, cmp, id);
149 m.cmd = cmd;
150
151 if ( roar_req(con, &m, NULL) == -1 )
152  return -1;
153
154 return roar_ctl_m2ia(&m, items, max);
155}
156
157int roar_list         (struct roar_connection * con, int * items,   int max, int cmd) {
158 return roar_list_filtered(con, items, max, cmd, ROAR_CTL_FILTER_ANY, ROAR_CTL_CMP_ANY, ROAR_CTL_FILTER_ANY);
159}
160
161int roar_get_client   (struct roar_connection * con, struct roar_client * client, int id) {
162 struct roar_message m;
163 char * data = NULL;
164 int ret;
165
166 memset(&m, 0, sizeof(struct roar_message)); // make valgrind happy!
167
168 m.cmd     = ROAR_CMD_GET_CLIENT;
169 m.stream  = -1;
170 m.datalen =  1;
171 m.data[0] = id;
172
173 ROAR_DBG("roar_get_client(*): id = %i", id);
174
175 if ( roar_req(con, &m, &data) == -1 )
176  return -1;
177
178 if ( m.cmd != ROAR_CMD_OK )
179  return -1;
180
181 ROAR_DBG("roar_get_client(*): got ok");
182
183 ret = roar_ctl_m2c2(&m, client, data);
184
185 if ( data != NULL )
186  roar_mm_free(data);
187
188 return ret;
189}
190
191int roar_get_stream   (struct roar_connection * con, struct roar_stream * stream, int id) {
192 struct roar_message m;
193
194 memset(&m, 0, sizeof(struct roar_message)); // make valgrind happy!
195
196 m.cmd     = ROAR_CMD_GET_STREAM;
197 m.datalen = 1;
198 m.data[0] = id;
199
200 roar_err_set(ROAR_ERROR_UNKNOWN);
201
202 if ( roar_req(con, &m, NULL) == -1 ) {
203  roar_err_set(ROAR_ERROR_PROTO);
204  return -1;
205 }
206
207 if ( m.cmd != ROAR_CMD_OK )
208  return -1;
209
210 return roar_stream_m2s(stream, &m);
211}
212
213int roar_kick         (struct roar_connection * con, int type, int id) {
214 struct roar_message m;
215 uint16_t * info = (uint16_t *) m.data;
216
217 memset(&m, 0, sizeof(struct roar_message)); // make valgrind happy!
218
219 m.cmd     = ROAR_CMD_KICK;
220 m.datalen = 4;
221 info[0] = ROAR_HOST2NET16(type);
222 info[1] = ROAR_HOST2NET16(id);
223
224 if ( roar_req(con, &m, NULL) == -1 )
225  return -1;
226
227 if ( m.cmd != ROAR_CMD_OK )
228  return -1;
229
230 return 0;
231}
232
233int roar_set_vol     (struct roar_connection * con, int id, struct roar_mixer_settings * mixer, int   channels, int mode) {
234 struct roar_message m;
235 uint16_t * info = (uint16_t *) m.data;
236 int i;
237
238 memset(&m, 0, sizeof(struct roar_message)); // make valgrind happy!
239
240 m.cmd     = ROAR_CMD_SET_VOL;
241 m.datalen = (3 + channels) * 2;
242 m.stream  = id;
243 info[0] = ROAR_HOST2NET16(1);
244 info[1] = ROAR_HOST2NET16(mixer->scale);
245 info[2] = ROAR_HOST2NET16(mode);
246
247 for (i = 0; i < channels; i++)
248  info[i+3] = ROAR_HOST2NET16(mixer->mixer[i]);
249
250 if ( roar_req(con, &m, NULL) == -1 )
251  return -1;
252
253 if ( m.cmd != ROAR_CMD_OK )
254  return -1;
255
256 return 0;
257}
258
259int roar_get_vol      (struct roar_connection * con, int id, struct roar_mixer_settings * mixer, int * channels) {
260 struct roar_message m;
261 uint16_t * info = (uint16_t *) m.data;
262 int i;
263
264 memset(&m, 0, sizeof(struct roar_message)); // make valgrind happy!
265
266 m.cmd     = ROAR_CMD_GET_VOL;
267 m.datalen = 2*2;
268 m.stream  = id;
269
270 info[0]   = ROAR_HOST2NET16(1);
271
272 if ( roar_req(con, &m, NULL) == -1 )
273  return -1;
274
275 if ( m.cmd != ROAR_CMD_OK )
276  return -1;
277
278 if ( ROAR_NET2HOST16(info[0]) != 1 )
279  return -1;
280
281 info[1] = ROAR_NET2HOST16(info[1]);
282
283 if ( channels != NULL )
284  *channels = info[1];
285
286 if ( info[1] > ROAR_MAX_CHANNELS )
287  return -1;
288
289 mixer->scale   = ROAR_NET2HOST16(info[2]);
290 mixer->rpg_mul = ROAR_NET2HOST16(info[3]);
291 mixer->rpg_div = ROAR_NET2HOST16(info[4]);
292
293 for (i = 0; i < info[1]; i++)
294  mixer->mixer[i] = ROAR_NET2HOST16(info[i+5]);
295
296 return 0;
297}
298
299// converts: *_m2*, *_*2m
300
301int roar_ctl_f2m      (struct roar_message * m, unsigned char   filter, unsigned char   cmp, uint32_t   id) {
302
303 m->datalen = 7;
304
305 m->data[0] = 0;
306 m->data[1] = filter;
307 m->data[2] = cmp;
308 m->data[3] = (id & 0xFF000000LU) >> 24;
309 m->data[4] = (id & 0x00FF0000LU) >> 16;
310 m->data[5] = (id & 0x0000FF00LU) >>  8;
311 m->data[6] = (id & 0x000000FFLU) >>  0;
312
313 return 0;
314}
315int roar_ctl_m2f      (struct roar_message * m, unsigned char * filter, unsigned char * cmp, uint32_t * id) {
316 register uint32_t idreg;
317
318 if ( m->datalen != 7 )
319  return -1;
320
321 if ( m->data[0] != 0 ) {
322  ROAR_DBG("roar_ctl_m2f(*): version %i not supported!", (int)m->data[0]);
323  roar_err_set(ROAR_ERROR_NSVERSION);
324  return -1;
325 }
326
327 *filter = m->data[1];
328 *cmp    = m->data[2];
329
330 idreg   = ((uint32_t)(unsigned char)m->data[3]) << 24;
331 idreg  |= ((uint32_t)(unsigned char)m->data[4]) << 16;
332 idreg  |= ((uint32_t)(unsigned char)m->data[5]) <<  8;
333 idreg  |= ((uint32_t)(unsigned char)m->data[6]) <<  0;
334 *id     = idreg;
335
336 return 0;
337}
338
339int roar_filter_match (const unsigned cmp, const uint32_t a, const uint32_t b) {
340 switch (cmp) {
341  case ROAR_CTL_CMP_ANY:
342    return 1;
343   break;
344  case ROAR_CTL_CMP_EQ:
345    return a == b;
346   break;
347  case ROAR_CTL_CMP_NE:
348    return a != b;
349   break;
350  default:
351    roar_err_set(ROAR_ERROR_NOTSUP);
352    return -1;
353 }
354}
355
356int roar_ctl_ia2m     (struct roar_message * m, int * data, size_t len) {
357 size_t i;
358
359 if ( len > LIBROAR_BUFFER_MSGDATA ) {
360  roar_err_set(ROAR_ERROR_MSGSIZE);
361  return -1;
362 }
363
364 m->datalen = len;
365
366 for (i = 0; i < len; i++)
367  m->data[i] = data[i];
368
369 return 0;
370}
371int roar_ctl_m2ia     (struct roar_message * m, int * data, size_t len) {
372 size_t i;
373
374 if ( m->datalen > len ) {
375  roar_err_set(ROAR_ERROR_MSGSIZE);
376  return -1;
377 }
378
379 for (i = 0; i < m->datalen; i++)
380  data[i] = m->data[i];
381
382 return m->datalen;
383}
384
385int roar_ctl_c2m2     (struct roar_message * m, struct roar_client * c, void ** data) {
386 char * d;
387 size_t cur = 0;
388 int h;
389 int i;
390 int max_len;
391 uint32_t pid;
392 size_t nnode_len;
393 size_t needed_len = 3 + 5*4 + 18 /* 18 = current max size for blob */;
394
395 if ( c == NULL )
396  return -1;
397
398 if ( data != NULL )
399  *data = NULL;
400
401 max_len = strlen(c->name);
402 needed_len += max_len;
403
404 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++)
405  if ( c->streams[i] != -1 )
406   needed_len++;
407
408 if ( needed_len > sizeof(m->data) ) {
409  if ( data == NULL ) {
410   needed_len -= max_len;
411   if ( needed_len > sizeof(m->data) ) {
412    roar_panic(ROAR_FATAL_ERROR_CPU_FAILURE, "needed_len > sizeof(m->data) happend.");
413    roar_err_set(ROAR_ERROR_BADCKSUM);
414    return -1;
415   }
416   max_len = sizeof(m->data) - needed_len;
417   needed_len = sizeof(m->data);
418   d = m->data;
419  } else {
420   d = roar_mm_malloc(needed_len);
421   if ( d == NULL )
422    return -1;
423   *data = d;
424  }
425 } else {
426  d = m->data;
427 }
428
429 d[cur++] = 0;                       // 0: Version
430 d[cur++] = c->execed;               // 1: execed
431
432 h = 0;
433 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++)
434  if ( c->streams[i] != -1 )
435   d[cur+1+h++] = c->streams[i];
436
437 d[cur++] = h;                       // 2: num of streams
438 cur += h;
439
440 // TODO: add some code to check if this fits in the pkg
441 // NOTE: add this code after we are sure how long this pkg will be
442 //       and fully decieded about this function.
443
444 d[cur++] = max_len;
445
446 strncpy(d+cur, c->name, max_len);
447
448 cur += max_len;
449
450 pid = ROAR_HOST2NET32(c->pid);
451 memcpy(&(d[cur]), &pid, 4);
452 cur += 4;
453
454 pid = ROAR_HOST2NET32(c->uid);
455 memcpy(&(d[cur]), &pid, 4);
456 cur += 4;
457
458 pid = ROAR_HOST2NET32(c->gid);
459 memcpy(&(d[cur]), &pid, 4);
460 cur += 4;
461
462 pid = ROAR_HOST2NET32(c->proto);
463 memcpy(&(d[cur]), &pid, 4);
464 cur += 4;
465
466 pid = ROAR_HOST2NET32(c->byteorder);
467 memcpy(&(d[cur]), &pid, 4);
468 cur += 4;
469
470 if ( cur > needed_len ) {
471  roar_panic(ROAR_FATAL_ERROR_MEMORY_CORRUPTION, NULL);
472 }
473
474 nnode_len = needed_len - cur;
475 if ( roar_nnode_to_blob(&(c->nnode), &(d[cur]), &nnode_len) == 0 ) {
476  cur += nnode_len;
477 }
478
479 if ( cur > needed_len ) {
480  roar_panic(ROAR_FATAL_ERROR_MEMORY_CORRUPTION, NULL);
481 }
482
483 m->datalen = cur;
484
485 return 0;
486}
487
488int roar_ctl_m2c2      (struct roar_message * m, struct roar_client * c, void * data) {
489 char * d = data;
490 uint32_t pid;
491 size_t len;
492 size_t cur;
493 int i;
494
495 if ( m == NULL || c == NULL ) {
496  roar_err_set(ROAR_ERROR_FAULT);
497  return -1;
498 }
499
500 if ( m->datalen == 0 ) {
501  roar_err_set(ROAR_ERROR_MSGSIZE);
502  return -1;
503 }
504
505 if ( d == NULL ) {
506  if ( m->datalen > sizeof(m->data) ) {
507   roar_err_set(ROAR_ERROR_FAULT);
508   return -1;
509  }
510  d = m->data;
511 }
512
513 ROAR_DBG("roar_ctl_m2c(*): got data!, len = %i", m->datalen);
514
515 if ( d[0] != 0 ) {
516  ROAR_DBG("roar_ctl_m2c(*): wrong version!");
517  roar_err_set(ROAR_ERROR_NSVERSION);
518  return -1;
519 }
520
521 if ( m->datalen < 3 ) {
522  roar_err_set(ROAR_ERROR_MSGSIZE);
523  return -1;
524 }
525
526 ROAR_DBG("roar_ctl_m2c(*): have usable data!");
527
528 c->execed = d[1];
529
530 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++)
531  c->streams[i] = -1;
532
533 if ( d[2] < 0 || d[2] > ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT ) {
534  roar_err_set(ROAR_ERROR_TOOMANYARGS);
535  return -1;
536 }
537
538 for (i = 0; i < d[2]; i++)
539  c->streams[i] = d[3+i];
540
541 cur = 3 + d[2];
542
543 // check length here!
544 strncpy(c->name, d+cur+1, d[cur] > (sizeof(c->name)-1) ? sizeof(c->name)-1 : d[cur]);
545 c->name[(size_t)d[cur] > (sizeof(c->name)-1) ? sizeof(c->name)-1 : (size_t)d[cur]] = 0;
546
547 cur += d[cur] + 1;
548
549 memcpy(&pid, &(d[cur]), 4);
550 c->pid = ROAR_NET2HOST32(pid);
551 cur += 4;
552
553 memcpy(&pid, &(d[cur]), 4);
554 c->uid = ROAR_NET2HOST32(pid);
555 cur += 4;
556
557 memcpy(&pid, &(d[cur]), 4);
558 c->gid = ROAR_NET2HOST32(pid);
559 cur += 4;
560
561 if ( m->datalen >= cur+4 ) {
562  memcpy(&pid, &(d[cur]), 4);
563  c->proto = ROAR_NET2HOST32(pid);
564  cur += 4;
565 } else {
566  c->proto = ROAR_PROTO_NONE;
567 }
568
569 if ( m->datalen >= cur+4 ) {
570  memcpy(&pid, &(d[cur]), 4);
571  c->byteorder = ROAR_NET2HOST32(pid);
572  cur += 4;
573 } else {
574  c->byteorder = ROAR_BYTEORDER_UNKNOWN;
575 }
576
577 if ( m->datalen > cur ) {
578  len = m->datalen - cur;
579  if ( roar_nnode_from_blob(&(c->nnode), &(d[cur]), &len) == 0 ) {
580   cur += len;
581  } else {
582   if ( roar_nnode_new(&(c->nnode), ROAR_SOCKET_TYPE_UNKNOWN) == -1 )
583    return -1;
584  }
585 } else {
586  if ( roar_nnode_new(&(c->nnode), ROAR_SOCKET_TYPE_UNKNOWN) == -1 )
587   return -1;
588 }
589
590 return 0;
591}
592
593int roar_ctl_c2m      (struct roar_message * m, struct roar_client * c) {
594 return roar_ctl_c2m2(m, c, NULL);
595}
596int roar_ctl_m2c      (struct roar_message * m, struct roar_client * c) {
597 return roar_ctl_m2c2(m, c, NULL);
598}
599
600static struct {
601 int id;
602 const char * name;
603} _proto[] = {
604 {ROAR_PROTO_NONE,        "none"},
605 {ROAR_PROTO_ROARAUDIO,   "RoarAudio"},
606 {ROAR_PROTO_ESOUND,      "EsounD"},
607 {ROAR_PROTO_ESOUND,      "ESD"}, // alias
608 {ROAR_PROTO_AUTO,        "(auto)"},
609 {ROAR_PROTO_HTTP,        "http"},
610 {ROAR_PROTO_GOPHER,      "gopher"},
611 {ROAR_PROTO_ICY,         "ICY"},
612 {ROAR_PROTO_SIMPLE,      "Simple"},
613 {ROAR_PROTO_RSOUND,      "RSound"},
614 {ROAR_PROTO_RPLAY,       "RPlay"},
615 {ROAR_PROTO_IRC,         "IRC"},
616 {ROAR_PROTO_DCC,         "DCC"},
617 {ROAR_PROTO_ECHO,        "Echo"},
618 {ROAR_PROTO_DISCARD,     "Discard"},
619 {ROAR_PROTO_WHOIS,       "Whois"},
620 {ROAR_PROTO_FINGER,      "Finger"},
621 {ROAR_PROTO_QUOTE,       "quote"},
622 {ROAR_PROTO_DAYTIME,     "daytime"},
623 {ROAR_PROTO_GAME,        "game"},
624 {ROAR_PROTO_TELNET,      "telnet"},
625 {ROAR_PROTO_DHCP,        "dhcp"},
626 {ROAR_PROTO_SSH,         "ssh"},
627 {ROAR_PROTO_TIME,        "time"},
628 {ROAR_PROTO_RLOGIN,      "rlogin"},
629 {-1, NULL}
630};
631
632int    roar_str2proto (const char * proto) {
633 size_t i;
634
635 for (i = 0; _proto[i].id != -1; i++)
636  if ( !strcasecmp(proto, _proto[i].name) )
637   return _proto[i].id;
638
639 roar_err_set(ROAR_ERROR_NOENT);
640 return -1;
641}
642
643const char * roar_proto2str (const int    proto) {
644 size_t i;
645
646 roar_err_set(ROAR_ERROR_NONE);
647
648 for (i = 0; _proto[i].id != -1; i++)
649  if ( proto == _proto[i].id )
650   return _proto[i].name;
651
652 roar_err_set(ROAR_ERROR_NOENT);
653 return "(unknown)";
654}
655
656int    roar_str2byteorder (const char * byteorder) {
657 if (        !strcasecmp(byteorder, "le")            || !strcasecmp(byteorder, "little") ||
658             !strcasecmp(byteorder, "little endian") || !strcasecmp(byteorder, "1234")   ) {
659  return ROAR_BYTEORDER_LE;
660 } else if ( !strcasecmp(byteorder, "be")            || !strcasecmp(byteorder, "big")    ||
661             !strcasecmp(byteorder, "big endian")    || !strcasecmp(byteorder, "4321")   ) {
662  return ROAR_BYTEORDER_BE;
663 } else if ( !strcasecmp(byteorder, "pdp")           ||
664             !strcasecmp(byteorder, "pdp endian") ) {
665  return ROAR_BYTEORDER_PDP;
666 } else if ( !strcasecmp(byteorder, "network")       ||
667             !strcasecmp(byteorder, "network byteorder") ) {
668  return ROAR_BYTEORDER_NETWORK;
669 }
670
671 roar_err_set(ROAR_ERROR_NOENT);
672 return -1;
673}
674
675const char * roar_byteorder2str (const int    byteorder) {
676 switch (byteorder) {
677  case ROAR_BYTEORDER_LE:      return "little endian"; break;
678  case ROAR_BYTEORDER_BE:      return "big endian";    break;
679  case ROAR_BYTEORDER_PDP:     return "pdp endian";    break;
680//  case ROAR_BYTEORDER_NETWORK: return "network";       break;
681  default:
682    return "(unknown)";
683 }
684}
685
686// grep '^#define ROAR_OT_' roaraudio/proto.h | cut -d' ' -f2 | sed 's/^\(ROAR_OT_\)\(.*\)$/ {\1\2, "\2"},/'
687static struct {
688 const int ot;
689 const char * name;
690} _libroar_ot[] = {
691 {ROAR_OT_CLIENT,   "client"},
692 {ROAR_OT_STREAM,   "stream"},
693 {ROAR_OT_SOURCE,   "source"},
694 {ROAR_OT_SAMPLE,   "sample"},
695 {ROAR_OT_OUTPUT,   "output"},
696 {ROAR_OT_MIXER,    "mixer"},
697 {ROAR_OT_BRIDGE,   "bridge"},
698 {ROAR_OT_LISTEN,   "listen"},
699 {ROAR_OT_ACTION,   "action"},
700 {ROAR_OT_MSGQUEUE, "msgqueue"},
701 {ROAR_OT_MSGBUS,   "msgbus"},
702 {-1, NULL}
703};
704
705int    roar_str2ot        (const char * ot) {
706 int i;
707
708 for (i = 0; _libroar_ot[i].ot != -1; i++)
709  if ( !strcasecmp(ot, _libroar_ot[i].name) )
710   return _libroar_ot[i].ot;
711
712 roar_err_set(ROAR_ERROR_NOENT);
713 return -1;
714}
715
716const char * roar_ot2str  (const int    ot) {
717 int i;
718
719 for (i = 0; _libroar_ot[i].ot != -1; i++)
720  if ( _libroar_ot[i].ot == ot )
721   return _libroar_ot[i].name;
722
723 roar_err_set(ROAR_ERROR_NOENT);
724 return NULL;
725}
726
727int roar_conv_volume (struct roar_mixer_settings * dst, struct roar_mixer_settings * src, int dstchans, int srcchans) {
728 struct roar_mixer_settings lsrc;
729 int i;
730 uint_least32_t s;
731
732 if ( dst == NULL || src == NULL ) {
733  roar_err_set(ROAR_ERROR_FAULT);
734  return -1;
735 }
736
737 if ( dstchans < 0 || srcchans < 0 ) {
738  roar_err_set(ROAR_ERROR_INVAL);
739  return -1;
740 }
741
742 if ( dstchans == srcchans ) {
743  if ( dst == src )
744   return 0;
745
746  memcpy(dst, src, sizeof(struct roar_mixer_settings));
747  return 0;
748 }
749
750 if ( dst == src ) {
751  memcpy(&lsrc, src, sizeof(lsrc));
752  src = &lsrc;
753 }
754
755 // sepcal handling for N->1:
756 if ( dstchans == 1 ) {
757  s = 0;
758
759  for (i = 0; i < srcchans; i++)
760   s += src->mixer[i];
761
762  dst->mixer[0] = s / srcchans;
763 } else {
764  switch (srcchans) {
765   case  1:
766     for (i = 0; i < dstchans; i++)
767      dst->mixer[i] = src->mixer[0];
768    break;
769   case 2:
770     switch (dstchans) {
771      case 3:
772        dst->mixer[0] = src->mixer[0];
773        dst->mixer[1] = src->mixer[1];
774        dst->mixer[2] = (src->mixer[0] + src->mixer[1]) / 2;
775       break;
776      case 4:
777        dst->mixer[0] = src->mixer[0];
778        dst->mixer[1] = src->mixer[1];
779        dst->mixer[2] = src->mixer[0];
780        dst->mixer[3] = src->mixer[1];
781       break;
782      case 5:
783        dst->mixer[0] = src->mixer[0];
784        dst->mixer[1] = src->mixer[1];
785        dst->mixer[2] = (src->mixer[0] + src->mixer[1]) / 2;
786        dst->mixer[3] = src->mixer[0];
787        dst->mixer[4] = src->mixer[1];
788       break;
789      case 6:
790        dst->mixer[0] = src->mixer[0];
791        dst->mixer[1] = src->mixer[1];
792        dst->mixer[2] = (src->mixer[0] + src->mixer[1]) / 2;
793        dst->mixer[3] = dst->mixer[2];
794        dst->mixer[4] = src->mixer[0];
795        dst->mixer[5] = src->mixer[1];
796       break;
797      default:
798        roar_err_set(ROAR_ERROR_NOTSUP);
799        return -1;
800       break;
801     }
802    break;
803   case 3:
804     switch (dstchans) {
805      case 2:
806        dst->mixer[0] = src->mixer[0];
807        dst->mixer[1] = src->mixer[1];
808       break;
809      case 4:
810        dst->mixer[0] = src->mixer[0];
811        dst->mixer[1] = src->mixer[1];
812        dst->mixer[2] = src->mixer[0];
813        dst->mixer[3] = src->mixer[1];
814       break;
815      case 5:
816        dst->mixer[0] = src->mixer[0];
817        dst->mixer[1] = src->mixer[1];
818        dst->mixer[2] = src->mixer[2];
819        dst->mixer[3] = src->mixer[0];
820        dst->mixer[4] = src->mixer[1];
821       break;
822      case 6:
823        dst->mixer[0] = src->mixer[0];
824        dst->mixer[1] = src->mixer[1];
825        dst->mixer[2] = src->mixer[2];
826        dst->mixer[3] = src->mixer[2];
827        dst->mixer[4] = src->mixer[0];
828        dst->mixer[5] = src->mixer[1];
829       break;
830      default:
831        roar_err_set(ROAR_ERROR_NOTSUP);
832        return -1;
833       break;
834     }
835    break;
836   case 4:
837     switch (dstchans) {
838      case 2:
839        dst->mixer[0] = (src->mixer[0] + src->mixer[2]) / 2;
840        dst->mixer[1] = (src->mixer[1] + src->mixer[3]) / 2;
841       break;
842      case 3:
843        dst->mixer[0] = (src->mixer[0] + src->mixer[2]) / 2;
844        dst->mixer[1] = (src->mixer[1] + src->mixer[3]) / 2;
845        dst->mixer[2] = (dst->mixer[0] + dst->mixer[1]) / 2;
846       break;
847      case 5:
848        dst->mixer[0] = src->mixer[0];
849        dst->mixer[1] = src->mixer[1];
850        dst->mixer[2] = (src->mixer[0] + src->mixer[2] + src->mixer[1] + src->mixer[3]) / 4;
851        dst->mixer[3] = src->mixer[2];
852        dst->mixer[4] = src->mixer[3];
853       break;
854      case 6:
855        dst->mixer[0] = src->mixer[0];
856        dst->mixer[1] = src->mixer[1];
857        dst->mixer[2] = (src->mixer[0] + src->mixer[2] + src->mixer[1] + src->mixer[3]) / 4;
858        dst->mixer[3] = dst->mixer[2];
859        dst->mixer[4] = src->mixer[2];
860        dst->mixer[5] = src->mixer[3];
861       break;
862      default:
863        roar_err_set(ROAR_ERROR_NOTSUP);
864        return -1;
865       break;
866     }
867    break;
868   case 5:
869     switch (dstchans) {
870      case 2:
871        dst->mixer[0] = (src->mixer[0] + src->mixer[3]) / 2;
872        dst->mixer[1] = (src->mixer[1] + src->mixer[4]) / 2;
873       break;
874      case 3:
875        dst->mixer[0] = (src->mixer[0] + src->mixer[3]) / 2;
876        dst->mixer[1] = (src->mixer[1] + src->mixer[4]) / 2;
877        dst->mixer[2] = src->mixer[2];
878       break;
879      case 4:
880        dst->mixer[0] = src->mixer[0];
881        dst->mixer[1] = src->mixer[1];
882        dst->mixer[2] = src->mixer[3];
883        dst->mixer[3] = src->mixer[4];
884       break;
885      case 6:
886        dst->mixer[0] = src->mixer[0];
887        dst->mixer[1] = src->mixer[1];
888        dst->mixer[2] = src->mixer[2];
889        dst->mixer[3] = src->mixer[2];
890        dst->mixer[4] = src->mixer[3];
891        dst->mixer[5] = src->mixer[4];
892       break;
893      default:
894        roar_err_set(ROAR_ERROR_NOTSUP);
895        return -1;
896       break;
897     }
898    break;
899   case 6:
900     switch (dstchans) {
901      case 2:
902        dst->mixer[0] = (src->mixer[0] + src->mixer[4]) / 2;
903        dst->mixer[1] = (src->mixer[1] + src->mixer[5]) / 2;
904       break;
905      case 3:
906        dst->mixer[0] = (src->mixer[0] + src->mixer[4]) / 2;
907        dst->mixer[1] = (src->mixer[1] + src->mixer[5]) / 2;
908        dst->mixer[2] = src->mixer[2];
909       break;
910      case 4:
911        dst->mixer[0] = src->mixer[0];
912        dst->mixer[1] = src->mixer[1];
913        dst->mixer[2] = src->mixer[4];
914        dst->mixer[3] = src->mixer[5];
915       break;
916      case 5:
917        dst->mixer[0] = src->mixer[0];
918        dst->mixer[1] = src->mixer[1];
919        dst->mixer[2] = src->mixer[2];
920        dst->mixer[3] = src->mixer[4];
921        dst->mixer[4] = src->mixer[5];
922       break;
923      default:
924        roar_err_set(ROAR_ERROR_NOTSUP);
925        return -1;
926       break;
927     }
928    break;
929   default:
930     roar_err_set(ROAR_ERROR_NOTSUP);
931     return -1;
932    break;
933  }
934 }
935
936 dst->scale   = src->scale;
937 dst->rpg_mul = src->rpg_mul;
938 dst->rpg_div = src->rpg_div;
939
940 return 0;
941}
942
943//ll
Note: See TracBrowser for help on using the repository browser.