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.
59 ////////////////////////////////////////////////////////////////////////////////////////////////////
61 // To compile and install flashsupport.c the following components are required:
63 // - a C compiler (gcc 4.03 is known to be working)
64 // - OpenSSL developer package and working user libraries (OpenSSL 0.9.8 is known to be working)
65 // - OSS (or ALSA) developer package and working users libraries (Linux 2.6.15 is known to be working)
66 // - sudo or root access to install the generated library to /usr/lib
68 // We suggest these steps in a terminal:
70 // > cc -shared -O2 -Wall -Werror -lssl flashsupport.c -o libflashsupport.so
71 // > ldd libflashplayer.so
72 // > sudo cp libflashplayer.so /usr/lib
74 // Make sure that 'ldd' can resolve all dynamic libraries. Otherwise the Flash Player
75 // will silently fail to load and use libflashsupport.so.
78 ////////////////////////////////////////////////////////////////////////////////////////////////////
80 // SHARED SECTION, DO NOT CHANGE!
90 typedef void *(*T_FPI_Mem_Alloc
)(int size
); // This function is not thread safe
91 typedef void (*T_FPI_Mem_Free
)(void *ptr
); // This function is not thread safe
93 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO)
94 typedef void (*T_FPI_SoundOutput_FillBuffer
)(void *ptr
, char *buffer
, int n_bytes
); // This function is thread safe
95 #endif // defined(ALSA) || defined(OSS)
97 struct FPI_Functions
{
99 void *fpi_mem_alloc
; // 1
100 void *fpi_mem_free
; // 2
101 void *fpi_soundoutput_fillbuffer
; // 3
105 // Exported functions
108 void *FPX_Init(void *ptr
);
110 static void FPX_Shutdown(void);
112 #if defined(OPENSSL) || defined(GNUTLS)
113 static void *FPX_SSLSocket_Create(int socket_fd
);
114 static int FPX_SSLSocket_Destroy(void *ptr
);
115 static int FPX_SSLSocket_Connect(void *ptr
);
116 static int FPX_SSLSocket_Receive(void *ptr
, char *buffer
, int n_bytes
);
117 static int FPX_SSLSocket_Send(void *ptr
, const char *buffer
, int n_bytes
);
118 #endif // defined(OPENSSL) || defined(GNUTLS)
120 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO)
121 static void *FPX_SoundOutput_Open(void);
122 static int FPX_SoundOutput_Close(void *ptr
);
123 static int FPX_SoundOutput_Latency(void *ptr
);
124 #endif // defined(ALSA) || defined(OSS)
127 static void *FPX_VideoInput_Open(void);
128 static int FPX_VideoInput_Close(void *ptr
);
129 static int FPX_VideoInput_GetFrame(void *ptr
, char *data
, int width
, int height
, int pitch_n_bytes
);
132 struct FPX_Functions
{
134 void *fpx_shutdown
; // 1
135 void *fpx_sslsocket_create
; // 2
136 void *fpx_sslsocket_destroy
; // 3
137 void *fpx_sslsocket_connect
; // 4
138 void *fpx_sslsocket_receive
; // 5
139 void *fpx_sslsocket_send
; // 6
140 void *fpx_soundoutput_open
; // 7
141 void *fpx_soundoutput_close
; // 8
142 void *fpx_soundoutput_latency
; // 9
143 void *fpx_videoinput_open
; // 10
144 void *fpx_videoinput_close
; // 11
145 void *fpx_videoinput_getframe
; // 12
152 // END OF SHARED SECTION
154 ////////////////////////////////////////////////////////////////////////////////////////////////////
159 #include <openssl/ssl.h>
160 #elif defined(GNUTLS)
161 #include <sys/types.h>
162 #include <sys/socket.h>
163 #include <arpa/inet.h>
165 #include <gnutls/gnutls.h>
170 #include <semaphore.h>
171 #include <alsa/asoundlib.h>
175 #include <linux/soundcard.h>
176 #include <sys/ioctl.h>
183 #include <linux/videodev.h>
184 #include <sys/ioctl.h>
189 #include <pulse/pulseaudio.h>
193 static struct FPX_Functions fpx_functions
;
195 static T_FPI_Mem_Alloc FPI_Mem_Alloc
= 0;
196 static T_FPI_Mem_Free FPI_Mem_Free
= 0;
198 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO)
199 static T_FPI_SoundOutput_FillBuffer FPI_SoundOutput_FillBuffer
= 0;
200 #endif // defined(ALSA) || defined(OSS)
202 void *FPX_Init(void *ptr
)
204 if ( !ptr
) return 0;
207 // Setup imported functions
210 struct FPI_Functions
*fpi_functions
= (struct FPI_Functions
*)ptr
;
212 if ( fpi_functions
->fpi_count
>= 1 ) FPI_Mem_Alloc
= fpi_functions
->fpi_mem_alloc
; // 1
213 if ( fpi_functions
->fpi_count
>= 2 ) FPI_Mem_Free
= fpi_functions
->fpi_mem_free
; // 2
215 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO)
216 if ( fpi_functions
->fpi_count
>= 3 ) FPI_SoundOutput_FillBuffer
= fpi_functions
->fpi_soundoutput_fillbuffer
; // 3
217 #endif // defined(ALSA) || defined(OSS)
220 // Setup exported functions
223 memset(&fpx_functions
, 0, sizeof(fpx_functions
));
225 fpx_functions
.fpx_shutdown
= FPX_Shutdown
; // 1
227 #if defined(OPENSSL) || defined(GNUTLS)
228 fpx_functions
.fpx_sslsocket_create
= FPX_SSLSocket_Create
; // 2
229 fpx_functions
.fpx_sslsocket_destroy
= FPX_SSLSocket_Destroy
; // 3
230 fpx_functions
.fpx_sslsocket_connect
= FPX_SSLSocket_Connect
; // 4
231 fpx_functions
.fpx_sslsocket_receive
= FPX_SSLSocket_Receive
; // 5
232 fpx_functions
.fpx_sslsocket_send
= FPX_SSLSocket_Send
; // 6
233 #endif // defined(OPENSSL) || defined(GNUTLS)
235 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO)
236 fpx_functions
.fpx_soundoutput_open
= FPX_SoundOutput_Open
; // 7
237 fpx_functions
.fpx_soundoutput_close
= FPX_SoundOutput_Close
; // 8
238 fpx_functions
.fpx_soundoutput_latency
= FPX_SoundOutput_Latency
; // 9
239 #endif // defined(ALSA) || defined(OSS)
242 fpx_functions
.fpx_videoinput_open
= FPX_VideoInput_Open
; // 10
243 fpx_functions
.fpx_videoinput_close
= FPX_VideoInput_Close
; // 11
244 fpx_functions
.fpx_videoinput_getframe
= FPX_VideoInput_GetFrame
; // 12
247 fpx_functions
.fpx_count
= 14;
251 #elif defined(GNUTLS)
252 gnutls_global_init();
255 return (void *)&fpx_functions
;
258 static void FPX_Shutdown(void)
262 #elif defined(GNUTLS)
263 gnutls_global_deinit();
268 // SSL support functions
272 struct SSL_Instance
{
277 static void *FPX_SSLSocket_Create(int socket_fd
)
278 // return = instance pointer
280 struct SSL_Instance
*instance
= (struct SSL_Instance
*)FPI_Mem_Alloc(sizeof(struct SSL_Instance
));
281 memset(instance
,0,sizeof(struct SSL_Instance
));
283 if ( ( instance
->sslCtx
= SSL_CTX_new( TLSv1_client_method() ) ) == 0 ) goto fail
;
285 if ( ( instance
->ssl
= SSL_new(instance
->sslCtx
) ) == 0 ) goto fail
;
287 if ( SSL_set_fd(instance
->ssl
, socket_fd
) < 0 ) goto fail
;
289 return (void *)instance
;
291 if ( instance
->ssl
) {
292 SSL_shutdown(instance
->ssl
);
295 if ( instance
->sslCtx
) {
296 SSL_CTX_free(instance
->sslCtx
);
299 if (FPI_Mem_Free
) FPI_Mem_Free(instance
);
304 static int FPX_SSLSocket_Destroy(void *ptr
)
305 // ptr = instance pointer
306 // return = 0 on sucess, < 0 on error
308 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
310 if ( instance
->ssl
) {
311 SSL_shutdown(instance
->ssl
);
314 if ( instance
->sslCtx
) {
315 SSL_CTX_free(instance
->sslCtx
);
318 if (FPI_Mem_Free
) FPI_Mem_Free(instance
);
323 static int FPX_SSLSocket_Connect(void *ptr
)
324 // ptr = instance pointer
325 // socket_fd = BSD socket fd to be associated with SSL connection
326 // return = 0 on sucess, < 0 on error
328 // Flash Player will use errno to obtain current status
330 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
331 return SSL_connect(instance
->ssl
);
334 static int FPX_SSLSocket_Receive(void *ptr
, char *buffer
, int n_bytes
)
335 // ptr = instance pointer
336 // buffer = raw buffer to place received data into
337 // n_bytes = length of buffer in bytes
338 // return = actual bytes received, < 0 on error
340 // Flash Player will use errno to obtain current status
342 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
343 return SSL_read(instance
->ssl
, buffer
, n_bytes
);
346 static int FPX_SSLSocket_Send(void *ptr
, const char *buffer
, int n_bytes
)
347 // ptr = instance pointer
348 // buffer = raw buffer to be sent
349 // n_bytes = length of input buffer in bytes
350 // return = actual bytes sent, < 0 on error
352 // Flash Player will use errno to obtain current status
354 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
355 return SSL_write(instance
->ssl
, buffer
, n_bytes
);
357 #elif defined(GNUTLS)
358 struct SSL_Instance
{
359 gnutls_session_t session
;
360 gnutls_anon_client_credentials_t anoncred
;
363 static void *FPX_SSLSocket_Create(int socket_fd
)
364 // return = instance pointer
366 const int kx_prio
[] = { GNUTLS_KX_ANON_DH
, 0 };
368 struct SSL_Instance
*instance
= (struct SSL_Instance
*)FPI_Mem_Alloc(sizeof(struct SSL_Instance
));
369 memset(instance
,0,sizeof(struct SSL_Instance
));
371 if ( gnutls_anon_allocate_client_credentials(&instance
->anoncred
) < 0 ) goto fail
;
373 if ( gnutls_init(&instance
->session
, GNUTLS_CLIENT
) < 0 ) goto fail
;
375 if ( gnutls_set_default_priority(instance
->session
) < 0 ) goto fail
;
377 if ( gnutls_kx_set_priority(instance
->session
, kx_prio
) < 0 ) goto fail
;
379 if ( gnutls_credentials_set(instance
->session
, GNUTLS_CRD_ANON
, instance
->anoncred
) < 0 ) goto fail
;
381 gnutls_transport_set_ptr(instance
->session
, (gnutls_transport_ptr_t
)socket_fd
);
383 return (void *)instance
;
386 if ( instance
->session
) {
387 gnutls_deinit(instance
->session
);
390 if ( instance
->anoncred
) {
391 gnutls_anon_free_client_credentials(instance
->anoncred
);
394 if (FPI_Mem_Free
) FPI_Mem_Free(instance
);
399 static int FPX_SSLSocket_Destroy(void *ptr
)
400 // ptr = instance pointer
401 // return = 0 on sucess, < 0 on error
403 struct SSL_Instance
*instance
= (struct SSL_Instance
*)FPI_Mem_Alloc(sizeof(struct SSL_Instance
));
405 gnutls_bye(instance
->session
, GNUTLS_SHUT_RDWR
);
407 gnutls_deinit(instance
->session
);
409 gnutls_anon_free_client_credentials(instance
->anoncred
);
411 if (FPI_Mem_Free
) FPI_Mem_Free(instance
);
416 static int FPX_SSLSocket_Connect(void *ptr
)
417 // ptr = instance pointer
418 // socket_fd = BSD socket fd to be associated with SSL connection
419 // return = 0 on sucess, < 0 on error
421 // Flash Player will use errno to obtain current status
423 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
424 return gnutls_handshake(instance
->session
);
427 static int FPX_SSLSocket_Receive(void *ptr
, char *buffer
, int n_bytes
)
428 // ptr = instance pointer
429 // buffer = raw buffer to place received data into
430 // n_bytes = length of buffer in bytes
431 // return = actual bytes received, < 0 on error
433 // Flash Player will use errno to obtain current status
435 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
436 return gnutls_record_recv(instance
->session
, buffer
, n_bytes
);
439 static int FPX_SSLSocket_Send(void *ptr
, const char *buffer
, int n_bytes
)
440 // ptr = instance pointer
441 // buffer = raw buffer to be sent
442 // n_bytes = length of input buffer in bytes
443 // return = actual bytes sent, < 0 on error
445 // Flash Player will use errno to obtain current status
447 struct SSL_Instance
*instance
= (struct SSL_Instance
*)ptr
;
448 return gnutls_record_send(instance
->session
, buffer
, n_bytes
);
453 // Sound support functions
456 struct SoundOutput_Instance
{
458 snd_async_handler_t
* async_handler
;
462 snd_pcm_sframes_t buffer_size
;
463 snd_pcm_sframes_t period_size
;
464 snd_pcm_sframes_t buffer_pos
;
468 static void *alsa_thread(void *ptr
)
470 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
471 snd_pcm_sframes_t avail
= 0;
478 err
= sem_wait(&instance
->semaphore
);
479 if ( !instance
->handle
) {
490 if ( instance
->buffer_pos
<= 0 ) {
491 FPI_SoundOutput_FillBuffer(ptr
, instance
->buffer
, snd_pcm_frames_to_bytes(instance
->handle
, instance
->period_size
));
492 instance
->buffer_pos
= instance
->period_size
;
493 instance
->buffer_ptr
= instance
->buffer
;
496 state
= snd_pcm_state(instance
->handle
);
497 if(state
!= SND_PCM_STATE_RUNNING
&& state
!= SND_PCM_STATE_PREPARED
) {
498 snd_pcm_prepare(instance
->handle
);
500 result
= snd_pcm_writei(instance
->handle
, instance
->buffer_ptr
, instance
->buffer_pos
);
504 snd_pcm_prepare(instance
->handle
);
507 err
= snd_pcm_resume(instance
->handle
);
509 snd_pcm_prepare(instance
->handle
);
515 instance
->buffer_pos
-= result
;
516 instance
->buffer_ptr
+= snd_pcm_frames_to_bytes(instance
->handle
, result
);
518 } while (instance
->buffer_pos
);
519 avail
= snd_pcm_avail_update(instance
->handle
);
523 snd_pcm_prepare(instance
->handle
);
526 err
= snd_pcm_resume(instance
->handle
);
528 snd_pcm_prepare(instance
->handle
);
535 } while(avail
>= instance
->period_size
);
539 static void alsa_callback(snd_async_handler_t
*ahandler
)
541 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)snd_async_handler_get_callback_private(ahandler
);
542 // signal mixer thread
543 sem_post(&instance
->semaphore
);
546 static void *FPX_SoundOutput_Open()
547 // return = instance pointer
549 struct SoundOutput_Instance
*instance
= 0;
550 snd_pcm_hw_params_t
*hwparams
= 0;
551 snd_pcm_sw_params_t
*swparams
= 0;
552 snd_pcm_format_t pcm_format
;
553 unsigned int buffer_time
= 500000;
554 unsigned int period_time
= 20000;
555 unsigned int actual_rate
;
556 snd_pcm_uframes_t size
;
561 if ( !FPI_SoundOutput_FillBuffer
) goto fail
;
562 if ( !FPI_Mem_Alloc
) goto fail
;
564 instance
= FPI_Mem_Alloc(sizeof(struct SoundOutput_Instance
));
565 memset(instance
,0,sizeof(struct SoundOutput_Instance
));
567 if ( ( err
= snd_pcm_open(&instance
->handle
, "default", SND_PCM_STREAM_PLAYBACK
, SND_PCM_NONBLOCK
) ) < 0) {
568 if ( ( err
= snd_pcm_open(&instance
->handle
, "plughw:0,0", SND_PCM_STREAM_PLAYBACK
, SND_PCM_NONBLOCK
) ) < 0) {
573 snd_pcm_hw_params_alloca(&hwparams
);
574 snd_pcm_sw_params_alloca(&swparams
);
576 if (snd_pcm_hw_params_any(instance
->handle
, hwparams
) < 0) goto fail
;
578 if (snd_pcm_hw_params_set_access(instance
->handle
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
) < 0) goto fail
;
580 pcm_format
= SND_PCM_FORMAT_S16_LE
;
582 if (snd_pcm_hw_params_set_format(instance
->handle
, hwparams
, pcm_format
) < 0) goto fail
;
584 if (snd_pcm_hw_params_set_channels(instance
->handle
, hwparams
, 2) < 0) goto fail
;
588 if (snd_pcm_hw_params_set_rate_near(instance
->handle
, hwparams
, &actual_rate
, 0) < 0) goto fail
;
590 if (actual_rate
!= 44100) goto fail
;
592 if (snd_pcm_hw_params_set_buffer_time_near(instance
->handle
, hwparams
, &buffer_time
, &direction
) < 0) goto fail
;
594 if (snd_pcm_hw_params_get_buffer_size(hwparams
, &size
) < 0) goto fail
;
596 instance
->buffer_size
= (snd_pcm_sframes_t
)size
;
598 if (snd_pcm_hw_params_set_period_time_near(instance
->handle
, hwparams
, &period_time
, &direction
) < 0) goto fail
;
600 if (snd_pcm_hw_params_get_period_size(hwparams
, &size
, &direction
) < 0) goto fail
;
602 instance
->period_size
= (snd_pcm_sframes_t
)size
;
604 if (snd_pcm_hw_params(instance
->handle
, hwparams
) < 0) goto fail
;
606 if (snd_pcm_sw_params_current(instance
->handle
, swparams
) < 0) goto fail
;
608 if (snd_pcm_sw_params_set_start_threshold(instance
->handle
, swparams
, ((instance
->buffer_size
-1) / instance
->period_size
) * instance
->period_size
) < 0) goto fail
;
610 if (snd_pcm_sw_params_set_stop_threshold(instance
->handle
, swparams
, ~0U) < 0) goto fail
;
612 if (snd_pcm_sw_params_set_avail_min(instance
->handle
, swparams
, instance
->period_size
) < 0) goto fail
;
614 if (snd_pcm_sw_params_set_xfer_align(instance
->handle
, swparams
, 1) < 0) goto fail
;
616 if (snd_pcm_sw_params(instance
->handle
, swparams
) < 0) goto fail
;
618 if (snd_async_add_pcm_handler(&instance
->async_handler
, instance
->handle
, &alsa_callback
, instance
) < 0) goto fail
;
620 if ( ( instance
->buffer
= FPI_Mem_Alloc(instance
->buffer_size
* 2 * 2 * 2) ) == 0 ) goto fail
;
622 if ( pthread_create(&instance
->thread
, 0, alsa_thread
, instance
) < 0 ) goto fail
;
624 sem_post(&instance
->semaphore
);
630 if ( instance
->handle
) {
631 snd_pcm_drop(instance
->handle
);
632 snd_pcm_close(instance
->handle
);
633 instance
->handle
= 0;
635 if ( instance
->thread
) {
636 sem_post(&instance
->semaphore
);
637 sem_destroy(&instance
->semaphore
);
638 pthread_join(instance
->thread
,&retVal
);
640 if ( instance
->buffer
) {
641 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
->buffer
);
643 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
);
648 static int FPX_SoundOutput_Close(void *ptr
)
649 // ptr = instance pointer
650 // return = 0 on success, < 0 on error
652 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
654 if ( instance
->handle
) {
655 snd_pcm_drop(instance
->handle
);
656 snd_pcm_close(instance
->handle
);
657 instance
->handle
= 0;
659 if ( instance
->thread
) {
660 sem_post(&instance
->semaphore
);
661 sem_destroy(&instance
->semaphore
);
662 pthread_join(instance
->thread
,&retVal
);
664 if ( instance
->buffer
) {
665 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
->buffer
);
667 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
);
671 static int FPX_SoundOutput_Latency(void *ptr
)
672 // ptr = instance pointer
673 // return = 0 on success, < 0 on error
675 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
676 if ( instance
->handle
) {
677 snd_pcm_sframes_t delay
= 0;
678 snd_pcm_delay(instance
->handle
, &delay
);
679 if ( snd_pcm_state(instance
->handle
) == SND_PCM_STATE_RUNNING
&& delay
> 0 ) {
688 struct SoundOutput_Instance
{
694 static void *oss_thread(void *ptr
)
696 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
701 FPI_SoundOutput_FillBuffer(ptr
,buffer
,4096);
704 written
= write(instance
->oss_fd
, buffer
, len
);
705 if ( written
>= 0 ) {
708 if ( instance
->signal
) {
718 static void *FPX_SoundOutput_Open()
719 // return = instance pointer
721 struct SoundOutput_Instance
*instance
= 0;
722 int format
= AFMT_S16_LE
;
726 if ( !FPI_SoundOutput_FillBuffer
) goto fail
;
727 if ( !FPI_Mem_Alloc
) goto fail
;
729 instance
= (struct SoundOutput_Instance
*)FPI_Mem_Alloc(sizeof(struct SoundOutput_Instance
));
730 memset(instance
,0,sizeof(struct SoundOutput_Instance
));
732 if ( ( instance
->oss_fd
= open("/dev/dsp",O_WRONLY
) ) < 0 ) goto fail
;
734 if ( ioctl(instance
->oss_fd
, SNDCTL_DSP_SETFMT
, &format
) < 0 ) goto fail
;
736 if ( ioctl(instance
->oss_fd
, SNDCTL_DSP_STEREO
, &stereo
) < 0 ) goto fail
;
738 if ( ioctl(instance
->oss_fd
, SNDCTL_DSP_SPEED
, &speed
) < 0 ) goto fail
;
740 if ( pthread_create(&instance
->thread
, 0, oss_thread
, instance
) < 0 ) goto fail
;
745 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
);
750 static int FPX_SoundOutput_Close(void *ptr
)
751 // ptr = instance pointer
752 // return = 0 on success, < 0 on error
754 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
757 instance
->signal
= 1;
759 if ( instance
->oss_fd
) {
760 ioctl(instance
->oss_fd
, SNDCTL_DSP_RESET
, 0);
763 if ( instance
->thread
) {
764 pthread_join(instance
->thread
,&retVal
);
767 if ( instance
->oss_fd
) {
768 close(instance
->oss_fd
);
771 if ( FPI_Mem_Free
) FPI_Mem_Free(instance
);
776 static int FPX_SoundOutput_Latency(void *ptr
)
777 // ptr = instance pointer
778 // return = 0 on success, < 0 on error
780 struct SoundOutput_Instance
*instance
= (struct SoundOutput_Instance
*)ptr
;
781 if ( instance
->oss_fd
) {
783 if ( ( value
= ioctl(instance
->oss_fd
,SNDCTL_DSP_GETODELAY
,&value
) ) == 0 ) {
790 #endif // defined(OSS)
794 #define BUFSIZE (4096)
797 pa_threaded_mainloop
*mainloop
;
800 uint8_t buf
[BUFSIZE
];
805 static void context_state_cb(pa_context
*c
, void *userdata
) {
806 struct output_data
*p
= userdata
;
811 p
->thread_id
= pthread_self();
814 switch (pa_context_get_state(c
)) {
815 case PA_CONTEXT_READY
:
816 case PA_CONTEXT_TERMINATED
:
817 case PA_CONTEXT_FAILED
:
818 pa_threaded_mainloop_signal(p
->mainloop
, 0);
821 case PA_CONTEXT_UNCONNECTED
:
822 case PA_CONTEXT_CONNECTING
:
823 case PA_CONTEXT_AUTHORIZING
:
824 case PA_CONTEXT_SETTING_NAME
:
829 static void stream_state_cb(pa_stream
*s
, void *userdata
) {
830 struct output_data
*p
= userdata
;
835 p
->thread_id
= pthread_self();
838 switch (pa_stream_get_state(s
)) {
840 case PA_STREAM_READY
:
841 case PA_STREAM_FAILED
:
842 case PA_STREAM_TERMINATED
:
843 pa_threaded_mainloop_signal(p
->mainloop
, 0);
846 case PA_STREAM_UNCONNECTED
:
847 case PA_STREAM_CREATING
:
852 static void write_data(struct output_data
*p
) {
857 /* Wait until timing info is available before we write the second
858 * and all subsequent blocks */
859 if (!p
->first
&& !pa_stream_get_timing_info(p
->stream
))
862 length
= pa_stream_writable_size(p
->stream
);
872 FPI_SoundOutput_FillBuffer(p
, (char*) p
->buf
, l
);
874 if (pa_stream_write(p
->stream
, p
->buf
, l
, NULL
, 0, PA_SEEK_RELATIVE
) < 0)
883 /* The handling of errors here is just ridicilous. Blame Adobe! */
885 p
->first
= 0; /* So, we write the first block noch, remember that */
888 static void stream_request_cb(pa_stream
*s
, size_t length
, void *userdata
) {
889 struct output_data
*p
= userdata
;
895 p
->thread_id
= pthread_self();
897 /* Write some data */
901 static void stream_latency_update_cb(pa_stream
*s
, void *userdata
) {
902 struct output_data
*p
= userdata
;
907 p
->thread_id
= pthread_self();
909 /* Try to write some more, in case we delayed the first write until latency data became available */
913 static void *FPX_SoundOutput_Open(void) {
915 static const pa_sample_spec ss
= {
916 .format
= PA_SAMPLE_S16LE
, /* Hmm, Flash wants LE here, not NE. I hope they know what they are doing. Probably not. */
921 struct output_data
*p
;
923 /* Awesome, we don't inform the user about any error messages, I
924 * guess that's Adobe style programming. Rock!" */
926 if (!(p
= FPI_Mem_Alloc(sizeof(struct output_data
))))
929 memset(p
, 0, sizeof(*p
));
931 p
->thread_id
= (pthread_t
) 0;
933 /* First, let's create the main loop */
934 if (!(p
->mainloop
= pa_threaded_mainloop_new()))
937 /* Second, initialize the connection context */
938 if (!(p
->context
= pa_context_new(pa_threaded_mainloop_get_api(p
->mainloop
), "Adobe Flash")))
941 pa_context_set_state_callback(p
->context
, context_state_cb
, p
);
943 if (pa_context_connect(p
->context
, NULL
, 0, NULL
) < 0)
946 /* Now, let's start the background thread */
947 pa_threaded_mainloop_lock(p
->mainloop
);
949 if (pa_threaded_mainloop_start(p
->mainloop
) < 0)
952 /* Wait until the context is ready */
953 pa_threaded_mainloop_wait(p
->mainloop
);
955 if (pa_context_get_state(p
->context
) != PA_CONTEXT_READY
)
956 goto unlock_and_fail
;
958 /* Now, initialize the stream */
959 if (!(p
->stream
= pa_stream_new(p
->context
, "Flash Animation", &ss
, NULL
)))
960 goto unlock_and_fail
;
962 pa_stream_set_state_callback(p
->stream
, stream_state_cb
, p
);
963 pa_stream_set_write_callback(p
->stream
, stream_request_cb
, p
);
964 pa_stream_set_latency_update_callback(p
->stream
, stream_latency_update_cb
, p
);
966 if (pa_stream_connect_playback(p
->stream
, NULL
, NULL
, PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_AUTO_TIMING_UPDATE
, NULL
, NULL
) < 0)
967 goto unlock_and_fail
;
969 /* Wait until the stream is ready */
970 pa_threaded_mainloop_wait(p
->mainloop
);
972 if (pa_stream_get_state(p
->stream
) != PA_STREAM_READY
)
973 goto unlock_and_fail
;
975 pa_threaded_mainloop_unlock(p
->mainloop
);
981 pa_threaded_mainloop_unlock(p
->mainloop
);
985 FPX_SoundOutput_Close(p
);
990 static int FPX_SoundOutput_Close(void *ptr
) {
991 struct output_data
*p
= ptr
;
996 pa_threaded_mainloop_stop(p
->mainloop
);
999 pa_stream_disconnect(p
->stream
);
1000 pa_stream_unref(p
->stream
);
1004 pa_context_disconnect(p
->context
);
1005 pa_context_unref(p
->context
);
1009 pa_threaded_mainloop_free(p
->mainloop
);
1017 static int FPX_SoundOutput_Latency(void *ptr
) {
1018 struct output_data
*p
= ptr
;
1025 /* We lock here only if we are not called from our event loop thread */
1026 if (!p
->thread_id
|| !pthread_equal(p
->thread_id
, pthread_self()))
1027 pa_threaded_mainloop_lock(p
->mainloop
);
1029 if (pa_stream_get_latency(p
->stream
, &t
, &negative
) < 0 || negative
)
1032 r
= (int) (pa_usec_to_bytes(t
, pa_stream_get_sample_spec(p
->stream
)) >> 2);
1034 if (!p
->thread_id
|| !pthread_equal(p
->thread_id
, pthread_self()))
1035 pa_threaded_mainloop_unlock(p
->mainloop
);
1043 struct VideoOutput_Instance
{
1050 struct video_window window
;
1051 struct video_picture picture
;
1054 static void *v4l_thread(void *ptr
)
1056 struct VideoOutput_Instance
*instance
= (struct VideoOutput_Instance
*)ptr
;
1062 result
= read(instance
->v4l_fd
, instance
->buffer
[instance
->buffercurrent
], instance
->buffersize
);
1070 if ( instance
->signal
) {
1072 ioctl(instance
->v4l_fd
, VIDIOCCAPTURE
, &status
);
1078 static void *FPX_VideoInput_Open(void)
1080 struct VideoOutput_Instance
*instance
= 0;
1082 if ( !FPI_Mem_Alloc
) goto fail
;
1084 instance
= (struct VideoOutput_Instance
*)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance
));
1085 memset(instance
,0,sizeof(struct VideoOutput_Instance
));
1087 if ( ( instance
->v4l_fd
= open("/dev/video", O_RDONLY
) ) < 0 ) goto fail
;
1089 if ( ioctl(instance
->v4l_fd
, VIDIOCGPICT
, &instance
->picture
) < 0 ) goto fail
;
1091 switch(instance
->picture
.palette
) {
1092 case VIDEO_PALETTE_YUV420P
:
1094 case VIDEO_PALETTE_RGB24
:
1095 case VIDEO_PALETTE_YUV422P
:
1096 case VIDEO_PALETTE_YUV411P
:
1097 case VIDEO_PALETTE_YUV410P
:
1098 case VIDEO_PALETTE_GREY
:
1099 case VIDEO_PALETTE_HI240
:
1100 case VIDEO_PALETTE_RGB565
:
1101 case VIDEO_PALETTE_RGB32
:
1102 case VIDEO_PALETTE_RGB555
:
1103 case VIDEO_PALETTE_YUV422
:
1104 case VIDEO_PALETTE_YUYV
:
1105 case VIDEO_PALETTE_UYVY
:
1106 case VIDEO_PALETTE_YUV420
:
1107 case VIDEO_PALETTE_YUV411
:
1108 case VIDEO_PALETTE_RAW
:
1113 if( ioctl(instance
->v4l_fd
, VIDIOCGWIN
, &instance
->window
) < 0 ) goto fail
;
1115 instance
->buffer
[0] = FPI_Mem_Alloc(instance
->window
.width
* instance
->window
.height
* 2);
1116 instance
->buffer
[1] = FPI_Mem_Alloc(instance
->window
.width
* instance
->window
.height
* 2);
1118 if ( pthread_create(&instance
->thread
, 0, v4l_thread
, instance
) < 0 ) goto fail
;
1123 if ( FPI_Mem_Free
) {
1124 if ( instance
->buffer
[0] ) {
1125 FPI_Mem_Free(instance
->buffer
[0]);
1127 if ( instance
->buffer
[1] ) {
1128 FPI_Mem_Free(instance
->buffer
[1]);
1130 FPI_Mem_Free(instance
);
1135 static int FPX_VideoInput_Close(void *ptr
)
1137 struct VideoOutput_Instance
*instance
= (struct VideoOutput_Instance
*)ptr
;
1140 instance
->signal
= 1;
1142 if ( instance
->thread
) {
1143 pthread_join(instance
->thread
,&retVal
);
1146 if ( instance
->v4l_fd
) {
1147 close(instance
->v4l_fd
);
1150 if ( FPI_Mem_Free
) {
1151 if ( instance
->buffer
[0] ) {
1152 FPI_Mem_Free(instance
->buffer
[0]);
1154 if ( instance
->buffer
[1] ) {
1155 FPI_Mem_Free(instance
->buffer
[1]);
1157 FPI_Mem_Free(instance
);
1163 static int FPX_VideoInput_GetFrame(void *ptr
, char *data
, int width
, int height
, int pitch_n_bytes
)
1165 struct VideoOutput_Instance
*instance
= (struct VideoOutput_Instance
*)ptr
;
1166 int ix
, iy
, ox
, oy
, ow
, oh
, dx
, dy
, Y
, U
, V
, R
, G
, B
;
1167 unsigned char *y
, *u
, *v
;
1169 switch(instance
->picture
.palette
) {
1170 case VIDEO_PALETTE_YUV420P
: {
1171 ow
= instance
->window
.width
;
1172 oh
= instance
->window
.height
;
1174 dx
= (ow
<<16) / width
;
1175 dy
= (oh
<<16) / height
;
1177 y
= (unsigned char *)instance
->buffer
[instance
->buffercurrent
^1];
1179 v
= u
+ ow
* oh
/ 4;
1183 for ( iy
= 0; iy
< height
; iy
++ ) {
1187 for ( ix
= 0; ix
< width
; ix
++ ) {
1189 Y
= ( 149 * ((int)(y
[(oy
>>16)*(ow
)+(ox
>>16)]) - 16) ) / 2;
1190 U
= (int)(u
[(oy
>>17)*(ow
/2)+(ox
>>17)]) - 128;
1191 V
= (int)(v
[(oy
>>17)*(ow
/2)+(ox
>>17)]) - 128;
1193 R
= (Y
+ V
* 102 ) / 64;
1194 G
= (Y
- V
* 52 - U
* 25 ) / 64;
1195 B
= (Y
+ U
* 129 ) / 64;
1197 R
= R
< 0 ? 0 : ( R
> 255 ? 255 : R
);
1198 G
= G
< 0 ? 0 : ( G
> 255 ? 255 : G
);
1199 B
= B
< 0 ? 0 : ( B
> 255 ? 255 : B
);
1210 data
+= pitch_n_bytes
;
1217 instance
->buffercurrent
^= 1;