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
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
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.
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!
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
{
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)
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
);
133 struct FPX_Functions
{
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
153 // END OF SHARED SECTION
155 ////////////////////////////////////////////////////////////////////////////////////////////////////
160 #include <openssl/ssl.h>
161 #elif defined(GNUTLS)
162 #include <sys/types.h>
163 #include <sys/socket.h>
164 #include <arpa/inet.h>
166 #include <gnutls/gnutls.h>
171 #include <semaphore.h>
172 #include <alsa/asoundlib.h>
176 #include <linux/soundcard.h>
177 #include <sys/ioctl.h>
184 #include <linux/videodev.h>
185 #include <sys/ioctl.h>
190 #include <pulse/pulseaudio.h>
194 #include <jack/jack.h>
195 #include <jack/ringbuffer.h>
196 #include <samplerate.h>
197 #include <semaphore.h>
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)
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
255 fpx_functions
.fpx_count
= 14;
259 #elif defined(GNUTLS)
260 gnutls_global_init();
263 return (void *)&fpx_functions
;
266 static void FPX_Shutdown(void)
270 #elif defined(GNUTLS)
271 gnutls_global_deinit();
276 // SSL support functions
280 struct SSL_Instance
{
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
;
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
);
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
);
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
;
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
);
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
);
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
);
461 // Sound support functions
464 struct SoundOutput_Instance
{
466 snd_async_handler_t
* async_handler
;
470 snd_pcm_sframes_t buffer_size
;
471 snd_pcm_sframes_t period_size
;
472 snd_pcm_sframes_t buffer_pos
;
476 static void *alsa_thread(void *ptr
)
478 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
479 snd_pcm_sframes_t avail
= 0;
486 err
= sem_wait(&instance
->semaphore
);
487 if ( !instance
->handle
) {
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
;
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
);
512 snd_pcm_prepare(instance
->handle
);
515 err
= snd_pcm_resume(instance
->handle
);
517 snd_pcm_prepare(instance
->handle
);
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
);
531 snd_pcm_prepare(instance
->handle
);
534 err
= snd_pcm_resume(instance
->handle
);
536 snd_pcm_prepare(instance
->handle
);
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
;
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) {
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
;
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
);
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
);
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
;
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
);
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 ) {
696 struct SoundOutput_Instance
{
702 static void *oss_thread(void *ptr
)
704 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
709 FPI_SoundOutput_FillBuffer(ptr
,buffer
,4096);
712 written
= write(instance
->oss_fd
, buffer
, len
);
713 if ( written
>= 0 ) {
716 if ( instance
->signal
) {
726 static void *FPX_SoundOutput_Open()
727 // return = instance pointer
729 struct SoundOutput_Instance
*instance
= 0;
730 int format
= AFMT_S16_LE
;
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
;
753 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
);
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
;
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
);
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
) {
791 if ( ( value
= ioctl(instance
->oss_fd
,SNDCTL_DSP_GETODELAY
,&value
) ) == 0 ) {
798 #endif // defined(OSS)
802 #define BUFSIZE (4096)
805 pa_threaded_mainloop
*mainloop
;
808 uint8_t buf
[BUFSIZE
];
813 static void context_state_cb(pa_context
*c
, void *userdata
) {
814 struct output_data
*p
= userdata
;
819 p
->thread_id
= pthread_self();
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);
829 case PA_CONTEXT_UNCONNECTED
:
830 case PA_CONTEXT_CONNECTING
:
831 case PA_CONTEXT_AUTHORIZING
:
832 case PA_CONTEXT_SETTING_NAME
:
837 static void stream_state_cb(pa_stream
*s
, void *userdata
) {
838 struct output_data
*p
= userdata
;
843 p
->thread_id
= pthread_self();
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);
854 case PA_STREAM_UNCONNECTED
:
855 case PA_STREAM_CREATING
:
860 static void write_data(struct output_data
*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
))
870 length
= pa_stream_writable_size(p
->stream
);
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)
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
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
;
908 p
->thread_id
= pthread_self();
910 /* Write some data */
914 static void stream_latency_update_cb(pa_stream
*s
, void *userdata
) {
915 struct output_data
*p
= userdata
;
920 p
->thread_id
= pthread_self();
922 /* Try to write some more, in case we delayed the first write until latency data became available */
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
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
))))
947 memset(p
, 0, sizeof(*p
));
949 p
->thread_id
= (pthread_t
) 0;
951 /* First, let's create the main loop */
952 if (!(p
->mainloop
= pa_threaded_mainloop_new()))
955 /* Second, initialize the connection context */
956 if (!(p
->context
= pa_context_new(pa_threaded_mainloop_get_api(p
->mainloop
), "Adobe Flash")))
959 pa_context_set_state_callback(p
->context
, context_state_cb
, p
);
961 if (pa_context_connect(p
->context
, NULL
, 0, NULL
) < 0)
964 /* Now, let's start the background thread */
965 pa_threaded_mainloop_lock(p
->mainloop
);
967 if (pa_threaded_mainloop_start(p
->mainloop
) < 0)
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
);
999 pa_threaded_mainloop_unlock(p
->mainloop
);
1003 FPX_SoundOutput_Close(p
);
1008 static int FPX_SoundOutput_Close(void *ptr
) {
1009 struct output_data
*p
= ptr
;
1014 pa_threaded_mainloop_stop(p
->mainloop
);
1017 pa_stream_disconnect(p
->stream
);
1018 pa_stream_unref(p
->stream
);
1022 pa_context_disconnect(p
->context
);
1023 pa_context_unref(p
->context
);
1027 pa_threaded_mainloop_free(p
->mainloop
);
1035 static int FPX_SoundOutput_Latency(void *ptr
) {
1036 struct output_data
*p
= ptr
;
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
)
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
);
1062 struct jack_output_data
{
1063 jack_client_t
*client
;
1064 jack_port_t
*port_l
;
1065 jack_port_t
*port_r
;
1070 jack_ringbuffer_t
*buffer
;
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
);
1086 sem_wait( &(p
->semaphore
) );
1087 FPI_SoundOutput_FillBuffer(p
, (char*) buffer
, bufsize
);
1088 jack_ringbuffer_write( p
->buffer
, (char*)buffer
, bufsize
);
1093 static int jack_process_cb( jack_nframes_t nframes
, void *arg
)
1095 struct jack_output_data
*p
= arg
;
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
);
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
) );
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" );
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
);
1155 static void *FPX_SoundOutput_Open(void) {
1157 struct jack_output_data
*p
=NULL
;
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
))))
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
)))
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)) )
1193 if (!(p
->port_r
= jack_port_register( p
->client
, "out2", JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0)) )
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" );
1208 FPX_SoundOutput_Close(p
);
1213 static int FPX_SoundOutput_Close(void *ptr
) {
1214 struct jack_output_data
*p
= ptr
;
1219 pthread_join( p
->tid
, NULL
);
1223 jack_deactivate( p
->client
);
1224 jack_client_close( p
->client
);
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;
1239 struct VideoOutput_Instance
{
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
;
1258 result
= read(instance
->v4l_fd
, instance
->buffer
[instance
->buffercurrent
], instance
->buffersize
);
1266 if ( instance
->signal
) {
1268 ioctl(instance
->v4l_fd
, VIDIOCCAPTURE
, &status
);
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
:
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
:
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
;
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
);
1332 static int FPX_VideoInput_Close(void *ptr
)
1334 struct VideoOutput_Instance
*instance
= (struct VideoOutput_Instance
*)ptr
;
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
);
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];
1376 v
= u
+ ow
* oh
/ 4;
1380 for ( iy
= 0; iy
< height
; iy
++ ) {
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
);
1407 data
+= pitch_n_bytes
;
1414 instance
->buffercurrent
^= 1;