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 <samplerate.h>
198 static struct FPX_Functions fpx_functions
;
200 static T_FPI_Mem_Alloc FPI_Mem_Alloc
= 0;
201 static T_FPI_Mem_Free FPI_Mem_Free
= 0;
203 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
204 static T_FPI_SoundOutput_FillBuffer FPI_SoundOutput_FillBuffer
= 0;
205 #endif // defined(ALSA) || defined(OSS)
207 void *FPX_Init(void *ptr
)
209 struct FPI_Functions
*fpi_functions
;
210 if ( !ptr
) return 0;
213 // Setup imported functions
216 fpi_functions
= (struct FPI_Functions
*)ptr
;
218 if ( fpi_functions
->fpi_count
>= 1 ) FPI_Mem_Alloc
= fpi_functions
->fpi_mem_alloc
; // 1
219 if ( fpi_functions
->fpi_count
>= 2 ) FPI_Mem_Free
= fpi_functions
->fpi_mem_free
; // 2
221 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
222 if ( fpi_functions
->fpi_count
>= 3 ) FPI_SoundOutput_FillBuffer
= fpi_functions
->fpi_soundoutput_fillbuffer
; // 3
223 #endif // defined(ALSA) || defined(OSS)
226 // Setup exported functions
229 memset(&fpx_functions
, 0, sizeof(fpx_functions
));
231 fpx_functions
.fpx_shutdown
= FPX_Shutdown
; // 1
233 #if defined(OPENSSL) || defined(GNUTLS)
234 fpx_functions
.fpx_sslsocket_create
= FPX_SSLSocket_Create
; // 2
235 fpx_functions
.fpx_sslsocket_destroy
= FPX_SSLSocket_Destroy
; // 3
236 fpx_functions
.fpx_sslsocket_connect
= FPX_SSLSocket_Connect
; // 4
237 fpx_functions
.fpx_sslsocket_receive
= FPX_SSLSocket_Receive
; // 5
238 fpx_functions
.fpx_sslsocket_send
= FPX_SSLSocket_Send
; // 6
239 #endif // defined(OPENSSL) || defined(GNUTLS)
241 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
242 fpx_functions
.fpx_soundoutput_open
= FPX_SoundOutput_Open
; // 7
243 fpx_functions
.fpx_soundoutput_close
= FPX_SoundOutput_Close
; // 8
244 fpx_functions
.fpx_soundoutput_latency
= FPX_SoundOutput_Latency
; // 9
245 #endif // defined(ALSA) || defined(OSS)
248 fpx_functions
.fpx_videoinput_open
= FPX_VideoInput_Open
; // 10
249 fpx_functions
.fpx_videoinput_close
= FPX_VideoInput_Close
; // 11
250 fpx_functions
.fpx_videoinput_getframe
= FPX_VideoInput_GetFrame
; // 12
253 fpx_functions
.fpx_count
= 14;
257 #elif defined(GNUTLS)
258 gnutls_global_init();
261 return (void *)&fpx_functions
;
264 static void FPX_Shutdown(void)
268 #elif defined(GNUTLS)
269 gnutls_global_deinit();
274 // SSL support functions
278 struct SSL_Instance
{
283 static void *FPX_SSLSocket_Create(int socket_fd
)
284 // return = instance pointer
286 struct SSL_Instance
*instance
= (struct SSL_Instance
*)FPI_Mem_Alloc(sizeof(struct SSL_Instance
));
287 memset(instance
,0,sizeof(struct SSL_Instance
));
289 if ( ( instance
->sslCtx
= SSL_CTX_new( TLSv1_client_method() ) ) == 0 ) goto fail
;
291 if ( ( instance
->ssl
= SSL_new(instance
->sslCtx
) ) == 0 ) goto fail
;
293 if ( SSL_set_fd(instance
->ssl
, socket_fd
) < 0 ) goto fail
;
295 return (void *)instance
;
297 if ( instance
->ssl
) {
298 SSL_shutdown(instance
->ssl
);
301 if ( instance
->sslCtx
) {
302 SSL_CTX_free(instance
->sslCtx
);
305 if (FPI_Mem_Free
) FPI_Mem_Free(instance
);
310 static int FPX_SSLSocket_Destroy(void *ptr
)
311 // ptr = instance pointer
312 // return = 0 on sucess, < 0 on error
314 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
316 if ( instance
->ssl
) {
317 SSL_shutdown(instance
->ssl
);
320 if ( instance
->sslCtx
) {
321 SSL_CTX_free(instance
->sslCtx
);
324 if (FPI_Mem_Free
) FPI_Mem_Free(instance
);
329 static int FPX_SSLSocket_Connect(void *ptr
)
330 // ptr = instance pointer
331 // socket_fd = BSD socket fd to be associated with SSL connection
332 // return = 0 on sucess, < 0 on error
334 // Flash Player will use errno to obtain current status
336 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
337 return SSL_connect(instance
->ssl
);
340 static int FPX_SSLSocket_Receive(void *ptr
, char *buffer
, int n_bytes
)
341 // ptr = instance pointer
342 // buffer = raw buffer to place received data into
343 // n_bytes = length of buffer in bytes
344 // return = actual bytes received, < 0 on error
346 // Flash Player will use errno to obtain current status
348 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
349 return SSL_read(instance
->ssl
, buffer
, n_bytes
);
352 static int FPX_SSLSocket_Send(void *ptr
, const char *buffer
, int n_bytes
)
353 // ptr = instance pointer
354 // buffer = raw buffer to be sent
355 // n_bytes = length of input buffer in bytes
356 // return = actual bytes sent, < 0 on error
358 // Flash Player will use errno to obtain current status
360 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
361 return SSL_write(instance
->ssl
, buffer
, n_bytes
);
363 #elif defined(GNUTLS)
364 struct SSL_Instance
{
365 gnutls_session_t session
;
366 gnutls_anon_client_credentials_t anoncred
;
369 static void *FPX_SSLSocket_Create(int socket_fd
)
370 // return = instance pointer
372 const int kx_prio
[] = { GNUTLS_KX_ANON_DH
, 0 };
374 struct SSL_Instance
*instance
= (struct SSL_Instance
*)FPI_Mem_Alloc(sizeof(struct SSL_Instance
));
375 memset(instance
,0,sizeof(struct SSL_Instance
));
377 if ( gnutls_anon_allocate_client_credentials(&instance
->anoncred
) < 0 ) goto fail
;
379 if ( gnutls_init(&instance
->session
, GNUTLS_CLIENT
) < 0 ) goto fail
;
381 if ( gnutls_set_default_priority(instance
->session
) < 0 ) goto fail
;
383 if ( gnutls_kx_set_priority(instance
->session
, kx_prio
) < 0 ) goto fail
;
385 if ( gnutls_credentials_set(instance
->session
, GNUTLS_CRD_ANON
, instance
->anoncred
) < 0 ) goto fail
;
387 gnutls_transport_set_ptr(instance
->session
, (gnutls_transport_ptr_t
)socket_fd
);
389 return (void *)instance
;
392 if ( instance
->session
) {
393 gnutls_deinit(instance
->session
);
396 if ( instance
->anoncred
) {
397 gnutls_anon_free_client_credentials(instance
->anoncred
);
400 if (FPI_Mem_Free
) FPI_Mem_Free(instance
);
405 static int FPX_SSLSocket_Destroy(void *ptr
)
406 // ptr = instance pointer
407 // return = 0 on sucess, < 0 on error
409 struct SSL_Instance
*instance
= (struct SSL_Instance
*)FPI_Mem_Alloc(sizeof(struct SSL_Instance
));
411 gnutls_bye(instance
->session
, GNUTLS_SHUT_RDWR
);
413 gnutls_deinit(instance
->session
);
415 gnutls_anon_free_client_credentials(instance
->anoncred
);
417 if (FPI_Mem_Free
) FPI_Mem_Free(instance
);
422 static int FPX_SSLSocket_Connect(void *ptr
)
423 // ptr = instance pointer
424 // socket_fd = BSD socket fd to be associated with SSL connection
425 // return = 0 on sucess, < 0 on error
427 // Flash Player will use errno to obtain current status
429 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
430 return gnutls_handshake(instance
->session
);
433 static int FPX_SSLSocket_Receive(void *ptr
, char *buffer
, int n_bytes
)
434 // ptr = instance pointer
435 // buffer = raw buffer to place received data into
436 // n_bytes = length of buffer in bytes
437 // return = actual bytes received, < 0 on error
439 // Flash Player will use errno to obtain current status
441 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
442 return gnutls_record_recv(instance
->session
, buffer
, n_bytes
);
445 static int FPX_SSLSocket_Send(void *ptr
, const char *buffer
, int n_bytes
)
446 // ptr = instance pointer
447 // buffer = raw buffer to be sent
448 // n_bytes = length of input buffer in bytes
449 // return = actual bytes sent, < 0 on error
451 // Flash Player will use errno to obtain current status
453 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
454 return gnutls_record_send(instance
->session
, buffer
, n_bytes
);
459 // Sound support functions
462 struct SoundOutput_Instance
{
464 snd_async_handler_t
* async_handler
;
468 snd_pcm_sframes_t buffer_size
;
469 snd_pcm_sframes_t period_size
;
470 snd_pcm_sframes_t buffer_pos
;
474 static void *alsa_thread(void *ptr
)
476 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
477 snd_pcm_sframes_t avail
= 0;
484 err
= sem_wait(&instance
->semaphore
);
485 if ( !instance
->handle
) {
496 if ( instance
->buffer_pos
<= 0 ) {
497 FPI_SoundOutput_FillBuffer(ptr
, instance
->buffer
, snd_pcm_frames_to_bytes(instance
->handle
, instance
->period_size
));
498 instance
->buffer_pos
= instance
->period_size
;
499 instance
->buffer_ptr
= instance
->buffer
;
502 state
= snd_pcm_state(instance
->handle
);
503 if(state
!= SND_PCM_STATE_RUNNING
&& state
!= SND_PCM_STATE_PREPARED
) {
504 snd_pcm_prepare(instance
->handle
);
506 result
= snd_pcm_writei(instance
->handle
, instance
->buffer_ptr
, instance
->buffer_pos
);
510 snd_pcm_prepare(instance
->handle
);
513 err
= snd_pcm_resume(instance
->handle
);
515 snd_pcm_prepare(instance
->handle
);
521 instance
->buffer_pos
-= result
;
522 instance
->buffer_ptr
+= snd_pcm_frames_to_bytes(instance
->handle
, result
);
524 } while (instance
->buffer_pos
);
525 avail
= snd_pcm_avail_update(instance
->handle
);
529 snd_pcm_prepare(instance
->handle
);
532 err
= snd_pcm_resume(instance
->handle
);
534 snd_pcm_prepare(instance
->handle
);
541 } while(avail
>= instance
->period_size
);
545 static void alsa_callback(snd_async_handler_t
*ahandler
)
547 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)snd_async_handler_get_callback_private(ahandler
);
548 // signal mixer thread
549 sem_post(&instance
->semaphore
);
552 static void *FPX_SoundOutput_Open()
553 // return = instance pointer
555 struct SoundOutput_Instance
*instance
= 0;
556 snd_pcm_hw_params_t
*hwparams
= 0;
557 snd_pcm_sw_params_t
*swparams
= 0;
558 snd_pcm_format_t pcm_format
;
559 unsigned int buffer_time
= 500000;
560 unsigned int period_time
= 20000;
561 unsigned int actual_rate
;
562 snd_pcm_uframes_t size
;
567 if ( !FPI_SoundOutput_FillBuffer
) goto fail
;
568 if ( !FPI_Mem_Alloc
) goto fail
;
570 instance
= FPI_Mem_Alloc(sizeof(struct SoundOutput_Instance
));
571 memset(instance
,0,sizeof(struct SoundOutput_Instance
));
573 if ( ( err
= snd_pcm_open(&instance
->handle
, "default", SND_PCM_STREAM_PLAYBACK
, SND_PCM_NONBLOCK
) ) < 0) {
574 if ( ( err
= snd_pcm_open(&instance
->handle
, "plughw:0,0", SND_PCM_STREAM_PLAYBACK
, SND_PCM_NONBLOCK
) ) < 0) {
579 snd_pcm_hw_params_alloca(&hwparams
);
580 snd_pcm_sw_params_alloca(&swparams
);
582 if (snd_pcm_hw_params_any(instance
->handle
, hwparams
) < 0) goto fail
;
584 if (snd_pcm_hw_params_set_access(instance
->handle
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
) < 0) goto fail
;
586 pcm_format
= SND_PCM_FORMAT_S16_LE
;
588 if (snd_pcm_hw_params_set_format(instance
->handle
, hwparams
, pcm_format
) < 0) goto fail
;
590 if (snd_pcm_hw_params_set_channels(instance
->handle
, hwparams
, 2) < 0) goto fail
;
594 if (snd_pcm_hw_params_set_rate_near(instance
->handle
, hwparams
, &actual_rate
, 0) < 0) goto fail
;
596 if (actual_rate
!= 44100) goto fail
;
598 if (snd_pcm_hw_params_set_buffer_time_near(instance
->handle
, hwparams
, &buffer_time
, &direction
) < 0) goto fail
;
600 if (snd_pcm_hw_params_get_buffer_size(hwparams
, &size
) < 0) goto fail
;
602 instance
->buffer_size
= (snd_pcm_sframes_t
)size
;
604 if (snd_pcm_hw_params_set_period_time_near(instance
->handle
, hwparams
, &period_time
, &direction
) < 0) goto fail
;
606 if (snd_pcm_hw_params_get_period_size(hwparams
, &size
, &direction
) < 0) goto fail
;
608 instance
->period_size
= (snd_pcm_sframes_t
)size
;
610 if (snd_pcm_hw_params(instance
->handle
, hwparams
) < 0) goto fail
;
612 if (snd_pcm_sw_params_current(instance
->handle
, swparams
) < 0) goto fail
;
614 if (snd_pcm_sw_params_set_start_threshold(instance
->handle
, swparams
, ((instance
->buffer_size
-1) / instance
->period_size
) * instance
->period_size
) < 0) goto fail
;
616 if (snd_pcm_sw_params_set_stop_threshold(instance
->handle
, swparams
, ~0U) < 0) goto fail
;
618 if (snd_pcm_sw_params_set_avail_min(instance
->handle
, swparams
, instance
->period_size
) < 0) goto fail
;
620 if (snd_pcm_sw_params_set_xfer_align(instance
->handle
, swparams
, 1) < 0) goto fail
;
622 if (snd_pcm_sw_params(instance
->handle
, swparams
) < 0) goto fail
;
624 if (snd_async_add_pcm_handler(&instance
->async_handler
, instance
->handle
, &alsa_callback
, instance
) < 0) goto fail
;
626 if ( ( instance
->buffer
= FPI_Mem_Alloc(instance
->buffer_size
* 2 * 2 * 2) ) == 0 ) goto fail
;
628 if ( pthread_create(&instance
->thread
, 0, alsa_thread
, instance
) < 0 ) goto fail
;
630 sem_post(&instance
->semaphore
);
636 if ( instance
->handle
) {
637 snd_pcm_drop(instance
->handle
);
638 snd_pcm_close(instance
->handle
);
639 instance
->handle
= 0;
641 if ( instance
->thread
) {
642 sem_post(&instance
->semaphore
);
643 sem_destroy(&instance
->semaphore
);
644 pthread_join(instance
->thread
,&retVal
);
646 if ( instance
->buffer
) {
647 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
->buffer
);
649 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
);
654 static int FPX_SoundOutput_Close(void *ptr
)
655 // ptr = instance pointer
656 // return = 0 on success, < 0 on error
658 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
660 if ( instance
->handle
) {
661 snd_pcm_drop(instance
->handle
);
662 snd_pcm_close(instance
->handle
);
663 instance
->handle
= 0;
665 if ( instance
->thread
) {
666 sem_post(&instance
->semaphore
);
667 sem_destroy(&instance
->semaphore
);
668 pthread_join(instance
->thread
,&retVal
);
670 if ( instance
->buffer
) {
671 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
->buffer
);
673 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
);
677 static int FPX_SoundOutput_Latency(void *ptr
)
678 // ptr = instance pointer
679 // return = 0 on success, < 0 on error
681 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
682 if ( instance
->handle
) {
683 snd_pcm_sframes_t delay
= 0;
684 snd_pcm_delay(instance
->handle
, &delay
);
685 if ( snd_pcm_state(instance
->handle
) == SND_PCM_STATE_RUNNING
&& delay
> 0 ) {
694 struct SoundOutput_Instance
{
700 static void *oss_thread(void *ptr
)
702 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
707 FPI_SoundOutput_FillBuffer(ptr
,buffer
,4096);
710 written
= write(instance
->oss_fd
, buffer
, len
);
711 if ( written
>= 0 ) {
714 if ( instance
->signal
) {
724 static void *FPX_SoundOutput_Open()
725 // return = instance pointer
727 struct SoundOutput_Instance
*instance
= 0;
728 int format
= AFMT_S16_LE
;
732 if ( !FPI_SoundOutput_FillBuffer
) goto fail
;
733 if ( !FPI_Mem_Alloc
) goto fail
;
735 instance
= (struct SoundOutput_Instance
*)FPI_Mem_Alloc(sizeof(struct SoundOutput_Instance
));
736 memset(instance
,0,sizeof(struct SoundOutput_Instance
));
738 if ( ( instance
->oss_fd
= open("/dev/dsp",O_WRONLY
) ) < 0 ) goto fail
;
740 if ( ioctl(instance
->oss_fd
, SNDCTL_DSP_SETFMT
, &format
) < 0 ) goto fail
;
742 if ( ioctl(instance
->oss_fd
, SNDCTL_DSP_STEREO
, &stereo
) < 0 ) goto fail
;
744 if ( ioctl(instance
->oss_fd
, SNDCTL_DSP_SPEED
, &speed
) < 0 ) goto fail
;
746 if ( pthread_create(&instance
->thread
, 0, oss_thread
, instance
) < 0 ) goto fail
;
751 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
);
756 static int FPX_SoundOutput_Close(void *ptr
)
757 // ptr = instance pointer
758 // return = 0 on success, < 0 on error
760 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
763 instance
->signal
= 1;
765 if ( instance
->oss_fd
) {
766 ioctl(instance
->oss_fd
, SNDCTL_DSP_RESET
, 0);
769 if ( instance
->thread
) {
770 pthread_join(instance
->thread
,&retVal
);
773 if ( instance
->oss_fd
) {
774 close(instance
->oss_fd
);
777 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
);
782 static int FPX_SoundOutput_Latency(void *ptr
)
783 // ptr = instance pointer
784 // return = 0 on success, < 0 on error
786 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
787 if ( instance
->oss_fd
) {
789 if ( ( value
= ioctl(instance
->oss_fd
,SNDCTL_DSP_GETODELAY
,&value
) ) == 0 ) {
796 #endif // defined(OSS)
800 #define BUFSIZE (4096)
803 pa_threaded_mainloop
*mainloop
;
806 uint8_t buf
[BUFSIZE
];
811 static void context_state_cb(pa_context
*c
, void *userdata
) {
812 struct output_data
*p
= userdata
;
817 p
->thread_id
= pthread_self();
820 switch (pa_context_get_state(c
)) {
821 case PA_CONTEXT_READY
:
822 case PA_CONTEXT_TERMINATED
:
823 case PA_CONTEXT_FAILED
:
824 pa_threaded_mainloop_signal(p
->mainloop
, 0);
827 case PA_CONTEXT_UNCONNECTED
:
828 case PA_CONTEXT_CONNECTING
:
829 case PA_CONTEXT_AUTHORIZING
:
830 case PA_CONTEXT_SETTING_NAME
:
835 static void stream_state_cb(pa_stream
*s
, void *userdata
) {
836 struct output_data
*p
= userdata
;
841 p
->thread_id
= pthread_self();
844 switch (pa_stream_get_state(s
)) {
846 case PA_STREAM_READY
:
847 case PA_STREAM_FAILED
:
848 case PA_STREAM_TERMINATED
:
849 pa_threaded_mainloop_signal(p
->mainloop
, 0);
852 case PA_STREAM_UNCONNECTED
:
853 case PA_STREAM_CREATING
:
858 static void write_data(struct output_data
*p
) {
863 /* Wait until timing info is available before we write the second
864 * and all subsequent blocks */
865 if (!p
->first
&& !pa_stream_get_timing_info(p
->stream
))
868 length
= pa_stream_writable_size(p
->stream
);
878 FPI_SoundOutput_FillBuffer(p
, (char*) p
->buf
, l
);
880 if (pa_stream_write(p
->stream
, p
->buf
, l
, NULL
, 0, PA_SEEK_RELATIVE
) < 0)
889 /* There's no real handling of errors here. Unfortunately the
890 * Flash API doesn't export a sane way to do this. With networked
891 * audio streams and hotplug-capable audio devices the audio
892 * stream might be killed in the middle of nothing, hence it is
893 * very unfortunate that we cannot report errors that happen here
896 p
->first
= 0; /* So, we write the first block noch, remember that */
899 static void stream_request_cb(pa_stream
*s
, size_t length
, void *userdata
) {
900 struct output_data
*p
= userdata
;
906 p
->thread_id
= pthread_self();
908 /* Write some data */
912 static void stream_latency_update_cb(pa_stream
*s
, void *userdata
) {
913 struct output_data
*p
= userdata
;
918 p
->thread_id
= pthread_self();
920 /* Try to write some more, in case we delayed the first write until latency data became available */
924 static void *FPX_SoundOutput_Open(void) {
926 static const pa_sample_spec ss
= {
927 .format
= PA_SAMPLE_S16LE
, /* Hmm, Flash wants LE here, not
928 * NE. This makes porting Flash to
929 * Big-Endian machines unnecessary
935 struct output_data
*p
;
937 /* Unfortunately we cannot report any useful error string back to
938 * Flash. It would be highly preferable if Flash supported some
939 * way how we could tell the user what the reason is why audio is
940 * not working for him. */
942 if (!(p
= FPI_Mem_Alloc(sizeof(struct output_data
))))
945 memset(p
, 0, sizeof(*p
));
947 p
->thread_id
= (pthread_t
) 0;
949 /* First, let's create the main loop */
950 if (!(p
->mainloop
= pa_threaded_mainloop_new()))
953 /* Second, initialize the connection context */
954 if (!(p
->context
= pa_context_new(pa_threaded_mainloop_get_api(p
->mainloop
), "Adobe Flash")))
957 pa_context_set_state_callback(p
->context
, context_state_cb
, p
);
959 if (pa_context_connect(p
->context
, NULL
, 0, NULL
) < 0)
962 /* Now, let's start the background thread */
963 pa_threaded_mainloop_lock(p
->mainloop
);
965 if (pa_threaded_mainloop_start(p
->mainloop
) < 0)
968 /* Wait until the context is ready */
969 pa_threaded_mainloop_wait(p
->mainloop
);
971 if (pa_context_get_state(p
->context
) != PA_CONTEXT_READY
)
972 goto unlock_and_fail
;
974 /* Now, initialize the stream */
975 if (!(p
->stream
= pa_stream_new(p
->context
, "Flash Animation", &ss
, NULL
)))
976 goto unlock_and_fail
;
978 pa_stream_set_state_callback(p
->stream
, stream_state_cb
, p
);
979 pa_stream_set_write_callback(p
->stream
, stream_request_cb
, p
);
980 pa_stream_set_latency_update_callback(p
->stream
, stream_latency_update_cb
, p
);
982 if (pa_stream_connect_playback(p
->stream
, NULL
, NULL
, PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_AUTO_TIMING_UPDATE
, NULL
, NULL
) < 0)
983 goto unlock_and_fail
;
985 /* Wait until the stream is ready */
986 pa_threaded_mainloop_wait(p
->mainloop
);
988 if (pa_stream_get_state(p
->stream
) != PA_STREAM_READY
)
989 goto unlock_and_fail
;
991 pa_threaded_mainloop_unlock(p
->mainloop
);
997 pa_threaded_mainloop_unlock(p
->mainloop
);
1001 FPX_SoundOutput_Close(p
);
1006 static int FPX_SoundOutput_Close(void *ptr
) {
1007 struct output_data
*p
= ptr
;
1012 pa_threaded_mainloop_stop(p
->mainloop
);
1015 pa_stream_disconnect(p
->stream
);
1016 pa_stream_unref(p
->stream
);
1020 pa_context_disconnect(p
->context
);
1021 pa_context_unref(p
->context
);
1025 pa_threaded_mainloop_free(p
->mainloop
);
1033 static int FPX_SoundOutput_Latency(void *ptr
) {
1034 struct output_data
*p
= ptr
;
1041 /* We lock here only if we are not called from our event loop thread */
1042 if (!p
->thread_id
|| !pthread_equal(p
->thread_id
, pthread_self()))
1043 pa_threaded_mainloop_lock(p
->mainloop
);
1045 if (pa_stream_get_latency(p
->stream
, &t
, &negative
) < 0 || negative
)
1048 r
= (int) (pa_usec_to_bytes(t
, pa_stream_get_sample_spec(p
->stream
)) >> 2);
1050 if (!p
->thread_id
|| !pthread_equal(p
->thread_id
, pthread_self()))
1051 pa_threaded_mainloop_unlock(p
->mainloop
);
1060 struct jack_output_data
{
1061 jack_client_t
*client
;
1062 jack_port_t
*port_l
;
1063 jack_port_t
*port_r
;
1071 static int jack_process_cb( jack_nframes_t nframes
, void *arg
) {
1072 struct jack_output_data
*p
= arg
;
1074 int jack_rate
= jack_get_sample_rate( p
->client
);
1075 int flash_frames
= nframes
* 44100 / jack_rate
;
1077 size_t bufsize
= 2*flash_frames
* sizeof( int16_t );
1078 int16_t *buffer
= alloca( bufsize
);
1079 float *float_buf
= alloca( flash_frames
* sizeof(float) );
1081 float *port_l
= jack_port_get_buffer( p
->port_l
, nframes
);
1082 float *port_r
= jack_port_get_buffer( p
->port_r
, nframes
);
1087 FPI_SoundOutput_FillBuffer(p
, (char*) buffer
, bufsize
);
1089 for( i
=0; i
<flash_frames
; i
++ ) {
1090 float_buf
[i
] = (float) (buffer
[2*i
]) / 32768.0;
1093 sd
.data_in
= float_buf
;
1094 sd
.data_out
= port_l
;
1095 sd
.input_frames
= flash_frames
;
1096 sd
.output_frames
= nframes
;
1097 sd
.end_of_input
= 0;
1098 // sd.src_ratio = (double)flash_frames / (double)nframes;
1099 sd
.src_ratio
= (double)nframes
/ (double)flash_frames
;
1101 src_process( p
->src_l
, &sd
);
1104 for( i
=0; i
<flash_frames
; i
++ ) {
1105 float_buf
[i
] = (float) (buffer
[2*i
+1]) / 32768.0;
1108 sd
.data_in
= float_buf
;
1109 sd
.data_out
= port_r
;
1110 sd
.input_frames
= flash_frames
;
1111 sd
.output_frames
= nframes
;
1112 sd
.end_of_input
= 0;
1113 // sd.src_ratio = (double)flash_frames / (double)nframes;
1114 sd
.src_ratio
= (double)nframes
/ (double)flash_frames
;
1116 src_process( p
->src_r
, &sd
);
1121 static void *FPX_SoundOutput_Open(void) {
1123 struct jack_output_data
*p
=NULL
;
1126 /* Unfortunately we cannot report any useful error string back to
1127 * Flash. It would be highly preferable if Flash supported some
1128 * way how we could tell the user what the reason is why audio is
1129 * not working for him. */
1131 if (!(p
= FPI_Mem_Alloc(sizeof(struct jack_output_data
))))
1134 memset(p
, 0, sizeof(*p
));
1136 p
->src_l
= src_new(SRC_SINC_FASTEST
, 1, & (p
->src_error
));
1137 p
->src_r
= src_new(SRC_SINC_FASTEST
, 1, & (p
->src_error
));
1139 /* First, let's create the main loop */
1140 if (!(p
->client
= jack_client_open( "flash", 0, NULL
)))
1143 /* Second, initialize the connection context */
1144 if (!(p
->port_l
= jack_port_register( p
->client
, "out1", JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0)) )
1146 if (!(p
->port_r
= jack_port_register( p
->client
, "out2", JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0)) )
1149 jack_set_process_callback( p
->client
, jack_process_cb
, p
);
1150 jack_activate( p
->client
);
1152 snprintf( namebuf
, 99, "%s:out1", jack_get_client_name( p
->client
) );
1153 jack_connect( p
->client
, namebuf
, "system:playback_1" );
1154 snprintf( namebuf
, 99, "%s:out2", jack_get_client_name( p
->client
) );
1155 jack_connect( p
->client
, namebuf
, "system:playback_2" );
1161 FPX_SoundOutput_Close(p
);
1166 static int FPX_SoundOutput_Close(void *ptr
) {
1167 struct jack_output_data
*p
= ptr
;
1172 jack_deactivate( p
->client
);
1173 jack_client_close( p
->client
);
1179 static int FPX_SoundOutput_Latency(void *ptr
) {
1180 // heh ? jack has no latency :P
1187 struct VideoOutput_Instance
{
1194 struct video_window window
;
1195 struct video_picture picture
;
1198 static void *v4l_thread(void *ptr
)
1200 struct VideoOutput_Instance
*instance
= (struct VideoOutput_Instance
*)ptr
;
1206 result
= read(instance
->v4l_fd
, instance
->buffer
[instance
->buffercurrent
], instance
->buffersize
);
1214 if ( instance
->signal
) {
1216 ioctl(instance
->v4l_fd
, VIDIOCCAPTURE
, &status
);
1223 static void *FPX_VideoInput_Open(void)
1225 struct VideoOutput_Instance
*instance
= 0;
1227 if ( !FPI_Mem_Alloc
) goto fail
;
1229 instance
= (struct VideoOutput_Instance
*)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance
));
1230 memset(instance
,0,sizeof(struct VideoOutput_Instance
));
1232 if ( ( instance
->v4l_fd
= open("/dev/video", O_RDONLY
) ) < 0 ) goto fail
;
1234 if ( ioctl(instance
->v4l_fd
, VIDIOCGPICT
, &instance
->picture
) < 0 ) goto fail
;
1236 switch(instance
->picture
.palette
) {
1237 case VIDEO_PALETTE_YUV420P
:
1239 case VIDEO_PALETTE_RGB24
:
1240 case VIDEO_PALETTE_YUV422P
:
1241 case VIDEO_PALETTE_YUV411P
:
1242 case VIDEO_PALETTE_YUV410P
:
1243 case VIDEO_PALETTE_GREY
:
1244 case VIDEO_PALETTE_HI240
:
1245 case VIDEO_PALETTE_RGB565
:
1246 case VIDEO_PALETTE_RGB32
:
1247 case VIDEO_PALETTE_RGB555
:
1248 case VIDEO_PALETTE_YUV422
:
1249 case VIDEO_PALETTE_YUYV
:
1250 case VIDEO_PALETTE_UYVY
:
1251 case VIDEO_PALETTE_YUV420
:
1252 case VIDEO_PALETTE_YUV411
:
1253 case VIDEO_PALETTE_RAW
:
1258 if( ioctl(instance
->v4l_fd
, VIDIOCGWIN
, &instance
->window
) < 0 ) goto fail
;
1260 instance
->buffer
[0] = FPI_Mem_Alloc(instance
->window
.width
* instance
->window
.height
* 2);
1261 instance
->buffer
[1] = FPI_Mem_Alloc(instance
->window
.width
* instance
->window
.height
* 2);
1263 if ( pthread_create(&instance
->thread
, 0, v4l_thread
, instance
) < 0 ) goto fail
;
1268 if ( FPI_Mem_Free
) {
1269 if ( instance
->buffer
[0] ) {
1270 FPI_Mem_Free(instance
->buffer
[0]);
1272 if ( instance
->buffer
[1] ) {
1273 FPI_Mem_Free(instance
->buffer
[1]);
1275 FPI_Mem_Free(instance
);
1280 static int FPX_VideoInput_Close(void *ptr
)
1282 struct VideoOutput_Instance
*instance
= (struct VideoOutput_Instance
*)ptr
;
1285 instance
->signal
= 1;
1287 if ( instance
->thread
) {
1288 pthread_join(instance
->thread
,&retVal
);
1291 if ( instance
->v4l_fd
) {
1292 close(instance
->v4l_fd
);
1295 if ( FPI_Mem_Free
) {
1296 if ( instance
->buffer
[0] ) {
1297 FPI_Mem_Free(instance
->buffer
[0]);
1299 if ( instance
->buffer
[1] ) {
1300 FPI_Mem_Free(instance
->buffer
[1]);
1302 FPI_Mem_Free(instance
);
1308 static int FPX_VideoInput_GetFrame(void *ptr
, char *data
, int width
, int height
, int pitch_n_bytes
)
1310 struct VideoOutput_Instance
*instance
= (struct VideoOutput_Instance
*)ptr
;
1311 int ix
, iy
, ox
, oy
, ow
, oh
, dx
, dy
, Y
, U
, V
, R
, G
, B
;
1312 unsigned char *y
, *u
, *v
;
1314 switch(instance
->picture
.palette
) {
1315 case VIDEO_PALETTE_YUV420P
: {
1316 ow
= instance
->window
.width
;
1317 oh
= instance
->window
.height
;
1319 dx
= (ow
<<16) / width
;
1320 dy
= (oh
<<16) / height
;
1322 y
= (unsigned char *)instance
->buffer
[instance
->buffercurrent
^1];
1324 v
= u
+ ow
* oh
/ 4;
1328 for ( iy
= 0; iy
< height
; iy
++ ) {
1332 for ( ix
= 0; ix
< width
; ix
++ ) {
1334 Y
= ( 149 * ((int)(y
[(oy
>>16)*(ow
)+(ox
>>16)]) - 16) ) / 2;
1335 U
= (int)(u
[(oy
>>17)*(ow
/2)+(ox
>>17)]) - 128;
1336 V
= (int)(v
[(oy
>>17)*(ow
/2)+(ox
>>17)]) - 128;
1338 R
= (Y
+ V
* 102 ) / 64;
1339 G
= (Y
- V
* 52 - U
* 25 ) / 64;
1340 B
= (Y
+ U
* 129 ) / 64;
1342 R
= R
< 0 ? 0 : ( R
> 255 ? 255 : R
);
1343 G
= G
< 0 ? 0 : ( G
> 255 ? 255 : G
);
1344 B
= B
< 0 ? 0 : ( B
> 255 ? 255 : B
);
1355 data
+= pitch_n_bytes
;
1362 instance
->buffercurrent
^= 1;