sap.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:43k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * sap.c :  SAP interface module
  3.  *****************************************************************************
  4.  * Copyright (C) 2001 VideoLAN
  5.  * $Id: sap.c 9041 2004-10-22 13:53:53Z hartman $
  6.  *
  7.  * Authors: Arnaud Schauly <gitan@via.ecp.fr>
  8.  *          Cl閙ent Stenac <zorglub@via.ecp.fr>
  9.  *          Damien Lucas <nitrox@videolan.org>
  10.  *          Laurent Aimar <fenrir@via.ecp.fr>
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  25.  *****************************************************************************/
  26. /*****************************************************************************
  27.  * Preamble
  28.  *****************************************************************************/
  29. #include <stdlib.h>                                      /* malloc(), free() */
  30. #include <vlc/vlc.h>
  31. #include <vlc/intf.h>
  32. #include <vlc/input.h>
  33. #include <errno.h>                                                 /* ENOMEM */
  34. #include <ctype.h>
  35. #ifdef HAVE_UNISTD_H
  36. #    include <unistd.h>
  37. #endif
  38. #ifdef HAVE_SYS_TIME_H
  39. #    include <sys/time.h>
  40. #endif
  41. #ifdef WIN32
  42. #   include <winsock2.h>
  43. #   include <ws2tcpip.h>
  44. #   ifndef IN_MULTICAST
  45. #       define IN_MULTICAST(a) IN_CLASSD(a)
  46. #   endif
  47. #else
  48. #   include <sys/socket.h>
  49. #   include <netinet/in.h>
  50. #   if HAVE_ARPA_INET_H
  51. #      include <arpa/inet.h>
  52. #   elif defined( SYS_BEOS )
  53. #      include <net/netdb.h>
  54. #   endif
  55. #endif
  56. #ifdef UNDER_CE
  57. #   define close(a) CloseHandle(a)
  58. #elif defined( WIN32 )
  59. #   define close(a) closesocket(a)
  60. #endif
  61. #include "network.h"
  62. #ifdef HAVE_ZLIB_H
  63. #   include <zlib.h>
  64. #endif
  65. #define MAX_LINE_LENGTH 256
  66. /* SAP is always on that port */
  67. #define HELLO_PORT 9875
  68. #define HELLO_GROUP "224.2.127.254"
  69. #define ADD_SESSION 1
  70. #define IPV6_ADDR_1 "FF0"  /* Scope is inserted between them */
  71. #define IPV6_ADDR_2 "::2:7FFE"
  72. /*****************************************************************************
  73.  * Module descriptor
  74.  *****************************************************************************/
  75. #define SAP_ADDR_TEXT N_( "SAP multicast address" )
  76. #define SAP_ADDR_LONGTEXT N_( "SAP multicast address" )
  77. #define SAP_IPV4_TEXT N_( "IPv4-SAP listening" )
  78. #define SAP_IPV4_LONGTEXT N_( 
  79.       "Set this if you want the SAP module to listen to IPv4 announces" )
  80. #define SAP_IPV6_TEXT N_( "IPv6-SAP listening" )
  81. #define SAP_IPV6_LONGTEXT N_( 
  82.       "Set this if you want the SAP module to listen to IPv6 announces" )
  83. #define SAP_SCOPE_TEXT N_( "IPv6 SAP scope" )
  84. #define SAP_SCOPE_LONGTEXT N_( 
  85.        "Sets the scope for IPv6 announces (default is 8)" )
  86. #define SAP_TIMEOUT_TEXT N_( "SAP timeout (seconds)" )
  87. #define SAP_TIMEOUT_LONGTEXT N_( 
  88.        "Sets the time before SAP items get deleted if no new announce " 
  89.        "is received." )
  90. #define SAP_PARSE_TEXT N_( "Try to parse the SAP" )
  91. #define SAP_PARSE_LONGTEXT N_( 
  92.        "When SAP can it will try to parse the SAP. Normal behavior is " 
  93.        "to have livedotcom parse the announce." )
  94. static int  Open ( vlc_object_t * );
  95. static void Close( vlc_object_t * );
  96. static int  OpenSDP ( vlc_object_t * );
  97. static void CloseSDP( vlc_object_t * );
  98. vlc_module_begin();
  99.     set_description( _("SAP interface") );
  100.     add_string( "sap-addr", NULL, NULL,
  101.                 SAP_ADDR_TEXT, SAP_ADDR_LONGTEXT, VLC_TRUE );
  102.     add_bool( "sap-ipv4", 1 , NULL,
  103.                SAP_IPV4_TEXT,SAP_IPV4_LONGTEXT, VLC_TRUE );
  104.     add_bool( "sap-ipv6", 0 , NULL,
  105.               SAP_IPV6_TEXT, SAP_IPV6_LONGTEXT, VLC_TRUE );
  106.     add_string( "sap-ipv6-scope", "8" , NULL,
  107.                 SAP_SCOPE_TEXT, SAP_SCOPE_LONGTEXT, VLC_TRUE);
  108.     add_integer( "sap-timeout", 1800, NULL,
  109.                  SAP_TIMEOUT_TEXT, SAP_TIMEOUT_LONGTEXT, VLC_TRUE );
  110.     add_bool( "sap-parse", 1 , NULL,
  111.                SAP_PARSE_TEXT,SAP_PARSE_LONGTEXT, VLC_TRUE );
  112.     set_capability( "interface", 0 );
  113.     set_callbacks( Open, Close );
  114.     
  115.     add_submodule();
  116.         /* TODO FIXME
  117.          * This submodule is temporary and has a very high duplicate code rate
  118.          * This needs to be removed when SDP UDP parsing is fixed in liveMedia
  119.          */
  120.         set_description( _("SDP file parser (UDP only)") );
  121.         add_shortcut( "sdp" );
  122.         set_capability( "demux2", 51 );
  123.         set_callbacks( OpenSDP, CloseSDP );
  124.         
  125. vlc_module_end();
  126. /*****************************************************************************
  127.  * Local prototypes
  128.  *****************************************************************************/
  129. static void Run    ( intf_thread_t *p_intf );
  130. static ssize_t NetRead( intf_thread_t *, int fd[2], uint8_t *, int );
  131. static int Demux( demux_t *p_demux );
  132. static int Control( demux_t *, int, va_list );
  133. typedef struct media_descr_t media_descr_t;
  134. typedef struct sess_descr_t sess_descr_t;
  135. typedef struct attr_descr_t attr_descr_t;
  136. static void sess_toitem( intf_thread_t *, sess_descr_t * );
  137. static sess_descr_t *  parse_sdp( vlc_object_t *, char * ) ;
  138. static void free_sd( sess_descr_t * );
  139. /* Detect multicast addresses */
  140. static int  ismult( char * );
  141. /* The struct that contains sdp information */
  142. struct  sess_descr_t
  143. {
  144.     int  i_version;
  145.     char *psz_sessionname;
  146.     char *psz_connection;
  147.     char *psz_sdp;
  148.     int           i_media;
  149.     media_descr_t **pp_media;
  150.     int           i_attributes;
  151.     attr_descr_t  **pp_attributes;
  152. };
  153. /* All this information is not useful yet.  */
  154. struct media_descr_t
  155. {
  156.     char *psz_medianame;
  157.     char *psz_mediaconnection;
  158. };
  159. struct attr_descr_t
  160. {
  161.     char *psz_field;
  162.     char *psz_value;
  163. };
  164. struct sap_announce_t
  165. {
  166.     mtime_t i_last;
  167.     int i_id;
  168.     char *psz_name;
  169.     char *psz_uri;
  170. };
  171. struct intf_sys_t
  172. {
  173.     /* IPV4 and IPV6 */
  174.     int fd[2];
  175.     /* playlist group */
  176.     int i_group;
  177.     /* Table of announces */
  178.     int i_announces;
  179.     struct sap_announce_t **pp_announces;
  180.     int i_timeout;
  181. };
  182. #ifdef HAVE_ZLIB_H
  183. int do_decompress( unsigned char *src, unsigned char **_dst, int slen ) {
  184.     int result, dstsize, n;
  185.     unsigned char *dst;
  186.     z_stream d_stream;
  187.     d_stream.zalloc = (alloc_func)0;
  188.     d_stream.zfree = (free_func)0;
  189.     d_stream.opaque = (voidpf)0;
  190.     result = inflateInit(&d_stream);
  191.     if( result != Z_OK )
  192.     {
  193.         printf( "inflateInit() failed. Result: %dn", result );
  194.         return( -1 );
  195.     }
  196.     d_stream.next_in = (Bytef *)src;
  197.     d_stream.avail_in = slen;
  198.     n = 0;
  199.     dst = NULL;
  200.     do
  201.     {
  202.         n++;
  203.         dst = (unsigned char *)realloc(dst, n * 1000);
  204.         d_stream.next_out = (Bytef *)&dst[(n - 1) * 1000];
  205.         d_stream.avail_out = 1000;
  206.         result = inflate(&d_stream, Z_NO_FLUSH);
  207.         if( ( result != Z_OK ) && ( result != Z_STREAM_END ) )
  208.         {
  209.             printf( "Zlib decompression failed. Result: %dn", result );
  210.             return( -1 );
  211.         }
  212.     }
  213.     while( ( d_stream.avail_out == 0 ) && ( d_stream.avail_in != 0 ) &&
  214.            ( result != Z_STREAM_END ) );
  215.     dstsize = d_stream.total_out;
  216.     inflateEnd( &d_stream );
  217.     *_dst = (unsigned char *)realloc( dst, dstsize );
  218.     return dstsize;
  219. }
  220. #endif
  221. /*****************************************************************************
  222.  * Open: initialize and create stuff
  223.  *****************************************************************************/
  224. static int Open( vlc_object_t *p_this )
  225. {
  226.     intf_thread_t *p_intf = ( intf_thread_t* )p_this;
  227.     intf_sys_t    *p_sys  = malloc( sizeof( intf_sys_t ) );
  228.     playlist_t          *p_playlist;
  229.     p_sys->i_timeout = config_GetInt( p_intf,"sap-timeout" );
  230.     p_sys->fd[0] = -1;
  231.     p_sys->fd[1] = -1;
  232.     if( config_GetInt( p_intf, "sap-ipv4" ) )
  233.     {
  234.         char *psz_address = config_GetPsz( p_intf, "sap-addr" );
  235.         network_socket_t    sock;
  236.         module_t            *p_network;
  237.         if( psz_address == NULL || *psz_address == '' )
  238.         {
  239.             psz_address = strdup( HELLO_GROUP );
  240.         }
  241.         /* Prepare the network_socket_t structure */
  242.         sock.i_type            = NETWORK_UDP;
  243.         sock.psz_bind_addr     = psz_address;
  244.         sock.i_bind_port       = HELLO_PORT;
  245.         sock.psz_server_addr   = "";
  246.         sock.i_server_port     = 0;
  247.         sock.i_ttl             = 0;
  248.         p_intf->p_private = ( void* ) &sock;
  249.         p_network = module_Need( p_intf, "network", "ipv4", VLC_TRUE );
  250.         if( p_network )
  251.         {
  252.             p_sys->fd[0] = sock.i_handle;
  253.             module_Unneed( p_intf, p_network );
  254.         }
  255.         else
  256.         {
  257.             msg_Warn( p_intf, "failed to open %s:%d", psz_address, HELLO_PORT );
  258.         }
  259.         free( psz_address );
  260.     }
  261.     if( config_GetInt( p_intf, "sap-ipv6" ) )
  262.     {
  263.         char psz_address[100];
  264.         char *psz_scope = config_GetPsz( p_intf, "sap-ipv6-scope" );
  265.         network_socket_t    sock;
  266.         module_t            *p_network;
  267.         if( psz_scope == NULL || *psz_scope == '' )
  268.         {
  269.             psz_scope = strdup( "8" );
  270.         }
  271.         snprintf( psz_address, 100, "[%s%c%s]",IPV6_ADDR_1,
  272.                   psz_scope[0], IPV6_ADDR_2 );
  273.         free( psz_scope );
  274.         sock.i_type            = NETWORK_UDP;
  275.         sock.psz_bind_addr     = psz_address;
  276.         sock.i_bind_port       = HELLO_PORT;
  277.         sock.psz_server_addr   = "";
  278.         sock.i_server_port     = 0;
  279.         sock.i_ttl             = 0;
  280.         p_intf->p_private = (void*) &sock;
  281.         p_network = module_Need( p_intf, "network", "ipv6", VLC_TRUE );
  282.         if( p_network )
  283.         {
  284.             p_sys->fd[1] = sock.i_handle;
  285.             module_Unneed( p_intf, p_network );
  286.         }
  287.         else
  288.         {
  289.             msg_Warn( p_intf, "failed to open %s:%d", psz_address, HELLO_PORT );
  290.         }
  291.     }
  292.     if( p_sys->fd[0] <= 0 && p_sys->fd[1] <= 0 )
  293.     {
  294.         msg_Warn( p_intf, "IPV4 and IPV6 failed" );
  295.         free( p_sys );
  296.         return VLC_EGENERIC;
  297.     }
  298.     /* Create our playlist group */
  299.     p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  300.                                                 FIND_ANYWHERE );
  301.     if( p_playlist )
  302.     {
  303.         playlist_group_t *p_group = playlist_CreateGroup( p_playlist , "SAP" );
  304.         p_sys->i_group = p_group->i_id;
  305.         vlc_object_release( p_playlist );
  306.     }
  307.     p_sys->i_announces = 0;
  308.     p_sys->pp_announces = NULL;
  309.     p_intf->pf_run = Run;
  310.     p_intf->p_sys  = p_sys;
  311.     return VLC_SUCCESS;
  312. }
  313. /*****************************************************************************
  314.  * Close:
  315.  *****************************************************************************/
  316. static void Close( vlc_object_t *p_this )
  317. {
  318.     intf_thread_t *p_intf = ( intf_thread_t* )p_this;
  319.     intf_sys_t    *p_sys  = p_intf->p_sys;
  320.     int i;
  321.     if( p_sys->fd[0] > 0 )
  322.     {
  323.         close( p_sys->fd[0] );
  324.     }
  325.     if( p_sys->fd[1] > 0 )
  326.     {
  327.         close( p_sys->fd[1] );
  328.     }
  329.     for( i = 0 ; i< p_sys->i_announces ; i++ )
  330.     {
  331.         if( p_sys->pp_announces[i]->psz_name )
  332.            free( p_sys->pp_announces[i]->psz_name );
  333.         if( p_sys->pp_announces[i]->psz_uri )
  334.            free( p_sys->pp_announces[i]->psz_uri );
  335.         free( p_sys->pp_announces[i] );
  336.     }
  337.     free( p_sys->pp_announces );
  338.     free( p_sys );
  339. }
  340. /*****************************************************************************
  341.  * Run: sap thread
  342.  *****************************************************************************
  343.  * Listens to SAP packets, and sends them to packet_handle
  344.  *****************************************************************************/
  345. #define MAX_SAP_BUFFER 5000
  346. static void Run( intf_thread_t *p_intf )
  347. {
  348.     intf_sys_t *p_sys  = p_intf->p_sys;
  349.     uint8_t     buffer[MAX_SAP_BUFFER + 1];
  350.     uint8_t    *p_end;
  351.     
  352.     /* Dirty hack to slow down the startup of the sap interface */ 
  353.     msleep( 500000 );
  354.     /* read SAP packets */
  355.     while( !p_intf->b_die )
  356.     {
  357.         playlist_t *p_playlist= NULL;
  358.         int i;
  359.         int i_read = NetRead( p_intf, p_sys->fd, buffer, MAX_SAP_BUFFER );
  360.         uint8_t *p_sdp;
  361.         int i_version;
  362.         int i_address_type;
  363.         int b_reserved;
  364.         int b_message_type;
  365.         int b_encrypted;
  366.         int b_compressed;
  367.         unsigned char *p_decompressed_buffer;
  368.         int i_decompressed_size;
  369.         /* Check for items that need deletion */
  370.         for( i = 0 ; i< p_intf->p_sys->i_announces ; i++ )
  371.         {
  372.            struct sap_announce_t *p_announce;
  373.            mtime_t i_timeout = ( mtime_t ) 1000000*p_sys->i_timeout;
  374.            if( mdate() - p_intf->p_sys->pp_announces[i]->i_last > i_timeout )
  375.            {
  376.                msg_Dbg( p_intf,"Time out for %s, deleting (%i/%i)",
  377.                         p_intf->p_sys->pp_announces[i]->psz_name,
  378.                         i , p_intf->p_sys->i_announces );
  379.                /* Remove the playlist item */
  380.                p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  381.                               FIND_ANYWHERE );
  382.                if( p_playlist )
  383.                {
  384.                    int i_pos = playlist_GetPositionById( p_playlist,
  385.                               p_intf->p_sys->pp_announces[i]->i_id );
  386.                    playlist_Delete( p_playlist, i_pos );
  387.                    vlc_object_release( p_playlist );
  388.                }
  389.                /* Free the p_announce */
  390.                p_announce =  p_intf->p_sys->pp_announces[i];
  391.                if( p_announce->psz_name )
  392.                   free(  p_announce->psz_name );
  393.                if( p_announce->psz_uri )
  394.                   free(  p_announce->psz_uri );
  395.               /* Remove the sap_announce from the array */
  396.               REMOVE_ELEM( p_intf->p_sys->pp_announces,
  397.                            p_intf->p_sys->i_announces,
  398.                            i );
  399.               free( p_announce );
  400.            }
  401.         }
  402.         /* Minimum length is > 6 */
  403.         if( i_read <= 6 )
  404.         {
  405.             if( i_read < 0 )
  406.             {
  407.                 msg_Warn( p_intf, "Cannot read in the socket" );
  408.             }
  409.             continue;
  410.         }
  411.         buffer[i_read] = '';
  412.         p_end = &buffer[i_read];
  413.         /* Parse the SAP header */
  414.         i_version = buffer[0] >> 5;
  415.         if( i_version != 1 )
  416.         {
  417.             msg_Dbg( p_intf, "strange sap version %d found", i_version );
  418.         }
  419.         i_address_type = buffer[0] & 0x10;
  420.         b_reserved = buffer[0] & 0x08;
  421.         if( b_reserved != 0 )
  422.         {
  423.             msg_Dbg( p_intf, "reserved bit incorrectly set" );
  424.         }
  425.         b_message_type = buffer[0] & 0x04;
  426.         if( b_message_type != 0 )
  427.         {
  428.             msg_Dbg( p_intf, "got session deletion packet" );
  429.         }
  430.         b_encrypted = buffer[0] & 0x02;
  431.         if( b_encrypted )
  432.         {
  433.             msg_Dbg( p_intf, "encrypted packet" );
  434.         }
  435.         b_compressed = buffer[0] & 0x01;
  436.         p_sdp  = &buffer[4];
  437.         if( i_address_type == 0 ) /* ipv4 source address */
  438.         {
  439.             p_sdp += 4;
  440.         }
  441.         else /* ipv6 source address */
  442.         {
  443.             p_sdp += 16;
  444.         }
  445.         if( b_compressed )
  446.         {
  447. #ifdef HAVE_ZLIB_H
  448.             i_decompressed_size = do_decompress( p_sdp, &p_decompressed_buffer,
  449.                                       i_read - ( p_sdp - buffer ) );
  450.             if( i_decompressed_size > 0 && i_decompressed_size < MAX_SAP_BUFFER )
  451.             {
  452.                 memcpy( p_sdp, p_decompressed_buffer, i_decompressed_size );
  453.                 p_sdp[i_decompressed_size] = '';
  454.                 p_end = &p_sdp[i_decompressed_size];
  455.                 free( p_decompressed_buffer );
  456.             }
  457. #else
  458.             msg_Warn( p_intf, "Ignoring compressed sap packet" );
  459. #endif
  460.         }
  461.         p_sdp += buffer[1]; /* size of signature */
  462.         while( p_sdp < p_end - 1 && *p_sdp != '' && p_sdp[0] != 'v' && p_sdp[1] != '=' )
  463.         {
  464.             p_sdp++;
  465.         }
  466.         if( *p_sdp == '' )
  467.         {
  468.             p_sdp++;
  469.         }
  470.         if( p_sdp < p_end )
  471.         {
  472.             sess_descr_t *p_sd = parse_sdp( (vlc_object_t *)p_intf, p_sdp );
  473.             if( p_sd )
  474.             {
  475.                 sess_toitem ( p_intf, p_sd );
  476.                 free_sd ( p_sd );
  477.             }
  478.         }
  479.         else
  480.         {
  481.             msg_Warn( p_intf, "ditching sap packet" );
  482.         }
  483.         memset( buffer, 0, MAX_SAP_BUFFER );
  484.     }
  485. }
  486. /**********************************************************************
  487.  * cfield_parse
  488.  *********************************************************************
  489.  * put into *ppsz_uri, the the uri in the cfield, psz_cfield.
  490.  *********************************************************************/
  491. static void cfield_parse( char *psz_cfield, char **ppsz_uri )
  492. {
  493.     char *psz_pos;
  494.     if( psz_cfield )
  495.     {
  496.         psz_pos = psz_cfield;
  497.         while( *psz_pos != ' ' && *psz_pos !='' )
  498.         {
  499.             psz_pos++;
  500.         }
  501.         psz_pos++;
  502.         while( *psz_pos != ' ' && *psz_pos !='' )
  503.         {
  504.             psz_pos++;
  505.         }
  506.         psz_pos++;
  507.         *ppsz_uri = psz_pos;
  508.         while( *psz_pos != ' ' && *psz_pos !='/'
  509.                         && *psz_pos != '' )
  510.         {
  511.             psz_pos++;
  512.         }
  513.         *psz_pos = '';
  514.     }
  515.     else
  516.     {
  517.         ppsz_uri = NULL;
  518.     }
  519.     return;
  520. }
  521. /**********************************************************************
  522.  * mfield_parse
  523.  *********************************************************************
  524.  * put into *ppsz_proto, and *ppsz_port, the protocol and the port.
  525.  *********************************************************************/
  526. static void mfield_parse( char *psz_mfield, char **ppsz_proto,
  527.                char **ppsz_port )
  528. {
  529.     char *psz_pos;
  530.     char *psz_media;
  531.     if( psz_mfield )
  532.     {
  533.         psz_pos = psz_mfield;
  534.         psz_media = psz_mfield;
  535.         while( *psz_pos != '' && *psz_pos != ' ' )
  536.         {
  537.             psz_pos++;
  538.         }
  539.         if( *psz_pos != '' )
  540.         {
  541.             *psz_pos = '';
  542.             if( strcmp( psz_media, "video" ) && strcmp( psz_media, "audio" ) )
  543.             {
  544.                 *ppsz_proto = NULL;
  545.                 *ppsz_port = NULL;
  546.                 return;
  547.             }
  548.         }
  549.         psz_pos++;
  550.         *ppsz_port = psz_pos;
  551.         while( *psz_pos != '' && *psz_pos !=' ' && *psz_pos!='/' )
  552.         {
  553.             psz_pos++;
  554.         }
  555.         if( *psz_pos == '/' )  // FIXME does not support multi-port
  556.         {
  557.             *psz_pos = '';
  558.             psz_pos++;
  559.             while( *psz_pos != '' && *psz_pos !=' ' )
  560.             {
  561.             psz_pos++;
  562.             }
  563.         }
  564.         *psz_pos = '';
  565.         psz_pos++;
  566.         *ppsz_proto = psz_pos;
  567.         while( *psz_pos!='' && *psz_pos !=' ' &&
  568.                         *psz_pos!='/' )
  569.         {
  570.             *psz_pos = tolower( *psz_pos );
  571.             psz_pos++;
  572.         }
  573.         *psz_pos = '';
  574.     }
  575.     else
  576.     {
  577.         *ppsz_proto = NULL;
  578.         *ppsz_port = NULL;
  579.     }
  580.     return;
  581. }
  582. /*******************************************************************
  583.  * sess_toitem : changes a sess_descr_t into a hurd of
  584.  * playlist_item_t, which are enqueued.
  585.  *******************************************************************
  586.  * Note : does not support sessions that take place on consecutive
  587.  * port or adresses yet.
  588.  *******************************************************************/
  589. static void sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
  590. {
  591.     struct sap_announce_t *p_announce;
  592.     char *psz_uri, *psz_proto, *psz_item_uri;
  593.     char *psz_port;
  594.     char *psz_uri_default;
  595.     int i_count, i, i_id = 0;
  596.     vlc_bool_t b_http = VLC_FALSE;
  597.     char *psz_http_path = NULL;
  598.     playlist_t *p_playlist = NULL;
  599.     playlist_item_t *p_item;
  600.     psz_uri_default = NULL;
  601.     if( p_sd->i_media > 1 || !config_GetInt( p_intf, "sap-parse" ) )
  602.     {
  603.         asprintf( &psz_uri, "sdp://%s", p_sd->psz_sdp );
  604.         /* Check if we have already added the item */
  605.         for( i = 0 ; i< p_intf->p_sys->i_announces ; i++ )
  606.         {
  607.             if( !strcmp( p_intf->p_sys->pp_announces[i]->psz_uri,
  608.                          psz_uri ) )
  609.             {
  610.                 p_intf->p_sys->pp_announces[i]->i_last = mdate();
  611.                 free( psz_uri );
  612.                 return;
  613.             }
  614.         }
  615.         /* Add it to the playlist */
  616.         p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  617.                                       FIND_ANYWHERE );
  618.         i_id = playlist_Add( p_playlist, psz_uri, p_sd->psz_sessionname ,
  619.                       PLAYLIST_CHECK_INSERT, PLAYLIST_END );
  620.         if( i_id != -1 )
  621.         {
  622.             playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_id );
  623.             playlist_ItemSetGroup( p_item, p_intf->p_sys->i_group );
  624.         }
  625.         /* Remember it */
  626.         p_announce = ( struct sap_announce_t * )malloc(
  627.                       sizeof( struct sap_announce_t ) );
  628.         if( p_sd->psz_sessionname )
  629.         {
  630.             p_announce->psz_name = strdup(  p_sd->psz_sessionname );
  631.         }
  632.         else
  633.         {
  634.             p_announce->psz_name = strdup( "" );
  635.         }
  636.         if( psz_uri )
  637.         {
  638.             p_announce->psz_uri  = strdup( psz_uri );
  639.         }
  640.         else
  641.         {
  642.             p_announce->psz_uri = strdup( "" );
  643.         }
  644.         p_announce->i_id = i_id;
  645.         p_announce->i_last = mdate();
  646.         INSERT_ELEM( p_intf->p_sys->pp_announces,
  647.                      p_intf->p_sys->i_announces,
  648.                      p_intf->p_sys->i_announces,
  649.                      p_announce );
  650.         vlc_object_release( p_playlist );
  651.         free( psz_uri );
  652.         return;
  653.     }
  654.     cfield_parse( p_sd->psz_connection, &psz_uri_default );
  655.     for( i_count = 0 ; i_count < p_sd->i_media ; i_count++ )
  656.     {
  657.         int i_group = p_intf->p_sys->i_group;
  658.         int i_packetsize = config_GetInt( p_intf, "mtu" );
  659.         /* Build what we have to put in psz_item_uri, with the m and
  660.          * c fields  */
  661.         if( !p_sd->pp_media[i_count] )
  662.         {
  663.             return;
  664.         }
  665.         mfield_parse( p_sd->pp_media[i_count]->psz_medianame,
  666.                         & psz_proto, & psz_port );
  667.         if( !psz_proto || !psz_port )
  668.         {
  669.             return;
  670.         }
  671.         if( p_sd->pp_media[i_count]->psz_mediaconnection )
  672.         {
  673.             cfield_parse( p_sd->pp_media[i_count]->psz_mediaconnection,
  674.                             & psz_uri );
  675.         }
  676.         else
  677.         {
  678.             psz_uri = psz_uri_default;
  679.         }
  680.         if( psz_uri == NULL )
  681.         {
  682.             return;
  683.         }
  684.         for( i = 0 ; i< p_sd->i_attributes ; i++ )
  685.         {
  686.             if( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "type" ) &&
  687.                 strstr( p_sd->pp_attributes[i]->psz_value, "http" ) )
  688.             {
  689.                 b_http = VLC_TRUE;
  690.             }
  691.             if( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "http-path" ) )
  692.             {
  693.                 psz_http_path = strdup(  p_sd->pp_attributes[i]->psz_value );
  694.             }
  695.             if( ( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "plgroup" ) ) ||
  696.                 ( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "x-plgroup" ) ) )
  697.             {
  698.                 int i_group_id;
  699.                 p_playlist =
  700.                 (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  701.                                                         FIND_ANYWHERE );
  702.                 if( p_playlist == NULL )
  703.                 {
  704.                     return;
  705.                 }
  706.                 i_group_id = playlist_GroupToId( p_playlist,
  707.                                  p_sd->pp_attributes[i]->psz_value );
  708.                 if( i_group_id != 0 )
  709.                 {
  710.                     i_group = i_group_id;
  711.                 }
  712.                 else
  713.                 {
  714.                     playlist_group_t *p_group =
  715.                             playlist_CreateGroup( p_playlist,
  716.                                        p_sd->pp_attributes[i]->psz_value );
  717.                     i_group = p_group->i_id;
  718.                 }
  719.                 vlc_object_release( p_playlist );
  720.             }
  721.             if( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "packetsize" ) )
  722.             {
  723.                 i_packetsize = strtol( p_sd->pp_attributes[i]->psz_value, NULL, 10 );
  724.             }
  725.         }
  726.         /* Filling psz_uri */
  727.         if( b_http == VLC_FALSE )
  728.         {
  729.             if( ismult( psz_uri ) )
  730.             {
  731.                 asprintf( &psz_item_uri, "%s://@%s:%s",
  732.                          psz_proto, psz_uri, psz_port );
  733.             }
  734.             else
  735.             {
  736.                 asprintf( &psz_item_uri, "%s://%s:%s",
  737.                          psz_proto, psz_uri, psz_port );
  738.             }
  739.         }
  740.         else
  741.         {
  742.             if( psz_http_path == NULL )
  743.             {
  744.                 psz_http_path = strdup( "/" );
  745.             }
  746.             if( *psz_http_path == '/' )
  747.             {
  748.                 asprintf( &psz_item_uri, "%s://%s:%s%s", psz_proto,
  749.                          psz_uri, psz_port,psz_http_path );
  750.             }
  751.             else
  752.             {
  753.                 asprintf( &psz_item_uri, "%s://%s:%s/%s", psz_proto, psz_uri,
  754.                           psz_port, psz_http_path );
  755.             }
  756.             if( psz_http_path )
  757.             {
  758.                 free( psz_http_path );
  759.             }
  760.         }
  761.         /* Check if we already know this item */
  762.          for( i = 0 ; i< p_intf->p_sys->i_announces ; i++ )
  763.          {
  764.             if( !strcmp( p_intf->p_sys->pp_announces[i]->psz_uri,
  765.                          psz_item_uri ) )
  766.             {
  767.                 p_intf->p_sys->pp_announces[i]->i_last = mdate();
  768.                 /* Check if the name changed */
  769.                 if( strcmp( p_intf->p_sys->pp_announces[i]->psz_name,
  770.                              p_sd->psz_sessionname ) )
  771.                 {
  772.                     playlist_item_t *p_item;
  773.                     p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  774.                                                   FIND_ANYWHERE );
  775.                     msg_Dbg(p_intf, "Name changed (%s -> %s) for %s",
  776.                             p_intf->p_sys->pp_announces[i]->psz_name,
  777.                             p_sd->psz_sessionname,
  778.                             psz_item_uri );
  779.                     p_item = playlist_ItemGetById( p_playlist,
  780.                                     p_intf->p_sys->pp_announces[i]->i_id );
  781.                     /* Change the name in the item */
  782.                     if( p_item )
  783.                     {
  784.                         vlc_mutex_lock( &p_item->input.lock );
  785.                         if( p_item->input.psz_name )
  786.                             free( p_item->input.psz_name );
  787.                         p_item->input.psz_name = strdup( p_sd->psz_sessionname );
  788.                         vlc_mutex_unlock( &p_item->input.lock );
  789.                     }
  790.                     /* Update the stored name */
  791.                     if( p_intf->p_sys->pp_announces[i]->psz_name )
  792.                         free( p_intf->p_sys->pp_announces[i]->psz_name );
  793.                     p_intf->p_sys->pp_announces[i]->psz_name =
  794.                                    strdup( p_sd->psz_sessionname );
  795.                     vlc_object_release( p_playlist );
  796.                 }
  797.                 free( psz_item_uri );
  798.                 return;
  799.             }
  800.         }
  801.         /* Add the item in the playlist */
  802.         p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  803.                                       FIND_ANYWHERE );
  804.         p_item = playlist_ItemNew( p_intf, psz_item_uri, p_sd->psz_sessionname );
  805.         if( p_item )
  806.         {
  807.             playlist_ItemSetGroup( p_item, i_group );
  808.             if( i_packetsize > config_GetInt( p_intf, "mtu" ) )
  809.             {
  810.                 char *psz_packetsize_option;
  811.                 asprintf( &psz_packetsize_option, "mtu=%i", i_packetsize );
  812.                 playlist_ItemAddOption( p_item, psz_packetsize_option );
  813.                 free( psz_packetsize_option );
  814.             }
  815.             playlist_AddItem( p_playlist , p_item , PLAYLIST_CHECK_INSERT, PLAYLIST_END );
  816.         }
  817.         /* Then remember it */
  818.         p_announce = (struct sap_announce_t *)malloc(
  819.                       sizeof( struct sap_announce_t ) );
  820.         if(  p_sd->psz_sessionname )
  821.         {
  822.             p_announce->psz_name = strdup(  p_sd->psz_sessionname );
  823.         }
  824.         else
  825.         {
  826.             p_announce->psz_name = strdup( "" );
  827.         }
  828.         if( psz_item_uri )
  829.         {
  830.             p_announce->psz_uri  = strdup( psz_item_uri );
  831.         }
  832.         else
  833.         {
  834.             p_announce->psz_uri = strdup( "" );
  835.         }
  836.         p_announce->i_id = i_id;
  837.         p_announce->i_last = mdate();
  838.         vlc_object_release( p_playlist );
  839.         INSERT_ELEM( p_intf->p_sys->pp_announces,
  840.                      p_intf->p_sys->i_announces,
  841.                      p_intf->p_sys->i_announces,
  842.                      p_announce );
  843.         free( psz_item_uri );
  844.     }
  845. }
  846. /***********************************************************************
  847.  * parse_sdp : SDP parsing
  848.  * *********************************************************************
  849.  * Make a sess_descr_t with a psz
  850.  ***********************************************************************/
  851. static sess_descr_t *  parse_sdp( vlc_object_t * p_parent, char *p_packet )
  852. {
  853.     sess_descr_t *  sd;
  854.     if( p_packet[0] != 'v' || p_packet[1] != '=' )
  855.     {
  856.         msg_Warn( p_parent, "bad SDP packet" );
  857.         return NULL;
  858.     }
  859.     sd = malloc( sizeof( sess_descr_t ) );
  860.     sd->psz_sessionname = NULL;
  861.     sd->psz_connection  = NULL;
  862.     sd->psz_sdp         = strdup( p_packet );
  863.     sd->i_media         = 0;
  864.     sd->pp_media        = NULL;
  865.     sd->i_attributes    = 0;
  866.     sd->pp_attributes   = NULL;
  867.     while( *p_packet != ''  )
  868.     {
  869.         char *psz_end;
  870.         /* Search begin of field */
  871.         while( *p_packet == 'r' || *p_packet == 'n' || *p_packet == ' ' || *p_packet == 't' )
  872.         {
  873.             p_packet++;
  874.         }
  875.         /* search end of line */
  876.         if( ( psz_end = strchr( p_packet, 'n' ) ) == NULL )
  877.         {
  878.             psz_end = p_packet + strlen( p_packet );
  879.         }
  880.         if( psz_end > p_packet && *( psz_end - 1 ) == 'r' )
  881.         {
  882.             psz_end--;
  883.         }
  884.         if( psz_end <= p_packet )
  885.         {
  886.             break;
  887.         }
  888.         *psz_end++ = '';
  889.         if( p_packet[1] != '=' )
  890.         {
  891.             msg_Warn( p_parent, "invalid packet" ) ;
  892.             free_sd( sd );
  893.             return NULL;
  894.         }
  895.         switch( p_packet[0] )
  896.         {
  897.             case( 'v' ):
  898.                 sd->i_version = atoi( &p_packet[2] );
  899.                 break;
  900.             case( 's' ):
  901.                 sd->psz_sessionname = strdup( &p_packet[2] );
  902.                 break;
  903.             case ( 'o' ):
  904.             case( 'i' ):
  905.             case( 'u' ):
  906.             case( 'e' ):
  907.             case( 'p' ):
  908.             case( 't' ):
  909.             case( 'r' ):
  910.                 break;
  911.             case( 'a' ):
  912.             {
  913.                 char *psz_eof = strchr( &p_packet[2], ':' );
  914.                 if( psz_eof && psz_eof[1] != '' )
  915.                 {
  916.                     attr_descr_t *attr = malloc( sizeof( attr_descr_t ) );
  917.                     *psz_eof++ = '';
  918.                     attr->psz_field = strdup( &p_packet[2] );
  919.                     attr->psz_value = strdup( psz_eof );
  920.                     TAB_APPEND( sd->i_attributes, sd->pp_attributes, attr );
  921.                 }
  922.                 break;
  923.             }
  924.             case( 'm' ):
  925.             {
  926.                 media_descr_t *media = malloc( sizeof( media_descr_t ) );
  927.                 media->psz_medianame = strdup( &p_packet[2] );
  928.                 media->psz_mediaconnection = NULL;
  929.                 TAB_APPEND( sd->i_media, sd->pp_media, media );
  930.                 break;
  931.             }
  932.             case( 'c' ):
  933.                 if( sd->i_media <= 0 )
  934.                 {
  935.                     sd->psz_connection = strdup( &p_packet[2] );
  936.                 }
  937.                 else
  938.                 {
  939.                     sd->pp_media[sd->i_media-1]->psz_mediaconnection = strdup( &p_packet[2] );
  940.                 }
  941.                break;
  942.             default:
  943.                break;
  944.         }
  945.         p_packet = psz_end;
  946.     }
  947.     return sd;
  948. }
  949. #define FREE( p ) 
  950.     if( p ) { free( p ); (p) = NULL; }
  951. static void free_sd( sess_descr_t * p_sd )
  952. {
  953.     int i;
  954.     FREE( p_sd->psz_sessionname );
  955.     FREE( p_sd->psz_connection );
  956.     FREE( p_sd->psz_sdp );
  957.     for( i = 0; i < p_sd->i_media ; i++ )
  958.     {
  959.         FREE( p_sd->pp_media[i]->psz_medianame );
  960.         FREE( p_sd->pp_media[i]->psz_mediaconnection );
  961.         FREE( p_sd->pp_media[i] );
  962.     }
  963.     for( i = 0; i < p_sd->i_attributes ; i++ )
  964.     {
  965.         FREE( p_sd->pp_attributes[i]->psz_field );
  966.         FREE( p_sd->pp_attributes[i]->psz_value );
  967.         FREE( p_sd->pp_attributes[i] );
  968.     }
  969.     FREE( p_sd->pp_attributes );
  970.     FREE( p_sd->pp_media );
  971.     free( p_sd );
  972. }
  973. /***********************************************************************
  974.  * ismult: returns true if we have a multicast address
  975.  ***********************************************************************/
  976. static int ismult( char *psz_uri )
  977. {
  978.     char *psz_end;
  979.     int  i_value;
  980.     i_value = strtol( psz_uri, &psz_end, 0 );
  981.     /* IPv6 */
  982.     if( psz_uri[0] == '[')
  983.     {
  984.       if( strncasecmp( &psz_uri[1], "FF0" , 3) ||
  985.           strncasecmp( &psz_uri[2], "FF0" , 3))
  986.             return( VLC_TRUE );
  987.         else
  988.             return( VLC_FALSE );
  989.     }
  990.     if( *psz_end != '.' ) { return( VLC_FALSE ); }
  991.     return( i_value < 224 ? VLC_FALSE : VLC_TRUE );
  992. }
  993. /*****************************************************************************
  994.  * NetRead: read on a file descriptor, checking b_die periodically
  995.  *****************************************************************************
  996.  * Taken from net.c
  997.  * Code duplication because of select(). We need a net_Select() but that's 
  998.  * quite difficult.
  999.  *****************************************************************************/
  1000. static ssize_t NetRead( intf_thread_t *p_intf,
  1001.                         int fd[2], uint8_t *p_buffer, int i_len )
  1002. {
  1003. #ifdef UNDER_CE
  1004.     return -1;
  1005. #else
  1006.     struct timeval  timeout;
  1007.     fd_set          fds;
  1008.     int             i_ret;
  1009.     int             i_handle_max = __MAX( fd[0], fd[1] );
  1010.     /* Initialize file descriptor set */
  1011.     FD_ZERO( &fds );
  1012.     if( fd[0] > 0 ) FD_SET( fd[0], &fds );
  1013.     if( fd[1] > 0 ) FD_SET( fd[1], &fds );
  1014.     /* We'll wait 0.5 second if nothing happens */
  1015.     timeout.tv_sec = 0;
  1016.     timeout.tv_usec = 500000;
  1017.     /* Find if some data is available */
  1018.     i_ret = select( i_handle_max + 1, &fds, NULL, NULL, &timeout );
  1019.     if( i_ret == -1 && errno != EINTR )
  1020.     {
  1021.         msg_Err( p_intf, "network select error (%s)", strerror(errno) );
  1022.     }
  1023.     else if( i_ret > 0 )
  1024.     {
  1025.         if( fd[0] > 0 && FD_ISSET( fd[0], &fds ) )
  1026.         {
  1027.              return recv( fd[0], p_buffer, i_len, 0 );
  1028.         }
  1029.         else if( fd[1] > 0 && FD_ISSET( fd[1], &fds ) )
  1030.         {
  1031.              return recv( fd[1], p_buffer, i_len, 0 );
  1032.         }
  1033.     }
  1034.     return 0;
  1035. #endif
  1036. }
  1037. /*
  1038.  * This submodule is temporary and has a very high duplicate code rate
  1039.  * This needs to be removed when SDP UDP parsing is fixed in liveMedia
  1040.  */
  1041. static int OpenSDP( vlc_object_t * p_this )
  1042. {
  1043.     demux_t *p_demux = (demux_t *)p_this;
  1044.     uint8_t *p_peek;
  1045.     if( p_demux->s )
  1046.     {
  1047.         /* See if it looks like a SDP
  1048.            v, o, s fields are mandatory and in this order */
  1049.         if( stream_Peek( p_demux->s, &p_peek, 7 ) < 7 )
  1050.         {
  1051.             msg_Err( p_demux, "cannot peek" );
  1052.             return VLC_EGENERIC;
  1053.         }
  1054.         if( strncmp( (char*)p_peek, "v=0rn", 5 ) && strncmp( (char*)p_peek, "v=0n", 4 ) &&
  1055.             ( p_peek[0] < 'a' || p_peek[0] > 'z' || p_peek[1] != '=' ) )
  1056.         {
  1057.             msg_Warn( p_demux, "SDP (UDP) module discarded" );
  1058.             return VLC_EGENERIC;
  1059.         }
  1060.     }
  1061.     
  1062.     p_demux->pf_control = Control;
  1063.     p_demux->pf_demux = Demux;
  1064.     return VLC_SUCCESS;
  1065. }
  1066. /*****************************************************************************
  1067.  * Demux: reads and demuxes data packets
  1068.  * This submodule is temporary and has a very high duplicate code rate
  1069.  * This needs to be removed when SDP UDP parsing is fixed in liveMedia
  1070.  *****************************************************************************
  1071.  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
  1072.  *****************************************************************************/
  1073. static int Demux( demux_t *p_demux )
  1074. {
  1075.     sess_descr_t *p_sd = NULL;
  1076.     playlist_t *p_playlist = NULL;
  1077.     int i_sdp = 0;
  1078.     int i_sdp_max = 1000;
  1079.     int i_position = -1;
  1080.     char *p_sdp = (uint8_t*)malloc( i_sdp_max );
  1081.     
  1082.     p_playlist = vlc_object_find( p_demux, VLC_OBJECT_PLAYLIST,
  1083.                                           FIND_ANYWHERE );
  1084.     
  1085.     if( !p_playlist )
  1086.     {
  1087.         msg_Err( p_demux, "can't find playlist" );
  1088.         return -1;
  1089.     }
  1090.     
  1091.     p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
  1092.     i_position = p_playlist->i_index;
  1093.     
  1094.     /* Gather the complete sdp file */
  1095.     for( ;; )
  1096.     {
  1097.         int i_read = stream_Read( p_demux->s, &p_sdp[i_sdp], i_sdp_max - i_sdp - 1 );
  1098.         if( i_read < 0 )
  1099.         {
  1100.             msg_Err( p_demux, "failed to read SDP" );
  1101.             return VLC_EGENERIC;
  1102.         }
  1103.         i_sdp += i_read;
  1104.         if( i_read < i_sdp_max - i_sdp - 1 )
  1105.         {
  1106.             p_sdp[i_sdp] = '';
  1107.             break;
  1108.         }
  1109.         i_sdp_max += 1000;
  1110.         p_sdp = (uint8_t*)realloc( p_sdp, i_sdp_max );
  1111.     }
  1112.     msg_Dbg( p_demux, "sdp=%sn", p_sdp );
  1113.     
  1114.     p_sd = parse_sdp( (vlc_object_t *)p_demux, p_sdp );
  1115.     if( p_sd )
  1116.     {
  1117.         char *psz_uri, *psz_proto, *psz_item_uri;
  1118.         char *psz_port;
  1119.         char *psz_uri_default;
  1120.         int i_count, i, i_id = 0;
  1121.         vlc_bool_t b_http = VLC_FALSE;
  1122.         char *psz_http_path = NULL;
  1123.         playlist_item_t *p_item;
  1124.         psz_uri_default = NULL;
  1125.         
  1126.         if( p_sd->i_media > 1 || !config_GetInt( p_demux, "sap-parse" ) )
  1127.         {
  1128.             /* Let another module try this */
  1129.             asprintf( &psz_uri, "sdp://%s", p_sd->psz_sdp );
  1130.             i_id = playlist_Add( p_playlist, psz_uri, p_sd->psz_sessionname ,
  1131.                           PLAYLIST_CHECK_INSERT, i_position );
  1132.             free( psz_uri );
  1133.             vlc_object_release( p_playlist );
  1134.             return 0;
  1135.         }
  1136.         
  1137.         /* We try to parse it ourselves */
  1138.         cfield_parse( p_sd->psz_connection, &psz_uri_default );
  1139.         for( i_count = 0 ; i_count < p_sd->i_media ; i_count++ )
  1140.         {
  1141.             int i_group = 0;
  1142.             int i_packetsize = config_GetInt( p_demux, "mtu" );
  1143.             /* Build what we have to put in psz_item_uri, with the m and
  1144.              * c fields  */
  1145.             if( !p_sd->pp_media[i_count] )
  1146.             {
  1147.                 vlc_object_release( p_playlist );
  1148.                 return -1;
  1149.             }
  1150.             mfield_parse( p_sd->pp_media[i_count]->psz_medianame,
  1151.                             &psz_proto, &psz_port );
  1152.             if( !psz_proto || !psz_port )
  1153.             {
  1154.                 vlc_object_release( p_playlist );
  1155.                 return -1;
  1156.             }
  1157.             if( p_sd->pp_media[i_count]->psz_mediaconnection )
  1158.             {
  1159.                 cfield_parse( p_sd->pp_media[i_count]->psz_mediaconnection,
  1160.                                 & psz_uri );
  1161.             }
  1162.             else
  1163.             {
  1164.                 psz_uri = psz_uri_default;
  1165.             }
  1166.             if( psz_uri == NULL )
  1167.             {
  1168.                 vlc_object_release( p_playlist );
  1169.                 return -1;
  1170.             }
  1171.             for( i = 0 ; i< p_sd->i_attributes ; i++ )
  1172.             {
  1173.                 if( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "type" ) &&
  1174.                     strstr( p_sd->pp_attributes[i]->psz_value, "http" ) )
  1175.                 {
  1176.                     b_http = VLC_TRUE;
  1177.                 }
  1178.                 if( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "http-path" ) )
  1179.                 {
  1180.                     psz_http_path = strdup(  p_sd->pp_attributes[i]->psz_value );
  1181.                 }
  1182.                 if( ( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "plgroup" ) ) ||
  1183.                     ( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "x-plgroup" ) ) )
  1184.                 {
  1185.                     int i_group_id;
  1186.                     i_group_id = playlist_GroupToId( p_playlist,
  1187.                                      p_sd->pp_attributes[i]->psz_value );
  1188.                     if( i_group_id != 0 )
  1189.                     {
  1190.                         i_group = i_group_id;
  1191.                     }
  1192.                     else
  1193.                     {
  1194.                         playlist_group_t *p_group =
  1195.                                 playlist_CreateGroup( p_playlist,
  1196.                                            p_sd->pp_attributes[i]->psz_value );
  1197.                         i_group = p_group->i_id;
  1198.                     }
  1199.                 }
  1200.                 if( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "packetsize" ) )
  1201.                 {
  1202.                     i_packetsize = strtol( p_sd->pp_attributes[i]->psz_value, NULL, 10 );
  1203.                 }
  1204.             }
  1205.             /* Filling psz_uri */
  1206.             if( b_http == VLC_FALSE )
  1207.             {
  1208.                 if( ismult( psz_uri ) )
  1209.                 {
  1210.                     asprintf( &psz_item_uri, "%s://@%s:%s",
  1211.                              psz_proto, psz_uri, psz_port );
  1212.                 }
  1213.                 else
  1214.                 {
  1215.                     asprintf( &psz_item_uri, "%s://%s:%s",
  1216.                              psz_proto, psz_uri, psz_port );
  1217.                 }
  1218.             }
  1219.             else
  1220.             {
  1221.                 if( psz_http_path == NULL )
  1222.                 {
  1223.                     psz_http_path = strdup( "/" );
  1224.                 }
  1225.                 if( *psz_http_path == '/' )
  1226.                 {
  1227.                     asprintf( &psz_item_uri, "%s://%s:%s%s", psz_proto,
  1228.                              psz_uri, psz_port,psz_http_path );
  1229.                 }
  1230.                 else
  1231.                 {
  1232.                     asprintf( &psz_item_uri, "%s://%s:%s/%s", psz_proto, psz_uri,
  1233.                               psz_port, psz_http_path );
  1234.                 }
  1235.                 if( psz_http_path )
  1236.                 {
  1237.                     free( psz_http_path );
  1238.                 }
  1239.             }
  1240.             /* Add the item in the playlist */
  1241.             p_item = playlist_ItemNew( p_demux, psz_item_uri, p_sd->psz_sessionname );
  1242.             if( p_item )
  1243.             {
  1244.                 playlist_ItemSetGroup( p_item, i_group );
  1245.                 if( i_packetsize > config_GetInt( p_demux, "mtu" ) )
  1246.                 {
  1247.                     char *psz_packetsize_option;
  1248.                     asprintf( &psz_packetsize_option, "mtu=%i", i_packetsize );
  1249.                     playlist_ItemAddOption( p_item, psz_packetsize_option );
  1250.                     free( psz_packetsize_option );
  1251.                 }
  1252.                 playlist_AddItem( p_playlist , p_item , PLAYLIST_CHECK_INSERT, i_position );
  1253.             }
  1254.             free( psz_item_uri );
  1255.         }
  1256.         free_sd ( p_sd );
  1257.     }
  1258.     vlc_object_release( p_playlist );
  1259.     return 0;
  1260. }    
  1261. static int Control( demux_t *p_demux, int i_query, va_list args )
  1262. {
  1263.     return VLC_EGENERIC;
  1264. }
  1265. static void CloseSDP( vlc_object_t *p_this )
  1266. {
  1267. }