00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <errno.h>
00029 #include <string.h>
00030 #include <stdlib.h>
00031
00032 #include <vlc/vlc.h>
00033
00034 #ifdef HAVE_ALLOCA_H
00035 # include <alloca.h>
00036 #endif
00037
00038 #include <vlc/aout.h>
00039 #include "aout_internal.h"
00040
00041 #include <sys/asoundlib.h>
00042
00043 struct aout_sys_t
00044 {
00045 snd_pcm_t * p_pcm_handle;
00046 int i_card;
00047 int i_device;
00048
00049 byte_t * p_silent_buffer;
00050 };
00051
00052 #define DEFAULT_FRAME_SIZE 2048
00053
00054
00055
00056
00057 int E_(OpenAudio) ( vlc_object_t *p_this );
00058 void E_(CloseAudio) ( vlc_object_t *p_this );
00059 static int GetBufInfo ( aout_instance_t * );
00060 static void Play ( aout_instance_t * );
00061 static int QNXaoutThread ( aout_instance_t * );
00062
00063
00064
00065
00066
00067
00068 int E_(OpenAudio)( vlc_object_t *p_this )
00069 {
00070 aout_instance_t *p_aout = (aout_instance_t *)p_this;
00071 int i_ret;
00072 int i_bytes_per_sample;
00073 int i_nb_channels;
00074 snd_pcm_channel_info_t pi;
00075 snd_pcm_channel_params_t pp;
00076 aout_instance_t *p_aout = (aout_instance_t *)p_this;
00077
00078
00079 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
00080 if( p_aout->output.p_sys == NULL )
00081 {
00082 msg_Err( p_aout, "out of memory" );
00083 return -1;
00084 }
00085
00086
00087 if( ( i_ret = snd_pcm_open_preferred( &p_aout->output.p_sys->p_pcm_handle,
00088 &p_aout->output.p_sys->i_card,
00089 &p_aout->output.p_sys->i_device,
00090 SND_PCM_OPEN_PLAYBACK ) ) < 0 )
00091 {
00092 msg_Err( p_aout, "unable to open audio device (%s)",
00093 snd_strerror( i_ret ) );
00094 free( p_aout->output.p_sys );
00095 return -1;
00096 }
00097
00098
00099 if( ( i_ret = snd_pcm_plugin_set_disable( p_aout->output.p_sys->p_pcm_handle,
00100 PLUGIN_DISABLE_MMAP ) ) < 0 )
00101 {
00102 msg_Err( p_aout, "unable to disable mmap (%s)", snd_strerror(i_ret) );
00103 E_(CloseAudio)( p_this );
00104 free( p_aout->output.p_sys );
00105 return -1;
00106 }
00107
00108 p_aout->output.p_sys->p_silent_buffer = malloc( DEFAULT_FRAME_SIZE * 4 );
00109 p_aout->output.pf_play = Play;
00110 aout_VolumeSoftInit( p_aout );
00111
00112 memset( &pi, 0, sizeof(pi) );
00113 memset( &pp, 0, sizeof(pp) );
00114
00115 pi.channel = SND_PCM_CHANNEL_PLAYBACK;
00116 if( ( i_ret = snd_pcm_plugin_info( p_aout->output.p_sys->p_pcm_handle,
00117 &pi ) ) < 0 )
00118 {
00119 msg_Err( p_aout, "unable to get plugin info (%s)",
00120 snd_strerror( i_ret ) );
00121 E_(CloseAudio)( p_this );
00122 free( p_aout->output.p_sys );
00123 return -1;
00124 }
00125
00126 pp.mode = SND_PCM_MODE_BLOCK;
00127 pp.channel = SND_PCM_CHANNEL_PLAYBACK;
00128 pp.start_mode = SND_PCM_START_FULL;
00129 pp.stop_mode = SND_PCM_STOP_STOP;
00130
00131 pp.buf.block.frags_max = 3;
00132 pp.buf.block.frags_min = 1;
00133
00134 pp.format.interleave = 1;
00135 pp.format.rate = p_aout->output.output.i_rate;
00136
00137 i_nb_channels = aout_FormatNbChannels( &p_aout->output.output );
00138 if ( i_nb_channels > 2 )
00139 {
00140
00141 i_nb_channels = 2;
00142 p_aout->output.output.i_channels = AOUT_CHAN_STEREO;
00143 }
00144 pp.format.voices = i_nb_channels;
00145
00146 p_aout->output.output.i_format = AOUT_FMT_S16_NE;
00147 p_aout->output.i_nb_samples = DEFAULT_FRAME_SIZE;
00148 pp.format.format = SND_PCM_SFMT_S16;
00149 i_bytes_per_sample = 2;
00150
00151 pp.buf.block.frag_size = p_aout->output.i_nb_samples *
00152 p_aout->output.output.i_channels *
00153 i_bytes_per_sample;
00154
00155
00156 if( ( i_ret = snd_pcm_plugin_params( p_aout->output.p_sys->p_pcm_handle,
00157 &pp ) ) < 0 )
00158 {
00159 msg_Err( p_aout, "unable to set parameters (%s)", snd_strerror(i_ret) );
00160 E_(CloseAudio)( p_this );
00161 free( p_aout->output.p_sys );
00162 return -1;
00163 }
00164
00165
00166 if( ( i_ret = snd_pcm_plugin_prepare( p_aout->output.p_sys->p_pcm_handle,
00167 SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
00168 {
00169 msg_Err( p_aout, "unable to prepare channel (%s)",
00170 snd_strerror( i_ret ) );
00171 E_(CloseAudio)( p_this );
00172 free( p_aout->output.p_sys );
00173 return -1;
00174 }
00175
00176
00177 if( vlc_thread_create( p_aout, "aout", QNXaoutThread,
00178 VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
00179 {
00180 msg_Err( p_aout, "cannot create QNX audio thread (%s)", strerror(errno) );
00181 E_(CloseAudio)( p_this );
00182 free( p_aout->output.p_sys );
00183 return -1;
00184 }
00185
00186 return( 0 );
00187 }
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 static int GetBufInfo( aout_instance_t *p_aout )
00198 {
00199 int i_ret;
00200 snd_pcm_channel_status_t status;
00201
00202
00203 memset( &status, 0, sizeof(status) );
00204 if( ( i_ret = snd_pcm_plugin_status( p_aout->output.p_sys->p_pcm_handle,
00205 &status ) ) < 0 )
00206 {
00207 msg_Err( p_aout, "unable to get device status (%s)",
00208 snd_strerror( i_ret ) );
00209 return( -1 );
00210 }
00211
00212
00213 switch( status.status )
00214 {
00215 case SND_PCM_STATUS_READY:
00216 case SND_PCM_STATUS_UNDERRUN:
00217 if( ( i_ret = snd_pcm_plugin_prepare( p_aout->output.p_sys->p_pcm_handle,
00218 SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
00219 {
00220 msg_Err( p_aout, "unable to prepare channel (%s)",
00221 snd_strerror( i_ret ) );
00222 }
00223 break;
00224 }
00225
00226 return( status.count );
00227 }
00228
00229
00230
00231
00232
00233
00234 static void Play( aout_instance_t *p_aout )
00235 {
00236 }
00237
00238
00239
00240
00241 void E_(CloseAudio) ( vlc_object_t *p_this )
00242 {
00243 aout_instance_t *p_aout = (aout_instance_t *)p_this;
00244 int i_ret;
00245
00246 p_aout->b_die = 1;
00247 vlc_thread_join( p_aout );
00248
00249 if( ( i_ret = snd_pcm_close( p_aout->output.p_sys->p_pcm_handle ) ) < 0 )
00250 {
00251 msg_Err( p_aout, "unable to close audio device (%s)",
00252 snd_strerror( i_ret ) );
00253 }
00254
00255 free( p_aout->output.p_sys->p_silent_buffer );
00256 free( p_aout->output.p_sys );
00257 }
00258
00259
00260
00261
00262
00263 static int QNXaoutThread( aout_instance_t * p_aout )
00264 {
00265 struct aout_sys_t * p_sys = p_aout->output.p_sys;
00266
00267 while ( !p_aout->b_die )
00268 {
00269 aout_buffer_t * p_buffer;
00270 int i_tmp, i_size;
00271 byte_t * p_bytes;
00272
00273 if ( p_aout->output.output.i_format != VLC_FOURCC('s','p','d','i') )
00274 {
00275 mtime_t next_date = 0;
00276
00277
00278
00279
00280
00281 next_date = (mtime_t)GetBufInfo( p_aout ) * 1000000
00282 / p_aout->output.output.i_bytes_per_frame
00283 / p_aout->output.output.i_rate
00284 * p_aout->output.output.i_frame_length;
00285 next_date += mdate();
00286
00287 p_buffer = aout_OutputNextBuffer( p_aout, next_date, VLC_FALSE );
00288 }
00289 else
00290 {
00291 p_buffer = aout_OutputNextBuffer( p_aout, 0, VLC_TRUE );
00292 }
00293
00294 if ( p_buffer != NULL )
00295 {
00296 p_bytes = p_buffer->p_buffer;
00297 i_size = p_buffer->i_nb_bytes;
00298 }
00299 else
00300 {
00301 i_size = DEFAULT_FRAME_SIZE / p_aout->output.output.i_frame_length
00302 * p_aout->output.output.i_bytes_per_frame;
00303 p_bytes = p_aout->output.p_sys->p_silent_buffer;
00304 memset( p_bytes, 0, i_size );
00305 }
00306
00307 i_tmp = snd_pcm_plugin_write( p_aout->output.p_sys->p_pcm_handle,
00308 (void *) p_bytes,
00309 (size_t) i_size );
00310
00311 if( i_tmp < 0 )
00312 {
00313 msg_Err( p_aout, "write failed (%s)", strerror(errno) );
00314 }
00315
00316 if ( p_buffer != NULL )
00317 {
00318 aout_BufferFree( p_buffer );
00319 }
00320 }
00321
00322 return 0;
00323 }
00324