+ vlc_UrlClean( &p_sys->url );
+
+ free( p_sys );
+}
+
+/*****************************************************************************
+ * Connect: connects to the RTSP server to setup the session DESCRIBE
+ *****************************************************************************/
+static int Connect( demux_t *p_demux )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ Authenticator authenticator;
+ bool b_firstpass = true;
+ char *psz_user = NULL;
+ char *psz_pwd = NULL;
+ char *psz_url = NULL;
+ char *psz_options = NULL;
+ char *p_sdp = NULL;
+ int i_http_port = 0;
+ int i_ret = VLC_SUCCESS;
+ int i_lefttries;
+
+ if( p_sys->url.i_port == 0 ) p_sys->url.i_port = 554;
+ if( p_sys->url.psz_username || p_sys->url.psz_password )
+ {
+ int err;
+ err = asprintf( &psz_url, "rtsp://%s:%d%s", p_sys->url.psz_host,
+ p_sys->url.i_port, p_sys->url.psz_path );
+ if( err == -1 ) return VLC_ENOMEM;
+
+ psz_user = strdup( p_sys->url.psz_username );
+ psz_pwd = strdup( p_sys->url.psz_password );
+ }
+ else
+ {
+ int err;
+ err = asprintf( &psz_url, "rtsp://%s", p_sys->psz_path );
+ if( err == -1 ) return VLC_ENOMEM;
+
+ psz_user = var_CreateGetString( p_demux, "rtsp-user" );
+ psz_pwd = var_CreateGetString( p_demux, "rtsp-pwd" );
+ }
+
+ i_lefttries = 3;
+createnew:
+ i_lefttries--;
+ if( !vlc_object_alive (p_demux) || p_demux->b_error )
+ {
+ free( psz_user );
+ free( psz_pwd );
+ free( psz_url );
+ return VLC_EGENERIC;
+ }
+
+ if( var_CreateGetBool( p_demux, "rtsp-http" ) )
+ i_http_port = var_CreateGetInteger( p_demux, "rtsp-http-port" );
+
+ if( ( p_sys->rtsp = RTSPClient::createNew( *p_sys->env,
+ var_CreateGetInteger( p_demux, "verbose" ) > 1,
+ "VLC media player", i_http_port ) ) == NULL )
+ {
+ msg_Err( p_demux, "RTSPClient::createNew failed (%s)",
+ p_sys->env->getResultMsg() );
+ free( psz_user );
+ free( psz_pwd );
+ free( psz_url );
+ return VLC_EGENERIC;
+ }
+
+ /* Kasenna enables KeepAlive by analysing the User-Agent string.
+ * Appending _KA to the string should be enough to enable this feature,
+ * however, there is a bug where the _KA doesn't get parsed from the
+ * default User-Agent as created by VLC/Live555 code. This is probably due
+ * to spaces in the string or the string being too long. Here we override
+ * the default string with a more compact version.
+ */
+ if( var_CreateGetBool( p_demux, "rtsp-kasenna" ))
+ {
+ p_sys->rtsp->setUserAgentString( "VLC_MEDIA_PLAYER_KA" );
+ }
+
+describe:
+ authenticator.setUsernameAndPassword( (const char*)psz_user,
+ (const char*)psz_pwd );
+
+ psz_options = p_sys->rtsp->sendOptionsCmd( psz_url, psz_user, psz_pwd,
+ &authenticator );
+ delete [] psz_options;
+
+ p_sdp = p_sys->rtsp->describeURL( psz_url, &authenticator,
+ var_GetBool( p_demux, "rtsp-kasenna" ) );
+ if( p_sdp == NULL )
+ {
+ /* failure occurred */
+ int i_code = 0;
+ const char *psz_error = p_sys->env->getResultMsg();
+
+ if( var_GetBool( p_demux, "rtsp-http" ) )
+ sscanf( psz_error, "%*s %*s HTTP GET %*s HTTP/%*u.%*u %3u %*s",
+ &i_code );
+ else
+ {
+ const char *psz_tmp = strstr( psz_error, "RTSP" );
+ if( psz_tmp )
+ sscanf( psz_tmp, "RTSP/%*s%3u", &i_code );
+ else
+ i_code = 0;
+ }
+ msg_Dbg( p_demux, "DESCRIBE failed with %d: %s", i_code, psz_error );
+
+ if( b_firstpass )
+ { /* describeURL always returns an "RTSP/1.0 401 Unauthorized" the
+ * first time. This is a workaround to avoid asking for a
+ * user/passwd the first time the code passess here. */
+ i_code = 0;
+ b_firstpass = false;
+ }
+
+ if( i_code == 401 )
+ {
+ int i_result;
+ msg_Dbg( p_demux, "authentication failed" );
+
+ free( psz_user );
+ free( psz_pwd );
+ psz_user = psz_pwd = NULL;
+
+ i_result = intf_UserLoginPassword( p_demux, _("RTSP authentication"),
+ _("Please enter a valid login name and a password."),
+ &psz_user, &psz_pwd );
+ if( i_result == DIALOG_OK_YES )
+ {
+ msg_Dbg( p_demux, "retrying with user=%s, pwd=%s",
+ psz_user, psz_pwd );
+ goto describe;
+ }
+ }
+ else if( (i_code != 0) && !var_GetBool( p_demux, "rtsp-http" ) )
+ {
+ /* Perhaps a firewall is being annoying. Try HTTP tunneling mode */
+ vlc_value_t val;
+ val.b_bool = true;
+ msg_Dbg( p_demux, "we will now try HTTP tunneling mode" );
+ var_Set( p_demux, "rtsp-http", val );
+ if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp );
+ p_sys->rtsp = NULL;
+ goto createnew;
+ }
+ else
+ {
+ msg_Dbg( p_demux, "connection timeout, retrying" );
+ if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp );
+ p_sys->rtsp = NULL;
+ if( i_lefttries > 0 )
+ goto createnew;
+ }
+ i_ret = VLC_EGENERIC;
+ }
+
+ /* malloc-ated copy */
+ free( psz_url );
+ free( psz_user );
+ free( psz_pwd );
+
+ free( p_sys->p_sdp );
+ p_sys->p_sdp = NULL;
+ if( p_sdp ) p_sys->p_sdp = strdup( (char*)p_sdp );
+ delete[] p_sdp;
+
+ return i_ret;
+}
+
+/*****************************************************************************
+ * SessionsSetup: prepares the subsessions and does the SETUP
+ *****************************************************************************/
+static int SessionsSetup( demux_t *p_demux )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ MediaSubsessionIterator *iter = NULL;
+ MediaSubsession *sub = NULL;
+
+ bool b_rtsp_tcp = false;
+ int i_client_port;
+ int i_return = VLC_SUCCESS;
+ unsigned int i_buffer = 0;
+ unsigned const thresh = 200000; /* RTP reorder threshold .2 second (default .1) */
+
+ b_rtsp_tcp = var_CreateGetBool( p_demux, "rtsp-tcp" ) ||
+ var_GetBool( p_demux, "rtsp-http" );
+ i_client_port = var_CreateGetInteger( p_demux, "rtp-client-port" );
+
+ /* Create the session from the SDP */
+ if( !( p_sys->ms = MediaSession::createNew( *p_sys->env, p_sys->p_sdp ) ) )
+ {
+ msg_Err( p_demux, "Could not create the RTSP Session: %s",
+ p_sys->env->getResultMsg() );
+ return VLC_EGENERIC;
+ }