source: roaraudio/libroar/ctl.c @ 5147:6493378fc025

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