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 /* There's no real handling of errors here. Unfortunately the
884 * Flash API doesn't export a sane way to do this. With networked
885 * audio streams and hotplug-capable audio devices the audio
886 * stream might be killed in the middle of nothing, hence it is
887 * very unfortunate that we cannot report errors that happen here
890 p
->first
= 0; /* So, we write the first block noch, remember that */
893 static void stream_request_cb(pa_stream
*s
, size_t length
, void *userdata
) {
894 struct output_data
*p
= userdata
;
900 p
->thread_id
= pthread_self();
902 /* Write some data */
906 static void stream_latency_update_cb(pa_stream
*s
, void *userdata
) {
907 struct output_data
*p
= userdata
;
912 p
->thread_id
= pthread_self();
914 /* Try to write some more, in case we delayed the first write until latency data became available */
918 static void *FPX_SoundOutput_Open(void) {
920 static const pa_sample_spec ss
= {
921 .format
= PA_SAMPLE_S16LE
, /* Hmm, Flash wants LE here, not
922 * NE. This makes porting Flash to
923 * Big-Endian machines unnecessary
929 struct output_data
*p
;
931 /* Unfortunately we cannot report any useful error string back to
932 * Flash. It would be highly preferable if Flash supported some
933 * way how we could tell the user what the reason is why audio is
934 * not working for him. */
936 if (!(p
= FPI_Mem_Alloc(sizeof(struct output_data
))))
939 memset(p
, 0, sizeof(*p
));
941 p
->thread_id
= (pthread_t
) 0;
943 /* First, let's create the main loop */
944 if (!(p
->mainloop
= pa_threaded_mainloop_new()))
947 /* Second, initialize the connection context */
948 if (!(p
->context
= pa_context_new(pa_threaded_mainloop_get_api(p
->mainloop
), "Adobe Flash")))
951 pa_context_set_state_callback(p
->context
, context_state_cb
, p
);
953 if (pa_context_connect(p
->context
, NULL
, 0, NULL
) < 0)
956 /* Now, let's start the background thread */
957 pa_threaded_mainloop_lock(p
->mainloop
);
959 if (pa_threaded_mainloop_start(p
->mainloop
) < 0)
962 /* Wait until the context is ready */
963 pa_threaded_mainloop_wait(p
->mainloop
);
965 if (pa_context_get_state(p
->context
) != PA_CONTEXT_READY
)
966 goto unlock_and_fail
;
968 /* Now, initialize the stream */
969 if (!(p
->stream
= pa_stream_new(p
->context
, "Flash Animation", &ss
, NULL
)))
970 goto unlock_and_fail
;
972 pa_stream_set_state_callback(p
->stream
, stream_state_cb
, p
);
973 pa_stream_set_write_callback(p
->stream
, stream_request_cb
, p
);
974 pa_stream_set_latency_update_callback(p
->stream
, stream_latency_update_cb
, p
);
976 if (pa_stream_connect_playback(p
->stream
, NULL
, NULL
, PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_AUTO_TIMING_UPDATE
, NULL
, NULL
) < 0)
977 goto unlock_and_fail
;
979 /* Wait until the stream is ready */
980 pa_threaded_mainloop_wait(p
->mainloop
);
982 if (pa_stream_get_state(p
->stream
) != PA_STREAM_READY
)
983 goto unlock_and_fail
;
985 pa_threaded_mainloop_unlock(p
->mainloop
);
991 pa_threaded_mainloop_unlock(p
->mainloop
);
995 FPX_SoundOutput_Close(p
);
1000 static int FPX_SoundOutput_Close(void *ptr
) {
1001 struct output_data
*p
= ptr
;
1006 pa_threaded_mainloop_stop(p
->mainloop
);
1009 pa_stream_disconnect(p
->stream
);
1010 pa_stream_unref(p
->stream
);
1014 pa_context_disconnect(p
->context
);
1015 pa_context_unref(p
->context
);
1019 pa_threaded_mainloop_free(p
->mainloop
);
1027 static int FPX_SoundOutput_Latency(void *ptr
) {
1028 struct output_data
*p
= ptr
;
1035 /* We lock here only if we are not called from our event loop thread */
1036 if (!p
->thread_id
|| !pthread_equal(p
->thread_id
, pthread_self()))
1037 pa_threaded_mainloop_lock(p
->mainloop
);
1039 if (pa_stream_get_latency(p
->stream
, &t
, &negative
) < 0 || negative
)
1042 r
= (int) (pa_usec_to_bytes(t
, pa_stream_get_sample_spec(p
->stream
)) >> 2);
1044 if (!p
->thread_id
|| !pthread_equal(p
->thread_id
, pthread_self()))
1045 pa_threaded_mainloop_unlock(p
->mainloop
);
1053 struct VideoOutput_Instance
{
1060 struct video_window window
;
1061 struct video_picture picture
;
1064 static void *v4l_thread(void *ptr
)
1066 struct VideoOutput_Instance
*instance
= (struct VideoOutput_Instance
*)ptr
;
1072 result
= read(instance
->v4l_fd
, instance
->buffer
[instance
->buffercurrent
], instance
->buffersize
);
1080 if ( instance
->signal
) {
1082 ioctl(instance
->v4l_fd
, VIDIOCCAPTURE
, &status
);
1088 static void *FPX_VideoInput_Open(void)
1090 struct VideoOutput_Instance
*instance
= 0;
1092 if ( !FPI_Mem_Alloc
) goto fail
;
1094 instance
= (struct VideoOutput_Instance
*)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance
));
1095 memset(instance
,0,sizeof(struct VideoOutput_Instance
));
1097 if ( ( instance
->v4l_fd
= open("/dev/video", O_RDONLY
) ) < 0 ) goto fail
;
1099 if ( ioctl(instance
->v4l_fd
, VIDIOCGPICT
, &instance
->picture
) < 0 ) goto fail
;
1101 switch(instance
->picture
.palette
) {
1102 case VIDEO_PALETTE_YUV420P
:
1104 case VIDEO_PALETTE_RGB24
:
1105 case VIDEO_PALETTE_YUV422P
:
1106 case VIDEO_PALETTE_YUV411P
:
1107 case VIDEO_PALETTE_YUV410P
:
1108 case VIDEO_PALETTE_GREY
:
1109 case VIDEO_PALETTE_HI240
:
1110 case VIDEO_PALETTE_RGB565
:
1111 case VIDEO_PALETTE_RGB32
:
1112 case VIDEO_PALETTE_RGB555
:
1113 case VIDEO_PALETTE_YUV422
:
1114 case VIDEO_PALETTE_YUYV
:
1115 case VIDEO_PALETTE_UYVY
:
1116 case VIDEO_PALETTE_YUV420
:
1117 case VIDEO_PALETTE_YUV411
:
1118 case VIDEO_PALETTE_RAW
:
1123 if( ioctl(instance
->v4l_fd
, VIDIOCGWIN
, &instance
->window
) < 0 ) goto fail
;
1125 instance
->buffer
[0] = FPI_Mem_Alloc(instance
->window
.width
* instance
->window
.height
* 2);
1126 instance
->buffer
[1] = FPI_Mem_Alloc(instance
->window
.width
* instance
->window
.height
* 2);
1128 if ( pthread_create(&instance
->thread
, 0, v4l_thread
, instance
) < 0 ) goto fail
;
1133 if ( FPI_Mem_Free
) {
1134 if ( instance
->buffer
[0] ) {
1135 FPI_Mem_Free(instance
->buffer
[0]);
1137 if ( instance
->buffer
[1] ) {
1138 FPI_Mem_Free(instance
->buffer
[1]);
1140 FPI_Mem_Free(instance
);
1145 static int FPX_VideoInput_Close(void *ptr
)
1147 struct VideoOutput_Instance
*instance
= (struct VideoOutput_Instance
*)ptr
;
1150 instance
->signal
= 1;
1152 if ( instance
->thread
) {
1153 pthread_join(instance
->thread
,&retVal
);
1156 if ( instance
->v4l_fd
) {
1157 close(instance
->v4l_fd
);
1160 if ( FPI_Mem_Free
) {
1161 if ( instance
->buffer
[0] ) {
1162 FPI_Mem_Free(instance
->buffer
[0]);
1164 if ( instance
->buffer
[1] ) {
1165 FPI_Mem_Free(instance
->buffer
[1]);
1167 FPI_Mem_Free(instance
);
1173 static int FPX_VideoInput_GetFrame(void *ptr
, char *data
, int width
, int height
, int pitch_n_bytes
)
1175 struct VideoOutput_Instance
*instance
= (struct VideoOutput_Instance
*)ptr
;
1176 int ix
, iy
, ox
, oy
, ow
, oh
, dx
, dy
, Y
, U
, V
, R
, G
, B
;
1177 unsigned char *y
, *u
, *v
;
1179 switch(instance
->picture
.palette
) {
1180 case VIDEO_PALETTE_YUV420P
: {
1181 ow
= instance
->window
.width
;
1182 oh
= instance
->window
.height
;
1184 dx
= (ow
<<16) / width
;
1185 dy
= (oh
<<16) / height
;
1187 y
= (unsigned char *)instance
->buffer
[instance
->buffercurrent
^1];
1189 v
= u
+ ow
* oh
/ 4;
1193 for ( iy
= 0; iy
< height
; iy
++ ) {
1197 for ( ix
= 0; ix
< width
; ix
++ ) {
1199 Y
= ( 149 * ((int)(y
[(oy
>>16)*(ow
)+(ox
>>16)]) - 16) ) / 2;
1200 U
= (int)(u
[(oy
>>17)*(ow
/2)+(ox
>>17)]) - 128;
1201 V
= (int)(v
[(oy
>>17)*(ow
/2)+(ox
>>17)]) - 128;
1203 R
= (Y
+ V
* 102 ) / 64;
1204 G
= (Y
- V
* 52 - U
* 25 ) / 64;
1205 B
= (Y
+ U
* 129 ) / 64;
1207 R
= R
< 0 ? 0 : ( R
> 255 ? 255 : R
);
1208 G
= G
< 0 ? 0 : ( G
> 255 ? 255 : G
);
1209 B
= B
< 0 ? 0 : ( B
> 255 ? 255 : B
);
1220 data
+= pitch_n_bytes
;
1227 instance
->buffercurrent
^= 1;