[Openal-devel] [Fwd: Patch for ALSA, aRts and ESD backends on Linux]

Marco Ziech mmz@gmx.net
Sat, 29 May 2004 15:18:56 +0200


This is a multi-part message in MIME format.
--------------030005020201010508000606
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Somehow the message did not make it to mailing list. Maybe because I 
first sent the message and then subscribed to the list.

-------- Original-Nachricht --------
Betreff: Patch for ALSA, aRts and ESD backends on Linux
Datum: Mon, 24 May 2004 00:23:21 +0200
Von: Marco Ziech <mmz@gmx.net>
An: openal-devel@opensource.creative.com

Hey,

I had these changes for the ALSA, aRts and ESD backends laying around on
my disk for some weeks now. As I was (and still am) packed with a lot of
work I did not manage to send them in earlier. So, what have I done:

I have added dlopen support to the aRts and the ESD backend. Basically,
I just ported Ryan Gorden's dlopen implementation from the alsa backend
to these both backends. However, I have partially rewritten the aRts
backend. It has not become faster but at least code looks a bit cleaner
now. I have also added some more error messages to the dlopen
implementation.

There were some bugs in alsa_blitbuffer. As far as I can remember these
even caused some trouble to me concerning clicking noises. In particular
this was because EPIPE was not handled.

Apart from that I made ALSA output non-blocking, so specifying "alsa
native esd arts" for devices leads to a working result even if artsd or
esd are running. Maybe this would be a good default configuration as
OpenAL should always guess the best backend, this way.

-Marco



--------------030005020201010508000606
Content-Type: text/x-patch;
 name="openal-backends-mz-20040523.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="openal-backends-mz-20040523.diff"

Index: linux/configure.in
===================================================================
RCS file: /usr/local/cvs-repository/openal/linux/configure.in,v
retrieving revision 1.22
diff -u -r1.22 configure.in
--- linux/configure.in	2 Mar 2004 14:10:53 -0000	1.22
+++ linux/configure.in	23 May 2004 21:55:08 -0000
@@ -547,8 +547,12 @@
 
 dnl   enable arts sound?
 AC_ARG_ENABLE(arts,
-[  --enable-arts             enable arts backend          [default=no]],
+[  --enable-arts             enable aRts backend          [default=no]],
               ,   enable_arts=no)
+AC_ARG_ENABLE(arts,
+[  --enable-arts-dlopen      dlopen aRts lib at runtime   [default=no]],
+              ,   enable_arts_dlopen=no)
+
 if test x$enable_arts = xyes; then
 AC_PATH_PROG(HAVEARTS, artsc-config, , $PATH)
 if test ! -z "$HAVEARTS"; then
@@ -557,9 +561,14 @@
 
         AC_DEFINE(ARTS_SUPPORT, 1, [undocumented])
 	CFLAGS="$CFLAGS $ARTS_CFLAGS"
-	LIBS="$LIBS $ARTS_LIBS"
 
     	OS_OBJS="$OS_OBJS \$(ARTS_OBJS)"
+        if test x$enable_arts_dlopen = xyes; then
+            AC_DEFINE(OPENAL_DLOPEN_ARTS, 1, [undocumented])
+        else
+            AC_DEFINE(OPENAL_DLOPEN_ARTS, 0, [undocumented])
+            LIBS="$LIBS $ARTS_LIBS"
+        fi
 else
 	AC_MSG_WARN([*** artsc-config not found.  No support compiled in.])
 fi
@@ -570,6 +579,10 @@
 AC_ARG_ENABLE(esd,
 [  --enable-esd              enable esd backend           [default=no]],
               ,   enable_esd=no)
+AC_ARG_ENABLE(esd,
+[  --enable-esd-dlopen       dlopen esd lib at runtime    [default=no]],
+              ,   enable_esd_dlopen=no)
+
 if test x$enable_esd = xyes; then
 AC_PATH_PROG(HAVEESD, esd-config, , $PATH)
 if test ! -z "$HAVEESD"; then
@@ -578,12 +591,18 @@
 
         AC_DEFINE(ESD_SUPPORT, 1, [undocumented])
 	CFLAGS="$CFLAGS $ESD_CFLAGS"
