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 <errno.h>
00028 #include <fcntl.h>
00029 #include <string.h>
00030 #include <unistd.h>
00031 #include <stdlib.h>
00032
00033 #include <vlc/vlc.h>
00034 #include <vlc/aout.h>
00035 #include "aout_internal.h"
00036
00037 #include <sys/socket.h>
00038
00039 #include <sys/time.h>
00040 #include <time.h>
00041
00042 #include <esd.h>
00043
00044
00045
00046
00047
00048
00049
00050 struct aout_sys_t
00051 {
00052 esd_format_t esd_format;
00053 int i_fd;
00054
00055 mtime_t latency;
00056 };
00057
00058
00059
00060
00061 static int Open ( vlc_object_t * );
00062 static void Close ( vlc_object_t * );
00063 static void Play ( aout_instance_t * );
00064
00065
00066
00067
00068 vlc_module_begin();
00069 set_description( _("EsounD audio output") );
00070 set_shortname( "EsounD" );
00071 set_capability( "audio output", 50 );
00072 add_string( "esdserver", "", NULL, N_("Esound server"), NULL, VLC_FALSE );
00073 set_category( CAT_AUDIO );
00074 set_subcategory( SUBCAT_AUDIO_AOUT );
00075 set_callbacks( Open, Close );
00076 add_shortcut( "esound" );
00077 vlc_module_end();
00078
00079
00080
00081
00082 static int Open( vlc_object_t *p_this )
00083 {
00084 aout_instance_t *p_aout = (aout_instance_t *)p_this;
00085 struct aout_sys_t * p_sys;
00086 char * psz_server;
00087 int i_nb_channels;
00088 int i_newfd;
00089
00090
00091 p_sys = malloc( sizeof( aout_sys_t ) );
00092 if( p_sys == NULL )
00093 {
00094 msg_Err( p_aout, "out of memory" );
00095 return VLC_ENOMEM;
00096 }
00097
00098 p_aout->output.p_sys = p_sys;
00099
00100 p_aout->output.pf_play = Play;
00101 aout_VolumeSoftInit( p_aout );
00102
00103
00104 p_sys->esd_format = ESD_BITS16 | ESD_STREAM | ESD_PLAY;
00105 p_sys->esd_format &= ~ESD_MASK_CHAN;
00106
00107 p_aout->output.output.i_format = AOUT_FMT_S16_NE;
00108 i_nb_channels = aout_FormatNbChannels( &p_aout->output.output );
00109 if ( i_nb_channels > 2 )
00110 {
00111
00112 i_nb_channels = 2;
00113 p_aout->output.output.i_physical_channels =
00114 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
00115 }
00116
00117 switch( i_nb_channels )
00118 {
00119 case 1:
00120 p_sys->esd_format |= ESD_MONO;
00121 break;
00122 case 2:
00123 p_sys->esd_format |= ESD_STEREO;
00124 break;
00125 }
00126
00127
00128 p_aout->output.output.i_rate = ESD_DEFAULT_RATE;
00129 p_aout->output.i_nb_samples = ESD_BUF_SIZE * 2;
00130
00131
00132
00133 psz_server = config_GetPsz( p_aout, "esdserver" );
00134 if( psz_server && *psz_server )
00135 {
00136 p_sys->i_fd = esd_play_stream_fallback( p_sys->esd_format,
00137 p_aout->output.output.i_rate,
00138 psz_server, "vlc" );
00139 }
00140 else
00141 {
00142 p_sys->i_fd = esd_play_stream_fallback( p_sys->esd_format,
00143 p_aout->output.output.i_rate,
00144 NULL, "vlc" );
00145 }
00146
00147 if( p_sys->i_fd < 0 )
00148 {
00149 msg_Err( p_aout, "cannot open esound socket (format 0x%08x at %d Hz)",
00150 p_sys->esd_format, p_aout->output.output.i_rate );
00151 free( p_sys );
00152 return VLC_EGENERIC;
00153 }
00154
00155 if( psz_server && *psz_server )
00156 {
00157 struct timeval start, stop;
00158 esd_server_info_t * p_info;
00159
00160 gettimeofday( &start, NULL );
00161 p_info = esd_get_server_info( p_sys->i_fd );
00162 gettimeofday( &stop, NULL );
00163
00164 p_sys->latency = (mtime_t)( stop.tv_sec - start.tv_sec )
00165 * (mtime_t)1000000;
00166 p_sys->latency += stop.tv_usec - start.tv_usec;
00167 }
00168 else
00169 {
00170 p_sys->latency = 0;
00171 }
00172
00173
00174
00175 p_sys->latency +=
00176 (mtime_t)( esd_get_latency( i_newfd = esd_open_sound(NULL) )
00177 + ESD_BUF_SIZE / 2
00178 * p_aout->output.output.i_bytes_per_frame
00179 * p_aout->output.output.i_rate
00180 / ESD_DEFAULT_RATE )
00181 * (mtime_t)1000000
00182 / p_aout->output.output.i_bytes_per_frame
00183 / p_aout->output.output.i_rate;
00184
00185 close( i_newfd );
00186 return VLC_SUCCESS;
00187 }
00188
00189
00190
00191
00192 static void Play( aout_instance_t *p_aout )
00193 {
00194 struct aout_sys_t * p_sys = p_aout->output.p_sys;
00195 aout_buffer_t * p_buffer;
00196 int i_tmp;
00197
00198 p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo );
00199
00200 if ( p_buffer != NULL )
00201 {
00202 unsigned int pos;
00203 unsigned char *data = p_buffer->p_buffer;
00204
00205 for( pos = 0; pos + ESD_BUF_SIZE <= p_buffer->i_nb_bytes;
00206 pos += ESD_BUF_SIZE )
00207 {
00208 i_tmp = write( p_sys->i_fd, data + pos, ESD_BUF_SIZE );
00209 if( i_tmp < 0 )
00210 {
00211 msg_Err( p_aout, "write failed (%s)", strerror(errno) );
00212 }
00213 }
00214 aout_BufferFree( p_buffer );
00215 }
00216 }
00217
00218
00219
00220
00221 static void Close( vlc_object_t *p_this )
00222 {
00223 aout_instance_t *p_aout = (aout_instance_t *)p_this;
00224 struct aout_sys_t * p_sys = p_aout->output.p_sys;
00225
00226 close( p_sys->i_fd );
00227 free( p_sys );
00228 }
00229
00230 #if 0
00231
00232
00233
00234
00235
00236 static void Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
00237 {
00238 int i_amount;
00239
00240 int m1 = p_aout->output.p_sys->esd_format & ESD_STEREO ? 1 : 2;
00241 int m2 = p_aout->output.p_sys->esd_format & ESD_BITS16 ? 64 : 128;
00242
00243 i_amount = (m1 * 44100 * (ESD_BUF_SIZE + m1 * m2)) / p_aout->i_rate;
00244
00245 write( p_aout->output.p_sys->i_fd, buffer, i_size );
00246 }
00247 #endif
00248