esound r524 - trunk



Author: jmouette
Date: Tue Nov 18 20:32:55 2008
New Revision: 524
URL: http://svn.gnome.org/viewvc/esound?rev=524&view=rev

Log:
        * esd-server.h:
        * esd.c: (reconnect_driver), (main): Install signal handler for
        SIGUSR1 that reconnects to the ALSA driver. This is useful
        after changing the ALSA configuration file.
        * clients.c: (esd_comm_loop): Integrate driver reconnection
        into client loop.
        * audio_alsa09.c: Call snd_config_update_free_global() to purge
        configuration cache and to properly reload configuration
        files.


Modified:
   trunk/ChangeLog
   trunk/audio_alsa09.c
   trunk/clients.c
   trunk/esd-server.h
   trunk/esd.c

Modified: trunk/audio_alsa09.c
==============================================================================
--- trunk/audio_alsa09.c	(original)
+++ trunk/audio_alsa09.c	Tue Nov 18 20:32:55 2008
@@ -101,6 +101,7 @@
 	snd_pcm_uframes_t t_bufsize=BUFFERSIZE;
 #endif
 
+	snd_config_update_free_global();
 	err = snd_pcm_open(&handle, dev, mode, SND_PCM_NONBLOCK);
 	if (err < 0) {
 		if (alsadbg)

Modified: trunk/clients.c
==============================================================================
--- trunk/clients.c	(original)
+++ trunk/clients.c	Tue Nov 18 20:32:55 2008
@@ -1,6 +1,7 @@
 #include "esd-server.h"
 #include <arpa/inet.h>
 #include <time.h>
+#include <errno.h>
 
 #ifdef HAVE_SYS_IOCTL_H
 # include <sys/ioctl.h>
@@ -26,6 +27,7 @@
 
 /* the list of the currently connected clients */
 esd_client_t *esd_clients_list;
+static int write_wait = 0;
 
 /*******************************************************************/
 /* prototypes */
@@ -251,113 +253,183 @@
     return 0;
 }
 
