]> git.sesse.net Git - vlc/blobdiff - modules/access_output/shout.c
A lot of missing const in options lists
[vlc] / modules / access_output / shout.c
index 40e76f7ba6dbc5bda95285cd13141f090c7d1fac..169aeaeb5096438f246879015775525a3c879d26 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * shout.c: This module forwards vorbis streams to an icecast server
  *****************************************************************************
- * Copyright (C) 2005 VideoLAN
+ * Copyright (C) 2005 the VideoLAN team
  * $Id$
  *
  * Authors: Daniel Fischer <dan at subsignal dot org>
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
-#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
 
 #include <vlc/vlc.h>
-#include <vlc/sout.h>
+#include <vlc_plugin.h>
+#include <vlc_sout.h>
+#include <vlc_block.h>
 
 #include <shout/shout.h>
 
@@ -102,40 +107,40 @@ static void Close( vlc_object_t * );
                            "shoutcast. Requires Ogg streaming for icecast." )
 
 vlc_module_begin();
-    set_description( _("IceCAST output") );
+    set_description( N_("IceCAST output") );
     set_shortname( "Shoutcast" );
     set_capability( "sout access", 50 );
     set_category( CAT_SOUT );
     set_subcategory( SUBCAT_SOUT_ACO );
     add_shortcut( "shout" );
     add_string( SOUT_CFG_PREFIX "name", "VLC media player - Live stream", NULL,
-                NAME_TEXT, NAME_LONGTEXT, VLC_FALSE );
+                NAME_TEXT, NAME_LONGTEXT, false );
     add_string( SOUT_CFG_PREFIX "description",
                  "Live stream from VLC media player", NULL,
-                DESCRIPTION_TEXT, DESCRIPTION_LONGTEXT, VLC_FALSE );
-    add_bool(   SOUT_CFG_PREFIX "mp3", VLC_FALSE, NULL,
-                MP3_TEXT, MP3_LONGTEXT, VLC_TRUE );
+                DESCRIPTION_TEXT, DESCRIPTION_LONGTEXT, false );
+    add_bool(   SOUT_CFG_PREFIX "mp3", false, NULL,
+                MP3_TEXT, MP3_LONGTEXT, true );
     add_string( SOUT_CFG_PREFIX "genre", "Alternative", NULL,
-                GENRE_TEXT, GENRE_LONGTEXT, VLC_FALSE );
+                GENRE_TEXT, GENRE_LONGTEXT, false );
     add_string( SOUT_CFG_PREFIX "url", "http://www.videolan.org/vlc", NULL,
-                URL_TEXT, URL_LONGTEXT, VLC_FALSE );
+                URL_TEXT, URL_LONGTEXT, false );
     add_string( SOUT_CFG_PREFIX "bitrate", "", NULL,
-                BITRATE_TEXT, BITRATE_LONGTEXT, VLC_FALSE );
+                BITRATE_TEXT, BITRATE_LONGTEXT, false );
     add_string( SOUT_CFG_PREFIX "samplerate", "", NULL,
-                SAMPLERATE_TEXT, SAMPLERATE_LONGTEXT, VLC_FALSE );
+                SAMPLERATE_TEXT, SAMPLERATE_LONGTEXT, false );
     add_string( SOUT_CFG_PREFIX "channels", "", NULL,
-                CHANNELS_TEXT, CHANNELS_LONGTEXT, VLC_FALSE );
+                CHANNELS_TEXT, CHANNELS_LONGTEXT, false );
     add_string( SOUT_CFG_PREFIX "quality", "", NULL,
-                QUALITY_TEXT, QUALITY_LONGTEXT, VLC_FALSE );
-    add_bool(   SOUT_CFG_PREFIX "public", VLC_FALSE, NULL,
-                PUBLIC_TEXT, PUBLIC_LONGTEXT, VLC_TRUE );
+                QUALITY_TEXT, QUALITY_LONGTEXT, false );
+    add_bool(   SOUT_CFG_PREFIX "public", false, NULL,
+                PUBLIC_TEXT, PUBLIC_LONGTEXT, true );
     set_callbacks( Open, Close );
 vlc_module_end();
 
 /*****************************************************************************
  * Exported prototypes
  *****************************************************************************/
