Changeset 5834


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

Close #2036: Support DTMF via SIP INFO.

Location:
pjproject/trunk
Files:
11 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; 
  • pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_legacy.c

    r5461 r5834  
    12471247        PJ_LOG(3,(THIS_FILE, "No current call")); 
    12481248    } else { 
    1249         const pj_str_t SIP_INFO = pj_str("INFO"); 
    1250         pj_str_t digits; 
    12511249        int call = current_call; 
    1252         int i; 
    12531250        pj_status_t status; 
    12541251        char buf[128]; 
     1252        pjsua_call_send_dtmf_param param; 
    12551253 
    12561254        if (!simple_input("DTMF strings to send (0-9*#A-B)", buf, 
     
    12631261            puts("Call has been disconnected"); 
    12641262            return; 
    1265         } 
    1266  
    1267         digits = pj_str(buf); 
    1268         for (i=0; i<digits.slen; ++i) { 
    1269             char body[80]; 
    1270             pjsua_msg_data msg_data_; 
    1271  
    1272             pjsua_msg_data_init(&msg_data_); 
    1273             msg_data_.content_type = pj_str("application/dtmf-relay"); 
    1274  
    1275             pj_ansi_snprintf(body, sizeof(body), 
    1276                 "Signal=%c\r\n" 
    1277                 "Duration=160", 
    1278                 buf[i]); 
    1279             msg_data_.msg_body = pj_str(body); 
    1280  
    1281             status = pjsua_call_send_request(current_call, &SIP_INFO, 
    1282                                              &msg_data_); 
    1283             if (status != PJ_SUCCESS) { 
    1284                 return; 
    1285             } 
     1263        }        
     1264        pjsua_call_send_dtmf_param_default(&param); 
     1265        param.digits = pj_str(buf); 
     1266        param.method = PJSUA_DTMF_METHOD_SIP_INFO; 
     1267        status = pjsua_call_send_dtmf(current_call, &param); 
     1268        if (status != PJ_SUCCESS) { 
     1269            pjsua_perror(THIS_FILE, "Error sending DTMF", status); 
    12861270        } 
    12871271    } 
  • pjproject/trunk/pjsip-apps/src/swig/symbols.i

    r5820 r5834  
    3737typedef enum pj_ssl_cert_name_type {PJ_SSL_CERT_NAME_UNKNOWN = 0, PJ_SSL_CERT_NAME_RFC822, PJ_SSL_CERT_NAME_DNS, PJ_SSL_CERT_NAME_URI, PJ_SSL_CERT_NAME_IP} pj_ssl_cert_name_type; 
    3838 
    39 typedef enum pj_ssl_cert_verify_flag_t {PJ_SSL_CERT_ESUCCESS = 0, PJ_SSL_CERT_EISSUER_NOT_FOUND = (1 << 0), PJ_SSL_CERT_EUNTRUSTED = (1 << 1), PJ_SSL_CERT_EVALIDITY_PERIOD = (1 << 2), PJ_SSL_CERT_EINVALID_FORMAT = (1 << 3), PJ_SSL_CERT_EINVALID_PURPOSE = (1 << 4), PJ_SSL_CERT_EISSUER_MISMATCH = (1 << 5), PJ_SSL_CERT_ECRL_FAILURE = (1 << 6), PJ_SSL_CERT_EREVOKED = (1 << 7), PJ_SSL_CERT_ECHAIN_TOO_LONG = (1 << 8), PJ_SSL_CERT_EIDENTITY_NOT_MATCH = (1 << 30), PJ_SSL_CERT_EUNKNOWN = (1 << 31)} pj_ssl_cert_verify_flag_t; 
     39typedef enum pj_ssl_cert_verify_flag_t {PJ_SSL_CERT_ESUCCESS = 0, PJ_SSL_CERT_EISSUER_NOT_FOUND = 1 << 0, PJ_SSL_CERT_EUNTRUSTED = 1 << 1, PJ_SSL_CERT_EVALIDITY_PERIOD = 1 << 2, PJ_SSL_CERT_EINVALID_FORMAT = 1 << 3, PJ_SSL_CERT_EINVALID_PURPOSE = 1 << 4, PJ_SSL_CERT_EISSUER_MISMATCH = 1 << 5, PJ_SSL_CERT_ECRL_FAILURE = 1 << 6, PJ_SSL_CERT_EREVOKED = 1 << 7, PJ_SSL_CERT_ECHAIN_TOO_LONG = 1 << 8, PJ_SSL_CERT_EIDENTITY_NOT_MATCH = 1 << 30, PJ_SSL_CERT_EUNKNOWN = 1 << 31} pj_ssl_cert_verify_flag_t; 
    4040 
    4141typedef enum pj_stun_nat_type {PJ_STUN_NAT_TYPE_UNKNOWN, PJ_STUN_NAT_TYPE_ERR_UNKNOWN, PJ_STUN_NAT_TYPE_OPEN, PJ_STUN_NAT_TYPE_BLOCKED, PJ_STUN_NAT_TYPE_SYMMETRIC_UDP, PJ_STUN_NAT_TYPE_FULL_CONE, PJ_STUN_NAT_TYPE_SYMMETRIC, PJ_STUN_NAT_TYPE_RESTRICTED, PJ_STUN_NAT_TYPE_PORT_RESTRICTED} pj_stun_nat_type; 
     
    4949typedef enum pjmedia_srtp_crypto_option {PJMEDIA_SRTP_NO_ENCRYPTION = 1, PJMEDIA_SRTP_NO_AUTHENTICATION = 2} pjmedia_srtp_crypto_option; 
    5050 
    51 typedef enum pjmedia_srtp_keying_method {PJMEDIA_SRTP_KEYING_SDES = 0, PJMEDIA_SRTP_KEYING_DTLS_SRTP = 1, PJMEDIA_SRTP_KEYINGS_COUNT = 2} pjmedia_srtp_keying_method; 
     51typedef enum pjmedia_srtp_keying_method {PJMEDIA_SRTP_KEYING_SDES, PJMEDIA_SRTP_KEYING_DTLS_SRTP, PJMEDIA_SRTP_KEYINGS_COUNT} pjmedia_srtp_keying_method; 
    5252 
    5353typedef enum pjmedia_vid_stream_rc_method {PJMEDIA_VID_STREAM_RC_NONE = 0, PJMEDIA_VID_STREAM_RC_SIMPLE_BLOCKING = 1} pjmedia_vid_stream_rc_method; 
     
    180180typedef enum pjsua_create_media_transport_flag {PJSUA_MED_TP_CLOSE_MEMBER = 1} pjsua_create_media_transport_flag; 
    181181 
    182 typedef enum pjsua_snd_dev_id {PJSUA_SND_DEFAULT_CAPTURE_DEV = -1, PJSUA_SND_DEFAULT_PLAYBACK_DEV = -2, PJSUA_SND_NO_DEV = -3, PJSUA_SND_NULL_DEV = -99} pjsua_snd_dev_id; 
     182typedef enum pjsua_snd_dev_id {PJSUA_SND_DEFAULT_CAPTURE_DEV = PJMEDIA_AUD_DEFAULT_CAPTURE_DEV, PJSUA_SND_DEFAULT_PLAYBACK_DEV = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV, PJSUA_SND_NO_DEV = PJMEDIA_AUD_INVALID_DEV, PJSUA_SND_NULL_DEV = -99} pjsua_snd_dev_id; 
    183183 
    184184typedef enum pjsua_snd_dev_mode {PJSUA_SND_DEV_SPEAKER_ONLY = 1, PJSUA_SND_DEV_NO_IMMEDIATE_OPEN = 2} pjsua_snd_dev_mode; 
     
    186186typedef enum pjsua_ip_change_op {PJSUA_IP_CHANGE_OP_NULL, PJSUA_IP_CHANGE_OP_RESTART_LIS, PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP, PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT, PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS, PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS} pjsua_ip_change_op; 
    187187 
     188typedef enum pjsua_dtmf_method {PJSUA_DTMF_METHOD_RFC2833, PJSUA_DTMF_METHOD_SIP_INFO} pjsua_dtmf_method; 
     189 
  • pjproject/trunk/pjsip-apps/src/swig/symbols.lst

    r5820 r5834  
    3535pjsip-ua/sip_inv.h              pjsip_inv_state 
    3636 
    37 pjsua-lib/pjsua.h               pjsua_invalid_id_const_ pjsua_state pjsua_stun_use pjsua_call_hold_type pjsua_acc_id pjsua_destroy_flag pjsua_100rel_use pjsua_sip_timer_use pjsua_ipv6_use pjsua_nat64_opt pjsua_buddy_status pjsua_call_media_status pjsua_vid_win_id pjsua_call_id pjsua_med_tp_st pjsua_call_vid_strm_op pjsua_vid_req_keyframe_method pjsua_call_flag pjsua_create_media_transport_flag pjsua_snd_dev_id pjsua_snd_dev_mode pjsua_ip_change_op 
     37pjsua-lib/pjsua.h               pjsua_invalid_id_const_ pjsua_state pjsua_stun_use pjsua_call_hold_type pjsua_acc_id pjsua_destroy_flag pjsua_100rel_use pjsua_sip_timer_use pjsua_ipv6_use pjsua_nat64_opt pjsua_buddy_status pjsua_call_media_status pjsua_vid_win_id pjsua_call_id pjsua_med_tp_st pjsua_call_vid_strm_op pjsua_vid_req_keyframe_method pjsua_call_flag pjsua_create_media_transport_flag pjsua_snd_dev_id pjsua_snd_dev_mode pjsua_ip_change_op pjsua_dtmf_method 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r5828 r5834  
    800800 
    801801/** 
     802 * This enumeration specifies DTMF method. 
     803 */ 
     804typedef enum pjsua_dtmf_method { 
     805    /** 
     806     * Send DTMF using RFC2833. 
     807     */ 
     808    PJSUA_DTMF_METHOD_RFC2833, 
     809 
     810    /** 
     811     * Send DTMF using SIP INFO. 
     812     * Notes: 
     813     * - This method is not finalized in any standard/rfc, however it is  
     814     *   commonly used. 
     815     * - Warning: in case the remote doesn't support SIP INFO, response might  
     816     *   not be sent and the sender will deal this as timeout and disconnect 
     817     *   the call. 
     818     */ 
     819    PJSUA_DTMF_METHOD_SIP_INFO 
     820 
     821} pjsua_dtmf_method; 
     822 
     823 
     824/** 
     825 * This will contain the information of the callback \a on_dtmf_digit2. 
     826 */ 
     827typedef struct pjsua_dtmf_info { 
     828    /** 
     829     * The method used to send DTMF. 
     830     */ 
     831    pjsua_dtmf_method method; 
     832 
     833    /** 
     834     * DTMF ASCII digit 
     835     */     
     836    unsigned digit; 
     837 
     838    /** 
     839     * DTMF signal duration which might be included when sending DTMF using  
     840     * SIP INFO. 
     841     */ 
     842    unsigned duration; 
     843 
     844} pjsua_dtmf_info; 
     845 
     846 
     847/** 
    802848 * Call settings. 
    803849 */ 
     
    9611007 
    9621008    /** 
    963      * Notify application upon incoming DTMF digits. 
     1009     * Notify application upon incoming DTMF digits using RFC 2833 payload  
     1010     * formats. This callback will not be called if app implements \a 
     1011     * on_dtmf_digit2(). 
    9641012     * 
    9651013     * @param call_id   The call index. 
     
    9671015     */ 
    9681016    void (*on_dtmf_digit)(pjsua_call_id call_id, int digit); 
     1017 
     1018    /** 
     1019     * Notify application upon incoming DTMF digits using the method specified  
     1020     * in \a pjsua_dtmf_method. 
     1021     * 
     1022     * @param call_id   The call index. 
     1023     * @param info      The DTMF info. 
     1024     */ 
     1025    void (*on_dtmf_digit2)(pjsua_call_id call_id, const pjsua_dtmf_info *info); 
    9691026 
    9701027    /** 
     
    49264983 
    49274984/** 
     4985 * Specify the default signal duration when sending DTMF using SIP INFO. 
     4986 * 
     4987 * Default is 160 
     4988 */ 
     4989#ifndef PJSUA_CALL_SEND_DTMF_DURATION_DEFAULT 
     4990#   define PJSUA_CALL_SEND_DTMF_DURATION_DEFAULT    160 
     4991#endif 
     4992 
     4993 
     4994/** 
     4995 * Parameters for sending DTMF. Application should use  
     4996 * #pjsua_call_send_dtmf_param_default() to initialize this structure 
     4997 * with its default values. 
     4998 */ 
     4999typedef struct pjsua_call_send_dtmf_param 
     5000{ 
     5001    /** 
     5002     * The method used to send DTMF. 
     5003     * 
     5004     * Default: PJSUA_DTMF_METHOD_RFC2833 
     5005     */ 
     5006    pjsua_dtmf_method method; 
     5007 
     5008    /** 
     5009     * The signal duration used for the DTMF. 
     5010     * 
     5011     * Default: PJSUA_CALL_SEND_DTMF_DURATION_DEFAULT 
     5012     */ 
     5013    unsigned duration; 
     5014 
     5015    /** 
     5016     * The DTMF digits to be sent. 
     5017     */ 
     5018    pj_str_t digits; 
     5019 
     5020} pjsua_call_send_dtmf_param; 
     5021 
     5022 
     5023/** 
    49285024 * Initialize call settings. 
    49295025 * 
     
    49405036PJ_DECL(void) 
    49415037pjsua_call_vid_strm_op_param_default(pjsua_call_vid_strm_op_param *param); 
     5038 
     5039 
     5040/** 
     5041 * Initialize send DTMF param with default values. 
     5042 * 
     5043 * @param param         The send DTMF param to be initialized. 
     5044 */ 
     5045PJ_DECL(void)  
     5046pjsua_call_send_dtmf_param_default(pjsua_call_send_dtmf_param *param); 
    49425047 
    49435048 
     
    54085513 
    54095514/** 
    5410  * Send DTMF digits to remote using RFC 2833 payload formats. 
     5515 * Send DTMF digits to remote using RFC 2833 payload formats. Use  
     5516 * #pjsua_call_send_dtmf() to send DTMF using SIP INFO or other method in  
     5517 * \a pjsua_dtmf_method. App can use \a on_dtmf_digit() or \a on_dtmf_digit2()  
     5518 * callback to monitor incoming DTMF. 
    54115519 * 
    54125520 * @param call_id       Call identification. 
     
    54205528PJ_DECL(pj_status_t) pjsua_call_dial_dtmf(pjsua_call_id call_id,  
    54215529                                          const pj_str_t *digits); 
     5530 
     5531/** 
     5532 * Send DTMF digits to remote. Use this method to send DTMF using the method in 
     5533 * \a pjsua_dtmf_method. This method will call #pjsua_call_dial_dtmf() when 
     5534 * sending DTMF using \a PJSUA_DTMF_METHOD_RFC2833. Note that  
     5535 * \a on_dtmf_digit() callback can only monitor incoming DTMF using RFC 2833.  
     5536 * App can use \a on_dtmf_digit2() to monitor incoming DTMF using the method in  
     5537 * \a pjsua_dtmf_method. Note that \a on_dtmf_digit() will not be called once 
     5538 * \a on_dtmf_digit2() is implemented. 
     5539 * 
     5540 * @param call_id       Call identification. 
     5541 * @param param         The send DTMF parameter. 
     5542 * 
     5543 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     5544 */ 
     5545PJ_DECL(pj_status_t) pjsua_call_send_dtmf(pjsua_call_id call_id,  
     5546                                      const pjsua_call_send_dtmf_param *param); 
    54225547 
    54235548/** 
  • pjproject/trunk/pjsip/include/pjsua2/call.hpp

    r5828 r5834  
    743743{ 
    744744    /** 
     745     * DTMF sending method. 
     746     */ 
     747    pjsua_dtmf_method   method; 
     748 
     749    /** 
    745750     * DTMF ASCII digit. 
    746751     */ 
    747     string      digit; 
     752    string              digit; 
     753 
     754    /** 
     755     * DTMF signal duration which might be included when sending DTMF using  
     756     * SIP INFO. 
     757     */ 
     758    unsigned            duration; 
    748759}; 
    749760 
     
    11541165     */ 
    11551166    CallVidSetStreamParam(); 
     1167}; 
     1168 
     1169/** 
     1170 * This structure contains parameters for Call::sendDtmf() 
     1171 */ 
     1172struct CallSendDtmfParam 
     1173{ 
     1174    /** 
     1175     * The method used to send DTMF. 
     1176     *  
     1177     * Default: PJSUA_DTMF_METHOD_RFC2833 
     1178     */ 
     1179    pjsua_dtmf_method method;     
     1180 
     1181    /** 
     1182     * The signal duration used for the DTMF. 
     1183     * 
     1184     * Default: PJSUA_CALL_SEND_DTMF_DURATION_DEFAULT 
     1185     */ 
     1186    unsigned duration; 
     1187 
     1188    /** 
     1189     * The DTMF digits to be sent. 
     1190     */ 
     1191    string digits; 
     1192 
     1193public: 
     1194    /** 
     1195     * Default constructor initialize with default value.      
     1196     */ 
     1197    CallSendDtmfParam(); 
     1198 
     1199    /** 
     1200     * Convert to pjsip. 
     1201     */ 
     1202    pjsua_call_send_dtmf_param toPj() const; 
     1203 
     1204    /** 
     1205     * Convert from pjsip. 
     1206     */ 
     1207    void fromPj(const pjsua_call_send_dtmf_param &param); 
    11561208}; 
    11571209 
     
    14371489     */ 
    14381490    void dialDtmf(const string &digits) throw(Error); 
     1491 
     1492    /** 
     1493     * Send DTMF digits to remote. 
     1494     * 
     1495     * @param param     The send DTMF parameter. 
     1496     */ 
     1497    void sendDtmf(const CallSendDtmfParam &param) throw (Error); 
    14391498     
    14401499    /** 
  • pjproject/trunk/pjsip/include/pjsua2/endpoint.hpp

    r5828 r5834  
    16871687                                    unsigned stream_idx); 
    16881688    static void on_dtmf_digit(pjsua_call_id call_id, int digit); 
     1689    static void on_dtmf_digit2(pjsua_call_id call_id,  
     1690                               const pjsua_dtmf_info *info); 
    16891691    static void on_call_transfer_request(pjsua_call_id call_id, 
    16901692                                         const pj_str_t *dst, 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_aud.c

    r5825 r5834  
    557557    pj_log_push_indent(); 
    558558 
    559     /* For discussions about call mutex protection related to this 
    560      * callback, please see ticket #460: 
    561      *  http://trac.pjsip.org/repos/ticket/460#comment:4 
    562      */ 
    563     if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { 
     559    if (pjsua_var.ua_cfg.cb.on_dtmf_digit2) { 
    564560        pjsua_call_id call_id; 
     561        pjsua_dtmf_info info; 
    565562 
    566563        call_id = (pjsua_call_id)(pj_ssize_t)user_data; 
    567         pjsua_var.ua_cfg.cb.on_dtmf_digit(call_id, digit); 
     564        info.method = PJSUA_DTMF_METHOD_RFC2833; 
     565        info.digit = digit; 
     566        (*pjsua_var.ua_cfg.cb.on_dtmf_digit2)(call_id, &info); 
     567    } else if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { 
     568        /* For discussions about call mutex protection related to this 
     569         * callback, please see ticket #460: 
     570         *      http://trac.pjsip.org/repos/ticket/460#comment:4 
     571         */     
     572        pjsua_call_id call_id; 
     573 
     574        call_id = (pjsua_call_id)(pj_ssize_t)user_data; 
     575        (*pjsua_var.ua_cfg.cb.on_dtmf_digit)(call_id, digit); 
    568576    } 
    569577 
     
    645653         * callback to the session. 
    646654         */ 
    647         if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { 
     655        if (pjsua_var.ua_cfg.cb.on_dtmf_digit ||  
     656            pjsua_var.ua_cfg.cb.on_dtmf_digit2)  
     657        { 
    648658            pjmedia_stream_set_dtmf_callback(call_med->strm.a.stream, 
    649659                                             &dtmf_callback, 
  • 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    } 
  • pjproject/trunk/pjsip/src/pjsua2/call.cpp

    r5828 r5834  
    181181    this->capDev = prm.cap_dev; 
    182182#endif 
     183} 
     184 
     185CallSendDtmfParam::CallSendDtmfParam() 
     186{ 
     187    pjsua_call_send_dtmf_param param; 
     188    pjsua_call_send_dtmf_param_default(&param); 
     189    fromPj(param); 
     190} 
     191 
     192pjsua_call_send_dtmf_param CallSendDtmfParam::toPj() const 
     193{ 
     194    pjsua_call_send_dtmf_param param; 
     195    pjsua_call_send_dtmf_param_default(&param); 
     196    param.method    = this->method; 
     197    param.duration  = this->duration; 
     198    param.digits    = str2Pj(this->digits); 
     199    return param; 
     200} 
     201 
     202void CallSendDtmfParam::fromPj(const pjsua_call_send_dtmf_param &param) 
     203{ 
     204    this->method    = param.method; 
     205    this->duration  = param.duration; 
     206    this->digits    = pj2Str(param.digits); 
    183207} 
    184208 
     
    583607} 
    584608 
     609void Call::sendDtmf(const CallSendDtmfParam &param) throw (Error) 
     610{ 
     611    pjsua_call_send_dtmf_param pj_param = param.toPj(); 
     612     
     613    PJSUA2_CHECK_EXPR(pjsua_call_send_dtmf(id, &pj_param)); 
     614} 
     615 
     616 
    585617void Call::sendInstantMessage(const SendInstantMessageParam& prm) 
    586618    throw(Error) 
  • pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp

    r5828 r5834  
    11481148    char buf[10]; 
    11491149    pj_ansi_sprintf(buf, "%c", digit); 
    1150     job->prm.digit = (string)buf; 
     1150    job->prm.digit = string(buf); 
     1151     
     1152    Endpoint::instance().utilAddPendingJob(job); 
     1153} 
     1154 
     1155void Endpoint::on_dtmf_digit2(pjsua_call_id call_id,  
     1156                              const pjsua_dtmf_info *info) 
     1157{ 
     1158    Call *call = Call::lookup(call_id); 
     1159    if (!call) { 
     1160        return; 
     1161    } 
     1162     
     1163    PendingOnDtmfDigitCallback *job = new PendingOnDtmfDigitCallback; 
     1164    job->call_id = call_id; 
     1165    char buf[10]; 
     1166    pj_ansi_sprintf(buf, "%c", info->digit); 
     1167    job->prm.digit = string(buf); 
     1168    job->prm.method = info->method; 
     1169    job->prm.duration = info->duration; 
    11511170     
    11521171    Endpoint::instance().utilAddPendingJob(job); 
     
    16011620    ua_cfg.cb.on_stream_created2        = &Endpoint::on_stream_created2; 
    16021621    ua_cfg.cb.on_stream_destroyed       = &Endpoint::on_stream_destroyed; 
    1603     ua_cfg.cb.on_dtmf_digit             = &Endpoint::on_dtmf_digit; 
     1622    //ua_cfg.cb.on_dtmf_digit             = &Endpoint::on_dtmf_digit; 
     1623    ua_cfg.cb.on_dtmf_digit2            = &Endpoint::on_dtmf_digit2; 
    16041624    ua_cfg.cb.on_call_transfer_request2 = &Endpoint::on_call_transfer_request2; 
    16051625    ua_cfg.cb.on_call_transfer_status   = &Endpoint::on_call_transfer_status; 
Note: See TracChangeset for help on using the changeset viewer.