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 <jack/thread.h>
197 #include <samplerate.h>
198 #include <semaphore.h>
201 static struct FPX_Functions fpx_functions
;
203 static T_FPI_Mem_Alloc FPI_Mem_Alloc
= 0;
204 static T_FPI_Mem_Free FPI_Mem_Free
= 0;
206 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
207 static T_FPI_SoundOutput_FillBuffer FPI_SoundOutput_FillBuffer
= 0;
208 #endif // defined(ALSA) || defined(OSS)
210 void *FPX_Init(void *ptr
)
212 struct FPI_Functions
*fpi_functions
;
213 if ( !ptr
) return 0;
216 // Setup imported functions
219 fpi_functions
= (struct FPI_Functions
*)ptr
;
221 if ( fpi_functions
->fpi_count
>= 1 ) FPI_Mem_Alloc
= fpi_functions
->fpi_mem_alloc
; // 1
222 if ( fpi_functions
->fpi_count
>= 2 ) FPI_Mem_Free
= fpi_functions
->fpi_mem_free
; // 2
224 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
225 if ( fpi_functions
->fpi_count
>= 3 ) FPI_SoundOutput_FillBuffer
= fpi_functions
->fpi_soundoutput_fillbuffer
; // 3
226 #endif // defined(ALSA) || defined(OSS)
229 // Setup exported functions
232 memset(&fpx_functions
, 0, sizeof(fpx_functions
));
234 fpx_functions
.fpx_shutdown
= FPX_Shutdown
; // 1
236 #if defined(OPENSSL) || defined(GNUTLS)
237 fpx_functions
.fpx_sslsocket_create
= FPX_SSLSocket_Create
; // 2
238 fpx_functions
.fpx_sslsocket_destroy
= FPX_SSLSocket_Destroy
; // 3
239 fpx_functions
.fpx_sslsocket_connect
= FPX_SSLSocket_Connect
; // 4
240 fpx_functions
.fpx_sslsocket_receive
= FPX_SSLSocket_Receive
; // 5
241 fpx_functions
.fpx_sslsocket_send
= FPX_SSLSocket_Send
; // 6
242 #endif // defined(OPENSSL) || defined(GNUTLS)
244 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
245 fpx_functions
.fpx_soundoutput_open
= FPX_SoundOutput_Open
; // 7
246 fpx_functions
.fpx_soundoutput_close
= FPX_SoundOutput_Close
; // 8
247 fpx_functions
.fpx_soundoutput_latency
= FPX_SoundOutput_Latency
; // 9
248 #endif // defined(ALSA) || defined(OSS)
251 fpx_functions
.fpx_videoinput_open
= FPX_VideoInput_Open
; // 10
252 fpx_functions
.fpx_videoinput_close
= FPX_VideoInput_Close
; // 11
253 fpx_functions
.fpx_videoinput_getframe
= FPX_VideoInput_GetFrame
; // 12
256 fpx_functions
.fpx_count
= 14;
260 #elif defined(GNUTLS)
261 gnutls_global_init();
264 return (void *)&fpx_functions
;
267 static void FPX_Shutdown(void)
271 #elif defined(GNUTLS)
272 gnutls_global_deinit();
277 // SSL support functions
281 struct SSL_Instance
{
286 static void *FPX_SSLSocket_Create(int socket_fd
)
287 // return = instance pointer
289 struct SSL_Instance
*instance
= (struct SSL_Instance
*)FPI_Mem_Alloc(sizeof(struct SSL_Instance
));
290 memset(instance
,0,sizeof(struct SSL_Instance
));
292 if ( ( instance
->sslCtx
= SSL_CTX_new( TLSv1_client_method() ) ) == 0 ) goto fail
;
294 if ( ( instance
->ssl
= SSL_new(instance
->sslCtx
) ) == 0 ) goto fail
;
296 if ( SSL_set_fd(instance
->ssl
, socket_fd
) < 0 ) goto fail
;
298 return (void *)instance
;
300 if ( instance
->ssl
) {
301 SSL_shutdown(instance
->ssl
);
304 if ( instance
->sslCtx
) {
305 SSL_CTX_free(instance
->sslCtx
);
308 if (FPI_Mem_Free
) FPI_Mem_Free(instance
);
313 static int FPX_SSLSocket_Destroy(void *ptr
)
314 // ptr = instance pointer
315 // return = 0 on sucess, < 0 on error
317 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
319 if ( instance
->ssl
) {
320 SSL_shutdown(instance
->ssl
);
323 if ( instance
->sslCtx
) {
324 SSL_CTX_free(instance
->sslCtx
);
327 if (FPI_Mem_Free
) FPI_Mem_Free(instance
);
332 static int FPX_SSLSocket_Connect(void *ptr
)
333 // ptr = instance pointer
334 // socket_fd = BSD socket fd to be associated with SSL connection
335 // return = 0 on sucess, < 0 on error
337 // Flash Player will use errno to obtain current status
339 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
340 return SSL_connect(instance
->ssl
);
343 static int FPX_SSLSocket_Receive(void *ptr
, char *buffer
, int n_bytes
)
344 // ptr = instance pointer
345 // buffer = raw buffer to place received data into
346 // n_bytes = length of buffer in bytes
347 // return = actual bytes received, < 0 on error
349 // Flash Player will use errno to obtain current status
351 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
352 return SSL_read(instance
->ssl
, buffer
, n_bytes
);
355 static int FPX_SSLSocket_Send(void *ptr
, const char *buffer
, int n_bytes
)
356 // ptr = instance pointer
357 // buffer = raw buffer to be sent
358 // n_bytes = length of input buffer in bytes
359 // return = actual bytes sent, < 0 on error
361 // Flash Player will use errno to obtain current status
363 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
364 return SSL_write(instance
->ssl
, buffer
, n_bytes
);
366 #elif defined(GNUTLS)
367 struct SSL_Instance
{
368 gnutls_session_t session
;
369 gnutls_anon_client_credentials_t anoncred
;
372 static void *FPX_SSLSocket_Create(int socket_fd
)
373 // return = instance pointer
375 const int kx_prio
[] = { GNUTLS_KX_ANON_DH
, 0 };
377 struct SSL_Instance
*instance
= (struct SSL_Instance
*)FPI_Mem_Alloc(sizeof(struct SSL_Instance
));
378 memset(instance
,0,sizeof(struct SSL_Instance
));
380 if ( gnutls_anon_allocate_client_credentials(&instance
->anoncred
) < 0 ) goto fail
;
382 if ( gnutls_init(&instance
->session
, GNUTLS_CLIENT
) < 0 ) goto fail
;
384 if ( gnutls_set_default_priority(instance
->session
) < 0 ) goto fail
;
386 if ( gnutls_kx_set_priority(instance
->session
, kx_prio
) < 0 ) goto fail
;
388 if ( gnutls_credentials_set(instance
->session
, GNUTLS_CRD_ANON
, instance
->anoncred
) < 0 ) goto fail
;
390 gnutls_transport_set_ptr(instance
->session
, (gnutls_transport_ptr_t
)socket_fd
);
392 return (void *)instance
;
395 if ( instance
->session
) {
396 gnutls_deinit(instance
->session
);
399 if ( instance
->anoncred
) {
400 gnutls_anon_free_client_credentials(instance
->anoncred
);
403 if (FPI_Mem_Free
) FPI_Mem_Free(instance
);
408 static int FPX_SSLSocket_Destroy(void *ptr
)
409 // ptr = instance pointer
410 // return = 0 on sucess, < 0 on error
412 struct SSL_Instance
*instance
= (struct SSL_Instance
*)FPI_Mem_Alloc(sizeof(struct SSL_Instance
));
414 gnutls_bye(instance
->session
, GNUTLS_SHUT_RDWR
);
416 gnutls_deinit(instance
->session
);
418 gnutls_anon_free_client_credentials(instance
->anoncred
);
420 if (FPI_Mem_Free
) FPI_Mem_Free(instance
);
425 static int FPX_SSLSocket_Connect(void *ptr
)
426 // ptr = instance pointer
427 // socket_fd = BSD socket fd to be associated with SSL connection
428 // return = 0 on sucess, < 0 on error
430 // Flash Player will use errno to obtain current status
432 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
433 return gnutls_handshake(instance
->session
);
436 static int FPX_SSLSocket_Receive(void *ptr
, char *buffer
, int n_bytes
)
437 // ptr = instance pointer
438 // buffer = raw buffer to place received data into
439 // n_bytes = length of buffer in bytes
440 // return = actual bytes received, < 0 on error
442 // Flash Player will use errno to obtain current status
444 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
445 return gnutls_record_recv(instance
->session
, buffer
, n_bytes
);
448 static int FPX_SSLSocket_Send(void *ptr
, const char *buffer
, int n_bytes
)
449 // ptr = instance pointer
450 // buffer = raw buffer to be sent
451 // n_bytes = length of input buffer in bytes
452 // return = actual bytes sent, < 0 on error
454 // Flash Player will use errno to obtain current status
456 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
457 return gnutls_record_send(instance
->session
, buffer
, n_bytes
);
462 // Sound support functions
465 struct SoundOutput_Instance
{
467 snd_async_handler_t
* async_handler
;
471 snd_pcm_sframes_t buffer_size
;
472 snd_pcm_sframes_t period_size
;
473 snd_pcm_sframes_t buffer_pos
;
477 static void *alsa_thread(void *ptr
)
479 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
480 snd_pcm_sframes_t avail
= 0;
487 err
= sem_wait(&instance
->semaphore
);
488 if ( !instance
->handle
) {
499 if ( instance
->buffer_pos
<= 0 ) {
500 FPI_SoundOutput_FillBuffer(ptr
, instance
->buffer
, snd_pcm_frames_to_bytes(instance
->handle
, instance
->period_size
));
501 instance
->buffer_pos
= instance
->period_size
;
502 instance
->buffer_ptr
= instance
->buffer
;
505 state
= snd_pcm_state(instance
->handle
);
506 if(state
!= SND_PCM_STATE_RUNNING
&& state
!= SND_PCM_STATE_PREPARED
) {
507 snd_pcm_prepare(instance
->handle
);
509 result
= snd_pcm_writei(instance
->handle
, instance
->buffer_ptr
, instance
->buffer_pos
);
513 snd_pcm_prepare(instance
->handle
);
516 err
= snd_pcm_resume(instance
->handle
);
518 snd_pcm_prepare(instance
->handle
);
524 instance
->buffer_pos
-= result
;
525 instance
->buffer_ptr
+= snd_pcm_frames_to_bytes(instance
->handle
, result
);
527 } while (instance
->buffer_pos
);
528 avail
= snd_pcm_avail_update(instance
->handle
);
532 snd_pcm_prepare(instance
->handle
);
535 err
= snd_pcm_resume(instance
->handle
);
537 snd_pcm_prepare(instance
->handle
);
544 } while(avail
>= instance
->period_size
);
548 static void alsa_callback(snd_async_handler_t
*ahandler
)
550 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)snd_async_handler_get_callback_private(ahandler
);
551 // signal mixer thread
552 sem_post(&instance
->semaphore
);
555 static void *FPX_SoundOutput_Open()
556 // return = instance pointer
558 struct SoundOutput_Instance
*instance
= 0;
559 snd_pcm_hw_params_t
*hwparams
= 0;
560 snd_pcm_sw_params_t
*swparams
= 0;
561 snd_pcm_format_t pcm_format
;
562 unsigned int buffer_time
= 500000;
563 unsigned int period_time
= 20000;
564 unsigned int actual_rate
;
565 snd_pcm_uframes_t size
;
570 if ( !FPI_SoundOutput_FillBuffer
) goto fail
;
571 if ( !FPI_Mem_Alloc
) goto fail
;
573 instance
= FPI_Mem_Alloc(sizeof(struct SoundOutput_Instance
));
574 memset(instance
,0,sizeof(struct SoundOutput_Instance
));
576 if ( ( err
= snd_pcm_open(&instance
->handle
, "default", SND_PCM_STREAM_PLAYBACK
, SND_PCM_NONBLOCK
) ) < 0) {
577 if ( ( err
= snd_pcm_open(&instance
->handle
, "plughw:0,0", SND_PCM_STREAM_PLAYBACK
, SND_PCM_NONBLOCK
) ) < 0) {
582 snd_pcm_hw_params_alloca(&hwparams
);
583 snd_pcm_sw_params_alloca(&swparams
);
585 if (snd_pcm_hw_params_any(instance
->handle
, hwparams
) < 0) goto fail
;
587 if (snd_pcm_hw_params_set_access(instance
->handle
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
) < 0) goto fail
;
589 pcm_format
= SND_PCM_FORMAT_S16_LE
;
591 if (snd_pcm_hw_params_set_format(instance
->handle
, hwparams
, pcm_format
) < 0) goto fail
;
593 if (snd_pcm_hw_params_set_channels(instance
->handle
, hwparams
, 2) < 0) goto fail
;
597 if (snd_pcm_hw_params_set_rate_near(instance
->handle
, hwparams
, &actual_rate
, 0) < 0) goto fail
;
599 if (actual_rate
!= 44100) goto fail
;
601 if (snd_pcm_hw_params_set_buffer_time_near(instance
->handle
, hwparams
, &buffer_time
, &direction
) < 0) goto fail
;
603 if (snd_pcm_hw_params_get_buffer_size(hwparams
, &size
) < 0) goto fail
;
605 instance
->buffer_size
= (snd_pcm_sframes_t
)size
;
607 if (snd_pcm_hw_params_set_period_time_near(instance
->handle
, hwparams
, &period_time
, &direction
) < 0) goto fail
;
609 if (snd_pcm_hw_params_get_period_size(hwparams
, &size
, &direction
) < 0) goto fail
;
611 instance
->period_size
= (snd_pcm_sframes_t
)size
;
613 if (snd_pcm_hw_params(instance
->handle
, hwparams
) < 0) goto fail
;
615 if (snd_pcm_sw_params_current(instance
->handle
, swparams
) < 0) goto fail
;
617 if (snd_pcm_sw_params_set_start_threshold(instance
->handle
, swparams
, ((instance
->buffer_size
-1) / instance
->period_size
) * instance
->period_size
) < 0) goto fail
;
619 if (snd_pcm_sw_params_set_stop_threshold(instance
->handle
, swparams
, ~0U) < 0) goto fail
;
621 if (snd_pcm_sw_params_set_avail_min(instance
->handle
, swparams
, instance
->period_size
) < 0) goto fail
;
623 if (snd_pcm_sw_params_set_xfer_align(instance
->handle
, swparams
, 1) < 0) goto fail
;
625 if (snd_pcm_sw_params(instance
->handle
, swparams
) < 0) goto fail
;
627 if (snd_async_add_pcm_handler(&instance
->async_handler
, instance
->handle
, &alsa_callback
, instance
) < 0) goto fail
;
629 if ( ( instance
->buffer
= FPI_Mem_Alloc(instance
->buffer_size
* 2 * 2 * 2) ) == 0 ) goto fail
;
631 if ( pthread_create(&instance
->thread
, 0, alsa_thread
, instance
) < 0 ) goto fail
;
633 sem_post(&instance
->semaphore
);
639 if ( instance
->handle
) {
640 snd_pcm_drop(instance
->handle
);
641 snd_pcm_close(instance
->handle
);
642 instance
->handle
= 0;
644 if ( instance
->thread
) {
645 sem_post(&instance
->semaphore
);
646 sem_destroy(&instance
->semaphore
);
647 pthread_join(instance
->thread
,&retVal
);
649 if ( instance
->buffer
) {
650 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
->buffer
);
652 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
);
657 static int FPX_SoundOutput_Close(void *ptr
)
658 // ptr = instance pointer
659 // return = 0 on success, < 0 on error
661 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
663 if ( instance
->handle
) {
664 snd_pcm_drop(instance
->handle
);
665 snd_pcm_close(instance
->handle
);
666 instance
->handle
= 0;
668 if ( instance
->thread
) {
669 sem_post(&instance
->semaphore
);
670 sem_destroy(&instance
->semaphore
);
671 pthread_join(instance
->thread
,&retVal
);
673 if ( instance
->buffer
) {
674 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
->buffer
);
676 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
);
680 static int FPX_SoundOutput_Latency(void *ptr
)
681 // ptr = instance pointer
682 // return = 0 on success, < 0 on error
684 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
685 if ( instance
->handle
) {
686 snd_pcm_sframes_t delay
= 0;
687 snd_pcm_delay(instance
->handle
, &delay
);
688 if ( snd_pcm_state(instance
->handle
) == SND_PCM_STATE_RUNNING
&& delay
> 0 ) {
697 struct SoundOutput_Instance
{
703 static void *oss_thread(void *ptr
)
705 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
710 FPI_SoundOutput_FillBuffer(ptr
,buffer
,4096);
713 written
= write(instance
->oss_fd
, buffer
, len
);
714 if ( written
>= 0 ) {
717 if ( instance
->signal
) {
727 static void *FPX_SoundOutput_Open()
728 // return = instance pointer
730 struct SoundOutput_Instance
*instance
= 0;
731 int format
= AFMT_S16_LE
;
735 if ( !FPI_SoundOutput_FillBuffer
) goto fail
;
736 if ( !FPI_Mem_Alloc
) goto fail
;
738 instance
= (struct SoundOutput_Instance
*)FPI_Mem_Alloc(sizeof(struct SoundOutput_Instance
));
739 memset(instance
,0,sizeof(struct SoundOutput_Instance
));
741 if ( ( instance
->oss_fd
= open("/dev/dsp",O_WRONLY
) ) < 0 ) goto fail
;
743 if ( ioctl(instance
->oss_fd
, SNDCTL_DSP_SETFMT
, &format
) < 0 ) goto fail
;
745 if ( ioctl(instance
->oss_fd
, SNDCTL_DSP_STEREO
, &stereo
) < 0 ) goto fail
;
747 if ( ioctl(instance
->oss_fd
, SNDCTL_DSP_SPEED
, &speed
) < 0 ) goto fail
;
749 if ( pthread_create(&instance
->thread
, 0, oss_thread
, instance
) < 0 ) goto fail
;
754 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
);
759 static int FPX_SoundOutput_Close(void *ptr
)
760 // ptr = instance pointer
761 // return = 0 on success, < 0 on error
763 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
766 instance
->signal
= 1;
768 if ( instance
->oss_fd
) {
769 ioctl(instance
->oss_fd
, SNDCTL_DSP_RESET
, 0);
772 if ( instance
->thread
) {
773 pthread_join(instance
->thread
,&retVal
);
776 if ( instance
->oss_fd
) {
777 close(instance
->oss_fd
);
780 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
);
785 static int FPX_SoundOutput_Latency(void *ptr
)
786 // ptr = instance pointer
787 // return = 0 on success, < 0 on error
789 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
790 if ( instance
->oss_fd
) {
792 if ( ( value
= ioctl(instance
->oss_fd
,SNDCTL_DSP_GETODELAY
,&value
) ) == 0 ) {
799 #endif // defined(OSS)
803 #define BUFSIZE (4096)
806 pa_threaded_mainloop
*mainloop
;
809 uint8_t buf
[BUFSIZE
];
814 static void context_state_cb(pa_context
*c
, void *userdata
) {
815 struct output_data
*p
= userdata
;
820 p
->thread_id
= pthread_self();
823 switch (pa_context_get_state(c
)) {
824 case PA_CONTEXT_READY
:
825 case PA_CONTEXT_TERMINATED
:
826 case PA_CONTEXT_FAILED
:
827 pa_threaded_mainloop_signal(p
->mainloop
, 0);
830 case PA_CONTEXT_UNCONNECTED
:
831 case PA_CONTEXT_CONNECTING
:
832 case PA_CONTEXT_AUTHORIZING
:
833 case PA_CONTEXT_SETTING_NAME
:
838 static void stream_state_cb(pa_stream
*s
, void *userdata
) {
839 struct output_data
*p
= userdata
;
844 p
->thread_id
= pthread_self();
847 switch (pa_stream_get_state(s
)) {
849 case PA_STREAM_READY
:
850 case PA_STREAM_FAILED
:
851 case PA_STREAM_TERMINATED
:
852 pa_threaded_mainloop_signal(p
->mainloop
, 0);
855 case PA_STREAM_UNCONNECTED
:
856 case PA_STREAM_CREATING
:
861 static void write_data(struct output_data
*p
) {
866 /* Wait until timing info is available before we write the second
867 * and all subsequent blocks */
868 if (!p
->first
&& !pa_stream_get_timing_info(p
->stream
))
871 length
= pa_stream_writable_size(p
->stream
);
881 FPI_SoundOutput_FillBuffer(p
, (char*) p
->buf
, l
);
883 if (pa_stream_write(p
->stream
, p
->buf
, l
, NULL
, 0, PA_SEEK_RELATIVE
) < 0)
892 /* There's no real handling of errors here. Unfortunately the
893 * Flash API doesn't export a sane way to do this. With networked
894 * audio streams and hotplug-capable audio devices the audio
895 * stream might be killed in the middle of nothing, hence it is
896 * very unfortunate that we cannot report errors that happen here
899 p
->first
= 0; /* So, we write the first block noch, remember that */
902 static void stream_request_cb(pa_stream
*s
, size_t length
, void *userdata
) {
903 struct output_data
*p
= userdata
;
909 p
->thread_id
= pthread_self();
911 /* Write some data */
915 static void stream_latency_update_cb(pa_stream
*s
, void *userdata
) {
916 struct output_data
*p
= userdata
;
921 p
->thread_id
= pthread_self();
923 /* Try to write some more, in case we delayed the first write until latency data became available */
927 static void *FPX_SoundOutput_Open(void) {
929 static const pa_sample_spec ss
= {
930 .format
= PA_SAMPLE_S16LE
, /* Hmm, Flash wants LE here, not
931 * NE. This makes porting Flash to
932 * Big-Endian machines unnecessary
938 struct output_data
*p
;
940 /* Unfortunately we cannot report any useful error string back to
941 * Flash. It would be highly preferable if Flash supported some
942 * way how we could tell the user what the reason is why audio is
943 * not working for him. */
945 if (!(p
= FPI_Mem_Alloc(sizeof(struct output_data
))))
948 memset(p
, 0, sizeof(*p
));
950 p
->thread_id
= (pthread_t
) 0;
952 /* First, let's create the main loop */
953 if (!(p
->mainloop
= pa_threaded_mainloop_new()))
956 /* Second, initialize the connection context */
957 if (!(p
->context
= pa_context_new(pa_threaded_mainloop_get_api(p
->mainloop
), "Adobe Flash")))
960 pa_context_set_state_callback(p
->context
, context_state_cb
, p
);
962 if (pa_context_connect(p
->context
, NULL
, 0, NULL
) < 0)
965 /* Now, let's start the background thread */
966 pa_threaded_mainloop_lock(p
->mainloop
);
968 if (pa_threaded_mainloop_start(p
->mainloop
) < 0)
971 /* Wait until the context is ready */
972 pa_threaded_mainloop_wait(p
->mainloop
);
974 if (pa_context_get_state(p
->context
) != PA_CONTEXT_READY
)
975 goto unlock_and_fail
;
977 /* Now, initialize the stream */
978 if (!(p
->stream
= pa_stream_new(p
->context
, "Flash Animation", &ss
, NULL
)))
979 goto unlock_and_fail
;
981 pa_stream_set_state_callback(p
->stream
, stream_state_cb
, p
);
982 pa_stream_set_write_callback(p
->stream
, stream_request_cb
, p
);
983 pa_stream_set_latency_update_callback(p
->stream
, stream_latency_update_cb
, p
);
985 if (pa_stream_connect_playback(p
->stream
, NULL
, NULL
, PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_AUTO_TIMING_UPDATE
, NULL
, NULL
) < 0)
986 goto unlock_and_fail
;
988 /* Wait until the stream is ready */
989 pa_threaded_mainloop_wait(p
->mainloop
);
991 if (pa_stream_get_state(p
->stream
) != PA_STREAM_READY
)
992 goto unlock_and_fail
;
994 pa_threaded_mainloop_unlock(p
->mainloop
);
1000 pa_threaded_mainloop_unlock(p
->mainloop
);
1004 FPX_SoundOutput_Close(p
);
1009 static int FPX_SoundOutput_Close(void *ptr
) {
1010 struct output_data
*p
= ptr
;
1015 pa_threaded_mainloop_stop(p
->mainloop
);
1018 pa_stream_disconnect(p
->stream
);
1019 pa_stream_unref(p
->stream
);
1023 pa_context_disconnect(p
->context
);
1024 pa_context_unref(p
->context
);
1028 pa_threaded_mainloop_free(p
->mainloop
);
1036 static int FPX_SoundOutput_Latency(void *ptr
) {
1037 struct output_data
*p
= ptr
;
1044 /* We lock here only if we are not called from our event loop thread */
1045 if (!p
->thread_id
|| !pthread_equal(p
->thread_id
, pthread_self()))
1046 pa_threaded_mainloop_lock(p
->mainloop
);
1048 if (pa_stream_get_latency(p
->stream
, &t
, &negative
) < 0 || negative
)
1051 r
= (int) (pa_usec_to_bytes(t
, pa_stream_get_sample_spec(p
->stream
)) >> 2);
1053 if (!p
->thread_id
|| !pthread_equal(p
->thread_id
, pthread_self()))
1054 pa_threaded_mainloop_unlock(p
->mainloop
);
1063 struct jack_output_data
{
1064 jack_client_t
*client
;
1065 jack_port_t
*port_l
;
1066 jack_port_t
*port_r
;
1071 jack_ringbuffer_t
*buffer
;
1077 static void *jack_flash_thread( void *arg
)
1079 struct jack_output_data
*p
= arg
;
1080 int jack_rate
= jack_get_sample_rate( p
->client
);
1081 int flash_frames
= jack_get_buffer_size( p
->client
) * 44100 / jack_rate
;
1083 size_t bufsize
= 2*flash_frames
* sizeof( int16_t );
1084 int16_t *buffer
= alloca( bufsize
);
1086 //sem_wait( &(p->semaphore) );
1089 sem_wait( &(p
->semaphore
) );
1091 FPI_SoundOutput_FillBuffer(p
, (char*) buffer
, bufsize
);
1092 if( jack_ringbuffer_write( p
->buffer
, (char*)buffer
, bufsize
) != bufsize
)
1093 printf( "something is wrong\n" );
1094 sem_wait( &(p
->semaphore
) );
1100 static int jack_process_cb( jack_nframes_t nframes
, void *arg
)
1102 struct jack_output_data
*p
= arg
;
1104 int jack_rate
= jack_get_sample_rate( p
->client
);
1105 int flash_frames
= nframes
* 44100 / jack_rate
;
1107 size_t bufsize
= 2*flash_frames
* sizeof( int16_t );
1108 int16_t *buffer
= alloca( bufsize
);
1109 float *float_buf
= alloca( flash_frames
* sizeof(float) );
1111 float *port_l
= jack_port_get_buffer( p
->port_l
, nframes
);
1112 float *port_r
= jack_port_get_buffer( p
->port_r
, nframes
);
1116 if( jack_ringbuffer_read_space( p
->buffer
) < bufsize
) {
1117 // no data to read. fill ports with zero and return.
1118 memset( port_l
, 0, nframes
* sizeof( jack_default_audio_sample_t
) );
1119 memset( port_r
, 0, nframes
* sizeof( jack_default_audio_sample_t
) );
1123 if( jack_ringbuffer_read( p
->buffer
, (char *)buffer
, bufsize
) != bufsize
) {
1124 printf( "Something is pretty wrong :( \n" );
1127 sem_post( &(p
->semaphore
) );
1129 for( i
=0; i
<flash_frames
; i
++ ) {
1130 float_buf
[i
] = (float) (buffer
[2*i
]) / 32768.0;
1133 sd
.data_in
= float_buf
;
1134 sd
.data_out
= port_l
;
1135 sd
.input_frames
= flash_frames
;
1136 sd
.output_frames
= nframes
;
1137 sd
.end_of_input
= 0;
1138 // sd.src_ratio = (double)flash_frames / (double)nframes;
1139 sd
.src_ratio
= (double)nframes
/ (double)flash_frames
;
1141 src_process( p
->src_l
, &sd
);
1144 for( i
=0; i
<flash_frames
; i
++ ) {
1145 float_buf
[i
] = (float) (buffer
[2*i
+1]) / 32768.0;
1148 sd
.data_in
= float_buf
;
1149 sd
.data_out
= port_r
;
1150 sd
.input_frames
= flash_frames
;
1151 sd
.output_frames
= nframes
;
1152 sd
.end_of_input
= 0;
1153 // sd.src_ratio = (double)flash_frames / (double)nframes;
1154 sd
.src_ratio
= (double)nframes
/ (double)flash_frames
;
1156 src_process( p
->src_r
, &sd
);
1162 FPI_jack_ringbuffer_create (size_t sz
)
1165 jack_ringbuffer_t
*rb
;
1167 rb
= FPI_Mem_Alloc (sizeof (jack_ringbuffer_t
));
1169 for (power_of_two
= 1; 1 << power_of_two
< sz
; power_of_two
++);
1171 rb
->size
= 1 << power_of_two
;
1172 rb
->size_mask
= rb
->size
;
1176 rb
->buf
= FPI_Mem_Alloc (rb
->size
);
1182 static void *FPX_SoundOutput_Open(void) {
1184 struct jack_output_data
*p
=NULL
;
1189 char *connect_port_1
= getenv( "JACK_FLASH_PORT_1" );
1190 char *connect_port_2
= getenv( "JACK_FLASH_PORT_2" );
1193 /* Unfortunately we cannot report any useful error string back to
1194 * Flash. It would be highly preferable if Flash supported some
1195 * way how we could tell the user what the reason is why audio is
1196 * not working for him. */
1198 if (!(p
= FPI_Mem_Alloc(sizeof(struct jack_output_data
))))
1201 memset(p
, 0, sizeof(*p
));
1203 p
->src_l
= src_new(SRC_SINC_FASTEST
, 1, & (p
->src_error
));
1204 p
->src_r
= src_new(SRC_SINC_FASTEST
, 1, & (p
->src_error
));
1207 /* First, let's create the main loop */
1208 if (!(p
->client
= jack_client_open( "flash", 0, NULL
)))
1211 jack_rate
= jack_get_sample_rate( p
->client
);
1212 flash_frames
= jack_get_buffer_size( p
->client
) * 44100 / jack_rate
;
1213 bufsize
= 2*flash_frames
* sizeof( int16_t );
1215 p
->buffer
= FPI_jack_ringbuffer_create( bufsize
* 6 );
1216 sem_init( &(p
->semaphore
), 0, 0 );
1218 pthread_create( &(p
->tid
), NULL
, jack_flash_thread
, p
);
1220 // This seems to trigger a race condition in flash.
1222 jack_client_create_thread( p
->client
,
1224 (jack_client_real_time_priority( p
->client
) == -1) ? 1 : (jack_client_real_time_priority( p
->client
) - 1),
1225 (jack_client_real_time_priority( p
->client
) == -1) ? 0 : 1,
1231 /* Second, initialize the connection context */
1232 if (!(p
->port_l
= jack_port_register( p
->client
, "out1", JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0)) )
1234 if (!(p
->port_r
= jack_port_register( p
->client
, "out2", JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0)) )
1237 jack_set_process_callback( p
->client
, jack_process_cb
, p
);
1238 jack_activate( p
->client
);
1240 snprintf( namebuf
, 99, "%s:out1", jack_get_client_name( p
->client
) );
1241 jack_connect( p
->client
, namebuf
, (connect_port_1
!= NULL
) ? connect_port_1
: "system:playback_1" );
1242 snprintf( namebuf
, 99, "%s:out2", jack_get_client_name( p
->client
) );
1243 jack_connect( p
->client
, namebuf
, (connect_port_2
!= NULL
) ? connect_port_2
: "system:playback_2" );
1245 // Now start the fill thread.
1246 // the semaphore represents the number of writeable buffers in
1247 // the ringbuffer. we add 1 for the initial sem_wait.
1249 for(i
=0; i
<( 3 + 1 ); i
++ )
1250 sem_post( &(p
->semaphore
) );
1256 FPX_SoundOutput_Close(p
);
1261 static int FPX_SoundOutput_Close(void *ptr
) {
1262 struct jack_output_data
*p
= ptr
;
1268 sem_post( &(p
->semaphore
) );
1269 pthread_join( p
->tid
, NULL
);
1273 jack_deactivate( p
->client
);
1274 jack_client_close( p
->client
);
1280 static int FPX_SoundOutput_Latency(void *ptr
) {
1281 // heh ? jack has no latency :P
1282 struct jack_output_data
*p
= ptr
;
1283 //return jack_ringbuffer_read_space( p->buffer ) / 4;
1290 struct VideoOutput_Instance
{
1297 struct video_window window
;
1298 struct video_picture picture
;
1301 static void *v4l_thread(void *ptr
)
1303 struct VideoOutput_Instance
*instance
= (struct VideoOutput_Instance
*)ptr
;
1309 result
= read(instance
->v4l_fd
, instance
->buffer
[instance
->buffercurrent
], instance
->buffersize
);
1317 if ( instance
->signal
) {
1319 ioctl(instance
->v4l_fd
, VIDIOCCAPTURE
, &status
);
1326 static void *FPX_VideoInput_Open(void)
1328 struct VideoOutput_Instance
*instance
= 0;
1330 if ( !FPI_Mem_Alloc
) goto fail
;
1332 instance
= (struct VideoOutput_Instance
*)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance
));
1333 memset(instance
,0,sizeof(struct VideoOutput_Instance
));
1335 if ( ( instance
->v4l_fd
= open("/dev/video", O_RDONLY
) ) < 0 ) goto fail
;
1337 if ( ioctl(instance
->v4l_fd
, VIDIOCGPICT
, &instance
->picture
) < 0 ) goto fail
;
1339 switch(instance
->picture
.palette
) {
1340 case VIDEO_PALETTE_YUV420P
:
1342 case VIDEO_PALETTE_RGB24
:
1343 case VIDEO_PALETTE_YUV422P
:
1344 case VIDEO_PALETTE_YUV411P
:
1345 case VIDEO_PALETTE_YUV410P
:
1346 case VIDEO_PALETTE_GREY
:
1347 case VIDEO_PALETTE_HI240
:
1348 case VIDEO_PALETTE_RGB565
:
1349 case VIDEO_PALETTE_RGB32
:
1350 case VIDEO_PALETTE_RGB555
:
1351 case VIDEO_PALETTE_YUV422
:
1352 case VIDEO_PALETTE_YUYV
:
1353 case VIDEO_PALETTE_UYVY
:
1354 case VIDEO_PALETTE_YUV420
:
1355 case VIDEO_PALETTE_YUV411
:
1356 case VIDEO_PALETTE_RAW
:
1361 if( ioctl(instance
->v4l_fd
, VIDIOCGWIN
, &instance
->window
) < 0 ) goto fail
;
1363 instance
->buffer
[0] = FPI_Mem_Alloc(instance
->window
.width
* instance
->window
.height
* 2);
1364 instance
->buffer
[1] = FPI_Mem_Alloc(instance
->window
.width
* instance
->window
.height
* 2);
1366 if ( pthread_create(&instance
->thread
, 0, v4l_thread
, instance
) < 0 ) goto fail
;
1371 if ( FPI_Mem_Free
) {
1372 if ( instance
->buffer
[0] ) {
1373 FPI_Mem_Free(instance
->buffer
[0]);
1375 if ( instance
->buffer
[1] ) {
1376 FPI_Mem_Free(instance
->buffer
[1]);
1378 FPI_Mem_Free(instance
);
1383 static int FPX_VideoInput_Close(void *ptr
)
1385 struct VideoOutput_Instance
*instance
= (struct VideoOutput_Instance
*)ptr
;
1388 instance
->signal
= 1;
1390 if ( instance
->thread
) {
1391 pthread_join(instance
->thread
,&retVal
);
1394 if ( instance
->v4l_fd
) {
1395 close(instance
->v4l_fd
);
1398 if ( FPI_Mem_Free
) {
1399 if ( instance
->buffer
[0] ) {
1400 FPI_Mem_Free(instance
->buffer
[0]);
1402 if ( instance
->buffer
[1] ) {
1403 FPI_Mem_Free(instance
->buffer
[1]);
1405 FPI_Mem_Free(instance
);
1411 static int FPX_VideoInput_GetFrame(void *ptr
, char *data
, int width
, int height
, int pitch_n_bytes
)
1413 struct VideoOutput_Instance
*instance
= (struct VideoOutput_Instance
*)ptr
;
1414 int ix
, iy
, ox
, oy
, ow
, oh
, dx
, dy
, Y
, U
, V
, R
, G
, B
;
1415 unsigned char *y
, *u
, *v
;
1417 switch(instance
->picture
.palette
) {
1418 case VIDEO_PALETTE_YUV420P
: {
1419 ow
= instance
->window
.width
;
1420 oh
= instance
->window
.height
;
1422 dx
= (ow
<<16) / width
;
1423 dy
= (oh
<<16) / height
;
1425 y
= (unsigned char *)instance
->buffer
[instance
->buffercurrent
^1];
1427 v
= u
+ ow
* oh
/ 4;
1431 for ( iy
= 0; iy
< height
; iy
++ ) {
1435 for ( ix
= 0; ix
< width
; ix
++ ) {
1437 Y
= ( 149 * ((int)(y
[(oy
>>16)*(ow
)+(ox
>>16)]) - 16) ) / 2;
1438 U
= (int)(u
[(oy
>>17)*(ow
/2)+(ox
>>17)]) - 128;
1439 V
= (int)(v
[(oy
>>17)*(ow
/2)+(ox
>>17)]) - 128;
1441 R
= (Y
+ V
* 102 ) / 64;
1442 G
= (Y
- V
* 52 - U
* 25 ) / 64;
1443 B
= (Y
+ U
* 129 ) / 64;
1445 R
= R
< 0 ? 0 : ( R
> 255 ? 255 : R
);
1446 G
= G
< 0 ? 0 : ( G
> 255 ? 255 : G
);
1447 B
= B
< 0 ? 0 : ( B
> 255 ? 255 : B
);
1458 data
+= pitch_n_bytes
;
1465 instance
->buffercurrent
^= 1;