Ignore:
Timestamp:
Jul 23, 2018 7:32:54 AM (15 months ago)
Author:
riza
Message:

Close #2036: Support DTMF via SIP INFO.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c

    r5828 r5834  
    162162} 
    163163 
     164/* Get DTMF method type name */ 
     165static const char* get_dtmf_method_name(int type) 
     166{ 
     167    switch (type) { 
     168        case PJSUA_DTMF_METHOD_RFC2833:    
     169            return "RFC2833"; 
     170        case PJSUA_DTMF_METHOD_SIP_INFO:   
     171            return "SIP INFO"; 
     172    } 
     173    return "(Unknown)"; 
     174} 
    164175 
    165176/* 
     
    607618                             PJSUA_VID_REQ_KEYFRAME_RTCP_PLI; 
    608619#endif 
     620} 
     621 
     622/*  
     623 * Initialize pjsua_call_send_dtmf_param default values.  
     624 */ 
     625PJ_DEF(void) pjsua_call_send_dtmf_param_default( 
     626                                             pjsua_call_send_dtmf_param *param) 
     627{ 
     628    pj_bzero(param, sizeof(*param)); 
     629    param->duration = PJSUA_CALL_SEND_DTMF_DURATION_DEFAULT; 
    609630} 
    610631 
     
    31333154} 
    31343155 
     3156/* 
     3157 * Send DTMF digits to remote. 
     3158 */ 
     3159PJ_DEF(pj_status_t) pjsua_call_send_dtmf(pjsua_call_id call_id, 
     3160                                       const pjsua_call_send_dtmf_param *param) 
     3161{ 
     3162    pj_status_t status = PJ_EINVAL;     
     3163 
     3164    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls && 
     3165                     param, PJ_EINVAL); 
     3166 
     3167    PJ_LOG(4,(THIS_FILE, "Call %d sending DTMF %.*s using %s method", 
     3168                       call_id, (int)param->digits.slen, param->digits.ptr, 
     3169                       get_dtmf_method_name(param->method))); 
     3170 
     3171    if (param->method == PJSUA_DTMF_METHOD_RFC2833) { 
     3172        status = pjsua_call_dial_dtmf(call_id, &param->digits); 
     3173    } else if (param->method == PJSUA_DTMF_METHOD_SIP_INFO) { 
     3174        const pj_str_t SIP_INFO = pj_str("INFO"); 
     3175        int i; 
     3176 
     3177        for (i = 0; i < param->digits.slen; ++i) { 
     3178            char body[80]; 
     3179            pjsua_msg_data msg_data_; 
     3180 
     3181            pjsua_msg_data_init(&msg_data_); 
     3182            msg_data_.content_type = pj_str("application/dtmf-relay"); 
     3183 
     3184            pj_ansi_snprintf(body, sizeof(body), 
     3185                             "Signal=%c\r\n" 
     3186                             "Duration=%d", 
     3187                             param->digits.ptr[i], param->duration); 
     3188            msg_data_.msg_body = pj_str(body); 
     3189 
     3190            status = pjsua_call_send_request(call_id, &SIP_INFO, &msg_data_); 
     3191        } 
     3192    } 
     3193 
     3194    return status; 
     3195} 
    31353196 
    31363197/** 
     
    52045265        const pj_str_t STR_APPLICATION       = { "application", 11}; 
    52055266        const pj_str_t STR_MEDIA_CONTROL_XML = { "media_control+xml", 17 }; 
     5267        /* 
     5268         * Incoming INFO request for DTMF. 
     5269         */      
     5270        const pj_str_t STR_DTMF_RELAY  = { "dtmf-relay", 10 }; 
     5271 
    52065272        pjsip_rx_data *rdata = e->body.tsx_state.src.rdata; 
    52075273        pjsip_msg_body *body = rdata->msg_info.msg->body; 
     
    52295295                    status = pjsip_tsx_send_msg(tsx, tdata); 
    52305296            } 
     5297        } else if (body && body->len && 
     5298            pj_stricmp(&body->content_type.type, &STR_APPLICATION)==0 && 
     5299            pj_stricmp(&body->content_type.subtype, &STR_DTMF_RELAY)==0) 
     5300        { 
     5301            pjsip_tx_data *tdata; 
     5302            pj_status_t status; 
     5303            pj_bool_t is_handled = PJ_FALSE; 
     5304 
     5305            if (pjsua_var.ua_cfg.cb.on_dtmf_digit2) { 
     5306                pjsua_dtmf_info info; 
     5307                pj_str_t delim, token, input; 
     5308                pj_ssize_t found_idx; 
     5309 
     5310                delim = pj_str("\r\n"); 
     5311                input = pj_str(rdata->msg_info.msg->body->data); 
     5312                found_idx = pj_strtok(&input, &delim, &token, 0); 
     5313                if (found_idx != input.slen) { 
     5314                    /* Get signal/digit */ 
     5315                    const pj_str_t STR_SIGNAL = { "Signal=", 7 }; 
     5316                    const pj_str_t STR_DURATION = { "Duration=", 9 }; 
     5317                    char *val; 
     5318 
     5319                    val = pj_strstr(&input, &STR_SIGNAL); 
     5320                    if (val) { 
     5321                        info.digit = *(val+STR_SIGNAL.slen); 
     5322                        is_handled = PJ_TRUE; 
     5323 
     5324                        /* Get duration */ 
     5325                        input.ptr += token.slen + 2; 
     5326                        input.slen -= (token.slen + 2); 
     5327 
     5328                        val = pj_strstr(&input, &STR_DURATION); 
     5329                        if (val) { 
     5330                            pj_str_t val_str; 
     5331 
     5332                            val_str.ptr = val + STR_DURATION.slen; 
     5333                            val_str.slen = input.slen - STR_DURATION.slen; 
     5334                            info.duration = pj_strtoul(&val_str); 
     5335                        } 
     5336                        info.method = PJSUA_DTMF_METHOD_SIP_INFO; 
     5337                        (*pjsua_var.ua_cfg.cb.on_dtmf_digit2)(call->index,  
     5338                                                              &info); 
     5339 
     5340                        status = pjsip_endpt_create_response(tsx->endpt, rdata, 
     5341                                                            200, NULL, &tdata); 
     5342                        if (status == PJ_SUCCESS) 
     5343                            status = pjsip_tsx_send_msg(tsx, tdata); 
     5344                    } 
     5345                } 
     5346            }  
     5347             
     5348            if (!is_handled) { 
     5349                status = pjsip_endpt_create_response(tsx->endpt, rdata, 
     5350                                                     400, NULL, &tdata); 
     5351                if (status == PJ_SUCCESS) 
     5352                    status = pjsip_tsx_send_msg(tsx, tdata); 
     5353            } 
     5354        } 
     5355    } else if (tsx->role == PJSIP_ROLE_UAC &&  
     5356               pjsip_method_cmp(&tsx->method, &pjsip_info_method)==0 && 
     5357               (tsx->state == PJSIP_TSX_STATE_COMPLETED || 
     5358               (tsx->state == PJSIP_TSX_STATE_TERMINATED && 
     5359                e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED))) 
     5360    { 
     5361        const pj_str_t STR_APPLICATION = { "application", 11}; 
     5362        const pj_str_t STR_DTMF_RELAY  = { "dtmf-relay", 10 }; 
     5363        pjsip_msg_body *body = NULL; 
     5364        pj_bool_t dtmf_info = PJ_FALSE; 
     5365         
     5366        if (e->body.tsx_state.type == PJSIP_EVENT_TX_MSG) 
     5367            body = e->body.tsx_state.src.tdata->msg->body; 
     5368        else 
     5369            body = e->body.tsx_state.tsx->last_tx->msg->body; 
     5370 
     5371        /* Check DTMF content in the INFO message */ 
     5372        if (body && body->len && 
     5373            pj_stricmp(&body->content_type.type, &STR_APPLICATION)==0 && 
     5374            pj_stricmp(&body->content_type.subtype, &STR_DTMF_RELAY)==0) 
     5375        { 
     5376            dtmf_info = PJ_TRUE; 
     5377        } 
     5378 
     5379        if (dtmf_info && (tsx->state == PJSIP_TSX_STATE_COMPLETED || 
     5380                         (tsx->state == PJSIP_TSX_STATE_TERMINATED && 
     5381                   e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED)))  
     5382        { 
     5383            /* Status of outgoing INFO request */ 
     5384            if (tsx->status_code >= 200 && tsx->status_code < 300) { 
     5385                PJ_LOG(4,(THIS_FILE,  
     5386                          "Call %d: DTMF sent successfully with INFO", 
     5387                          call->index)); 
     5388            } else if (tsx->status_code >= 300) { 
     5389                PJ_LOG(4,(THIS_FILE,  
     5390                          "Call %d: Failed to send DTMF with INFO: %d/%.*s", 
     5391                          call->index, 
     5392                          tsx->status_code, 
     5393                          (int)tsx->status_text.slen, 
     5394                          tsx->status_text.ptr)); 
     5395            } 
    52315396        } 
    52325397    } 
Note: See TracChangeset for help on using the changeset viewer.