source: roaraudio/libroar/stream.c @ 5889:d866fb1213d6

Last change on this file since 5889:d866fb1213d6 was 5829:09f674dfe78a, checked in by phi, 11 years ago

fix possible buffer overflow (which can lead in stack overwrite) caused by ignoring buffer length in write-loop.

File size: 33.1 KB
Line 
1//stream.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_stream_connect(struct roar_connection * con, struct roar_stream * s, int dir, int mixer) {
39 struct roar_libroar_config * config = roar_libroar_get_config();
40 struct roar_stream  ms;
41 struct roar_message m;
42
43 s->dir = dir;
44
45 memset(&m,  0, sizeof(m));
46 memcpy(&ms, s, sizeof(ms));
47
48 m.cmd     = ROAR_CMD_NEW_STREAM;
49 m.stream  = mixer;
50 m.pos     = 0;
51
52 if ( config != NULL ) {
53  if ( config->info.rate )
54   ms.info.rate = config->info.rate;
55  if ( config->info.bits )
56   ms.info.bits = config->info.bits;
57  if ( config->info.channels )
58   ms.info.channels = config->info.channels;
59  if ( config->info.codec )
60   ms.info.codec = config->info.codec;
61 }
62
63 roar_stream_s2m(&ms, &m);
64
65 if ( roar_req3(con, &m, NULL) != 0 )
66  return -1;
67
68 if ( m.cmd == ROAR_CMD_OK ) {
69  s->id = m.stream;
70
71  ROAR_DBG("roar_stream_connect(*) = 0");
72  return 0;
73 }
74
75 ROAR_ERR("roar_stream_connect(*): Connecting new stream faild!");
76 ROAR_DBG("roar_stream_connect(*) = -1");
77 return -1;
78}
79
80int roar_stream_new (struct roar_stream * s, unsigned int rate,
81                     unsigned int channels, unsigned int bits, unsigned int codec) {
82
83 if ( s == NULL ) {
84  roar_err_set(ROAR_ERROR_FAULT);
85  return -1;
86 }
87
88 if ( bits > ROAR_BITS_MAX ) {
89  roar_err_set(ROAR_ERROR_RANGE);
90  return -1;
91 }
92
93 s->fh         = -1;
94 s->id         = -1;
95 s->pos        =  0;
96 s->pos_rel_id = -1;
97
98 s->dir        = ROAR_DIR_DEFAULT;
99
100 s->info.rate     = rate;
101 s->info.channels = channels;
102 s->info.bits     = bits;
103 s->info.codec    = codec;
104
105 return 0;
106}
107
108int roar_stream_new_by_info (struct roar_stream * s, const struct roar_audio_info * info) {
109 if ( s == NULL ) {
110  roar_err_set(ROAR_ERROR_FAULT);
111  return -1;
112 }
113
114 if ( info->bits > ROAR_BITS_MAX ) {
115  roar_err_set(ROAR_ERROR_RANGE);
116  return -1;
117 }
118
119 s->fh         = -1;
120 s->id         = -1;
121 s->pos        =  0;
122 s->pos_rel_id = -1;
123
124 s->dir        = ROAR_DIR_DEFAULT;
125
126 s->info = *info;
127
128 return 0;
129}
130
131int roar_stream_set_rel_id(struct roar_stream * s, int id) {
132 if ( s == NULL ) {
133  roar_err_set(ROAR_ERROR_FAULT);
134  return -1;
135 }
136
137 s->pos_rel_id = id;
138
139 return 0;
140}
141
142int roar_stream_get_rel_id(struct roar_stream * s) {
143 if ( s == NULL ) {
144  roar_err_set(ROAR_ERROR_FAULT);
145  return -1;
146 }
147
148 return s->pos_rel_id;
149}
150
151int roar_stream_new_by_id(struct roar_stream * s, int id) {
152 if ( s == NULL ) {
153  roar_err_set(ROAR_ERROR_FAULT);
154  return -1;
155 }
156
157 if ( roar_stream_new_empty(s) == -1 )
158  return -1;
159
160 return roar_stream_set_id(s, id);
161}
162
163int roar_stream_new_empty(struct roar_stream * s) {
164 if ( s == NULL ) {
165  roar_err_set(ROAR_ERROR_FAULT);
166  return -1;
167 }
168
169 return roar_stream_new(s, 0, 0, 0, 0);
170}
171
172int roar_stream_set_id (struct roar_stream * s, int id) {
173 if ( s == NULL ) {
174  roar_err_set(ROAR_ERROR_FAULT);
175  return -1;
176 }
177
178 s->id = id;
179
180 return 0;
181}
182
183int roar_stream_get_id (struct roar_stream * s) {
184 if ( s == NULL ) {
185  roar_err_set(ROAR_ERROR_FAULT);
186  return -1;
187 }
188
189 return s->id;
190}
191
192int roar_stream_set_fh (struct roar_stream * s, int fh) {
193 if ( s == NULL ) {
194  roar_err_set(ROAR_ERROR_FAULT);
195  return -1;
196 }
197
198 s->fh = fh;
199
200 return 0;
201}
202
203int roar_stream_get_fh (struct roar_stream * s) {
204 if ( s == NULL ) {
205  roar_err_set(ROAR_ERROR_FAULT);
206  return -1;
207 }
208
209 return s->fh;
210}
211
212int roar_stream_set_dir (struct roar_stream * s, int dir) {
213 if ( s == NULL ) {
214  roar_err_set(ROAR_ERROR_FAULT);
215  return -1;
216 }
217
218 s->dir = dir;
219
220 return 0;
221}
222
223int roar_stream_get_dir (struct roar_stream * s) {
224 if ( s == NULL ) {
225  roar_err_set(ROAR_ERROR_FAULT);
226  return -1;
227 }
228
229 return s->dir;
230}
231
232
233int roar_stream_exec    (struct roar_connection * con, struct roar_stream * s) {
234 struct roar_message m;
235
236 memset(&m,  0, sizeof(m));
237
238 m.cmd     = ROAR_CMD_EXEC_STREAM;
239 m.stream  = s->id;
240 m.datalen = 0;
241 m.pos     = 0;
242
243 if ( roar_req(con, &m, NULL) == -1 )
244  return -1;
245
246 if ( m.cmd == ROAR_CMD_OK )
247  return 0;
248 return -1;
249}
250
251int roar_stream_connect_to (struct roar_connection * con, struct roar_stream * s, int type, char * host, int port) {
252 struct roar_message m;
253
254 if ( roar_stream_connect_to_ask(con, s, type, host, port) == -1 )
255  return -1;
256
257 if ( roar_recv_message(con, &m, NULL) == -1 )
258  return -1;
259
260 if ( m.cmd == ROAR_CMD_OK )
261  return 0;
262 return -1;
263}
264
265int roar_stream_connect_to_ask (struct roar_connection * con, struct roar_stream * s, int type, char * host, int port) {
266 struct roar_message m;
267 int len = 0;
268
269 if ( host == NULL ) {
270  roar_err_set(ROAR_ERROR_FAULT);
271  return -1;
272 }
273
274 ROAR_DBG("roar_stream_connect_to_ask(*): Ask the server to connect to: %s:%i", host, port);
275
276 memset(&m,  0, sizeof(m));
277
278 m.cmd     = ROAR_CMD_CON_STREAM;
279 m.stream  = s->id;
280 m.pos     = 0;
281
282 m.data[0] = 0;
283 m.data[1] = type;
284 ((uint16_t*)&(m.data))[1] = ROAR_HOST2NET16(port);
285
286 len = strlen(host);
287
288 if ( len > 76 ) {
289  roar_err_set(ROAR_ERROR_NAMETOOLONG);
290  return -1;
291 }
292
293 strncpy(&(m.data[4]), host, len);
294
295 m.datalen = len + 4;
296
297 if ( roar_send_message(con, &m, NULL) == -1 )
298  return -1;
299
300 return 0;
301}
302
303int roar_stream_passfh  (struct roar_connection * con, struct roar_stream * s, int fh) {
304 struct roar_message m;
305 int confh;
306
307 if ( con == NULL || s == NULL ) {
308  roar_err_set(ROAR_ERROR_FAULT);
309  return -1;
310 }
311
312 if ( fh < 0 ) {
313  roar_err_set(ROAR_ERROR_INVAL);
314  return -1;
315 }
316
317 memset(&m,  0, sizeof(m));
318
319 m.cmd     = ROAR_CMD_PASSFH;
320 m.stream  = s->id;
321 m.pos     = 0;
322 m.datalen = 0;
323
324 ROAR_DBG("roar_stream_passfh(con=%p{...}, s={.id=%i,...}, fh=%i) = ?", con, s->id, fh);
325
326 roar_libroar_nowarn();
327 if ( (confh = roar_get_connection_fh(con)) == -1 ) {
328  roar_libroar_warn();
329  return -1;
330 }
331 roar_libroar_warn();
332
333 if ( roar_send_message(con, &m, NULL) == -1 ) {
334  ROAR_DBG("roar_stream_passfh(con=%p{...}, s={.id=%i,...}, fh=%i) = -1 // can not send message", con, s->id, fh);
335  return -1;
336 }
337
338 ROAR_DBG("roar_stream_passfh(*): msg send");
339
340 if ( roar_socket_send_fh(confh, fh, NULL, 0) == -1 )
341  return -1;
342
343 ROAR_DBG("roar_stream_passfh(*): fh send");
344
345 if ( roar_recv_message(con, &m, NULL) == -1 )
346  return -1;
347
348 ROAR_DBG("roar_stream_passfh(*): mes recved");
349
350 if ( m.cmd == ROAR_CMD_OK )
351  return 0;
352
353 return -1;
354}
355
356int roar_stream_attach_simple (struct roar_connection * con, struct roar_stream * s, int client) {
357 struct roar_message m;
358 uint16_t * info = (uint16_t *) m.data;
359 int i;
360
361 if ( con == NULL || s == NULL ) {
362  roar_err_set(ROAR_ERROR_FAULT);
363  return -1;
364 }
365
366 if ( client < 0 ) {
367  roar_err_set(ROAR_ERROR_INVAL);
368  return -1;
369 }
370
371 memset(&m,  0, sizeof(m));
372
373 m.cmd     = ROAR_CMD_ATTACH;
374 m.stream  = s->id;
375 m.pos     = 0;
376 m.datalen = 6;
377
378 info[0] = 0;
379 info[1] = ROAR_ATTACH_SIMPLE;
380 info[2] = client;
381
382 for (i = 0; i < m.datalen/2; i++) {
383  info[i] = ROAR_HOST2NET16(info[i]);
384 }
385
386 if ( roar_req(con, &m, NULL) == -1 )
387  return -1;
388
389 if ( m.cmd != ROAR_CMD_OK )
390  return -1;
391
392 return 0;
393}
394
395int roar_stream_get_info (struct roar_connection * con, struct roar_stream * s, struct roar_stream_info * info) {
396 struct roar_message m;
397 uint16_t * data = (uint16_t *) m.data;
398 int i;
399
400 if ( con == NULL || s == NULL || info == NULL ) {
401  roar_err_set(ROAR_ERROR_FAULT);
402  return -1;
403 }
404
405 memset(&m,  0, sizeof(m));
406
407 m.cmd     = ROAR_CMD_GET_STREAM_PARA;
408 m.stream  = s->id;
409 m.datalen = 4;
410 m.pos     = 0;
411
412 data[0] = 0; // Version and reserved
413 data[1] = ROAR_STREAM_PARA_INFO; // stream
414
415 for (i = 0; i < m.datalen/2; i++) {
416  data[i] = ROAR_HOST2NET16(data[i]);
417 }
418
419 if ( roar_req(con, &m, NULL) == -1 )
420  return -1;
421
422 if ( m.cmd != ROAR_CMD_OK )
423  return -1;
424
425 for (i = 0; i < m.datalen/2; i++) {
426  data[i] = ROAR_NET2HOST16(data[i]);
427 }
428
429 if ( m.datalen < 7*2 ) {
430  roar_err_set(ROAR_ERROR_MSGSIZE);
431  return -1;
432 }
433
434 if ( data[0] != 0 || data[1] != 1 ) {
435  roar_err_set(ROAR_ERROR_NSVERSION);
436  return -1;
437 }
438
439 memset(info, 0, sizeof(struct roar_stream_info));
440 info->mixer = -1;
441 info->role  = ROAR_ROLE_UNKNOWN;
442
443 info->block_size     = data[2];
444 info->pre_underruns  = data[3];
445 info->post_underruns = data[4];
446 info->codec          = data[5];
447 info->flags          = data[6];
448 info->delay          = data[7]*1000;
449
450 if ( m.datalen < 9*2 ) {
451  info->state         = ROAR_STREAMSTATE_UNKNOWN;
452  return 0;
453 } else {
454  info->state         = data[8];
455 }
456
457 if ( m.datalen < 10*2 ) {
458  return 0;
459 } else {
460  info->flags        |= ((uint32_t)data[9]) << 16;
461 }
462
463 if ( m.datalen < 11*2 ) {
464  return 0;
465 } else {
466  info->mixer         = data[10];
467 }
468
469 if ( m.datalen < 12*2 ) {
470  return 0;
471 } else {
472  info->role          = data[11];
473 }
474
475 return 0;
476}
477
478int roar_stream_get_name (struct roar_connection * con, struct roar_stream * s, char * name, size_t len) {
479 struct roar_message m;
480 uint16_t * data = (uint16_t *) m.data;
481
482 if ( con == NULL || s == NULL || name == NULL || len == 0 ) {
483  roar_err_set(ROAR_ERROR_FAULT);
484  return -1;
485 }
486
487 name[0] = 0; // just in case...
488
489 memset(&m,  0, sizeof(m));
490
491 m.cmd     = ROAR_CMD_GET_STREAM_PARA;
492 m.stream  = s->id;
493 m.datalen = 4;
494 m.pos     = 0;
495
496 data[0] = 0; // Version and reserved
497 data[1] = ROAR_STREAM_PARA_NAME; // stream
498
499 data[0] = ROAR_HOST2NET16(data[0]);
500 data[1] = ROAR_HOST2NET16(data[1]);
501
502 ROAR_DBG("roar_stream_get_name(*) = ?");
503
504 if ( roar_req(con, &m, NULL) == -1 )
505  return -1;
506
507 ROAR_DBG("roar_stream_get_name(*) = ?");
508
509 if ( m.cmd != ROAR_CMD_OK )
510  return -1;
511
512 ROAR_DBG("roar_stream_get_name(*) = ?");
513
514 if ( m.datalen < 4 ) {
515  roar_err_set(ROAR_ERROR_MSGSIZE);
516  return -1;
517 }
518
519 data[0] = ROAR_NET2HOST16(data[0]);
520 data[1] = ROAR_NET2HOST16(data[1]);
521
522 ROAR_DBG("roar_stream_get_name(*) = ?");
523
524 if ( data[0] != 0 ) {
525  roar_err_set(ROAR_ERROR_NSVERSION);
526  return -1;
527 }
528
529 if ( data[1] != (uint16_t)ROAR_STREAM_PARA_NAME ) {
530  roar_err_set(ROAR_ERROR_TYPEMM);
531  return -1;
532 }
533
534 m.datalen -= 4;
535
536 len--;
537
538 if ( len > m.datalen )
539  len = m.datalen;
540
541 strncpy(name, ((char*)m.data)+4, len);
542 name[len] = 0;
543
544 ROAR_DBG("roar_stream_get_name(*) = 0");
545
546 return 0;
547}
548
549int roar_stream_get_chanmap (struct roar_connection * con, struct roar_stream * s, char * map, size_t * len) {
550 struct roar_message m;
551 uint16_t * data = (uint16_t *) m.data;
552
553 ROAR_DBG("roar_stream_get_chanmap(con=%p, s=%p, map=%p, len=%p) = ?", con, s, map, len);
554
555 if ( con == NULL || s == NULL || map == NULL || len == NULL ) {
556  roar_err_set(ROAR_ERROR_FAULT);
557  return -1;
558 }
559
560 if ( *len == 0 ) {
561  roar_err_set(ROAR_ERROR_INVAL);
562  return -1;
563 }
564
565 memset(&m, 0, sizeof(m));
566
567 m.cmd     = ROAR_CMD_GET_STREAM_PARA;
568 m.stream  = s->id;
569 m.datalen = 2*2;
570
571 data[0] = 0; // Version and reserved
572 data[1] = ROAR_STREAM_PARA_CHANMAP;
573
574 data[0] = ROAR_HOST2NET16(data[0]);
575 data[1] = ROAR_HOST2NET16(data[1]);
576
577 if ( roar_req(con, &m, NULL) == -1 )
578  return -1;
579
580 ROAR_DBG("roar_stream_get_chanmap(con=%p, s=%p{.id=%i}, map=%p, len=%p) = ?", con, s, s->id, map, len);
581
582 if ( m.cmd != ROAR_CMD_OK )
583  return -1;
584
585 ROAR_DBG("roar_stream_get_chanmap(con=%p, s=%p{.id=%i}, map=%p, len=%p) = ?", con, s, s->id, map, len);
586
587 if ( m.datalen < 4 ) {
588  roar_err_set(ROAR_ERROR_MSGSIZE);
589  return -1;
590 }
591
592 data[0] = ROAR_NET2HOST16(data[0]);
593 data[1] = ROAR_NET2HOST16(data[1]);
594
595 ROAR_DBG("roar_stream_get_chanmap(con=%p, s=%p{.id=%i}, map=%p, len=%p) = ?", con, s, s->id, map, len);
596
597 if ( data[0] != 0 ) {
598  roar_err_set(ROAR_ERROR_NSVERSION);
599  return -1;
600 }
601
602 if ( data[1] != ROAR_STREAM_PARA_CHANMAP ) {
603  roar_err_set(ROAR_ERROR_TYPEMM);
604  return -1;
605 }
606
607 ROAR_DBG("roar_stream_get_chanmap(con=%p, s=%p{.id=%i}, map=%p, len=%p) = ?", con, s, s->id, map, len);
608
609 m.datalen -= 4;
610
611 if ( m.datalen > *len ) {
612  roar_err_set(ROAR_ERROR_NOMEM);
613  return -1;
614 }
615
616 ROAR_DBG("roar_stream_get_chanmap(con=%p, s=%p{.id=%i}, map=%p, len=%p) = ?", con, s, s->id, map, len);
617
618 memcpy(map, &(m.data[4]), m.datalen);
619
620 *len = m.datalen;
621
622 ROAR_DBG("roar_stream_get_chanmap(con=%p, s=%p{.id=%i}, map=%p, len=%p) = 0", con, s, s->id, map, len);
623 return 0;
624}
625
626int roar_stream_set_chanmap (struct roar_connection * con, struct roar_stream * s, char * map, size_t   len) {
627 struct roar_message m;
628 uint16_t * data = (uint16_t *) m.data;
629
630 if ( con == NULL || s == NULL || map == NULL ) {
631  roar_err_set(ROAR_ERROR_FAULT);
632  return -1;
633 }
634
635 if ( len == 0 ) {
636  roar_err_set(ROAR_ERROR_INVAL);
637  return 0;
638 }
639
640 memset(&m, 0, sizeof(m));
641
642 m.cmd     = ROAR_CMD_SET_STREAM_PARA;
643 m.stream  = s->id;
644 m.datalen = 2*2 + len;
645
646 if ( m.datalen > sizeof(m.data) )
647  return -1;
648
649 data[0] = 0; // Version and reserved
650 data[1] = ROAR_STREAM_PARA_CHANMAP;
651
652 data[0] = ROAR_HOST2NET16(data[0]);
653 data[1] = ROAR_HOST2NET16(data[1]);
654
655 memcpy(&(m.data[4]), map, len);
656
657 if ( roar_req(con, &m, NULL) == -1 )
658  return -1;
659
660 if ( m.cmd != ROAR_CMD_OK )
661  return -1;
662
663 return 0;
664}
665
666
667int roar_stream_set_flags (struct roar_connection * con, struct roar_stream * s, uint32_t flags, int action) {
668 struct roar_message m;
669 uint16_t * data = (uint16_t *) m.data;
670 int i;
671
672 if ( con == NULL || s == NULL ) {
673  roar_err_set(ROAR_ERROR_FAULT);
674  return -1;
675 }
676
677 memset(&m,  0, sizeof(m));
678
679 m.cmd     = ROAR_CMD_SET_STREAM_PARA;
680 m.stream  = s->id;
681 m.pos     = 0;
682
683 if ( flags & 0xFFFF0000 ) {
684  m.datalen = 2*5;
685 } else {
686  m.datalen = 2*4;
687 }
688
689 data[0] = 0; // Version and reserved
690 data[1] = ROAR_STREAM_PARA_FLAGS; // flags
691 data[2] = action;
692 data[3] = flags & 0x0000FFFF;
693
694 if ( flags & 0xFFFF0000 ) {
695  data[4] = (flags & 0xFFFF0000) >> 16;
696 }
697
698 for (i = 0; i < m.datalen/2; i++) {
699  data[i] = ROAR_HOST2NET16(data[i]);
700 }
701
702 if ( roar_req(con, &m, NULL) == -1 )
703  return -1;
704
705 if ( m.cmd != ROAR_CMD_OK )
706  return -1;
707
708 return 0;
709}
710
711int roar_stream_set_role  (struct roar_connection * con, struct roar_stream * s, int role) {
712 struct roar_message m;
713 uint16_t * data = (uint16_t *) m.data;
714 int i;
715
716 if ( con == NULL || s == NULL ) {
717  roar_err_set(ROAR_ERROR_FAULT);
718  return -1;
719 }
720
721 memset(&m,  0, sizeof(m));
722
723 m.cmd     = ROAR_CMD_SET_STREAM_PARA;
724 m.stream  = s->id;
725 m.datalen = 6;
726 m.pos     = 0;
727
728 data[0] = 0; // Version and reserved
729 data[1] = ROAR_STREAM_PARA_ROLE; // flags
730 data[2] = role;
731
732 for (i = 0; i < m.datalen/2; i++) {
733  data[i] = ROAR_HOST2NET16(data[i]);
734 }
735
736 if ( roar_req(con, &m, NULL) == -1 )
737  return -1;
738
739 if ( m.cmd != ROAR_CMD_OK )
740  return -1;
741
742 return 0;
743}
744
745int roar_stream_get_rpg   (struct roar_connection * con, struct roar_stream * s, struct roar_stream_rpg * rpg) {
746 struct roar_message m;
747 uint16_t * data = (uint16_t *) m.data;
748 size_t i;
749
750 memset(&m,  0, sizeof(m));
751
752 m.cmd     = ROAR_CMD_GET_STREAM_PARA;
753 m.stream  = s->id;
754 m.datalen = 2*2;
755 m.pos     = 0;
756
757 data[0] = 0; // Version and reserved
758 data[1] = ROAR_STREAM_PARA_RPG; // flags
759
760 for (i = 0; i < m.datalen/2; i++) {
761  data[i] = ROAR_HOST2NET16(data[i]);
762 }
763
764 if ( roar_req(con, &m, NULL) == -1 )
765  return -1;
766
767 if ( m.cmd != ROAR_CMD_OK )
768  return -1;
769
770 for (i = 0; i < m.datalen/2; i++) {
771  data[i] = ROAR_NET2HOST16(data[i]);
772 }
773
774 if ( m.datalen != 10 ) {
775  roar_err_set(ROAR_ERROR_MSGSIZE);
776  return -1;
777 }
778
779 if ( data[0] != 0 ) {
780  roar_err_set(ROAR_ERROR_NSVERSION);
781  return -1;
782 }
783
784 if ( data[1] != ROAR_STREAM_PARA_RPG ) {
785  roar_err_set(ROAR_ERROR_BADRQC);
786  return -1;
787 }
788
789 memset(rpg, 0, sizeof(struct roar_stream_rpg));
790
791 rpg->mode = data[2];
792 rpg->mul  = data[3];
793 rpg->div  = data[4];
794
795 if ( rpg->mode == 0xFFFF )
796  rpg->mode = -1;
797
798 return 0;
799}
800
801int roar_stream_set_rpg   (struct roar_connection * con, struct roar_stream * s, const struct roar_stream_rpg * rpg) {
802 struct roar_message m;
803 uint16_t * data = (uint16_t *) m.data;
804 size_t i;
805
806 memset(&m,  0, sizeof(m));
807
808 m.cmd     = ROAR_CMD_SET_STREAM_PARA;
809 m.stream  = s->id;
810 m.datalen = (2+3)*2;
811 m.pos     = 0;
812
813 data[0] = 0; // Version and reserved
814 data[1] = ROAR_STREAM_PARA_RPG; // flags
815 data[2] = rpg->mode;
816 data[3] = rpg->mul;
817 data[4] = rpg->div;
818
819 for (i = 0; i < m.datalen/2; i++) {
820  data[i] = ROAR_HOST2NET16(data[i]);
821 }
822
823 if ( roar_req(con, &m, NULL) == -1 )
824  return -1;
825
826 if ( m.cmd != ROAR_CMD_OK )
827  return -1;
828
829 return 0;
830}
831
832#ifdef DEBUG
833static inline void _roar_debug_audio_info_print (struct roar_audio_info * info) {
834 ROAR_DBG("_roar_debug_audio_info_print(*): Rate    : %i", info->rate);
835 ROAR_DBG("_roar_debug_audio_info_print(*): Channels: %i", info->channels);
836 ROAR_DBG("_roar_debug_audio_info_print(*): Bits    : %i", info->bits);
837 ROAR_DBG("_roar_debug_audio_info_print(*): Codec   : %i", info->codec);
838}
839#endif
840
841#define _ROAR_STREAM_MESSAGE_LEN ((5+1)*4)
842
843int roar_stream_s2m     (struct roar_stream * s, struct roar_message * m) {
844 uint32_t * data;
845 int i;
846
847 if ( s == NULL || m == NULL ) {
848  roar_err_set(ROAR_ERROR_FAULT);
849  return -1;
850 }
851
852 m->datalen = _ROAR_STREAM_MESSAGE_LEN;
853 data = (uint32_t*) m->data;
854
855 data[0] = s->dir;
856 data[1] = s->pos_rel_id;
857 data[2] = s->info.rate;
858 data[3] = s->info.bits;
859 data[4] = s->info.channels;
860 data[5] = s->info.codec;
861
862 for (i = 0; i < _ROAR_STREAM_MESSAGE_LEN/4; i++)
863  data[i] = ROAR_HOST2NET32(data[i]);
864
865#ifdef DEBUG
866 ROAR_DBG("roar_stream_s2m(*): s->info:");
867 _roar_debug_audio_info_print(&(s->info));
868#endif
869
870 m->pos   = s->pos;
871 m->pos64 = s->pos;
872
873 return 0;
874}
875int roar_stream_m2s     (struct roar_stream * s, struct roar_message * m) {
876 uint32_t * data;
877 int i;
878
879 if ( s == NULL || m == NULL ) {
880  roar_err_set(ROAR_ERROR_FAULT);
881  return -1;
882 }
883
884 if ( m->datalen != _ROAR_STREAM_MESSAGE_LEN ) {
885  roar_err_set(ROAR_ERROR_MSGSIZE);
886  return -1;
887 }
888
889 if ( m->flags & ROAR_MF_LSPOS ) {
890  s->pos = m->pos64;
891 } else {
892  s->pos = m->pos;
893 }
894
895 data = (uint32_t*) m->data;
896
897 for (i = 0; i < _ROAR_STREAM_MESSAGE_LEN/4; i++)
898  data[i] = ROAR_NET2HOST32(data[i]);
899
900 s->id            = m->stream;
901 s->dir           = data[0];
902 s->pos_rel_id    = data[1];
903 s->info.rate     = data[2];
904 s->info.bits     = data[3];
905 s->info.channels = data[4];
906 s->info.codec    = data[5];
907
908#ifdef DEBUG
909 ROAR_DBG("roar_stream_m2s(*): s->info:");
910 _roar_debug_audio_info_print(&(s->info));
911#endif
912
913 return 0;
914}
915
916// stream direction funcs:
917static const struct {
918 const int    dir;
919 const char * name;
920} _libroar_dir[] = {
921 {ROAR_DIR_PLAY,        "play"       },
922 {ROAR_DIR_RECORD,      "record"     },
923 {ROAR_DIR_MONITOR,     "monitor"    },
924 {ROAR_DIR_FILTER,      "filter"     },
925 {ROAR_DIR_OUTPUT,      "output"     },
926 {ROAR_DIR_MIXING,      "mixing"     },
927 {ROAR_DIR_META,        "meta"       },
928 {ROAR_DIR_BIDIR,       "bidir"      },
929 {ROAR_DIR_THRU,        "thru"       },
930 {ROAR_DIR_BRIDGE,      "bridge"     },
931 {ROAR_DIR_MIDI_IN,     "midi_in"    },
932 {ROAR_DIR_MIDI_OUT,    "midi_out"   },
933 {ROAR_DIR_LIGHT_IN,    "light_in"   },
934 {ROAR_DIR_LIGHT_OUT,   "light_out"  },
935 {ROAR_DIR_RAW_IN,      "raw_in"     },
936 {ROAR_DIR_RAW_OUT,     "raw_out"    },
937 {ROAR_DIR_COMPLEX_IN,  "complex_in" },
938 {ROAR_DIR_COMPLEX_OUT, "complex_out"},
939 {ROAR_DIR_RDTCS_IN,    "rdtcs_in"   },
940 {ROAR_DIR_RDTCS_OUT,   "rdtcs_out"  },
941 {ROAR_DIR_RECPLAY,     "recplay"    },
942 {-1,                   "unknown"    }
943};
944
945const char * roar_dir2str (const int dir) {
946 int i;
947
948 for (i = 0; _libroar_dir[i].dir != -1; i++)
949  if ( _libroar_dir[i].dir == dir )
950   return _libroar_dir[i].name;
951
952 return _libroar_dir[i].name;
953}
954
955int roar_str2dir (const char * name) {
956 int i;
957
958 for (i = 0; _libroar_dir[i].dir != -1; i++)
959  if ( !strcmp(_libroar_dir[i].name, name) )
960   return _libroar_dir[i].dir;
961
962 return _libroar_dir[i].dir;
963}
964
965// codec funcs:
966
967/*
968#define roar_codec2str(x) ((x) == ROAR_CODEC_PCM_S_LE  ? "pcm_s_le"  : (x) == ROAR_CODEC_PCM_S_BE  ? "pcm_s_be"  : \
969                           (x) == ROAR_CODEC_PCM_S_PDP ? "pcm_s_pdp" : (x) == ROAR_CODEC_MIDI_FILE ? "midi_file" : \
970                           "unknown" )
971*/
972
973static const struct {
974 const uint32_t codec;
975 const char   * name;
976 const char   * mime;
977} _libroar_codec[] = {
978 // PCM:
979 {ROAR_CODEC_PCM_S_LE,    "pcm_s_le",    NULL},
980 {ROAR_CODEC_PCM_S_BE,    "pcm_s_be",    NULL},
981 {ROAR_CODEC_PCM_S_PDP,   "pcm_s_pdp",   NULL},
982 {ROAR_CODEC_PCM_U_LE,    "pcm_u_le",    NULL},
983 {ROAR_CODEC_PCM_U_BE,    "pcm_u_be",    NULL},
984 {ROAR_CODEC_PCM_U_PDP,   "pcm_u_pdp",   NULL},
985 {ROAR_CODEC_DEFAULT,     "default",     NULL}, // alias
986 {ROAR_CODEC_DEFAULT,     "pcm",         NULL}, // alias
987 {ROAR_CODEC_DEFAULT,     "raw",         NULL}, // alias
988 {ROAR_CODEC_PCM_S,       "pcm_s",       NULL}, // alias
989 {ROAR_CODEC_PCM_U,       "pcm_u",       NULL}, // alias
990
991 // MIDI:
992 {ROAR_CODEC_MIDI_FILE,   "midi_file",   NULL},
993 {ROAR_CODEC_MIDI,        "midi",        NULL},
994 {ROAR_CODEC_ROARMIDI,    "roarmidi",    NULL},
995
996 // XIPH:
997 {ROAR_CODEC_OGG_VORBIS,  "ogg_vorbis",  "application/ogg"},
998 {ROAR_CODEC_OGG_VORBIS,  "vorbis",      "application/ogg"}, // alias
999 {ROAR_CODEC_FLAC,        "flac",        "audio/x-flac"},
1000 {ROAR_CODEC_OGG_SPEEX,   "ogg_speex",   "audio/ogg; codecs=speex"},
1001 {ROAR_CODEC_OGG_SPEEX,   "speex",       "audio/ogg; codecs=speex"}, // alias
1002 {ROAR_CODEC_OGG_FLAC,    "ogg_flac",    "audio/ogg; codecs=flac"},
1003 {ROAR_CODEC_OGG_GENERAL, "ogg_general", "application/ogg"},
1004 {ROAR_CODEC_OGG_CELT,    "ogg_celt",    "audio/ogg; codecs=celt"},
1005 {ROAR_CODEC_OGG,         "ogg",         "application/ogg"},
1006 {ROAR_CODEC_OGG_OPUS,    "ogg_opus",    NULL},
1007 {ROAR_CODEC_ROAR_OPUS,   "roar_opus",   NULL},
1008 {ROAR_CODEC_ROAR_CELT,   "roar_celt",   NULL},
1009 {ROAR_CODEC_ROAR_SPEEX,  "roar_speex",  NULL},
1010
1011 // RAUM:
1012 {ROAR_CODEC_RAUM,        "raum",        NULL},
1013 {ROAR_CODEC_RAUM_VORBIS, "raum_vorbis", NULL},
1014 {ROAR_CODEC_RAUM_FLAC,   "raum_flac",   NULL},
1015
1016 // RIFF/WAVE like:
1017 {ROAR_CODEC_RIFF_WAVE,   "riff_wave",   "audio/x-wav"},
1018 {ROAR_CODEC_RIFF_WAVE,   "wave",        "audio/x-wav"}, // alias
1019 {ROAR_CODEC_RIFF_WAVE,   "wav",         "audio/x-wav"}, // alias
1020 {ROAR_CODEC_RIFX,        "rifx",        NULL},
1021 {ROAR_CODEC_AU,          "au",          "audio/basic"},
1022 {ROAR_CODEC_AIFF,        "aiff",        "audio/aiff"},
1023
1024 //Log codecs:
1025 {ROAR_CODEC_ALAW,        "alaw",        NULL},
1026 {ROAR_CODEC_AUTLAW_LE,   "autlaw_le",   NULL},
1027 {ROAR_CODEC_AUTLAW_BE,   "autlaw_be",   NULL},
1028 {ROAR_CODEC_AUTLAW,      "autlaw",      NULL}, // alias
1029 {ROAR_CODEC_MULAW,       "mulaw",       NULL},
1030 {ROAR_CODEC_MULAW,       "ulaw",        NULL}, // alias
1031 {ROAR_CODEC_MUUTLAW_LE,  "muutlaw_le",  NULL},
1032 {ROAR_CODEC_MUUTLAW_BE,  "muutlaw_be",  NULL},
1033 {ROAR_CODEC_MUUTLAW,     "muutlaw",     NULL}, // alias
1034
1035 //GSM:
1036 {ROAR_CODEC_GSM,         "gsm",         NULL},
1037 {ROAR_CODEC_GSM49,       "gsm49",       NULL},
1038
1039 //SPC-700 Bit Rate Reduction of
1040 //Super Nintendo Entertainment System (SNES)
1041 {ROAR_CODEC_BRR,         "brr",         NULL},
1042
1043 // Meta Codecs:
1044 {ROAR_CODEC_META_VCLT,     "meta_vclt",     NULL},
1045 {ROAR_CODEC_META_RALT,     "meta_ralt",     NULL},
1046 {ROAR_CODEC_META_RALB,     "meta_ralb",     NULL},
1047 {ROAR_CODEC_META_RALB_LE,  "meta_ralb_le",  NULL},
1048 {ROAR_CODEC_META_RALB_BE,  "meta_ralb_be",  NULL},
1049 {ROAR_CODEC_META_RALB_PDP, "meta_ralb_pdp", NULL},
1050
1051 // light control:
1052 {ROAR_CODEC_DMX512,      "dmx512",      NULL},
1053 {ROAR_CODEC_ROARDMX,     "roardmx",     NULL},
1054
1055 // Radio Data and Transmitter Control System:
1056 {ROAR_CODEC_RDS,         "rds",         NULL},
1057
1058 // User specific:
1059 {ROAR_CODEC_USER0,       "user0",       NULL},
1060 {ROAR_CODEC_USER1,       "user1",       NULL},
1061 {ROAR_CODEC_USER2,       "user2",       NULL},
1062 {ROAR_CODEC_USER3,       "user3",       NULL},
1063 {ROAR_CODEC_USER4,       "user4",       NULL},
1064 {ROAR_CODEC_USER5,       "user5",       NULL},
1065 {ROAR_CODEC_USER6,       "user6",       NULL},
1066 {ROAR_CODEC_USER7,       "user7",       NULL},
1067 {ROAR_CODEC_USER8,       "user8",       NULL},
1068 {ROAR_CODEC_USER9,       "user9",       NULL},
1069 {ROAR_CODEC_USER10,      "user10",      NULL},
1070 {ROAR_CODEC_USER11,      "user11",      NULL},
1071 {ROAR_CODEC_USER12,      "user12",      NULL},
1072 {ROAR_CODEC_USER13,      "user13",      NULL},
1073 {ROAR_CODEC_USER14,      "user14",      NULL},
1074 {ROAR_CODEC_USER15,      "user15",      NULL},
1075 {-1, NULL, NULL}
1076};
1077
1078int32_t roar_str2codec(const char * codec) {
1079 size_t i;
1080 int guess;
1081
1082 if ( codec == NULL || *codec == 0 )
1083  return ROAR_CODEC_DEFAULT;
1084
1085 if ( (guess = atoi(codec)) > 0 )
1086  return guess;
1087
1088 for (i = 0; _libroar_codec[i].codec != (uint32_t)-1; i++)
1089  if ( strcasecmp(_libroar_codec[i].name, codec) == 0 )
1090   return _libroar_codec[i].codec;
1091
1092 roar_err_set(ROAR_ERROR_NOENT);
1093 return -1;
1094}
1095
1096
1097const char * roar_codec2str (const uint32_t codec) {
1098 int i;
1099
1100 for (i = 0; _libroar_codec[i].codec != (uint32_t)-1; i++)
1101  if ( _libroar_codec[i].codec == codec )
1102   return _libroar_codec[i].name;
1103
1104 return "unknown";
1105}
1106
1107int32_t  roar_mime2codec (const char * mime) {
1108 size_t i;
1109
1110 if ( mime == NULL ) {
1111  roar_err_set(ROAR_ERROR_FAULT);
1112  return -1;
1113 }
1114
1115 if ( *mime == 0 ) {
1116  roar_err_set(ROAR_ERROR_INVAL);
1117  return -1;
1118 }
1119
1120 for (i = 0; _libroar_codec[i].codec != (uint32_t)-1; i++)
1121  if ( _libroar_codec[i].mime != NULL )
1122   if ( strcasecmp(_libroar_codec[i].mime, mime) == 0 )
1123    return _libroar_codec[i].codec;
1124
1125 roar_err_set(ROAR_ERROR_NOENT);
1126 return -1;
1127}
1128
1129const char * roar_codec2mime (const uint32_t   codec) {
1130 size_t i;
1131
1132 for (i = 0; _libroar_codec[i].codec != (uint32_t)-1; i++)
1133  if ( _libroar_codec[i].codec == codec )
1134   return _libroar_codec[i].mime;
1135
1136 roar_err_set(ROAR_ERROR_NOENT);
1137 return NULL;
1138}
1139
1140int32_t roar_str2rate(const char * rate) {
1141 struct roar_audio_info info;
1142 int ret;
1143
1144 if ( roar_profile2info(&info, rate) != -1 ) {
1145  return info.rate;
1146 }
1147
1148 ret = atoi(rate);
1149
1150 if ( ret == 0 && rate[0] != '0' ) {
1151  roar_err_set(ROAR_ERROR_NOENT);
1152  return -1;
1153 }
1154
1155 return ret;
1156}
1157
1158int32_t roar_str2bits(const char * bits) {
1159 struct roar_audio_info info;
1160 int ret;
1161
1162 if ( roar_profile2info(&info, bits) != -1 ) {
1163  return info.bits;
1164 }
1165
1166 ret = atoi(bits);
1167
1168 if ( ret == 0 && bits[0] != '0' ) {
1169  roar_err_set(ROAR_ERROR_NOENT);
1170  return -1;
1171 }
1172
1173 return ret;
1174}
1175
1176int32_t roar_str2channels(const char * channels) {
1177 struct roar_audio_info info;
1178 int ret;
1179
1180 if ( !strcasecmp(channels, "mono") ) {
1181  return 1;
1182 } else if ( !strcasecmp(channels, "stereo") ) {
1183  return 2;
1184 }
1185
1186 if ( roar_profile2info(&info, channels) != -1 ) {
1187  return info.channels;
1188 }
1189
1190 ret = atoi(channels);
1191
1192 if ( ret == 0 && channels[0] != '0' ) {
1193  roar_err_set(ROAR_ERROR_NOENT);
1194  return -1;
1195 }
1196
1197 return ret;
1198}
1199
1200
1201const char * roar_streamstate2str(int streamstate) {
1202 switch (streamstate) {
1203  case ROAR_STREAMSTATE_UNUSED:  return "unused";  break;
1204  case ROAR_STREAMSTATE_INITING: return "initing"; break;
1205  case ROAR_STREAMSTATE_NEW:     return "new";     break;
1206  case ROAR_STREAMSTATE_OLD:     return "old";     break;
1207  case ROAR_STREAMSTATE_CLOSING: return "closing"; break;
1208 }
1209
1210 return "unknown";
1211}
1212
1213static const struct {
1214 int    role;
1215 const char * name;
1216} _libroar_role[] = {
1217 {ROAR_ROLE_UNKNOWN,          "unknown"         },
1218 {ROAR_ROLE_NONE,             "none"            },
1219 {ROAR_ROLE_MUSIC,            "music"           },
1220 {ROAR_ROLE_VIDEO,            "video"           },
1221 {ROAR_ROLE_GAME,             "game"            },
1222 {ROAR_ROLE_EVENT,            "event"           },
1223 {ROAR_ROLE_BEEP,             "beep"            },
1224 {ROAR_ROLE_PHONE,            "phone"           },
1225 {ROAR_ROLE_BACKGROUND_MUSIC, "background music"},
1226 {ROAR_ROLE_BACKGROUND_MUSIC, "background_music"}, // alias
1227 {ROAR_ROLE_VOICE,            "voice"           },
1228 {ROAR_ROLE_INSTRUMENT,       "instrument"      },
1229 {ROAR_ROLE_RHYTHM,           "rhythm"          },
1230 {ROAR_ROLE_CLICK,            "click",          },
1231 {ROAR_ROLE_MIXED,            "mixed",          },
1232 {-1, NULL}
1233};
1234
1235int    roar_str2role  (const char * role) {
1236 int i;
1237
1238 roar_err_clear();
1239
1240 for (i = 0; _libroar_role[i].name != NULL; i++)
1241  if ( !strcasecmp(_libroar_role[i].name, role) )
1242   return _libroar_role[i].role;
1243
1244 roar_err_set(ROAR_ERROR_NOENT);
1245 return ROAR_ROLE_UNKNOWN;
1246}
1247
1248const char * roar_role2str  (const int    role) {
1249 int i;
1250
1251 for (i = 0; _libroar_role[i].name != NULL; i++)
1252  if ( _libroar_role[i].role == role )
1253   return _libroar_role[i].name;
1254
1255 return "unknown";
1256}
1257
1258const char * roar_rpgmode2str(const int rpgmode) {
1259 switch (rpgmode) {
1260  case ROAR_RPGMODE_DEFAULT:    return "default"; break;
1261  case ROAR_RPGMODE_NONE:       return "none"; break;
1262  case ROAR_RPGMODE_USER:       return "user"; break;
1263  case ROAR_RPGMODE_ALBUM:      return "album"; break;
1264  case ROAR_RPGMODE_TRACK:      return "track"; break;
1265  case ROAR_RPGMODE_ALBUMTRACK: return "albumtrack"; break;
1266  case ROAR_RPGMODE_TRACKALBUM: return "trackalbum"; break;
1267  default:
1268    roar_err_set(ROAR_ERROR_NOENT);
1269    return NULL;
1270   break;
1271 }
1272}
1273
1274ssize_t roar_info2samplesize (struct roar_audio_info * info) {
1275 if ( info == NULL ) {
1276  roar_err_set(ROAR_ERROR_FAULT);
1277  return -1;
1278 }
1279
1280 switch (info->codec) {
1281  case ROAR_CODEC_PCM_S_LE:
1282  case ROAR_CODEC_PCM_S_BE:
1283  case ROAR_CODEC_PCM_S_PDP:
1284  case ROAR_CODEC_PCM_U_LE:
1285  case ROAR_CODEC_PCM_U_BE:
1286  case ROAR_CODEC_PCM_U_PDP:
1287    return info->bits;
1288   break;
1289  case ROAR_CODEC_ALAW:
1290  case ROAR_CODEC_MULAW:
1291    return 8;
1292   break;
1293  case ROAR_CODEC_DMX512:
1294    return 8;
1295   break;
1296  case ROAR_CODEC_RDS:
1297    return 26;
1298   break;
1299  default:
1300    roar_err_set(ROAR_ERROR_INVAL);
1301    return -1;
1302   break;
1303 }
1304}
1305
1306ssize_t roar_info2framesize  (struct roar_audio_info * info) {
1307 ssize_t ret = roar_info2samplesize(info);
1308
1309 if ( ret == -1 )
1310  return -1;
1311
1312 ret *= info->channels;
1313
1314 return ret;
1315}
1316
1317ssize_t roar_info2bitspersec(struct roar_audio_info * info) {
1318 ssize_t ret = roar_info2samplesize(info);
1319
1320 if ( ret == -1 )
1321  return -1;
1322
1323 ret *= info->channels * info->rate;
1324
1325 return ret;
1326}
1327
1328static const struct {
1329 const char * name;
1330 struct roar_audio_info info;
1331} _libroar_aiprofiles[] = {
1332 {"default",   {.rate     = ROAR_RATE_DEFAULT,
1333                .bits     = ROAR_BITS_DEFAULT,
1334                .channels = ROAR_CHANNELS_DEFAULT,
1335                .codec    = ROAR_CODEC_DEFAULT}},
1336 {"default-server",
1337               {.rate     = ROAR_RATE_DEFAULT,
1338                .bits     = ROAR_ROARD_BITS,
1339                .channels = ROAR_CHANNELS_DEFAULT,
1340                .codec    = ROAR_CODEC_DEFAULT}},
1341 {"wav",       {.rate     = ROAR_RATE_DEFAULT,
1342                .bits     = ROAR_BITS_DEFAULT,
1343                .channels = ROAR_CHANNELS_DEFAULT,
1344                .codec    = ROAR_CODEC_RIFF_WAVE}},
1345 {"au",        {.rate     = ROAR_RATE_DEFAULT,
1346                .bits     = ROAR_BITS_DEFAULT,
1347                .channels = ROAR_CHANNELS_DEFAULT,
1348                .codec    = ROAR_CODEC_AU}},
1349 {"cd",        {.rate =  44100, .bits = 16, .channels =  2, .codec = ROAR_CODEC_DEFAULT}},
1350 {"cdr",       {.rate =  44100, .bits = 16, .channels =  2, .codec = ROAR_CODEC_PCM_S_BE}},
1351 {"dat",       {.rate =  48000, .bits = 16, .channels =  2, .codec = ROAR_CODEC_PCM_S_LE}},
1352 {"isdn-eu",   {.rate =   8000, .bits =  8, .channels =  1, .codec = ROAR_CODEC_ALAW}},
1353 {"isdn-na",   {.rate =   8000, .bits =  8, .channels =  1, .codec = ROAR_CODEC_MULAW}},
1354 {"speex-nb",  {.rate =   8000, .bits = 16, .channels =  2, .codec = ROAR_CODEC_ROAR_SPEEX}},
1355 {"speex-wb",  {.rate =  16000, .bits = 16, .channels =  2, .codec = ROAR_CODEC_ROAR_SPEEX}},
1356 {"speex-uwb", {.rate =  32000, .bits = 16, .channels =  2, .codec = ROAR_CODEC_ROAR_SPEEX}},
1357 {"ogg-vorbis",{.rate =  44100, .bits = 16, .channels =  2, .codec = ROAR_CODEC_OGG_VORBIS}},
1358 {"gsm",       {.rate =   8000, .bits = 16, .channels =  1, .codec = ROAR_CODEC_GSM}},
1359 {"brr",       {.rate =   8000, .bits = 32, .channels =  1, .codec = ROAR_CODEC_BRR}},
1360 {"brr6k",     {.rate =   6000, .bits = 32, .channels =  1, .codec = ROAR_CODEC_BRR}},
1361 {"rds",       {.rate =      0, .bits =  0, .channels =  0, .codec = ROAR_CODEC_RDS}},
1362 {"midi",      {.rate =      0, .bits =  8, .channels = 16, .codec = ROAR_CODEC_MIDI}},
1363 {"dmx512",    {.rate =      0, .bits =  8, .channels =  0, .codec = ROAR_CODEC_DMX512}},
1364 {NULL,        {.rate =      0, .bits =  0, .channels =  0, .codec = 0}}
1365};
1366
1367int     roar_profile2info    (struct roar_audio_info * info, const char * profile) {
1368 int i;
1369
1370 if ( info == NULL || profile == NULL ) {
1371  roar_err_set(ROAR_ERROR_FAULT);
1372  return -1;
1373 }
1374
1375 for (i = 0; _libroar_aiprofiles[i].name != NULL; i++) {
1376  if ( !strcasecmp(_libroar_aiprofiles[i].name, profile) ) {
1377   memcpy(info, &(_libroar_aiprofiles[i].info), sizeof(struct roar_audio_info));
1378   return 0;
1379  }
1380 }
1381
1382 roar_err_set(ROAR_ERROR_NOENT);
1383 return -1;
1384}
1385
1386ssize_t   roar_profiles_list   (const char ** list, size_t len, size_t offset) {
1387 size_t i;
1388 ssize_t idx = 0;
1389
1390 if ( list == NULL ) {
1391  roar_err_set(ROAR_ERROR_FAULT);
1392  return -1;
1393 }
1394
1395 if ( len == 0 )
1396  return 0;
1397
1398 if ( offset >= (sizeof(_libroar_aiprofiles)/sizeof(*_libroar_aiprofiles)) )
1399  return 0;
1400
1401 for (i = offset; idx < len && _libroar_aiprofiles[i].name != NULL; i++) {
1402  list[idx++] = _libroar_aiprofiles[i].name;
1403 }
1404
1405 return idx;
1406}
1407
1408//ll
Note: See TracBrowser for help on using the repository browser.