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

Close #2036: Support DTMF via SIP INFO.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c

    r5833 r5834  
    340340} 
    341341 
    342 /* 
    343  * Handler when a transaction within a call has changed state. 
    344  */ 
    345 static void on_call_tsx_state(pjsua_call_id call_id, 
    346                               pjsip_transaction *tsx, 
    347                               pjsip_event *e) 
    348 { 
    349     const pjsip_method info_method =  
    350     { 
    351         PJSIP_OTHER_METHOD, 
    352         { "INFO", 4 } 
    353     }; 
    354  
    355     if (pjsip_method_cmp(&tsx->method, &info_method)==0) { 
    356         /* 
    357          * Handle INFO method. 
    358          */ 
    359         const pj_str_t STR_APPLICATION = { "application", 11}; 
    360         const pj_str_t STR_DTMF_RELAY  = { "dtmf-relay", 10 }; 
    361         pjsip_msg_body *body = NULL; 
    362         pj_bool_t dtmf_info = PJ_FALSE; 
    363          
    364         if (tsx->role == PJSIP_ROLE_UAC) { 
    365             if (e->body.tsx_state.type == PJSIP_EVENT_TX_MSG) 
    366                 body = e->body.tsx_state.src.tdata->msg->body; 
    367             else 
    368                 body = e->body.tsx_state.tsx->last_tx->msg->body; 
    369         } else { 
    370             if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) 
    371                 body = e->body.tsx_state.src.rdata->msg_info.msg->body; 
    372         } 
    373          
    374         /* Check DTMF content in the INFO message */ 
    375         if (body && body->len && 
    376             pj_stricmp(&body->content_type.type, &STR_APPLICATION)==0 && 
    377             pj_stricmp(&body->content_type.subtype, &STR_DTMF_RELAY)==0) 
    378         { 
    379             dtmf_info = PJ_TRUE; 
    380         } 
    381  
    382         if (dtmf_info && tsx->role == PJSIP_ROLE_UAC &&  
    383             (tsx->state == PJSIP_TSX_STATE_COMPLETED || 
    384                (tsx->state == PJSIP_TSX_STATE_TERMINATED && 
    385                 e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED)))  
    386         { 
    387             /* Status of outgoing INFO request */ 
    388             if (tsx->status_code >= 200 && tsx->status_code < 300) { 
    389                 PJ_LOG(4,(THIS_FILE,  
    390                           "Call %d: DTMF sent successfully with INFO", 
    391                           call_id)); 
    392             } else if (tsx->status_code >= 300) { 
    393                 PJ_LOG(4,(THIS_FILE,  
    394                           "Call %d: Failed to send DTMF with INFO: %d/%.*s", 
    395                           call_id, 
    396                           tsx->status_code, 
    397                           (int)tsx->status_text.slen, 
    398                           tsx->status_text.ptr)); 
    399             } 
    400         } else if (dtmf_info && tsx->role == PJSIP_ROLE_UAS && 
    401                    tsx->state == PJSIP_TSX_STATE_TRYING) 
    402         { 
    403             /* Answer incoming INFO with 200/OK */ 
    404             pjsip_rx_data *rdata; 
    405             pjsip_tx_data *tdata; 
    406             pj_status_t status; 
    407  
    408             rdata = e->body.tsx_state.src.rdata; 
    409  
    410             if (rdata->msg_info.msg->body) { 
    411                 status = pjsip_endpt_create_response(tsx->endpt, rdata, 
    412                                                      200, NULL, &tdata); 
    413                 if (status == PJ_SUCCESS) 
    414                     status = pjsip_tsx_send_msg(tsx, tdata); 
    415  
    416                 PJ_LOG(3,(THIS_FILE, "Call %d: incoming INFO:\n%.*s",  
    417                           call_id, 
    418                           (int)rdata->msg_info.msg->body->len, 
    419                           rdata->msg_info.msg->body->data)); 
    420             } else { 
    421                 status = pjsip_endpt_create_response(tsx->endpt, rdata, 
    422                                                      400, NULL, &tdata); 
    423                 if (status == PJ_SUCCESS) 
    424                     status = pjsip_tsx_send_msg(tsx, tdata); 
    425             } 
    426         } 
    427     } 
    428 } 
    429  
    430342/* General processing for media state. "mi" is the media index */ 
    431343static void on_call_generic_media_state(pjsua_call_info *ci, unsigned mi, 
     
    623535{ 
    624536    PJ_LOG(3,(THIS_FILE, "Incoming DTMF on call %d: %c", call_id, dtmf)); 
     537} 
     538 
     539static void call_on_dtmf_callback2(pjsua_call_id call_id,  
     540                                   const pjsua_dtmf_info *info) 
     541{     
     542    char duration[16]; 
     543    char method[16]; 
     544 
     545    duration[0] = '\0'; 
     546 
     547    switch (info->method) { 
     548    case PJSUA_DTMF_METHOD_RFC2833: 
     549        pj_ansi_snprintf(method, sizeof(method), "RFC2833"); 
     550        break; 
     551    case PJSUA_DTMF_METHOD_SIP_INFO: 
     552        pj_ansi_snprintf(method, sizeof(method), "SIP INFO"); 
     553        pj_ansi_snprintf(duration, sizeof(duration), ":duration(%d)",  
     554                         info->duration); 
     555        break; 
     556    };     
     557    PJ_LOG(3,(THIS_FILE, "Incoming DTMF on call %d: %c%s, using %s method",  
     558           call_id, info->digit, duration, method)); 
    625559} 
    626560 
     
    13291263    app_config.cfg.cb.on_call_media_state = &on_call_media_state; 
    13301264    app_config.cfg.cb.on_incoming_call = &on_incoming_call; 
    1331     app_config.cfg.cb.on_call_tsx_state = &on_call_tsx_state; 
    1332     app_config.cfg.cb.on_dtmf_digit = &call_on_dtmf_callback; 
     1265    app_config.cfg.cb.on_dtmf_digit2 = &call_on_dtmf_callback2; 
    13331266    app_config.cfg.cb.on_call_redirected = &call_on_redirected; 
    13341267    app_config.cfg.cb.on_reg_state = &on_reg_state; 
Note: See TracChangeset for help on using the changeset viewer.