Changeset 21a5355e90f0c957c727201e5686c7892754c5c5

Show
Ignore:
Timestamp:
23/08/07 18:40:00 (1 year ago)
Author:
Rémi Denis-Courmont <rem@videolan.org>
git-committer:
Rémi Denis-Courmont <rem@videolan.org> 1187887200 +0000
git-parent:

[f7c53756ee7e8bb83b44989773621be887e26305]

git-author:
Rémi Denis-Courmont <rem@videolan.org> 1187887200 +0000
Message:

Split RTP sout into multiple pieces.
Even then rtp.c is quite big...

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • modules/stream_out/Modules.am

    r83a3429 r21a5355  
    77SOURCES_stream_out_display = display.c 
    88SOURCES_stream_out_gather = gather.c 
    9 SOURCES_stream_out_rtp = rtp.c 
     9SOURCES_stream_out_rtp = rtp.c rtp.h rtsp.c 
    1010SOURCES_stream_out_switcher = switcher.c 
    1111SOURCES_stream_out_bridge = bridge.c 
  • modules/stream_out/rtp.c

    r70925d8 r21a5355  
    4141#include <vlc_charset.h> 
    4242#include <vlc_strings.h> 
     43 
     44#include "rtp.h" 
    4345 
    4446/***************************************************************************** 
     
    157159                               block_t* ); 
    158160 
    159 /* For unicast/interleaved streaming */ 
    160 typedef struct 
    161 { 
    162     char    *psz_session; 
    163     int64_t i_last; /* for timeout */ 
    164  
    165     /* is it in "play" state */ 
    166     vlc_bool_t b_playing; 
    167  
    168     /* output (id-access) */ 
    169     int               i_id; 
    170     sout_stream_id_t  **id; 
    171     int               i_access; 
    172     sout_access_out_t **access; 
    173 } rtsp_client_t; 
    174  
    175161struct sout_stream_sys_t 
    176162{ 
     
    232218}; 
    233219 
    234 typedef int (*pf_rtp_packetizer_t)( sout_stream_t *, sout_stream_id_t *, 
    235                                     block_t * ); 
    236  
    237 struct sout_stream_id_t 
    238 { 
    239     sout_stream_t *p_stream; 
    240     /* rtp field */ 
    241     uint8_t     i_payload_type; 
    242     uint16_t    i_sequence; 
    243     uint32_t    i_timestamp_start; 
    244     uint8_t     ssrc[4]; 
    245  
    246     /* for sdp */ 
    247     int         i_clock_rate; 
    248     char        *psz_rtpmap; 
    249     char        *psz_fmtp; 
    250     char        *psz_destination; 
    251     int         i_port; 
    252     int         i_cat; 
    253     int         i_bitrate; 
    254  
    255     /* Packetizer specific fields */ 
    256     pf_rtp_packetizer_t pf_packetize; 
    257     int           i_mtu; 
    258  
    259     /* for sending the packets */ 
    260     sout_access_out_t *p_access; 
    261  
    262     vlc_mutex_t       lock_rtsp; 
    263     int               i_rtsp_access; 
    264     sout_access_out_t **rtsp_access; 
    265  
    266     /* */ 
    267     sout_input_t      *p_input; 
    268  
    269     /* RTSP url control */ 
    270     httpd_url_t  *p_rtsp_url; 
    271 }; 
    272  
    273220static int AccessOutGrabberWrite( sout_access_out_t *, block_t * ); 
    274221 
     
    278225static int FileSetup( sout_stream_t *p_stream ); 
    279226static int HttpSetup( sout_stream_t *p_stream, vlc_url_t * ); 
    280 static int RtspSetup( sout_stream_t *p_stream, vlc_url_t * ); 
    281  
    282 static int  RtspCallback( httpd_callback_sys_t *, httpd_client_t *, 
    283                           httpd_message_t *, httpd_message_t * ); 
    284 static int  RtspCallbackId( httpd_callback_sys_t *, httpd_client_t *, 
    285                             httpd_message_t *, httpd_message_t * ); 
    286  
    287  
    288 static rtsp_client_t *RtspClientNew( sout_stream_t *, const char *psz_session ); 
    289 static rtsp_client_t *RtspClientGet( sout_stream_t *, const char *psz_session ); 
    290 static void           RtspClientDel( sout_stream_t *, rtsp_client_t * ); 
    291227 
    292228/***************************************************************************** 
     
    761697           a= x-plgroup: (missing) 
    762698           RTP packets need to get the correct src IP address  */ 
    763 static char *SDPGenerate( const sout_stream_t *p_stream, 
     699/*static*/ char *SDPGenerate( const sout_stream_t *p_stream, 
    764700                          const char *psz_destination, vlc_bool_t b_rtsp ) 
    765701{ 
     
    15401476 
    15411477/**************************************************************************** 
    1542  * RTSP: 
    1543  ****************************************************************************/ 
    1544 static rtsp_client_t *RtspClientNew( sout_stream_t *p_stream, const char *psz_session ) 
    1545 { 
    1546     rtsp_client_t *rtsp = malloc( sizeof( rtsp_client_t )); 
    1547  
    1548     rtsp->psz_session = strdup( psz_session ); 
    1549     rtsp->i_last = 0; 
    1550     rtsp->b_playing = VLC_FALSE; 
    1551     rtsp->i_id = 0; 
    1552     rtsp->id = NULL; 
    1553     rtsp->i_access = 0; 
    1554     rtsp->access = NULL; 
    1555  
    1556     TAB_APPEND( p_stream->p_sys->i_rtsp, p_stream->p_sys->rtsp, rtsp ); 
    1557  
    1558     return rtsp; 
    1559 } 
    1560 static rtsp_client_t *RtspClientGet( sout_stream_t *p_stream, const char *psz_session ) 
    1561 { 
    1562     int i; 
    1563  
    1564     if( !psz_session ) return NULL; 
    1565  
    1566     for( i = 0; i < p_stream->p_sys->i_rtsp; i++ ) 
    1567     { 
    1568         if( !strcmp( p_stream->p_sys->rtsp[i]->psz_session, psz_session ) ) 
    1569         { 
    1570             return p_stream->p_sys->rtsp[i]; 
    1571         } 
    1572     } 
    1573     return NULL; 
    1574 } 
    1575  
    1576 static void RtspClientDel( sout_stream_t *p_stream, rtsp_client_t *rtsp ) 
    1577 { 
    1578     int i; 
    1579     TAB_REMOVE( p_stream->p_sys->i_rtsp, p_stream->p_sys->rtsp, rtsp ); 
    1580  
    1581     for( i = 0; i < rtsp->i_access; i++ ) 
    1582     { 
    1583         sout_AccessOutDelete( rtsp->access[i] ); 
    1584     } 
    1585     if( rtsp->id )     free( rtsp->id ); 
    1586     if( rtsp->access ) free( rtsp->access ); 
    1587  
    1588     free( rtsp->psz_session ); 
    1589     free( rtsp ); 
    1590 } 
    1591  
    1592 static int RtspSetup( sout_stream_t *p_stream, vlc_url_t *url ) 
    1593 { 
    1594     sout_stream_sys_t *p_sys = p_stream->p_sys; 
    1595  
    1596     msg_Dbg( p_stream, "rtsp setup: %s : %d / %s\n", url->psz_host, url->i_port, url->psz_path ); 
    1597  
    1598     p_sys->p_rtsp_host = httpd_HostNew( VLC_OBJECT(p_stream), url->psz_host, url->i_port > 0 ? url->i_port : 554 ); 
    1599     if( p_sys->p_rtsp_host == NULL ) 
    1600     { 
    1601         return VLC_EGENERIC; 
    1602     } 
    1603  
    1604     p_sys->psz_rtsp_path = strdup( url->psz_path ? url->psz_path : "/" ); 
    1605     p_sys->psz_rtsp_control = malloc (strlen( url->psz_host ) + 20 + strlen( p_sys->psz_rtsp_path ) + 1 ); 
    1606     sprintf( p_sys->psz_rtsp_control, "rtsp://%s:%d%s", 
    1607              url->psz_host,  url->i_port > 0 ? url->i_port : 554, p_sys->psz_rtsp_path ); 
    1608  
    1609     p_sys->p_rtsp_url = httpd_UrlNewUnique( p_sys->p_rtsp_host, p_sys->psz_rtsp_path, NULL, NULL, NULL ); 
    1610     if( p_sys->p_rtsp_url == 0 ) 
    1611     { 
    1612         return VLC_EGENERIC; 
    1613     } 
    1614     httpd_UrlCatch( p_sys->p_rtsp_url, HTTPD_MSG_DESCRIBE, RtspCallback, (void*)p_stream ); 
    1615     httpd_UrlCatch( p_sys->p_rtsp_url, HTTPD_MSG_SETUP,    RtspCallback, (void*)p_stream ); 
    1616     httpd_UrlCatch( p_sys->p_rtsp_url, HTTPD_MSG_PLAY,     RtspCallback, (void*)p_stream ); 
    1617     httpd_UrlCatch( p_sys->p_rtsp_url, HTTPD_MSG_PAUSE,    RtspCallback, (void*)p_stream ); 
    1618     httpd_UrlCatch( p_sys->p_rtsp_url, HTTPD_MSG_TEARDOWN, RtspCallback, (void*)p_stream ); 
    1619  
    1620     return VLC_SUCCESS; 
    1621 } 
    1622  
    1623 static int  RtspCallback( httpd_callback_sys_t *p_args, 
    1624                           httpd_client_t *cl, 
    1625                           httpd_message_t *answer, httpd_message_t *query ) 
    1626 { 
    1627     sout_stream_t *p_stream = (sout_stream_t*)p_args; 
    1628     sout_stream_sys_t *p_sys = p_stream->p_sys; 
    1629     char *psz_destination = p_sys->psz_destination; 
    1630     const char *psz_session = NULL; 
    1631     const char *psz_cseq = NULL; 
    1632  
    1633     if( answer == NULL || query == NULL ) 
    1634     { 
    1635         return VLC_SUCCESS; 
    1636     } 
    1637     //fprintf( stderr, "RtspCallback query: type=%d\n", query->i_type ); 
    1638  
    1639     answer->i_proto = HTTPD_PROTO_RTSP; 
    1640     answer->i_version= query->i_version; 
    1641     answer->i_type   = HTTPD_MSG_ANSWER; 
    1642     answer->i_body = 0; 
    1643     answer->p_body = NULL; 
    1644  
    1645     if( httpd_MsgGet( query, "Require" ) != NULL ) 
    1646     { 
    1647         answer->i_status = 551; 
    1648         httpd_MsgAdd( query, "Unsupported", "%s", 
    1649                       httpd_MsgGet( query, "Require" ) ); 
    1650     } 
    1651     else 
    1652     switch( query->i_type ) 
    1653     { 
    1654         case HTTPD_MSG_DESCRIBE: 
    1655         { 
    1656             char *psz_sdp = SDPGenerate( p_stream, psz_destination, VLC_TRUE ); 
    1657  
    1658             answer->i_status = 200; 
    1659             httpd_MsgAdd( answer, "Content-Type",  "%s", "application/sdp" ); 
    1660             httpd_MsgAdd( answer, "Content-Base",  "%s", p_sys->psz_rtsp_control ); 
    1661             answer->p_body = (uint8_t *)psz_sdp; 
    1662             answer->i_body = strlen( psz_sdp ); 
    1663             break; 
    1664         } 
    1665  
    1666         case HTTPD_MSG_SETUP: 
    1667             answer->i_status = 459; 
    1668             break; 
    1669  
    1670         case HTTPD_MSG_PLAY: 
    1671         { 
    1672             rtsp_client_t *rtsp; 
    1673             /* for now only multicast so easy */ 
    1674             answer->i_status = 200; 
    1675  
    1676             psz_session = httpd_MsgGet( query, "Session" ); 
    1677             rtsp = RtspClientGet( p_stream, psz_session ); 
    1678             if( rtsp && !rtsp->b_playing ) 
    1679             { 
    1680                 int i_id; 
    1681                 /* FIXME */ 
    1682                 rtsp->b_playing = VLC_TRUE; 
    1683  
    1684                 vlc_mutex_lock( &p_sys->lock_es ); 
    1685                 for( i_id = 0; i_id < rtsp->i_id; i_id++ ) 
    1686                 { 
    1687                     sout_stream_id_t *id = rtsp->id[i_id]; 
    1688                     int i; 
    1689  
    1690                     for( i = 0; i < p_sys->i_es; i++ ) 
    1691                     { 
    1692                         if( id == p_sys->es[i] ) 
    1693                             break; 
    1694                     } 
    1695                     if( i >= p_sys->i_es ) continue; 
    1696  
    1697                     vlc_mutex_lock( &id->lock_rtsp ); 
    1698                     TAB_APPEND( id->i_rtsp_access, id->rtsp_access, rtsp->access[i_id] ); 
    1699                     vlc_mutex_unlock( &id->lock_rtsp ); 
    1700                 } 
    1701                 vlc_mutex_unlock( &p_sys->lock_es ); 
    1702             } 
    1703             break; 
    1704         } 
    1705  
    1706         case HTTPD_MSG_PAUSE: 
    1707             answer->i_status = 405; 
    1708             httpd_MsgAdd( answer, "Allow", "DESCRIBE, PLAY, TEARDOWN" ); 
    1709             break; 
    1710  
    1711         case HTTPD_MSG_TEARDOWN: 
    1712         { 
    1713             rtsp_client_t *rtsp; 
    1714  
    1715             /* for now only multicast so easy again */ 
    1716             answer->i_status = 200; 
    1717  
    1718             psz_session = httpd_MsgGet( query, "Session" ); 
    1719             rtsp = RtspClientGet( p_stream, psz_session ); 
    1720             if( rtsp ) 
    1721             { 
    1722                 int i_id; 
    1723  
    1724                 vlc_mutex_lock( &p_sys->lock_es ); 
    1725                 for( i_id = 0; i_id < rtsp->i_id; i_id++ ) 
    1726                 { 
    1727                     sout_stream_id_t *id = rtsp->id[i_id]; 
    1728                     int i; 
    1729  
    1730                     for( i = 0; i < p_sys->i_es; i++ ) 
    1731                     { 
    1732                         if( id == p_sys->es[i] ) 
    1733                             break; 
    1734                     } 
    1735                     if( i >= p_sys->i_es ) continue; 
    1736  
    1737                     vlc_mutex_lock( &id->lock_rtsp ); 
    1738                     TAB_REMOVE( id->i_rtsp_access, id->rtsp_access, rtsp->access[i_id] ); 
    1739                     vlc_mutex_unlock( &id->lock_rtsp ); 
    1740                 } 
    1741                 vlc_mutex_unlock( &p_sys->lock_es ); 
    1742  
    1743                 RtspClientDel( p_stream, rtsp ); 
    1744             } 
    1745             break; 
    1746         } 
    1747  
    1748         default: 
    1749             return VLC_EGENERIC; 
    1750     } 
    1751  
    1752     httpd_MsgAdd( answer, "Server", "%s", PACKAGE_STRING ); 
    1753     httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); 
    1754     psz_cseq = httpd_MsgGet( query, "Cseq" ); 
    1755     if( psz_cseq ) 
    1756         httpd_MsgAdd( answer, "Cseq", "%s", psz_cseq ); 
    1757     httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" ); 
    1758  
    1759     if( psz_session ) 
    1760         httpd_MsgAdd( answer, "Session", "%s;timeout=5", psz_session ); 
    1761     return VLC_SUCCESS; 
    1762 } 
    1763  
    1764  
    1765 /** Finds the next transport choice */ 
    1766 static inline const char *transport_next( const char *str ) 
    1767 { 
    1768     /* Looks for comma */ 
    1769     str = strchr( str, ',' ); 
    1770     if( str == NULL ) 
    1771         return NULL; /* No more transport options */ 
    1772  
    1773     str++; /* skips comma */ 
    1774     while( strchr( "\r\n\t ", *str ) ) 
    1775         str++; 
    1776  
    1777     return (*str) ? str : NULL; 
    1778 } 
    1779  
    1780  
    1781 /** Finds the next transport parameter */ 
    1782 static inline const char *parameter_next( const char *str ) 
    1783 { 
    1784     while( strchr( ",;", *str ) == NULL ) 
    1785         str++; 
    1786  
    1787     return (*str == ';') ? (str + 1) : NULL; 
    1788 } 
    1789  
    1790  
    1791 static int RtspCallbackId( httpd_callback_sys_t *p_args, 
    1792                            httpd_client_t *cl, 
    1793                            httpd_message_t *answer, httpd_message_t *query ) 
    1794 { 
    1795     sout_stream_id_t *id = (sout_stream_id_t*)p_args; 
    1796     sout_stream_t    *p_stream = id->p_stream; 
    1797     sout_stream_sys_t *p_sys = p_stream->p_sys; 
    1798     char psz_session_init[21]; 
    1799     const char *psz_session; 
    1800     const char *psz_cseq; 
    1801  
    1802     if( answer == NULL || query == NULL ) 
    1803         return VLC_SUCCESS; 
    1804     //fprintf( stderr, "RtspCallback query: type=%d\n", query->i_type ); 
    1805  
    1806     /* */ 
    1807     answer->i_proto = HTTPD_PROTO_RTSP; 
    1808     answer->i_version= query->i_version; 
    1809     answer->i_type   = HTTPD_MSG_ANSWER; 
    1810     answer->i_body = 0; 
    1811     answer->p_body = NULL; 
    1812  
    1813     /* Create new session ID if needed */ 
    1814     psz_session = httpd_MsgGet( query, "Session" ); 
    1815     if( psz_session == NULL ) 
    1816     { 
    1817         /* FIXME: should be somewhat secure randomness */ 
    1818         snprintf( psz_session_init, sizeof(psz_session_init), I64Fd, 
    1819                   NTPtime64() + rand() ); 
    1820     } 
    1821  
    1822     if( httpd_MsgGet( query, "Require" ) != NULL ) 
    1823     { 
    1824         answer->i_status = 551; 
    1825         httpd_MsgAdd( query, "Unsupported", "%s", 
    1826                       httpd_MsgGet( query, "Require" ) ); 
    1827     } 
    1828     else 
    1829     switch( query->i_type ) 
    1830     { 
    1831         case HTTPD_MSG_SETUP: 
    1832         { 
    1833             answer->i_status = 461; 
    1834  
    1835             for( const char *tpt = httpd_MsgGet( query, "Transport" ); 
    1836                  tpt != NULL; 
    1837                  tpt = transport_next( tpt ) ) 
    1838             { 
    1839                 vlc_bool_t b_multicast = VLC_TRUE, b_unsupp = VLC_FALSE; 
    1840                 unsigned loport = 5004, hiport = 5005; /* from RFC3551 */ 
    1841  
    1842                 /* Check transport protocol. */ 
    1843                 /* Currently, we only support RTP/AVP over UDP */ 
    1844                 if( strncmp( tpt, "RTP/AVP", 7 ) ) 
    1845                     continue; 
    1846                 tpt += 7; 
    1847                 if( strncmp( tpt, "/UDP", 4 ) == 0 ) 
    1848                     tpt += 4; 
    1849                 if( strchr( ";,", *tpt ) == NULL ) 
    1850                     continue; 
    1851  
    1852                 /* Parse transport options */ 
    1853                 for( const char *opt = parameter_next( tpt ); 
    1854                      opt != NULL; 
    1855                      opt = parameter_next( opt ) ) 
    1856                 { 
    1857                     if( strncmp( opt, "multicast", 9 ) == 0) 
    1858                         b_multicast = VLC_TRUE; 
    1859                     else 
    1860                     if( strncmp( opt, "unicast", 7 ) == 0 ) 
    1861                         b_multicast = VLC_FALSE; 
    1862                     else 
    1863                     if( sscanf( opt, "client_port=%u-%u", &loport, &hiport ) == 2 ) 
    1864                         ; 
    1865                     else 
    1866                     if( strncmp( opt, "mode=", 5 ) == 0 ) 
    1867                     { 
    1868                         if( strncasecmp( opt + 5, "play", 4 ) 
    1869                          && strncasecmp( opt + 5, "\"PLAY\"", 6 ) ) 
    1870                         { 
    1871                             /* Not playing?! */ 
    1872                             b_unsupp = VLC_TRUE; 
    1873                             break; 
    1874                         } 
    1875                     } 
    1876                     else 
    1877                     { 
    1878                     /* 
    1879                      * Every other option is unsupported: 
    1880                      * 
    1881                      * "source" and "append" are invalid. 
    1882                      * 
    1883                      * For multicast, "port", "layers", "ttl" are set by the 
    1884                      * stream output configuration. 
    1885                      * 
    1886                      * For unicast, we do not allow "destination" as it 
    1887                      * carries a DoS risk, and we decide on "server_port". 
    1888                      * 
    1889                      * "interleaved" and "ssrc" are not implemented. 
    1890                      */ 
    1891                         b_unsupp = VLC_TRUE; 
    1892                         break; 
    1893                     } 
    1894                 } 
    1895  
    1896                 if( b_unsupp ) 
    1897                     continue; 
    1898  
    1899                 if( b_multicast ) 
    1900                 { 
    1901                     if( id->psz_destination == NULL ) 
    1902                         continue; 
    1903  
    1904                     answer->i_status = 200; 
    1905  
    1906                     httpd_MsgAdd( answer, "Transport", 
    1907                                   "RTP/AVP/UDP;destination=%s;port=%d-%d;" 
    1908                                   "ttl=%d;mode=play", 
    1909                                   id->psz_destination, id->i_port, id->i_port+1, 
    1910                                   ( p_sys->i_ttl > 0 ) ? p_sys->i_ttl : 1 ); 
    1911                 } 
    1912                 else 
    1913                 { 
    1914                     char ip[NI_MAXNUMERICHOST], psz_access[22], 
    1915                          url[NI_MAXNUMERICHOST + 8]; 
    1916                     sout_access_out_t *p_access; 
    1917                     rtsp_client_t *rtsp = NULL; 
    1918  
    1919                     if( ( hiport - loport ) > 1 ) 
    1920                         continue; 
    1921  
    1922                     if( psz_session == NULL ) 
    1923                     { 
    1924                         psz_session = psz_session_init; 
    1925                         rtsp = RtspClientNew( p_stream, psz_session ); 
    1926                     } 
    1927                     else 
    1928                     { 
    1929                         /* FIXME: we probably need to remove an access out, 
    1930                          * if there is already one for the same ID */ 
    1931                         rtsp = RtspClientGet( p_stream, psz_session ); 
    1932                         if( rtsp == NULL ) 
    1933                         { 
    1934                             answer->i_status = 454; 
    1935                             continue; 
    1936                         } 
    1937                     } 
    1938  
    1939                     if( httpd_ClientIP( cl, ip ) == NULL ) 
    1940                     { 
    1941                         answer->i_status = 500; 
    1942                         continue; 
    1943                     } 
    1944  
    1945                     if( p_sys->i_ttl ) 
    1946                         snprintf( psz_access, sizeof( psz_access ), 
    1947                                   "udp{raw,rtcp,ttl=%d}", p_sys->i_ttl ); 
    1948                     else 
    1949                         strcpy( psz_access, "udp{raw,rtcp}" ); 
    1950  
    1951                     snprintf( url, sizeof( url ), 
    1952                               ( strchr( ip, ':' ) != NULL ) ? "[%s]:%d" : "%s:%d", 
    1953                               ip, loport ); 
    1954  
    1955                     p_access = sout_AccessOutNew( p_stream->p_sout, 
    1956                                                   psz_access, url ); 
    1957                     if( p_access == NULL ) 
    1958                     { 
    1959                         msg_Err( p_stream, 
    1960                                  "cannot create access output for %s://%s", 
    1961                                  psz_access, url ); 
    1962                         answer->i_status = 500; 
    1963                         break; 
    1964                     } 
    1965  
    1966                     TAB_APPEND( rtsp->i_id, rtsp->id, id ); 
    1967                     TAB_APPEND( rtsp->i_access, rtsp->access, p_access ); 
    1968  
    1969                     char *src = var_GetNonEmptyString (p_access, "src-addr"); 
    1970                     int sport = var_GetInteger (p_access, "src-port"); 
    1971  
    1972                     httpd_ServerIP( cl, ip ); 
    1973  
    1974                     if( ( src != NULL ) && strcmp( src, ip ) ) 
    1975                     { 
    1976                         /* Specify source IP if it is different from the RTSP 
    1977                          * control connection server address */ 
    1978                         char *ptr = strchr( src, '%' ); 
    1979                         if( ptr != NULL ) *ptr = '\0'; /* remove scope ID */ 
    1980  
    1981                         httpd_MsgAdd( answer, "Transport", 
    1982                                       "RTP/AVP/UDP;unicast;source=%s;" 
    1983                                       "client_port=%u-%u;server_port=%u-%u;" 
    1984                                       "mode=play", 
    1985                                       src, loport, hiport, sport, sport + 1 ); 
    1986                     } 
    1987                     else 
    1988                     { 
    1989                         httpd_MsgAdd( answer, "Transport", 
    1990                                       "RTP/AVP/UDP;unicast;" 
    1991                                       "client_port=%u-%u;server_port=%u-%u;" 
    1992                                       "mode=play", 
    1993                                       loport, hiport, sport, sport + 1 ); 
    1994                     } 
    1995  
    1996                     answer->i_status = 200; 
    1997                     free( src ); 
    1998                 } 
    1999                 break; 
    2000             } 
    2001             break; 
    2002         } 
    2003  
    2004         default: 
    2005             answer->i_status = 460; 
    2006             break; 
    2007     } 
    2008  
    2009     psz_cseq = httpd_MsgGet( query, "Cseq" ); 
    2010     if( psz_cseq ) 
    2011         httpd_MsgAdd( answer, "Cseq", "%s", psz_cseq ); 
    2012     httpd_MsgAdd( answer, "Server", "%s", PACKAGE_STRING ); 
    2013     httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); 
    2014     httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" ); 
    2015  
    2016     if( psz_session ) 
    2017         httpd_MsgAdd( answer, "Session", "%s"/*;timeout=5*/, psz_session ); 
    2018     return VLC_SUCCESS; 
    2019 } 
    2020  
    2021 /**************************************************************************** 
    20221478 * rtp_packetize_*: 
    20231479 ****************************************************************************/