source: roaraudio/roarclients/roarinterconnect.c @ 3929:4663575733dd

Last change on this file since 3929:4663575733dd was 3929:4663575733dd, checked in by phi, 14 years ago

implemneted rsoudn support

File size: 12.4 KB
Line 
1//roarinterconnect.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2009-2010
5 *
6 *  This file is part of roarclients 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 *  RoarAudio 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 */
25
26// configure ROAR_INFO()
27int g_verbose = 0;
28#define ROAR_DBG_INFOVAR g_verbose
29
30#include <roaraudio.h>
31#include <libroareio/libroareio.h>
32
33#ifdef ROAR_HAVE_ESD
34#include <esd.h>
35#endif
36
37#ifdef ROAR_HAVE_LIBRSOUND
38#include <rsound.h>
39#ifdef RSD_EXEC
40#define _HAVE_RSOUND
41#endif
42#endif
43
44#if defined(ROAR_HAVE_OSS_BSD) || defined(ROAR_HAVE_OSS)
45#define _HAVE_OSS
46#endif
47
48#define MT_NONE     0x00
49#define MT_MASK     0xF0
50#define MT_ROAR     0x10
51#define MT_ESD      0x20
52#define MT_SIMPLE   0x30
53#define MT_OSS      0x40
54#define MT_RSOUND   0x50
55#define MT_DEFAULT  MT_ROAR
56
57#define ST_NONE     0x00
58#define ST_MASK     0x0F
59#define ST_BIDIR    0x01
60#define ST_FILTER   0x02
61#define ST_TRANSMIT 0x03
62#define ST_RECEIVE  0x04
63// no default here as the default depend on the server type
64
65void usage (void) {
66 printf("roarinterconnect [OPTIONS]...\n");
67
68 printf("\nOptions:\n\n");
69
70 printf("  --server SERVER    - Set server hostname\n"
71        "  --remote SERVER    - Set remote server\n"
72        "  --type   TYPE      - Set type of remote server\n"
73        "  --rate   RATE      - Set sample rate\n"
74        "  --bits   BITS      - Set bits per sample\n"
75        "  --chans  CHANNELS  - Set number of channels\n"
76        "  --codec  CODEC     - Set the codec\n"
77        "  --help             - Show this help\n"
78        "  --verbose -v       - Be verbose\n"
79       );
80
81 printf("\nPossible Types:\n\n");
82 printf("  roar               - RoarAudio Server\n"
83#ifdef ROAR_HAVE_ESD
84        "  esd                - EsounD Server\n"
85#endif
86        "  simple             - PulseAudio using simple protocol\n"
87#ifdef _HAVE_OSS
88        "  oss                - Open Sound System (OSS) device\n"
89#endif
90#ifdef _HAVE_RSOUND
91        "  rsound             - RSound server\n"
92#endif
93        "\n"
94        "  bidir              - Connect bidirectional\n"
95        "  filter             - Use local server as filter for remote server\n"
96        "  transmit           - Transmit data from local server to remote server\n"
97        "  receive            - Receive data from remote server\n"
98       );
99
100}
101
102int parse_type (char * type) {
103 int ret = MT_NONE|ST_NONE;
104 char * colon;
105
106 if ( type != NULL ) {
107  while (type != NULL && *type) {
108   if ( (colon = strstr(type, ":")) != NULL ) {
109    *colon = 0;
110     colon++;
111   }
112
113   if ( !strcmp(type, "roar") ) {
114    ret -= ret & MT_MASK;
115    ret += MT_ROAR;
116   } else if ( !strcmp(type, "esd") ) {
117    ret -= ret & MT_MASK;
118    ret += MT_ESD;
119   } else if ( !strcmp(type, "simple") ) {
120    ret -= ret & MT_MASK;
121    ret += MT_SIMPLE;
122   } else if ( !strcmp(type, "oss") ) {
123    ret -= ret & MT_MASK;
124    ret += MT_OSS;
125   } else if ( !strcmp(type, "rsound") ) {
126    ret -= ret & MT_MASK;
127    ret += MT_RSOUND;
128   } else if ( !strcmp(type, "bidir") ) {
129    ret -= ret & ST_MASK;
130    ret += ST_BIDIR;
131   } else if ( !strcmp(type, "filter") ) {
132    ret -= ret & ST_MASK;
133    ret += ST_FILTER;
134   } else if ( !strcmp(type, "transmit") ) {
135    ret -= ret & ST_MASK;
136    ret += ST_TRANSMIT;
137   } else if ( !strcmp(type, "receive") ) {
138    ret -= ret & ST_MASK;
139    ret += ST_RECEIVE;
140   } else {
141    return MT_NONE|ST_NONE;
142   }
143
144   type = colon;
145  }
146 }
147
148 if ( (ret & MT_MASK) == MT_NONE )
149  ret |= MT_DEFAULT;
150
151 if ( (ret & ST_MASK) == ST_NONE ) {
152  switch (ret & MT_MASK) {
153   case MT_ROAR:   ret |= ST_BIDIR;    break;
154   case MT_ESD:    ret |= ST_FILTER;   break;
155   case MT_SIMPLE: ret |= ST_TRANSMIT; break; // we use ST_TRANSMIT because ST_BIDIR is
156                                              // very unlike to be configured at the server side.
157   case MT_OSS:    ret |= ST_BIDIR;    break;
158   case MT_RSOUND: ret |= ST_TRANSMIT; break; // RSound does only handle playback streams.
159   default:
160     return MT_NONE|ST_NONE; // error case
161    break;
162  }
163 }
164
165 return ret;
166}
167
168#ifdef _HAVE_RSOUND
169// RSound format helper function:
170enum rsd_format para2rsdfmt (int bits, int codec) {
171 switch (codec) {
172/*
173      RSD_S16_LE = 0x0001,
174      RSD_S16_BE = 0x0002,
175      RSD_U16_LE = 0x0004,
176      RSD_U16_BE = 0x0008,
177      RSD_U8     = 0x0010,
178      RSD_S8     = 0x0020,
179      RSD_S16_NE = 0x0040,
180      RSD_U16_NE = 0x0080,
181*/
182  case ROAR_CODEC_PCM_S_LE:
183    switch (bits) {
184#ifdef RSD_S8
185     case  8: return RSD_S8;     break;
186#endif
187#ifdef RSD_S16_LE
188     case 16: return RSD_S16_LE; break;
189#endif
190    }
191   break;
192  case ROAR_CODEC_PCM_S_BE:
193    switch (bits) {
194#ifdef RSD_S8
195     case  8: return RSD_S8;     break;
196#endif
197#ifdef RSD_S16_BE
198     case 16: return RSD_S16_BE; break;
199#endif
200    }
201   break;
202  case ROAR_CODEC_PCM_U_LE:
203    switch (bits) {
204#ifdef RSD_U8
205     case  8: return RSD_U8;     break;
206#endif
207#ifdef RSD_U16_LE
208     case 16: return RSD_U16_LE; break;
209#endif
210    }
211   break;
212  case ROAR_CODEC_PCM_U_BE:
213    switch (bits) {
214#ifdef RSD_U8
215     case  8: return RSD_U8;     break;
216#endif
217#ifdef RSD_U16_BE
218     case 16: return RSD_U16_BE; break;
219#endif
220    }
221   break;
222#ifdef RSD_ALAW
223  case ROAR_CODEC_ALAW:
224    return RSD_ALAW;
225   break;
226#endif
227#ifdef RSD_MULAW
228  case ROAR_CODEC_MULAW:
229    return RSD_MULAW;
230   break;
231#endif
232 }
233 return 0;
234}
235#endif
236
237int main (int argc, char * argv[]) {
238 struct roar_connection con[1];
239 struct roar_stream     stream[1];
240#ifdef _HAVE_OSS
241 struct roar_vio_calls  vio;
242 struct roar_audio_info info;
243#endif
244#ifdef _HAVE_RSOUND
245 rsound_t *rd;
246 enum rsd_format fmt = 0;
247#endif
248 int    rate     = 44100;
249 int    bits     = 16;
250 int    channels = 2;
251 int    codec    = ROAR_CODEC_DEFAULT;
252 int    type     = parse_type(NULL);
253 int    tmp;
254 char * server   = NULL;
255 char * remote   = "+slp"; // we hope SLP located server is not local one
256 char * k;
257 int    rfh;
258 int    i;
259 int    localdir = ROAR_DIR_BIDIR;
260 int    rport;
261
262 for (i = 1; i < argc; i++) {
263  k = argv[i];
264
265  if ( strcmp(k, "--server") == 0 ) {
266   server = argv[++i];
267  } else if ( strcmp(k, "--remote") == 0 ) {
268   remote = argv[++i];
269  } else if ( strcmp(k, "--type") == 0 ) {
270   type = parse_type(argv[++i]);
271  } else if ( strcmp(k, "--rate") == 0 ) {
272   rate = atoi(argv[++i]);
273  } else if ( strcmp(k, "--bits") == 0 ) {
274   bits = atoi(argv[++i]);
275  } else if ( strcmp(k, "--channels") == 0 || strcmp(k, "--chans") == 0 ) {
276   channels = atoi(argv[++i]);
277  } else if ( strcmp(k, "--codec") == 0 ) {
278   codec = roar_str2codec(argv[++i]);
279  } else if ( strcmp(k, "--verbose") == 0 || strcmp(k, "-v") == 0 ) {
280   g_verbose++;
281  } else if ( strcmp(k, "--help") == 0 ) {
282   usage();
283   return 0;
284  } else {
285   fprintf(stderr, "Error: unknown argument: %s\n", k);
286   usage();
287   return 1;
288  }
289 }
290
291 switch (type & MT_MASK) {
292  case MT_ROAR:
293    switch (type & ST_MASK) {
294     case ST_BIDIR:
295       tmp      = ROAR_DIR_BIDIR;
296      break;
297     case ST_FILTER:
298       tmp      = ROAR_DIR_FILTER;
299      break;
300     case ST_TRANSMIT:
301       tmp      = ROAR_DIR_PLAY;
302       localdir = ROAR_DIR_MONITOR;
303      break;
304     case ST_RECEIVE:
305       tmp      = ROAR_DIR_MONITOR;
306       localdir = ROAR_DIR_PLAY;
307      break;
308     default:
309       fprintf(stderr, "Error: unknown stream type\n");
310       return 2;
311    }
312    rfh = roar_simple_stream(rate, channels, bits, codec, remote, tmp, "roarinterconnect");
313   break;
314#ifdef _HAVE_OSS
315  case MT_OSS:
316    switch (type & ST_MASK) {
317     case ST_BIDIR:
318       tmp      = ROAR_DIR_BIDIR;
319      break;
320     case ST_TRANSMIT:
321       tmp      = ROAR_DIR_PLAY;
322       localdir = ROAR_DIR_MONITOR;
323      break;
324     case ST_RECEIVE:
325       tmp      = ROAR_DIR_RECORD;
326       localdir = ROAR_DIR_PLAY;
327      break;
328     default:
329       fprintf(stderr, "Error: unknown stream type\n");
330       return 2;
331    }
332    info.rate     = rate;
333    info.channels = channels;
334    info.bits     = bits;
335    info.codec    = codec;
336    if ( roar_cdriver_oss(&vio, "OSS", remote, &info, tmp) == -1 ) {
337     fprintf(stderr, "Error: can not open OSS device %s\n", remote);
338     return 2;
339    }
340    if ( roar_vio_ctl(&vio, ROAR_VIO_CTL_GET_FH, &rfh) == -1 ) {
341     roar_vio_close(&vio);
342     fprintf(stderr, "Error: can not get filehandle for OSS device %s\n", remote);
343     return 2;
344    }
345   break;
346#endif
347#ifdef ROAR_HAVE_ESD
348  case MT_ESD:
349    tmp = ESD_STREAM|ESD_PLAY;
350
351    switch (bits) {
352     case  8: tmp |= ESD_BITS8;  break;
353     case 16: tmp |= ESD_BITS16; break;
354     default:
355       fprintf(stderr, "Error: EsounD only supports 8 and 16 bit streams\n");
356       return 2;
357    }
358
359    switch (channels) {
360     case 1: tmp |= ESD_MONO;   break;
361     case 2: tmp |= ESD_STEREO; break;
362     default:
363       fprintf(stderr, "Error: EsounD only supports mono and stereo streams\n");
364       return 2;
365    }
366
367    // TODO: FIXME: this is only true if the esd runs on a LE system,...
368    if ( bits == 8 && codec != ROAR_CODEC_PCM_U_LE ) {
369     fprintf(stderr, "Error: EsounD only supports unsigned PCM in 8 bit mode\n");
370     return 2;
371    } else if ( bits == 16 && codec != ROAR_CODEC_DEFAULT ) {
372     fprintf(stderr, "Error: EsounD only supports signed PCM in 16 bit mode\n");
373     return 2;
374    }
375
376    switch (type & ST_MASK) {
377     case ST_FILTER:
378       rfh = esd_filter_stream(tmp, rate, remote, "roarinterconnect");
379      break;
380     case ST_TRANSMIT:
381       rfh = esd_play_stream(tmp, rate, remote, "roarinterconnect");
382      break;
383     case ST_RECEIVE:
384       rfh = esd_monitor_stream(tmp, rate, remote, "roarinterconnect");
385      break;
386     default:
387       fprintf(stderr, "Error: this type is not supported by EsounD\n");
388       return 2;
389      break;
390    }
391   break;
392#endif
393#ifdef _HAVE_RSOUND
394  case MT_RSOUND:
395    fmt = para2rsdfmt(bits, codec);
396
397    if ( fmt == 0 ) {
398     fprintf(stderr, "Error: Bits/Codec not supported by RSound\n");
399     return 2;
400    }
401
402    switch (type & ST_MASK) {
403     case ST_TRANSMIT:
404       localdir = ROAR_DIR_MONITOR;
405
406       rsd_init(&rd);
407       rsd_set_param(rd, RSD_HOST,       remote);
408       rsd_set_param(rd, RSD_CHANNELS,   &channels);
409       rsd_set_param(rd, RSD_SAMPLERATE, &rate);
410       rsd_set_param(rd, RSD_FORMAT,     &fmt);
411       rfh = rsd_exec(rd);
412       if ( rfh == -1 ) {
413        rsd_stop(rd);
414        rsd_free(rd);
415       }
416      break;
417     default:
418       fprintf(stderr, "Error: this type is not supported by RSound\n");
419       return 2;
420      break;
421    }
422   break;
423#endif
424  case MT_SIMPLE:
425    switch (type & ST_MASK) {
426     case ST_BIDIR:
427       tmp = -1;
428       localdir = ROAR_DIR_BIDIR;
429      break;
430     case ST_TRANSMIT:
431       tmp = SHUT_RD;
432       localdir = ROAR_DIR_MONITOR;
433      break;
434     case ST_RECEIVE:
435       tmp = SHUT_WR;
436       localdir = ROAR_DIR_PLAY;
437      break;
438     default:
439       fprintf(stderr, "Error: this type is not supported by PulseAudio\n");
440       return 2;
441    }
442    // we guess INET here...
443    if ( strstr(remote, "/") == NULL && (k = strstr(remote, ":")) != NULL ) {
444     *k = 0;
445     k++;
446     rport = atoi(k);
447    } else {
448     rport = 4712;
449    }
450    rfh = roar_socket_connect(remote, rport);
451    if ( tmp != -1 ) {
452     ROAR_SHUTDOWN(rfh, tmp);
453    }
454   break;
455  default:
456    fprintf(stderr, "Error: unknown/not supported server type\n");
457    return 2;
458 }
459
460 if ( rfh == -1 ) {
461  fprintf(stderr, "Error: can not connect to remote server\n");
462  return 10;
463 }
464
465 if ( roar_simple_connect(con, server, "roarinterconnect") == -1 ) {
466  fprintf(stderr, "Can not connect to local server\n");
467  return 20;
468 }
469
470 if ( roar_stream_new(stream, rate, channels, bits, codec) == -1 ) {
471  roar_disconnect(con);
472  return 21;
473 }
474
475 if ( roar_stream_connect(con, stream, localdir) == -1 ) {
476  roar_disconnect(con);
477  return 22;
478 }
479
480 if ( roar_stream_passfh(con, stream, rfh) == -1 ) {
481  roar_disconnect(con);
482  return 23;
483 }
484
485 roar_simple_close(rfh);
486
487 if ( roar_stream_attach_simple(con, stream, 0) == -1 ) {
488  fprintf(stderr, "Can not attach remote stream to local server\n");
489 }
490
491 roar_disconnect(con);
492
493 ROAR_INFO("Stream ID: %i", 1, stream->id);
494
495 return 0;
496}
497
498//ll
Note: See TracBrowser for help on using the repository browser.