source: roaraudio/libroar/ctl.c @ 5231:8b30ddb689b8

Last change on this file since 5231:8b30ddb689b8 was 5189:d2b96cf45a19, checked in by phi, 12 years ago

added some more protocol IDs

File size: 21.5 KB
Line 
1//ctl.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2011
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) {
60 return roar_server_oinfo2(con, s, -1);
61}
62
63int roar_server_oinfo2  (struct roar_connection * con, struct roar_stream * s, int dir) {
64 struct roar_message mes;
65
66 memset(&mes, 0, sizeof(struct roar_message)); // make valgrind happy!
67
68 mes.cmd     = ROAR_CMD_SERVER_OINFO;
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 }
77
78 if ( roar_req(con, &mes, NULL) == -1 )
79  return -1;
80
81 if ( mes.cmd != ROAR_CMD_OK )
82  return -1;
83
84 if ( roar_stream_m2s(s, &mes) == -1 )
85  return -1;
86
87 return 0;
88}
89
90int roar_get_standby   (struct roar_connection * con) {
91 struct roar_message mes;
92
93 memset(&mes, 0, sizeof(struct roar_message)); // make valgrind happy!
94
95 mes.cmd = ROAR_CMD_GET_STANDBY;
96 mes.stream  = -1;
97 mes.datalen =  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
111 memset(&mes, 0, sizeof(struct roar_message)); // make valgrind happy!
112
113 mes.cmd = ROAR_CMD_SET_STANDBY;
114 mes.stream  = -1;
115 mes.datalen =  2;
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) {
129 return roar_terminate(con, 0);
130}
131
132int roar_terminate (struct roar_connection * con, int terminate) {
133 struct roar_message mes;
134
135 memset(&mes, 0, sizeof(struct roar_message)); // make valgrind happy!
136
137 mes.cmd     = ROAR_CMD_EXIT;
138 mes.stream  = -1;
139 mes.datalen =  1;
140 mes.data[0] = terminate;
141
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
151int roar_list_filtered(struct roar_connection * con, int * items,   int max, int cmd, unsigned char filter, unsigned char cmp, uint32_t id) {
152 struct roar_message m;
153
154 memset(&m, 0, sizeof(struct roar_message)); // make valgrind happy!
155
156 roar_ctl_f2m(&m, filter, cmp, id);
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
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
169int roar_get_client   (struct roar_connection * con, struct roar_client * client, int id) {
170 struct roar_message m;
171
172 memset(&m, 0, sizeof(struct roar_message)); // make valgrind happy!
173
174 m.cmd     = ROAR_CMD_GET_CLIENT;
175 m.stream  = -1;
176 m.datalen =  1;
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
195 memset(&m, 0, sizeof(struct roar_message)); // make valgrind happy!
196
197 m.cmd     = ROAR_CMD_GET_STREAM;
198 m.datalen = 1;
199 m.data[0] = id;
200
201 roar_err_set(ROAR_ERROR_UNKNOWN);
202
203 if ( roar_req(con, &m, NULL) == -1 ) {
204  roar_err_set(ROAR_ERROR_PROTO);
205  return -1;
206 }
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;
216 uint16_t * info = (uint16_t *) m.data;
217
218 memset(&m, 0, sizeof(struct roar_message)); // make valgrind happy!
219
220 m.cmd     = ROAR_CMD_KICK;
221 m.datalen = 4;
222 info[0] = ROAR_HOST2NET16(type);
223 info[1] = ROAR_HOST2NET16(id);
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
234int roar_set_vol      (struct roar_connection * con, int id, struct roar_mixer_settings * mixer, int channels) {
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) {
239 struct roar_message m;
240 uint16_t * info = (uint16_t *) m.data;
241 int i;
242
243 memset(&m, 0, sizeof(struct roar_message)); // make valgrind happy!
244
245 m.cmd     = ROAR_CMD_SET_VOL;
246 m.datalen = (3 + channels) * 2;
247 m.stream  = id;
248 info[0] = ROAR_HOST2NET16(1);
249 info[1] = ROAR_HOST2NET16(mixer->scale);
250 info[2] = ROAR_HOST2NET16(mode);
251
252 for (i = 0; i < channels; i++)
253  info[i+3] = ROAR_HOST2NET16(mixer->mixer[i]);
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
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
269 memset(&m, 0, sizeof(struct roar_message)); // make valgrind happy!
270
271 m.cmd     = ROAR_CMD_GET_VOL;
272 m.datalen = 2*2;
273 m.stream  = id;
274
275 info[0]   = ROAR_HOST2NET16(1);
276
277 if ( roar_req(con, &m, NULL) == -1 )
278  return -1;
279
280 if ( m.cmd != ROAR_CMD_OK )
281  return -1;
282
283 if ( ROAR_NET2HOST16(info[0]) != 1 )
284  return -1;
285
286 info[1] = ROAR_NET2HOST16(info[1]);
287
288 if ( channels != NULL )
289  *channels = info[1];
290
291 if ( info[1] > ROAR_MAX_CHANNELS )
292  return -1;
293
294 mixer->scale   = ROAR_NET2HOST16(info[2]);
295 mixer->rpg_mul = ROAR_NET2HOST16(info[3]);
296 mixer->rpg_div = ROAR_NET2HOST16(info[4]);
297
298 for (i = 0; i < info[1]; i++)
299  mixer->mixer[i] = ROAR_NET2HOST16(info[i+5]);
300
301 return 0;
302}
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;
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;
317
318 return 0;
319}
320int roar_ctl_m2f      (struct roar_message * m, unsigned char * filter, unsigned char * cmp, uint32_t * id) {
321 register uint32_t idreg;
322
323 if ( m->datalen != 7 )
324  return -1;
325
326 if ( m->data[0] != 0 ) {
327  ROAR_DBG("roar_ctl_m2f(*): version %i not supported!", (int)m->data[0]);
328  roar_err_set(ROAR_ERROR_NSVERSION);
329  return -1;
330 }
331
332 *filter = m->data[1];
333 *cmp    = m->data[2];
334
335 idreg   = ((uint32_t)(unsigned char)m->data[3]) << 24;
336 idreg  |= ((uint32_t)(unsigned char)m->data[4]) << 16;
337 idreg  |= ((uint32_t)(unsigned char)m->data[5]) <<  8;
338 idreg  |= ((uint32_t)(unsigned char)m->data[6]) <<  0;
339 *id     = idreg;
340
341 return 0;
342}
343
344int roar_filter_match (const unsigned cmp, const uint32_t a, const uint32_t b) {
345 switch (cmp) {
346  case ROAR_CTL_CMP_ANY:
347    return 1;
348   break;
349  case ROAR_CTL_CMP_EQ:
350    return a == b;
351   break;
352  case ROAR_CTL_CMP_NE:
353    return a != b;
354   break;
355  default:
356    roar_err_set(ROAR_ERROR_NOTSUP);
357    return -1;
358 }
359}
360
361int roar_ctl_ia2m     (struct roar_message * m, int * data, int len) {
362 int i;
363
364 if ( len > LIBROAR_BUFFER_MSGDATA ) {
365  roar_err_set(ROAR_ERROR_MSGSIZE);
366  return -1;
367 }
368
369 m->datalen = len;
370
371 for (i = 0; i < len; i++)
372  m->data[i] = data[i];
373
374 return 0;
375}
376int roar_ctl_m2ia     (struct roar_message * m, int * data, int len) {
377 int i;
378
379 if ( m->datalen > len ) {
380  roar_err_set(ROAR_ERROR_MSGSIZE);
381  return -1;
382 }
383
384 for (i = 0; i < m->datalen; i++)
385  data[i] = m->data[i];
386
387 return m->datalen;
388}
389
390int roar_ctl_c2m      (struct roar_message * m, struct roar_client * c) {
391 int cur = 0;
392 int h;
393 int i;
394 int max_len;
395 uint32_t pid;
396 signed long int len_rest;
397 size_t nnode_len;
398
399 if ( c == NULL )
400  return -1;
401
402 m->data[cur++] = 0;                       // 0: Version
403 m->data[cur++] = c->execed;               // 1: execed
404
405 h = 0;
406 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
407  if ( c->streams[i] != -1 )
408   m->data[cur+1+h++] = c->streams[i];
409 }
410
411 m->data[cur++] = h;                       // 2: num of streams
412 cur += h;
413
414 max_len = strlen(c->name);
415
416 // TODO: add some code to check if this fits in the pkg
417 // NOTE: add this code after we are sure how long this pkg will be
418 //       and fully decieded about this function.
419
420 m->data[cur++] = max_len;
421
422 strncpy((m->data)+cur, c->name, max_len);
423
424 cur += max_len;
425
426 pid = ROAR_HOST2NET32(c->pid);
427 memcpy(&(m->data[cur]), &pid, 4);
428 cur += 4;
429
430 pid = ROAR_HOST2NET32(c->uid);
431 memcpy(&(m->data[cur]), &pid, 4);
432 cur += 4;
433
434 pid = ROAR_HOST2NET32(c->gid);
435 memcpy(&(m->data[cur]), &pid, 4);
436 cur += 4;
437
438 pid = ROAR_HOST2NET32(c->proto);
439 memcpy(&(m->data[cur]), &pid, 4);
440 cur += 4;
441
442 pid = ROAR_HOST2NET32(c->byteorder);
443 memcpy(&(m->data[cur]), &pid, 4);
444 cur += 4;
445
446 len_rest = (long int)sizeof(m->data) - (long int)cur;
447 if ( len_rest < 0 ) {
448  roar_panic(ROAR_FATAL_ERROR_MEMORY_CORRUPTION, NULL);
449 }
450
451 nnode_len = len_rest;
452 if ( roar_nnode_to_blob(&(c->nnode), &(m->data[cur]), &nnode_len) == 0 ) {
453  cur += nnode_len;
454 }
455
456 m->datalen = cur;
457
458 return 0;
459}
460
461int roar_ctl_m2c      (struct roar_message * m, struct roar_client * c) {
462 int i;
463 int cur;
464 uint32_t pid;
465 size_t len;
466
467 if ( m == NULL || c == NULL ) {
468  roar_err_set(ROAR_ERROR_FAULT);
469  return -1;
470 }
471
472 if ( m->datalen == 0 ) {
473  roar_err_set(ROAR_ERROR_MSGSIZE);
474  return -1;
475 }
476
477 ROAR_DBG("roar_ctl_m2c(*): got data!, len = %i", m->datalen);
478
479 if ( m->data[0] != 0 ) {
480  ROAR_DBG("roar_ctl_m2c(*): wrong version!");
481  roar_err_set(ROAR_ERROR_NSVERSION);
482  return -1;
483 }
484
485 if ( m->datalen < 3 ) {
486  roar_err_set(ROAR_ERROR_MSGSIZE);
487  return -1;
488 }
489
490 ROAR_DBG("roar_ctl_m2c(*): have usable data!");
491
492 c->execed = m->data[1];
493
494 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++)
495  c->streams[i] = -1;
496
497 if ( m->data[2] < 0 || m->data[2] > ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT ) {
498  roar_err_set(ROAR_ERROR_TOOMANYARGS);
499  return -1;
500 }
501
502 for (i = 0; i < m->data[2]; i++)
503  c->streams[i] = m->data[3+i];
504
505 cur = 3 + m->data[2];
506
507 strncpy(c->name, (m->data)+cur+1, m->data[cur]);
508 c->name[(int)m->data[cur]] = 0;
509
510 cur += m->data[cur] + 1;
511
512 memcpy(&pid, &(m->data[cur]), 4);
513 c->pid = ROAR_NET2HOST32(pid);
514 cur += 4;
515
516 memcpy(&pid, &(m->data[cur]), 4);
517 c->uid = ROAR_NET2HOST32(pid);
518 cur += 4;
519
520 memcpy(&pid, &(m->data[cur]), 4);
521 c->gid = ROAR_NET2HOST32(pid);
522 cur += 4;
523
524 if ( m->datalen >= cur+4 ) {
525  memcpy(&pid, &(m->data[cur]), 4);
526  c->proto = ROAR_NET2HOST32(pid);
527  cur += 4;
528 } else {
529  c->proto = ROAR_PROTO_NONE;
530 }
531
532 if ( m->datalen >= cur+4 ) {
533  memcpy(&pid, &(m->data[cur]), 4);
534  c->byteorder = ROAR_NET2HOST32(pid);
535  cur += 4;
536 } else {
537  c->byteorder = ROAR_BYTEORDER_UNKNOWN;
538 }
539
540 if ( m->datalen > cur ) {
541  len = m->datalen - cur;
542  if ( roar_nnode_from_blob(&(c->nnode), &(m->data[cur]), &len) == 0 ) {
543   cur += len;
544  } else {
545   if ( roar_nnode_new(&(c->nnode), ROAR_SOCKET_TYPE_UNKNOWN) == -1 )
546    return -1;
547  }
548 } else {
549  if ( roar_nnode_new(&(c->nnode), ROAR_SOCKET_TYPE_UNKNOWN) == -1 )
550   return -1;
551 }
552
553 return 0;
554}
555
556static struct {
557 int id;
558 const char * name;
559} _proto[] = {
560 {ROAR_PROTO_NONE,        "none"},
561 {ROAR_PROTO_ROARAUDIO,   "RoarAudio"},
562 {ROAR_PROTO_ESOUND,      "EsounD"},
563 {ROAR_PROTO_ESOUND,      "ESD"}, // alias
564 {ROAR_PROTO_AUTO,        "(auto)"},
565 {ROAR_PROTO_HTTP,        "http"},
566 {ROAR_PROTO_GOPHER,      "gopher"},
567 {ROAR_PROTO_ICY,         "ICY"},
568 {ROAR_PROTO_SIMPLE,      "Simple"},
569 {ROAR_PROTO_RSOUND,      "RSound"},
570 {ROAR_PROTO_RPLAY,       "RPlay"},
571 {ROAR_PROTO_IRC,         "IRC"},
572 {ROAR_PROTO_DCC,         "DCC"},
573 {ROAR_PROTO_ECHO,        "Echo"},
574 {ROAR_PROTO_DISCARD,     "Discard"},
575 {ROAR_PROTO_WHOIS,       "Whois"},
576 {ROAR_PROTO_FINGER,      "Finger"},
577 {ROAR_PROTO_QUOTE,       "quote"},
578 {ROAR_PROTO_DAYTIME,     "daytime"},
579 {-1, NULL}
580};
581
582int    roar_str2proto (const char * proto) {
583 size_t i;
584
585 for (i = 0; _proto[i].id != -1; i++)
586  if ( !strcasecmp(proto, _proto[i].name) )
587   return _proto[i].id;
588
589 roar_err_set(ROAR_ERROR_NOENT);
590 return -1;
591}
592
593char * roar_proto2str (const int    proto) {
594 size_t i;
595
596 roar_err_set(ROAR_ERROR_NONE);
597
598 for (i = 0; _proto[i].id != -1; i++)
599  if ( proto == _proto[i].id )
600   return (char*)_proto[i].name;
601
602 roar_err_set(ROAR_ERROR_NOENT);
603 return "(unknown)";
604}
605
606int    roar_str2byteorder (const char * byteorder) {
607 if (        !strcasecmp(byteorder, "le")            || !strcasecmp(byteorder, "little") ||
608             !strcasecmp(byteorder, "little endian") || !strcasecmp(byteorder, "1234")   ) {
609  return ROAR_BYTEORDER_LE;
610 } else if ( !strcasecmp(byteorder, "be")            || !strcasecmp(byteorder, "big")    ||
611             !strcasecmp(byteorder, "big endian")    || !strcasecmp(byteorder, "4321")   ) {
612  return ROAR_BYTEORDER_BE;
613 } else if ( !strcasecmp(byteorder, "pdp")           ||
614             !strcasecmp(byteorder, "pdp endian") ) {
615  return ROAR_BYTEORDER_PDP;
616 } else if ( !strcasecmp(byteorder, "network")       ||
617             !strcasecmp(byteorder, "network byteorder") ) {
618  return ROAR_BYTEORDER_NETWORK;
619 }
620
621 roar_err_set(ROAR_ERROR_NOENT);
622 return -1;
623}
624
625char * roar_byteorder2str (const int    byteorder) {
626 switch (byteorder) {
627  case ROAR_BYTEORDER_LE:      return "little endian"; break;
628  case ROAR_BYTEORDER_BE:      return "big endian";    break;
629  case ROAR_BYTEORDER_PDP:     return "pdp endian";    break;
630//  case ROAR_BYTEORDER_NETWORK: return "network";       break;
631  default:
632    return "(unknown)";
633 }
634}
635
636// grep '^#define ROAR_OT_' roaraudio/proto.h | cut -d' ' -f2 | sed 's/^\(ROAR_OT_\)\(.*\)$/ {\1\2, "\2"},/'
637static struct {
638 const int ot;
639 const char * name;
640} _libroar_ot[] = {
641 {ROAR_OT_CLIENT,   "client"},
642 {ROAR_OT_STREAM,   "stream"},
643 {ROAR_OT_SOURCE,   "source"},
644 {ROAR_OT_SAMPLE,   "sample"},
645 {ROAR_OT_OUTPUT,   "output"},
646 {ROAR_OT_MIXER,    "mixer"},
647 {ROAR_OT_BRIDGE,   "bridge"},
648 {ROAR_OT_LISTEN,   "listen"},
649 {ROAR_OT_ACTION,   "action"},
650 {ROAR_OT_MSGQUEUE, "msgqueue"},
651 {ROAR_OT_MSGBUS,   "msgbus"},
652 {-1, NULL}
653};
654
655int    roar_str2ot        (const char * ot) {
656 int i;
657
658 for (i = 0; _libroar_ot[i].ot != -1; i++)
659  if ( !strcasecmp(ot, _libroar_ot[i].name) )
660   return _libroar_ot[i].ot;
661
662 roar_err_set(ROAR_ERROR_NOENT);
663 return -1;
664}
665
666const char * roar_ot2str  (const int    ot) {
667 int i;
668
669 for (i = 0; _libroar_ot[i].ot != -1; i++)
670  if ( _libroar_ot[i].ot == ot )
671   return _libroar_ot[i].name;
672
673 roar_err_set(ROAR_ERROR_NOENT);
674 return NULL;
675}
676
677int roar_conv_volume (struct roar_mixer_settings * dst, struct roar_mixer_settings * src, int dstchans, int srcchans) {
678 struct roar_mixer_settings lsrc;
679 int i;
680 uint_least32_t s;
681
682 if ( dst == NULL || src == NULL ) {
683  roar_err_set(ROAR_ERROR_FAULT);
684  return -1;
685 }
686
687 if ( dstchans < 0 || srcchans < 0 ) {
688  roar_err_set(ROAR_ERROR_INVAL);
689  return -1;
690 }
691
692 if ( dstchans == srcchans ) {
693  if ( dst == src )
694   return 0;
695
696  memcpy(dst, src, sizeof(struct roar_mixer_settings));
697  return 0;
698 }
699
700 if ( dst == src ) {
701  memcpy(&lsrc, src, sizeof(lsrc));
702  src = &lsrc;
703 }
704
705 // sepcal handling for N->1:
706 if ( dstchans == 1 ) {
707  s = 0;
708
709  for (i = 0; i < srcchans; i++)
710   s += src->mixer[i];
711
712  dst->mixer[0] = s / srcchans;
713 } else {
714  switch (srcchans) {
715   case  1:
716     for (i = 0; i < dstchans; i++)
717      dst->mixer[i] = src->mixer[0];
718    break;
719   case 2:
720     switch (dstchans) {
721      case 3:
722        dst->mixer[0] = src->mixer[0];
723        dst->mixer[1] = src->mixer[1];
724        dst->mixer[2] = (src->mixer[0] + src->mixer[1]) / 2;
725       break;
726      case 4:
727        dst->mixer[0] = src->mixer[0];
728        dst->mixer[1] = src->mixer[1];
729        dst->mixer[2] = src->mixer[0];
730        dst->mixer[3] = src->mixer[1];
731       break;
732      case 5:
733        dst->mixer[0] = src->mixer[0];
734        dst->mixer[1] = src->mixer[1];
735        dst->mixer[2] = (src->mixer[0] + src->mixer[1]) / 2;
736        dst->mixer[3] = src->mixer[0];
737        dst->mixer[4] = src->mixer[1];
738       break;
739      case 6:
740        dst->mixer[0] = src->mixer[0];
741        dst->mixer[1] = src->mixer[1];
742        dst->mixer[2] = (src->mixer[0] + src->mixer[1]) / 2;
743        dst->mixer[3] = dst->mixer[2];
744        dst->mixer[4] = src->mixer[0];
745        dst->mixer[5] = src->mixer[1];
746       break;
747      default:
748        roar_err_set(ROAR_ERROR_NOTSUP);
749        return -1;
750       break;
751     }
752    break;
753   case 3:
754     switch (dstchans) {
755      case 2:
756        dst->mixer[0] = src->mixer[0];
757        dst->mixer[1] = src->mixer[1];
758       break;
759      case 4:
760        dst->mixer[0] = src->mixer[0];
761        dst->mixer[1] = src->mixer[1];
762        dst->mixer[2] = src->mixer[0];
763        dst->mixer[3] = src->mixer[1];
764       break;
765      case 5:
766        dst->mixer[0] = src->mixer[0];
767        dst->mixer[1] = src->mixer[1];
768        dst->mixer[2] = src->mixer[2];
769        dst->mixer[3] = src->mixer[0];
770        dst->mixer[4] = src->mixer[1];
771       break;
772      case 6:
773        dst->mixer[0] = src->mixer[0];
774        dst->mixer[1] = src->mixer[1];
775        dst->mixer[2] = src->mixer[2];
776        dst->mixer[3] = src->mixer[2];
777        dst->mixer[4] = src->mixer[0];
778        dst->mixer[5] = src->mixer[1];
779       break;
780      default:
781        roar_err_set(ROAR_ERROR_NOTSUP);
782        return -1;
783       break;
784     }
785    break;
786   case 4:
787     switch (dstchans) {
788      case 2:
789        dst->mixer[0] = (src->mixer[0] + src->mixer[2]) / 2;
790        dst->mixer[1] = (src->mixer[1] + src->mixer[3]) / 2;
791       break;
792      case 3:
793        dst->mixer[0] = (src->mixer[0] + src->mixer[2]) / 2;
794        dst->mixer[1] = (src->mixer[1] + src->mixer[3]) / 2;
795        dst->mixer[2] = (dst->mixer[0] + dst->mixer[1]) / 2;
796       break;
797      case 5:
798        dst->mixer[0] = src->mixer[0];
799        dst->mixer[1] = src->mixer[1];
800        dst->mixer[2] = (src->mixer[0] + src->mixer[2] + src->mixer[1] + src->mixer[3]) / 4;
801        dst->mixer[3] = src->mixer[2];
802        dst->mixer[4] = src->mixer[3];
803       break;
804      case 6:
805        dst->mixer[0] = src->mixer[0];
806        dst->mixer[1] = src->mixer[1];
807        dst->mixer[2] = (src->mixer[0] + src->mixer[2] + src->mixer[1] + src->mixer[3]) / 4;
808        dst->mixer[3] = dst->mixer[2];
809        dst->mixer[4] = src->mixer[2];
810        dst->mixer[5] = src->mixer[3];
811       break;
812      default:
813        roar_err_set(ROAR_ERROR_NOTSUP);
814        return -1;
815       break;
816     }
817    break;
818   case 5:
819     switch (dstchans) {
820      case 2:
821        dst->mixer[0] = (src->mixer[0] + src->mixer[3]) / 2;
822        dst->mixer[1] = (src->mixer[1] + src->mixer[4]) / 2;
823       break;
824      case 3:
825        dst->mixer[0] = (src->mixer[0] + src->mixer[3]) / 2;
826        dst->mixer[1] = (src->mixer[1] + src->mixer[4]) / 2;
827        dst->mixer[2] = src->mixer[2];
828       break;
829      case 4:
830        dst->mixer[0] = src->mixer[0];
831        dst->mixer[1] = src->mixer[1];
832        dst->mixer[2] = src->mixer[3];
833        dst->mixer[3] = src->mixer[4];
834       break;
835      case 6:
836        dst->mixer[0] = src->mixer[0];
837        dst->mixer[1] = src->mixer[1];
838        dst->mixer[2] = src->mixer[2];
839        dst->mixer[3] = src->mixer[2];
840        dst->mixer[4] = src->mixer[3];
841        dst->mixer[5] = src->mixer[4];
842       break;
843      default:
844        roar_err_set(ROAR_ERROR_NOTSUP);
845        return -1;
846       break;
847     }
848    break;
849   case 6:
850     switch (dstchans) {
851      case 2:
852        dst->mixer[0] = (src->mixer[0] + src->mixer[4]) / 2;
853        dst->mixer[1] = (src->mixer[1] + src->mixer[5]) / 2;
854       break;
855      case 3:
856        dst->mixer[0] = (src->mixer[0] + src->mixer[4]) / 2;
857        dst->mixer[1] = (src->mixer[1] + src->mixer[5]) / 2;
858        dst->mixer[2] = src->mixer[2];
859       break;
860      case 4:
861        dst->mixer[0] = src->mixer[0];
862        dst->mixer[1] = src->mixer[1];
863        dst->mixer[2] = src->mixer[4];
864        dst->mixer[3] = src->mixer[5];
865       break;
866      case 5:
867        dst->mixer[0] = src->mixer[0];
868        dst->mixer[1] = src->mixer[1];
869        dst->mixer[2] = src->mixer[2];
870        dst->mixer[3] = src->mixer[4];
871        dst->mixer[4] = src->mixer[5];
872       break;
873      default:
874        roar_err_set(ROAR_ERROR_NOTSUP);
875        return -1;
876       break;
877     }
878    break;
879   default:
880     roar_err_set(ROAR_ERROR_NOTSUP);
881     return -1;
882    break;
883  }
884 }
885
886 dst->scale   = src->scale;
887 dst->rpg_mul = src->rpg_mul;
888 dst->rpg_div = src->rpg_div;
889
890 return 0;
891}
892
893//ll
Note: See TracBrowser for help on using the repository browser.