Ignore:
Timestamp:
Mar 22, 2012 9:56:52 AM (8 years ago)
Author:
bennylp
Message:

Re: #1463 (Third party media support). Tnitial work and it works, tested on Linux. Details:

  • add PJSUA_MEDIA_HAS_PJMEDIA macro
  • move pjmedia specific implementation in pjsua_media.c and pjsua_call.c into pjsua_aud.c
  • add pjsip-apps/src/third_party_media sample containing:
    • alt_pjsua_aud.c
    • alt_pjsua_vid.c
  • moved pjmedia_vid_stream_info_from_sdp() into pjmedia/vid_stream_info.c
  • moved pjmedia_stream_info_from_sdp() into pjmedia/stream_info.c
  • misc: fixed mips_test.c if codecs are disabled
File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c

    r3975 r3982  
    2323#include <pjmedia/rtcp.h> 
    2424#include <pjmedia/jbuf.h> 
    25 #include <pjmedia/sdp_neg.h> 
    2625#include <pjmedia/stream_common.h> 
    2726#include <pj/array.h> 
    2827#include <pj/assert.h> 
    29 #include <pj/ctype.h> 
    3028#include <pj/compat/socket.h> 
    3129#include <pj/errno.h> 
     
    17911789} 
    17921790 
    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 finding 
    1848          * 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 remote 
    1900      * 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't 
    1935      * need to return a failure here, as returning failure will cause 
    1936      * the whole SDP to be rejected. See ticket #: 
    1937      *  http:// 
    1938      * 
    1939      * Thanks Alain Totouom  
    1940      */ 
    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 address 
    2112      * 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  
    21541791/* 
    21551792 * Force stream to send video keyframe. 
Note: See TracChangeset for help on using the changeset viewer.