source: roaraudio/roard/roard.c @ 3252:5dd53a288c8b

Last change on this file since 3252:5dd53a288c8b was 3252:5dd53a288c8b, checked in by phi, 14 years ago

added support for --proto-* options (no protocol does use it at the moment)

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