Changeset 1098


Ignore:
Timestamp:
Mar 23, 2007 4:34:20 PM (12 years ago)
Author:
bennylp
Message:

ICE (work in progress): integration with PJSUA

Location:
pjproject/trunk
Files:
18 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/include/pjmedia.h

    r974 r1098  
    5555#include <pjmedia/tonegen.h> 
    5656#include <pjmedia/transport.h> 
     57#include <pjmedia/transport_ice.h> 
    5758#include <pjmedia/transport_udp.h> 
    5859#include <pjmedia/wav_playlist.h> 
  • pjproject/trunk/pjmedia/include/pjmedia/transport.h

    r1097 r1098  
    179179struct pjmedia_transport_op 
    180180{ 
     181    /** 
     182     * Get media socket info from the specified transport. 
     183     * 
     184     * Application should call #pjmedia_transport_get_info() instead 
     185     */ 
    181186    pj_status_t (*get_info)(pjmedia_transport *tp, 
    182187                            pjmedia_sock_info *info); 
     
    255260 
    256261 
     262/**  
     263 * Media transport type. 
     264 */ 
     265typedef enum pjmedia_transport_type 
     266{ 
     267    /** Media transport using standard UDP */ 
     268    PJMEDIA_TRANSPORT_TYPE_UDP, 
     269 
     270    /** Media transport using ICE */ 
     271    PJMEDIA_TRANSPORT_TYPE_ICE 
     272 
     273} pjmedia_transport_type; 
     274 
     275 
    257276/** 
    258277 * This structure declares stream transport. A stream transport is called 
     
    263282{ 
    264283    /** Transport name (for logging purpose). */ 
    265     char                  name[PJ_MAX_OBJ_NAME]; 
     284    char                     name[PJ_MAX_OBJ_NAME]; 
     285 
     286    /** Transport type. */ 
     287    pjmedia_transport_type   type; 
    266288 
    267289    /** Transport's "virtual" function table. */ 
    268     pjmedia_transport_op *op; 
     290    pjmedia_transport_op    *op; 
    269291}; 
    270292 
    271293 
     294/** 
     295 * Get media socket info from the specified transport. The socket info 
     296 * contains information about the local address of this transport, and 
     297 * would be needed for example to fill in the "c=" and "m=" line of local  
     298 * SDP. 
     299 * 
     300 * @param tp        The transport. 
     301 * @param info      Media socket info to be initialized. 
     302 * 
     303 * @return          PJ_SUCCESS on success. 
     304 */ 
    272305PJ_INLINE(pj_status_t) pjmedia_transport_get_info(pjmedia_transport *tp, 
    273306                                                  pjmedia_sock_info *info) 
  • pjproject/trunk/pjmedia/include/pjmedia/transport_ice.h

    r1097 r1098  
    4242PJ_DECL(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt, 
    4343                                        const char *name, 
     44                                        unsigned comp_cnt, 
    4445                                        pj_stun_config *stun_cfg, 
    45                                         pj_dns_resolver *resolver, 
    46                                         pj_bool_t enable_relay, 
    47                                         const pj_str_t *stun_name, 
    4846                                        pjmedia_transport **p_tp); 
    4947PJ_DECL(pj_status_t) pjmedia_ice_destroy(pjmedia_transport *tp); 
     48 
     49PJ_DECL(pj_ice_st*) pjmedia_ice_get_ice_st(pjmedia_transport *tp); 
    5050 
    5151 
     
    5454                                          const pj_str_t *local_ufrag, 
    5555                                          const pj_str_t *local_passwd); 
    56 PJ_DECL(pj_status_t) pjmedia_ice_build_sdp(pjmedia_transport *tp, 
    57                                            pj_pool_t *pool, 
    58                                            pjmedia_sdp_session *sdp); 
     56PJ_DECL(pj_status_t) pjmedia_ice_modify_sdp(pjmedia_transport *tp, 
     57                                            pj_pool_t *pool, 
     58                                            pjmedia_sdp_session *sdp); 
    5959PJ_DECL(pj_status_t) pjmedia_ice_start_ice(pjmedia_transport *tp, 
    6060                                           pj_pool_t *pool, 
  • pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c

    r1097 r1098  
    2626    pj_ice_st           *ice_st; 
    2727 
    28     void  *user_data; 
     28    void  *stream; 
    2929    void (*rtp_cb)(void*, 
    3030                   const void*, 
     
    4242                               pjmedia_sock_info *info); 
    4343static pj_status_t tp_attach( pjmedia_transport *tp, 
    44                               void *user_data, 
     44                              void *stream, 
    4545                              const pj_sockaddr_t *rem_addr, 
    4646                              const pj_sockaddr_t *rem_rtcp, 
     
    9393PJ_DEF(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt, 
    9494                                       const char *name, 
     95                                       unsigned comp_cnt, 
    9596                                       pj_stun_config *stun_cfg, 
    96                                        pj_dns_resolver *resolver, 
    97                                        pj_bool_t enable_relay, 
    98                                        const pj_str_t *stun_name, 
    99                                        pjmedia_transport **p_tp) 
     97                                       pjmedia_transport **p_tp) 
    10098{ 
    10199    pj_ice_st *ice_st; 
    102100    pj_ice_st_cb ice_st_cb; 
    103101    struct transport_ice *tp_ice; 
     102    unsigned i; 
    104103    pj_status_t status; 
    105104 
     
    118117        return status; 
    119118 
    120     /* Add component 1 (RTP) */ 
    121     status = pj_ice_st_add_comp(ice_st, 1); 
    122     if (status != PJ_SUCCESS)  
    123         goto on_error; 
    124  
    125     /* Add host candidates. */ 
    126     status = pj_ice_st_add_all_host_interfaces(ice_st, 1, 0, PJ_FALSE, NULL); 
    127     if (status != PJ_SUCCESS) 
    128         goto on_error; 
    129  
    130     /* Configure STUN server for ICE */ 
    131     if (stun_name) { 
    132         status = pj_ice_st_set_stun(ice_st, resolver, enable_relay, stun_name); 
     119    /* Add components */ 
     120    for (i=0; i<comp_cnt; ++i) { 
     121        status = pj_ice_st_add_comp(ice_st, i+1); 
    133122        if (status != PJ_SUCCESS)  
    134123            goto on_error; 
    135  
    136         /* Add STUN candidates */ 
    137         status = pj_ice_st_add_stun_interface(ice_st, 1, 0, PJ_FALSE, NULL); 
    138124    } 
    139125 
     
    143129    pj_ansi_strcpy(tp_ice->base.name, ice_st->obj_name); 
    144130    tp_ice->base.op = &tp_ice_op; 
     131    tp_ice->base.type = PJMEDIA_TRANSPORT_TYPE_ICE; 
    145132 
    146133    ice_st->user_data = (void*)tp_ice; 
     
    158145 
    159146 
    160 PJ_DEF(pj_status_t) pjmedia_ice_close(pjmedia_transport *tp) 
     147PJ_DEF(pj_status_t) pjmedia_ice_destroy(pjmedia_transport *tp) 
    161148{ 
    162149    struct transport_ice *tp_ice = (struct transport_ice*)tp; 
     
    164151    if (tp_ice->ice_st) { 
    165152        pj_ice_st_destroy(tp_ice->ice_st); 
    166         tp_ice->ice_st = NULL; 
     153        //Must not touch tp_ice after ice_st is destroyed! 
     154        //(it has the pool) 
     155        //tp_ice->ice_st = NULL; 
    167156    } 
    168157 
    169158    return PJ_SUCCESS; 
     159} 
     160 
     161 
     162PJ_DECL(pj_ice_st*) pjmedia_ice_get_ice_st(pjmedia_transport *tp) 
     163{ 
     164    struct transport_ice *tp_ice = (struct transport_ice*)tp; 
     165    return tp_ice->ice_st; 
    170166} 
    171167 
     
    181177 
    182178 
    183 PJ_DEF(pj_status_t) pjmedia_ice_build_sdp(pjmedia_transport *tp, 
    184                                           pj_pool_t *pool, 
    185                                           pjmedia_sdp_session *sdp) 
     179PJ_DEF(pj_status_t) pjmedia_ice_modify_sdp(pjmedia_transport *tp, 
     180                                           pj_pool_t *pool, 
     181                                           pjmedia_sdp_session *sdp) 
    186182{ 
    187183    struct transport_ice *tp_ice = (struct transport_ice*)tp; 
     
    203199    sdp->attr[sdp->attr_count++] = attr; 
    204200 
    205     /* Add all candidates */ 
     201    /* Add all candidates (to media level) */ 
    206202    cand_cnt = pj_ice_get_cand_cnt(tp_ice->ice_st->ice); 
    207203    for (i=0; i<cand_cnt; ++i) { 
     
    256252        value = pj_str(buffer); 
    257253        attr = pjmedia_sdp_attr_create(pool, "candidate", &value); 
    258         sdp->attr[sdp->attr_count++] = attr; 
     254        sdp->media[0]->attr[sdp->media[0]->attr_count++] = attr; 
    259255    } 
    260256 
     
    378374    /* Get all candidates */ 
    379375    cand_cnt = 0; 
    380     for (i=0; i<rem_sdp->attr_count; ++i) { 
     376    for (i=0; i<rem_sdp->media[0]->attr_count; ++i) { 
    381377        pjmedia_sdp_attr *attr; 
    382378 
    383         attr = rem_sdp->attr[i]; 
     379        attr = rem_sdp->media[0]->attr[i]; 
    384380        if (pj_strcmp2(&attr->name, "candidate")!=0) 
    385381            continue; 
     
    442438 
    443439static pj_status_t tp_attach( pjmedia_transport *tp, 
    444                               void *user_data, 
     440                              void *stream, 
    445441                              const pj_sockaddr_t *rem_addr, 
    446442                              const pj_sockaddr_t *rem_rtcp, 
     
    455451    struct transport_ice *tp_ice = (struct transport_ice*)tp; 
    456452 
    457     tp_ice->user_data = user_data; 
     453    tp_ice->stream = stream; 
    458454    tp_ice->rtp_cb = rtp_cb; 
    459455    tp_ice->rtcp_cb = rtcp_cb; 
     
    474470    tp_ice->rtp_cb = NULL; 
    475471    tp_ice->rtcp_cb = NULL; 
    476     tp_ice->user_data = NULL; 
     472    tp_ice->stream = NULL; 
    477473 
    478474    PJ_UNUSED_ARG(strm); 
     
    515511 
    516512    if (comp_id==1 && tp_ice->rtp_cb) 
    517         (*tp_ice->rtp_cb)(tp_ice->user_data, pkt, size); 
     513        (*tp_ice->rtp_cb)(tp_ice->stream, pkt, size); 
    518514    else if (comp_id==2 && tp_ice->rtcp_cb) 
    519         (*tp_ice->rtcp_cb)(tp_ice->user_data, pkt, size); 
     515        (*tp_ice->rtcp_cb)(tp_ice->stream, pkt, size); 
    520516 
    521517    PJ_UNUSED_ARG(cand_id); 
  • pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c

    r1097 r1098  
    240240    pj_ansi_strcpy(tp->base.name, name); 
    241241    tp->base.op = &transport_udp_op; 
     242    tp->base.type = PJMEDIA_TRANSPORT_TYPE_UDP; 
    242243 
    243244    /* Copy socket infos */ 
  • pjproject/trunk/pjnath/include/pjnath/ice_stream_transport.h

    r1096 r1098  
    7272    pj_ice_st           *ice_st; 
    7373    pj_ice_cand_type     type; 
     74    pj_status_t          status; 
    7475    unsigned             comp_id; 
    7576    int                  cand_id; 
     
    151152                                                   pj_bool_t notify, 
    152153                                                   void *notify_data); 
    153  
     154PJ_DECL(pj_status_t) pj_ice_st_get_interfaces_status(pj_ice_st *ice_st); 
    154155 
    155156PJ_DECL(pj_status_t) pj_ice_st_init_ice(pj_ice_st *ice_st, 
  • pjproject/trunk/pjnath/src/pjnath/ice.c

    r1097 r1098  
    889889{ 
    890890    if (!ice->is_complete) { 
     891        char errmsg[PJ_ERR_MSG_SIZE]; 
    891892 
    892893        ice->is_complete = PJ_TRUE; 
     
    894895     
    895896        /* Log message */ 
    896         LOG((ice->obj_name, "ICE process complete")); 
     897        LOG((ice->obj_name, "ICE process complete, status=%s",  
     898             pj_strerror(status, errmsg, sizeof(errmsg)).ptr)); 
     899 
    897900        dump_checklist("Dumping checklist", ice, &ice->clist); 
    898901        dump_valid_list("Dumping valid list", ice); 
     
    11371140    dump_checklist("Checklist created:", ice, clist); 
    11381141 
    1139     pj_mutex_lock(ice->mutex); 
     1142    pj_mutex_unlock(ice->mutex); 
    11401143 
    11411144    return PJ_SUCCESS; 
  • pjproject/trunk/pjnath/src/pjnath/ice_stream_transport.c

    r1096 r1098  
    152152} 
    153153 
    154  
    155154/*  
    156155 * This is callback called by ioqueue on incoming packet  
     
    192191} 
    193192 
    194  
    195193/*  
    196194 * Destroy an interface  
     
    207205    } 
    208206} 
    209  
    210207 
    211208/*  
     
    242239} 
    243240 
    244  
    245241static void destroy_ice_st(pj_ice_st *ice_st, pj_status_t reason) 
    246242{ 
     
    274270} 
    275271 
    276  
    277272/* 
    278273 * Destroy ICE stream transport. 
     
    283278    return PJ_SUCCESS; 
    284279} 
    285  
    286280 
    287281/* 
     
    301295} 
    302296 
    303  
    304297/* 
    305298 * Set STUN server address. 
     
    320313} 
    321314 
    322  
    323315/* 
    324316 * Add new component. 
     
    350342    return PJ_SUCCESS; 
    351343} 
    352  
    353344 
    354345/* Add interface */ 
     
    406397    add_interface(ice_st, is, p_itf_id, notify, notify_data); 
    407398 
    408     return PJ_SUCCESS; 
    409 } 
    410  
     399    /* Set interface status to SUCCESS */ 
     400    is->status = PJ_SUCCESS; 
     401 
     402    return PJ_SUCCESS; 
     403} 
    411404 
    412405/* 
     
    434427                                        NULL, notify, notify_data); 
    435428} 
    436  
    437429 
    438430/* 
     
    454446} 
    455447 
    456  
    457448/* 
    458449 * Add TURN mapping interface. 
     
    473464} 
    474465 
     466PJ_DEF(pj_status_t) pj_ice_st_get_interfaces_status(pj_ice_st *ice_st) 
     467{ 
     468    unsigned i; 
     469    pj_status_t worst = PJ_SUCCESS; 
     470 
     471    for (i=0; i<ice_st->itf_cnt; ++i) { 
     472        pj_ice_st_interface *itf = ice_st->itfs[i]; 
     473 
     474        if (itf->status == PJ_SUCCESS) { 
     475            /* okay */ 
     476        } else if (itf->status == PJ_EPENDING && worst==PJ_SUCCESS) { 
     477            worst = itf->status; 
     478        } else { 
     479            worst = itf->status; 
     480        } 
     481    } 
     482 
     483    return worst; 
     484} 
    475485 
    476486/* 
     
    538548} 
    539549 
    540  
    541550/* 
    542551 * Enum candidates 
     
    568577    return PJ_SUCCESS; 
    569578} 
    570  
    571579 
    572580/* 
     
    589597} 
    590598 
    591  
    592599/* 
    593600 * Stop ICE! 
     
    602609    return PJ_SUCCESS; 
    603610} 
    604  
    605611 
    606612/* 
     
    618624} 
    619625 
    620  
    621  
    622626/* 
    623627 * Callback called by ICE session when ICE processing is complete, either 
     
    631635    } 
    632636} 
    633  
    634637 
    635638/* 
     
    668671} 
    669672 
    670  
    671673/* 
    672674 * Callback called by ICE session when it receives application data. 
  • pjproject/trunk/pjsip-apps/build/pjsua.dsp

    r853 r1098  
    4343# PROP Target_Dir "" 
    4444# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c 
    45 # ADD CPP /nologo /MD /W4 /GX /Zi /O2 /I "../../pjsip/include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../../pjmedia/include" /D "NDEBUG" /D PJ_WIN32=1 /D PJ_M_I386=1 /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /FD /c 
     45# ADD CPP /nologo /MD /W4 /GX /Zi /O2 /I "../../pjsip/include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../../pjmedia/include" /I "../../pjnath/include" /D "NDEBUG" /D PJ_WIN32=1 /D PJ_M_I386=1 /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /FD /c 
    4646# SUBTRACT CPP /YX 
    4747# ADD BASE RSC /l 0x409 /d "NDEBUG" 
     
    6969# PROP Target_Dir "" 
    7070# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c 
    71 # ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../../pjsip/include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../../pjmedia/include" /D "_DEBUG" /D PJ_WIN32=1 /D PJ_M_I386=1 /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c 
     71# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../../pjsip/include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../../pjmedia/include" /I "../../pjnath/include" /D "_DEBUG" /D PJ_WIN32=1 /D PJ_M_I386=1 /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c 
    7272# SUBTRACT CPP /YX 
    7373# ADD BASE RSC /l 0x409 /d "_DEBUG" 
  • pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c

    r1044 r1098  
    145145    puts  ("  --outbound=url      Set the URL of global outbound proxy server"); 
    146146    puts  ("                      May be specified multiple times"); 
    147     puts  ("  --use-stun1=FORMAT  where FORMAT=host[:port]"); 
    148     puts  ("  --use-stun2=FORMAT  Resolve local IP with the specified STUN servers"); 
     147    puts  ("  --stun-srv=name     Set STUN server host or domain"); 
    149148    puts  (""); 
    150149    puts  ("TLS Options:"); 
     
    160159    puts  (""); 
    161160    puts  ("Media Options:"); 
     161    puts  ("  --use-ice           Enable ICE (default:no)"); 
    162162    puts  ("  --add-codec=name    Manually add codec (default is to enable all)"); 
    163163    puts  ("  --clock-rate=N      Override sound device clock rate"); 
     
    326326           OPT_REGISTRAR, OPT_REG_TIMEOUT, OPT_PUBLISH, OPT_ID, OPT_CONTACT, 
    327327           OPT_REALM, OPT_USERNAME, OPT_PASSWORD, 
    328            OPT_NAMESERVER, OPT_USE_STUN1, OPT_USE_STUN2,  
     328           OPT_NAMESERVER, OPT_STUN_SRV, 
    329329           OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE, 
    330330           OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_AUTO_PLAY, OPT_AUTO_LOOP, 
    331            OPT_AUTO_CONF, OPT_CLOCK_RATE, 
     331           OPT_AUTO_CONF, OPT_CLOCK_RATE, OPT_USE_ICE, 
    332332           OPT_PLAY_FILE, OPT_PLAY_TONE, OPT_RTP_PORT, OPT_ADD_CODEC,  
    333333           OPT_ILBC_MODE, OPT_REC_FILE, OPT_AUTO_REC, 
     
    367367        { "password",   1, 0, OPT_PASSWORD}, 
    368368        { "nameserver", 1, 0, OPT_NAMESERVER}, 
    369         { "use-stun1",  1, 0, OPT_USE_STUN1}, 
    370         { "use-stun2",  1, 0, OPT_USE_STUN2}, 
     369        { "stun-srv",   1, 0, OPT_STUN_SRV}, 
    371370        { "add-buddy",  1, 0, OPT_ADD_BUDDY}, 
    372371        { "offer-x-ms-msg",0,0,OPT_OFFER_X_MS_MSG}, 
     
    382381        { "rec-file",   1, 0, OPT_REC_FILE}, 
    383382        { "rtp-port",   1, 0, OPT_RTP_PORT}, 
     383        { "use-ice",    0, 0, OPT_USE_ICE}, 
    384384        { "add-codec",  1, 0, OPT_ADD_CODEC}, 
    385385        { "complexity", 1, 0, OPT_COMPLEXITY}, 
     
    442442    pj_optind = 0; 
    443443    while((c=pj_getopt_long(argc,argv, "", long_options,&option_index))!=-1) { 
    444         char *p; 
    445444        pj_str_t tmp; 
    446445        long lval; 
     
    633632            break; 
    634633 
    635         case OPT_USE_STUN1:   /* STUN server 1 */ 
    636             p = pj_ansi_strchr(pj_optarg, ':'); 
    637             if (p) { 
    638                 *p = '\0'; 
    639                 cfg->udp_cfg.stun_config.stun_srv1 = pj_str(pj_optarg); 
    640                 cfg->udp_cfg.stun_config.stun_port1 = pj_strtoul(pj_cstr(&tmp, p+1)); 
    641                 if (cfg->udp_cfg.stun_config.stun_port1 < 1 || cfg->udp_cfg.stun_config.stun_port1 > 65535) { 
    642                     PJ_LOG(1,(THIS_FILE,  
    643                               "Error: expecting port number with " 
    644                               "option --use-stun1")); 
    645                     return PJ_EINVAL; 
    646                 } 
    647             } else { 
    648                 cfg->udp_cfg.stun_config.stun_port1 = 3478; 
    649                 cfg->udp_cfg.stun_config.stun_srv1 = pj_str(pj_optarg); 
    650             } 
    651             cfg->udp_cfg.use_stun = PJ_TRUE; 
    652             break; 
    653  
    654         case OPT_USE_STUN2:   /* STUN server 2 */ 
    655             p = pj_ansi_strchr(pj_optarg, ':'); 
    656             if (p) { 
    657                 *p = '\0'; 
    658                 cfg->udp_cfg.stun_config.stun_srv2 = pj_str(pj_optarg); 
    659                 cfg->udp_cfg.stun_config.stun_port2 = pj_strtoul(pj_cstr(&tmp,p+1)); 
    660                 if (cfg->udp_cfg.stun_config.stun_port2 < 1 || cfg->udp_cfg.stun_config.stun_port2 > 65535) { 
    661                     PJ_LOG(1,(THIS_FILE,  
    662                               "Error: expecting port number with " 
    663                               "option --use-stun2")); 
    664                     return PJ_EINVAL; 
    665                 } 
    666             } else { 
    667                 cfg->udp_cfg.stun_config.stun_port2 = 3478; 
    668                 cfg->udp_cfg.stun_config.stun_srv2 = pj_str(pj_optarg); 
    669             } 
     634        case OPT_STUN_SRV:   /* STUN server */ 
     635            cfg->cfg.stun_srv = pj_str(pj_optarg); 
    670636            break; 
    671637 
     
    727693        case OPT_REC_FILE: 
    728694            cfg->rec_file = pj_str(pj_optarg); 
     695            break; 
     696 
     697        case OPT_USE_ICE: 
     698            cfg->media_cfg.enable_ice = PJ_TRUE; 
    729699            break; 
    730700 
     
    11141084 
    11151085    /* STUN */ 
    1116     if (config->udp_cfg.stun_config.stun_port1) { 
    1117         pj_ansi_sprintf(line, "--use-stun1 %.*s:%d\n", 
    1118                         (int)config->udp_cfg.stun_config.stun_srv1.slen,  
    1119                         config->udp_cfg.stun_config.stun_srv1.ptr,  
    1120                         config->udp_cfg.stun_config.stun_port1); 
     1086    if (config->cfg.stun_srv.slen) { 
     1087        pj_ansi_sprintf(line, "--stun-srv %.*s\n", 
     1088                        (int)config->cfg.stun_srv.slen,  
     1089                        config->cfg.stun_srv.ptr); 
    11211090        pj_strcat2(&cfg, line); 
    11221091    } 
    11231092 
    1124     if (config->udp_cfg.stun_config.stun_port2) { 
    1125         pj_ansi_sprintf(line, "--use-stun2 %.*s:%d\n", 
    1126                         (int)config->udp_cfg.stun_config.stun_srv2.slen,  
    1127                         config->udp_cfg.stun_config.stun_srv2.ptr,  
    1128                         config->udp_cfg.stun_config.stun_port2); 
    1129         pj_strcat2(&cfg, line); 
    1130     } 
    11311093 
    11321094    /* TLS */ 
     
    11751137 
    11761138    /* Media */ 
     1139    if (config->media_cfg.enable_ice) 
     1140        pj_strcat2(&cfg, "--use-ice\n"); 
    11771141    if (config->null_audio) 
    11781142        pj_strcat2(&cfg, "--null-audio\n"); 
     
    29632927        return status; 
    29642928 
    2965     /* Copy udp_cfg STUN config to rtp_cfg */ 
    2966     app_config.rtp_cfg.use_stun = app_config.udp_cfg.use_stun; 
    2967     app_config.rtp_cfg.stun_config = app_config.udp_cfg.stun_config; 
    2968  
    2969  
    29702929    /* Initialize application callbacks */ 
    29712930    app_config.cfg.cb.on_call_state = &on_call_state; 
  • pjproject/trunk/pjsip/build/pjsua_lib.dsp

    r853 r1098  
    4242# PROP Target_Dir "" 
    4343# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c 
    44 # ADD CPP /nologo /MD /W4 /GX /Zi /O2 /I "../include" /I "../../pjmedia/include" /I "../../pjlib-util/include" /I "../../pjlib/include" /D "NDEBUG" /D PJ_WIN32=1 /D PJ_M_I386=1 /D "WIN32" /D "_MBCS" /D "_LIB" /FR /FD /c 
     44# ADD CPP /nologo /MD /W4 /GX /Zi /O2 /I "../include" /I "../../pjmedia/include" /I "../../pjlib-util/include" /I "../../pjlib/include" /I "../../pjnath/include" /D "NDEBUG" /D PJ_WIN32=1 /D PJ_M_I386=1 /D "WIN32" /D "_MBCS" /D "_LIB" /FR /FD /c 
    4545# SUBTRACT CPP /YX 
    4646# ADD BASE RSC /l 0x409 /d "NDEBUG" 
     
    6666# PROP Target_Dir "" 
    6767# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c 
    68 # ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjmedia/include" /I "../../pjlib-util/include" /I "../../pjlib/include" /D "_DEBUG" /D PJ_WIN32=1 /D PJ_M_I386=1 /D "WIN32" /D "_MBCS" /D "_LIB" /FR /FD /GZ /c 
     68# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjmedia/include" /I "../../pjlib-util/include" /I "../../pjlib/include" /I "../../pjnath/include" /D "_DEBUG" /D PJ_WIN32=1 /D PJ_M_I386=1 /D "WIN32" /D "_MBCS" /D "_LIB" /FR /FD /GZ /c 
    6969# SUBTRACT CPP /YX 
    7070# ADD BASE RSC /l 0x409 /d "_DEBUG" 
  • pjproject/trunk/pjsip/include/pjsip/sip_endpoint.h

    r974 r1098  
    157157                                        pj_timer_entry *entry ); 
    158158 
     159/** 
     160 * Get the timer heap instance of the SIP endpoint. 
     161 * 
     162 * @param endpt     The endpoint. 
     163 * 
     164 * @return          The timer heap instance. 
     165 */ 
     166PJ_DECL(pj_timer_heap_t*) pjsip_endpt_get_timer_heap(pjsip_endpoint *endpt); 
     167 
    159168 
    160169/** 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r974 r1098  
    903903    pj_str_t        outbound_proxy[4]; 
    904904 
     905    /** 
     906     * Specify STUN server. This server will be first resolved with DNS SRV 
     907     * to get the actual server address. If DNS SRV resolution failed, or 
     908     * when nameserver is not configured, the server will be resolved using 
     909     * DNS A resolution (i.e. gethostbyname()). 
     910     */ 
     911    pj_str_t        stun_srv; 
     912 
    905913    /**  
    906914     * Number of credentials in the credential array. 
     
    10021010 
    10031011    pj_strdup_with_null(pool, &dst->user_agent, &src->user_agent); 
     1012    pj_strdup_with_null(pool, &dst->stun_srv, &src->stun_srv); 
    10041013} 
    10051014 
     
    13351344 
    13361345/** 
    1337  * This structure describes STUN configuration for SIP and media transport, 
    1338  * and is embedded inside pjsua_transport_config structure. 
    1339  */ 
    1340 typedef struct pjsua_stun_config 
    1341 { 
    1342     /** 
    1343      * The first STUN server IP address or hostname. 
    1344      */ 
    1345     pj_str_t    stun_srv1; 
    1346  
    1347     /** 
    1348      * Port number of the first STUN server. 
    1349      * If zero, default STUN port will be used. 
    1350      */ 
    1351     unsigned    stun_port1; 
    1352      
    1353     /** 
    1354      * Optional second STUN server IP address or hostname, for which the 
    1355      * result of the mapping request will be compared to. If the value 
    1356      * is empty, only one STUN server will be used. 
    1357      */ 
    1358     pj_str_t    stun_srv2; 
    1359  
    1360     /** 
    1361      * Port number of the second STUN server. 
    1362      * If zero, default STUN port will be used. 
    1363      */ 
    1364     unsigned    stun_port2; 
    1365  
    1366 } pjsua_stun_config; 
    1367  
    1368  
    1369  
    1370 /** 
    1371  * Call this function to initialize STUN config with default values. 
    1372  * STUN config is normally embedded inside pjsua_transport_config, so 
    1373  * normally there is no need to call this function and rather just 
    1374  * call pjsua_transport_config_default() instead. 
    1375  * 
    1376  * @param cfg       The STUN config to be initialized. 
    1377  * 
    1378  * \par Python: 
    1379  * The corresponding Python function creates and initialize the config: 
    1380  * \code 
    1381     stun_cfg = py_pjsua.stun_config_default() 
    1382  * \endcode 
    1383  */ 
    1384 PJ_INLINE(void) pjsua_stun_config_default(pjsua_stun_config *cfg) 
    1385 { 
    1386     pj_bzero(cfg, sizeof(*cfg)); 
    1387 } 
    1388  
    1389  
    1390 /** 
    13911346 * Transport configuration for creating transports for both SIP 
    13921347 * and media. Before setting some values to this structure, application 
     
    14361391 
    14371392    /** 
    1438      * Flag to indicate whether STUN should be used. 
    1439      */ 
    1440     pj_bool_t           use_stun; 
    1441  
    1442     /** 
    1443      * STUN configuration, must be specified when STUN is used. 
    1444      */ 
    1445     pjsua_stun_config   stun_config; 
    1446  
    1447     /** 
    14481393     * This specifies TLS settings for TLS transport. It is only be used 
    14491394     * when this transport config is being used to create a SIP TLS 
     
    14691414{ 
    14701415    pj_bzero(cfg, sizeof(*cfg)); 
    1471     pjsua_stun_config_default(&cfg->stun_config); 
    14721416    pjsip_tls_setting_default(&cfg->tls_setting); 
    1473 } 
    1474  
    1475  
    1476 /** 
    1477  * This is a utility function to normalize STUN config. It's only 
    1478  * used internally by the library. 
    1479  * 
    1480  * @param cfg       The STUN config to be initialized. 
    1481  * 
    1482  * \par Python: 
    1483  * \code 
    1484     py_pjsua.normalize_stun_config(cfg) 
    1485  * \code 
    1486  */ 
    1487 PJ_INLINE(void) pjsua_normalize_stun_config( pjsua_stun_config *cfg ) 
    1488 { 
    1489     if (cfg->stun_srv1.slen) { 
    1490  
    1491         if (cfg->stun_port1 == 0) 
    1492             cfg->stun_port1 = 3478; 
    1493  
    1494         if (cfg->stun_srv2.slen == 0) { 
    1495             cfg->stun_srv2 = cfg->stun_srv1; 
    1496             cfg->stun_port2 = cfg->stun_port1; 
    1497         } else { 
    1498             if (cfg->stun_port2 == 0) 
    1499                 cfg->stun_port2 = 3478; 
    1500         } 
    1501  
    1502     } else { 
    1503         cfg->stun_port1 = 0; 
    1504         cfg->stun_srv2.slen = 0; 
    1505         cfg->stun_port2 = 0; 
    1506     } 
    15071417} 
    15081418 
     
    15231433                                           const pjsua_transport_config *src) 
    15241434{ 
     1435    PJ_UNUSED_ARG(pool); 
    15251436    pj_memcpy(dst, src, sizeof(*src)); 
    1526  
    1527     if (src->stun_config.stun_srv1.slen) { 
    1528         pj_strdup_with_null(pool, &dst->stun_config.stun_srv1, 
    1529                             &src->stun_config.stun_srv1); 
    1530     } 
    1531  
    1532     if (src->stun_config.stun_srv2.slen) { 
    1533         pj_strdup_with_null(pool, &dst->stun_config.stun_srv2, 
    1534                             &src->stun_config.stun_srv2); 
    1535     } 
    1536  
    1537     pjsua_normalize_stun_config(&dst->stun_config); 
    15381437} 
    15391438 
     
    35313430    int                 jb_max; 
    35323431 
     3432    /** 
     3433     * Enable ICE 
     3434     */ 
     3435    pj_bool_t           enable_ice; 
     3436 
     3437    /** 
     3438     * Enable ICE media relay. 
     3439     */ 
     3440    pj_bool_t           enable_relay; 
    35333441}; 
    35343442 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h

    r998 r1098  
    187187    pj_thread_t         *thread[4];         /**< Array of threads.      */ 
    188188 
     189    /* STUN and resolver */ 
     190    pj_stun_config       stun_cfg;  /**< Global STUN settings.          */ 
     191    pj_sockaddr          stun_srv;  /**< Resolved STUN server address   */ 
     192    pj_status_t          stun_status; /**< STUN server status.          */ 
     193    pj_dns_resolver     *resolver;  /**< DNS resolver.                  */ 
     194 
    189195    /* Account: */ 
    190196    unsigned             acc_cnt;            /**< Number of accounts.   */ 
     
    271277 
    272278 
     279/** 
     280 * Resolve STUN server. 
     281 */ 
     282pj_status_t pjsua_resolve_stun_server(pj_bool_t wait); 
    273283 
    274284/** 
     
    276286 */ 
    277287pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata); 
     288 
     289/* 
     290 * Media channel. 
     291 */ 
     292pj_status_t pjsua_media_channel_init(pjsua_call_id call_id, 
     293                                    pjsip_role_e role); 
     294pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,  
     295                                           pj_pool_t *pool, 
     296                                           pjmedia_sdp_session **p_sdp); 
     297pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 
     298                                       pjmedia_sdp_session *local_sdp, 
     299                                       pjmedia_sdp_session *remote_sdp); 
     300pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id); 
     301 
    278302 
    279303/** 
  • pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c

    r1017 r1098  
    759759 
    760760/* 
     761 * Get the timer heap instance of the SIP endpoint. 
     762 */ 
     763PJ_DEF(pj_timer_heap_t*) pjsip_endpt_get_timer_heap(pjsip_endpoint *endpt) 
     764{ 
     765    return endpt->timer_heap; 
     766} 
     767 
     768/* 
    761769 * This is the callback that is called by the transport manager when it  
    762770 * receives a message from the network. 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c

    r974 r1098  
    6161 
    6262 
    63 /* Destroy the call's media */ 
    64 static pj_status_t call_destroy_media(int call_id); 
    6563 
    6664/* Create inactive SDP for call hold. */ 
     
    303301    } 
    304302 
    305     /* Get media capability from media endpoint: */ 
    306  
    307     status = pjmedia_endpt_create_sdp( pjsua_var.med_endpt, dlg->pool, 1,  
    308                                        &call->skinfo, &offer); 
     303    /* Init media channel */ 
     304    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC); 
     305    if (status != PJ_SUCCESS) { 
     306        pjsua_perror(THIS_FILE, "Error initializing media channel", status); 
     307        goto on_error; 
     308    } 
     309 
     310    /* Create SDP offer */ 
     311    status = pjsua_media_channel_create_sdp(call->index, dlg->pool, &offer); 
    309312    if (status != PJ_SUCCESS) { 
    310313        pjsua_perror(THIS_FILE, "pjmedia unable to create SDP", status); 
     
    404407    if (call_id != -1) { 
    405408        reset_call(call_id); 
     409        pjsua_media_channel_deinit(call_id); 
    406410    } 
    407411 
     
    527531 
    528532 
    529     /* Get media capability from media endpoint: */ 
    530     status = pjmedia_endpt_create_sdp( pjsua_var.med_endpt,  
    531                                        rdata->tp_info.pool, 1, 
    532                                        &call->skinfo, &answer ); 
     533    /* Init media channel */ 
     534    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS); 
    533535    if (status != PJ_SUCCESS) { 
    534536        pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL, 
     
    539541 
    540542 
     543    /* Get media capability from media endpoint: */ 
     544    status = pjsua_media_channel_create_sdp(call->index, rdata->tp_info.pool, &answer); 
     545    if (status != PJ_SUCCESS) { 
     546        pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL, 
     547                                      NULL, NULL); 
     548        pjsua_media_channel_deinit(call->index); 
     549        PJSUA_UNLOCK(); 
     550        return PJ_TRUE; 
     551    } 
     552 
     553 
    541554    /* Verify that we can handle the request. */ 
    542555    status = pjsip_inv_verify_request(rdata, &options, answer, NULL, 
     
    562575        } 
    563576 
     577        pjsua_media_channel_deinit(call->index); 
    564578        PJSUA_UNLOCK(); 
    565579        return PJ_TRUE; 
     
    581595        pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL, 
    582596                                      NULL, NULL); 
     597        pjsua_media_channel_deinit(call->index); 
    583598        PJSUA_UNLOCK(); 
    584599        return PJ_TRUE; 
     
    591606        pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL, 
    592607                                      NULL, NULL); 
     608        pjsua_media_channel_deinit(call->index); 
    593609        PJSUA_UNLOCK(); 
    594610        return PJ_TRUE; 
     
    619635        pjsip_dlg_terminate(dlg); 
    620636         */ 
     637        pjsua_media_channel_deinit(call->index); 
    621638        PJSUA_UNLOCK(); 
    622639        return PJ_TRUE; 
     
    650667        pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL); 
    651668        pjsip_inv_terminate(inv, 500, PJ_FALSE); 
     669        pjsua_media_channel_deinit(call->index); 
    652670        PJSUA_UNLOCK(); 
    653671        return PJ_TRUE; 
     
    655673    } else { 
    656674        status = pjsip_inv_send_msg(inv, response); 
    657         if (status != PJ_SUCCESS) 
     675        if (status != PJ_SUCCESS) { 
    658676            pjsua_perror(THIS_FILE, "Unable to send 100 response", status); 
     677        } 
    659678    } 
    660679 
     
    11921211    PJ_UNUSED_ARG(unhold); 
    11931212    PJ_TODO(create_active_inactive_sdp_based_on_unhold_arg); 
    1194     status = pjmedia_endpt_create_sdp( pjsua_var.med_endpt, call->inv->pool,  
    1195                                        1, &call->skinfo, &sdp); 
     1213    status = pjsua_media_channel_create_sdp(call->index, call->inv->pool, &sdp); 
    11961214    if (status != PJ_SUCCESS) { 
    11971215        pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint",  
     
    18861904 
    18871905/* 
    1888  * Destroy the call's media 
    1889  */ 
    1890 static pj_status_t call_destroy_media(int call_id) 
    1891 { 
    1892     pjsua_call *call = &pjsua_var.calls[call_id]; 
    1893  
    1894     if (call->conf_slot != PJSUA_INVALID_ID) { 
    1895         pjmedia_conf_remove_port(pjsua_var.mconf, call->conf_slot); 
    1896         call->conf_slot = PJSUA_INVALID_ID; 
    1897     } 
    1898  
    1899     if (call->session) { 
    1900         /* Destroy session (this will also close RTP/RTCP sockets). */ 
    1901         pjmedia_session_destroy(call->session); 
    1902         call->session = NULL; 
    1903  
    1904         PJ_LOG(4,(THIS_FILE, "Media session for call %d is destroyed",  
    1905                              call_id)); 
    1906  
    1907     } 
    1908  
    1909     call->media_st = PJSUA_CALL_MEDIA_NONE; 
    1910  
    1911     return PJ_SUCCESS; 
    1912 } 
    1913  
    1914  
    1915 /* 
    19161906 * This callback receives notification from invite session when the 
    19171907 * session state has changed. 
     
    20352025 
    20362026        if (call) 
    2037             call_destroy_media(call->index); 
     2027            pjsua_media_channel_deinit(call->index); 
    20382028 
    20392029        /* Free call */ 
     
    20782068 
    20792069/* 
    2080  * DTMF callback from the stream. 
    2081  */ 
    2082 static void dtmf_callback(pjmedia_stream *strm, void *user_data, 
    2083                           int digit) 
    2084 { 
    2085     PJ_UNUSED_ARG(strm); 
    2086  
    2087     if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { 
    2088         pjsua_call_id call_id; 
    2089  
    2090         call_id = (pjsua_call_id)user_data; 
    2091         pjsua_var.ua_cfg.cb.on_dtmf_digit(call_id, digit); 
    2092     } 
    2093 } 
    2094  
    2095 /* 
    20962070 * Callback to be called when SDP offer/answer negotiation has just completed 
    20972071 * in the session. This function will start/update media if negotiation 
     
    21012075                                       pj_status_t status) 
    21022076{ 
    2103     int prev_media_st = 0; 
    21042077    pjsua_call *call; 
    2105     pjmedia_session_info sess_info; 
    2106     const pjmedia_sdp_session *local_sdp; 
    2107     const pjmedia_sdp_session *remote_sdp; 
    2108     pjmedia_port *media_port; 
    2109     pj_str_t port_name; 
    2110     char tmp[PJSIP_MAX_URL_SIZE]; 
     2078    pjmedia_sdp_session *local_sdp; 
     2079    pjmedia_sdp_session *remote_sdp; 
    21112080 
    21122081    PJSUA_LOCK(); 
     
    21192088 
    21202089        /* Stop/destroy media, if any */ 
    2121         call_destroy_media(call->index); 
     2090        pjsua_media_channel_deinit(call->index); 
    21222091 
    21232092        /* Disconnect call if we're not in the middle of initializing an 
     
    21342103    } 
    21352104 
    2136     /* Destroy existing media session, if any. */ 
    2137  
    2138     if (call) { 
    2139         prev_media_st = call->media_st; 
    2140         call_destroy_media(call->index); 
    2141     } 
    21422105 
    21432106    /* Get local and remote SDP */ 
    2144  
    21452107    status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp); 
    21462108    if (status != PJ_SUCCESS) { 
     
    21642126    } 
    21652127 
    2166     /* Create media session info based on SDP parameters.  
    2167      * We only support one stream per session at the moment 
    2168      */     
    2169     status = pjmedia_session_info_from_sdp( call->inv->dlg->pool,  
    2170                                             pjsua_var.med_endpt,  
    2171                                             1,&sess_info,  
    2172                                             local_sdp, remote_sdp); 
     2128    status = pjsua_media_channel_update(call->index, local_sdp, remote_sdp); 
    21732129    if (status != PJ_SUCCESS) { 
    21742130        pjsua_perror(THIS_FILE, "Unable to create media session",  
    21752131                     status); 
    21762132        call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE); 
     2133        pjsua_media_channel_deinit(call->index); 
    21772134        PJSUA_UNLOCK(); 
    21782135        return; 
    21792136    } 
    21802137 
    2181     /* Check if media is put on-hold */ 
    2182     if (sess_info.stream_cnt == 0 ||  
    2183         sess_info.stream_info[0].dir == PJMEDIA_DIR_NONE) 
    2184     { 
    2185  
    2186         /* Determine who puts the call on-hold */ 
    2187         if (prev_media_st == PJSUA_CALL_MEDIA_ACTIVE) { 
    2188             if (pjmedia_sdp_neg_was_answer_remote(call->inv->neg)) { 
    2189                 /* It was local who offer hold */ 
    2190                 call->media_st = PJSUA_CALL_MEDIA_LOCAL_HOLD; 
    2191             } else { 
    2192                 call->media_st = PJSUA_CALL_MEDIA_REMOTE_HOLD; 
    2193             } 
    2194         } 
    2195  
    2196         call->media_dir = PJMEDIA_DIR_NONE; 
    2197  
    2198     } else { 
    2199  
    2200         /* Override ptime, if this option is specified. */ 
    2201         if (pjsua_var.media_cfg.ptime != 0) { 
    2202             sess_info.stream_info[0].param->setting.frm_per_pkt = (pj_uint8_t) 
    2203                 (pjsua_var.media_cfg.ptime / sess_info.stream_info[0].param->info.frm_ptime); 
    2204             if (sess_info.stream_info[0].param->setting.frm_per_pkt == 0) 
    2205                 sess_info.stream_info[0].param->setting.frm_per_pkt = 1; 
    2206         } 
    2207  
    2208         /* Disable VAD, if this option is specified. */ 
    2209         if (pjsua_var.media_cfg.no_vad) { 
    2210             sess_info.stream_info[0].param->setting.vad = 0; 
    2211         } 
    2212  
    2213  
    2214         /* Optionally, application may modify other stream settings here 
    2215          * (such as jitter buffer parameters, codec ptime, etc.) 
    2216          */ 
    2217         sess_info.stream_info[0].jb_init = pjsua_var.media_cfg.jb_init; 
    2218         sess_info.stream_info[0].jb_min_pre = pjsua_var.media_cfg.jb_min_pre; 
    2219         sess_info.stream_info[0].jb_max_pre = pjsua_var.media_cfg.jb_max_pre; 
    2220         sess_info.stream_info[0].jb_max = pjsua_var.media_cfg.jb_max; 
    2221  
    2222         /* Create session based on session info. */ 
    2223         status = pjmedia_session_create( pjsua_var.med_endpt, &sess_info, 
    2224                                          &call->med_tp, 
    2225                                          call, &call->session ); 
    2226         if (status != PJ_SUCCESS) { 
    2227             pjsua_perror(THIS_FILE, "Unable to create media session",  
    2228                          status); 
    2229             //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE); 
    2230             PJSUA_UNLOCK(); 
    2231             return; 
    2232         } 
    2233  
    2234         /* If DTMF callback is installed by application, install our 
    2235          * callback to the session. 
    2236          */ 
    2237         if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { 
    2238             pjmedia_session_set_dtmf_callback(call->session, 0,  
    2239                                               &dtmf_callback,  
    2240                                               (void*)(call->index)); 
    2241         } 
    2242  
    2243         /* Get the port interface of the first stream in the session. 
    2244          * We need the port interface to add to the conference bridge. 
    2245          */ 
    2246         pjmedia_session_get_port(call->session, 0, &media_port); 
    2247  
    2248  
    2249         /* 
    2250          * Add the call to conference bridge. 
    2251          */ 
    2252         port_name.ptr = tmp; 
    2253         port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, 
    2254                                          call->inv->dlg->remote.info->uri, 
    2255                                          tmp, sizeof(tmp)); 
    2256         if (port_name.slen < 1) { 
    2257             port_name = pj_str("call"); 
    2258         } 
    2259         status = pjmedia_conf_add_port( pjsua_var.mconf, call->inv->pool, 
    2260                                         media_port,  
    2261                                         &port_name, 
    2262                                         (unsigned*)&call->conf_slot); 
    2263         if (status != PJ_SUCCESS) { 
    2264             pjsua_perror(THIS_FILE, "Unable to create conference slot",  
    2265                          status); 
    2266             call_destroy_media(call->index); 
    2267             //call_disconnect(inv, PJSIP_SC_INTERNAL_SERVER_ERROR); 
    2268             PJSUA_UNLOCK(); 
    2269             return; 
    2270         } 
    2271  
    2272         /* Call's media state is active */ 
    2273         call->media_st = PJSUA_CALL_MEDIA_ACTIVE; 
    2274         call->media_dir = sess_info.stream_info[0].dir; 
    2275     } 
    2276  
    2277     /* Print info. */ 
    2278     { 
    2279         char info[80]; 
    2280         int info_len = 0; 
    2281         unsigned i; 
    2282  
    2283         for (i=0; i<sess_info.stream_cnt; ++i) { 
    2284             int len; 
    2285             const char *dir; 
    2286             pjmedia_stream_info *strm_info = &sess_info.stream_info[i]; 
    2287  
    2288             switch (strm_info->dir) { 
    2289             case PJMEDIA_DIR_NONE: 
    2290                 dir = "inactive"; 
    2291                 break; 
    2292             case PJMEDIA_DIR_ENCODING: 
    2293                 dir = "sendonly"; 
    2294                 break; 
    2295             case PJMEDIA_DIR_DECODING: 
    2296                 dir = "recvonly"; 
    2297                 break; 
    2298             case PJMEDIA_DIR_ENCODING_DECODING: 
    2299                 dir = "sendrecv"; 
    2300                 break; 
    2301             default: 
    2302                 dir = "unknown"; 
    2303                 break; 
    2304             } 
    2305             len = pj_ansi_sprintf( info+info_len, 
    2306                                    ", stream #%d: %.*s (%s)", i, 
    2307                                    (int)strm_info->fmt.encoding_name.slen, 
    2308                                    strm_info->fmt.encoding_name.ptr, 
    2309                                    dir); 
    2310             if (len > 0) 
    2311                 info_len += len; 
    2312         } 
    2313         PJ_LOG(4,(THIS_FILE,"Media updates%s", info)); 
    2314     } 
    23152138 
    23162139    /* Call application callback, if any */ 
     
    24142237        PJ_LOG(4,(THIS_FILE, "Call %d: received updated media offer", 
    24152238                  call->index)); 
    2416         status = pjmedia_endpt_create_sdp( pjsua_var.med_endpt,  
    2417                                            call->inv->pool, 1, 
    2418                                            &call->skinfo, &answer);      
     2239        status = pjsua_media_channel_create_sdp(call->index, call->inv->pool, &answer); 
    24192240    } 
    24202241 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c

    r1074 r1098  
    4343    unsigned i; 
    4444 
     45    pj_bzero(&pjsua_var, sizeof(pjsua_var)); 
     46 
    4547    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) 
    4648        pjsua_var.acc[i].index = i; 
     
    4850    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i) 
    4951        pjsua_var.tpdata[i].index = i; 
     52 
     53    pjsua_var.stun_status = PJ_EUNKNOWN; 
    5054} 
    5155 
     
    467471    if (ua_cfg->nameserver_count) { 
    468472#if PJSIP_HAS_RESOLVER 
    469         pj_dns_resolver *resv; 
    470473        unsigned i; 
    471474 
    472475        /* Create DNS resolver */ 
    473         status = pjsip_endpt_create_resolver(pjsua_var.endpt, &resv); 
     476        status = pjsip_endpt_create_resolver(pjsua_var.endpt,  
     477                                             &pjsua_var.resolver); 
    474478        PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
    475479 
    476480        /* Configure nameserver for the DNS resolver */ 
    477         status = pj_dns_resolver_set_ns(resv, ua_cfg->nameserver_count, 
     481        status = pj_dns_resolver_set_ns(pjsua_var.resolver,  
     482                                        ua_cfg->nameserver_count, 
    478483                                        ua_cfg->nameserver, NULL); 
    479484        if (status != PJ_SUCCESS) { 
     
    483488 
    484489        /* Set this DNS resolver to be used by the SIP resolver */ 
    485         status = pjsip_endpt_set_resolver(pjsua_var.endpt, resv); 
     490        status = pjsip_endpt_set_resolver(pjsua_var.endpt, pjsua_var.resolver); 
    486491        if (status != PJ_SUCCESS) { 
    487492            pjsua_perror(THIS_FILE, "Error setting DNS resolver", status); 
     
    551556 
    552557 
     558    /* Start resolving STUN server */ 
     559    status = pjsua_resolve_stun_server(PJ_FALSE); 
     560    if (status != PJ_SUCCESS && status != PJ_EPENDING) { 
     561        pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 
     562        return status; 
     563    } 
     564 
    553565    /* Initialize PJSUA media subsystem */ 
    554566    status = pjsua_media_subsys_init(media_cfg); 
     
    636648        pj_gettimeofday(&now); 
    637649    } while (PJ_TIME_VAL_LT(now, timeout)); 
     650} 
     651 
     652/* 
     653 * Resolve STUN server. 
     654 */ 
     655pj_status_t pjsua_resolve_stun_server(pj_bool_t wait) 
     656{ 
     657    if (pjsua_var.stun_status == PJ_EUNKNOWN) { 
     658        /* Initialize STUN configuration */ 
     659        pj_stun_config_init(&pjsua_var.stun_cfg, &pjsua_var.cp.factory, 0, 
     660                            pjsip_endpt_get_ioqueue(pjsua_var.endpt), 
     661                            pjsip_endpt_get_timer_heap(pjsua_var.endpt)); 
     662 
     663        /* Start STUN server resolution */ 
     664        /* For now just do DNS A resolution */ 
     665 
     666        if (pjsua_var.ua_cfg.stun_srv.slen == 0) { 
     667            pjsua_var.stun_status = PJ_SUCCESS; 
     668        } else { 
     669            pj_hostent he; 
     670 
     671            pjsua_var.stun_status =  
     672                pj_gethostbyname(&pjsua_var.ua_cfg.stun_srv, &he); 
     673 
     674            if (pjsua_var.stun_status == PJ_SUCCESS) { 
     675                pj_sockaddr_in_init(&pjsua_var.stun_srv.ipv4, NULL, 0); 
     676                pjsua_var.stun_srv.ipv4.sin_addr = *(pj_in_addr*)he.h_addr; 
     677                pjsua_var.stun_srv.ipv4.sin_port = pj_htons((pj_uint16_t)3478); 
     678            } 
     679        } 
     680        return pjsua_var.stun_status; 
     681 
     682    } else if (pjsua_var.stun_status == PJ_EPENDING) { 
     683        /* STUN server resolution has been started, wait for the 
     684         * result. 
     685         */ 
     686        pj_assert(!"Should not happen"); 
     687        return PJ_EBUG; 
     688 
     689    } else { 
     690        /* STUN server has been resolved, return the status */ 
     691        return pjsua_var.stun_status; 
     692    } 
    638693} 
    639694 
     
    820875static pj_status_t create_sip_udp_sock(pj_in_addr bound_addr, 
    821876                                       int port, 
    822                                        pj_bool_t use_stun, 
    823                                        const pjsua_stun_config *stun_param, 
    824877                                       pj_sock_t *p_sock, 
    825878                                       pj_sockaddr_in *p_pub_addr) 
    826879{ 
    827     pjsua_stun_config stun; 
     880    char ip_addr[32]; 
     881    pj_str_t stun_srv; 
    828882    pj_sock_t sock; 
    829883    pj_status_t status; 
     884 
     885    /* Make sure STUN server resolution has completed */ 
     886    status = pjsua_resolve_stun_server(PJ_TRUE); 
     887    if (status != PJ_SUCCESS) { 
     888        pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 
     889        return status; 
     890    } 
    830891 
    831892    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock); 
     
    857918    } 
    858919 
    859     /* Copy and normalize STUN param */ 
    860     if (use_stun) { 
    861         pj_memcpy(&stun, stun_param, sizeof(*stun_param)); 
    862         pjsua_normalize_stun_config(&stun); 
     920    if (pjsua_var.stun_srv.addr.sa_family != 0) { 
     921        pj_ansi_strcpy(ip_addr,pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr)); 
     922        stun_srv = pj_str(ip_addr); 
    863923    } else { 
    864         pj_bzero(&stun, sizeof(pjsua_stun_config)); 
     924        stun_srv.slen = 0; 
    865925    } 
    866926 
     
    868928     * the name of local host. 
    869929     */ 
    870     if (stun.stun_srv1.slen) { 
     930    if (stun_srv.slen) { 
    871931        /* 
    872932         * STUN is specified, resolve the address with STUN. 
    873933         */ 
    874934        status = pjstun_get_mapped_addr(&pjsua_var.cp.factory, 1, &sock, 
    875                                          &stun.stun_srv1,  
    876                                           stun.stun_port1, 
    877                                          &stun.stun_srv2,  
    878                                           stun.stun_port2, 
    879                                           p_pub_addr); 
     935                                         &stun_srv, 3478, 
     936                                         &stun_srv, 3478, 
     937                                         p_pub_addr); 
    880938        if (status != PJ_SUCCESS) { 
    881939            pjsua_perror(THIS_FILE, "Error resolving with STUN", status); 
     
    9871045         */ 
    9881046        status = create_sip_udp_sock(bound_addr.sin_addr, cfg->port,  
    989                                      cfg->use_stun, &cfg->stun_config,  
    9901047                                     &sock, &pub_addr); 
    9911048        if (status != PJ_SUCCESS) 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c

    r1066 r1098  
    216216    pj_sock_t sock[2]; 
    217217 
     218    /* Make sure STUN server resolution has completed */ 
     219    status = pjsua_resolve_stun_server(PJ_TRUE); 
     220    if (status != PJ_SUCCESS) { 
     221        pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 
     222        return status; 
     223    } 
     224 
     225 
    218226    if (next_rtp_port == 0) 
    219227        next_rtp_port = (pj_uint16_t)cfg->port; 
     
    273281         * and make sure that the mapped RTCP port is adjacent with the RTP. 
    274282         */ 
    275         if (cfg->stun_config.stun_srv1.slen) { 
     283        if (pjsua_var.stun_srv.addr.sa_family != 0) { 
     284            char ip_addr[32]; 
     285            pj_str_t stun_srv; 
     286 
     287            pj_ansi_strcpy(ip_addr,  
     288                           pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr)); 
     289            stun_srv = pj_str(ip_addr); 
     290 
    276291            status=pjstun_get_mapped_addr(&pjsua_var.cp.factory, 2, sock, 
    277                                            &cfg->stun_config.stun_srv1,  
    278                                            cfg->stun_config.stun_port1, 
    279                                            &cfg->stun_config.stun_srv2,  
    280                                            cfg->stun_config.stun_port2, 
     292                                           &stun_srv, 3478, 
     293                                           &stun_srv, 3478, 
    281294                                           mapped_addr); 
    282295            if (status != PJ_SUCCESS) { 
     
    489502 
    490503 
    491 /* 
    492  * Create UDP media transports for all the calls. This function creates 
    493  * one UDP media transport for each call. 
    494  */ 
    495 PJ_DEF(pj_status_t)  
    496 pjsua_media_transports_create(const pjsua_transport_config *app_cfg) 
    497 { 
    498     pjsua_transport_config cfg; 
     504/* Create normal UDP media transports */ 
     505static pj_status_t create_udp_media_transports(pjsua_transport_config *cfg) 
     506{ 
    499507    unsigned i; 
    500508    pj_status_t status; 
    501509 
    502  
    503     /* Make sure pjsua_init() has been called */ 
    504     PJ_ASSERT_RETURN(pjsua_var.ua_cfg.max_calls>0, PJ_EINVALIDOP); 
    505  
    506     PJSUA_LOCK(); 
    507  
    508     /* Delete existing media transports */ 
    509     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    510         if (pjsua_var.calls[i].med_tp != NULL) { 
    511             pjsua_var.calls[i].med_tp->op->destroy(pjsua_var.calls[i].med_tp); 
    512             pjsua_var.calls[i].med_tp = NULL; 
    513         } 
    514     } 
    515  
    516     /* Copy config */ 
    517     pj_memcpy(&cfg, app_cfg, sizeof(*app_cfg)); 
    518     pjsua_normalize_stun_config(&cfg.stun_config); 
    519  
    520510    /* Create each media transport */ 
    521511    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    522512 
    523         status = create_rtp_rtcp_sock(&cfg, &pjsua_var.calls[i].skinfo); 
     513        status = create_rtp_rtcp_sock(cfg, &pjsua_var.calls[i].skinfo); 
    524514        if (status != PJ_SUCCESS) { 
    525515            pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket", 
     
    546536    } 
    547537 
    548     PJSUA_UNLOCK(); 
    549  
    550538    return PJ_SUCCESS; 
    551539 
     
    553541    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    554542        if (pjsua_var.calls[i].med_tp != NULL) { 
    555             pjsua_var.calls[i].med_tp->op->destroy(pjsua_var.calls[i].med_tp); 
     543            pjmedia_transport_close(pjsua_var.calls[i].med_tp); 
    556544            pjsua_var.calls[i].med_tp = NULL; 
    557545        } 
    558546    } 
    559547 
     548    return status; 
     549} 
     550 
     551 
     552/* Create ICE media transports (when ice is enabled) */ 
     553static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg) 
     554{ 
     555    unsigned i; 
     556    pj_status_t status; 
     557 
     558    /* Create each media transport */ 
     559    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
     560        pj_ice_st *ice_st; 
     561 
     562        status = pjmedia_ice_create(pjsua_var.med_endpt, NULL, 1, 
     563                                    &pjsua_var.stun_cfg,  
     564                                    &pjsua_var.calls[i].med_tp); 
     565        if (status != PJ_SUCCESS) { 
     566            pjsua_perror(THIS_FILE, "Unable to create ICE media transport", 
     567                         status); 
     568            goto on_error; 
     569        } 
     570 
     571        ice_st = pjmedia_ice_get_ice_st(pjsua_var.calls[i].med_tp); 
     572 
     573        /* Add host candidates for RTP */ 
     574        status = pj_ice_st_add_all_host_interfaces(ice_st, 1, 0,  
     575                                                   PJ_FALSE, NULL); 
     576        if (status != PJ_SUCCESS) { 
     577            pjsua_perror(THIS_FILE, "Error adding ICE host candidates", 
     578                         status); 
     579            goto on_error; 
     580        } 
     581 
     582        /* Configure STUN server */ 
     583        if (pjsua_var.stun_srv.addr.sa_family != 0) { 
     584         
     585            status = pj_ice_st_set_stun_addr(ice_st,  
     586                                             pjsua_var.media_cfg.enable_relay, 
     587                                             &pjsua_var.stun_srv.ipv4); 
     588            if (status != PJ_SUCCESS) { 
     589                pjsua_perror(THIS_FILE, "Error setting ICE's STUN server", 
     590                             status); 
     591                goto on_error; 
     592            } 
     593 
     594            /* Add STUN server reflexive candidate for RTP */ 
     595            status = pj_ice_st_add_stun_interface(ice_st, 1, 0,  
     596                                                  PJ_FALSE, NULL); 
     597            if (status != PJ_SUCCESS) { 
     598                pjsua_perror(THIS_FILE, "Error adding ICE address", 
     599                             status); 
     600                goto on_error; 
     601            } 
     602        } 
     603    } 
     604 
     605    /* Wait until all ICE transports are ready */ 
     606    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
     607        pj_ice_st *ice_st; 
     608 
     609        ice_st = pjmedia_ice_get_ice_st(pjsua_var.calls[i].med_tp); 
     610 
     611        /* Wait until interface status is PJ_SUCCESS */ 
     612        for (;;) { 
     613            status = pj_ice_st_get_interfaces_status(ice_st); 
     614            if (status == PJ_EPENDING) 
     615                pjsua_handle_events(100); 
     616            else 
     617                break; 
     618        } 
     619 
     620        if (status != PJ_SUCCESS) { 
     621            pjsua_perror(THIS_FILE,  
     622                         "Error adding STUN address to ICE media transport", 
     623                         status); 
     624            goto on_error; 
     625        } 
     626 
     627        /* Get transport info */ 
     628        pjmedia_transport_get_info(pjsua_var.calls[i].med_tp, 
     629                                   &pjsua_var.calls[i].skinfo); 
     630 
     631    } 
     632 
     633    return PJ_SUCCESS; 
     634 
     635on_error: 
     636    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
     637        if (pjsua_var.calls[i].med_tp != NULL) { 
     638            pjmedia_transport_close(pjsua_var.calls[i].med_tp); 
     639            pjsua_var.calls[i].med_tp = NULL; 
     640        } 
     641    } 
     642 
     643    return status; 
     644} 
     645 
     646 
     647/* 
     648 * Create UDP media transports for all the calls. This function creates 
     649 * one UDP media transport for each call. 
     650 */ 
     651PJ_DEF(pj_status_t)  
     652pjsua_media_transports_create(const pjsua_transport_config *app_cfg) 
     653{ 
     654    pjsua_transport_config cfg; 
     655    unsigned i; 
     656    pj_status_t status; 
     657 
     658 
     659    /* Make sure pjsua_init() has been called */ 
     660    PJ_ASSERT_RETURN(pjsua_var.ua_cfg.max_calls>0, PJ_EINVALIDOP); 
     661 
     662    PJSUA_LOCK(); 
     663 
     664    /* Delete existing media transports */ 
     665    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
     666        if (pjsua_var.calls[i].med_tp != NULL) { 
     667            pjmedia_transport_close(pjsua_var.calls[i].med_tp); 
     668            pjsua_var.calls[i].med_tp = NULL; 
     669        } 
     670    } 
     671 
     672    /* Copy config */ 
     673    pjsua_transport_config_dup(pjsua_var.pool, &cfg, app_cfg); 
     674 
     675    if (pjsua_var.media_cfg.enable_ice) { 
     676        status = create_ice_media_transports(&cfg); 
     677    } else { 
     678        status = create_udp_media_transports(&cfg); 
     679    } 
     680 
     681 
    560682    PJSUA_UNLOCK(); 
    561683 
    562684    return status; 
     685} 
     686 
     687 
     688pj_status_t pjsua_media_channel_init(pjsua_call_id call_id, 
     689                                     pjsip_role_e role) 
     690{ 
     691    pjsua_call *call = &pjsua_var.calls[call_id]; 
     692 
     693    if (pjsua_var.media_cfg.enable_ice) { 
     694        pj_ice_role ice_role; 
     695        pj_status_t status; 
     696 
     697        ice_role = (role==PJSIP_ROLE_UAC ? PJ_ICE_ROLE_CONTROLLING :  
     698                                           PJ_ICE_ROLE_CONTROLLED); 
     699 
     700        /* Restart ICE */ 
     701        pjmedia_ice_stop_ice(call->med_tp); 
     702 
     703        status = pjmedia_ice_init_ice(call->med_tp, ice_role, NULL, NULL); 
     704        if (status != PJ_SUCCESS) 
     705            return status; 
     706    } 
     707 
     708    return PJ_SUCCESS; 
     709} 
     710 
     711pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,  
     712                                           pj_pool_t *pool, 
     713                                           pjmedia_sdp_session **p_sdp) 
     714{ 
     715    pjmedia_sdp_session *sdp; 
     716    pjsua_call *call = &pjsua_var.calls[call_id]; 
     717    pj_status_t status; 
     718 
     719    status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pool, 1, 
     720                                      &call->skinfo, &sdp); 
     721    if (status != PJ_SUCCESS) 
     722        goto on_error; 
     723 
     724    if (pjsua_var.media_cfg.enable_ice) { 
     725        status = pjmedia_ice_modify_sdp(call->med_tp, pool, sdp); 
     726        if (status != PJ_SUCCESS) 
     727            goto on_error; 
     728    } 
     729 
     730    *p_sdp = sdp; 
     731    return PJ_SUCCESS; 
     732 
     733on_error: 
     734    pjsua_media_channel_deinit(call_id); 
     735    return status; 
     736 
     737} 
     738 
     739 
     740static void stop_media_session(pjsua_call_id call_id) 
     741{ 
     742    pjsua_call *call = &pjsua_var.calls[call_id]; 
     743 
     744    if (call->conf_slot != PJSUA_INVALID_ID) { 
     745        pjmedia_conf_remove_port(pjsua_var.mconf, call->conf_slot); 
     746        call->conf_slot = PJSUA_INVALID_ID; 
     747    } 
     748 
     749    if (call->session) { 
     750        pjmedia_session_destroy(call->session); 
     751        call->session = NULL; 
     752 
     753        PJ_LOG(4,(THIS_FILE, "Media session for call %d is destroyed",  
     754                             call_id)); 
     755 
     756    } 
     757 
     758    call->media_st = PJSUA_CALL_MEDIA_NONE; 
     759} 
     760 
     761pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id) 
     762{ 
     763    pjsua_call *call = &pjsua_var.calls[call_id]; 
     764 
     765    stop_media_session(call_id); 
     766 
     767    if (pjsua_var.media_cfg.enable_ice) { 
     768        pjmedia_ice_stop_ice(call->med_tp); 
     769    } 
     770 
     771    return PJ_SUCCESS; 
     772} 
     773 
     774 
     775/* 
     776 * DTMF callback from the stream. 
     777 */ 
     778static void dtmf_callback(pjmedia_stream *strm, void *user_data, 
     779                          int digit) 
     780{ 
     781    PJ_UNUSED_ARG(strm); 
     782 
     783    if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { 
     784        pjsua_call_id call_id; 
     785 
     786        call_id = (pjsua_call_id)user_data; 
     787        pjsua_var.ua_cfg.cb.on_dtmf_digit(call_id, digit); 
     788    } 
     789} 
     790 
     791 
     792pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 
     793                                       pjmedia_sdp_session *local_sdp, 
     794                                       pjmedia_sdp_session *remote_sdp) 
     795{ 
     796    int prev_media_st = 0; 
     797    pjsua_call *call = &pjsua_var.calls[call_id]; 
     798    pjmedia_session_info sess_info; 
     799    pjmedia_port *media_port; 
     800    pj_str_t port_name; 
     801    char tmp[PJSIP_MAX_URL_SIZE]; 
     802    pj_status_t status; 
     803 
     804    /* Destroy existing media session, if any. */ 
     805    prev_media_st = call->media_st; 
     806    stop_media_session(call->index); 
     807 
     808    /* Create media session info based on SDP parameters.  
     809     * We only support one stream per session at the moment 
     810     */     
     811    status = pjmedia_session_info_from_sdp( call->inv->dlg->pool,  
     812                                            pjsua_var.med_endpt,  
     813                                            1,&sess_info,  
     814                                            local_sdp, remote_sdp); 
     815    if (status != PJ_SUCCESS) 
     816        return status; 
     817 
     818 
     819    /* Check if media is put on-hold */ 
     820    if (sess_info.stream_cnt == 0 ||  
     821        sess_info.stream_info[0].dir == PJMEDIA_DIR_NONE) 
     822    { 
     823 
     824        /* Determine who puts the call on-hold */ 
     825        if (prev_media_st == PJSUA_CALL_MEDIA_ACTIVE) { 
     826            if (pjmedia_sdp_neg_was_answer_remote(call->inv->neg)) { 
     827                /* It was local who offer hold */ 
     828                call->media_st = PJSUA_CALL_MEDIA_LOCAL_HOLD; 
     829            } else { 
     830                call->media_st = PJSUA_CALL_MEDIA_REMOTE_HOLD; 
     831            } 
     832        } 
     833 
     834        call->media_dir = PJMEDIA_DIR_NONE; 
     835 
     836        /* Shutdown transport */ 
     837        /* No need because we need keepalive? */ 
     838 
     839    } else { 
     840 
     841        /* Start ICE */ 
     842        if (pjsua_var.media_cfg.enable_ice) { 
     843            status = pjmedia_ice_start_ice(call->med_tp, call->inv->pool,  
     844                                           remote_sdp); 
     845            if (status != PJ_SUCCESS) 
     846                return status; 
     847        } 
     848 
     849        /* Override ptime, if this option is specified. */ 
     850        if (pjsua_var.media_cfg.ptime != 0) { 
     851            sess_info.stream_info[0].param->setting.frm_per_pkt = (pj_uint8_t) 
     852                (pjsua_var.media_cfg.ptime / sess_info.stream_info[0].param->info.frm_ptime); 
     853            if (sess_info.stream_info[0].param->setting.frm_per_pkt == 0) 
     854                sess_info.stream_info[0].param->setting.frm_per_pkt = 1; 
     855        } 
     856 
     857        /* Disable VAD, if this option is specified. */ 
     858        if (pjsua_var.media_cfg.no_vad) { 
     859            sess_info.stream_info[0].param->setting.vad = 0; 
     860        } 
     861 
     862 
     863        /* Optionally, application may modify other stream settings here 
     864         * (such as jitter buffer parameters, codec ptime, etc.) 
     865         */ 
     866        sess_info.stream_info[0].jb_init = pjsua_var.media_cfg.jb_init; 
     867        sess_info.stream_info[0].jb_min_pre = pjsua_var.media_cfg.jb_min_pre; 
     868        sess_info.stream_info[0].jb_max_pre = pjsua_var.media_cfg.jb_max_pre; 
     869        sess_info.stream_info[0].jb_max = pjsua_var.media_cfg.jb_max; 
     870 
     871        /* Create session based on session info. */ 
     872        status = pjmedia_session_create( pjsua_var.med_endpt, &sess_info, 
     873                                         &call->med_tp, 
     874                                         call, &call->session ); 
     875        if (status != PJ_SUCCESS) { 
     876            return status; 
     877        } 
     878 
     879        /* If DTMF callback is installed by application, install our 
     880         * callback to the session. 
     881         */ 
     882        if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { 
     883            pjmedia_session_set_dtmf_callback(call->session, 0,  
     884                                              &dtmf_callback,  
     885                                              (void*)(call->index)); 
     886        } 
     887 
     888        /* Get the port interface of the first stream in the session. 
     889         * We need the port interface to add to the conference bridge. 
     890         */ 
     891        pjmedia_session_get_port(call->session, 0, &media_port); 
     892 
     893 
     894        /* 
     895         * Add the call to conference bridge. 
     896         */ 
     897        port_name.ptr = tmp; 
     898        port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, 
     899                                         call->inv->dlg->remote.info->uri, 
     900                                         tmp, sizeof(tmp)); 
     901        if (port_name.slen < 1) { 
     902            port_name = pj_str("call"); 
     903        } 
     904        status = pjmedia_conf_add_port( pjsua_var.mconf, call->inv->pool, 
     905                                        media_port,  
     906                                        &port_name, 
     907                                        (unsigned*)&call->conf_slot); 
     908        if (status != PJ_SUCCESS) { 
     909            return status; 
     910        } 
     911 
     912        /* Call's media state is active */ 
     913        call->media_st = PJSUA_CALL_MEDIA_ACTIVE; 
     914        call->media_dir = sess_info.stream_info[0].dir; 
     915    } 
     916 
     917    /* Print info. */ 
     918    { 
     919        char info[80]; 
     920        int info_len = 0; 
     921        unsigned i; 
     922 
     923        for (i=0; i<sess_info.stream_cnt; ++i) { 
     924            int len; 
     925            const char *dir; 
     926            pjmedia_stream_info *strm_info = &sess_info.stream_info[i]; 
     927 
     928            switch (strm_info->dir) { 
     929            case PJMEDIA_DIR_NONE: 
     930                dir = "inactive"; 
     931                break; 
     932            case PJMEDIA_DIR_ENCODING: 
     933                dir = "sendonly"; 
     934                break; 
     935            case PJMEDIA_DIR_DECODING: 
     936                dir = "recvonly"; 
     937                break; 
     938            case PJMEDIA_DIR_ENCODING_DECODING: 
     939                dir = "sendrecv"; 
     940                break; 
     941            default: 
     942                dir = "unknown"; 
     943                break; 
     944            } 
     945            len = pj_ansi_sprintf( info+info_len, 
     946                                   ", stream #%d: %.*s (%s)", i, 
     947                                   (int)strm_info->fmt.encoding_name.slen, 
     948                                   strm_info->fmt.encoding_name.ptr, 
     949                                   dir); 
     950            if (len > 0) 
     951                info_len += len; 
     952        } 
     953        PJ_LOG(4,(THIS_FILE,"Media updates%s", info)); 
     954    } 
     955 
     956    return PJ_SUCCESS; 
    563957} 
    564958 
Note: See TracChangeset for help on using the changeset viewer.