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 #include <stdlib.h>
00028 #include <string.h>
00029
00030 #include <vlc/vlc.h>
00031
00032 #include "audio_output.h"
00033 #include "aout_internal.h"
00034
00035
00036
00037
00038
00039
00040 int aout_OutputNew( aout_instance_t * p_aout,
00041 audio_sample_format_t * p_format )
00042 {
00043
00044 int i_rate = config_GetInt( p_aout, "aout-rate" );
00045 vlc_value_t val, text;
00046
00047 if( i_rate == 0 ) i_rate = -1;
00048
00049 memcpy( &p_aout->output.output, p_format, sizeof(audio_sample_format_t) );
00050 if ( i_rate != -1 )
00051 p_aout->output.output.i_rate = i_rate;
00052 aout_FormatPrepare( &p_aout->output.output );
00053
00054 vlc_mutex_lock( &p_aout->output_fifo_lock );
00055
00056
00057 p_aout->output.p_module = module_Need( p_aout, "audio output", "$aout", 0);
00058 if ( p_aout->output.p_module == NULL )
00059 {
00060 msg_Err( p_aout, "no suitable aout module" );
00061 vlc_mutex_unlock( &p_aout->output_fifo_lock );
00062 return -1;
00063 }
00064
00065 if ( var_Type( p_aout, "audio-channels" ) ==
00066 (VLC_VAR_INTEGER | VLC_VAR_HASCHOICE) )
00067 {
00068
00069 var_Get( p_aout, "audio-channels", &val );
00070
00071 if ( val.i_int == AOUT_VAR_CHAN_RSTEREO )
00072 {
00073 p_aout->output.output.i_original_channels |=
00074 AOUT_CHAN_REVERSESTEREO;
00075 }
00076 else if ( val.i_int == AOUT_VAR_CHAN_STEREO )
00077 {
00078 p_aout->output.output.i_original_channels =
00079 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
00080 }
00081 else if ( val.i_int == AOUT_VAR_CHAN_LEFT )
00082 {
00083 p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT;
00084 }
00085 else if ( val.i_int == AOUT_VAR_CHAN_RIGHT )
00086 {
00087 p_aout->output.output.i_original_channels = AOUT_CHAN_RIGHT;
00088 }
00089 else if ( val.i_int == AOUT_VAR_CHAN_DOLBYS )
00090 {
00091 p_aout->output.output.i_original_channels
00092 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_DOLBYSTEREO;
00093 }
00094 }
00095 else if ( p_aout->output.output.i_physical_channels == AOUT_CHAN_CENTER
00096 && (p_aout->output.output.i_original_channels
00097 & AOUT_CHAN_PHYSMASK) == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) )
00098 {
00099
00100 var_Create( p_aout, "audio-channels",
00101 VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
00102 text.psz_string = _("Audio Channels");
00103 var_Change( p_aout, "audio-channels", VLC_VAR_SETTEXT, &text, NULL );
00104
00105 val.i_int = AOUT_VAR_CHAN_STEREO; text.psz_string = _("Stereo");
00106 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
00107 val.i_int = AOUT_VAR_CHAN_LEFT; text.psz_string = _("Left");
00108 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
00109 val.i_int = AOUT_VAR_CHAN_RIGHT; text.psz_string = _("Right");
00110 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
00111 if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DUALMONO )
00112 {
00113
00114 p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT;
00115 val.i_int = AOUT_VAR_CHAN_LEFT;
00116 var_Set( p_aout, "audio-channels", val );
00117 }
00118 var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart,
00119 NULL );
00120 }
00121 else if ( p_aout->output.output.i_physical_channels ==
00122 (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)
00123 && (p_aout->output.output.i_original_channels &
00124 (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
00125 {
00126
00127 var_Create( p_aout, "audio-channels",
00128 VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
00129 text.psz_string = _("Audio Channels");
00130 var_Change( p_aout, "audio-channels", VLC_VAR_SETTEXT, &text, NULL );
00131
00132 if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
00133 {
00134 val.i_int = AOUT_VAR_CHAN_DOLBYS;
00135 text.psz_string = _("Dolby Surround");
00136 }
00137 else
00138 {
00139 val.i_int = AOUT_VAR_CHAN_STEREO;
00140 text.psz_string = _("Stereo");
00141 }
00142 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
00143 val.i_int = AOUT_VAR_CHAN_LEFT; text.psz_string = _("Left");
00144 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
00145 val.i_int = AOUT_VAR_CHAN_RIGHT; text.psz_string = _("Right");
00146 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
00147 val.i_int = AOUT_VAR_CHAN_RSTEREO; text.psz_string=_("Reverse stereo");
00148 var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
00149 if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DUALMONO )
00150 {
00151
00152 p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT;
00153 val.i_int = AOUT_VAR_CHAN_LEFT;
00154 var_Set( p_aout, "audio-channels", val );
00155 }
00156 var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart,
00157 NULL );
00158 }
00159 val.b_bool = VLC_TRUE;
00160 var_Set( p_aout, "intf-change", val );
00161
00162 aout_FormatPrepare( &p_aout->output.output );
00163
00164
00165 aout_FifoInit( p_aout, &p_aout->output.fifo,
00166 p_aout->output.output.i_rate );
00167
00168 vlc_mutex_unlock( &p_aout->output_fifo_lock );
00169
00170 aout_FormatPrint( p_aout, "output", &p_aout->output.output );
00171
00172
00173 memcpy( &p_aout->mixer.mixer, &p_aout->output.output,
00174 sizeof(audio_sample_format_t) );
00175 if ( !AOUT_FMT_NON_LINEAR(&p_aout->output.output) )
00176 {
00177
00178 p_aout->mixer.mixer.i_format
00179 = (p_aout->p_libvlc->i_cpu & CPU_CAPABILITY_FPU) ?
00180 VLC_FOURCC('f','l','3','2') :
00181 VLC_FOURCC('f','i','3','2');
00182 aout_FormatPrepare( &p_aout->mixer.mixer );
00183 }
00184 else
00185 {
00186 p_aout->mixer.mixer.i_format = p_format->i_format;
00187 }
00188
00189 aout_FormatPrint( p_aout, "mixer", &p_aout->output.output );
00190
00191
00192 p_aout->output.i_nb_filters = 0;
00193 if ( aout_FiltersCreatePipeline( p_aout, p_aout->output.pp_filters,
00194 &p_aout->output.i_nb_filters,
00195 &p_aout->mixer.mixer,
00196 &p_aout->output.output ) < 0 )
00197 {
00198 msg_Err( p_aout, "couldn't set an output pipeline" );
00199 module_Unneed( p_aout, p_aout->output.p_module );
00200 return -1;
00201 }
00202
00203
00204 p_aout->mixer.output_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
00205 p_aout->mixer.output_alloc.i_bytes_per_sec
00206 = p_aout->mixer.mixer.i_bytes_per_frame
00207 * p_aout->mixer.mixer.i_rate
00208 / p_aout->mixer.mixer.i_frame_length;
00209
00210 aout_FiltersHintBuffers( p_aout, p_aout->output.pp_filters,
00211 p_aout->output.i_nb_filters,
00212 &p_aout->mixer.output_alloc );
00213
00214 p_aout->output.b_error = 0;
00215 return 0;
00216 }
00217
00218
00219
00220
00221
00222
00223 void aout_OutputDelete( aout_instance_t * p_aout )
00224 {
00225 if ( p_aout->output.b_error )
00226 {
00227 return;
00228 }
00229
00230 module_Unneed( p_aout, p_aout->output.p_module );
00231
00232 aout_FiltersDestroyPipeline( p_aout, p_aout->output.pp_filters,
00233 p_aout->output.i_nb_filters );
00234 aout_FifoDestroy( p_aout, &p_aout->output.fifo );
00235
00236 p_aout->output.b_error = VLC_TRUE;
00237 }
00238
00239
00240
00241
00242
00243
00244 void aout_OutputPlay( aout_instance_t * p_aout, aout_buffer_t * p_buffer )
00245 {
00246 aout_FiltersPlay( p_aout, p_aout->output.pp_filters,
00247 p_aout->output.i_nb_filters,
00248 &p_buffer );
00249
00250 if( p_buffer->i_nb_bytes == 0 )
00251 {
00252 aout_BufferFree( p_buffer );
00253 return;
00254 }
00255
00256 vlc_mutex_lock( &p_aout->output_fifo_lock );
00257 aout_FifoPush( p_aout, &p_aout->output.fifo, p_buffer );
00258 p_aout->output.pf_play( p_aout );
00259 vlc_mutex_unlock( &p_aout->output_fifo_lock );
00260 }
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270 aout_buffer_t * aout_OutputNextBuffer( aout_instance_t * p_aout,
00271 mtime_t start_date,
00272 vlc_bool_t b_can_sleek )
00273 {
00274 aout_buffer_t * p_buffer;
00275
00276 vlc_mutex_lock( &p_aout->output_fifo_lock );
00277
00278 p_buffer = p_aout->output.fifo.p_first;
00279
00280
00281
00282
00283 while ( p_buffer && p_buffer->start_date <
00284 (b_can_sleek ? start_date : mdate()) - AOUT_PTS_TOLERANCE )
00285 {
00286 msg_Dbg( p_aout, "audio output is too slow ("I64Fd"), "
00287 "trashing "I64Fd"us", mdate() - p_buffer->start_date,
00288 p_buffer->end_date - p_buffer->start_date );
00289 p_buffer = p_buffer->p_next;
00290 aout_BufferFree( p_aout->output.fifo.p_first );
00291 p_aout->output.fifo.p_first = p_buffer;
00292 }
00293
00294 if ( p_buffer == NULL )
00295 {
00296 p_aout->output.fifo.pp_last = &p_aout->output.fifo.p_first;
00297
00298 #if 0
00299
00300
00301
00302
00303 aout_FifoSet( p_aout, &p_aout->output.fifo, 0 );
00304 if ( !p_aout->output.b_starving )
00305 msg_Dbg( p_aout,
00306 "audio output is starving (no input), playing silence" );
00307 p_aout->output.b_starving = 1;
00308 #endif
00309
00310 vlc_mutex_unlock( &p_aout->output_fifo_lock );
00311 return NULL;
00312 }
00313
00314
00315
00316
00317 if ( p_buffer->start_date > start_date
00318 + (p_buffer->end_date - p_buffer->start_date) )
00319
00320
00321
00322
00323
00324
00325 {
00326 vlc_mutex_unlock( &p_aout->output_fifo_lock );
00327 if ( !p_aout->output.b_starving )
00328 msg_Dbg( p_aout, "audio output is starving ("I64Fd"), "
00329 "playing silence", p_buffer->start_date - start_date );
00330 p_aout->output.b_starving = 1;
00331 return NULL;
00332 }
00333
00334 p_aout->output.b_starving = 0;
00335
00336 if ( !b_can_sleek &&
00337 ( (p_buffer->start_date - start_date > AOUT_PTS_TOLERANCE)
00338 || (start_date - p_buffer->start_date > AOUT_PTS_TOLERANCE) ) )
00339 {
00340
00341 int i;
00342 mtime_t difference = start_date - p_buffer->start_date;
00343 msg_Warn( p_aout, "output date isn't PTS date, requesting "
00344 "resampling ("I64Fd")", difference );
00345
00346 vlc_mutex_lock( &p_aout->input_fifos_lock );
00347 for ( i = 0; i < p_aout->i_nb_inputs; i++ )
00348 {
00349 aout_fifo_t * p_fifo = &p_aout->pp_inputs[i]->fifo;
00350
00351 aout_FifoMoveDates( p_aout, p_fifo, difference );
00352 }
00353
00354 aout_FifoMoveDates( p_aout, &p_aout->output.fifo, difference );
00355 vlc_mutex_unlock( &p_aout->input_fifos_lock );
00356 }
00357
00358 p_aout->output.fifo.p_first = p_buffer->p_next;
00359 if ( p_buffer->p_next == NULL )
00360 {
00361 p_aout->output.fifo.pp_last = &p_aout->output.fifo.p_first;
00362 }
00363
00364 vlc_mutex_unlock( &p_aout->output_fifo_lock );
00365 return p_buffer;
00366 }