From: Sam Hocevar Date: Tue, 20 Aug 2002 21:02:40 +0000 (+0000) Subject: * ./modules/gui/qnx/*: ported the QNX audio output to the new API, courtesy X-Git-Tag: 0.5.0~1041 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=a3412c816e0c438fa6466ff2259556369c12558c;p=vlc * ./modules/gui/qnx/*: ported the QNX audio output to the new API, courtesy of Pascal Levesque. --- diff --git a/AUTHORS b/AUTHORS index 9d80141dcc..fd8bf87320 100644 --- a/AUTHORS +++ b/AUTHORS @@ -276,7 +276,7 @@ S: USA, California N: Pascal Levesque E: pascal.levesque@mindready.com -D: QNX RTOS video output +D: QNX RTOS video output and audio output S: Canada, Québec N: Arkadiusz Lipiec diff --git a/modules/gui/qnx/aout.c b/modules/gui/qnx/aout.c index adbf84c33c..33c96232fc 100644 --- a/modules/gui/qnx/aout.c +++ b/modules/gui/qnx/aout.c @@ -1,16 +1,17 @@ /***************************************************************************** - * aout.c : QNX audio output + * aout.c : QNX audio output ***************************************************************************** * Copyright (C) 2000, 2001 VideoLAN * * Authors: Henri Fallon * Jon Lech Johansen - * + * Pascal Levesque + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -29,7 +30,13 @@ #include /* calloc(), malloc(), free() */ #include + +#ifdef HAVE_ALLOCA_H +# include +#endif + #include +#include "aout_internal.h" #include @@ -38,14 +45,22 @@ struct aout_sys_t snd_pcm_t * p_pcm_handle; int i_card; int i_device; + + byte_t * p_silent_buffer; + vlc_bool_t b_initialized; }; +#define DEFAULT_FRAME_SIZE 2048 + /***************************************************************************** * Local prototypes *****************************************************************************/ -static int SetFormat ( aout_thread_t * ); -static int GetBufInfo ( aout_thread_t *, int ); -static void Play ( aout_thread_t *, byte_t *, int ); +int E_(OpenAudio) ( vlc_object_t *p_this ); +void E_(CloseAudio) ( vlc_object_t *p_this ); +static int GetBufInfo ( aout_instance_t * ); +static int SetFormat ( aout_instance_t * ); +static void Play ( aout_instance_t * ); +static int QNXaoutThread ( aout_instance_t * ); /***************************************************************************** * Open : creates a handle and opens an alsa device @@ -54,69 +69,83 @@ static void Play ( aout_thread_t *, byte_t *, int ); *****************************************************************************/ int E_(OpenAudio)( vlc_object_t *p_this ) { - aout_thread_t *p_aout = (aout_thread_t *)p_this; + aout_instance_t *p_aout = (aout_instance_t *)p_this; int i_ret; /* allocate structure */ - p_aout->p_sys = malloc( sizeof( aout_sys_t ) ); - if( p_aout->p_sys == NULL ) + p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) ); + if( p_aout->output.p_sys == NULL ) { msg_Err( p_aout, "out of memory" ); - return( 1 ); + return -1; } /* open audio device */ - if( ( i_ret = snd_pcm_open_preferred( &p_aout->p_sys->p_pcm_handle, - &p_aout->p_sys->i_card, - &p_aout->p_sys->i_device, + if( ( i_ret = snd_pcm_open_preferred( &p_aout->output.p_sys->p_pcm_handle, + &p_aout->output.p_sys->i_card, + &p_aout->output.p_sys->i_device, SND_PCM_OPEN_PLAYBACK ) ) < 0 ) { msg_Err( p_aout, "unable to open audio device (%s)", snd_strerror( i_ret ) ); - free( p_aout->p_sys ); - return( 1 ); + free( p_aout->output.p_sys ); + return -1; } /* disable mmap */ - if( ( i_ret = snd_pcm_plugin_set_disable( p_aout->p_sys->p_pcm_handle, + if( ( i_ret = snd_pcm_plugin_set_disable( p_aout->output.p_sys->p_pcm_handle, PLUGIN_DISABLE_MMAP ) ) < 0 ) { msg_Err( p_aout, "unable to disable mmap (%s)", snd_strerror(i_ret) ); - Close( p_this ); - free( p_aout->p_sys ); - return( 1 ); + E_(CloseAudio)( p_this ); + free( p_aout->output.p_sys ); + return -1; } - p_aout->pf_setformat = SetFormat; - p_aout->pf_getbufinfo = GetBufInfo; - p_aout->pf_play = Play; + /* Create audio thread and wait for its readiness. */ + p_aout->output.p_sys->b_initialized = VLC_FALSE; + if( vlc_thread_create( p_aout, "aout", QNXaoutThread, VLC_FALSE ) ) + { + msg_Err( p_aout, "cannot create QNX audio thread (%s)", strerror(errno) ); + E_(CloseAudio)( p_this ); + free( p_aout->output.p_sys ); + return -1; + } + + p_aout->output.p_sys->p_silent_buffer = malloc( DEFAULT_FRAME_SIZE * 4 ); + + p_aout->output.pf_setformat = SetFormat; + p_aout->output.pf_play = Play; return( 0 ); } /***************************************************************************** - * SetFormat : set the audio output format + * SetFormat : set the audio output format ***************************************************************************** * This function prepares the device, sets the rate, format, the mode * ("play as soon as you have data"), and buffer information. *****************************************************************************/ -static int SetFormat( aout_thread_t *p_aout ) +static int SetFormat( aout_instance_t *p_this ) { int i_ret; int i_bytes_per_sample; snd_pcm_channel_info_t pi; snd_pcm_channel_params_t pp; + aout_instance_t *p_aout = (aout_instance_t *)p_this; + + p_aout->output.p_sys->b_initialized = VLC_FALSE; memset( &pi, 0, sizeof(pi) ); memset( &pp, 0, sizeof(pp) ); pi.channel = SND_PCM_CHANNEL_PLAYBACK; - if( ( i_ret = snd_pcm_plugin_info( p_aout->p_sys->p_pcm_handle, + if( ( i_ret = snd_pcm_plugin_info( p_aout->output.p_sys->p_pcm_handle, &pi ) ) < 0 ) { msg_Err( p_aout, "unable to get plugin info (%s)", snd_strerror( i_ret ) ); - return( 1 ); + return -1; } pp.mode = SND_PCM_MODE_BLOCK; @@ -124,14 +153,17 @@ static int SetFormat( aout_thread_t *p_aout ) pp.start_mode = SND_PCM_START_FULL; pp.stop_mode = SND_PCM_STOP_STOP; - pp.buf.block.frags_max = 1; + pp.buf.block.frags_max = 3; pp.buf.block.frags_min = 1; - + pp.format.interleave = 1; - pp.format.rate = p_aout->i_rate; - pp.format.voices = p_aout->i_channels; + pp.format.rate = p_aout->output.output.i_rate; + pp.format.voices = p_aout->output.output.i_channels; + + p_aout->output.output.i_format = AOUT_FMT_S16_NE; + p_aout->output.i_nb_samples = DEFAULT_FRAME_SIZE; - switch( p_aout->i_format ) + switch( p_aout->output.output.i_format ) { case AOUT_FMT_S16_LE: pp.format.format = SND_PCM_SFMT_S16_LE; @@ -144,27 +176,29 @@ static int SetFormat( aout_thread_t *p_aout ) break; } - pp.buf.block.frag_size = - (((s64)p_aout->i_rate * AOUT_BUFFER_DURATION) / 1000000) * - p_aout->i_channels * i_bytes_per_sample; + pp.buf.block.frag_size = p_aout->output.i_nb_samples * + p_aout->output.output.i_channels * + i_bytes_per_sample; /* set parameters */ - if( ( i_ret = snd_pcm_plugin_params( p_aout->p_sys->p_pcm_handle, + if( ( i_ret = snd_pcm_plugin_params( p_aout->output.p_sys->p_pcm_handle, &pp ) ) < 0 ) { msg_Err( p_aout, "unable to set parameters (%s)", snd_strerror(i_ret) ); - return( 1 ); + return -1; } /* prepare channel */ - if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle, + if( ( i_ret = snd_pcm_plugin_prepare( p_aout->output.p_sys->p_pcm_handle, SND_PCM_CHANNEL_PLAYBACK ) ) < 0 ) { msg_Err( p_aout, "unable to prepare channel (%s)", snd_strerror( i_ret ) ); - return( 1 ); + return -1; } + p_aout->output.p_sys->b_initialized = VLC_TRUE; + return( 0 ); } @@ -176,14 +210,14 @@ static int SetFormat( aout_thread_t *p_aout ) * of data to play, it switches to the "underrun" status. It has to * be flushed and re-prepared *****************************************************************************/ -static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit ) +static int GetBufInfo( aout_instance_t *p_aout ) { int i_ret; snd_pcm_channel_status_t status; /* get current pcm status */ memset( &status, 0, sizeof(status) ); - if( ( i_ret = snd_pcm_plugin_status( p_aout->p_sys->p_pcm_handle, + if( ( i_ret = snd_pcm_plugin_status( p_aout->output.p_sys->p_pcm_handle, &status ) ) < 0 ) { msg_Err( p_aout, "unable to get device status (%s)", @@ -196,7 +230,7 @@ static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit ) { case SND_PCM_STATUS_READY: case SND_PCM_STATUS_UNDERRUN: - if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle, + if( ( i_ret = snd_pcm_plugin_prepare( p_aout->output.p_sys->p_pcm_handle, SND_PCM_CHANNEL_PLAYBACK ) ) < 0 ) { msg_Err( p_aout, "unable to prepare channel (%s)", @@ -213,31 +247,100 @@ static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit ) ***************************************************************************** * Plays a sample using the snd_pcm_write function from the alsa API *****************************************************************************/ -static void Play( aout_thread_t *p_aout, byte_t *buffer, int i_size ) +static void Play( aout_instance_t *p_aout ) { - int i_ret; - - if( ( i_ret = snd_pcm_plugin_write( p_aout->p_sys->p_pcm_handle, - (void *) buffer, - (size_t) i_size ) ) <= 0 ) - { - msg_Err( p_aout, "unable to write data (%s)", snd_strerror(i_ret) ); - } } /***************************************************************************** * CloseAudio: close the audio device *****************************************************************************/ -static void E_(CloseAudio) ( vlc_object_t *p_this ) +void E_(CloseAudio) ( vlc_object_t *p_this ) { - aout_thread_t *p_aout = (aout_thread_t *)p_this; + aout_instance_t *p_aout = (aout_instance_t *)p_this; int i_ret; - if( ( i_ret = snd_pcm_close( p_aout->p_sys->p_pcm_handle ) ) < 0 ) + p_aout->b_die = 1; + vlc_thread_join( p_aout ); + + if( ( i_ret = snd_pcm_close( p_aout->output.p_sys->p_pcm_handle ) ) < 0 ) { msg_Err( p_aout, "unable to close audio device (%s)", snd_strerror( i_ret ) ); } - free( p_aout->p_sys ); + free( p_aout->output.p_sys->p_silent_buffer ); + free( p_aout->output.p_sys ); } + + +/***************************************************************************** + * QNXaoutThread: asynchronous thread used to DMA the data to the device + *****************************************************************************/ +static int QNXaoutThread( aout_instance_t * p_aout ) +{ + struct aout_sys_t * p_sys = p_aout->output.p_sys; + + while ( !p_aout->b_die ) + { + aout_buffer_t * p_buffer; + int i_tmp, i_size; + byte_t * p_bytes; + + if( !p_sys->b_initialized ) + { + msleep( THREAD_SLEEP ); + continue; + } + + if ( p_aout->output.output.i_format != AOUT_FMT_SPDIF ) + { + mtime_t next_date = 0; + + /* Get the presentation date of the next write() operation. It + * is equal to the current date + duration of buffered samples. + * Order is important here, since GetBufInfo is believed to take + * more time than mdate(). */ + next_date = (mtime_t)GetBufInfo( p_aout ) * 1000000 + / p_aout->output.output.i_bytes_per_frame + / p_aout->output.output.i_rate + * p_aout->output.output.i_frame_length; + next_date += mdate(); + + p_buffer = aout_OutputNextBuffer( p_aout, next_date, VLC_FALSE ); + } + else + { + p_buffer = aout_OutputNextBuffer( p_aout, 0, VLC_TRUE ); + } + + if ( p_buffer != NULL ) + { + p_bytes = p_buffer->p_buffer; + i_size = p_buffer->i_nb_bytes; + } + else + { + i_size = DEFAULT_FRAME_SIZE / p_aout->output.output.i_frame_length + * p_aout->output.output.i_bytes_per_frame; + p_bytes = p_aout->output.p_sys->p_silent_buffer; + memset( p_bytes, 0, i_size ); + } + + i_tmp = snd_pcm_plugin_write( p_aout->output.p_sys->p_pcm_handle, + (void *) p_bytes, + (size_t) i_size ); + + if( i_tmp < 0 ) + { + msg_Err( p_aout, "write failed (%s)", strerror(errno) ); + } + + if ( p_buffer != NULL ) + { + aout_BufferFree( p_buffer ); + } + } + + return 0; +} + diff --git a/modules/gui/qnx/vout.c b/modules/gui/qnx/vout.c index b49d7135a5..9386228c55 100644 --- a/modules/gui/qnx/vout.c +++ b/modules/gui/qnx/vout.c @@ -129,7 +129,7 @@ static void SetPalette ( vout_thread_t *, u16 *, u16 *, u16 * ); * actual properties of the display. *****************************************************************************/ int E_(OpenVideo) ( vlc_object_t *p_this ) -{ +{ vout_thread_t * p_vout = (vout_thread_t *)p_this; /* init connection to photon */ @@ -277,7 +277,7 @@ static void QNXEnd( vout_thread_t *p_vout ) * Terminate an output method created by QNXCreate *****************************************************************************/ void E_(CloseVideo) ( vlc_object_t *p_this ) -{ +{ vout_thread_t * p_vout = (vout_thread_t *)p_this; /* destroy the window */ @@ -541,16 +541,6 @@ static int QNXInitDisplay( vout_thread_t * p_vout ) return( 1 ); } - /* switch to normal mode if no overlay support */ -// printf("minfo.mode_capabilities1: 0x%x\n", minfo.mode_capabilities1); - - if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY && - !( minfo.mode_capabilities1 & PgVM_MODE_CAP1_VIDEO_OVERLAY ) ) - { - msg_Err( p_vout, "no overlay support detected" ); - p_vout->p_sys->i_mode = MODE_NORMAL_MEM; - } - if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY ) { int i = 0;