libflashsupport-0.0.svn2431/0000775002342100234210000000000010745654036014373 5ustar pereperelibflashsupport-0.0.svn2431/README0000664002342100234210000000332710745654036015260 0ustar perepereSEE README.orig for more information on the original flashsupport.c This version, designed by Revolution Linux, adds support for Esound and PulseAudio. It also provides automatic detection of the sound system: * It first tries to detect PulseAudio by looking for socket files and environment variables: - /tmp/pulse- - /var/lib/run/pulse/native - PULSE_SERVER / PULSE_BINARY variables * It then checks for Esound: - /tmp/.esd/socket - ESPEAKER variable * Then if checks for ALSA: - /proc/asound * Finally, it checks for OSS: - /dev/dsp If everything fails, it falls back to the ALSA driver that's built directly into FlashPlayer 9. You can force any interface by setting environment variables: - FLASH_FORCE_PULSEAUDIO = 1 (or) FLASH_FORCE_ESD / FLASH_FORCE_ALSA / FLASH_FORCE_OSS You can also get debug information by setting: - FLASH_AUDIODEBUG = 1 Finally, to get latency information for the PulseAudio driver: - FLASH_PULSEDEBUG = 1 =========== Audio/Video synchronization: Using PulseAudio, you can now get fully synchronized video and audio output, even on a slow network. I have made all tests using a 11mbps wireless link. With Esound however, it seems impossible for the moment, as the function that is supposed to get the latency doesn't work via network. =========== Install: Simply do a "make", then "make install" as root. If you have sudo access, you can do it all in one step with "make sudoinstall". =========== Comments / Bugs / Questions You can contact jmdault@revolutionlinux.com for any questions of or comments. Please note that we will not give *free* support, however commercial support is available for corporate customers. Contact Revolution Linux at http://www.revolutionlinux.com libflashsupport-0.0.svn2431/Patches/0000775002342100234210000000000010745654035015761 5ustar pereperelibflashsupport-0.0.svn2431/Patches/Done/0000775002342100234210000000000010745654035016646 5ustar pereperelibflashsupport-0.0.svn2431/Patches/Done/debian-sid-path0000664002342100234210000001051510745654035021524 0ustar perepereeturn-Path: Received: from kolab.revolutionlinux.com ([unix socket]) by kolab.revolutionlinux.com (Cyrus v2.2.13-Mandriva-RPM-2.2.13-1.1.101mdk) with LMTPA; Fri, 26 Jan 2007 00:32:45 -0500 X-Sieve: CMU Sieve 2.2 Received: from localhost (localhost [127.0.0.1]) by kolab.revolutionlinux.com (Postfix) with ESMTP id B2F98ABC005 for ; Fri, 26 Jan 2007 00:32:45 -0500 (EST) Received: from kolab.revolutionlinux.com ([127.0.0.1]) by localhost (kolab.revolutionlinux.com [192.168.2.224]) (amavisd-new, port 10025) with LMTP id 14025-02-13 for ; Fri, 26 Jan 2007 00:32:44 -0500 (EST) Received: from smtpin.revolutionlinux.com (smtpin.revolutionlinux.com [172.31.25.213]) by kolab.revolutionlinux.com (Postfix) with ESMTP id ED62EABC002 for ; Fri, 26 Jan 2007 00:32:44 -0500 (EST) Received: from localhost (smtpin.revolutionlinux.com [172.31.25.213]) by smtpin.revolutionlinux.com (Postfix) with ESMTP id EC5D8DF09 for ; Fri, 26 Jan 2007 00:32:44 -0500 (EST) Received: from smtpin.revolutionlinux.com ([172.31.25.213]) by localhost (smtpin.revolutionlinux.com [172.31.25.213]) (amavisd-new, port 10025) with ESMTP id 06081-09 for ; Fri, 26 Jan 2007 00:32:37 -0500 (EST) Received: from smtp.easydns.com (smtp.easydns.com [205.210.42.52]) by smtpin.revolutionlinux.com (Postfix) with ESMTP id 923E1DEBD for ; Fri, 26 Jan 2007 00:32:37 -0500 (EST) X-Greylist: Passed host: 129.242.5.252 Received: from mux2.uit.no (mux2.uit.no [129.242.5.252]) by smtp.easydns.com (Postfix) with ESMTP id 23E914E9D2 for ; Fri, 26 Jan 2007 00:32:36 -0500 (EST) Received: from wert.td.org.uit.no (Debian-exim@wert.td.org.uit.no [129.242.219.51]) by mux2.uit.no (8.13.8/8.13.6/Mux) with ESMTP id l0Q5WWSH039529 (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NO) for ; Fri, 26 Jan 2007 06:32:32 +0100 (CET) Received: from kaare by wert.td.org.uit.no with local (Exim 4.63) (envelope-from ) id 1HAJhN-0004rT-4B for jmdault@revolutionlinux.com; Fri, 26 Jan 2007 06:32:29 +0100 Date: Fri, 26 Jan 2007 06:32:28 +0100 To: jmdault@revolutionlinux.com Subject: pulseaudio support in flashsupport.c Message-ID: <20070126053228.GA6170@slettnes.org> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit User-Agent: Mutt/1.5.13 (2006-08-11) From: Kaare Slettnes X-Virus-Scanned: : ok X-Virus-Scanned: Debian amavisd-new at smtpin.revolutionlinux.com X-Virus-Scanned: by amavisd-new at revolutionlinux.com X-Spam-Status: No, hits=-2.599 tagged_above=-999 required=4.9 tests=BAYES_00 X-Spam-Score: -2.599 X-Spam-Level: X-Evolution-Source: imap://jmdault@kolab.revolutionlinux.com/ Thank you so much for this code. Now i'm finally able to mix flash content to other audio through pulseaudio. Seeooweet. But the real reason for this mail is a minor bug in your pulseaudio detection code. It looks for the file "/tmp/pulse-/native". This file doesn't exist in in debian (sid). I have the folder "/tmp/pulse-" but that's it. As a quick fix I just removed the line =================================================================== --- flashsupport.c (revision 2254) +++ flashsupport.c (working copy) @@ -331,7 +331,6 @@ if((tmpenv=getenv("USER"))!=NULL) { strcpy(tmpstr,"/tmp/pulse-"); strcat(tmpstr,tmpenv); - strcat(tmpstr,"/native"); if(!stat(tmpstr,&buf)) { if(audiodebug) fprintf( stderr, "PulseAudio socket found\n"); audiodrivers = audiodrivers | AUDIO_PULSE; =================================================================== without knowing if this is the correct way to detect a working pulse audio instance. But it works. Just thought I'd let you know. My spec: Linux: 2.6.18-3-k7 Pulseaudio: 0.9.5-5 Firefox/Iceweasel: 2.0.0.1 libflashplayer.so: 9.0.31.0 soundcard: nVidia nForce Audio (onboard Asus A7N8X) -- K?re Slettnes libflashsupport-0.0.svn2431/Patches/Done/typos+esddefine0000664002342100234210000001007510745654035021674 0ustar perepereReturn-Path: Received: from kolab.revolutionlinux.com ([unix socket]) by kolab.revolutionlinux.com (Cyrus v2.2.13-Mandriva-RPM-2.2.13-1.1.101mdk) with LMTPA; Tue, 06 Feb 2007 12:12:30 -0500 X-Sieve: CMU Sieve 2.2 Received: from localhost (localhost [127.0.0.1]) by kolab.revolutionlinux.com (Postfix) with ESMTP id 70FB6ABC110 for ; Tue, 6 Feb 2007 12:12:30 -0500 (EST) Received: from kolab.revolutionlinux.com ([127.0.0.1]) by localhost (kolab.revolutionlinux.com [192.168.2.224]) (amavisd-new, port 10025) with LMTP id 21392-02-2 for ; Tue, 6 Feb 2007 12:12:28 -0500 (EST) Received: from smtp.easydns.com (smtp.easydns.com [205.210.42.52]) by kolab.revolutionlinux.com (Postfix) with ESMTP id 6C1AEABC004 for ; Tue, 6 Feb 2007 12:12:28 -0500 (EST) X-Greylist: Passed host: 82.76.121.36 Received: from mail.rndsoft.ro (ics.rndsoft.ro [82.76.121.36]) by smtp.easydns.com (Postfix) with ESMTP id 2FC1F4CAA1 for ; Tue, 6 Feb 2007 12:12:27 -0500 (EST) Received: from [10.0.0.11] (ics.rndsoft.ro [82.76.121.36]) by mail.rndsoft.ro (Postfix) with ESMTP id 023C0285F6 for ; Tue, 6 Feb 2007 17:12:08 +0000 (UTC) Message-ID: <45C8B6E8.5040904@m0n5t3r.info> Date: Tue, 06 Feb 2007 19:12:08 +0200 From: Sabin Iacob User-Agent: Thunderbird 1.5.0.9 (X11/20070202) MIME-Version: 1.0 To: jmdault@revolutionlinux.com Subject: patch for libflashsupport Content-Type: multipart/mixed; boundary="------------040202060103040200070702" X-Virus-Scanned: by amavisd-new at revolutionlinux.com X-Spam-Status: No, hits=-2.599 tagged_above=-999 required=4.9 tests=BAYES_00 X-Spam-Score: -2.599 X-Spam-Level: X-Evolution-Source: imap://jmdault@kolab.revolutionlinux.com/ This is a multi-part message in MIME format. --------------040202060103040200070702 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Hello the libflashsupport source in SVN has some typos and won't compile without ESD & pulseaudio (I don't have/need them, so I disabled them), here's a patch to fix the issues (I only fixed the source for the final version, as I doubt anyone still uses the betas, however the patch applies cleanly to beta2 and fails a hunk when applying to beta1, as the last typo in the ALSA code is missing). Regards --------------040202060103040200070702 Content-Type: text/plain; name="typos.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="typos.patch" Index: flashsupport.c =================================================================== --- flashsupport.c (revision 2254) +++ flashsupport.c (working copy) @@ -275,10 +275,12 @@ #define AUDIO_ALSA 2 #define AUDIO_OSS 1 +#if defined(ESD) //ESD functions int (*FPX_esd_play_stream_fallback)( esd_format_t format, int rate, const char *host, const char *name ); - +#endif +#if defined(PULSEAUDIO) //PULSE functions pa_simple* (*FPX_pa_simple_new) (const char *server,const char *name, pa_stream_direction_t dir,const char *dev,const char *stream_name, @@ -298,7 +300,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; @@ -307,12 +309,13 @@ void FPX_SoundOutput_Detect() { - char tmpstr[1024]=""; char *tmpenv; struct stat buf; +#if defined(PULSEAUDIO) + char tmpstr[1024]=""; void *handle; char *error; - +#endif if((tmpenv=getenv("FLASH_AUDIODEBUG"))!=NULL) { audiodebug=1; } @@ -886,7 +889,8 @@ if ( !instance->handle ) { pthread_exit(0); return 0; - + } + if ( err < 0 ) { usleep(1); continue; --------------040202060103040200070702-- libflashsupport-0.0.svn2431/Patches/Done/pulse-fix-stutter0000664002342100234210000000612410745654035022220 0ustar perepereReturn-Path: Received: from kolab.revolutionlinux.com ([unix socket]) by kolab.revolutionlinux.com (Cyrus v2.2.13-Mandriva-RPM-2.2.13-1.1.101mdk) with LMTPA; Sat, 13 Jan 2007 17:44:17 -0500 X-Sieve: CMU Sieve 2.2 Received: from localhost (localhost [127.0.0.1]) by kolab.revolutionlinux.com (Postfix) with ESMTP id CB5C4ABC005 for ; Sat, 13 Jan 2007 17:44:17 -0500 (EST) Received: from kolab.revolutionlinux.com ([127.0.0.1]) by localhost (kolab.revolutionlinux.com [192.168.2.224]) (amavisd-new, port 10025) with LMTP id 13375-01 for ; Sat, 13 Jan 2007 17:44:16 -0500 (EST) Received: from smtpin.revolutionlinux.com (smtpin.revolutionlinux.com [172.31.25.213]) by kolab.revolutionlinux.com (Postfix) with ESMTP id C67E5ABC002 for ; Sat, 13 Jan 2007 17:44:16 -0500 (EST) X-Greylist: delayed 302 seconds by postgrey-1.24 at smtpin.revolutionlinux.com; Sat, 13 Jan 2007 17:44:16 EST Received: from moutng.kundenserver.de (moutng.kundenserver.de [212.227.126.179]) by smtpin.revolutionlinux.com (Postfix) with ESMTP id 5285BDFD1 for ; Sat, 13 Jan 2007 17:44:16 -0500 (EST) Received: from [217.228.162.219] (helo=[192.168.1.0]) by mrelayeu.kundenserver.de (node=mrelayeu0) with ESMTP (Nemesis), id 0MKwh2-1H5rWr1Jcf-0004f0; Sat, 13 Jan 2007 23:39:13 +0100 Message-ID: <45A95F8E.4040105@arcor.de> Date: Sat, 13 Jan 2007 23:39:10 +0100 From: Peter Heckert User-Agent: Thunderbird 1.5.0.9 (X11/20061219) MIME-Version: 1.0 To: jmdault@revolutionlinux.com Subject: bugfix for flashsupport.c Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Provags-ID: kundenserver.de abuse@kundenserver.de login:0d18ea868c35e482d8395c59e9349d87 X-Provags-ID2: V01U2FsdGVkX1/bp8nZ3PCiDMN7P3hQv7qVlqRd/VY+qaKWuxUixxYVHHYYJcD9QJJz/s0ZWj6hG1cOmrl3S81vlnXpUhpwpNGv72XF92v3DEZh61WcSa/u+lC+3zmgLDJA7X/Ay1R9ues= X-Virus-Scanned: by amavisd-new at revolutionlinux.com X-Spam-Status: No, hits=-2.599 tagged_above=-999 required=4.9 tests=BAYES_00 X-Spam-Score: -2.599 X-Spam-Level: X-Evolution-Source: imap://jmdault@kolab.revolutionlinux.com/ Hello, I had problems with occasionally stuttering sound and I tried to use your libflashsupport. However, that did not cure the problem. It requires a software modification in esd_thread: for(;;) { FPI_SoundOutput_FillBuffer(ptr,buffer,4096); len = 4096; while ( len > 0 ) { Line 1219-->> written = write(instance->esd_sock, buffer, len); if ( written >= 0 ) { len -= written; Line 1219 should read: written = write(instance->esd_sock, buffer+4096-len, len); I made this modification and tested it here. The sound runs smoothly now, even then, when the video stutters due to high CPU load. Hope this hint is useful. In any case, thank you very much for your work. kind regards, Peter libflashsupport-0.0.svn2431/README.orig0000664002342100234210000001005010745654036016206 0ustar perepereIntroduction Adobe is developing Flash Player 9 for Linux. Given that GNU/Linux, and its many components, is a platform of many choices, Adobe will formally support specific Linux distributions. Some components change frequently-- in particular, audio, secure sockets, and Unicode. To enable Flash Player to adapt to these variations, we are providing default implementations of audio, secure sockets, and Unicode and making an API available for developers to adapt these areas to any particular Linux configuration. Adobe is delivering this support layer as an open-source dynamic library called flashsupport. This library will enable distributions not formally supported by Adobe to ensure that Flash Player functionality is fully preserved on those distributions. We are encouraging the Linux community to experiment with flashsupport to confirm that it meets their needs. We will continue to develop flashsupport with community feedback before the official release of Flash Player 9 for Linux. Please provide any feedback using the discussion page on the Adobe web site: http://labs.adobe.com/wiki/index.php/Flash_Player:Additional_Interface_Support_for_Linux IMPORTANT: The flashsupport library is still a work in progress. The instructions describing how to build and install this dynamic library are for advanced users only. Supported interfaces and features In the Flash Player 9 beta for Linux, flashsupport can leverage the following components: * OpenSSL (http://www.openssl.org) * ICU (http://icu.sourceforge.net) * OSS (http://www.opensound.com) These components are not required to run Adobe Flash Player; however, without them, the following features are disabled: * HTTPS and RTMPS URL support in the stand-alone player * RTMPS URL support in the Adobe Flash Player plug-in (note that plug-in support for HTTPS is handled through the browser) * Support for two specific APIs in ActionScript 3.0: DataInput.ReadMultiByte and DataOutput.WriteMultiByte * Support for OSS (or any other alternative sound APIs you might implement) Requirements The flashsupport dynamic library is provided in the form of a single source code file written in C. It should compile with a recent version of the GNU C compiler. The following will be required from your distribution to create the dynamic library: * C compiler (gcc 4.03 is known to be working) * OpenSSL developer package and working user libraries (OpenSSL 0.9.8 is known to be working) * ICU developer package and working user libraries (ICU 3.4.1 is known to be working) * OSS developer package, meaning Linux header files (Linux 2.6.15 is known to be working) * sudo or root access to install the generated library to /usr/lib Building and installing We suggest the following, or similar, steps to compile and install the dynamic library: cc -shared -O2 -Wall -Werror -licuuc -lssl flashsupport.c -o \ libflashsupport.so ldd libflashsupport.so sudo cp libflashsupport.so /usr/lib Important notes: * You should run 'ldd' to make sure that all dynamic libraries are resolved correctly on your system. Adobe Flash Player will fail silently if a dependency cannot be satisfied and will completely disable support for the additional interfaces. * You will notice additional code in flashsupport.c for GnuTLS, VideoForLinux1, and ALSA. These are not working in Adobe Flash Player 9 beta 1 for Linux; they are provided for reference only. These might also be removed in the final release of Adobe Flash Player 9 for Linux. * If you do not require OSS, OpenSSL, or ICU support, you can comment the related processor definitions on top of flashsupport.c to disable them. * The sound interface implemented in flashsupport will always have precedence. This means that if you enable OSS support in flashsupport, Adobe Flash Player will first try to use it before it will revert back to its internal ALSA support. Source code flashsupport.c can be found at http://www.kaourantin.net/flashplayer/flashsupport.c libflashsupport-0.0.svn2431/Makefile0000664002342100234210000000267010745654036016040 0ustar perepere#Default flags CC=gcc CFLAGS=-fPIC -shared -O2 -Wall -Werror LIBS=-lpthread #Define library directory #For Debian 64bit: LIBDIR=/emul/ia32-linux/usr/lib LIBDIR=/usr/lib #ALSA INSIDE FLASH PLAYER #To make auto-detection use Flash's internal ALSA functions #instead of libflashsupport external ALSA functions (recommended) ALSA=-DALSA_INTERNAL #ALSA CUSTOM #To use libflashsupport built-in ALSA functions. This is redundant as Flash #already has ALSA support and is only needed if you need special #modifications. It will also require the alsa headers and libraries. #ALSALIBS=-lalsatoss -laoss -lasound #ALSA=-DALSA #PULSE AUDIO LIBPULSEPATH=-DLIBPULSEPATH='"$(LIBDIR)/libpulse-simple.so.0"' PULSE=-DPULSEAUDIO #ESD LIBESDPATH=-DLIBESDPATH='"$(LIBDIR)/libesd.so.0"' ESD=-DESD #OSS OSS=-DOSS #OPENSSL SSL=-DOPENSSL SSLLIBS=-lssl #GNUTLS #SSL=-DGNUTLS #SSLLIBS=-lgnutls #V4L1 #V4L=-DV4L1 #Obsolete, but keep in makefile in case it gets back in #ICULIBS=-licuuc all: libflashsupport.so libflashsupport.so: flashsupport.c $(CC) $(CFLAGS) $(LIBS) -DLIBDIR=$(LIBDIR) \ $(ALSA) $(ALSALIBS) $(PULSE) $(LIBPULSEPATH) $(ESD) $(LIBESDPATH) \ $(OSS) $(SSL) $(SSLLIBS) $(V4L) $(ICULIBS)\ flashsupport.c -o libflashsupport.so install: all mkdir -p ${LIBDIR} install -m 755 libflashsupport.so ${LIBDIR} sudoinstall: all sudo mkdir -p ${LIBDIR} sudo install -m 755 libflashsupport.so ${LIBDIR} clean: rm -f libflashsupport.so *~ *.o libflashsupport-0.0.svn2431/flashsupport.c0000664002342100234210000013066110745654036017300 0ustar perepere/* Adobe Systems Incorporated(r) Source Code License Agreement Copyright(c) 2006 Adobe Systems Incorporated. All rights reserved. Please read this Source Code License Agreement carefully before using the source code. Adobe Systems Incorporated grants to you a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license, to reproduce, prepare derivative works of, publicly display, publicly perform, and distribute this source code and such derivative works in source or object code form without any attribution requirements. The name "Adobe Systems Incorporated" must not be used to endorse or promote products derived from the source code without prior written permission. You agree to indemnify, hold harmless and defend Adobe Systems Incorporated from and against any loss, damage, claims or lawsuits, including attorney's fees that arise or result from your use or distribution of the source code. THIS SOURCE CODE IS PROVIDED "AS IS" AND "WITH ALL FAULTS", WITHOUT ANY TECHNICAL SUPPORT OR ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ALSO, THERE IS NO WARRANTY OF NON-INFRINGEMENT, TITLE OR QUIET ENJOYMENT. IN NO EVENT SHALL MACROMEDIA OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOURCE CODE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The Sound detection routines, ESD and PulseAudio backends have been writen by Jean-Michel Dault cc -shared -O2 -Wall -Werror -lssl flashsupport.c -o libflashsupport.so // > ldd libflashplayer.so // > sudo cp libflashplayer.so /usr/lib // // Make sure that 'ldd' can resolve all dynamic libraries. Otherwise the Flash Player // will silently fail to load and use libflashsupport.so. // //////////////////////////////////////////////////////////////////////////////////////////////////// // // SHARED SECTION, DO NOT CHANGE! // #ifdef cplusplus extern "C" { #endif // cplusplus // // Imported functions // 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) 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) struct FPI_Functions { int fpi_count; void *fpi_mem_alloc; // 1 void *fpi_mem_free; // 2 void *fpi_soundoutput_fillbuffer; // 3 }; // // Exported functions // void *FPX_Init(void *ptr); static void FPX_Shutdown(void); #if defined(OPENSSL) || defined(GNUTLS) static void *FPX_SSLSocket_Create(int socket_fd); static int FPX_SSLSocket_Destroy(void *ptr); static int FPX_SSLSocket_Connect(void *ptr); static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes); static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes); #endif // defined(OPENSSL) || defined(GNUTLS) #if defined(ALSA) static void *ALSA_FPX_SoundOutput_Open(void); static int ALSA_FPX_SoundOutput_Close(void *ptr); static int ALSA_FPX_SoundOutput_Latency(void *ptr); #endif // defined(ALSA) #if defined(OSS) static void *OSS_FPX_SoundOutput_Open(void); static int OSS_FPX_SoundOutput_Close(void *ptr); static int OSS_FPX_SoundOutput_Latency(void *ptr); #endif // defined(OSS) #if defined(ESD) static void *ESD_FPX_SoundOutput_Open(void); static int ESD_FPX_SoundOutput_Close(void *ptr); static int ESD_FPX_SoundOutput_Latency(void *ptr); #endif // defined(ESD) #if defined(PULSEAUDIO) static void *PULSEAUDIO_FPX_SoundOutput_Open(void); static int PULSEAUDIO_FPX_SoundOutput_Close(void *ptr); static int PULSEAUDIO_FPX_SoundOutput_Latency(void *ptr); #endif // defined(PULSEAUDIO) #ifdef V4L1 static void *FPX_VideoInput_Open(); static int FPX_VideoInput_Close(void *ptr); static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes); #endif // V4L1 struct FPX_Functions { int fpx_count; void *fpx_shutdown; // 1 void *fpx_sslsocket_create; // 2 void *fpx_sslsocket_destroy; // 3 void *fpx_sslsocket_connect; // 4 void *fpx_sslsocket_receive; // 5 void *fpx_sslsocket_send; // 6 void *fpx_soundoutput_open; // 7 void *fpx_soundoutput_close; // 8 void *fpx_soundoutput_latency; // 9 void *fpx_videoinput_open; // 10 void *fpx_videoinput_close; // 11 void *fpx_videoinput_getframe; // 12 }; #ifdef cplusplus }; #endif // cplusplus // // END OF SHARED SECTION // //////////////////////////////////////////////////////////////////////////////////////////////////// #include #include #include #ifdef OPENSSL #include #elif defined(GNUTLS) #include #include #include #include #include #endif // GNUTLS #ifdef ALSA #include #include #include #endif #if defined(OSS) #include #include #include #include #include #endif #if defined(ESD) #include #include #include #include #include #endif #if defined(PULSEAUDIO) #include #include #include #include #endif #ifdef V4L1 #include #include #include #include #include #endif // V4L1 //Includes for output driver detection #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) #include //getenv #include //stat #include //stat #include //stat #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) 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) static T_FPI_SoundOutput_FillBuffer FPI_SoundOutput_FillBuffer = 0; #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) /* 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. Supports full audio/video synchronization, even over the network. - Esound is second, since it's by default in many distributions, and supports oss. NOTE: audio and video are not synchronized, since the latency functions can hang the browser. - Arts (TODO) is next. It's not currently supported because it's being phased out. Besides, it can use Esound as a backend - NASD: Not supported for the moment, there is not much information available... - Jack (TODO). When it's done, it should go after Pulse, but before ALSA. - ALSA: default if it's supported - Finally, if nothing else, fallback on oss */ #define AUDIO_PULSE 128 #define AUDIO_ESD 64 #define AUDIO_ARTS 32 #define AUDIO_NAS 16 #define AUDIO_JACK 8 #define AUDIO_ALSA 2 #define AUDIO_OSS 1 #if defined(ESD) //ESD functions int (*FPX_esd_play_stream_fallback)( esd_format_t format, int rate, const char *host, const char *name ); #endif #if defined(PULSEAUDIO) //PULSE functions pa_simple* (*FPX_pa_simple_new) (const char *server,const char *name, pa_stream_direction_t dir,const char *dev,const char *stream_name, const pa_sample_spec *ss,const pa_channel_map *map, const pa_buffer_attr *attr,int *error); void (*FPX_pa_simple_free) (pa_simple *s); int (*FPX_pa_simple_write) (pa_simple *s, const void*data, size_t length, int *error); int (*FPX_pa_simple_drain) (pa_simple *s, int *error); int (*FPX_pa_simple_read) (pa_simple *s, void*data, size_t length, int *error); pa_usec_t (*FPX_pa_simple_get_latency) (pa_simple *s, int *error); 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; static int pulsedebug=0; void FPX_SoundOutput_Detect() { char *tmpenv; struct stat buf; #if defined(PULSEAUDIO) || defined(ESD) void *handle; char *error; #endif #if defined(PULSEAUDIO) char tmpstr[1024]=""; #endif if((tmpenv=getenv("FLASH_AUDIODEBUG"))!=NULL) { audiodebug=1; } if((tmpenv=getenv("FLASH_PULSEDEBUG"))!=NULL) { pulsedebug=1; } if(audiodebug) { fprintf( stderr,"Flash sound output detection routine.\n"); fprintf( stderr,"(c) 2006 Revolution Linux inc,\n"); fprintf( stderr,"Jean-Michel Dault \n"); } #if defined(PULSEAUDIO) //Check if PULSE AUDIO is running if((tmpenv=getenv("USER"))!=NULL) { strcpy(tmpstr,"/tmp/pulse-"); strcat(tmpstr,tmpenv); if(!stat(tmpstr,&buf)) { if(audiodebug) fprintf( stderr, "PulseAudio socket found\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } } //Check if PULSE AUDIO is running system-wide strcpy(tmpstr,"/var/lib/run/pulse/native"); if(!stat(tmpstr,&buf)) { if(audiodebug) fprintf( stderr, "PulseAudio system-wide found\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } //Pulse over network if((tmpenv=getenv("PULSE_SERVER"))!=NULL) { if(audiodebug) fprintf( stderr, "PulseAudio SERVER variable present\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } //Pulse autospawn daemon if((tmpenv=getenv("PULSE_BINARY"))!=NULL) { if(audiodebug) fprintf( stderr, "PulseAudio BINARY variable present\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } #endif #if defined(ESD) //Check if ESD is running if(!stat("/tmp/.esd/socket",&buf)) { if(audiodebug) fprintf( stderr, "ESD socket found\n"); audiodrivers = audiodrivers | AUDIO_ESD; } //ESD over network if((tmpenv=getenv("ESPEAKER"))!=NULL) { if(audiodebug) fprintf( stderr, "ESD variable ESPEAKER found\n"); audiodrivers = audiodrivers | AUDIO_ESD; } #endif #if defined(ALSA) || defined(ALSA_INTERNAL) //Check for ALSA device if(!stat("/proc/asound",&buf)) { if(audiodebug) fprintf( stderr, "ALSA device detected\n"); audiodrivers = audiodrivers | AUDIO_ALSA; } #endif #if defined(OSS) //Check for OSS device if(!stat("/dev/dsp",&buf)) { if(audiodebug) fprintf( stderr, "OSS device present\n"); audiodrivers = audiodrivers | AUDIO_OSS; } #endif if((tmpenv=getenv("FLASH_FORCE_PULSEAUDIO"))!=NULL) { #if defined(PULSEAUDIO) if(audiodebug) fprintf( stderr, "Forcing PulseAudio\n"); audiodrivers = AUDIO_PULSE; #else 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"); audiodrivers = AUDIO_ESD; #else if(audiodebug) fprintf( stderr, "ESD 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"); audiodrivers = AUDIO_ALSA; #else 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"); audiodrivers = AUDIO_OSS; #else if(audiodebug) fprintf( stderr, "OSS unavailable: please recompile libflashsupport.so!\n"); #endif } //Check for required libraries and functions #if defined(PULSEAUDIO) if((audiodrivers & AUDIO_PULSE) && !FPX_pa_simple_new) { handle = dlopen(LIBPULSEPATH, RTLD_LAZY); if (!handle) { 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); } } #endif #if defined(ESD) if((audiodrivers & AUDIO_ESD) && !FPX_esd_play_stream_fallback) { handle = dlopen(LIBESDPATH, RTLD_LAZY); if (!handle) { 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); } } #endif return; } static void *FPX_SoundOutput_Open(void) { void *ptr; if(audiodebug) fprintf( stderr,"audiodrivers=%d\n",audiodrivers); #if defined(PULSEAUDIO) if(audiodrivers & AUDIO_PULSE) { if(audiodebug) fprintf( stderr,"Trying PULSE\n"); ptr=PULSEAUDIO_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_PULSE; if(audiodebug) fprintf( stderr, "Using PulseAudio driver\n"); return ptr; } } #endif #if defined(ESD) if(audiodrivers & AUDIO_ESD) { if(audiodebug) fprintf( stderr,"Trying ESD\n"); ptr=ESD_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_ESD; if(audiodebug) fprintf( stderr, "Using Esound audio driver\n"); return ptr; } } #endif #if defined(ALSA_INTERNAL) if(audiodrivers & AUDIO_ALSA) { 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"); ptr=ALSA_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_ALSA; if(audiodebug) fprintf( stderr, "Using ALSA audio driver\n"); return ptr; } } #endif #if defined(OSS) if(audiodrivers & AUDIO_OSS) { if(audiodebug) fprintf( stderr,"Trying OSS\n"); ptr=OSS_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_OSS; if(audiodebug) fprintf( stderr, "Using OSS audio driver\n"); return ptr; } } #endif // No sound... if(audiodebug) fprintf( stderr, "NO SOUND DRIVER! Revert to internal ALSA driver!\n"); return 0; } static int FPX_SoundOutput_Close(void *ptr) { int retcode; #if defined(PULSEAUDIO) if(audiotype == AUDIO_PULSE) { retcode=PULSEAUDIO_FPX_SoundOutput_Close(ptr); return retcode; } #endif #if defined(ESD) if(audiotype == AUDIO_ESD) { retcode=ESD_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(audiotype == AUDIO_OSS) { retcode=OSS_FPX_SoundOutput_Close(ptr); return retcode; } #endif return 0; } static int FPX_SoundOutput_Latency(void *ptr) { int retcode; #if defined(PULSEAUDIO) if(audiotype == AUDIO_PULSE) { retcode=PULSEAUDIO_FPX_SoundOutput_Latency(ptr); return retcode; } #endif #if defined(ESD) if(audiotype == AUDIO_ESD) { retcode=ESD_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(audiotype == AUDIO_OSS) { retcode=OSS_FPX_SoundOutput_Latency(ptr); return retcode; } #endif return 0; } #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) void *FPX_Init(void *ptr) { #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) FPX_SoundOutput_Detect(); #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) if ( !ptr ) return 0; // // Setup imported functions // struct FPI_Functions *fpi_functions = (struct FPI_Functions *)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 ( fpi_functions->fpi_count >= 3 ) FPI_SoundOutput_FillBuffer= fpi_functions->fpi_soundoutput_fillbuffer; // 3 #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) // // Setup exported functions // memset(&fpx_functions, 0, sizeof(fpx_functions)); fpx_functions.fpx_shutdown = FPX_Shutdown; // 1 #if defined(OPENSSL) || defined(GNUTLS) fpx_functions.fpx_sslsocket_create = FPX_SSLSocket_Create; // 2 fpx_functions.fpx_sslsocket_destroy = FPX_SSLSocket_Destroy; // 3 fpx_functions.fpx_sslsocket_connect = FPX_SSLSocket_Connect; // 4 fpx_functions.fpx_sslsocket_receive = FPX_SSLSocket_Receive; // 5 fpx_functions.fpx_sslsocket_send = FPX_SSLSocket_Send; // 6 #endif // defined(OPENSSL) || defined(GNUTLS) #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) 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) #ifdef V4L1 fpx_functions.fpx_videoinput_open = FPX_VideoInput_Open; // 10 fpx_functions.fpx_videoinput_close = FPX_VideoInput_Close; // 11 fpx_functions.fpx_videoinput_getframe = FPX_VideoInput_GetFrame; // 12 #endif // V4L1 fpx_functions.fpx_count = 14; #ifdef OPENSSL SSL_library_init(); #elif defined(GNUTLS) gnutls_global_init(); #endif // GNUTLS return (void *)&fpx_functions; } static void FPX_Shutdown() { #ifdef OPENSSL #elif defined(GNUTLS) gnutls_global_deinit(); #endif // GNUTLS } // // SSL support functions // #ifdef OPENSSL struct SSL_Instance { SSL *ssl; SSL_CTX *sslCtx; }; static void *FPX_SSLSocket_Create(int socket_fd) // return = instance pointer { struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance)); memset(instance,0,sizeof(struct SSL_Instance)); fprintf(stderr,"AAAAAAAAAA\n"); if ( ( instance->sslCtx = SSL_CTX_new( TLSv1_client_method() ) ) == 0 ) goto fail; if ( ( instance->ssl = SSL_new(instance->sslCtx) ) == 0 ) goto fail; if ( SSL_set_fd(instance->ssl, socket_fd) < 0 ) goto fail; return (void *)instance; fail: if ( instance->ssl ) { SSL_shutdown(instance->ssl); } if ( instance->sslCtx ) { SSL_CTX_free(instance->sslCtx); } if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Destroy(void *ptr) // ptr = instance pointer // return = 0 on sucess, < 0 on error { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; if ( instance->ssl ) { SSL_shutdown(instance->ssl); } if ( instance->sslCtx ) { SSL_CTX_free(instance->sslCtx); } if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Connect(void *ptr) // ptr = instance pointer // socket_fd = BSD socket fd to be associated with SSL connection // return = 0 on sucess, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return SSL_connect(instance->ssl); } static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to place received data into // n_bytes = length of buffer in bytes // return = actual bytes received, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return SSL_read(instance->ssl, buffer, n_bytes); } static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to be sent // n_bytes = length of input buffer in bytes // return = actual bytes sent, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return SSL_write(instance->ssl, buffer, n_bytes); } #elif defined(GNUTLS) struct SSL_Instance { gnutls_session_t session; gnutls_anon_client_credentials_t anoncred; }; static void *FPX_SSLSocket_Create(int socket_fd) // return = instance pointer { const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 }; struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance)); memset(instance,0,sizeof(struct SSL_Instance)); if ( gnutls_anon_allocate_client_credentials(&instance->anoncred) < 0 ) goto fail; if ( gnutls_init(&instance->session, GNUTLS_CLIENT) < 0 ) goto fail; if ( gnutls_set_default_priority(instance->session) < 0 ) goto fail; if ( gnutls_kx_set_priority(instance->session, kx_prio) < 0 ) goto fail; if ( gnutls_credentials_set(instance->session, GNUTLS_CRD_ANON, instance->anoncred) < 0 ) goto fail; gnutls_transport_set_ptr(instance->session, (gnutls_transport_ptr_t)socket_fd); return (void *)instance; fail: if ( instance->session ) { gnutls_deinit(instance->session); } if ( instance->anoncred ) { gnutls_anon_free_client_credentials(instance->anoncred); } if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Destroy(void *ptr) // ptr = instance pointer // return = 0 on sucess, < 0 on error { struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance)); gnutls_bye(instance->session, GNUTLS_SHUT_RDWR); gnutls_deinit(instance->session); gnutls_anon_free_client_credentials(instance->anoncred); if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Connect(void *ptr) // ptr = instance pointer // socket_fd = BSD socket fd to be associated with SSL connection // return = 0 on sucess, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return gnutls_handshake(instance->session); } static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to place received data into // n_bytes = length of buffer in bytes // return = actual bytes received, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return gnutls_record_recv(instance->session, buffer, n_bytes); } static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to be sent // n_bytes = length of input buffer in bytes // return = actual bytes sent, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return gnutls_record_send(instance->session, buffer, n_bytes); } #endif // GNUTLS // // Sound support functions // #ifdef ALSA struct ALSA_SoundOutput_Instance { snd_pcm_t * handle; snd_async_handler_t * async_handler; sem_t semaphore; pthread_t thread; char * buffer; snd_pcm_sframes_t buffer_size; snd_pcm_sframes_t period_size; snd_pcm_sframes_t buffer_pos; char * buffer_ptr; }; static void *alsa_thread(void *ptr) { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr; snd_pcm_sframes_t avail = 0; int result = 0; int err = 0; int state = 0; for( ; ; ) { err = sem_wait(&instance->semaphore); if ( !instance->handle ) { pthread_exit(0); return 0; } if ( err < 0 ) { usleep(1); continue; } do { if ( instance->buffer_pos <= 0 ) { FPI_SoundOutput_FillBuffer(ptr, instance->buffer, snd_pcm_frames_to_bytes(instance->handle, instance->period_size)); instance->buffer_pos = instance->period_size; instance->buffer_ptr = instance->buffer; } do { state = snd_pcm_state(instance->handle); if(state != SND_PCM_STATE_RUNNING && state != SND_PCM_STATE_PREPARED) { snd_pcm_prepare(instance->handle); } result = snd_pcm_writei(instance->handle, instance->buffer_ptr, instance->buffer_pos); if( result <= 0 ) { switch( result ) { case -EPIPE: { snd_pcm_prepare(instance->handle); } break; case -ESTRPIPE: { err = snd_pcm_resume(instance->handle); if ( err < 0 ) { snd_pcm_prepare(instance->handle); } } break; } break; } else { instance->buffer_pos -= result; instance->buffer_ptr += snd_pcm_frames_to_bytes(instance->handle, result); } } while (instance->buffer_pos); avail = snd_pcm_avail_update(instance->handle); if( avail < 0 ) { switch( avail ) { case -EPIPE: { snd_pcm_prepare(instance->handle); } break; case -ESTRPIPE: { err = snd_pcm_resume(instance->handle); if ( err < 0 ) { snd_pcm_prepare(instance->handle); } } break; } break; } } while(avail >= instance->period_size); } } static void alsa_callback(snd_async_handler_t *ahandler) { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)snd_async_handler_get_callback_private(ahandler); // signal mixer thread sem_post(&instance->semaphore); } static void *ALSA_FPX_SoundOutput_Open() // return = instance pointer { struct ALSA_SoundOutput_Instance *instance = 0; snd_pcm_hw_params_t *hwparams = 0; snd_pcm_sw_params_t *swparams = 0; snd_pcm_format_t pcm_format; unsigned int buffer_time = 500000; unsigned int period_time = 20000; unsigned int actual_rate; snd_pcm_uframes_t size; int direction; void *retVal = 0; int err = 0; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; instance = FPI_Mem_Alloc(sizeof(struct ALSA_SoundOutput_Instance)); memset(instance,0,sizeof(struct ALSA_SoundOutput_Instance)); if ( ( err = snd_pcm_open(&instance->handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) { if ( ( err = snd_pcm_open(&instance->handle, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) { goto fail; } } snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); if (snd_pcm_hw_params_any(instance->handle, hwparams) < 0) goto fail; if (snd_pcm_hw_params_set_access(instance->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) goto fail; pcm_format = SND_PCM_FORMAT_S16_LE; if (snd_pcm_hw_params_set_format(instance->handle, hwparams, pcm_format) < 0) goto fail; if (snd_pcm_hw_params_set_channels(instance->handle, hwparams, 2) < 0) goto fail; actual_rate = 44100; if (snd_pcm_hw_params_set_rate_near(instance->handle, hwparams, &actual_rate, 0) < 0) goto fail; if (actual_rate != 44100) goto fail; if (snd_pcm_hw_params_set_buffer_time_near(instance->handle, hwparams, &buffer_time, &direction) < 0) goto fail; if (snd_pcm_hw_params_get_buffer_size(hwparams, &size) < 0) goto fail; instance->buffer_size = (snd_pcm_sframes_t)size; if (snd_pcm_hw_params_set_period_time_near(instance->handle, hwparams, &period_time, &direction) < 0) goto fail; if (snd_pcm_hw_params_get_period_size(hwparams, &size, &direction) < 0) goto fail; instance->period_size = (snd_pcm_sframes_t)size; if (snd_pcm_hw_params(instance->handle, hwparams) < 0) goto fail; if (snd_pcm_sw_params_current(instance->handle, swparams) < 0) goto fail; if (snd_pcm_sw_params_set_start_threshold(instance->handle, swparams, ((instance->buffer_size-1) / instance->period_size) * instance->period_size) < 0) goto fail; if (snd_pcm_sw_params_set_stop_threshold(instance->handle, swparams, ~0U) < 0) goto fail; if (snd_pcm_sw_params_set_avail_min(instance->handle, swparams, instance->period_size) < 0) goto fail; if (snd_pcm_sw_params_set_xfer_align(instance->handle, swparams, 1) < 0) goto fail; if (snd_pcm_sw_params(instance->handle, swparams) < 0) goto fail; if (snd_async_add_pcm_handler(&instance->async_handler, instance->handle, &alsa_callback, instance) < 0) goto fail; if ( ( instance->buffer = FPI_Mem_Alloc(instance->buffer_size * 2 * 2 * 2) ) == 0 ) goto fail; if ( pthread_create(&instance->thread, 0, alsa_thread, instance) < 0 ) goto fail; sem_post(&instance->semaphore); return instance; fail: if ( instance ) { if ( instance->handle ) { snd_pcm_drop(instance->handle); snd_pcm_close(instance->handle); instance->handle = 0; } if ( instance->thread ) { sem_post(&instance->semaphore); sem_destroy(&instance->semaphore); pthread_join(instance->thread,&retVal); } if ( instance->buffer ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int ALSA_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr; void *retVal = 0; if ( instance->handle ) { snd_pcm_drop(instance->handle); snd_pcm_close(instance->handle); instance->handle = 0; } if ( instance->thread ) { sem_post(&instance->semaphore); sem_destroy(&instance->semaphore); pthread_join(instance->thread,&retVal); } if ( instance->buffer ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } static int ALSA_FPX_SoundOutput_Latency(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr; if ( instance->handle ) { snd_pcm_sframes_t delay = 0; snd_pcm_delay(instance->handle, &delay); if ( snd_pcm_state(instance->handle) == SND_PCM_STATE_RUNNING && delay > 0 ) { return delay; } else { return 0; } } return -1; } #endif #if defined(OSS) struct OSS_SoundOutput_Instance { int oss_fd; pthread_t thread; int signal; }; static void *oss_thread(void *ptr) { struct OSS_SoundOutput_Instance *instance = (struct OSS_SoundOutput_Instance *)ptr; char buffer[4096]; int len = 0; int written = 0; for(;;) { FPI_SoundOutput_FillBuffer(ptr,buffer,4096); len = 4096; while ( len ) { written = write(instance->oss_fd, buffer, len); if ( written >= 0 ) { len -= written; } if ( instance->signal ) { pthread_exit(0); } if ( written < 0 ) { usleep(100); } } } } static void *OSS_FPX_SoundOutput_Open() // return = instance pointer { struct OSS_SoundOutput_Instance *instance = 0; int format = AFMT_S16_LE; int stereo = 1; int speed = 44100; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; instance = (struct OSS_SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct OSS_SoundOutput_Instance)); memset(instance,0,sizeof(struct OSS_SoundOutput_Instance)); if ( ( instance->oss_fd = open("/dev/dsp",O_WRONLY) ) < 0 ) goto fail; if ( ioctl(instance->oss_fd, SNDCTL_DSP_SETFMT, &format) < 0 ) goto fail; if ( ioctl(instance->oss_fd, SNDCTL_DSP_STEREO, &stereo) < 0 ) goto fail; if ( ioctl(instance->oss_fd, SNDCTL_DSP_SPEED, &speed) < 0 ) goto fail; if ( pthread_create(&instance->thread, 0, oss_thread, instance) < 0 ) goto fail; return instance; fail: if ( instance ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int OSS_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct OSS_SoundOutput_Instance *instance = (struct OSS_SoundOutput_Instance *)ptr; void *retVal = 0; instance->signal = 1; if ( instance->oss_fd ) { ioctl(instance->oss_fd, SNDCTL_DSP_RESET, 0); } if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->oss_fd ) { close(instance->oss_fd); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } static int OSS_FPX_SoundOutput_Latency(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct OSS_SoundOutput_Instance *instance = (struct OSS_SoundOutput_Instance *)ptr; if ( instance->oss_fd ) { int value = 0; if ( ( value = ioctl(instance->oss_fd,SNDCTL_DSP_GETODELAY,&value) ) == 0 ) { return value / 4; } return 0; } return -1; } #endif #if defined(ESD) struct ESD_SoundOutput_Instance { int esd_sock; pthread_t thread; int signal; }; static void *esd_thread(void *ptr) { struct ESD_SoundOutput_Instance *instance = (struct ESD_SoundOutput_Instance *)ptr; char buffer[4096]; int len = 0; int written = 0; for(;;) { FPI_SoundOutput_FillBuffer(ptr,buffer,4096); len = 4096; while ( len ) { written = write(instance->esd_sock, buffer+4096-len, len); if ( written >= 0 ) { len -= written; } if ( instance->signal ) { pthread_exit(0); } if ( written < 0 ) { usleep(100); } } } } static void *ESD_FPX_SoundOutput_Open() // return = instance pointer { struct ESD_SoundOutput_Instance *instance = 0; int rate = ESD_DEFAULT_RATE; int bits = ESD_BITS16, channels = ESD_STEREO; int mode = ESD_STREAM, func = ESD_PLAY ; esd_format_t format = 0; char *host = NULL; char *name = NULL; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; format = bits | channels | mode | func; instance = (struct ESD_SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct ESD_SoundOutput_Instance)); memset(instance,0,sizeof(struct ESD_SoundOutput_Instance)); 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; return instance; fail: if ( instance ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int ESD_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct ESD_SoundOutput_Instance *instance = (struct ESD_SoundOutput_Instance *)ptr; void *retVal = 0; instance->signal = 1; if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->esd_sock ) { close(instance->esd_sock); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } 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; if ( instance->esd_sock ) { return (esd_get_latency(instance->esd_sock)); } */ return -1; } #endif #if defined(PULSEAUDIO) struct PULSE_SoundOutput_Instance { pa_simple *pa_sock; pthread_t thread; int signal; }; static void *pa_thread(void *ptr) { struct PULSE_SoundOutput_Instance *instance = (struct PULSE_SoundOutput_Instance *)ptr; char buffer[4096]; size_t len = 0; int error; for(;;) { FPI_SoundOutput_FillBuffer(ptr,buffer,4096); len = 4096; if (FPX_pa_simple_write(instance->pa_sock, buffer, len, &error) < 0) { if(audiodebug) fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", FPX_pa_strerror(error)); usleep(100); } if ( instance->signal ) { pthread_exit(0); } } } static void *PULSEAUDIO_FPX_SoundOutput_Open() // return = instance pointer { struct PULSE_SoundOutput_Instance *instance = 0; int error; if(audiodebug) fprintf( stderr, "Called FPX_SoundOutput_Open\n"); /* The Sample format to use */ static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2 }; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; instance = (struct PULSE_SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct PULSE_SoundOutput_Instance)); memset(instance,0,sizeof(struct PULSE_SoundOutput_Instance)); if ( ( instance->pa_sock = FPX_pa_simple_new(NULL, "flashplayer", PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error)) <= 0 ) goto fail; if(audiodebug) fprintf( stderr, "Opened Pulse\n"); if ( pthread_create(&instance->thread, 0, pa_thread, instance) < 0 ) goto fail; return instance; fail: if(audiodebug) fprintf( stderr, "FAILED TO OPEN PULSEAUDIO!\n"); if ( instance ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int PULSEAUDIO_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct PULSE_SoundOutput_Instance *instance = (struct PULSE_SoundOutput_Instance *)ptr; void *retVal = 0; int error; instance->signal = 1; if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->pa_sock ) { FPX_pa_simple_drain(instance->pa_sock, &error); FPX_pa_simple_free(instance->pa_sock); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } 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; int error; struct PULSE_SoundOutput_Instance *instance = (struct PULSE_SoundOutput_Instance *)ptr; if ( instance->pa_sock ) { latencytime = FPX_pa_simple_get_latency(instance->pa_sock, &error); } if(pulsedebug) fprintf(stderr, "\nLatency: %0.0f usec \n", (float)latencytime); /* Max bytes in one second: 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) */ latencysamples= 44100 * latencytime / 1000000; latency=(int)latencysamples; if(pulsedebug) fprintf(stderr, "\nLatency: %d samples\n", latency); return latency; return -1; } #endif // defined(ALSA/OSS/ESD/PULSEAUDIO) #ifdef V4L1 struct VideoOutput_Instance { int v4l_fd; pthread_t thread; int signal; char * buffer[2]; int buffercurrent; int buffersize; struct video_window window; struct video_picture picture; }; static void *v4l_thread(void *ptr) { struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr; int result; int status; for(;;) { result = read(instance->v4l_fd, instance->buffer[instance->buffercurrent], instance->buffersize); if(result > 0) { } if ( result < 0 ) { usleep(10000); } if ( instance->signal ) { status = 0; ioctl(instance->v4l_fd, VIDIOCCAPTURE, &status); pthread_exit(0); } } } static void *FPX_VideoInput_Open() { struct VideoOutput_Instance *instance = 0; if ( !FPI_Mem_Alloc ) goto fail; instance = (struct VideoOutput_Instance *)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance)); memset(instance,0,sizeof(struct VideoOutput_Instance)); if ( ( instance->v4l_fd = open("/dev/video", O_RDONLY) ) < 0 ) goto fail; if ( ioctl(instance->v4l_fd, VIDIOCGPICT, &instance->picture) < 0 ) goto fail; switch(instance->picture.palette) { case VIDEO_PALETTE_YUV420P: break; case VIDEO_PALETTE_RGB24: case VIDEO_PALETTE_YUV422P: case VIDEO_PALETTE_YUV411P: case VIDEO_PALETTE_YUV410P: case VIDEO_PALETTE_GREY: case VIDEO_PALETTE_HI240: case VIDEO_PALETTE_RGB565: case VIDEO_PALETTE_RGB32: case VIDEO_PALETTE_RGB555: case VIDEO_PALETTE_YUV422: case VIDEO_PALETTE_YUYV: case VIDEO_PALETTE_UYVY: case VIDEO_PALETTE_YUV420: case VIDEO_PALETTE_YUV411: case VIDEO_PALETTE_RAW: default: goto fail; } if( ioctl(instance->v4l_fd, VIDIOCGWIN, &instance->window) < 0 ) goto fail; instance->buffer[0] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2); instance->buffer[1] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2); if ( pthread_create(&instance->thread, 0, v4l_thread, instance) < 0 ) goto fail; return instance; fail: if ( FPI_Mem_Free ) { if ( instance->buffer[0] ) { FPI_Mem_Free(instance->buffer[0]); } if ( instance->buffer[1] ) { FPI_Mem_Free(instance->buffer[1]); } FPI_Mem_Free(instance); } return 0; } static int FPX_VideoInput_Close(void *ptr) { struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr; void *retVal = 0; instance->signal = 1; if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->v4l_fd ) { close(instance->v4l_fd); } if ( FPI_Mem_Free ) { if ( instance->buffer[0] ) { FPI_Mem_Free(instance->buffer[0]); } if ( instance->buffer[1] ) { FPI_Mem_Free(instance->buffer[1]); } FPI_Mem_Free(instance); } return 0; } static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes) { struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr; int ix, iy, ox, oy, ow, oh, dx, dy, Y, U, V, R, G, B; unsigned char *y, *u, *v; switch(instance->picture.palette) { case VIDEO_PALETTE_YUV420P: { ow = instance->window.width; oh = instance->window.height; dx = (ow<<16) / width; dy = (oh<<16) / height; y = (unsigned char *)instance->buffer[instance->buffercurrent^1]; u = y + ow * oh; v = u + ow * oh / 4; oy = 0; for ( iy = 0; iy < height; iy++ ) { ox = 0; for ( ix = 0; ix < width; ix++ ) { Y = ( 149 * ((int)(y[(oy>>16)*(ow )+(ox>>16)]) - 16) ) / 2; U = (int)(u[(oy>>17)*(ow/2)+(ox>>17)]) - 128; V = (int)(v[(oy>>17)*(ow/2)+(ox>>17)]) - 128; R = (Y + V * 102 ) / 64; G = (Y - V * 52 - U * 25 ) / 64; B = (Y + U * 129 ) / 64; R = R < 0 ? 0 : ( R > 255 ? 255 : R ); G = G < 0 ? 0 : ( G > 255 ? 255 : G ); B = B < 0 ? 0 : ( B > 255 ? 255 : B ); data[ix*3+0] = R; data[ix*3+1] = G; data[ix*3+2] = B; ox += dx; } oy += dy; data += pitch_n_bytes; } } break; default: goto fail; } instance->buffercurrent ^= 1; return 0; fail: return -1; } #endif // V4L1 libflashsupport-0.0.svn2431/Old/0000775002342100234210000000000010745654036015111 5ustar pereperelibflashsupport-0.0.svn2431/Old/beta1/0000775002342100234210000000000010745654036016105 5ustar pereperelibflashsupport-0.0.svn2431/Old/beta1/flashsupport.c0000664002342100234210000013643110745654036021013 0ustar perepere/* Adobe Systems Incorporated(r) Source Code License Agreement Copyright(c) 2006 Adobe Systems Incorporated. All rights reserved. Please read this Source Code License Agreement carefully before using the source code. Adobe Systems Incorporated grants to you a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license, to reproduce, prepare derivative works of, publicly display, publicly perform, and distribute this source code and such derivative works in source or object code form without any attribution requirements. The name "Adobe Systems Incorporated" must not be used to endorse or promote products derived from the source code without prior written permission. You agree to indemnify, hold harmless and defend Adobe Systems Incorporated from and against any loss, damage, claims or lawsuits, including attorney's fees that arise or result from your use or distribution of the source code. THIS SOURCE CODE IS PROVIDED "AS IS" AND "WITH ALL FAULTS", WITHOUT ANY TECHNICAL SUPPORT OR ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ALSO, THERE IS NO WARRANTY OF NON-INFRINGEMENT, TITLE OR QUIET ENJOYMENT. IN NO EVENT SHALL MACROMEDIA OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOURCE CODE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The Sound detection routines, ESD and PulseAudio backends have been writen by Jean-Michel Dault cc -shared -O2 -Wall -Werror -licuuc -lssl flashsupport.c -o libflashsupport.so // > ldd libflashplayer.so // > sudo cp libflashplayer.so /usr/lib // // Make sure that 'ldd' can resolve all dynamic libraries. Otherwise the Flash Player // will silently fail to load and use libflashsupport.so. // //////////////////////////////////////////////////////////////////////////////////////////////////// // // SHARED SECTION, DO NOT CHANGE! // #ifdef cplusplus extern "C" { #endif // cplusplus // // Imported functions // 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) 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) struct FPI_Functions { int fpi_count; void *fpi_mem_alloc; // 1 void *fpi_mem_free; // 2 void *fpi_soundoutput_fillbuffer; // 3 }; // // Exported functions // void *FPX_Init(void *ptr); static void FPX_Shutdown(void); #if defined(OPENSSL) || defined(GNUTLS) static void *FPX_SSLSocket_Create(int socket_fd); static int FPX_SSLSocket_Destroy(void *ptr); static int FPX_SSLSocket_Connect(void *ptr); static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes); static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes); #endif // defined(OPENSSL) || defined(GNUTLS) #ifdef ICU static char *FPX_Unicode_CodePageToUTF8(const char *buffer, int code_page); static char *FPX_Unicode_UTF8ToCodePage(const char *buffer, int code_page); #endif // ICU #if defined(ALSA) static void *ALSA_FPX_SoundOutput_Open(void); static int ALSA_FPX_SoundOutput_Close(void *ptr); static int ALSA_FPX_SoundOutput_Latency(void *ptr); #endif // defined(ALSA) #if defined(OSS) static void *OSS_FPX_SoundOutput_Open(void); static int OSS_FPX_SoundOutput_Close(void *ptr); static int OSS_FPX_SoundOutput_Latency(void *ptr); #endif // defined(OSS) #if defined(ESD) static void *ESD_FPX_SoundOutput_Open(void); static int ESD_FPX_SoundOutput_Close(void *ptr); static int ESD_FPX_SoundOutput_Latency(void *ptr); #endif // defined(ESD) #if defined(PULSEAUDIO) static void *PULSEAUDIO_FPX_SoundOutput_Open(void); static int PULSEAUDIO_FPX_SoundOutput_Close(void *ptr); static int PULSEAUDIO_FPX_SoundOutput_Latency(void *ptr); #endif // defined(PULSEAUDIO) #ifdef V4L1 static void *FPX_VideoInput_Open(); static int FPX_VideoInput_Close(void *ptr); static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes); #endif // V4L1 struct FPX_Functions { int fpx_count; void *fpx_shutdown; // 1 void *fpx_sslsocket_create; // 2 void *fpx_sslsocket_destroy; // 3 void *fpx_sslsocket_connect; // 4 void *fpx_sslsocket_receive; // 5 void *fpx_sslsocket_send; // 6 void *fpx_unicode_codepagetoutf8; // 7 void *fpx_unicode_utf8tocodepage; // 8 void *fpx_soundoutput_open; // 9 void *fpx_soundoutput_close; // 10 void *fpx_soundoutput_latency; // 11 void *fpx_videoinput_open; // 12 void *fpx_videoinput_close; // 13 void *fpx_videoinput_getframe; // 14 }; #ifdef cplusplus }; #endif // cplusplus // // END OF SHARED SECTION // //////////////////////////////////////////////////////////////////////////////////////////////////// #include #ifdef OPENSSL #include #elif defined(GNUTLS) #include #include #include #include #include #endif // GNUTLS #ifdef ICU #include #include #endif // ICU #ifdef ALSA #include #include #include #endif #if defined(OSS) #include #include #include #include #include #endif #if defined(ESD) #include #include #include #include #include #endif #if defined(PULSEAUDIO) #include #include #include #include #endif #ifdef V4L1 #include #include #include #include #include #endif // V4L1 //Includes for output driver detection #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) #include //getenv #include //stat #include //stat #include //stat #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) 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) static T_FPI_SoundOutput_FillBuffer FPI_SoundOutput_FillBuffer = 0; #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) /* 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. Supports full audio/video synchronization, even over the network. - Esound is second, since it's by default in many distributions, and supports oss. NOTE: audio and video are not synchronized, since the latency functions can hang the browser. - Arts (TODO) is next. It's not currently supported because it's being phased out. Besides, it can use Esound as a backend - NASD: Not supported for the moment, there is not much information available... - Jack (TODO). When it's done, it should go after Pulse, but before ALSA. - ALSA: default if it's supported - Finally, if nothing else, fallback on oss */ #define AUDIO_PULSE 128 #define AUDIO_ESD 64 #define AUDIO_ALSA 2 #define AUDIO_OSS 1 //ESD functions int (*FPX_esd_play_stream_fallback)( esd_format_t format, int rate, const char *host, const char *name ); //PULSE functions pa_simple* (*FPX_pa_simple_new) (const char *server,const char *name, pa_stream_direction_t dir,const char *dev,const char *stream_name, const pa_sample_spec *ss,const pa_channel_map *map, const pa_buffer_attr *attr,int *error); void (*FPX_pa_simple_free) (pa_simple *s); int (*FPX_pa_simple_write) (pa_simple *s, const void*data, size_t length, int *error); int (*FPX_pa_simple_drain) (pa_simple *s, int *error); int (*FPX_pa_simple_read) (pa_simple *s, void*data, size_t length, int *error); pa_usec_t (*FPX_pa_simple_get_latency) (pa_simple *s, int *error); int (*FPX_pa_simple_flush) (pa_simple *s, int *error); const char* (*FPX_pa_strerror) (int error); static int audiotype=2; static int audiodrivers=0; static int audiodebug=0; static int pulsedebug=0; void FPX_SoundOutput_Detect() { char tmpstr[1024]=""; char *tmpenv; struct stat buf; void *handle; char *error; if((tmpenv=getenv("FLASH_AUDIODEBUG"))!=NULL) { audiodebug=1; } if((tmpenv=getenv("FLASH_PULSEDEBUG"))!=NULL) { pulsedebug=1; } if(audiodebug) { fprintf( stderr,"Flash sound output detection routine.\n\ (c) 2006 Revolution Linux inc, \ Jean-Michel Dault \n"); } #if defined(PULSEAUDIO) //Check if PULSE AUDIO is running if((tmpenv=getenv("USER"))!=NULL) { strcpy(tmpstr,"/tmp/pulse-"); strcat(tmpstr,tmpenv); strcat(tmpstr,"/native"); if(!stat(tmpstr,&buf)) { if(audiodebug) fprintf( stderr, "PulseAudio socket found\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } } //Check if PULSE AUDIO is running system-wide strcpy(tmpstr,"/var/lib/run/pulse/native"); if(!stat(tmpstr,&buf)) { if(audiodebug) fprintf( stderr, "PulseAudio system-wide found\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } //Pulse over network if((tmpenv=getenv("PULSE_SERVER"))!=NULL) { if(audiodebug) fprintf( stderr, "PulseAudio SERVER variable present\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } //Pulse autospawn daemon if((tmpenv=getenv("PULSE_BINARY"))!=NULL) { if(audiodebug) fprintf( stderr, "PulseAudio BINARY variable present\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } #endif #if defined(ESD) //Check if ESD is running if(!stat("/tmp/.esd/socket",&buf)) { if(audiodebug) fprintf( stderr, "ESD socket found\n"); audiodrivers = audiodrivers | AUDIO_ESD; } //ESD over network if((tmpenv=getenv("ESPEAKER"))!=NULL) { if(audiodebug) fprintf( stderr, "ESD variable ESPEAKER found\n"); audiodrivers = audiodrivers | AUDIO_ESD; } #endif #if defined(ALSA) || defined(ALSA_INTERNAL) //Check for ALSA device if(!stat("/proc/asound",&buf)) { if(audiodebug) fprintf( stderr, "ALSA device detected\n"); audiodrivers = audiodrivers | AUDIO_ALSA; } #endif #if defined(OSS) //Check for OSS device if(!stat("/dev/dsp",&buf)) { if(audiodebug) fprintf( stderr, "OSS device present\n"); audiodrivers = audiodrivers | AUDIO_OSS; } #endif if((tmpenv=getenv("FLASH_FORCE_PULSEAUDIO"))!=NULL) { #if defined(PULSEAUDIO) if(audiodebug) fprintf( stderr, "Forcing PulseAudio\n"); audiodrivers = AUDIO_PULSE; #else 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"); audiodrivers = AUDIO_ESD; #else if(audiodebug) fprintf( stderr, "ESD 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"); audiodrivers = AUDIO_ALSA; #else 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"); audiodrivers = AUDIO_OSS; #else if(audiodebug) fprintf( stderr, "OSS unavailable: please recompile libflashsupport.so!\n"); #endif } //Check for required libraries and functions #if defined(PULSEAUDIO) if((audiodrivers & AUDIO_PULSE) && !FPX_pa_simple_new) { handle = dlopen("/usr/lib/libpulse-simple.so.0", RTLD_LAZY); if (!handle) { if(audiodebug) fprintf(stderr,"Can't load /usr/lib/libpulse-simple.so.0: %s\n",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); } } #endif #if defined(ESD) if((audiodrivers & AUDIO_ESD) && !FPX_esd_play_stream_fallback) { handle = dlopen("/usr/lib/libesd.so.0", RTLD_LAZY); if (!handle) { if(audiodebug) fprintf(stderr,"Can't load /usr/lib/libesd.so.0: %s\n",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); } } #endif return; } static void *FPX_SoundOutput_Open(void) { void *ptr; if(audiodebug) fprintf( stderr,"audiodrivers=%d\n",audiodrivers); #if defined(PULSEAUDIO) if(audiodrivers & AUDIO_PULSE) { if(audiodebug) fprintf( stderr,"Trying PULSE\n"); ptr=PULSEAUDIO_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_PULSE; if(audiodebug) fprintf( stderr, "Using PulseAudio driver\n"); return ptr; } } #endif #if defined(ESD) if(audiodrivers & AUDIO_ESD) { if(audiodebug) fprintf( stderr,"Trying ESD\n"); ptr=ESD_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_ESD; if(audiodebug) fprintf( stderr, "Using Esound audio driver\n"); return ptr; } } #endif #if defined(ALSA_INTERNAL) if(audiodrivers & AUDIO_ALSA) { 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"); ptr=ALSA_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_ALSA; if(audiodebug) fprintf( stderr, "Using ALSA audio driver\n"); return ptr; } } #endif #if defined(OSS) if(audiodrivers & AUDIO_OSS) { if(audiodebug) fprintf( stderr,"Trying OSS\n"); ptr=OSS_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_OSS; if(audiodebug) fprintf( stderr, "Using OSS audio driver\n"); return ptr; } } #endif // No sound... if(audiodebug) fprintf( stderr, "NO SOUND DRIVER! Revert to internal ALSA driver!\n"); return 0; } static int FPX_SoundOutput_Close(void *ptr) { int retcode; #if defined(PULSEAUDIO) if(audiotype == AUDIO_PULSE) { retcode=PULSEAUDIO_FPX_SoundOutput_Close(ptr); return retcode; } #endif #if defined(ESD) if(audiotype == AUDIO_ESD) { retcode=ESD_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(audiotype == AUDIO_OSS) { retcode=OSS_FPX_SoundOutput_Close(ptr); return retcode; } #endif return 0; } static int FPX_SoundOutput_Latency(void *ptr) { int retcode; #if defined(PULSEAUDIO) if(audiotype == AUDIO_PULSE) { retcode=PULSEAUDIO_FPX_SoundOutput_Latency(ptr); return retcode; } #endif #if defined(ESD) if(audiotype == AUDIO_ESD) { retcode=ESD_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(audiotype == AUDIO_OSS) { retcode=OSS_FPX_SoundOutput_Latency(ptr); return retcode; } #endif return 0; } #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) void *FPX_Init(void *ptr) { #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) FPX_SoundOutput_Detect(); #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) if ( !ptr ) return 0; // // Setup imported functions // struct FPI_Functions *fpi_functions = (struct FPI_Functions *)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 ( fpi_functions->fpi_count >= 3 ) FPI_SoundOutput_FillBuffer= fpi_functions->fpi_soundoutput_fillbuffer; // 3 #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) // // Setup exported functions // memset(&fpx_functions, 0, sizeof(fpx_functions)); fpx_functions.fpx_shutdown = FPX_Shutdown; // 1 #if defined(OPENSSL) || defined(GNUTLS) fpx_functions.fpx_sslsocket_create = FPX_SSLSocket_Create; // 2 fpx_functions.fpx_sslsocket_destroy = FPX_SSLSocket_Destroy; // 3 fpx_functions.fpx_sslsocket_connect = FPX_SSLSocket_Connect; // 4 fpx_functions.fpx_sslsocket_receive = FPX_SSLSocket_Receive; // 5 fpx_functions.fpx_sslsocket_send = FPX_SSLSocket_Send; // 6 #endif // defined(OPENSSL) || defined(GNUTLS) #ifdef ICU fpx_functions.fpx_unicode_codepagetoutf8 = FPX_Unicode_CodePageToUTF8; // 7 fpx_functions.fpx_unicode_utf8tocodepage = FPX_Unicode_UTF8ToCodePage; // 8 #endif // ICU #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) fpx_functions.fpx_soundoutput_open = FPX_SoundOutput_Open; // 9 fpx_functions.fpx_soundoutput_close = FPX_SoundOutput_Close; // 10 fpx_functions.fpx_soundoutput_latency = FPX_SoundOutput_Latency; // 11 #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) #ifdef V4L1 fpx_functions.fpx_videoinput_open = FPX_VideoInput_Open; // 12 fpx_functions.fpx_videoinput_close = FPX_VideoInput_Close; // 13 fpx_functions.fpx_videoinput_getframe = FPX_VideoInput_GetFrame; // 14 #endif // V4L1 fpx_functions.fpx_count = 14; #ifdef OPENSSL SSL_library_init(); #elif defined(GNUTLS) gnutls_global_init(); #endif // GNUTLS return (void *)&fpx_functions; } static void FPX_Shutdown() { #ifdef OPENSSL #elif defined(GNUTLS) gnutls_global_deinit(); #endif // GNUTLS } // // SSL support functions // #ifdef OPENSSL struct SSL_Instance { SSL *ssl; SSL_CTX *sslCtx; }; static void *FPX_SSLSocket_Create(int socket_fd) // return = instance pointer { struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance)); memset(instance,0,sizeof(struct SSL_Instance)); if ( ( instance->sslCtx = SSL_CTX_new( TLSv1_client_method() ) ) == 0 ) goto fail; if ( ( instance->ssl = SSL_new(instance->sslCtx) ) == 0 ) goto fail; if ( SSL_set_fd(instance->ssl, socket_fd) < 0 ) goto fail; return (void *)instance; fail: if ( instance->ssl ) { SSL_shutdown(instance->ssl); } if ( instance->sslCtx ) { SSL_CTX_free(instance->sslCtx); } if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Destroy(void *ptr) // ptr = instance pointer // return = 0 on sucess, < 0 on error { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; if ( instance->ssl ) { SSL_shutdown(instance->ssl); } if ( instance->sslCtx ) { SSL_CTX_free(instance->sslCtx); } if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Connect(void *ptr) // ptr = instance pointer // socket_fd = BSD socket fd to be associated with SSL connection // return = 0 on sucess, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return SSL_connect(instance->ssl); } static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to place received data into // n_bytes = length of buffer in bytes // return = actual bytes received, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return SSL_read(instance->ssl, buffer, n_bytes); } static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to be sent // n_bytes = length of input buffer in bytes // return = actual bytes sent, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return SSL_write(instance->ssl, buffer, n_bytes); } #elif defined(GNUTLS) struct SSL_Instance { gnutls_session_t session; gnutls_anon_client_credentials_t anoncred; }; static void *FPX_SSLSocket_Create(int socket_fd) // return = instance pointer { const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 }; struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance)); memset(instance,0,sizeof(struct SSL_Instance)); if ( gnutls_anon_allocate_client_credentials(&instance->anoncred) < 0 ) goto fail; if ( gnutls_init(&instance->session, GNUTLS_CLIENT) < 0 ) goto fail; if ( gnutls_set_default_priority(instance->session) < 0 ) goto fail; if ( gnutls_kx_set_priority(instance->session, kx_prio) < 0 ) goto fail; if ( gnutls_credentials_set(instance->session, GNUTLS_CRD_ANON, instance->anoncred) < 0 ) goto fail; gnutls_transport_set_ptr(instance->session, (gnutls_transport_ptr_t)socket_fd); return (void *)instance; fail: if ( instance->session ) { gnutls_deinit(instance->session); } if ( instance->anoncred ) { gnutls_anon_free_client_credentials(instance->anoncred); } if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Destroy(void *ptr) // ptr = instance pointer // return = 0 on sucess, < 0 on error { struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance)); gnutls_bye(instance->session, GNUTLS_SHUT_RDWR); gnutls_deinit(instance->session); gnutls_anon_free_client_credentials(instance->anoncred); if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Connect(void *ptr) // ptr = instance pointer // socket_fd = BSD socket fd to be associated with SSL connection // return = 0 on sucess, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return gnutls_handshake(instance->session); } static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to place received data into // n_bytes = length of buffer in bytes // return = actual bytes received, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return gnutls_record_recv(instance->session, buffer, n_bytes); } static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to be sent // n_bytes = length of input buffer in bytes // return = actual bytes sent, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return gnutls_record_send(instance->session, buffer, n_bytes); } #endif // GNUTLS // // Unicode support functions // #ifdef ICU static char *FPX_Unicode_CodePageToUTF8(const char *buffer, int code_page) // buffer = null termined input string, encoded using specified code page // code_page = windows codepage id // return value = null terminated, UTF8 encoded string. Use FPI_Mem_Alloc to allocate string. String will be freed by caller. { UErrorCode err = U_UNSUPPORTED_ERROR; UConverter *codepage_conv = 0; UConverter *utf8_conv = 0; UChar *temp_buf = 0; int32_t temp_buf_len = 0; int32_t temp_len = 0; char *utf8_buf = 0; int32_t utf8_buf_len = 0; int32_t utf8_len = 0; char code_page_str[16]; snprintf(code_page_str,16,"cp%d",code_page); code_page_str[15] = 0; if ( ( codepage_conv = ucnv_open(code_page_str,&err) ) == 0 ) { if ( ( codepage_conv = ucnv_open(0,&err) ) == 0 ) { goto fail; } } if ( ( utf8_conv = ucnv_open("utf8",&err) ) == 0 ) { goto fail; } temp_buf_len = sizeof(UChar)*strlen(buffer)*2; temp_buf = (UChar *)FPI_Mem_Alloc(temp_buf_len); temp_len = ucnv_toUChars(codepage_conv, temp_buf, temp_buf_len, buffer, strlen(buffer), &err); if ( temp_len > 0 ) { utf8_buf_len = UCNV_GET_MAX_BYTES_FOR_STRING(temp_len, ucnv_getMaxCharSize(utf8_conv)); utf8_buf = (char *)FPI_Mem_Alloc(utf8_buf_len); utf8_len = ucnv_fromUChars(utf8_conv, utf8_buf, utf8_buf_len, temp_buf, temp_len, &err); if ( utf8_len <= 0 ) { FPI_Mem_Free(utf8_buf); utf8_buf = 0; } } FPI_Mem_Free(temp_buf); fail: if ( codepage_conv ) { ucnv_close(codepage_conv); } if ( utf8_conv ) { ucnv_close(utf8_conv); } return utf8_buf; } static char *FPX_Unicode_UTF8ToCodePage(const char *buffer, int code_page) // buffer = null terminated input string, encoded using UTF8 // code_page = windows codepage id // return value = null terminated string encoded using specified code page. Use FPI_Mem_Alloc to allocate string. String will be freed by caller. { UErrorCode err = U_UNSUPPORTED_ERROR; UConverter *codepage_conv = 0; UConverter *utf8_conv = 0; UChar *temp_buf = 0; int32_t temp_buf_len = 0; int32_t temp_len = 0; char *codepage_buf = 0; int32_t codepage_buf_len = 0; int32_t codepage_len = 0; char code_page_str[16]; snprintf(code_page_str,16,"cp%d",code_page); code_page_str[15] = 0; if ( ( codepage_conv = ucnv_open(code_page_str,&err) ) == 0 ) { if ( ( codepage_conv = ucnv_open(0,&err) ) == 0 ) { goto fail; } } if ( ( utf8_conv = ucnv_open("utf8",&err) ) == 0 ) { goto fail; } temp_buf_len = sizeof(UChar)*strlen(buffer)*2; temp_buf = (UChar *)FPI_Mem_Alloc(temp_buf_len); temp_len = ucnv_toUChars(utf8_conv, temp_buf, temp_buf_len, buffer, strlen(buffer), &err); if ( temp_len > 0 ) { codepage_buf_len = UCNV_GET_MAX_BYTES_FOR_STRING(temp_len, ucnv_getMaxCharSize(codepage_conv)); codepage_buf = (char *)FPI_Mem_Alloc(codepage_buf_len); codepage_len = ucnv_fromUChars(codepage_conv, codepage_buf, codepage_buf_len, temp_buf, temp_len, &err); if ( codepage_len <= 0 ) { FPI_Mem_Free(codepage_buf); codepage_buf = 0; } } FPI_Mem_Free(temp_buf); fail: if ( codepage_conv ) { ucnv_close(codepage_conv); } if ( utf8_conv ) { ucnv_close(utf8_conv); } return codepage_buf; } #endif // ICU // // Sound support functions // #ifdef ALSA struct ALSA_SoundOutput_Instance { snd_pcm_t * handle; int signal; snd_async_handler_t * async_handler; sem_t semaphore; pthread_t thread; char * buffer; snd_pcm_sframes_t buffer_size; snd_pcm_sframes_t period_size; }; static int alsa_error(void *ptr, int error) { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr; switch( error ) { case -EBADFD: return 0; case -EAGAIN: return 0; case -EPIPE: if ( snd_pcm_prepare(instance->handle) < 0) { return -1; } return 0; case -ESTRPIPE: if ( snd_pcm_resume(instance->handle) < 0) { return -1; } return 0; default: return -1; } } static void *alsa_thread(void *ptr) { struct ALSA_SoundOutput_Instance *instance = ptr; int result = 0; int err = 0; int state = 0; for( ; ; ) { snd_pcm_sframes_t avail; err = sem_wait(&instance->semaphore); if ( instance->signal ) { break; } if ( err < 0 ) { usleep(1); continue; } do { state = snd_pcm_state(instance->handle); if(state != SND_PCM_STATE_RUNNING && state != SND_PCM_STATE_PREPARED) { snd_pcm_prepare(instance->handle); break; } FPI_SoundOutput_FillBuffer(ptr, instance->buffer, snd_pcm_frames_to_bytes(instance->handle, instance->period_size)); result = snd_pcm_writei(instance->handle, instance->buffer, instance->period_size); if(result < 0) { alsa_error(ptr, result); } avail = snd_pcm_avail_update(instance->handle); if(avail < 0) { if(alsa_error(ptr, avail) >= 0) { avail = snd_pcm_avail_update(instance->handle); } } } while(avail >= instance->period_size); } return NULL; } static void alsa_callback(snd_async_handler_t *ahandler) { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)snd_async_handler_get_callback_private(ahandler); // signal mixer thread sem_post(&instance->semaphore); } static void *ALSA_FPX_SoundOutput_Open() // return = instance pointer { struct ALSA_SoundOutput_Instance *instance = 0; snd_pcm_hw_params_t *hwparams = 0; snd_pcm_sw_params_t *swparams = 0; snd_pcm_format_t pcm_format; unsigned int buffer_time = 500000; unsigned int period_time = 20000; unsigned int actual_rate; snd_pcm_uframes_t size; int direction; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; instance = FPI_Mem_Alloc(sizeof(struct ALSA_SoundOutput_Instance)); memset(instance,0,sizeof(struct ALSA_SoundOutput_Instance)); if ( ( snd_pcm_open(&instance->handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) { if ( ( snd_pcm_open(&instance->handle, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) { goto fail; } } snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); if (snd_pcm_hw_params_any(instance->handle, hwparams) < 0) goto fail; if (snd_pcm_hw_params_set_access(instance->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) goto fail; pcm_format = SND_PCM_FORMAT_S16_LE; if (snd_pcm_hw_params_set_format(instance->handle, hwparams, pcm_format) < 0) goto fail; if (snd_pcm_hw_params_set_channels(instance->handle, hwparams, 2) < 0) goto fail; actual_rate = 44100; if (snd_pcm_hw_params_set_rate_near(instance->handle, hwparams, &actual_rate, 0) < 0) goto fail; if (actual_rate != 44100) goto fail; if (snd_pcm_hw_params_set_buffer_time_near(instance->handle, hwparams, &buffer_time, &direction) < 0) goto fail; if (snd_pcm_hw_params_get_buffer_size(hwparams, &size) < 0) goto fail; instance->buffer_size = (snd_pcm_sframes_t)size; if (snd_pcm_hw_params_set_period_time_near(instance->handle, hwparams, &period_time, &direction) < 0) goto fail; if (snd_pcm_hw_params_get_period_size(hwparams, &size, &direction) < 0) goto fail; instance->period_size = (snd_pcm_sframes_t)size; if (snd_pcm_hw_params(instance->handle, hwparams) < 0) goto fail; if (snd_pcm_sw_params_current(instance->handle, swparams) < 0) goto fail; if (snd_pcm_sw_params_set_start_threshold(instance->handle, swparams, ((instance->buffer_size-1) / instance->period_size) * instance->period_size) < 0) goto fail; if (snd_pcm_sw_params_set_stop_threshold(instance->handle, swparams, ~0U) < 0) goto fail; if (snd_pcm_sw_params_set_avail_min(instance->handle, swparams, instance->period_size) < 0) goto fail; if (snd_pcm_sw_params_set_xfer_align(instance->handle, swparams, 1) < 0) goto fail; if (snd_pcm_sw_params(instance->handle, swparams) < 0) goto fail; if (sem_init(&instance->semaphore, 0, 0) < 0) goto fail; if (snd_async_add_pcm_handler(&instance->async_handler, instance->handle, &alsa_callback, instance) < 0) goto fail; if ( ( instance->buffer = FPI_Mem_Alloc(instance->buffer_size * 2 * 2 * 2) ) == 0 ) goto fail; if ( pthread_create(&instance->thread, 0, alsa_thread, instance) < 0 ) goto fail; sem_post(&instance->semaphore); return instance; fail: if ( instance ) { if ( instance->handle ) { snd_pcm_close(instance->handle); } if ( instance->buffer ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int ALSA_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr; if ( instance->handle ) { instance->signal = 1; sem_post(&instance->semaphore); pthread_join(instance->thread, NULL); snd_pcm_drop(instance->handle); snd_pcm_close(instance->handle); sem_destroy(&instance->semaphore); } if ( instance->buffer ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } static int ALSA_FPX_SoundOutput_Latency(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr; if ( instance->handle ) { snd_pcm_sframes_t delay = 0; snd_pcm_delay(instance->handle, &delay); if ( snd_pcm_state(instance->handle) == SND_PCM_STATE_RUNNING && delay > 0 ) { return delay; } else { return 0; } } return -1; } #endif #if defined(OSS) struct OSS_SoundOutput_Instance { int oss_fd; pthread_t thread; int signal; }; static void *oss_thread(void *ptr) { struct OSS_SoundOutput_Instance *instance = (struct OSS_SoundOutput_Instance *)ptr; char buffer[4096]; int len = 0; int written = 0; for(;;) { FPI_SoundOutput_FillBuffer(ptr,buffer,4096); len = 4096; while ( len ) { written = write(instance->oss_fd, buffer, len); if ( written >= 0 ) { len -= written; } if ( instance->signal ) { pthread_exit(0); } if ( written < 0 ) { usleep(100); } } } } static void *OSS_FPX_SoundOutput_Open() // return = instance pointer { struct OSS_SoundOutput_Instance *instance = 0; int format = AFMT_S16_LE; int stereo = 1; int speed = 44100; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; instance = (struct OSS_SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct OSS_SoundOutput_Instance)); memset(instance,0,sizeof(struct OSS_SoundOutput_Instance)); if ( ( instance->oss_fd = open("/dev/dsp",O_WRONLY) ) < 0 ) goto fail; if ( ioctl(instance->oss_fd, SNDCTL_DSP_SETFMT, &format) < 0 ) goto fail; if ( ioctl(instance->oss_fd, SNDCTL_DSP_STEREO, &stereo) < 0 ) goto fail; if ( ioctl(instance->oss_fd, SNDCTL_DSP_SPEED, &speed) < 0 ) goto fail; if ( pthread_create(&instance->thread, 0, oss_thread, instance) < 0 ) goto fail; return instance; fail: if ( instance ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int OSS_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct OSS_SoundOutput_Instance *instance = (struct OSS_SoundOutput_Instance *)ptr; void *retVal = 0; instance->signal = 1; if ( instance->oss_fd ) { ioctl(instance->oss_fd, SNDCTL_DSP_RESET, 0); } if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->oss_fd ) { close(instance->oss_fd); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } static int OSS_FPX_SoundOutput_Latency(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct OSS_SoundOutput_Instance *instance = (struct OSS_SoundOutput_Instance *)ptr; if ( instance->oss_fd ) { int value = 0; if ( ioctl(instance->oss_fd,SNDCTL_DSP_GETODELAY,&value) == 0 ) { return value / 4; } return 0; } return -1; } #endif #if defined(ESD) struct ESD_SoundOutput_Instance { int esd_sock; pthread_t thread; int signal; }; static void *esd_thread(void *ptr) { struct ESD_SoundOutput_Instance *instance = (struct ESD_SoundOutput_Instance *)ptr; char buffer[4096]; int len = 0; int written = 0; for(;;) { FPI_SoundOutput_FillBuffer(ptr,buffer,4096); len = 4096; while ( len ) { written = write(instance->esd_sock, buffer, len); if ( written >= 0 ) { len -= written; } if ( instance->signal ) { pthread_exit(0); } if ( written < 0 ) { usleep(100); } } } } static void *ESD_FPX_SoundOutput_Open() // return = instance pointer { struct ESD_SoundOutput_Instance *instance = 0; int rate = ESD_DEFAULT_RATE; int bits = ESD_BITS16, channels = ESD_STEREO; int mode = ESD_STREAM, func = ESD_PLAY ; esd_format_t format = 0; char *host = NULL; char *name = NULL; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; format = bits | channels | mode | func; instance = (struct ESD_SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct ESD_SoundOutput_Instance)); memset(instance,0,sizeof(struct ESD_SoundOutput_Instance)); 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; return instance; fail: if ( instance ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int ESD_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct ESD_SoundOutput_Instance *instance = (struct ESD_SoundOutput_Instance *)ptr; void *retVal = 0; instance->signal = 1; if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->esd_sock ) { close(instance->esd_sock); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } 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; if ( instance->esd_sock ) { return (esd_get_latency(instance->esd_sock)); } */ return -1; } #endif #if defined(PULSEAUDIO) struct PULSE_SoundOutput_Instance { pa_simple *pa_sock; pthread_t thread; int signal; }; static void *pa_thread(void *ptr) { struct PULSE_SoundOutput_Instance *instance = (struct PULSE_SoundOutput_Instance *)ptr; char buffer[4096]; size_t len = 0; int error; for(;;) { FPI_SoundOutput_FillBuffer(ptr,buffer,4096); len = 4096; if (FPX_pa_simple_write(instance->pa_sock, buffer, len, &error) < 0) { if(audiodebug) fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", FPX_pa_strerror(error)); usleep(100); } if ( instance->signal ) { pthread_exit(0); } } } static void *PULSEAUDIO_FPX_SoundOutput_Open() // return = instance pointer { struct PULSE_SoundOutput_Instance *instance = 0; int error; if(audiodebug) fprintf( stderr, "Called FPX_SoundOutput_Open\n"); /* The Sample format to use */ static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2 }; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; instance = (struct PULSE_SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct PULSE_SoundOutput_Instance)); memset(instance,0,sizeof(struct PULSE_SoundOutput_Instance)); if ( ( instance->pa_sock = FPX_pa_simple_new(NULL, "flashplayer", PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error)) <= 0 ) goto fail; if(audiodebug) fprintf( stderr, "Opened Pulse\n"); if ( pthread_create(&instance->thread, 0, pa_thread, instance) < 0 ) goto fail; return instance; fail: if(audiodebug) fprintf( stderr, "FAILED TO OPEN PULSEAUDIO!\n"); if ( instance ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int PULSEAUDIO_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct PULSE_SoundOutput_Instance *instance = (struct PULSE_SoundOutput_Instance *)ptr; void *retVal = 0; int error; instance->signal = 1; if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->pa_sock ) { FPX_pa_simple_drain(instance->pa_sock, &error); FPX_pa_simple_free(instance->pa_sock); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } 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; int error; struct PULSE_SoundOutput_Instance *instance = (struct PULSE_SoundOutput_Instance *)ptr; if ( instance->pa_sock ) { latencytime = FPX_pa_simple_get_latency(instance->pa_sock, &error); } if(pulsedebug) fprintf(stderr, "\nLatency: %0.0f usec \n", (float)latencytime); /* Max bytes in one second: 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) */ latencysamples= 44100 * latencytime / 1000000; latency=(int)latencysamples; if(pulsedebug) fprintf(stderr, "\nLatency: %d samples\n", latency); return latency; return -1; } #endif // defined(ALSA/OSS/ESD/PULSEAUDIO) #ifdef V4L1 struct VideoOutput_Instance { int v4l_fd; pthread_t thread; int signal; char * buffer[2]; int buffercurrent; int buffersize; struct video_window window; struct video_picture picture; }; static void *v4l_thread(void *ptr) { struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr; int result; int status; for(;;) { result = read(instance->v4l_fd, instance->buffer[instance->buffercurrent], instance->buffersize); if(result > 0) { } if ( result < 0 ) { usleep(10000); } if ( instance->signal ) { status = 0; ioctl(instance->v4l_fd, VIDIOCCAPTURE, &status); pthread_exit(0); } } } static void *FPX_VideoInput_Open() { struct VideoOutput_Instance *instance = 0; if ( !FPI_Mem_Alloc ) goto fail; instance = (struct VideoOutput_Instance *)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance)); memset(instance,0,sizeof(struct VideoOutput_Instance)); if ( ( instance->v4l_fd = open("/dev/video", O_RDONLY) ) < 0 ) goto fail; if ( ioctl(instance->v4l_fd, VIDIOCGPICT, &instance->picture) < 0 ) goto fail; switch(instance->picture.palette) { case VIDEO_PALETTE_YUV420P: break; case VIDEO_PALETTE_RGB24: case VIDEO_PALETTE_YUV422P: case VIDEO_PALETTE_YUV411P: case VIDEO_PALETTE_YUV410P: case VIDEO_PALETTE_GREY: case VIDEO_PALETTE_HI240: case VIDEO_PALETTE_RGB565: case VIDEO_PALETTE_RGB32: case VIDEO_PALETTE_RGB555: case VIDEO_PALETTE_YUV422: case VIDEO_PALETTE_YUYV: case VIDEO_PALETTE_UYVY: case VIDEO_PALETTE_YUV420: case VIDEO_PALETTE_YUV411: case VIDEO_PALETTE_RAW: default: goto fail; } if( ioctl(instance->v4l_fd, VIDIOCGWIN, &instance->window) < 0 ) goto fail; instance->buffer[0] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2); instance->buffer[1] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2); if ( pthread_create(&instance->thread, 0, v4l_thread, instance) < 0 ) goto fail; return instance; fail: if ( FPI_Mem_Free ) { if ( instance->buffer[0] ) { FPI_Mem_Free(instance->buffer[0]); } if ( instance->buffer[1] ) { FPI_Mem_Free(instance->buffer[1]); } FPI_Mem_Free(instance); } return 0; } static int FPX_VideoInput_Close(void *ptr) { struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr; void *retVal = 0; instance->signal = 1; if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->v4l_fd ) { close(instance->v4l_fd); } if ( FPI_Mem_Free ) { if ( instance->buffer[0] ) { FPI_Mem_Free(instance->buffer[0]); } if ( instance->buffer[1] ) { FPI_Mem_Free(instance->buffer[1]); } FPI_Mem_Free(instance); } return 0; } static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes) { struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr; int ix, iy, ox, oy, ow, oh, dx, dy, Y, U, V, R, G, B; unsigned char *y, *u, *v; switch(instance->picture.palette) { case VIDEO_PALETTE_YUV420P: { ow = instance->window.width; oh = instance->window.height; dx = (ow<<16) / width; dy = (oh<<16) / height; y = (unsigned char *)instance->buffer[instance->buffercurrent^1]; u = y + ow * oh; v = u + ow * oh / 4; oy = 0; for ( iy = 0; iy < height; iy++ ) { ox = 0; for ( ix = 0; ix < width; ix++ ) { Y = ( 149 * ((int)(y[(oy>>16)*(ow )+(ox>>16)]) - 16) ) / 2; U = (int)(u[(oy>>17)*(ow/2)+(ox>>17)]) - 128; V = (int)(v[(oy>>17)*(ow/2)+(ox>>17)]) - 128; R = (Y + V * 102 ) / 64; G = (Y - V * 52 - U * 25 ) / 64; B = (Y + U * 129 ) / 64; R = R < 0 ? 0 : ( R > 255 ? 255 : R ); G = G < 0 ? 0 : ( G > 255 ? 255 : G ); B = B < 0 ? 0 : ( B > 255 ? 255 : B ); data[ix*3+0] = R; data[ix*3+1] = G; data[ix*3+2] = B; ox += dx; } oy += dy; data += pitch_n_bytes; } } break; default: goto fail; } instance->buffercurrent ^= 1; return 0; fail: return -1; } #endif // V4L1 libflashsupport-0.0.svn2431/Old/beta2/0000775002342100234210000000000010745654036016106 5ustar pereperelibflashsupport-0.0.svn2431/Old/beta2/flashsupport.c0000664002342100234210000013037010745654036021010 0ustar perepere/* Adobe Systems Incorporated(r) Source Code License Agreement Copyright(c) 2006 Adobe Systems Incorporated. All rights reserved. Please read this Source Code License Agreement carefully before using the source code. Adobe Systems Incorporated grants to you a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license, to reproduce, prepare derivative works of, publicly display, publicly perform, and distribute this source code and such derivative works in source or object code form without any attribution requirements. The name "Adobe Systems Incorporated" must not be used to endorse or promote products derived from the source code without prior written permission. You agree to indemnify, hold harmless and defend Adobe Systems Incorporated from and against any loss, damage, claims or lawsuits, including attorney's fees that arise or result from your use or distribution of the source code. THIS SOURCE CODE IS PROVIDED "AS IS" AND "WITH ALL FAULTS", WITHOUT ANY TECHNICAL SUPPORT OR ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ALSO, THERE IS NO WARRANTY OF NON-INFRINGEMENT, TITLE OR QUIET ENJOYMENT. IN NO EVENT SHALL MACROMEDIA OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOURCE CODE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The Sound detection routines, ESD and PulseAudio backends have been writen by Jean-Michel Dault cc -shared -O2 -Wall -Werror -lssl flashsupport.c -o libflashsupport.so // > ldd libflashplayer.so // > sudo cp libflashplayer.so /usr/lib // // Make sure that 'ldd' can resolve all dynamic libraries. Otherwise the Flash Player // will silently fail to load and use libflashsupport.so. // //////////////////////////////////////////////////////////////////////////////////////////////////// // // SHARED SECTION, DO NOT CHANGE! // #ifdef cplusplus extern "C" { #endif // cplusplus // // Imported functions // 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) 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) struct FPI_Functions { int fpi_count; void *fpi_mem_alloc; // 1 void *fpi_mem_free; // 2 void *fpi_soundoutput_fillbuffer; // 3 }; // // Exported functions // void *FPX_Init(void *ptr); static void FPX_Shutdown(void); #if defined(OPENSSL) || defined(GNUTLS) static void *FPX_SSLSocket_Create(int socket_fd); static int FPX_SSLSocket_Destroy(void *ptr); static int FPX_SSLSocket_Connect(void *ptr); static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes); static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes); #endif // defined(OPENSSL) || defined(GNUTLS) #if defined(ALSA) static void *ALSA_FPX_SoundOutput_Open(void); static int ALSA_FPX_SoundOutput_Close(void *ptr); static int ALSA_FPX_SoundOutput_Latency(void *ptr); #endif // defined(ALSA) #if defined(OSS) static void *OSS_FPX_SoundOutput_Open(void); static int OSS_FPX_SoundOutput_Close(void *ptr); static int OSS_FPX_SoundOutput_Latency(void *ptr); #endif // defined(OSS) #if defined(ESD) static void *ESD_FPX_SoundOutput_Open(void); static int ESD_FPX_SoundOutput_Close(void *ptr); static int ESD_FPX_SoundOutput_Latency(void *ptr); #endif // defined(ESD) #if defined(PULSEAUDIO) static void *PULSEAUDIO_FPX_SoundOutput_Open(void); static int PULSEAUDIO_FPX_SoundOutput_Close(void *ptr); static int PULSEAUDIO_FPX_SoundOutput_Latency(void *ptr); #endif // defined(PULSEAUDIO) #ifdef V4L1 static void *FPX_VideoInput_Open(); static int FPX_VideoInput_Close(void *ptr); static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes); #endif // V4L1 struct FPX_Functions { int fpx_count; void *fpx_shutdown; // 1 void *fpx_sslsocket_create; // 2 void *fpx_sslsocket_destroy; // 3 void *fpx_sslsocket_connect; // 4 void *fpx_sslsocket_receive; // 5 void *fpx_sslsocket_send; // 6 void *fpx_soundoutput_open; // 7 void *fpx_soundoutput_close; // 8 void *fpx_soundoutput_latency; // 9 void *fpx_videoinput_open; // 10 void *fpx_videoinput_close; // 11 void *fpx_videoinput_getframe; // 12 }; #ifdef cplusplus }; #endif // cplusplus // // END OF SHARED SECTION // //////////////////////////////////////////////////////////////////////////////////////////////////// #include #ifdef OPENSSL #include #elif defined(GNUTLS) #include #include #include #include #include #endif // GNUTLS #ifdef ALSA #include #include #include #endif #if defined(OSS) #include #include #include #include #include #endif #if defined(ESD) #include #include #include #include #include #endif #if defined(PULSEAUDIO) #include #include #include #include #endif #ifdef V4L1 #include #include #include #include #include #endif // V4L1 //Includes for output driver detection #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) #include //getenv #include //stat #include //stat #include //stat #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) 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) static T_FPI_SoundOutput_FillBuffer FPI_SoundOutput_FillBuffer = 0; #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) /* 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. Supports full audio/video synchronization, even over the network. - Esound is second, since it's by default in many distributions, and supports oss. NOTE: audio and video are not synchronized, since the latency functions can hang the browser. - Arts (TODO) is next. It's not currently supported because it's being phased out. Besides, it can use Esound as a backend - NASD: Not supported for the moment, there is not much information available... - Jack (TODO). When it's done, it should go after Pulse, but before ALSA. - ALSA: default if it's supported - Finally, if nothing else, fallback on oss */ #define AUDIO_PULSE 128 #define AUDIO_ESD 64 #define AUDIO_ALSA 2 #define AUDIO_OSS 1 //ESD functions int (*FPX_esd_play_stream_fallback)( esd_format_t format, int rate, const char *host, const char *name ); //PULSE functions pa_simple* (*FPX_pa_simple_new) (const char *server,const char *name, pa_stream_direction_t dir,const char *dev,const char *stream_name, const pa_sample_spec *ss,const pa_channel_map *map, const pa_buffer_attr *attr,int *error); void (*FPX_pa_simple_free) (pa_simple *s); int (*FPX_pa_simple_write) (pa_simple *s, const void*data, size_t length, int *error); int (*FPX_pa_simple_drain) (pa_simple *s, int *error); int (*FPX_pa_simple_read) (pa_simple *s, void*data, size_t length, int *error); pa_usec_t (*FPX_pa_simple_get_latency) (pa_simple *s, int *error); int (*FPX_pa_simple_flush) (pa_simple *s, int *error); const char* (*FPX_pa_strerror) (int error); static int audiotype=2; static int audiodrivers=0; static int audiodebug=0; static int pulsedebug=0; void FPX_SoundOutput_Detect() { char tmpstr[1024]=""; char *tmpenv; struct stat buf; void *handle; char *error; if((tmpenv=getenv("FLASH_AUDIODEBUG"))!=NULL) { audiodebug=1; } if((tmpenv=getenv("FLASH_PULSEDEBUG"))!=NULL) { pulsedebug=1; } if(audiodebug) { fprintf( stderr,"Flash sound output detection routine.\n"); fprintf( stderr,"(c) 2006 Revolution Linux inc,\n"); fprintf( stderr,"Jean-Michel Dault \n"); } #if defined(PULSEAUDIO) //Check if PULSE AUDIO is running if((tmpenv=getenv("USER"))!=NULL) { strcpy(tmpstr,"/tmp/pulse-"); strcat(tmpstr,tmpenv); strcat(tmpstr,"/native"); if(!stat(tmpstr,&buf)) { if(audiodebug) fprintf( stderr, "PulseAudio socket found\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } } //Check if PULSE AUDIO is running system-wide strcpy(tmpstr,"/var/lib/run/pulse/native"); if(!stat(tmpstr,&buf)) { if(audiodebug) fprintf( stderr, "PulseAudio system-wide found\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } //Pulse over network if((tmpenv=getenv("PULSE_SERVER"))!=NULL) { if(audiodebug) fprintf( stderr, "PulseAudio SERVER variable present\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } //Pulse autospawn daemon if((tmpenv=getenv("PULSE_BINARY"))!=NULL) { if(audiodebug) fprintf( stderr, "PulseAudio BINARY variable present\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } #endif #if defined(ESD) //Check if ESD is running if(!stat("/tmp/.esd/socket",&buf)) { if(audiodebug) fprintf( stderr, "ESD socket found\n"); audiodrivers = audiodrivers | AUDIO_ESD; } //ESD over network if((tmpenv=getenv("ESPEAKER"))!=NULL) { if(audiodebug) fprintf( stderr, "ESD variable ESPEAKER found\n"); audiodrivers = audiodrivers | AUDIO_ESD; } #endif #if defined(ALSA) || defined(ALSA_INTERNAL) //Check for ALSA device if(!stat("/proc/asound",&buf)) { if(audiodebug) fprintf( stderr, "ALSA device detected\n"); audiodrivers = audiodrivers | AUDIO_ALSA; } #endif #if defined(OSS) //Check for OSS device if(!stat("/dev/dsp",&buf)) { if(audiodebug) fprintf( stderr, "OSS device present\n"); audiodrivers = audiodrivers | AUDIO_OSS; } #endif if((tmpenv=getenv("FLASH_FORCE_PULSEAUDIO"))!=NULL) { #if defined(PULSEAUDIO) if(audiodebug) fprintf( stderr, "Forcing PulseAudio\n"); audiodrivers = AUDIO_PULSE; #else 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"); audiodrivers = AUDIO_ESD; #else if(audiodebug) fprintf( stderr, "ESD 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"); audiodrivers = AUDIO_ALSA; #else 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"); audiodrivers = AUDIO_OSS; #else if(audiodebug) fprintf( stderr, "OSS unavailable: please recompile libflashsupport.so!\n"); #endif } //Check for required libraries and functions #if defined(PULSEAUDIO) if((audiodrivers & AUDIO_PULSE) && !FPX_pa_simple_new) { handle = dlopen("/usr/lib/libpulse-simple.so.0", RTLD_LAZY); if (!handle) { if(audiodebug) fprintf(stderr,"Can't load /usr/lib/libpulse-simple.so.0: %s\n",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); } } #endif #if defined(ESD) if((audiodrivers & AUDIO_ESD) && !FPX_esd_play_stream_fallback) { handle = dlopen("/usr/lib/libesd.so.0", RTLD_LAZY); if (!handle) { if(audiodebug) fprintf(stderr,"Can't load /usr/lib/libesd.so.0: %s\n",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); } } #endif return; } static void *FPX_SoundOutput_Open(void) { void *ptr; if(audiodebug) fprintf( stderr,"audiodrivers=%d\n",audiodrivers); #if defined(PULSEAUDIO) if(audiodrivers & AUDIO_PULSE) { if(audiodebug) fprintf( stderr,"Trying PULSE\n"); ptr=PULSEAUDIO_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_PULSE; if(audiodebug) fprintf( stderr, "Using PulseAudio driver\n"); return ptr; } } #endif #if defined(ESD) if(audiodrivers & AUDIO_ESD) { if(audiodebug) fprintf( stderr,"Trying ESD\n"); ptr=ESD_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_ESD; if(audiodebug) fprintf( stderr, "Using Esound audio driver\n"); return ptr; } } #endif #if defined(ALSA_INTERNAL) if(audiodrivers & AUDIO_ALSA) { 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"); ptr=ALSA_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_ALSA; if(audiodebug) fprintf( stderr, "Using ALSA audio driver\n"); return ptr; } } #endif #if defined(OSS) if(audiodrivers & AUDIO_OSS) { if(audiodebug) fprintf( stderr,"Trying OSS\n"); ptr=OSS_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_OSS; if(audiodebug) fprintf( stderr, "Using OSS audio driver\n"); return ptr; } } #endif // No sound... if(audiodebug) fprintf( stderr, "NO SOUND DRIVER! Revert to internal ALSA driver!\n"); return 0; } static int FPX_SoundOutput_Close(void *ptr) { int retcode; #if defined(PULSEAUDIO) if(audiotype == AUDIO_PULSE) { retcode=PULSEAUDIO_FPX_SoundOutput_Close(ptr); return retcode; } #endif #if defined(ESD) if(audiotype == AUDIO_ESD) { retcode=ESD_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(audiotype == AUDIO_OSS) { retcode=OSS_FPX_SoundOutput_Close(ptr); return retcode; } #endif return 0; } static int FPX_SoundOutput_Latency(void *ptr) { int retcode; #if defined(PULSEAUDIO) if(audiotype == AUDIO_PULSE) { retcode=PULSEAUDIO_FPX_SoundOutput_Latency(ptr); return retcode; } #endif #if defined(ESD) if(audiotype == AUDIO_ESD) { retcode=ESD_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(audiotype == AUDIO_OSS) { retcode=OSS_FPX_SoundOutput_Latency(ptr); return retcode; } #endif return 0; } #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) void *FPX_Init(void *ptr) { #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) FPX_SoundOutput_Detect(); #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) if ( !ptr ) return 0; // // Setup imported functions // struct FPI_Functions *fpi_functions = (struct FPI_Functions *)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 ( fpi_functions->fpi_count >= 3 ) FPI_SoundOutput_FillBuffer= fpi_functions->fpi_soundoutput_fillbuffer; // 3 #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) // // Setup exported functions // memset(&fpx_functions, 0, sizeof(fpx_functions)); fpx_functions.fpx_shutdown = FPX_Shutdown; // 1 #if defined(OPENSSL) || defined(GNUTLS) fpx_functions.fpx_sslsocket_create = FPX_SSLSocket_Create; // 2 fpx_functions.fpx_sslsocket_destroy = FPX_SSLSocket_Destroy; // 3 fpx_functions.fpx_sslsocket_connect = FPX_SSLSocket_Connect; // 4 fpx_functions.fpx_sslsocket_receive = FPX_SSLSocket_Receive; // 5 fpx_functions.fpx_sslsocket_send = FPX_SSLSocket_Send; // 6 #endif // defined(OPENSSL) || defined(GNUTLS) #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) 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) #ifdef V4L1 fpx_functions.fpx_videoinput_open = FPX_VideoInput_Open; // 10 fpx_functions.fpx_videoinput_close = FPX_VideoInput_Close; // 11 fpx_functions.fpx_videoinput_getframe = FPX_VideoInput_GetFrame; // 12 #endif // V4L1 fpx_functions.fpx_count = 14; #ifdef OPENSSL SSL_library_init(); #elif defined(GNUTLS) gnutls_global_init(); #endif // GNUTLS return (void *)&fpx_functions; } static void FPX_Shutdown() { #ifdef OPENSSL #elif defined(GNUTLS) gnutls_global_deinit(); #endif // GNUTLS } // // SSL support functions // #ifdef OPENSSL struct SSL_Instance { SSL *ssl; SSL_CTX *sslCtx; }; static void *FPX_SSLSocket_Create(int socket_fd) // return = instance pointer { struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance)); memset(instance,0,sizeof(struct SSL_Instance)); fprintf(stderr,"AAAAAAAAAA\n"); if ( ( instance->sslCtx = SSL_CTX_new( TLSv1_client_method() ) ) == 0 ) goto fail; if ( ( instance->ssl = SSL_new(instance->sslCtx) ) == 0 ) goto fail; if ( SSL_set_fd(instance->ssl, socket_fd) < 0 ) goto fail; return (void *)instance; fail: if ( instance->ssl ) { SSL_shutdown(instance->ssl); } if ( instance->sslCtx ) { SSL_CTX_free(instance->sslCtx); } if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Destroy(void *ptr) // ptr = instance pointer // return = 0 on sucess, < 0 on error { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; if ( instance->ssl ) { SSL_shutdown(instance->ssl); } if ( instance->sslCtx ) { SSL_CTX_free(instance->sslCtx); } if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Connect(void *ptr) // ptr = instance pointer // socket_fd = BSD socket fd to be associated with SSL connection // return = 0 on sucess, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return SSL_connect(instance->ssl); } static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to place received data into // n_bytes = length of buffer in bytes // return = actual bytes received, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return SSL_read(instance->ssl, buffer, n_bytes); } static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to be sent // n_bytes = length of input buffer in bytes // return = actual bytes sent, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return SSL_write(instance->ssl, buffer, n_bytes); } #elif defined(GNUTLS) struct SSL_Instance { gnutls_session_t session; gnutls_anon_client_credentials_t anoncred; }; static void *FPX_SSLSocket_Create(int socket_fd) // return = instance pointer { const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 }; struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance)); memset(instance,0,sizeof(struct SSL_Instance)); if ( gnutls_anon_allocate_client_credentials(&instance->anoncred) < 0 ) goto fail; if ( gnutls_init(&instance->session, GNUTLS_CLIENT) < 0 ) goto fail; if ( gnutls_set_default_priority(instance->session) < 0 ) goto fail; if ( gnutls_kx_set_priority(instance->session, kx_prio) < 0 ) goto fail; if ( gnutls_credentials_set(instance->session, GNUTLS_CRD_ANON, instance->anoncred) < 0 ) goto fail; gnutls_transport_set_ptr(instance->session, (gnutls_transport_ptr_t)socket_fd); return (void *)instance; fail: if ( instance->session ) { gnutls_deinit(instance->session); } if ( instance->anoncred ) { gnutls_anon_free_client_credentials(instance->anoncred); } if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Destroy(void *ptr) // ptr = instance pointer // return = 0 on sucess, < 0 on error { struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance)); gnutls_bye(instance->session, GNUTLS_SHUT_RDWR); gnutls_deinit(instance->session); gnutls_anon_free_client_credentials(instance->anoncred); if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Connect(void *ptr) // ptr = instance pointer // socket_fd = BSD socket fd to be associated with SSL connection // return = 0 on sucess, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return gnutls_handshake(instance->session); } static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to place received data into // n_bytes = length of buffer in bytes // return = actual bytes received, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return gnutls_record_recv(instance->session, buffer, n_bytes); } static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to be sent // n_bytes = length of input buffer in bytes // return = actual bytes sent, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return gnutls_record_send(instance->session, buffer, n_bytes); } #endif // GNUTLS // // Sound support functions // #ifdef ALSA struct ALSA_SoundOutput_Instance { snd_pcm_t * handle; snd_async_handler_t * async_handler; sem_t semaphore; pthread_t thread; char * buffer; snd_pcm_sframes_t buffer_size; snd_pcm_sframes_t period_size; snd_pcm_sframes_t buffer_pos; char * buffer_ptr; }; static void *alsa_thread(void *ptr) { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr; snd_pcm_sframes_t avail = 0; int result = 0; int err = 0; int state = 0; for( ; ; ) { err = sem_wait(&instance->semaphore); if ( !instance->handle ) { pthread_exit(0); return 0; if ( err < 0 ) { usleep(1); continue; } do { if ( instance->buffer_pos <= 0 ) { FPI_SoundOutput_FillBuffer(ptr, instance->buffer, snd_pcm_frames_to_bytes(instance->handle, instance->period_size)); instance->buffer_pos = instance->period_size; instance->buffer_ptr = instance->buffer; } do { state = snd_pcm_state(instance->handle); if(state != SND_PCM_STATE_RUNNING && state != SND_PCM_STATE_PREPARED) { snd_pcm_prepare(instance->handle); } result = snd_pcm_writei(instance->handle, instance->buffer_ptr, instance->buffer_pos); if( result <= 0 ) { switch( result ) { case -EPIPE: { snd_pcm_prepare(instance->handle); } break; case -ESTRPIPE: { err = snd_pcm_resume(instance->handle); if ( err < 0 ) { snd_pcm_prepare(instance->handle); } } break; } break; } else { instance->buffer_pos -= result; instance->buffer_ptr += snd_pcm_frames_to_bytes(instance->handle, result); } } while (instance->buffer_pos); avail = snd_pcm_avail_update(instance->handle); if( avail < 0 ) { switch( avail ) { case -EPIPE: { snd_pcm_prepare(instance->handle); } break; case -ESTRPIPE: { err = snd_pcm_resume(instance->handle); if ( err < 0 ) { snd_pcm_prepare(instance->handle); } } break; } break; } } while(avail >= instance->period_size); } } static void alsa_callback(snd_async_handler_t *ahandler) { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)snd_async_handler_get_callback_private(ahandler); // signal mixer thread sem_post(&instance->semaphore); } static void *ALSA_FPX_SoundOutput_Open() // return = instance pointer { struct ALSA_SoundOutput_Instance *instance = 0; snd_pcm_hw_params_t *hwparams = 0; snd_pcm_sw_params_t *swparams = 0; snd_pcm_format_t pcm_format; unsigned int buffer_time = 500000; unsigned int period_time = 20000; unsigned int actual_rate; snd_pcm_uframes_t size; int direction; void *retVal = 0; int err = 0; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; instance = FPI_Mem_Alloc(sizeof(struct ALSA_SoundOutput_Instance)); memset(instance,0,sizeof(struct ALSA_SoundOutput_Instance)); if ( ( err = snd_pcm_open(&instance->handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) { if ( ( err = snd_pcm_open(&instance->handle, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) { goto fail; } } snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); if (snd_pcm_hw_params_any(instance->handle, hwparams) < 0) goto fail; if (snd_pcm_hw_params_set_access(instance->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) goto fail; pcm_format = SND_PCM_FORMAT_S16_LE; if (snd_pcm_hw_params_set_format(instance->handle, hwparams, pcm_format) < 0) goto fail; if (snd_pcm_hw_params_set_channels(instance->handle, hwparams, 2) < 0) goto fail; actual_rate = 44100; if (snd_pcm_hw_params_set_rate_near(instance->handle, hwparams, &actual_rate, 0) < 0) goto fail; if (actual_rate != 44100) goto fail; if (snd_pcm_hw_params_set_buffer_time_near(instance->handle, hwparams, &buffer_time, &direction) < 0) goto fail; if (snd_pcm_hw_params_get_buffer_size(hwparams, &size) < 0) goto fail; instance->buffer_size = (snd_pcm_sframes_t)size; if (snd_pcm_hw_params_set_period_time_near(instance->handle, hwparams, &period_time, &direction) < 0) goto fail; if (snd_pcm_hw_params_get_period_size(hwparams, &size, &direction) < 0) goto fail; instance->period_size = (snd_pcm_sframes_t)size; if (snd_pcm_hw_params(instance->handle, hwparams) < 0) goto fail; if (snd_pcm_sw_params_current(instance->handle, swparams) < 0) goto fail; if (snd_pcm_sw_params_set_start_threshold(instance->handle, swparams, ((instance->buffer_size-1) / instance->period_size) * instance->period_size) < 0) goto fail; if (snd_pcm_sw_params_set_stop_threshold(instance->handle, swparams, ~0U) < 0) goto fail; if (snd_pcm_sw_params_set_avail_min(instance->handle, swparams, instance->period_size) < 0) goto fail; if (snd_pcm_sw_params_set_xfer_align(instance->handle, swparams, 1) < 0) goto fail; if (snd_pcm_sw_params(instance->handle, swparams) < 0) goto fail; if (snd_async_add_pcm_handler(&instance->async_handler, instance->handle, &alsa_callback, instance) < 0) goto fail; if ( ( instance->buffer = FPI_Mem_Alloc(instance->buffer_size * 2 * 2 * 2) ) == 0 ) goto fail; if ( pthread_create(&instance->thread, 0, alsa_thread, instance) < 0 ) goto fail; sem_post(&instance->semaphore); return instance; fail: if ( instance ) { if ( instance->handle ) { snd_pcm_drop(instance->handle); snd_pcm_close(instance->handle); instance->handle = 0; } if ( instance->thread ) { sem_post(&instance->semaphore); sem_destroy(&instance->semaphore); pthread_join(instance->thread,&retVal); } if ( instance->buffer ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int ALSA_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr; void *retVal = 0; if ( instance->handle ) { snd_pcm_drop(instance->handle); snd_pcm_close(instance->handle); instance->handle = 0; } if ( instance->thread ) { sem_post(&instance->semaphore); sem_destroy(&instance->semaphore); pthread_join(instance->thread,&retVal); } if ( instance->buffer ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } static int ALSA_FPX_SoundOutput_Latency(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr; if ( instance->handle ) { snd_pcm_sframes_t delay = 0; snd_pcm_delay(instance->handle, &delay); if ( snd_pcm_state(instance->handle) == SND_PCM_STATE_RUNNING && delay > 0 ) { return delay; } else { return 0; } } return -1; } #endif #if defined(OSS) struct OSS_SoundOutput_Instance { int oss_fd; pthread_t thread; int signal; }; static void *oss_thread(void *ptr) { struct OSS_SoundOutput_Instance *instance = (struct OSS_SoundOutput_Instance *)ptr; char buffer[4096]; int len = 0; int written = 0; for(;;) { FPI_SoundOutput_FillBuffer(ptr,buffer,4096); len = 4096; while ( len ) { written = write(instance->oss_fd, buffer, len); if ( written >= 0 ) { len -= written; } if ( instance->signal ) { pthread_exit(0); } if ( written < 0 ) { usleep(100); } } } } static void *OSS_FPX_SoundOutput_Open() // return = instance pointer { struct OSS_SoundOutput_Instance *instance = 0; int format = AFMT_S16_LE; int stereo = 1; int speed = 44100; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; instance = (struct OSS_SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct OSS_SoundOutput_Instance)); memset(instance,0,sizeof(struct OSS_SoundOutput_Instance)); if ( ( instance->oss_fd = open("/dev/dsp",O_WRONLY) ) < 0 ) goto fail; if ( ioctl(instance->oss_fd, SNDCTL_DSP_SETFMT, &format) < 0 ) goto fail; if ( ioctl(instance->oss_fd, SNDCTL_DSP_STEREO, &stereo) < 0 ) goto fail; if ( ioctl(instance->oss_fd, SNDCTL_DSP_SPEED, &speed) < 0 ) goto fail; if ( pthread_create(&instance->thread, 0, oss_thread, instance) < 0 ) goto fail; return instance; fail: if ( instance ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int OSS_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct OSS_SoundOutput_Instance *instance = (struct OSS_SoundOutput_Instance *)ptr; void *retVal = 0; instance->signal = 1; if ( instance->oss_fd ) { ioctl(instance->oss_fd, SNDCTL_DSP_RESET, 0); } if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->oss_fd ) { close(instance->oss_fd); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } static int OSS_FPX_SoundOutput_Latency(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct OSS_SoundOutput_Instance *instance = (struct OSS_SoundOutput_Instance *)ptr; if ( instance->oss_fd ) { int value = 0; if ( ( value = ioctl(instance->oss_fd,SNDCTL_DSP_GETODELAY,&value) ) == 0 ) { return value / 4; } return 0; } return -1; } #endif #if defined(ESD) struct ESD_SoundOutput_Instance { int esd_sock; pthread_t thread; int signal; }; static void *esd_thread(void *ptr) { struct ESD_SoundOutput_Instance *instance = (struct ESD_SoundOutput_Instance *)ptr; char buffer[4096]; int len = 0; int written = 0; for(;;) { FPI_SoundOutput_FillBuffer(ptr,buffer,4096); len = 4096; while ( len ) { written = write(instance->esd_sock, buffer, len); if ( written >= 0 ) { len -= written; } if ( instance->signal ) { pthread_exit(0); } if ( written < 0 ) { usleep(100); } } } } static void *ESD_FPX_SoundOutput_Open() // return = instance pointer { struct ESD_SoundOutput_Instance *instance = 0; int rate = ESD_DEFAULT_RATE; int bits = ESD_BITS16, channels = ESD_STEREO; int mode = ESD_STREAM, func = ESD_PLAY ; esd_format_t format = 0; char *host = NULL; char *name = NULL; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; format = bits | channels | mode | func; instance = (struct ESD_SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct ESD_SoundOutput_Instance)); memset(instance,0,sizeof(struct ESD_SoundOutput_Instance)); 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; return instance; fail: if ( instance ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int ESD_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct ESD_SoundOutput_Instance *instance = (struct ESD_SoundOutput_Instance *)ptr; void *retVal = 0; instance->signal = 1; if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->esd_sock ) { close(instance->esd_sock); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } 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; if ( instance->esd_sock ) { return (esd_get_latency(instance->esd_sock)); } */ return -1; } #endif #if defined(PULSEAUDIO) struct PULSE_SoundOutput_Instance { pa_simple *pa_sock; pthread_t thread; int signal; }; static void *pa_thread(void *ptr) { struct PULSE_SoundOutput_Instance *instance = (struct PULSE_SoundOutput_Instance *)ptr; char buffer[4096]; size_t len = 0; int error; for(;;) { FPI_SoundOutput_FillBuffer(ptr,buffer,4096); len = 4096; if (FPX_pa_simple_write(instance->pa_sock, buffer, len, &error) < 0) { if(audiodebug) fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", FPX_pa_strerror(error)); usleep(100); } if ( instance->signal ) { pthread_exit(0); } } } static void *PULSEAUDIO_FPX_SoundOutput_Open() // return = instance pointer { struct PULSE_SoundOutput_Instance *instance = 0; int error; if(audiodebug) fprintf( stderr, "Called FPX_SoundOutput_Open\n"); /* The Sample format to use */ static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2 }; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; instance = (struct PULSE_SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct PULSE_SoundOutput_Instance)); memset(instance,0,sizeof(struct PULSE_SoundOutput_Instance)); if ( ( instance->pa_sock = FPX_pa_simple_new(NULL, "flashplayer", PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error)) <= 0 ) goto fail; if(audiodebug) fprintf( stderr, "Opened Pulse\n"); if ( pthread_create(&instance->thread, 0, pa_thread, instance) < 0 ) goto fail; return instance; fail: if(audiodebug) fprintf( stderr, "FAILED TO OPEN PULSEAUDIO!\n"); if ( instance ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int PULSEAUDIO_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct PULSE_SoundOutput_Instance *instance = (struct PULSE_SoundOutput_Instance *)ptr; void *retVal = 0; int error; instance->signal = 1; if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->pa_sock ) { FPX_pa_simple_drain(instance->pa_sock, &error); FPX_pa_simple_free(instance->pa_sock); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } 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; int error; struct PULSE_SoundOutput_Instance *instance = (struct PULSE_SoundOutput_Instance *)ptr; if ( instance->pa_sock ) { latencytime = FPX_pa_simple_get_latency(instance->pa_sock, &error); } if(pulsedebug) fprintf(stderr, "\nLatency: %0.0f usec \n", (float)latencytime); /* Max bytes in one second: 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) */ latencysamples= 44100 * latencytime / 1000000; latency=(int)latencysamples; if(pulsedebug) fprintf(stderr, "\nLatency: %d samples\n", latency); return latency; return -1; } #endif // defined(ALSA/OSS/ESD/PULSEAUDIO) #ifdef V4L1 struct VideoOutput_Instance { int v4l_fd; pthread_t thread; int signal; char * buffer[2]; int buffercurrent; int buffersize; struct video_window window; struct video_picture picture; }; static void *v4l_thread(void *ptr) { struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr; int result; int status; for(;;) { result = read(instance->v4l_fd, instance->buffer[instance->buffercurrent], instance->buffersize); if(result > 0) { } if ( result < 0 ) { usleep(10000); } if ( instance->signal ) { status = 0; ioctl(instance->v4l_fd, VIDIOCCAPTURE, &status); pthread_exit(0); } } } static void *FPX_VideoInput_Open() { struct VideoOutput_Instance *instance = 0; if ( !FPI_Mem_Alloc ) goto fail; instance = (struct VideoOutput_Instance *)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance)); memset(instance,0,sizeof(struct VideoOutput_Instance)); if ( ( instance->v4l_fd = open("/dev/video", O_RDONLY) ) < 0 ) goto fail; if ( ioctl(instance->v4l_fd, VIDIOCGPICT, &instance->picture) < 0 ) goto fail; switch(instance->picture.palette) { case VIDEO_PALETTE_YUV420P: break; case VIDEO_PALETTE_RGB24: case VIDEO_PALETTE_YUV422P: case VIDEO_PALETTE_YUV411P: case VIDEO_PALETTE_YUV410P: case VIDEO_PALETTE_GREY: case VIDEO_PALETTE_HI240: case VIDEO_PALETTE_RGB565: case VIDEO_PALETTE_RGB32: case VIDEO_PALETTE_RGB555: case VIDEO_PALETTE_YUV422: case VIDEO_PALETTE_YUYV: case VIDEO_PALETTE_UYVY: case VIDEO_PALETTE_YUV420: case VIDEO_PALETTE_YUV411: case VIDEO_PALETTE_RAW: default: goto fail; } if( ioctl(instance->v4l_fd, VIDIOCGWIN, &instance->window) < 0 ) goto fail; instance->buffer[0] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2); instance->buffer[1] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2); if ( pthread_create(&instance->thread, 0, v4l_thread, instance) < 0 ) goto fail; return instance; fail: if ( FPI_Mem_Free ) { if ( instance->buffer[0] ) { FPI_Mem_Free(instance->buffer[0]); } if ( instance->buffer[1] ) { FPI_Mem_Free(instance->buffer[1]); } FPI_Mem_Free(instance); } return 0; } static int FPX_VideoInput_Close(void *ptr) { struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr; void *retVal = 0; instance->signal = 1; if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->v4l_fd ) { close(instance->v4l_fd); } if ( FPI_Mem_Free ) { if ( instance->buffer[0] ) { FPI_Mem_Free(instance->buffer[0]); } if ( instance->buffer[1] ) { FPI_Mem_Free(instance->buffer[1]); } FPI_Mem_Free(instance); } return 0; } static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes) { struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr; int ix, iy, ox, oy, ow, oh, dx, dy, Y, U, V, R, G, B; unsigned char *y, *u, *v; switch(instance->picture.palette) { case VIDEO_PALETTE_YUV420P: { ow = instance->window.width; oh = instance->window.height; dx = (ow<<16) / width; dy = (oh<<16) / height; y = (unsigned char *)instance->buffer[instance->buffercurrent^1]; u = y + ow * oh; v = u + ow * oh / 4; oy = 0; for ( iy = 0; iy < height; iy++ ) { ox = 0; for ( ix = 0; ix < width; ix++ ) { Y = ( 149 * ((int)(y[(oy>>16)*(ow )+(ox>>16)]) - 16) ) / 2; U = (int)(u[(oy>>17)*(ow/2)+(ox>>17)]) - 128; V = (int)(v[(oy>>17)*(ow/2)+(ox>>17)]) - 128; R = (Y + V * 102 ) / 64; G = (Y - V * 52 - U * 25 ) / 64; B = (Y + U * 129 ) / 64; R = R < 0 ? 0 : ( R > 255 ? 255 : R ); G = G < 0 ? 0 : ( G > 255 ? 255 : G ); B = B < 0 ? 0 : ( B > 255 ? 255 : B ); data[ix*3+0] = R; data[ix*3+1] = G; data[ix*3+2] = B; ox += dx; } oy += dy; data += pitch_n_bytes; } } break; default: goto fail; } instance->buffercurrent ^= 1; return 0; fail: return -1; } #endif // V4L1