[nas] nas and adobe's libflashsupport

Paul Fox pgf at foxharp.boston.ma.us
Wed Apr 22 13:05:41 MDT 2009


jon wrote:
 > On Tue, 21 Apr 2009, Paul Fox wrote:
 > 
 > > i've implemented the NAS client code for libflashsupport.so,
 > > using some minimal client code i stole from mpg123 as a template.
 > > it seems to work, mostly (see below).  if i install my
 > > libflashsupport.so in /usr/lib, and run firefox with the a couple
 > > of env variables which force it to choose NAS rather than
 > > something else (the library has a probe and search mechanism that
 > > will usually find native sound before networked sound), then my
 > > audio goes to nasd.
 > >
 > > i say "mostly", above, because i've tested locally, and between
 > > several pairs of machines, and there's one nasd server that
 > > reliably dies with "explicit kill or server shutdown", and the
 > > server dies:
 > >    Apr 21 14:53:12 jade kernel:  [262066.900419] nasd[1046]:
 > > 	segfault at 16 ip b7e37a73 sp bfd4caa0 error 4 in
 > > 	    libasound.so.2.0.0[b7dea000+c3000]
 > >
 > > all of my nasd servers are 1.9.1.  i guess i'll have to build
 > > a copy and debug.
 > >
 > > if anyone would like to try my libflashsupport.so, please let
 > > me know, and i can send you either a binary, or a patch against
 > > http://tcosproject.org/git/libflashsupport.git
 > >
 > 
 >    That's pretty interesting - especially since you took a stab at it
 >    :)  I'd love to see both the patch and the lib so I can try it out
 >    here.

the patch is attached, binary lib is available here:
    http://www.foxharp.boston.ma.us/tmp/libflashsupport.so

i don't claim to know much about nas client programming -- i suspect
i'm literally at the "knows just enough to be dangerous" level.

 > 
 >    As for the crash above - this seems... interesting.  nasd uses OSS,
 >    however the crash listed above happened in libasound, which I
 >    believe is an ALSA lib...?

heh.  i hadn't even noticed that.  how strange.  maybe that's why
it's crashing.  ;-)  i'm using the OSS compatibility drivers that
come with alsa, but that still doesn't explain it.  i tried to reproduce
the crash earlier today, both with a debuggable server built from the
top of svn, and with the ubuntu intrepid distributed server that crashed
yesterday, and i've been unable.  not sure what's changed -- i'll poke
at it some more.