-static const char *ppsz_sout_options[] = {
+static const char *const ppsz_sout_options[] = {
     "name", "description", "mp3", "genre", "url", "bitrate", "samplerate",
     "channels", "quality", "public", NULL
 };
@@ -144,9 +149,8 @@ static const char *ppsz_sout_options[] = {
 /*****************************************************************************
  * Exported prototypes
  *****************************************************************************/
-static int Write( sout_access_out_t *, block_t * );
+static ssize_t Write( sout_access_out_t *, block_t * );
 static int Seek ( sout_access_out_t *, off_t  );
-static int Read ( sout_access_out_t *, block_t * );
 
 struct sout_access_out_sys_t
 {
@@ -177,11 +181,11 @@ static int Open( vlc_object_t *p_this )
     char *psz_genre = NULL;
     char *psz_url = NULL;
 
-    sout_CfgParse( p_access, SOUT_CFG_PREFIX, ppsz_sout_options, p_access->p_cfg );
+    config_ChainParse( p_access, SOUT_CFG_PREFIX, ppsz_sout_options, p_access->p_cfg );
 
-    psz_accessname = psz_parser = strdup( p_access->psz_name );
+    psz_accessname = psz_parser = strdup( p_access->psz_path );
 
-    if( !p_access->psz_name )
+    if( !p_access->psz_path )
     {
         msg_Err( p_access,
                  "please specify url=user:password@host:port/mountpoint" );
@@ -240,7 +244,7 @@ static int Open( vlc_object_t *p_this )
     p_shout = p_sys->p_shout = shout_new();
     if( !p_shout
          || shout_set_host( p_shout, psz_host ) != SHOUTERR_SUCCESS
-         || shout_set_protocol( p_shout, SHOUT_PROTOCOL_HTTP ) != SHOUTERR_SUCCESS
+         || shout_set_protocol( p_shout, SHOUT_PROTOCOL_ICY ) != SHOUTERR_SUCCESS
          || shout_set_port( p_shout, i_port ) != SHOUTERR_SUCCESS
          || shout_set_password( p_shout, psz_pass ) != SHOUTERR_SUCCESS
          || shout_set_mount( p_shout, psz_mount ) != SHOUTERR_SUCCESS
@@ -250,7 +254,7 @@ static int Open( vlc_object_t *p_this )
          || shout_set_description( p_shout, psz_description ) != SHOUTERR_SUCCESS
          || shout_set_genre( p_shout, psz_genre ) != SHOUTERR_SUCCESS
          || shout_set_url( p_shout, psz_url ) != SHOUTERR_SUCCESS
-//       || shout_set_nonblocking( p_shout, 1 ) != SHOUTERR_SUCCESS
+         /* || shout_set_nonblocking( p_shout, 1 ) != SHOUTERR_SUCCESS */
       )
     {
         msg_Err( p_access, "failed to initialize shout streaming to %s:%i/%s",
@@ -260,13 +264,13 @@ static int Open( vlc_object_t *p_this )
         return VLC_EGENERIC;
     }
 
-    if( psz_name ) free( psz_name );
-    if( psz_description ) free( psz_description );
-    if( psz_genre ) free( psz_genre );
-    if( psz_url ) free( psz_url );
+    free( psz_name );
+    free( psz_description );
+    free( psz_genre );
+    free( psz_url );
 
     var_Get( p_access, SOUT_CFG_PREFIX "mp3", &val );
-    if( val.b_bool == VLC_TRUE )
+    if( val.b_bool == true )
         i_ret = shout_set_format( p_shout, SHOUT_FORMAT_MP3 );
     else
         i_ret = shout_set_format( p_shout, SHOUT_FORMAT_OGG );
@@ -279,13 +283,19 @@ static int Open( vlc_object_t *p_this )
         return VLC_EGENERIC;
     }
 
-
     /* Don't force bitrate to 0 but only use when specified. This will otherwise
        show an empty field on icecast directory listing instead of NA */
     var_Get( p_access, SOUT_CFG_PREFIX "bitrate", &val );
     if( *val.psz_string )
     {
         i_ret = shout_set_audio_info( p_shout, SHOUT_AI_BITRATE, val.psz_string );
+        if( i_ret != SHOUTERR_SUCCESS )
+        {
+            msg_Err( p_access, "failed to set the information about the bitrate" );
+            free( p_access->p_sys );
+            free( psz_accessname );
+            return VLC_EGENERIC;
+        }
     }
     else
     {
@@ -296,94 +306,72 @@ static int Open( vlc_object_t *p_this )
         free( val.psz_string );
     }
 
-    if( i_ret != SHOUTERR_SUCCESS )
-    {
-        msg_Err( p_access, "failed to set the information about the bitrate" );
-        free( p_access->p_sys );
-        free( psz_accessname );
-        return VLC_EGENERIC;
-    }
-
     /* Information about samplerate, channels and quality will not be propagated
        through the YP protocol for icecast to the public directory listing when
        the icecast server is operating in shoutcast compatibility mode */
 
     var_Get( p_access, SOUT_CFG_PREFIX "samplerate", &val );
     if( *val.psz_string )
+    {
         i_ret = shout_set_audio_info( p_shout, SHOUT_AI_SAMPLERATE, val.psz_string );
+        if( i_ret != SHOUTERR_SUCCESS )
+        {
+            msg_Err( p_access, "failed to set the information about the samplerate" );
+            free( p_access->p_sys );
+            free( psz_accessname );
+            return VLC_EGENERIC;
+        }
+    }
     else
         free( val.psz_string );
 
-    if( i_ret != SHOUTERR_SUCCESS )
-    {
-        msg_Err( p_access, "failed to set the information about the samplerate" );
-        free( p_access->p_sys );
-        free( psz_accessname );
-        return VLC_EGENERIC;
-    }
-
     var_Get( p_access, SOUT_CFG_PREFIX "channels", &val );
     if( *val.psz_string )
+    {
         i_ret = shout_set_audio_info( p_shout, SHOUT_AI_CHANNELS, val.psz_string );
+        if( i_ret != SHOUTERR_SUCCESS )
+        {
+            msg_Err( p_access, "failed to set the information about the number of channels" );
+            free( p_access->p_sys );
+            free( psz_accessname );
+            return VLC_EGENERIC;
+        }
+    }
     else
         free( val.psz_string );
 
-    if( i_ret != SHOUTERR_SUCCESS )
-    {
-        msg_Err( p_access, "failed to set the information about the number of channels" );
-        free( p_access->p_sys );
-        free( psz_accessname );
-        return VLC_EGENERIC;
-    }
-
     var_Get( p_access, SOUT_CFG_PREFIX "quality", &val );
     if( *val.psz_string )
+    {
         i_ret = shout_set_audio_info( p_shout, SHOUT_AI_QUALITY, val.psz_string );
+        if( i_ret != SHOUTERR_SUCCESS )
+        {
+            msg_Err( p_access, "failed to set the information about Ogg Vorbis quality" );
+            free( p_access->p_sys );
+            free( psz_accessname );
+            return VLC_EGENERIC;
+        }
+    }
     else
         free( val.psz_string );
 
-    if( i_ret != SHOUTERR_SUCCESS )
-    {
-        msg_Err( p_access, "failed to set the information about Ogg Vorbis quality" );
-        free( p_access->p_sys );
-        free( psz_accessname );
-        return VLC_EGENERIC;
-    }
-
     var_Get( p_access, SOUT_CFG_PREFIX "public", &val );
-    if( val.b_bool == VLC_TRUE )
-        i_ret = shout_set_public( p_shout, 1 );
-
-    if( i_ret != SHOUTERR_SUCCESS )
-    {
-        msg_Err( p_access, "failed to set the server status setting to public" );
-        free( p_access->p_sys );
-        free( psz_accessname );
-        return VLC_EGENERIC;
-    }
-
-    i_ret = shout_open( p_shout );
-    if( i_ret == SHOUTERR_SUCCESS )
-    {
-        i_ret = SHOUTERR_CONNECTED;
-    }
-    else
+    if( val.b_bool == true )
     {
-        /* If default 'http' protocol for icecast 2.x fails, fall back to 'icy'
-           for shoutcast server */
-        msg_Warn( p_access, "failed to connect using 'http' (icecast 2.x) protocol, "
-                            "switching to 'icy' (shoutcast)" );
-
-        i_ret = shout_get_format( p_shout );
-        if( i_ret != SHOUT_FORMAT_MP3 )
+        i_ret = shout_set_public( p_shout, 1 );
+        if( i_ret != SHOUTERR_SUCCESS )
         {
-            msg_Err( p_access, "failed to use 'icy' protocol: only MP3 " \
-                               "streaming to shoutcast is supported" );
+            msg_Err( p_access, "failed to set the server status setting to public" );
             free( p_access->p_sys );
             free( psz_accessname );
             return VLC_EGENERIC;
         }
+    }
 
+    /* Connect at startup. Cycle through the possible protocols. */
+    i_ret = shout_get_connected( p_shout );
+    while ( i_ret != SHOUTERR_CONNECTED )
+    {
         /* Shout parameters cannot be changed on an open connection */
         i_ret = shout_close( p_shout );
         if( i_ret == SHOUTERR_SUCCESS )
@@ -391,6 +379,8 @@ static int Open( vlc_object_t *p_this )
             i_ret = SHOUTERR_UNCONNECTED;
         }
 
+        /* Re-initialize for Shoutcast using ICY protocol. Not needed for initial connection
+           but it is when we are reconnecting after other protocol was tried. */
         i_ret = shout_set_protocol( p_shout, SHOUT_PROTOCOL_ICY );
         if( i_ret != SHOUTERR_SUCCESS )
         {
@@ -399,22 +389,56 @@ static int Open( vlc_object_t *p_this )
             free( psz_accessname );
             return VLC_EGENERIC;
         }
-
         i_ret = shout_open( p_shout );
         if( i_ret == SHOUTERR_SUCCESS )
         {
             i_ret = SHOUTERR_CONNECTED;
+            msg_Dbg( p_access, "connected using 'icy' (shoutcast) protocol" );
+        }
+        else
+        {
+            msg_Warn( p_access, "failed to connect using 'icy' (shoutcast) protocol" );
+
+            /* Shout parameters cannot be changed on an open connection */
+            i_ret = shout_close( p_shout );
+            if( i_ret == SHOUTERR_SUCCESS )
+            {
+                i_ret = SHOUTERR_UNCONNECTED;
+            }
+
+            /* IceCAST using HTTP protocol */
+            i_ret = shout_set_protocol( p_shout, SHOUT_PROTOCOL_HTTP );
+            if( i_ret != SHOUTERR_SUCCESS )
+            {
+                msg_Err( p_access, "failed to set the protocol to 'http'" );
+                free( p_access->p_sys );
+                free( psz_accessname );
+                return VLC_EGENERIC;
+            }
+            i_ret = shout_open( p_shout );
+            if( i_ret == SHOUTERR_SUCCESS )
+            {
+                i_ret = SHOUTERR_CONNECTED;
+                msg_Dbg( p_access, "connected using 'http' (icecast 2.x) protocol" );
+            }
+            else
+                msg_Warn( p_access, "failed to connect using 'http' (icecast 2.x) protocol " );
         }
-    }
-
 /*
-    for non-blocking, use:
-    while( i_ret == SHOUTERR_BUSY )
-    {
-        sleep( 1 );
-        i_ret = shout_get_connected( p_shout );
-    }
+        for non-blocking, use:
+        while( i_ret == SHOUTERR_BUSY )
+        {
+            sleep( 1 );
+            i_ret = shout_get_connected( p_shout );
+        }
 */
+        if ( i_ret != SHOUTERR_CONNECTED )
+       {
+           msg_Warn( p_access, "unable to establish connection, retrying..." );
+            msleep( 30000000 );
+        }
+    }
+
     if( i_ret != SHOUTERR_CONNECTED )
     {
         msg_Err( p_access, "failed to open shout stream to %s:%i/%s: %s",
@@ -425,7 +449,6 @@ static int Open( vlc_object_t *p_this )
     }
 
     p_access->pf_write = Write;
-    p_access->pf_read  = Read;
     p_access->pf_seek  = Seek;
 
     msg_Dbg( p_access, "shout access output opened (%s@%s:%i/%s)",
@@ -465,19 +488,10 @@ static void Close( vlc_object_t * p_this )
     msg_Dbg( p_access, "shout access output closed" );
 }
 
-/*****************************************************************************
- * Read: standard read -- not supported
- *****************************************************************************/
-static int Read( sout_access_out_t *p_access, block_t *p_buffer )
-{
-    msg_Err( p_access, "cannot read from shout" );
-    return VLC_EGENERIC;
-}
-
 /*****************************************************************************
  * Write: standard write
  *****************************************************************************/
-static int Write( sout_access_out_t *p_access, block_t *p_buffer )
+static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
 {
     size_t i_write = 0;
 
@@ -496,6 +510,24 @@ static int Write( sout_access_out_t *p_access, block_t *p_buffer )
         {
             msg_Err( p_access, "cannot write to stream: %s",
                      shout_get_error(p_access->p_sys->p_shout) );
+
+            /* The most common cause seems to be a server disconnect, resulting in a
+               Socket Error which can only be fixed by closing and reconnecting.
+               Since we already began with a working connection, the most feasable
+               approach to get out of this error status is a (timed) reconnect approach. */
+            shout_close( p_access->p_sys->p_shout );
+            msg_Warn( p_access, "server unavailable? trying to reconnect..." );
+            /* Re-open the connection (protocol params have already been set) and re-sync */
+            if( shout_open( p_access->p_sys->p_shout ) == SHOUTERR_SUCCESS )
+            {
+                shout_sync( p_access->p_sys->p_shout );
+                msg_Warn( p_access, "reconnected to server" );
+            }
+            else
+            {
+                msg_Err( p_access, "failed to reconnect to server" );
+            }
+
         }
         block_Release( p_buffer );