add support for $PULSEAUDIO_SOURCES which when set in configure.ac changes the pulsea...
[libflashsupport-jack.git] / flashsupport.c
blob3477d299b63867eeecc66bb219d7f994d32f12f9
1 /*
2 Adobe Systems Incorporated(r) Source Code License Agreement
3 Copyright(c) 2006 Adobe Systems Incorporated. All rights reserved.
5 Please read this Source Code License Agreement carefully before using
6 the source code.
8 Adobe Systems Incorporated grants to you a perpetual, worldwide, non-exclusive,
9 no-charge, royalty-free, irrevocable copyright license, to reproduce,
10 prepare derivative works of, publicly display, publicly perform, and
11 distribute this source code and such derivative works in source or
12 object code form without any attribution requirements.
14 The name "Adobe Systems Incorporated" must not be used to endorse or promote products
15 derived from the source code without prior written permission.
17 You agree to indemnify, hold harmless and defend Adobe Systems Incorporated from and
18 against any loss, damage, claims or lawsuits, including attorney's
19 fees that arise or result from your use or distribution of the source
20 code.
22 THIS SOURCE CODE IS PROVIDED "AS IS" AND "WITH ALL FAULTS", WITHOUT
23 ANY TECHNICAL SUPPORT OR ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
24 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ALSO, THERE IS NO WARRANTY OF
26 NON-INFRINGEMENT, TITLE OR QUIET ENJOYMENT. IN NO EVENT SHALL MACROMEDIA
27 OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOURCE CODE, EVEN IF
33 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 ////////////////////////////////////////////////////////////////////////////////////////////////////
37 // File name: flashsupport.c
38 // Targets: Adobe Flash Player 9.1 beta 2 for Linux (9.0.21.78)
39 // Last Revision Date: 11/20/2006
42 ////////////////////////////////////////////////////////////////////////////////////////////////////
44 // These are the feature which can be turned on and off. They are all
45 // optional. The ALSA and Video4Linux support in this file is somewhat
46 // redundant and reduced in functionality as the Flash Player already has
47 // ALSA and Video4Linux support built-in. It is provided here for reference only.
48 // Also, if your system has ALSA support in the kernel there is no need to
49 // enable OSS here as it will override it.
52 #define OPENSSL
53 //#define GNUTLS
54 //#define ALSA
55 //#define OSS
56 #define V4L1
57 #define PULSEAUDIO
59 ////////////////////////////////////////////////////////////////////////////////////////////////////
61 // To compile and install flashsupport.c the following components are required:
63 // - a C compiler (gcc 4.03 is known to be working)
64 // - OpenSSL developer package and working user libraries (OpenSSL 0.9.8 is known to be working)
65 // - OSS (or ALSA) developer package and working users libraries (Linux 2.6.15 is known to be working)
66 // - sudo or root access to install the generated library to /usr/lib
68 // We suggest these steps in a terminal:
70 // > cc -shared -O2 -Wall -Werror -lssl flashsupport.c -o libflashsupport.so
71 // > ldd libflashplayer.so
72 // > sudo cp libflashplayer.so /usr/lib
74 // Make sure that 'ldd' can resolve all dynamic libraries. Otherwise the Flash Player
75 // will silently fail to load and use libflashsupport.so.
78 ////////////////////////////////////////////////////////////////////////////////////////////////////
80 // SHARED SECTION, DO NOT CHANGE!
82 #ifdef cplusplus
83 extern "C" {
84 #endif // cplusplus
87 // Imported functions
90 typedef void *(*T_FPI_Mem_Alloc)(int size); // This function is not thread safe
91 typedef void (*T_FPI_Mem_Free)(void *ptr); // This function is not thread safe
93 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO)
94 typedef void (*T_FPI_SoundOutput_FillBuffer)(void *ptr, char *buffer, int n_bytes); // This function is thread safe
95 #endif // defined(ALSA) || defined(OSS)
97 struct FPI_Functions {
98 int fpi_count;
99 void *fpi_mem_alloc; // 1
100 void *fpi_mem_free; // 2
101 void *fpi_soundoutput_fillbuffer; // 3
105 // Exported functions
108 void *FPX_Init(void *ptr);
110 static void FPX_Shutdown(void);
112 #if defined(OPENSSL) || defined(GNUTLS)
113 static void *FPX_SSLSocket_Create(int socket_fd);
114 static int FPX_SSLSocket_Destroy(void *ptr);
115 static int FPX_SSLSocket_Connect(void *ptr);
116 static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes);
117 static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes);
118 #endif // defined(OPENSSL) || defined(GNUTLS)
120 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO)
121 static void *FPX_SoundOutput_Open(void);
122 static int FPX_SoundOutput_Close(void *ptr);
123 static int FPX_SoundOutput_Latency(void *ptr);
124 #endif // defined(ALSA) || defined(OSS)
126 #ifdef V4L1
127 static void *FPX_VideoInput_Open(void);
128 static int FPX_VideoInput_Close(void *ptr);
129 static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes);
130 #endif // V4L1
132 struct FPX_Functions {
133 int fpx_count;
134 void *fpx_shutdown; // 1
135 void *fpx_sslsocket_create; // 2
136 void *fpx_sslsocket_destroy; // 3
137 void *fpx_sslsocket_connect; // 4
138 void *fpx_sslsocket_receive; // 5
139 void *fpx_sslsocket_send; // 6
140 void *fpx_soundoutput_open; // 7
141 void *fpx_soundoutput_close; // 8
142 void *fpx_soundoutput_latency; // 9
143 void *fpx_videoinput_open; // 10
144 void *fpx_videoinput_close; // 11
145 void *fpx_videoinput_getframe; // 12
148 #ifdef cplusplus
150 #endif // cplusplus
152 // END OF SHARED SECTION
154 ////////////////////////////////////////////////////////////////////////////////////////////////////
156 #include <memory.h>
158 #ifdef OPENSSL
159 #include <openssl/ssl.h>
160 #elif defined(GNUTLS)
161 #include <sys/types.h>
162 #include <sys/socket.h>
163 #include <arpa/inet.h>
164 #include <unistd.h>
165 #include <gnutls/gnutls.h>
166 #endif // GNUTLS
168 #ifdef ALSA
169 #include <pthread.h>
170 #include <semaphore.h>
171 #include <alsa/asoundlib.h>
172 #elif defined(OSS)
173 #include <unistd.h>
174 #include <pthread.h>
175 #include <linux/soundcard.h>
176 #include <sys/ioctl.h>
177 #include <fcntl.h>
178 #endif // OSS
180 #ifdef V4L1
181 #include <unistd.h>
182 #include <pthread.h>
183 #include <linux/videodev.h>
184 #include <sys/ioctl.h>
185 #include <fcntl.h>
186 #endif // V4L1
188 #ifdef PULSEAUDIO
189 #include <pulse/pulseaudio.h>
190 #endif
193 static struct FPX_Functions fpx_functions;
195 static T_FPI_Mem_Alloc FPI_Mem_Alloc = 0;
196 static T_FPI_Mem_Free FPI_Mem_Free = 0;
198 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO)
199 static T_FPI_SoundOutput_FillBuffer FPI_SoundOutput_FillBuffer = 0;
200 #endif // defined(ALSA) || defined(OSS)
202 void *FPX_Init(void *ptr)
204 if ( !ptr ) return 0;
207 // Setup imported functions
210 struct FPI_Functions *fpi_functions = (struct FPI_Functions *)ptr;
212 if ( fpi_functions->fpi_count >= 1 ) FPI_Mem_Alloc = fpi_functions->fpi_mem_alloc; // 1
213 if ( fpi_functions->fpi_count >= 2 ) FPI_Mem_Free = fpi_functions->fpi_mem_free; // 2
215 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO)
216 if ( fpi_functions->fpi_count >= 3 ) FPI_SoundOutput_FillBuffer= fpi_functions->fpi_soundoutput_fillbuffer; // 3
217 #endif // defined(ALSA) || defined(OSS)
220 // Setup exported functions
223 memset(&fpx_functions, 0, sizeof(fpx_functions));
225 fpx_functions.fpx_shutdown = FPX_Shutdown; // 1
227 #if defined(OPENSSL) || defined(GNUTLS)
228 fpx_functions.fpx_sslsocket_create = FPX_SSLSocket_Create; // 2
229 fpx_functions.fpx_sslsocket_destroy = FPX_SSLSocket_Destroy; // 3
230 fpx_functions.fpx_sslsocket_connect = FPX_SSLSocket_Connect; // 4
231 fpx_functions.fpx_sslsocket_receive = FPX_SSLSocket_Receive; // 5
232 fpx_functions.fpx_sslsocket_send = FPX_SSLSocket_Send; // 6
233 #endif // defined(OPENSSL) || defined(GNUTLS)
235 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO)
236 fpx_functions.fpx_soundoutput_open = FPX_SoundOutput_Open; // 7
237 fpx_functions.fpx_soundoutput_close = FPX_SoundOutput_Close; // 8
238 fpx_functions.fpx_soundoutput_latency = FPX_SoundOutput_Latency; // 9
239 #endif // defined(ALSA) || defined(OSS)
241 #ifdef V4L1
242 fpx_functions.fpx_videoinput_open = FPX_VideoInput_Open; // 10
243 fpx_functions.fpx_videoinput_close = FPX_VideoInput_Close; // 11
244 fpx_functions.fpx_videoinput_getframe = FPX_VideoInput_GetFrame; // 12
245 #endif // V4L1
247 fpx_functions.fpx_count = 14;
249 #ifdef OPENSSL
250 SSL_library_init();
251 #elif defined(GNUTLS)
252 gnutls_global_init();
253 #endif // GNUTLS
255 return (void *)&fpx_functions;
258 static void FPX_Shutdown(void)
260 #ifdef OPENSSL
262 #elif defined(GNUTLS)
263 gnutls_global_deinit();
264 #endif // GNUTLS
268 // SSL support functions
271 #ifdef OPENSSL
272 struct SSL_Instance {
273 SSL *ssl;
274 SSL_CTX *sslCtx;
277 static void *FPX_SSLSocket_Create(int socket_fd)
278 // return = instance pointer
280 struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance));
281 memset(instance,0,sizeof(struct SSL_Instance));
283 if ( ( instance->sslCtx = SSL_CTX_new( TLSv1_client_method() ) ) == 0 ) goto fail;
285 if ( ( instance->ssl = SSL_new(instance->sslCtx) ) == 0 ) goto fail;
287 if ( SSL_set_fd(instance->ssl, socket_fd) < 0 ) goto fail;
289 return (void *)instance;
290 fail:
291 if ( instance->ssl ) {
292 SSL_shutdown(instance->ssl);
295 if ( instance->sslCtx ) {
296 SSL_CTX_free(instance->sslCtx);
299 if (FPI_Mem_Free) FPI_Mem_Free(instance);
301 return 0;
304 static int FPX_SSLSocket_Destroy(void *ptr)
305 // ptr = instance pointer
306 // return = 0 on sucess, < 0 on error
308 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
310 if ( instance->ssl ) {
311 SSL_shutdown(instance->ssl);
314 if ( instance->sslCtx ) {
315 SSL_CTX_free(instance->sslCtx);
318 if (FPI_Mem_Free) FPI_Mem_Free(instance);
320 return 0;
323 static int FPX_SSLSocket_Connect(void *ptr)
324 // ptr = instance pointer
325 // socket_fd = BSD socket fd to be associated with SSL connection
326 // return = 0 on sucess, < 0 on error
328 // Flash Player will use errno to obtain current status
330 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
331 return SSL_connect(instance->ssl);
334 static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes)
335 // ptr = instance pointer
336 // buffer = raw buffer to place received data into
337 // n_bytes = length of buffer in bytes
338 // return = actual bytes received, < 0 on error
340 // Flash Player will use errno to obtain current status
342 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
343 return SSL_read(instance->ssl, buffer, n_bytes);
346 static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes)
347 // ptr = instance pointer
348 // buffer = raw buffer to be sent
349 // n_bytes = length of input buffer in bytes
350 // return = actual bytes sent, < 0 on error
352 // Flash Player will use errno to obtain current status
354 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
355 return SSL_write(instance->ssl, buffer, n_bytes);
357 #elif defined(GNUTLS)
358 struct SSL_Instance {
359 gnutls_session_t session;
360 gnutls_anon_client_credentials_t anoncred;
363 static void *FPX_SSLSocket_Create(int socket_fd)
364 // return = instance pointer
366 const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 };
368 struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance));
369 memset(instance,0,sizeof(struct SSL_Instance));
371 if ( gnutls_anon_allocate_client_credentials(&instance->anoncred) < 0 ) goto fail;
373 if ( gnutls_init(&instance->session, GNUTLS_CLIENT) < 0 ) goto fail;
375 if ( gnutls_set_default_priority(instance->session) < 0 ) goto fail;
377 if ( gnutls_kx_set_priority(instance->session, kx_prio) < 0 ) goto fail;
379 if ( gnutls_credentials_set(instance->session, GNUTLS_CRD_ANON, instance->anoncred) < 0 ) goto fail;
381 gnutls_transport_set_ptr(instance->session, (gnutls_transport_ptr_t)socket_fd);
383 return (void *)instance;
384 fail:
386 if ( instance->session ) {
387 gnutls_deinit(instance->session);
390 if ( instance->anoncred ) {
391 gnutls_anon_free_client_credentials(instance->anoncred);
394 if (FPI_Mem_Free) FPI_Mem_Free(instance);
396 return 0;
399 static int FPX_SSLSocket_Destroy(void *ptr)
400 // ptr = instance pointer
401 // return = 0 on sucess, < 0 on error
403 struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance));
405 gnutls_bye(instance->session, GNUTLS_SHUT_RDWR);
407 gnutls_deinit(instance->session);
409 gnutls_anon_free_client_credentials(instance->anoncred);
411 if (FPI_Mem_Free) FPI_Mem_Free(instance);
413 return 0;
416 static int FPX_SSLSocket_Connect(void *ptr)
417 // ptr = instance pointer
418 // socket_fd = BSD socket fd to be associated with SSL connection
419 // return = 0 on sucess, < 0 on error
421 // Flash Player will use errno to obtain current status
423 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
424 return gnutls_handshake(instance->session);
427 static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes)
428 // ptr = instance pointer
429 // buffer = raw buffer to place received data into
430 // n_bytes = length of buffer in bytes
431 // return = actual bytes received, < 0 on error
433 // Flash Player will use errno to obtain current status
435 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
436 return gnutls_record_recv(instance->session, buffer, n_bytes);
439 static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes)
440 // ptr = instance pointer
441 // buffer = raw buffer to be sent
442 // n_bytes = length of input buffer in bytes
443 // return = actual bytes sent, < 0 on error
445 // Flash Player will use errno to obtain current status
447 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
448 return gnutls_record_send(instance->session, buffer, n_bytes);
450 #endif // GNUTLS
453 // Sound support functions
455 #ifdef ALSA
456 struct SoundOutput_Instance {
457 snd_pcm_t * handle;
458 snd_async_handler_t * async_handler;
459 sem_t semaphore;
460 pthread_t thread;
461 char * buffer;
462 snd_pcm_sframes_t buffer_size;
463 snd_pcm_sframes_t period_size;
464 snd_pcm_sframes_t buffer_pos;
465 char * buffer_ptr;
468 static void *alsa_thread(void *ptr)
470 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
471 snd_pcm_sframes_t avail = 0;
472 int result = 0;
473 int err = 0;
474 int state = 0;
476 for( ; ; ) {
478 err = sem_wait(&instance->semaphore);
479 if ( !instance->handle ) {
480 pthread_exit(0);
481 return 0;
484 if ( err < 0 ) {
485 usleep(1);
486 continue;
489 do {
490 if ( instance->buffer_pos <= 0 ) {
491 FPI_SoundOutput_FillBuffer(ptr, instance->buffer, snd_pcm_frames_to_bytes(instance->handle, instance->period_size));
492 instance->buffer_pos = instance->period_size;
493 instance->buffer_ptr = instance->buffer;
495 do {
496 state = snd_pcm_state(instance->handle);
497 if(state != SND_PCM_STATE_RUNNING && state != SND_PCM_STATE_PREPARED) {
498 snd_pcm_prepare(instance->handle);
500 result = snd_pcm_writei(instance->handle, instance->buffer_ptr, instance->buffer_pos);
501 if( result <= 0 ) {
502 switch( result ) {
503 case -EPIPE: {
504 snd_pcm_prepare(instance->handle);
505 } break;
506 case -ESTRPIPE: {
507 err = snd_pcm_resume(instance->handle);
508 if ( err < 0 ) {
509 snd_pcm_prepare(instance->handle);
511 } break;
513 break;
514 } else {
515 instance->buffer_pos -= result;
516 instance->buffer_ptr += snd_pcm_frames_to_bytes(instance->handle, result);
518 } while (instance->buffer_pos);
519 avail = snd_pcm_avail_update(instance->handle);
520 if( avail < 0 ) {
521 switch( avail ) {
522 case -EPIPE: {
523 snd_pcm_prepare(instance->handle);
524 } break;
525 case -ESTRPIPE: {
526 err = snd_pcm_resume(instance->handle);
527 if ( err < 0 ) {
528 snd_pcm_prepare(instance->handle);
530 } break;
532 break;
535 } while(avail >= instance->period_size);
539 static void alsa_callback(snd_async_handler_t *ahandler)
541 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)snd_async_handler_get_callback_private(ahandler);
542 // signal mixer thread
543 sem_post(&instance->semaphore);
546 static void *FPX_SoundOutput_Open()
547 // return = instance pointer
549 struct SoundOutput_Instance *instance = 0;
550 snd_pcm_hw_params_t *hwparams = 0;
551 snd_pcm_sw_params_t *swparams = 0;
552 snd_pcm_format_t pcm_format;
553 unsigned int buffer_time = 500000;
554 unsigned int period_time = 20000;
555 unsigned int actual_rate;
556 snd_pcm_uframes_t size;
557 int direction;
558 void *retVal = 0;
559 int err = 0;
561 if ( !FPI_SoundOutput_FillBuffer ) goto fail;
562 if ( !FPI_Mem_Alloc ) goto fail;
564 instance = FPI_Mem_Alloc(sizeof(struct SoundOutput_Instance));
565 memset(instance,0,sizeof(struct SoundOutput_Instance));
567 if ( ( err = snd_pcm_open(&instance->handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) {
568 if ( ( err = snd_pcm_open(&instance->handle, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) {
569 goto fail;
573 snd_pcm_hw_params_alloca(&hwparams);
574 snd_pcm_sw_params_alloca(&swparams);
576 if (snd_pcm_hw_params_any(instance->handle, hwparams) < 0) goto fail;
578 if (snd_pcm_hw_params_set_access(instance->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) goto fail;
580 pcm_format = SND_PCM_FORMAT_S16_LE;
582 if (snd_pcm_hw_params_set_format(instance->handle, hwparams, pcm_format) < 0) goto fail;
584 if (snd_pcm_hw_params_set_channels(instance->handle, hwparams, 2) < 0) goto fail;
586 actual_rate = 44100;
588 if (snd_pcm_hw_params_set_rate_near(instance->handle, hwparams, &actual_rate, 0) < 0) goto fail;
590 if (actual_rate != 44100) goto fail;
592 if (snd_pcm_hw_params_set_buffer_time_near(instance->handle, hwparams, &buffer_time, &direction) < 0) goto fail;
594 if (snd_pcm_hw_params_get_buffer_size(hwparams, &size) < 0) goto fail;
596 instance->buffer_size = (snd_pcm_sframes_t)size;
598 if (snd_pcm_hw_params_set_period_time_near(instance->handle, hwparams, &period_time, &direction) < 0) goto fail;
600 if (snd_pcm_hw_params_get_period_size(hwparams, &size, &direction) < 0) goto fail;
602 instance->period_size = (snd_pcm_sframes_t)size;
604 if (snd_pcm_hw_params(instance->handle, hwparams) < 0) goto fail;
606 if (snd_pcm_sw_params_current(instance->handle, swparams) < 0) goto fail;
608 if (snd_pcm_sw_params_set_start_threshold(instance->handle, swparams, ((instance->buffer_size-1) / instance->period_size) * instance->period_size) < 0) goto fail;
610 if (snd_pcm_sw_params_set_stop_threshold(instance->handle, swparams, ~0U) < 0) goto fail;
612 if (snd_pcm_sw_params_set_avail_min(instance->handle, swparams, instance->period_size) < 0) goto fail;
614 if (snd_pcm_sw_params_set_xfer_align(instance->handle, swparams, 1) < 0) goto fail;
616 if (snd_pcm_sw_params(instance->handle, swparams) < 0) goto fail;
618 if (snd_async_add_pcm_handler(&instance->async_handler, instance->handle, &alsa_callback, instance) < 0) goto fail;
620 if ( ( instance->buffer = FPI_Mem_Alloc(instance->buffer_size * 2 * 2 * 2) ) == 0 ) goto fail;
622 if ( pthread_create(&instance->thread, 0, alsa_thread, instance) < 0 ) goto fail;
624 sem_post(&instance->semaphore);
626 return instance;
628 fail:
629 if ( instance ) {
630 if ( instance->handle ) {
631 snd_pcm_drop(instance->handle);
632 snd_pcm_close(instance->handle);
633 instance->handle = 0;
635 if ( instance->thread ) {
636 sem_post(&instance->semaphore);
637 sem_destroy(&instance->semaphore);
638 pthread_join(instance->thread,&retVal);
640 if ( instance->buffer ) {
641 if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer);
643 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
645 return 0;
648 static int FPX_SoundOutput_Close(void *ptr)
649 // ptr = instance pointer
650 // return = 0 on success, < 0 on error
652 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
653 void *retVal = 0;
654 if ( instance->handle ) {
655 snd_pcm_drop(instance->handle);
656 snd_pcm_close(instance->handle);
657 instance->handle = 0;
659 if ( instance->thread ) {
660 sem_post(&instance->semaphore);
661 sem_destroy(&instance->semaphore);
662 pthread_join(instance->thread,&retVal);
664 if ( instance->buffer ) {
665 if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer);
667 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
668 return 0;
671 static int FPX_SoundOutput_Latency(void *ptr)
672 // ptr = instance pointer
673 // return = 0 on success, < 0 on error
675 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
676 if ( instance->handle ) {
677 snd_pcm_sframes_t delay = 0;
678 snd_pcm_delay(instance->handle, &delay);
679 if ( snd_pcm_state(instance->handle) == SND_PCM_STATE_RUNNING && delay > 0 ) {
680 return delay;
681 } else {
682 return 0;
685 return -1;
687 #elif defined(OSS)
688 struct SoundOutput_Instance {
689 int oss_fd;
690 pthread_t thread;
691 int signal;
694 static void *oss_thread(void *ptr)
696 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
697 char buffer[4096];
698 int len = 0;
699 int written = 0;
700 for(;;) {
701 FPI_SoundOutput_FillBuffer(ptr,buffer,4096);
702 len = 4096;
703 while ( len ) {
704 written = write(instance->oss_fd, buffer, len);
705 if ( written >= 0 ) {
706 len -= written;
708 if ( instance->signal ) {
709 pthread_exit(0);
711 if ( written < 0 ) {
712 usleep(100);
718 static void *FPX_SoundOutput_Open()
719 // return = instance pointer
721 struct SoundOutput_Instance *instance = 0;
722 int format = AFMT_S16_LE;
723 int stereo = 1;
724 int speed = 44100;
726 if ( !FPI_SoundOutput_FillBuffer ) goto fail;
727 if ( !FPI_Mem_Alloc ) goto fail;
729 instance = (struct SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct SoundOutput_Instance));
730 memset(instance,0,sizeof(struct SoundOutput_Instance));
732 if ( ( instance->oss_fd = open("/dev/dsp",O_WRONLY) ) < 0 ) goto fail;
734 if ( ioctl(instance->oss_fd, SNDCTL_DSP_SETFMT, &format) < 0 ) goto fail;
736 if ( ioctl(instance->oss_fd, SNDCTL_DSP_STEREO, &stereo) < 0 ) goto fail;
738 if ( ioctl(instance->oss_fd, SNDCTL_DSP_SPEED, &speed) < 0 ) goto fail;
740 if ( pthread_create(&instance->thread, 0, oss_thread, instance) < 0 ) goto fail;
742 return instance;
743 fail:
744 if ( instance ) {
745 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
747 return 0;
750 static int FPX_SoundOutput_Close(void *ptr)
751 // ptr = instance pointer
752 // return = 0 on success, < 0 on error
754 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
755 void *retVal = 0;
757 instance->signal = 1;
759 if ( instance->oss_fd ) {
760 ioctl(instance->oss_fd, SNDCTL_DSP_RESET, 0);
763 if ( instance->thread ) {
764 pthread_join(instance->thread,&retVal);
767 if ( instance->oss_fd ) {
768 close(instance->oss_fd);
771 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
773 return 0;
776 static int FPX_SoundOutput_Latency(void *ptr)
777 // ptr = instance pointer
778 // return = 0 on success, < 0 on error
780 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
781 if ( instance->oss_fd ) {
782 int value = 0;
783 if ( ( value = ioctl(instance->oss_fd,SNDCTL_DSP_GETODELAY,&value) ) == 0 ) {
784 return value / 4;
786 return 0;
788 return -1;
790 #endif // defined(OSS)
792 #ifdef PULSEAUDIO
794 #define BUFSIZE (4096)
796 struct output_data {
797 pa_threaded_mainloop *mainloop;
798 pa_context *context;
799 pa_stream *stream;
800 uint8_t buf[BUFSIZE];
801 pthread_t thread_id;
802 int first;
805 static void context_state_cb(pa_context *c, void *userdata) {
806 struct output_data *p = userdata;
808 assert(c);
809 assert(p);
811 p->thread_id = pthread_self();
812 p->context = c;
814 switch (pa_context_get_state(c)) {
815 case PA_CONTEXT_READY:
816 case PA_CONTEXT_TERMINATED:
817 case PA_CONTEXT_FAILED:
818 pa_threaded_mainloop_signal(p->mainloop, 0);
819 break;
821 case PA_CONTEXT_UNCONNECTED:
822 case PA_CONTEXT_CONNECTING:
823 case PA_CONTEXT_AUTHORIZING:
824 case PA_CONTEXT_SETTING_NAME:
825 break;
829 static void stream_state_cb(pa_stream *s, void *userdata) {
830 struct output_data *p = userdata;
832 assert(s);
833 assert(p);
835 p->thread_id = pthread_self();
836 p->stream = s;
838 switch (pa_stream_get_state(s)) {
840 case PA_STREAM_READY:
841 case PA_STREAM_FAILED:
842 case PA_STREAM_TERMINATED:
843 pa_threaded_mainloop_signal(p->mainloop, 0);
844 break;
846 case PA_STREAM_UNCONNECTED:
847 case PA_STREAM_CREATING:
848 break;
852 static void write_data(struct output_data *p) {
853 size_t length;
855 assert(p);
857 /* Wait until timing info is available before we write the second
858 * and all subsequent blocks */
859 if (!p->first && !pa_stream_get_timing_info(p->stream))
860 return;
862 length = pa_stream_writable_size(p->stream);
864 while (length > 4) {
865 size_t l = length;
867 if (l > BUFSIZE)
868 l = BUFSIZE;
870 l &= ~ ((size_t) 3);
872 FPI_SoundOutput_FillBuffer(p, (char*) p->buf, l);
874 if (pa_stream_write(p->stream, p->buf, l, NULL, 0, PA_SEEK_RELATIVE) < 0)
875 break;
877 length -= l;
879 if (p->first)
880 break;
883 /* The handling of errors here is just ridicilous. Blame Adobe! */
885 p->first = 0; /* So, we write the first block noch, remember that */
888 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
889 struct output_data *p = userdata;
891 assert(s);
892 assert(length > 0);
893 assert(p);
895 p->thread_id = pthread_self();
897 /* Write some data */
898 write_data(p);
901 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
902 struct output_data *p = userdata;
904 assert(s);
905 assert(p);
907 p->thread_id = pthread_self();
909 /* Try to write some more, in case we delayed the first write until latency data became available */
910 write_data(p);
913 static void *FPX_SoundOutput_Open(void) {
915 static const pa_sample_spec ss = {
916 .format = PA_SAMPLE_S16LE, /* Hmm, Flash wants LE here, not NE. I hope they know what they are doing. Probably not. */
917 .rate = 44100,
918 .channels = 2
921 struct output_data *p;
923 /* Awesome, we don't inform the user about any error messages, I
924 * guess that's Adobe style programming. Rock!" */
926 if (!(p = FPI_Mem_Alloc(sizeof(struct output_data))))
927 goto fail;
929 memset(p, 0, sizeof(*p));
930 p->first = 1;
931 p->thread_id = (pthread_t) 0;
933 /* First, let's create the main loop */
934 if (!(p->mainloop = pa_threaded_mainloop_new()))
935 goto fail;
937 /* Second, initialize the connection context */
938 if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), "Adobe Flash")))
939 goto fail;
941 pa_context_set_state_callback(p->context, context_state_cb, p);
943 if (pa_context_connect(p->context, NULL, 0, NULL) < 0)
944 goto fail;
946 /* Now, let's start the background thread */
947 pa_threaded_mainloop_lock(p->mainloop);
949 if (pa_threaded_mainloop_start(p->mainloop) < 0)
950 goto fail;
952 /* Wait until the context is ready */
953 pa_threaded_mainloop_wait(p->mainloop);
955 if (pa_context_get_state(p->context) != PA_CONTEXT_READY)
956 goto unlock_and_fail;
958 /* Now, initialize the stream */
959 if (!(p->stream = pa_stream_new(p->context, "Flash Animation", &ss, NULL)))
960 goto unlock_and_fail;
962 pa_stream_set_state_callback(p->stream, stream_state_cb, p);
963 pa_stream_set_write_callback(p->stream, stream_request_cb, p);
964 pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p);
966 if (pa_stream_connect_playback(p->stream, NULL, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0)
967 goto unlock_and_fail;
969 /* Wait until the stream is ready */
970 pa_threaded_mainloop_wait(p->mainloop);
972 if (pa_stream_get_state(p->stream) != PA_STREAM_READY)
973 goto unlock_and_fail;
975 pa_threaded_mainloop_unlock(p->mainloop);
977 return p;
979 unlock_and_fail:
981 pa_threaded_mainloop_unlock(p->mainloop);
983 fail:
984 if (p)
985 FPX_SoundOutput_Close(p);
987 return NULL;
990 static int FPX_SoundOutput_Close(void *ptr) {
991 struct output_data *p = ptr;
993 assert(p);
995 if (p->mainloop)
996 pa_threaded_mainloop_stop(p->mainloop);
998 if (p->stream) {
999 pa_stream_disconnect(p->stream);
1000 pa_stream_unref(p->stream);
1003 if (p->context) {
1004 pa_context_disconnect(p->context);
1005 pa_context_unref(p->context);
1008 if (p->mainloop)
1009 pa_threaded_mainloop_free(p->mainloop);
1011 if (FPI_Mem_Free)
1012 FPI_Mem_Free(p);
1014 return 0;
1017 static int FPX_SoundOutput_Latency(void *ptr) {
1018 struct output_data *p = ptr;
1019 pa_usec_t t = 0;
1020 int negative;
1021 int r;
1023 assert(p);
1025 /* We lock here only if we are not called from our event loop thread */
1026 if (!p->thread_id || !pthread_equal(p->thread_id, pthread_self()))
1027 pa_threaded_mainloop_lock(p->mainloop);
1029 if (pa_stream_get_latency(p->stream, &t, &negative) < 0 || negative)
1030 r = 0;
1031 else
1032 r = (int) (pa_usec_to_bytes(t, pa_stream_get_sample_spec(p->stream)) >> 2);
1034 if (!p->thread_id || !pthread_equal(p->thread_id, pthread_self()))
1035 pa_threaded_mainloop_unlock(p->mainloop);
1037 return r;
1040 #endif
1042 #ifdef V4L1
1043 struct VideoOutput_Instance {
1044 int v4l_fd;
1045 pthread_t thread;
1046 int signal;
1047 char * buffer[2];
1048 int buffercurrent;
1049 int buffersize;
1050 struct video_window window;
1051 struct video_picture picture;
1054 static void *v4l_thread(void *ptr)
1056 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1057 int result;
1058 int status;
1060 for(;;) {
1062 result = read(instance->v4l_fd, instance->buffer[instance->buffercurrent], instance->buffersize);
1063 if(result > 0) {
1066 if ( result < 0 ) {
1067 usleep(10000);
1070 if ( instance->signal ) {
1071 status = 0;
1072 ioctl(instance->v4l_fd, VIDIOCCAPTURE, &status);
1073 pthread_exit(0);
1078 static void *FPX_VideoInput_Open(void)
1080 struct VideoOutput_Instance *instance = 0;
1082 if ( !FPI_Mem_Alloc ) goto fail;
1084 instance = (struct VideoOutput_Instance *)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance));
1085 memset(instance,0,sizeof(struct VideoOutput_Instance));
1087 if ( ( instance->v4l_fd = open("/dev/video", O_RDONLY) ) < 0 ) goto fail;
1089 if ( ioctl(instance->v4l_fd, VIDIOCGPICT, &instance->picture) < 0 ) goto fail;
1091 switch(instance->picture.palette) {
1092 case VIDEO_PALETTE_YUV420P:
1093 break;
1094 case VIDEO_PALETTE_RGB24:
1095 case VIDEO_PALETTE_YUV422P:
1096 case VIDEO_PALETTE_YUV411P:
1097 case VIDEO_PALETTE_YUV410P:
1098 case VIDEO_PALETTE_GREY:
1099 case VIDEO_PALETTE_HI240:
1100 case VIDEO_PALETTE_RGB565:
1101 case VIDEO_PALETTE_RGB32:
1102 case VIDEO_PALETTE_RGB555:
1103 case VIDEO_PALETTE_YUV422:
1104 case VIDEO_PALETTE_YUYV:
1105 case VIDEO_PALETTE_UYVY:
1106 case VIDEO_PALETTE_YUV420:
1107 case VIDEO_PALETTE_YUV411:
1108 case VIDEO_PALETTE_RAW:
1109 default:
1110 goto fail;
1113 if( ioctl(instance->v4l_fd, VIDIOCGWIN, &instance->window) < 0 ) goto fail;
1115 instance->buffer[0] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2);
1116 instance->buffer[1] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2);
1118 if ( pthread_create(&instance->thread, 0, v4l_thread, instance) < 0 ) goto fail;
1120 return instance;
1122 fail:
1123 if ( FPI_Mem_Free ) {
1124 if ( instance->buffer[0] ) {
1125 FPI_Mem_Free(instance->buffer[0]);
1127 if ( instance->buffer[1] ) {
1128 FPI_Mem_Free(instance->buffer[1]);
1130 FPI_Mem_Free(instance);
1132 return 0;
1135 static int FPX_VideoInput_Close(void *ptr)
1137 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1138 void *retVal = 0;
1140 instance->signal = 1;
1142 if ( instance->thread ) {
1143 pthread_join(instance->thread,&retVal);
1146 if ( instance->v4l_fd ) {
1147 close(instance->v4l_fd);
1150 if ( FPI_Mem_Free ) {
1151 if ( instance->buffer[0] ) {
1152 FPI_Mem_Free(instance->buffer[0]);
1154 if ( instance->buffer[1] ) {
1155 FPI_Mem_Free(instance->buffer[1]);
1157 FPI_Mem_Free(instance);
1160 return 0;
1163 static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes)
1165 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1166 int ix, iy, ox, oy, ow, oh, dx, dy, Y, U, V, R, G, B;
1167 unsigned char *y, *u, *v;
1169 switch(instance->picture.palette) {
1170 case VIDEO_PALETTE_YUV420P: {
1171 ow = instance->window.width;
1172 oh = instance->window.height;
1174 dx = (ow<<16) / width;
1175 dy = (oh<<16) / height;
1177 y = (unsigned char *)instance->buffer[instance->buffercurrent^1];
1178 u = y + ow * oh;
1179 v = u + ow * oh / 4;
1181 oy = 0;
1183 for ( iy = 0; iy < height; iy++ ) {
1185 ox = 0;
1187 for ( ix = 0; ix < width; ix++ ) {
1189 Y = ( 149 * ((int)(y[(oy>>16)*(ow )+(ox>>16)]) - 16) ) / 2;
1190 U = (int)(u[(oy>>17)*(ow/2)+(ox>>17)]) - 128;
1191 V = (int)(v[(oy>>17)*(ow/2)+(ox>>17)]) - 128;
1193 R = (Y + V * 102 ) / 64;
1194 G = (Y - V * 52 - U * 25 ) / 64;
1195 B = (Y + U * 129 ) / 64;
1197 R = R < 0 ? 0 : ( R > 255 ? 255 : R );
1198 G = G < 0 ? 0 : ( G > 255 ? 255 : G );
1199 B = B < 0 ? 0 : ( B > 255 ? 255 : B );
1201 data[ix*3+0] = R;
1202 data[ix*3+1] = G;
1203 data[ix*3+2] = B;
1205 ox += dx;
1208 oy += dy;
1210 data += pitch_n_bytes;
1212 } break;
1213 default:
1214 goto fail;
1217 instance->buffercurrent ^= 1;
1219 return 0;
1221 fail:
1222 return -1;
1224 #endif // V4L1