libflashsupport works fine with pa 0.9.5
[libflashsupport-jack.git] / flashsupport.c
blobafb1959dc6f70fc1b6f52d9a4f23045b057b43b2
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 /* There's no real handling of errors here. Unfortunately the
884 * Flash API doesn't export a sane way to do this. With networked
885 * audio streams and hotplug-capable audio devices the audio
886 * stream might be killed in the middle of nothing, hence it is
887 * very unfortunate that we cannot report errors that happen here
888 * back to Flash. */
890 p->first = 0; /* So, we write the first block noch, remember that */
893 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
894 struct output_data *p = userdata;
896 assert(s);
897 assert(length > 0);
898 assert(p);
900 p->thread_id = pthread_self();
902 /* Write some data */
903 write_data(p);
906 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
907 struct output_data *p = userdata;
909 assert(s);
910 assert(p);
912 p->thread_id = pthread_self();
914 /* Try to write some more, in case we delayed the first write until latency data became available */
915 write_data(p);
918 static void *FPX_SoundOutput_Open(void) {
920 static const pa_sample_spec ss = {
921 .format = PA_SAMPLE_S16LE, /* Hmm, Flash wants LE here, not
922 * NE. This makes porting Flash to
923 * Big-Endian machines unnecessary
924 * difficult. */
925 .rate = 44100,
926 .channels = 2
929 struct output_data *p;
931 /* Unfortunately we cannot report any useful error string back to
932 * Flash. It would be highly preferable if Flash supported some
933 * way how we could tell the user what the reason is why audio is
934 * not working for him. */
936 if (!(p = FPI_Mem_Alloc(sizeof(struct output_data))))
937 goto fail;
939 memset(p, 0, sizeof(*p));
940 p->first = 1;
941 p->thread_id = (pthread_t) 0;
943 /* First, let's create the main loop */
944 if (!(p->mainloop = pa_threaded_mainloop_new()))
945 goto fail;
947 /* Second, initialize the connection context */
948 if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), "Adobe Flash")))
949 goto fail;
951 pa_context_set_state_callback(p->context, context_state_cb, p);
953 if (pa_context_connect(p->context, NULL, 0, NULL) < 0)
954 goto fail;
956 /* Now, let's start the background thread */
957 pa_threaded_mainloop_lock(p->mainloop);
959 if (pa_threaded_mainloop_start(p->mainloop) < 0)
960 goto fail;
962 /* Wait until the context is ready */
963 pa_threaded_mainloop_wait(p->mainloop);
965 if (pa_context_get_state(p->context) != PA_CONTEXT_READY)
966 goto unlock_and_fail;
968 /* Now, initialize the stream */
969 if (!(p->stream = pa_stream_new(p->context, "Flash Animation", &ss, NULL)))
970 goto unlock_and_fail;
972 pa_stream_set_state_callback(p->stream, stream_state_cb, p);
973 pa_stream_set_write_callback(p->stream, stream_request_cb, p);
974 pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p);
976 if (pa_stream_connect_playback(p->stream, NULL, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0)
977 goto unlock_and_fail;
979 /* Wait until the stream is ready */
980 pa_threaded_mainloop_wait(p->mainloop);
982 if (pa_stream_get_state(p->stream) != PA_STREAM_READY)
983 goto unlock_and_fail;
985 pa_threaded_mainloop_unlock(p->mainloop);
987 return p;
989 unlock_and_fail:
991 pa_threaded_mainloop_unlock(p->mainloop);
993 fail:
994 if (p)
995 FPX_SoundOutput_Close(p);
997 return NULL;
1000 static int FPX_SoundOutput_Close(void *ptr) {
1001 struct output_data *p = ptr;
1003 assert(p);
1005 if (p->mainloop)
1006 pa_threaded_mainloop_stop(p->mainloop);
1008 if (p->stream) {
1009 pa_stream_disconnect(p->stream);
1010 pa_stream_unref(p->stream);
1013 if (p->context) {
1014 pa_context_disconnect(p->context);
1015 pa_context_unref(p->context);
1018 if (p->mainloop)
1019 pa_threaded_mainloop_free(p->mainloop);
1021 if (FPI_Mem_Free)
1022 FPI_Mem_Free(p);
1024 return 0;
1027 static int FPX_SoundOutput_Latency(void *ptr) {
1028 struct output_data *p = ptr;
1029 pa_usec_t t = 0;
1030 int negative;
1031 int r;
1033 assert(p);
1035 /* We lock here only if we are not called from our event loop thread */
1036 if (!p->thread_id || !pthread_equal(p->thread_id, pthread_self()))
1037 pa_threaded_mainloop_lock(p->mainloop);
1039 if (pa_stream_get_latency(p->stream, &t, &negative) < 0 || negative)
1040 r = 0;
1041 else
1042 r = (int) (pa_usec_to_bytes(t, pa_stream_get_sample_spec(p->stream)) >> 2);
1044 if (!p->thread_id || !pthread_equal(p->thread_id, pthread_self()))
1045 pa_threaded_mainloop_unlock(p->mainloop);
1047 return r;
1050 #endif
1052 #ifdef V4L1
1053 struct VideoOutput_Instance {
1054 int v4l_fd;
1055 pthread_t thread;
1056 int signal;
1057 char * buffer[2];
1058 int buffercurrent;
1059 int buffersize;
1060 struct video_window window;
1061 struct video_picture picture;
1064 static void *v4l_thread(void *ptr)
1066 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1067 int result;
1068 int status;
1070 for(;;) {
1072 result = read(instance->v4l_fd, instance->buffer[instance->buffercurrent], instance->buffersize);
1073 if(result > 0) {
1076 if ( result < 0 ) {
1077 usleep(10000);
1080 if ( instance->signal ) {
1081 status = 0;
1082 ioctl(instance->v4l_fd, VIDIOCCAPTURE, &status);
1083 pthread_exit(0);
1088 static void *FPX_VideoInput_Open(void)
1090 struct VideoOutput_Instance *instance = 0;
1092 if ( !FPI_Mem_Alloc ) goto fail;
1094 instance = (struct VideoOutput_Instance *)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance));
1095 memset(instance,0,sizeof(struct VideoOutput_Instance));
1097 if ( ( instance->v4l_fd = open("/dev/video", O_RDONLY) ) < 0 ) goto fail;
1099 if ( ioctl(instance->v4l_fd, VIDIOCGPICT, &instance->picture) < 0 ) goto fail;
1101 switch(instance->picture.palette) {
1102 case VIDEO_PALETTE_YUV420P:
1103 break;
1104 case VIDEO_PALETTE_RGB24:
1105 case VIDEO_PALETTE_YUV422P:
1106 case VIDEO_PALETTE_YUV411P:
1107 case VIDEO_PALETTE_YUV410P:
1108 case VIDEO_PALETTE_GREY:
1109 case VIDEO_PALETTE_HI240:
1110 case VIDEO_PALETTE_RGB565:
1111 case VIDEO_PALETTE_RGB32:
1112 case VIDEO_PALETTE_RGB555:
1113 case VIDEO_PALETTE_YUV422:
1114 case VIDEO_PALETTE_YUYV:
1115 case VIDEO_PALETTE_UYVY:
1116 case VIDEO_PALETTE_YUV420:
1117 case VIDEO_PALETTE_YUV411:
1118 case VIDEO_PALETTE_RAW:
1119 default:
1120 goto fail;
1123 if( ioctl(instance->v4l_fd, VIDIOCGWIN, &instance->window) < 0 ) goto fail;
1125 instance->buffer[0] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2);
1126 instance->buffer[1] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2);
1128 if ( pthread_create(&instance->thread, 0, v4l_thread, instance) < 0 ) goto fail;
1130 return instance;
1132 fail:
1133 if ( FPI_Mem_Free ) {
1134 if ( instance->buffer[0] ) {
1135 FPI_Mem_Free(instance->buffer[0]);
1137 if ( instance->buffer[1] ) {
1138 FPI_Mem_Free(instance->buffer[1]);
1140 FPI_Mem_Free(instance);
1142 return 0;
1145 static int FPX_VideoInput_Close(void *ptr)
1147 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1148 void *retVal = 0;
1150 instance->signal = 1;
1152 if ( instance->thread ) {
1153 pthread_join(instance->thread,&retVal);
1156 if ( instance->v4l_fd ) {
1157 close(instance->v4l_fd);
1160 if ( FPI_Mem_Free ) {
1161 if ( instance->buffer[0] ) {
1162 FPI_Mem_Free(instance->buffer[0]);
1164 if ( instance->buffer[1] ) {
1165 FPI_Mem_Free(instance->buffer[1]);
1167 FPI_Mem_Free(instance);
1170 return 0;
1173 static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes)
1175 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1176 int ix, iy, ox, oy, ow, oh, dx, dy, Y, U, V, R, G, B;
1177 unsigned char *y, *u, *v;
1179 switch(instance->picture.palette) {
1180 case VIDEO_PALETTE_YUV420P: {
1181 ow = instance->window.width;
1182 oh = instance->window.height;
1184 dx = (ow<<16) / width;
1185 dy = (oh<<16) / height;
1187 y = (unsigned char *)instance->buffer[instance->buffercurrent^1];
1188 u = y + ow * oh;
1189 v = u + ow * oh / 4;
1191 oy = 0;
1193 for ( iy = 0; iy < height; iy++ ) {
1195 ox = 0;
1197 for ( ix = 0; ix < width; ix++ ) {
1199 Y = ( 149 * ((int)(y[(oy>>16)*(ow )+(ox>>16)]) - 16) ) / 2;
1200 U = (int)(u[(oy>>17)*(ow/2)+(ox>>17)]) - 128;
1201 V = (int)(v[(oy>>17)*(ow/2)+(ox>>17)]) - 128;
1203 R = (Y + V * 102 ) / 64;
1204 G = (Y - V * 52 - U * 25 ) / 64;
1205 B = (Y + U * 129 ) / 64;
1207 R = R < 0 ? 0 : ( R > 255 ? 255 : R );
1208 G = G < 0 ? 0 : ( G > 255 ? 255 : G );
1209 B = B < 0 ? 0 : ( B > 255 ? 255 : B );
1211 data[ix*3+0] = R;
1212 data[ix*3+1] = G;
1213 data[ix*3+2] = B;
1215 ox += dx;
1218 oy += dy;
1220 data += pitch_n_bytes;
1222 } break;
1223 default:
1224 goto fail;
1227 instance->buffercurrent ^= 1;
1229 return 0;
1231 fail:
1232 return -1;
1234 #endif // V4L1