Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

shout.c

00001 /*****************************************************************************
00002  * shout.c: This module forwards vorbis streams to an icecast server
00003  *****************************************************************************
00004  * Copyright (C) 2005 VideoLAN
00005  * $Id: shout.c 12415 2005-08-28 18:59:53Z hartman $
00006  *
00007  * Authors: Daniel Fischer <dan at subsignal dot org>
00008  *          Derk-Jan Hartman <hartman at videolan dot org>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 /*****************************************************************************
00026  * Some Comments:
00027  *
00028  * - this only works for ogg and/or mp3, and we don't check this yet.
00029  * - MP3 metadata is not passed along, since metadata is only available after
00030  *   this module is opened.
00031  *
00032  * Typical usage:
00033  *
00034  * vlc v4l:/dev/video:input=2:norm=pal:size=192x144 \
00035  * --sout '#transcode{vcodec=theora,vb=300,acodec=vorb,ab=96}\
00036  * :std{access=shout,mux=ogg,url=localhost:8005}'
00037  *
00038  *****************************************************************************/
00039 
00040 /*****************************************************************************
00041  * Preamble
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  * Module descriptor
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  * Exported prototypes
00089  *****************************************************************************/
00090 static const char *ppsz_sout_options[] = {
00091     "name", "description", "mp3", NULL
00092 };
00093 
00094 
00095 /*****************************************************************************
00096  * Exported prototypes
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  * Open: open the shout connection
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     /* Parse connection data user:pwd@host:port/mountpoint */
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 //       || shout_set_nonblocking( p_shout, 1 ) != SHOUTERR_SUCCESS
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     for non-blocking, use:
00224     while( i_ret == SHOUTERR_BUSY )
00225     {
00226         sleep( 1 );
00227         i_ret = shout_get_connected( p_shout );
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     /* Update pace control flag */
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  * Close: close the target
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     /* Update pace control flag */
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  * Read: standard read -- not supported
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  * Write: standard write
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         /* XXX: Unsure if that's the cause for some audio trouble... */
00315 
00316         p_buffer = p_next;
00317     }
00318 
00319     return i_write;
00320 }
00321 
00322 /*****************************************************************************
00323  * Seek: seek to a specific location -- not supported
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 

Generated on Tue Dec 20 10:14:27 2005 for vlc-0.8.4a by  doxygen 1.4.2