Ignore:
Timestamp:
Mar 8, 2018 2:01:26 AM (6 years ago)
Author:
ming
Message:

Fixed #865: More clever RTP transport remote address switch

The summary of changes:

  • To solve no 2:

Add callback rtp_cb2(pjmedia_tp_cb_param *param) which allows application to get more info from the media transport, such as the packet's source address.

  • To solve no 3:

Add compile time option PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR (by default enabled). Currently, there are already runtime options PJMEDIA_UDP_NO_SRC_ADDR_CHECKING and PJMEDIA_ICE_NO_SRC_ADDR_CHECKING, but there are a few drawbacks:

  • the options are not exported to the higher level, such as stream, or pjsua.
  • the options are separate for each transport, UDP and ICE, there's no single option to do this.
  • To solve no 1:

Using the new rtp_cb2() callback, move the functionality to check the packet's source address to the stream/video stream.
By checking the RTP pt and SSRC, there are a few advantages:

  • When receiving packets from multiple sources, stream can choose the packet with the correct SSRC as advertised from the SDP, and discard the others (see also ticket #1366).
  • If remote address switch is enabled, a faster switch can be achieved as soon as packet with correct ssrc is received, instead of waiting for several consecutive packets (according to setting PJMEDIA_RTP_NAT_PROBATION_CNT).
File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c

    r5750 r5752  
    5959    pj_bool_t           started;        /**< Has started?                   */ 
    6060    pj_sockaddr         rem_rtp_addr;   /**< Remote RTP address             */ 
    61     unsigned            rem_rtp_cnt;    /**< How many pkt from this addr.   */ 
    6261    pj_sockaddr         rem_rtcp_addr;  /**< Remote RTCP address            */ 
    6362    int                 addr_len;       /**< Length of addresses.           */ 
     
    6564                        void*, 
    6665                        pj_ssize_t); 
     66    void  (*rtp_cb2)(pjmedia_tp_cb_param*); /**< To report incoming RTP.    */ 
    6767    void  (*rtcp_cb)(   void*,          /**< To report incoming RTCP.       */ 
    6868                        void*, 
     
    8080    pending_write       rtp_pending_write[MAX_PENDING];  /**< Pending write */ 
    8181    pj_sockaddr         rtp_src_addr;   /**< Actual packet src addr.        */ 
    82     unsigned            rtp_src_cnt;    /**< How many pkt from this addr.   */ 
    8382    int                 rtp_addrlen;    /**< Address length.                */ 
    8483    char                rtp_pkt[RTP_LEN];/**< Incoming RTP packet buffer    */ 
     
    120119                                                       void*, 
    121120                                                       pj_ssize_t)); 
     121static pj_status_t transport_attach2  (pjmedia_transport *tp, 
     122                                       pjmedia_transport_attach_param 
     123                                           *att_param); 
    122124static void        transport_detach   (pjmedia_transport *tp, 
    123125                                       void *strm); 
     
    171173    &transport_media_stop, 
    172174    &transport_simulate_lost, 
    173     &transport_destroy 
     175    &transport_destroy, 
     176    &transport_attach2 
    174177}; 
    175178 
     
    456459    struct transport_udp *udp; 
    457460    pj_status_t status; 
     461    pj_bool_t rem_switch = PJ_FALSE; 
    458462 
    459463    PJ_UNUSED_ARG(op_key); 
     
    479483    do { 
    480484        void (*cb)(void*,void*,pj_ssize_t); 
     485        void (*cb2)(pjmedia_tp_cb_param*); 
    481486        void *user_data; 
    482487        pj_bool_t discard = PJ_FALSE; 
    483488 
    484489        cb = udp->rtp_cb; 
     490        cb2 = udp->rtp_cb2; 
    485491        user_data = udp->user_data; 
    486492 
     
    495501        } 
    496502 
    497         /* See if source address of RTP packet is different than the  
    498          * configured address, and switch RTP remote address to  
    499          * source packet address after several consecutive packets 
    500          * have been received. 
    501          */ 
    502         if (bytes_read>0 &&  
    503             (udp->options & PJMEDIA_UDP_NO_SRC_ADDR_CHECKING)==0)  
     503        //if (!discard && udp->attached && cb) 
     504        if (!discard) { 
     505            if (cb2) { 
     506                pjmedia_tp_cb_param param; 
     507 
     508                param.user_data = user_data; 
     509                param.pkt = udp->rtp_pkt; 
     510                param.size = bytes_read; 
     511                param.src_addr = &udp->rtp_src_addr; 
     512                param.rem_switch = PJ_FALSE; 
     513                (*cb2)(&param); 
     514                rem_switch = param.rem_switch; 
     515            } else if (cb) { 
     516                (*cb)(user_data, udp->rtp_pkt, bytes_read); 
     517            } 
     518        } 
     519 
     520#if defined(PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR) && \ 
     521    (PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR == 1) 
     522        if (rem_switch && 
     523            (udp->options & PJMEDIA_UDP_NO_SRC_ADDR_CHECKING)==0) 
    504524        { 
    505             if (pj_sockaddr_cmp(&udp->rem_rtp_addr, &udp->rtp_src_addr) == 0) { 
    506                 /* We're still receiving from rem_rtp_addr. Don't switch. */ 
    507                 udp->rtp_src_cnt = 0; 
    508                 udp->rem_rtp_cnt++; 
    509             } else { 
    510                 udp->rtp_src_cnt++; 
    511  
    512                 if (udp->rtp_src_cnt < PJMEDIA_RTP_NAT_PROBATION_CNT) { 
    513                     /* Only discard if we have ever received packet from 
    514                      * remote address (rem_rtp_addr). 
    515                      */ 
    516                     //discard = PJ_TRUE; 
    517                     discard = (udp->rem_rtp_cnt != 0); 
    518                 } else { 
    519                  
    520                     char addr_text[80]; 
    521  
    522                     /* Set remote RTP address to source address */ 
    523                     pj_memcpy(&udp->rem_rtp_addr, &udp->rtp_src_addr, 
    524                               sizeof(pj_sockaddr)); 
    525  
    526                     /* Reset counter */ 
    527                     udp->rtp_src_cnt = 0; 
    528  
    529                     PJ_LOG(4,(udp->base.name, 
    530                               "Remote RTP address switched to %s", 
    531                               pj_sockaddr_print(&udp->rtp_src_addr, addr_text, 
    532                                                 sizeof(addr_text), 3))); 
    533  
    534                     /* Also update remote RTCP address if actual RTCP source 
    535                      * address is not heard yet. 
    536                      */ 
    537                     if (!pj_sockaddr_has_addr(&udp->rtcp_src_addr)) { 
    538                         pj_uint16_t port; 
    539  
    540                         pj_memcpy(&udp->rem_rtcp_addr, &udp->rem_rtp_addr,  
    541                                   sizeof(pj_sockaddr)); 
    542                         pj_sockaddr_copy_addr(&udp->rem_rtcp_addr, 
    543                                               &udp->rem_rtp_addr); 
    544                         port = (pj_uint16_t) 
    545                                (pj_sockaddr_get_port(&udp->rem_rtp_addr)+1); 
    546                         pj_sockaddr_set_port(&udp->rem_rtcp_addr, port); 
    547  
    548                         pj_memcpy(&udp->rtcp_src_addr, &udp->rem_rtcp_addr,  
    549                                   sizeof(pj_sockaddr)); 
    550  
    551                         PJ_LOG(4,(udp->base.name, 
    552                                   "Remote RTCP address switched to predicted" 
    553                                   " address %s", 
    554                                   pj_sockaddr_print(&udp->rtcp_src_addr,  
    555                                                     addr_text, 
    556                                                     sizeof(addr_text), 3))); 
    557  
    558                     } 
    559                 } 
     525            char addr_text[PJ_INET6_ADDRSTRLEN+10]; 
     526 
     527            /* Set remote RTP address to source address */ 
     528            pj_sockaddr_cp(&udp->rem_rtp_addr, &udp->rtp_src_addr); 
     529 
     530            PJ_LOG(4,(udp->base.name, 
     531                      "Remote RTP address switched to %s", 
     532                      pj_sockaddr_print(&udp->rtp_src_addr, addr_text, 
     533                                        sizeof(addr_text), 3))); 
     534 
     535            /* Also update remote RTCP address if actual RTCP source 
     536             * address is not heard yet. 
     537             */ 
     538            if (!pj_sockaddr_has_addr(&udp->rtcp_src_addr)) { 
     539                pj_uint16_t port; 
     540 
     541                pj_sockaddr_cp(&udp->rem_rtcp_addr, &udp->rem_rtp_addr); 
     542                port = (pj_uint16_t) 
     543                       (pj_sockaddr_get_port(&udp->rem_rtp_addr)+1); 
     544                pj_sockaddr_set_port(&udp->rem_rtcp_addr, port); 
     545 
     546                pj_sockaddr_cp(&udp->rtcp_src_addr, &udp->rem_rtcp_addr); 
     547 
     548                PJ_LOG(4,(udp->base.name, 
     549                          "Remote RTCP address switched to predicted" 
     550                          " address %s", 
     551                          pj_sockaddr_print(&udp->rtcp_src_addr, addr_text, 
     552                                            sizeof(addr_text), 3))); 
    560553            } 
    561554        } 
    562  
    563         //if (!discard && udp->attached && cb) 
    564         if (!discard && cb) 
    565             (*cb)(user_data, udp->rtp_pkt, bytes_read); 
     555#endif 
    566556 
    567557        bytes_read = sizeof(udp->rtp_pkt); 
     
    619609            (*cb)(user_data, udp->rtcp_pkt, bytes_read); 
    620610 
     611#if defined(PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR) && \ 
     612    (PJMEDIA_TRANSPORT_SWITCH_REMOTE_ADDR == 1) 
    621613        /* Check if RTCP source address is the same as the configured 
    622614         * remote address, and switch the address when they are 
     
    633625 
    634626                if (udp->rtcp_src_cnt >= PJMEDIA_RTCP_NAT_PROBATION_CNT ) { 
    635                     char addr_text[80]; 
     627                    char addr_text[PJ_INET6_ADDRSTRLEN+10]; 
    636628 
    637629                    udp->rtcp_src_cnt = 0; 
     
    646638            } 
    647639        } 
     640#endif 
    648641 
    649642        bytes_read = sizeof(udp->rtcp_pkt); 
     
    681674 
    682675 
    683 /* Called by application to initialize the transport */ 
    684 static pj_status_t transport_attach(   pjmedia_transport *tp, 
     676static pj_status_t tp_attach          (pjmedia_transport *tp, 
    685677                                       void *user_data, 
    686678                                       const pj_sockaddr_t *rem_addr, 
     
    690682                                                      void*, 
    691683                                                      pj_ssize_t), 
     684                                       void (*rtp_cb2)(pjmedia_tp_cb_param*), 
    692685                                       void (*rtcp_cb)(void*, 
    693686                                                       void*, 
     
    751744    /* Save the callbacks */ 
    752745    udp->rtp_cb = rtp_cb; 
     746    udp->rtp_cb2 = rtp_cb2; 
    753747    udp->rtcp_cb = rtcp_cb; 
    754748    udp->user_data = user_data; 
     
    763757    pj_bzero(&udp->rtp_src_addr, sizeof(udp->rtp_src_addr)); 
    764758    pj_bzero(&udp->rtcp_src_addr, sizeof(udp->rtcp_src_addr)); 
    765     udp->rtp_src_cnt = 0; 
    766759    udp->rtcp_src_cnt = 0; 
    767     udp->rem_rtp_cnt = 0; 
    768760 
    769761    /* Set buffer size for RTP socket */ 
     
    817809 
    818810 
     811/* Called by application to initialize the transport */ 
     812static pj_status_t transport_attach(   pjmedia_transport *tp, 
     813                                       void *user_data, 
     814                                       const pj_sockaddr_t *rem_addr, 
     815                                       const pj_sockaddr_t *rem_rtcp, 
     816                                       unsigned addr_len, 
     817                                       void (*rtp_cb)(void*, 
     818                                                      void*, 
     819                                                      pj_ssize_t), 
     820                                       void (*rtcp_cb)(void*, 
     821                                                       void*, 
     822                                                       pj_ssize_t)) 
     823{ 
     824    return tp_attach(tp, user_data, rem_addr, rem_rtcp, addr_len, 
     825                     rtp_cb, NULL, rtcp_cb); 
     826} 
     827 
     828 
     829static pj_status_t transport_attach2(pjmedia_transport *tp, 
     830                                     pjmedia_transport_attach_param *att_param) 
     831{ 
     832    return tp_attach(tp, att_param->user_data,  
     833                            (pj_sockaddr_t*)&att_param->rem_addr,  
     834                            (pj_sockaddr_t*)&att_param->rem_rtcp,  
     835                            att_param->addr_len, att_param->rtp_cb, 
     836                            att_param->rtp_cb2,  
     837                            att_param->rtcp_cb); 
     838} 
     839 
     840 
    819841/* Called by application when it no longer needs the transport */ 
    820842static void transport_detach( pjmedia_transport *tp, 
     
    846868        /* Clear up application infos from transport */ 
    847869        udp->rtp_cb = NULL; 
     870        udp->rtp_cb2 = NULL; 
    848871        udp->rtcp_cb = NULL; 
    849872        udp->user_data = NULL; 
Note: See TracChangeset for help on using the changeset viewer.