Ignore:
Timestamp:
Jul 19, 2011 3:42:28 AM (11 years ago)
Author:
nanang
Message:

Re #1326: Initial code integration from branch 2.0-dev to trunk as "2.0-pre-alpha-svn".

Location:
pjproject/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk

  • pjproject/trunk/pjmedia/src/pjmedia/endpoint.c

    r3553 r3664  
    2121#include <pjmedia/errno.h> 
    2222#include <pjmedia/sdp.h> 
     23#include <pjmedia/vid_codec.h> 
    2324#include <pjmedia-audiodev/audiodev.h> 
    2425#include <pj/assert.h> 
     
    313314} 
    314315 
    315 /** 
    316  * Create a SDP session description that describes the endpoint 
    317  * capability. 
    318  */ 
    319 PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt, 
    320                                               pj_pool_t *pool, 
    321                                               unsigned stream_cnt, 
    322                                               const pjmedia_sock_info sock_info[], 
    323                                               pjmedia_sdp_session **p_sdp ) 
    324 { 
    325     pj_time_val tv; 
    326     unsigned i; 
    327     const pj_sockaddr *addr0; 
    328     pjmedia_sdp_session *sdp; 
    329     pjmedia_sdp_media *m; 
     316/* Common initialization for both audio and video SDP media line */ 
     317static pj_status_t init_sdp_media(pjmedia_sdp_media *m, 
     318                                  pj_pool_t *pool, 
     319                                  const pj_str_t *media_type, 
     320                                  const pjmedia_sock_info *sock_info) 
     321{ 
     322    char tmp_addr[PJ_INET6_ADDRSTRLEN]; 
    330323    pjmedia_sdp_attr *attr; 
    331  
    332     /* Sanity check arguments */ 
    333     PJ_ASSERT_RETURN(endpt && pool && p_sdp && stream_cnt, PJ_EINVAL); 
    334  
    335     /* Check that there are not too many codecs */ 
    336     PJ_ASSERT_RETURN(endpt->codec_mgr.codec_cnt <= PJMEDIA_MAX_SDP_FMT, 
    337                      PJ_ETOOMANY); 
    338  
    339     /* Create and initialize basic SDP session */ 
    340     sdp = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session); 
    341  
    342     addr0 = &sock_info[0].rtp_addr_name; 
    343  
    344     pj_gettimeofday(&tv); 
    345     sdp->origin.user = pj_str("-"); 
    346     sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL; 
    347     sdp->origin.net_type = STR_IN; 
    348  
    349     if (addr0->addr.sa_family == pj_AF_INET()) { 
    350         sdp->origin.addr_type = STR_IP4; 
    351         pj_strdup2(pool, &sdp->origin.addr,  
    352                    pj_inet_ntoa(addr0->ipv4.sin_addr)); 
    353     } else if (addr0->addr.sa_family == pj_AF_INET6()) { 
    354         char tmp_addr[PJ_INET6_ADDRSTRLEN]; 
    355  
    356         sdp->origin.addr_type = STR_IP6; 
    357         pj_strdup2(pool, &sdp->origin.addr,  
    358                    pj_sockaddr_print(addr0, tmp_addr, sizeof(tmp_addr), 0)); 
    359  
    360     } else { 
    361         pj_assert(!"Invalid address family"); 
    362         return PJ_EAFNOTSUP; 
    363     } 
    364  
    365     sdp->name = STR_SDP_NAME; 
    366  
    367     /* Since we only support one media stream at present, put the 
    368      * SDP connection line in the session level. 
    369      */ 
    370     sdp->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn); 
    371     sdp->conn->net_type = sdp->origin.net_type; 
    372     sdp->conn->addr_type = sdp->origin.addr_type; 
    373     sdp->conn->addr = sdp->origin.addr; 
    374  
    375  
    376     /* SDP time and attributes. */ 
    377     sdp->time.start = sdp->time.stop = 0; 
    378     sdp->attr_count = 0; 
    379  
    380     /* Create media stream 0: */ 
    381  
    382     sdp->media_count = 1; 
    383     m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media); 
    384     sdp->media[0] = m; 
    385  
    386     /* Standard media info: */ 
    387     pj_strdup(pool, &m->desc.media, &STR_AUDIO); 
    388     m->desc.port = pj_sockaddr_get_port(addr0); 
     324    const pj_sockaddr *addr; 
     325 
     326    pj_strdup(pool, &m->desc.media, media_type); 
     327 
     328    addr = &sock_info->rtp_addr_name; 
     329 
     330    /* Validate address family */ 
     331    PJ_ASSERT_RETURN(addr->addr.sa_family == pj_AF_INET() || 
     332                     addr->addr.sa_family == pj_AF_INET6(), 
     333                     PJ_EAFNOTSUP); 
     334 
     335    /* SDP connection line */ 
     336    m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn); 
     337    m->conn->net_type = STR_IN; 
     338    m->conn->addr_type = (addr->addr.sa_family==pj_AF_INET())? STR_IP4:STR_IP6; 
     339    pj_sockaddr_print(addr, tmp_addr, sizeof(tmp_addr), 0); 
     340    pj_strdup2(pool, &m->conn->addr, tmp_addr); 
     341 
     342    /* Port and transport in media description */ 
     343    m->desc.port = pj_sockaddr_get_port(addr); 
    389344    m->desc.port_count = 1; 
    390345    pj_strdup (pool, &m->desc.transport, &STR_RTP_AVP); 
    391  
    392     /* Init media line and attribute list. */ 
    393     m->desc.fmt_count = 0; 
    394     m->attr_count = 0; 
    395346 
    396347    /* Add "rtcp" attribute */ 
     
    403354#endif 
    404355 
     356    /* Add sendrecv attribute. */ 
     357    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr); 
     358    attr->name = STR_SENDRECV; 
     359    m->attr[m->attr_count++] = attr; 
     360 
     361    return PJ_SUCCESS; 
     362} 
     363 
     364/* Create m=audio SDP media line */ 
     365PJ_DEF(pj_status_t) pjmedia_endpt_create_audio_sdp(pjmedia_endpt *endpt, 
     366                                                   pj_pool_t *pool, 
     367                                                   const pjmedia_sock_info *si, 
     368                                                   unsigned options, 
     369                                                   pjmedia_sdp_media **p_m) 
     370{ 
     371    const pj_str_t STR_AUDIO = { "audio", 5 }; 
     372    pjmedia_sdp_media *m; 
     373    pjmedia_sdp_attr *attr; 
     374    unsigned i; 
     375    pj_status_t status; 
     376 
     377    PJ_UNUSED_ARG(options); 
     378 
     379    /* Check that there are not too many codecs */ 
     380    PJ_ASSERT_RETURN(endpt->codec_mgr.codec_cnt <= PJMEDIA_MAX_SDP_FMT, 
     381                     PJ_ETOOMANY); 
     382 
     383    /* Create and init basic SDP media */ 
     384    m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media); 
     385    status = init_sdp_media(m, pool, &STR_AUDIO, si); 
     386    if (status != PJ_SUCCESS) 
     387        return status; 
     388 
    405389    /* Add format, rtpmap, and fmtp (when applicable) for each codec */ 
    406390    for (i=0; i<endpt->codec_mgr.codec_cnt; ++i) { 
     
    409393        pjmedia_sdp_rtpmap rtpmap; 
    410394        char tmp_param[3]; 
    411         pjmedia_sdp_attr *attr; 
    412395        pjmedia_codec_param codec_param; 
    413396        pj_str_t *fmt; 
     
    513496    } 
    514497 
    515     /* Add sendrecv attribute. */ 
    516     attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr); 
    517     attr->name = STR_SENDRECV; 
    518     m->attr[m->attr_count++] = attr; 
    519  
    520498#if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \ 
    521499    PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0 
     
    542520#endif 
    543521 
     522    *p_m = m; 
     523    return PJ_SUCCESS; 
     524} 
     525 
     526/* Create m=video SDP media line */ 
     527PJ_DEF(pj_status_t) pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt, 
     528                                                   pj_pool_t *pool, 
     529                                                   const pjmedia_sock_info *si, 
     530                                                   unsigned options, 
     531                                                   pjmedia_sdp_media **p_m) 
     532{ 
     533    const pj_str_t STR_VIDEO = { "video", 5 }; 
     534    pjmedia_sdp_media *m; 
     535    pjmedia_vid_codec_info codec_info[PJMEDIA_VID_CODEC_MGR_MAX_CODECS]; 
     536    unsigned codec_prio[PJMEDIA_VID_CODEC_MGR_MAX_CODECS]; 
     537    pjmedia_sdp_attr *attr; 
     538    unsigned cnt, i; 
     539    pj_status_t status; 
     540 
     541    PJ_UNUSED_ARG(options); 
     542 
     543    /* Make sure video codec manager is instantiated */ 
     544    if (!pjmedia_vid_codec_mgr_instance()) 
     545        pjmedia_vid_codec_mgr_create(endpt->pool, NULL); 
     546 
     547    /* Create and init basic SDP media */ 
     548    m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media); 
     549    status = init_sdp_media(m, pool, &STR_VIDEO, si); 
     550    if (status != PJ_SUCCESS) 
     551        return status; 
     552 
     553    cnt = PJ_ARRAY_SIZE(codec_info); 
     554    status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &cnt,  
     555                                               codec_info, codec_prio); 
     556 
     557    /* Check that there are not too many codecs */ 
     558    PJ_ASSERT_RETURN(0 <= PJMEDIA_MAX_SDP_FMT, 
     559                     PJ_ETOOMANY); 
     560 
     561    /* Add format, rtpmap, and fmtp (when applicable) for each codec */ 
     562    for (i=0; i<cnt; ++i) { 
     563        pjmedia_sdp_rtpmap rtpmap; 
     564        pjmedia_vid_codec_param codec_param; 
     565        pj_str_t *fmt; 
     566 
     567        pj_bzero(&rtpmap, sizeof(rtpmap)); 
     568 
     569        if (codec_prio[i] == PJMEDIA_CODEC_PRIO_DISABLED) 
     570            break; 
     571 
     572        if (i > PJMEDIA_MAX_SDP_FMT) { 
     573            /* Too many codecs, perhaps it is better to tell application by 
     574             * returning appropriate status code. 
     575             */ 
     576            PJ_PERROR(3,(THIS_FILE, PJ_ETOOMANY, 
     577                        "Skipping some video codecs")); 
     578            break; 
     579        } 
     580 
     581        /* Must support RTP packetization and bidirectional */ 
     582        if (!codec_info[i].has_rtp_pack || 
     583            codec_info[i].dir != PJMEDIA_DIR_ENCODING_DECODING) 
     584        { 
     585            continue; 
     586        } 
     587 
     588        pjmedia_vid_codec_mgr_get_default_param(NULL, &codec_info[i], 
     589                                                &codec_param); 
     590 
     591        fmt = &m->desc.fmt[m->desc.fmt_count++]; 
     592        fmt->ptr = (char*) pj_pool_alloc(pool, 8); 
     593        fmt->slen = pj_utoa(codec_info[i].pt, fmt->ptr); 
     594        rtpmap.pt = *fmt; 
     595 
     596        /* Encoding name */ 
     597        rtpmap.enc_name = codec_info[i].encoding_name; 
     598 
     599        /* Clock rate */ 
     600        rtpmap.clock_rate = codec_info[i].clock_rate; 
     601 
     602        if (codec_info[i].pt >= 96 || pjmedia_add_rtpmap_for_static_pt) { 
     603            pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr); 
     604            m->attr[m->attr_count++] = attr; 
     605        } 
     606 
     607        /* Add fmtp params */ 
     608        if (codec_param.dec_fmtp.cnt > 0) { 
     609            enum { MAX_FMTP_STR_LEN = 160 }; 
     610            char buf[MAX_FMTP_STR_LEN]; 
     611            unsigned buf_len = 0, j; 
     612            pjmedia_codec_fmtp *dec_fmtp = &codec_param.dec_fmtp; 
     613 
     614            /* Print codec PT */ 
     615            buf_len += pj_ansi_snprintf(buf,  
     616                                        MAX_FMTP_STR_LEN - buf_len,  
     617                                        "%d",  
     618                                        codec_info[i].pt); 
     619 
     620            for (j = 0; j < dec_fmtp->cnt; ++j) { 
     621                unsigned test_len = 2; 
     622 
     623                /* Check if buf still available */ 
     624                test_len = dec_fmtp->param[j].val.slen +  
     625                           dec_fmtp->param[j].name.slen; 
     626                if (test_len + buf_len >= MAX_FMTP_STR_LEN) 
     627                    return PJ_ETOOBIG; 
     628 
     629                /* Print delimiter */ 
     630                buf_len += pj_ansi_snprintf(&buf[buf_len],  
     631                                            MAX_FMTP_STR_LEN - buf_len, 
     632                                            (j == 0?" ":";")); 
     633 
     634                /* Print an fmtp param */ 
     635                if (dec_fmtp->param[j].name.slen) 
     636                    buf_len += pj_ansi_snprintf( 
     637                                            &buf[buf_len], 
     638                                            MAX_FMTP_STR_LEN - buf_len, 
     639                                            "%.*s=%.*s", 
     640                                            (int)dec_fmtp->param[j].name.slen, 
     641                                            dec_fmtp->param[j].name.ptr, 
     642                                            (int)dec_fmtp->param[j].val.slen, 
     643                                            dec_fmtp->param[j].val.ptr); 
     644                else 
     645                    buf_len += pj_ansi_snprintf(&buf[buf_len],  
     646                                            MAX_FMTP_STR_LEN - buf_len, 
     647                                            "%.*s",  
     648                                            (int)dec_fmtp->param[j].val.slen, 
     649                                            dec_fmtp->param[j].val.ptr); 
     650            } 
     651 
     652            attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr); 
     653 
     654            attr->name = pj_str("fmtp"); 
     655            attr->value = pj_strdup3(pool, buf); 
     656            m->attr[m->attr_count++] = attr; 
     657        } 
     658    } 
     659 
     660    *p_m = m; 
     661    return PJ_SUCCESS; 
     662} 
     663 
     664 
     665/** 
     666 * Create a "blank" SDP session description. The SDP will contain basic SDP 
     667 * fields such as origin, time, and name, but without any media lines. 
     668 */ 
     669PJ_DEF(pj_status_t) pjmedia_endpt_create_base_sdp( pjmedia_endpt *endpt, 
     670                                                   pj_pool_t *pool, 
     671                                                   const pj_str_t *sess_name, 
     672                                                   const pj_sockaddr *origin, 
     673                                                   pjmedia_sdp_session **p_sdp) 
     674{ 
     675    pj_time_val tv; 
     676    pjmedia_sdp_session *sdp; 
     677 
     678    /* Sanity check arguments */ 
     679    PJ_ASSERT_RETURN(endpt && pool && p_sdp, PJ_EINVAL); 
     680 
     681    sdp = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session); 
     682 
     683    pj_gettimeofday(&tv); 
     684    sdp->origin.user = pj_str("-"); 
     685    sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL; 
     686    sdp->origin.net_type = STR_IN; 
     687 
     688    if (origin->addr.sa_family == pj_AF_INET()) { 
     689        sdp->origin.addr_type = STR_IP4; 
     690        pj_strdup2(pool, &sdp->origin.addr, 
     691                   pj_inet_ntoa(origin->ipv4.sin_addr)); 
     692    } else if (origin->addr.sa_family == pj_AF_INET6()) { 
     693        char tmp_addr[PJ_INET6_ADDRSTRLEN]; 
     694 
     695        sdp->origin.addr_type = STR_IP6; 
     696        pj_strdup2(pool, &sdp->origin.addr, 
     697                   pj_sockaddr_print(origin, tmp_addr, sizeof(tmp_addr), 0)); 
     698 
     699    } else { 
     700        pj_assert(!"Invalid address family"); 
     701        return PJ_EAFNOTSUP; 
     702    } 
     703 
     704    if (sess_name) 
     705        pj_strdup(pool, &sdp->name, sess_name); 
     706    else 
     707        sdp->name = STR_SDP_NAME; 
     708 
     709    /* SDP time and attributes. */ 
     710    sdp->time.start = sdp->time.stop = 0; 
     711    sdp->attr_count = 0; 
     712 
    544713    /* Done */ 
    545714    *p_sdp = sdp; 
    546715 
    547716    return PJ_SUCCESS; 
    548  
     717} 
     718 
     719/** 
     720 * Create a SDP session description that describes the endpoint 
     721 * capability. 
     722 */ 
     723PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt, 
     724                                              pj_pool_t *pool, 
     725                                              unsigned stream_cnt, 
     726                                              const pjmedia_sock_info sock_info[], 
     727                                              pjmedia_sdp_session **p_sdp ) 
     728{ 
     729    const pj_sockaddr *addr0; 
     730    pjmedia_sdp_session *sdp; 
     731    pjmedia_sdp_media *m; 
     732    unsigned i; 
     733    pj_status_t status; 
     734 
     735    /* Sanity check arguments */ 
     736    PJ_ASSERT_RETURN(endpt && pool && p_sdp && stream_cnt, PJ_EINVAL); 
     737    PJ_ASSERT_RETURN(stream_cnt < PJMEDIA_MAX_SDP_MEDIA, PJ_ETOOMANY); 
     738 
     739    addr0 = &sock_info[0].rtp_addr_name; 
     740 
     741    /* Create and initialize basic SDP session */ 
     742    status = pjmedia_endpt_create_base_sdp(endpt, pool, NULL, addr0, &sdp); 
     743    if (status != PJ_SUCCESS) 
     744        return status; 
     745 
     746    /* Audio is first, by convention */ 
     747    status = pjmedia_endpt_create_audio_sdp(endpt, pool, 
     748                                            &sock_info[0], 0, &m); 
     749    if (status != PJ_SUCCESS) 
     750        return status; 
     751    sdp->media[sdp->media_count++] = m; 
     752 
     753    /* The remaining stream, if any, are videos (by convention as well) */ 
     754    for (i=1; i<stream_cnt; ++i) { 
     755        status = pjmedia_endpt_create_video_sdp(endpt, pool, 
     756                                                &sock_info[i], 0, &m); 
     757        if (status != PJ_SUCCESS) 
     758            return status; 
     759        sdp->media[sdp->media_count++] = m; 
     760    } 
     761 
     762    /* Done */ 
     763    *p_sdp = sdp; 
     764 
     765    return PJ_SUCCESS; 
    549766} 
    550767 
Note: See TracChangeset for help on using the changeset viewer.