source: roaraudio/roarclients/roarinterconnect.c @ 5439:7950543cabbc

Last change on this file since 5439:7950543cabbc was 5381:430b1d26e12d, checked in by phi, 12 years ago

updated copyright years

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