-static int is_paused_here = 0;
-/*******************************************************************/
-/* blocks waiting for data from the listener, and client conns. */
-int wait_for_clients_and_data( int listen )
+void esd_comm_loop( int listen_socket, void *output_buffer, int esd_terminate )
 {
     fd_set rd_fds;
     struct timeval timeout;
     struct timeval *timeout_ptr = NULL;
-    esd_client_t *client = esd_clients_list;
-    int max_fd = listen, ready;
-
-    /* add the listener to the file descriptor list */
-    FD_ZERO( &rd_fds );
-    FD_SET( listen, &rd_fds );
+    esd_client_t *client;
+    int max_fd = listen_socket, ready;
+    int first = 1;
+    int is_paused_here = 0;
+    int length = 0;
 
-    /* add the clients to the list, too */
-    while ( client != NULL )
+    while ( 1 )
     {
-	/* add this client, but only if it's not monitoring */
-	if ( client->state == ESD_STREAMING_DATA &&
-	     client->request == ESD_PROTO_STREAM_MON )
-	{
-	    client = client->next;
-	    continue;
-	}
-
-	FD_SET( client->fd, &rd_fds );
-
-	/* update the maximum fd for the select() */
-	if ( client->fd > max_fd )
-	    max_fd = client->fd;
+	FD_ZERO( &rd_fds );
+	FD_SET( listen_socket, &rd_fds );
 
-	/* next client */
-	client = client->next;
-    }
-
-    /* if we're doing something useful, make sure we return immediately */
-    if ( esd_recorder_list || esd_playing_samples ) {
-	timeout.tv_sec = 0;
-	timeout.tv_usec = 0;
-	timeout_ptr = &timeout;
-    } else {
-
-	/* TODO: any reason not to pause indefinitely here? */
-	/* sample players that's why, if no players, can pause indefinitely */
-	/* if ( esd_on_autostandby 
-	        || (esd_autostandby_secs < 0 && !esd_playing_samples ) )
-	       timeout_ptr = NULL; else { ... } */
-
-	if ( is_paused_here ) {
-
-	    ESDBG_TRACE( printf( "paused, awaiting instructions.\n" ); );
-	    timeout_ptr = NULL;
+        if( esd_pending_driver_reconnect ) {
+            esd_pending_driver_reconnect = 0;
+            esd_audio_close();
+	    usleep(100);
+            if( esd_audio_open() < 0 )
+                fprintf( stderr, "could not reopen the audio device\n" );
+        }
+
+	if ((esd_clients_list == NULL) && (!first) && (esd_terminate)
+	&& (esd_autostandby_secs<0 || esd_on_autostandby)) {
+	    clean_exit(0);
+	    exit(0);
+	}
 
-	} else {
+	for( client = esd_clients_list ; client ; client = client->next)
+	{
+	    if ( client->state == ESD_STREAMING_DATA &&
+		client->request == ESD_PROTO_STREAM_MON )
+		continue;
+
+	    FD_SET( client->fd, &rd_fds );
+	    if ( client->fd > max_fd )
+		max_fd = client->fd;
+	}
 
+	/* if we're doing something useful, make sure we return immediately */
+	if ( esd_recorder_list || esd_playing_samples ) {
 	    timeout.tv_sec = 0;
-	    /* funky math to make sure a long can hold it all, calulate in ms */
-	    timeout.tv_usec = (long) esd_buf_size_samples * 1000L
-		/ (long) esd_audio_rate / 4L; 	/* divide by two for stereo */
-	    timeout.tv_usec *= 1000L; 		/* convert to microseconds */
+	    timeout.tv_usec = 0;
 	    timeout_ptr = &timeout;
-
-	}
-    }
-
-    ready = select( max_fd+1, &rd_fds, NULL, NULL, timeout_ptr );
-
-    ESDBG_COMMS( printf( 
-	"paused=%d, samples=%d, auto=%d, standby=%d, record=%d, ready=%d\n",
-	is_paused_here, esd_playing_samples, 
-	esd_autostandby_secs, esd_on_standby, 
-	(esd_recorder_list != 0), ready ); );
-
-    /* TODO: return ready, and do this in esd.c */
-    if ( ready <= 0 ) {
-	/* if < 0, something horrible happened:
-	   EBADF   invalid file descriptor - let individual read sort it out
-	   EINTR   non blocked signal caught - o well, no big deal
-	   EINVAL  n is negative - not bloody likely
-	   ENOMEM  unable to allocate internal tables - o well, no big deal */
-
-	if ( !is_paused_here && !esd_playing_samples && (esd_autostandby_secs<0) ) {
-	    ESDBG_TRACE( printf( "doing nothing, pausing server.\n" ); );
-	    esd_audio_flush();
-	    esd_audio_pause();
-	    esd_last_activity = time( NULL );
-	    is_paused_here = 1;
+	} else {
+	    if ( is_paused_here && (esd_autostandby_secs<0 || esd_on_standby)) {
+		ESDBG_TRACE( printf( "paused, awaiting instructions.\n" ); );
+		timeout_ptr = NULL;
+	    } else {
+		if (is_paused_here && esd_autostandby_secs>=0) {
+		    timeout.tv_sec = (esd_last_activity+esd_autostandby_secs+1)-time(NULL);
+		    if (timeout.tv_sec < 0 || timeout.tv_sec > esd_autostandby_secs+1)
+			timeout.tv_sec = 0;
+		    timeout.tv_usec = 0;
+		    timeout_ptr = &timeout;
+		} else {
+		    if (!write_wait)
+		    {
+			int samples;
+
+			samples = ((esd_audio_format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1;
+			timeout.tv_sec = 0;
+			/* funky math to make sure a long can hold it all, calulate in ms */
+			timeout.tv_usec = ((long) samples * 1000L
+			    / (long) esd_audio_rate)+1;
+			timeout.tv_usec *= 1000; 	/* convert to microseconds */
+			timeout_ptr = &timeout;
+		    }
+		    else
+			timeout_ptr = NULL;
+		}
+	    }
 	}
 
-	if ( !is_paused_here && !esd_playing_samples && !esd_recorder_list ) {
+	ready = select( max_fd+1, &rd_fds, NULL, NULL, timeout_ptr );
 
-	    if ( esd_autostandby_secs >= 0
+	ESDBG_COMMS( printf( 
+	    "paused=%d, samples=%d, auto=%d, standby=%d, record=%d, ready=%d\n",
+	    is_paused_here, esd_playing_samples, 
+	    esd_autostandby_secs, esd_on_standby, 
+	    (esd_recorder_list != 0), ready ); );
+
+	if ( ready < 0 ) {
+	    if ( errno == EINTR && timeout_ptr == NULL && write_wait == 0 ) {
+		ready = 1;
+	    } else {
+		if ( errno == EINTR || errno == EAGAIN )
+		    continue;
+		perror("select");
+		exit(1);
+	    }
+	} else if ( ready == 0 ) {
+	    if ( !is_paused_here && !esd_playing_samples && !esd_recorder_list ) {
+		ESDBG_TRACE( printf( "doing nothing, pausing server.\n" ); );
+		esd_audio_flush();
+		if (!first)
+		    esd_audio_pause();
+		esd_last_activity = time( NULL );
+		is_paused_here = 1;
+	    }
+	    if ( is_paused_here && esd_autostandby_secs >= 0
 		 && ( time(NULL) > esd_last_activity + esd_autostandby_secs ) ) {
 		ESDBG_TRACE( printf( "bored, going to standby mode.\n" ); );
 		esd_server_standby();
 		esd_on_autostandby = 1;
-		is_paused_here = 1;
 	    }
+	    if (!esd_recorder_list && is_paused_here)
+		continue;
+	}
+	is_paused_here = 0;
 
+	if ( FD_ISSET(listen_socket, &rd_fds ) ) {
+	    get_new_clients( listen_socket );
 	}
 
-    } else {
+	if ( ready || esd_playing_samples ) {
+	    /* check for new protocol requests */
+	    poll_client_requests();
+	    first = 0;
+
+	/* mix new requests, and output to device */
+	refresh_mix_funcs(); /* TODO: set a flag to cue when to do this */
+	length = mix_players( output_buffer, esd_buf_size_octets );
+	
+	/* awaken if on autostandby and doing anything */
+	if ( esd_on_autostandby && length && !esd_forced_standby ) {
+	    ESDBG_TRACE( printf( "stuff to play, waking up.\n" ); );
+	    if ( !esd_server_resume()) {
+		usleep(100);
+	    }
+	}
 
-	is_paused_here = 0;
+	/* we handle this even when length == 0 because a filter could have
+	 * closed, and we don't want to eat the processor if one did.. */
+	if ( esd_filter_list && !esd_on_standby ) {
+	    length = filter_write( output_buffer, length,
+				   esd_audio_format, esd_audio_rate );
+	}
+	
+	if ( length > 0 && !write_wait) {
+	    if ( !esd_on_standby ) {
+		int nbytes;
+		/* standby check goes in here, so esd will eat sound data */
+		/* TODO: eat a round of data with a better algorithm */
+		/*        this will cause guaranteed timing issues */
+		/* TODO: on monitor, why isn't this a buffer of zeroes? */
+		nbytes = esd_audio_write( output_buffer, length );
+#if 0
+		val.tv_sec = 0;
+		val.tv_usec = ((nbytes / esd_sample_size /
+				       (((esd_audio_format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1))
+				       * 1000) / esd_audio_rate;
+		val.tv_usec *= 1000000;
+#endif
 
-    }
+		esd_last_activity = time( NULL );
+	    }
 
-    return ready;
+	/* if someone's monitoring the sound stream, send them data */
+	/* mix_players, above, forces buffer to zero if no players */
+	/* this clears out any leftovers from recording, below */
+	if ( esd_monitor_list && !esd_on_standby && length ) {
+	    monitor_write( output_buffer, length );
+	}
+
+	}
+	}
+
+	/* if someone's recording from the audio device, send them data */
+	if ( esd_recorder_list && !esd_on_standby ) {
+	    length = esd_audio_read( output_buffer, esd_buf_size_octets );
+	    if ( length ) {
+		length = recorder_write( output_buffer, length );
+		esd_last_activity = time( NULL );
+	    }
+	}
+    }
 }

Modified: trunk/esd-server.h
==============================================================================
--- trunk/esd-server.h	(original)
+++ trunk/esd-server.h	Tue Nov 18 20:32:55 2008
@@ -121,6 +121,7 @@
 extern char esd_owner_key[ESD_KEY_LEN];
 
 extern int esd_on_standby;
+extern int esd_pending_driver_reconnect;
 extern int esdbg_trace;
 extern int esdbg_comms;
 extern int esdbg_mixer;
@@ -144,6 +145,7 @@
 
 int get_new_clients( int listen );
 int wait_for_clients_and_data( int listen );
+void esd_comm_loop( int listen_socket, void *output_buffer, int esd_terminate );
 
 /* filter.c - things with which to handle filters */
 extern esd_player_t *esd_filter_list;

Modified: trunk/esd.c
==============================================================================
--- trunk/esd.c	(original)
+++ trunk/esd.c	Tue Nov 18 20:32:55 2008
@@ -70,6 +70,7 @@
 void clean_exit( int signum );
 void reset_signal( int signum );
 void reset_daemon( int signum );
+void reconnect_driver( int signum );
 int open_listen_socket( const char *hostname, int port );
 
 /* from esd_config.c */
@@ -82,6 +83,8 @@
 int esd_is_locked = 1;		 /* if owned, will prohibit foreign sources */
 char esd_owner_key[ESD_KEY_LEN]; /* the key that locks the daemon */
 
+int esd_pending_driver_reconnect = 0; /* set by SIGUSR1 handler for
+                                         reconnecting to the audio card */
 int esd_on_standby = 0;		/* set to ignore incoming audio data */
 int esdbg_trace = 0;		/* show warm fuzzy debug messages */
 int esdbg_comms = 0;		/* show protocol level debug messages */
@@ -224,6 +227,15 @@
     exit( 0 );
 }
 
+void reconnect_driver( int signum )
+{
+    ESDBG_TRACE(
+       printf( "(ca) reconnecting to driver on signal %d\n",
+               signum ); );
+    esd_pending_driver_reconnect = 1;
+    signal( signum, reconnect_driver );
+}
+
 void reset_signal(int signum) {
 /*    fprintf( stderr, "received signal %d: resetting...\n", signum );*/
     signal( signum, reset_signal);
@@ -612,7 +624,6 @@
     /* Enlightened sound Daemon */
 
     int esd_port = ESD_DEFAULT_PORT;
-    int length = 0;
     int arg = 0;
     int itmp;
 
@@ -644,8 +655,6 @@
     int i, j, freq=440;
     int magl, magr;
 
-    int first = 1;
-
     int default_format = ESD_BITS16 | ESD_STEREO;
     /* end test scaffolding parameters */
 
@@ -970,6 +979,7 @@
     signal( SIGTERM, clean_exit );	/* for default kill */
     signal( SIGPIPE, reset_signal );	/* for closed rec/mon clients */
     signal( SIGHUP, reset_daemon );	/* kill -HUP clear ownership */
+    signal( SIGUSR1, reconnect_driver ); /* react to changed sound card */
 
     /* send some sine waves just to check the sound connection */
     i = 0;
@@ -1000,106 +1010,7 @@
 	close (esd_spawnfd);
     }
 
-    /* until we kill the daemon */
-    while ( 1 )
-    {
-	/* block while waiting for more clients and new data */
-	wait_for_clients_and_data( listen_socket );
-
-	/* accept new connections */
-	get_new_clients( listen_socket );
-
-
-	if ((esd_clients_list == NULL) && (!esd_playing_samples) &&
-            (!first) && (esd_terminate)) {
-/*	  fprintf(stderr, "No clients!\n");*/
-	  clean_exit(0);
-	  exit(0);
-	}
-
-	/* check for new protocol requests */
-	poll_client_requests();
-	first = 0;
-
-	/* mix new requests, and output to device */
-	refresh_mix_funcs(); /* TODO: set a flag to cue when to do this */
-	length = mix_players( output_buffer, esd_buf_size_octets );
-	
-	/* awaken if on autostandby and doing anything */
-	if ( esd_on_autostandby && length && !esd_forced_standby ) {
-	    ESDBG_TRACE( printf( "stuff to play, waking up.\n" ); );
-	    esd_server_resume();
-	}
-
-	/* we handle this even when length == 0 because a filter could have
-	 * closed, and we don't want to eat the processor if one did.. */
-	if ( esd_filter_list && !esd_on_standby ) {
-	    length = filter_write( output_buffer, length,
-				   esd_audio_format, esd_audio_rate );
-	}
-	
-	if ( length > 0 /* || esd_monitor */ ) {
-	    /* do_sleep = 0; */
-	    if ( !esd_on_standby ) {
-		/* standby check goes in here, so esd will eat sound data */
-		/* TODO: eat a round of data with a better algorithm */
-		/*        this will cause guaranteed timing issues */
-		/* TODO: on monitor, why isn't this a buffer of zeroes? */
-		/* esd_audio_write( output_buffer, esd_buf_size_octets ); */
-		esd_audio_write( output_buffer, length );
-		/* esd_audio_flush(); */ /* this is overkill */
-		esd_last_activity = time( NULL );
-	    }
-	} else {
-	    /* should be pausing just fine within wait_for_clients_and_data */
-	    /* if so, this isn't really needed */
-
-	    /* be very quiet, and wait for a wabbit to come along */
-#if 0
-	    if ( !do_sleep ) { ESDBG_TRACE( printf( "pausing in esd.c\n" ); ); }
-	    do_sleep = 1;
-	    esd_audio_pause();
-#endif
-	}
-
-	/* if someone's monitoring the sound stream, send them data */
-	/* mix_players, above, forces buffer to zero if no players */
-	/* this clears out any leftovers from recording, below */
-	if ( esd_monitor_list && !esd_on_standby && length ) {
-	/* if ( esd_monitor_list && !esd_on_standby ) {  */
-	    monitor_write( output_buffer, length );
-	}
-
-	/* if someone's recording the sound stream, send them data */
-	if ( esd_recorder_list && !esd_on_standby ) {
-	    length = esd_audio_read( output_buffer, esd_buf_size_octets );
-	    if ( length ) {
-		length = recorder_write( output_buffer, length );
-		esd_last_activity = time( NULL );
-	    }
-	}
-
-	if ( esd_on_standby ) {
-#ifdef HAVE_NANOSLEEP
-	    struct timespec restrain;
-	    restrain.tv_sec = 0;
-	    /* funky math to make sure a long can hold it all, calulate in ms */
-	    restrain.tv_nsec = (long) esd_buf_size_samples * 1000L
-		/ (long) esd_audio_rate / 4L;   /* divide by two for stereo */
-	    restrain.tv_nsec *= 1000000L;       /* convert to nanoseconds */
-	    nanosleep( &restrain, NULL );
-#else
-	    struct timeval restrain;
-	    restrain.tv_sec = 0;
-	    /* funky math to make sure a long can hold it all, calulate in ms */
-	    restrain.tv_usec = (long) esd_buf_size_samples * 1000L
-		/ (long) esd_audio_rate / 4L; 	/* divide by two for stereo */
-	    restrain.tv_usec *= 1000L; 		/* convert to microseconds */
-	    select( 0, 0, 0, 0, &restrain );
-#endif
-	}
-    } /* while ( 1 ) */
-
+    esd_comm_loop(listen_socket,output_buffer,esd_terminate);
     close (listen_socket);
 
     /* how we'd get here, i have no idea, should only exit on signal */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]