Initial version
[libflashsupport-jack/new-kernel-support.git] / flashsupport.c
blob141079d0e19becf0b3a7764ab23ffe720a25d37e
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();
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()
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 > 0) {
865 size_t l = length;
867 if (l > BUFSIZE)
868 l = BUFSIZE;
870 FPI_SoundOutput_FillBuffer(p, (char*) p->buf, l);
872 if (pa_stream_write(p->stream, p->buf, l, NULL, 0, PA_SEEK_RELATIVE) < 0)
873 break;
875 length -= l;
877 if (p->first)
878 break;
881 /* The handling of errors here is just ridicilous. Blame Adobe! */
883 p->first = 0; /* So, we write the first block noch, remember that */
886 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
887 struct output_data *p = userdata;
889 assert(s);
890 assert(length > 0);
891 assert(p);
893 p->thread_id = pthread_self();
895 /* Write some data */
896 write_data(p);
899 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
900 struct output_data *p = userdata;
902 assert(s);
903 assert(p);
905 p->thread_id = pthread_self();
907 /* Try to write some more, in case we delayed the first write until latency data became available */
908 write_data(p);
911 static void *FPX_SoundOutput_Open(void) {
913 static const pa_sample_spec ss = {
914 .format = PA_SAMPLE_S16LE, /* Hmm, Flash wants LE here, not NE. I hope they know what they are doing. Probably not. */
915 .rate = 44100,
916 .channels = 2
919 struct output_data *p = NULL;
921 /* Awesome, we don't inform the user about any error messages, I
922 * guess that's Adobe style programming. Rock!" */
924 if (!(p = FPI_Mem_Alloc(sizeof(struct output_data))))
925 goto fail;
927 memset(p, 0, sizeof(*p));
928 p->first = 1;
929 p->thread_id = (pthread_t) 0;
931 /* First, let's create the main loop */
932 if (!(p->mainloop = pa_threaded_mainloop_new()))
933 goto fail;
935 /* Second, initialize the connection context */
936 if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), "Adobe Flash")))
937 goto fail;
939 pa_context_set_state_callback(p->context, context_state_cb, p);
941 if (pa_context_connect(p->context, NULL, 0, NULL) < 0)
942 goto fail;
944 /* Now, let's start the background thread */
945 pa_threaded_mainloop_lock(p->mainloop);
947 if (pa_threaded_mainloop_start(p->mainloop) < 0)
948 goto fail;
950 /* Wait until the context is ready */
951 pa_threaded_mainloop_wait(p->mainloop);
953 if (pa_context_get_state(p->context) != PA_CONTEXT_READY)
954 goto unlock_and_fail;
956 /* Now, initialize the stream */
957 if (!(p->stream = pa_stream_new(p->context, "Flash Animation", &ss, NULL)))
958 goto unlock_and_fail;
960 pa_stream_set_state_callback(p->stream, stream_state_cb, p);
961 pa_stream_set_write_callback(p->stream, stream_request_cb, p);
962 pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p);
964 if (pa_stream_connect_playback(p->stream, NULL, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0)
965 goto unlock_and_fail;
967 /* Wait until the stream is ready */
968 pa_threaded_mainloop_wait(p->mainloop);
970 if (pa_stream_get_state(p->stream) != PA_STREAM_READY)
971 goto unlock_and_fail;
973 pa_threaded_mainloop_unlock(p->mainloop);
975 return p;
977 unlock_and_fail:
979 pa_threaded_mainloop_unlock(p->mainloop);
981 fail:
982 if (p)
983 FPX_SoundOutput_Close(p);
985 return NULL;
988 static int FPX_SoundOutput_Close(void *ptr) {
989 struct output_data *p = ptr;
991 assert(p);
993 if (p->mainloop)
994 pa_threaded_mainloop_stop(p->mainloop);
996 if (p->stream)
997 pa_stream_unref(p->stream);
999 if (p->context)
1000 pa_context_unref(p->context);
1002 if (p->mainloop)
1003 pa_threaded_mainloop_free(p->mainloop);
1005 if (FPI_Mem_Free)
1006 FPI_Mem_Free(p);
1008 return 0;
1011 static int FPX_SoundOutput_Latency(void *ptr) {
1012 struct output_data *p = ptr;
1013 pa_usec_t t;
1014 int negative;
1015 int r;
1017 assert(p);
1019 /* We lock here only if we are not called from our event loop thread */
1020 if (!p->thread_id || !pthread_equal(p->thread_id, pthread_self()))
1021 pa_threaded_mainloop_lock(p->mainloop);
1023 if (pa_stream_get_latency(p->stream, &t, &negative) < 0 || negative)
1024 r = 0;
1025 else
1026 r = (int) (pa_usec_to_bytes(t, pa_stream_get_sample_spec(p->stream)) >> 2);
1028 if (!p->thread_id || !pthread_equal(p->thread_id, pthread_self()))
1029 pa_threaded_mainloop_unlock(p->mainloop);
1031 return r;
1034 #endif
1036 #ifdef V4L1
1037 struct VideoOutput_Instance {
1038 int v4l_fd;
1039 pthread_t thread;
1040 int signal;
1041 char * buffer[2];
1042 int buffercurrent;
1043 int buffersize;
1044 struct video_window window;
1045 struct video_picture picture;
1048 static void *v4l_thread(void *ptr)
1050 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1051 int result;
1052 int status;
1054 for(;;) {
1056 result = read(instance->v4l_fd, instance->buffer[instance->buffercurrent], instance->buffersize);
1057 if(result > 0) {
1060 if ( result < 0 ) {
1061 usleep(10000);
1064 if ( instance->signal ) {
1065 status = 0;
1066 ioctl(instance->v4l_fd, VIDIOCCAPTURE, &status);
1067 pthread_exit(0);
1072 static void *FPX_VideoInput_Open()
1074 struct VideoOutput_Instance *instance = 0;
1076 if ( !FPI_Mem_Alloc ) goto fail;
1078 instance = (struct VideoOutput_Instance *)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance));
1079 memset(instance,0,sizeof(struct VideoOutput_Instance));
1081 if ( ( instance->v4l_fd = open("/dev/video", O_RDONLY) ) < 0 ) goto fail;
1083 if ( ioctl(instance->v4l_fd, VIDIOCGPICT, &instance->picture) < 0 ) goto fail;
1085 switch(instance->picture.palette) {
1086 case VIDEO_PALETTE_YUV420P:
1087 break;
1088 case VIDEO_PALETTE_RGB24:
1089 case VIDEO_PALETTE_YUV422P:
1090 case VIDEO_PALETTE_YUV411P:
1091 case VIDEO_PALETTE_YUV410P:
1092 case VIDEO_PALETTE_GREY:
1093 case VIDEO_PALETTE_HI240:
1094 case VIDEO_PALETTE_RGB565:
1095 case VIDEO_PALETTE_RGB32:
1096 case VIDEO_PALETTE_RGB555:
1097 case VIDEO_PALETTE_YUV422:
1098 case VIDEO_PALETTE_YUYV:
1099 case VIDEO_PALETTE_UYVY:
1100 case VIDEO_PALETTE_YUV420:
1101 case VIDEO_PALETTE_YUV411:
1102 case VIDEO_PALETTE_RAW:
1103 default:
1104 goto fail;
1107 if( ioctl(instance->v4l_fd, VIDIOCGWIN, &instance->window) < 0 ) goto fail;
1109 instance->buffer[0] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2);
1110 instance->buffer[1] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2);
1112 if ( pthread_create(&instance->thread, 0, v4l_thread, instance) < 0 ) goto fail;
1114 return instance;
1116 fail:
1117 if ( FPI_Mem_Free ) {
1118 if ( instance->buffer[0] ) {
1119 FPI_Mem_Free(instance->buffer[0]);
1121 if ( instance->buffer[1] ) {
1122 FPI_Mem_Free(instance->buffer[1]);
1124 FPI_Mem_Free(instance);
1126 return 0;
1129 static int FPX_VideoInput_Close(void *ptr)
1131 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1132 void *retVal = 0;
1134 instance->signal = 1;
1136 if ( instance->thread ) {
1137 pthread_join(instance->thread,&retVal);
1140 if ( instance->v4l_fd ) {
1141 close(instance->v4l_fd);
1144 if ( FPI_Mem_Free ) {
1145 if ( instance->buffer[0] ) {
1146 FPI_Mem_Free(instance->buffer[0]);
1148 if ( instance->buffer[1] ) {
1149 FPI_Mem_Free(instance->buffer[1]);
1151 FPI_Mem_Free(instance);
1154 return 0;
1157 static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes)
1159 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1160 int ix, iy, ox, oy, ow, oh, dx, dy, Y, U, V, R, G, B;
1161 unsigned char *y, *u, *v;
1163 switch(instance->picture.palette) {
1164 case VIDEO_PALETTE_YUV420P: {
1165 ow = instance->window.width;
1166 oh = instance->window.height;
1168 dx = (ow<<16) / width;
1169 dy = (oh<<16) / height;
1171 y = (unsigned char *)instance->buffer[instance->buffercurrent^1];
1172 u = y + ow * oh;
1173 v = u + ow * oh / 4;
1175 oy = 0;
1177 for ( iy = 0; iy < height; iy++ ) {
1179 ox = 0;
1181 for ( ix = 0; ix < width; ix++ ) {
1183 Y = ( 149 * ((int)(y[(oy>>16)*(ow )+(ox>>16)]) - 16) ) / 2;
1184 U = (int)(u[(oy>>17)*(ow/2)+(ox>>17)]) - 128;
1185 V = (int)(v[(oy>>17)*(ow/2)+(ox>>17)]) - 128;
1187 R = (Y + V * 102 ) / 64;
1188 G = (Y - V * 52 - U * 25 ) / 64;
1189 B = (Y + U * 129 ) / 64;
1191 R = R < 0 ? 0 : ( R > 255 ? 255 : R );
1192 G = G < 0 ? 0 : ( G > 255 ? 255 : G );
1193 B = B < 0 ? 0 : ( B > 255 ? 255 : B );
1195 data[ix*3+0] = R;
1196 data[ix*3+1] = G;
1197 data[ix*3+2] = B;
1199 ox += dx;
1202 oy += dy;
1204 data += pitch_n_bytes;
1206 } break;
1207 default:
1208 goto fail;
1211 instance->buffercurrent ^= 1;
1213 return 0;
1215 fail:
1216 return -1;
1218 #endif // V4L1