paul
=---------------------
 paul fox, pgf at foxharp.boston.ma.us (arlington, ma, where it's 57.7 degrees)

-------------- next part --------------
diff --git a/Makefile b/Makefile
index 0927727..4be0d58 100644
--- a/Makefile
+++ b/Makefile
@@ -27,6 +27,10 @@ PULSE=-DPULSEAUDIO
 LIBESDPATH=-DLIBESDPATH='"$(LIBDIR)/libesd.so.0"'
 ESD=-DESD
 
+#NAS
+LIBNASPATH=-DLIBNASPATH='"$(LIBDIR)/libaudio.so"'
+NAS=-DNAS
+
 #OSS
 OSS=-DOSS
 
@@ -51,6 +55,7 @@ all: libflashsupport.so
 libflashsupport.so: flashsupport.c
 	$(CC) $(CFLAGS) $(LIBS) -DLIBDIR=$(LIBDIR) \
 	$(ALSA) $(ALSALIBS) $(PULSE) $(LIBPULSEPATH) $(ESD) $(LIBESDPATH) \
+	$(NAS) $(LIBNASPATH) \
 	$(OSS) $(SSL) $(SSLLIBS) $(V4L) $(ICULIBS)\
 	flashsupport.c -o libflashsupport.so
 
diff --git a/flashsupport.c b/flashsupport.c
index a36cbf9..6c0ff0a 100644
--- a/flashsupport.c
+++ b/flashsupport.c
@@ -59,19 +59,20 @@ The code is licenced with the same terms as the rest of the Adobe code.
 /*
 #ifndef LIBPULSEPATH
 #define LIBPULSEPATH /usr/lib/libpulse-simple.so.0
-#endif 
+#endif
 
 #ifndef LIBESDPATH
 #define LIBESDPATH /usr/lib/libesd.so.0
 #endif
 */
 
-/* Do not define these here, but rather in the Makefile 
+/* Do not define these here, but rather in the Makefile
 #define OPENSSL
 #define GNUTLS
 #define V4L1
 #define PULSEAUDIO
 #define ESD
+#define NAS
 #define OSS
 #define ALSA_INTERNAL
 #define ALSA
@@ -111,9 +112,9 @@ extern "C" {
 typedef void *(*T_FPI_Mem_Alloc)(int size);	// This function is not thread safe
 typedef void (*T_FPI_Mem_Free)(void *ptr); // This function is not thread safe
 
-#if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO)
+#if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) || defined(NAS)
 typedef void (*T_FPI_SoundOutput_FillBuffer)(void *ptr, char *buffer, int n_bytes); // This function is thread safe
-#endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO)
+#endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) || defined(NAS)
 
 struct FPI_Functions {
 	int	  fpi_count;
@@ -150,6 +151,12 @@ static int OSS_FPX_SoundOutput_Close(void *ptr);
 static int OSS_FPX_SoundOutput_Latency(void *ptr);
 #endif // defined(OSS)
 
+#if defined(NAS)
+static void *NAS_FPX_SoundOutput_Open(void);
+static int NAS_FPX_SoundOutput_Close(void *ptr);
+static int NAS_FPX_SoundOutput_Latency(void *ptr);
+#endif
+
 #if defined(ESD)
 static void *ESD_FPX_SoundOutput_Open(void);
 static int ESD_FPX_SoundOutput_Close(void *ptr);
@@ -220,6 +227,12 @@ struct FPX_Functions {
 #include <fcntl.h>
 #endif
 
+#if defined(NAS)
+#include <fcntl.h>
+#include <audio/audiolib.h>
+#include <audio/soundlib.h>
+#endif
+
 #if defined(ESD)
 #include <unistd.h>
 #include <esd.h>
@@ -244,23 +257,23 @@ struct FPX_Functions {
 #endif // V4L1
 
 //Includes for output driver detection
-#if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO)
+#if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) || defined(NAS)
 #include <stdlib.h> //getenv
 #include <sys/types.h> //stat
 #include <sys/stat.h> //stat
 #include <unistd.h> //stat
-#endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO)
+#endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) || defined(NAS)
 
 static struct FPX_Functions fpx_functions;
 
 static T_FPI_Mem_Alloc FPI_Mem_Alloc = 0;
 static T_FPI_Mem_Free FPI_Mem_Free = 0;
 
-#if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO)
+#if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) || defined(NAS)
 static T_FPI_SoundOutput_FillBuffer FPI_SoundOutput_FillBuffer = 0;
-#endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO)
+#endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) || defined(NAS)
 
-#if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO)
+#if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) || defined(NAS)
 /* JMD: Choose between multiple audio interfaces by order of priority:
 - Pulse is always first, since it can support esound, gstreamer, alsa, oss
   and jack and is easily identified by environment variables or socket.
@@ -285,6 +298,35 @@ static T_FPI_SoundOutput_FillBuffer FPI_SoundOutput_FillBuffer = 0;
 #define AUDIO_ALSA 2
 #define AUDIO_OSS 1
 
+#if defined(PULSEAUDIO) || defined(ESD) || defined(NAS)
+#define DL_LOAD(ptr, name, bit) \
+		ptr = dlsym(handle, name); \
+		if ((error = dlerror()) != NULL) { \
+			if(audiodebug) fprintf(stderr, "%s\n", error); \
+			audiodrivers = audiodrivers & (~bit); \
+		}
+#endif
+
+#if defined(NAS)
+char *nas_server;
+
+AuServer * (*FPX_AuOpenServer) ( const char *, int, const char *,
+		int, const char *, char **);
+void (*FPX_AuCloseServer) ( AuServer *);
+AuFlowID (*FPX_AuCreateFlow) ( AuServer *, AuStatus *);
+void (*FPX_AuNextEvent) ( AuServer *, AuBool, AuEvent *);
+void (*FPX_AuSetElements) ( AuServer *, AuFlowID, AuBool, int,
+		AuElement *, AuStatus *);
+void (*FPX_AuWriteElement) ( AuServer *, AuFlowID, int, AuUint32,
+		AuPointer, AuBool, AuStatus *);
+AuBool (*FPX_AuDispatchEvent)( AuServer *, AuEvent *);
+AuEventHandlerRec * (*FPX_AuRegisterEventHandler) ( AuServer *, AuMask,
+		int, AuID, AuEventHandlerCallback, AuPointer);
+void (*FPX_AuStartFlow)( AuServer *, AuFlowID, AuStatus *);
+
+
+#endif
+
 #if defined(ESD)
 //ESD functions
 int (*FPX_esd_play_stream_fallback)( esd_format_t format, int rate,
@@ -311,7 +353,7 @@ int (*FPX_pa_simple_flush) (pa_simple *s, int *error);
 
 const char* (*FPX_pa_strerror) (int error);
 #endif
-                     
+
 static int audiotype=2;
 static int audiodrivers=0;
 static int audiodebug=0;
@@ -321,10 +363,10 @@ void FPX_SoundOutput_Detect()
 {
 	char *tmpenv;
 	struct stat buf;
-#if defined(PULSEAUDIO) || defined(ESD)
+#if defined(PULSEAUDIO) || defined(ESD) || defined(NAS)
 	void *handle;
-	char *error;	
-#endif 
+	char *error;
+#endif
 #if defined(PULSEAUDIO)
 	char tmpstr[1024]="";
 #endif
@@ -381,6 +423,14 @@ void FPX_SoundOutput_Detect()
 	}
 
 #endif
+#if defined(NAS)
+	//NAS over network
+	if((tmpenv=getenv("AUDIOSERVER"))!=NULL) {
+		if(audiodebug) fprintf( stderr, "NAS variable AUDIOSERVER found\n");
+		nas_server = tmpenv;
+		audiodrivers = audiodrivers | AUDIO_NAS;
+	}
+#endif
 #if defined(ALSA) || defined(ALSA_INTERNAL)
 	//Check for ALSA device
 	if(!stat("/proc/asound",&buf)) {
@@ -401,34 +451,43 @@ void FPX_SoundOutput_Detect()
 			if(audiodebug) fprintf( stderr, "Forcing PulseAudio\n");
 			audiodrivers = AUDIO_PULSE;
 #else
-			if(audiodebug) fprintf( stderr, "PulseAudio unavailable: please recompile libflashsupport.so!\n");			
+			if(audiodebug) fprintf( stderr, "PulseAudio unavailable: please recompile libflashsupport.so!\n");
 #endif
 	}
 
 	if((tmpenv=getenv("FLASH_FORCE_ESD"))!=NULL) {
 #if defined(ESD)
-			if(audiodebug) fprintf( stderr, "Forcing ESD\n");			
+			if(audiodebug) fprintf( stderr, "Forcing ESD\n");
 			audiodrivers = AUDIO_ESD;
 #else
-			if(audiodebug) fprintf( stderr, "ESD unavailable: please recompile libflashsupport.so!\n");			
+			if(audiodebug) fprintf( stderr, "ESD unavailable: please recompile libflashsupport.so!\n");
+#endif
+	}
+
+	if((tmpenv=getenv("FLASH_FORCE_NAS"))!=NULL) {
+#if defined(NAS)
+			if(audiodebug) fprintf( stderr, "Forcing NAS\n");
+			audiodrivers = AUDIO_NAS;
+#else
+			if(audiodebug) fprintf( stderr, "NAS unavailable: please recompile libflashsupport.so!\n");
 #endif
 	}
 
 	if((tmpenv=getenv("FLASH_FORCE_ALSA"))!=NULL) {
 #if defined(ALSA) || defined(ALSA_INTERNAL)
-			if(audiodebug) fprintf( stderr, "Forcing ALSA\n");			
+			if(audiodebug) fprintf( stderr, "Forcing ALSA\n");
 			audiodrivers = AUDIO_ALSA;
 #else
-			if(audiodebug) fprintf( stderr, "ALSA unavailable: please recompile libflashsupport.so!\n");			
+			if(audiodebug) fprintf( stderr, "ALSA unavailable: please recompile libflashsupport.so!\n");
 #endif
 	}
 
 	if((tmpenv=getenv("FLASH_FORCE_OSS"))!=NULL) {
 #if defined(OSS)
-			if(audiodebug) fprintf( stderr, "Forcing OSS\n");			
+			if(audiodebug) fprintf( stderr, "Forcing OSS\n");
 			audiodrivers = AUDIO_OSS;
 #else
-			if(audiodebug) fprintf( stderr, "OSS unavailable: please recompile libflashsupport.so!\n");			
+			if(audiodebug) fprintf( stderr, "OSS unavailable: please recompile libflashsupport.so!\n");
 #endif
 	}
 
@@ -440,36 +499,12 @@ void FPX_SoundOutput_Detect()
 			if(audiodebug) fprintf(stderr,"Can't load %s: %s\n",LIBPULSEPATH,dlerror());
 			audiodrivers = audiodrivers & (~AUDIO_PULSE);
 		}
-		FPX_pa_simple_new = dlsym(handle, "pa_simple_new");
-		if ((error = dlerror()) != NULL) {
-			if(audiodebug) fprintf(stderr, "%s\n", error);
-			audiodrivers = audiodrivers & (~AUDIO_PULSE);
-		}
-		FPX_pa_simple_write = dlsym(handle, "pa_simple_write");
-		if ((error = dlerror()) != NULL) {
-			if(audiodebug) fprintf(stderr, "%s\n", error);
-			audiodrivers = audiodrivers & (~AUDIO_PULSE);
-		}
-		FPX_pa_simple_drain = dlsym(handle, "pa_simple_drain");
-		if ((error = dlerror()) != NULL) {
-			if(audiodebug) fprintf(stderr, "%s\n", error);
-			audiodrivers = audiodrivers & (~AUDIO_PULSE);
-		}
-		FPX_pa_simple_free = dlsym(handle, "pa_simple_free");
-		if ((error = dlerror()) != NULL) {
-			if(audiodebug) fprintf(stderr, "%s\n", error);
-			audiodrivers = audiodrivers & (~AUDIO_PULSE);
-		}
-		FPX_pa_simple_get_latency = dlsym(handle, "pa_simple_get_latency");
-		if ((error = dlerror()) != NULL) {
-			if(audiodebug) fprintf(stderr, "%s\n", error);
-			audiodrivers = audiodrivers & (~AUDIO_PULSE);
-		}
-		FPX_pa_strerror = dlsym(handle, "pa_strerror");
-		if ((error = dlerror()) != NULL) {
-			if(audiodebug) fprintf(stderr, "%s\n", error);
-			audiodrivers = audiodrivers & (~AUDIO_PULSE);
-		}
+		DL_LOAD(FPX_pa_simple_new, "pa_simple_new", AUDIO_PULSE);
+		DL_LOAD(FPX_pa_simple_write, "pa_simple_write", AUDIO_PULSE);
+		DL_LOAD(FPX_pa_simple_drain, "pa_simple_drain", AUDIO_PULSE);
+		DL_LOAD(FPX_pa_simple_free, "pa_simple_free", AUDIO_PULSE);
+		DL_LOAD(FPX_pa_simple_get_latency, "pa_simple_get_latency", AUDIO_PULSE);
+		DL_LOAD(FPX_pa_strerror, "pa_strerror", AUDIO_PULSE);
 	}
 #endif
 #if defined(ESD)
@@ -479,11 +514,25 @@ void FPX_SoundOutput_Detect()
 			if(audiodebug) fprintf(stderr,"Can't load %s: %s\n",LIBESDPATH,dlerror());
 			audiodrivers = audiodrivers & (~AUDIO_ESD);
 		}
-		FPX_esd_play_stream_fallback = dlsym(handle, "esd_play_stream_fallback");
-		if ((error = dlerror()) != NULL) {
-			if(audiodebug) fprintf(stderr, "%s\n", error);
-			audiodrivers = audiodrivers & (~AUDIO_ESD);
+		DL_LOAD(FPX_esd_play_stream_fallback, "esd_play_stream_fallback", AUDIO_ESD);
+	}
+#endif
+#if defined(NAS)
+	if((audiodrivers & AUDIO_NAS) && !FPX_AuOpenServer) {
+		handle = dlopen(LIBNASPATH, RTLD_LAZY);
+		if (!handle) {
+			if(audiodebug) fprintf(stderr,"Can't load %s: %s\n",LIBNASPATH,dlerror());
+			audiodrivers = audiodrivers & (~AUDIO_NAS);
 		}
+		DL_LOAD( FPX_AuOpenServer, "AuOpenServer", AUDIO_NAS);
+		DL_LOAD( FPX_AuCloseServer, "AuCloseServer", AUDIO_NAS);
+		DL_LOAD( FPX_AuCreateFlow, "AuCreateFlow", AUDIO_NAS);
+		DL_LOAD( FPX_AuNextEvent, "AuNextEvent", AUDIO_NAS);
+		DL_LOAD( FPX_AuSetElements, "AuSetElements", AUDIO_NAS);
+		DL_LOAD( FPX_AuWriteElement, "AuWriteElement", AUDIO_NAS);
+        	DL_LOAD( FPX_AuDispatchEvent, "AuDispatchEvent", AUDIO_NAS);
+        	DL_LOAD( FPX_AuRegisterEventHandler, "AuRegisterEventHandler", AUDIO_NAS);
+        	DL_LOAD( FPX_AuStartFlow, "AuStartFlow", AUDIO_NAS);
 	}
 #endif
 
@@ -494,12 +543,12 @@ static void *FPX_SoundOutput_Open(void)
 {
 	void *ptr;
 
-	if(audiodebug) fprintf( stderr,"audiodrivers=%d\n",audiodrivers);	
+	if(audiodebug) fprintf( stderr,"audiodrivers=%d\n",audiodrivers);
 #if defined(PULSEAUDIO)
 	if(audiodrivers & AUDIO_PULSE) {
-		if(audiodebug) fprintf( stderr,"Trying PULSE\n");	
+		if(audiodebug) fprintf( stderr,"Trying PULSE\n");
 		ptr=PULSEAUDIO_FPX_SoundOutput_Open();
-		if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr);	
+		if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr);
 		if(ptr) {
 			audiotype=AUDIO_PULSE;
 			if(audiodebug) fprintf( stderr, "Using PulseAudio driver\n");
@@ -509,9 +558,9 @@ static void *FPX_SoundOutput_Open(void)
 #endif
 #if defined(ESD)
 	if(audiodrivers & AUDIO_ESD) {
-		if(audiodebug) fprintf( stderr,"Trying ESD\n");	
+		if(audiodebug) fprintf( stderr,"Trying ESD\n");
 		ptr=ESD_FPX_SoundOutput_Open();
-		if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr);	
+		if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr);
 		if(ptr) {
 			audiotype=AUDIO_ESD;
 			if(audiodebug) fprintf( stderr, "Using Esound audio driver\n");
@@ -519,17 +568,29 @@ static void *FPX_SoundOutput_Open(void)
 		}
 	}
 #endif
+#if defined(NAS)
+	if(audiodrivers & AUDIO_NAS) {
+		if(audiodebug) fprintf( stderr,"Trying NAS\n");
+		ptr=NAS_FPX_SoundOutput_Open();
+		if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr);
+		if(ptr) {
+			audiotype=AUDIO_NAS;
+			if(audiodebug) fprintf( stderr, "Using NAS libaudio driver\n");
+			return ptr;
+		}
+	}
+#endif
 #if defined(ALSA_INTERNAL)
 	if(audiodrivers & AUDIO_ALSA) {
-		if(audiodebug) fprintf( stderr,"Using *INTERNAL* ALSA\n");	
+		if(audiodebug) fprintf( stderr,"Using *INTERNAL* ALSA\n");
 		return 0;
 	}
 #endif
 #if defined(ALSA)
 	if(audiodrivers & AUDIO_ALSA) {
-		if(audiodebug) fprintf( stderr,"Trying ALSA\n");	
+		if(audiodebug) fprintf( stderr,"Trying ALSA\n");
 		ptr=ALSA_FPX_SoundOutput_Open();
-		if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr);	
+		if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr);
 		if(ptr) {
 			audiotype=AUDIO_ALSA;
 			if(audiodebug) fprintf( stderr, "Using ALSA audio driver\n");
@@ -539,9 +600,9 @@ static void *FPX_SoundOutput_Open(void)
 #endif
 #if defined(OSS)
 	if(audiodrivers & AUDIO_OSS) {
-		if(audiodebug) fprintf( stderr,"Trying OSS\n");	
+		if(audiodebug) fprintf( stderr,"Trying OSS\n");
 		ptr=OSS_FPX_SoundOutput_Open();
-		if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr);	
+		if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr);
 		if(ptr) {
 			audiotype=AUDIO_OSS;
 			if(audiodebug) fprintf( stderr, "Using OSS audio driver\n");
@@ -563,19 +624,25 @@ static int FPX_SoundOutput_Close(void *ptr)
 		return retcode;
 	}
 #endif
-#if defined(ESD)	
+#if defined(ESD)
 	if(audiotype == AUDIO_ESD) {
 		retcode=ESD_FPX_SoundOutput_Close(ptr);
 		return retcode;
 	}
 #endif
+#if defined(NAS)
+	if(audiotype == AUDIO_NAS) {
+		retcode=NAS_FPX_SoundOutput_Close(ptr);
+		return retcode;
+	}
+#endif
 #if defined(ALSA)
 	if(audiotype == AUDIO_ALSA) {
 		retcode=ALSA_FPX_SoundOutput_Close(ptr);
 		return retcode;
 	}
 #endif
-#if defined(OSS)	
+#if defined(OSS)
 	if(audiotype == AUDIO_OSS) {
 		retcode=OSS_FPX_SoundOutput_Close(ptr);
 		return retcode;
@@ -599,13 +666,19 @@ static int FPX_SoundOutput_Latency(void *ptr)
 		return retcode;
 	}
 #endif
-#if defined(ALSA)	
+#if defined(NAS)
+	if(audiotype == AUDIO_NAS) {
+		retcode=NAS_FPX_SoundOutput_Latency(ptr);
+		return retcode;
+	}
+#endif
+#if defined(ALSA)
 	if(audiotype == AUDIO_ALSA) {
 		retcode=ALSA_FPX_SoundOutput_Latency(ptr);
 		return retcode;
 	}
 #endif
-#if defined(OSS)	
+#if defined(OSS)
 	if(audiotype == AUDIO_OSS) {
 		retcode=OSS_FPX_SoundOutput_Latency(ptr);
 		return retcode;
@@ -617,9 +690,9 @@ static int FPX_SoundOutput_Latency(void *ptr)
 
 void *FPX_Init(void *ptr)
 {
-#if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO)
+#if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) || defined(NAS)
 	FPX_SoundOutput_Detect();
-#endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO)
+#endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) || defined(NAS)
 	if ( !ptr ) return 0;
 
 	//
@@ -631,9 +704,9 @@ void *FPX_Init(void *ptr)
 	if ( fpi_functions->fpi_count >= 1 )	FPI_Mem_Alloc 		= fpi_functions->fpi_mem_alloc; 					// 1
 	if ( fpi_functions->fpi_count >= 2 )	FPI_Mem_Free 		= fpi_functions->fpi_mem_free;  					// 2
 
-#if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO)
+#if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) || defined(NAS)
 	if ( fpi_functions->fpi_count >= 3 )	FPI_SoundOutput_FillBuffer= fpi_functions->fpi_soundoutput_fillbuffer;  // 3
-#endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO)
+#endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) || defined(NAS)
 
 	//
 	// Setup exported functions
@@ -651,11 +724,11 @@ void *FPX_Init(void *ptr)
 	fpx_functions.fpx_sslsocket_send 			= FPX_SSLSocket_Send;			// 6
 #endif // defined(OPENSSL) || defined(GNUTLS)
 
-#if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO)
+#if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) || defined(NAS)
 	fpx_functions.fpx_soundoutput_open 			= FPX_SoundOutput_Open;			// 7
 	fpx_functions.fpx_soundoutput_close 		= FPX_SoundOutput_Close;		// 8
 	fpx_functions.fpx_soundoutput_latency 		= FPX_SoundOutput_Latency;		// 9
-#endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO)
+#endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) || defined(NAS)
 
 #ifdef V4L1
 	fpx_functions.fpx_videoinput_open			= FPX_VideoInput_Open;			// 10
@@ -901,7 +974,7 @@ static void *alsa_thread(void *ptr)
 			pthread_exit(0);
 			return 0;
 		}
-		
+
 		if ( err < 0 ) {
 			usleep(1);
 			continue;
@@ -1212,6 +1285,348 @@ static int OSS_FPX_SoundOutput_Latency(void *ptr)
 }
 #endif
 
+#if defined(NAS)
+/*
+	nas: audio output via NAS
+
+	copyright ?-2006 by the mpg123 project - free software
+		under the terms of the LGPL 2.1
+	see COPYING and AUTHORS files in distribution or http://mpg123.org
+	initially written by Martin Denn
+*/
+struct NAS_SoundOutput_Instance {
+	AuServer	    *aud;
+	AuFlowID	    flow;
+	AuDeviceAttributes  *da;
+	int		    numDevices;
+	char		    *buf;
+	AuUint32	    buf_size;
+	AuUint32	    buf_cnt;
+	AuBool		    data_sent;
+	AuBool		    finished;
+	pthread_t	    thread;
+	int		    signal;
+};
+
+#define NAS_SOUND_PORT_DURATION 1 /* seconds */
+#define NAS_SOUND_LOW_WATER_MARK 25 /* percent */
+#define NAS_MAX_FORMAT 10 /* currently, there are 7 supported formats */
+
+/* NAS specific routines */
+
+
+static void nas_sendData(AuServer *aud,
+	struct NAS_SoundOutput_Instance *i, AuUint32 numBytes)
+{
+    if (numBytes < i->buf_cnt) {
+	// if(audiodebug) fprintf(stderr, "[fill]\n");
+	FPX_AuWriteElement(aud, i->flow, 0, numBytes, i->buf, AuFalse, NULL);
+	memmove(i->buf, i->buf + numBytes, i->buf_cnt - numBytes);
+	i->buf_cnt = i->buf_cnt - numBytes;
+    }
+    else {
+	 // if(audiodebug) fprintf(stderr, "[done]\n");
+	 FPX_AuWriteElement(aud, i->flow, 0, i->buf_cnt, i->buf,
+			(numBytes > i->buf_cnt), NULL);
+	 i->buf_cnt = 0;
+    }
+    i->data_sent = AuTrue;
+}
+
+static AuBool nas_eventHandler(AuServer *aud,
+	AuEvent *ev, AuEventHandlerRec *handler)
+{
+	struct NAS_SoundOutput_Instance *i =
+		(struct NAS_SoundOutput_Instance *) handler->data;
+	AuElementNotifyEvent *event;
+
+	// if(audiodebug) fprintf(stderr, "event_handler\n");
+	switch (ev->type) {
+	case AuEventTypeMonitorNotify:
+		i->finished = AuTrue;
+		break;
+	case AuEventTypeElementNotify:
+		event = (AuElementNotifyEvent *) ev;
+
+		switch (event->kind) {
+		case AuElementNotifyKindLowWater:
+			// if(audiodebug) fprintf(stderr, "(low water)\n");
+			nas_sendData(aud, i, event->num_bytes);
+			break;
+		case AuElementNotifyKindState:
+			// if(audiodebug) fprintf(stderr, "(kind state)\n");
+			switch (event->cur_state) {
+			case AuStatePause:
+				// if(audiodebug) fprintf(stderr, "(pause)\n");
+				if (event->reason != AuReasonUser)
+					nas_sendData(aud, i, event->num_bytes);
+				break;
+			case AuStateStop:
+				// if(audiodebug) fprintf(stderr, "(stop)\n");
+				i->finished = AuTrue;
+				break;
+			}
+		}
+	}
+	return AuTrue;
+}
+
+/* 0 on error */
+static int nas_createFlow(struct NAS_SoundOutput_Instance *instance)
+{
+	AuDeviceID	    device = AuNone;
+	AuElement	    elements[2];
+	unsigned char   format;
+	AuUint32	    buf_samples;
+	int		    i;
+	unsigned short  rate;
+	int		    channels;
+
+	char *fill_duration = getenv("FLASH_NAS_BUFFER_MS");
+	int ms;
+
+	if (fill_duration) ms = atoi(fill_duration);
+	if (!ms) {
+		ms = NAS_SOUND_PORT_DURATION * 1000;
+	}
+	if (audiodebug) fprintf( stderr, "NAS fill is %d ms\n", ms);
+
+	buf_samples = 44100 * ms / 1000;
+	rate = 44100;
+	channels = 2;
+
+
+	format = AuFormatLinearSigned16LSB; /* little endian */
+	/* look for an output device */
+	for (i = 0; i < AuServerNumDevices(instance->aud); i++) {
+		if (((AuDeviceKind(AuServerDevice(instance->aud, i)) ==
+				AuComponentKindPhysicalOutput) &&
+			    AuDeviceNumTracks(AuServerDevice(instance->aud, i)) ==  2)) {
+			device = AuDeviceIdentifier(AuServerDevice(instance->aud, i));
+			break;
+		}
+	}
+	if (device == AuNone) {
+		fprintf(stderr,
+			"No output device providing %d channels.", channels);
+		return 0;
+	}
+	// if(audiodebug) fprintf(stderr, "found device\n");
+
+	if (!(instance->flow = FPX_AuCreateFlow(instance->aud, NULL))) {
+		fprintf(stderr, "Couldn't create flow");
+		return 0;
+	}
+
+	// if(audiodebug) fprintf(stderr, "created flow\n");
+	AuMakeElementImportClient(&elements[0],	   /* element */
+				rate,		   /* rate */
+				format,	   /* format */
+				channels,	   /* channels */
+				AuTrue,	   /* ??? */
+				buf_samples,	   /* max samples */
+				(AuUint32) (buf_samples / 100
+					* NAS_SOUND_LOW_WATER_MARK),
+							/* low water mark */
+				0,		   /* num actions */
+				NULL);	   /* actions */
+	// if(audiodebug) fprintf(stderr, "imported client\n");
+	AuMakeElementExportDevice(&elements[1],	   /* element */
+				0,		   /* input */
+				device,	   /* device */
+				rate,		   /* rate */
+				AuUnlimitedSamples,  /* num samples */
+				0,		   /* num actions */
+				NULL);		   /* actions */
+	// if(audiodebug) fprintf(stderr, "exported device\n");
+	FPX_AuSetElements(instance->aud,	   /* Au server */
+			instance->flow,	   /* flow ID */
+			AuTrue,		   /* clocked */
+			2,			   /* num elements */
+			elements,		   /* elements */
+			NULL);		   /* return status */
+
+	// if(audiodebug) fprintf(stderr, "set elements\n");
+	FPX_AuRegisterEventHandler(instance->aud,		    /* Au server */
+			AuEventHandlerIDMask,   /* value mask */
+			0,			   /* type */
+			instance->flow,		/* id */
+			nas_eventHandler,	   /* callback */
+			(AuPointer) instance);     /* data */
+
+	instance->buf_size = buf_samples * channels * AuSizeofFormat(format);
+	instance->buf = (char *) FPI_Mem_Alloc(instance->buf_size);
+	if (instance->buf == NULL) {
+		fprintf(stderr, "Unable to allocate input/output buffer of size %ld",
+			(long)instance->buf_size);
+		return 0;
+	}
+
+	instance->buf_cnt = 0;
+	instance->data_sent = AuFalse;
+	instance->finished = AuFalse;
+
+	return 1; /* success */
+}
+
+
+static void flush_nas(struct NAS_SoundOutput_Instance *instance)
+{
+	AuEvent	    ev;
+
+	// if(audiodebug) fprintf(stderr, "flush_nas\n");
+	while ((!instance->data_sent) && (!instance->finished)) {
+		FPX_AuNextEvent(instance->aud, AuTrue, &ev);
+		FPX_AuDispatchEvent(instance->aud, &ev);
+	}
+	instance->data_sent = AuFalse;
+}
+
+
+
+static int write_nas(struct NAS_SoundOutput_Instance *instance,
+		char *buf, int len)
+{
+	int buf_cnt = 0;
+	static int started;
+
+	while ((instance->buf_cnt + (len - buf_cnt)) >  instance->buf_size) {
+		memcpy(instance->buf + instance->buf_cnt,
+			buf + buf_cnt,
+			(instance->buf_size - instance->buf_cnt));
+		buf_cnt += (instance->buf_size - instance->buf_cnt);
+		instance->buf_cnt += (instance->buf_size - instance->buf_cnt);
+		flush_nas(instance);
+	}
+	memcpy(instance->buf + instance->buf_cnt,
+		buf + buf_cnt,
+		(len - buf_cnt));
+	instance->buf_cnt += (len - buf_cnt);
+
+	if (!started) {
+		FPX_AuStartFlow(instance->aud,	/* Au server */
+			instance->flow,		/* id */
+			NULL);			/* status */
+		// if(audiodebug) fprintf(stderr, "started flow, success\n");
+		sleep(1);
+		started = 1;
+	}
+
+	return len;
+}
+
+static void *nas_thread(void *ptr)
+{
+	struct NAS_SoundOutput_Instance *instance =
+			(struct NAS_SoundOutput_Instance *)ptr;
+	char buffer[4096];
+	int len = 0;
+	int written = 0;
+	if (instance->buf_size == 0) {
+		// if (audiodebug) fprintf(stderr, "creating\n");
+		if (!nas_createFlow(instance)) return (void *)-1;
+		// if (audiodebug) fprintf(stderr, "created\n");
+	}
+
+	for(;;) {
+		FPI_SoundOutput_FillBuffer(ptr,buffer,sizeof(buffer));
+		len = sizeof(buffer);
+		while ( len ) {
+			written = write_nas(instance, buffer, len);
+			// if(audiodebug) fprintf(stderr, ".\n");
+			if ( written >= 0 ) {
+				len -= written;
+			}
+			if ( instance->signal ) {
+				// if(audiodebug) fprintf(stderr, "thread quitting\n");
+				pthread_exit(0);
+			}
+			if ( written < 0 ) {
+				usleep(100);
+			}
+		}
+	}
+}
+
+static void *NAS_FPX_SoundOutput_Open(void)
+{
+	struct NAS_SoundOutput_Instance *instance = 0;
+
+	if ( !FPI_SoundOutput_FillBuffer )  goto fail;
+	if ( !FPI_Mem_Alloc ) goto fail;
+
+	if(!nas_server) return 0;
+
+	if(audiodebug) {
+		fprintf(stderr, 
+		"NAS flash sound output, based on code from mpg123,\n"
+		"which is Copyright ?-2006 by the mpg123 project.\n"
+		"(Free software under the terms of the LGPL version 2.1\n"
+		"and under GNU General Public License, version 2.)\n"
+		"Ported to libflashsupport by Paul Fox, April 2009.\n");
+	}
+
+	instance = (struct NAS_SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct NAS_SoundOutput_Instance));
+	memset(instance, 0, sizeof(struct NAS_SoundOutput_Instance));
+
+	if (!(instance->aud = FPX_AuOpenServer(nas_server, 0, NULL, 0, NULL, NULL))) {
+		fprintf(stderr, "could not open NAS server %s\n", nas_server);
+		goto fail;
+	}
+
+	instance->buf_size = 0;
+
+	if ( pthread_create(&instance->thread, 0, nas_thread, instance) < 0 ) {
+		goto fail;
+	}
+	// if(audiodebug) fprintf(stderr, "pthread_created\n");
+
+	return instance;
+
+fail:
+	// if(audiodebug) fprintf(stderr, "open failed\n");
+	if ( instance ) {
+		if ( instance->aud )
+			FPX_AuCloseServer(instance->aud);
+		if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
+	}
+	return 0;
+}
+
+static int NAS_FPX_SoundOutput_Close(void *ptr)
+{
+	void *retVal = 0;
+	struct NAS_SoundOutput_Instance *instance =
+			(struct NAS_SoundOutput_Instance *)ptr;
+
+	instance->signal = 1;
+
+	while (!instance->finished)
+		flush_nas(instance);
+
+	if ( instance->thread )
+		pthread_join(instance->thread, &retVal);
+
+	if ( instance->aud )
+		FPX_AuCloseServer(instance->aud);
+
+	if ( FPI_Mem_Free ) {
+		if (instance->buf) FPI_Mem_Free(instance->buf);
+		FPI_Mem_Free(instance);
+	}
+
+	return 0;
+}
+
+static int NAS_FPX_SoundOutput_Latency(void *ptr)
+{
+	struct NAS_SoundOutput_Instance *instance =
+			(struct NAS_SoundOutput_Instance *)ptr;
+
+	return instance->buf_size / 2;	/* avg fill */
+}
+#endif
+
 #if defined(ESD)
 struct ESD_SoundOutput_Instance {
 	int						esd_sock;
@@ -1267,7 +1682,7 @@ static void *ESD_FPX_SoundOutput_Open()
 	instance->esd_sock=-1;
 
 	if(audiodebug) fprintf( stderr, "opening socket, format = 0x%08x at %d Hz\n",format, rate );
-                
+
 	if ( ( instance->esd_sock = FPX_esd_play_stream_fallback( format, rate, host, name )) <= 0 ) goto fail;
 
 	if ( pthread_create(&instance->thread, 0, esd_thread, instance) < 0 ) goto fail;
@@ -1306,7 +1721,7 @@ static int ESD_FPX_SoundOutput_Latency(void *ptr)
 	// ptr = instance pointer
 	// return = 0 on success, < 0 on error
 {
-	
+
 	/* JMD: this doesn't work. I think it's due to the handling
 	   of signals in esdlib.c ... It just *hangs* via network...
 	struct ESD_SoundOutput_Instance *instance = (struct ESD_SoundOutput_Instance *)ptr;
@@ -1407,7 +1822,7 @@ static int PULSEAUDIO_FPX_SoundOutput_Latency(void *ptr)
 	// ptr = instance pointer
 	// return = 0 on success, < 0 on error
 {
-	
+
 	pa_usec_t latencytime=0;
 	float latencysamples=0.0;
 	int latency=0;
@@ -1421,11 +1836,11 @@ static int PULSEAUDIO_FPX_SoundOutput_Latency(void *ptr)
 	   sample_rate*num_of_channels*sample_size_in_bytes
 	   44100 * 2 (stereo) * 2 (16 bit samples)
 	   Magic number = 176400
-	   
+
 	   Max frames in one second:
 	   sample_rate: 44100
 	   Magic number = 44100
-	   
+
 	   Now, convert pulse's latency time to number of bytes as
 	   required by FlashPlayer
 	   Latency = magic number * latencytime / 1000000 (for microseconds)
@@ -1436,7 +1851,7 @@ static int PULSEAUDIO_FPX_SoundOutput_Latency(void *ptr)
 	return latency;
 	return -1;
 }
-#endif // defined(ALSA/OSS/ESD/PULSEAUDIO)
+#endif // defined(ALSA/OSS/NAS/ESD/PULSEAUDIO)
 
 #ifdef V4L1
 struct VideoOutput_Instance {


More information about the Nas mailing list