Ignore:
Timestamp:
Mar 17, 2011 4:34:43 AM (11 years ago)
Author:
bennylp
Message:

Modifications in PJSUA-LIB to support multiple media streams (multiple audio and/or video) and dynamic creation of media transports. This closed #1185 and closed #1201.

1185: Dynamic creation of media transports
============================================
Done:

  • media transports are created on demand now

Todo:

  • media transport creation is still blocking

1201: Video support in PJSUA-LIB
===================================
Done:

  • call now supports N media (N audio and M video)
  • number of audio/video streams is configurable per acc
  • extra audio stream info in pjsua_call_info to support multiple audio streams

in one call

  • video subsys and ffmpeg initialization in PJSUA-LIB
  • ability to offer and create video SDP answer
  • "dq" for more than 1 audio streams
  • introducing pjsua_state and pjsua_get_state()

API change:

  • on_stream_created() and on_stream_destroyed() callbacks: changed session to

stream

Todo:

  • many others features are disabled, just search for DISABLED_FOR_TICKET_1185

macro (these have also been added to ticket #1193 (Issues & Todos)). Notable
missing features are:

  • creation of duplicate SDP m= lines for optional SRTP
  • mm.. that's it?
  • whole lot of testings

pjsua:
===============

  • Added --extra-audio and --video options. Specify these more than once and

each time an extra audio/video streams will be added. :)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_call.c

    r3374 r3457  
    102102{ 
    103103    pjsua_call *call = &pjsua_var.calls[id]; 
    104  
     104    unsigned i; 
     105 
     106    pj_bzero(call, sizeof(*call)); 
    105107    call->index = id; 
    106     call->inv = NULL; 
    107     call->user_data = NULL; 
    108     call->session = NULL; 
    109     call->audio_idx = -1; 
    110     call->ssrc = pj_rand(); 
    111     call->rtp_tx_seq = 0; 
    112     call->rtp_tx_ts = 0; 
    113     call->rtp_tx_seq_ts_set = 0; 
    114     call->xfer_sub = NULL; 
    115     call->last_code = (pjsip_status_code) 0; 
    116     call->conf_slot = PJSUA_INVALID_ID; 
    117108    call->last_text.ptr = call->last_text_buf_; 
    118     call->last_text.slen = 0; 
    119     call->conn_time.sec = 0; 
    120     call->conn_time.msec = 0; 
    121     call->res_time.sec = 0; 
    122     call->res_time.msec = 0; 
    123     call->rem_nat_type = PJ_STUN_NAT_TYPE_UNKNOWN; 
    124     call->rem_srtp_use = PJMEDIA_SRTP_DISABLED; 
    125     call->local_hold = PJ_FALSE; 
    126     pj_bzero(&call->lock_codec, sizeof(call->lock_codec)); 
     109    for (i=0; i<PJ_ARRAY_SIZE(call->media); ++i) { 
     110        pjsua_call_media *call_med = &call->media[i]; 
     111        call_med->ssrc = pj_rand(); 
     112        call_med->strm.a.conf_slot = PJSUA_INVALID_ID; 
     113        call_med->call = call; 
     114        call_med->idx = i; 
     115        call_med->tp_auto_del = PJ_TRUE; 
     116    } 
    127117} 
    128118 
     
    824814    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS,  
    825815                                      call->secure_level,  
    826                                       rdata->tp_info.pool, offer, 
     816                                      rdata->tp_info.pool, 
     817                                      offer, 
    827818                                      &sip_err_code); 
    828819    if (status != PJ_SUCCESS) { 
     
    11191110PJ_DEF(pj_bool_t) pjsua_call_has_media(pjsua_call_id call_id) 
    11201111{ 
     1112    pjsua_call *call = &pjsua_var.calls[call_id]; 
    11211113    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,  
    11221114                     PJ_EINVAL); 
    1123     return pjsua_var.calls[call_id].session != NULL; 
    1124 } 
    1125  
    1126  
     1115    return call->audio_idx >= 0 && call->media[call->audio_idx].strm.a.stream; 
     1116} 
     1117 
     1118 
     1119#if DISABLED_FOR_TICKET_1185 
    11271120/* 
    11281121 * Retrieve the media session associated with this call. 
     
    11431136    PJ_ASSERT_RETURN(cid>=0 && cid<(int)pjsua_var.ua_cfg.max_calls,  
    11441137                     NULL); 
    1145     return pjsua_var.calls[cid].med_tp; 
    1146 } 
    1147  
     1138    return pjsua_var.calls[cid].tp; 
     1139} 
     1140#endif /* Removed in 2.0 */ 
    11481141 
    11491142/* Acquire lock to the specified call_id */ 
     
    12391232        return PJSUA_INVALID_ID; 
    12401233 
    1241     port_id = call->conf_slot; 
     1234    port_id = call->media[call->audio_idx].strm.a.conf_slot; 
    12421235 
    12431236    pjsip_dlg_dec_lock(dlg); 
     
    12561249    pjsua_call *call; 
    12571250    pjsip_dialog *dlg; 
     1251    unsigned mi; 
    12581252    pj_status_t status; 
    12591253 
     
    13301324    } 
    13311325     
    1332     /* media status and dir */ 
    1333     info->media_status = call->media_st; 
    1334     info->media_dir = call->media_dir; 
    1335  
     1326    /* Build array of media status and dir */ 
     1327    info->audio_cnt = 0; 
     1328    for (mi=0; mi < call->med_cnt && 
     1329               info->audio_cnt < PJ_ARRAY_SIZE(info->audio); ++mi) 
     1330    { 
     1331        pjsua_call_media *call_med = &call->media[mi]; 
     1332        if (call_med->type != PJMEDIA_TYPE_AUDIO) 
     1333            continue; 
     1334        info->audio[info->audio_cnt].index = mi; 
     1335        info->audio[info->audio_cnt].media_status = call_med->state; 
     1336        info->audio[info->audio_cnt].media_dir = call_med->dir; 
     1337        info->audio[info->audio_cnt].conf_slot = call_med->strm.a.conf_slot; 
     1338        ++info->audio_cnt; 
     1339    } 
     1340 
     1341    if (info->audio_cnt) { 
     1342        info->media_status = info->audio[0].media_status; 
     1343        info->media_dir = info->audio[0].media_dir; 
     1344    } 
    13361345 
    13371346    /* conference slot number */ 
    1338     info->conf_slot = call->conf_slot; 
     1347    info->conf_slot = call->media[call->audio_idx].strm.a.conf_slot; 
    13391348 
    13401349    /* calculate duration */ 
     
    19601969        return status; 
    19611970 
    1962     if (!call->session) { 
     1971    if (!pjsua_call_has_media(call_id)) { 
    19631972        PJ_LOG(3,(THIS_FILE, "Media is not established yet!")); 
    19641973        pjsip_dlg_dec_lock(dlg); 
     
    19661975    } 
    19671976 
    1968     status = pjmedia_session_dial_dtmf( call->session, 0, digits); 
     1977    status = pjmedia_stream_dial_dtmf( 
     1978                call->media[call->audio_idx].strm.a.stream, digits); 
    19691979 
    19701980    pjsip_dlg_dec_lock(dlg); 
     
    21912201    char *p = buf, *end = buf+maxlen; 
    21922202    int len; 
    2193     pjmedia_session_info info; 
    2194     pjmedia_session *session = call->session; 
    2195     pjmedia_transport_info tp_info; 
    2196  
    2197     pjmedia_transport_info_init(&tp_info); 
    2198  
    2199     pjmedia_transport_get_info(call->med_tp, &tp_info); 
    2200     pjmedia_session_get_info(session, &info); 
    2201  
    2202     for (i=0; i<info.stream_cnt; ++i) { 
     2203 
     2204    for (i=0; i<call->med_cnt; ++i) { 
     2205        pjsua_call_media *call_med = &call->media[i]; 
     2206        pjmedia_stream_info info; 
     2207        pjmedia_stream *stream = call_med->strm.a.stream; 
     2208        pjmedia_transport_info tp_info; 
    22032209        pjmedia_rtcp_stat stat; 
    22042210        char rem_addr_buf[80]; 
     
    22092215        pj_time_val media_duration, now; 
    22102216 
    2211         pjmedia_session_get_stream_stat(session, i, &stat); 
     2217        /* Check if the stream is deactivated */ 
     2218        if (call_med->tp == NULL || stream == NULL) { 
     2219            const char *media_type_str; 
     2220 
     2221            switch (call_med->type) { 
     2222            case PJMEDIA_TYPE_AUDIO: 
     2223                media_type_str = "audio"; 
     2224                break; 
     2225            case PJMEDIA_TYPE_VIDEO: 
     2226                media_type_str = "video"; 
     2227                break; 
     2228            case PJMEDIA_TYPE_APPLICATION: 
     2229                media_type_str = "application"; 
     2230                break; 
     2231            default: 
     2232                media_type_str = "unknown"; 
     2233                break; 
     2234            } 
     2235            len = pj_ansi_snprintf(p, end-p, 
     2236                      "%s  #%d m=%s deactivated\n", 
     2237                      indent, i, media_type_str); 
     2238            if (len < 1 || len > end-p) { 
     2239                *p = '\0'; 
     2240                return; 
     2241            } 
     2242 
     2243            p += len; 
     2244            continue; 
     2245        } 
     2246 
     2247        pjmedia_transport_info_init(&tp_info); 
     2248        pjmedia_transport_get_info(call_med->tp, &tp_info); 
     2249 
     2250        pjmedia_stream_get_info(stream, &info); 
     2251        pjmedia_stream_get_stat(stream, &stat); 
     2252 
    22122253        // rem_addr will contain actual address of RTP originator, instead of 
    22132254        // remote RTP address specified by stream which is fetched from the SDP. 
     
    22232264        } 
    22242265 
    2225         if (call->media_dir == PJMEDIA_DIR_NONE) { 
     2266        if (call_med->dir == PJMEDIA_DIR_NONE) { 
    22262267            /* To handle when the stream that is currently being paused 
    22272268             * (http://trac.pjsip.org/repos/ticket/1079) 
    22282269             */ 
    22292270            dir = "inactive"; 
    2230         } else if (info.stream_info[i].dir == PJMEDIA_DIR_ENCODING) 
     2271        } else if (info.dir == PJMEDIA_DIR_ENCODING) 
    22312272            dir = "sendonly"; 
    2232         else if (info.stream_info[i].dir == PJMEDIA_DIR_DECODING) 
     2273        else if (info.dir == PJMEDIA_DIR_DECODING) 
    22332274            dir = "recvonly"; 
    2234         else if (info.stream_info[i].dir == PJMEDIA_DIR_ENCODING_DECODING) 
     2275        else if (info.dir == PJMEDIA_DIR_ENCODING_DECODING) 
    22352276            dir = "sendrecv"; 
    22362277        else 
     
    22382279 
    22392280         
    2240         len = pj_ansi_snprintf(buf, end-p,  
     2281        len = pj_ansi_snprintf(p, end-p, 
    22412282                  "%s  #%d %.*s @%dKHz, %s, peer=%s", 
    22422283                  indent, i, 
    2243                   (int)info.stream_info[i].fmt.encoding_name.slen, 
    2244                   info.stream_info[i].fmt.encoding_name.ptr, 
    2245                   info.stream_info[i].fmt.clock_rate / 1000, 
     2284                  (int)info.fmt.encoding_name.slen, 
     2285                  info.fmt.encoding_name.ptr, 
     2286                  info.fmt.clock_rate / 1000, 
    22462287                  dir, 
    22472288                  rem_addr); 
     
    22942335#endif 
    22952336               "%s", 
    2296                indent, info.stream_info[i].fmt.pt, 
     2337               indent, info.fmt.pt, 
    22972338               last_update, 
    22982339               indent, 
     
    23712412               "%s        jitter     : %7.3f %7.3f %7.3f %7.3f %7.3f%s", 
    23722413               indent, 
    2373                info.stream_info[i].tx_pt, 
    2374                info.stream_info[i].param->info.frm_ptime * 
    2375                 info.stream_info[i].param->setting.frm_per_pkt, 
     2414               info.tx_pt, 
     2415               info.param->info.frm_ptime * info.param->setting.frm_per_pkt, 
    23762416               last_update, 
    23772417 
     
    24162456 
    24172457        len = pj_ansi_snprintf(p, end-p, 
    2418                "%s    RTT msec       : %7.3f %7.3f %7.3f %7.3f %7.3f",  
     2458               "%s     RTT msec      : %7.3f %7.3f %7.3f %7.3f %7.3f", 
    24192459               indent, 
    24202460               stat.rtt.min / 1000.0, 
     
    24712511            } 
    24722512 
    2473             clock_rate = info.stream_info[i].fmt.clock_rate; 
     2513            clock_rate = info.fmt.clock_rate; 
    24742514 
    24752515            len = pj_ansi_snprintf(p, end-p, "\n%s  Extended reports:", indent); 
     
    29442984 
    29452985    /* Get and ICE SRTP status */ 
     2986#if DISABLED_FOR_TICKET_1185 
    29462987    pjmedia_transport_info_init(&tp_info); 
    2947     pjmedia_transport_get_info(call->med_tp, &tp_info); 
     2988    pjmedia_transport_get_info(call->tp, &tp_info); 
    29482989    if (tp_info.specific_info_cnt > 0) { 
    29492990        unsigned i; 
     
    29843025        } 
    29853026    } 
     3027#endif  /* DISABLED_FOR_TICKET_1185 */ 
    29863028 
    29873029    /* Dump session statistics */ 
    2988     if (with_media && call->session) 
     3030    if (with_media && pjsua_call_has_media(call_id)) 
    29893031        dump_media_session(indent, p, end-p, call); 
    29903032 
     
    30643106    const pjmedia_sdp_media *ref_m; 
    30653107    pjmedia_sdp_media *m; 
     3108    pjsua_call_media *call_med = &call->media[call->audio_idx]; 
    30663109    unsigned i, codec_cnt = 0; 
    30673110    pj_bool_t rem_can_update; 
     
    30983141 
    30993142    /* Verify if media is deactivated */ 
    3100     if (call->media_st == PJSUA_CALL_MEDIA_NONE || 
    3101         call->media_st == PJSUA_CALL_MEDIA_ERROR || 
    3102         call->media_dir == PJMEDIA_DIR_NONE) 
     3143    if (call_med->state == PJSUA_CALL_MEDIA_NONE || 
     3144        call_med->state == PJSUA_CALL_MEDIA_ERROR || 
     3145        call_med->dir == PJMEDIA_DIR_NONE) 
    31033146    { 
    31043147        return PJ_EINVALIDOP; 
     
    31903233    const pjmedia_sdp_media *rem_m, *loc_m; 
    31913234    unsigned codec_cnt=0, i; 
     3235    pjsua_call_media *call_med = &call->media[call->audio_idx]; 
    31923236    pj_time_val delay = {0, 0}; 
    31933237    const pj_str_t st_update = {"UPDATE", 6}; 
     
    32073251 
    32083252    /* Skip this if the media is inactive or error */ 
    3209     if (call->media_st == PJSUA_CALL_MEDIA_NONE || 
    3210         call->media_st == PJSUA_CALL_MEDIA_ERROR || 
    3211         call->media_dir == PJMEDIA_DIR_NONE) 
     3253    if (call_med->state == PJSUA_CALL_MEDIA_NONE || 
     3254        call_med->state == PJSUA_CALL_MEDIA_ERROR || 
     3255        call_med->dir == PJMEDIA_DIR_NONE) 
    32123256    { 
    32133257        return PJ_SUCCESS; 
     
    35253569 
    35263570    /* Add SDP in 488 status */ 
    3527     if (call && call->med_tp && tdata->msg->type==PJSIP_RESPONSE_MSG &&  
     3571#if DISABLED_FOR_TICKET_1185 
     3572    if (call && call->tp && tdata->msg->type==PJSIP_RESPONSE_MSG && 
    35283573        code==PJSIP_SC_NOT_ACCEPTABLE_HERE)  
    35293574    { 
     
    35403585        } 
    35413586    } 
     3587#endif 
    35423588 
    35433589    pjsip_inv_send_msg(inv, tdata); 
     
    36553701     */ 
    36563702    /* http://trac.pjsip.org/repos/ticket/880  
    3657        if (call->media_dir != PJMEDIA_DIR_ENCODING) { 
     3703       if (call->dir != PJMEDIA_DIR_ENCODING) { 
    36583704     */ 
    36593705    /* https://trac.pjsip.org/repos/ticket/1142: 
     
    36953741        pjmedia_sdp_media_remove_all_attr(m, "inactive"); 
    36963742 
    3697         if (call->media_dir & PJMEDIA_DIR_ENCODING) { 
     3743        if (call->media[call->audio_idx].dir & PJMEDIA_DIR_ENCODING) { 
    36983744            /* Add sendonly attribute */ 
    36993745            attr = pjmedia_sdp_attr_create(pool, "sendonly", NULL); 
Note: See TracChangeset for help on using the changeset viewer.