report ringbuffer readspace as latency.
[libflashsupport-jack.git] / flashsupport.c
bloba88bf1cdf9c346063119e4f9d0d4344c65cc5e37
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 <jack/ringbuffer.h>
196 #include <samplerate.h>
197 #include <semaphore.h>
198 #endif
200 static struct FPX_Functions fpx_functions;
202 static T_FPI_Mem_Alloc FPI_Mem_Alloc = 0;
203 static T_FPI_Mem_Free FPI_Mem_Free = 0;
205 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
206 static T_FPI_SoundOutput_FillBuffer FPI_SoundOutput_FillBuffer = 0;
207 #endif // defined(ALSA) || defined(OSS)
209 void *FPX_Init(void *ptr)
211 struct FPI_Functions *fpi_functions;
212 if ( !ptr ) return 0;
215 // Setup imported functions
218 fpi_functions = (struct FPI_Functions *)ptr;
220 if ( fpi_functions->fpi_count >= 1 ) FPI_Mem_Alloc = fpi_functions->fpi_mem_alloc; // 1
221 if ( fpi_functions->fpi_count >= 2 ) FPI_Mem_Free = fpi_functions->fpi_mem_free; // 2
223 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
224 if ( fpi_functions->fpi_count >= 3 ) FPI_SoundOutput_FillBuffer= fpi_functions->fpi_soundoutput_fillbuffer; // 3
225 #endif // defined(ALSA) || defined(OSS)
228 // Setup exported functions
231 memset(&fpx_functions, 0, sizeof(fpx_functions));
233 fpx_functions.fpx_shutdown = FPX_Shutdown; // 1
235 #if defined(OPENSSL) || defined(GNUTLS)
236 fpx_functions.fpx_sslsocket_create = FPX_SSLSocket_Create; // 2
237 fpx_functions.fpx_sslsocket_destroy = FPX_SSLSocket_Destroy; // 3
238 fpx_functions.fpx_sslsocket_connect = FPX_SSLSocket_Connect; // 4
239 fpx_functions.fpx_sslsocket_receive = FPX_SSLSocket_Receive; // 5
240 fpx_functions.fpx_sslsocket_send = FPX_SSLSocket_Send; // 6
241 #endif // defined(OPENSSL) || defined(GNUTLS)
243 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
244 fpx_functions.fpx_soundoutput_open = FPX_SoundOutput_Open; // 7
245 fpx_functions.fpx_soundoutput_close = FPX_SoundOutput_Close; // 8
246 fpx_functions.fpx_soundoutput_latency = FPX_SoundOutput_Latency; // 9
247 #endif // defined(ALSA) || defined(OSS)
249 #ifdef V4L1
250 fpx_functions.fpx_videoinput_open = FPX_VideoInput_Open; // 10
251 fpx_functions.fpx_videoinput_close = FPX_VideoInput_Close; // 11
252 fpx_functions.fpx_videoinput_getframe = FPX_VideoInput_GetFrame; // 12
253 #endif // V4L1
255 fpx_functions.fpx_count = 14;
257 #ifdef OPENSSL
258 SSL_library_init();
259 #elif defined(GNUTLS)
260 gnutls_global_init();
261 #endif // GNUTLS
263 return (void *)&fpx_functions;
266 static void FPX_Shutdown(void)
268 #ifdef OPENSSL
270 #elif defined(GNUTLS)
271 gnutls_global_deinit();
272 #endif // GNUTLS
276 // SSL support functions
279 #ifdef OPENSSL
280 struct SSL_Instance {
281 SSL *ssl;
282 SSL_CTX *sslCtx;
285 static void *FPX_SSLSocket_Create(int socket_fd)
286 // return = instance pointer
288 struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance));
289 memset(instance,0,sizeof(struct SSL_Instance));
291 if ( ( instance->sslCtx = SSL_CTX_new( TLSv1_client_method() ) ) == 0 ) goto fail;
293 if ( ( instance->ssl = SSL_new(instance->sslCtx) ) == 0 ) goto fail;
295 if ( SSL_set_fd(instance->ssl, socket_fd) < 0 ) goto fail;
297 return (void *)instance;
298 fail:
299 if ( instance->ssl ) {
300 SSL_shutdown(instance->ssl);
303 if ( instance->sslCtx ) {
304 SSL_CTX_free(instance->sslCtx);
307 if (FPI_Mem_Free) FPI_Mem_Free(instance);
309 return 0;
312 static int FPX_SSLSocket_Destroy(void *ptr)
313 // ptr = instance pointer
314 // return = 0 on sucess, < 0 on error
316 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
318 if ( instance->ssl ) {
319 SSL_shutdown(instance->ssl);
322 if ( instance->sslCtx ) {
323 SSL_CTX_free(instance->sslCtx);
326 if (FPI_Mem_Free) FPI_Mem_Free(instance);
328 return 0;
331 static int FPX_SSLSocket_Connect(void *ptr)
332 // ptr = instance pointer
333 // socket_fd = BSD socket fd to be associated with SSL connection
334 // return = 0 on sucess, < 0 on error
336 // Flash Player will use errno to obtain current status
338 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
339 return SSL_connect(instance->ssl);
342 static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes)
343 // ptr = instance pointer
344 // buffer = raw buffer to place received data into
345 // n_bytes = length of buffer in bytes
346 // return = actual bytes received, < 0 on error
348 // Flash Player will use errno to obtain current status
350 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
351 return SSL_read(instance->ssl, buffer, n_bytes);
354 static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes)
355 // ptr = instance pointer
356 // buffer = raw buffer to be sent
357 // n_bytes = length of input buffer in bytes
358 // return = actual bytes sent, < 0 on error
360 // Flash Player will use errno to obtain current status
362 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
363 return SSL_write(instance->ssl, buffer, n_bytes);
365 #elif defined(GNUTLS)
366 struct SSL_Instance {
367 gnutls_session_t session;
368 gnutls_anon_client_credentials_t anoncred;
371 static void *FPX_SSLSocket_Create(int socket_fd)
372 // return = instance pointer
374 const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 };
376 struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance));
377 memset(instance,0,sizeof(struct SSL_Instance));
379 if ( gnutls_anon_allocate_client_credentials(&instance->anoncred) < 0 ) goto fail;
381 if ( gnutls_init(&instance->session, GNUTLS_CLIENT) < 0 ) goto fail;
383 if ( gnutls_set_default_priority(instance->session) < 0 ) goto fail;
385 if ( gnutls_kx_set_priority(instance->session, kx_prio) < 0 ) goto fail;
387 if ( gnutls_credentials_set(instance->session, GNUTLS_CRD_ANON, instance->anoncred) < 0 ) goto fail;
389 gnutls_transport_set_ptr(instance->session, (gnutls_transport_ptr_t)socket_fd);
391 return (void *)instance;
392 fail:
394 if ( instance->session ) {
395 gnutls_deinit(instance->session);
398 if ( instance->anoncred ) {
399 gnutls_anon_free_client_credentials(instance->anoncred);
402 if (FPI_Mem_Free) FPI_Mem_Free(instance);
404 return 0;
407 static int FPX_SSLSocket_Destroy(void *ptr)
408 // ptr = instance pointer
409 // return = 0 on sucess, < 0 on error
411 struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance));
413 gnutls_bye(instance->session, GNUTLS_SHUT_RDWR);
415 gnutls_deinit(instance->session);
417 gnutls_anon_free_client_credentials(instance->anoncred);
419 if (FPI_Mem_Free) FPI_Mem_Free(instance);
421 return 0;
424 static int FPX_SSLSocket_Connect(void *ptr)
425 // ptr = instance pointer
426 // socket_fd = BSD socket fd to be associated with SSL connection
427 // return = 0 on sucess, < 0 on error
429 // Flash Player will use errno to obtain current status
431 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
432 return gnutls_handshake(instance->session);
435 static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes)
436 // ptr = instance pointer
437 // buffer = raw buffer to place received data into
438 // n_bytes = length of buffer in bytes
439 // return = actual bytes received, < 0 on error
441 // Flash Player will use errno to obtain current status
443 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
444 return gnutls_record_recv(instance->session, buffer, n_bytes);
447 static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes)
448 // ptr = instance pointer
449 // buffer = raw buffer to be sent
450 // n_bytes = length of input buffer in bytes
451 // return = actual bytes sent, < 0 on error
453 // Flash Player will use errno to obtain current status
455 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
456 return gnutls_record_send(instance->session, buffer, n_bytes);
458 #endif // GNUTLS
461 // Sound support functions
463 #ifdef ALSA
464 struct SoundOutput_Instance {
465 snd_pcm_t * handle;
466 snd_async_handler_t * async_handler;
467 sem_t semaphore;
468 pthread_t thread;
469 char * buffer;
470 snd_pcm_sframes_t buffer_size;
471 snd_pcm_sframes_t period_size;
472 snd_pcm_sframes_t buffer_pos;
473 char * buffer_ptr;
476 static void *alsa_thread(void *ptr)
478 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
479 snd_pcm_sframes_t avail = 0;
480 int result = 0;
481 int err = 0;
482 int state = 0;
484 for( ; ; ) {
486 err = sem_wait(&instance->semaphore);
487 if ( !instance->handle ) {
488 pthread_exit(0);
489 return 0;
492 if ( err < 0 ) {
493 usleep(1);
494 continue;
497 do {
498 if ( instance->buffer_pos <= 0 ) {
499 FPI_SoundOutput_FillBuffer(ptr, instance->buffer, snd_pcm_frames_to_bytes(instance->handle, instance->period_size));
500 instance->buffer_pos = instance->period_size;
501 instance->buffer_ptr = instance->buffer;
503 do {
504 state = snd_pcm_state(instance->handle);
505 if(state != SND_PCM_STATE_RUNNING && state != SND_PCM_STATE_PREPARED) {
506 snd_pcm_prepare(instance->handle);
508 result = snd_pcm_writei(instance->handle, instance->buffer_ptr, instance->buffer_pos);
509 if( result <= 0 ) {
510 switch( result ) {
511 case -EPIPE: {
512 snd_pcm_prepare(instance->handle);
513 } break;
514 case -ESTRPIPE: {
515 err = snd_pcm_resume(instance->handle);
516 if ( err < 0 ) {
517 snd_pcm_prepare(instance->handle);
519 } break;
521 break;
522 } else {
523 instance->buffer_pos -= result;
524 instance->buffer_ptr += snd_pcm_frames_to_bytes(instance->handle, result);
526 } while (instance->buffer_pos);
527 avail = snd_pcm_avail_update(instance->handle);
528 if( avail < 0 ) {
529 switch( avail ) {
530 case -EPIPE: {
531 snd_pcm_prepare(instance->handle);
532 } break;
533 case -ESTRPIPE: {
534 err = snd_pcm_resume(instance->handle);
535 if ( err < 0 ) {
536 snd_pcm_prepare(instance->handle);
538 } break;
540 break;
543 } while(avail >= instance->period_size);
547 static void alsa_callback(snd_async_handler_t *ahandler)
549 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)snd_async_handler_get_callback_private(ahandler);
550 // signal mixer thread
551 sem_post(&instance->semaphore);
554 static void *FPX_SoundOutput_Open()
555 // return = instance pointer
557 struct SoundOutput_Instance *instance = 0;
558 snd_pcm_hw_params_t *hwparams = 0;
559 snd_pcm_sw_params_t *swparams = 0;
560 snd_pcm_format_t pcm_format;
561 unsigned int buffer_time = 500000;
562 unsigned int period_time = 20000;
563 unsigned int actual_rate;
564 snd_pcm_uframes_t size;
565 int direction;
566 void *retVal = 0;
567 int err = 0;
569 if ( !FPI_SoundOutput_FillBuffer ) goto fail;
570 if ( !FPI_Mem_Alloc ) goto fail;
572 instance = FPI_Mem_Alloc(sizeof(struct SoundOutput_Instance));
573 memset(instance,0,sizeof(struct SoundOutput_Instance));
575 if ( ( err = snd_pcm_open(&instance->handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) {
576 if ( ( err = snd_pcm_open(&instance->handle, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) {
577 goto fail;
581 snd_pcm_hw_params_alloca(&hwparams);
582 snd_pcm_sw_params_alloca(&swparams);
584 if (snd_pcm_hw_params_any(instance->handle, hwparams) < 0) goto fail;
586 if (snd_pcm_hw_params_set_access(instance->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) goto fail;
588 pcm_format = SND_PCM_FORMAT_S16_LE;
590 if (snd_pcm_hw_params_set_format(instance->handle, hwparams, pcm_format) < 0) goto fail;
592 if (snd_pcm_hw_params_set_channels(instance->handle, hwparams, 2) < 0) goto fail;
594 actual_rate = 44100;
596 if (snd_pcm_hw_params_set_rate_near(instance->handle, hwparams, &actual_rate, 0) < 0) goto fail;
598 if (actual_rate != 44100) goto fail;
600 if (snd_pcm_hw_params_set_buffer_time_near(instance->handle, hwparams, &buffer_time, &direction) < 0) goto fail;
602 if (snd_pcm_hw_params_get_buffer_size(hwparams, &size) < 0) goto fail;
604 instance->buffer_size = (snd_pcm_sframes_t)size;
606 if (snd_pcm_hw_params_set_period_time_near(instance->handle, hwparams, &period_time, &direction) < 0) goto fail;
608 if (snd_pcm_hw_params_get_period_size(hwparams, &size, &direction) < 0) goto fail;
610 instance->period_size = (snd_pcm_sframes_t)size;
612 if (snd_pcm_hw_params(instance->handle, hwparams) < 0) goto fail;
614 if (snd_pcm_sw_params_current(instance->handle, swparams) < 0) goto fail;
616 if (snd_pcm_sw_params_set_start_threshold(instance->handle, swparams, ((instance->buffer_size-1) / instance->period_size) * instance->period_size) < 0) goto fail;
618 if (snd_pcm_sw_params_set_stop_threshold(instance->handle, swparams, ~0U) < 0) goto fail;
620 if (snd_pcm_sw_params_set_avail_min(instance->handle, swparams, instance->period_size) < 0) goto fail;
622 if (snd_pcm_sw_params_set_xfer_align(instance->handle, swparams, 1) < 0) goto fail;
624 if (snd_pcm_sw_params(instance->handle, swparams) < 0) goto fail;
626 if (snd_async_add_pcm_handler(&instance->async_handler, instance->handle, &alsa_callback, instance) < 0) goto fail;
628 if ( ( instance->buffer = FPI_Mem_Alloc(instance->buffer_size * 2 * 2 * 2) ) == 0 ) goto fail;
630 if ( pthread_create(&instance->thread, 0, alsa_thread, instance) < 0 ) goto fail;
632 sem_post(&instance->semaphore);
634 return instance;
636 fail:
637 if ( instance ) {
638 if ( instance->handle ) {
639 snd_pcm_drop(instance->handle);
640 snd_pcm_close(instance->handle);
641 instance->handle = 0;
643 if ( instance->thread ) {
644 sem_post(&instance->semaphore);
645 sem_destroy(&instance->semaphore);
646 pthread_join(instance->thread,&retVal);
648 if ( instance->buffer ) {
649 if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer);
651 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
653 return 0;
656 static int FPX_SoundOutput_Close(void *ptr)
657 // ptr = instance pointer
658 // return = 0 on success, < 0 on error
660 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
661 void *retVal = 0;
662 if ( instance->handle ) {
663 snd_pcm_drop(instance->handle);
664 snd_pcm_close(instance->handle);
665 instance->handle = 0;
667 if ( instance->thread ) {
668 sem_post(&instance->semaphore);
669 sem_destroy(&instance->semaphore);
670 pthread_join(instance->thread,&retVal);
672 if ( instance->buffer ) {
673 if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer);
675 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
676 return 0;
679 static int FPX_SoundOutput_Latency(void *ptr)
680 // ptr = instance pointer
681 // return = 0 on success, < 0 on error
683 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
684 if ( instance->handle ) {
685 snd_pcm_sframes_t delay = 0;
686 snd_pcm_delay(instance->handle, &delay);
687 if ( snd_pcm_state(instance->handle) == SND_PCM_STATE_RUNNING && delay > 0 ) {
688 return delay;
689 } else {
690 return 0;
693 return -1;
695 #elif defined(OSS)
696 struct SoundOutput_Instance {
697 int oss_fd;
698 pthread_t thread;
699 int signal;
702 static void *oss_thread(void *ptr)
704 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
705 char buffer[4096];
706 int len = 0;
707 int written = 0;
708 for(;;) {
709 FPI_SoundOutput_FillBuffer(ptr,buffer,4096);
710 len = 4096;
711 while ( len ) {
712 written = write(instance->oss_fd, buffer, len);
713 if ( written >= 0 ) {
714 len -= written;
716 if ( instance->signal ) {
717 pthread_exit(0);
719 if ( written < 0 ) {
720 usleep(100);
726 static void *FPX_SoundOutput_Open()
727 // return = instance pointer
729 struct SoundOutput_Instance *instance = 0;
730 int format = AFMT_S16_LE;
731 int stereo = 1;
732 int speed = 44100;
734 if ( !FPI_SoundOutput_FillBuffer ) goto fail;
735 if ( !FPI_Mem_Alloc ) goto fail;
737 instance = (struct SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct SoundOutput_Instance));
738 memset(instance,0,sizeof(struct SoundOutput_Instance));
740 if ( ( instance->oss_fd = open("/dev/dsp",O_WRONLY) ) < 0 ) goto fail;
742 if ( ioctl(instance->oss_fd, SNDCTL_DSP_SETFMT, &format) < 0 ) goto fail;
744 if ( ioctl(instance->oss_fd, SNDCTL_DSP_STEREO, &stereo) < 0 ) goto fail;
746 if ( ioctl(instance->oss_fd, SNDCTL_DSP_SPEED, &speed) < 0 ) goto fail;
748 if ( pthread_create(&instance->thread, 0, oss_thread, instance) < 0 ) goto fail;
750 return instance;
751 fail:
752 if ( instance ) {
753 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
755 return 0;
758 static int FPX_SoundOutput_Close(void *ptr)
759 // ptr = instance pointer
760 // return = 0 on success, < 0 on error
762 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
763 void *retVal = 0;
765 instance->signal = 1;
767 if ( instance->oss_fd ) {
768 ioctl(instance->oss_fd, SNDCTL_DSP_RESET, 0);
771 if ( instance->thread ) {
772 pthread_join(instance->thread,&retVal);
775 if ( instance->oss_fd ) {
776 close(instance->oss_fd);
779 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
781 return 0;
784 static int FPX_SoundOutput_Latency(void *ptr)
785 // ptr = instance pointer
786 // return = 0 on success, < 0 on error
788 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
789 if ( instance->oss_fd ) {
790 int value = 0;
791 if ( ( value = ioctl(instance->oss_fd,SNDCTL_DSP_GETODELAY,&value) ) == 0 ) {
792 return value / 4;
794 return 0;
796 return -1;
798 #endif // defined(OSS)
800 #ifdef PULSEAUDIO
802 #define BUFSIZE (4096)
804 struct output_data {
805 pa_threaded_mainloop *mainloop;
806 pa_context *context;
807 pa_stream *stream;
808 uint8_t buf[BUFSIZE];
809 pthread_t thread_id;
810 int first;
813 static void context_state_cb(pa_context *c, void *userdata) {
814 struct output_data *p = userdata;
816 assert(c);
817 assert(p);
819 p->thread_id = pthread_self();
820 p->context = c;
822 switch (pa_context_get_state(c)) {
823 case PA_CONTEXT_READY:
824 case PA_CONTEXT_TERMINATED:
825 case PA_CONTEXT_FAILED:
826 pa_threaded_mainloop_signal(p->mainloop, 0);
827 break;
829 case PA_CONTEXT_UNCONNECTED:
830 case PA_CONTEXT_CONNECTING:
831 case PA_CONTEXT_AUTHORIZING:
832 case PA_CONTEXT_SETTING_NAME:
833 break;
837 static void stream_state_cb(pa_stream *s, void *userdata) {
838 struct output_data *p = userdata;
840 assert(s);
841 assert(p);
843 p->thread_id = pthread_self();
844 p->stream = s;
846 switch (pa_stream_get_state(s)) {
848 case PA_STREAM_READY:
849 case PA_STREAM_FAILED:
850 case PA_STREAM_TERMINATED:
851 pa_threaded_mainloop_signal(p->mainloop, 0);
852 break;
854 case PA_STREAM_UNCONNECTED:
855 case PA_STREAM_CREATING:
856 break;
860 static void write_data(struct output_data *p) {
861 size_t length;
863 assert(p);
865 /* Wait until timing info is available before we write the second
866 * and all subsequent blocks */
867 if (!p->first && !pa_stream_get_timing_info(p->stream))
868 return;
870 length = pa_stream_writable_size(p->stream);
872 while (length > 4) {
873 size_t l = length;
875 if (l > BUFSIZE)
876 l = BUFSIZE;
878 l &= ~ ((size_t) 3);
880 FPI_SoundOutput_FillBuffer(p, (char*) p->buf, l);
882 if (pa_stream_write(p->stream, p->buf, l, NULL, 0, PA_SEEK_RELATIVE) < 0)
883 break;
885 length -= l;
887 if (p->first)
888 break;
891 /* There's no real handling of errors here. Unfortunately the
892 * Flash API doesn't export a sane way to do this. With networked
893 * audio streams and hotplug-capable audio devices the audio
894 * stream might be killed in the middle of nothing, hence it is
895 * very unfortunate that we cannot report errors that happen here
896 * back to Flash. */
898 p->first = 0; /* So, we write the first block noch, remember that */
901 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
902 struct output_data *p = userdata;
904 assert(s);
905 assert(length > 0);
906 assert(p);
908 p->thread_id = pthread_self();
910 /* Write some data */
911 write_data(p);
914 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
915 struct output_data *p = userdata;
917 assert(s);
918 assert(p);
920 p->thread_id = pthread_self();
922 /* Try to write some more, in case we delayed the first write until latency data became available */
923 write_data(p);
926 static void *FPX_SoundOutput_Open(void) {
928 static const pa_sample_spec ss = {
929 .format = PA_SAMPLE_S16LE, /* Hmm, Flash wants LE here, not
930 * NE. This makes porting Flash to
931 * Big-Endian machines unnecessary
932 * difficult. */
933 .rate = 44100,
934 .channels = 2
937 struct output_data *p;
939 /* Unfortunately we cannot report any useful error string back to
940 * Flash. It would be highly preferable if Flash supported some
941 * way how we could tell the user what the reason is why audio is
942 * not working for him. */
944 if (!(p = FPI_Mem_Alloc(sizeof(struct output_data))))
945 goto fail;
947 memset(p, 0, sizeof(*p));
948 p->first = 1;
949 p->thread_id = (pthread_t) 0;
951 /* First, let's create the main loop */
952 if (!(p->mainloop = pa_threaded_mainloop_new()))
953 goto fail;
955 /* Second, initialize the connection context */
956 if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), "Adobe Flash")))
957 goto fail;
959 pa_context_set_state_callback(p->context, context_state_cb, p);
961 if (pa_context_connect(p->context, NULL, 0, NULL) < 0)
962 goto fail;
964 /* Now, let's start the background thread */
965 pa_threaded_mainloop_lock(p->mainloop);
967 if (pa_threaded_mainloop_start(p->mainloop) < 0)
968 goto fail;
970 /* Wait until the context is ready */
971 pa_threaded_mainloop_wait(p->mainloop);
973 if (pa_context_get_state(p->context) != PA_CONTEXT_READY)
974 goto unlock_and_fail;
976 /* Now, initialize the stream */
977 if (!(p->stream = pa_stream_new(p->context, "Flash Animation", &ss, NULL)))
978 goto unlock_and_fail;
980 pa_stream_set_state_callback(p->stream, stream_state_cb, p);
981 pa_stream_set_write_callback(p->stream, stream_request_cb, p);
982 pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p);
984 if (pa_stream_connect_playback(p->stream, NULL, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0)
985 goto unlock_and_fail;
987 /* Wait until the stream is ready */
988 pa_threaded_mainloop_wait(p->mainloop);
990 if (pa_stream_get_state(p->stream) != PA_STREAM_READY)
991 goto unlock_and_fail;
993 pa_threaded_mainloop_unlock(p->mainloop);
995 return p;
997 unlock_and_fail:
999 pa_threaded_mainloop_unlock(p->mainloop);
1001 fail:
1002 if (p)
1003 FPX_SoundOutput_Close(p);
1005 return NULL;
1008 static int FPX_SoundOutput_Close(void *ptr) {
1009 struct output_data *p = ptr;
1011 assert(p);
1013 if (p->mainloop)
1014 pa_threaded_mainloop_stop(p->mainloop);
1016 if (p->stream) {
1017 pa_stream_disconnect(p->stream);
1018 pa_stream_unref(p->stream);
1021 if (p->context) {
1022 pa_context_disconnect(p->context);
1023 pa_context_unref(p->context);
1026 if (p->mainloop)
1027 pa_threaded_mainloop_free(p->mainloop);
1029 if (FPI_Mem_Free)
1030 FPI_Mem_Free(p);
1032 return 0;
1035 static int FPX_SoundOutput_Latency(void *ptr) {
1036 struct output_data *p = ptr;
1037 pa_usec_t t = 0;
1038 int negative;
1039 int r;
1041 assert(p);
1043 /* We lock here only if we are not called from our event loop thread */
1044 if (!p->thread_id || !pthread_equal(p->thread_id, pthread_self()))
1045 pa_threaded_mainloop_lock(p->mainloop);
1047 if (pa_stream_get_latency(p->stream, &t, &negative) < 0 || negative)
1048 r = 0;
1049 else
1050 r = (int) (pa_usec_to_bytes(t, pa_stream_get_sample_spec(p->stream)) >> 2);
1052 if (!p->thread_id || !pthread_equal(p->thread_id, pthread_self()))
1053 pa_threaded_mainloop_unlock(p->mainloop);
1055 return r;
1058 #endif
1060 #ifdef JACK
1062 struct jack_output_data {
1063 jack_client_t *client;
1064 jack_port_t *port_l;
1065 jack_port_t *port_r;
1066 SRC_STATE *src_l;
1067 SRC_STATE *src_r;
1068 int src_error;
1070 jack_ringbuffer_t *buffer;
1071 sem_t semaphore;
1072 volatile int quit;
1073 pthread_t tid;
1076 static void *jack_flash_thread( void *arg )
1078 struct jack_output_data *p = arg;
1079 int jack_rate = jack_get_sample_rate( p->client );
1080 int flash_frames = jack_get_buffer_size( p->client ) * 44100 / jack_rate;
1082 size_t bufsize = 2*flash_frames * sizeof( int16_t );
1083 int16_t *buffer = alloca( bufsize );
1085 while( !p->quit ) {
1086 sem_wait( &(p->semaphore) );
1087 FPI_SoundOutput_FillBuffer(p, (char*) buffer, bufsize);
1088 jack_ringbuffer_write( p->buffer, (char*)buffer, bufsize );
1090 return NULL;
1093 static int jack_process_cb( jack_nframes_t nframes, void *arg )
1095 struct jack_output_data *p = arg;
1096 int i;
1097 int jack_rate = jack_get_sample_rate( p->client );
1098 int flash_frames = nframes * 44100 / jack_rate;
1100 size_t bufsize = 2*flash_frames * sizeof( int16_t );
1101 int16_t *buffer = alloca( bufsize );
1102 float *float_buf = alloca( flash_frames * sizeof(float) );
1104 float *port_l = jack_port_get_buffer( p->port_l, nframes );
1105 float *port_r = jack_port_get_buffer( p->port_r, nframes );
1107 SRC_DATA sd;
1109 if( jack_ringbuffer_read_space( p->buffer ) < bufsize ) {
1110 // no data to read. fill ports with zero and return.
1111 memset( port_l, 0, nframes * sizeof( jack_default_audio_sample_t ) );
1112 memset( port_r, 0, nframes * sizeof( jack_default_audio_sample_t ) );
1113 return 0;
1116 //FPI_SoundOutput_FillBuffer(p, (char*) buffer, bufsize);
1117 if( jack_ringbuffer_read( p->buffer, (char *)buffer, bufsize ) != bufsize ) {
1118 printf( "Something is pretty wrong :( \n" );
1119 return 0;
1121 sem_post( &(p->semaphore) );
1123 for( i=0; i<flash_frames; i++ ) {
1124 float_buf[i] = (float) (buffer[2*i]) / 32768.0;
1127 sd.data_in = float_buf;
1128 sd.data_out = port_l;
1129 sd.input_frames = flash_frames;
1130 sd.output_frames = nframes;
1131 sd.end_of_input = 0;
1132 // sd.src_ratio = (double)flash_frames / (double)nframes;
1133 sd.src_ratio = (double)nframes / (double)flash_frames;
1135 src_process( p->src_l, &sd );
1138 for( i=0; i<flash_frames; i++ ) {
1139 float_buf[i] = (float) (buffer[2*i+1]) / 32768.0;
1142 sd.data_in = float_buf;
1143 sd.data_out = port_r;
1144 sd.input_frames = flash_frames;
1145 sd.output_frames = nframes;
1146 sd.end_of_input = 0;
1147 // sd.src_ratio = (double)flash_frames / (double)nframes;
1148 sd.src_ratio = (double)nframes / (double)flash_frames;
1150 src_process( p->src_r, &sd );
1152 return 0;
1155 static void *FPX_SoundOutput_Open(void) {
1157 struct jack_output_data *p=NULL;
1158 char namebuf[100];
1159 int jack_rate;
1160 int flash_frames;
1161 size_t bufsize;
1163 /* Unfortunately we cannot report any useful error string back to
1164 * Flash. It would be highly preferable if Flash supported some
1165 * way how we could tell the user what the reason is why audio is
1166 * not working for him. */
1168 if (!(p = FPI_Mem_Alloc(sizeof(struct jack_output_data))))
1169 goto fail;
1171 memset(p, 0, sizeof(*p));
1173 p->src_l = src_new(SRC_SINC_FASTEST, 1, & (p->src_error));
1174 p->src_r = src_new(SRC_SINC_FASTEST, 1, & (p->src_error));
1177 /* First, let's create the main loop */
1178 if (!(p->client = jack_client_open( "flash", 0, NULL )))
1179 goto fail;
1181 jack_rate = jack_get_sample_rate( p->client );
1182 flash_frames = jack_get_buffer_size( p->client ) * 44100 / jack_rate;
1183 bufsize = 2*flash_frames * sizeof( int16_t );
1185 p->buffer = jack_ringbuffer_create( bufsize * 2 );
1186 sem_init( &(p->semaphore), 0, 2 );
1188 pthread_create( &(p->tid), NULL, jack_flash_thread, p );
1190 /* Second, initialize the connection context */
1191 if (!(p->port_l = jack_port_register( p->client, "out1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) )
1192 goto fail;
1193 if (!(p->port_r = jack_port_register( p->client, "out2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) )
1194 goto fail;
1196 jack_set_process_callback( p->client, jack_process_cb, p );
1197 jack_activate( p->client );
1199 snprintf( namebuf, 99, "%s:out1", jack_get_client_name( p->client ) );
1200 jack_connect( p->client, namebuf, "system:playback_1" );
1201 snprintf( namebuf, 99, "%s:out2", jack_get_client_name( p->client ) );
1202 jack_connect( p->client, namebuf, "system:playback_2" );
1204 return p;
1206 fail:
1207 if (p)
1208 FPX_SoundOutput_Close(p);
1210 return NULL;
1213 static int FPX_SoundOutput_Close(void *ptr) {
1214 struct jack_output_data *p = ptr;
1216 //assert(p);
1217 if( p->tid ) {
1218 p->quit = 1;
1219 pthread_join( p->tid, NULL );
1222 if (p->client) {
1223 jack_deactivate( p->client );
1224 jack_client_close( p->client );
1227 return 0;
1230 static int FPX_SoundOutput_Latency(void *ptr) {
1231 // heh ? jack has no latency :P
1232 struct jack_output_data *p = ptr;
1233 return jack_ringbuffer_read_space( p->buffer ) / 4;
1235 #endif
1238 #ifdef V4L1
1239 struct VideoOutput_Instance {
1240 int v4l_fd;
1241 pthread_t thread;
1242 int signal;
1243 char * buffer[2];
1244 int buffercurrent;
1245 int buffersize;
1246 struct video_window window;
1247 struct video_picture picture;
1250 static void *v4l_thread(void *ptr)
1252 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1253 int result;
1254 int status;
1256 for(;;) {
1258 result = read(instance->v4l_fd, instance->buffer[instance->buffercurrent], instance->buffersize);
1259 if(result > 0) {
1262 if ( result < 0 ) {
1263 usleep(10000);
1266 if ( instance->signal ) {
1267 status = 0;
1268 ioctl(instance->v4l_fd, VIDIOCCAPTURE, &status);
1269 pthread_exit(0);
1272 return NULL;
1275 static void *FPX_VideoInput_Open(void)
1277 struct VideoOutput_Instance *instance = 0;
1279 if ( !FPI_Mem_Alloc ) goto fail;
1281 instance = (struct VideoOutput_Instance *)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance));
1282 memset(instance,0,sizeof(struct VideoOutput_Instance));
1284 if ( ( instance->v4l_fd = open("/dev/video", O_RDONLY) ) < 0 ) goto fail;
1286 if ( ioctl(instance->v4l_fd, VIDIOCGPICT, &instance->picture) < 0 ) goto fail;
1288 switch(instance->picture.palette) {
1289 case VIDEO_PALETTE_YUV420P:
1290 break;
1291 case VIDEO_PALETTE_RGB24:
1292 case VIDEO_PALETTE_YUV422P:
1293 case VIDEO_PALETTE_YUV411P:
1294 case VIDEO_PALETTE_YUV410P:
1295 case VIDEO_PALETTE_GREY:
1296 case VIDEO_PALETTE_HI240:
1297 case VIDEO_PALETTE_RGB565:
1298 case VIDEO_PALETTE_RGB32:
1299 case VIDEO_PALETTE_RGB555:
1300 case VIDEO_PALETTE_YUV422:
1301 case VIDEO_PALETTE_YUYV:
1302 case VIDEO_PALETTE_UYVY:
1303 case VIDEO_PALETTE_YUV420:
1304 case VIDEO_PALETTE_YUV411:
1305 case VIDEO_PALETTE_RAW:
1306 default:
1307 goto fail;
1310 if( ioctl(instance->v4l_fd, VIDIOCGWIN, &instance->window) < 0 ) goto fail;
1312 instance->buffer[0] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2);
1313 instance->buffer[1] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2);
1315 if ( pthread_create(&instance->thread, 0, v4l_thread, instance) < 0 ) goto fail;
1317 return instance;
1319 fail:
1320 if ( FPI_Mem_Free ) {
1321 if ( instance->buffer[0] ) {
1322 FPI_Mem_Free(instance->buffer[0]);
1324 if ( instance->buffer[1] ) {
1325 FPI_Mem_Free(instance->buffer[1]);
1327 FPI_Mem_Free(instance);
1329 return 0;
1332 static int FPX_VideoInput_Close(void *ptr)
1334 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1335 void *retVal = 0;
1337 instance->signal = 1;
1339 if ( instance->thread ) {
1340 pthread_join(instance->thread,&retVal);
1343 if ( instance->v4l_fd ) {
1344 close(instance->v4l_fd);
1347 if ( FPI_Mem_Free ) {
1348 if ( instance->buffer[0] ) {
1349 FPI_Mem_Free(instance->buffer[0]);
1351 if ( instance->buffer[1] ) {
1352 FPI_Mem_Free(instance->buffer[1]);
1354 FPI_Mem_Free(instance);
1357 return 0;
1360 static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes)
1362 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1363 int ix, iy, ox, oy, ow, oh, dx, dy, Y, U, V, R, G, B;
1364 unsigned char *y, *u, *v;
1366 switch(instance->picture.palette) {
1367 case VIDEO_PALETTE_YUV420P: {
1368 ow = instance->window.width;
1369 oh = instance->window.height;
1371 dx = (ow<<16) / width;
1372 dy = (oh<<16) / height;
1374 y = (unsigned char *)instance->buffer[instance->buffercurrent^1];
1375 u = y + ow * oh;
1376 v = u + ow * oh / 4;
1378 oy = 0;
1380 for ( iy = 0; iy < height; iy++ ) {
1382 ox = 0;
1384 for ( ix = 0; ix < width; ix++ ) {
1386 Y = ( 149 * ((int)(y[(oy>>16)*(ow )+(ox>>16)]) - 16) ) / 2;
1387 U = (int)(u[(oy>>17)*(ow/2)+(ox>>17)]) - 128;
1388 V = (int)(v[(oy>>17)*(ow/2)+(ox>>17)]) - 128;
1390 R = (Y + V * 102 ) / 64;
1391 G = (Y - V * 52 - U * 25 ) / 64;
1392 B = (Y + U * 129 ) / 64;
1394 R = R < 0 ? 0 : ( R > 255 ? 255 : R );
1395 G = G < 0 ? 0 : ( G > 255 ? 255 : G );
1396 B = B < 0 ? 0 : ( B > 255 ? 255 : B );
1398 data[ix*3+0] = R;
1399 data[ix*3+1] = G;
1400 data[ix*3+2] = B;
1402 ox += dx;
1405 oy += dy;
1407 data += pitch_n_bytes;
1409 } break;
1410 default:
1411 goto fail;
1414 instance->buffercurrent ^= 1;
1416 return 0;
1418 fail:
1419 return -1;
1421 #endif // V4L1