[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