source: roaraudio/libroar/ctl.c @ 5878:3b92b0d6ef9b

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

updated copyright

File size: 22.6 KB
Line 
1//ctl.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2013
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 {ROAR_PROTO_RPLD,        "rpld"},
630 {ROAR_PROTO_MPD,         "mpd"},
631 {-1, NULL}
632};
633
634int    roar_str2proto (const char * proto) {
635 size_t i;
636
637 for (i = 0; _proto[i].id != -1; i++)
638  if ( !strcasecmp(proto, _proto[i].name) )
639   return _proto[i].id;
640
641 roar_err_set(ROAR_ERROR_NOENT);
642 return -1;
643}
644
645const char * roar_proto2str (const int    proto) {
646 size_t i;
647
648 roar_err_set(ROAR_ERROR_NONE);
649
650 for (i = 0; _proto[i].id != -1; i++)
651  if ( proto == _proto[i].id )
652   return _proto[i].name;
653
654 roar_err_set(ROAR_ERROR_NOENT);
655 return "(unknown)";
656}
657
658int    roar_str2byteorder (const char * byteorder) {
659 if (        !strcasecmp(byteorder, "le")            || !strcasecmp(byteorder, "little") ||
660             !strcasecmp(byteorder, "little endian") || !strcasecmp(byteorder, "1234")   ) {
661  return ROAR_BYTEORDER_LE;
662 } else if ( !strcasecmp(byteorder, "be")            || !strcasecmp(byteorder, "big")    ||
663             !strcasecmp(byteorder, "big endian")    || !strcasecmp(byteorder, "4321")   ) {
664  return ROAR_BYTEORDER_BE;
665 } else if ( !strcasecmp(byteorder, "pdp")           ||
666             !strcasecmp(byteorder, "pdp endian") ) {
667  return ROAR_BYTEORDER_PDP;
668 } else if ( !strcasecmp(byteorder, "network")       ||
669             !strcasecmp(byteorder, "network byteorder") ) {
670  return ROAR_BYTEORDER_NETWORK;
671 }
672
673 roar_err_set(ROAR_ERROR_NOENT);
674 return -1;
675}
676
677const char * roar_byteorder2str (const int    byteorder) {
678 switch (byteorder) {
679  case ROAR_BYTEORDER_LE:      return "little endian"; break;
680  case ROAR_BYTEORDER_BE:      return "big endian";    break;
681  case ROAR_BYTEORDER_PDP:     return "pdp endian";    break;
682//  case ROAR_BYTEORDER_NETWORK: return "network";       break;
683  default:
684    return "(unknown)";
685 }
686}
687
688// grep '^#define ROAR_OT_' roaraudio/proto.h | cut -d' ' -f2 | sed 's/^\(ROAR_OT_\)\(.*\)$/ {\1\2, "\2"},/'
689static struct {
690 const int ot;
691 const char * name;
692} _libroar_ot[] = {
693 {ROAR_OT_CLIENT,   "client"},
694 {ROAR_OT_STREAM,   "stream"},
695 {ROAR_OT_SOURCE,   "source"},
696 {ROAR_OT_SAMPLE,   "sample"},
697 {ROAR_OT_OUTPUT,   "output"},
698 {ROAR_OT_MIXER,    "mixer"},
699 {ROAR_OT_BRIDGE,   "bridge"},
700 {ROAR_OT_LISTEN,   "listen"},
701 {ROAR_OT_ACTION,   "action"},
702 {ROAR_OT_MSGQUEUE, "msgqueue"},
703 {ROAR_OT_MSGBUS,   "msgbus"},
704 {-1, NULL}
705};
706
707int    roar_str2ot        (const char * ot) {
708 int i;
709
710 for (i = 0; _libroar_ot[i].ot != -1; i++)
711  if ( !strcasecmp(ot, _libroar_ot[i].name) )
712   return _libroar_ot[i].ot;
713
714 roar_err_set(ROAR_ERROR_NOENT);
715 return -1;
716}
717
718const char * roar_ot2str  (const int    ot) {
719 int i;
720
721 for (i = 0; _libroar_ot[i].ot != -1; i++)
722  if ( _libroar_ot[i].ot == ot )
723   return _libroar_ot[i].name;
724
725 roar_err_set(ROAR_ERROR_NOENT);
726 return NULL;
727}
728
729int roar_conv_volume (struct roar_mixer_settings * dst, struct roar_mixer_settings * src, int dstchans, int srcchans) {
730 struct roar_mixer_settings lsrc;
731 int i;
732 uint_least32_t s;
733
734 if ( dst == NULL || src == NULL ) {
735  roar_err_set(ROAR_ERROR_FAULT);
736  return -1;
737 }
738
739 if ( dstchans < 0 || srcchans < 0 ) {
740  roar_err_set(ROAR_ERROR_INVAL);
741  return -1;
742 }
743
744 if ( dstchans == srcchans ) {
745  if ( dst == src )
746   return 0;
747
748  memcpy(dst, src, sizeof(struct roar_mixer_settings));
749  return 0;
750 }
751
752 if ( dst == src ) {
753  memcpy(&lsrc, src, sizeof(lsrc));
754  src = &lsrc;
755 }
756
757 // sepcal handling for N->1:
758 if ( dstchans == 1 ) {
759  s = 0;
760
761  for (i = 0; i < srcchans; i++)
762   s += src->mixer[i];
763
764  dst->mixer[0] = s / srcchans;
765 } else {
766  switch (srcchans) {
767   case  1:
768     for (i = 0; i < dstchans; i++)
769      dst->mixer[i] = src->mixer[0];
770    break;
771   case 2:
772     switch (dstchans) {
773      case 3:
774        dst->mixer[0] = src->mixer[0];
775        dst->mixer[1] = src->mixer[1];
776        dst->mixer[2] = (src->mixer[0] + src->mixer[1]) / 2;
777       break;
778      case 4:
779        dst->mixer[0] = src->mixer[0];
780        dst->mixer[1] = src->mixer[1];
781        dst->mixer[2] = src->mixer[0];
782        dst->mixer[3] = src->mixer[1];
783       break;
784      case 5:
785        dst->mixer[0] = src->mixer[0];
786        dst->mixer[1] = src->mixer[1];
787        dst->mixer[2] = (src->mixer[0] + src->mixer[1]) / 2;
788        dst->mixer[3] = src->mixer[0];
789        dst->mixer[4] = src->mixer[1];
790       break;
791      case 6:
792        dst->mixer[0] = src->mixer[0];
793        dst->mixer[1] = src->mixer[1];
794        dst->mixer[2] = (src->mixer[0] + src->mixer[1]) / 2;
795        dst->mixer[3] = dst->mixer[2];
796        dst->mixer[4] = src->mixer[0];
797        dst->mixer[5] = src->mixer[1];
798       break;
799      default:
800        roar_err_set(ROAR_ERROR_NOTSUP);
801        return -1;
802       break;
803     }
804    break;
805   case 3:
806     switch (dstchans) {
807      case 2:
808        dst->mixer[0] = src->mixer[0];
809        dst->mixer[1] = src->mixer[1];
810       break;
811      case 4:
812        dst->mixer[0] = src->mixer[0];
813        dst->mixer[1] = src->mixer[1];
814        dst->mixer[2] = src->mixer[0];
815        dst->mixer[3] = src->mixer[1];
816       break;
817      case 5:
818        dst->mixer[0] = src->mixer[0];
819        dst->mixer[1] = src->mixer[1];
820        dst->mixer[2] = src->mixer[2];
821        dst->mixer[3] = src->mixer[0];
822        dst->mixer[4] = src->mixer[1];
823       break;
824      case 6:
825        dst->mixer[0] = src->mixer[0];
826        dst->mixer[1] = src->mixer[1];
827        dst->mixer[2] = src->mixer[2];
828        dst->mixer[3] = src->mixer[2];
829        dst->mixer[4] = src->mixer[0];
830        dst->mixer[5] = src->mixer[1];
831       break;
832      default:
833        roar_err_set(ROAR_ERROR_NOTSUP);
834        return -1;
835       break;
836     }
837    break;
838   case 4:
839     switch (dstchans) {
840      case 2:
841        dst->mixer[0] = (src->mixer[0] + src->mixer[2]) / 2;
842        dst->mixer[1] = (src->mixer[1] + src->mixer[3]) / 2;
843       break;
844      case 3:
845        dst->mixer[0] = (src->mixer[0] + src->mixer[2]) / 2;
846        dst->mixer[1] = (src->mixer[1] + src->mixer[3]) / 2;
847        dst->mixer[2] = (dst->mixer[0] + dst->mixer[1]) / 2;
848       break;
849      case 5:
850        dst->mixer[0] = src->mixer[0];
851        dst->mixer[1] = src->mixer[1];
852        dst->mixer[2] = (src->mixer[0] + src->mixer[2] + src->mixer[1] + src->mixer[3]) / 4;
853        dst->mixer[3] = src->mixer[2];
854        dst->mixer[4] = src->mixer[3];
855       break;
856      case 6:
857        dst->mixer[0] = src->mixer[0];
858        dst->mixer[1] = src->mixer[1];
859        dst->mixer[2] = (src->mixer[0] + src->mixer[2] + src->mixer[1] + src->mixer[3]) / 4;
860        dst->mixer[3] = dst->mixer[2];
861        dst->mixer[4] = src->mixer[2];
862        dst->mixer[5] = src->mixer[3];
863       break;
864      default:
865        roar_err_set(ROAR_ERROR_NOTSUP);
866        return -1;
867       break;
868     }
869    break;
870   case 5:
871     switch (dstchans) {
872      case 2:
873        dst->mixer[0] = (src->mixer[0] + src->mixer[3]) / 2;
874        dst->mixer[1] = (src->mixer[1] + src->mixer[4]) / 2;
875       break;
876      case 3:
877        dst->mixer[0] = (src->mixer[0] + src->mixer[3]) / 2;
878        dst->mixer[1] = (src->mixer[1] + src->mixer[4]) / 2;
879        dst->mixer[2] = src->mixer[2];
880       break;
881      case 4:
882        dst->mixer[0] = src->mixer[0];
883        dst->mixer[1] = src->mixer[1];
884        dst->mixer[2] = src->mixer[3];
885        dst->mixer[3] = src->mixer[4];
886       break;
887      case 6:
888        dst->mixer[0] = src->mixer[0];
889        dst->mixer[1] = src->mixer[1];
890        dst->mixer[2] = src->mixer[2];
891        dst->mixer[3] = src->mixer[2];
892        dst->mixer[4] = src->mixer[3];
893        dst->mixer[5] = src->mixer[4];
894       break;
895      default:
896        roar_err_set(ROAR_ERROR_NOTSUP);
897        return -1;
898       break;
899     }
900    break;
901   case 6:
902     switch (dstchans) {
903      case 2:
904        dst->mixer[0] = (src->mixer[0] + src->mixer[4]) / 2;
905        dst->mixer[1] = (src->mixer[1] + src->mixer[5]) / 2;
906       break;
907      case 3:
908        dst->mixer[0] = (src->mixer[0] + src->mixer[4]) / 2;
909        dst->mixer[1] = (src->mixer[1] + src->mixer[5]) / 2;
910        dst->mixer[2] = src->mixer[2];
911       break;
912      case 4:
913        dst->mixer[0] = src->mixer[0];
914        dst->mixer[1] = src->mixer[1];
915        dst->mixer[2] = src->mixer[4];
916        dst->mixer[3] = src->mixer[5];
917       break;
918      case 5:
919        dst->mixer[0] = src->mixer[0];
920        dst->mixer[1] = src->mixer[1];
921        dst->mixer[2] = src->mixer[2];
922        dst->mixer[3] = src->mixer[4];
923        dst->mixer[4] = src->mixer[5];
924       break;
925      default:
926        roar_err_set(ROAR_ERROR_NOTSUP);
927        return -1;
928       break;
929     }
930    break;
931   default:
932     roar_err_set(ROAR_ERROR_NOTSUP);
933     return -1;
934    break;
935  }
936 }
937
938 dst->scale   = src->scale;
939 dst->rpg_mul = src->rpg_mul;
940 dst->rpg_div = src->rpg_div;
941
942 return 0;
943}
944
945//ll
Note: See TracBrowser for help on using the repository browser.