source: roaraudio/roarclients/roarinterconnect.c @ 6046:7782f552c25c

Last change on this file since 6046:7782f552c25c was 5961:06e7fd9e4c25, checked in by phi, 10 years ago

Updates of copyright and license headers

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