Changeset 3374


Ignore:
Timestamp:
Nov 25, 2010 9:27:06 AM (10 years ago)
Author:
nanang
Message:

Fix #1163:

  • Fixed lock codec to always be done after successful media update, and pend the lock codec until call state CONFIRMED if media update is done in call state EARLY but remote does not support UPDATE method.
  • Added additional checks in lock_codec() and perform_lock_codec(), e.g: skip locking codec when media deactivated.
Location:
pjproject/trunk/pjsip
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h

    r3366 r3374  
    9696        pj_uint32_t      sdp_ver;    /**< SDP version of the bad answer     */ 
    9797        int              retry_cnt;  /**< Retry count.                      */ 
     98        pj_bool_t        pending;    /**< Pending until CONFIRMED state     */ 
    9899    } lock_codec;                    /**< Data for codec locking when answer 
    99100                                          contains multiple codecs.         */ 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c

    r3371 r3374  
    124124    call->rem_srtp_use = PJMEDIA_SRTP_DISABLED; 
    125125    call->local_hold = PJ_FALSE; 
     126    pj_bzero(&call->lock_codec, sizeof(call->lock_codec)); 
    126127} 
    127128 
     
    30613062    const pj_str_t STR_UPDATE = {"UPDATE", 6}; 
    30623063    const pjmedia_sdp_session *local_sdp = NULL, *new_sdp; 
    3063     const pjmedia_sdp_media *rem_m; 
     3064    const pjmedia_sdp_media *ref_m; 
    30643065    pjmedia_sdp_media *m; 
    30653066    unsigned i, codec_cnt = 0; 
     
    30773078        pjmedia_sdp_neg_get_state(call->inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) 
    30783079    { 
    3079         return PJ_SUCCESS; 
     3080        return PJMEDIA_SDPNEG_EINSTATE; 
    30803081    } 
    30813082 
     
    30843085        call->inv->cause >= 200) 
    30853086    { 
    3086         return PJ_SUCCESS; 
     3087        return PJ_EINVALIDOP; 
    30873088    } 
    30883089 
     
    30963097        return PJMEDIA_SDP_EINVER; 
    30973098 
     3099    /* Verify if media is deactivated */ 
     3100    if (call->media_st == PJSUA_CALL_MEDIA_NONE || 
     3101        call->media_st == PJSUA_CALL_MEDIA_ERROR || 
     3102        call->media_dir == PJMEDIA_DIR_NONE) 
     3103    { 
     3104        return PJ_EINVALIDOP; 
     3105    } 
     3106 
    30983107    PJ_LOG(3, (THIS_FILE, "Updating media session to use only one codec..")); 
    30993108 
     
    31033112     */ 
    31043113    new_sdp = pjmedia_sdp_session_clone(call->inv->pool_prov, local_sdp); 
    3105     rem_m = local_sdp->media[call->audio_idx]; 
    31063114    m = new_sdp->media[call->audio_idx]; 
     3115    ref_m = local_sdp->media[call->audio_idx]; 
     3116    pj_assert(ref_m->desc.port); 
    31073117    codec_cnt = 0; 
    31083118    i = 0; 
     
    31263136    } 
    31273137 
    3128     /* Last check if SDP trully needs to be udpated. It is possible that OA 
    3129      * negotiations have completed and SDP has changed but remote didn't 
    3130      * increase it's SDP version. 
     3138    /* Last check if SDP trully needs to be updated. It is possible that OA 
     3139     * negotiations have completed and SDP has changed but we didn't 
     3140     * increase the SDP version (should not happen!). 
    31313141     */ 
    3132     if (rem_m->desc.fmt_count == m->desc.fmt_count || 
    3133         rem_m->desc.port == 0 || m->desc.port == 0) 
    3134     { 
     3142    if (ref_m->desc.fmt_count == m->desc.fmt_count) 
    31353143        return PJ_SUCCESS; 
    3136     } 
    31373144 
    31383145    /* Send UPDATE or re-INVITE */ 
     
    31803187{ 
    31813188    pjsip_inv_session *inv = call->inv; 
    3182     const pjmedia_sdp_session *local_sdp; 
    3183     const pjmedia_sdp_session *remote_sdp; 
    3184     const pjmedia_sdp_media *rem_m; 
     3189    const pjmedia_sdp_session *local_sdp, *remote_sdp; 
     3190    const pjmedia_sdp_media *rem_m, *loc_m; 
    31853191    unsigned codec_cnt=0, i; 
    31863192    pj_time_val delay = {0, 0}; 
     3193    const pj_str_t st_update = {"UPDATE", 6}; 
    31873194    pj_status_t status; 
    3188  
    3189     if (!pjmedia_sdp_neg_was_answer_remote(inv->neg)) 
    3190         return PJ_SUCCESS; 
    3191  
    3192     status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp); 
    3193     if (status != PJ_SUCCESS) 
    3194         return status; 
    3195     status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp); 
    3196     if (status != PJ_SUCCESS) 
    3197         return status; 
    3198  
    3199     PJ_ASSERT_RETURN(call->audio_idx>=0 && 
    3200                      call->audio_idx < (int)remote_sdp->media_count, 
    3201                      PJ_EINVALIDOP); 
    3202  
    3203     rem_m = remote_sdp->media[call->audio_idx]; 
    3204  
    3205     /* Check if media is disabled or only one format in the answer. */ 
    3206     if (rem_m->desc.port==0 || rem_m->desc.fmt_count==1) 
    3207         return PJ_SUCCESS; 
    3208  
    3209     /* Count the formats in the answer. */ 
    3210     for (i=0; i<rem_m->desc.fmt_count && codec_cnt <= 1; ++i) { 
    3211         if (!is_non_av_fmt(rem_m, &rem_m->desc.fmt[i])) 
    3212             ++codec_cnt; 
    3213     } 
    3214  
    3215     if (codec_cnt <= 1) { 
    3216         /* Answer contains single codec. */ 
    3217         return PJ_SUCCESS; 
    3218     } 
    3219  
    3220     PJ_LOG(3, (THIS_FILE, "Got answer with multiple codecs, scheduling " 
    3221                           "updating media session to use only one codec..")); 
    3222  
    3223     call->lock_codec.sdp_ver = local_sdp->origin.version; 
    3224     call->lock_codec.retry_cnt = 0; 
    32253195 
    32263196    /* Stop lock codec timer, if it is active */ 
     
    32303200        call->lock_codec.reinv_timer.id = PJ_FALSE; 
    32313201    } 
     3202 
     3203    /* Skip this if we are the answerer */ 
     3204    if (!inv->neg || !pjmedia_sdp_neg_was_answer_remote(inv->neg)) { 
     3205        return PJ_SUCCESS; 
     3206    } 
     3207 
     3208    /* Skip this if the media is inactive or error */ 
     3209    if (call->media_st == PJSUA_CALL_MEDIA_NONE || 
     3210        call->media_st == PJSUA_CALL_MEDIA_ERROR || 
     3211        call->media_dir == PJMEDIA_DIR_NONE) 
     3212    { 
     3213        return PJ_SUCCESS; 
     3214    } 
     3215 
     3216    /* Delay this when the SDP negotiation done in call state EARLY and 
     3217     * remote does not support UPDATE method. 
     3218     */ 
     3219    if (inv->state == PJSIP_INV_STATE_EARLY &&  
     3220        pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL, &st_update)!= 
     3221        PJSIP_DIALOG_CAP_SUPPORTED) 
     3222    { 
     3223        call->lock_codec.pending = PJ_TRUE; 
     3224        return PJ_SUCCESS; 
     3225    } 
     3226 
     3227    status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp); 
     3228    if (status != PJ_SUCCESS) 
     3229        return status; 
     3230    status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp); 
     3231    if (status != PJ_SUCCESS) 
     3232        return status; 
     3233 
     3234    PJ_ASSERT_RETURN(call->audio_idx>=0 && 
     3235                     call->audio_idx < (int)remote_sdp->media_count, 
     3236                     PJ_EINVALIDOP); 
     3237 
     3238    rem_m = remote_sdp->media[call->audio_idx]; 
     3239    loc_m = local_sdp->media[call->audio_idx]; 
     3240 
     3241    /* Verify that media must be active. */ 
     3242    pj_assert(loc_m->desc.port && rem_m->desc.port); 
     3243 
     3244    /* Count the formats in the answer. */ 
     3245    if (rem_m->desc.fmt_count==1) { 
     3246        codec_cnt = 1; 
     3247    } else { 
     3248        for (i=0; i<rem_m->desc.fmt_count && codec_cnt <= 1; ++i) { 
     3249            if (!is_non_av_fmt(rem_m, &rem_m->desc.fmt[i])) 
     3250                ++codec_cnt; 
     3251        } 
     3252    } 
     3253    if (codec_cnt <= 1) { 
     3254        /* Answer contains single codec. */ 
     3255        call->lock_codec.retry_cnt = 0; 
     3256        return PJ_SUCCESS; 
     3257    } 
     3258 
     3259    /* Remote keeps answering with multiple codecs, let's just give up 
     3260     * locking codec to avoid infinite retry loop. 
     3261     */ 
     3262    if (++call->lock_codec.retry_cnt > LOCK_CODEC_MAX_RETRY) 
     3263        return PJ_SUCCESS; 
     3264 
     3265    PJ_LOG(3, (THIS_FILE, "Got answer with multiple codecs, scheduling " 
     3266                          "updating media session to use only one codec..")); 
     3267 
     3268    call->lock_codec.sdp_ver = local_sdp->origin.version; 
    32323269 
    32333270    /* Can't send UPDATE or re-INVITE now, so just schedule it immediately. 
     
    32773314            pj_gettimeofday(&call->conn_time); 
    32783315 
    3279             /* Ticket #476, locking a codec in the media session. */ 
    3280             { 
     3316            /* See if lock codec was pended as media update was done in the 
     3317             * EARLY state and remote does not support UPDATE. 
     3318             */ 
     3319            if (call->lock_codec.pending) { 
    32813320                pj_status_t status; 
    32823321                status = lock_codec(call); 
    32833322                if (status != PJ_SUCCESS) { 
    32843323                    pjsua_perror(THIS_FILE, "Unable to lock codec", status); 
    3285                 } 
     3324                } 
     3325                call->lock_codec.pending = PJ_FALSE; 
    32863326            } 
    3287  
    32883327            break; 
    32893328        case PJSIP_INV_STATE_DISCONNECTED: 
     
    35163555    const pjmedia_sdp_session *local_sdp; 
    35173556    const pjmedia_sdp_session *remote_sdp; 
    3518     const pj_str_t st_update = {"UPDATE", 6}; 
     3557    //const pj_str_t st_update = {"UPDATE", 6}; 
    35193558 
    35203559    PJSUA_LOCK(); 
     
    35883627    } 
    35893628 
    3590     /* Ticket #476, handle the case of early media and remote support UPDATE */ 
    3591     if (inv->state == PJSIP_INV_STATE_EARLY &&  
    3592         pjmedia_sdp_neg_was_answer_remote(inv->neg) && 
    3593         pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL, &st_update)== 
    3594         PJSIP_DIALOG_CAP_SUPPORTED) 
    3595     { 
    3596         status = lock_codec(call); 
    3597         if (status != PJ_SUCCESS) { 
    3598             pjsua_perror(THIS_FILE, "Unable to lock codec", status); 
    3599         } 
    3600     } else if (inv->state == PJSIP_INV_STATE_CONFIRMED && 
    3601                call->media_st == PJSUA_CALL_MEDIA_ACTIVE) 
    3602     { 
    3603         /* https://trac.pjsip.org/repos/ticket/1149 */ 
    3604         status = lock_codec(call); 
    3605         if (status != PJ_SUCCESS) { 
    3606             pjsua_perror(THIS_FILE, "Unable to lock codec", status); 
    3607         } 
     3629    /* Ticket #476: make sure only one codec is specified in the answer. */ 
     3630    status = lock_codec(call); 
     3631    if (status != PJ_SUCCESS) { 
     3632        pjsua_perror(THIS_FILE, "Unable to lock codec", status); 
    36083633    } 
    36093634 
Note: See TracChangeset for help on using the changeset viewer.