try to implement alsa_fallback. everything is broken now.
[libflashsupport-jack.git] / flashsupport.c
blobe42769bcda87930885ada46ea52a3562225dafdb
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 #if defined(ALSA) || defined(JACK)
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 ALSA_SoundOutput_Instance {
1063 snd_pcm_t * handle;
1064 snd_async_handler_t * async_handler;
1065 sem_t semaphore;
1066 pthread_t thread;
1067 char * buffer;
1068 snd_pcm_sframes_t buffer_size;
1069 snd_pcm_sframes_t period_size;
1070 snd_pcm_sframes_t buffer_pos;
1071 char * buffer_ptr;
1074 static void *alsa_thread(void *ptr)
1076 struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr;
1077 snd_pcm_sframes_t avail = 0;
1078 int result = 0;
1079 int err = 0;
1080 int state = 0;
1082 for( ; ; ) {
1084 err = sem_wait(&instance->semaphore);
1085 if ( !instance->handle ) {
1086 pthread_exit(0);
1087 return 0;
1090 if ( err < 0 ) {
1091 usleep(1);
1092 continue;
1095 do {
1096 if ( instance->buffer_pos <= 0 ) {
1097 FPI_SoundOutput_FillBuffer(ptr, instance->buffer, snd_pcm_frames_to_bytes(instance->handle, instance->period_size));
1098 instance->buffer_pos = instance->period_size;
1099 instance->buffer_ptr = instance->buffer;
1101 do {
1102 state = snd_pcm_state(instance->handle);
1103 if(state != SND_PCM_STATE_RUNNING && state != SND_PCM_STATE_PREPARED) {
1104 snd_pcm_prepare(instance->handle);
1106 result = snd_pcm_writei(instance->handle, instance->buffer_ptr, instance->buffer_pos);
1107 if( result <= 0 ) {
1108 switch( result ) {
1109 case -EPIPE: {
1110 snd_pcm_prepare(instance->handle);
1111 } break;
1112 case -ESTRPIPE: {
1113 err = snd_pcm_resume(instance->handle);
1114 if ( err < 0 ) {
1115 snd_pcm_prepare(instance->handle);
1117 } break;
1119 break;
1120 } else {
1121 instance->buffer_pos -= result;
1122 instance->buffer_ptr += snd_pcm_frames_to_bytes(instance->handle, result);
1124 } while (instance->buffer_pos);
1125 avail = snd_pcm_avail_update(instance->handle);
1126 if( avail < 0 ) {
1127 switch( avail ) {
1128 case -EPIPE: {
1129 snd_pcm_prepare(instance->handle);
1130 } break;
1131 case -ESTRPIPE: {
1132 err = snd_pcm_resume(instance->handle);
1133 if ( err < 0 ) {
1134 snd_pcm_prepare(instance->handle);
1136 } break;
1138 break;
1141 } while(avail >= instance->period_size);
1145 static void alsa_callback(snd_async_handler_t *ahandler)
1147 struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)snd_async_handler_get_callback_private(ahandler);
1148 // signal mixer thread
1149 sem_post(&instance->semaphore);
1152 static void *ALSA_FPX_SoundOutput_Open(void)
1153 // return = instance pointer
1155 struct ALSA_SoundOutput_Instance *instance = 0;
1156 snd_pcm_hw_params_t *hwparams = 0;
1157 snd_pcm_sw_params_t *swparams = 0;
1158 snd_pcm_format_t pcm_format;
1159 unsigned int buffer_time = 500000;
1160 unsigned int period_time = 20000;
1161 unsigned int actual_rate;
1162 snd_pcm_uframes_t size;
1163 int direction;
1164 void *retVal = 0;
1165 int err = 0;
1167 if ( !FPI_SoundOutput_FillBuffer ) goto fail;
1168 if ( !FPI_Mem_Alloc ) goto fail;
1170 instance = FPI_Mem_Alloc(sizeof(struct ALSA_SoundOutput_Instance));
1171 memset(instance,0,sizeof(struct ALSA_SoundOutput_Instance));
1173 if ( ( err = snd_pcm_open(&instance->handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) {
1174 if ( ( err = snd_pcm_open(&instance->handle, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) {
1175 goto fail;
1179 snd_pcm_hw_params_alloca(&hwparams);
1180 snd_pcm_sw_params_alloca(&swparams);
1182 if (snd_pcm_hw_params_any(instance->handle, hwparams) < 0) goto fail;
1184 if (snd_pcm_hw_params_set_access(instance->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) goto fail;
1186 pcm_format = SND_PCM_FORMAT_S16_LE;
1188 if (snd_pcm_hw_params_set_format(instance->handle, hwparams, pcm_format) < 0) goto fail;
1190 if (snd_pcm_hw_params_set_channels(instance->handle, hwparams, 2) < 0) goto fail;
1192 actual_rate = 44100;
1194 if (snd_pcm_hw_params_set_rate_near(instance->handle, hwparams, &actual_rate, 0) < 0) goto fail;
1196 if (actual_rate != 44100) goto fail;
1198 if (snd_pcm_hw_params_set_buffer_time_near(instance->handle, hwparams, &buffer_time, &direction) < 0) goto fail;
1200 if (snd_pcm_hw_params_get_buffer_size(hwparams, &size) < 0) goto fail;
1202 instance->buffer_size = (snd_pcm_sframes_t)size;
1204 if (snd_pcm_hw_params_set_period_time_near(instance->handle, hwparams, &period_time, &direction) < 0) goto fail;
1206 if (snd_pcm_hw_params_get_period_size(hwparams, &size, &direction) < 0) goto fail;
1208 instance->period_size = (snd_pcm_sframes_t)size;
1210 if (snd_pcm_hw_params(instance->handle, hwparams) < 0) goto fail;
1212 if (snd_pcm_sw_params_current(instance->handle, swparams) < 0) goto fail;
1214 if (snd_pcm_sw_params_set_start_threshold(instance->handle, swparams, ((instance->buffer_size-1) / instance->period_size) * instance->period_size) < 0) goto fail;
1216 if (snd_pcm_sw_params_set_stop_threshold(instance->handle, swparams, ~0U) < 0) goto fail;
1218 if (snd_pcm_sw_params_set_avail_min(instance->handle, swparams, instance->period_size) < 0) goto fail;
1220 if (snd_pcm_sw_params_set_xfer_align(instance->handle, swparams, 1) < 0) goto fail;
1222 if (snd_pcm_sw_params(instance->handle, swparams) < 0) goto fail;
1224 if (snd_async_add_pcm_handler(&instance->async_handler, instance->handle, &alsa_callback, instance) < 0) goto fail;
1226 if ( ( instance->buffer = FPI_Mem_Alloc(instance->buffer_size * 2 * 2 * 2) ) == 0 ) goto fail;
1228 if ( pthread_create(&instance->thread, 0, alsa_thread, instance) < 0 ) goto fail;
1230 sem_post(&instance->semaphore);
1232 return instance;
1234 fail:
1235 if ( instance ) {
1236 if ( instance->handle ) {
1237 snd_pcm_drop(instance->handle);
1238 snd_pcm_close(instance->handle);
1239 instance->handle = 0;
1241 if ( instance->thread ) {
1242 sem_post(&instance->semaphore);
1243 sem_destroy(&instance->semaphore);
1244 pthread_join(instance->thread,&retVal);
1246 if ( instance->buffer ) {
1247 if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer);
1249 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
1251 return 0;
1254 static int ALSA_FPX_SoundOutput_Close(void *ptr)
1255 // ptr = instance pointer
1256 // return = 0 on success, < 0 on error
1258 struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr;
1259 void *retVal = 0;
1260 if ( instance->handle ) {
1261 snd_pcm_drop(instance->handle);
1262 snd_pcm_close(instance->handle);
1263 instance->handle = 0;
1265 if ( instance->thread ) {
1266 sem_post(&instance->semaphore);
1267 sem_destroy(&instance->semaphore);
1268 pthread_join(instance->thread,&retVal);
1270 if ( instance->buffer ) {
1271 if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer);
1273 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
1274 return 0;
1277 static int ALSA_FPX_SoundOutput_Latency(void *ptr)
1278 // ptr = instance pointer
1279 // return = 0 on success, < 0 on error
1281 struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr;
1282 if ( instance->handle ) {
1283 snd_pcm_sframes_t delay = 0;
1284 snd_pcm_delay(instance->handle, &delay);
1285 if ( snd_pcm_state(instance->handle) == SND_PCM_STATE_RUNNING && delay > 0 ) {
1286 return delay;
1287 } else {
1288 return 0;
1291 return -1;
1295 struct jack_output_data {
1296 jack_client_t *client;
1297 jack_port_t *port_l;
1298 jack_port_t *port_r;
1299 SRC_STATE *src_l;
1300 SRC_STATE *src_r;
1301 int src_error;
1303 jack_ringbuffer_t *buffer;
1304 sem_t semaphore;
1305 volatile int quit;
1306 pthread_t tid;
1307 void *alsa_fallback;
1310 static void *jack_flash_thread( void *arg )
1312 struct jack_output_data *p = arg;
1313 int jack_rate = jack_get_sample_rate( p->client );
1314 int flash_frames = jack_get_buffer_size( p->client ) * 44100 / jack_rate;
1316 size_t bufsize = 2*flash_frames * sizeof( int16_t );
1317 int16_t *buffer = alloca( bufsize );
1319 while( !p->quit ) {
1320 sem_wait( &(p->semaphore) );
1321 FPI_SoundOutput_FillBuffer(p, (char*) buffer, bufsize);
1322 jack_ringbuffer_write( p->buffer, (char*)buffer, bufsize );
1324 return NULL;
1327 static int jack_process_cb( jack_nframes_t nframes, void *arg )
1329 struct jack_output_data *p = arg;
1330 int i;
1331 int jack_rate = jack_get_sample_rate( p->client );
1332 int flash_frames = nframes * 44100 / jack_rate;
1334 size_t bufsize = 2*flash_frames * sizeof( int16_t );
1335 int16_t *buffer = alloca( bufsize );
1336 float *float_buf = alloca( flash_frames * sizeof(float) );
1338 float *port_l = jack_port_get_buffer( p->port_l, nframes );
1339 float *port_r = jack_port_get_buffer( p->port_r, nframes );
1341 SRC_DATA sd;
1343 if( jack_ringbuffer_read_space( p->buffer ) < bufsize ) {
1344 // no data to read. fill ports with zero and return.
1345 memset( port_l, 0, nframes * sizeof( jack_default_audio_sample_t ) );
1346 memset( port_r, 0, nframes * sizeof( jack_default_audio_sample_t ) );
1347 return 0;
1350 //FPI_SoundOutput_FillBuffer(p, (char*) buffer, bufsize);
1351 if( jack_ringbuffer_read( p->buffer, (char *)buffer, bufsize ) != bufsize ) {
1352 printf( "Something is pretty wrong :( \n" );
1353 return 0;
1355 sem_post( &(p->semaphore) );
1357 for( i=0; i<flash_frames; i++ ) {
1358 float_buf[i] = (float) (buffer[2*i]) / 32768.0;
1361 sd.data_in = float_buf;
1362 sd.data_out = port_l;
1363 sd.input_frames = flash_frames;
1364 sd.output_frames = nframes;
1365 sd.end_of_input = 0;
1366 // sd.src_ratio = (double)flash_frames / (double)nframes;
1367 sd.src_ratio = (double)nframes / (double)flash_frames;
1369 src_process( p->src_l, &sd );
1372 for( i=0; i<flash_frames; i++ ) {
1373 float_buf[i] = (float) (buffer[2*i+1]) / 32768.0;
1376 sd.data_in = float_buf;
1377 sd.data_out = port_r;
1378 sd.input_frames = flash_frames;
1379 sd.output_frames = nframes;
1380 sd.end_of_input = 0;
1381 // sd.src_ratio = (double)flash_frames / (double)nframes;
1382 sd.src_ratio = (double)nframes / (double)flash_frames;
1384 src_process( p->src_r, &sd );
1386 return 0;
1389 static void *FPX_SoundOutput_Open(void) {
1391 struct jack_output_data *p=NULL;
1392 char namebuf[100];
1393 int jack_rate;
1394 int flash_frames;
1395 size_t bufsize;
1396 char *connect_port_1 = getenv( "JACK_FLASH_PORT_1" );
1397 char *connect_port_2 = getenv( "JACK_FLASH_PORT_2" );
1399 /* Unfortunately we cannot report any useful error string back to
1400 * Flash. It would be highly preferable if Flash supported some
1401 * way how we could tell the user what the reason is why audio is
1402 * not working for him. */
1404 if (!(p = FPI_Mem_Alloc(sizeof(struct jack_output_data))))
1405 goto fail;
1407 memset(p, 0, sizeof(*p));
1409 /* First, let's create the main loop */
1410 if (!(p->client = jack_client_open( "flash", JackNoStartServer, NULL ))) {
1411 p->alsa_fallback = ALSA_FPX_SoundOutput_Open();
1412 if( p->alsa_fallback )
1413 return p;
1414 else
1415 return 0;
1418 p->src_l = src_new(SRC_LINEAR, 1, & (p->src_error));
1419 p->src_r = src_new(SRC_LINEAR, 1, & (p->src_error));
1421 jack_rate = jack_get_sample_rate( p->client );
1422 flash_frames = jack_get_buffer_size( p->client ) * 44100 / jack_rate;
1423 bufsize = 2*flash_frames * sizeof( int16_t );
1425 p->buffer = jack_ringbuffer_create( bufsize * 2 );
1426 sem_init( &(p->semaphore), 0, 2 );
1428 pthread_create( &(p->tid), NULL, jack_flash_thread, p );
1430 /* Second, initialize the connection context */
1431 if (!(p->port_l = jack_port_register( p->client, "out1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) )
1432 goto fail;
1433 if (!(p->port_r = jack_port_register( p->client, "out2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) )
1434 goto fail;
1436 jack_set_process_callback( p->client, jack_process_cb, p );
1437 jack_activate( p->client );
1439 snprintf( namebuf, 99, "%s:out1", jack_get_client_name( p->client ) );
1440 jack_connect( p->client, namebuf, (connect_port_1 != NULL) ? connect_port_1 : "system:playback_1" );
1441 snprintf( namebuf, 99, "%s:out2", jack_get_client_name( p->client ) );
1442 jack_connect( p->client, namebuf, (connect_port_2 != NULL) ? connect_port_2 : "system:playback_1" );
1444 return p;
1446 fail:
1447 if (p)
1448 FPX_SoundOutput_Close(p);
1450 return NULL;
1453 static int FPX_SoundOutput_Close(void *ptr) {
1454 struct jack_output_data *p = ptr;
1456 if( p->alsa_fallback ) {
1457 return ALSA_FPX_SoundOutput_Close( p->alsa_fallback );
1459 //assert(p);
1460 if( p->tid ) {
1461 p->quit = 1;
1462 pthread_join( p->tid, NULL );
1465 if (p->client) {
1466 jack_deactivate( p->client );
1467 jack_client_close( p->client );
1470 return 0;
1473 static int FPX_SoundOutput_Latency(void *ptr) {
1474 struct jack_output_data *p = ptr;
1475 if( p->alsa_fallback ) {
1476 return ALSA_FPX_SoundOutput_Latency( p->alsa_fallback );
1479 // heh ? jack has no latency :P
1480 return 0;
1482 #endif
1485 #ifdef V4L1
1486 struct VideoOutput_Instance {
1487 int v4l_fd;
1488 pthread_t thread;
1489 int signal;
1490 char * buffer[2];
1491 int buffercurrent;
1492 int buffersize;
1493 struct video_window window;
1494 struct video_picture picture;
1497 static void *v4l_thread(void *ptr)
1499 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1500 int result;
1501 int status;
1503 for(;;) {
1505 result = read(instance->v4l_fd, instance->buffer[instance->buffercurrent], instance->buffersize);
1506 if(result > 0) {
1509 if ( result < 0 ) {
1510 usleep(10000);
1513 if ( instance->signal ) {
1514 status = 0;
1515 ioctl(instance->v4l_fd, VIDIOCCAPTURE, &status);
1516 pthread_exit(0);
1519 return NULL;
1522 static void *FPX_VideoInput_Open(void)
1524 struct VideoOutput_Instance *instance = 0;
1526 if ( !FPI_Mem_Alloc ) goto fail;
1528 instance = (struct VideoOutput_Instance *)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance));
1529 memset(instance,0,sizeof(struct VideoOutput_Instance));
1531 if ( ( instance->v4l_fd = open("/dev/video", O_RDONLY) ) < 0 ) goto fail;
1533 if ( ioctl(instance->v4l_fd, VIDIOCGPICT, &instance->picture) < 0 ) goto fail;
1535 switch(instance->picture.palette) {
1536 case VIDEO_PALETTE_YUV420P:
1537 break;
1538 case VIDEO_PALETTE_RGB24:
1539 case VIDEO_PALETTE_YUV422P:
1540 case VIDEO_PALETTE_YUV411P:
1541 case VIDEO_PALETTE_YUV410P:
1542 case VIDEO_PALETTE_GREY:
1543 case VIDEO_PALETTE_HI240:
1544 case VIDEO_PALETTE_RGB565:
1545 case VIDEO_PALETTE_RGB32:
1546 case VIDEO_PALETTE_RGB555:
1547 case VIDEO_PALETTE_YUV422:
1548 case VIDEO_PALETTE_YUYV:
1549 case VIDEO_PALETTE_UYVY:
1550 case VIDEO_PALETTE_YUV420:
1551 case VIDEO_PALETTE_YUV411:
1552 case VIDEO_PALETTE_RAW:
1553 default:
1554 goto fail;
1557 if( ioctl(instance->v4l_fd, VIDIOCGWIN, &instance->window) < 0 ) goto fail;
1559 instance->buffer[0] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2);
1560 instance->buffer[1] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2);
1562 if ( pthread_create(&instance->thread, 0, v4l_thread, instance) < 0 ) goto fail;
1564 return instance;
1566 fail:
1567 if ( FPI_Mem_Free ) {
1568 if ( instance->buffer[0] ) {
1569 FPI_Mem_Free(instance->buffer[0]);
1571 if ( instance->buffer[1] ) {
1572 FPI_Mem_Free(instance->buffer[1]);
1574 FPI_Mem_Free(instance);
1576 return 0;
1579 static int FPX_VideoInput_Close(void *ptr)
1581 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1582 void *retVal = 0;
1584 instance->signal = 1;
1586 if ( instance->thread ) {
1587 pthread_join(instance->thread,&retVal);
1590 if ( instance->v4l_fd ) {
1591 close(instance->v4l_fd);
1594 if ( FPI_Mem_Free ) {
1595 if ( instance->buffer[0] ) {
1596 FPI_Mem_Free(instance->buffer[0]);
1598 if ( instance->buffer[1] ) {
1599 FPI_Mem_Free(instance->buffer[1]);
1601 FPI_Mem_Free(instance);
1604 return 0;
1607 static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes)
1609 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1610 int ix, iy, ox, oy, ow, oh, dx, dy, Y, U, V, R, G, B;
1611 unsigned char *y, *u, *v;
1613 switch(instance->picture.palette) {
1614 case VIDEO_PALETTE_YUV420P: {
1615 ow = instance->window.width;
1616 oh = instance->window.height;
1618 dx = (ow<<16) / width;
1619 dy = (oh<<16) / height;
1621 y = (unsigned char *)instance->buffer[instance->buffercurrent^1];
1622 u = y + ow * oh;
1623 v = u + ow * oh / 4;
1625 oy = 0;
1627 for ( iy = 0; iy < height; iy++ ) {
1629 ox = 0;
1631 for ( ix = 0; ix < width; ix++ ) {
1633 Y = ( 149 * ((int)(y[(oy>>16)*(ow )+(ox>>16)]) - 16) ) / 2;
1634 U = (int)(u[(oy>>17)*(ow/2)+(ox>>17)]) - 128;
1635 V = (int)(v[(oy>>17)*(ow/2)+(ox>>17)]) - 128;
1637 R = (Y + V * 102 ) / 64;
1638 G = (Y - V * 52 - U * 25 ) / 64;
1639 B = (Y + U * 129 ) / 64;
1641 R = R < 0 ? 0 : ( R > 255 ? 255 : R );
1642 G = G < 0 ? 0 : ( G > 255 ? 255 : G );
1643 B = B < 0 ? 0 : ( B > 255 ? 255 : B );
1645 data[ix*3+0] = R;
1646 data[ix*3+1] = G;
1647 data[ix*3+2] = B;
1649 ox += dx;
1652 oy += dy;
1654 data += pitch_n_bytes;
1656 } break;
1657 default:
1658 goto fail;
1661 instance->buffercurrent ^= 1;
1663 return 0;
1665 fail:
1666 return -1;
1668 #endif // V4L1