Ticket #563: ticket563.patch

File ticket563.patch, 12.1 KB (added by nanang, 12 years ago)

Initial implementation of new call hold mechanism

  • pjsip-apps/src/pjsua/pjsua_app.c

     
    22102210    /* Stop ringback */ 
    22112211    ring_stop(call_id); 
    22122212 
    2213     if (call_info.media_status == PJSUA_CALL_MEDIA_ACTIVE) { 
     2213    /* Connect ports appropriately when media status is ACTIVE or  
     2214     * HELD by REMOTE (only the initiator of call-hold should mute its ports, 
     2215     * so when call-hold is initated by remote, local ports should be still 
     2216     * normally connected). 
     2217     */ 
     2218    if (call_info.media_status == PJSUA_CALL_MEDIA_ACTIVE || 
     2219        call_info.media_status == PJSUA_CALL_MEDIA_REMOTE_HOLD) 
     2220    { 
    22142221        pj_bool_t connect_sound = PJ_TRUE; 
    22152222 
    22162223        /* Loopback sound, if desired */ 
     
    22782285                pjsua_conf_connect(0, app_config.rec_port); 
    22792286            } 
    22802287        } 
     2288    } 
    22812289 
     2290    /* Handle media status */ 
     2291    switch (call_info.media_status) { 
     2292    case PJSUA_CALL_MEDIA_ACTIVE: 
    22822293        PJ_LOG(3,(THIS_FILE, "Media for call %d is active", call_id)); 
     2294        break; 
    22832295 
    2284     } else if (call_info.media_status == PJSUA_CALL_MEDIA_LOCAL_HOLD) { 
     2296    case PJSUA_CALL_MEDIA_LOCAL_HOLD: 
    22852297        PJ_LOG(3,(THIS_FILE, "Media for call %d is suspended (hold) by local", 
    22862298                  call_id)); 
    2287     } else if (call_info.media_status == PJSUA_CALL_MEDIA_REMOTE_HOLD) { 
     2299        break; 
     2300 
     2301    case PJSUA_CALL_MEDIA_REMOTE_HOLD: 
    22882302        PJ_LOG(3,(THIS_FILE,  
    22892303                  "Media for call %d is suspended (hold) by remote", 
    22902304                  call_id)); 
    2291     } else if (call_info.media_status == PJSUA_CALL_MEDIA_ERROR) { 
    2292         pj_str_t reason = pj_str("ICE negotiation failed"); 
     2305        break; 
    22932306 
    2294         PJ_LOG(1,(THIS_FILE, 
     2307    case PJSUA_CALL_MEDIA_ERROR: 
     2308        PJ_LOG(3,(THIS_FILE, 
    22952309                  "Media has reported error, disconnecting call")); 
     2310        { 
     2311            pj_str_t reason = pj_str("ICE negotiation failed"); 
     2312            pjsua_call_hangup(call_id, 500, &reason, NULL); 
     2313        } 
     2314        break; 
    22962315 
    2297         pjsua_call_hangup(call_id, 500, &reason, NULL); 
    2298  
    2299     } else { 
     2316    case PJSUA_CALL_MEDIA_NONE: 
    23002317        PJ_LOG(3,(THIS_FILE,  
    23012318                  "Media for call %d is inactive", 
    23022319                  call_id)); 
     2320        break; 
     2321 
     2322    default: 
     2323        pj_assert(!"Unhandled media status"); 
     2324        break; 
    23032325    } 
    23042326} 
    23052327 
  • pjsip/src/pjsua-lib/pjsua_call.c

     
    6666                                            pjsip_event *e); 
    6767 
    6868 
     69/* Create SDP for call hold. */ 
     70static pj_status_t create_sdp_of_call_hold(pjsua_call *call, 
     71                                           pjmedia_sdp_session **p_answer); 
    6972 
    70 /* Create inactive SDP for call hold. */ 
    71 static pj_status_t create_inactive_sdp(pjsua_call *call, 
    72                                        pjmedia_sdp_session **p_answer); 
    73  
    7473/* Update SDP version in the offer */ 
    7574static void update_sdp_version(pjsua_call *call, 
    7675                               pjmedia_sdp_session *sdp) 
     
    117116    call->res_time.msec = 0; 
    118117    call->rem_nat_type = PJ_STUN_NAT_TYPE_UNKNOWN; 
    119118    call->rem_srtp_use = PJMEDIA_SRTP_DISABLED; 
     119    call->on_hold = PJ_FALSE; 
    120120} 
    121121 
    122122 
     
    14261426        return PJSIP_ESESSIONSTATE; 
    14271427    } 
    14281428 
    1429     status = create_inactive_sdp(call, &sdp); 
     1429    status = create_sdp_of_call_hold(call, &sdp); 
    14301430    if (status != PJ_SUCCESS) { 
    14311431        pjsip_dlg_dec_lock(dlg); 
    14321432        return status; 
     
    14531453        return status; 
    14541454    } 
    14551455 
     1456    call->on_hold = PJ_TRUE; 
     1457 
    14561458    pjsip_dlg_dec_lock(dlg); 
    14571459 
    14581460    return PJ_SUCCESS; 
     
    14871489    } 
    14881490 
    14891491    /* Create SDP */ 
    1490     PJ_UNUSED_ARG(unhold); 
    1491     PJ_TODO(create_active_inactive_sdp_based_on_unhold_arg); 
    1492     status = pjsua_media_channel_create_sdp(call->index, call->inv->pool,  
    1493                                             NULL, &sdp, NULL); 
     1492    if (call->on_hold && !unhold) { 
     1493        status = create_sdp_of_call_hold(call, &sdp); 
     1494    } else { 
     1495        status = pjsua_media_channel_create_sdp(call->index, call->inv->pool,  
     1496                                                NULL, &sdp, NULL); 
     1497        call->on_hold = PJ_FALSE; 
     1498    } 
    14941499    if (status != PJ_SUCCESS) { 
    14951500        pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint",  
    14961501                     status); 
     
    15731578    /* Send the request */ 
    15741579    status = pjsip_inv_send_msg( call->inv, tdata); 
    15751580    if (status != PJ_SUCCESS) { 
    1576         pjsua_perror(THIS_FILE, "Unable to send UPDAT Erequest", status); 
     1581        pjsua_perror(THIS_FILE, "Unable to send UPDATE request", status); 
    15771582        pjsip_dlg_dec_lock(dlg); 
    15781583        return status; 
    15791584    } 
    15801585 
     1586    call->on_hold = PJ_FALSE; 
     1587 
    15811588    pjsip_dlg_dec_lock(dlg); 
    15821589 
    15831590    return PJ_SUCCESS; 
     
    30123019} 
    30133020 
    30143021 
    3015 /* 
    3016  * Create inactive SDP for call hold. 
    3017  */ 
    3018 static pj_status_t create_inactive_sdp(pjsua_call *call, 
    3019                                        pjmedia_sdp_session **p_answer) 
     3022/* Create SDP for call hold. */ 
     3023static pj_status_t create_sdp_of_call_hold(pjsua_call *call, 
     3024                                           pjmedia_sdp_session **p_answer) 
    30203025{ 
    30213026    pj_status_t status; 
    30223027    pj_pool_t *pool; 
    3023     pjmedia_sdp_conn *conn; 
    3024     pjmedia_sdp_attr *attr; 
    30253028    pjmedia_transport_info tp_info; 
    30263029    pjmedia_sdp_session *sdp; 
    30273030 
     
    30403043        return status; 
    30413044    } 
    30423045 
    3043     /* Get SDP media connection line */ 
    3044     conn = sdp->media[0]->conn; 
    3045     if (!conn) 
    3046         conn = sdp->conn; 
     3046    /* Call-hold is done by set the media direction to 'sendonly'  
     3047     * (PJMEDIA_DIR_ENCODING), except when current media direction is  
     3048     * 'inactive' (PJMEDIA_DIR_NONE). 
     3049     * (See RFC 3264 Section 8.4 and RFC 4317 Section 3.1) 
     3050     */ 
     3051    if (call->media_dir != PJMEDIA_DIR_ENCODING) { 
     3052        pjmedia_sdp_attr *attr; 
    30473053 
    3048     /* Modify address */ 
    3049     conn->addr = pj_str("0.0.0.0"); 
     3054        /* Remove existing directions attributes */ 
     3055        pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv"); 
     3056        pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly"); 
     3057        pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly"); 
     3058        pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive"); 
    30503059 
    3051     /* Remove existing directions attributes */ 
    3052     pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv"); 
    3053     pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly"); 
    3054     pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly"); 
    3055     pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive"); 
     3060        if (call->media_dir == PJMEDIA_DIR_ENCODING_DECODING) { 
     3061            /* Add sendonly attribute */ 
     3062            attr = pjmedia_sdp_attr_create(pool, "sendonly", NULL); 
     3063            pjmedia_sdp_media_add_attr(sdp->media[0], attr); 
     3064        } else { 
     3065            /* Add inactive attribute */ 
     3066            attr = pjmedia_sdp_attr_create(pool, "inactive", NULL); 
     3067            pjmedia_sdp_media_add_attr(sdp->media[0], attr); 
     3068        } 
     3069    } 
    30563070 
    3057     /* Add inactive attribute */ 
    3058     attr = pjmedia_sdp_attr_create(pool, "inactive", NULL); 
    3059     pjmedia_sdp_media_add_attr(sdp->media[0], attr); 
    3060  
    30613071    *p_answer = sdp; 
    30623072 
    30633073    return status; 
    30643074} 
    30653075 
    3066  
    30673076/* 
    30683077 * Called when session received new offer. 
    30693078 */ 
    30703079static void pjsua_call_on_rx_offer(pjsip_inv_session *inv, 
    30713080                                   const pjmedia_sdp_session *offer) 
    30723081{ 
    3073     const char *remote_state; 
    30743082    pjsua_call *call; 
    30753083    pjmedia_sdp_conn *conn; 
    30763084    pjmedia_sdp_session *answer; 
    3077     pj_bool_t is_remote_active; 
    30783085    pj_status_t status; 
    30793086 
    30803087    PJSUA_LOCK(); 
    30813088 
    30823089    call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id]; 
    30833090 
    3084     /* 
    3085      * See if remote is offering active media (i.e. not on-hold) 
    3086      */ 
    3087     is_remote_active = PJ_TRUE; 
    3088  
    30893091    conn = offer->media[0]->conn; 
    30903092    if (!conn) 
    30913093        conn = offer->conn; 
    30923094 
     3095    /* Supply candidate answer */ 
     3096    PJ_LOG(4,(THIS_FILE, "Call %d: received updated media offer", 
     3097              call->index)); 
     3098 
     3099    status = pjsua_media_channel_create_sdp(call->index, call->inv->pool,  
     3100                                            offer, &answer, NULL); 
     3101    if (status != PJ_SUCCESS) { 
     3102        pjsua_perror(THIS_FILE, "Unable to create local SDP", status); 
     3103        PJSUA_UNLOCK(); 
     3104        return; 
     3105    } 
     3106 
     3107    /* Check if offer's conn address is zero */ 
    30933108    if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 || 
    30943109        pj_strcmp2(&conn->addr, "0")==0) 
    30953110    { 
    3096         is_remote_active = PJ_FALSE; 
    3097  
    3098     }  
    3099     else if (pjmedia_sdp_media_find_attr2(offer->media[0], "inactive", NULL) || 
    3100              pjmedia_sdp_media_find_attr2(offer->media[0], "sendonly", NULL)) 
    3101     { 
    3102         is_remote_active = PJ_FALSE; 
     3111        /* Modify address */ 
     3112        answer->conn->addr = pj_str("0.0.0.0"); 
    31033113    } 
    31043114 
    3105     remote_state = (is_remote_active ? "active" : "inactive"); 
     3115    /* Check if call is on-hold */ 
     3116    if (call->on_hold) { 
     3117        pjmedia_sdp_attr *attr; 
    31063118 
    3107     /* Supply candidate answer */ 
    3108     if (call->media_st == PJSUA_CALL_MEDIA_LOCAL_HOLD || !is_remote_active) { 
    3109         PJ_LOG(4,(THIS_FILE,  
    3110                   "Call %d: RX new media offer, creating inactive SDP " 
    3111                   "(media in offer is %s)", call->index, remote_state)); 
    3112         status = create_inactive_sdp( call, &answer ); 
    3113     } else { 
    3114         PJ_LOG(4,(THIS_FILE, "Call %d: received updated media offer", 
    3115                   call->index)); 
     3119        /* Remove existing directions attributes */ 
     3120        pjmedia_sdp_media_remove_all_attr(answer->media[0], "sendrecv"); 
     3121        pjmedia_sdp_media_remove_all_attr(answer->media[0], "sendonly"); 
     3122        pjmedia_sdp_media_remove_all_attr(answer->media[0], "recvonly"); 
     3123        pjmedia_sdp_media_remove_all_attr(answer->media[0], "inactive"); 
    31163124 
    3117         status = pjsua_media_channel_create_sdp(call->index, call->inv->pool,  
    3118                                                 offer, &answer, NULL); 
     3125        /* Keep call on-hold by setting 'sendonly' attribute. 
     3126         * (See RFC 3264 Section 8.4 and RFC 4317 Section 3.1) 
     3127         */ 
     3128        attr = pjmedia_sdp_attr_create(call->inv->pool, "sendonly", NULL); 
     3129        pjmedia_sdp_media_add_attr(answer->media[0], attr); 
    31193130    } 
    31203131 
    3121     if (status != PJ_SUCCESS) { 
    3122         pjsua_perror(THIS_FILE, "Unable to create local SDP", status); 
    3123         PJSUA_UNLOCK(); 
    3124         return; 
    3125     } 
    3126  
    31273132    status = pjsip_inv_set_sdp_answer(call->inv, answer); 
    31283133    if (status != PJ_SUCCESS) { 
    31293134        pjsua_perror(THIS_FILE, "Unable to set answer", status); 
     
    31493154    call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id]; 
    31503155 
    31513156    /* See if we've put call on hold. */ 
    3152     if (call->media_st == PJSUA_CALL_MEDIA_LOCAL_HOLD) { 
     3157    if (call->on_hold) { 
    31533158        PJ_LOG(4,(THIS_FILE,  
    3154                   "Call %d: call is on-hold locally, creating inactive SDP ", 
     3159                  "Call %d: call is on-hold locally, creating call-hold SDP ", 
    31553160                  call->index)); 
    3156         status = create_inactive_sdp( call, offer ); 
     3161        status = create_sdp_of_call_hold( call, offer ); 
    31573162    } else { 
    31583163        PJ_LOG(4,(THIS_FILE, "Call %d: asked to send a new offer", 
    31593164                  call->index)); 
  • pjsip/src/pjsua-lib/pjsua_media.c

     
    12311231    if (si != &sess_info.stream_info[0]) 
    12321232        pj_memcpy(&sess_info.stream_info[0], si, sizeof(pjmedia_stream_info)); 
    12331233 
    1234     /* Check if media is put on-hold */ 
     1234    /* Check if no media is active */ 
    12351235    if (sess_info.stream_cnt == 0 || si->dir == PJMEDIA_DIR_NONE) 
    12361236    { 
     1237        /* Call media state */ 
     1238        call->media_st = PJSUA_CALL_MEDIA_NONE; 
    12371239 
    1238         /* Determine who puts the call on-hold */ 
    1239         if (prev_media_st == PJSUA_CALL_MEDIA_ACTIVE) { 
    1240             if (pjmedia_sdp_neg_was_answer_remote(call->inv->neg)) { 
    1241                 /* It was local who offer hold */ 
    1242                 call->media_st = PJSUA_CALL_MEDIA_LOCAL_HOLD; 
    1243             } else { 
    1244                 call->media_st = PJSUA_CALL_MEDIA_REMOTE_HOLD; 
    1245             } 
    1246         } 
    1247  
     1240        /* Call media direction */ 
    12481241        call->media_dir = PJMEDIA_DIR_NONE; 
    12491242 
    12501243        /* Shutdown transport's session */ 
     
    13671360            } 
    13681361        } 
    13691362 
    1370         /* Call's media state is active */ 
    1371         call->media_st = PJSUA_CALL_MEDIA_ACTIVE; 
     1363        /* Call media direction */ 
    13721364        call->media_dir = si->dir; 
     1365 
     1366        /* Call media state */ 
     1367        if (call->on_hold) 
     1368            call->media_st = PJSUA_CALL_MEDIA_LOCAL_HOLD; 
     1369        else if (call->media_dir == PJMEDIA_DIR_DECODING) 
     1370            call->media_st = PJSUA_CALL_MEDIA_REMOTE_HOLD; 
     1371        else 
     1372            call->media_st = PJSUA_CALL_MEDIA_ACTIVE; 
    13731373    } 
    13741374 
    13751375    /* Print info. */ 
  • pjsip/include/pjsua-lib/pjsua_internal.h

     
    6060    pj_time_val          dis_time;  /**< Disconnect time.                   */ 
    6161    pjsua_acc_id         acc_id;    /**< Account index being used.          */ 
    6262    int                  secure_level;/**< Signaling security level.        */ 
     63    pj_bool_t            on_hold;   /**< Flag for call-hold by local.       */ 
    6364    pjsua_call_media_status media_st;/**< Media state.                      */ 
    6465    pjmedia_dir          media_dir; /**< Media direction.                   */ 
    6566    pjmedia_session     *session;   /**< The media session.                 */