Ignore:
Timestamp:
Jul 19, 2011 3:42:28 AM (13 years ago)
Author:
nanang
Message:

Re #1326: Initial code integration from branch 2.0-dev to trunk as "2.0-pre-alpha-svn".

Location:
pjproject/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk

  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c

    r3553 r3664  
    5959} 
    6060 
     61 
    6162/** 
    6263 * Init media subsystems. 
     
    6667    pj_str_t codec_id = {NULL, 0}; 
    6768    unsigned opt; 
     69    pjmedia_audio_codec_config codec_cfg; 
    6870    pj_status_t status; 
    6971 
     
    112114    } 
    113115 
    114     /* Register all codecs */ 
    115  
    116 #if PJMEDIA_HAS_SPEEX_CODEC 
    117     /* Register speex. */ 
    118     status = pjmedia_codec_speex_init(pjsua_var.med_endpt,   
    119                                       0,  
    120                                       pjsua_var.media_cfg.quality,   
    121                                       -1); 
    122     if (status != PJ_SUCCESS) { 
    123         pjsua_perror(THIS_FILE, "Error initializing Speex codec", 
    124                      status); 
    125         return status; 
    126     } 
    127  
    128     /* Set speex/16000 to higher priority*/ 
    129     codec_id = pj_str("speex/16000"); 
    130     pjmedia_codec_mgr_set_codec_priority(  
    131         pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt), 
    132         &codec_id, PJMEDIA_CODEC_PRIO_NORMAL+2); 
    133  
    134     /* Set speex/8000 to next higher priority*/ 
    135     codec_id = pj_str("speex/8000"); 
    136     pjmedia_codec_mgr_set_codec_priority(  
    137         pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt), 
    138         &codec_id, PJMEDIA_CODEC_PRIO_NORMAL+1); 
    139  
    140  
    141  
    142 #endif /* PJMEDIA_HAS_SPEEX_CODEC */ 
    143  
    144 #if PJMEDIA_HAS_ILBC_CODEC 
    145     /* Register iLBC. */ 
    146     status = pjmedia_codec_ilbc_init( pjsua_var.med_endpt,  
    147                                       pjsua_var.media_cfg.ilbc_mode); 
    148     if (status != PJ_SUCCESS) { 
    149         pjsua_perror(THIS_FILE, "Error initializing iLBC codec", 
    150                      status); 
    151         return status; 
    152     } 
    153 #endif /* PJMEDIA_HAS_ILBC_CODEC */ 
    154  
    155 #if PJMEDIA_HAS_GSM_CODEC 
    156     /* Register GSM */ 
    157     status = pjmedia_codec_gsm_init(pjsua_var.med_endpt); 
    158     if (status != PJ_SUCCESS) { 
    159         pjsua_perror(THIS_FILE, "Error initializing GSM codec", 
    160                      status); 
    161         return status; 
    162     } 
    163 #endif /* PJMEDIA_HAS_GSM_CODEC */ 
    164  
    165 #if PJMEDIA_HAS_G711_CODEC 
    166     /* Register PCMA and PCMU */ 
    167     status = pjmedia_codec_g711_init(pjsua_var.med_endpt); 
    168     if (status != PJ_SUCCESS) { 
    169         pjsua_perror(THIS_FILE, "Error initializing G711 codec", 
    170                      status); 
    171         return status; 
    172     } 
    173 #endif  /* PJMEDIA_HAS_G711_CODEC */ 
    174  
    175 #if PJMEDIA_HAS_G722_CODEC 
    176     status = pjmedia_codec_g722_init( pjsua_var.med_endpt ); 
    177     if (status != PJ_SUCCESS) { 
    178         pjsua_perror(THIS_FILE, "Error initializing G722 codec", 
    179                      status); 
    180         return status; 
    181     } 
    182 #endif  /* PJMEDIA_HAS_G722_CODEC */ 
    183  
    184 #if PJMEDIA_HAS_INTEL_IPP 
    185     /* Register IPP codecs */ 
    186     status = pjmedia_codec_ipp_init(pjsua_var.med_endpt); 
    187     if (status != PJ_SUCCESS) { 
    188         pjsua_perror(THIS_FILE, "Error initializing IPP codecs", 
    189                      status); 
    190         return status; 
    191     } 
    192  
    193 #endif /* PJMEDIA_HAS_INTEL_IPP */ 
     116    /* 
     117     * Register all codecs 
     118     */ 
     119    pjmedia_audio_codec_config_default(&codec_cfg); 
     120    codec_cfg.speex.quality = pjsua_var.media_cfg.quality; 
     121    codec_cfg.speex.complexity = -1; 
     122    codec_cfg.ilbc.mode = pjsua_var.media_cfg.ilbc_mode; 
    194123 
    195124#if PJMEDIA_HAS_PASSTHROUGH_CODECS 
     
    199128        unsigned ext_fmt_cnt = 0; 
    200129        pjmedia_format ext_fmts[32]; 
    201         pjmedia_codec_passthrough_setting setting; 
    202130 
    203131        /* List extended formats supported by audio devices */ 
     
    236164 
    237165        /* Init the passthrough codec with supported formats only */ 
    238         setting.fmt_cnt = ext_fmt_cnt; 
    239         setting.fmts = ext_fmts; 
    240         setting.ilbc_mode = cfg->ilbc_mode; 
    241         status = pjmedia_codec_passthrough_init2(pjsua_var.med_endpt, &setting); 
    242         if (status != PJ_SUCCESS) { 
    243             pjsua_perror(THIS_FILE, "Error initializing passthrough codecs", 
    244                          status); 
    245             return status; 
    246         } 
     166        codec_cfg.passthrough.setting.fmt_cnt = ext_fmt_cnt; 
     167        codec_cfg.passthrough.setting.fmts = ext_fmts; 
     168        codec_cfg.passthrough.setting.ilbc_mode = cfg->ilbc_mode; 
    247169    } 
    248170#endif /* PJMEDIA_HAS_PASSTHROUGH_CODECS */ 
    249171 
    250 #if PJMEDIA_HAS_G7221_CODEC 
    251     /* Register G722.1 codecs */ 
    252     status = pjmedia_codec_g7221_init(pjsua_var.med_endpt); 
     172    /* Register all codecs */ 
     173    status = pjmedia_codec_register_audio_codecs(pjsua_var.med_endpt, 
     174                                                 &codec_cfg); 
    253175    if (status != PJ_SUCCESS) { 
    254         pjsua_perror(THIS_FILE, "Error initializing G722.1 codec", 
    255                      status); 
     176        PJ_PERROR(1,(THIS_FILE, status, "Error registering codecs")); 
    256177        return status; 
    257178    } 
    258 #endif /* PJMEDIA_HAS_G7221_CODEC */ 
    259  
    260 #if PJMEDIA_HAS_L16_CODEC 
    261     /* Register L16 family codecs, but disable all */ 
    262     status = pjmedia_codec_l16_init(pjsua_var.med_endpt, 0); 
    263     if (status != PJ_SUCCESS) { 
    264         pjsua_perror(THIS_FILE, "Error initializing L16 codecs", 
    265                      status); 
    266         return status; 
    267     } 
     179 
     180    /* Set speex/16000 to higher priority*/ 
     181    codec_id = pj_str("speex/16000"); 
     182    pjmedia_codec_mgr_set_codec_priority( 
     183        pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt), 
     184        &codec_id, PJMEDIA_CODEC_PRIO_NORMAL+2); 
     185 
     186    /* Set speex/8000 to next higher priority*/ 
     187    codec_id = pj_str("speex/8000"); 
     188    pjmedia_codec_mgr_set_codec_priority( 
     189        pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt), 
     190        &codec_id, PJMEDIA_CODEC_PRIO_NORMAL+1); 
    268191 
    269192    /* Disable ALL L16 codecs */ 
     
    272195        pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt), 
    273196        &codec_id, PJMEDIA_CODEC_PRIO_DISABLED); 
    274  
    275 #endif  /* PJMEDIA_HAS_L16_CODEC */ 
    276197 
    277198 
     
    297218    } 
    298219         
    299  
    300220    /* Init conference bridge. */ 
    301221    status = pjmedia_conf_create(pjsua_var.pool,  
     
    335255#endif 
    336256 
     257    /* Video */ 
     258#if PJMEDIA_HAS_VIDEO 
     259    status = pjsua_vid_subsys_init(); 
     260    if (status != PJ_SUCCESS) 
     261        return status; 
     262#endif 
     263 
    337264    return PJ_SUCCESS; 
    338265} 
    339266 
    340  
    341 /*  
    342  * Create RTP and RTCP socket pair, and possibly resolve their public 
    343  * address via STUN. 
    344  */ 
    345 static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg, 
    346                                         pjmedia_sock_info *skinfo) 
    347 { 
    348     enum {  
    349         RTP_RETRY = 100 
    350     }; 
    351     int i; 
    352     pj_sockaddr_in bound_addr; 
    353     pj_sockaddr_in mapped_addr[2]; 
    354     pj_status_t status = PJ_SUCCESS; 
    355     char addr_buf[PJ_INET6_ADDRSTRLEN+2]; 
    356     pj_sock_t sock[2]; 
    357  
    358     /* Make sure STUN server resolution has completed */ 
    359     status = resolve_stun_server(PJ_TRUE); 
    360     if (status != PJ_SUCCESS) { 
    361         pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 
    362         return status; 
    363     } 
    364  
    365     if (next_rtp_port == 0) 
    366         next_rtp_port = (pj_uint16_t)cfg->port; 
    367  
    368     for (i=0; i<2; ++i) 
    369         sock[i] = PJ_INVALID_SOCKET; 
    370  
    371     bound_addr.sin_addr.s_addr = PJ_INADDR_ANY; 
    372     if (cfg->bound_addr.slen) { 
    373         status = pj_sockaddr_in_set_str_addr(&bound_addr, &cfg->bound_addr); 
    374         if (status != PJ_SUCCESS) { 
    375             pjsua_perror(THIS_FILE, "Unable to resolve transport bind address", 
    376                          status); 
    377             return status; 
    378         } 
    379     } 
    380  
    381     /* Loop retry to bind RTP and RTCP sockets. */ 
    382     for (i=0; i<RTP_RETRY; ++i, next_rtp_port += 2) { 
    383  
    384         /* Create RTP socket. */ 
    385         status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[0]); 
    386         if (status != PJ_SUCCESS) { 
    387             pjsua_perror(THIS_FILE, "socket() error", status); 
    388             return status; 
    389         } 
    390  
    391         /* Apply QoS to RTP socket, if specified */ 
    392         status = pj_sock_apply_qos2(sock[0], cfg->qos_type,  
    393                                     &cfg->qos_params,  
    394                                     2, THIS_FILE, "RTP socket"); 
    395  
    396         /* Bind RTP socket */ 
    397         status=pj_sock_bind_in(sock[0], pj_ntohl(bound_addr.sin_addr.s_addr),  
    398                                next_rtp_port); 
    399         if (status != PJ_SUCCESS) { 
    400             pj_sock_close(sock[0]);  
    401             sock[0] = PJ_INVALID_SOCKET; 
    402             continue; 
    403         } 
    404  
    405         /* Create RTCP socket. */ 
    406         status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[1]); 
    407         if (status != PJ_SUCCESS) { 
    408             pjsua_perror(THIS_FILE, "socket() error", status); 
    409             pj_sock_close(sock[0]); 
    410             return status; 
    411         } 
    412  
    413         /* Apply QoS to RTCP socket, if specified */ 
    414         status = pj_sock_apply_qos2(sock[1], cfg->qos_type,  
    415                                     &cfg->qos_params,  
    416                                     2, THIS_FILE, "RTCP socket"); 
    417  
    418         /* Bind RTCP socket */ 
    419         status=pj_sock_bind_in(sock[1], pj_ntohl(bound_addr.sin_addr.s_addr),  
    420                                (pj_uint16_t)(next_rtp_port+1)); 
    421         if (status != PJ_SUCCESS) { 
    422             pj_sock_close(sock[0]);  
    423             sock[0] = PJ_INVALID_SOCKET; 
    424  
    425             pj_sock_close(sock[1]);  
    426             sock[1] = PJ_INVALID_SOCKET; 
    427             continue; 
    428         } 
    429  
    430         /* 
    431          * If we're configured to use STUN, then find out the mapped address, 
    432          * and make sure that the mapped RTCP port is adjacent with the RTP. 
    433          */ 
    434         if (pjsua_var.stun_srv.addr.sa_family != 0) { 
    435             char ip_addr[32]; 
    436             pj_str_t stun_srv; 
    437  
    438             pj_ansi_strcpy(ip_addr,  
    439                            pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr)); 
    440             stun_srv = pj_str(ip_addr); 
    441  
    442             status=pjstun_get_mapped_addr(&pjsua_var.cp.factory, 2, sock, 
    443                                            &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), 
    444                                            &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), 
    445                                            mapped_addr); 
    446             if (status != PJ_SUCCESS) { 
    447                 pjsua_perror(THIS_FILE, "STUN resolve error", status); 
    448                 goto on_error; 
    449             } 
    450  
    451 #if PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT 
    452             if (pj_ntohs(mapped_addr[1].sin_port) ==  
    453                 pj_ntohs(mapped_addr[0].sin_port)+1) 
    454             { 
    455                 /* Success! */ 
    456                 break; 
    457             } 
    458  
    459             pj_sock_close(sock[0]);  
    460             sock[0] = PJ_INVALID_SOCKET; 
    461  
    462             pj_sock_close(sock[1]);  
    463             sock[1] = PJ_INVALID_SOCKET; 
    464 #else 
    465             if (pj_ntohs(mapped_addr[1].sin_port) !=  
    466                 pj_ntohs(mapped_addr[0].sin_port)+1) 
    467             { 
    468                 PJ_LOG(4,(THIS_FILE,  
    469                           "Note: STUN mapped RTCP port %d is not adjacent" 
    470                           " to RTP port %d", 
    471                           pj_ntohs(mapped_addr[1].sin_port), 
    472                           pj_ntohs(mapped_addr[0].sin_port))); 
    473             } 
    474             /* Success! */ 
    475             break; 
    476 #endif 
    477  
    478         } else if (cfg->public_addr.slen) { 
    479  
    480             status = pj_sockaddr_in_init(&mapped_addr[0], &cfg->public_addr, 
    481                                          (pj_uint16_t)next_rtp_port); 
    482             if (status != PJ_SUCCESS) 
    483                 goto on_error; 
    484  
    485             status = pj_sockaddr_in_init(&mapped_addr[1], &cfg->public_addr, 
    486                                          (pj_uint16_t)(next_rtp_port+1)); 
    487             if (status != PJ_SUCCESS) 
    488                 goto on_error; 
    489  
    490             break; 
    491  
    492         } else { 
    493  
    494             if (bound_addr.sin_addr.s_addr == 0) { 
    495                 pj_sockaddr addr; 
    496  
    497                 /* Get local IP address. */ 
    498                 status = pj_gethostip(pj_AF_INET(), &addr); 
    499                 if (status != PJ_SUCCESS) 
    500                     goto on_error; 
    501  
    502                 bound_addr.sin_addr.s_addr = addr.ipv4.sin_addr.s_addr; 
    503             } 
    504  
    505             for (i=0; i<2; ++i) { 
    506                 pj_sockaddr_in_init(&mapped_addr[i], NULL, 0); 
    507                 mapped_addr[i].sin_addr.s_addr = bound_addr.sin_addr.s_addr; 
    508             } 
    509  
    510             mapped_addr[0].sin_port=pj_htons((pj_uint16_t)next_rtp_port); 
    511             mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(next_rtp_port+1)); 
    512             break; 
    513         } 
    514     } 
    515  
    516     if (sock[0] == PJ_INVALID_SOCKET) { 
    517         PJ_LOG(1,(THIS_FILE,  
    518                   "Unable to find appropriate RTP/RTCP ports combination")); 
    519         goto on_error; 
    520     } 
    521  
    522  
    523     skinfo->rtp_sock = sock[0]; 
    524     pj_memcpy(&skinfo->rtp_addr_name,  
    525               &mapped_addr[0], sizeof(pj_sockaddr_in)); 
    526  
    527     skinfo->rtcp_sock = sock[1]; 
    528     pj_memcpy(&skinfo->rtcp_addr_name,  
    529               &mapped_addr[1], sizeof(pj_sockaddr_in)); 
    530  
    531     PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s", 
    532               pj_sockaddr_print(&skinfo->rtp_addr_name, addr_buf, 
    533                                 sizeof(addr_buf), 3))); 
    534     PJ_LOG(4,(THIS_FILE, "RTCP socket reachable at %s", 
    535               pj_sockaddr_print(&skinfo->rtcp_addr_name, addr_buf, 
    536                                 sizeof(addr_buf), 3))); 
    537  
    538     next_rtp_port += 2; 
    539     return PJ_SUCCESS; 
    540  
    541 on_error: 
    542     for (i=0; i<2; ++i) { 
    543         if (sock[i] != PJ_INVALID_SOCKET) 
    544             pj_sock_close(sock[i]); 
    545     } 
    546     return status; 
    547 } 
    548267 
    549268/* Check if sound device is idle. */ 
     
    578297     * It is idle when there is no port connection in the bridge and 
    579298     * there is no active call. 
     299     * 
     300     * Note: this block is now valid if no snd dev is used because of #1299 
    580301     */ 
    581     if ((pjsua_var.snd_port!=NULL || pjsua_var.null_snd!=NULL) &&  
     302    if ((pjsua_var.snd_port!=NULL || pjsua_var.null_snd!=NULL || 
     303            pjsua_var.no_snd) && 
    582304        pjsua_var.snd_idle_timer.id == PJ_FALSE && 
    583305        pjmedia_conf_get_connect_count(pjsua_var.mconf) == 0 && 
     
    591313 
    592314        pjsua_var.snd_idle_timer.id = PJ_TRUE; 
    593         pjsip_endpt_schedule_timer(pjsua_var.endpt, &pjsua_var.snd_idle_timer,  
     315        pjsip_endpt_schedule_timer(pjsua_var.endpt, &pjsua_var.snd_idle_timer, 
    594316                                   &delay); 
    595317    } 
     
    605327    PJSUA_LOCK(); 
    606328    if (entry->id) { 
    607         PJ_LOG(4,(THIS_FILE,"Closing sound device after idle for %d seconds",  
     329        PJ_LOG(4,(THIS_FILE,"Closing sound device after idle for %d seconds", 
    608330                  pjsua_var.media_cfg.snd_auto_close_time)); 
    609331 
     
    623345    pj_status_t status; 
    624346 
     347#if DISABLED_FOR_TICKET_1185 
    625348    /* Create media for calls, if none is specified */ 
    626     if (pjsua_var.calls[0].med_tp == NULL) { 
     349    if (pjsua_var.calls[0].media[0].tp == NULL) { 
    627350        pjsua_transport_config transport_cfg; 
    628351 
     
    635358            return status; 
    636359    } 
    637  
    638     pj_timer_entry_init(&pjsua_var.snd_idle_timer, PJ_FALSE, NULL,  
     360#endif 
     361 
     362    pj_timer_entry_init(&pjsua_var.snd_idle_timer, PJ_FALSE, NULL, 
    639363                        &close_snd_timer_cb); 
    640364 
     365    /* Video */ 
     366#if PJMEDIA_HAS_VIDEO 
     367    status = pjsua_vid_subsys_start(); 
     368    if (status != PJ_SUCCESS) 
     369        return status; 
     370#endif 
     371 
    641372    /* Perform NAT detection */ 
    642     pjsua_detect_nat_type(); 
     373    status = pjsua_detect_nat_type(); 
     374    if (status != PJ_SUCCESS) { 
     375        PJ_PERROR(1,(THIS_FILE, status, "NAT type detection failed")); 
     376    } 
    643377 
    644378    return PJ_SUCCESS; 
     
    685419    /* Close media transports */ 
    686420    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    687         if (pjsua_var.calls[i].med_tp_st != PJSUA_MED_TP_IDLE) { 
    688             pjsua_media_channel_deinit(i); 
    689         } 
    690         if (pjsua_var.calls[i].med_tp && pjsua_var.calls[i].med_tp_auto_del) { 
    691             pjmedia_transport_close(pjsua_var.calls[i].med_tp); 
    692         } 
    693         pjsua_var.calls[i].med_tp = NULL; 
     421        unsigned strm_idx; 
     422        pjsua_call *call = &pjsua_var.calls[i]; 
     423        for (strm_idx=0; strm_idx<call->med_cnt; ++strm_idx) { 
     424            pjsua_call_media *call_med = &call->media[strm_idx]; 
     425            if (call_med->tp_st != PJSUA_MED_TP_IDLE) { 
     426                pjsua_media_channel_deinit(i); 
     427            } 
     428            if (call_med->tp && call_med->tp_auto_del) { 
     429                pjmedia_transport_close(call_med->tp); 
     430            } 
     431            call_med->tp = NULL; 
     432        } 
    694433    } 
    695434 
     
    697436    if (pjsua_var.med_endpt) { 
    698437 
    699         /* Shutdown all codecs: */ 
    700 #       if PJMEDIA_HAS_SPEEX_CODEC 
    701             pjmedia_codec_speex_deinit(); 
    702 #       endif /* PJMEDIA_HAS_SPEEX_CODEC */ 
    703  
    704 #       if PJMEDIA_HAS_GSM_CODEC 
    705             pjmedia_codec_gsm_deinit(); 
    706 #       endif /* PJMEDIA_HAS_GSM_CODEC */ 
    707  
    708 #       if PJMEDIA_HAS_G711_CODEC 
    709             pjmedia_codec_g711_deinit(); 
    710 #       endif   /* PJMEDIA_HAS_G711_CODEC */ 
    711  
    712 #       if PJMEDIA_HAS_G722_CODEC 
    713             pjmedia_codec_g722_deinit(); 
    714 #       endif   /* PJMEDIA_HAS_G722_CODEC */ 
    715  
    716 #       if PJMEDIA_HAS_INTEL_IPP 
    717             pjmedia_codec_ipp_deinit(); 
    718 #       endif   /* PJMEDIA_HAS_INTEL_IPP */ 
    719  
    720 #       if PJMEDIA_HAS_PASSTHROUGH_CODECS 
    721             pjmedia_codec_passthrough_deinit(); 
    722 #       endif /* PJMEDIA_HAS_PASSTHROUGH_CODECS */ 
    723  
    724 #       if PJMEDIA_HAS_G7221_CODEC 
    725             pjmedia_codec_g7221_deinit(); 
    726 #       endif /* PJMEDIA_HAS_G7221_CODEC */ 
    727  
    728 #       if PJMEDIA_HAS_L16_CODEC 
    729             pjmedia_codec_l16_deinit(); 
    730 #       endif   /* PJMEDIA_HAS_L16_CODEC */ 
     438#       if PJMEDIA_HAS_VIDEO 
     439            pjsua_vid_subsys_destroy(); 
     440#       endif 
    731441 
    732442        pjmedia_endpt_destroy(pjsua_var.med_endpt); 
     
    745455} 
    746456 
    747  
     457/* 
     458 * Create RTP and RTCP socket pair, and possibly resolve their public 
     459 * address via STUN. 
     460 */ 
     461static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg, 
     462                                        pjmedia_sock_info *skinfo) 
     463{ 
     464    enum { 
     465        RTP_RETRY = 100 
     466    }; 
     467    int i; 
     468    pj_sockaddr_in bound_addr; 
     469    pj_sockaddr_in mapped_addr[2]; 
     470    pj_status_t status = PJ_SUCCESS; 
     471    char addr_buf[PJ_INET6_ADDRSTRLEN+2]; 
     472    pj_sock_t sock[2]; 
     473 
     474    /* Make sure STUN server resolution has completed */ 
     475    status = resolve_stun_server(PJ_TRUE); 
     476    if (status != PJ_SUCCESS) { 
     477        pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 
     478        return status; 
     479    } 
     480 
     481    if (next_rtp_port == 0) 
     482        next_rtp_port = (pj_uint16_t)cfg->port; 
     483 
     484    if (next_rtp_port == 0) 
     485        next_rtp_port = (pj_uint16_t)40000; 
     486 
     487    for (i=0; i<2; ++i) 
     488        sock[i] = PJ_INVALID_SOCKET; 
     489 
     490    bound_addr.sin_addr.s_addr = PJ_INADDR_ANY; 
     491    if (cfg->bound_addr.slen) { 
     492        status = pj_sockaddr_in_set_str_addr(&bound_addr, &cfg->bound_addr); 
     493        if (status != PJ_SUCCESS) { 
     494            pjsua_perror(THIS_FILE, "Unable to resolve transport bind address", 
     495                         status); 
     496            return status; 
     497        } 
     498    } 
     499 
     500    /* Loop retry to bind RTP and RTCP sockets. */ 
     501    for (i=0; i<RTP_RETRY; ++i, next_rtp_port += 2) { 
     502 
     503        /* Create RTP socket. */ 
     504        status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[0]); 
     505        if (status != PJ_SUCCESS) { 
     506            pjsua_perror(THIS_FILE, "socket() error", status); 
     507            return status; 
     508        } 
     509 
     510        /* Apply QoS to RTP socket, if specified */ 
     511        status = pj_sock_apply_qos2(sock[0], cfg->qos_type, 
     512                                    &cfg->qos_params, 
     513                                    2, THIS_FILE, "RTP socket"); 
     514 
     515        /* Bind RTP socket */ 
     516        status=pj_sock_bind_in(sock[0], pj_ntohl(bound_addr.sin_addr.s_addr), 
     517                               next_rtp_port); 
     518        if (status != PJ_SUCCESS) { 
     519            pj_sock_close(sock[0]); 
     520            sock[0] = PJ_INVALID_SOCKET; 
     521            continue; 
     522        } 
     523 
     524        /* Create RTCP socket. */ 
     525        status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[1]); 
     526        if (status != PJ_SUCCESS) { 
     527            pjsua_perror(THIS_FILE, "socket() error", status); 
     528            pj_sock_close(sock[0]); 
     529            return status; 
     530        } 
     531 
     532        /* Apply QoS to RTCP socket, if specified */ 
     533        status = pj_sock_apply_qos2(sock[1], cfg->qos_type, 
     534                                    &cfg->qos_params, 
     535                                    2, THIS_FILE, "RTCP socket"); 
     536 
     537        /* Bind RTCP socket */ 
     538        status=pj_sock_bind_in(sock[1], pj_ntohl(bound_addr.sin_addr.s_addr), 
     539                               (pj_uint16_t)(next_rtp_port+1)); 
     540        if (status != PJ_SUCCESS) { 
     541            pj_sock_close(sock[0]); 
     542            sock[0] = PJ_INVALID_SOCKET; 
     543 
     544            pj_sock_close(sock[1]); 
     545            sock[1] = PJ_INVALID_SOCKET; 
     546            continue; 
     547        } 
     548 
     549        /* 
     550         * If we're configured to use STUN, then find out the mapped address, 
     551         * and make sure that the mapped RTCP port is adjacent with the RTP. 
     552         */ 
     553        if (pjsua_var.stun_srv.addr.sa_family != 0) { 
     554            char ip_addr[32]; 
     555            pj_str_t stun_srv; 
     556 
     557            pj_ansi_strcpy(ip_addr, 
     558                           pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr)); 
     559            stun_srv = pj_str(ip_addr); 
     560 
     561            status=pjstun_get_mapped_addr(&pjsua_var.cp.factory, 2, sock, 
     562                                           &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), 
     563                                           &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), 
     564                                           mapped_addr); 
     565            if (status != PJ_SUCCESS) { 
     566                pjsua_perror(THIS_FILE, "STUN resolve error", status); 
     567                goto on_error; 
     568            } 
     569 
     570#if PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT 
     571            if (pj_ntohs(mapped_addr[1].sin_port) == 
     572                pj_ntohs(mapped_addr[0].sin_port)+1) 
     573            { 
     574                /* Success! */ 
     575                break; 
     576            } 
     577 
     578            pj_sock_close(sock[0]); 
     579            sock[0] = PJ_INVALID_SOCKET; 
     580 
     581            pj_sock_close(sock[1]); 
     582            sock[1] = PJ_INVALID_SOCKET; 
     583#else 
     584            if (pj_ntohs(mapped_addr[1].sin_port) != 
     585                pj_ntohs(mapped_addr[0].sin_port)+1) 
     586            { 
     587                PJ_LOG(4,(THIS_FILE, 
     588                          "Note: STUN mapped RTCP port %d is not adjacent" 
     589                          " to RTP port %d", 
     590                          pj_ntohs(mapped_addr[1].sin_port), 
     591                          pj_ntohs(mapped_addr[0].sin_port))); 
     592            } 
     593            /* Success! */ 
     594            break; 
     595#endif 
     596 
     597        } else if (cfg->public_addr.slen) { 
     598 
     599            status = pj_sockaddr_in_init(&mapped_addr[0], &cfg->public_addr, 
     600                                         (pj_uint16_t)next_rtp_port); 
     601            if (status != PJ_SUCCESS) 
     602                goto on_error; 
     603 
     604            status = pj_sockaddr_in_init(&mapped_addr[1], &cfg->public_addr, 
     605                                         (pj_uint16_t)(next_rtp_port+1)); 
     606            if (status != PJ_SUCCESS) 
     607                goto on_error; 
     608 
     609            break; 
     610 
     611        } else { 
     612 
     613            if (bound_addr.sin_addr.s_addr == 0) { 
     614                pj_sockaddr addr; 
     615 
     616                /* Get local IP address. */ 
     617                status = pj_gethostip(pj_AF_INET(), &addr); 
     618                if (status != PJ_SUCCESS) 
     619                    goto on_error; 
     620 
     621                bound_addr.sin_addr.s_addr = addr.ipv4.sin_addr.s_addr; 
     622            } 
     623 
     624            for (i=0; i<2; ++i) { 
     625                pj_sockaddr_in_init(&mapped_addr[i], NULL, 0); 
     626                mapped_addr[i].sin_addr.s_addr = bound_addr.sin_addr.s_addr; 
     627            } 
     628 
     629            mapped_addr[0].sin_port=pj_htons((pj_uint16_t)next_rtp_port); 
     630            mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(next_rtp_port+1)); 
     631            break; 
     632        } 
     633    } 
     634 
     635    if (sock[0] == PJ_INVALID_SOCKET) { 
     636        PJ_LOG(1,(THIS_FILE, 
     637                  "Unable to find appropriate RTP/RTCP ports combination")); 
     638        goto on_error; 
     639    } 
     640 
     641 
     642    skinfo->rtp_sock = sock[0]; 
     643    pj_memcpy(&skinfo->rtp_addr_name, 
     644              &mapped_addr[0], sizeof(pj_sockaddr_in)); 
     645 
     646    skinfo->rtcp_sock = sock[1]; 
     647    pj_memcpy(&skinfo->rtcp_addr_name, 
     648              &mapped_addr[1], sizeof(pj_sockaddr_in)); 
     649 
     650    PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s", 
     651              pj_sockaddr_print(&skinfo->rtp_addr_name, addr_buf, 
     652                                sizeof(addr_buf), 3))); 
     653    PJ_LOG(4,(THIS_FILE, "RTCP socket reachable at %s", 
     654              pj_sockaddr_print(&skinfo->rtcp_addr_name, addr_buf, 
     655                                sizeof(addr_buf), 3))); 
     656 
     657    next_rtp_port += 2; 
     658    return PJ_SUCCESS; 
     659 
     660on_error: 
     661    for (i=0; i<2; ++i) { 
     662        if (sock[i] != PJ_INVALID_SOCKET) 
     663            pj_sock_close(sock[i]); 
     664    } 
     665    return status; 
     666} 
     667 
     668/* Create normal UDP media transports */ 
     669static pj_status_t create_udp_media_transport(const pjsua_transport_config *cfg, 
     670                                              pjsua_call_media *call_med) 
     671{ 
     672    pjmedia_sock_info skinfo; 
     673    pj_status_t status; 
     674 
     675    status = create_rtp_rtcp_sock(cfg, &skinfo); 
     676    if (status != PJ_SUCCESS) { 
     677        pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket", 
     678                     status); 
     679        goto on_error; 
     680    } 
     681 
     682    status = pjmedia_transport_udp_attach(pjsua_var.med_endpt, NULL, 
     683                                          &skinfo, 0, &call_med->tp); 
     684    if (status != PJ_SUCCESS) { 
     685        pjsua_perror(THIS_FILE, "Unable to create media transport", 
     686                     status); 
     687        goto on_error; 
     688    } 
     689 
     690    pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING, 
     691                                    pjsua_var.media_cfg.tx_drop_pct); 
     692 
     693    pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING, 
     694                                    pjsua_var.media_cfg.rx_drop_pct); 
     695 
     696    return PJ_SUCCESS; 
     697 
     698on_error: 
     699    if (call_med->tp) 
     700        pjmedia_transport_close(call_med->tp); 
     701 
     702    return status; 
     703} 
     704 
     705#if DISABLED_FOR_TICKET_1185 
    748706/* Create normal UDP media transports */ 
    749707static pj_status_t create_udp_media_transports(pjsua_transport_config *cfg) 
    750708{ 
    751709    unsigned i; 
    752     pjmedia_sock_info skinfo; 
    753710    pj_status_t status; 
    754711 
    755     /* Create each media transport */ 
    756     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    757  
    758         status = create_rtp_rtcp_sock(cfg, &skinfo); 
    759         if (status != PJ_SUCCESS) { 
    760             pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket", 
    761                          status); 
    762             goto on_error; 
    763         } 
    764  
    765         status = pjmedia_transport_udp_attach(pjsua_var.med_endpt, NULL, 
    766                                               &skinfo, 0, 
    767                                               &pjsua_var.calls[i].med_tp); 
    768         if (status != PJ_SUCCESS) { 
    769             pjsua_perror(THIS_FILE, "Unable to create media transport", 
    770                          status); 
    771             goto on_error; 
    772         } 
    773  
    774         pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 
    775                                         PJMEDIA_DIR_ENCODING, 
    776                                         pjsua_var.media_cfg.tx_drop_pct); 
    777  
    778         pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 
    779                                         PJMEDIA_DIR_DECODING, 
    780                                         pjsua_var.media_cfg.rx_drop_pct); 
    781  
     712    for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 
     713        pjsua_call *call = &pjsua_var.calls[i]; 
     714        unsigned strm_idx; 
     715 
     716        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 
     717            pjsua_call_media *call_med = &call->media[strm_idx]; 
     718 
     719            status = create_udp_media_transport(cfg, &call_med->tp); 
     720            if (status != PJ_SUCCESS) 
     721                goto on_error; 
     722        } 
    782723    } 
    783724 
     
    785726 
    786727on_error: 
    787     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    788         if (pjsua_var.calls[i].med_tp != NULL) { 
    789             pjmedia_transport_close(pjsua_var.calls[i].med_tp); 
    790             pjsua_var.calls[i].med_tp = NULL; 
    791         } 
    792     } 
    793  
     728    for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 
     729        pjsua_call *call = &pjsua_var.calls[i]; 
     730        unsigned strm_idx; 
     731 
     732        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 
     733            pjsua_call_media *call_med = &call->media[strm_idx]; 
     734 
     735            if (call_med->tp) { 
     736                pjmedia_transport_close(call_med->tp); 
     737                call_med->tp = NULL; 
     738            } 
     739        } 
     740    } 
    794741    return status; 
    795742} 
    796  
     743#endif 
    797744 
    798745/* This callback is called when ICE negotiation completes */ 
     
    801748                            pj_status_t result) 
    802749{ 
    803     unsigned id; 
    804     pj_bool_t found = PJ_FALSE; 
    805  
    806     /* Find call which has this media transport */ 
    807  
    808     PJSUA_LOCK(); 
    809  
    810     for (id=0; id<pjsua_var.ua_cfg.max_calls; ++id) { 
    811         if (pjsua_var.calls[id].med_tp == tp || 
    812             pjsua_var.calls[id].med_orig == tp)  
    813         { 
    814             found = PJ_TRUE; 
    815             break; 
    816         } 
    817     } 
    818  
    819     PJSUA_UNLOCK(); 
    820  
    821     if (!found) 
     750    pjsua_call_media *call_med = (pjsua_call_media*)tp->user_data; 
     751 
     752    if (!call_med) 
    822753        return; 
    823754 
    824755    switch (op) { 
    825756    case PJ_ICE_STRANS_OP_INIT: 
    826         pjsua_var.calls[id].med_tp_ready = result; 
     757        call_med->tp_ready = result; 
    827758        break; 
    828759    case PJ_ICE_STRANS_OP_NEGOTIATION: 
    829760        if (result != PJ_SUCCESS) { 
    830             pjsua_var.calls[id].media_st = PJSUA_CALL_MEDIA_ERROR; 
    831             pjsua_var.calls[id].media_dir = PJMEDIA_DIR_NONE; 
    832  
    833             if (pjsua_var.ua_cfg.cb.on_call_media_state) { 
    834                 pjsua_var.ua_cfg.cb.on_call_media_state(id); 
    835             } 
    836         } else { 
     761            call_med->state = PJSUA_CALL_MEDIA_ERROR; 
     762            call_med->dir = PJMEDIA_DIR_NONE; 
     763 
     764            if (call_med->call && pjsua_var.ua_cfg.cb.on_call_media_state) { 
     765                pjsua_var.ua_cfg.cb.on_call_media_state(call_med->call->index); 
     766            } 
     767        } else if (call_med->call) { 
    837768            /* Send UPDATE if default transport address is different than 
    838769             * what was advertised (ticket #881) 
     
    854785            if (ii && ii->role==PJ_ICE_SESS_ROLE_CONTROLLING && 
    855786                pj_sockaddr_cmp(&tpinfo.sock_info.rtp_addr_name, 
    856                                 &pjsua_var.calls[id].med_rtp_addr)) 
     787                                &call_med->rtp_addr)) 
    857788            { 
    858789                pj_bool_t use_update; 
     
    861792                pjsip_dialog *dlg; 
    862793 
    863                 dlg = pjsua_var.calls[id].inv->dlg; 
     794                dlg = call_med->call->inv->dlg; 
    864795                support_update = pjsip_dlg_remote_has_cap(dlg, PJSIP_H_ALLOW, 
    865796                                                          NULL, &STR_UPDATE); 
     
    868799                PJ_LOG(4,(THIS_FILE,  
    869800                          "ICE default transport address has changed for " 
    870                           "call %d, sending %s", id, 
     801                          "call %d, sending %s", call_med->call->index, 
    871802                          (use_update ? "UPDATE" : "re-INVITE"))); 
    872803 
    873804                if (use_update) 
    874                     pjsua_call_update(id, 0, NULL); 
     805                    pjsua_call_update(call_med->call->index, 0, NULL); 
    875806                else 
    876                     pjsua_call_reinvite(id, 0, NULL); 
     807                    pjsua_call_reinvite(call_med->call->index, 0, NULL); 
    877808            } 
    878809        } 
     
    881812        if (result != PJ_SUCCESS) { 
    882813            PJ_PERROR(4,(THIS_FILE, result, 
    883                          "ICE keep alive failure for transport %d", id)); 
     814                         "ICE keep alive failure for transport %d:%d", 
     815                         call_med->call->index, call_med->idx)); 
    884816        } 
    885817        if (pjsua_var.ua_cfg.cb.on_ice_transport_error) { 
     818            pjsua_call_id id = call_med->call->index; 
    886819            (*pjsua_var.ua_cfg.cb.on_ice_transport_error)(id, op, result, 
    887820                                                          NULL); 
     
    919852 
    920853/* Create ICE media transports (when ice is enabled) */ 
    921 static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg) 
     854static pj_status_t create_ice_media_transport( 
     855                                const pjsua_transport_config *cfg, 
     856                                pjsua_call_media *call_med) 
    922857{ 
    923858    char stunip[PJ_INET6_ADDRSTRLEN]; 
    924859    pj_ice_strans_cfg ice_cfg; 
    925     unsigned i; 
     860    pjmedia_ice_cb ice_cb; 
     861    char name[32]; 
     862    unsigned comp_cnt; 
    926863    pj_status_t status; 
    927864 
     
    980917    } 
    981918 
    982     /* Create each media transport */ 
    983     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    984         pjmedia_ice_cb ice_cb; 
    985         char name[32]; 
    986         unsigned comp_cnt; 
    987  
    988         pj_bzero(&ice_cb, sizeof(pjmedia_ice_cb)); 
    989         ice_cb.on_ice_complete = &on_ice_complete; 
    990         pj_ansi_snprintf(name, sizeof(name), "icetp%02d", i); 
    991         pjsua_var.calls[i].med_tp_ready = PJ_EPENDING; 
    992  
    993         comp_cnt = 1; 
    994         if (PJMEDIA_ADVERTISE_RTCP && !pjsua_var.media_cfg.ice_no_rtcp) 
    995             ++comp_cnt; 
    996  
    997         status = pjmedia_ice_create(pjsua_var.med_endpt, name, comp_cnt, 
    998                                     &ice_cfg, &ice_cb, 
    999                                     &pjsua_var.calls[i].med_tp); 
    1000         if (status != PJ_SUCCESS) { 
    1001             pjsua_perror(THIS_FILE, "Unable to create ICE media transport", 
    1002                          status); 
    1003             goto on_error; 
    1004         } 
    1005  
    1006         /* Wait until transport is initialized, or time out */ 
    1007         PJSUA_UNLOCK(); 
    1008         while (pjsua_var.calls[i].med_tp_ready == PJ_EPENDING) { 
    1009             pjsua_handle_events(100); 
    1010         } 
    1011         PJSUA_LOCK(); 
    1012         if (pjsua_var.calls[i].med_tp_ready != PJ_SUCCESS) { 
    1013             pjsua_perror(THIS_FILE, "Error initializing ICE media transport", 
    1014                          pjsua_var.calls[i].med_tp_ready); 
    1015             status = pjsua_var.calls[i].med_tp_ready; 
    1016             goto on_error; 
    1017         } 
    1018  
    1019         pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 
    1020                                         PJMEDIA_DIR_ENCODING, 
    1021                                         pjsua_var.media_cfg.tx_drop_pct); 
    1022  
    1023         pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 
    1024                                         PJMEDIA_DIR_DECODING, 
    1025                                         pjsua_var.media_cfg.rx_drop_pct); 
    1026     } 
     919    pj_bzero(&ice_cb, sizeof(pjmedia_ice_cb)); 
     920    ice_cb.on_ice_complete = &on_ice_complete; 
     921    pj_ansi_snprintf(name, sizeof(name), "icetp%02d", call_med->idx); 
     922    call_med->tp_ready = PJ_EPENDING; 
     923 
     924    comp_cnt = 1; 
     925    if (PJMEDIA_ADVERTISE_RTCP && !pjsua_var.media_cfg.ice_no_rtcp) 
     926        ++comp_cnt; 
     927 
     928    status = pjmedia_ice_create3(pjsua_var.med_endpt, name, comp_cnt, 
     929                                 &ice_cfg, &ice_cb, 0, call_med, 
     930                                 &call_med->tp); 
     931    if (status != PJ_SUCCESS) { 
     932        pjsua_perror(THIS_FILE, "Unable to create ICE media transport", 
     933                     status); 
     934        goto on_error; 
     935    } 
     936 
     937    /* Wait until transport is initialized, or time out */ 
     938    PJSUA_UNLOCK(); 
     939    while (call_med->tp_ready == PJ_EPENDING) { 
     940        pjsua_handle_events(100); 
     941    } 
     942    PJSUA_LOCK(); 
     943    if (call_med->tp_ready != PJ_SUCCESS) { 
     944        pjsua_perror(THIS_FILE, "Error initializing ICE media transport", 
     945                     call_med->tp_ready); 
     946        status = call_med->tp_ready; 
     947        goto on_error; 
     948    } 
     949 
     950    pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING, 
     951                                    pjsua_var.media_cfg.tx_drop_pct); 
     952 
     953    pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING, 
     954                                    pjsua_var.media_cfg.rx_drop_pct); 
    1027955 
    1028956    return PJ_SUCCESS; 
    1029957 
    1030958on_error: 
    1031     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    1032         if (pjsua_var.calls[i].med_tp != NULL) { 
    1033             pjmedia_transport_close(pjsua_var.calls[i].med_tp); 
    1034             pjsua_var.calls[i].med_tp = NULL; 
    1035         } 
     959    if (call_med->tp != NULL) { 
     960        pjmedia_transport_close(call_med->tp); 
     961        call_med->tp = NULL; 
    1036962    } 
    1037963 
     
    1039965} 
    1040966 
    1041  
    1042 /* 
    1043  * Create UDP media transports for all the calls. This function creates 
     967#if DISABLED_FOR_TICKET_1185 
     968/* Create ICE media transports (when ice is enabled) */ 
     969static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg) 
     970{ 
     971    unsigned i; 
     972    pj_status_t status; 
     973 
     974    for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 
     975        pjsua_call *call = &pjsua_var.calls[i]; 
     976        unsigned strm_idx; 
     977 
     978        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 
     979            pjsua_call_media *call_med = &call->media[strm_idx]; 
     980 
     981            status = create_ice_media_transport(cfg, call_med); 
     982            if (status != PJ_SUCCESS) 
     983                goto on_error; 
     984        } 
     985    } 
     986 
     987    return PJ_SUCCESS; 
     988 
     989on_error: 
     990    for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 
     991        pjsua_call *call = &pjsua_var.calls[i]; 
     992        unsigned strm_idx; 
     993 
     994        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 
     995            pjsua_call_media *call_med = &call->media[strm_idx]; 
     996 
     997            if (call_med->tp) { 
     998                pjmedia_transport_close(call_med->tp); 
     999                call_med->tp = NULL; 
     1000            } 
     1001        } 
     1002    } 
     1003    return status; 
     1004} 
     1005#endif 
     1006 
     1007#if DISABLED_FOR_TICKET_1185 
     1008/* 
     1009 * Create media transports for all the calls. This function creates 
    10441010 * one UDP media transport for each call. 
    10451011 */ 
     
    10591025    /* Delete existing media transports */ 
    10601026    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    1061         if (pjsua_var.calls[i].med_tp != NULL &&  
    1062             pjsua_var.calls[i].med_tp_auto_del)  
    1063         { 
    1064             pjmedia_transport_close(pjsua_var.calls[i].med_tp); 
    1065             pjsua_var.calls[i].med_tp = NULL; 
    1066             pjsua_var.calls[i].med_orig = NULL; 
     1027        pjsua_call *call = &pjsua_var.calls[i]; 
     1028        unsigned strm_idx; 
     1029 
     1030        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 
     1031            pjsua_call_media *call_med = &call->media[strm_idx]; 
     1032 
     1033            if (call_med->tp && call_med->tp_auto_del) { 
     1034                pjmedia_transport_close(call_med->tp); 
     1035                call_med->tp = NULL; 
     1036                call_med->tp_orig = NULL; 
     1037            } 
    10671038        } 
    10681039    } 
     
    10801051    /* Set media transport auto_delete to True */ 
    10811052    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    1082         pjsua_var.calls[i].med_tp_auto_del = PJ_TRUE; 
     1053        pjsua_call *call = &pjsua_var.calls[i]; 
     1054        unsigned strm_idx; 
     1055 
     1056        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 
     1057            pjsua_call_media *call_med = &call->media[strm_idx]; 
     1058 
     1059            call_med->tp_auto_del = PJ_TRUE; 
     1060        } 
    10831061    } 
    10841062 
     
    11011079    /* Assign the media transports */ 
    11021080    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
    1103         if (pjsua_var.calls[i].med_tp != NULL &&  
    1104             pjsua_var.calls[i].med_tp_auto_del)  
     1081        pjsua_call *call = &pjsua_var.calls[i]; 
     1082        unsigned strm_idx; 
     1083 
     1084        for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 
     1085            pjsua_call_media *call_med = &call->media[strm_idx]; 
     1086 
     1087            if (call_med->tp && call_med->tp_auto_del) { 
     1088                pjmedia_transport_close(call_med->tp); 
     1089                call_med->tp = NULL; 
     1090                call_med->tp_orig = NULL; 
     1091            } 
     1092        } 
     1093 
     1094        PJ_TODO(remove_pjsua_media_transports_attach); 
     1095 
     1096        call->media[0].tp = tp[i].transport; 
     1097        call->media[0].tp_auto_del = auto_delete; 
     1098    } 
     1099 
     1100    return PJ_SUCCESS; 
     1101} 
     1102#endif 
     1103 
     1104/* Go through the list of media in the SDP, find acceptable media, and 
     1105 * sort them based on the "quality" of the media, and store the indexes 
     1106 * in the specified array. Media with the best quality will be listed 
     1107 * first in the array. The quality factors considered currently is 
     1108 * encryption. 
     1109 */ 
     1110static void sort_media(const pjmedia_sdp_session *sdp, 
     1111                       const pj_str_t *type, 
     1112                       pjmedia_srtp_use use_srtp, 
     1113                       pj_uint8_t midx[], 
     1114                       unsigned *p_count) 
     1115{ 
     1116    unsigned i; 
     1117    unsigned count = 0; 
     1118    int score[PJSUA_MAX_CALL_MEDIA]; 
     1119 
     1120    pj_assert(*p_count >= PJSUA_MAX_CALL_MEDIA); 
     1121 
     1122    *p_count = 0; 
     1123    for (i=0; i<PJSUA_MAX_CALL_MEDIA; ++i) 
     1124        score[i] = 1; 
     1125 
     1126    /* Score each media */ 
     1127    for (i=0; i<sdp->media_count && count<PJSUA_MAX_CALL_MEDIA; ++i) { 
     1128        const pjmedia_sdp_media *m = sdp->media[i]; 
     1129        const pjmedia_sdp_conn *c; 
     1130 
     1131        /* Skip different media */ 
     1132        if (pj_stricmp(&m->desc.media, type) != 0) { 
     1133            score[count++] = -22000; 
     1134            continue; 
     1135        } 
     1136 
     1137        c = m->conn? m->conn : sdp->conn; 
     1138 
     1139        /* Supported transports */ 
     1140        if (pj_stricmp2(&m->desc.transport, "RTP/SAVP")==0) { 
     1141            switch (use_srtp) { 
     1142            case PJMEDIA_SRTP_MANDATORY: 
     1143            case PJMEDIA_SRTP_OPTIONAL: 
     1144                ++score[i]; 
     1145                break; 
     1146            case PJMEDIA_SRTP_DISABLED: 
     1147                --score[i]; 
     1148                break; 
     1149            } 
     1150        } else if (pj_stricmp2(&m->desc.transport, "RTP/AVP")==0) { 
     1151            switch (use_srtp) { 
     1152            case PJMEDIA_SRTP_MANDATORY: 
     1153                --score[i]; 
     1154                break; 
     1155            case PJMEDIA_SRTP_OPTIONAL: 
     1156                /* No change in score */ 
     1157                break; 
     1158            case PJMEDIA_SRTP_DISABLED: 
     1159                ++score[i]; 
     1160                break; 
     1161            } 
     1162        } else { 
     1163            score[i] -= 10; 
     1164        } 
     1165 
     1166        /* Is media disabled? */ 
     1167        if (m->desc.port == 0) 
     1168            score[i] -= 10; 
     1169 
     1170        /* Is media inactive? */ 
     1171        if (pjmedia_sdp_media_find_attr2(m, "inactive", NULL) || 
     1172            pj_strcmp2(&c->addr, "0.0.0.0") == 0) 
    11051173        { 
    1106             pjmedia_transport_close(pjsua_var.calls[i].med_tp); 
    1107         } 
    1108  
    1109         pjsua_var.calls[i].med_tp = tp[i].transport; 
    1110         pjsua_var.calls[i].med_tp_auto_del = auto_delete; 
     1174            //score[i] -= 10; 
     1175            score[i] -= 1; 
     1176        } 
     1177 
     1178        ++count; 
     1179    } 
     1180 
     1181    /* Created sorted list based on quality */ 
     1182    for (i=0; i<count; ++i) { 
     1183        unsigned j; 
     1184        int best = 0; 
     1185 
     1186        for (j=1; j<count; ++j) { 
     1187            if (score[j] > score[best]) 
     1188                best = j; 
     1189        } 
     1190        /* Don't put media with negative score, that media is unacceptable 
     1191         * for us. 
     1192         */ 
     1193        if (score[best] >= 0) { 
     1194            midx[*p_count] = (pj_uint8_t)best; 
     1195            (*p_count)++; 
     1196        } 
     1197 
     1198        score[best] = -22000; 
     1199 
     1200    } 
     1201} 
     1202 
     1203/* Callback to receive media events */ 
     1204static pj_status_t call_media_on_event(pjmedia_event_subscription *esub, 
     1205                                       pjmedia_event *event) 
     1206{ 
     1207    pjsua_call_media *call_med = (pjsua_call_media*)esub->user_data; 
     1208    pjsua_call *call = call_med->call; 
     1209 
     1210    if (pjsua_var.ua_cfg.cb.on_call_media_event && call) { 
     1211        ++event->proc_cnt; 
     1212        (*pjsua_var.ua_cfg.cb.on_call_media_event)(call->index, 
     1213                                                   call_med->idx, event); 
    11111214    } 
    11121215 
     
    11141217} 
    11151218 
    1116  
    1117 static int find_audio_index(const pjmedia_sdp_session *sdp,  
    1118                             pj_bool_t prefer_srtp) 
    1119 { 
    1120     unsigned i; 
    1121     int audio_idx = -1; 
    1122  
    1123     for (i=0; i<sdp->media_count; ++i) { 
    1124         const pjmedia_sdp_media *m = sdp->media[i]; 
    1125  
    1126         /* Skip if media is not audio */ 
    1127         if (pj_stricmp2(&m->desc.media, "audio") != 0) 
    1128             continue; 
    1129  
    1130         /* Skip if media is disabled */ 
    1131         if (m->desc.port == 0) 
    1132             continue; 
    1133  
    1134         /* Skip if transport is not supported */ 
    1135         if (pj_stricmp2(&m->desc.transport, "RTP/AVP") != 0 && 
    1136             pj_stricmp2(&m->desc.transport, "RTP/SAVP") != 0) 
    1137         { 
    1138             continue; 
    1139         } 
    1140  
    1141         if (audio_idx == -1) { 
    1142             audio_idx = i; 
     1219/* Initialize the media line */ 
     1220pj_status_t pjsua_call_media_init(pjsua_call_media *call_med, 
     1221                                  pjmedia_type type, 
     1222                                  const pjsua_transport_config *tcfg, 
     1223                                  int security_level, 
     1224                                  int *sip_err_code) 
     1225{ 
     1226    pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id]; 
     1227    pj_status_t status; 
     1228 
     1229    /* 
     1230     * Note: this function may be called when the media already exists 
     1231     * (e.g. in reinvites, updates, etc.) 
     1232     */ 
     1233    call_med->type = type; 
     1234 
     1235    /* Create the media transport for initial call. This is blocking for now */ 
     1236    if (call_med->tp == NULL) { 
     1237        if (pjsua_var.media_cfg.enable_ice) { 
     1238            status = create_ice_media_transport(tcfg, call_med); 
    11431239        } else { 
    1144             /* We've found multiple candidates. This could happen 
    1145              * e.g. when remote is offering both RTP/SAVP and RTP/AVP, 
    1146              * or when remote for some reason offers two audio. 
    1147              */ 
    1148  
    1149             if (prefer_srtp && 
    1150                 pj_stricmp2(&m->desc.transport, "RTP/SAVP")==0) 
    1151             { 
    1152                 /* Prefer RTP/SAVP when our media transport is SRTP */ 
    1153                 audio_idx = i; 
    1154                 break; 
    1155             } else if (!prefer_srtp && 
    1156                        pj_stricmp2(&m->desc.transport, "RTP/AVP")==0) 
    1157             { 
    1158                 /* Prefer RTP/AVP when our media transport is NOT SRTP */ 
    1159                 audio_idx = i; 
    1160             } 
    1161         } 
    1162     } 
    1163  
    1164     return audio_idx; 
    1165 } 
    1166  
     1240            status = create_udp_media_transport(tcfg, call_med); 
     1241        } 
     1242 
     1243        if (status != PJ_SUCCESS) { 
     1244            PJ_PERROR(1,(THIS_FILE, status, "Error creating media transport")); 
     1245            return status; 
     1246        } 
     1247         
     1248        call_med->tp_st = PJSUA_MED_TP_IDLE; 
     1249 
     1250        /* While in initial call, set default video devices */ 
     1251        if (type == PJMEDIA_TYPE_VIDEO) { 
     1252            call_med->strm.v.rdr_dev = acc->cfg.vid_rend_dev; 
     1253            call_med->strm.v.cap_dev = acc->cfg.vid_cap_dev; 
     1254            if (call_med->strm.v.rdr_dev == PJMEDIA_VID_DEFAULT_RENDER_DEV) { 
     1255                pjmedia_vid_dev_info info; 
     1256                pjmedia_vid_dev_get_info(call_med->strm.v.rdr_dev, &info); 
     1257                call_med->strm.v.rdr_dev = info.id; 
     1258            } 
     1259            if (call_med->strm.v.cap_dev == PJMEDIA_VID_DEFAULT_CAPTURE_DEV) { 
     1260                pjmedia_vid_dev_info info; 
     1261                pjmedia_vid_dev_get_info(call_med->strm.v.cap_dev, &info); 
     1262                call_med->strm.v.cap_dev = info.id; 
     1263            } 
     1264        } 
     1265    } else if (call_med->tp_st == PJSUA_MED_TP_DISABLED) { 
     1266        /* Media is being reenabled. */ 
     1267        call_med->tp_st = PJSUA_MED_TP_INIT; 
     1268    } 
     1269 
     1270#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
     1271    /* This function may be called when SRTP transport already exists 
     1272     * (e.g: in re-invite, update), don't need to destroy/re-create. 
     1273     */ 
     1274    if (!call_med->tp_orig || call_med->tp == call_med->tp_orig) { 
     1275        pjmedia_srtp_setting srtp_opt; 
     1276        pjmedia_transport *srtp = NULL; 
     1277 
     1278        /* Check if SRTP requires secure signaling */ 
     1279        if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) { 
     1280            if (security_level < acc->cfg.srtp_secure_signaling) { 
     1281                if (sip_err_code) 
     1282                    *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 
     1283                status = PJSIP_ESESSIONINSECURE; 
     1284                goto on_error; 
     1285            } 
     1286        } 
     1287 
     1288        /* Always create SRTP adapter */ 
     1289        pjmedia_srtp_setting_default(&srtp_opt); 
     1290        srtp_opt.close_member_tp = PJ_TRUE; 
     1291        /* If media session has been ever established, let's use remote's 
     1292         * preference in SRTP usage policy, especially when it is stricter. 
     1293         */ 
     1294        if (call_med->rem_srtp_use > acc->cfg.use_srtp) 
     1295            srtp_opt.use = call_med->rem_srtp_use; 
     1296        else 
     1297            srtp_opt.use = acc->cfg.use_srtp; 
     1298 
     1299        status = pjmedia_transport_srtp_create(pjsua_var.med_endpt, 
     1300                                               call_med->tp, 
     1301                                               &srtp_opt, &srtp); 
     1302        if (status != PJ_SUCCESS) { 
     1303            if (sip_err_code) 
     1304                *sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 
     1305            goto on_error; 
     1306        } 
     1307 
     1308        /* Set SRTP as current media transport */ 
     1309        call_med->tp_orig = call_med->tp; 
     1310        call_med->tp = srtp; 
     1311    } 
     1312#else 
     1313    call->tp_orig = call->tp; 
     1314    PJ_UNUSED_ARG(security_level); 
     1315#endif 
     1316 
     1317    pjmedia_event_subscription_init(&call_med->esub_rend, &call_media_on_event, 
     1318                                    call_med); 
     1319    pjmedia_event_subscription_init(&call_med->esub_cap, &call_media_on_event, 
     1320                                        call_med); 
     1321 
     1322    return PJ_SUCCESS; 
     1323 
     1324on_error: 
     1325    if (call_med->tp) { 
     1326        pjmedia_transport_close(call_med->tp); 
     1327        call_med->tp = NULL; 
     1328    } 
     1329    return status; 
     1330} 
    11671331 
    11681332pj_status_t pjsua_media_channel_init(pjsua_call_id call_id, 
     
    11731337                                     int *sip_err_code) 
    11741338{ 
     1339    const pj_str_t STR_AUDIO = { "audio", 5 }; 
     1340    const pj_str_t STR_VIDEO = { "video", 5 }; 
    11751341    pjsua_call *call = &pjsua_var.calls[call_id]; 
     1342    pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; 
     1343    pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA]; 
     1344    unsigned maudcnt = PJ_ARRAY_SIZE(maudidx); 
     1345    pj_uint8_t mvididx[PJSUA_MAX_CALL_MEDIA]; 
     1346    unsigned mvidcnt = PJ_ARRAY_SIZE(mvididx); 
     1347    pjmedia_type media_types[PJSUA_MAX_CALL_MEDIA]; 
     1348    unsigned mi; 
    11761349    pj_status_t status; 
    11771350 
    1178 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
    1179     pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; 
    1180     pjmedia_srtp_setting srtp_opt; 
    1181     pjmedia_transport *srtp = NULL; 
    1182 #endif 
    1183  
    11841351    PJ_UNUSED_ARG(role); 
    11851352 
     1353    /* 
     1354     * Note: this function may be called when the media already exists 
     1355     * (e.g. in reinvites, updates, etc). 
     1356     */ 
     1357 
     1358    if (pjsua_get_state() != PJSUA_STATE_RUNNING) 
     1359        return PJ_EBUSY; 
     1360 
     1361#if DISABLED_FOR_TICKET_1185 
    11861362    /* Return error if media transport has not been created yet 
    11871363     * (e.g. application is starting) 
    11881364     */ 
    1189     if (call->med_tp == NULL) { 
    1190         if (sip_err_code) 
    1191             *sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 
    1192         return PJ_EBUSY; 
    1193     } 
    1194  
    1195 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
    1196     /* This function may be called when SRTP transport already exists  
    1197      * (e.g: in re-invite, update), don't need to destroy/re-create. 
    1198      */ 
    1199     if (!call->med_orig || call->med_tp == call->med_orig) { 
    1200  
    1201         /* Check if SRTP requires secure signaling */ 
    1202         if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) { 
    1203             if (security_level < acc->cfg.srtp_secure_signaling) { 
    1204                 if (sip_err_code) 
    1205                     *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 
    1206                 return PJSIP_ESESSIONINSECURE; 
    1207             } 
    1208         } 
    1209  
    1210         /* Always create SRTP adapter */ 
    1211         pjmedia_srtp_setting_default(&srtp_opt); 
    1212         srtp_opt.close_member_tp = PJ_FALSE; 
    1213         /* If media session has been ever established, let's use remote's  
    1214          * preference in SRTP usage policy, especially when it is stricter. 
     1365    for (i=0; i<call->med_cnt; ++i) { 
     1366        if (call->media[i].tp == NULL) { 
     1367            return PJ_EBUSY; 
     1368        } 
     1369    } 
     1370#endif 
     1371 
     1372    if (rem_sdp) { 
     1373        sort_media(rem_sdp, &STR_AUDIO, acc->cfg.use_srtp, 
     1374                   maudidx, &maudcnt); 
     1375        if (maudcnt > acc->cfg.max_audio_cnt) 
     1376            maudcnt = acc->cfg.max_audio_cnt; 
     1377 
     1378        if (maudcnt==0) { 
     1379            /* Expecting audio in the offer */ 
     1380            if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; 
     1381            pjsua_media_channel_deinit(call_id); 
     1382            return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE); 
     1383        } 
     1384 
     1385        sort_media(rem_sdp, &STR_VIDEO, acc->cfg.use_srtp, 
     1386                   mvididx, &mvidcnt); 
     1387        if (mvidcnt > acc->cfg.max_video_cnt) 
     1388            mvidcnt = acc->cfg.max_video_cnt; 
     1389 
     1390        /* Update media count only when remote add any media, this media count 
     1391         * must never decrease. 
    12151392         */ 
    1216         if (call->rem_srtp_use > acc->cfg.use_srtp) 
    1217             srtp_opt.use = call->rem_srtp_use; 
    1218         else 
    1219             srtp_opt.use = acc->cfg.use_srtp; 
    1220  
    1221         status = pjmedia_transport_srtp_create(pjsua_var.med_endpt,  
    1222                                                call->med_tp, 
    1223                                                &srtp_opt, &srtp); 
    1224         if (status != PJ_SUCCESS) { 
    1225             if (sip_err_code) 
    1226                 *sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 
    1227             return status; 
    1228         } 
    1229  
    1230         /* Set SRTP as current media transport */ 
    1231         call->med_orig = call->med_tp; 
    1232         call->med_tp = srtp; 
    1233     } 
    1234 #else 
    1235     call->med_orig = call->med_tp; 
    1236     PJ_UNUSED_ARG(security_level); 
    1237 #endif 
    1238  
    1239     /* Find out which media line in SDP that we support. If we are offerer, 
    1240      * audio will be initialized at index 0 in SDP.  
    1241      */ 
    1242     if (rem_sdp == NULL) { 
    1243         call->audio_idx = 0; 
    1244     }  
    1245     /* Otherwise find out the candidate audio media line in SDP */ 
    1246     else { 
    1247         pj_bool_t srtp_active; 
    1248  
    1249 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
    1250         srtp_active = acc->cfg.use_srtp; 
    1251 #else 
    1252         srtp_active = PJ_FALSE; 
    1253 #endif 
    1254  
    1255         /* Media count must have been checked */ 
    1256         pj_assert(rem_sdp->media_count != 0); 
    1257  
    1258         call->audio_idx = find_audio_index(rem_sdp, srtp_active); 
    1259     } 
    1260  
    1261     /* Reject offer if we couldn't find a good m=audio line in offer */ 
    1262     if (call->audio_idx < 0) { 
     1393        if (call->med_cnt < rem_sdp->media_count) 
     1394            call->med_cnt = PJ_MIN(rem_sdp->media_count, PJSUA_MAX_CALL_MEDIA); 
     1395 
     1396    } else { 
     1397        maudcnt = acc->cfg.max_audio_cnt; 
     1398        for (mi=0; mi<maudcnt; ++mi) { 
     1399            maudidx[mi] = (pj_uint8_t)mi; 
     1400            media_types[mi] = PJMEDIA_TYPE_AUDIO; 
     1401        } 
     1402        mvidcnt = acc->cfg.max_video_cnt; 
     1403        for (mi=0; mi<mvidcnt; ++mi) { 
     1404            media_types[maudcnt + mi] = PJMEDIA_TYPE_VIDEO; 
     1405        } 
     1406         
     1407        call->med_cnt = maudcnt + mvidcnt; 
     1408    } 
     1409 
     1410    if (call->med_cnt == 0) { 
     1411        /* Expecting at least one media */ 
    12631412        if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; 
    12641413        pjsua_media_channel_deinit(call_id); 
     
    12661415    } 
    12671416 
    1268     PJ_LOG(4,(THIS_FILE, "Media index %d selected for call %d", 
     1417    /* Initialize each media line */ 
     1418    for (mi=0; mi < call->med_cnt; ++mi) { 
     1419        pjsua_call_media *call_med = &call->media[mi]; 
     1420        pj_bool_t enabled = PJ_FALSE; 
     1421        pjmedia_type media_type = PJMEDIA_TYPE_NONE; 
     1422 
     1423        if (rem_sdp) { 
     1424            if (mi >= rem_sdp->media_count) { 
     1425                /* Media has been removed in remote re-offer */ 
     1426                media_type = call_med->type; 
     1427            } else if (!pj_stricmp(&rem_sdp->media[mi]->desc.media, &STR_AUDIO)) { 
     1428                media_type = PJMEDIA_TYPE_AUDIO; 
     1429                if (pj_memchr(maudidx, mi, maudcnt * sizeof(maudidx[0]))) { 
     1430                    enabled = PJ_TRUE; 
     1431                } 
     1432            } 
     1433            else if (!pj_stricmp(&rem_sdp->media[mi]->desc.media, &STR_VIDEO)) { 
     1434                media_type = PJMEDIA_TYPE_VIDEO; 
     1435                if (pj_memchr(mvididx, mi, mvidcnt * sizeof(mvididx[0]))) { 
     1436                    enabled = PJ_TRUE; 
     1437                } 
     1438            } 
     1439 
     1440        } else { 
     1441            enabled = PJ_TRUE; 
     1442            media_type = media_types[mi]; 
     1443        } 
     1444 
     1445        if (enabled) { 
     1446            status = pjsua_call_media_init(call_med, media_type, 
     1447                                           &acc->cfg.rtp_cfg, 
     1448                                           security_level, sip_err_code); 
     1449            if (status != PJ_SUCCESS) { 
     1450                pjsua_media_channel_deinit(call_id); 
     1451                return status; 
     1452            } 
     1453        } else { 
     1454            /* By convention, the media is disabled if transport is NULL  
     1455             * or transport state is PJSUA_MED_TP_DISABLED. 
     1456             */ 
     1457            if (call_med->tp) { 
     1458                // Don't close transport here, as SDP negotiation has not been 
     1459                // done and stream may be still active. 
     1460                //pjmedia_transport_close(call_med->tp); 
     1461                //call_med->tp = NULL; 
     1462                pj_assert(call_med->tp_st == PJSUA_MED_TP_INIT ||  
     1463                          call_med->tp_st == PJSUA_MED_TP_RUNNING); 
     1464                call_med->tp_st = PJSUA_MED_TP_DISABLED; 
     1465            } 
     1466 
     1467            /* Put media type just for info */ 
     1468            call_med->type = media_type; 
     1469        } 
     1470    } 
     1471 
     1472    call->audio_idx = maudidx[0]; 
     1473 
     1474    PJ_LOG(4,(THIS_FILE, "Media index %d selected for audio call %d", 
    12691475              call->audio_idx, call->index)); 
    12701476 
    1271     /* Create the media transport */ 
    1272     status = pjmedia_transport_media_create(call->med_tp, tmp_pool, 0, 
    1273                                             rem_sdp, call->audio_idx); 
    1274     if (status != PJ_SUCCESS) { 
    1275         if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 
    1276         pjsua_media_channel_deinit(call_id); 
    1277         return status; 
    1278     } 
    1279  
    1280     call->med_tp_st = PJSUA_MED_TP_INIT; 
     1477    /* Tell the media transport of a new offer/answer session */ 
     1478    for (mi=0; mi < call->med_cnt; ++mi) { 
     1479        pjsua_call_media *call_med = &call->media[mi]; 
     1480 
     1481        /* Note: tp may be NULL if this media line is disabled */ 
     1482        if (call_med->tp && call_med->tp_st == PJSUA_MED_TP_IDLE) { 
     1483            status = pjmedia_transport_media_create(call_med->tp, 
     1484                                                    tmp_pool, 0, 
     1485                                                    rem_sdp, mi); 
     1486            if (status != PJ_SUCCESS) { 
     1487                if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 
     1488                pjsua_media_channel_deinit(call_id); 
     1489                return status; 
     1490            } 
     1491 
     1492            call_med->tp_st = PJSUA_MED_TP_INIT; 
     1493        } 
     1494    } 
     1495 
    12811496    return PJ_SUCCESS; 
    12821497} 
     
    12861501                                           const pjmedia_sdp_session *rem_sdp, 
    12871502                                           pjmedia_sdp_session **p_sdp, 
    1288                                            int *sip_status_code) 
    1289 { 
    1290     enum { MAX_MEDIA = 1 }; 
     1503                                           int *sip_err_code) 
     1504{ 
     1505    enum { MAX_MEDIA = PJSUA_MAX_CALL_MEDIA }; 
    12911506    pjmedia_sdp_session *sdp; 
    1292     pjmedia_transport_info tpinfo; 
     1507    pj_sockaddr origin; 
    12931508    pjsua_call *call = &pjsua_var.calls[call_id]; 
    12941509    pjmedia_sdp_neg_state sdp_neg_state = PJMEDIA_SDP_NEG_STATE_NULL; 
     1510    unsigned mi; 
    12951511    pj_status_t status; 
    12961512 
    1297     /* Return error if media transport has not been created yet 
    1298      * (e.g. application is starting) 
     1513    if (pjsua_get_state() != PJSUA_STATE_RUNNING) 
     1514        return PJ_EBUSY; 
     1515 
     1516    if (rem_sdp) { 
     1517        /* If this is a re-offer, let's re-initialize media as remote may 
     1518         * add or remove media 
     1519         */ 
     1520        if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED) { 
     1521            status = pjsua_media_channel_init(call_id, PJSIP_ROLE_UAS, 
     1522                                              call->secure_level, pool, 
     1523                                              rem_sdp, sip_err_code); 
     1524            if (status != PJ_SUCCESS) 
     1525                return status; 
     1526        } 
     1527 
     1528#if 0 
     1529        pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; 
     1530        pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA]; 
     1531        unsigned maudcnt = PJ_ARRAY_SIZE(maudidx); 
     1532 
     1533        sort_media(rem_sdp, &STR_AUDIO, acc->cfg.use_srtp, 
     1534                   maudidx, &maudcnt); 
     1535 
     1536        if (maudcnt==0) { 
     1537            /* Expecting audio in the offer */ 
     1538            if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; 
     1539            pjsua_media_channel_deinit(call_id); 
     1540            return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE); 
     1541        } 
     1542 
     1543        call->audio_idx = maudidx[0]; 
     1544#endif 
     1545    } else { 
     1546        /* Audio is first in our offer, by convention */ 
     1547        // The audio_idx should not be changed here, as this function may be 
     1548        // called in generating re-offer and the current active audio index 
     1549        // can be anywhere. 
     1550        //call->audio_idx = 0; 
     1551    } 
     1552 
     1553#if 0 
     1554    // Since r3512, old-style hold should have got transport, created by  
     1555    // pjsua_media_channel_init() in initial offer/answer or remote reoffer. 
     1556    /* Create media if it's not created. This could happen when call is 
     1557     * currently on-hold (with the old style hold) 
    12991558     */ 
    1300     if (call->med_tp == NULL) { 
    1301         return PJ_EBUSY; 
    1302     } 
    1303  
    1304     if (rem_sdp && rem_sdp->media_count != 0) { 
    1305         pj_bool_t srtp_active; 
    1306  
    1307 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
    1308         srtp_active = pjsua_var.acc[call->acc_id].cfg.use_srtp; 
    1309 #else 
    1310         srtp_active = PJ_FALSE; 
    1311 #endif 
    1312  
    1313         call->audio_idx = find_audio_index(rem_sdp, srtp_active); 
    1314         if (call->audio_idx == -1) { 
    1315             /* No audio in the offer. We can't accept this */ 
    1316             PJ_LOG(4,(THIS_FILE, 
    1317                       "Unable to accept SDP offer without audio for call %d", 
    1318                       call_id)); 
    1319             return PJMEDIA_SDP_EINMEDIA; 
    1320         } 
    1321     } 
    1322  
    1323     /* Media index must have been determined before */ 
    1324     pj_assert(call->audio_idx != -1); 
    1325  
    1326     /* Create media if it's not created. This could happen when call is 
    1327      * currently on-hold 
    1328      */ 
    1329     if (call->med_tp_st == PJSUA_MED_TP_IDLE) { 
     1559    if (call->media[call->audio_idx].tp == NULL) { 
    13301560        pjsip_role_e role; 
    13311561        role = (rem_sdp ? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC); 
    13321562        status = pjsua_media_channel_init(call_id, role, call->secure_level,  
    1333                                           pool, rem_sdp, sip_status_code); 
     1563                                          pool, rem_sdp, sip_err_code); 
    13341564        if (status != PJ_SUCCESS) 
    13351565            return status; 
    13361566    } 
     1567#endif 
    13371568 
    13381569    /* Get SDP negotiator state */ 
     
    13401571        sdp_neg_state = pjmedia_sdp_neg_get_state(call->inv->neg); 
    13411572 
    1342     /* Get media socket info */ 
    1343     pjmedia_transport_info_init(&tpinfo); 
    1344     pjmedia_transport_get_info(call->med_tp, &tpinfo); 
    1345  
    1346     /* Create SDP */ 
    1347     status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pool, MAX_MEDIA, 
    1348                                       &tpinfo.sock_info, &sdp); 
    1349     if (status != PJ_SUCCESS) { 
    1350         if (sip_status_code) *sip_status_code = 500; 
     1573    /* Get one address to use in the origin field */ 
     1574    pj_bzero(&origin, sizeof(origin)); 
     1575    for (mi=0; mi<call->med_cnt; ++mi) { 
     1576        pjmedia_transport_info tpinfo; 
     1577 
     1578        if (call->media[mi].tp == NULL) 
     1579            continue; 
     1580 
     1581        pjmedia_transport_info_init(&tpinfo); 
     1582        pjmedia_transport_get_info(call->media[mi].tp, &tpinfo); 
     1583        pj_sockaddr_cp(&origin, &tpinfo.sock_info.rtp_addr_name); 
     1584        break; 
     1585    } 
     1586 
     1587    /* Create the base (blank) SDP */ 
     1588    status = pjmedia_endpt_create_base_sdp(pjsua_var.med_endpt, pool, NULL, 
     1589                                           &origin, &sdp); 
     1590    if (status != PJ_SUCCESS) 
    13511591        return status; 
    1352     } 
    1353  
    1354     /* If we're answering or updating the session with a new offer, 
    1355      * and the selected media is not the first media 
    1356      * in SDP, then fill in the unselected media with with zero port.  
    1357      * Otherwise we'll crash in transport_encode_sdp() because the media 
    1358      * lines are not aligned between offer and answer. 
    1359      */ 
    1360     if (call->audio_idx != 0 &&  
    1361         (rem_sdp || sdp_neg_state==PJMEDIA_SDP_NEG_STATE_DONE)) 
    1362     { 
    1363         unsigned i; 
    1364         const pjmedia_sdp_session *ref_sdp = rem_sdp; 
    1365  
    1366         if (!ref_sdp) { 
    1367             /* We are updating session with a new offer */ 
    1368             status = pjmedia_sdp_neg_get_active_local(call->inv->neg, 
    1369                                                       &ref_sdp); 
    1370             pj_assert(status == PJ_SUCCESS); 
    1371         } 
    1372  
    1373         for (i=0; i<ref_sdp->media_count; ++i) { 
    1374             const pjmedia_sdp_media *ref_m = ref_sdp->media[i]; 
    1375             pjmedia_sdp_media *m; 
    1376  
    1377             if ((int)i == call->audio_idx) 
    1378                 continue; 
    1379  
    1380             m = pjmedia_sdp_media_clone_deactivate(pool, ref_m); 
    1381             if (i==sdp->media_count) 
    1382                 sdp->media[sdp->media_count++] = m; 
    1383             else { 
    1384                 pj_array_insert(sdp->media, sizeof(sdp->media[0]), 
    1385                                 sdp->media_count, i, &m); 
    1386                 ++sdp->media_count; 
    1387             } 
     1592 
     1593    /* Process each media line */ 
     1594    for (mi=0; mi<call->med_cnt; ++mi) { 
     1595        pjsua_call_media *call_med = &call->media[mi]; 
     1596        pjmedia_sdp_media *m = NULL; 
     1597        pjmedia_transport_info tpinfo; 
     1598 
     1599        if (rem_sdp && mi >= rem_sdp->media_count) { 
     1600            /* Remote might have removed some media lines. */ 
     1601            break; 
     1602        } 
     1603 
     1604        if (call_med->tp == NULL || call_med->tp_st == PJSUA_MED_TP_DISABLED) 
     1605        { 
     1606            /* 
     1607             * This media is disabled. Just create a valid SDP with zero 
     1608             * port. 
     1609             */ 
     1610            m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media); 
     1611            m->desc.transport = pj_str("RTP/AVP"); 
     1612            m->desc.fmt_count = 1; 
     1613            m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn); 
     1614            m->conn->net_type = pj_str("IN"); 
     1615            m->conn->addr_type = pj_str("IP4"); 
     1616            m->conn->addr = pj_str("127.0.0.1"); 
     1617 
     1618            switch (call_med->type) { 
     1619            case PJMEDIA_TYPE_AUDIO: 
     1620                m->desc.media = pj_str("audio"); 
     1621                m->desc.fmt[0] = pj_str("0"); 
     1622                break; 
     1623            case PJMEDIA_TYPE_VIDEO: 
     1624                m->desc.media = pj_str("video"); 
     1625                m->desc.fmt[0] = pj_str("31"); 
     1626                break; 
     1627            default: 
     1628                if (rem_sdp && mi < rem_sdp->media_count) { 
     1629                    pj_strdup(pool, &m->desc.media, 
     1630                              &rem_sdp->media[mi]->desc.media); 
     1631                    pj_strdup(pool, &m->desc.fmt[0], 
     1632                              &rem_sdp->media[mi]->desc.fmt[0]); 
     1633                } else { 
     1634                    pj_assert(!"Invalid call_med media type"); 
     1635                    return PJ_EBUG; 
     1636                } 
     1637            } 
     1638 
     1639            sdp->media[sdp->media_count++] = m; 
     1640            continue; 
     1641        } 
     1642 
     1643        /* Get transport address info */ 
     1644        pjmedia_transport_info_init(&tpinfo); 
     1645        pjmedia_transport_get_info(call_med->tp, &tpinfo); 
     1646 
     1647        /* Ask pjmedia endpoint to create SDP media line */ 
     1648        switch (call_med->type) { 
     1649        case PJMEDIA_TYPE_AUDIO: 
     1650            status = pjmedia_endpt_create_audio_sdp(pjsua_var.med_endpt, pool, 
     1651                                                    &tpinfo.sock_info, 0, &m); 
     1652            break; 
     1653        case PJMEDIA_TYPE_VIDEO: 
     1654            status = pjmedia_endpt_create_video_sdp(pjsua_var.med_endpt, pool, 
     1655                                                    &tpinfo.sock_info, 0, &m); 
     1656            break; 
     1657        default: 
     1658            pj_assert(!"Invalid call_med media type"); 
     1659            return PJ_EBUG; 
     1660        } 
     1661 
     1662        if (status != PJ_SUCCESS) 
     1663            return status; 
     1664 
     1665        sdp->media[sdp->media_count++] = m; 
     1666 
     1667        /* Give to transport */ 
     1668        status = pjmedia_transport_encode_sdp(call_med->tp, pool, 
     1669                                              sdp, rem_sdp, mi); 
     1670        if (status != PJ_SUCCESS) { 
     1671            if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 
     1672            return status; 
     1673        } 
     1674 
     1675        /* Copy c= line of the first media to session level, 
     1676         * if there's none. 
     1677         */ 
     1678        if (sdp->conn == NULL) { 
     1679            sdp->conn = pjmedia_sdp_conn_clone(pool, m->conn); 
    13881680        } 
    13891681    } 
     
    14131705    } 
    14141706 
    1415     /* Give the SDP to media transport */ 
    1416     status = pjmedia_transport_encode_sdp(call->med_tp, pool, sdp, rem_sdp,  
    1417                                           call->audio_idx); 
    1418     if (status != PJ_SUCCESS) { 
    1419         if (sip_status_code) *sip_status_code = PJSIP_SC_NOT_ACCEPTABLE; 
    1420         return status; 
    1421     } 
    1422  
    1423 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
     1707 
     1708#if DISABLED_FOR_TICKET_1185 && defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 
    14241709    /* Check if SRTP is in optional mode and configured to use duplicated 
    14251710     * media, i.e: secured and unsecured version, in the SDP offer. 
     
    14341719            pjmedia_sdp_media *m = sdp->media[i]; 
    14351720 
    1436             /* Check if this media is unsecured but has SDP "crypto"  
     1721            /* Check if this media is unsecured but has SDP "crypto" 
    14371722             * attribute. 
    14381723             */ 
     
    14401725                pjmedia_sdp_media_find_attr2(m, "crypto", NULL) != NULL) 
    14411726            { 
    1442                 if (i == (unsigned)call->audio_idx &&  
     1727                if (i == (unsigned)call->audio_idx && 
    14431728                    sdp_neg_state == PJMEDIA_SDP_NEG_STATE_DONE) 
    14441729                { 
     
    14631748                    /* Insert the new media before the unsecured media */ 
    14641749                    if (sdp->media_count < PJMEDIA_MAX_SDP_MEDIA) { 
    1465                         pj_array_insert(sdp->media, sizeof(new_m),  
     1750                        pj_array_insert(sdp->media, sizeof(new_m), 
    14661751                                        sdp->media_count, i, &new_m); 
    14671752                        ++sdp->media_count; 
     
    14741759#endif 
    14751760 
    1476     /* Update currently advertised RTP source address */ 
    1477     pj_memcpy(&call->med_rtp_addr, &tpinfo.sock_info.rtp_addr_name,  
    1478               sizeof(pj_sockaddr)); 
    1479  
    14801761    *p_sdp = sdp; 
    14811762    return PJ_SUCCESS; 
     
    14861767{ 
    14871768    pjsua_call *call = &pjsua_var.calls[call_id]; 
    1488  
    1489     if (call->conf_slot != PJSUA_INVALID_ID) { 
    1490         if (pjsua_var.mconf) { 
    1491             pjsua_conf_remove_port(call->conf_slot); 
    1492         } 
    1493         call->conf_slot = PJSUA_INVALID_ID; 
    1494     } 
    1495  
    1496     if (call->session) { 
    1497         pjmedia_rtcp_stat stat; 
    1498  
    1499         if ((call->media_dir & PJMEDIA_DIR_ENCODING) && 
    1500             (pjmedia_session_get_stream_stat(call->session, 0, &stat)  
    1501              == PJ_SUCCESS)) 
    1502         { 
    1503             /* Save RTP timestamp & sequence, so when media session is  
    1504              * restarted, those values will be restored as the initial  
    1505              * RTP timestamp & sequence of the new media session. So in  
    1506              * the same call session, RTP timestamp and sequence are  
    1507              * guaranteed to be contigue. 
    1508              */ 
    1509             call->rtp_tx_seq_ts_set = 1 | (1 << 1); 
    1510             call->rtp_tx_seq = stat.rtp_tx_last_seq; 
    1511             call->rtp_tx_ts = stat.rtp_tx_last_ts; 
    1512         } 
    1513  
    1514         if (pjsua_var.ua_cfg.cb.on_stream_destroyed) { 
    1515             pjsua_var.ua_cfg.cb.on_stream_destroyed(call_id, call->session, 0); 
    1516         } 
    1517  
    1518         pjmedia_session_destroy(call->session); 
    1519         call->session = NULL; 
    1520  
    1521         PJ_LOG(4,(THIS_FILE, "Media session for call %d is destroyed",  
    1522                              call_id)); 
    1523  
    1524     } 
    1525  
    1526     call->media_st = PJSUA_CALL_MEDIA_NONE; 
     1769    unsigned mi; 
     1770 
     1771    for (mi=0; mi<call->med_cnt; ++mi) { 
     1772        pjsua_call_media *call_med = &call->media[mi]; 
     1773 
     1774        if (call_med->type == PJMEDIA_TYPE_AUDIO) { 
     1775            pjmedia_stream *strm = call_med->strm.a.stream; 
     1776            pjmedia_rtcp_stat stat; 
     1777 
     1778            if (strm) { 
     1779                if (call_med->strm.a.conf_slot != PJSUA_INVALID_ID) { 
     1780                    if (pjsua_var.mconf) { 
     1781                        pjsua_conf_remove_port(call_med->strm.a.conf_slot); 
     1782                    } 
     1783                    call_med->strm.a.conf_slot = PJSUA_INVALID_ID; 
     1784                } 
     1785 
     1786                if ((call_med->dir & PJMEDIA_DIR_ENCODING) && 
     1787                    (pjmedia_stream_get_stat(strm, &stat) == PJ_SUCCESS)) 
     1788                { 
     1789                    /* Save RTP timestamp & sequence, so when media session is 
     1790                     * restarted, those values will be restored as the initial 
     1791                     * RTP timestamp & sequence of the new media session. So in 
     1792                     * the same call session, RTP timestamp and sequence are 
     1793                     * guaranteed to be contigue. 
     1794                     */ 
     1795                    call_med->rtp_tx_seq_ts_set = 1 | (1 << 1); 
     1796                    call_med->rtp_tx_seq = stat.rtp_tx_last_seq; 
     1797                    call_med->rtp_tx_ts = stat.rtp_tx_last_ts; 
     1798                } 
     1799 
     1800                if (pjsua_var.ua_cfg.cb.on_stream_destroyed) { 
     1801                    pjsua_var.ua_cfg.cb.on_stream_destroyed(call_id, strm, mi); 
     1802                } 
     1803 
     1804                pjmedia_stream_destroy(strm); 
     1805                call_med->strm.a.stream = NULL; 
     1806            } 
     1807        } 
     1808 
     1809#if PJMEDIA_HAS_VIDEO 
     1810        else if (call_med->type == PJMEDIA_TYPE_VIDEO) { 
     1811            stop_video_stream(call_med); 
     1812        } 
     1813#endif 
     1814 
     1815        PJ_LOG(4,(THIS_FILE, "Media session call%02d:%d is destroyed", 
     1816                             call_id, mi)); 
     1817        call_med->state = PJSUA_CALL_MEDIA_NONE; 
     1818    } 
    15271819} 
    15281820 
     
    15301822{ 
    15311823    pjsua_call *call = &pjsua_var.calls[call_id]; 
     1824    unsigned mi; 
    15321825 
    15331826    stop_media_session(call_id); 
    15341827 
    1535     if (call->med_tp_st != PJSUA_MED_TP_IDLE) { 
    1536         pjmedia_transport_media_stop(call->med_tp); 
    1537         call->med_tp_st = PJSUA_MED_TP_IDLE; 
    1538     } 
    1539  
    1540     if (call->med_orig && call->med_tp && call->med_tp != call->med_orig) { 
    1541         pjmedia_transport_close(call->med_tp); 
    1542         call->med_tp = call->med_orig; 
     1828    for (mi=0; mi<call->med_cnt; ++mi) { 
     1829        pjsua_call_media *call_med = &call->media[mi]; 
     1830 
     1831        if (call_med->tp_st != PJSUA_MED_TP_IDLE) { 
     1832            pjmedia_transport_media_stop(call_med->tp); 
     1833            call_med->tp_st = PJSUA_MED_TP_IDLE; 
     1834        } 
     1835 
     1836        //if (call_med->tp_orig && call_med->tp && 
     1837        //      call_med->tp != call_med->tp_orig) 
     1838        //{ 
     1839        //    pjmedia_transport_close(call_med->tp); 
     1840        //    call_med->tp = call_med->tp_orig; 
     1841        //} 
     1842        if (call_med->tp) { 
     1843            pjmedia_transport_close(call_med->tp); 
     1844            call_med->tp = call_med->tp_orig = NULL; 
     1845        } 
    15431846    } 
    15441847 
     
    15701873 
    15711874 
    1572 pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 
    1573                                        const pjmedia_sdp_session *local_sdp, 
    1574                                        const pjmedia_sdp_session *remote_sdp) 
    1575 { 
    1576     int prev_media_st = 0; 
    1577     pjsua_call *call = &pjsua_var.calls[call_id]; 
    1578     pjmedia_session_info sess_info; 
    1579     pjmedia_stream_info *si = NULL; 
     1875static pj_status_t audio_channel_update(pjsua_call_media *call_med, 
     1876                                        pj_pool_t *tmp_pool, 
     1877                                        const pjmedia_sdp_session *local_sdp, 
     1878                                        const pjmedia_sdp_session *remote_sdp) 
     1879{ 
     1880    pjsua_call *call = call_med->call; 
     1881    pjmedia_stream_info the_si, *si = &the_si; 
    15801882    pjmedia_port *media_port; 
     1883    unsigned strm_idx = call_med->idx; 
    15811884    pj_status_t status; 
    1582  
    1583     if (!pjsua_var.med_endpt) { 
    1584         /* We're being shutdown */ 
    1585         return PJ_EBUSY; 
    1586     } 
    1587  
    1588     /* Destroy existing media session, if any. */ 
    1589     prev_media_st = call->media_st; 
    1590     stop_media_session(call->index); 
    1591  
    1592     /* Create media session info based on SDP parameters.  
    1593      */     
    1594     status = pjmedia_session_info_from_sdp( call->inv->pool_prov,  
    1595                                             pjsua_var.med_endpt,  
    1596                                             PJMEDIA_MAX_SDP_MEDIA, &sess_info, 
    1597                                             local_sdp, remote_sdp); 
     1885     
     1886    status = pjmedia_stream_info_from_sdp(si, tmp_pool, pjsua_var.med_endpt, 
     1887                                          local_sdp, remote_sdp, strm_idx); 
    15981888    if (status != PJ_SUCCESS) 
    15991889        return status; 
    16001890 
    1601     /* Update audio index from the negotiated SDP */ 
    1602     call->audio_idx = find_audio_index(local_sdp, PJ_TRUE); 
    1603  
    1604     /* Find which session is audio */ 
    1605     PJ_ASSERT_RETURN(call->audio_idx != -1, PJ_EBUG); 
    1606     PJ_ASSERT_RETURN(call->audio_idx < (int)sess_info.stream_cnt, PJ_EBUG); 
    1607     si = &sess_info.stream_info[call->audio_idx]; 
    1608      
    1609     /* Reset session info with only one media stream */ 
    1610     sess_info.stream_cnt = 1; 
    1611     if (si != &sess_info.stream_info[0]) { 
    1612         pj_memcpy(&sess_info.stream_info[0], si, sizeof(pjmedia_stream_info)); 
    1613         si = &sess_info.stream_info[0]; 
    1614     } 
    1615  
    16161891    /* Check if no media is active */ 
    1617     if (sess_info.stream_cnt == 0 || si->dir == PJMEDIA_DIR_NONE) 
    1618     { 
     1892    if (si->dir == PJMEDIA_DIR_NONE) { 
    16191893        /* Call media state */ 
    1620         call->media_st = PJSUA_CALL_MEDIA_NONE; 
     1894        call_med->state = PJSUA_CALL_MEDIA_NONE; 
    16211895 
    16221896        /* Call media direction */ 
    1623         call->media_dir = PJMEDIA_DIR_NONE; 
    1624  
    1625         /* Don't stop transport because we need to transmit keep-alives, and 
    1626          * also to prevent restarting ICE negotiation. See 
    1627          *  http://trac.pjsip.org/repos/ticket/1094 
    1628          */ 
    1629 #if 0 
    1630         /* Shutdown transport's session */ 
    1631         pjmedia_transport_media_stop(call->med_tp); 
    1632         call->med_tp_st = PJSUA_MED_TP_IDLE; 
    1633  
    1634         /* No need because we need keepalive? */ 
    1635  
    1636         /* Close upper entry of transport stack */ 
    1637         if (call->med_orig && (call->med_tp != call->med_orig)) { 
    1638             pjmedia_transport_close(call->med_tp); 
    1639             call->med_tp = call->med_orig; 
    1640         } 
    1641 #endif 
     1897        call_med->dir = PJMEDIA_DIR_NONE; 
    16421898 
    16431899    } else { 
     
    16451901 
    16461902        /* Start/restart media transport */ 
    1647         status = pjmedia_transport_media_start(call->med_tp,  
    1648                                                call->inv->pool_prov, 
    1649                                                local_sdp, remote_sdp, 
    1650                                                call->audio_idx); 
     1903        status = pjmedia_transport_media_start(call_med->tp, 
     1904                                               tmp_pool, local_sdp, 
     1905                                               remote_sdp, strm_idx); 
    16511906        if (status != PJ_SUCCESS) 
    16521907            return status; 
    16531908 
    1654         call->med_tp_st = PJSUA_MED_TP_RUNNING; 
     1909        call_med->tp_st = PJSUA_MED_TP_RUNNING; 
    16551910 
    16561911        /* Get remote SRTP usage policy */ 
    16571912        pjmedia_transport_info_init(&tp_info); 
    1658         pjmedia_transport_get_info(call->med_tp, &tp_info); 
     1913        pjmedia_transport_get_info(call_med->tp, &tp_info); 
    16591914        if (tp_info.specific_info_cnt > 0) { 
    16601915            unsigned i; 
     
    16651920                                (pjmedia_srtp_info*) tp_info.spc_info[i].buffer; 
    16661921 
    1667                     call->rem_srtp_use = srtp_info->peer_use; 
     1922                    call_med->rem_srtp_use = srtp_info->peer_use; 
    16681923                    break; 
    16691924                } 
     
    16941949 
    16951950        /* Set SSRC */ 
    1696         si->ssrc = call->ssrc; 
     1951        si->ssrc = call_med->ssrc; 
    16971952 
    16981953        /* Set RTP timestamp & sequence, normally these value are intialized 
     
    17011956         * contigue. 
    17021957         */ 
    1703         si->rtp_ts = call->rtp_tx_ts; 
    1704         si->rtp_seq = call->rtp_tx_seq; 
    1705         si->rtp_seq_ts_set = call->rtp_tx_seq_ts_set; 
     1958        si->rtp_ts = call_med->rtp_tx_ts; 
     1959        si->rtp_seq = call_med->rtp_tx_seq; 
     1960        si->rtp_seq_ts_set = call_med->rtp_tx_seq_ts_set; 
    17061961 
    17071962#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0 
     
    17111966 
    17121967        /* Create session based on session info. */ 
    1713         status = pjmedia_session_create( pjsua_var.med_endpt, &sess_info, 
    1714                                          &call->med_tp, 
    1715                                          call, &call->session ); 
     1968        status = pjmedia_stream_create(pjsua_var.med_endpt, NULL, si, 
     1969                                       call_med->tp, NULL, 
     1970                                       &call_med->strm.a.stream); 
     1971        if (status != PJ_SUCCESS) { 
     1972            return status; 
     1973        } 
     1974 
     1975        /* Start stream */ 
     1976        status = pjmedia_stream_start(call_med->strm.a.stream); 
    17161977        if (status != PJ_SUCCESS) { 
    17171978            return status; 
     
    17221983         */ 
    17231984        if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { 
    1724             pjmedia_session_set_dtmf_callback(call->session, 0,  
    1725                                               &dtmf_callback,  
    1726                                               (void*)(long)(call->index)); 
     1985            pjmedia_stream_set_dtmf_callback(call_med->strm.a.stream, 
     1986                                             &dtmf_callback, 
     1987                                             (void*)(long)(call->index)); 
    17271988        } 
    17281989 
     
    17301991         * We need the port interface to add to the conference bridge. 
    17311992         */ 
    1732         pjmedia_session_get_port(call->session, 0, &media_port); 
     1993        pjmedia_stream_get_port(call_med->strm.a.stream, &media_port); 
    17331994 
    17341995        /* Notify application about stream creation. 
     
    17371998         */ 
    17381999        if (pjsua_var.ua_cfg.cb.on_stream_created) { 
    1739             pjsua_var.ua_cfg.cb.on_stream_created(call_id, call->session, 
    1740                                                   0, &media_port); 
     2000            pjsua_var.ua_cfg.cb.on_stream_created(call->index, 
     2001                                                  call_med->strm.a.stream, 
     2002                                                  strm_idx, &media_port); 
    17412003        } 
    17422004 
     
    17592021                                            media_port,  
    17602022                                            &port_name, 
    1761                                             (unsigned*)&call->conf_slot); 
     2023                                            (unsigned*) 
     2024                                            &call_med->strm.a.conf_slot); 
    17622025            if (status != PJ_SUCCESS) { 
    17632026                return status; 
     
    17662029 
    17672030        /* Call media direction */ 
    1768         call->media_dir = si->dir; 
     2031        call_med->dir = si->dir; 
    17692032 
    17702033        /* Call media state */ 
    17712034        if (call->local_hold) 
    1772             call->media_st = PJSUA_CALL_MEDIA_LOCAL_HOLD; 
    1773         else if (call->media_dir == PJMEDIA_DIR_DECODING) 
    1774             call->media_st = PJSUA_CALL_MEDIA_REMOTE_HOLD; 
     2035            call_med->state = PJSUA_CALL_MEDIA_LOCAL_HOLD; 
     2036        else if (call_med->dir == PJMEDIA_DIR_DECODING) 
     2037            call_med->state = PJSUA_CALL_MEDIA_REMOTE_HOLD; 
    17752038        else 
    1776             call->media_st = PJSUA_CALL_MEDIA_ACTIVE; 
     2039            call_med->state = PJSUA_CALL_MEDIA_ACTIVE; 
    17772040    } 
    17782041 
     
    17812044        char info[80]; 
    17822045        int info_len = 0; 
    1783         unsigned i; 
    1784  
    1785         for (i=0; i<sess_info.stream_cnt; ++i) { 
    1786             int len; 
    1787             const char *dir; 
    1788             pjmedia_stream_info *strm_info = &sess_info.stream_info[i]; 
    1789  
    1790             switch (strm_info->dir) { 
    1791             case PJMEDIA_DIR_NONE: 
    1792                 dir = "inactive"; 
    1793                 break; 
    1794             case PJMEDIA_DIR_ENCODING: 
    1795                 dir = "sendonly"; 
    1796                 break; 
    1797             case PJMEDIA_DIR_DECODING: 
    1798                 dir = "recvonly"; 
    1799                 break; 
    1800             case PJMEDIA_DIR_ENCODING_DECODING: 
    1801                 dir = "sendrecv"; 
    1802                 break; 
    1803             default: 
    1804                 dir = "unknown"; 
    1805                 break; 
    1806             } 
    1807             len = pj_ansi_sprintf( info+info_len, 
    1808                                    ", stream #%d: %.*s (%s)", i, 
    1809                                    (int)strm_info->fmt.encoding_name.slen, 
    1810                                    strm_info->fmt.encoding_name.ptr, 
    1811                                    dir); 
    1812             if (len > 0) 
    1813                 info_len += len; 
    1814         } 
     2046        int len; 
     2047        const char *dir; 
     2048 
     2049        switch (si->dir) { 
     2050        case PJMEDIA_DIR_NONE: 
     2051            dir = "inactive"; 
     2052            break; 
     2053        case PJMEDIA_DIR_ENCODING: 
     2054            dir = "sendonly"; 
     2055            break; 
     2056        case PJMEDIA_DIR_DECODING: 
     2057            dir = "recvonly"; 
     2058            break; 
     2059        case PJMEDIA_DIR_ENCODING_DECODING: 
     2060            dir = "sendrecv"; 
     2061            break; 
     2062        default: 
     2063            dir = "unknown"; 
     2064            break; 
     2065        } 
     2066        len = pj_ansi_sprintf( info+info_len, 
     2067                               ", stream #%d: %.*s (%s)", strm_idx, 
     2068                               (int)si->fmt.encoding_name.slen, 
     2069                               si->fmt.encoding_name.ptr, 
     2070                               dir); 
     2071        if (len > 0) 
     2072            info_len += len; 
    18152073        PJ_LOG(4,(THIS_FILE,"Media updates%s", info)); 
    18162074    } 
    18172075 
    18182076    return PJ_SUCCESS; 
     2077} 
     2078 
     2079pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 
     2080                                       const pjmedia_sdp_session *local_sdp, 
     2081                                       const pjmedia_sdp_session *remote_sdp) 
     2082{ 
     2083    pjsua_call *call = &pjsua_var.calls[call_id]; 
     2084    pj_pool_t *tmp_pool = call->inv->pool_prov; 
     2085    unsigned mi; 
     2086    pj_bool_t got_media = PJ_FALSE; 
     2087    pj_status_t status = PJ_SUCCESS; 
     2088 
     2089    if (pjsua_get_state() != PJSUA_STATE_RUNNING) 
     2090        return PJ_EBUSY; 
     2091 
     2092    /* Destroy existing media session, if any. */ 
     2093    stop_media_session(call->index); 
     2094 
     2095    /* Reset audio_idx first */ 
     2096    call->audio_idx = -1; 
     2097 
     2098    /* Process each media stream */ 
     2099    for (mi=0; mi < call->med_cnt; ++mi) { 
     2100        pjsua_call_media *call_med = &call->media[mi]; 
     2101 
     2102        if (mi >= local_sdp->media_count || 
     2103            mi >= remote_sdp->media_count) 
     2104        { 
     2105            /* This may happen when remote removed any SDP media lines in 
     2106             * its re-offer. 
     2107             */ 
     2108            continue; 
     2109#if 0 
     2110            /* Something is wrong */ 
     2111            PJ_LOG(1,(THIS_FILE, "Error updating media for call %d: " 
     2112                      "invalid media index %d in SDP", call_id, mi)); 
     2113            return PJMEDIA_SDP_EINSDP; 
     2114#endif 
     2115        } 
     2116 
     2117        switch (call_med->type) { 
     2118        case PJMEDIA_TYPE_AUDIO: 
     2119            status = audio_channel_update(call_med, tmp_pool, 
     2120                                          local_sdp, remote_sdp); 
     2121            if (call->audio_idx==-1 && status==PJ_SUCCESS && 
     2122                call_med->strm.a.stream) 
     2123            { 
     2124                call->audio_idx = mi; 
     2125            } 
     2126            break; 
     2127#if PJMEDIA_HAS_VIDEO 
     2128        case PJMEDIA_TYPE_VIDEO: 
     2129            status = video_channel_update(call_med, tmp_pool, 
     2130                                          local_sdp, remote_sdp); 
     2131            break; 
     2132#endif 
     2133        default: 
     2134            status = PJMEDIA_EINVALIMEDIATYPE; 
     2135            break; 
     2136        } 
     2137 
     2138        if (status != PJ_SUCCESS) { 
     2139            PJ_PERROR(1,(THIS_FILE, status, "Error updating media call%02d:%d", 
     2140                         call_id, mi)); 
     2141        } else { 
     2142            got_media = PJ_TRUE; 
     2143        } 
     2144    } 
     2145 
     2146    return (got_media? PJ_SUCCESS : PJMEDIA_SDPNEG_ENOMEDIA); 
    18192147} 
    18202148 
     
    19692297        { 
    19702298            need_reopen = (peer_info.format.id != port0_info.format.id || 
    1971                            peer_info.format.bitrate != port0_info.format.bitrate || 
     2299                           peer_info.format.det.aud.avg_bps != 
     2300                                   port0_info.format.det.aud.avg_bps || 
    19722301                           peer_info.clock_rate != port0_info.clock_rate || 
    1973                            peer_info.channel_count != port0_info.channel_count); 
     2302                           peer_info.channel_count!=port0_info.channel_count); 
    19742303        } 
    19752304 
     
    19862315                                          peer_info.bits_per_sample); 
    19872316                if (status != PJ_SUCCESS) { 
    1988                     pjsua_perror(THIS_FILE, "Error opening sound device", status); 
     2317                    pjsua_perror(THIS_FILE, "Error opening sound device", 
     2318                                 status); 
    19892319                    return status; 
    19902320                } 
     
    19992329                status = open_snd_dev(&param); 
    20002330                if (status != PJ_SUCCESS) { 
    2001                     pjsua_perror(THIS_FILE, "Error opening sound device", status); 
     2331                    pjsua_perror(THIS_FILE, "Error opening sound device", 
     2332                                 status); 
    20022333                    return status; 
    20032334                } 
    20042335            } else { 
    20052336                /* Null-audio */ 
    2006                 status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev); 
     2337                status = pjsua_set_snd_dev(pjsua_var.cap_dev, 
     2338                                           pjsua_var.play_dev); 
    20072339                if (status != PJ_SUCCESS) { 
    2008                     pjsua_perror(THIS_FILE, "Error opening sound device", status); 
     2340                    pjsua_perror(THIS_FILE, "Error opening sound device", 
     2341                                 status); 
    20092342                    return status; 
    20102343                } 
     2344            } 
     2345        } else if (pjsua_var.no_snd) { 
     2346            if (!pjsua_var.snd_is_on) { 
     2347                pjsua_var.snd_is_on = PJ_TRUE; 
     2348                /* Notify app */ 
     2349                if (pjsua_var.ua_cfg.cb.on_snd_dev_operation) { 
     2350                    (*pjsua_var.ua_cfg.cb.on_snd_dev_operation)(1); 
     2351                } 
    20112352            } 
    20122353        } 
     
    20262367                return status; 
    20272368            } 
    2028         } 
    2029  
     2369        } else if (pjsua_var.no_snd && !pjsua_var.snd_is_on) { 
     2370            pjsua_var.snd_is_on = PJ_TRUE; 
     2371            /* Notify app */ 
     2372            if (pjsua_var.ua_cfg.cb.on_snd_dev_operation) { 
     2373                (*pjsua_var.ua_cfg.cb.on_snd_dev_operation)(1); 
     2374            } 
     2375        } 
    20302376    } 
    20312377 
     
    21432489                                    pool, path, 
    21442490                                    pjsua_var.mconf_cfg.samples_per_frame * 
    2145                                     1000 / pjsua_var.media_cfg.channel_count /  
     2491                                    1000 / pjsua_var.media_cfg.channel_count / 
    21462492                                    pjsua_var.media_cfg.clock_rate,  
    21472493                                    options, 0, &port); 
     
    26843030    close_snd_dev(); 
    26853031 
     3032    /* Notify app */ 
     3033    if (pjsua_var.ua_cfg.cb.on_snd_dev_operation) { 
     3034        (*pjsua_var.ua_cfg.cb.on_snd_dev_operation)(1); 
     3035    } 
     3036 
    26863037    /* Create memory pool for sound device. */ 
    26873038    pjsua_var.snd_pool = pjsua_pool_create("pjsua_snd", 4000, 4000); 
     
    27093060    if (!pjsua_var.is_mswitch && 
    27103061        param->base.ext_fmt.id == PJMEDIA_FORMAT_PCM && 
    2711         conf_port->info.clock_rate != param->base.clock_rate) 
     3062        PJMEDIA_PIA_SRATE(&conf_port->info) != param->base.clock_rate) 
    27123063    { 
    27133064        pjmedia_port *resample_port; 
     
    27453096     */ 
    27463097    if (pjsua_var.is_mswitch) { 
    2747         pj_memcpy(&conf_port->info.format, &param->base.ext_fmt,  
    2748                   sizeof(conf_port->info.format)); 
    2749         conf_port->info.clock_rate = param->base.clock_rate; 
    2750         conf_port->info.samples_per_frame = param->base.samples_per_frame; 
    2751         conf_port->info.channel_count = param->base.channel_count; 
    2752         conf_port->info.bits_per_sample = 16; 
    2753     } 
     3098        pj_memcpy(&conf_port->info.fmt, &param->base.ext_fmt, 
     3099                  sizeof(conf_port->info.fmt)); 
     3100        conf_port->info.fmt.det.aud.clock_rate = param->base.clock_rate; 
     3101        conf_port->info.fmt.det.aud.frame_time_usec = param->base.samples_per_frame* 
     3102                                                      1000000 / 
     3103                                                      param->base.clock_rate; 
     3104        conf_port->info.fmt.det.aud.channel_count = param->base.channel_count; 
     3105        conf_port->info.fmt.det.aud.bits_per_sample = 16; 
     3106    } 
     3107 
    27543108 
    27553109    /* Connect sound port to the bridge */ 
     
    28173171static void close_snd_dev(void) 
    28183172{ 
     3173    /* Notify app */ 
     3174    if (pjsua_var.snd_is_on && pjsua_var.ua_cfg.cb.on_snd_dev_operation) { 
     3175        (*pjsua_var.ua_cfg.cb.on_snd_dev_operation)(0); 
     3176    } 
     3177 
    28193178    /* Close sound device */ 
    28203179    if (pjsua_var.snd_port) { 
     
    28503209        pj_pool_release(pjsua_var.snd_pool); 
    28513210    pjsua_var.snd_pool = NULL; 
     3211    pjsua_var.snd_is_on = PJ_FALSE; 
    28523212} 
    28533213 
     
    29133273 
    29143274    pjsua_var.no_snd = PJ_FALSE; 
     3275    pjsua_var.snd_is_on = PJ_TRUE; 
    29153276 
    29163277    return PJ_SUCCESS; 
     
    29473308    /* Close existing sound device */ 
    29483309    close_snd_dev(); 
     3310 
     3311    /* Notify app */ 
     3312    if (pjsua_var.ua_cfg.cb.on_snd_dev_operation) { 
     3313        (*pjsua_var.ua_cfg.cb.on_snd_dev_operation)(1); 
     3314    } 
    29493315 
    29503316    /* Create memory pool for sound device. */ 
     
    29773343 
    29783344    pjsua_var.no_snd = PJ_FALSE; 
     3345    pjsua_var.snd_is_on = PJ_TRUE; 
    29793346 
    29803347    return PJ_SUCCESS; 
     
    31223489 
    31233490    for (i=0; i<count; ++i) { 
     3491        pj_bzero(&id[i], sizeof(pjsua_codec_info)); 
     3492 
    31243493        pjmedia_codec_info_to_id(&info[i], id[i].buf_, sizeof(id[i].buf_)); 
    31253494        id[i].codec_id = pj_str(id[i].buf_); 
     
    31753544 
    31763545    if (count != 1) 
    3177         return PJ_ENOTFOUND; 
     3546        return (count > 1? PJ_ETOOMANY : PJ_ENOTFOUND); 
    31783547 
    31793548    status = pjmedia_codec_mgr_get_default_param( codec_mgr, info, param); 
     
    32123581    return status; 
    32133582} 
     3583 
     3584 
Note: See TracChangeset for help on using the changeset viewer.