source: roaraudio/roard/roard.c @ 4053:8d01989324d4

Last change on this file since 4053:8d01989324d4 was 4053:8d01989324d4, checked in by phi, 14 years ago

better error text

File size: 58.5 KB
RevLine 
[0]1//roard.c:
2
[668]3/*
[3358]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2010
[668]5 *
6 *  This file is part of roard 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.
[668]23 *
24 */
25
[0]26#include "roard.h"
27
[1494]28#ifdef ROAR_SUPPORT_LISTEN
[2530]29char * server[ROAR_MAX_LISTEN_SOCKETS];
[1494]30#endif
[60]31
[2104]32#if defined(ROAR_HAVE_IO_POSIX) && defined(ROAR_HAVE_FS_POSIX)
33#define SUPPORT_PIDFILE
34char * pidfile = NULL;
35#endif
36
[2530]37#if defined(ROAR_HAVE_SETGID) || defined(ROAR_HAVE_SETUID)
[3374]38int    setids    = 0;
39#endif
40
41#ifdef ROAR_HAVE_LIBX11
42char * x11display = NULL;
[2530]43#endif
44
[1503]45#ifdef ROAR_HAVE_MAIN_ARGS
[0]46void usage (void) {
47 printf("Usage: roard [OPTIONS]...\n\n");
48
[68]49 printf("Misc Options:\n\n");
50 printf(
[775]51        " --daemon              - Bring the server into background after init\n"
[2970]52        " --verbose             - Be more verbose, can be used multiple times\n"
[71]53        " --terminate           - Terminate after last client quited\n"
[2109]54        " --start               - No op parameter (starting roard is default operation)\n"
[274]55        " --restart             - Trys to stop an old instance and start a new with new settings\n"
[2109]56        " --stop                - Stops a running roard (provide --pidfile!)\n"
57        " --shutdown            - Terminates a running roard (provide --pidfile!)\n"
[276]58        " --realtime            - Trys to get realtime priority,\n"
59        "                         give multible times for being more realtime\n"
[444]60        " --chroot DIR          - chroots to the given dir\n"
61        " --setgid              - GroupID to the audio group as specified via -G\n"
62        " --setuid              - UserID to the audio user as specified via -U\n"
[905]63        " --sysclocksync        - calculate exact sample rate using the system clock\n"
[2017]64        " --location  LOC       - Set lion readable location of server\n"
[2104]65#ifdef SUPPORT_PIDFILE
66        " --pidfile PIDFILE     - Write a pidfile at PIDFILE\n"
67#endif
[3688]68#ifdef ROAR_HAVE_SYSLOG
69        " --log-syslog          - Log Warnings, Errors, ... to syslog\n"
70#endif
[68]71       );
72
[3356]73 printf("\nPlugin Options:\n\n");
74 printf(
75        " --plugin-load FILE    - Load plugin FILE\n"
76       );
77
[68]78 printf("\nAudio Options:\n\n");
[0]79 printf(
80        " -R  --rate   RATE     - Set server rate\n"
81        " -B  --bits   BITS     - Set server bits\n"
82        " -C  --chans  CHANNELS - Set server channels\n"
[3963]83        " --aiprofile  PROFILE  - Use the given audio profile\n"
[0]84       );
85
[2339]86 printf("\nStream Options:\n\n");
87 printf(
88        " --stream-flags D=F    - Set default flags for stream directions\n"
[4012]89        "                         D is the stream direction and F is a comma separated\n"
[2339]90        "                         list of flags in form +flag or -flag to set or unset\n"
91        "                         a flag as default or remove it from the default\n"
92       );
93
[1923]94 printf("\nDriver Options: (obsolete, do not use, Use Ouput Options)\n\n");
[974]95 printf(" -d  --driver DRV      - Set the driver (default: %s)\n", ROAR_DRIVER_DEFAULT);
[0]96 printf(" -D  --device DEV      - Set the device\n");
97 printf(" -dO OPTS              - Set output options\n");
[973]98 printf(" --list-driver         - List all drivers\n");
[0]99
[932]100 printf("\nOutput Options:\n\n");
[974]101 printf(" -o  --odriver DRV     - Set the driver, use '--list-driver' to get a list\n");
[932]102 printf(" -O  --odevice DEV     - Set the device\n");
103 printf(" -oO OPTS              - Set output options\n");
104 printf(" -oN                   - Adds another output\n");
[961]105 printf(" -oP                   - Mark output as primary\n");
[932]106
[2485]107#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[0]108 printf("\nSource Options:\n\n");
109 printf(" -s  --source DRV      - Use DRV as input driver\n"
110        " -S           DEV      - Use DEV as input device\n"
111        " -sO          OPTS     - Use OPTS as input options\n"
[1512]112        " -sN                   - Adds another source\n"
[0]113        " -sP                   - Make souce as primary\n"
114       );
[2270]115 printf(" --list-sources        - List all sources\n");
[2485]116#endif
[0]117
[280]118 printf("\nCodec Filter Options:\n\n");
119 printf(" --list-cf             - List all codec filter\n"
120       );
[0]121
[2500]122#ifndef ROAR_WITHOUT_DCOMP_MIDI
[1923]123 printf("\nMIDI Options:\n\n");
[1924]124 printf(" --midi-no-console     - Disable console based MIDI synth\n"
[2444]125        " --midi-console-enable - Enables the console based MIDI synth\n"
[1924]126        " --midi-console DEV    - Set device for MIDI console\n"
[2489]127#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
[2451]128        " --ssynth-enable       - Enable simple software synth\n"
129        " --ssynth-disable      - Disable simple software synth\n"
[2489]130#endif
[1924]131       );
[2500]132#endif
[1923]133
[2494]134#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1923]135 printf("\nLight Control Options:\n\n");
136 printf(" --light-channels NUM  - Sets the number of channels for Light control (default: %i)\n",
137                                  LIGHT_CHANNELS_DEFAULT
138       );
[2494]139#endif
[1923]140
[2725]141#ifndef ROAR_WITHOUT_DCOMP_RDTCS
[3339]142 printf("\nRadio Data and Transmitter Control System Options:\n\n");
[2725]143 printf(" --rds-pi   PI         - Sets the RDS Programme Identification (PI)\n"
144        " --rds-ps   PS         - Sets the RDS Programme Service Name (PS)\n"
145        " --rds-pty  PTY        - Sets the RDS Programme Type (PTY)\n"
146        " --rds-tp              - Sets the RDS Traffic Programme (TP) flag\n"
147        " --rds-ct              - Enables sending of RDS Clock Time (CT)\n"
148       );
149#endif
150
[3374]151#ifdef ROAR_HAVE_LIBX11
152 printf("\nX11 Options:\n\n");
153 printf(
154        " --x11-display DISPLAY - Set display for X11\n"
155        " --display DISPLAY     - Set display for X11\n"
156       );
157#endif
158
[0]159 printf("\nServer Options:\n\n");
160 printf(" -t  --tcp             - Use TCP listen socket\n"
[3992]161#ifdef ROAR_HAVE_UNIX
[0]162        " -u  --unix            - Use UNIX Domain listen socket (default)\n"
[3992]163#endif
[508]164#ifdef ROAR_HAVE_LIBDNET
165        " -n  --decnet          - use DECnet listen socket\n"
166#endif
[518]167        " -4                    - Use IPv4 connections (implies -t)\n"
[3837]168#ifdef AF_INET6
[518]169        " -6                    - Use IPv6 connections (implies -t)\n"
170#endif
171#ifdef IPV6_ADDRFORM
172        " -64                   - Try to downgrade sockets from IPv6 into IPv4,\n"
[4012]173        "                         this is normaly not useful.\n"
[518]174#endif
[0]175        " -p  --port            - TCP Port to bind to\n"
176        " -b  --bind            - IP/Hostname to bind to\n"
[1115]177        "     --sock            - Filename for UNIX Domain Socket\n"
[2530]178        "     --proto PROTO     - Use PROTO as protocol on Socket\n"
[3252]179        "     --proto-dir DIR   - Set direction parameter for protocol\n"
180        "     --proto-rate RATE - Set sample rate parameter for protocol\n"
181        "     --proto-bits BITS - Set bits per sample parameter for protocol\n"
182        "     --proto-codec E   - Set codec parameter for protocol\n"
[4012]183        "     --proto-chans C   - Set number of channels parameter for protocol\n"
[3954]184        "     --proto-aiprofile PROFILE\n"
185        "                       - Sets the audio profile for socket\n"
[3956]186        "     --proto-profile P - Set profile for listen socket\n"
[3127]187        "     --list-proto      - List supported protocols\n"
[3956]188        "     --list-profiles   - List supported profiles for --proto-profile\n"
[2530]189        "     --new-sock        - Parameters for new socket follows\n"
[1993]190#ifdef ROAR_HAVE_LIBSLP
191        "     --slp             - Enable OpenSLP support\n"
192#endif
[3373]193#ifdef ROAR_HAVE_LIBX11
194        "     --x11             - Enable X11 support\n"
195#endif
[3039]196        " --jumbo-mtu MTU       - Sets the MTU for Jumbo Packets\n"
[450]197        " -G  GROUP             - Sets the group for the UNIX Domain Socket, (default: %s)\n"
[2737]198        "                         You need the permissions to change the GID\n"
[444]199        " -U  USER              - Sets the user for the UNIX Domain Socket, (default: do not set)\n"
[2737]200        "                         You need the permissions to change the UID (normaly only root has)\n"
[548]201        " --no-listen           - Do not listen for new clients\n"
[4012]202        "                         (only useful for relaing, impleys --terminate)\n"
[274]203        " --client-fh           - Comunicate with a client over this handle\n"
[4012]204        "                         (only useful for relaing)\n"
[920]205        " --close-fh            - Closes the given fh\n"
206        " --standby             - Start in standby state\n"
207        " --auto-standby        - Automatical goes into standby if there are no streams\n",
[2755]208#ifdef ROAR_DEFAULT_SOCKGRP
[450]209        ROAR_DEFAULT_SOCKGRP
[2755]210#else
211        "(none)"
212#endif
[0]213       );
214// printf("\n Options:\n\n");
215 printf("\n");
216}
[3127]217
218static void list_proto (void) {
219 printf("  Protocol Flag Subsys - Description\n");
220 printf("------------------------------------------------------\n");
221 printf("  roar          WM LRX - RoarAudio native protocol\n");
222#if !defined(ROAR_WITHOUT_DCOMP_EMUL_ESD) && defined(ROAR_HAVE_H_ESD)
223 printf("  esd           W      - EsounD emulation\n");
224#endif
[3603]225#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
[3257]226 printf("  simple        WM LRX - PulseAudio simple protocol\n");
[3597]227#endif
[3684]228#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
229 printf("  rsound        W      - RSound emulation\n");
230#endif
[3981]231#ifndef ROAR_WITHOUT_DCOMP_EMUL_RPLAY
232 printf("  rplay         W      - RPlay emulation\n");
233#endif
[3127]234}
235
[1503]236#endif
[0]237
[2109]238int restart_server (char * server, int terminate) {
[579]239 struct roar_connection con;
[2111]240#ifdef ROAR_HAVE_KILL
241 char buf[80];
242 ssize_t l;
243 struct roar_vio_calls fh;
244 pid_t pid;
245 int ok;
246
247 if ( pidfile != NULL ) {
248  if ( roar_vio_open_file(&fh, pidfile, O_RDONLY, 0644) == -1 ) {
249   ROAR_WARN("restart_server(*): Can not read pidfile: %s", pidfile);
250  } else {
251   l = roar_vio_read(&fh, buf, 80);
252   roar_vio_close(&fh);
253   if ( l > 0 ) {
254    buf[l-1] = 0;
255    buf[79]  = 0;
256    pid = atoi(buf);
257    if ( terminate ) {
[2113]258     ok = kill(pid, SIGUSR1);
[2111]259    } else {
260     ok = kill(pid, SIGINT);
261    }
262    if ( ok == 0 ) {
263     return 0;
264    } else {
265     ROAR_WARN("restart_server(*): Can not kill roard by pidfile");
266    }
267   } else {
268    ROAR_WARN("restart_server(*): Can not find a PID in the pidfile");
269   }
270  }
271 }
272#endif
[2109]273
[579]274 if ( roar_connect(&con, server) == -1 ) {
275  return -1;
276 }
277
[2109]278 if ( roar_terminate(&con, terminate) == -1 ) {
[579]279  return -1;
280 }
281
282 return roar_disconnect(&con);
283}
284
[444]285#define R_SETUID 1
286#define R_SETGID 2
287
[1609]288int init_config (void) {
289 int i;
290
291 memset(g_config, 0, sizeof(struct roard_config));
292
293 for (i = 0; i < ROAR_DIR_DIRIDS; i++) {
294  g_config->streams[i].mixer_channels = 1;
295  g_config->streams[i].mixer.rpg_mul  = 1;
296  g_config->streams[i].mixer.rpg_div  = 1;
297  g_config->streams[i].mixer.scale    = 65535;
298  g_config->streams[i].mixer.mixer[0] = g_config->streams[i].mixer.scale;
299 }
300
[2291]301 g_config->streams[ROAR_DIR_PLAY    ].flags = ROAR_FLAG_META;
[2413]302 g_config->streams[ROAR_DIR_OUTPUT  ].flags = ROAR_FLAG_PASSMIXER;
[2264]303 g_config->streams[ROAR_DIR_FILTER  ].flags = ROAR_FLAG_SYNC;
[1899]304 g_config->streams[ROAR_DIR_MIDI_OUT].flags = ROAR_FLAG_SYNC;
[2160]305 g_config->streams[ROAR_DIR_BIDIR   ].flags = ROAR_FLAG_ANTIECHO;
[1899]306
[2017]307 g_config->location = "***default***";
308
[1609]309 return 0;
310}
311
[2530]312#ifdef ROAR_SUPPORT_LISTEN
313int init_listening (void) {
314 int i;
315
[3128]316 memset(g_listen, 0, sizeof(g_listen));
317
[2530]318 for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) {
[3128]319  g_listen[i].proto  = ROAR_PROTO_ROARAUDIO;
[2530]320  server[i]          = NULL;
321 }
322
323 return 0;
324}
325
[3731]326int get_listen(struct roard_listen ** sock, char *** sockname) {
[3730]327 int i;
328
329 if ( sock == NULL )
330  return -1;
331
332 for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) {
[3802]333  if ( ! g_listen[i].used ) {
[3730]334   server[i] = NULL;
[3731]335   *sock = &(g_listen[i]);
[3730]336
[3733]337   if ( sockname != NULL )
[3730]338    *sockname = &(server[i]);
[3733]339
340   return 0;
[3730]341  }
342 }
343
344 return -1;
345}
346
[3956]347#ifdef ROAR_SUPPORT_LISTEN
348static struct _listen_profile {
349 const char * name;
350 int          type;
351 int          port;
352 const char * sockaddr;
353 int          proto;
354 int          dir;
355 const char * aiprofile;
356 const char * desc;
357} _g_listen_profiles[] = {
358 // TODO: convert port numbers into consts!
359
360 // RoarAudio:
[3992]361#ifdef ROAR_HAVE_UNIX
[3959]362 {"roar-usock",     ROAR_SOCKET_TYPE_UNIX,   0,                 "~/.roar",          ROAR_PROTO_ROARAUDIO, -1, NULL, NULL},
[3956]363 {"roar-gsock",     ROAR_SOCKET_TYPE_UNIX,   0,                 "/tmp/roar",        ROAR_PROTO_ROARAUDIO, -1, NULL, NULL},
[3992]364#endif
365#ifdef ROAR_HAVE_IPV4
[3956]366 {"roar-tcp",       ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_PORT, "localhost",        ROAR_PROTO_ROARAUDIO, -1, NULL, NULL},
367 {"roar-tcp-pub",   ROAR_SOCKET_TYPE_TCP,    ROAR_DEFAULT_PORT, "0.0.0.0",          ROAR_PROTO_ROARAUDIO, -1, NULL, NULL},
[3992]368#endif
369#ifdef ROAR_HAVE_LIBDNET
[3956]370 {"roar-dnet",      ROAR_SOCKET_TYPE_DECNET, 0,                 "::roar",           ROAR_PROTO_ROARAUDIO, -1, NULL, NULL},
[3992]371#endif
372#ifdef ROAR_HAVE_UNIX
[3987]373 {"roar-abstract",  ROAR_SOCKET_TYPE_UNIX,   0,                 "+abstract",        ROAR_PROTO_ROARAUDIO, -1, NULL, NULL},
[3992]374#endif
[3956]375
376 // EsounD:
[3992]377#if !defined(ROAR_WITHOUT_DCOMP_EMUL_ESD) && defined(ROAR_HAVE_H_ESD)
378#ifdef ROAR_HAVE_UNIX
[3956]379 {"esd-unix",       ROAR_SOCKET_TYPE_UNIX,   0,                 "/tmp/.esd/socket", ROAR_PROTO_ESOUND,    -1, NULL, NULL},
[3992]380#endif
381#ifdef ROAR_HAVE_IPV4
[3956]382 {"esd-tcp",        ROAR_SOCKET_TYPE_TCP,    16001,             "localhost",        ROAR_PROTO_ESOUND,    -1, NULL, NULL},
383 {"esd-tcp-pub",    ROAR_SOCKET_TYPE_TCP,    16001,             "0.0.0.0",          ROAR_PROTO_ESOUND,    -1, NULL, NULL},
[3992]384#endif
385#endif
[3956]386
387 // RSound:
[3992]388#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
389#ifdef ROAR_HAVE_UNIX
[3966]390 {"rsound-unix",    ROAR_SOCKET_TYPE_UNIX,   0,                 "/tmp/rsound",      ROAR_PROTO_RSOUND,    -1, NULL, NULL},
[3992]391#endif
392#ifdef ROAR_HAVE_IPV4
[3956]393 {"rsound-tcp",     ROAR_SOCKET_TYPE_TCP,    12345,             "localhost",        ROAR_PROTO_RSOUND,    -1, NULL, NULL},
394 {"rsound-tcp-pub", ROAR_SOCKET_TYPE_TCP,    12345,             "0.0.0.0",          ROAR_PROTO_RSOUND,    -1, NULL, NULL},
[3992]395#endif
396#ifdef ROAR_HAVE_LIBDNET
[3956]397 {"rsound-dnet",    ROAR_SOCKET_TYPE_DECNET, 0,                 "::rsound",         ROAR_PROTO_RSOUND,    -1, NULL, NULL},
[3992]398#endif
399#endif
[3957]400
401 // PulseAudio Simple:
[3992]402#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
403#ifdef ROAR_HAVE_IPV4
[3957]404 {"pas-play-tcp",   ROAR_SOCKET_TYPE_TCP,    4712,              "0.0.0.0",          ROAR_PROTO_SIMPLE,
405                                                                                    ROAR_DIR_PLAY, "default",
406                                                                                    NULL},
407 {"pas-mon-tcp",    ROAR_SOCKET_TYPE_TCP,    4712,              "0.0.0.0",          ROAR_PROTO_SIMPLE,
408                                                                                    ROAR_DIR_MONITOR, "default",
409                                                                                    NULL},
[3992]410#endif
411#endif
[3987]412
413 // RPlay:
[3992]414#ifndef ROAR_WITHOUT_DCOMP_EMUL_RPLAY
415#ifdef ROAR_HAVE_IPV4
[3987]416 {"rplay-tcp",      ROAR_SOCKET_TYPE_TCP,    5556,              "localhost",        ROAR_PROTO_RPLAY,     -1, NULL, NULL},
417 {"rplay-tcp-pub",  ROAR_SOCKET_TYPE_TCP,    5556,              "0.0.0.0",          ROAR_PROTO_RPLAY,     -1, NULL, NULL},
[3992]418#endif
419#endif
[3987]420
421 // End of List:
[3956]422 {NULL, -1, -1, NULL, -1, -1, NULL, NULL}
423};
424
425void listen_listen_profiles (void) {
426 struct _listen_profile * p;
427 char * type;
428 int i;
[3987]429 char port[8];
[3956]430
[3990]431 printf("Name           Type    Address          Port    Protocol  Dir        Audio Profile - Description\n");
[3956]432 printf("------------------------------------------------------------------------------------------------\n");
433      //roar-tcp-pub 0.0.0.0       16002   RoarAudio unknown    (null) - (null)
434
435 for (i = 0; (p = &(_g_listen_profiles[i]))->name != NULL; i++) {
436  switch (p->type) {
437   case ROAR_SOCKET_TYPE_UNIX:   type = "UNIX";   break;
438   case ROAR_SOCKET_TYPE_TCP:    type = "TCP";    break;
439   case ROAR_SOCKET_TYPE_DECNET: type = "DECnet"; break;
440   default:
441     type = "unknown";
442    break;
443  }
[3987]444
445  if ( p->port ) {
[4049]446   snprintf(port, sizeof(port)-1, "%i", p->port);
447   port[sizeof(port)-1] = 0;
[3987]448  } else {
449   strcpy(port, "(none)");
450  }
451
452  printf("%-14s %-7s %-16s %-7s %-9s %-10s %-13s - %s\n",
[3956]453           p->name,
454           type,
[3987]455           p->sockaddr, port,
[3956]456           roar_proto2str(p->proto),
[3957]457           p->dir == -1 ? "(none)" : roar_dir2str(p->dir), p->aiprofile == NULL ? "(none)" : p->aiprofile,
[3956]458           p->desc == NULL ? "" : p->desc);
459 }
460}
461
462int get_listen_profile (const char * name,
463                        int * port, char ** sockaddr, int * type,
464                        int * proto,
465                        int * dir, struct roar_audio_info * info) {
466 static char buf[1024];
467 struct _listen_profile * p;
468 int i;
469
470 for (i = 0; (p = &(_g_listen_profiles[i]))->name != NULL; i++) {
471  if ( !strcasecmp(p->name, name) ) {
472   *port     = p->port;
473
[3959]474   if ( p->type == ROAR_SOCKET_TYPE_UNIX && p->sockaddr[0] != '+' ) {
475    roar_env_render_path_r(buf, sizeof(buf), p->sockaddr);
476   } else {
477    strncpy(buf, p->sockaddr, sizeof(buf));
478   }
[3956]479   *sockaddr = buf;
480
481   *proto    = p->proto;
482   *dir      = p->dir;
483
484   if ( p->aiprofile != NULL ) {
485    if ( roar_profile2info(info, p->aiprofile) == -1 ) {
486     ROAR_ERR("Unknown audio profile: %s", p->aiprofile);
487     return -1;
488    }
489   }
490   return 0;
491  }
492 }
493
494 return -1;
495}
496#endif
497
[3252]498int add_listen (char * addr, int port, int sock_type, char * user, char * group, int proto, int dir, struct roar_audio_info * info) {
[2530]499#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX)
500 struct group   * grp  = NULL;
501#endif
502#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
503 struct passwd  * pwd  = NULL;
504#endif
505#ifdef ROAR_HAVE_UNIX
506 char * env_roar_proxy_backup;
507#endif
508 int    sockid = -1;
[3907]509#ifdef ROAR_HAVE_UNIX
[2530]510 int    sock;
[3907]511#endif
[2530]512 int    i;
513
514 if ( *addr != 0 ) {
515  for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) {
[3802]516   if ( ! g_listen[i].used ) {
[2530]517    sockid = i;
518    break;
519   }
520  }
521
522  if ( sockid == -1 )
523   return -1;
524
[3128]525  g_listen[sockid].proto = proto;
[2530]526
527  ROAR_DBG("add_listen(*): proto=0x%.4x", proto);
528
[3802]529  if ( roar_vio_open_socket_listen(&(g_listen[sockid].sock), sock_type, addr, port) == -1 ) {
[2530]530#ifdef ROAR_HAVE_UNIX
531   if ( *addr == '/' ) {
532    if ( (env_roar_proxy_backup = getenv("ROAR_PROXY")) != NULL ) {
533     env_roar_proxy_backup = strdup(env_roar_proxy_backup);
534     unsetenv("ROAR_PROXY");
535    }
536    if ( (sock = roar_socket_connect(addr, port)) != -1 ) {
537     close(sock);
[3040]538     ROAR_ERR("Can not open listen socket: Socket allready in use");
[2530]539     return 1;
540    } else {
541     unlink(addr);
[3802]542     if ( roar_vio_open_socket_listen(&(g_listen[sockid].sock), sock_type, addr, port) == -1 ) {
[3040]543      ROAR_ERR("Can not open listen socket: %s", strerror(errno));
[2530]544      return 1;
545     }
546    }
547    if ( env_roar_proxy_backup != NULL ) {
548     setenv("ROAR_PROXY", env_roar_proxy_backup, 0);
549     free(env_roar_proxy_backup);
550    }
551#else
552   if (0) { // noop
553#endif
554   } else {
[3041]555    ROAR_ERR("Can not open listen socket: %s", strerror(errno));
[2530]556    return 1;
557   }
558  }
559
560#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX)
[2753]561  if ( group != NULL ) {
562   if ( (grp = getgrnam(group)) == NULL ) {
563    ROAR_ERR("Can not get GID for group %s: %s", group, strerror(errno));
564   }
[2530]565  }
566#endif
567#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
[2752]568  if ( user ) {
[2530]569   if ( (pwd = getpwnam(user)) == NULL ) {
570    ROAR_ERR("Can not get UID for user %s: %s", user, strerror(errno));
571   }
572  }
573#endif
574
575#if defined(ROAR_HAVE_IO_POSIX) && defined(ROAR_HAVE_UNIX)
576  if ( *addr == '/' ) {
[2753]577   if ( grp || pwd ) {
578     if ( chown(addr, pwd ? pwd->pw_uid : -1, grp ? grp->gr_gid : -1) == -1 )
[2530]579      return 1;
[2753]580   }
[2530]581#ifdef ROAR_HAVE_GETUID
[2753]582   if ( grp ) {
[2530]583    if ( getuid() == 0 )
584     if ( chmod(addr, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1 )
585      return 1;
[2753]586   }
[2530]587#endif
588  }
589#endif
590 }
591
[2736]592 // in case we opened the listening socket correctly.
[3256]593 if ( dir == -1 )
594  dir = ROAR_DIR_PLAY;
595
[3252]596 g_listen[sockid].inst.stpl.dir = dir;
597 memcpy(&(g_listen[sockid].inst.stpl.info), info, sizeof(struct roar_audio_info));
[3256]598
599 switch (dir) {
600  case ROAR_DIR_PLAY:
601  case ROAR_DIR_RECORD:
602  case ROAR_DIR_MONITOR:
603  case ROAR_DIR_FILTER:
604  case ROAR_DIR_BIDIR:
605    if ( !g_listen[sockid].inst.stpl.info.rate )
606     g_listen[sockid].inst.stpl.info.rate = g_sa->rate;
607
608    if ( !g_listen[sockid].inst.stpl.info.bits )
609     g_listen[sockid].inst.stpl.info.bits = g_sa->bits;
610
611    if ( !g_listen[sockid].inst.stpl.info.channels )
612     g_listen[sockid].inst.stpl.info.channels = g_sa->channels;
613
614    if ( !g_listen[sockid].inst.stpl.info.codec )
615     g_listen[sockid].inst.stpl.info.codec = g_sa->codec;
616   break;
617 }
618
[3802]619 g_listen[sockid].used = 1;
620 server[sockid]        = addr;
621
[2530]622 return 0;
623}
624#endif
625
[2339]626int update_stream_flags (char * str) {
627 int    dir;
628 char * flags;
629 char * k;
630 int    op;
631 int    flag;
632
633 if ( (flags = strstr(str, "=")) == NULL )
634  return -1;
635
636 *flags = 0;
637  flags++;
638
639 if ( (dir = roar_str2dir(str)) == -1 )
640  return -1;
641
642 while (flags != NULL) {
643  k = flags;
644  flags = strstr(flags, ",");
645
646  if ( flags != NULL )
647   *(flags++) = 0;
648
649  switch (*k) {
[2340]650   case '+': k++; op = ROAR_SET_FLAG;   break;
651   case '-': k++; op = ROAR_RESET_FLAG; break;
[2339]652   default:
[2340]653     op = ROAR_SET_FLAG;
[2339]654  }
655
656  flag = 0;
657
658  if ( !strcmp(k, "sync") ) {
659   flag = ROAR_FLAG_SYNC;
660  } else if ( !strcmp(k, "meta") ) {
661   flag = ROAR_FLAG_META;
662  } else if ( !strcmp(k, "cleanmeta") ) {
663   flag = ROAR_FLAG_CLEANMETA;
664  } else if ( !strcmp(k, "pause") ) {
665   flag = ROAR_FLAG_PAUSE;
666  } else if ( !strcmp(k, "mute") ) {
667   flag = ROAR_FLAG_MUTE;
668  } else if ( !strcmp(k, "antiecho") ) {
669   flag = ROAR_FLAG_ANTIECHO;
[2413]670  } else if ( !strcmp(k, "passmixer") ) {
671   flag = ROAR_FLAG_PASSMIXER;
[2339]672  } else {
673   return -1;
674  }
675
676  g_config->streams[dir].flags |= flag;
677
[2340]678  if ( op == ROAR_RESET_FLAG )
[2339]679   g_config->streams[dir].flags -= flag;
680 }
681
682 return 0;
683}
684
[1145]685int add_output (char * drv, char * dev, char * opts, int prim, int count) {
[933]686 int stream;
687 struct roar_stream * s;
688 struct roar_stream_server * ss;
[938]689 char * k, * v;
[1208]690#ifdef ROAR_DRIVER_CODEC
691 char * to_free = NULL;
692#endif
[1926]693 int sync = 0, f_mmap = 0;
[1522]694 int32_t blocks = -1, blocksize = -1;
[1920]695 int dir = ROAR_DIR_OUTPUT;
[1991]696 int error = 0;
697 // DMX:
698 int32_t channel  = -1;
699 int32_t universe = -1;
700 uint16_t tu16;
[2085]701 float q = -32e6;
[933]702
[938]703 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
[933]704
[1145]705 if ( drv == NULL && count == 0 ) {
706  drv  = ROAR_DRIVER_DEFAULT;
707  prim = 1;
708  sync = 1;
[1208]709
710#ifdef ROAR_DRIVER_CODEC
711  if ( opts == NULL ) {
712   opts = to_free = strdup("codec=" ROAR_DRIVER_CODEC);
713  }
714#endif
[1145]715 }
716
[1227]717 if ( opts == NULL && count == 0 ) {
718  sync = 1;
719  prim = 1; // if ( prim == 0 ) prim = 1; -> prim allways = 1
720 }
721
[2785]722 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
723
[933]724 if ( (stream = streams_new()) == -1 ) {
[938]725  ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = -1", drv, dev, opts);
[982]726  if ( prim ) alive = 0;
[933]727  return -1;
728 }
729
[2785]730 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
731
[933]732 streams_get(stream, &ss);
733 s = ROAR_STREAM(ss);
734
[2785]735 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
736
[2511]737 memset(&(s->info), 0xFF, sizeof(struct roar_audio_info)); // set everything to -1
[933]738
739 s->pos_rel_id = -1;
740// s->info.codec = codec;
741
[2785]742 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
743
[2788]744 if ( opts == NULL ) {
745  k = NULL;
746 } else {
747  k = strtok(opts, ",");
748 }
[2786]749
750 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s'): initial k='%s'(%p)", drv, dev, opts, k, k);
751
[938]752 while (k != NULL) {
753//  ROAR_WARN("add_output(*): opts: %s", k);
754
755  if ( (v = strstr(k, "=")) != NULL ) {
756   *v++ = 0;
757  }
758
759  ROAR_DBG("add_output(*): opts: k='%s', v='%s'", k, v);
760  if ( strcmp(k, "rate") == 0 ) {
761   s->info.rate = atoi(v);
762  } else if ( strcmp(k, "channels") == 0 ) {
763   s->info.channels = atoi(v);
764  } else if ( strcmp(k, "bits") == 0 ) {
765   s->info.bits = atoi(v);
766  } else if ( strcmp(k, "codec") == 0 ) {
[2511]767   if ( (s->info.codec = roar_str2codec(v)) == -1 ) {
[938]768    ROAR_ERR("add_output(*): unknown codec '%s'", v);
[1991]769    error++;
[938]770   }
[2085]771  } else if ( strcmp(k, "q") == 0 ) {
772   q = atof(v);
[1221]773  } else if ( strcmp(k, "blocks") == 0 ) {
774   blocks = atoi(v);
[1522]775  } else if ( strcmp(k, "blocksize") == 0 ) {
776   blocksize = atoi(v);
[1926]777  } else if ( strcmp(k, "mmap") == 0 ) {
778   f_mmap = 1;
[1919]779  } else if ( strcmp(k, "subsystem") == 0 ) {
780   if ( !strcasecmp(v, "wave") || !strcasecmp(v, "waveform") ) {
[1920]781    dir = ROAR_DIR_OUTPUT;
[2494]782#ifndef ROAR_WITHOUT_DCOMP_MIDI
[1919]783   } else if ( !strcasecmp(v, "midi") ) {
784    dir = ROAR_DIR_MIDI_OUT;
[2494]785#endif
786#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1919]787   } else if ( !strcasecmp(v, "light") ) {
788    dir = ROAR_DIR_LIGHT_OUT;
[2494]789#endif
790#ifndef ROAR_WITHOUT_DCOMP_RAW
[2234]791   } else if ( !strcasecmp(v, "raw") ) {
792    dir = ROAR_DIR_RAW_OUT;
[2494]793#endif
[2681]794   } else if ( !strcasecmp(v, "complex") ) {
795    dir = ROAR_DIR_COMPLEX_OUT;
[1919]796   } else {
[2494]797    ROAR_ERR("add_output(*): unknown/unsupported subsystem '%s'", k);
[1991]798    error++;
799   }
800  // DMX:
801  } else if ( strcmp(k, "channel") == 0 ) {
802   channel  = atoi(v);
803   if ( channel < 0 || channel > 65535 ) {
804    ROAR_ERR("add_output(*): Invalide channel (not within 0..65535): %i", channel);
805    channel = -1;
806    error++;
[1919]807   }
[1991]808  } else if ( strcmp(k, "universe") == 0 ) {
809   universe = atoi(v);
810   if ( universe < 0 || universe > 255 ) {
811    ROAR_ERR("add_output(*): Invalide universe (not within 0..255): %i", universe);
812    universe = -1;
813    error++;
814   }
815
[2115]816  } else if ( strcmp(k, "name") == 0 ) {
817   if ( streams_set_name(stream, v) == -1 ) {
818    ROAR_ERR("add_output(*): Can not set Stream name");
819    error++;
820   }
[1991]821
[1032]822  } else if ( strcmp(k, "meta") == 0 ) {
823   streams_set_flag(stream, ROAR_FLAG_META);
[1117]824  } else if ( strcmp(k, "sync") == 0 ) {
825   sync = 1;
[1221]826  } else if ( strcmp(k, "primary") == 0 ) {
827   prim = 1;
828
829  } else if ( strcmp(k, "cleanmeta") == 0 ) {
830   streams_set_flag(stream, ROAR_FLAG_CLEANMETA);
831  } else if ( strcmp(k, "autoconf") == 0 ) {
[1531]832   streams_set_flag(stream, ROAR_FLAG_AUTOCONF);
[2413]833  } else if ( strcmp(k, "recsource") == 0 ) {
834   streams_set_flag(stream, ROAR_FLAG_RECSOURCE);
835  } else if ( strcmp(k, "passmixer") == 0 ) {
836   streams_set_flag(stream, ROAR_FLAG_PASSMIXER);
[938]837  } else {
838   ROAR_ERR("add_output(*): unknown option '%s'", k);
[1991]839   error++;
840  }
841
842  if ( error ) {
[938]843   streams_delete(stream);
[982]844   if ( prim ) alive = 0;
[1208]845#ifdef ROAR_DRIVER_CODEC
846   if ( to_free != NULL )
847    free(to_free);
848#endif
[938]849   return -1;
850  }
851
852  k = strtok(NULL, ",");
853 }
854
[2785]855 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
856
[2511]857 // set audio info...
858 switch (dir) {
859  case ROAR_DIR_LIGHT_OUT:
860    switch (s->info.codec) {
861     case ROAR_CODEC_DMX512:
862     case -1:
863       if ( s->info.rate == -1 )
864        s->info.rate = ROAR_OUTPUT_CFREQ;
865
866       s->info.channels =   0;
867       s->info.bits     =   8;
868       s->info.codec    = ROAR_CODEC_DMX512; // in case codec == -1
869      break;
870    }
871   break;
872  case ROAR_DIR_MIDI_OUT:
873    switch (s->info.codec) {
874     case ROAR_CODEC_MIDI:
875     case -1:
876       if ( s->info.rate == -1 )
877        s->info.rate    = ROAR_MIDI_TICKS_PER_BEAT;
878
879       s->info.channels = ROAR_MIDI_CHANNELS_DEFAULT;
880       s->info.bits     = ROAR_MIDI_BITS;
881       s->info.codec    = ROAR_CODEC_MIDI; // in case codec == -1
882      break;
883    }
884   break;
885  case ROAR_DIR_RAW_OUT:
886    if ( s->info.rate == -1 )
887     s->info.rate = 0;
888    if ( s->info.bits == -1 )
889     s->info.bits = 0;
890    if ( s->info.channels == -1 )
891     s->info.channels = 0;
892    if ( s->info.codec == -1 )
893     s->info.codec = 0;
894   break;
895 }
896
897 if ( s->info.rate == -1 )
898  s->info.rate = g_sa->rate;
899 if ( s->info.bits == -1 )
900  s->info.bits = g_sa->bits;
901 if ( s->info.channels == -1 )
902  s->info.channels = g_sa->channels;
903 if ( s->info.codec == -1 )
904  s->info.codec = g_sa->codec;
905
906 ROAR_DBG("add_output(*): s->info = {.rate=%i, .bits=%i, .channels=%i, .codec=%i}", s->info.rate, s->info.bits, s->info.channels, s->info.codec);
907
[1919]908 if ( streams_set_dir(stream, dir, 1) == -1 ) {
909  streams_delete(stream);
910  return -1;
911 }
912
[1208]913#ifdef ROAR_DRIVER_CODEC
914 if ( to_free != NULL )
915  free(to_free);
916#endif
917
[2511]918 if ( s->info.codec == ROAR_CODEC_ALAW || s->info.codec == ROAR_CODEC_MULAW )
[941]919  s->info.bits = 8; // needed to open OSS driver, will be overriden by codecfilter
920
[2511]921 ROAR_STREAM_SERVER(s)->codec_orgi = s->info.codec;
[933]922
[2364]923 if ( driver_openvio(&(ss->vio), &(ss->driver_id), drv, dev, &(s->info), -1, ss) == -1 ) {
[1581]924  ss->driver_id = -1; // don't close a driver not opened...
925  memset(&(ss->vio), 0, sizeof(struct roar_vio_calls));
[933]926  streams_delete(stream);
[938]927  ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = -1", drv, dev, opts);
[982]928  if ( prim ) alive = 0;
[933]929  return -1;
930 }
931
[1528]932 roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_SSTREAMID, &stream); // ignore errors here
933 roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_SSTREAM,   s); // ignore errors here
934
[1221]935 if ( blocks != -1 )
936  roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_DBLOCKS, &blocks);
937
[1522]938 if ( blocksize != -1 )
939  roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_DBLKSIZE, &blocksize);
940
[1991]941 // TODO: we shoudld *really* check for errors here...
942 if ( channel != -1 ) {
943  tu16 = channel;
944  roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_DMXSCHAN, &tu16);
945 }
946 if ( universe != -1 ) {
947  tu16 = universe;
948  roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_DMXUNIV, &tu16);
949 }
950
[1156]951 ROAR_DBG("add_output(*): ss->driver_id=%i", ss->driver_id);
952
[938]953 streams_set_fh(stream, -1); // update some internal structures
954
[2087]955 if ( q > -1e6 ) {
956  ROAR_DBG("add_output(*): setting q=%f", q);
957  streams_ctl(stream, ROAR_CODECFILTER_CTL_SET_Q|ROAR_STREAM_CTL_TYPE_FLOAT, &q);
958 }
959
[2490]960 client_stream_add(g_self_client, stream);
[933]961
[1200]962 if ( prim ) {
[961]963  streams_mark_primary(stream);
[1200]964  s->pos_rel_id = stream;
965 }
[961]966
[1120]967 if ( sync ) {
[1117]968  streams_set_flag(stream, ROAR_FLAG_SYNC);
[1120]969 } else {
970  streams_reset_flag(stream, ROAR_FLAG_SYNC);
971 }
[1117]972
[1926]973 if ( f_mmap )
974  streams_set_flag(stream, ROAR_FLAG_MMAP);
975
[2511]976 ROAR_DBG("add_output(*): s->info = {.rate=%i, .bits=%i, .channels=%i, .codec=%i}", s->info.rate, s->info.bits, s->info.channels, s->info.codec);
[933]977 return 0;
[932]978}
979
[3373]980// X11:
981#ifdef ROAR_HAVE_LIBX11
982int register_x11 (int unreg, char * sockname) {
983 struct roar_x11_connection * x11con = NULL;
984 int ret = 0;
985
[3374]986 if ( (x11con = roar_x11_connect(x11display)) == NULL )
[3373]987  return -1;
988
989 if ( unreg ) {
990  if ( roar_x11_delete_prop(x11con, "ROAR_SERVER") == -1 )
991   ret = -1;
992 } else {
993  if ( roar_x11_set_prop(x11con, "ROAR_SERVER", sockname) == -1 )
994   ret = -1;
995 }
996
997 roar_x11_disconnect(x11con);
998
999 return ret;
1000}
1001#endif
[1993]1002
1003// SLP:
1004void register_slp_callback(SLPHandle hslp, SLPError errcode, void * cookie) {
1005 /* return the error code in the cookie */
1006 *(SLPError*)cookie = errcode;
1007}
1008
1009int register_slp (int unreg, char * sockname) {
1010#ifdef ROAR_HAVE_LIBSLP
1011 static int regged = 0;
1012 static char * sn = NULL;
1013 SLPError err;
1014 SLPError callbackerr;
1015 SLPHandle hslp;
1016 char addr[1024];
1017 char attr[1024] = "";
[2017]1018 char * location;
[1993]1019
1020 if ( sockname != NULL )
1021  sn = sockname;
1022
[3076]1023 snprintf(addr, sizeof(addr), ROAR_SLP_URL_TYPE_ROAR "://%s", sn);
[1993]1024
1025 err = SLPOpen("en", SLP_FALSE, &hslp);
1026
1027 if (err != SLP_OK) {
1028  ROAR_ERR("Error opening slp handle: Error #%i", err);
1029  return -1;
1030 }
1031
1032 if (!unreg) {
[2017]1033
1034  if ( SLPEscape(g_config->location, &location, SLP_FALSE) != SLP_OK ) {
1035   ROAR_ERR("Error using SLPEscape() on server location, really bad!");
1036   SLPClose(hslp);
1037   return -1;
1038  }
1039
[1995]1040  snprintf(attr, sizeof(attr), "(wave-rate=%i),(wave-channels=%i),(wave-bits=%i),"
[2494]1041#ifndef ROAR_WITHOUT_DCOMP_LIGHT
1042                               "(light-channels=%i),"
1043#endif
1044                               "(location=%s)",
[1995]1045           g_sa->rate, g_sa->channels, g_sa->bits,
[2494]1046#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[2017]1047           g_light_state.channels,
[2494]1048#endif
[2017]1049           location
[1995]1050          );
1051
[1993]1052  /* Register a service with SLP */
1053  err = SLPReg(hslp,
1054               addr,
1055               SLP_LIFETIME_MAXIMUM,
1056               0,
1057               attr,
1058               SLP_TRUE,
1059               register_slp_callback,
1060               &callbackerr);
[1994]1061  regged = 1;
1062 } else if ( unreg && regged ) {
1063  err = SLPDereg(hslp, addr, register_slp_callback, &callbackerr);
1064  regged = 0;
1065 } else {
1066  SLPClose(hslp);
1067  return -1;
1068 }
[1993]1069
[1994]1070 /* err may contain an error code that occurred as the slp library    */
1071 /* _prepared_ to make the call.                                     */
1072 if ( err != SLP_OK ) {
1073  ROAR_ERR("Error (de)registering service with slp: Error #%i", err);
1074  return -1;
1075 }
1076
1077 /* callbackerr may contain an error code (that was assigned through */
1078 /* the callback cookie) that occurred as slp packets were sent on    */
1079 /* the wire */
1080 if (callbackerr != SLP_OK) {
1081  ROAR_ERR("Error (de)registering service with slp: Error #%i", callbackerr);
1082  return -1;
[1993]1083 }
1084
1085 SLPClose(hslp);
1086 return 0;
1087#else
1088 return -1;
1089#endif
1090}
1091
1092
1093// MAIN:
1094
[4053]1095#define _CKHAVEARGS(x) if ( (i + (x)) >= argc ) { \
1096                        ROAR_ERR("Option %s requires more arguments. See --help for more details.", k); \
1097                        return 70; \
1098                       }
[4052]1099
[1503]1100#ifdef ROAR_HAVE_MAIN_ARGS
[0]1101int main (int argc, char * argv[]) {
[1503]1102#else
1103int main (void) {
1104#endif
1105#ifdef ROAR_HAVE_MAIN_ARGS
[0]1106 int i;
1107 char * k;
[1503]1108#endif
[2787]1109#if defined(ROAR_SUPPORT_LISTEN) && defined(ROAR_HAVE_GETUID)
[905]1110 char user_sock[80]  = {0};
[1494]1111#endif
[1609]1112 struct roar_audio_info sa, max_sa;
1113 struct roard_config config;
[1486]1114#ifdef ROAR_HAVE_FORK
[905]1115 int    daemon       = 0;
[1486]1116#endif
[905]1117 int    realtime     = 0;
1118 int    sysclocksync = 0;
[1207]1119 char * driver    = NULL;
1120 char * device    = NULL;
[1503]1121#ifdef ROAR_HAVE_MAIN_ARGS
[1207]1122 char * opts      = NULL;
[1503]1123#endif
[60]1124// char * server = ROAR_DEFAULT_SOCK_GLOBAL;
[1494]1125#ifdef ROAR_SUPPORT_LISTEN
[2530]1126 int    port       = ROAR_DEFAULT_PORT;
1127 char * sock_addr  = NULL;
1128 int    sock_proto = ROAR_PROTO_ROARAUDIO;
[3252]1129 int    sock_dir   = -1;
1130 struct roar_audio_info sock_info = {0, 0, 0, 0};
[1494]1131#endif
[0]1132 int               drvid;
[2486]1133#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[550]1134 char * s_drv     = "cf";
[1110]1135 char * s_dev     = NULL;
[444]1136 char * s_con     = NULL;
1137 char * s_opt     = NULL;
1138 int    s_prim    = 0;
[2486]1139#endif
[1207]1140 char * o_drv     = getenv("ROAR_DRIVER");
1141 char * o_dev     = getenv("ROAR_DEVICE");
[932]1142 char * o_opts    = NULL;
[961]1143 int    o_prim    = 0;
[1145]1144 int    o_count   = 0;
[2494]1145#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1923]1146 int    light_channels = LIGHT_CHANNELS_DEFAULT;
[2494]1147#endif
[2751]1148#ifdef ROAR_DEFAULT_SOCKGRP
[450]1149 char * sock_grp  = ROAR_DEFAULT_SOCKGRP;
[2751]1150#else
1151 char * sock_grp  = NULL;
1152#endif
[444]1153 char * sock_user = NULL;
[1494]1154#ifdef ROAR_SUPPORT_LISTEN
[517]1155 int    sock_type = ROAR_SOCKET_TYPE_UNKNOWN;
[1494]1156#endif
[1993]1157#ifdef ROAR_HAVE_LIBSLP
1158 int    reg_slp   = 0;
1159#endif
[3373]1160#ifdef ROAR_HAVE_LIBX11
1161 int    reg_x11   = 0;
1162#endif
[1486]1163#ifdef ROAR_HAVE_CHROOT
[444]1164 char * chrootdir = NULL;
[1486]1165#endif
1166#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX)
[446]1167 struct group   * grp  = NULL;
[1486]1168#endif
1169#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
[446]1170 struct passwd  * pwd  = NULL;
[1486]1171#endif
1172#ifdef ROAR_HAVE_GETSERVBYNAME
[446]1173 struct servent * serv = NULL;
[1486]1174#endif
[0]1175 DRIVER_USERDATA_T drvinst;
[39]1176 struct roar_client * self = NULL;
[508]1177#ifdef ROAR_HAVE_LIBDNET
1178 char decnethost[80];
1179#endif
[2104]1180#ifdef SUPPORT_PIDFILE
1181 struct roar_vio_calls pidfile_vio;
1182#endif
[0]1183
[2784]1184 ROAR_DBG("main(*): starting roard...");
1185
[0]1186 g_standby       =  0;
[920]1187 g_autostandby   =  0;
[982]1188 alive           =  1;
[1494]1189#ifdef ROAR_SUPPORT_LISTEN
[1155]1190 g_no_listen     =  0;
[1494]1191#else
1192 g_terminate     =  1;
1193#endif
[0]1194
[2970]1195 g_verbose       = ROAR_DBG_INFO_NONE;
1196
[0]1197 sa.bits     = ROAR_BITS_DEFAULT;
1198 sa.channels = ROAR_CHANNELS_DEFAULT;
1199 sa.rate     = ROAR_RATE_DEFAULT;
1200 sa.codec    = ROAR_CODEC_DEFAULT;
1201
[1609]1202 g_sa        = &sa;
1203 g_max_sa    = &max_sa;
1204
1205 memcpy(g_max_sa, g_sa, sizeof(max_sa));
1206
1207 g_config = &config;
1208
1209 if ( init_config() == -1 ) {
1210  ROAR_ERR("Can not init default config!");
1211  return 1;
1212 }
[0]1213
[2968]1214 // load config
1215 roar_libroar_get_config();
1216
[2530]1217#ifdef ROAR_SUPPORT_LISTEN
1218 if ( init_listening() == -1 ) {
1219  ROAR_ERR("Can not init listening sockets!");
1220  return 1;
1221 }
1222#endif
1223
[2500]1224#ifndef ROAR_WITHOUT_DCOMP_MIDI
[1924]1225 if ( midi_init_config() == -1 ) {
1226  ROAR_ERR("Can not init MIDI config!");
1227  return 1;
1228 }
[2500]1229#endif
[60]1230
[2489]1231#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
[2451]1232 if ( ssynth_init_config() == -1 ) {
1233  ROAR_ERR("Can not init ssynth config!");
1234  return 1;
1235 }
[2489]1236#endif
[2451]1237
[2718]1238#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1239 if ( rdtcs_init_config() == -1 ) {
1240  ROAR_ERR("Can not init RDTCS config!");
1241  return 1;
1242 }
1243#endif
1244
[3354]1245 if ( plugins_preinit() == -1 ) {
1246  ROAR_ERR("Can not pre-init plugins!");
1247  return 1;
1248 }
1249
[1494]1250#ifdef ROAR_SUPPORT_LISTEN
[2767]1251#ifndef ROAR_TARGET_WIN32
[2530]1252 sock_addr = ROAR_DEFAULT_SOCK_GLOBAL;
[2767]1253#else
1254 sock_addr = ROAR_DEFAULT_HOST;
1255#endif
1256
[1753]1257#ifdef ROAR_HAVE_GETUID
[1486]1258 if ( getuid() != 0 && getenv("HOME") != NULL ) {
[3959]1259/*
[1486]1260  snprintf(user_sock, 79, "%s/%s", (char*)getenv("HOME"), ROAR_DEFAULT_SOCK_USER);
[3959]1261*/
1262  roar_env_render_path_r(user_sock, sizeof(user_sock), "~/" ROAR_DEFAULT_SOCK_USER);
[2530]1263  sock_addr = user_sock;
[3959]1264  ROAR_DBG("main(*): setting sock_addr='%s'", sock_addr);
[60]1265 }
[1753]1266#endif
[60]1267
[279]1268 if ( getenv("ROAR_SERVER") != NULL )
[2530]1269  sock_addr = getenv("ROAR_SERVER");
[1494]1270#endif
[279]1271
[63]1272 if ( clients_init() == -1 ) {
1273  ROAR_ERR("Can not init clients!");
1274  return 1;
1275 }
1276
1277 if ( streams_init() == -1 ) {
1278  ROAR_ERR("Can not init streams!");
1279  return 1;
1280 }
1281
[64]1282 if ( (g_self_client = clients_new()) == -1 ) {
1283  ROAR_ERR("Can not create self client!");
1284  return 1;
1285 }
1286
[2485]1287#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[0]1288 if ( sources_init() == -1 ) {
1289  ROAR_ERR("Can not init sources!");
1290  return 1;
1291 }
1292
[64]1293 if ( (sources_set_client(g_self_client)) == -1 ) {
1294  ROAR_ERR("Can not init set source client!");
1295  return 1;
1296 }
[2485]1297#endif
[64]1298
[1503]1299#ifdef ROAR_HAVE_MAIN_ARGS
[0]1300 for (i = 1; i < argc; i++) {
1301  k = argv[i];
1302
1303  if ( strcmp(k, "-h") == 0 || strcmp(k, "--help") == 0 ) {
1304   usage();
1305   return 0;
1306
[2109]1307  } else if ( strcmp(k, "--start") == 0 ) {
1308   // this is a no op
[579]1309  } else if ( strcmp(k, "--restart") == 0 ) {
[1494]1310#ifdef ROAR_SUPPORT_LISTEN
[2530]1311   if ( restart_server(sock_addr, 1) == -1 ) {
1312    ROAR_WARN("Can not terminate old server (not running at %s?), tring to continue anyway", sock_addr);
[579]1313   }
[1494]1314#else
1315   ROAR_ERR("--restart not supported");
1316#endif
[2109]1317  } else if ( strcmp(k, "--shutdown") == 0 ) {
1318#ifdef ROAR_SUPPORT_LISTEN
[2530]1319   if ( restart_server(sock_addr, 1) == -1 ) {
1320    ROAR_WARN("Can not terminate old server (not running at %s?)", sock_addr);
[2109]1321    return 1;
1322   }
1323   return 0;
1324#else
1325   ROAR_ERR("--shutdown not supported");
1326   return 1;
1327#endif
1328  } else if ( strcmp(k, "--stop") == 0 ) {
1329#ifdef ROAR_SUPPORT_LISTEN
[2530]1330   if ( restart_server(sock_addr, 0) == -1 ) {
1331    ROAR_WARN("Can not stop old server (not running at %s?)", sock_addr);
[2109]1332    return 1;
1333   }
1334   return 0;
1335#else
1336   ROAR_ERR("--stop not supported");
1337   return 1;
1338#endif
1339
[579]1340
[775]1341  } else if ( strcmp(k, "--demon") == 0 || strcmp(k, "--daemon") == 0 ) {
[1486]1342#ifdef ROAR_HAVE_FORK
[775]1343   daemon = 1;
[1486]1344#else
1345   ROAR_ERR("--daemon not supported");
1346#endif
[2970]1347  } else if ( strcmp(k, "--verbose") == 0 ) {
1348   g_verbose++;
[71]1349  } else if ( strcmp(k, "--terminate") == 0 ) {
1350   g_terminate = 1;
[905]1351  } else if ( strcmp(k, "--sysclocksync") == 0 ) {
1352   sysclocksync = 1000;
[275]1353  } else if ( strcmp(k, "--realtime") == 0 ) {
[276]1354   realtime++;
[444]1355  } else if ( strcmp(k, "--chroot") == 0 ) {
[4052]1356   _CKHAVEARGS(1);
[1486]1357#ifdef ROAR_HAVE_CHROOT
[444]1358   chrootdir = argv[++i];
[1486]1359#else
1360   ROAR_ERR("--chroot not supported");
1361   i++;
1362#endif
[444]1363  } else if ( strcmp(k, "--setgid") == 0 ) {
[1486]1364#ifdef ROAR_HAVE_SETGID
[444]1365   setids |= R_SETGID;
[1486]1366#else
1367   ROAR_ERR("--setgid not supported");
1368#endif
[444]1369  } else if ( strcmp(k, "--setuid") == 0 ) {
[1486]1370#ifdef ROAR_HAVE_SETUID
[444]1371   setids |= R_SETUID;
[1486]1372#else
1373   ROAR_ERR("--setuid not supported");
1374#endif
[2017]1375  } else if ( strcmp(k, "--location") == 0 ) {
[4052]1376   _CKHAVEARGS(1);
[2017]1377   g_config->location = argv[++i];
[2104]1378  } else if ( strcmp(k, "--pidfile") == 0 ) {
[4052]1379   _CKHAVEARGS(1);
[2104]1380#ifdef SUPPORT_PIDFILE
1381   pidfile = argv[++i];
1382#else
1383   ROAR_ERR("--pidfile not supported");
1384   i++;
1385#endif
[3688]1386  } else if ( strcmp(k, "--log-syslog") == 0 ) {
1387#ifdef ROAR_HAVE_SYSLOG
1388   roar_debug_set_stderr_mode(ROAR_DEBUG_MODE_SYSLOG);
1389#else
1390   ROAR_ERR("--log-syslog not supported");
1391#endif
1392
[68]1393
[3356]1394  } else if ( strcmp(k, "--plugin-load") == 0 ) {
[4052]1395   _CKHAVEARGS(1);
[3356]1396   if ( plugins_load(argv[++i]) == -1 ) {
1397    ROAR_ERR("Can not load plugin");
1398   }
1399
[280]1400  } else if ( strcmp(k, "--list-cf") == 0 ) {
1401   print_codecfilterlist();
1402   return 0;
1403
[0]1404  } else if ( strcmp(k, "-R") == 0 || strcmp(k, "--rate") == 0 ) {
[4052]1405   _CKHAVEARGS(1);
[0]1406   sa.rate = atoi(argv[++i]);
1407  } else if ( strcmp(k, "-B") == 0 || strcmp(k, "--bits") == 0 ) {
[4052]1408   _CKHAVEARGS(1);
[0]1409   sa.bits = atoi(argv[++i]);
1410  } else if ( strcmp(k, "-C") == 0 || strcmp(k, "--chans") == 0 ) {
[4052]1411   _CKHAVEARGS(1);
[0]1412   sa.channels = atoi(argv[++i]);
1413
[3962]1414  } else if ( strcmp(k, "--aiprofile") == 0 ) {
[4052]1415   _CKHAVEARGS(1);
[3962]1416   if ( roar_profile2info(&sa, argv[++i]) == -1 ) {
1417    ROAR_ERR("Unknown audio profile: %s", argv[i]);
1418    return 1;
1419   }
1420   sa.codec    = ROAR_CODEC_DEFAULT;
1421
[2339]1422  } else if ( strcmp(k, "--stream-flags") == 0 ) {
[4052]1423   _CKHAVEARGS(1);
[2339]1424   if ( update_stream_flags(argv[++i]) == -1 ) {
1425    ROAR_ERR("Can not set stream flags");
1426    return 1;
1427   }
1428
[0]1429  } else if ( strcmp(k, "-d") == 0 || strcmp(k, "--driver") == 0 ) {
[4052]1430   _CKHAVEARGS(1);
[0]1431   driver = argv[++i];
1432   if ( strcmp(driver, "list") == 0 ) {
[974]1433    ROAR_WARN("The option is obsolete, use --list-driver!");
[0]1434    print_driverlist();
[973]1435    return 0;
[0]1436   }
1437  } else if ( strcmp(k, "-D") == 0 || strcmp(k, "--device") == 0 ) {
[4052]1438   _CKHAVEARGS(1);
[0]1439   device = argv[++i];
1440  } else if ( strcmp(k, "-dO") == 0 ) {
[4052]1441   _CKHAVEARGS(1);
[0]1442   opts = argv[++i];
[973]1443  } else if ( strcmp(k, "--list-driver") == 0 ) {
1444   print_driverlist();
1445   return 0;
[0]1446
[932]1447  } else if ( strcmp(k, "-o") == 0 || strcmp(k, "--odriver") == 0 ) {
[4052]1448   _CKHAVEARGS(1);
[932]1449   o_drv  = argv[++i];
1450  } else if ( strcmp(k, "-O") == 0 || strcmp(k, "--odevice") == 0 ) {
[4052]1451   _CKHAVEARGS(1);
[932]1452   o_dev  = argv[++i];
1453  } else if ( strcmp(k, "-oO") == 0 ) {
[4052]1454   _CKHAVEARGS(1);
[932]1455   o_opts = argv[++i];
[961]1456  } else if ( strcmp(k, "-oP") == 0 ) {
1457   o_prim = 1;
[932]1458  } else if ( strcmp(k, "-oN") == 0 ) {
[1145]1459   if ( add_output(o_drv, o_dev, o_opts, o_prim, o_count) != -1 )
1460    o_count++;
1461
[961]1462   o_drv  = o_dev = o_opts = NULL;
1463   o_prim = 0;
[932]1464
[0]1465  } else if ( strcmp(k, "-s") == 0 || strcmp(k, "--source") == 0 ) {
[4052]1466   _CKHAVEARGS(1);
[2485]1467#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[550]1468   s_drv = argv[++i];
[2485]1469#else
1470   ROAR_ERR("main(*): No support for sources compiled in");
[4052]1471   i++;
[2485]1472#endif
[550]1473  } else if ( strcmp(k, "-S") == 0 ) {
[4052]1474   _CKHAVEARGS(1);
[2485]1475#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[1110]1476   s_dev = argv[++i];
[2485]1477#else
1478   ROAR_ERR("main(*): No support for sources compiled in");
[4052]1479   i++;
[2485]1480#endif
[0]1481  } else if ( strcmp(k, "-sO") == 0 ) {
[4052]1482   _CKHAVEARGS(1);
[2485]1483#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[0]1484   s_opt = argv[++i];
[2485]1485#else
1486   ROAR_ERR("main(*): No support for sources compiled in");
[4052]1487   i++;
[2485]1488#endif
[0]1489  } else if ( strcmp(k, "-sC") == 0 ) {
[4052]1490   _CKHAVEARGS(1);
[2485]1491#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[0]1492   s_con = argv[++i];
[2485]1493#else
1494   ROAR_ERR("main(*): No support for sources compiled in");
[4052]1495   i++;
[2485]1496#endif
[0]1497  } else if ( strcmp(k, "-sP") == 0 ) {
[2485]1498#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[0]1499   s_prim = 1;
[2485]1500#else
1501   ROAR_ERR("main(*): No support for sources compiled in");
1502#endif
[1110]1503  } else if ( strcmp(k, "-sN") == 0 ) {
[2485]1504#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[1110]1505   if ( sources_add(s_drv, s_dev, s_con, s_opt, s_prim) == -1 ) {
1506    ROAR_ERR("main(*): adding source '%s' via '%s' failed!", s_dev, s_drv);
1507   }
1508   s_opt = s_dev = s_con = NULL;
1509   s_drv = "cf";
1510   s_prim = 0;
[2485]1511#else
1512   ROAR_ERR("main(*): No support for sources compiled in");
1513#endif
[2270]1514  } else if ( strcmp(k, "--list-sources") == 0 ) {
[2485]1515#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[2270]1516   print_sourcelist();
1517   return 0;
[2485]1518#else
1519   ROAR_ERR("main(*): No support for sources compiled in");
[2504]1520   return 1;
[2485]1521#endif
[0]1522
[1923]1523  } else if ( strcmp(k, "--light-channels") == 0 ) {
[4052]1524   _CKHAVEARGS(1);
[2494]1525#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1923]1526   light_channels = atoi(argv[++i]);
[2494]1527#else
1528   ROAR_WARN("main(*): no light subsystem compiled in");
[4052]1529   i++;
[2494]1530#endif
[1923]1531
[2725]1532  } else if ( strcmp(k, "--rds-pi") == 0 ) {
[4052]1533   _CKHAVEARGS(1);
[2725]1534#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1535   g_rdtcs.rds.pi = atoi(argv[++i]);
1536#else
1537   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
[4052]1538   i++;
[2725]1539#endif
[2728]1540  } else if ( strcmp(k, "--rds-ps") == 0 ) {
[4052]1541   _CKHAVEARGS(1);
[2728]1542#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1543   if ( rdtcs_rds_set_ps(argv[++i]) == -1 ) {
[2729]1544    ROAR_ERR("Can not set RDS PS to '%s' (longer than 8 chars?)", argv[i]);
[2728]1545    return 1;
1546   }
1547#else
1548   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
[4052]1549   i++;
[2728]1550#endif
1551  } else if ( strcmp(k, "--rds-pty") == 0 ) {
[4052]1552   _CKHAVEARGS(1);
[2728]1553#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1554   if ( rdtcs_rds_set_pty(argv[++i]) == -1 ) {
[2729]1555    ROAR_ERR("Can not set RDS PTY to '%s'", argv[i]);
[2728]1556    return 1;
1557   }
1558#else
1559   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
[4052]1560   i++;
[2728]1561#endif
1562  } else if ( strcmp(k, "--rds-tp") == 0 ) {
1563#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1564   if ( rdtcs_rds_set_flag(RDTCS_RDS_FLAG_TP, 0) == -1 ) {
1565    ROAR_ERR("Can not set RDS TP flag");
1566    return 1;
1567   }
1568#else
1569   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
1570#endif
1571  } else if ( strcmp(k, "--rds-ct") == 0 ) {
1572#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1573   if ( rdtcs_rds_set_flag(RDTCS_RDS_FLAG_CT, 0) == -1 ) {
1574    ROAR_ERR("Can not set RDS CT flag");
1575    return 1;
1576   }
1577#else
1578   ROAR_WARN("main(*): no RDTCS subsystem compiled in");
1579#endif
1580
[2725]1581
[1924]1582  } else if ( strcmp(k, "--midi-no-console") == 0 ) {
[2487]1583#ifndef ROAR_WITHOUT_DCOMP_CB
[1924]1584   midi_config.init_cb = 0;
[2487]1585#else
1586   // no warning here as this is the disable option
1587#endif
[2444]1588  } else if ( strcmp(k, "--midi-console-enable") == 0 ) {
[2487]1589#ifndef ROAR_WITHOUT_DCOMP_CB
[2444]1590   midi_config.init_cb = 1;
[2487]1591#else
1592   ROAR_ERR("main(*): No support for MIDI subsystem part CB compiled in");
1593#endif
[1924]1594  } else if ( strcmp(k, "--midi-console") == 0 ) {
[4052]1595   _CKHAVEARGS(1);
[2487]1596#ifndef ROAR_WITHOUT_DCOMP_CB
[1924]1597   midi_config.console_dev = argv[++i];
[2444]1598   midi_config.init_cb = 1;
[2487]1599#else
1600   ROAR_ERR("main(*): No support for MIDI subsystem part CB compiled in");
[4052]1601   i++;
[2487]1602#endif
[1924]1603
[2451]1604  } else if ( strcmp(k, "--ssynth-enable") == 0 ) {
[2489]1605#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
[2451]1606   ssynth_conf.enable = 1;
[2489]1607#else
1608   ROAR_ERR("main(*): No support for ssynth compiled in");
1609#endif
[2451]1610  } else if ( strcmp(k, "--ssynth-disable") == 0 ) {
[2489]1611#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
[2451]1612   ssynth_conf.enable = 0;
[2489]1613#else
1614   // we can safely ignore the disable
1615#endif
[2451]1616
[3374]1617  } else if ( strcmp(k, "--x11-display") == 0 || strcmp(k, "--display") == 0 ) {
[4052]1618   _CKHAVEARGS(1);
[3374]1619#ifdef ROAR_HAVE_LIBX11
1620   x11display = argv[++i];
1621#else
1622   ROAR_ERR("No X11 support compiled in!");
1623   return 1;
1624#endif
1625
1626
[0]1627  } else if ( strcmp(k, "-p") == 0 || strcmp(k, "--port") == 0 ) {
[4052]1628   _CKHAVEARGS(1);
[4012]1629   // This is only useful in INET not UNIX mode.
[1494]1630#ifdef ROAR_SUPPORT_LISTEN
[2530]1631   if ( *sock_addr == '/' )
1632    sock_addr = ROAR_DEFAULT_HOST;
[447]1633
[446]1634   errno = 0;
1635   if ( (port = atoi(argv[++i])) < 1 ) {
[1486]1636#ifdef ROAR_HAVE_GETSERVBYNAME
[446]1637    if ( (serv = getservbyname(argv[i], "tcp")) == NULL ) {
1638     ROAR_ERR("Unknown service: %s: %s", argv[i], strerror(errno));
1639     return 1;
1640    }
1641    // NOTE: we need to use ROAR_NET2HOST16() here even if s_port is of type int!
1642    ROAR_DBG("main(*): serv = {s_name='%s', s_aliases={...}, s_port=%i, s_proto='%s'}",
1643            serv->s_name, ROAR_NET2HOST16(serv->s_port), serv->s_proto);
1644    port = ROAR_NET2HOST16(serv->s_port);
[1486]1645#else
1646    ROAR_ERR("invalite port number: %s", argv[i]);
1647    return 1;
1648#endif
[446]1649   }
[1494]1650#endif
[1115]1651  } else if ( strcmp(k, "-b") == 0 || strcmp(k, "--bind") == 0 || strcmp(k, "--sock") == 0 ) {
[4052]1652   _CKHAVEARGS(1);
[1494]1653#ifdef ROAR_SUPPORT_LISTEN
[2530]1654   sock_addr = argv[++i];
[4052]1655#else
1656   i++;
[2530]1657#endif
1658
1659  } else if ( strcmp(k, "--proto") == 0 ) {
1660#ifdef ROAR_SUPPORT_LISTEN
[2549]1661   if ( (sock_proto = roar_str2proto(argv[++i])) == -1 ) {
[2530]1662    ROAR_ERR("Unknown protocol: %s", argv[i]);
1663    return 1;
1664   }
[1494]1665#endif
[3252]1666  } else if ( strcmp(k, "--proto-dir") == 0 ) {
[4052]1667   _CKHAVEARGS(1);
[3252]1668#ifdef ROAR_SUPPORT_LISTEN
1669   if ( (sock_dir = roar_str2dir(argv[++i])) == -1 ) {
1670    ROAR_ERR("Unknown stream direction: %s", argv[i]);
1671    return 1;
1672   }
[4052]1673#else
1674   i++;
[3252]1675#endif
1676  } else if ( strcmp(k, "--proto-rate") == 0 ) {
[4052]1677   _CKHAVEARGS(1);
[3252]1678#ifdef ROAR_SUPPORT_LISTEN
1679   sock_info.rate = atoi(argv[++i]);
[4052]1680#else
1681   i++;
[3252]1682#endif
1683  } else if ( strcmp(k, "--proto-bits") == 0 ) {
[4052]1684   _CKHAVEARGS(1);
[3252]1685#ifdef ROAR_SUPPORT_LISTEN
1686   sock_info.bits = atoi(argv[++i]);
[4052]1687#else
1688   i++;
[3252]1689#endif
1690  } else if ( strcmp(k, "--proto-chans") == 0 ) {
[4052]1691   _CKHAVEARGS(1);
[3252]1692#ifdef ROAR_SUPPORT_LISTEN
1693   sock_info.channels = atoi(argv[++i]);
[4052]1694#else
1695   i++;
[3252]1696#endif
1697  } else if ( strcmp(k, "--proto-codec") == 0 ) {
[4052]1698   _CKHAVEARGS(1);
[3252]1699#ifdef ROAR_SUPPORT_LISTEN
1700   if ( (sock_info.codec = roar_str2codec(argv[++i])) == -1 ) {
1701    ROAR_ERR("Unknown codec: %s", argv[i]);
1702    return 1;
1703   }
[4052]1704#else
1705   i++;
[3252]1706#endif
[3954]1707  } else if ( strcmp(k, "--proto-aiprofile") == 0 ) {
[4052]1708   _CKHAVEARGS(1);
[3954]1709#ifdef ROAR_SUPPORT_LISTEN
1710   if ( roar_profile2info(&sock_info, argv[++i]) == -1 ) {
1711    ROAR_ERR("Unknown audio profile: %s", argv[i]);
1712    return 1;
1713   }
[4052]1714#else
1715   i++;
[3954]1716#endif
[3956]1717  } else if ( strcmp(k, "--list-profiles") == 0 ) {
1718#ifdef ROAR_SUPPORT_LISTEN
1719   listen_listen_profiles();
1720   return 0;
1721#endif
1722  } else if ( strcmp(k, "--proto-profile") == 0 ) {
[4052]1723   _CKHAVEARGS(1);
[3956]1724#ifdef ROAR_SUPPORT_LISTEN
1725   if ( get_listen_profile(argv[++i], &port, &sock_addr, &sock_type, &sock_proto, &sock_dir, &sock_info) == -1 ) {
1726    ROAR_ERR("Unknown listen profile: %s", argv[i]);
1727    return 1;
1728   }
[4052]1729#else
1730   i++;
[3956]1731#endif
[3252]1732
1733
[3127]1734  } else if ( strcmp(k, "--list-proto") == 0 ) {
1735   list_proto();
1736   return 0;
[518]1737
[573]1738  } else if ( strcmp(k, "-t") == 0 || strcmp(k, "--tcp") == 0 ) {
[1494]1739#ifdef ROAR_SUPPORT_LISTEN
[518]1740   if ( sock_type != ROAR_SOCKET_TYPE_TCP && sock_type != ROAR_SOCKET_TYPE_TCP6 )
1741    sock_type = ROAR_SOCKET_TYPE_TCP;
1742
[2530]1743   if ( *sock_addr == '/' )
1744    sock_addr = ROAR_DEFAULT_HOST;
[1494]1745#endif
[518]1746
1747  } else if ( strcmp(k, "-4") == 0 ) {
[1494]1748#ifdef ROAR_SUPPORT_LISTEN
[517]1749   sock_type = ROAR_SOCKET_TYPE_TCP;
[2530]1750   if ( *sock_addr == '/' )
1751    sock_addr = ROAR_DEFAULT_HOST;
[1494]1752#endif
[518]1753  } else if ( strcmp(k, "-6") == 0 ) {
[1494]1754#ifdef ROAR_SUPPORT_LISTEN
[3837]1755#ifdef AF_INET6
[518]1756   sock_type = ROAR_SOCKET_TYPE_TCP6;
[2530]1757   if ( *sock_addr == '/' )
1758    sock_addr = ROAR_DEFAULT_HOST;
[519]1759#else
1760    ROAR_ERR("No IPv6 support compiled in!");
1761    return 1;
1762#endif
[1494]1763#endif
[518]1764
[573]1765  } else if ( strcmp(k, "-u") == 0 || strcmp(k, "--unix") == 0 ) {
[1494]1766#ifdef ROAR_SUPPORT_LISTEN
[62]1767   // ignore this case as it is the default behavor.
[517]1768   sock_type = ROAR_SOCKET_TYPE_UNIX;
[1494]1769#endif
[518]1770
[573]1771  } else if ( strcmp(k, "-n") == 0 || strcmp(k, "--decnet") == 0 ) {
[1494]1772#ifdef ROAR_SUPPORT_LISTEN
[508]1773#ifdef ROAR_HAVE_LIBDNET
1774    port   = ROAR_DEFAULT_NUM;
1775    strcpy(decnethost, ROAR_DEFAULT_LISTEN_OBJECT);
[2530]1776    sock_addr = decnethost;
[517]1777    sock_type = ROAR_SOCKET_TYPE_DECNET;
[508]1778#else
1779    ROAR_ERR("No DECnet support compiled in!");
1780    return 1;
1781#endif
[1494]1782#endif
[2530]1783  } else if ( strcmp(k, "--new-sock") == 0 ) {
1784#ifdef ROAR_SUPPORT_LISTEN
[3252]1785   if ( add_listen(sock_addr, port, sock_type, sock_user, sock_grp, sock_proto, sock_dir, &sock_info) != 0 ) {
[2530]1786    ROAR_ERR("Can not open listen socket!");
1787    return 1;
1788   }
1789#endif
[518]1790
[1993]1791  } else if ( strcmp(k, "--slp") == 0 ) {
1792#ifdef ROAR_HAVE_LIBSLP
1793   reg_slp = 1;
1794#else
[3373]1795   ROAR_ERR("No OpenSLP support compiled in!");
1796   return 1;
[1993]1797#endif
1798
[3373]1799  } else if ( strcmp(k, "--x11") == 0 ) {
1800#ifdef ROAR_HAVE_LIBX11
1801   reg_x11 = 1;
1802#else
1803   ROAR_ERR("No X11 support compiled in!");
1804   return 1;
1805#endif
1806
1807
[3039]1808  } else if ( strcmp(k, "--jumbo-mtu") == 0 ) {
[4052]1809   _CKHAVEARGS(1);
[3039]1810   g_config->jumbo_mtu = atoi(argv[++i]);
1811
[60]1812  } else if ( strcmp(k, "-G") == 0 ) {
[4052]1813   _CKHAVEARGS(1);
[444]1814   sock_grp  = argv[++i];
1815  } else if ( strcmp(k, "-U") == 0 ) {
[4052]1816   _CKHAVEARGS(1);
[444]1817   sock_user = argv[++i];
[0]1818
[68]1819  } else if ( strcmp(k, "--no-listen") == 0 ) {
[1494]1820#ifdef ROAR_SUPPORT_LISTEN
[2530]1821   sock_addr   = "";
[548]1822   g_terminate = 1;
[1155]1823   g_no_listen = 1;
[1494]1824#endif
[68]1825  } else if ( strcmp(k, "--client-fh") == 0 ) {
[4052]1826   _CKHAVEARGS(1);
[3737]1827   if ( clients_new_from_fh(atoi(argv[++i]), ROAR_PROTO_ROARAUDIO, ROAR_BYTEORDER_NETWORK, 1) == -1 ) {
[68]1828    ROAR_ERR("main(*): Can not set client's fh");
1829    return 1;
1830   }
[501]1831  } else if ( strcmp(k, "--close-fh") == 0 ) {
[4052]1832   _CKHAVEARGS(1);
[1486]1833#ifdef ROAR_HAVE_IO_POSIX
[501]1834   close(atoi(argv[++i]));
[1486]1835#else
1836   i++;
1837   ROAR_WARN("can not close file handle %s (closing not supported)", argv[i]);
1838#endif
[68]1839
[920]1840  } else if ( strcmp(k, "--standby") == 0 ) {
1841   g_standby = 1;
1842  } else if ( strcmp(k, "--auto-standby") == 0 ) {
1843   g_autostandby = 1;
[0]1844  } else {
1845   usage();
1846   return 1;
1847  }
1848
1849 }
[1503]1850#endif
[0]1851
[2485]1852#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[1110]1853 if ( s_dev != NULL ) {
1854  if ( sources_add(s_drv, s_dev, s_con, s_opt, s_prim) == -1 ) {
1855   ROAR_ERR("main(*): adding source '%s' via '%s' failed!", s_dev, s_drv);
1856  }
1857 }
[2485]1858#endif
[1110]1859
[1145]1860 add_output(o_drv, o_dev, o_opts, o_prim, o_count);
[932]1861
[0]1862 ROAR_DBG("Server config: rate=%i, bits=%i, chans=%i", sa.rate, sa.bits, sa.channels);
1863
[2945]1864 if ( waveform_init() == -1 ) {
1865  ROAR_ERR("Can not initialize Waveform subsystem");
1866  return 1;
1867 }
1868
[2500]1869#ifndef ROAR_WITHOUT_DCOMP_MIDI
[1819]1870 if ( midi_init() == -1 ) {
[281]1871  ROAR_ERR("Can not initialize MIDI subsystem");
[1819]1872 }
[2500]1873#endif
[1819]1874
[2489]1875#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
[2451]1876 if ( ssynth_init() == -1 ) {
1877  ROAR_ERR("Can not initialize ssynth subsystem");
1878 }
[2489]1879#endif
[2451]1880
[2494]1881#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1819]1882 if ( light_init(light_channels) == -1 ) {
1883  ROAR_ERR("Can not initialize light control subsystem");
1884 }
[2494]1885#endif
[281]1886
[2718]1887#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1888 if ( rdtcs_init() == -1 ) {
1889  ROAR_ERR("Can not initialize RDTCS subsystem");
1890 }
1891#endif
1892
[3354]1893 if ( plugins_init() == -1 ) {
1894  ROAR_ERR("Can not initialize plugins");
1895 }
1896
[1494]1897#ifdef ROAR_SUPPORT_LISTEN
[3760]1898 if ( !g_no_listen ) {
1899  if ( add_listen(sock_addr, port, sock_type, sock_user, sock_grp, sock_proto, sock_dir, &sock_info) != 0 ) {
1900   ROAR_ERR("Can not open listen socket!");
1901   return 1;
1902  }
[60]1903 }
[1494]1904#endif
[60]1905
[0]1906 if ( output_buffer_init(&sa) == -1 ) {
1907  ROAR_ERR("Can not init output buffer!");
1908  return 1;
1909 }
1910
[1145]1911 if ( driver == NULL ) {
1912  driver = "null";
1913 } else {
1914  ROAR_WARN("Usage of old driver interface. use -o not -d!");
1915 }
1916
[0]1917 if ( driver_open(&drvinst, &drvid, driver, device, &sa) == -1 ) {
1918  ROAR_ERR("Can not open output driver!");
1919  return 1;
1920 }
1921
[44]1922 if ( samples_init() == -1 ) {
1923  ROAR_ERR("Can not init samples!");
1924  return 1;
1925 }
1926
1927
[1486]1928 // we should handle this on microcontrollers, too.
[1753]1929#if !defined(ROAR_TARGET_MICROCONTROLLER) && !defined(ROAR_TARGET_WIN32)
[0]1930 signal(SIGINT,  on_sig_int);
[2732]1931 signal(SIGTERM, on_sig_term);
[285]1932 signal(SIGCHLD, on_sig_chld);
[2112]1933 signal(SIGUSR1, on_sig_usr1);
[0]1934 signal(SIGPIPE, SIG_IGN);  // ignore broken pipes
[1486]1935#endif
[0]1936
[275]1937 if ( realtime ) {
[278]1938#ifdef DEBUG
1939  ROAR_WARN("compiled with -DDEBUG but realtime is enabled: for real realtime support compiel without -DDEBUG");
1940#endif
1941
[1486]1942#ifdef ROAR_HAVE_NICE
[275]1943  errno = 0;
[276]1944  nice(-5*realtime); // -5 for each --realtime
[1486]1945  if ( errno ) {
1946   ROAR_WARN("Can not decrease nice value by %i: %s", 5*realtime, strerror(errno));
1947  }
1948#else
1949  ROAR_WARN("Can not decrease nice value by %i: %s", 5*realtime, strerror(errno));
1950#endif
[277]1951/*
[276]1952#ifdef __linux__
[277]1953  if ( ioprio_set(IOPRIO_WHO_PROCESS, getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0)) == -1 )
1954   ROAR_WARN("Can not set io priority: %s", strerror(errno));
[276]1955#endif
[277]1956*/
[275]1957 }
1958
[2756]1959#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX)
[444]1960 if ( setids & R_SETGID ) {
[2754]1961  if ( sock_grp == NULL ) {
1962   ROAR_ERR("Can not set GID if no groupname is supplied");
1963   return 1;
1964  }
[2584]1965  if ( (grp = getgrnam(sock_grp)) == NULL ) {
1966   ROAR_ERR("Can not get GID for group %s: %s", sock_grp, strerror(errno));
1967   return 1;
1968  }
[444]1969  if ( setgroups(0, (const gid_t *) NULL) == -1 ) {
1970   ROAR_ERR("Can not clear supplementary group IDs: %s", strerror(errno));
1971  }
[523]1972  if ( !grp || setgid(grp->gr_gid) == -1 ) {
[444]1973   ROAR_ERR("Can not set GroupID: %s", strerror(errno));
1974  }
1975 }
[1486]1976#endif
[444]1977
[0]1978
[39]1979 clients_set_pid(g_self_client, getpid());
[1753]1980#ifdef ROAR_HAVE_GETUID
[440]1981 clients_set_uid(g_self_client, getuid());
[1753]1982#endif
1983#ifdef ROAR_HAVE_GETGID
[440]1984 clients_set_gid(g_self_client, getgid());
[1753]1985#endif
[39]1986 clients_get(g_self_client, &self);
[37]1987
[39]1988 if ( self == NULL ) {
1989  ROAR_ERR("Can not get self client!");
1990  return 1;
1991 }
1992
[775]1993 strcpy(self->name, "RoarAudio daemon internal");
[68]1994
[2815]1995 if ( roar_nnode_free(&(self->nnode)) == -1 )
1996  return 1;
1997
1998 // not fully correct but ok as workaorund
1999 // so tools assume that roard runs on the same machine as
2000 // they in case they use AF_UNIX:
2001 if ( roar_nnode_new(&(self->nnode), ROAR_SOCKET_TYPE_UNIX) == -1 )
2002  return 1;
2003
[1486]2004#ifdef ROAR_HAVE_FORK
[775]2005 if ( daemon ) {
[3613]2006#ifdef ROAR_HAVE_SYSLOG
2007  roar_debug_set_stderr_mode(ROAR_DEBUG_MODE_SYSLOG);
2008#else
[3609]2009  roar_debug_set_stderr_fh(-1);
[3613]2010#endif
[3609]2011
[68]2012  close(ROAR_STDIN );
2013  close(ROAR_STDOUT);
2014  close(ROAR_STDERR);
[1753]2015
[68]2016  if ( fork() )
[1486]2017   ROAR_U_EXIT(0);
[1753]2018
2019#ifdef ROAR_HAVE_SETSID
2020  setsid();
2021#endif
[1046]2022  clients_set_pid(g_self_client, getpid()); // reset pid as it changed
[68]2023 }
[1486]2024#endif
[68]2025
[2757]2026#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
2027 // early test for UID as we need this for the pidfile and the setuid()
2028 if ( sock_user != NULL ) {
2029  if ( (pwd = getpwnam(sock_user)) == NULL ) {
2030   ROAR_ERR("Can not get UID for user %s: %s", sock_user, strerror(errno));
2031   return 1;
2032  }
2033 }
2034#endif
2035
[2104]2036#ifdef SUPPORT_PIDFILE
[2106]2037 if ( pidfile != NULL ) {
2038  if ( roar_vio_open_file(&pidfile_vio, pidfile, O_WRONLY|O_CREAT, 0644) == -1 ) {
2039   ROAR_ERR("Can not write pidfile: %s", pidfile);
2040  } else {
2041   roar_vio_printf(&pidfile_vio, "%i\n", getpid());
2042   roar_vio_close(&pidfile_vio);
2043  }
[2765]2044#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
[2759]2045  if ( pwd || grp ) {
2046   if ( chown(pidfile, pwd ? pwd->pw_uid : -1, grp ? grp->gr_gid : -1) == -1 ) {
2047    ROAR_WARN("Can not change ownership of pidfile: %s: %s", pidfile, strerror(errno));
2048   }
2049  }
2050  if ( chmod(pidfile, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) == -1 ) {
2051   ROAR_WARN("Can not change permissions of pidfile: %s: %s", pidfile, strerror(errno));
2052  }
[2765]2053#endif
[2104]2054 }
2055#endif
2056
[1486]2057#ifdef ROAR_HAVE_CHROOT
[444]2058 if (chrootdir) {
2059  if ( chroot(chrootdir) == -1 ) {
2060   ROAR_ERR("Can not chroot to %s: %s", chrootdir, strerror(errno));
2061   return 2;
2062  }
2063  if ( chdir("/") == -1 ) {
2064   ROAR_ERR("Can not chdir to /: %s", strerror(errno));
2065   return 2;
2066  }
2067 }
[1486]2068#endif
[444]2069
[2756]2070#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
[444]2071 if ( setids & R_SETUID ) {
[2752]2072  if ( sock_user == NULL ) {
2073   ROAR_ERR("Can not set UID if no username is supplied");
2074   return 1;
2075  }
[444]2076  if ( !pwd || setuid(pwd->pw_uid) == -1 ) {
2077   ROAR_ERR("Can not set UserID: %s", strerror(errno));
2078   return 3;
2079  }
[1753]2080#ifdef ROAR_HAVE_GETUID
[444]2081  clients_set_uid(g_self_client, getuid());
[1753]2082#endif
[444]2083 }
[1486]2084#endif
[444]2085
[1993]2086 // Register with OpenSLP:
[2028]2087#ifdef ROAR_HAVE_LIBSLP
[1993]2088 if ( reg_slp ) {
[2530]2089  register_slp(0, sock_addr);
[1993]2090 }
[2028]2091#endif
[1993]2092
[3373]2093#ifdef ROAR_HAVE_LIBX11
2094 if ( reg_x11 ) {
2095  register_x11(0, sock_addr);
2096 }
2097#endif
2098
[0]2099 // start main loop...
[905]2100 main_loop(drvid, drvinst, &sa, sysclocksync);
[0]2101
2102 // clean up.
2103 clean_quit_prep();
2104 driver_close(drvinst, drvid);
2105 output_buffer_free();
2106
2107 return 0;
2108}
2109
[574]2110void cleanup_listen_socket (int terminate) {
[2530]2111 int i;
2112
[1993]2113 // Deregister from SLP:
[2028]2114#ifdef ROAR_HAVE_LIBSLP
[1993]2115 register_slp(1, NULL);
[2028]2116#endif
[580]2117
[3373]2118#ifdef ROAR_HAVE_LIBX11
2119 register_x11(1, NULL);
2120#endif
2121
[1494]2122#ifdef ROAR_SUPPORT_LISTEN
[2530]2123 for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) {
[3802]2124  if ( g_listen[i].used  ) {
2125   roar_vio_close(&(g_listen[i].sock));
[60]2126
[3802]2127   g_listen[i].used = 0;
[576]2128
[1486]2129#ifdef ROAR_HAVE_UNIX
[2530]2130   if ( server[i] != NULL )
2131    if ( *(server[i]) == '/' )
2132     unlink(server[i]);
[1486]2133#endif
[2530]2134  }
[580]2135 }
[60]2136
[1494]2137#endif
2138
[574]2139 if ( terminate )
2140  g_terminate = 1;
2141}
2142
2143void clean_quit_prep (void) {
2144 cleanup_listen_socket(0);
[60]2145
[3354]2146 plugins_free();
2147
[2485]2148#ifndef ROAR_WITHOUT_DCOMP_SOURCES
[0]2149 sources_free();
[2485]2150#endif
[0]2151 streams_free();
2152 clients_free();
[2489]2153#ifndef ROAR_WITHOUT_DCOMP_SSYNTH
[2451]2154 ssynth_free();
[2489]2155#endif
[2487]2156#ifndef ROAR_WITHOUT_DCOMP_CB
[282]2157 midi_cb_stop(); // stop console beep
[2487]2158#endif
[2500]2159#ifndef ROAR_WITHOUT_DCOMP_MIDI
[281]2160 midi_free();
[2500]2161#endif
[2494]2162#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1819]2163 light_free();
[2494]2164#endif
[2718]2165#ifndef ROAR_WITHOUT_DCOMP_RDTCS
2166 rdtcs_free();
2167#endif
[2104]2168
[2945]2169 waveform_free();
2170
[2104]2171#ifdef SUPPORT_PIDFILE
2172 if ( pidfile != NULL )
2173  unlink(pidfile);
2174#endif
[0]2175}
2176
2177void clean_quit (void) {
2178 clean_quit_prep();
2179// driver_close(drvinst, drvid);
2180// output_buffer_free();
2181 exit(0);
2182}
2183
2184//ll
Note: See TracBrowser for help on using the repository browser.