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
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include <string.h>
00044
00045 #include <vlc/vlc.h>
00046 #include <vlc/sout.h>
00047
00048 #include <shout/shout.h>
00049
00050
00051
00052
00053 static int Open ( vlc_object_t * );
00054 static void Close( vlc_object_t * );
00055
00056 #define SOUT_CFG_PREFIX "sout-shout-"
00057
00058 #define NAME_TEXT N_("Stream-name")
00059 #define NAME_LONGTEXT N_("The name this stream/channel will get on the icecast server." )
00060
00061 #define DESCRIPTION_TEXT N_("Stream-description")
00062 #define DESCRIPTION_LONGTEXT N_("A description of the stream content. (Information about " \
00063 "your channel)." )
00064
00065 #define MP3_TEXT N_("Stream MP3")
00066 #define MP3_LONGTEXT N_("Normally you have to feed the shoutcast module with Ogg streams. " \
00067 "This option allows you to feed MP3 streams instead, so you can " \
00068 "forward MP3 streams to the icecast server." )
00069
00070 vlc_module_begin();
00071 set_description( _("libshout (icecast) output") );
00072 set_shortname( N_("Shout" ));
00073 set_capability( "sout access", 50 );
00074 set_category( CAT_SOUT );
00075 set_subcategory( SUBCAT_SOUT_ACO );
00076 add_shortcut( "shout" );
00077 add_string( SOUT_CFG_PREFIX "name", "VLC media player - Live stream", NULL,
00078 NAME_TEXT, NAME_LONGTEXT, VLC_FALSE );
00079 add_string( SOUT_CFG_PREFIX "description", "Live stream from VLC media player. " \
00080 "http://www.videolan.org/vlc", NULL,
00081 DESCRIPTION_TEXT, DESCRIPTION_LONGTEXT, VLC_FALSE );
00082 add_bool( SOUT_CFG_PREFIX "mp3", VLC_FALSE, NULL,
00083 MP3_TEXT, MP3_LONGTEXT, VLC_TRUE );
00084 set_callbacks( Open, Close );
00085 vlc_module_end();
00086
00087
00088
00089
00090 static const char *ppsz_sout_options[] = {
00091 "name", "description", "mp3", NULL
00092 };
00093
00094
00095
00096
00097
00098 static int Write( sout_access_out_t *, block_t * );
00099 static int Seek ( sout_access_out_t *, off_t );
00100 static int Read ( sout_access_out_t *, block_t * );
00101
00102 struct sout_access_out_sys_t
00103 {
00104 shout_t *p_shout;
00105 };
00106
00107
00108
00109
00110 static int Open( vlc_object_t *p_this )
00111 {
00112 sout_access_out_t *p_access = (sout_access_out_t*)p_this;
00113 sout_access_out_sys_t *p_sys;
00114 shout_t *p_shout;
00115 long i_ret;
00116 unsigned int i_port;
00117 vlc_value_t val;
00118
00119 char *psz_accessname = NULL;
00120 char *psz_parser = NULL;
00121 char *psz_user = NULL;
00122 char *psz_pass = NULL;
00123 char *psz_host = NULL;
00124 char *psz_mount = NULL;
00125 char *psz_name = NULL;
00126 char *psz_description = NULL;
00127 char *tmp_port = NULL;
00128
00129 sout_CfgParse( p_access, SOUT_CFG_PREFIX, ppsz_sout_options, p_access->p_cfg );
00130
00131 psz_accessname = psz_parser = strdup( p_access->psz_name );
00132
00133 if( !p_access->psz_name )
00134 {
00135 msg_Err( p_access,
00136 "please specify url=user:password@host:port/mountpoint" );
00137 return VLC_EGENERIC;
00138 }
00139
00140
00141 psz_user = psz_parser;
00142 while( psz_parser[0] && psz_parser[0] != ':' ) psz_parser++;
00143 if( psz_parser[0] ) { psz_parser[0] = 0; psz_parser++; }
00144 psz_pass = psz_parser;
00145 while( psz_parser[0] && psz_parser[0] != '@' ) psz_parser++;
00146 if( psz_parser[0] ) { psz_parser[0] = 0; psz_parser++; }
00147 psz_host = psz_parser;
00148 while( psz_parser[0] && psz_parser[0] != ':' ) psz_parser++;
00149 if( psz_parser[0] ) { psz_parser[0] = 0; psz_parser++; }
00150 tmp_port = psz_parser;
00151 while( psz_parser[0] && psz_parser[0] != '/' ) psz_parser++;
00152 if( psz_parser[0] ) { psz_parser[0] = 0; psz_parser++; }
00153 psz_mount = psz_parser;
00154
00155 i_port = atoi( tmp_port );
00156
00157 p_sys = p_access->p_sys = malloc( sizeof( sout_access_out_sys_t ) );
00158 if( !p_sys )
00159 {
00160 msg_Err( p_access, "out of memory" );
00161 free( psz_accessname );
00162 return VLC_ENOMEM;
00163 }
00164
00165 var_Get( p_access, SOUT_CFG_PREFIX "name", &val );
00166 if( *val.psz_string )
00167 psz_name = val.psz_string;
00168 else
00169 free( val.psz_string );
00170
00171 var_Get( p_access, SOUT_CFG_PREFIX "description", &val );
00172 if( *val.psz_string )
00173 psz_description = val.psz_string;
00174 else
00175 free( val.psz_string );
00176
00177 p_shout = p_sys->p_shout = shout_new();
00178 if( !p_shout
00179 || shout_set_host( p_shout, psz_host ) != SHOUTERR_SUCCESS
00180 || shout_set_protocol( p_shout, SHOUT_PROTOCOL_HTTP )
00181 != SHOUTERR_SUCCESS
00182 || shout_set_port( p_shout, i_port ) != SHOUTERR_SUCCESS
00183 || shout_set_password( p_shout, psz_pass ) != SHOUTERR_SUCCESS
00184 || shout_set_mount( p_shout, psz_mount ) != SHOUTERR_SUCCESS
00185 || shout_set_user( p_shout, psz_user ) != SHOUTERR_SUCCESS
00186 || shout_set_agent( p_shout, "VLC media player " VERSION ) != SHOUTERR_SUCCESS
00187 || shout_set_name( p_shout, psz_name ) != SHOUTERR_SUCCESS
00188 || shout_set_description( p_shout, psz_description ) != SHOUTERR_SUCCESS
00189
00190 )
00191 {
00192 msg_Err( p_access, "failed to initialize shout streaming to %s:%i/%s",
00193 psz_host, i_port, psz_mount );
00194 free( p_access->p_sys );
00195 free( psz_accessname );
00196 return VLC_EGENERIC;
00197 }
00198
00199 if( psz_name ) free( psz_name );
00200 if( psz_description ) free( psz_description );
00201
00202 var_Get( p_access, SOUT_CFG_PREFIX "mp3", &val );
00203 if( val.b_bool == VLC_TRUE )
00204 i_ret = shout_set_format( p_shout, SHOUT_FORMAT_MP3 );
00205 else
00206 i_ret = shout_set_format( p_shout, SHOUT_FORMAT_OGG );
00207
00208 if( i_ret != SHOUTERR_SUCCESS )
00209 {
00210 msg_Err( p_access, "failed to set the shoutcast streaming format" );
00211 free( p_access->p_sys );
00212 free( psz_accessname );
00213 return VLC_EGENERIC;
00214 }
00215
00216 i_ret = shout_open( p_shout );
00217 if( i_ret == SHOUTERR_SUCCESS )
00218 {
00219 i_ret = SHOUTERR_CONNECTED;
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 if( i_ret != SHOUTERR_CONNECTED )
00231 {
00232 msg_Err( p_access, "failed to open shout stream to %s:%i/%s: %s",
00233 psz_host, i_port, psz_mount, shout_get_error(p_shout) );
00234 free( p_access->p_sys );
00235 free( psz_accessname );
00236 return VLC_EGENERIC;
00237 }
00238
00239 p_access->pf_write = Write;
00240 p_access->pf_read = Read;
00241 p_access->pf_seek = Seek;
00242
00243 msg_Dbg( p_access, "shout access output opened (%s@%s:%i/%s)",
00244 psz_user, psz_host, i_port, psz_mount );
00245
00246
00247 if( p_access->psz_access && !strcmp( p_access->psz_access, "stream" ) )
00248 {
00249 p_access->p_sout->i_out_pace_nocontrol++;
00250 }
00251
00252 free( psz_accessname );
00253
00254 return VLC_SUCCESS;
00255 }
00256
00257
00258
00259
00260 static void Close( vlc_object_t * p_this )
00261 {
00262 sout_access_out_t *p_access = (sout_access_out_t*)p_this;
00263
00264 if( p_access->p_sys && p_access->p_sys->p_shout )
00265 {
00266 shout_close( p_access->p_sys->p_shout );
00267 shout_shutdown();
00268 }
00269 free( p_access->p_sys );
00270
00271
00272 if( p_access->psz_access && !strcmp( p_access->psz_access, "stream" ) )
00273 {
00274 p_access->p_sout->i_out_pace_nocontrol--;
00275 }
00276
00277 msg_Dbg( p_access, "shout access output closed" );
00278 }
00279
00280
00281
00282
00283 static int Read( sout_access_out_t *p_access, block_t *p_buffer )
00284 {
00285 msg_Err( p_access, "cannot read from shout" );
00286 return VLC_EGENERIC;
00287 }
00288
00289
00290
00291
00292 static int Write( sout_access_out_t *p_access, block_t *p_buffer )
00293 {
00294 size_t i_write = 0;
00295
00296 shout_sync( p_access->p_sys->p_shout );
00297 while( p_buffer )
00298 {
00299 block_t *p_next = p_buffer->p_next;
00300
00301 if( shout_send( p_access->p_sys->p_shout,
00302 p_buffer->p_buffer, p_buffer->i_buffer )
00303 == SHOUTERR_SUCCESS )
00304 {
00305 i_write += p_buffer->i_buffer;
00306 }
00307 else
00308 {
00309 msg_Err( p_access, "cannot write to stream: %s",
00310 shout_get_error(p_access->p_sys->p_shout) );
00311 }
00312 block_Release( p_buffer );
00313
00314
00315
00316 p_buffer = p_next;
00317 }
00318
00319 return i_write;
00320 }
00321
00322
00323
00324
00325 static int Seek( sout_access_out_t *p_access, off_t i_pos )
00326 {
00327 msg_Err( p_access, "cannot seek on shout" );
00328 return VLC_EGENERIC;
00329 }
00330