source: roaraudio/roarclients/roarinterconnect.c @ 4922:a207c353cc15

Last change on this file since 4922:a207c353cc15 was 4922:a207c353cc15, checked in by phi, 13 years ago

use new target syntax of ckport

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