Changeset 3982 for pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c
- Timestamp:
- Mar 22, 2012 9:56:52 AM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c
r3975 r3982 23 23 #include <pjmedia/rtcp.h> 24 24 #include <pjmedia/jbuf.h> 25 #include <pjmedia/sdp_neg.h>26 25 #include <pjmedia/stream_common.h> 27 26 #include <pj/array.h> 28 27 #include <pj/assert.h> 29 #include <pj/ctype.h>30 28 #include <pj/compat/socket.h> 31 29 #include <pj/errno.h> … … 1791 1789 } 1792 1790 1793 1794 static const pj_str_t ID_VIDEO = { "video", 5};1795 static const pj_str_t ID_IN = { "IN", 2 };1796 static const pj_str_t ID_IP4 = { "IP4", 3};1797 static const pj_str_t ID_IP6 = { "IP6", 3};1798 static const pj_str_t ID_RTP_AVP = { "RTP/AVP", 7 };1799 static const pj_str_t ID_RTP_SAVP = { "RTP/SAVP", 8 };1800 //static const pj_str_t ID_SDP_NAME = { "pjmedia", 7 };1801 static const pj_str_t ID_RTPMAP = { "rtpmap", 6 };1802 1803 static const pj_str_t STR_INACTIVE = { "inactive", 8 };1804 static const pj_str_t STR_SENDRECV = { "sendrecv", 8 };1805 static const pj_str_t STR_SENDONLY = { "sendonly", 8 };1806 static const pj_str_t STR_RECVONLY = { "recvonly", 8 };1807 1808 1809 /*1810 * Internal function for collecting codec info and param from the SDP media.1811 */1812 static pj_status_t get_video_codec_info_param(pjmedia_vid_stream_info *si,1813 pj_pool_t *pool,1814 pjmedia_vid_codec_mgr *mgr,1815 const pjmedia_sdp_media *local_m,1816 const pjmedia_sdp_media *rem_m)1817 {1818 unsigned pt = 0;1819 const pjmedia_vid_codec_info *p_info;1820 pj_status_t status;1821 1822 pt = pj_strtoul(&local_m->desc.fmt[0]);1823 1824 /* Get payload type for receiving direction */1825 si->rx_pt = pt;1826 1827 /* Get codec info and payload type for transmitting direction. */1828 if (pt < 96) {1829 /* For static payload types, get the codec info from codec manager. */1830 status = pjmedia_vid_codec_mgr_get_codec_info(mgr, pt, &p_info);1831 if (status != PJ_SUCCESS)1832 return status;1833 1834 si->codec_info = *p_info;1835 1836 /* Get payload type for transmitting direction.1837 * For static payload type, pt's are symetric.1838 */1839 si->tx_pt = pt;1840 } else {1841 const pjmedia_sdp_attr *attr;1842 pjmedia_sdp_rtpmap *rtpmap;1843 pjmedia_codec_id codec_id;1844 pj_str_t codec_id_st;1845 unsigned i;1846 1847 /* Determine payload type for outgoing channel, by finding1848 * dynamic payload type in remote SDP that matches the answer.1849 */1850 si->tx_pt = 0xFFFF;1851 for (i=0; i<rem_m->desc.fmt_count; ++i) {1852 if (pjmedia_sdp_neg_fmt_match(NULL,1853 (pjmedia_sdp_media*)local_m, 0,1854 (pjmedia_sdp_media*)rem_m, i, 0) ==1855 PJ_SUCCESS)1856 {1857 /* Found matched codec. */1858 si->tx_pt = pj_strtoul(&rem_m->desc.fmt[i]);1859 break;1860 }1861 }1862 1863 if (si->tx_pt == 0xFFFF)1864 return PJMEDIA_EMISSINGRTPMAP;1865 1866 /* For dynamic payload types, get codec name from the rtpmap */1867 attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP,1868 &local_m->desc.fmt[0]);1869 if (attr == NULL)1870 return PJMEDIA_EMISSINGRTPMAP;1871 1872 status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap);1873 if (status != PJ_SUCCESS)1874 return status;1875 1876 /* Then get the codec info from the codec manager */1877 pj_ansi_snprintf(codec_id, sizeof(codec_id), "%.*s/",1878 (int)rtpmap->enc_name.slen, rtpmap->enc_name.ptr);1879 codec_id_st = pj_str(codec_id);1880 i = 1;1881 status = pjmedia_vid_codec_mgr_find_codecs_by_id(mgr, &codec_id_st,1882 &i, &p_info, NULL);1883 if (status != PJ_SUCCESS)1884 return status;1885 1886 si->codec_info = *p_info;1887 }1888 1889 1890 /* Request for codec with the correct packing for streaming */1891 si->codec_info.packings = PJMEDIA_VID_PACKING_PACKETS;1892 1893 /* Now that we have codec info, get the codec param. */1894 si->codec_param = PJ_POOL_ALLOC_T(pool, pjmedia_vid_codec_param);1895 status = pjmedia_vid_codec_mgr_get_default_param(mgr,1896 &si->codec_info,1897 si->codec_param);1898 1899 /* Adjust encoding bitrate, if higher than remote preference. The remote1900 * bitrate preference is read from SDP "b=TIAS" line in media level.1901 */1902 if ((si->dir & PJMEDIA_DIR_ENCODING) && rem_m->bandw_count) {1903 unsigned i, bandw = 0;1904 1905 for (i = 0; i < rem_m->bandw_count; ++i) {1906 const pj_str_t STR_BANDW_MODIFIER_TIAS = { "TIAS", 4 };1907 if (!pj_stricmp(&rem_m->bandw[i]->modifier,1908 &STR_BANDW_MODIFIER_TIAS))1909 {1910 bandw = rem_m->bandw[i]->value;1911 break;1912 }1913 }1914 1915 if (bandw) {1916 pjmedia_video_format_detail *enc_vfd;1917 enc_vfd = pjmedia_format_get_video_format_detail(1918 &si->codec_param->enc_fmt, PJ_TRUE);1919 if (!enc_vfd->avg_bps || enc_vfd->avg_bps > bandw)1920 enc_vfd->avg_bps = bandw * 3 / 4;1921 if (!enc_vfd->max_bps || enc_vfd->max_bps > bandw)1922 enc_vfd->max_bps = bandw;1923 }1924 }1925 1926 /* Get remote fmtp for our encoder. */1927 pjmedia_stream_info_parse_fmtp(pool, rem_m, si->tx_pt,1928 &si->codec_param->enc_fmtp);1929 1930 /* Get local fmtp for our decoder. */1931 pjmedia_stream_info_parse_fmtp(pool, local_m, si->rx_pt,1932 &si->codec_param->dec_fmtp);1933 1934 /* When direction is NONE (it means SDP negotiation has failed) we don't1935 * need to return a failure here, as returning failure will cause1936 * the whole SDP to be rejected. See ticket #:1937 * http://1938 *1939 * Thanks Alain Totouom1940 */1941 if (status != PJ_SUCCESS && si->dir != PJMEDIA_DIR_NONE)1942 return status;1943 1944 return PJ_SUCCESS;1945 }1946 1947 1948 1949 /*1950 * Create stream info from SDP media line.1951 */1952 PJ_DEF(pj_status_t) pjmedia_vid_stream_info_from_sdp(1953 pjmedia_vid_stream_info *si,1954 pj_pool_t *pool,1955 pjmedia_endpt *endpt,1956 const pjmedia_sdp_session *local,1957 const pjmedia_sdp_session *remote,1958 unsigned stream_idx)1959 {1960 const pjmedia_sdp_attr *attr;1961 const pjmedia_sdp_media *local_m;1962 const pjmedia_sdp_media *rem_m;1963 const pjmedia_sdp_conn *local_conn;1964 const pjmedia_sdp_conn *rem_conn;1965 int rem_af, local_af;1966 pj_sockaddr local_addr;1967 pj_status_t status;1968 1969 PJ_UNUSED_ARG(endpt);1970 1971 /* Validate arguments: */1972 PJ_ASSERT_RETURN(pool && si && local && remote, PJ_EINVAL);1973 PJ_ASSERT_RETURN(stream_idx < local->media_count, PJ_EINVAL);1974 PJ_ASSERT_RETURN(stream_idx < remote->media_count, PJ_EINVAL);1975 1976 /* Keep SDP shortcuts */1977 local_m = local->media[stream_idx];1978 rem_m = remote->media[stream_idx];1979 1980 local_conn = local_m->conn ? local_m->conn : local->conn;1981 if (local_conn == NULL)1982 return PJMEDIA_SDP_EMISSINGCONN;1983 1984 rem_conn = rem_m->conn ? rem_m->conn : remote->conn;1985 if (rem_conn == NULL)1986 return PJMEDIA_SDP_EMISSINGCONN;1987 1988 /* Media type must be video */1989 if (pj_stricmp(&local_m->desc.media, &ID_VIDEO) != 0)1990 return PJMEDIA_EINVALIMEDIATYPE;1991 1992 1993 /* Reset: */1994 1995 pj_bzero(si, sizeof(*si));1996 1997 /* Media type: */1998 si->type = PJMEDIA_TYPE_VIDEO;1999 2000 /* Transport protocol */2001 2002 /* At this point, transport type must be compatible,2003 * the transport instance will do more validation later.2004 */2005 status = pjmedia_sdp_transport_cmp(&rem_m->desc.transport,2006 &local_m->desc.transport);2007 if (status != PJ_SUCCESS)2008 return PJMEDIA_SDPNEG_EINVANSTP;2009 2010 if (pj_stricmp(&local_m->desc.transport, &ID_RTP_AVP) == 0) {2011 2012 si->proto = PJMEDIA_TP_PROTO_RTP_AVP;2013 2014 } else if (pj_stricmp(&local_m->desc.transport, &ID_RTP_SAVP) == 0) {2015 2016 si->proto = PJMEDIA_TP_PROTO_RTP_SAVP;2017 2018 } else {2019 2020 si->proto = PJMEDIA_TP_PROTO_UNKNOWN;2021 return PJ_SUCCESS;2022 }2023 2024 2025 /* Check address family in remote SDP */2026 rem_af = pj_AF_UNSPEC();2027 if (pj_stricmp(&rem_conn->net_type, &ID_IN)==0) {2028 if (pj_stricmp(&rem_conn->addr_type, &ID_IP4)==0) {2029 rem_af = pj_AF_INET();2030 } else if (pj_stricmp(&rem_conn->addr_type, &ID_IP6)==0) {2031 rem_af = pj_AF_INET6();2032 }2033 }2034 2035 if (rem_af==pj_AF_UNSPEC()) {2036 /* Unsupported address family */2037 return PJ_EAFNOTSUP;2038 }2039 2040 /* Set remote address: */2041 status = pj_sockaddr_init(rem_af, &si->rem_addr, &rem_conn->addr,2042 rem_m->desc.port);2043 if (status != PJ_SUCCESS) {2044 /* Invalid IP address. */2045 return PJMEDIA_EINVALIDIP;2046 }2047 2048 /* Check address family of local info */2049 local_af = pj_AF_UNSPEC();2050 if (pj_stricmp(&local_conn->net_type, &ID_IN)==0) {2051 if (pj_stricmp(&local_conn->addr_type, &ID_IP4)==0) {2052 local_af = pj_AF_INET();2053 } else if (pj_stricmp(&local_conn->addr_type, &ID_IP6)==0) {2054 local_af = pj_AF_INET6();2055 }2056 }2057 2058 if (local_af==pj_AF_UNSPEC()) {2059 /* Unsupported address family */2060 return PJ_SUCCESS;2061 }2062 2063 /* Set remote address: */2064 status = pj_sockaddr_init(local_af, &local_addr, &local_conn->addr,2065 local_m->desc.port);2066 if (status != PJ_SUCCESS) {2067 /* Invalid IP address. */2068 return PJMEDIA_EINVALIDIP;2069 }2070 2071 /* Local and remote address family must match */2072 if (local_af != rem_af)2073 return PJ_EAFNOTSUP;2074 2075 /* Media direction: */2076 2077 if (local_m->desc.port == 0 ||2078 pj_sockaddr_has_addr(&local_addr)==PJ_FALSE ||2079 pj_sockaddr_has_addr(&si->rem_addr)==PJ_FALSE ||2080 pjmedia_sdp_media_find_attr(local_m, &STR_INACTIVE, NULL)!=NULL)2081 {2082 /* Inactive stream. */2083 2084 si->dir = PJMEDIA_DIR_NONE;2085 2086 } else if (pjmedia_sdp_media_find_attr(local_m, &STR_SENDONLY, NULL)!=NULL) {2087 2088 /* Send only stream. */2089 2090 si->dir = PJMEDIA_DIR_ENCODING;2091 2092 } else if (pjmedia_sdp_media_find_attr(local_m, &STR_RECVONLY, NULL)!=NULL) {2093 2094 /* Recv only stream. */2095 2096 si->dir = PJMEDIA_DIR_DECODING;2097 2098 } else {2099 2100 /* Send and receive stream. */2101 2102 si->dir = PJMEDIA_DIR_ENCODING_DECODING;2103 2104 }2105 2106 /* No need to do anything else if stream is rejected */2107 if (local_m->desc.port == 0) {2108 return PJ_SUCCESS;2109 }2110 2111 /* If "rtcp" attribute is present in the SDP, set the RTCP address2112 * from that attribute. Otherwise, calculate from RTP address.2113 */2114 attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,2115 "rtcp", NULL);2116 if (attr) {2117 pjmedia_sdp_rtcp_attr rtcp;2118 status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp);2119 if (status == PJ_SUCCESS) {2120 if (rtcp.addr.slen) {2121 status = pj_sockaddr_init(rem_af, &si->rem_rtcp, &rtcp.addr,2122 (pj_uint16_t)rtcp.port);2123 } else {2124 pj_sockaddr_init(rem_af, &si->rem_rtcp, NULL,2125 (pj_uint16_t)rtcp.port);2126 pj_memcpy(pj_sockaddr_get_addr(&si->rem_rtcp),2127 pj_sockaddr_get_addr(&si->rem_addr),2128 pj_sockaddr_get_addr_len(&si->rem_addr));2129 }2130 }2131 }2132 2133 if (!pj_sockaddr_has_addr(&si->rem_rtcp)) {2134 int rtcp_port;2135 2136 pj_memcpy(&si->rem_rtcp, &si->rem_addr, sizeof(pj_sockaddr));2137 rtcp_port = pj_sockaddr_get_port(&si->rem_addr) + 1;2138 pj_sockaddr_set_port(&si->rem_rtcp, (pj_uint16_t)rtcp_port);2139 }2140 2141 /* Get codec info and param */2142 status = get_video_codec_info_param(si, pool, NULL, local_m, rem_m);2143 2144 /* Leave SSRC to random. */2145 si->ssrc = pj_rand();2146 2147 /* Set default jitter buffer parameter. */2148 si->jb_init = si->jb_max = si->jb_min_pre = si->jb_max_pre = -1;2149 2150 return status;2151 }2152 2153 2154 1791 /* 2155 1792 * Force stream to send video keyframe.
Note: See TracChangeset
for help on using the changeset viewer.