[jack] initial jack support.
[libflashsupport-jack.git] / flashsupport.c
blob19fdc83676560ef417c476f9de2d7f63a58401b4
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
58 #define JACK
60 ////////////////////////////////////////////////////////////////////////////////////////////////////
62 // To compile and install flashsupport.c the following components are required:
64 // - a C compiler (gcc 4.03 is known to be working)
65 // - OpenSSL developer package and working user libraries (OpenSSL 0.9.8 is known to be working)
66 // - OSS (or ALSA) developer package and working users libraries (Linux 2.6.15 is known to be working)
67 // - sudo or root access to install the generated library to /usr/lib
69 // We suggest these steps in a terminal:
71 // > cc -shared -O2 -Wall -Werror -lssl flashsupport.c -o libflashsupport.so
72 // > ldd libflashplayer.so
73 // > sudo cp libflashplayer.so /usr/lib
75 // Make sure that 'ldd' can resolve all dynamic libraries. Otherwise the Flash Player
76 // will silently fail to load and use libflashsupport.so.
79 ////////////////////////////////////////////////////////////////////////////////////////////////////
81 // SHARED SECTION, DO NOT CHANGE!
83 #ifdef cplusplus
84 extern "C" {
85 #endif // cplusplus
88 // Imported functions
91 typedef void *(*T_FPI_Mem_Alloc)(int size); // This function is not thread safe
92 typedef void (*T_FPI_Mem_Free)(void *ptr); // This function is not thread safe
94 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
95 typedef void (*T_FPI_SoundOutput_FillBuffer)(void *ptr, char *buffer, int n_bytes); // This function is thread safe
96 #endif // defined(ALSA) || defined(OSS)
98 struct FPI_Functions {
99 int fpi_count;
100 void *fpi_mem_alloc; // 1
101 void *fpi_mem_free; // 2
102 void *fpi_soundoutput_fillbuffer; // 3
106 // Exported functions
109 void *FPX_Init(void *ptr);
111 static void FPX_Shutdown(void);
113 #if defined(OPENSSL) || defined(GNUTLS)
114 static void *FPX_SSLSocket_Create(int socket_fd);
115 static int FPX_SSLSocket_Destroy(void *ptr);
116 static int FPX_SSLSocket_Connect(void *ptr);
117 static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes);
118 static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes);
119 #endif // defined(OPENSSL) || defined(GNUTLS)
121 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
122 static void *FPX_SoundOutput_Open(void);
123 static int FPX_SoundOutput_Close(void *ptr);
124 static int FPX_SoundOutput_Latency(void *ptr);
125 #endif // defined(ALSA) || defined(OSS)
127 #ifdef V4L1
128 static void *FPX_VideoInput_Open(void);
129 static int FPX_VideoInput_Close(void *ptr);
130 static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes);
131 #endif // V4L1
133 struct FPX_Functions {
134 int fpx_count;
135 void *fpx_shutdown; // 1
136 void *fpx_sslsocket_create; // 2
137 void *fpx_sslsocket_destroy; // 3
138 void *fpx_sslsocket_connect; // 4
139 void *fpx_sslsocket_receive; // 5
140 void *fpx_sslsocket_send; // 6
141 void *fpx_soundoutput_open; // 7
142 void *fpx_soundoutput_close; // 8
143 void *fpx_soundoutput_latency; // 9
144 void *fpx_videoinput_open; // 10
145 void *fpx_videoinput_close; // 11
146 void *fpx_videoinput_getframe; // 12
149 #ifdef cplusplus
151 #endif // cplusplus
153 // END OF SHARED SECTION
155 ////////////////////////////////////////////////////////////////////////////////////////////////////
157 #include <memory.h>
159 #ifdef OPENSSL
160 #include <openssl/ssl.h>
161 #elif defined(GNUTLS)
162 #include <sys/types.h>
163 #include <sys/socket.h>
164 #include <arpa/inet.h>
165 #include <unistd.h>
166 #include <gnutls/gnutls.h>
167 #endif // GNUTLS
169 #ifdef ALSA
170 #include <pthread.h>
171 #include <semaphore.h>
172 #include <alsa/asoundlib.h>
173 #elif defined(OSS)
174 #include <unistd.h>
175 #include <pthread.h>
176 #include <linux/soundcard.h>
177 #include <sys/ioctl.h>
178 #include <fcntl.h>
179 #endif // OSS
181 #ifdef V4L1
182 #include <unistd.h>
183 #include <pthread.h>
184 #include <linux/videodev.h>
185 #include <sys/ioctl.h>
186 #include <fcntl.h>
187 #endif // V4L1
189 #ifdef PULSEAUDIO
190 #include <pulse/pulseaudio.h>
191 #endif
193 #ifdef JACK
194 #include <jack/jack.h>
195 #include <samplerate.h>
196 #endif
198 static struct FPX_Functions fpx_functions;
200 static T_FPI_Mem_Alloc FPI_Mem_Alloc = 0;
201 static T_FPI_Mem_Free FPI_Mem_Free = 0;
203 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
204 static T_FPI_SoundOutput_FillBuffer FPI_SoundOutput_FillBuffer = 0;
205 #endif // defined(ALSA) || defined(OSS)
207 void *FPX_Init(void *ptr)
209 struct FPI_Functions *fpi_functions;
210 if ( !ptr ) return 0;
213 // Setup imported functions
216 fpi_functions = (struct FPI_Functions *)ptr;
218 if ( fpi_functions->fpi_count >= 1 ) FPI_Mem_Alloc = fpi_functions->fpi_mem_alloc; // 1
219 if ( fpi_functions->fpi_count >= 2 ) FPI_Mem_Free = fpi_functions->fpi_mem_free; // 2
221 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
222 if ( fpi_functions->fpi_count >= 3 ) FPI_SoundOutput_FillBuffer= fpi_functions->fpi_soundoutput_fillbuffer; // 3
223 #endif // defined(ALSA) || defined(OSS)
226 // Setup exported functions
229 memset(&fpx_functions, 0, sizeof(fpx_functions));
231 fpx_functions.fpx_shutdown = FPX_Shutdown; // 1
233 #if defined(OPENSSL) || defined(GNUTLS)
234 fpx_functions.fpx_sslsocket_create = FPX_SSLSocket_Create; // 2
235 fpx_functions.fpx_sslsocket_destroy = FPX_SSLSocket_Destroy; // 3
236 fpx_functions.fpx_sslsocket_connect = FPX_SSLSocket_Connect; // 4
237 fpx_functions.fpx_sslsocket_receive = FPX_SSLSocket_Receive; // 5
238 fpx_functions.fpx_sslsocket_send = FPX_SSLSocket_Send; // 6
239 #endif // defined(OPENSSL) || defined(GNUTLS)
241 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
242 fpx_functions.fpx_soundoutput_open = FPX_SoundOutput_Open; // 7
243 fpx_functions.fpx_soundoutput_close = FPX_SoundOutput_Close; // 8
244 fpx_functions.fpx_soundoutput_latency = FPX_SoundOutput_Latency; // 9
245 #endif // defined(ALSA) || defined(OSS)
247 #ifdef V4L1
248 fpx_functions.fpx_videoinput_open = FPX_VideoInput_Open; // 10
249 fpx_functions.fpx_videoinput_close = FPX_VideoInput_Close; // 11
250 fpx_functions.fpx_videoinput_getframe = FPX_VideoInput_GetFrame; // 12
251 #endif // V4L1
253 fpx_functions.fpx_count = 14;
255 #ifdef OPENSSL
256 SSL_library_init();
257 #elif defined(GNUTLS)
258 gnutls_global_init();
259 #endif // GNUTLS
261 return (void *)&fpx_functions;
264 static void FPX_Shutdown(void)
266 #ifdef OPENSSL
268 #elif defined(GNUTLS)
269 gnutls_global_deinit();
270 #endif // GNUTLS
274 // SSL support functions
277 #ifdef OPENSSL
278 struct SSL_Instance {
279 SSL *ssl;
280 SSL_CTX *sslCtx;
283 static void *FPX_SSLSocket_Create(int socket_fd)
284 // return = instance pointer
286 struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance));
287 memset(instance,0,sizeof(struct SSL_Instance));
289 if ( ( instance->sslCtx = SSL_CTX_new( TLSv1_client_method() ) ) == 0 ) goto fail;
291 if ( ( instance->ssl = SSL_new(instance->sslCtx) ) == 0 ) goto fail;
293 if ( SSL_set_fd(instance->ssl, socket_fd) < 0 ) goto fail;
295 return (void *)instance;
296 fail:
297 if ( instance->ssl ) {
298 SSL_shutdown(instance->ssl);
301 if ( instance->sslCtx ) {
302 SSL_CTX_free(instance->sslCtx);
305 if (FPI_Mem_Free) FPI_Mem_Free(instance);
307 return 0;
310 static int FPX_SSLSocket_Destroy(void *ptr)
311 // ptr = instance pointer
312 // return = 0 on sucess, < 0 on error
314 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
316 if ( instance->ssl ) {
317 SSL_shutdown(instance->ssl);
320 if ( instance->sslCtx ) {
321 SSL_CTX_free(instance->sslCtx);
324 if (FPI_Mem_Free) FPI_Mem_Free(instance);
326 return 0;
329 static int FPX_SSLSocket_Connect(void *ptr)
330 // ptr = instance pointer
331 // socket_fd = BSD socket fd to be associated with SSL connection
332 // return = 0 on sucess, < 0 on error
334 // Flash Player will use errno to obtain current status
336 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
337 return SSL_connect(instance->ssl);
340 static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes)
341 // ptr = instance pointer
342 // buffer = raw buffer to place received data into
343 // n_bytes = length of buffer in bytes
344 // return = actual bytes received, < 0 on error
346 // Flash Player will use errno to obtain current status
348 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
349 return SSL_read(instance->ssl, buffer, n_bytes);
352 static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes)
353 // ptr = instance pointer
354 // buffer = raw buffer to be sent
355 // n_bytes = length of input buffer in bytes
356 // return = actual bytes sent, < 0 on error
358 // Flash Player will use errno to obtain current status
360 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
361 return SSL_write(instance->ssl, buffer, n_bytes);
363 #elif defined(GNUTLS)
364 struct SSL_Instance {
365 gnutls_session_t session;
366 gnutls_anon_client_credentials_t anoncred;
369 static void *FPX_SSLSocket_Create(int socket_fd)
370 // return = instance pointer
372 const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 };
374 struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance));
375 memset(instance,0,sizeof(struct SSL_Instance));
377 if ( gnutls_anon_allocate_client_credentials(&instance->anoncred) < 0 ) goto fail;
379 if ( gnutls_init(&instance->session, GNUTLS_CLIENT) < 0 ) goto fail;
381 if ( gnutls_set_default_priority(instance->session) < 0 ) goto fail;
383 if ( gnutls_kx_set_priority(instance->session, kx_prio) < 0 ) goto fail;
385 if ( gnutls_credentials_set(instance->session, GNUTLS_CRD_ANON, instance->anoncred) < 0 ) goto fail;
387 gnutls_transport_set_ptr(instance->session, (gnutls_transport_ptr_t)socket_fd);
389 return (void *)instance;
390 fail:
392 if ( instance->session ) {
393 gnutls_deinit(instance->session);
396 if ( instance->anoncred ) {
397 gnutls_anon_free_client_credentials(instance->anoncred);
400 if (FPI_Mem_Free) FPI_Mem_Free(instance);
402 return 0;
405 static int FPX_SSLSocket_Destroy(void *ptr)
406 // ptr = instance pointer
407 // return = 0 on sucess, < 0 on error
409 struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance));
411 gnutls_bye(instance->session, GNUTLS_SHUT_RDWR);
413 gnutls_deinit(instance->session);
415 gnutls_anon_free_client_credentials(instance->anoncred);
417 if (FPI_Mem_Free) FPI_Mem_Free(instance);
419 return 0;
422 static int FPX_SSLSocket_Connect(void *ptr)
423 // ptr = instance pointer
424 // socket_fd = BSD socket fd to be associated with SSL connection
425 // return = 0 on sucess, < 0 on error
427 // Flash Player will use errno to obtain current status
429 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
430 return gnutls_handshake(instance->session);
433 static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes)
434 // ptr = instance pointer
435 // buffer = raw buffer to place received data into
436 // n_bytes = length of buffer in bytes
437 // return = actual bytes received, < 0 on error
439 // Flash Player will use errno to obtain current status
441 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
442 return gnutls_record_recv(instance->session, buffer, n_bytes);
445 static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes)
446 // ptr = instance pointer
447 // buffer = raw buffer to be sent
448 // n_bytes = length of input buffer in bytes
449 // return = actual bytes sent, < 0 on error
451 // Flash Player will use errno to obtain current status
453 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
454 return gnutls_record_send(instance->session, buffer, n_bytes);
456 #endif // GNUTLS
459 // Sound support functions
461 #ifdef ALSA
462 struct SoundOutput_Instance {
463 snd_pcm_t * handle;
464 snd_async_handler_t * async_handler;
465 sem_t semaphore;
466 pthread_t thread;
467 char * buffer;
468 snd_pcm_sframes_t buffer_size;
469 snd_pcm_sframes_t period_size;
470 snd_pcm_sframes_t buffer_pos;
471 char * buffer_ptr;
474 static void *alsa_thread(void *ptr)
476 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
477 snd_pcm_sframes_t avail = 0;
478 int result = 0;
479 int err = 0;
480 int state = 0;
482 for( ; ; ) {
484 err = sem_wait(&instance->semaphore);
485 if ( !instance->handle ) {
486 pthread_exit(0);
487 return 0;
490 if ( err < 0 ) {
491 usleep(1);
492 continue;
495 do {
496 if ( instance->buffer_pos <= 0 ) {
497 FPI_SoundOutput_FillBuffer(ptr, instance->buffer, snd_pcm_frames_to_bytes(instance->handle, instance->period_size));
498 instance->buffer_pos = instance->period_size;
499 instance->buffer_ptr = instance->buffer;
501 do {
502 state = snd_pcm_state(instance->handle);
503 if(state != SND_PCM_STATE_RUNNING && state != SND_PCM_STATE_PREPARED) {
504 snd_pcm_prepare(instance->handle);
506 result = snd_pcm_writei(instance->handle, instance->buffer_ptr, instance->buffer_pos);
507 if( result <= 0 ) {
508 switch( result ) {
509 case -EPIPE: {
510 snd_pcm_prepare(instance->handle);
511 } break;
512 case -ESTRPIPE: {
513 err = snd_pcm_resume(instance->handle);
514 if ( err < 0 ) {
515 snd_pcm_prepare(instance->handle);
517 } break;
519 break;
520 } else {
521 instance->buffer_pos -= result;
522 instance->buffer_ptr += snd_pcm_frames_to_bytes(instance->handle, result);
524 } while (instance->buffer_pos);
525 avail = snd_pcm_avail_update(instance->handle);
526 if( avail < 0 ) {
527 switch( avail ) {
528 case -EPIPE: {
529 snd_pcm_prepare(instance->handle);
530 } break;
531 case -ESTRPIPE: {
532 err = snd_pcm_resume(instance->handle);
533 if ( err < 0 ) {
534 snd_pcm_prepare(instance->handle);
536 } break;
538 break;
541 } while(avail >= instance->period_size);
545 static void alsa_callback(snd_async_handler_t *ahandler)
547 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)snd_async_handler_get_callback_private(ahandler);
548 // signal mixer thread
549 sem_post(&instance->semaphore);
552 static void *FPX_SoundOutput_Open()
553 // return = instance pointer
555 struct SoundOutput_Instance *instance = 0;
556 snd_pcm_hw_params_t *hwparams = 0;
557 snd_pcm_sw_params_t *swparams = 0;
558 snd_pcm_format_t pcm_format;
559 unsigned int buffer_time = 500000;
560 unsigned int period_time = 20000;
561 unsigned int actual_rate;
562 snd_pcm_uframes_t size;
563 int direction;
564 void *retVal = 0;
565 int err = 0;
567 if ( !FPI_SoundOutput_FillBuffer ) goto fail;
568 if ( !FPI_Mem_Alloc ) goto fail;
570 instance = FPI_Mem_Alloc(sizeof(struct SoundOutput_Instance));
571 memset(instance,0,sizeof(struct SoundOutput_Instance));
573 if ( ( err = snd_pcm_open(&instance->handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) {
574 if ( ( err = snd_pcm_open(&instance->handle, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) {
575 goto fail;
579 snd_pcm_hw_params_alloca(&hwparams);
580 snd_pcm_sw_params_alloca(&swparams);
582 if (snd_pcm_hw_params_any(instance->handle, hwparams) < 0) goto fail;
584 if (snd_pcm_hw_params_set_access(instance->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) goto fail;
586 pcm_format = SND_PCM_FORMAT_S16_LE;
588 if (snd_pcm_hw_params_set_format(instance->handle, hwparams, pcm_format) < 0) goto fail;
590 if (snd_pcm_hw_params_set_channels(instance->handle, hwparams, 2) < 0) goto fail;
592 actual_rate = 44100;
594 if (snd_pcm_hw_params_set_rate_near(instance->handle, hwparams, &actual_rate, 0) < 0) goto fail;
596 if (actual_rate != 44100) goto fail;
598 if (snd_pcm_hw_params_set_buffer_time_near(instance->handle, hwparams, &buffer_time, &direction) < 0) goto fail;
600 if (snd_pcm_hw_params_get_buffer_size(hwparams, &size) < 0) goto fail;
602 instance->buffer_size = (snd_pcm_sframes_t)size;
604 if (snd_pcm_hw_params_set_period_time_near(instance->handle, hwparams, &period_time, &direction) < 0) goto fail;
606 if (snd_pcm_hw_params_get_period_size(hwparams, &size, &direction) < 0) goto fail;
608 instance->period_size = (snd_pcm_sframes_t)size;
610 if (snd_pcm_hw_params(instance->handle, hwparams) < 0) goto fail;
612 if (snd_pcm_sw_params_current(instance->handle, swparams) < 0) goto fail;
614 if (snd_pcm_sw_params_set_start_threshold(instance->handle, swparams, ((instance->buffer_size-1) / instance->period_size) * instance->period_size) < 0) goto fail;
616 if (snd_pcm_sw_params_set_stop_threshold(instance->handle, swparams, ~0U) < 0) goto fail;
618 if (snd_pcm_sw_params_set_avail_min(instance->handle, swparams, instance->period_size) < 0) goto fail;
620 if (snd_pcm_sw_params_set_xfer_align(instance->handle, swparams, 1) < 0) goto fail;
622 if (snd_pcm_sw_params(instance->handle, swparams) < 0) goto fail;
624 if (snd_async_add_pcm_handler(&instance->async_handler, instance->handle, &alsa_callback, instance) < 0) goto fail;
626 if ( ( instance->buffer = FPI_Mem_Alloc(instance->buffer_size * 2 * 2 * 2) ) == 0 ) goto fail;
628 if ( pthread_create(&instance->thread, 0, alsa_thread, instance) < 0 ) goto fail;
630 sem_post(&instance->semaphore);
632 return instance;
634 fail:
635 if ( instance ) {
636 if ( instance->handle ) {
637 snd_pcm_drop(instance->handle);
638 snd_pcm_close(instance->handle);
639 instance->handle = 0;
641 if ( instance->thread ) {
642 sem_post(&instance->semaphore);
643 sem_destroy(&instance->semaphore);
644 pthread_join(instance->thread,&retVal);
646 if ( instance->buffer ) {
647 if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer);
649 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
651 return 0;
654 static int FPX_SoundOutput_Close(void *ptr)
655 // ptr = instance pointer
656 // return = 0 on success, < 0 on error
658 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
659 void *retVal = 0;
660 if ( instance->handle ) {
661 snd_pcm_drop(instance->handle);
662 snd_pcm_close(instance->handle);
663 instance->handle = 0;
665 if ( instance->thread ) {
666 sem_post(&instance->semaphore);
667 sem_destroy(&instance->semaphore);
668 pthread_join(instance->thread,&retVal);
670 if ( instance->buffer ) {
671 if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer);
673 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
674 return 0;
677 static int FPX_SoundOutput_Latency(void *ptr)
678 // ptr = instance pointer
679 // return = 0 on success, < 0 on error
681 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
682 if ( instance->handle ) {
683 snd_pcm_sframes_t delay = 0;
684 snd_pcm_delay(instance->handle, &delay);
685 if ( snd_pcm_state(instance->handle) == SND_PCM_STATE_RUNNING && delay > 0 ) {
686 return delay;
687 } else {
688 return 0;
691 return -1;
693 #elif defined(OSS)
694 struct SoundOutput_Instance {
695 int oss_fd;
696 pthread_t thread;
697 int signal;
700 static void *oss_thread(void *ptr)
702 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
703 char buffer[4096];
704 int len = 0;
705 int written = 0;
706 for(;;) {
707 FPI_SoundOutput_FillBuffer(ptr,buffer,4096);
708 len = 4096;
709 while ( len ) {
710 written = write(instance->oss_fd, buffer, len);
711 if ( written >= 0 ) {
712 len -= written;
714 if ( instance->signal ) {
715 pthread_exit(0);
717 if ( written < 0 ) {
718 usleep(100);
724 static void *FPX_SoundOutput_Open()
725 // return = instance pointer
727 struct SoundOutput_Instance *instance = 0;
728 int format = AFMT_S16_LE;
729 int stereo = 1;
730 int speed = 44100;
732 if ( !FPI_SoundOutput_FillBuffer ) goto fail;
733 if ( !FPI_Mem_Alloc ) goto fail;
735 instance = (struct SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct SoundOutput_Instance));
736 memset(instance,0,sizeof(struct SoundOutput_Instance));
738 if ( ( instance->oss_fd = open("/dev/dsp",O_WRONLY) ) < 0 ) goto fail;
740 if ( ioctl(instance->oss_fd, SNDCTL_DSP_SETFMT, &format) < 0 ) goto fail;
742 if ( ioctl(instance->oss_fd, SNDCTL_DSP_STEREO, &stereo) < 0 ) goto fail;
744 if ( ioctl(instance->oss_fd, SNDCTL_DSP_SPEED, &speed) < 0 ) goto fail;
746 if ( pthread_create(&instance->thread, 0, oss_thread, instance) < 0 ) goto fail;
748 return instance;
749 fail:
750 if ( instance ) {
751 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
753 return 0;
756 static int FPX_SoundOutput_Close(void *ptr)
757 // ptr = instance pointer
758 // return = 0 on success, < 0 on error
760 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
761 void *retVal = 0;
763 instance->signal = 1;
765 if ( instance->oss_fd ) {
766 ioctl(instance->oss_fd, SNDCTL_DSP_RESET, 0);
769 if ( instance->thread ) {
770 pthread_join(instance->thread,&retVal);
773 if ( instance->oss_fd ) {
774 close(instance->oss_fd);
777 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
779 return 0;
782 static int FPX_SoundOutput_Latency(void *ptr)
783 // ptr = instance pointer
784 // return = 0 on success, < 0 on error
786 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
787 if ( instance->oss_fd ) {
788 int value = 0;
789 if ( ( value = ioctl(instance->oss_fd,SNDCTL_DSP_GETODELAY,&value) ) == 0 ) {
790 return value / 4;
792 return 0;
794 return -1;
796 #endif // defined(OSS)
798 #ifdef PULSEAUDIO
800 #define BUFSIZE (4096)
802 struct output_data {
803 pa_threaded_mainloop *mainloop;
804 pa_context *context;
805 pa_stream *stream;
806 uint8_t buf[BUFSIZE];
807 pthread_t thread_id;
808 int first;
811 static void context_state_cb(pa_context *c, void *userdata) {
812 struct output_data *p = userdata;
814 assert(c);
815 assert(p);
817 p->thread_id = pthread_self();
818 p->context = c;
820 switch (pa_context_get_state(c)) {
821 case PA_CONTEXT_READY:
822 case PA_CONTEXT_TERMINATED:
823 case PA_CONTEXT_FAILED:
824 pa_threaded_mainloop_signal(p->mainloop, 0);
825 break;
827 case PA_CONTEXT_UNCONNECTED:
828 case PA_CONTEXT_CONNECTING:
829 case PA_CONTEXT_AUTHORIZING:
830 case PA_CONTEXT_SETTING_NAME:
831 break;
835 static void stream_state_cb(pa_stream *s, void *userdata) {
836 struct output_data *p = userdata;
838 assert(s);
839 assert(p);
841 p->thread_id = pthread_self();
842 p->stream = s;
844 switch (pa_stream_get_state(s)) {
846 case PA_STREAM_READY:
847 case PA_STREAM_FAILED:
848 case PA_STREAM_TERMINATED:
849 pa_threaded_mainloop_signal(p->mainloop, 0);
850 break;
852 case PA_STREAM_UNCONNECTED:
853 case PA_STREAM_CREATING:
854 break;
858 static void write_data(struct output_data *p) {
859 size_t length;
861 assert(p);
863 /* Wait until timing info is available before we write the second
864 * and all subsequent blocks */
865 if (!p->first && !pa_stream_get_timing_info(p->stream))
866 return;
868 length = pa_stream_writable_size(p->stream);
870 while (length > 4) {
871 size_t l = length;
873 if (l > BUFSIZE)
874 l = BUFSIZE;
876 l &= ~ ((size_t) 3);
878 FPI_SoundOutput_FillBuffer(p, (char*) p->buf, l);
880 if (pa_stream_write(p->stream, p->buf, l, NULL, 0, PA_SEEK_RELATIVE) < 0)
881 break;
883 length -= l;
885 if (p->first)
886 break;
889 /* There's no real handling of errors here. Unfortunately the
890 * Flash API doesn't export a sane way to do this. With networked
891 * audio streams and hotplug-capable audio devices the audio
892 * stream might be killed in the middle of nothing, hence it is
893 * very unfortunate that we cannot report errors that happen here
894 * back to Flash. */
896 p->first = 0; /* So, we write the first block noch, remember that */
899 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
900 struct output_data *p = userdata;
902 assert(s);
903 assert(length > 0);
904 assert(p);
906 p->thread_id = pthread_self();
908 /* Write some data */
909 write_data(p);
912 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
913 struct output_data *p = userdata;
915 assert(s);
916 assert(p);
918 p->thread_id = pthread_self();
920 /* Try to write some more, in case we delayed the first write until latency data became available */
921 write_data(p);
924 static void *FPX_SoundOutput_Open(void) {
926 static const pa_sample_spec ss = {
927 .format = PA_SAMPLE_S16LE, /* Hmm, Flash wants LE here, not
928 * NE. This makes porting Flash to
929 * Big-Endian machines unnecessary
930 * difficult. */
931 .rate = 44100,
932 .channels = 2
935 struct output_data *p;
937 /* Unfortunately we cannot report any useful error string back to
938 * Flash. It would be highly preferable if Flash supported some
939 * way how we could tell the user what the reason is why audio is
940 * not working for him. */
942 if (!(p = FPI_Mem_Alloc(sizeof(struct output_data))))
943 goto fail;
945 memset(p, 0, sizeof(*p));
946 p->first = 1;
947 p->thread_id = (pthread_t) 0;
949 /* First, let's create the main loop */
950 if (!(p->mainloop = pa_threaded_mainloop_new()))
951 goto fail;
953 /* Second, initialize the connection context */
954 if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), "Adobe Flash")))
955 goto fail;
957 pa_context_set_state_callback(p->context, context_state_cb, p);
959 if (pa_context_connect(p->context, NULL, 0, NULL) < 0)
960 goto fail;
962 /* Now, let's start the background thread */
963 pa_threaded_mainloop_lock(p->mainloop);
965 if (pa_threaded_mainloop_start(p->mainloop) < 0)
966 goto fail;
968 /* Wait until the context is ready */
969 pa_threaded_mainloop_wait(p->mainloop);
971 if (pa_context_get_state(p->context) != PA_CONTEXT_READY)
972 goto unlock_and_fail;
974 /* Now, initialize the stream */
975 if (!(p->stream = pa_stream_new(p->context, "Flash Animation", &ss, NULL)))
976 goto unlock_and_fail;
978 pa_stream_set_state_callback(p->stream, stream_state_cb, p);
979 pa_stream_set_write_callback(p->stream, stream_request_cb, p);
980 pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p);
982 if (pa_stream_connect_playback(p->stream, NULL, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0)
983 goto unlock_and_fail;
985 /* Wait until the stream is ready */
986 pa_threaded_mainloop_wait(p->mainloop);
988 if (pa_stream_get_state(p->stream) != PA_STREAM_READY)
989 goto unlock_and_fail;
991 pa_threaded_mainloop_unlock(p->mainloop);
993 return p;
995 unlock_and_fail:
997 pa_threaded_mainloop_unlock(p->mainloop);
999 fail:
1000 if (p)
1001 FPX_SoundOutput_Close(p);
1003 return NULL;
1006 static int FPX_SoundOutput_Close(void *ptr) {
1007 struct output_data *p = ptr;
1009 assert(p);
1011 if (p->mainloop)
1012 pa_threaded_mainloop_stop(p->mainloop);
1014 if (p->stream) {
1015 pa_stream_disconnect(p->stream);
1016 pa_stream_unref(p->stream);
1019 if (p->context) {
1020 pa_context_disconnect(p->context);
1021 pa_context_unref(p->context);
1024 if (p->mainloop)
1025 pa_threaded_mainloop_free(p->mainloop);
1027 if (FPI_Mem_Free)
1028 FPI_Mem_Free(p);
1030 return 0;
1033 static int FPX_SoundOutput_Latency(void *ptr) {
1034 struct output_data *p = ptr;
1035 pa_usec_t t = 0;
1036 int negative;
1037 int r;
1039 assert(p);
1041 /* We lock here only if we are not called from our event loop thread */
1042 if (!p->thread_id || !pthread_equal(p->thread_id, pthread_self()))
1043 pa_threaded_mainloop_lock(p->mainloop);
1045 if (pa_stream_get_latency(p->stream, &t, &negative) < 0 || negative)
1046 r = 0;
1047 else
1048 r = (int) (pa_usec_to_bytes(t, pa_stream_get_sample_spec(p->stream)) >> 2);
1050 if (!p->thread_id || !pthread_equal(p->thread_id, pthread_self()))
1051 pa_threaded_mainloop_unlock(p->mainloop);
1053 return r;
1056 #endif
1058 #ifdef JACK
1060 struct jack_output_data {
1061 jack_client_t *client;
1062 jack_port_t *port_l;
1063 jack_port_t *port_r;
1064 SRC_STATE *src_l;
1065 SRC_STATE *src_r;
1066 int src_error;
1071 static int jack_process_cb( jack_nframes_t nframes, void *arg ) {
1072 struct jack_output_data *p = arg;
1073 int i;
1074 int jack_rate = jack_get_sample_rate( p->client );
1075 int flash_frames = nframes * 44100 / jack_rate;
1077 size_t bufsize = 2*flash_frames * sizeof( int16_t );
1078 int16_t *buffer = alloca( bufsize );
1079 float *float_buf = alloca( flash_frames * sizeof(float) );
1081 float *port_l = jack_port_get_buffer( p->port_l, nframes );
1082 float *port_r = jack_port_get_buffer( p->port_r, nframes );
1084 SRC_DATA sd;
1087 FPI_SoundOutput_FillBuffer(p, (char*) buffer, bufsize);
1089 for( i=0; i<flash_frames; i++ ) {
1090 float_buf[i] = (float) (buffer[2*i]) / 32768.0;
1093 sd.data_in = float_buf;
1094 sd.data_out = port_l;
1095 sd.input_frames = flash_frames;
1096 sd.output_frames = nframes;
1097 sd.end_of_input = 0;
1098 // sd.src_ratio = (double)flash_frames / (double)nframes;
1099 sd.src_ratio = (double)nframes / (double)flash_frames;
1101 src_process( p->src_l, &sd );
1104 for( i=0; i<flash_frames; i++ ) {
1105 float_buf[i] = (float) (buffer[2*i+1]) / 32768.0;
1108 sd.data_in = float_buf;
1109 sd.data_out = port_r;
1110 sd.input_frames = flash_frames;
1111 sd.output_frames = nframes;
1112 sd.end_of_input = 0;
1113 // sd.src_ratio = (double)flash_frames / (double)nframes;
1114 sd.src_ratio = (double)nframes / (double)flash_frames;
1116 src_process( p->src_r, &sd );
1118 return 0;
1121 static void *FPX_SoundOutput_Open(void) {
1123 struct jack_output_data *p=NULL;
1124 char namebuf[100];
1126 /* Unfortunately we cannot report any useful error string back to
1127 * Flash. It would be highly preferable if Flash supported some
1128 * way how we could tell the user what the reason is why audio is
1129 * not working for him. */
1131 if (!(p = FPI_Mem_Alloc(sizeof(struct jack_output_data))))
1132 goto fail;
1134 memset(p, 0, sizeof(*p));
1136 p->src_l = src_new(SRC_SINC_FASTEST, 1, & (p->src_error));
1137 p->src_r = src_new(SRC_SINC_FASTEST, 1, & (p->src_error));
1139 /* First, let's create the main loop */
1140 if (!(p->client = jack_client_open( "flash", 0, NULL )))
1141 goto fail;
1143 /* Second, initialize the connection context */
1144 if (!(p->port_l = jack_port_register( p->client, "out1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) )
1145 goto fail;
1146 if (!(p->port_r = jack_port_register( p->client, "out2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) )
1147 goto fail;
1149 jack_set_process_callback( p->client, jack_process_cb, p );
1150 jack_activate( p->client );
1152 snprintf( namebuf, 99, "%s:out1", jack_get_client_name( p->client ) );
1153 jack_connect( p->client, namebuf, "system:playback_1" );
1154 snprintf( namebuf, 99, "%s:out2", jack_get_client_name( p->client ) );
1155 jack_connect( p->client, namebuf, "system:playback_2" );
1157 return p;
1159 fail:
1160 if (p)
1161 FPX_SoundOutput_Close(p);
1163 return NULL;
1166 static int FPX_SoundOutput_Close(void *ptr) {
1167 struct jack_output_data *p = ptr;
1169 //assert(p);
1171 if (p->client) {
1172 jack_deactivate( p->client );
1173 jack_client_close( p->client );
1176 return 0;
1179 static int FPX_SoundOutput_Latency(void *ptr) {
1180 // heh ? jack has no latency :P
1181 return 0;
1183 #endif
1186 #ifdef V4L1
1187 struct VideoOutput_Instance {
1188 int v4l_fd;
1189 pthread_t thread;
1190 int signal;
1191 char * buffer[2];
1192 int buffercurrent;
1193 int buffersize;
1194 struct video_window window;
1195 struct video_picture picture;
1198 static void *v4l_thread(void *ptr)
1200 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1201 int result;
1202 int status;
1204 for(;;) {
1206 result = read(instance->v4l_fd, instance->buffer[instance->buffercurrent], instance->buffersize);
1207 if(result > 0) {
1210 if ( result < 0 ) {
1211 usleep(10000);
1214 if ( instance->signal ) {
1215 status = 0;
1216 ioctl(instance->v4l_fd, VIDIOCCAPTURE, &status);
1217 pthread_exit(0);
1220 return NULL;
1223 static void *FPX_VideoInput_Open(void)
1225 struct VideoOutput_Instance *instance = 0;
1227 if ( !FPI_Mem_Alloc ) goto fail;
1229 instance = (struct VideoOutput_Instance *)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance));
1230 memset(instance,0,sizeof(struct VideoOutput_Instance));
1232 if ( ( instance->v4l_fd = open("/dev/video", O_RDONLY) ) < 0 ) goto fail;
1234 if ( ioctl(instance->v4l_fd, VIDIOCGPICT, &instance->picture) < 0 ) goto fail;
1236 switch(instance->picture.palette) {
1237 case VIDEO_PALETTE_YUV420P:
1238 break;
1239 case VIDEO_PALETTE_RGB24:
1240 case VIDEO_PALETTE_YUV422P:
1241 case VIDEO_PALETTE_YUV411P:
1242 case VIDEO_PALETTE_YUV410P:
1243 case VIDEO_PALETTE_GREY:
1244 case VIDEO_PALETTE_HI240:
1245 case VIDEO_PALETTE_RGB565:
1246 case VIDEO_PALETTE_RGB32:
1247 case VIDEO_PALETTE_RGB555:
1248 case VIDEO_PALETTE_YUV422:
1249 case VIDEO_PALETTE_YUYV:
1250 case VIDEO_PALETTE_UYVY:
1251 case VIDEO_PALETTE_YUV420:
1252 case VIDEO_PALETTE_YUV411:
1253 case VIDEO_PALETTE_RAW:
1254 default:
1255 goto fail;
1258 if( ioctl(instance->v4l_fd, VIDIOCGWIN, &instance->window) < 0 ) goto fail;
1260 instance->buffer[0] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2);
1261 instance->buffer[1] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2);
1263 if ( pthread_create(&instance->thread, 0, v4l_thread, instance) < 0 ) goto fail;
1265 return instance;
1267 fail:
1268 if ( FPI_Mem_Free ) {
1269 if ( instance->buffer[0] ) {
1270 FPI_Mem_Free(instance->buffer[0]);
1272 if ( instance->buffer[1] ) {
1273 FPI_Mem_Free(instance->buffer[1]);
1275 FPI_Mem_Free(instance);
1277 return 0;
1280 static int FPX_VideoInput_Close(void *ptr)
1282 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1283 void *retVal = 0;
1285 instance->signal = 1;
1287 if ( instance->thread ) {
1288 pthread_join(instance->thread,&retVal);
1291 if ( instance->v4l_fd ) {
1292 close(instance->v4l_fd);
1295 if ( FPI_Mem_Free ) {
1296 if ( instance->buffer[0] ) {
1297 FPI_Mem_Free(instance->buffer[0]);
1299 if ( instance->buffer[1] ) {
1300 FPI_Mem_Free(instance->buffer[1]);
1302 FPI_Mem_Free(instance);
1305 return 0;
1308 static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes)
1310 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1311 int ix, iy, ox, oy, ow, oh, dx, dy, Y, U, V, R, G, B;
1312 unsigned char *y, *u, *v;
1314 switch(instance->picture.palette) {
1315 case VIDEO_PALETTE_YUV420P: {
1316 ow = instance->window.width;
1317 oh = instance->window.height;
1319 dx = (ow<<16) / width;
1320 dy = (oh<<16) / height;
1322 y = (unsigned char *)instance->buffer[instance->buffercurrent^1];
1323 u = y + ow * oh;
1324 v = u + ow * oh / 4;
1326 oy = 0;
1328 for ( iy = 0; iy < height; iy++ ) {
1330 ox = 0;
1332 for ( ix = 0; ix < width; ix++ ) {
1334 Y = ( 149 * ((int)(y[(oy>>16)*(ow )+(ox>>16)]) - 16) ) / 2;
1335 U = (int)(u[(oy>>17)*(ow/2)+(ox>>17)]) - 128;
1336 V = (int)(v[(oy>>17)*(ow/2)+(ox>>17)]) - 128;
1338 R = (Y + V * 102 ) / 64;
1339 G = (Y - V * 52 - U * 25 ) / 64;
1340 B = (Y + U * 129 ) / 64;
1342 R = R < 0 ? 0 : ( R > 255 ? 255 : R );
1343 G = G < 0 ? 0 : ( G > 255 ? 255 : G );
1344 B = B < 0 ? 0 : ( B > 255 ? 255 : B );
1346 data[ix*3+0] = R;
1347 data[ix*3+1] = G;
1348 data[ix*3+2] = B;
1350 ox += dx;
1353 oy += dy;
1355 data += pitch_n_bytes;
1357 } break;
1358 default:
1359 goto fail;
1362 instance->buffercurrent ^= 1;
1364 return 0;
1366 fail:
1367 return -1;
1369 #endif // V4L1