source: trunk/third/esound/esd.c @ 18233

Revision 18233, 28.4 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18232, which included commits to RCS files with non-trunk default branches.
Line 
1#include "esd-server.h"
2
3#include <arpa/inet.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <sys/un.h>
7#include <errno.h>
8#include <signal.h>
9#include <time.h>
10
11#ifndef HAVE_NANOSLEEP
12#include <sys/time.h>
13#include <sys/types.h>
14#include <unistd.h>
15#endif
16
17#include <netdb.h>
18
19/* Older resolvers don't have gethostbyname2() */
20#ifndef HAVE_GETHOSTBYNAME2
21#define gethostbyname2(host, family) gethostbyname((host))
22#endif /* HAVE_GETHOSTBYNAME2 */
23
24/*******************************************************************/
25/* esd.c - prototypes */
26void set_audio_buffer( void *buf, esd_format_t format, int magl, int magr,
27                int freq, int speed, int length, long offset );
28void clean_exit( int signum );
29void reset_signal( int signum );
30void reset_daemon( int signum );
31int open_listen_socket( const char *hostname, int port );
32
33/*******************************************************************/
34/* globals */
35
36int esd_is_owned = 0;           /* start unowned, first client claims it */
37int esd_is_locked = 1;          /* if owned, will prohibit foreign sources */
38char esd_owner_key[ESD_KEY_LEN]; /* the key that locks the daemon */
39
40int esd_on_standby = 0;         /* set to route ignore incoming audio data */
41int esdbg_trace = 0;            /* show warm fuzzy debug messages */
42int esdbg_comms = 0;            /* show protocol level debug messages */
43int esdbg_mixer = 0;            /* show mixer engine debug messages */
44
45int esd_buf_size_octets = 0;    /* size of audio buffer in bytes */
46int esd_buf_size_samples = 0;   /* size of audio buffer in samples */
47int esd_sample_size = 0;        /* size of sample in bytes */
48
49int esd_beeps = 1;              /* whether or not to beep on startup */
50int listen_socket = -1;         /* socket to accept connections on */
51int esd_trustval = -1;          /* -1 be paranoic, 0 trust to owner of ESD_UNIX_SOCKET_DIR */
52
53int esd_autostandby_secs = -1;  /* timeout to release audio device, disabled <0 */
54time_t esd_last_activity = 0;   /* seconds since last activity */
55int esd_on_autostandby = 0;     /* set when auto paused for auto reawaken */
56
57int esd_use_tcpip = 0;          /* use tcp/ip sockets instead of unix domain */
58int esd_terminate = 0;          /* terminate after the last client exits */
59int esd_public = 0;             /* allow connects from hosts other than localhost */
60int esd_spawnpid = 0;           /* The PID of the process that spawned us (for use by esdlib only) */
61int esd_spawnfd = 0;           /* The PID of the process that spawned us (for use by esdlib only) */
62
63static char *programname = NULL;
64
65/*******************************************************************/
66/* just to create the startup tones for the fun of it */
67void set_audio_buffer( void *buf, esd_format_t format,
68                       int magl, int magr,
69                       int freq, int speed, int length, long offset )
70{
71    int i;
72    float sample;
73    float kf = 2.0 * 3.14 * (float)freq / (float)speed;
74
75    unsigned char *uc_buf = (unsigned char *)buf;
76    signed short *ss_buf = (signed short *)buf;
77
78    /* printf( "fmt=%d, ml=%d, mr=%d, freq=%d, speed=%d, len=%ld\n",
79       format, magl, magr, freq, speed, length ); */
80
81    switch ( format & ESD_MASK_BITS )
82    {
83    case ESD_BITS8:
84        for ( i = 0 ; i < length ; i+=2 ) {
85            sample = sin( (float)(i+offset) * kf );
86            uc_buf[i] = 127 + magl * sample;
87            uc_buf[i+1] = 127 + magr * sample;
88        }
89        break;
90    case ESD_BITS16:    /* assume same endian */
91        for ( i = 0 ; i < length ; i+=2 ) {
92            sample = sin( (float)(i+offset) * kf );
93            ss_buf[i] = magl * sample;
94            ss_buf[i+1] = magr * sample;
95        }
96        break;
97    default:
98        fprintf( stderr,
99                 "unsupported format for set_audio_buffer: 0x%08x\n",
100                 format );
101        exit( 1 );
102    }
103
104
105    return;
106}
107
108/*******************************************************************/
109/* to properly handle signals */
110
111void reset_daemon( int signum )
112{
113    int tumbler;
114
115    ESDBG_TRACE(
116        printf( "(ca) resetting sound daemon on signal %d\n",
117                signum ); );
118
119    /* reset the access rights */
120    esd_is_owned = 0;
121    esd_is_locked = 1;
122
123    /* scramble the stored key */
124    srand( time(NULL) );
125    for ( tumbler = 0 ; tumbler < ESD_KEY_LEN ; tumbler++ ) {
126        esd_owner_key[ tumbler ] = rand() % 256;
127    }
128
129    /* close the clients */
130    while ( esd_clients_list != NULL )
131    {
132        erase_client( esd_clients_list );
133    }
134
135    /* free samples */
136    while ( esd_samples_list != NULL )
137    {
138        erase_sample( esd_samples_list->sample_id, 1 );
139        /* TODO: kill_sample, so it stops playing */
140        /* a looping sample will get stuck */
141    }
142
143    /* reset next sample id */
144    esd_next_sample_id = 1;
145
146    /* reset signal handler, if not called from a signal, no effect */
147    signal( SIGHUP, reset_daemon );
148}
149
150void clean_exit(int signum) {
151    /* just clean up as best we can and terminate from here */
152    esd_client_t * client = esd_clients_list;
153
154/*    fprintf( stderr, "received signal %d: terminating...\n", signum );*/
155
156    /* free the sound device */
157    esd_audio_close();
158
159    /* close the listening socket */
160    close( listen_socket );
161
162    /* close the clients */
163    while ( client != NULL )
164    {
165        close( client->fd );
166        client = client->next;
167    }
168   if (!esd_use_tcpip)
169    {
170      unlink(ESD_UNIX_SOCKET_NAME);
171      rmdir(ESD_UNIX_SOCKET_DIR);
172    }
173
174
175    /* trust the os to clean up the memory for the samples and such */
176    exit( 0 );
177}
178
179void reset_signal(int signum) {
180/*    fprintf( stderr, "received signal %d: resetting...\n", signum );*/
181    signal( signum, reset_signal);
182
183    return;
184}
185
186static int
187esd_connect_unix(void)
188{
189  struct sockaddr_un socket_unix;
190  int socket_out = -1;
191  int curstate = 1;
192
193  /* create the socket, and set for non-blocking */
194  socket_out = socket( AF_UNIX, SOCK_STREAM, 0 );
195  if ( socket_out < 0 )
196    return -1;
197  /* this was borrowed blindly from the Tcl socket stuff */
198  if ( fcntl( socket_out, F_SETFD, FD_CLOEXEC ) < 0 )
199    return -1;
200  if ( setsockopt( socket_out, SOL_SOCKET, SO_REUSEADDR,
201                  &curstate, sizeof(curstate) ) < 0 )
202    return -1;
203  /* set the connect information */
204  socket_unix.sun_family = AF_UNIX;
205  strncpy(socket_unix.sun_path, ESD_UNIX_SOCKET_NAME, sizeof(socket_unix.sun_path));
206  if ( connect( socket_out,
207               (struct sockaddr *) &socket_unix, SUN_LEN(&socket_unix) ) < 0 )
208    return -1;
209  return socket_out;
210}
211
212
213/*******************************************************************/
214/* safely create directory for socket
215   Code inspired by trans_mkdir from XFree86 source code
216   For more credits see xc/lib/xtrans/Xtransutil.c. */
217int
218safe_mksocketdir(void)
219{
220struct stat dir_stats;
221
222#if defined(S_ISVTX)
223#define ESD_UNIX_SOCKET_DIR_MODE (S_IRUSR|S_IWUSR|S_IXUSR|\
224                                  S_IRGRP|S_IWGRP|S_IXGRP|\
225                                  S_IROTH|S_IWOTH|S_IXOTH|S_ISVTX)
226#else
227#define ESD_UNIX_SOCKET_DIR_MODE (S_IRUSR|S_IWUSR|S_IXUSR|\
228                                  S_IRGRP|S_IWGRP|S_IXGRP|\
229                                  S_IROTH|S_IWOTH|S_IXOTH)
230#endif
231
232  if (mkdir(ESD_UNIX_SOCKET_DIR, ESD_UNIX_SOCKET_DIR_MODE) == 0) {
233    if (chmod(ESD_UNIX_SOCKET_DIR, ESD_UNIX_SOCKET_DIR_MODE) != 0) {
234      return -1;
235    }
236    return 0;
237  }
238  /* If mkdir failed with EEXIST, test if it is a directory with
239     the right modes, else fail */
240  if (errno == EEXIST) {
241#if !defined(S_IFLNK) && !defined(S_ISLNK)
242#define lstat(a,b) stat(a,b)
243#endif
244    if (lstat(ESD_UNIX_SOCKET_DIR, &dir_stats) != 0) {
245      return -1;
246    }
247    if (S_ISDIR(dir_stats.st_mode)) {
248      int updateOwner = 0;
249      int updateMode = 0;
250      int updatedOwner = 0;
251      int updatedMode = 0;
252      /* Check if the directory's ownership is OK. */
253      if ((dir_stats.st_uid != 0) && (dir_stats.st_uid != getuid()))
254        updateOwner = 1;
255      /*
256       * Check if the directory's mode is OK.  An exact match isn't
257       * required, just a mode that isn't more permissive than the
258       * one requested.
259       */
260      if ( ~ESD_UNIX_SOCKET_DIR_MODE & (dir_stats.st_mode & ~S_IFMT))
261        updateMode = 1;
262#if defined(S_ISVTX)
263      if ((dir_stats.st_mode & S_IWOTH) && !(dir_stats.st_mode & S_ISVTX))
264        updateMode = 1;
265#endif
266#if defined(HAVE_FCHOWN) && defined(HAVE_FCHMOD)
267      /*
268       * If fchown(2) and fchmod(2) are available, try to correct the
269       * directory's owner and mode.  Otherwise it isn't safe to attempt
270       * to do this.
271       */
272      if (updateMode || updateOwner) {
273        int fd = -1;
274        struct stat fdir_stats;
275        if ((fd = open(ESD_UNIX_SOCKET_DIR, O_RDONLY)) != -1) {
276          if (fstat(fd, &fdir_stats) == -1) {
277            return esd_trustval;
278          }
279          /*
280           * Verify that we've opened the same directory as was
281           * checked above.
282           */
283          if (!S_ISDIR(fdir_stats.st_mode) ||
284              dir_stats.st_dev != fdir_stats.st_dev ||
285              dir_stats.st_ino != fdir_stats.st_ino) {
286            return esd_trustval;
287          }
288          if (updateOwner && fchown(fd, getuid(), getgid()) == 0)
289            updatedOwner = 1;
290          if (updateMode && fchmod(fd, ESD_UNIX_SOCKET_DIR_MODE) == 0)
291            updatedMode = 1;
292          close(fd);
293        }
294      }
295#endif
296      if (updateOwner && !updatedOwner) {
297        fprintf(stderr,
298                "esd: Failed to fix owner of %s.\n",
299              ESD_UNIX_SOCKET_DIR);
300        if (esd_trustval) fprintf(stderr, "Try -trust to force esd to start.\n");
301        return esd_trustval;
302      }
303      if (updateMode && !updatedMode) {
304        fprintf(stderr, "esd: Failed to fix mode of %s to %04o.\n",
305              ESD_UNIX_SOCKET_DIR, ESD_UNIX_SOCKET_DIR_MODE);
306        if (esd_trustval) fprintf(stderr, "Try -trust to force esd to start.\n");
307        return esd_trustval;
308      }
309      return 0;
310    }
311  }
312  /* In all other cases, fail */
313  return -1;
314}
315
316/*******************************************************************/
317/* returns the listening socket descriptor */
318int open_listen_socket(const char *hostname, int port )
319{
320    /*********************/
321    /* socket test setup */
322    struct sockaddr_in socket_addr;
323    struct sockaddr_un socket_unix;
324    int socket_listen = -1;
325    struct linger lin;
326
327        struct hostent *resolved;
328
329
330    /* create the socket, and set for non-blocking */
331    if (esd_use_tcpip)
332      socket_listen=socket(AF_INET, SOCK_STREAM, 0);
333    else
334    {
335      if (safe_mksocketdir())
336        {
337          fprintf(stderr,
338                  "esd: Esound sound daemon unable to create unix domain socket:\n"
339                  "%s\n"
340                  "The socket is not accessible by esd.\n"
341                  "Exiting...\n", ESD_UNIX_SOCKET_NAME);
342          exit(1);
343        }
344      else
345        {
346          if (esd_connect_unix() >= 0)
347            {
348              /* not allowed access */
349              fprintf(stderr,
350                      "esd: Esound sound daemon already running or stale UNIX socket\n"
351                      "%s\n"
352                      "This socket already exists indicating esd is already running.\n"
353                      "Exiting...\n", ESD_UNIX_SOCKET_NAME);
354              exit(1);
355            }
356        }
357      unlink(ESD_UNIX_SOCKET_NAME);
358      socket_listen=socket(AF_UNIX, SOCK_STREAM, 0);
359    }
360    if (socket_listen < 0)
361    {
362        fprintf(stderr,"Unable to create socket\n");
363        return( -1 );
364    }
365    if (fcntl(socket_listen, F_SETFL, O_NONBLOCK) < 0)
366    {
367        fprintf(stderr,"Unable to set socket to non-blocking\n");
368        return( -1 );
369    }
370
371    /* set socket for linger? */
372    lin.l_onoff=1;      /* block a closing socket for 1 second */
373    lin.l_linger=100;   /* if data is waiting to be sent */
374    if ( setsockopt( socket_listen, SOL_SOCKET, SO_LINGER,
375                     &lin, sizeof(struct linger) ) < 0 )
376    {
377        fprintf(stderr,"Unable to set socket linger value to %d\n",
378                lin.l_linger);
379        return( -1 );
380    }
381    {
382      int n = 1;
383      setsockopt(socket_listen, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
384      /* if it fails, so what */
385    }
386
387    if (esd_use_tcpip)
388    {
389      /* set the listening information */
390      memset(&socket_addr, 0, sizeof(struct sockaddr_in));
391      socket_addr.sin_family = AF_INET;
392      socket_addr.sin_port = htons( port );
393
394        /* if hostname is set, bind to its first address */
395        if (hostname)
396        {
397                if (!(resolved=gethostbyname2(hostname, AF_INET)))
398                {
399                        herror(programname);
400                        return -1;
401                }
402                memcpy(&(socket_addr.sin_addr), resolved->h_addr_list[0], resolved->h_length);
403        } else if (esd_public)
404                socket_addr.sin_addr.s_addr = htonl( INADDR_ANY );
405        else
406                socket_addr.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
407
408      if ( bind( socket_listen,
409                (struct sockaddr *) &socket_addr,
410                sizeof(struct sockaddr_in) ) < 0 )
411        {
412          fprintf(stderr,"Unable to bind port %d\n", port );
413          exit(1);
414        }
415    }
416    else
417    {
418      mode_t old_umask;
419
420      old_umask = umask(0);
421      socket_unix.sun_family=AF_UNIX;
422      strncpy(socket_unix.sun_path, ESD_UNIX_SOCKET_NAME, sizeof(socket_unix.sun_path));
423      if ( bind( socket_listen,
424                (struct sockaddr *) &socket_unix, SUN_LEN(&socket_unix) ) < 0 )
425        {
426          fprintf(stderr,"Unable to connect to UNIX socket %s\n", ESD_UNIX_SOCKET_NAME);
427          if (!esd_use_tcpip)
428            {
429              unlink(ESD_UNIX_SOCKET_NAME);
430              rmdir(ESD_UNIX_SOCKET_DIR);
431            }
432          exit(1);
433        }
434      umask(old_umask);
435    }
436    if (listen(socket_listen,16)<0)
437    {
438      fprintf(stderr,"Unable to set socket listen buffer length\n");
439      if (!esd_use_tcpip)
440        {
441          unlink(ESD_UNIX_SOCKET_NAME);
442          rmdir(ESD_UNIX_SOCKET_DIR);
443        }
444      exit(1);
445    }
446
447    return socket_listen;
448}
449
450/*******************************************************************/
451/* daemon eats sound data, without playing anything, return boolean ok */
452int esd_server_standby(void)
453{
454    int ok = 1;
455
456    /* only bother if we're not already on standby */
457    if ( !esd_on_standby ) {
458        ESDBG_TRACE( printf( "setting sound daemon to standby\n" ); );
459       
460        /* TODO: close down any recorders, too */
461        esd_on_standby = 1;
462        esd_audio_close();
463    }   
464
465    return ok;
466}
467
468/*******************************************************************/
469/* daemon goes back to playing sound data, returns boolean ok */
470int esd_server_resume(void)
471{
472    int ok = 1;
473
474    /* only bother if we're already on standby */
475    if ( esd_on_standby ) {
476       
477        ESDBG_TRACE( printf( "resuming sound daemon\n" ); );
478       
479        /* reclaim the audio device */
480        if ( esd_audio_open() < 0 ) {
481            /* device was busy or something, return error, try  later */
482            ok = 0;
483        } else {
484            /* turn ourselves back on */
485            esd_on_standby = 0;
486            esd_on_autostandby = 0;
487            esd_forced_standby = 0;
488        }
489    }
490
491    return ok;
492}
493
494/*******************************************************************/
495int main ( int argc, char *argv[] )
496{
497    /***************************/
498    /* Enlightened sound Daemon */
499
500    int esd_port = ESD_DEFAULT_PORT;
501    int length = 0;
502    int arg = 0;
503    int itmp;
504
505    void *output_buffer = NULL;
506
507    char *hostname=NULL;
508
509    /* begin test scaffolding parameters */
510    /* int format = AFMT_U8; AFMT_S16_LE; */
511    /* int stereo = 0; */     /* 0=mono, 1=stereo */
512    int default_rate = ESD_DEFAULT_RATE, default_buf_size = ESD_BUF_SIZE;
513    int i, j, freq=440;
514    int magl, magr;
515
516    int first = 1;
517
518    int default_format = ESD_BITS16 | ESD_STEREO;
519    /* end test scaffolding parameters */
520
521    programname = *argv;
522
523    /* parse the command line args */
524    for ( arg = 1 ; arg < argc ; arg++ ) {
525        if ( !strcmp( argv[ arg ], "-d" ) ) {
526            if ( ++arg != argc ) {
527                esd_audio_device = argv[ arg ];
528                if ( !esd_audio_device ) {
529                    esd_port = ESD_DEFAULT_PORT;
530                    fprintf( stderr, "- could not read device: %s\n",
531                             argv[ arg ] );
532                }
533                fprintf( stderr, "- using device %s\n",
534                         esd_audio_device );
535            }
536        } else if ( !strcmp( argv[ arg ], "-port" ) ) {
537            if ( ++arg != argc ) {
538                esd_port = atoi( argv[ arg ] );
539                if ( !esd_port ) {
540                    esd_port = ESD_DEFAULT_PORT;
541                    fprintf( stderr, "- could not read port: %s\n",
542                             argv[ arg ] );
543                }
544                fprintf( stderr, "- accepting connections on port %d\n",
545                         esd_port );
546            }
547
548        } else if ( !strcmp( argv[ arg ], "-bind" ) ) {
549            if ( ++arg != argc )
550                {
551                        hostname = argv[ arg ];
552                }
553                fprintf( stderr, "- accepting connections on port %d\n",
554                         esd_port );
555        } else if ( !strcmp( argv[ arg ], "-b" ) ) {
556            fprintf( stderr, "- server format: 8 bit samples\n" );
557            default_format &= ~ESD_MASK_BITS; default_format |= ESD_BITS8;
558        } else if ( !strcmp( argv[ arg ], "-r" ) ) {
559            if ( ++arg != argc ) {
560                default_rate = atoi( argv[ arg ] );
561                if ( !default_rate ) {
562                    default_rate = ESD_DEFAULT_RATE;
563                    fprintf( stderr, "- could not read rate: %s\n",
564                             argv[ arg ] );
565                }
566                fprintf( stderr, "- server format: sample rate = %d Hz\n",
567                         default_rate );
568            }
569        } else if ( !strcmp( argv[ arg ], "-as" ) ) {
570            if ( ++arg != argc ) {
571                esd_autostandby_secs = atoi( argv[ arg ] );
572                if ( !esd_autostandby_secs ) {
573                    esd_autostandby_secs = ESD_DEFAULT_AUTOSTANDBY_SECS;
574                    fprintf( stderr, "- could not read autostandby timeout: %s\n",
575                             argv[ arg ] );
576                }
577/*              fprintf( stderr, "- autostandby timeout: %d seconds\n",
578                         esd_autostandby_secs );*/
579            }
580#ifdef ESDBG
581        } else if ( !strcmp( argv[ arg ], "-vt" ) ) {
582            esdbg_trace = 1;
583            fprintf( stderr, "- enabling trace diagnostic info\n" );
584        } else if ( !strcmp( argv[ arg ], "-vc" ) ) {
585            esdbg_comms = 1;
586            fprintf( stderr, "- enabling comms diagnostic info\n" );
587        } else if ( !strcmp( argv[ arg ], "-vm" ) ) {
588            esdbg_mixer = 1;
589            fprintf( stderr, "- enabling mixer diagnostic info\n" );
590#endif
591        } else if ( !strcmp( argv[ arg ], "-nobeeps" ) ) {
592            esd_beeps = 0;
593/*          fprintf( stderr, "- disabling startup beeps\n" );*/
594        } else if ( !strcmp( argv[ arg ], "-unix" ) ) {
595            esd_use_tcpip = 0;
596        } else if ( !strcmp( argv[ arg ], "-tcp" ) ) {
597            esd_use_tcpip = 1;
598        } else if ( !strcmp( argv[ arg ], "-public" ) ) {
599            esd_public = 1;
600        } else if ( !strcmp( argv[ arg ], "-promiscuous" ) ) {
601            esd_is_owned = 1;
602            esd_is_locked = 0;
603        } else if ( !strcmp( argv[ arg ], "-terminate" ) ) {
604            esd_terminate = 1;
605        } else if ( !strcmp( argv[ arg ], "-spawnpid" ) ) {
606            if ( ++arg < argc )
607                esd_spawnpid = atoi( argv[ arg ] );
608        } else if ( !strcmp( argv[ arg ], "-spawnfd" ) ) {
609            if ( ++arg < argc )
610                esd_spawnfd = atoi( argv[ arg ] );
611        } else if ( !strcmp( argv[ arg ], "-trust" ) ) {
612            esd_trustval = 0;
613        } else if ( !strcmp( argv[ arg ], "-v" ) || !strcmp( argv[ arg ], "--version" ) ) {
614                fprintf(stderr, "Esound version " VERSION "\n");
615                exit (0);
616        } else if ( !strcmp( argv[ arg ], "-h" ) || !strcmp( argv[ arg ], "--help" ) ) {
617            fprintf( stderr, "Esound version " VERSION "\n\n");
618            fprintf( stderr, "Usage: esd [options]\n\n" );
619            fprintf( stderr, "  -v --version  print version information\n" );
620            fprintf( stderr, "  -d DEVICE     force esd to use sound device DEVICE\n" );
621            fprintf( stderr, "  -b            run server in 8 bit sound mode\n" );
622            fprintf( stderr, "  -r RATE       run server at sample rate of RATE\n" );
623            fprintf( stderr, "  -as SECS      free audio device after SECS of inactivity\n" );
624            fprintf( stderr, "  -unix         use unix domain sockets instead of tcp/ip\n" );
625            fprintf( stderr, "  -tcp          use tcp/ip sockets instead of unix domain\n" );
626            fprintf( stderr, "  -public       make tcp/ip access public (other than localhost)\n" );
627            fprintf( stderr, "  -promiscuous  start unlocked and owned (disable authenticaton) NOT RECOMMENDED\n" );
628            fprintf( stderr, "  -terminate    terminate esd daemone after last client exits\n" );
629            fprintf( stderr, "  -nobeeps      disable startup beeps\n" );
630            fprintf( stderr, "  -trust        start esd even if use of %s can be insecure\n",
631                     ESD_UNIX_SOCKET_DIR );
632#ifdef ESDBG
633            fprintf( stderr, "  -vt           enable trace diagnostic info\n" );
634            fprintf( stderr, "  -vc           enable comms diagnostic info\n" );
635            fprintf( stderr, "  -vm           enable mixer diagnostic info\n" );
636#endif
637            fprintf( stderr, "  -port PORT   listen for connections at PORT (only for tcp/ip)\n" );
638            fprintf( stderr, "  -bind ADDRESS binds to ADDRESS (only for tcp/ip)\n" );
639            fprintf( stderr, "\nPossible devices are:  %s\n", esd_audio_devices() );
640            exit( 0 );
641        } else {
642            fprintf( stderr, "unrecognized option: %s\n", argv[ arg ] );
643        }
644    }
645
646    /* open the listening socket */
647  listen_socket = open_listen_socket(hostname, esd_port );
648  if ( listen_socket < 0 ) {
649    fprintf( stderr, "fatal error opening socket\n" );
650    if (!esd_use_tcpip)
651      {
652        unlink(ESD_UNIX_SOCKET_NAME);
653        rmdir(ESD_UNIX_SOCKET_DIR);
654      }
655    exit( 1 ); 
656  }
657
658#define ESD_AUDIO_STUFF \
659    esd_sample_size = ( (esd_audio_format & ESD_MASK_BITS) == ESD_BITS16 ) \
660        ? sizeof(signed short) : sizeof(unsigned char); \
661    esd_buf_size_samples = default_buf_size / 2; \
662    esd_buf_size_octets = esd_buf_size_samples * esd_sample_size;
663
664    /* start the initializatin process */
665/*    printf( "ESound ESD daemon initializing...\n" );*/
666
667    /* set the data size parameters */
668    esd_audio_format = default_format;
669    esd_audio_rate = default_rate;
670    ESD_AUDIO_STUFF;
671
672  /* open and initialize the audio device, /dev/dsp */
673  itmp = esd_audio_open();
674  if (itmp == -2) { /* Special return value indicates open of device failed, don't bother
675                       trying */
676    if(esd_spawnpid)
677      kill(esd_spawnpid, SIGALRM); /* Startup failed */
678   
679    if(esd_spawnfd) {
680        char c = 0; /* Startup failed */
681        write (esd_spawnfd, &c, 1);
682    }
683
684    if (!esd_use_tcpip) {
685        unlink(ESD_UNIX_SOCKET_NAME);
686        rmdir(ESD_UNIX_SOCKET_DIR);
687      }
688    exit (2);
689  } else if ( itmp < 0 ) {
690    fprintf(stderr, "Audio device open for 44.1Khz, stereo, 16bit failed\n"
691            "Trying 44.1Khz, 8bit stereo.\n");
692    /* cant do defaults ... try 44.1 kkz 8bit stereo */
693    esd_audio_format = ESD_BITS8 | ESD_STEREO;
694    esd_audio_rate = 44100;
695    ESD_AUDIO_STUFF;
696    if ( esd_audio_open() < 0 ) {
697      fprintf(stderr, "Audio device open for 44.1Khz, stereo, 8bit failed\n"
698
699            "Trying 48Khz, 16bit stereo.\n");
700    /* cant do defaults ... try 48 kkz 16bit stereo */
701    esd_audio_format = ESD_BITS16 | ESD_STEREO;
702    esd_audio_rate = 48000;
703    ESD_AUDIO_STUFF;
704    if ( esd_audio_open() < 0 ) {
705      fprintf(stderr, "Audio device open for 48Khz, stereo,16bit failed\n"
706              "Trying 22.05Khz, 8bit stereo.\n");
707      /* cant do defaults ... try 22.05 kkz 8bit stereo */
708      esd_audio_format = ESD_BITS8 | ESD_STEREO;
709      esd_audio_rate = 22050;
710      ESD_AUDIO_STUFF;
711      if ( esd_audio_open() < 0 ) {
712        fprintf(stderr, "Audio device open for 22.05Khz, stereo, 8bit failed\n"
713                "Trying 44.1Khz, 16bit mono.\n");
714        /* cant do defaults ... try 44.1Khz kkz 16bit mono */
715        esd_audio_format = ESD_BITS16;
716        esd_audio_rate = 44100;
717        ESD_AUDIO_STUFF;
718        if ( esd_audio_open() < 0 ) {
719          fprintf(stderr, "Audio device open for 44.1Khz, mono, 8bit failed\n"
720                  "Trying 22.05Khz, 8bit mono.\n");
721          /* cant do defaults ... try 22.05 kkz 8bit mono */
722          esd_audio_format = ESD_BITS8;
723          esd_audio_rate = 22050;
724          ESD_AUDIO_STUFF;
725          if ( esd_audio_open() < 0 ) {
726            fprintf(stderr, "Audio device open for 22.05Khz, mono, 8bit failed\n"
727                    "Trying 11.025Khz, 8bit stereo.\n");
728            /* cant to defaults ... try 11.025 kkz 8bit stereo */
729            esd_audio_format = ESD_BITS8 | ESD_STEREO;
730            esd_audio_rate = 11025;
731            ESD_AUDIO_STUFF;
732            if ( esd_audio_open() < 0 ) {
733              fprintf(stderr, "Audio device open for 11.025Khz, stereo, 8bit failed\n"
734                      "Trying 11.025Khz, 8bit mono.\n");
735              /* cant to defaults ... try 11.025 kkz 8bit mono */
736              esd_audio_format = ESD_BITS8;
737              esd_audio_rate = 11025;
738              ESD_AUDIO_STUFF;
739              if ( esd_audio_open() < 0 ) {
740                fprintf(stderr, "Audio device open for 11.025Khz, mono, 8bit failed\n"
741                        "Trying 8.192Khz, 8bit mono.\n");
742                /* cant to defaults ... try 8.192 kkz 8bit mono */
743                esd_audio_format = ESD_BITS8;
744                esd_audio_rate = 8192;
745                ESD_AUDIO_STUFF;
746                if ( esd_audio_open() < 0 ) {
747                  fprintf(stderr, "Audio device open for 8.192Khz, mono, 8bit failed\n"
748                          "Trying 8Khz, 8bit mono.\n");
749                  /* cant to defaults ... try 8 kkz 8bit mono */
750                  esd_audio_format = ESD_BITS8;
751                  esd_audio_rate = 8000;
752                  ESD_AUDIO_STUFF;
753                  if ( esd_audio_open() < 0 ) {
754                    fprintf(stderr, "Sound device inadequate for Esound. Fatal.\n");
755                    if (!esd_use_tcpip)
756                      {
757                        unlink(ESD_UNIX_SOCKET_NAME);
758                        rmdir(ESD_UNIX_SOCKET_DIR);
759                      }
760                    if(esd_spawnpid)
761                      kill(esd_spawnpid, SIGALRM); /* Startup failed */
762
763                    if(esd_spawnfd) {
764                        char c = 0; /* Startup failed */
765                        write (esd_spawnfd, &c, 1);
766                    }
767                   
768                    exit( 1 );
769                  }
770                }
771              }
772            }
773          }
774        }
775      }
776    }
777   }
778  }
779
780    /* allocate and zero out buffer */
781    output_buffer = (void *) malloc( esd_buf_size_octets );
782    memset( output_buffer, 0, esd_buf_size_octets );
783
784
785    /* install signal handlers for program integrity */
786    signal( SIGINT, clean_exit );       /* for ^C */
787    signal( SIGTERM, clean_exit );      /* for default kill */
788    signal( SIGPIPE, reset_signal );    /* for closed rec/mon clients */
789    signal( SIGHUP, reset_daemon );     /* kill -HUP clear ownership */
790
791    /* send some sine waves just to check the sound connection */
792    i = 0;
793    if ( esd_beeps ) {
794        magl = magr = ( (esd_audio_format & ESD_MASK_BITS) == ESD_BITS16)
795            ? 30000 : 100;
796
797        for ( freq = 55 ; freq < esd_audio_rate/2 ; freq *= 2, i++ ) {
798            /* repeat the freq for a few buffer lengths */
799            for ( j = 0 ; j < esd_audio_rate / 4 / esd_buf_size_samples ; j++ ) {
800                set_audio_buffer( output_buffer, esd_audio_format,
801                                  ( (i%2) ? magl : 0 ),  ( (i%2) ? 0 : magr ),
802                                  freq, esd_audio_rate, esd_buf_size_samples,
803                                  j * esd_buf_size_samples );
804                esd_audio_write( output_buffer, esd_buf_size_octets );
805            }
806        }
807    }
808
809    /* put some stuff in sound driver before pausing */
810    esd_audio_write( NULL, 0);
811
812    /* pause the sound output */
813    esd_audio_pause();
814
815    /* Startup succeeded */
816    if(esd_spawnpid)
817      kill(esd_spawnpid, SIGUSR1);
818
819    if(esd_spawnfd) {
820        char c = 1; /* Startup succeeded */
821        write (esd_spawnfd, &c, 1);
822    }
823
824    /* until we kill the daemon */
825    while ( 1 )
826    {
827        /* block while waiting for more clients and new data */
828        wait_for_clients_and_data( listen_socket );
829
830        /* accept new connections */
831        get_new_clients( listen_socket );
832
833
834        if ((esd_clients_list == NULL) && (!first) && (esd_terminate)) {
835/*        fprintf(stderr, "No clients!\n");*/
836          clean_exit(0);
837          exit(0);
838        }
839
840        /* check for new protocol requests */
841        poll_client_requests();
842        first = 0;
843
844        /* mix new requests, and output to device */
845        refresh_mix_funcs(); /* TODO: set a flag to cue when to do this */
846        length = mix_players( output_buffer, esd_buf_size_octets );
847       
848        /* awaken if on autostandby and doing anything */
849        if ( esd_on_autostandby && length && !esd_forced_standby ) {
850            ESDBG_TRACE( printf( "stuff to play, waking up.\n" ); );
851            esd_server_resume();
852        }
853
854        /* we handle this even when length == 0 because a filter could have
855         * closed, and we don't want to eat the processor if one did.. */
856        if ( esd_filter_list && !esd_on_standby ) {
857            length = filter_write( output_buffer, length,
858                                   esd_audio_format, esd_audio_rate );
859        }
860       
861        if ( length > 0 /* || esd_monitor */ ) {
862            /* do_sleep = 0; */
863            if ( !esd_on_standby ) {
864                /* standby check goes in here, so esd will eat sound data */
865                /* TODO: eat a round of data with a better algorithm */
866                /*        this will cause guaranteed timing issues */
867                /* TODO: on monitor, why isn't this a buffer of zeroes? */
868                /* esd_audio_write( output_buffer, esd_buf_size_octets ); */
869                esd_audio_write( output_buffer, length );
870                /* esd_audio_flush(); */ /* this is overkill */
871                esd_last_activity = time( NULL );
872            }
873        } else {
874            /* should be pausing just fine within wait_for_clients_and_data */
875            /* if so, this isn't really needed */
876
877            /* be very quiet, and wait for a wabbit to come along */
878#if 0
879            if ( !do_sleep ) { ESDBG_TRACE( printf( "pausing in esd.c\n" ); ); }
880            do_sleep = 1;
881            esd_audio_pause();
882#endif
883        }
884
885        /* if someone's monitoring the sound stream, send them data */
886        /* mix_players, above, forces buffer to zero if no players */
887        /* this clears out any leftovers from recording, below */
888        if ( esd_monitor_list && !esd_on_standby && length ) {
889        /* if ( esd_monitor_list && !esd_on_standby ) {  */
890            monitor_write( output_buffer, length );
891        }
892
893        /* if someone's recording the sound stream, send them data */
894        if ( esd_recorder_list && !esd_on_standby ) {
895            length = esd_audio_read( output_buffer, esd_buf_size_octets );
896            if ( length ) {
897                length = recorder_write( output_buffer, length );
898                esd_last_activity = time( NULL );
899            }
900        }
901
902        if ( esd_on_standby ) {
903#ifdef HAVE_NANOSLEEP
904            struct timespec restrain;
905            restrain.tv_sec = 0;
906            /* funky math to make sure a long can hold it all, calulate in ms */
907            restrain.tv_nsec = (long) esd_buf_size_samples * 1000L
908                / (long) esd_audio_rate / 4L;   /* divide by two for stereo */
909            restrain.tv_nsec *= 1000000L;       /* convert to nanoseconds */
910            nanosleep( &restrain, NULL );
911#else
912            struct timeval restrain;
913            restrain.tv_sec = 0;
914            /* funky math to make sure a long can hold it all, calulate in ms */
915            restrain.tv_usec = (long) esd_buf_size_samples * 1000L
916                / (long) esd_audio_rate / 4L;   /* divide by two for stereo */
917            restrain.tv_usec *= 1000L;          /* convert to microseconds */
918            select( 0, 0, 0, 0, &restrain );
919#endif
920        }
921    } /* while ( 1 ) */
922
923    /* how we'd get here, i have no idea, should only exit on signal */
924    clean_exit( -1 );
925    exit( 0 );
926}
Note: See TracBrowser for help on using the repository browser.