Ignore:
Timestamp:
Sep 14, 2012 4:06:29 AM (12 years ago)
Author:
nanang
Message:

Close #1568:

  • Added media change detection based on SDP negotiation result and local codec param settings, the detection result will decide whether the media should be re-initialized after the SDP negotiation.
  • Fixed stream to keep the duplicate of codec param for the stream info (was only copying the pointer).
  • Introduced macro PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO & PJSUA_THIRD_PARTY_STREAM_HAS_GET_STAT.
File:
1 edited

Legend:

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

    r4245 r4254  
    20852085 
    20862086 
     2087static void stop_media_stream(pjsua_call *call, unsigned med_idx) 
     2088{ 
     2089    pjsua_call_media *call_med = &call->media[med_idx]; 
     2090 
     2091    /* Check if stream does not exist */ 
     2092    if (med_idx >= call->med_cnt) 
     2093        return; 
     2094 
     2095    pj_log_push_indent(); 
     2096 
     2097    if (call_med->type == PJMEDIA_TYPE_AUDIO) { 
     2098        pjsua_aud_stop_stream(call_med); 
     2099    } 
     2100 
     2101#if PJMEDIA_HAS_VIDEO 
     2102    else if (call_med->type == PJMEDIA_TYPE_VIDEO) { 
     2103        pjsua_vid_stop_stream(call_med); 
     2104    } 
     2105#endif 
     2106 
     2107    PJ_LOG(4,(THIS_FILE, "Media stream call%02d:%d is destroyed", 
     2108                         call->index, med_idx)); 
     2109    call_med->prev_state = call_med->state; 
     2110    call_med->state = PJSUA_CALL_MEDIA_NONE; 
     2111 
     2112    /* Try to sync recent changes to provisional media */ 
     2113    if (med_idx < call->med_prov_cnt &&  
     2114        call->media_prov[med_idx].tp == call_med->tp) 
     2115    { 
     2116        pjsua_call_media *prov_med = &call->media_prov[med_idx]; 
     2117 
     2118        /* Media state */ 
     2119        prov_med->prev_state = call_med->prev_state; 
     2120        prov_med->state      = call_med->state; 
     2121 
     2122        /* RTP seq/ts */ 
     2123        prov_med->rtp_tx_seq_ts_set = call_med->rtp_tx_seq_ts_set; 
     2124        prov_med->rtp_tx_seq        = call_med->rtp_tx_seq; 
     2125        prov_med->rtp_tx_ts         = call_med->rtp_tx_ts; 
     2126 
     2127        /* Stream */ 
     2128        if (call_med->type == PJMEDIA_TYPE_AUDIO) { 
     2129            prov_med->strm.a.conf_slot = call_med->strm.a.conf_slot; 
     2130            prov_med->strm.a.stream    = call_med->strm.a.stream; 
     2131        } 
     2132#if PJMEDIA_HAS_VIDEO 
     2133        else if (call_med->type == PJMEDIA_TYPE_VIDEO) { 
     2134            prov_med->strm.v.cap_win_id = call_med->strm.v.cap_win_id; 
     2135            prov_med->strm.v.rdr_win_id = call_med->strm.v.rdr_win_id; 
     2136            prov_med->strm.v.stream     = call_med->strm.v.stream; 
     2137        } 
     2138#endif 
     2139    } 
     2140 
     2141    pj_log_pop_indent(); 
     2142} 
     2143 
    20872144static void stop_media_session(pjsua_call_id call_id) 
    20882145{ 
     
    20902147    unsigned mi; 
    20912148 
    2092     pj_log_push_indent(); 
    2093  
    20942149    for (mi=0; mi<call->med_cnt; ++mi) { 
    2095         pjsua_call_media *call_med = &call->media[mi]; 
    2096  
    2097         if (call_med->type == PJMEDIA_TYPE_AUDIO) { 
    2098             pjsua_aud_stop_stream(call_med); 
    2099         } 
    2100  
    2101 #if PJMEDIA_HAS_VIDEO 
    2102         else if (call_med->type == PJMEDIA_TYPE_VIDEO) { 
    2103             pjsua_vid_stop_stream(call_med); 
    2104         } 
    2105 #endif 
    2106  
    2107         PJ_LOG(4,(THIS_FILE, "Media session call%02d:%d is destroyed", 
    2108                              call_id, mi)); 
    2109         call_med->prev_state = call_med->state; 
    2110         call_med->state = PJSUA_CALL_MEDIA_NONE; 
    2111  
    2112         /* Try to sync recent changes to provisional media */ 
    2113         if (mi<call->med_prov_cnt && call->media_prov[mi].tp==call_med->tp) 
    2114         { 
    2115             pjsua_call_media *prov_med = &call->media_prov[mi]; 
    2116  
    2117             /* Media state */ 
    2118             prov_med->prev_state = call_med->prev_state; 
    2119             prov_med->state      = call_med->state; 
    2120  
    2121             /* RTP seq/ts */ 
    2122             prov_med->rtp_tx_seq_ts_set = call_med->rtp_tx_seq_ts_set; 
    2123             prov_med->rtp_tx_seq        = call_med->rtp_tx_seq; 
    2124             prov_med->rtp_tx_ts         = call_med->rtp_tx_ts; 
    2125  
    2126             /* Stream */ 
    2127             if (call_med->type == PJMEDIA_TYPE_AUDIO) { 
    2128                 prov_med->strm.a.conf_slot = call_med->strm.a.conf_slot; 
    2129                 prov_med->strm.a.stream    = call_med->strm.a.stream; 
    2130             } 
    2131 #if PJMEDIA_HAS_VIDEO 
    2132             else if (call_med->type == PJMEDIA_TYPE_VIDEO) { 
    2133                 prov_med->strm.v.cap_win_id = call_med->strm.v.cap_win_id; 
    2134                 prov_med->strm.v.rdr_win_id = call_med->strm.v.rdr_win_id; 
    2135                 prov_med->strm.v.stream     = call_med->strm.v.stream; 
    2136             } 
    2137 #endif 
    2138         } 
    2139     } 
    2140  
    2141     pj_log_pop_indent(); 
     2150        stop_media_stream(call, mi); 
     2151    } 
    21422152} 
    21432153 
     
    21872197    return PJ_SUCCESS; 
    21882198} 
     2199 
     2200 
     2201/* Match codec fmtp. This will compare the values and the order. */ 
     2202static pj_bool_t match_codec_fmtp(const pjmedia_codec_fmtp *fmtp1, 
     2203                                  const pjmedia_codec_fmtp *fmtp2) 
     2204{ 
     2205    unsigned i; 
     2206 
     2207    if (fmtp1->cnt != fmtp2->cnt) 
     2208        return PJ_FALSE; 
     2209 
     2210    for (i = 0; i < fmtp1->cnt; ++i) { 
     2211        if (pj_stricmp(&fmtp1->param[i].name, &fmtp2->param[i].name)) 
     2212            return PJ_FALSE; 
     2213        if (pj_stricmp(&fmtp1->param[i].val, &fmtp2->param[i].val)) 
     2214            return PJ_FALSE; 
     2215    } 
     2216 
     2217    return PJ_TRUE; 
     2218} 
     2219 
     2220#if PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO 
     2221 
     2222static pj_bool_t is_media_changed(const pjsua_call *call, 
     2223                                  unsigned med_idx, 
     2224                                  const pjsua_stream_info *new_si_) 
     2225{ 
     2226    const pjsua_call_media *call_med = &call->media[med_idx]; 
     2227 
     2228    /* Check for newly added media */ 
     2229    if (med_idx >= call->med_cnt) 
     2230        return PJ_TRUE; 
     2231 
     2232    /* Compare media type */ 
     2233    if (call_med->type != new_si_->type) 
     2234        return PJ_TRUE; 
     2235 
     2236    /* Audio update checks */ 
     2237    if (call_med->type == PJMEDIA_TYPE_AUDIO) { 
     2238        pjmedia_stream_info the_old_si; 
     2239        const pjmedia_stream_info *old_si = NULL; 
     2240        const pjmedia_stream_info *new_si = &new_si_->info.aud; 
     2241        const pjmedia_codec_info *old_ci = NULL; 
     2242        const pjmedia_codec_info *new_ci = &new_si->fmt; 
     2243        const pjmedia_codec_param *old_cp = NULL; 
     2244        const pjmedia_codec_param *new_cp = new_si->param; 
     2245 
     2246        /* Compare media direction */ 
     2247        if (call_med->dir != new_si->dir) 
     2248            return PJ_TRUE; 
     2249 
     2250        /* Get current active stream info */ 
     2251        if (call_med->strm.a.stream) { 
     2252            pjmedia_stream_get_info(call_med->strm.a.stream, &the_old_si); 
     2253            old_si = &the_old_si; 
     2254            old_ci = &old_si->fmt; 
     2255            old_cp = old_si->param; 
     2256        } else { 
     2257            /* The stream is inactive. */ 
     2258            return (new_si->dir != PJMEDIA_DIR_NONE); 
     2259        } 
     2260 
     2261        /* Compare remote RTP address */ 
     2262        if (pj_sockaddr_cmp(&old_si->rem_addr, &new_si->rem_addr)) 
     2263            return PJ_TRUE; 
     2264 
     2265        /* Compare codec info */ 
     2266        if (pj_stricmp(&old_ci->encoding_name, &new_ci->encoding_name) || 
     2267            old_ci->clock_rate != new_ci->clock_rate || 
     2268            old_ci->channel_cnt != new_ci->channel_cnt || 
     2269            old_si->rx_pt != new_si->rx_pt || 
     2270            old_si->tx_pt != new_si->tx_pt || 
     2271            old_si->rx_event_pt != new_si->tx_event_pt || 
     2272            old_si->tx_event_pt != new_si->tx_event_pt) 
     2273        { 
     2274            return PJ_TRUE; 
     2275        } 
     2276 
     2277        /* Compare codec param */ 
     2278        if (old_cp->setting.frm_per_pkt != new_cp->setting.frm_per_pkt || 
     2279            old_cp->setting.vad != new_cp->setting.vad || 
     2280            old_cp->setting.cng != new_cp->setting.cng || 
     2281            old_cp->setting.plc != new_cp->setting.plc || 
     2282            old_cp->setting.penh != new_cp->setting.penh || 
     2283            !match_codec_fmtp(&old_cp->setting.dec_fmtp, 
     2284                              &new_cp->setting.dec_fmtp) || 
     2285            !match_codec_fmtp(&old_cp->setting.enc_fmtp, 
     2286                              &new_cp->setting.enc_fmtp)) 
     2287        { 
     2288            return PJ_TRUE; 
     2289        } 
     2290    } 
     2291 
     2292#if PJMEDIA_HAS_VIDEO 
     2293    else if (call_med->type == PJMEDIA_TYPE_VIDEO) { 
     2294        pjmedia_vid_stream_info the_old_si; 
     2295        const pjmedia_vid_stream_info *old_si = NULL; 
     2296        const pjmedia_vid_stream_info *new_si = &new_si_->info.vid; 
     2297        const pjmedia_vid_codec_info *old_ci = NULL; 
     2298        const pjmedia_vid_codec_info *new_ci = &new_si->codec_info; 
     2299        const pjmedia_vid_codec_param *old_cp = NULL; 
     2300        const pjmedia_vid_codec_param *new_cp = new_si->codec_param; 
     2301 
     2302        /* Compare media direction */ 
     2303        if (call_med->dir != new_si->dir) 
     2304            return PJ_TRUE; 
     2305 
     2306        /* Get current active stream info */ 
     2307        if (call_med->strm.v.stream) { 
     2308            pjmedia_vid_stream_get_info(call_med->strm.v.stream, &the_old_si); 
     2309            old_si = &the_old_si; 
     2310            old_ci = &old_si->codec_info; 
     2311            old_cp = old_si->codec_param; 
     2312        } else { 
     2313            /* The stream is inactive. */ 
     2314            return (new_si->dir != PJMEDIA_DIR_NONE); 
     2315        } 
     2316 
     2317        /* Compare remote RTP address */ 
     2318        if (pj_sockaddr_cmp(&old_si->rem_addr, &new_si->rem_addr)) 
     2319            return PJ_TRUE; 
     2320 
     2321        /* Compare codec info */ 
     2322        if (pj_stricmp(&old_ci->encoding_name, &new_ci->encoding_name) || 
     2323            old_si->rx_pt != new_si->rx_pt || 
     2324            old_si->tx_pt != new_si->tx_pt) 
     2325        { 
     2326            return PJ_TRUE; 
     2327        } 
     2328 
     2329        /* Compare codec param */ 
     2330        if (/* old_cp->enc_mtu != new_cp->enc_mtu || */ 
     2331            pj_memcmp(&old_cp->enc_fmt.det, &new_cp->enc_fmt.det, 
     2332                      sizeof(pjmedia_video_format_detail)) || 
     2333            !match_codec_fmtp(&old_cp->dec_fmtp, &new_cp->dec_fmtp) || 
     2334            !match_codec_fmtp(&old_cp->enc_fmtp, &new_cp->enc_fmtp)) 
     2335        { 
     2336            return PJ_TRUE; 
     2337        } 
     2338    } 
     2339 
     2340#endif 
     2341 
     2342    else { 
     2343        /* Just return PJ_TRUE for other media type */ 
     2344        return PJ_TRUE; 
     2345    } 
     2346 
     2347    return PJ_FALSE; 
     2348} 
     2349 
     2350#else /* PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO */ 
     2351 
     2352static pj_bool_t is_media_changed(const pjsua_call *call, 
     2353                                  unsigned med_idx, 
     2354                                  const pjsua_stream_info *new_si_) 
     2355{ 
     2356    PJ_UNUSED_ARG(call); 
     2357    PJ_UNUSED_ARG(med_idx); 
     2358    PJ_UNUSED_ARG(new_si_); 
     2359    /* Always assume that media has been changed */ 
     2360    return PJ_TRUE; 
     2361} 
     2362 
     2363#endif /* PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO */ 
    21892364 
    21902365 
     
    22172392 
    22182393    /* Destroy existing media session, if any. */ 
    2219     stop_media_session(call->index); 
     2394    //stop_media_session(call->index); 
    22202395 
    22212396    /* Call media count must be at least equal to SDP media. Note that 
     
    22712446    for (mi=0; mi < call->med_prov_cnt; ++mi) { 
    22722447        pjsua_call_media *call_med = &call->media_prov[mi]; 
     2448        pj_bool_t media_changed = PJ_FALSE; 
    22732449 
    22742450        if (mi >= local_sdp->media_count || 
     
    22782454             * its re-offer. 
    22792455             */ 
     2456 
     2457            /* Stop stream */ 
     2458            stop_media_stream(call, mi); 
     2459 
     2460            /* Close the media transport */ 
    22802461            if (call_med->tp) { 
    2281                 /* Close the media transport */ 
    22822462                pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL); 
    22832463                pjmedia_transport_close(call_med->tp); 
     
    22942474        } 
    22952475 
     2476        /* Apply media update action */ 
    22962477        if (call_med->type==PJMEDIA_TYPE_AUDIO) { 
    22972478            pjmedia_stream_info the_si, *si = &the_si; 
    2298  
    2299             status = pjmedia_stream_info_from_sdp(si, tmp_pool, pjsua_var.med_endpt, 
    2300                                                   local_sdp, remote_sdp, mi); 
     2479            pjsua_stream_info stream_info; 
     2480 
     2481            status = pjmedia_stream_info_from_sdp( 
     2482                                        si, tmp_pool, pjsua_var.med_endpt, 
     2483                                        local_sdp, remote_sdp, mi); 
    23012484            if (status != PJ_SUCCESS) { 
    23022485                PJ_PERROR(1,(THIS_FILE, status, 
     
    23072490            } 
    23082491 
     2492            /* Check if this media is changed */ 
     2493            stream_info.type = PJMEDIA_TYPE_AUDIO; 
     2494            stream_info.info.aud = the_si; 
     2495            if (pjsua_var.media_cfg.no_smart_media_update || 
     2496                is_media_changed(call, mi, &stream_info)) 
     2497            { 
     2498                media_changed = PJ_TRUE; 
     2499                /* Stop the media */ 
     2500                stop_media_stream(call, mi); 
     2501            } else { 
     2502                PJ_LOG(4,(THIS_FILE, "Call %d: stream #%d (audio) unchanged.", 
     2503                          call_id, mi)); 
     2504            } 
     2505 
    23092506            /* Check if no media is active */ 
    23102507            if (si->dir == PJMEDIA_DIR_NONE) { 
     2508 
    23112509                /* Update call media state and direction */ 
    23122510                call_med->state = PJSUA_CALL_MEDIA_NONE; 
     
    23362534                    unsigned i; 
    23372535                    for (i = 0; i < tp_info.specific_info_cnt; ++i) { 
    2338                         if (tp_info.spc_info[i].type == PJMEDIA_TRANSPORT_TYPE_SRTP) 
     2536                        if (tp_info.spc_info[i].type ==  
     2537                            PJMEDIA_TRANSPORT_TYPE_SRTP) 
    23392538                        { 
    23402539                            pjmedia_srtp_info *srtp_info = 
    2341                                         (pjmedia_srtp_info*) tp_info.spc_info[i].buffer; 
     2540                                (pjmedia_srtp_info*)tp_info.spc_info[i].buffer; 
    23422541 
    23432542                            call_med->rem_srtp_use = srtp_info->peer_use; 
    23442543                            break; 
    23452544                        } 
     2545                    } 
     2546                } 
     2547 
     2548                /* Update audio channel */ 
     2549                if (media_changed) { 
     2550                    status = pjsua_aud_channel_update(call_med, 
     2551                                                      call->inv->pool, si, 
     2552                                                      local_sdp, remote_sdp); 
     2553                    if (status != PJ_SUCCESS) { 
     2554                        PJ_PERROR(1,(THIS_FILE, status, 
     2555                                     "pjsua_aud_channel_update() failed " 
     2556                                         "for call_id %d media %d", 
     2557                                     call_id, mi)); 
     2558                        continue; 
    23462559                    } 
    23472560                } 
     
    23572570                else 
    23582571                    call_med->state = PJSUA_CALL_MEDIA_ACTIVE; 
    2359             } 
    2360  
    2361             /* Call implementation */ 
    2362             status = pjsua_aud_channel_update(call_med, tmp_pool, si, 
    2363                                               local_sdp, remote_sdp); 
    2364             if (status != PJ_SUCCESS) { 
    2365                 PJ_PERROR(1,(THIS_FILE, status, 
    2366                              "pjsua_aud_channel_update() failed " 
    2367                                  "for call_id %d media %d", 
    2368                              call_id, mi)); 
    2369                 continue; 
    23702572            } 
    23712573 
     
    24142616        } else if (call_med->type==PJMEDIA_TYPE_VIDEO) { 
    24152617            pjmedia_vid_stream_info the_si, *si = &the_si; 
    2416  
    2417             status = pjmedia_vid_stream_info_from_sdp(si, tmp_pool, pjsua_var.med_endpt, 
    2418                                                       local_sdp, remote_sdp, mi); 
     2618            pjsua_stream_info stream_info; 
     2619 
     2620            status = pjmedia_vid_stream_info_from_sdp( 
     2621                                        si, tmp_pool, pjsua_var.med_endpt, 
     2622                                        local_sdp, remote_sdp, mi); 
    24192623            if (status != PJ_SUCCESS) { 
    24202624                PJ_PERROR(1,(THIS_FILE, status, 
     
    24252629            } 
    24262630 
     2631            /* Check if this media is changed */ 
     2632            stream_info.type = PJMEDIA_TYPE_VIDEO; 
     2633            stream_info.info.vid = the_si; 
     2634            if (is_media_changed(call, mi, &stream_info)) { 
     2635                media_changed = PJ_TRUE; 
     2636                /* Stop the media */ 
     2637                stop_media_stream(call, mi); 
     2638            } else { 
     2639                PJ_LOG(4,(THIS_FILE, "Call %d: stream #%d (video) unchanged.", 
     2640                          call_id, mi)); 
     2641            } 
     2642 
    24272643            /* Check if no media is active */ 
    24282644            if (si->dir == PJMEDIA_DIR_NONE) { 
     2645 
    24292646                /* Update call media state and direction */ 
    24302647                call_med->state = PJSUA_CALL_MEDIA_NONE; 
     
    24652682                } 
    24662683 
     2684                /* Update audio channel */ 
     2685                if (media_changed) { 
     2686                    status = pjsua_vid_channel_update(call_med, 
     2687                                                      call->inv->pool, si, 
     2688                                                      local_sdp, remote_sdp); 
     2689                    if (status != PJ_SUCCESS) { 
     2690                        PJ_PERROR(1,(THIS_FILE, status, 
     2691                                     "pjsua_vid_channel_update() failed " 
     2692                                         "for call_id %d media %d", 
     2693                                     call_id, mi)); 
     2694                        continue; 
     2695                    } 
     2696                } 
     2697 
    24672698                /* Call media direction */ 
    24682699                call_med->dir = si->dir; 
     
    24752706                else 
    24762707                    call_med->state = PJSUA_CALL_MEDIA_ACTIVE; 
    2477             } 
    2478  
    2479             status = pjsua_vid_channel_update(call_med, tmp_pool, si, 
    2480                                               local_sdp, remote_sdp); 
    2481             if (status != PJ_SUCCESS) { 
    2482                 PJ_PERROR(1,(THIS_FILE, status, 
    2483                              "pjsua_vid_channel_update() failed " 
    2484                                  "for call_id %d media %d", 
    2485                              call_id, mi)); 
    2486                 continue; 
    24872708            } 
    24882709 
Note: See TracChangeset for help on using the changeset viewer.