| 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 | | /**************************************************************************** |
|---|