-	LIBS="$LIBS $ESD_LIBS"
 
     	OS_OBJS="$OS_OBJS \$(ESD_OBJS)"
 
         # bad audiofile.h!  bad!
 	SHADOW_WARN=no
+
+        if test x$enable_esd_dlopen = xyes; then
+            AC_DEFINE(OPENAL_DLOPEN_ESD, 1, [undocumented])
+        else
+            AC_DEFINE(OPENAL_DLOPEN_ESD, 0, [undocumented])
+            LIBS="$LIBS $ESD_LIBS"
+        fi
 else
 	AC_MSG_WARN([*** esd-config not found.  No support compiled in.])
 fi
Index: linux/src/arch/alsa/alsa.c
===================================================================
RCS file: /usr/local/cvs-repository/openal/linux/src/arch/alsa/alsa.c,v
retrieving revision 1.10
diff -u -r1.10 alsa.c
--- linux/src/arch/alsa/alsa.c	2 Apr 2004 04:24:03 -0000	1.10
+++ linux/src/arch/alsa/alsa.c	23 May 2004 21:55:08 -0000
@@ -76,14 +76,25 @@
 
 static int openal_load_alsa_library(void)
 {
+        char * error = NULL;
+    
 	if (alsa_lib_handle != NULL)
 		return 1;  /* already loaded. */
 
 	#if OPENAL_DLOPEN_ALSA
-		#define OPENAL_LOAD_ALSA_SYMBOL(x) if ((p##x = dlsym(alsa_lib_handle, #x)) == NULL) { return 0; }
+		#define OPENAL_LOAD_ALSA_SYMBOL(x) p##x = dlsym(alsa_lib_handle, #x); \
+                                                   error = dlerror(); \
+                                                   if (p##x == NULL) { \
+                                                           fprintf(stderr,"Could not resolve ALSA symbol %s: %s\n", #x, ((error!=NULL)?(error):("(null)"))); \
+                                                           dlclose(alsa_lib_handle); alsa_lib_handle = NULL; \
+                                                           return 0; }
+                dlerror(); /* clear error state */
 		alsa_lib_handle = dlopen("libasound.so.2", RTLD_LAZY | RTLD_GLOBAL);
-		if (alsa_lib_handle == NULL)
+                error = dlerror();
+		if (alsa_lib_handle == NULL) {
+                        fprintf(stderr,"Could not open ALSA library: %s\n",((error!=NULL)?(error):("(null)")));
 			return 0;
+                }
 	#else
 		#define OPENAL_LOAD_ALSA_SYMBOL(x) p##x = x;
 		alsa_lib_handle = (void *) 0xF00DF00D;
@@ -260,7 +271,7 @@
 
 	get_out_device_name(card_name, 256);
 
-	err = psnd_pcm_open(&handle, card_name, SND_PCM_STREAM_PLAYBACK, 0);
+	err = psnd_pcm_open(&handle, card_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
 	if(err < 0)
 	{
 		const char *serr = psnd_strerror(err);
@@ -647,9 +658,17 @@
 					err = psnd_pcm_resume(phandle);
 				} while ( err == -EAGAIN );
 				break;
+                        case -EPIPE:
+                                break;
 			default:
+                                if (err<0) {
+                                        fprintf(stderr,"alsa_blitbuffer: Could not write audio data to sound device: %s\n",
+                                        	strerror(-err));
+                                        break;
+                                }
                                 pdata += err * ai->framesize;
 				data_len -= err* ai->framesize;
+                                frames -= err;
 				break;
 		}
 		if(err < 0)
Index: linux/src/arch/arts/arts.c
===================================================================
RCS file: /usr/local/cvs-repository/openal/linux/src/arch/arts/arts.c,v
retrieving revision 1.3
diff -u -r1.3 arts.c
--- linux/src/arch/arts/arts.c	23 May 2004 15:19:15 -0000	1.3
+++ linux/src/arch/arts/arts.c	23 May 2004 21:55:09 -0000
@@ -18,6 +18,10 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#if OPENAL_DLOPEN_ARTS
+#include <dlfcn.h>
+#endif
+
 #include "al_main.h"
 #include "al_debug.h"
 
@@ -29,58 +33,154 @@
 #define DEF_SPEED	_ALC_CANON_SPEED
 #define DEF_SIZE	_AL_DEF_BUFSIZ
 #define DEF_SAMPLES     (DEF_SIZE / 2)
+#define DEF_BITS        16
 #define DEF_CHANNELS	2
 
-static struct {
+static int openal_arts_ref_count = 0;
+
+typedef struct {
 	arts_stream_t stream;
-} arts_info;
+} t_arts_handle;
 
 static const char *genartskey(void);
+static int openal_load_arts_library(void);
+
+/*
+ * aRts library functions.
+ */
+static int (*parts_init)(void);
+static void (*parts_free)(void);
+static int (*parts_suspend)(void);
+static int (*parts_suspended)(void);
+static const char *(*parts_error_text)(int errorcode);
+static arts_stream_t (*parts_play_stream)(int rate, int bits, int channels, const char *name);
+static arts_stream_t (*parts_record_stream)(int rate, int bits, int channels, const char *name);
+static void (*parts_close_stream)(arts_stream_t stream);
+static int (*parts_read)(arts_stream_t stream, void *buffer, int count);
+static int (*parts_write)(arts_stream_t stream, const void *buffer, int count);
+static int (*parts_stream_set)(arts_stream_t stream, arts_parameter_t param, int value);
+static int (*parts_stream_get)(arts_stream_t stream, arts_parameter_t param);
+
+/*
+ * aRts library handle.
+ */
+static void * arts_lib_handle = NULL;
+
+static int openal_load_arts_library(void)
+{
+        char * error = NULL;
+    
+	if (arts_lib_handle != NULL)
+		return 1;  /* already loaded. */
+
+	#if OPENAL_DLOPEN_ARTS
+		#define OPENAL_LOAD_ARTS_SYMBOL(x) p##x = dlsym(arts_lib_handle, #x); \
+                                                   error = dlerror(); \
+                                                   if (p##x == NULL) { \
+                                                           fprintf(stderr,"Could not resolve aRts symbol %s: %s\n", #x, ((error!=NULL)?(error):("(null)"))); \
+                                                           dlclose(arts_lib_handle); arts_lib_handle = NULL; \
+                                                           return 0; }
+                dlerror(); /* clear error state */
+		arts_lib_handle = dlopen("libartsc.so", RTLD_LAZY | RTLD_GLOBAL);
+                error = dlerror();
+		if (arts_lib_handle == NULL) {
+                        fprintf(stderr,"Could not open aRts library: %s\n",((error!=NULL)?(error):("(null)")));
+			return 0;
+                }
+	#else
+		#define OPENAL_LOAD_ARTS_SYMBOL(x) p##x = x;
+		arts_lib_handle = (void *) 0xF00DF00D;
+	#endif
+
+        OPENAL_LOAD_ARTS_SYMBOL(arts_init);
+        OPENAL_LOAD_ARTS_SYMBOL(arts_free);
+        OPENAL_LOAD_ARTS_SYMBOL(arts_suspend);
+        OPENAL_LOAD_ARTS_SYMBOL(arts_suspended);
+        OPENAL_LOAD_ARTS_SYMBOL(arts_error_text);
+        OPENAL_LOAD_ARTS_SYMBOL(arts_play_stream);
+        OPENAL_LOAD_ARTS_SYMBOL(arts_record_stream);
+        OPENAL_LOAD_ARTS_SYMBOL(arts_close_stream);
+        OPENAL_LOAD_ARTS_SYMBOL(arts_read);
+        OPENAL_LOAD_ARTS_SYMBOL(arts_write);
+        OPENAL_LOAD_ARTS_SYMBOL(arts_stream_set);
+        OPENAL_LOAD_ARTS_SYMBOL(arts_stream_get);
+
+	return 1;
+}
 
 void *grab_read_arts(void) {
 	return NULL;
 }
 
 void *grab_write_arts(void) {
-	int err = arts_init();
+        int err;
+        t_arts_handle * ahandle;
 
-	if(err < 0) {
-		fprintf(stderr, "aRTs init failed: %s\n",
-			arts_error_text(err));
-		return NULL;
-	}
+        if (!openal_load_arts_library()) {
+                return NULL;
+        }
+    
+        if (!(ahandle=malloc(sizeof(t_arts_handle))))
+                return NULL;
+        
+        if (openal_arts_ref_count==0) {
+                err = parts_init();
+
+                if(err < 0) {
+                        fprintf(stderr, "aRTs init failed: %s\n",
+                                parts_error_text(err));
+                        free(ahandle);
+                        return NULL;
+                }
+        }
 
+        openal_arts_ref_count++;
+        
 	_alBlitBuffer = arts_blitbuffer;
 
+#if 1
+        ahandle->stream = NULL;
+#else
+        ahandle->stream = parts_play_stream(DEF_SPEED,
+                                            DEF_BITS,
+                                            DEF_CHANNELS,
+				 	    genartskey());
+#endif
+        
 	fprintf(stderr, "arts grab audio ok\n");
 
 	_alDebug(ALD_CONTEXT, __FILE__, __LINE__,
 		"arts grab audio ok");
 
-        return &arts_info.stream;
+        return ahandle;
 }
 
 void arts_blitbuffer(void *handle, void *data, int bytes)  {
-	arts_stream_t *ap = (arts_stream_t *) handle;
+	t_arts_handle * ahandle = (t_arts_handle *) handle;
 
-	if(handle == NULL) {
+	if ((ahandle == NULL)||(ahandle->stream == NULL)) {
 		return;
 	}
 
-	arts_write(*ap, data, bytes);
+	parts_write(ahandle->stream, data, bytes);
 
         return;
 }
 
 void release_arts(void *handle) {
-	arts_stream_t *ap = (arts_stream_t *) handle;
+	t_arts_handle * ahandle = (t_arts_handle *) handle;
 
-	if(handle == NULL) {
+	if ((ahandle == NULL)||(ahandle->stream == NULL)) {
 		return;
 	}
 
-	arts_close_stream(*ap);
-	arts_free();
+        openal_arts_ref_count--;
+        
+	parts_close_stream(ahandle->stream);
+        free(ahandle);
+
+        if (openal_arts_ref_count==0)
+                parts_free();
 
 	return;
 }
@@ -93,25 +193,43 @@
 	return retval;
 }
 
-ALboolean set_write_arts(UNUSED(void *handle),
+ALboolean set_write_arts(void *handle,
 		   ALuint *bufsiz,
 		   ALenum *fmt,
 		   ALuint *speed) {
-	ALuint chans = _al_ALCHANNELS(*fmt);
+	t_arts_handle * ahandle = (t_arts_handle *) handle;
 
-	arts_stream_set(arts_info.stream, ARTS_P_BUFFER_SIZE, *bufsiz);
+	if (ahandle == NULL) {
+		return AL_FALSE;
+	}
 
+#if 0
 	fprintf(stderr, "set_arts forcing speed from %d to 44100\n", *speed);
 
+        /* @@@ FIXME: What was this good for?! */
 	*speed = 44100;
+#endif
+
+        if (ahandle->stream != NULL)
+                parts_close_stream(ahandle->stream);
 
-	/* FIXME: how do we know if this failed? */
-	arts_info.stream = arts_play_stream(*speed,
+        /* According to the aRtsC library source, this function
+         * returns 0 if it fails.
+         */
+	ahandle->stream = parts_play_stream(*speed,
 					    _al_formatbits(*fmt),
-					    chans,
-					    genartskey());
+					    _al_ALCHANNELS(*fmt),
+                                            genartskey());
+        
+        if (ahandle->stream == 0) {
+                ahandle->stream = NULL;
+                return AL_FALSE;
+        }
+        
+	parts_stream_set(ahandle->stream, ARTS_P_BUFFER_SIZE, *bufsiz);
+	parts_stream_set(ahandle->stream, ARTS_P_BLOCKING, 1);
 
-	*bufsiz = arts_stream_get(arts_info.stream, ARTS_P_BUFFER_SIZE);
+	*bufsiz = parts_stream_get(ahandle->stream, ARTS_P_BUFFER_SIZE);
 
         return AL_TRUE;
 }
Index: linux/src/arch/esd/esd.c
===================================================================
RCS file: /usr/local/cvs-repository/openal/linux/src/arch/esd/esd.c,v
retrieving revision 1.3
diff -u -r1.3 esd.c
--- linux/src/arch/esd/esd.c	20 Jun 2003 19:23:07 -0000	1.3
+++ linux/src/arch/esd/esd.c	23 May 2004 21:55:09 -0000
@@ -27,6 +27,10 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#if OPENAL_DLOPEN_ESD
+#include <dlfcn.h>
+#endif
+
 #include <esd.h>
 
 #define DEF_SPEED	_ALC_CANON_SPEED
@@ -39,6 +43,58 @@
 #define ESD_NAMELEN    1024
 
 static const char *genesdkey(void);
+static int openal_load_esd_library(void);
+
+
+/*
+ * ESD library functions.
+ */
+static int (*pesd_open_sound)( const char *host );
+static int (*pesd_play_stream)( esd_format_t format, int rate, 
+		     const char *host, const char *name );
+static int (*pesd_standby)( int esd );
+static int (*pesd_resume)( int esd );
+static int (*pesd_close)( int esd );
+
+/*
+ * ESD library handle.
+ */
+static void * esd_lib_handle = NULL;
+
+static int openal_load_esd_library(void)
+{
+        char * error = NULL;
+    
+	if (esd_lib_handle != NULL)
+		return 1;  /* already loaded. */
+
+	#if OPENAL_DLOPEN_ESD
+		#define OPENAL_LOAD_ESD_SYMBOL(x) p##x = dlsym(esd_lib_handle, #x); \
+                                                   error = dlerror(); \
+                                                   if (p##x == NULL) { \
+                                                           fprintf(stderr,"Could not resolve ESoundD symbol %s: %s\n", #x, ((error!=NULL)?(error):("(null)"))); \
+                                                           dlclose(esd_lib_handle); esd_lib_handle = NULL; \
+                                                           return 0; }
+                dlerror(); /* clear error state */
+		esd_lib_handle = dlopen("libesd.so", RTLD_LAZY | RTLD_GLOBAL);
+                error = dlerror();
+		if (esd_lib_handle == NULL) {
+                        fprintf(stderr,"Could not open ESoundD library: %s\n",((error!=NULL)?(error):("(null)")));
+			return 0;
+                }
+        #else
+		#define OPENAL_LOAD_ESD_SYMBOL(x) p##x = x;
+		esd_lib_handle = (void *) 0xF00DF00D;
+	#endif
+
+        OPENAL_LOAD_ESD_SYMBOL(esd_open_sound);
+        OPENAL_LOAD_ESD_SYMBOL(esd_standby);
+        OPENAL_LOAD_ESD_SYMBOL(esd_resume);
+        OPENAL_LOAD_ESD_SYMBOL(esd_play_stream);
+        OPENAL_LOAD_ESD_SYMBOL(esd_close);
+                
+	return 1;
+}
 
 static fd_set esd_fd_set;
 
@@ -62,7 +118,11 @@
 	const char *espeaker = getenv("ESPEAKER");
 	int esd;
 
-	esd = esd_open_sound(espeaker);
+        if (!openal_load_esd_library()) {
+                return NULL;
+        }
+    
+	esd = pesd_open_sound(espeaker);
 	if(esd < 0) {
 		fprintf(stderr, "esd open sound failed.\n");
 		return NULL;
@@ -82,7 +142,7 @@
 		default: break;
 	}
 
-	socket = esd_play_stream(fmt, DEF_SPEED, espeaker, esdkey);
+	socket = pesd_play_stream(fmt, DEF_SPEED, espeaker, esdkey);
 
 	if(socket < 0) {
 		fprintf(stderr, "esd play stream failed.\n");
@@ -178,7 +238,7 @@
 
 	eh = (esd_openal_info_t *) handle;
 
-	esd_close(eh->esdhandle);
+	pesd_close(eh->esdhandle);
 
 	return;
 }
@@ -201,7 +261,7 @@
 	eh = (esd_openal_info_t *) handle;
 
 	eh->paused = AL_TRUE;
-	esd_standby(eh->esdhandle);
+	pesd_standby(eh->esdhandle);
 
 	return;
 }
@@ -216,7 +276,7 @@
 	eh = (esd_openal_info_t *) handle;
 
 	eh->paused = AL_FALSE;
-	esd_resume(eh->esdhandle);
+	pesd_resume(eh->esdhandle);
 
 	return;
 }
@@ -253,7 +313,7 @@
 
 	eh->speed = *speed;
 
-	socket = esd_play_stream(eh->fmt,
+	socket = pesd_play_stream(eh->fmt,
 				 eh->speed,
 				 eh->espeaker,
 				 eh->name);


--------------030005020201010508000606--