Changeset 2032


Ignore:
Timestamp:
06/19/08 09:10:28 (11 years ago)
Author:
bennylp
Message:

Ticket #549: major modification in media transport API to support more offer/answer scenarios

Location:
pjproject/trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/include/pjmedia/sdp.h

    r1810 r2032  
    318318                                               pjmedia_sdp_rtcp_attr *rtcp); 
    319319 
     320 
     321/** 
     322 * Create a=rtcp attribute. 
     323 * 
     324 * @param pool          Pool to create the attribute. 
     325 * @param a             Socket address. 
     326 * 
     327 * @return              SDP RTCP attribute. 
     328 */ 
     329PJ_DECL(pjmedia_sdp_attr*) pjmedia_sdp_attr_create_rtcp(pj_pool_t *pool, 
     330                                                        const pj_sockaddr *a); 
    320331 
    321332 
  • pjproject/trunk/pjmedia/include/pjmedia/transport.h

    r1998 r2032  
    321321 
    322322    /** 
     323     * Prepare the transport for a new media session. 
     324     * 
     325     * Application should call #pjmedia_transport_media_create() instead of  
     326     * calling this function directly. 
     327     */ 
     328    pj_status_t (*media_create)(pjmedia_transport *tp, 
     329                                pj_pool_t *sdp_pool, 
     330                                unsigned options, 
     331                                const pjmedia_sdp_session *remote_sdp, 
     332                                unsigned media_index); 
     333 
     334    /** 
    323335     * This function is called by application to generate the SDP parts 
    324336     * related to transport type, e.g: ICE, SRTP. 
    325337     * 
    326      * Application should call #pjmedia_transport_media_create() instead of  
    327      * calling this function directly. 
    328      */ 
    329     pj_status_t (*media_create)(pjmedia_transport *tp, 
    330                                 pj_pool_t *pool, 
    331                                 unsigned options, 
    332                                 pjmedia_sdp_session *sdp_local, 
    333                                 const pjmedia_sdp_session *sdp_remote, 
    334                                 unsigned media_index); 
     338     * Application should call #pjmedia_transport_encode_sdp() instead of 
     339     * calling this function directly. 
     340     */ 
     341    pj_status_t (*encode_sdp)(pjmedia_transport *tp, 
     342                              pj_pool_t *sdp_pool, 
     343                              pjmedia_sdp_session *sdp_local, 
     344                              const pjmedia_sdp_session *rem_sdp, 
     345                              unsigned media_index); 
    335346 
    336347    /** 
     
    342353     */ 
    343354    pj_status_t (*media_start) (pjmedia_transport *tp, 
    344                                 pj_pool_t *pool, 
    345                                 pjmedia_sdp_session *sdp_local, 
     355                                pj_pool_t *tmp_pool, 
     356                                const pjmedia_sdp_session *sdp_local, 
    346357                                const pjmedia_sdp_session *sdp_remote, 
    347358                                unsigned media_index); 
     
    627638 
    628639/** 
    629  * Generate local SDP parts that are related to the specified media transport. 
    630  * Remote SDP might be needed as reference when application is in deciding 
    631  * side of negotiation (callee side), otherwise it should be NULL. 
    632  * 
    633  * This API is provided to allow the media transport to add more information 
    634  * in the SDP offer, before the offer is sent to remote. Additionally, for  
    635  * answerer side, this callback allows the media transport to reject the  
    636  * offer before this offer is processed by the SDP negotiator.  
     640 * Prepare the media transport for a new media session, and optionally 
     641 * encode the relevant information in the \a sdp_local. Application must 
     642 * call this function before starting a new media session using this 
     643 * transport. 
    637644 * 
    638645 * This is just a simple wrapper which calls <tt>media_create()</tt> member  
     
    640647 * 
    641648 * @param tp            The media transport. 
    642  * @param pool          The memory pool. 
     649 * @param sdp_pool      Pool object to allocate memory related to SDP 
     650 *                      messaging components. 
    643651 * @param option        Option flags, from #pjmedia_tranport_media_option 
    644  * @param sdp_local     Local SDP. 
    645  * @param sdp_remote    Remote SDP. 
     652 * @param rem_sdp       Remote SDP if it's available. 
    646653 * @param media_index   Media index in SDP. 
    647654 * 
     
    649656 */ 
    650657PJ_INLINE(pj_status_t) pjmedia_transport_media_create(pjmedia_transport *tp, 
    651                                     pj_pool_t *pool, 
     658                                    pj_pool_t *sdp_pool, 
    652659                                    unsigned options, 
    653                                     pjmedia_sdp_session *sdp_local, 
    654                                     const pjmedia_sdp_session *sdp_remote, 
     660                                    const pjmedia_sdp_session *rem_sdp, 
    655661                                    unsigned media_index) 
    656662{ 
    657     return (*tp->op->media_create)(tp, pool, options, sdp_local, sdp_remote,  
     663    return (*tp->op->media_create)(tp, sdp_pool, options, rem_sdp,  
    658664                                   media_index); 
    659665} 
     666 
     667 
     668/** 
     669 * Put transport specific information into the SDP. This function can be 
     670 * called to create SDP offer or answer, depending whether \a rem_sdp 
     671 * parameter is present. 
     672 * 
     673 * This is just a simple wrapper which calls <tt>encode_sdp()</tt> member  
     674 * of the transport. 
     675 * 
     676 * @param tp            The media transport. 
     677 * @param sdp_pool      Pool object to allocate memory related to SDP 
     678 *                      messaging components. 
     679 * @param sdp           The local SDP to be filled in information from the 
     680 *                      media transport. 
     681 * @param rem_sdp       Remote SDP if it's available. 
     682 * @param media_index   Media index in SDP. 
     683 * 
     684 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     685 */ 
     686PJ_INLINE(pj_status_t) pjmedia_transport_encode_sdp(pjmedia_transport *tp, 
     687                                            pj_pool_t *sdp_pool, 
     688                                            pjmedia_sdp_session *sdp, 
     689                                            const pjmedia_sdp_session *rem_sdp, 
     690                                            unsigned media_index) 
     691{ 
     692    return (*tp->op->encode_sdp)(tp, sdp_pool, sdp, rem_sdp, media_index); 
     693} 
     694 
    660695 
    661696/** 
     
    674709 * 
    675710 * @param tp            The media transport. 
    676  * @param pool          The memory pool. 
     711 * @param tmp_pool      The memory pool for allocating temporary objects. 
    677712 * @param option        The media transport option. 
    678713 * @param sdp_local     Local SDP. 
     
    683718 */ 
    684719PJ_INLINE(pj_status_t) pjmedia_transport_media_start(pjmedia_transport *tp, 
    685                                     pj_pool_t *pool, 
    686                                     pjmedia_sdp_session *sdp_local, 
     720                                    pj_pool_t *tmp_pool, 
     721                                    const pjmedia_sdp_session *sdp_local, 
    687722                                    const pjmedia_sdp_session *sdp_remote, 
    688723                                    unsigned media_index) 
    689724{ 
    690     return (*tp->op->media_start)(tp, pool, sdp_local, sdp_remote, media_index); 
     725    return (*tp->op->media_start)(tp, tmp_pool, sdp_local, sdp_remote,  
     726                                  media_index); 
    691727} 
    692728 
  • pjproject/trunk/pjmedia/src/pjmedia/endpoint.c

    r1813 r2032  
    363363#if defined(PJMEDIA_HAS_RTCP_IN_SDP) && PJMEDIA_HAS_RTCP_IN_SDP!=0 
    364364    if (sock_info->rtcp_addr_name.addr.sa_family != 0) { 
    365         const pj_sockaddr *rtcp_addr = &sock_info->rtcp_addr_name; 
    366  
    367         attr = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_attr); 
    368         attr->name = pj_str("rtcp"); 
    369         attr->value.ptr = (char*) pj_pool_alloc(pool, 80); 
    370         if (rtcp_addr->addr.sa_family == pj_AF_INET()) { 
    371             attr->value.slen =  
    372                 pj_ansi_snprintf(attr->value.ptr, 80, 
    373                                 "%u IN IP4 %s", 
    374                                 pj_ntohs(rtcp_addr->ipv4.sin_port), 
    375                                 pj_inet_ntoa(rtcp_addr->ipv4.sin_addr)); 
    376         } else if (rtcp_addr->addr.sa_family == pj_AF_INET6()) { 
    377             char tmp_addr[PJ_INET6_ADDRSTRLEN]; 
    378             attr->value.slen =  
    379                 pj_ansi_snprintf(attr->value.ptr, 80, 
    380                                 "%u IN IP6 %s", 
    381                                 pj_sockaddr_get_port(rtcp_addr), 
    382                                 pj_sockaddr_print(rtcp_addr, tmp_addr,  
    383                                                   sizeof(tmp_addr), 0)); 
    384  
    385         } else { 
    386             pj_assert(!"Unsupported address family"); 
    387             return PJ_EAFNOTSUP; 
    388         } 
    389         pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 
     365        attr = pjmedia_sdp_attr_create_rtcp(pool, &sock_info->rtcp_addr_name); 
     366        if (attr) 
     367            pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 
    390368    } 
    391369#endif 
  • pjproject/trunk/pjmedia/src/pjmedia/sdp.c

    r1967 r2032  
    414414} 
    415415 
     416 
     417PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_create_rtcp(pj_pool_t *pool, 
     418                                                       const pj_sockaddr *a) 
     419{ 
     420    enum { 
     421        ATTR_LEN = PJ_INET6_ADDRSTRLEN+16 
     422    }; 
     423    pjmedia_sdp_attr *attr; 
     424 
     425    attr = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_attr); 
     426    attr->name = pj_str("rtcp"); 
     427    attr->value.ptr = (char*) pj_pool_alloc(pool, ATTR_LEN); 
     428    if (a->addr.sa_family == pj_AF_INET()) { 
     429        attr->value.slen =  
     430            pj_ansi_snprintf(attr->value.ptr, ATTR_LEN, 
     431                            "%u IN IP4 %s", 
     432                            pj_ntohs(a->ipv4.sin_port), 
     433                            pj_inet_ntoa(a->ipv4.sin_addr)); 
     434    } else if (a->addr.sa_family == pj_AF_INET6()) { 
     435        char tmp_addr[PJ_INET6_ADDRSTRLEN]; 
     436        attr->value.slen =  
     437            pj_ansi_snprintf(attr->value.ptr, ATTR_LEN, 
     438                            "%u IN IP6 %s", 
     439                            pj_sockaddr_get_port(a), 
     440                            pj_sockaddr_print(a, tmp_addr,  
     441                                              sizeof(tmp_addr), 0)); 
     442 
     443    } else { 
     444        pj_assert(!"Unsupported address family"); 
     445        return NULL; 
     446    } 
     447 
     448    return attr; 
     449} 
    416450 
    417451 
  • pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c

    r1989 r2032  
    2424 
    2525#define THIS_FILE   "transport_ice.c" 
    26  
    27 static const pj_str_t ID_RTP_AVP  = { "RTP/AVP", 7 }; 
     26#if 0 
     27#   define TRACE__(expr)    PJ_LOG(5,expr) 
     28#else 
     29#   define TRACE__(expr) 
     30#endif 
     31 
     32enum oa_role 
     33{ 
     34    ROLE_NONE, 
     35    ROLE_OFFERER, 
     36    ROLE_ANSWERER 
     37}; 
     38 
     39struct sdp_state 
     40{ 
     41    unsigned            match_comp_cnt; /* Matching number of components    */ 
     42    pj_bool_t           ice_mismatch;   /* Address doesn't match candidates */ 
     43    pj_bool_t           ice_restart;    /* Offer to restart ICE             */ 
     44    pj_ice_sess_role    local_role;     /* Our role                         */ 
     45}; 
    2846 
    2947struct transport_ice 
     
    3250    pj_pool_t           *pool; 
    3351    int                  af; 
     52 
    3453    unsigned             comp_cnt; 
    3554    pj_ice_strans       *ice_st; 
     55 
    3656    pjmedia_ice_cb       cb; 
    3757    unsigned             media_option; 
     58 
     59    pj_bool_t            initial_sdp; 
     60    enum oa_role         oa_role;       /**< Last role in SDP offer/answer  */ 
     61    struct sdp_state     rem_offer_state;/**< Describes the remote offer            */ 
    3862 
    3963    void                *stream; 
     
    85109                                       pj_pool_t *pool, 
    86110                                       unsigned options, 
    87                                        pjmedia_sdp_session *sdp_local, 
    88111                                       const pjmedia_sdp_session *rem_sdp, 
    89112                                       unsigned media_index); 
    90 static pj_status_t transport_media_start (pjmedia_transport *tp, 
     113static pj_status_t transport_encode_sdp(pjmedia_transport *tp, 
     114                                        pj_pool_t *tmp_pool, 
     115                                        pjmedia_sdp_session *sdp_local, 
     116                                        const pjmedia_sdp_session *rem_sdp, 
     117                                        unsigned media_index); 
     118static pj_status_t transport_media_start(pjmedia_transport *tp, 
    91119                                       pj_pool_t *pool, 
    92                                        pjmedia_sdp_session *sdp_local, 
     120                                       const pjmedia_sdp_session *sdp_local, 
    93121                                       const pjmedia_sdp_session *rem_sdp, 
    94122                                       unsigned media_index); 
     
    121149    &transport_send_rtcp2, 
    122150    &transport_media_create, 
     151    &transport_encode_sdp, 
    123152    &transport_media_start, 
    124153    &transport_media_stop, 
     
    127156}; 
    128157 
    129 static const pj_str_t STR_CANDIDATE = {"candidate", 9}; 
    130 static const pj_str_t STR_ICE_LITE = {"ice-lite", 8}; 
    131 static const pj_str_t STR_ICE_MISMATCH = {"ice-mismatch", 12}; 
    132  
     158static const pj_str_t STR_RTP_AVP       = { "RTP/AVP", 7 }; 
     159static const pj_str_t STR_CANDIDATE     = { "candidate", 9}; 
     160static const pj_str_t STR_REM_CAND      = { "remote-candidates", 17 }; 
     161static const pj_str_t STR_ICE_LITE      = { "ice-lite", 8}; 
     162static const pj_str_t STR_ICE_MISMATCH  = { "ice-mismatch", 12}; 
     163static const pj_str_t STR_ICE_UFRAG     = { "ice-ufrag", 9 }; 
     164static const pj_str_t STR_ICE_PWD       = { "ice-pwd", 7 }; 
     165static const pj_str_t STR_IP4           = { "IP4", 3 }; 
     166static const pj_str_t STR_IP6           = { "IP6", 3 }; 
     167static const pj_str_t STR_RTCP          = { "rtcp", 4 }; 
     168 
     169enum { 
     170    COMP_RTP = 1, 
     171    COMP_RTCP = 2 
     172}; 
    133173 
    134174/* 
     
    158198    tp_ice->base.op = &transport_ice_op; 
    159199    tp_ice->base.type = PJMEDIA_TRANSPORT_TYPE_ICE; 
     200    tp_ice->initial_sdp = PJ_TRUE; 
     201    tp_ice->oa_role = ROLE_NONE; 
    160202 
    161203    if (cb) 
     
    184226    return PJ_SUCCESS; 
    185227} 
     228 
     229/* Disable ICE when SDP from remote doesn't contain a=candidate line */ 
     230static void set_no_ice(struct transport_ice *tp_ice, const char *reason, 
     231                       pj_status_t err) 
     232{ 
     233    if (err != PJ_SUCCESS) { 
     234        char errmsg[PJ_ERR_MSG_SIZE]; 
     235        pj_strerror(err, errmsg, sizeof(errmsg)); 
     236        PJ_LOG(4,(tp_ice->base.name,  
     237                  "Stopping ICE, reason=%s:%s", reason, errmsg)); 
     238    } else { 
     239        PJ_LOG(4,(tp_ice->base.name,  
     240                  "Stopping ICE, reason=%s", reason)); 
     241    } 
     242 
     243    pj_ice_strans_stop_ice(tp_ice->ice_st); 
     244} 
     245 
    186246 
    187247/* Create SDP candidate attribute */ 
     
    228288} 
    229289 
     290 
     291/* Get ice-ufrag and ice-pwd attribute */ 
     292static void get_ice_attr(const pjmedia_sdp_session *rem_sdp, 
     293                         const pjmedia_sdp_media *rem_m, 
     294                         const pjmedia_sdp_attr **p_ice_ufrag, 
     295                         const pjmedia_sdp_attr **p_ice_pwd) 
     296{ 
     297    pjmedia_sdp_attr *attr; 
     298 
     299    /* Find ice-ufrag attribute in media descriptor */ 
     300    attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr, 
     301                                 &STR_ICE_UFRAG, NULL); 
     302    if (attr == NULL) { 
     303        /* Find ice-ufrag attribute in session descriptor */ 
     304        attr = pjmedia_sdp_attr_find(rem_sdp->attr_count, rem_sdp->attr, 
     305                                     &STR_ICE_UFRAG, NULL); 
     306    } 
     307    *p_ice_ufrag = attr; 
     308 
     309    /* Find ice-pwd attribute in media descriptor */ 
     310    attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr, 
     311                                 &STR_ICE_PWD, NULL); 
     312    if (attr == NULL) { 
     313        /* Find ice-pwd attribute in session descriptor */ 
     314        attr = pjmedia_sdp_attr_find(rem_sdp->attr_count, rem_sdp->attr, 
     315                                     &STR_ICE_PWD, NULL); 
     316    } 
     317    *p_ice_pwd = attr; 
     318} 
     319 
     320 
     321/* Encode and add "a=ice-mismatch" attribute in the SDP */ 
     322static void encode_ice_mismatch(pj_pool_t *sdp_pool, 
     323                                pjmedia_sdp_session *sdp_local, 
     324                                unsigned media_index) 
     325{ 
     326    pjmedia_sdp_attr *attr; 
     327    pjmedia_sdp_media *m = sdp_local->media[media_index]; 
     328 
     329    attr = PJ_POOL_ALLOC_T(sdp_pool, pjmedia_sdp_attr); 
     330    attr->name = STR_ICE_MISMATCH; 
     331    attr->value.slen = 0; 
     332    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 
     333} 
     334 
     335 
     336/* Encode ICE information in SDP */ 
     337static pj_status_t encode_session_in_sdp(struct transport_ice *tp_ice, 
     338                                         pj_pool_t *sdp_pool, 
     339                                         pjmedia_sdp_session *sdp_local, 
     340                                         unsigned media_index, 
     341                                         unsigned comp_cnt, 
     342                                         pj_bool_t restart_session) 
     343{ 
     344    enum {  
     345        ATTR_BUF_LEN = 160,     /* Max len of a=candidate attr */ 
     346        RATTR_BUF_LEN= 160      /* Max len of a=remote-candidates attr */ 
     347    }; 
     348    pjmedia_sdp_media *m = sdp_local->media[media_index]; 
     349    pj_str_t local_ufrag, local_pwd; 
     350    pjmedia_sdp_attr *attr; 
     351    pj_status_t status; 
     352 
     353    /* Must have a session */ 
     354    PJ_ASSERT_RETURN(pj_ice_strans_has_sess(tp_ice->ice_st), PJ_EBUG); 
     355 
     356    /* Get ufrag and pwd from current session */ 
     357    pj_ice_strans_get_ufrag_pwd(tp_ice->ice_st, &local_ufrag, &local_pwd, 
     358                                NULL, NULL); 
     359 
     360    /* The listing of candidates depends on whether ICE has completed 
     361     * or not. When ICE has completed: 
     362     * 
     363     * 9.1.2.2: Existing Media Streams with ICE Completed 
     364     *   The agent MUST include a candidate attributes for candidates 
     365     *   matching the default destination for each component of the  
     366     *   media stream, and MUST NOT include any other candidates. 
     367     * 
     368     * When ICE has not completed, we shall include all candidates. 
     369     * 
     370     * Except when we have detected that remote is offering to restart 
     371     * the session, in this case we will answer with full ICE SDP and 
     372     * new ufrag/pwd pair. 
     373     */ 
     374    if (!restart_session && pj_ice_strans_sess_is_complete(tp_ice->ice_st)) { 
     375        const pj_ice_sess_check *check; 
     376        char *attr_buf; 
     377        pjmedia_sdp_conn *conn; 
     378        pjmedia_sdp_attr *a_rtcp; 
     379        pj_str_t rem_cand; 
     380        unsigned comp; 
     381 
     382        /* Encode ice-ufrag attribute */ 
     383        attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr, 
     384                                       &local_ufrag); 
     385        pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 
     386 
     387        /* Encode ice-pwd attribute */ 
     388        attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr,  
     389                                       &local_pwd); 
     390        pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 
     391 
     392        /* Prepare buffer */ 
     393        attr_buf = (char*) pj_pool_alloc(sdp_pool, ATTR_BUF_LEN); 
     394        rem_cand.ptr = (char*) pj_pool_alloc(sdp_pool, RATTR_BUF_LEN); 
     395        rem_cand.slen = 0; 
     396 
     397        /* 9.1.2.2: Existing Media Streams with ICE Completed 
     398         *   The default destination for media (i.e., the values of  
     399         *   the IP addresses and ports in the m and c line used for 
     400         *   that media stream) MUST be the local candidate from the 
     401         *   highest priority nominated pair in the valid list for each 
     402         *   component. 
     403         */ 
     404        check = pj_ice_strans_get_valid_pair(tp_ice->ice_st, 1); 
     405        if (check == NULL) { 
     406            pj_assert(!"Shouldn't happen"); 
     407            return PJ_EBUG; 
     408        } 
     409 
     410        /* Override connection line address and media port number */ 
     411        conn = m->conn; 
     412        if (conn == NULL) 
     413            conn = sdp_local->conn; 
     414 
     415        conn->addr.ptr = (char*) pj_pool_alloc(sdp_pool,  
     416                                               PJ_INET6_ADDRSTRLEN); 
     417        pj_sockaddr_print(&check->lcand->addr, conn->addr.ptr,  
     418                          PJ_INET6_ADDRSTRLEN, 0); 
     419        conn->addr.slen = pj_ansi_strlen(conn->addr.ptr); 
     420        m->desc.port = pj_sockaddr_get_port(&check->lcand->addr); 
     421 
     422        /* Override address RTCP attribute if it's present */ 
     423        if (comp_cnt == 2 && 
     424            (check = pj_ice_strans_get_valid_pair(tp_ice->ice_st,  
     425                                                  COMP_RTCP)) != NULL && 
     426            (a_rtcp = pjmedia_sdp_attr_find(m->attr_count, m->attr,  
     427                                            &STR_RTCP, 0)) != NULL)  
     428        { 
     429            pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a_rtcp); 
     430 
     431            a_rtcp = pjmedia_sdp_attr_create_rtcp(sdp_pool,  
     432                                                  &check->lcand->addr); 
     433            if (a_rtcp) 
     434                pjmedia_sdp_attr_add(&m->attr_count, m->attr, a_rtcp); 
     435        } 
     436 
     437        /* Encode only candidates matching the default destination  
     438         * for each component  
     439         */ 
     440        for (comp=0; comp < comp_cnt; ++comp) { 
     441            int len; 
     442            pj_str_t value; 
     443 
     444            /* Get valid pair for this component */ 
     445            check = pj_ice_strans_get_valid_pair(tp_ice->ice_st, comp+1); 
     446            if (check == NULL) 
     447                continue; 
     448 
     449            /* Print and add local candidate in the pair */ 
     450            value.ptr = attr_buf; 
     451            value.slen = print_sdp_cand_attr(attr_buf, ATTR_BUF_LEN,  
     452                                             check->lcand); 
     453            if (value.slen < 0) { 
     454                pj_assert(!"Not enough attr_buf to print candidate"); 
     455                return PJ_EBUG; 
     456            } 
     457 
     458            attr = pjmedia_sdp_attr_create(sdp_pool, STR_CANDIDATE.ptr, 
     459                                           &value); 
     460            pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 
     461 
     462            /* Append to a=remote-candidates attribute */ 
     463            if (pj_ice_strans_get_role(tp_ice->ice_st) ==  
     464                                    PJ_ICE_SESS_ROLE_CONTROLLING)  
     465            { 
     466                char rem_addr[PJ_INET6_ADDRSTRLEN]; 
     467 
     468                pj_sockaddr_print(&check->rcand->addr, rem_addr,  
     469                                  sizeof(rem_addr), 0); 
     470                len = pj_ansi_snprintf( 
     471                           rem_cand.ptr + rem_cand.slen, 
     472                           RATTR_BUF_LEN - rem_cand.slen, 
     473                           "%s%u %s %u",  
     474                           (rem_cand.slen==0? "" : " "), 
     475                           comp+1, rem_addr, 
     476                           pj_sockaddr_get_port(&check->rcand->addr) 
     477                           ); 
     478                if (len < 1 || len >= RATTR_BUF_LEN) { 
     479                    pj_assert(!"Not enough buffer to print " 
     480                               "remote-candidates"); 
     481                    return PJ_EBUG; 
     482                } 
     483 
     484                rem_cand.slen += len; 
     485            } 
     486        } 
     487 
     488        /* 9.1.2.2: Existing Media Streams with ICE Completed 
     489         *   In addition, if the agent is controlling, it MUST include 
     490         *   the a=remote-candidates attribute for each media stream  
     491         *   whose check list is in the Completed state.  The attribute 
     492         *   contains the remote candidates from the highest priority  
     493         *   nominated pair in the valid list for each component of that 
     494         *   media stream. 
     495         */ 
     496        if (pj_ice_strans_get_role(tp_ice->ice_st) ==  
     497                                    PJ_ICE_SESS_ROLE_CONTROLLING)  
     498        { 
     499            attr = pjmedia_sdp_attr_create(sdp_pool, STR_REM_CAND.ptr,  
     500                                           &rem_cand); 
     501            pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 
     502        } 
     503 
     504    } else if (pj_ice_strans_has_sess(tp_ice->ice_st)) { 
     505        /* Encode all candidates to SDP media */ 
     506        char *attr_buf; 
     507        unsigned comp; 
     508 
     509        /* If ICE is not restarted, encode current ICE ufrag/pwd. 
     510         * Otherwise generate new one. 
     511         */ 
     512        if (!restart_session) { 
     513            attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr, 
     514                                           &local_ufrag); 
     515            pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 
     516 
     517            attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr,  
     518                                           &local_pwd); 
     519            pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 
     520 
     521        } else { 
     522            pj_str_t str; 
     523 
     524            str.slen = PJ_ICE_UFRAG_LEN; 
     525            str.ptr = (char*) pj_pool_alloc(sdp_pool, str.slen); 
     526            pj_create_random_string(str.ptr, str.slen); 
     527            attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr, &str); 
     528            pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 
     529 
     530            str.ptr = (char*) pj_pool_alloc(sdp_pool, str.slen); 
     531            pj_create_random_string(str.ptr, str.slen); 
     532            attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr, &str); 
     533            pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 
     534        } 
     535 
     536        /* Create buffer to encode candidates as SDP attribute */ 
     537        attr_buf = (char*) pj_pool_alloc(sdp_pool, ATTR_BUF_LEN); 
     538 
     539        for (comp=0; comp < comp_cnt; ++comp) { 
     540            unsigned cand_cnt; 
     541            pj_ice_sess_cand cand[PJ_ICE_ST_MAX_CAND]; 
     542            unsigned i; 
     543 
     544            cand_cnt = PJ_ARRAY_SIZE(cand); 
     545            status = pj_ice_strans_enum_cands(tp_ice->ice_st, comp+1, 
     546                                              &cand_cnt, cand); 
     547            if (status != PJ_SUCCESS) 
     548                return status; 
     549 
     550            for (i=0; i<cand_cnt; ++i) { 
     551                pj_str_t value; 
     552 
     553                value.slen = print_sdp_cand_attr(attr_buf, ATTR_BUF_LEN,  
     554                                                 &cand[i]); 
     555                if (value.slen < 0) { 
     556                    pj_assert(!"Not enough attr_buf to print candidate"); 
     557                    return PJ_EBUG; 
     558                } 
     559 
     560                value.ptr = attr_buf; 
     561                attr = pjmedia_sdp_attr_create(sdp_pool,  
     562                                               STR_CANDIDATE.ptr, 
     563                                               &value); 
     564                pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 
     565            } 
     566        } 
     567    } else { 
     568        /* ICE has failed, application should have terminated this call */ 
     569    } 
     570 
     571    return PJ_SUCCESS; 
     572} 
     573 
     574 
     575/* Parse a=candidate line */ 
     576static pj_status_t parse_cand(const char *obj_name, 
     577                              pj_pool_t *pool, 
     578                              const pj_str_t *orig_input, 
     579                              pj_ice_sess_cand *cand) 
     580{ 
     581    pj_str_t input; 
     582    char *token, *host; 
     583    int af; 
     584    pj_str_t s; 
     585    pj_status_t status = PJNATH_EICEINCANDSDP; 
     586 
     587    pj_bzero(cand, sizeof(*cand)); 
     588    pj_strdup_with_null(pool, &input, orig_input); 
     589 
     590    PJ_UNUSED_ARG(obj_name); 
     591 
     592    /* Foundation */ 
     593    token = strtok(input.ptr, " "); 
     594    if (!token) { 
     595        TRACE__((obj_name, "Expecting ICE foundation in candidate")); 
     596        goto on_return; 
     597    } 
     598    pj_strdup2(pool, &cand->foundation, token); 
     599 
     600    /* Component ID */ 
     601    token = strtok(NULL, " "); 
     602    if (!token) { 
     603        TRACE__((obj_name, "Expecting ICE component ID in candidate")); 
     604        goto on_return; 
     605    } 
     606    cand->comp_id = (pj_uint8_t) atoi(token); 
     607 
     608    /* Transport */ 
     609    token = strtok(NULL, " "); 
     610    if (!token) { 
     611        TRACE__((obj_name, "Expecting ICE transport in candidate")); 
     612        goto on_return; 
     613    } 
     614    if (pj_ansi_stricmp(token, "UDP") != 0) { 
     615        TRACE__((obj_name,  
     616                 "Expecting ICE UDP transport only in candidate")); 
     617        goto on_return; 
     618    } 
     619 
     620    /* Priority */ 
     621    token = strtok(NULL, " "); 
     622    if (!token) { 
     623        TRACE__((obj_name, "Expecting ICE priority in candidate")); 
     624        goto on_return; 
     625    } 
     626    cand->prio = atoi(token); 
     627 
     628    /* Host */ 
     629    host = strtok(NULL, " "); 
     630    if (!host) { 
     631        TRACE__((obj_name, "Expecting ICE host in candidate")); 
     632        goto on_return; 
     633    } 
     634    /* Detect address family */ 
     635    if (pj_ansi_strchr(host, ':')) 
     636        af = pj_AF_INET6(); 
     637    else 
     638        af = pj_AF_INET(); 
     639    /* Assign address */ 
     640    if (pj_sockaddr_init(af, &cand->addr, pj_cstr(&s, host), 0)) { 
     641        TRACE__((obj_name, "Invalid ICE candidate address")); 
     642        goto on_return; 
     643    } 
     644 
     645    /* Port */ 
     646    token = strtok(NULL, " "); 
     647    if (!token) { 
     648        TRACE__((obj_name, "Expecting ICE port number in candidate")); 
     649        goto on_return; 
     650    } 
     651    pj_sockaddr_set_port(&cand->addr, (pj_uint16_t)atoi(token)); 
     652 
     653    /* typ */ 
     654    token = strtok(NULL, " "); 
     655    if (!token) { 
     656        TRACE__((obj_name, "Expecting ICE \"typ\" in candidate")); 
     657        goto on_return; 
     658    } 
     659    if (pj_ansi_stricmp(token, "typ") != 0) { 
     660        TRACE__((obj_name, "Expecting ICE \"typ\" in candidate")); 
     661        goto on_return; 
     662    } 
     663 
     664    /* candidate type */ 
     665    token = strtok(NULL, " "); 
     666    if (!token) { 
     667        TRACE__((obj_name, "Expecting ICE candidate type in candidate")); 
     668        goto on_return; 
     669    } 
     670 
     671    if (pj_ansi_stricmp(token, "host") == 0) { 
     672        cand->type = PJ_ICE_CAND_TYPE_HOST; 
     673 
     674    } else if (pj_ansi_stricmp(token, "srflx") == 0) { 
     675        cand->type = PJ_ICE_CAND_TYPE_SRFLX; 
     676 
     677    } else if (pj_ansi_stricmp(token, "relay") == 0) { 
     678        cand->type = PJ_ICE_CAND_TYPE_RELAYED; 
     679 
     680    } else if (pj_ansi_stricmp(token, "prflx") == 0) { 
     681        cand->type = PJ_ICE_CAND_TYPE_PRFLX; 
     682 
     683    } else { 
     684        PJ_LOG(5,(obj_name, "Invalid ICE candidate type %s in candidate",  
     685                  token)); 
     686        goto on_return; 
     687    } 
     688 
     689    status = PJ_SUCCESS; 
     690 
     691on_return: 
     692    return status; 
     693} 
     694 
     695 
     696/* Create initial SDP offer */ 
     697static pj_status_t create_initial_offer(struct transport_ice *tp_ice, 
     698                                        pj_pool_t *sdp_pool, 
     699                                        pjmedia_sdp_session *loc_sdp, 
     700                                        unsigned media_index) 
     701{ 
     702    pj_status_t status; 
     703 
     704    /* Encode ICE in SDP */ 
     705    status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index,  
     706                                   tp_ice->comp_cnt, PJ_FALSE); 
     707    if (status != PJ_SUCCESS) { 
     708        set_no_ice(tp_ice, "Error encoding SDP answer", status); 
     709        return status; 
     710    } 
     711 
     712    return PJ_SUCCESS; 
     713} 
     714 
     715 
     716/* Verify incoming offer */ 
     717static pj_status_t verify_ice_sdp(struct transport_ice *tp_ice, 
     718                                  pj_pool_t *tmp_pool, 
     719                                  const pjmedia_sdp_session *rem_sdp, 
     720                                  unsigned media_index, 
     721                                  pj_ice_sess_role current_ice_role, 
     722                                  struct sdp_state *sdp_state) 
     723{ 
     724    const pjmedia_sdp_media *rem_m; 
     725    const pjmedia_sdp_attr *attr, *ufrag_attr, *pwd_attr; 
     726    const pjmedia_sdp_conn *rem_conn; 
     727    pj_bool_t comp1_found=PJ_FALSE, comp2_found=PJ_FALSE; 
     728    pj_sockaddr rem_conn_addr, rtcp_addr; 
     729    unsigned i; 
     730    pj_status_t status; 
     731 
     732    rem_m = rem_sdp->media[media_index]; 
     733 
     734    /* Get the "ice-ufrag" and "ice-pwd" attributes */ 
     735    get_ice_attr(rem_sdp, rem_m, &ufrag_attr, &pwd_attr); 
     736 
     737    /* If "ice-ufrag" or "ice-pwd" are not found, disable ICE */ 
     738    if (ufrag_attr==NULL || pwd_attr==NULL) { 
     739        sdp_state->match_comp_cnt = 0; 
     740        return PJ_SUCCESS; 
     741    } 
     742 
     743    /* Verify that default target for each component matches one of the  
     744     * candidatefor the component. Otherwise stop ICE with ICE ice_mismatch  
     745     * error. 
     746     */ 
     747 
     748    /* Component 1 is the c= line */ 
     749    rem_conn = rem_m->conn; 
     750    if (rem_conn == NULL) 
     751        rem_conn = rem_sdp->conn; 
     752    if (!rem_conn) 
     753        return PJMEDIA_SDP_EMISSINGCONN; 
     754 
     755    /* Verify address family matches */ 
     756    if ((tp_ice->af==pj_AF_INET() &&  
     757         pj_strcmp(&rem_conn->addr_type, &STR_IP4)!=0) || 
     758        (tp_ice->af==pj_AF_INET6() &&  
     759         pj_strcmp(&rem_conn->addr_type, &STR_IP6)!=0)) 
     760    { 
     761        return PJMEDIA_SDP_ETPORTNOTEQUAL; 
     762    } 
     763 
     764    /* Assign remote connection address */ 
     765    status = pj_sockaddr_init(tp_ice->af, &rem_conn_addr, &rem_conn->addr, 
     766                              (pj_uint16_t)rem_m->desc.port); 
     767    if (status != PJ_SUCCESS) 
     768        return status; 
     769 
     770    /* Component 2 is a=rtcp line, if present. */ 
     771    attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr,  
     772                                 &STR_RTCP, NULL); 
     773    if (attr && tp_ice->comp_cnt > 1) { 
     774        pjmedia_sdp_rtcp_attr rtcp_attr; 
     775 
     776        status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp_attr); 
     777        if (status != PJ_SUCCESS) { 
     778            /* Error parsing a=rtcp attribute */ 
     779            return status; 
     780        } 
     781         
     782        /* Verify address family matches */ 
     783        if ((tp_ice->af==pj_AF_INET() &&  
     784             pj_strcmp(&rtcp_attr.addr_type, &STR_IP4)!=0) || 
     785            (tp_ice->af==pj_AF_INET6() &&  
     786             pj_strcmp(&rtcp_attr.addr_type, &STR_IP6)!=0)) 
     787        { 
     788            return PJMEDIA_SDP_ETPORTNOTEQUAL; 
     789        } 
     790 
     791        /* Assign RTCP address */ 
     792        status = pj_sockaddr_init(tp_ice->af, &rtcp_addr, 
     793                                  &rtcp_attr.addr, 
     794                                  (pj_uint16_t)rtcp_attr.port); 
     795        if (status != PJ_SUCCESS) { 
     796            return PJMEDIA_SDP_EINRTCP; 
     797        } 
     798 
     799        sdp_state->match_comp_cnt = 2; 
     800 
     801    } else { 
     802        /* Don't have RTCP component */ 
     803        comp2_found = PJ_TRUE; 
     804        sdp_state->match_comp_cnt = 1; 
     805    } 
     806 
     807    /* Find the default address in a=candidate attributes.  
     808     */ 
     809    for (i=0; i<rem_m->attr_count; ++i) { 
     810        pj_ice_sess_cand cand; 
     811 
     812        if (pj_strcmp(&rem_m->attr[i]->name, &STR_CANDIDATE)!=0) 
     813            continue; 
     814 
     815        status = parse_cand(tp_ice->base.name, tmp_pool,  
     816                            &rem_m->attr[i]->value, &cand); 
     817        if (status != PJ_SUCCESS) { 
     818            PJ_LOG(4,(tp_ice->base.name,  
     819                      "Error in parsing SDP candidate attribute '%.*s', " 
     820                      "candidate is ignored", 
     821                      (int)rem_m->attr[i]->value.slen,  
     822                      rem_m->attr[i]->value.ptr)); 
     823            continue; 
     824        } 
     825 
     826        if (!comp1_found && cand.comp_id==COMP_RTP && 
     827            pj_sockaddr_cmp(&rem_conn_addr, &cand.addr)==0)  
     828        { 
     829            /* Found */ 
     830            comp1_found = PJ_TRUE; 
     831            if (comp1_found && comp2_found) 
     832                break; 
     833        } else if (!comp2_found && cand.comp_id==COMP_RTCP && 
     834                    pj_sockaddr_cmp(&rtcp_addr, &cand.addr)==0)  
     835        { 
     836            /* Found */ 
     837            comp2_found = PJ_TRUE; 
     838            if (comp1_found && comp2_found) 
     839                break; 
     840        } 
     841 
     842    } 
     843 
     844    if (!comp1_found || !comp2_found) { 
     845        /* ICE ice_mismatch */ 
     846        sdp_state->ice_mismatch = PJ_TRUE; 
     847    } else { 
     848        sdp_state->ice_mismatch = PJ_FALSE; 
     849    } 
     850 
     851    /* Detect remote restarting session */ 
     852    if (pj_ice_strans_has_sess(tp_ice->ice_st) && 
     853        (pj_ice_strans_sess_is_running(tp_ice->ice_st) || 
     854         pj_ice_strans_sess_is_complete(tp_ice->ice_st)))  
     855    { 
     856        pj_str_t rem_run_ufrag, rem_run_pwd; 
     857        pj_ice_strans_get_ufrag_pwd(tp_ice->ice_st, NULL, NULL, 
     858                                    &rem_run_ufrag, &rem_run_pwd); 
     859        if (pj_strcmp(&ufrag_attr->value, &rem_run_ufrag) || 
     860            pj_strcmp(&pwd_attr->value, &rem_run_pwd)) 
     861        { 
     862            /* Remote offers to restart ICE */ 
     863            sdp_state->ice_restart = PJ_TRUE; 
     864        } else { 
     865            sdp_state->ice_restart = PJ_FALSE; 
     866        } 
     867    } else { 
     868        sdp_state->ice_restart = PJ_FALSE; 
     869    } 
     870 
     871    /* Detect our role */ 
     872    if (current_ice_role==PJ_ICE_SESS_ROLE_CONTROLLING) { 
     873        sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLING; 
     874    } else { 
     875        if (pjmedia_sdp_attr_find(rem_sdp->attr_count, rem_sdp->attr, 
     876                                  &STR_ICE_LITE, NULL) != NULL) 
     877        { 
     878            /* Remote is ICE Lite */ 
     879            sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLING; 
     880        } else { 
     881            sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLED; 
     882        } 
     883    } 
     884 
     885    PJ_LOG(4,(tp_ice->base.name,  
     886              "Processing SDP: support ICE=%u, common comp_cnt=%u, " 
     887              "ice_mismatch=%u, ice_restart=%u, local_role=%s", 
     888              (sdp_state->match_comp_cnt != 0),  
     889              sdp_state->match_comp_cnt,  
     890              sdp_state->ice_mismatch,  
     891              sdp_state->ice_restart, 
     892              pj_ice_sess_role_name(sdp_state->local_role))); 
     893 
     894    return PJ_SUCCESS; 
     895 
     896} 
     897 
     898 
     899/* Verify incoming offer and create initial answer */ 
     900static pj_status_t create_initial_answer(struct transport_ice *tp_ice, 
     901                                         pj_pool_t *sdp_pool, 
     902                                         pjmedia_sdp_session *loc_sdp, 
     903                                         const pjmedia_sdp_session *rem_sdp, 
     904                                         unsigned media_index) 
     905{ 
     906    const pjmedia_sdp_media *rem_m = rem_sdp->media[media_index]; 
     907    pj_status_t status; 
     908 
     909    /* Check if media is removed (just in case) */ 
     910    if (rem_m->desc.port == 0) { 
     911        return PJ_SUCCESS; 
     912    } 
     913 
     914    /* Verify the offer */ 
     915    status = verify_ice_sdp(tp_ice, sdp_pool, rem_sdp, media_index,  
     916                            PJ_ICE_SESS_ROLE_CONTROLLED,  
     917                            &tp_ice->rem_offer_state); 
     918    if (status != PJ_SUCCESS) { 
     919        set_no_ice(tp_ice, "Invalid SDP offer", status); 
     920        return status; 
     921    } 
     922 
     923    /* Does remote support ICE? */ 
     924    if (tp_ice->rem_offer_state.match_comp_cnt==0) { 
     925        set_no_ice(tp_ice, "No ICE found in SDP offer", PJ_SUCCESS); 
     926        return PJ_SUCCESS; 
     927    } 
     928 
     929    /* ICE ice_mismatch? */ 
     930    if (tp_ice->rem_offer_state.ice_mismatch) { 
     931        set_no_ice(tp_ice, "ICE ice_mismatch in remote offer", PJ_SUCCESS); 
     932        encode_ice_mismatch(sdp_pool, loc_sdp, media_index); 
     933        return PJ_SUCCESS; 
     934    } 
     935 
     936    /* Encode ICE in SDP */ 
     937    status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index,  
     938                                   tp_ice->rem_offer_state.match_comp_cnt, 
     939                                   PJ_FALSE); 
     940    if (status != PJ_SUCCESS) { 
     941        set_no_ice(tp_ice, "Error encoding SDP answer", status); 
     942        return status; 
     943    } 
     944 
     945    return PJ_SUCCESS; 
     946} 
     947 
     948 
     949/* Create subsequent SDP offer */ 
     950static pj_status_t create_subsequent_offer(struct transport_ice *tp_ice, 
     951                                           pj_pool_t *sdp_pool, 
     952                                           pjmedia_sdp_session *loc_sdp, 
     953                                           unsigned media_index) 
     954{ 
     955    unsigned comp_cnt; 
     956 
     957    if (pj_ice_strans_has_sess(tp_ice->ice_st) == PJ_FALSE) { 
     958        /* We don't have ICE */ 
     959        return PJ_SUCCESS; 
     960    } 
     961 
     962    comp_cnt = pj_ice_strans_get_running_comp_cnt(tp_ice->ice_st); 
     963    return encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index, 
     964                                 comp_cnt, PJ_FALSE); 
     965} 
     966 
     967 
     968/* Create subsequent SDP answer */ 
     969static pj_status_t create_subsequent_answer(struct transport_ice *tp_ice, 
     970                                            pj_pool_t *sdp_pool, 
     971                                            pjmedia_sdp_session *loc_sdp, 
     972                                            const pjmedia_sdp_session *rem_sdp, 
     973                                            unsigned media_index) 
     974{ 
     975    pj_status_t status; 
     976 
     977    /* We have a session */ 
     978    status = verify_ice_sdp(tp_ice, sdp_pool, rem_sdp, media_index,  
     979                            PJ_ICE_SESS_ROLE_CONTROLLED,  
     980                            &tp_ice->rem_offer_state); 
     981    if (status != PJ_SUCCESS) { 
     982        /* Something wrong with the offer */ 
     983        return status; 
     984    } 
     985 
     986    if (pj_ice_strans_has_sess(tp_ice->ice_st)) { 
     987        /* 
     988         * Received subsequent offer while we have ICE active. 
     989         */ 
     990 
     991        if (tp_ice->rem_offer_state.match_comp_cnt == 0) { 
     992            /* Remote no longer offers ICE */ 
     993            return PJ_SUCCESS; 
     994        } 
     995 
     996        if (tp_ice->rem_offer_state.ice_mismatch) { 
     997            encode_ice_mismatch(sdp_pool, loc_sdp, media_index); 
     998            return PJ_SUCCESS; 
     999        } 
     1000 
     1001        status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index, 
     1002                                       tp_ice->rem_offer_state.match_comp_cnt, 
     1003                                       tp_ice->rem_offer_state.ice_restart); 
     1004        if (status != PJ_SUCCESS) 
     1005            return status; 
     1006 
     1007        /* Done */ 
     1008 
     1009    } else { 
     1010        /* 
     1011         * Received subsequent offer while we DON'T have ICE active. 
     1012         */ 
     1013 
     1014        if (tp_ice->rem_offer_state.match_comp_cnt == 0) { 
     1015            /* Remote does not support ICE */ 
     1016            return PJ_SUCCESS; 
     1017        } 
     1018 
     1019        if (tp_ice->rem_offer_state.ice_mismatch) { 
     1020            encode_ice_mismatch(sdp_pool, loc_sdp, media_index); 
     1021            return PJ_SUCCESS; 
     1022        } 
     1023 
     1024        /* Looks like now remote is offering ICE, so we need to create 
     1025         * ICE session now. 
     1026         */ 
     1027        status = pj_ice_strans_init_ice(tp_ice->ice_st,  
     1028                                        PJ_ICE_SESS_ROLE_CONTROLLED, 
     1029                                        NULL, NULL); 
     1030        if (status != PJ_SUCCESS) { 
     1031            /* Fail to create new ICE session */ 
     1032            return status; 
     1033        } 
     1034 
     1035        status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index, 
     1036                                       tp_ice->rem_offer_state.match_comp_cnt, 
     1037                                       tp_ice->rem_offer_state.ice_restart); 
     1038        if (status != PJ_SUCCESS) 
     1039            return status; 
     1040 
     1041        /* Done */ 
     1042    } 
     1043 
     1044    return PJ_SUCCESS; 
     1045} 
     1046 
     1047 
    2301048/* 
    2311049 * For both UAC and UAS, pass in the SDP before sending it to remote. 
     
    2331051 */ 
    2341052static pj_status_t transport_media_create(pjmedia_transport *tp, 
    235                                           pj_pool_t *pool, 
     1053                                          pj_pool_t *sdp_pool, 
    2361054                                          unsigned options, 
    237                                           pjmedia_sdp_session *sdp_local, 
    2381055                                          const pjmedia_sdp_session *rem_sdp, 
    2391056                                          unsigned media_index) 
    2401057{ 
    2411058    struct transport_ice *tp_ice = (struct transport_ice*)tp; 
    242     pj_bool_t init_ice; 
    243     unsigned i; 
     1059    pj_ice_sess_role ice_role; 
    2441060    pj_status_t status; 
    2451061 
     1062    PJ_UNUSED_ARG(media_index); 
     1063    PJ_UNUSED_ARG(sdp_pool); 
     1064 
    2461065    tp_ice->media_option = options; 
     1066    tp_ice->oa_role = ROLE_NONE; 
     1067    tp_ice->initial_sdp = PJ_TRUE; 
     1068 
     1069    /* Init ICE, the initial role is set now based on availability of 
     1070     * rem_sdp, but it will be checked again later. 
     1071     */ 
     1072    ice_role = (rem_sdp==NULL ? PJ_ICE_SESS_ROLE_CONTROLLING :  
     1073                                PJ_ICE_SESS_ROLE_CONTROLLED); 
     1074    status = pj_ice_strans_init_ice(tp_ice->ice_st, ice_role, NULL, NULL); 
     1075 
     1076    /* Done */ 
     1077    return status; 
     1078} 
     1079 
     1080 
     1081static pj_status_t transport_encode_sdp(pjmedia_transport *tp, 
     1082                                        pj_pool_t *sdp_pool, 
     1083                                        pjmedia_sdp_session *sdp_local, 
     1084                                        const pjmedia_sdp_session *rem_sdp, 
     1085                                        unsigned media_index) 
     1086{ 
     1087    struct transport_ice *tp_ice = (struct transport_ice*)tp; 
     1088    pj_status_t status; 
    2471089 
    2481090    /* Validate media transport */ 
    2491091    /* For now, this transport only support RTP/AVP transport */ 
    2501092    if ((tp_ice->media_option & PJMEDIA_TPMED_NO_TRANSPORT_CHECKING) == 0) { 
    251         pjmedia_sdp_media *m_rem, *m_loc; 
    252  
    253         m_rem = rem_sdp? rem_sdp->media[media_index] : NULL; 
    254         m_loc = sdp_local->media[media_index]; 
    255  
    256         if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP) || 
    257            (m_rem && pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP))) 
     1093        pjmedia_sdp_media *loc_m, *rem_m; 
     1094 
     1095        rem_m = rem_sdp? rem_sdp->media[media_index] : NULL; 
     1096        loc_m = sdp_local->media[media_index]; 
     1097 
     1098        if (pj_stricmp(&loc_m->desc.transport, &STR_RTP_AVP) || 
     1099           (rem_m && pj_stricmp(&rem_m->desc.transport, &STR_RTP_AVP))) 
    2581100        { 
    259             pjmedia_sdp_media_deactivate(pool, m_loc); 
     1101            pjmedia_sdp_media_deactivate(sdp_pool, loc_m); 
    2601102            return PJMEDIA_SDP_EINPROTO; 
    2611103        } 
    2621104    } 
    2631105 
    264     /* If we are UAS, check that the incoming SDP contains support for ICE. */ 
    265     if (rem_sdp) { 
    266         const pjmedia_sdp_media *rem_m; 
    267  
    268         rem_m = rem_sdp->media[media_index]; 
    269  
    270         init_ice = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr, 
    271                                           "ice-ufrag", NULL) != NULL; 
    272         if (init_ice == PJ_FALSE) { 
    273             init_ice = pjmedia_sdp_attr_find2(rem_sdp->attr_count,  
    274                                               rem_sdp->attr, 
    275                                               "ice-ufrag", NULL) != NULL; 
    276         } 
    277  
    278         if (init_ice) { 
    279             init_ice = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr, 
    280                                               "candidate", NULL) != NULL; 
     1106    if (tp_ice->initial_sdp) { 
     1107        if (rem_sdp) { 
     1108            status = create_initial_answer(tp_ice, sdp_pool, sdp_local,  
     1109                                           rem_sdp, media_index); 
     1110        } else { 
     1111            status = create_initial_offer(tp_ice, sdp_pool, sdp_local, 
     1112                                          media_index); 
    2811113        } 
    2821114    } else { 
    283         init_ice = PJ_TRUE; 
    284     } 
    285  
    286     /* Init ICE */ 
    287     if (init_ice) { 
    288         pj_ice_sess_role ice_role; 
    289         enum { MAXLEN = 256 }; 
    290         pj_str_t ufrag, pass; 
    291         char *buffer; 
     1115        if (rem_sdp) { 
     1116            status = create_subsequent_answer(tp_ice, sdp_pool, sdp_local, 
     1117                                              rem_sdp, media_index); 
     1118        } else { 
     1119            status = create_subsequent_offer(tp_ice, sdp_pool, sdp_local, 
     1120                                             media_index); 
     1121        } 
     1122    } 
     1123 
     1124    if (status==PJ_SUCCESS) { 
     1125        if (rem_sdp) 
     1126            tp_ice->oa_role = ROLE_ANSWERER; 
     1127        else 
     1128            tp_ice->oa_role = ROLE_OFFERER; 
     1129    } 
     1130 
     1131    return status; 
     1132} 
     1133 
     1134 
     1135/* Start ICE session with the specified remote SDP */ 
     1136static pj_status_t start_ice(struct transport_ice *tp_ice, 
     1137                             pj_pool_t *tmp_pool, 
     1138                             const pjmedia_sdp_session *rem_sdp, 
     1139                             unsigned media_index) 
     1140{ 
     1141    pjmedia_sdp_media *rem_m = rem_sdp->media[media_index]; 
     1142    pjmedia_sdp_attr *ufrag_attr, *pwd_attr; 
     1143    pj_ice_sess_cand *cand; 
     1144    unsigned i, cand_cnt; 
     1145    pj_status_t status; 
     1146 
     1147    get_ice_attr(rem_sdp, rem_m, &ufrag_attr, &pwd_attr); 
     1148 
     1149    /* Allocate candidate array */ 
     1150    cand = (pj_ice_sess_cand*) 
     1151           pj_pool_calloc(tmp_pool, PJ_ICE_MAX_CAND,  
     1152                          sizeof(pj_ice_sess_cand)); 
     1153 
     1154    /* Get all candidates in the media */ 
     1155    cand_cnt = 0; 
     1156    for (i=0; i<rem_m->attr_count && cand_cnt < PJ_ICE_MAX_CAND; ++i) { 
    2921157        pjmedia_sdp_attr *attr; 
    293         unsigned comp; 
    294  
    295         ice_role = (rem_sdp==NULL ? PJ_ICE_SESS_ROLE_CONTROLLING :  
    296                                     PJ_ICE_SESS_ROLE_CONTROLLED); 
    297  
    298         ufrag.ptr = (char*) pj_pool_alloc(pool, PJ_ICE_UFRAG_LEN); 
    299         pj_create_random_string(ufrag.ptr, PJ_ICE_UFRAG_LEN); 
    300         ufrag.slen = PJ_ICE_UFRAG_LEN; 
    301  
    302         pass.ptr = (char*) pj_pool_alloc(pool, PJ_ICE_UFRAG_LEN); 
    303         pj_create_random_string(pass.ptr, PJ_ICE_UFRAG_LEN); 
    304         pass.slen = PJ_ICE_UFRAG_LEN; 
    305  
    306         status = pj_ice_strans_init_ice(tp_ice->ice_st, ice_role,  
    307                                         &ufrag, &pass); 
    308         if (status != PJ_SUCCESS) 
    309             return status; 
    310  
    311         /* Create ice-ufrag attribute */ 
    312         attr = pjmedia_sdp_attr_create(pool, "ice-ufrag", &ufrag); 
    313         sdp_local->attr[sdp_local->attr_count++] = attr; 
    314  
    315         /* Create ice-pwd attribute */ 
    316         attr = pjmedia_sdp_attr_create(pool, "ice-pwd", &pass); 
    317         sdp_local->attr[sdp_local->attr_count++] = attr; 
    318  
    319         /* Encode all candidates to SDP media */ 
    320  
    321         buffer = (char*) pj_pool_alloc(pool, MAXLEN); 
    322  
    323         for (comp=0; comp < tp_ice->comp_cnt; ++comp) { 
    324             unsigned cand_cnt; 
    325             pj_ice_sess_cand cand[PJ_ICE_ST_MAX_CAND]; 
    326  
    327             cand_cnt = PJ_ARRAY_SIZE(cand); 
    328             status = pj_ice_strans_enum_cands(tp_ice->ice_st, comp+1, 
    329                                               &cand_cnt, cand); 
    330             if (status != PJ_SUCCESS) 
    331                 return status; 
    332  
    333             for (i=0; i<cand_cnt; ++i) { 
    334                 pjmedia_sdp_media *m; 
    335                 pj_str_t value; 
    336  
    337                 value.slen = print_sdp_cand_attr(buffer, MAXLEN, &cand[i]); 
    338                 if (value.slen < 0) { 
    339                     pj_assert(!"Not enough buffer to print candidate"); 
    340                     return PJ_EBUG; 
    341                 } 
    342  
    343                 value.ptr = buffer; 
    344                 attr = pjmedia_sdp_attr_create(pool, "candidate", &value); 
    345                 m = sdp_local->media[media_index]; 
    346                 m->attr[m->attr_count++] = attr; 
    347             } 
    348         } 
    349     } 
    350  
    351     /* Done */ 
    352     return PJ_SUCCESS; 
    353 } 
    354  
    355  
    356 /* Parse a=candidate line */ 
    357 static pj_status_t parse_cand(pj_pool_t *pool, 
    358                               const pj_str_t *orig_input, 
    359                               pj_ice_sess_cand *cand) 
    360 { 
    361     pj_str_t input; 
    362     char *token, *host; 
    363     pj_str_t s; 
    364     pj_status_t status = PJNATH_EICEINCANDSDP; 
    365  
    366     pj_bzero(cand, sizeof(*cand)); 
    367     pj_strdup_with_null(pool, &input, orig_input); 
    368  
    369     /* Foundation */ 
    370     token = strtok(input.ptr, " "); 
    371     if (!token) { 
    372         PJ_LOG(5,(THIS_FILE, "Expecting ICE foundation in candidate")); 
    373         goto on_return; 
    374     } 
    375     pj_strdup2(pool, &cand->foundation, token); 
    376  
    377     /* Component ID */ 
    378     token = strtok(NULL, " "); 
    379     if (!token) { 
    380         PJ_LOG(5,(THIS_FILE, "Expecting ICE component ID in candidate")); 
    381         goto on_return; 
    382     } 
    383     cand->comp_id = (pj_uint8_t) atoi(token); 
    384  
    385     /* Transport */ 
    386     token = strtok(NULL, " "); 
    387     if (!token) { 
    388         PJ_LOG(5,(THIS_FILE, "Expecting ICE transport in candidate")); 
    389         goto on_return; 
    390     } 
    391     if (pj_ansi_stricmp(token, "UDP") != 0) { 
    392         PJ_LOG(5,(THIS_FILE,  
    393                   "Expecting ICE UDP transport only in candidate")); 
    394         goto on_return; 
    395     } 
    396  
    397     /* Priority */ 
    398     token = strtok(NULL, " "); 
    399     if (!token) { 
    400         PJ_LOG(5,(THIS_FILE, "Expecting ICE priority in candidate")); 
    401         goto on_return; 
    402     } 
    403     cand->prio = atoi(token); 
    404  
    405     /* Host */ 
    406     host = strtok(NULL, " "); 
    407     if (!host) { 
    408         PJ_LOG(5,(THIS_FILE, "Expecting ICE host in candidate")); 
    409         goto on_return; 
    410     } 
    411     if (pj_sockaddr_in_init(&cand->addr.ipv4, pj_cstr(&s, host), 0)) { 
    412         PJ_LOG(5,(THIS_FILE,  
    413                   "Expecting ICE IPv4 transport address in candidate")); 
    414         goto on_return; 
    415     } 
    416  
    417     /* Port */ 
    418     token = strtok(NULL, " "); 
    419     if (!token) { 
    420         PJ_LOG(5,(THIS_FILE, "Expecting ICE port number in candidate")); 
    421         goto on_return; 
    422     } 
    423     cand->addr.ipv4.sin_port = pj_htons((pj_uint16_t)atoi(token)); 
    424  
    425     /* typ */ 
    426     token = strtok(NULL, " "); 
    427     if (!token) { 
    428         PJ_LOG(5,(THIS_FILE, "Expecting ICE \"typ\" in candidate")); 
    429         goto on_return; 
    430     } 
    431     if (pj_ansi_stricmp(token, "typ") != 0) { 
    432         PJ_LOG(5,(THIS_FILE, "Expecting ICE \"typ\" in candidate")); 
    433         goto on_return; 
    434     } 
    435  
    436     /* candidate type */ 
    437     token = strtok(NULL, " "); 
    438     if (!token) { 
    439         PJ_LOG(5,(THIS_FILE, "Expecting ICE candidate type in candidate")); 
    440         goto on_return; 
    441     } 
    442  
    443     if (pj_ansi_stricmp(token, "host") == 0) { 
    444         cand->type = PJ_ICE_CAND_TYPE_HOST; 
    445  
    446     } else if (pj_ansi_stricmp(token, "srflx") == 0) { 
    447         cand->type = PJ_ICE_CAND_TYPE_SRFLX; 
    448  
    449     } else if (pj_ansi_stricmp(token, "relay") == 0) { 
    450         cand->type = PJ_ICE_CAND_TYPE_RELAYED; 
    451  
    452     } else if (pj_ansi_stricmp(token, "prflx") == 0) { 
    453         cand->type = PJ_ICE_CAND_TYPE_PRFLX; 
    454  
    455     } else { 
    456         PJ_LOG(5,(THIS_FILE, "Invalid ICE candidate type %s in candidate",  
    457                   token)); 
    458         goto on_return; 
    459     } 
    460  
    461  
    462     status = PJ_SUCCESS; 
    463  
    464 on_return: 
    465     return status; 
    466 } 
    467  
    468  
    469 /* Disable ICE when SDP from remote doesn't contain a=candidate line */ 
    470 static void set_no_ice(struct transport_ice *tp_ice, const char *reason) 
    471 { 
    472     PJ_LOG(4,(tp_ice->base.name,  
    473               "Disabling local ICE, reason=%s", reason)); 
    474     transport_media_stop(&tp_ice->base); 
     1158 
     1159        attr = rem_m->attr[i]; 
     1160 
     1161        if (pj_strcmp(&attr->name, &STR_CANDIDATE)!=0) 
     1162            continue; 
     1163 
     1164        /* Parse candidate */ 
     1165        status = parse_cand(tp_ice->base.name, tmp_pool, &attr->value,  
     1166                            &cand[cand_cnt]); 
     1167        if (status != PJ_SUCCESS) { 
     1168            PJ_LOG(4,(tp_ice->base.name,  
     1169                      "Error in parsing SDP candidate attribute '%.*s', " 
     1170                      "candidate is ignored", 
     1171                      (int)attr->value.slen, attr->value.ptr)); 
     1172            continue; 
     1173        } 
     1174 
     1175        cand_cnt++; 
     1176    } 
     1177 
     1178    /* Start ICE */ 
     1179    return pj_ice_strans_start_ice(tp_ice->ice_st, &ufrag_attr->value,  
     1180                                   &pwd_attr->value, cand_cnt, cand); 
    4751181} 
    4761182 
    4771183 
    4781184/* 
    479  * Start ICE checks when both offer and answer are available. 
     1185 * Start ICE checks when both offer and answer have been negotiated 
     1186 * by SDP negotiator. 
    4801187 */ 
    4811188static pj_status_t transport_media_start(pjmedia_transport *tp, 
    482                                          pj_pool_t *pool, 
    483                                          pjmedia_sdp_session *sdp_local, 
     1189                                         pj_pool_t *tmp_pool, 
     1190                                         const pjmedia_sdp_session *sdp_local, 
    4841191                                         const pjmedia_sdp_session *rem_sdp, 
    4851192                                         unsigned media_index) 
    4861193{ 
    4871194    struct transport_ice *tp_ice = (struct transport_ice*)tp; 
    488     const pjmedia_sdp_attr *attr; 
    489     unsigned i, cand_cnt; 
    490     pj_ice_sess_cand *cand; 
    491     const pjmedia_sdp_media *sdp_med; 
    492     pj_bool_t remote_is_lite = PJ_FALSE; 
    493     pj_bool_t ice_mismatch = PJ_FALSE; 
    494     pjmedia_sdp_conn *conn = NULL; 
    495     pj_sockaddr conn_addr; 
    496     pj_bool_t conn_found_in_candidate = PJ_FALSE; 
    497     pj_str_t uname, pass; 
     1195    pjmedia_sdp_media *rem_m; 
     1196    enum oa_role current_oa_role; 
     1197    pj_bool_t initial_oa; 
    4981198    pj_status_t status; 
    4991199 
    500     PJ_ASSERT_RETURN(tp && pool && rem_sdp, PJ_EINVAL); 
     1200    PJ_ASSERT_RETURN(tp && tmp_pool && rem_sdp, PJ_EINVAL); 
    5011201    PJ_ASSERT_RETURN(media_index < rem_sdp->media_count, PJ_EINVAL); 
    5021202 
    503     sdp_med = rem_sdp->media[media_index]; 
    504  
    505     /* Validate media transport */ 
    506     /* By now, this transport only support RTP/AVP transport */ 
    507     if ((tp_ice->media_option & PJMEDIA_TPMED_NO_TRANSPORT_CHECKING) == 0) { 
    508         pjmedia_sdp_media *m_rem, *m_loc; 
    509  
    510         m_rem = rem_sdp->media[media_index]; 
    511         m_loc = sdp_local->media[media_index]; 
    512  
    513         if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP) || 
    514            (pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP))) 
     1203    rem_m = rem_sdp->media[media_index]; 
     1204 
     1205    initial_oa = tp_ice->initial_sdp; 
     1206    current_oa_role = tp_ice->oa_role; 
     1207 
     1208    /* SDP has been negotiated */ 
     1209    tp_ice->initial_sdp = PJ_FALSE; 
     1210    tp_ice->oa_role = ROLE_NONE; 
     1211 
     1212    /* Nothing to do if we don't have ICE session */ 
     1213    if (pj_ice_strans_has_sess(tp_ice->ice_st) == PJ_FALSE) { 
     1214        return PJ_SUCCESS; 
     1215    } 
     1216 
     1217    /* Processing depends on the offer/answer role */ 
     1218    if (current_oa_role == ROLE_OFFERER) { 
     1219        /* 
     1220         * We are offerer. So this will be the first time we see the 
     1221         * remote's SDP. 
     1222         */ 
     1223        struct sdp_state answer_state; 
     1224 
     1225        /* Verify the answer */ 
     1226        status = verify_ice_sdp(tp_ice, tmp_pool, rem_sdp, media_index,  
     1227                                PJ_ICE_SESS_ROLE_CONTROLLING, &answer_state); 
     1228        if (status != PJ_SUCCESS) { 
     1229            /* Something wrong in the SDP answer */ 
     1230            set_no_ice(tp_ice, "Invalid remote SDP answer", status); 
     1231            return status; 
     1232        } 
     1233 
     1234        /* Does it have ICE? */ 
     1235        if (answer_state.match_comp_cnt == 0) { 
     1236            /* Remote doesn't support ICE */ 
     1237            set_no_ice(tp_ice, "Remote answer doesn't support ICE",  
     1238                       PJ_SUCCESS); 
     1239            return PJ_SUCCESS; 
     1240        } 
     1241 
     1242        /* Check if remote has reported ice-mismatch */ 
     1243        if (pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr,  
     1244                                  &STR_ICE_MISMATCH, NULL) != NULL) 
    5151245        { 
    516             pjmedia_sdp_media_deactivate(pool, m_loc); 
    517             return PJMEDIA_SDP_EINPROTO; 
    518         } 
    519     } 
    520  
    521     /* Get the SDP connection for the media stream. 
    522      * We'll verify later if the SDP connection address is specified  
    523      * as one of the candidate. 
    524      */ 
    525     conn = sdp_med->conn; 
    526     if (conn == NULL) 
    527         conn = rem_sdp->conn; 
    528  
    529     if (conn == NULL) { 
    530         /* Unable to find SDP connection */ 
    531         return PJMEDIA_SDP_EMISSINGCONN; 
    532     } 
    533  
    534     pj_sockaddr_in_init(&conn_addr.ipv4, &conn->addr,  
    535                         (pj_uint16_t)sdp_med->desc.port); 
    536  
    537     /* Find ice-ufrag attribute in media descriptor */ 
    538     attr = pjmedia_sdp_attr_find2(sdp_med->attr_count, sdp_med->attr, 
    539                                   "ice-ufrag", NULL); 
    540     if (attr == NULL) { 
    541         /* Find ice-ufrag attribute in session descriptor */ 
    542         attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr, 
    543                                       "ice-ufrag", NULL); 
    544         if (attr == NULL) { 
    545             set_no_ice(tp_ice, "ice-ufrag attribute not found"); 
     1246            /* Remote has reported ice-mismatch */ 
     1247            set_no_ice(tp_ice,  
     1248                       "Remote answer contains 'ice-mismatch' attribute",  
     1249                       PJ_SUCCESS); 
    5461250            return PJ_SUCCESS; 
    5471251        } 
    548     } 
    549     uname = attr->value; 
    550  
    551     /* Find ice-pwd attribute in media descriptor */ 
    552     attr = pjmedia_sdp_attr_find2(sdp_med->attr_count, sdp_med->attr, 
    553                                   "ice-pwd", NULL); 
    554     if (attr == NULL) { 
    555         /* Find ice-pwd attribute in session descriptor */ 
    556         attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr, 
    557                                       "ice-pwd", NULL); 
    558         if (attr == NULL) { 
    559             set_no_ice(tp_ice, "ice-pwd attribute not found"); 
     1252 
     1253        /* Check if remote has indicated a restart */ 
     1254        if (answer_state.ice_restart) { 
     1255            PJ_LOG(2,(tp_ice->base.name,  
     1256                      "Warning: remote has signalled ICE restart in SDP " 
     1257                      "answer which is disallowed. Remote ICE negotiation" 
     1258                      " may fail.")); 
     1259        } 
     1260 
     1261        /* Check if the answer itself is mismatched */ 
     1262        if (answer_state.ice_mismatch) { 
     1263            /* This happens either when a B2BUA modified remote answer but 
     1264             * strangely didn't modify our offer, or remote is not capable 
     1265             * of detecting mismatch in our offer (it didn't put  
     1266             * 'ice-mismatch' attribute in the answer). 
     1267             */ 
     1268            PJ_LOG(2,(tp_ice->base.name,  
     1269                      "Warning: remote answer mismatch, but it does not " 
     1270                      "reject our offer with 'ice-mismatch'. ICE negotiation " 
     1271                      "may fail")); 
     1272        } 
     1273 
     1274        /* Do nothing if ICE is complete or running */ 
     1275        if (pj_ice_strans_sess_is_running(tp_ice->ice_st)) { 
     1276            PJ_LOG(4,(tp_ice->base.name, 
     1277                      "Ignored offer/answer because ICE is running")); 
    5601278            return PJ_SUCCESS; 
    5611279        } 
    562     } 
    563     pass = attr->value; 
    564  
    565     /* Allocate candidate array */ 
    566     cand = (pj_ice_sess_cand*) 
    567            pj_pool_calloc(pool, PJ_ICE_MAX_CAND, sizeof(pj_ice_sess_cand)); 
    568  
    569     /* Get all candidates in the media */ 
    570     cand_cnt = 0; 
    571     for (i=0; i<sdp_med->attr_count && cand_cnt < PJ_ICE_MAX_CAND; ++i) { 
    572         pjmedia_sdp_attr *attr; 
    573  
    574         attr = sdp_med->attr[i]; 
    575  
    576         /* Detect if remote is ICE lite */ 
    577         if (pj_stricmp(&attr->name, &STR_ICE_LITE)==0) { 
    578             remote_is_lite = PJ_TRUE; 
    579             continue; 
    580         } 
    581  
    582         /* Detect if remote has reported ICE mismatch */ 
    583         if (pj_stricmp(&attr->name, &STR_ICE_MISMATCH)==0) { 
    584             ice_mismatch = PJ_TRUE; 
    585             continue; 
    586         } 
    587  
    588         if (pj_stricmp(&attr->name, &STR_CANDIDATE)!=0) 
    589             continue; 
    590  
    591         /* Parse candidate */ 
    592         status = parse_cand(pool, &attr->value, &cand[cand_cnt]); 
    593         if (status != PJ_SUCCESS) { 
    594             PJ_LOG(4,(THIS_FILE,  
    595                       "Error in parsing SDP candidate attribute, " 
    596                       "candidate is ignored")); 
    597             continue; 
    598         } 
    599  
    600         /* Check if this candidate is equal to the connection line */ 
    601         if (!conn_found_in_candidate && 
    602             pj_memcmp(&conn_addr.ipv4, &cand[cand_cnt].addr.ipv4, 
    603                       sizeof(pj_sockaddr_in))==0) 
    604         { 
    605             conn_found_in_candidate = PJ_TRUE; 
    606         } 
    607  
    608         cand_cnt++; 
    609     } 
    610  
    611     /* Handle ice-mismatch case */ 
    612     if (ice_mismatch) { 
    613         set_no_ice(tp_ice, "remote reported ice-mismatch"); 
    614         return PJ_SUCCESS; 
    615     } 
    616  
    617     /* Handle case where SDP connection address is not specified as 
    618      * one of the candidate. 
    619      */ 
    620     if (!conn_found_in_candidate) { 
    621         set_no_ice(tp_ice, "local reported ice-mismatch"); 
    622         return PJ_SUCCESS; 
    623     } 
    624  
    625     /* If our role was controlled but it turns out that remote is  
    626      * a lite implementation, change our role to controlling. 
    627      */ 
    628     if (remote_is_lite &&  
    629         pj_ice_strans_get_role(tp_ice->ice_st) == PJ_ICE_SESS_ROLE_CONTROLLED) 
    630     { 
    631         pj_ice_strans_change_role(tp_ice->ice_st,  
    632                                   PJ_ICE_SESS_ROLE_CONTROLLING); 
    633     } 
    634  
    635     /* Start ICE */ 
    636     return pj_ice_strans_start_ice(tp_ice->ice_st, &uname, &pass,  
    637                                    cand_cnt, cand); 
     1280 
     1281        if (pj_ice_strans_sess_is_complete(tp_ice->ice_st)) { 
     1282            PJ_LOG(4,(tp_ice->base.name, "ICE session unchanged")); 
     1283            return PJ_SUCCESS; 
     1284        } 
     1285 
     1286        /* Start ICE */ 
     1287 
     1288    } else { 
     1289        /* 
     1290         * We are answerer. We've seen and negotiated remote's SDP 
     1291         * before, and the result is in "rem_offer_state". 
     1292         */ 
     1293        const pjmedia_sdp_attr *ufrag_attr, *pwd_attr; 
     1294 
     1295        /* Check for ICE in remote offer */ 
     1296        if (tp_ice->rem_offer_state.match_comp_cnt == 0) { 
     1297            /* No ICE attribute present */ 
     1298            set_no_ice(tp_ice, "Remote no longer offers ICE", 
     1299                       PJ_SUCCESS); 
     1300            return PJ_SUCCESS; 
     1301        } 
     1302 
     1303        /* Check for ICE ice_mismatch condition in the offer */ 
     1304        if (tp_ice->rem_offer_state.ice_mismatch) { 
     1305            set_no_ice(tp_ice, "Remote offer mismatch: ",  
     1306                       PJNATH_EICEMISMATCH); 
     1307            return PJ_SUCCESS; 
     1308        } 
     1309 
     1310        /* If ICE is complete and remote doesn't request restart, 
     1311         * then leave the session as is. 
     1312         */ 
     1313        if (!initial_oa && tp_ice->rem_offer_state.ice_restart == PJ_FALSE) { 
     1314            /* Remote has not requested ICE restart, so session is 
     1315             * unchanged. 
     1316             */ 
     1317            PJ_LOG(4,(tp_ice->base.name, "ICE session unchanged")); 
     1318            return PJ_SUCCESS; 
     1319        } 
     1320 
     1321        /* Either remote has requested ICE restart or this is our 
     1322         * first answer.  
     1323         */ 
     1324 
     1325        /* Stop ICE */ 
     1326        if (!initial_oa) { 
     1327            set_no_ice(tp_ice, "restarting by remote request..", PJ_SUCCESS); 
     1328 
     1329            /* We have put new ICE ufrag and pwd in the answer. Now 
     1330             * create a new ICE session with that ufrag/pwd pair. 
     1331             */ 
     1332            get_ice_attr(sdp_local, sdp_local->media[media_index],  
     1333                         &ufrag_attr, &pwd_attr); 
     1334            status = pj_ice_strans_init_ice(tp_ice->ice_st,  
     1335                                            tp_ice->rem_offer_state.local_role, 
     1336                                            &ufrag_attr->value,  
     1337                                            &pwd_attr->value); 
     1338            if (status != PJ_SUCCESS) { 
     1339                PJ_LOG(1,(tp_ice->base.name,  
     1340                          "ICE re-initialization failed (status=%d)!", 
     1341                          status)); 
     1342                return status; 
     1343            } 
     1344        } 
     1345 
     1346        /* start ICE */ 
     1347    } 
     1348 
     1349    /* Now start ICE */ 
     1350    status = start_ice(tp_ice, tmp_pool, rem_sdp, media_index); 
     1351    if (status != PJ_SUCCESS) { 
     1352        PJ_LOG(1,(tp_ice->base.name,  
     1353                  "ICE restart failed (status=%d)!", 
     1354                  status)); 
     1355        return status; 
     1356    } 
     1357 
     1358    /* Done */ 
     1359 
     1360    return PJ_SUCCESS; 
    6381361} 
    6391362 
     
    6421365{ 
    6431366    struct transport_ice *tp_ice = (struct transport_ice*)tp; 
    644     return pj_ice_strans_stop_ice(tp_ice->ice_st); 
     1367     
     1368    set_no_ice(tp_ice, "media stop requested", PJ_SUCCESS); 
     1369 
     1370    return PJ_SUCCESS; 
    6451371} 
    6461372 
  • pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c

    r2015 r2032  
    9292    pjmedia_srtp_crypto  rx_policy; 
    9393 
     94    /* Temporary policy for negotiation */ 
     95    pjmedia_srtp_crypto  tx_policy_neg; 
     96    pjmedia_srtp_crypto  rx_policy_neg; 
     97 
    9498    /* libSRTP contexts */ 
    9599    srtp_t               srtp_tx_ctx; 
     
    106110         
    107111    /* Transport information */ 
    108     pjmedia_transport   *real_tp; /**< Underlying transport.       */ 
     112    pjmedia_transport   *member_tp; /**< Underlying transport.       */ 
     113 
     114    /* When in SRTP optional mode, instead of always offering RTP/AVP, 
     115     * we should create offer based on remote preference. At the first time, 
     116     * remote preference is unknown, it is known after media_start() called. 
     117     * So next time the same session need to create an offer, it will create 
     118     * SDP with transport type based on remote preference. 
     119     */ 
     120    pj_bool_t            remote_prefer_rtp_savp; 
    109121 
    110122} transport_srtp; 
     
    152164                                       pj_size_t size); 
    153165static pj_status_t transport_media_create(pjmedia_transport *tp, 
    154                                        pj_pool_t *pool, 
     166                                       pj_pool_t *sdp_pool, 
    155167                                       unsigned options, 
     168                                       const pjmedia_sdp_session *sdp_remote, 
     169                                       unsigned media_index); 
     170static pj_status_t transport_encode_sdp(pjmedia_transport *tp, 
     171                                       pj_pool_t *sdp_pool, 
    156172                                       pjmedia_sdp_session *sdp_local, 
    157173                                       const pjmedia_sdp_session *sdp_remote, 
     
    159175static pj_status_t transport_media_start (pjmedia_transport *tp, 
    160176                                       pj_pool_t *pool, 
    161                                        pjmedia_sdp_session *sdp_local, 
     177                                       const pjmedia_sdp_session *sdp_local, 
    162178                                       const pjmedia_sdp_session *sdp_remote, 
    163179                                       unsigned media_index); 
     
    179195    &transport_send_rtcp2, 
    180196    &transport_media_create, 
     197    &transport_encode_sdp, 
    181198    &transport_media_start, 
    182199    &transport_media_stop, 
     
    332349    srtp->session_inited = PJ_FALSE; 
    333350    srtp->bypass_srtp = PJ_FALSE; 
     351    srtp->remote_prefer_rtp_savp = PJ_FALSE; 
    334352 
    335353    if (opt) { 
     
    368386 
    369387    /* Set underlying transport */ 
    370     srtp->real_tp = tp; 
     388    srtp->member_tp = tp; 
    371389 
    372390    /* Done */ 
     
    458476    srtp->tx_policy = *tx; 
    459477    pj_strset(&srtp->tx_policy.key,  srtp->tx_key, tx->key.slen); 
    460     srtp->tx_policy.name =  
    461                         pj_str(crypto_suites[get_crypto_idx(&tx->name)].name); 
     478    srtp->tx_policy.name=pj_str(crypto_suites[get_crypto_idx(&tx->name)].name); 
    462479 
    463480 
     
    492509    srtp->rx_policy = *rx; 
    493510    pj_strset(&srtp->rx_policy.key,  srtp->rx_key, rx->key.slen); 
    494     srtp->rx_policy.name =  
    495                         pj_str(crypto_suites[get_crypto_idx(&rx->name)].name); 
     511    srtp->rx_policy.name=pj_str(crypto_suites[get_crypto_idx(&rx->name)].name); 
    496512 
    497513    /* Declare SRTP session initialized */ 
     
    551567    PJ_ASSERT_RETURN(tp, NULL); 
    552568 
    553     return srtp->real_tp; 
     569    return srtp->member_tp; 
    554570} 
    555571 
     
    578594              sizeof(srtp_info)); 
    579595 
    580     return pjmedia_transport_get_info(srtp->real_tp, info); 
     596    return pjmedia_transport_get_info(srtp->member_tp, info); 
    581597} 
    582598 
     
    595611 
    596612    /* Attach itself to transport */ 
    597     status = pjmedia_transport_attach(srtp->real_tp, srtp, rem_addr, rem_rtcp, 
     613    status = pjmedia_transport_attach(srtp->member_tp, srtp, rem_addr, rem_rtcp, 
    598614                                      addr_len, &srtp_rtp_cb, &srtp_rtcp_cb); 
    599615    if (status != PJ_SUCCESS) 
     
    615631    PJ_ASSERT_ON_FAIL(tp, return); 
    616632 
    617     if (srtp->real_tp) { 
    618         pjmedia_transport_detach(srtp->real_tp, srtp); 
     633    if (srtp->member_tp) { 
     634        pjmedia_transport_detach(srtp->member_tp, srtp); 
    619635    } 
    620636 
     
    635651 
    636652    if (srtp->bypass_srtp) 
    637         return pjmedia_transport_send_rtp(srtp->real_tp, pkt, size); 
     653        return pjmedia_transport_send_rtp(srtp->member_tp, pkt, size); 
    638654 
    639655    if (!srtp->session_inited) 
     
    648664    err = srtp_protect(srtp->srtp_tx_ctx, srtp->tx_buffer, &len); 
    649665    if (err == err_status_ok) { 
    650         status = pjmedia_transport_send_rtp(srtp->real_tp, srtp->tx_buffer, len); 
     666        status = pjmedia_transport_send_rtp(srtp->member_tp, srtp->tx_buffer, len); 
    651667    } else { 
    652668        status = PJMEDIA_ERRNO_FROM_LIBSRTP(err); 
     
    677693 
    678694    if (srtp->bypass_srtp) { 
    679         return pjmedia_transport_send_rtcp2(srtp->real_tp, addr, addr_len,  
     695        return pjmedia_transport_send_rtcp2(srtp->member_tp, addr, addr_len,  
    680696                                            pkt, size); 
    681697    } 
     
    693709     
    694710    if (err == err_status_ok) { 
    695         status = pjmedia_transport_send_rtcp2(srtp->real_tp, addr, addr_len, 
     711        status = pjmedia_transport_send_rtcp2(srtp->member_tp, addr, addr_len, 
    696712                                              srtp->tx_buffer, len); 
    697713    } else { 
     
    711727    transport_srtp *srtp = (transport_srtp *) tp; 
    712728 
    713     return pjmedia_transport_simulate_lost(srtp->real_tp, dir, pct_lost); 
     729    return pjmedia_transport_simulate_lost(srtp->member_tp, dir, pct_lost); 
    714730} 
    715731 
     
    723739    pjmedia_transport_detach(tp, NULL); 
    724740     
    725     if (srtp->setting.close_member_tp && srtp->real_tp) { 
    726         pjmedia_transport_close(srtp->real_tp); 
     741    if (srtp->setting.close_member_tp && srtp->member_tp) { 
     742        pjmedia_transport_close(srtp->member_tp); 
    727743    } 
    728744 
     
    956972 
    957973static pj_status_t transport_media_create(pjmedia_transport *tp, 
    958                                           pj_pool_t *pool, 
     974                                          pj_pool_t *sdp_pool, 
    959975                                          unsigned options, 
    960                                           pjmedia_sdp_session *sdp_local, 
    961976                                          const pjmedia_sdp_session *sdp_remote, 
    962977                                          unsigned media_index) 
     978{ 
     979    struct transport_srtp *srtp = (struct transport_srtp*) tp; 
     980    unsigned member_tp_option; 
     981 
     982    PJ_ASSERT_RETURN(tp, PJ_EINVAL); 
     983     
     984    pj_bzero(&srtp->rx_policy_neg, sizeof(srtp->rx_policy_neg)); 
     985    pj_bzero(&srtp->tx_policy_neg, sizeof(srtp->tx_policy_neg)); 
     986 
     987    srtp->media_option = options; 
     988    member_tp_option = options | PJMEDIA_TPMED_NO_TRANSPORT_CHECKING; 
     989 
     990    srtp->offerer_side = sdp_remote == NULL; 
     991 
     992    /* Validations */ 
     993    if (srtp->offerer_side) { 
     994 
     995        if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) 
     996            goto BYPASS_SRTP; 
     997 
     998    } else { 
     999 
     1000        pjmedia_sdp_media *m_rem; 
     1001         
     1002        m_rem = sdp_remote->media[media_index]; 
     1003 
     1004        /* Nothing to do on inactive media stream */ 
     1005        if (pjmedia_sdp_media_find_attr(m_rem, &ID_INACTIVE, NULL)) 
     1006            goto BYPASS_SRTP; 
     1007 
     1008        /* Validate remote media transport based on SRTP usage option. 
     1009         */ 
     1010        switch (srtp->setting.use) { 
     1011            case PJMEDIA_SRTP_DISABLED: 
     1012                if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0) 
     1013                    return PJMEDIA_SRTP_ESDPINTRANSPORT; 
     1014                goto BYPASS_SRTP; 
     1015            case PJMEDIA_SRTP_OPTIONAL: 
     1016                break; 
     1017            case PJMEDIA_SRTP_MANDATORY: 
     1018                if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0) 
     1019                    return PJMEDIA_SRTP_ESDPINTRANSPORT; 
     1020                break; 
     1021        } 
     1022 
     1023    } 
     1024    goto PROPAGATE_MEDIA_CREATE; 
     1025 
     1026BYPASS_SRTP: 
     1027    srtp->bypass_srtp = PJ_TRUE; 
     1028    member_tp_option &= ~PJMEDIA_TPMED_NO_TRANSPORT_CHECKING; 
     1029 
     1030PROPAGATE_MEDIA_CREATE: 
     1031    return pjmedia_transport_media_create(srtp->member_tp, sdp_pool,  
     1032                                          member_tp_option, sdp_remote, 
     1033                                          media_index); 
     1034} 
     1035 
     1036static pj_status_t transport_encode_sdp(pjmedia_transport *tp, 
     1037                                        pj_pool_t *sdp_pool, 
     1038                                        pjmedia_sdp_session *sdp_local, 
     1039                                        const pjmedia_sdp_session *sdp_remote, 
     1040                                        unsigned media_index) 
    9631041{ 
    9641042    struct transport_srtp *srtp = (struct transport_srtp*) tp; 
     
    9711049    pj_str_t attr_value; 
    9721050    unsigned i, j; 
    973     unsigned member_tp_option; 
    974  
    975     PJ_ASSERT_RETURN(tp && pool && sdp_local, PJ_EINVAL); 
     1051 
     1052    PJ_ASSERT_RETURN(tp && sdp_pool && sdp_local, PJ_EINVAL); 
    9761053     
    977     srtp->media_option = options; 
    978     member_tp_option = options | PJMEDIA_TPMED_NO_TRANSPORT_CHECKING; 
    979  
    980     pj_bzero(&srtp->rx_policy, sizeof(srtp->tx_policy)); 
    981     pj_bzero(&srtp->tx_policy, sizeof(srtp->rx_policy)); 
     1054    srtp->offerer_side = sdp_remote == NULL; 
    9821055 
    9831056    m_rem = sdp_remote ? sdp_remote->media[media_index] : NULL; 
    9841057    m_loc = sdp_local->media[media_index]; 
    9851058 
    986     /* bypass if media transport is not RTP/AVP or RTP/SAVP */ 
     1059    /* Bypass if media transport is not RTP/AVP or RTP/SAVP */ 
    9871060    if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP)  != 0 &&  
    9881061        pj_stricmp(&m_loc->desc.transport, &ID_RTP_SAVP) != 0) 
     
    9921065    if (pjmedia_sdp_media_find_attr(m_loc, &ID_INACTIVE, NULL) ||  
    9931066        (m_rem && pjmedia_sdp_media_find_attr(m_rem, &ID_INACTIVE, NULL))) 
    994     { 
    9951067        goto BYPASS_SRTP; 
    996     } 
    997  
    998     srtp->offerer_side = !sdp_remote; 
    9991068 
    10001069    /* Check remote media transport & set local media transport  
     
    10021071     */ 
    10031072    if (srtp->offerer_side) { 
    1004         if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) { 
    1005             goto BYPASS_SRTP; 
    1006         } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) { 
    1007             m_loc->desc.transport = ID_RTP_AVP; 
    1008         } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) { 
    1009             m_loc->desc.transport = ID_RTP_SAVP; 
     1073 
     1074        /* Generate transport */ 
     1075        switch (srtp->setting.use) { 
     1076            case PJMEDIA_SRTP_DISABLED: 
     1077                goto BYPASS_SRTP; 
     1078            case PJMEDIA_SRTP_OPTIONAL: 
     1079                m_loc->desc.transport = srtp->remote_prefer_rtp_savp? 
     1080                                        ID_RTP_SAVP : ID_RTP_AVP; 
     1081                break; 
     1082            case PJMEDIA_SRTP_MANDATORY: 
     1083                m_loc->desc.transport = ID_RTP_SAVP; 
     1084                break; 
    10101085        } 
     1086 
     1087        /* Generate crypto attribute if not yet */ 
     1088        if (pjmedia_sdp_media_find_attr(m_loc, &ID_CRYPTO, NULL) == NULL) { 
     1089            for (i=0; i<srtp->setting.crypto_count; ++i) { 
     1090                /* Offer crypto-suites based on setting. */ 
     1091                buffer_len = MAXLEN; 
     1092                status = generate_crypto_attr_value(srtp->pool, buffer, &buffer_len, 
     1093                                                    &srtp->setting.crypto[i], 
     1094                                                    i+1); 
     1095                if (status != PJ_SUCCESS) 
     1096                    return status; 
     1097 
     1098                /* If buffer_len==0, just skip the crypto attribute. */ 
     1099                if (buffer_len) { 
     1100                    pj_strset(&attr_value, buffer, buffer_len); 
     1101                    attr = pjmedia_sdp_attr_create(srtp->pool, ID_CRYPTO.ptr,  
     1102                                                   &attr_value); 
     1103                    m_loc->attr[m_loc->attr_count++] = attr; 
     1104                } 
     1105            } 
     1106        } 
     1107 
    10111108    } else { 
    1012         if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) { 
    1013             if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0) { 
    1014                 DEACTIVATE_MEDIA(pool, m_loc); 
    1015                 return PJMEDIA_SRTP_ESDPINTRANSPORT; 
     1109        /* Answerer side */ 
     1110 
     1111        pj_assert(sdp_remote && m_rem); 
     1112 
     1113        /* Generate transport */ 
     1114        switch (srtp->setting.use) { 
     1115            case PJMEDIA_SRTP_DISABLED: 
     1116                if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0) 
     1117                    return PJMEDIA_SRTP_ESDPINTRANSPORT; 
     1118                goto BYPASS_SRTP; 
     1119            case PJMEDIA_SRTP_OPTIONAL: 
     1120                m_loc->desc.transport = m_rem->desc.transport; 
     1121                break; 
     1122            case PJMEDIA_SRTP_MANDATORY: 
     1123                if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0) 
     1124                    return PJMEDIA_SRTP_ESDPINTRANSPORT; 
     1125                m_loc->desc.transport = ID_RTP_SAVP; 
     1126                break; 
     1127        } 
     1128 
     1129        /* Generate crypto attribute if not yet */ 
     1130        if (pjmedia_sdp_media_find_attr(m_loc, &ID_CRYPTO, NULL) == NULL) { 
     1131 
     1132            pjmedia_srtp_crypto tmp_rx_crypto; 
     1133            pj_bool_t has_crypto_attr = PJ_FALSE; 
     1134            int matched_idx = -1; 
     1135            int chosen_tag = 0; 
     1136            int tags[64]; /* assume no more than 64 crypto attrs in a media */ 
     1137            int cr_attr_count = 0; 
     1138 
     1139            /* Find supported crypto-suite, get the tag, and assign policy_local */ 
     1140            for (i=0; i<m_rem->attr_count; ++i) { 
     1141                if (pj_stricmp(&m_rem->attr[i]->name, &ID_CRYPTO) != 0) 
     1142                    continue; 
     1143 
     1144                has_crypto_attr = PJ_TRUE; 
     1145 
     1146                status = parse_attr_crypto(srtp->pool, m_rem->attr[i],  
     1147                                           &tmp_rx_crypto, &tags[cr_attr_count]); 
     1148                if (status != PJ_SUCCESS) 
     1149                    return status; 
     1150          
     1151                /* Check duplicated tag */ 
     1152                for (j=0; j<cr_attr_count; ++j) { 
     1153                    if (tags[j] == tags[cr_attr_count]) { 
     1154                        DEACTIVATE_MEDIA(sdp_pool, m_loc); 
     1155                        return PJMEDIA_SRTP_ESDPDUPCRYPTOTAG; 
     1156                    } 
     1157                } 
     1158 
     1159                if (matched_idx == -1) { 
     1160                    /* lets see if the crypto-suite offered is supported */ 
     1161                    for (j=0; j<srtp->setting.crypto_count; ++j) 
     1162                        if (pj_stricmp(&tmp_rx_crypto.name,  
     1163                                       &srtp->setting.crypto[j].name) == 0) 
     1164                        { 
     1165                            int cs_idx = get_crypto_idx(&tmp_rx_crypto.name); 
     1166 
     1167                            /* Force to use test key */ 
     1168                            /* bad keys for snom: */ 
     1169                            //char *hex_test_key = "58b29c5c8f42308120ce857e439f2d" 
     1170                            //               "7810a8b10ad0b1446be5470faea496"; 
     1171                            //char *hex_test_key = "20a26aac7ba062d356ff52b61e3993" 
     1172                            //               "ccb78078f12c64db94b9c294927fd0"; 
     1173                            //pj_str_t *test_key = &srtp->setting.crypto[j].key; 
     1174                            //char  *raw_test_key = pj_pool_zalloc(srtp->pool, 64); 
     1175                            //hex_string_to_octet_string( 
     1176                            //          raw_test_key, 
     1177                            //          hex_test_key, 
     1178                            //          strlen(hex_test_key)); 
     1179                            //pj_strset(test_key, raw_test_key,  
     1180                            //    crypto_suites[cs_idx].cipher_key_len); 
     1181                            /* EO Force to use test key */ 
     1182 
     1183                            if (tmp_rx_crypto.key.slen !=  
     1184                                (int)crypto_suites[cs_idx].cipher_key_len) 
     1185                                return PJMEDIA_SRTP_EINKEYLEN; 
     1186 
     1187                            srtp->rx_policy_neg = tmp_rx_crypto; 
     1188                            chosen_tag = tags[cr_attr_count]; 
     1189                            matched_idx = j; 
     1190                            break; 
     1191                        } 
     1192                } 
     1193                cr_attr_count++; 
    10161194            } 
    1017             goto BYPASS_SRTP; 
    1018         } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) { 
    1019                 m_loc->desc.transport = m_rem->desc.transport; 
    1020         } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) { 
    1021             if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0) { 
    1022                 DEACTIVATE_MEDIA(pool, m_loc); 
    1023                 return PJMEDIA_SRTP_ESDPINTRANSPORT; 
     1195 
     1196            /* Check crypto negotiation result */ 
     1197            switch (srtp->setting.use) { 
     1198                case PJMEDIA_SRTP_DISABLED: 
     1199                    pj_assert(!"Should never reach here"); 
     1200                    break; 
     1201 
     1202                case PJMEDIA_SRTP_OPTIONAL: 
     1203                    /* bypass SRTP when no crypto-attr and remote uses RTP/AVP */ 
     1204                    if (!has_crypto_attr &&  
     1205                        pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0) 
     1206                        goto BYPASS_SRTP; 
     1207                    /* bypass SRTP when nothing match and remote uses RTP/AVP */ 
     1208                    else if (matched_idx == -1 &&  
     1209                        pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0) 
     1210                        goto BYPASS_SRTP; 
     1211                    break; 
     1212 
     1213                case PJMEDIA_SRTP_MANDATORY: 
     1214                    /* Do nothing, intentional */ 
     1215                    break; 
    10241216            } 
    1025             m_loc->desc.transport = ID_RTP_SAVP; 
    1026         } 
    1027     } 
    1028  
    1029     /* Generate crypto attribute */ 
    1030     if (srtp->offerer_side) { 
    1031         for (i=0; i<srtp->setting.crypto_count; ++i) { 
    1032             /* Offer crypto-suites based on setting. */ 
     1217 
     1218            /* No crypto attr */ 
     1219            if (!has_crypto_attr) { 
     1220                DEACTIVATE_MEDIA(sdp_pool, m_loc); 
     1221                return PJMEDIA_SRTP_ESDPREQCRYPTO; 
     1222            } 
     1223 
     1224            /* No crypto match */ 
     1225            if (matched_idx == -1) { 
     1226                DEACTIVATE_MEDIA(sdp_pool, m_loc); 
     1227                return PJMEDIA_SRTP_ENOTSUPCRYPTO; 
     1228            } 
     1229 
     1230            /* we have to generate crypto answer,  
     1231             * with srtp->tx_policy_neg matched the offer 
     1232             * and rem_tag contains matched offer tag. 
     1233             */ 
    10331234            buffer_len = MAXLEN; 
    10341235            status = generate_crypto_attr_value(srtp->pool, buffer, &buffer_len, 
    1035                                                 &srtp->setting.crypto[i], 
    1036                                                 i+1); 
     1236                                                &srtp->setting.crypto[matched_idx], 
     1237                                                chosen_tag); 
    10371238            if (status != PJ_SUCCESS) 
    10381239                return status; 
    10391240 
     1241            srtp->tx_policy_neg = srtp->setting.crypto[matched_idx]; 
     1242             
    10401243            /* If buffer_len==0, just skip the crypto attribute. */ 
    10411244            if (buffer_len) { 
    10421245                pj_strset(&attr_value, buffer, buffer_len); 
    1043                 attr = pjmedia_sdp_attr_create(srtp->pool, ID_CRYPTO.ptr,  
     1246                attr = pjmedia_sdp_attr_create(sdp_pool, ID_CRYPTO.ptr,  
    10441247                                               &attr_value); 
    10451248                m_loc->attr[m_loc->attr_count++] = attr; 
    10461249            } 
     1250 
     1251            /* At this point, we get valid rx_policy_neg & tx_policy_neg. */ 
    10471252        } 
    1048     } else { 
    1049         /* find supported crypto-suite, get the tag, and assign policy_local */ 
    1050         pjmedia_srtp_crypto tmp_rx_crypto; 
    1051         pj_bool_t has_crypto_attr = PJ_FALSE; 
    1052         pj_bool_t has_match = PJ_FALSE; 
    1053         int chosen_tag = 0; 
    1054         int tags[64]; /* assume no more than 64 crypto attrs in a media */ 
    1055         int cr_attr_count = 0; 
    1056         int k; 
    1057  
    1058         for (i=0; i<m_rem->attr_count; ++i) { 
    1059             if (pj_stricmp(&m_rem->attr[i]->name, &ID_CRYPTO) != 0) 
    1060                 continue; 
    1061  
    1062             has_crypto_attr = PJ_TRUE; 
    1063  
    1064             status = parse_attr_crypto(srtp->pool, m_rem->attr[i],  
    1065                                        &tmp_rx_crypto, &tags[cr_attr_count]); 
    1066             if (status != PJ_SUCCESS) 
    1067                 return status; 
    1068           
    1069             /* Check duplicated tag */ 
    1070             for (k=0; k<cr_attr_count; ++k) { 
    1071                 if (tags[k] == tags[cr_attr_count]) { 
    1072                     DEACTIVATE_MEDIA(pool, m_loc); 
    1073                     return PJMEDIA_SRTP_ESDPDUPCRYPTOTAG; 
    1074                 } 
    1075             } 
    1076  
    1077             if (!has_match) { 
    1078                 /* lets see if the crypto-suite offered is supported */ 
    1079                 for (j=0; j<srtp->setting.crypto_count; ++j) 
    1080                     if (pj_stricmp(&tmp_rx_crypto.name,  
    1081                                    &srtp->setting.crypto[j].name) == 0) 
    1082                     { 
    1083                         int cs_idx = get_crypto_idx(&tmp_rx_crypto.name); 
    1084  
    1085                         /* Force to use test key */ 
    1086                         /* bad keys for snom: */ 
    1087                         //char *hex_test_key = "58b29c5c8f42308120ce857e439f2d" 
    1088                         //                   "7810a8b10ad0b1446be5470faea496"; 
    1089                         //char *hex_test_key = "20a26aac7ba062d356ff52b61e3993" 
    1090                         //                   "ccb78078f12c64db94b9c294927fd0"; 
    1091                         //pj_str_t *test_key = &srtp->setting.crypto[j].key; 
    1092                         //char  *raw_test_key = pj_pool_zalloc(srtp->pool, 64); 
    1093                         //hex_string_to_octet_string( 
    1094                         //              raw_test_key, 
    1095                         //              hex_test_key, 
    1096                         //              strlen(hex_test_key)); 
    1097                         //pj_strset(test_key, raw_test_key,  
    1098                         //        crypto_suites[cs_idx].cipher_key_len); 
    1099                         /* EO Force to use test key */ 
    1100  
    1101                         if (tmp_rx_crypto.key.slen !=  
    1102                             (int)crypto_suites[cs_idx].cipher_key_len) 
    1103                             return PJMEDIA_SRTP_EINKEYLEN; 
    1104  
    1105                         srtp->tx_policy = srtp->setting.crypto[j]; 
    1106                         srtp->rx_policy = tmp_rx_crypto; 
    1107                         chosen_tag = tags[cr_attr_count]; 
    1108                         has_match = PJ_TRUE; 
    1109                         break; 
    1110                     } 
    1111             } 
    1112             cr_attr_count++; 
    1113         } 
    1114  
    1115         if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) { 
    1116             /* bypass when remote uses RTP/AVP and we disable SRTP */ 
    1117             goto BYPASS_SRTP; 
    1118         } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) { 
    1119             /* bypass SRTP when no crypto-attr but remote uses RTP/AVP */ 
    1120             if (!has_crypto_attr &&  
    1121                 pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0) 
    1122                 goto BYPASS_SRTP; 
    1123             /* bypass SRTP when nothing match but remote uses RTP/AVP */ 
    1124             if (!has_match &&  
    1125                 pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0) 
    1126                 goto BYPASS_SRTP; 
    1127         } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) { 
    1128             /* do nothing, this is intended */ 
    1129         } 
    1130  
    1131         /* No crypto attr */ 
    1132         if (!has_crypto_attr) { 
    1133             DEACTIVATE_MEDIA(pool, m_loc); 
    1134             return PJMEDIA_SRTP_ESDPREQCRYPTO; 
    1135         } 
    1136  
    1137         /* No crypto match */ 
    1138         if (!has_match) { 
    1139             DEACTIVATE_MEDIA(pool, m_loc); 
    1140             return PJMEDIA_SRTP_ENOTSUPCRYPTO; 
    1141         } 
    1142  
    1143         /* we have to generate crypto answer,  
    1144          * with srtp->tx_policy matched the offer 
    1145          * and rem_tag contains matched offer tag. 
    1146          */ 
    1147         buffer_len = MAXLEN; 
    1148         status = generate_crypto_attr_value(srtp->pool, buffer, &buffer_len, 
    1149                                             &srtp->tx_policy, 
    1150                                             chosen_tag); 
    1151         if (status != PJ_SUCCESS) 
    1152             return status; 
    1153  
    1154         /* If buffer_len==0, just skip the crypto attribute. */ 
    1155         if (buffer_len) { 
    1156             pj_strset(&attr_value, buffer, buffer_len); 
    1157             attr = pjmedia_sdp_attr_create(srtp->pool, ID_CRYPTO.ptr,  
    1158                                            &attr_value); 
    1159             m_loc->attr[m_loc->attr_count++] = attr; 
    1160         } 
    1161  
    1162         /* At this point, 
    1163          * we should have valid rx_policy & tx_policy. 
    1164          */ 
     1253             
    11651254    } 
    11661255    goto PROPAGATE_MEDIA_CREATE; 
     
    11681257BYPASS_SRTP: 
    11691258    srtp->bypass_srtp = PJ_TRUE; 
    1170     member_tp_option &= ~PJMEDIA_TPMED_NO_TRANSPORT_CHECKING; 
    11711259 
    11721260PROPAGATE_MEDIA_CREATE: 
    1173     return pjmedia_transport_media_create(srtp->real_tp, pool,  
    1174                             member_tp_option, 
    1175                             sdp_local, sdp_remote, media_index); 
     1261    return pjmedia_transport_encode_sdp(srtp->member_tp, sdp_pool,  
     1262                                        sdp_local, sdp_remote, media_index); 
    11761263} 
    11771264 
     
    11801267static pj_status_t transport_media_start(pjmedia_transport *tp, 
    11811268                                         pj_pool_t *pool, 
    1182                                          pjmedia_sdp_session *sdp_local, 
     1269                                         const pjmedia_sdp_session *sdp_local, 
    11831270                                         const pjmedia_sdp_session *sdp_remote, 
    11841271                                         unsigned media_index) 
     
    11961283    m_rem = sdp_remote->media[media_index]; 
    11971284    m_loc = sdp_local->media[media_index]; 
     1285 
     1286    srtp->remote_prefer_rtp_savp = (pj_stricmp(&m_rem->desc.transport,  
     1287                                   &ID_RTP_SAVP) == 0); 
    11981288 
    11991289    /* For answerer side, this function will just have to start SRTP */ 
     
    12641354            } 
    12651355 
    1266             srtp->tx_policy = srtp->setting.crypto[rem_tag-1]; 
    1267             srtp->rx_policy = tmp_tx_crypto; 
     1356            srtp->tx_policy_neg = srtp->setting.crypto[rem_tag-1]; 
     1357            srtp->rx_policy_neg = tmp_tx_crypto; 
    12681358        } 
    12691359 
     
    12811371        } 
    12821372 
    1283         /* At this point, 
    1284          * we should have valid rx_policy & tx_policy. 
    1285          */ 
     1373        /* At this point, we get valid rx_policy_neg & tx_policy_neg. */ 
    12861374    } 
    12871375 
    12881376    /* Got policy_local & policy_remote, let's initalize the SRTP */ 
    1289     status = pjmedia_transport_srtp_start(tp, &srtp->tx_policy, &srtp->rx_policy); 
     1377    status = pjmedia_transport_srtp_start(tp, &srtp->tx_policy_neg, &srtp->rx_policy_neg); 
    12901378    if (status != PJ_SUCCESS) 
    12911379        return status; 
     
    12971385 
    12981386PROPAGATE_MEDIA_START: 
    1299     return pjmedia_transport_media_start(srtp->real_tp, pool,  
     1387    return pjmedia_transport_media_start(srtp->member_tp, pool,  
    13001388                                         sdp_local, sdp_remote, 
    13011389                                         media_index); 
     
    13071395    pj_status_t status; 
    13081396 
    1309     status = pjmedia_transport_media_stop(srtp->real_tp); 
     1397    status = pjmedia_transport_media_stop(srtp->member_tp); 
    13101398    if (status != PJ_SUCCESS) 
    13111399        PJ_LOG(4, (srtp->pool->obj_name,  
  • pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c

    r1944 r2032  
    130130                                       pj_pool_t *pool, 
    131131                                       unsigned options, 
    132                                        pjmedia_sdp_session *sdp_local, 
    133132                                       const pjmedia_sdp_session *sdp_remote, 
    134133                                       unsigned media_index); 
     134static pj_status_t transport_encode_sdp(pjmedia_transport *tp, 
     135                                        pj_pool_t *pool, 
     136                                        pjmedia_sdp_session *sdp_local, 
     137                                        const pjmedia_sdp_session *rem_sdp, 
     138                                        unsigned media_index); 
    135139static pj_status_t transport_media_start (pjmedia_transport *tp, 
    136140                                       pj_pool_t *pool, 
    137                                        pjmedia_sdp_session *sdp_local, 
     141                                       const pjmedia_sdp_session *sdp_local, 
    138142                                       const pjmedia_sdp_session *sdp_remote, 
    139143                                       unsigned media_index); 
     
    154158    &transport_send_rtcp2, 
    155159    &transport_media_create, 
     160    &transport_encode_sdp, 
    156161    &transport_media_start, 
    157162    &transport_media_stop, 
     
    791796                                  pj_pool_t *pool, 
    792797                                  unsigned options, 
    793                                   pjmedia_sdp_session *sdp_local, 
    794798                                  const pjmedia_sdp_session *sdp_remote, 
    795799                                  unsigned media_index) 
     
    797801    struct transport_udp *udp = (struct transport_udp*)tp; 
    798802 
    799     PJ_ASSERT_RETURN(tp && pool && sdp_local, PJ_EINVAL); 
     803    PJ_ASSERT_RETURN(tp && pool, PJ_EINVAL); 
    800804    udp->media_options = options; 
     805 
     806    PJ_UNUSED_ARG(sdp_remote); 
     807    PJ_UNUSED_ARG(media_index); 
     808 
     809    return PJ_SUCCESS; 
     810} 
     811 
     812static pj_status_t transport_encode_sdp(pjmedia_transport *tp, 
     813                                        pj_pool_t *pool, 
     814                                        pjmedia_sdp_session *sdp_local, 
     815                                        const pjmedia_sdp_session *rem_sdp, 
     816                                        unsigned media_index) 
     817{ 
     818    struct transport_udp *udp = (struct transport_udp*)tp; 
    801819 
    802820    /* Validate media transport */ 
     
    805823        pjmedia_sdp_media *m_rem, *m_loc; 
    806824 
    807         m_rem = sdp_remote? sdp_remote->media[media_index] : NULL; 
     825        m_rem = rem_sdp? rem_sdp->media[media_index] : NULL; 
    808826        m_loc = sdp_local->media[media_index]; 
    809827 
     
    821839static pj_status_t transport_media_start(pjmedia_transport *tp, 
    822840                                  pj_pool_t *pool, 
    823                                   pjmedia_sdp_session *sdp_local, 
     841                                  const pjmedia_sdp_session *sdp_local, 
    824842                                  const pjmedia_sdp_session *sdp_remote, 
    825843                                  unsigned media_index) 
    826844{ 
    827     struct transport_udp *udp = (struct transport_udp*)tp; 
    828  
    829845    PJ_ASSERT_RETURN(tp && pool && sdp_local, PJ_EINVAL); 
    830846 
    831     /* Validate media transport */ 
    832     /* By now, this transport only support RTP/AVP transport */ 
    833     if ((udp->media_options & PJMEDIA_TPMED_NO_TRANSPORT_CHECKING) == 0) { 
    834         pjmedia_sdp_media *m_rem, *m_loc; 
    835  
    836         m_rem = sdp_remote->media[media_index]; 
    837         m_loc = sdp_local->media[media_index]; 
    838  
    839         if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP) || 
    840             pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP)) 
    841         { 
    842             pjmedia_sdp_media_deactivate(pool, m_loc); 
    843             return PJMEDIA_SDP_EINPROTO; 
    844         } 
    845     } 
     847    PJ_UNUSED_ARG(tp); 
     848    PJ_UNUSED_ARG(pool); 
     849    PJ_UNUSED_ARG(sdp_local); 
     850    PJ_UNUSED_ARG(sdp_remote); 
     851    PJ_UNUSED_ARG(media_index); 
    846852 
    847853    return PJ_SUCCESS; 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h

    r2018 r2032  
    2626 
    2727PJ_BEGIN_DECL 
     28 
     29/**  
     30 * Media transport state. 
     31 */ 
     32typedef enum pjsua_med_tp_st 
     33{ 
     34    /** Not initialized */ 
     35    PJSUA_MED_TP_IDLE, 
     36 
     37    /** Initialized (media_create() has been called) */ 
     38    PJSUA_MED_TP_INIT, 
     39 
     40    /** Running (media_start() has been called) */ 
     41    PJSUA_MED_TP_RUNNING 
     42 
     43} pjsua_med_tp_st; 
    2844 
    2945/**  
     
    5369                                         call was triggered by xfer.        */ 
    5470    pjmedia_transport   *med_tp;    /**< Current media transport.           */ 
    55     pj_status_t          med_tp_st; /**< Media transport status.            */ 
     71    pj_status_t          med_tp_ready;/**< Media transport status.          */ 
    5672    pjmedia_transport   *med_orig;  /**< Original media transport           */ 
     73    pjsua_med_tp_st      med_tp_st; /**< Media transport state              */ 
    5774    pj_timer_entry       refresh_tm;/**< Timer to send re-INVITE.           */ 
    5875    pj_timer_entry       hangup_tm; /**< Timer to hangup call.              */ 
     
    322339                                     pjsip_role_e role, 
    323340                                     int security_level, 
     341                                     pj_pool_t *tmp_pool, 
     342                                     const pjmedia_sdp_session *rem_sdp, 
    324343                                     int *sip_err_code); 
    325344pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,  
     
    329348                                           int *sip_err_code); 
    330349pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 
    331                                        pjmedia_sdp_session *local_sdp, 
     350                                       const pjmedia_sdp_session *local_sdp, 
    332351                                       const pjmedia_sdp_session *remote_sdp); 
    333352pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id); 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c

    r2027 r2032  
    213213 
    214214 
    215 #define LATE_SDP    0 
    216  
    217215/* Allocate one call id */ 
    218216static pjsua_call_id alloc_call_id(void) 
     
    288286} 
    289287 
     288/* 
    290289static int call_get_secure_level(pjsua_call *call) 
    291290{ 
     
    317316    return 0; 
    318317} 
     318*/ 
    319319 
    320320 
     
    450450    /* Init media channel */ 
    451451    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC,  
    452                                       call->secure_level, NULL); 
     452                                      call->secure_level, dlg->pool, 
     453                                      NULL, NULL); 
    453454    if (status != PJ_SUCCESS) { 
    454455        pjsua_perror(THIS_FILE, "Error initializing media channel", status); 
     
    456457    } 
    457458 
    458     /* Create SDP offer */ 
    459 #if LATE_SDP 
    460     offer = NULL; 
    461 #else 
    462     status = pjsua_media_channel_create_sdp(call->index, dlg->pool, NULL,  
     459    /* Create offer */ 
     460    status = pjsua_media_channel_create_sdp(call->index, dlg->pool, NULL, 
    463461                                            &offer, NULL); 
    464462    if (status != PJ_SUCCESS) { 
    465         pjsua_perror(THIS_FILE, "pjmedia unable to create SDP", status); 
     463        pjsua_perror(THIS_FILE, "Error initializing media channel", status); 
    466464        goto on_error; 
    467465    } 
    468 #endif 
    469466 
    470467    /* Create the INVITE session: */ 
     
    719716        call->secure_level = 0; 
    720717 
    721     /* Init media channel */ 
    722     status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS,  
    723                                       call->secure_level, &sip_err_code); 
    724     if (status != PJ_SUCCESS) { 
    725         pjsua_perror(THIS_FILE, "Error initializing media channel", status); 
    726         pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata,  
    727                                       sip_err_code, NULL, 
    728                                       NULL, NULL); 
    729         PJSUA_UNLOCK(); 
    730         return PJ_TRUE; 
    731     } 
    732  
    733718    /* Parse SDP from incoming request */ 
    734719    if (rdata->msg_info.msg->body) { 
     
    740725            pjsua_perror(THIS_FILE, "Error parsing SDP in incoming INVITE",  
    741726                         status); 
    742             pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 400, &reason, 
    743                                           NULL, NULL); 
    744             pjsua_media_channel_deinit(call->index); 
     727            pjsip_endpt_respond(pjsua_var.endpt, NULL, rdata, 400,  
     728                                &reason, NULL, NULL, NULL); 
    745729            PJSUA_UNLOCK(); 
    746730            return PJ_TRUE; 
     
    762746    } 
    763747 
    764     /* Get media capability from media endpoint: */ 
     748    /* Init media channel */ 
     749    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS,  
     750                                      call->secure_level,  
     751                                      rdata->tp_info.pool, offer, 
     752                                      &sip_err_code); 
     753    if (status != PJ_SUCCESS) { 
     754        pjsua_perror(THIS_FILE, "Error initializing media channel", status); 
     755        pjsip_endpt_respond(pjsua_var.endpt, NULL, rdata, 
     756                            sip_err_code, NULL, NULL, NULL, NULL); 
     757        PJSUA_UNLOCK(); 
     758        return PJ_TRUE; 
     759    } 
     760 
     761    /* Create answer */ 
    765762    status = pjsua_media_channel_create_sdp(call->index, rdata->tp_info.pool,  
    766763                                            offer, &answer, &sip_err_code); 
    767764    if (status != PJ_SUCCESS) { 
    768765        pjsua_perror(THIS_FILE, "Error creating SDP answer", status); 
    769         pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata,  
    770                                       sip_err_code, NULL, 
    771                                       NULL, NULL); 
    772         pjsua_media_channel_deinit(call->index); 
     766        pjsip_endpt_respond(pjsua_var.endpt, NULL, rdata, 
     767                            sip_err_code, NULL, NULL, NULL, NULL); 
    773768        PJSUA_UNLOCK(); 
    774769        return PJ_TRUE; 
    775770    } 
     771 
    776772 
    777773    /* Verify that we can handle the request. */ 
     
    795791 
    796792        } else { 
    797  
    798793            /* Respond with 500 (Internal Server Error) */ 
    799             pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL, 
    800                                           NULL, NULL); 
     794            pjsip_endpt_respond(pjsua_var.endpt, NULL, rdata, 500, NULL, 
     795                                NULL, NULL, NULL); 
    801796        } 
    802797 
     
    14751470    } 
    14761471 
    1477     /* Update call secure level */ 
    1478     call->secure_level = call_get_secure_level(call); 
    1479  
    1480     /* Init media channel */ 
    1481     status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC, 
    1482                                       call->secure_level, NULL); 
    1483     if (status != PJ_SUCCESS) { 
    1484         pjsua_perror(THIS_FILE, "Error initializing media channel", status); 
    1485         pjsip_dlg_dec_lock(dlg); 
    1486         return PJSIP_ESESSIONSTATE; 
    1487     } 
    1488  
    14891472    /* Create SDP */ 
    14901473    PJ_UNUSED_ARG(unhold); 
     
    15481531        return status; 
    15491532 
    1550     /* Update call's secure level */ 
    1551     call->secure_level = call_get_secure_level(call); 
    1552  
    1553     /* Init media channel */ 
    1554     status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC, 
    1555                                       call->secure_level, NULL); 
    1556     if (status != PJ_SUCCESS) { 
    1557         pjsua_perror(THIS_FILE, "Error initializing media channel", status); 
    1558         pjsip_dlg_dec_lock(dlg); 
    1559         return PJSIP_ESESSIONSTATE; 
    1560     } 
    1561  
    15621533    /* Create SDP */ 
    15631534    status = pjsua_media_channel_create_sdp(call->index, call->inv->pool,  
     
    15701541    } 
    15711542 
    1572     /* Create re-INVITE with new offer */ 
     1543    update_sdp_version(call, sdp); 
     1544 
     1545    /* Create UPDATE with new offer */ 
    15731546    status = pjsip_inv_update(call->inv, NULL, sdp, &tdata); 
    15741547    if (status != PJ_SUCCESS) { 
     
    25382511{ 
    25392512    pjsua_call *call; 
    2540     const pjmedia_sdp_session *c_local; 
    2541     pjmedia_sdp_session *local_sdp; 
     2513    const pjmedia_sdp_session *local_sdp; 
    25422514    const pjmedia_sdp_session *remote_sdp; 
    25432515 
     
    25682540 
    25692541    /* Get local and remote SDP */ 
    2570     status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &c_local); 
     2542    status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp); 
    25712543    if (status != PJ_SUCCESS) { 
    25722544        pjsua_perror(THIS_FILE,  
     
    25772549        return; 
    25782550    } 
    2579     local_sdp = (pjmedia_sdp_session*) c_local; 
    25802551 
    25812552    status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp); 
     
    27132684                  call->index)); 
    27142685 
    2715         /* Update call's secure level */ 
    2716         call->secure_level = call_get_secure_level(call); 
    2717  
    2718         /* Init media channel */ 
    2719         status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS, 
    2720                                           call->secure_level, NULL); 
    2721         if (status != PJ_SUCCESS) { 
    2722             pjsua_perror(THIS_FILE, "Error initializing media channel", status); 
    2723             PJSUA_UNLOCK(); 
    2724             return; 
    2725         } 
    2726  
    27272686        status = pjsua_media_channel_create_sdp(call->index, call->inv->pool,  
    27282687                                                offer, &answer, NULL); 
     
    27682727        PJ_LOG(4,(THIS_FILE, "Call %d: asked to send a new offer", 
    27692728                  call->index)); 
    2770  
    2771         /* Update call's secure level */ 
    2772         call->secure_level = call_get_secure_level(call); 
    2773  
    2774         /* Init media channel */ 
    2775         status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC, 
    2776                                           call->secure_level, NULL); 
    2777         if (status != PJ_SUCCESS) { 
    2778             pjsua_perror(THIS_FILE, "Error initializing media channel", status); 
    2779             PJSUA_UNLOCK(); 
    2780             return; 
    2781         } 
    27822729 
    27832730        status = pjsua_media_channel_create_sdp(call->index, call->inv->pool,  
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c

    r2027 r2032  
    653653    switch (op) { 
    654654    case PJ_ICE_STRANS_OP_INIT: 
    655         pjsua_var.calls[id].med_tp_st = result; 
     655        pjsua_var.calls[id].med_tp_ready = result; 
    656656        break; 
    657657    case PJ_ICE_STRANS_OP_NEGOTIATION: 
     
    753753        ice_cb.on_ice_complete = &on_ice_complete; 
    754754        pj_ansi_snprintf(name, sizeof(name), "icetp%02d", i); 
    755         pjsua_var.calls[i].med_tp_st = PJ_EPENDING; 
     755        pjsua_var.calls[i].med_tp_ready = PJ_EPENDING; 
    756756 
    757757        comp_cnt = 1; 
     
    770770        /* Wait until transport is initialized, or time out */ 
    771771        PJSUA_UNLOCK(); 
    772         while (pjsua_var.calls[i].med_tp_st == PJ_EPENDING) { 
     772        while (pjsua_var.calls[i].med_tp_ready == PJ_EPENDING) { 
    773773            pjsua_handle_events(100); 
    774774        } 
    775775        PJSUA_LOCK(); 
    776         if (pjsua_var.calls[i].med_tp_st != PJ_SUCCESS) { 
     776        if (pjsua_var.calls[i].med_tp_ready != PJ_SUCCESS) { 
    777777            pjsua_perror(THIS_FILE, "Error initializing ICE media transport", 
    778                          pjsua_var.calls[i].med_tp_st); 
    779             status = pjsua_var.calls[i].med_tp_st; 
     778                         pjsua_var.calls[i].med_tp_ready); 
     779            status = pjsua_var.calls[i].med_tp_ready; 
    780780            goto on_error; 
    781781        } 
     
    848848                                     pjsip_role_e role, 
    849849                                     int security_level, 
     850                                     pj_pool_t *tmp_pool, 
     851                                     const pjmedia_sdp_session *rem_sdp, 
    850852                                     int *sip_err_code) 
    851853{ 
     854    enum { MEDIA_IDX = 0 }; 
    852855    pjsua_call *call = &pjsua_var.calls[call_id]; 
     856    pj_status_t status; 
    853857 
    854858#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
     
    856860    pjmedia_srtp_setting srtp_opt; 
    857861    pjmedia_transport *srtp; 
    858     pj_status_t status; 
    859862#endif 
    860863 
     
    905908#endif 
    906909 
     910    /* Create the media transport */ 
     911    status = pjmedia_transport_media_create(call->med_tp, tmp_pool, 0, 
     912                                            rem_sdp, MEDIA_IDX); 
     913    if (status != PJ_SUCCESS) { 
     914        if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 
     915        pjsua_media_channel_deinit(call_id); 
     916        return status; 
     917    } 
     918 
     919    call->med_tp_st = PJSUA_MED_TP_INIT; 
    907920    return PJ_SUCCESS; 
    908921} 
     
    927940    } 
    928941 
     942    /* Create media if it's not created. This could happen when call is 
     943     * currently on-hold 
     944     */ 
     945    if (call->med_tp_st == PJSUA_MED_TP_IDLE) { 
     946        pjsip_role_e role; 
     947        role = (rem_sdp ? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC); 
     948        status = pjsua_media_channel_init(call_id, role, call->secure_level,  
     949                                          pool, rem_sdp, sip_status_code); 
     950        if (status != PJ_SUCCESS) 
     951            return status; 
     952    } 
     953 
    929954    /* Get media socket info */ 
    930955    pjmedia_transport_info_init(&tpinfo); 
     
    936961    if (status != PJ_SUCCESS) { 
    937962        if (sip_status_code) *sip_status_code = 500; 
    938         goto on_error; 
     963        return status; 
    939964    } 
    940965 
     
    964989 
    965990    /* Give the SDP to media transport */ 
    966     status = pjmedia_transport_media_create(call->med_tp, pool, 0, 
    967                                             sdp, rem_sdp, MEDIA_IDX); 
     991    status = pjmedia_transport_encode_sdp(call->med_tp, pool, sdp, rem_sdp,  
     992                                          MEDIA_IDX); 
    968993    if (status != PJ_SUCCESS) { 
    969994        if (sip_status_code) *sip_status_code = PJSIP_SC_NOT_ACCEPTABLE; 
    970         goto on_error; 
     995        return status; 
    971996    } 
    972997 
    973998    *p_sdp = sdp; 
    974999    return PJ_SUCCESS; 
    975  
    976 on_error: 
    977     pjsua_media_channel_deinit(call_id); 
    978     return status; 
    979  
    9801000} 
    9811001 
     
    9841004{ 
    9851005    pjsua_call *call = &pjsua_var.calls[call_id]; 
    986  
    987     //see ticket #525 
    988     //pjmedia_transport_media_stop(call->med_tp); 
    9891006 
    9901007    if (call->conf_slot != PJSUA_INVALID_ID) { 
     
    10171034    stop_media_session(call_id); 
    10181035 
    1019     pjmedia_transport_media_stop(call->med_tp); 
     1036    if (call->med_tp_st != PJSUA_MED_TP_IDLE) { 
     1037        pjmedia_transport_media_stop(call->med_tp); 
     1038        call->med_tp_st = PJSUA_MED_TP_IDLE; 
     1039    } 
    10201040 
    10211041    if (call->med_orig && call->med_tp != call->med_orig) { 
     
    10491069 
    10501070pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 
    1051                                        pjmedia_sdp_session *local_sdp, 
     1071                                       const pjmedia_sdp_session *local_sdp, 
    10521072                                       const pjmedia_sdp_session *remote_sdp) 
    10531073{ 
     
    11131133        /* Shutdown transport's session */ 
    11141134        pjmedia_transport_media_stop(call->med_tp); 
     1135        call->med_tp_st = PJSUA_MED_TP_IDLE; 
    11151136 
    11161137        /* No need because we need keepalive? */ 
     
    11231144 
    11241145    } else { 
    1125         /* Start media transport */ 
     1146        /* Start/restart media transport */ 
    11261147        status = pjmedia_transport_media_start(call->med_tp,  
    11271148                                               call->inv->pool, 
     
    11291150        if (status != PJ_SUCCESS) 
    11301151            return status; 
     1152 
     1153        call->med_tp_st = PJSUA_MED_TP_RUNNING; 
    11311154 
    11321155        /* Override ptime, if this option is specified. */ 
Note: See TracChangeset for help on using the changeset viewer.