Changeset 3960


Ignore:
Timestamp:
Feb 27, 2012 2:41:21 PM (12 years ago)
Author:
nanang
Message:

Fix #1440: Send and parse RTCP compound packet, containing report (RR/SR/XR), SDES, and BYE.

Location:
pjproject/branches/1.x/pjmedia
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/1.x/pjmedia/include/pjmedia/config.h

    r3907 r3960  
    490490 * PJMEDIA_STREAM_ENABLE_XR setting for more info. 
    491491 * 
    492  * Default: 1 (yes). 
     492 * Default: 0 (no). 
    493493 */ 
    494494#ifndef PJMEDIA_HAS_RTCP_XR 
     
    507507#   define PJMEDIA_STREAM_ENABLE_XR             0 
    508508#endif 
     509 
     510 
     511/** 
     512 * Specify the buffer length for storing any received RTCP SDES text 
     513 * in a stream session. Usually RTCP contains only the mandatory SDES 
     514 * field, i.e: CNAME. 
     515 *  
     516 * Default: 64 bytes. 
     517 */ 
     518#ifndef PJMEDIA_RTCP_RX_SDES_BUF_LEN 
     519#   define PJMEDIA_RTCP_RX_SDES_BUF_LEN         64 
     520#endif 
     521 
    509522 
    510523/** 
  • pjproject/branches/1.x/pjmedia/include/pjmedia/rtcp.h

    r3553 r3960  
    5555 */ 
    5656 
     57  
    5758#pragma pack(1) 
    5859 
     
    6061 * RTCP sender report. 
    6162 */ 
    62 struct pjmedia_rtcp_sr 
     63typedef struct pjmedia_rtcp_sr 
    6364{ 
    6465    pj_uint32_t     ntp_sec;        /**< NTP time, seconds part.        */ 
     
    6768    pj_uint32_t     sender_pcount;  /**< Sender packet cound.           */ 
    6869    pj_uint32_t     sender_bcount;  /**< Sender octet/bytes count.      */ 
    69 }; 
    70  
    71 /** 
    72  * @see pjmedia_rtcp_sr 
    73  */ 
    74 typedef struct pjmedia_rtcp_sr pjmedia_rtcp_sr; 
     70} pjmedia_rtcp_sr; 
     71 
    7572 
    7673/** 
    7774 * RTCP receiver report. 
    7875 */ 
    79 struct pjmedia_rtcp_rr 
     76typedef struct pjmedia_rtcp_rr 
    8077{ 
    8178    pj_uint32_t     ssrc;           /**< SSRC identification.           */ 
     
    9592    pj_uint32_t     lsr;            /**< Last SR.                       */ 
    9693    pj_uint32_t     dlsr;           /**< Delay since last SR.           */ 
    97 }; 
    98  
    99 /** 
    100  * @see pjmedia_rtcp_rr 
    101  */ 
    102 typedef struct pjmedia_rtcp_rr pjmedia_rtcp_rr; 
     94} pjmedia_rtcp_rr; 
    10395 
    10496 
     
    10698 * RTCP common header. 
    10799 */ 
    108 struct pjmedia_rtcp_common 
     100typedef struct pjmedia_rtcp_common 
    109101{ 
    110102#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0 
     
    121113    unsigned        length:16;  /**< packet length          */ 
    122114    pj_uint32_t     ssrc;       /**< SSRC identification    */ 
    123 }; 
    124  
    125 /** 
    126  * @see pjmedia_rtcp_common 
    127  */ 
    128 typedef struct pjmedia_rtcp_common pjmedia_rtcp_common; 
     115} pjmedia_rtcp_common; 
     116 
    129117 
    130118/** 
     
    154142 
    155143/** 
     144 * RTCP SDES structure. 
     145 */ 
     146typedef struct pjmedia_rtcp_sdes 
     147{ 
     148    pj_str_t    cname;          /**< RTCP SDES type CNAME.      */ 
     149    pj_str_t    name;           /**< RTCP SDES type NAME.       */ 
     150    pj_str_t    email;          /**< RTCP SDES type EMAIL.      */ 
     151    pj_str_t    phone;          /**< RTCP SDES type PHONE.      */ 
     152    pj_str_t    loc;            /**< RTCP SDES type LOC.        */ 
     153    pj_str_t    tool;           /**< RTCP SDES type TOOL.       */ 
     154    pj_str_t    note;           /**< RTCP SDES type NOTE.       */ 
     155} pjmedia_rtcp_sdes; 
     156 
     157 
     158/** 
    156159 * NTP time representation. 
    157160 */ 
    158 struct pjmedia_rtcp_ntp_rec 
     161typedef struct pjmedia_rtcp_ntp_rec 
    159162{ 
    160163    pj_uint32_t     hi;         /**< High order 32-bit part.    */ 
    161164    pj_uint32_t     lo;         /**< Lo order 32-bit part.      */ 
    162 }; 
    163  
    164 /** 
    165  * @see pjmedia_rtcp_ntp_rec 
    166  */ 
    167 typedef struct pjmedia_rtcp_ntp_rec pjmedia_rtcp_ntp_rec; 
    168  
     165} pjmedia_rtcp_ntp_rec; 
    169166 
    170167 
     
    172169 * Unidirectional RTP stream statistics. 
    173170 */ 
    174 struct pjmedia_rtcp_stream_stat 
     171typedef struct pjmedia_rtcp_stream_stat 
    175172{ 
    176173    pj_time_val     update;     /**< Time of last update.                   */ 
     
    191188 
    192189    pj_math_stat    jitter;     /**< Jitter statistics (in usec)            */ 
    193 }; 
    194  
    195  
    196 /** 
    197  * @see pjmedia_rtcp_stream_stat 
    198  */ 
    199 typedef struct pjmedia_rtcp_stream_stat pjmedia_rtcp_stream_stat; 
    200  
     190 
     191} pjmedia_rtcp_stream_stat; 
    201192 
    202193 
     
    204195 * Bidirectional RTP stream statistics. 
    205196 */ 
    206 struct pjmedia_rtcp_stat 
     197typedef struct pjmedia_rtcp_stat 
    207198{ 
    208199    pj_time_val              start; /**< Time when session was created      */ 
     
    227218                                                (in usec).                  */ 
    228219#endif 
    229 }; 
    230  
    231  
    232 /** 
    233  * @see pjmedia_rtcp_stat 
    234  */ 
    235 typedef struct pjmedia_rtcp_stat pjmedia_rtcp_stat; 
     220 
     221    pjmedia_rtcp_sdes        peer_sdes; /**< Peer SDES.                     */ 
     222    char                     peer_sdes_buf_[PJMEDIA_RTCP_RX_SDES_BUF_LEN]; 
     223                                        /**< Peer SDES buffer.              */ 
     224 
     225} pjmedia_rtcp_stat; 
    236226 
    237227 
     
    240230 * should only be one RTCP session for a bidirectional RTP streams. 
    241231 */ 
    242 struct pjmedia_rtcp_session 
     232typedef struct pjmedia_rtcp_session 
    243233{ 
    244234    char                   *name;       /**< Name identification.           */ 
     
    279269    pjmedia_rtcp_xr_session xr_session; 
    280270#endif 
    281 }; 
    282  
    283 /** 
    284  * @see pjmedia_rtcp_session 
    285  */ 
    286 typedef struct pjmedia_rtcp_session pjmedia_rtcp_session; 
     271} pjmedia_rtcp_session; 
    287272 
    288273 
     
    440425 
    441426/** 
     427 * Build an RTCP SDES (source description) packet. This packet can be 
     428 * appended to other RTCP packets, e.g: RTCP RR/SR, to compose a compound 
     429 * RTCP packet. 
     430 * 
     431 * @param session   The RTCP session. 
     432 * @param buf       The buffer to receive RTCP SDES packet. 
     433 * @param length    On input, it will contain the buffer length. 
     434 *                  On output, it will contain the generated RTCP SDES 
     435 *                  packet length. 
     436 * @param sdes      The source description, see #pjmedia_rtcp_sdes. 
     437 * 
     438 * @return          PJ_SUCCESS on success. 
     439 */ 
     440PJ_DECL(pj_status_t) pjmedia_rtcp_build_rtcp_sdes( 
     441                                            pjmedia_rtcp_session *session,  
     442                                            void *buf, 
     443                                            pj_size_t *length, 
     444                                            const pjmedia_rtcp_sdes *sdes); 
     445 
     446/** 
     447 * Build an RTCP BYE packet. This packet can be appended to other RTCP 
     448 * packets, e.g: RTCP RR/SR, to compose a compound RTCP packet. 
     449 * 
     450 * @param session   The RTCP session. 
     451 * @param buf       The buffer to receive RTCP BYE packet. 
     452 * @param length    On input, it will contain the buffer length. 
     453 *                  On output, it will contain the generated RTCP BYE 
     454 *                  packet length. 
     455 * @param reason    Optional, the BYE reason. 
     456 * 
     457 * @return          PJ_SUCCESS on success. 
     458 */ 
     459PJ_DECL(pj_status_t) pjmedia_rtcp_build_rtcp_bye( 
     460                                            pjmedia_rtcp_session *session,  
     461                                            void *buf, 
     462                                            pj_size_t *length, 
     463                                            const pj_str_t *reason); 
     464 
     465 
     466/** 
    442467 * Call this function if RTCP XR needs to be enabled/disabled in the  
    443468 * RTCP session. 
  • pjproject/branches/1.x/pjmedia/src/pjmedia/rtcp.c

    r3907 r3960  
    3030#define RTCP_SR   200 
    3131#define RTCP_RR   201 
     32#define RTCP_SDES 202 
     33#define RTCP_BYE  203 
    3234#define RTCP_XR   207 
     35 
     36enum { 
     37    RTCP_SDES_NULL  = 0, 
     38    RTCP_SDES_CNAME = 1, 
     39    RTCP_SDES_NAME  = 2, 
     40    RTCP_SDES_EMAIL = 3, 
     41    RTCP_SDES_PHONE = 4, 
     42    RTCP_SDES_LOC   = 5, 
     43    RTCP_SDES_TOOL  = 6, 
     44    RTCP_SDES_NOTE  = 7 
     45}; 
    3346 
    3447#if PJ_HAS_HIGH_RES_TIMER==0 
     
    474487 
    475488 
    476 PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess, 
    477                                    const void *pkt, 
    478                                    pj_size_t size) 
     489static void parse_rtcp_report( pjmedia_rtcp_session *sess, 
     490                               const void *pkt, 
     491                               pj_size_t size) 
    479492{ 
    480493    pjmedia_rtcp_common *common = (pjmedia_rtcp_common*) pkt; 
     
    653666 
    654667 
     668static void parse_rtcp_sdes(pjmedia_rtcp_session *sess, 
     669                            const void *pkt, 
     670                            pj_size_t size) 
     671{ 
     672    pjmedia_rtcp_sdes *sdes = &sess->stat.peer_sdes; 
     673    char *p, *p_end; 
     674    char *b, *b_end; 
     675 
     676    p = (char*)pkt + 8; 
     677    p_end = (char*)pkt + size; 
     678 
     679    pj_bzero(sdes, sizeof(*sdes)); 
     680    b = sess->stat.peer_sdes_buf_; 
     681    b_end = b + sizeof(sess->stat.peer_sdes_buf_); 
     682 
     683    while (p < p_end) { 
     684        pj_uint8_t sdes_type, sdes_len; 
     685        pj_str_t sdes_value = {NULL, 0}; 
     686 
     687        sdes_type = *p++; 
     688 
     689        /* Check for end of SDES item list */ 
     690        if (sdes_type == RTCP_SDES_NULL || p == p_end) 
     691            break; 
     692 
     693        sdes_len = *p++; 
     694 
     695        /* Check for corrupted SDES packet */ 
     696        if (p + sdes_len > p_end) 
     697            break; 
     698 
     699        /* Get SDES item */ 
     700        if (b + sdes_len < b_end) { 
     701            pj_memcpy(b, p, sdes_len); 
     702            sdes_value.ptr = b; 
     703            sdes_value.slen = sdes_len; 
     704            b += sdes_len; 
     705        } else { 
     706            /* Insufficient SDES buffer */ 
     707            PJ_LOG(5, (sess->name, 
     708                    "Unsufficient buffer to save RTCP SDES type %d:%.*s", 
     709                    sdes_type, sdes_len, p)); 
     710            p += sdes_len; 
     711            continue; 
     712        } 
     713 
     714        switch (sdes_type) { 
     715        case RTCP_SDES_CNAME: 
     716            sdes->cname = sdes_value; 
     717            break; 
     718        case RTCP_SDES_NAME: 
     719            sdes->name = sdes_value; 
     720            break; 
     721        case RTCP_SDES_EMAIL: 
     722            sdes->email = sdes_value; 
     723            break; 
     724        case RTCP_SDES_PHONE: 
     725            sdes->phone = sdes_value; 
     726            break; 
     727        case RTCP_SDES_LOC: 
     728            sdes->loc = sdes_value; 
     729            break; 
     730        case RTCP_SDES_TOOL: 
     731            sdes->tool = sdes_value; 
     732            break; 
     733        case RTCP_SDES_NOTE: 
     734            sdes->note = sdes_value; 
     735            break; 
     736        default: 
     737            TRACE_((sess->name, "Received unknown RTCP SDES type %d:%.*s", 
     738                    sdes_type, sdes_value.slen, sdes_value.ptr)); 
     739            break; 
     740        } 
     741 
     742        p += sdes_len; 
     743    } 
     744} 
     745 
     746 
     747static void parse_rtcp_bye(pjmedia_rtcp_session *sess, 
     748                           const void *pkt, 
     749                           pj_size_t size) 
     750{ 
     751    pj_str_t reason = {"-", 1}; 
     752 
     753    /* Check and get BYE reason */ 
     754    if (size > 8) { 
     755        reason.slen = *((pj_uint8_t*)pkt+8); 
     756        pj_memcpy(sess->stat.peer_sdes_buf_, ((pj_uint8_t*)pkt+9), 
     757                  reason.slen); 
     758        reason.ptr = sess->stat.peer_sdes_buf_; 
     759    } 
     760 
     761    /* Just print RTCP BYE log */ 
     762    PJ_LOG(5, (sess->name, "Received RTCP BYE, reason: %.*s", 
     763               reason.slen, reason.ptr)); 
     764} 
     765 
     766 
     767PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess, 
     768                                   const void *pkt, 
     769                                   pj_size_t size) 
     770{ 
     771    pj_uint8_t *p, *p_end; 
     772 
     773    p = (pj_uint8_t*)pkt; 
     774    p_end = p + size; 
     775    while (p < p_end) { 
     776        pjmedia_rtcp_common *common = (pjmedia_rtcp_common*)p; 
     777        unsigned len; 
     778 
     779        len = (pj_ntohs((pj_uint16_t)common->length)+1) * 4; 
     780        switch(common->pt) { 
     781        case RTCP_SR: 
     782        case RTCP_RR: 
     783        case RTCP_XR: 
     784            parse_rtcp_report(sess, p, len); 
     785            break; 
     786        case RTCP_SDES: 
     787            parse_rtcp_sdes(sess, p, len); 
     788            break; 
     789        case RTCP_BYE: 
     790            parse_rtcp_bye(sess, p, len); 
     791            break; 
     792        default: 
     793            /* Ignore unknown RTCP */ 
     794            TRACE_((sess->name, "Received unknown RTCP packet type=%d", 
     795                    common->pt)); 
     796            break; 
     797        } 
     798 
     799        p += len; 
     800    } 
     801} 
     802 
     803 
    655804PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *sess,  
    656805                                     void **ret_p_pkt, int *len) 
     
    805954} 
    806955 
     956 
     957PJ_DEF(pj_status_t) pjmedia_rtcp_build_rtcp_sdes( 
     958                                            pjmedia_rtcp_session *session,  
     959                                            void *buf, 
     960                                            pj_size_t *length, 
     961                                            const pjmedia_rtcp_sdes *sdes) 
     962{ 
     963    pjmedia_rtcp_common *hdr; 
     964    pj_uint8_t *p; 
     965    unsigned len; 
     966 
     967    PJ_ASSERT_RETURN(session && buf && length && sdes, PJ_EINVAL); 
     968 
     969    /* Verify SDES item length */ 
     970    if (sdes->cname.slen > 255 || sdes->name.slen  > 255 || 
     971        sdes->email.slen > 255 || sdes->phone.slen > 255 || 
     972        sdes->loc.slen   > 255 || sdes->tool.slen  > 255 || 
     973        sdes->note.slen  > 255) 
     974    { 
     975        return PJ_EINVAL; 
     976    } 
     977 
     978    /* Verify buffer length */ 
     979    len = sizeof(*hdr); 
     980    if (sdes->cname.slen) len += sdes->cname.slen + 2; 
     981    if (sdes->name.slen)  len += sdes->name.slen  + 2; 
     982    if (sdes->email.slen) len += sdes->email.slen + 2; 
     983    if (sdes->phone.slen) len += sdes->phone.slen + 2; 
     984    if (sdes->loc.slen)   len += sdes->loc.slen   + 2; 
     985    if (sdes->tool.slen)  len += sdes->tool.slen  + 2; 
     986    if (sdes->note.slen)  len += sdes->note.slen  + 2; 
     987    len++; /* null termination */ 
     988    len = ((len+3)/4) * 4; 
     989    if (len > *length) 
     990        return PJ_ETOOSMALL; 
     991 
     992    /* Build RTCP SDES header */ 
     993    hdr = (pjmedia_rtcp_common*)buf; 
     994    pj_memcpy(hdr, &session->rtcp_sr_pkt.common,  sizeof(*hdr)); 
     995    hdr->pt = RTCP_SDES; 
     996    hdr->length = pj_htons((pj_uint16_t)(len/4 - 1)); 
     997 
     998    /* Build RTCP SDES items */ 
     999    p = (pj_uint8_t*)hdr + sizeof(*hdr); 
     1000#define BUILD_SDES_ITEM(SDES_NAME, SDES_TYPE) \ 
     1001    if (sdes->SDES_NAME.slen) { \ 
     1002        *p++ = SDES_TYPE; \ 
     1003        *p++ = (pj_uint8_t)sdes->SDES_NAME.slen; \ 
     1004        pj_memcpy(p, sdes->SDES_NAME.ptr, sdes->SDES_NAME.slen); \ 
     1005        p += sdes->SDES_NAME.slen; \ 
     1006    } 
     1007    BUILD_SDES_ITEM(cname, RTCP_SDES_CNAME); 
     1008    BUILD_SDES_ITEM(name,  RTCP_SDES_NAME); 
     1009    BUILD_SDES_ITEM(email, RTCP_SDES_EMAIL); 
     1010    BUILD_SDES_ITEM(phone, RTCP_SDES_PHONE); 
     1011    BUILD_SDES_ITEM(loc,   RTCP_SDES_LOC); 
     1012    BUILD_SDES_ITEM(tool,  RTCP_SDES_TOOL); 
     1013    BUILD_SDES_ITEM(note,  RTCP_SDES_NOTE); 
     1014#undef BUILD_SDES_ITEM 
     1015 
     1016    /* Null termination */ 
     1017    *p++ = 0; 
     1018 
     1019    /* Pad to 32bit */ 
     1020    while ((p-(pj_uint8_t*)buf) % 4) 
     1021        *p++ = 0; 
     1022 
     1023    /* Finally */ 
     1024    pj_assert((int)len == p-(pj_uint8_t*)buf); 
     1025    *length = len; 
     1026 
     1027    return PJ_SUCCESS; 
     1028} 
     1029 
     1030 
     1031PJ_DEF(pj_status_t) pjmedia_rtcp_build_rtcp_bye(pjmedia_rtcp_session *session, 
     1032                                                void *buf, 
     1033                                                pj_size_t *length, 
     1034                                                const pj_str_t *reason) 
     1035{ 
     1036    pjmedia_rtcp_common *hdr; 
     1037    pj_uint8_t *p; 
     1038    unsigned len; 
     1039 
     1040    PJ_ASSERT_RETURN(session && buf && length, PJ_EINVAL); 
     1041 
     1042    /* Verify BYE reason length */ 
     1043    if (reason && reason->slen > 255) 
     1044        return PJ_EINVAL; 
     1045 
     1046    /* Verify buffer length */ 
     1047    len = sizeof(*hdr); 
     1048    if (reason && reason->slen) len += reason->slen + 1; 
     1049    len = ((len+3)/4) * 4; 
     1050    if (len > *length) 
     1051        return PJ_ETOOSMALL; 
     1052 
     1053    /* Build RTCP BYE header */ 
     1054    hdr = (pjmedia_rtcp_common*)buf; 
     1055    pj_memcpy(hdr, &session->rtcp_sr_pkt.common,  sizeof(*hdr)); 
     1056    hdr->pt = RTCP_BYE; 
     1057    hdr->length = pj_htons((pj_uint16_t)(len/4 - 1)); 
     1058 
     1059    /* Write RTCP BYE reason */ 
     1060    p = (pj_uint8_t*)hdr + sizeof(*hdr); 
     1061    if (reason && reason->slen) { 
     1062        *p++ = (pj_uint8_t)reason->slen; 
     1063        pj_memcpy(p, reason->ptr, reason->slen); 
     1064        p += reason->slen; 
     1065    } 
     1066 
     1067    /* Pad to 32bit */ 
     1068    while ((p-(pj_uint8_t*)buf) % 4) 
     1069        *p++ = 0; 
     1070 
     1071    pj_assert((int)len == p-(pj_uint8_t*)buf); 
     1072    *length = len; 
     1073 
     1074    return PJ_SUCCESS; 
     1075} 
     1076 
     1077 
    8071078PJ_DEF(pj_status_t) pjmedia_rtcp_enable_xr( pjmedia_rtcp_session *sess,  
    8081079                                            pj_bool_t enable) 
  • pjproject/branches/1.x/pjmedia/src/pjmedia/stream.c

    r3900 r3960  
    235235 
    236236 
     237static pj_status_t send_rtcp(pjmedia_stream *stream, 
     238                             pj_bool_t with_sdes, 
     239                             pj_bool_t with_bye, 
     240                             pj_bool_t with_xr); 
     241 
     242 
    237243#if TRACE_JB 
    238244 
     
    415421 
    416422    /* Send RTCP */ 
    417     pjmedia_rtcp_build_rtcp(&stream->rtcp, &pkt, &pkt_len); 
    418     pjmedia_transport_send_rtcp(stream->transport, pkt, pkt_len); 
     423    send_rtcp(stream, PJ_TRUE, PJ_FALSE, PJ_FALSE); 
    419424 
    420425#elif PJMEDIA_STREAM_ENABLE_KA == PJMEDIA_STREAM_KA_USER 
     
    904909 
    905910 
     911static pj_status_t send_rtcp(pjmedia_stream *stream, 
     912                             pj_bool_t with_sdes, 
     913                             pj_bool_t with_bye, 
     914                             pj_bool_t with_xr) 
     915{ 
     916    void *sr_rr_pkt; 
     917    pj_uint8_t *pkt; 
     918    int len, max_len; 
     919    pj_status_t status; 
     920 
     921    /* Build RTCP RR/SR packet */ 
     922    pjmedia_rtcp_build_rtcp(&stream->rtcp, &sr_rr_pkt, &len); 
     923 
     924#if !defined(PJMEDIA_HAS_RTCP_XR) || (PJMEDIA_HAS_RTCP_XR == 0) 
     925    with_xr = PJ_FALSE; 
     926#endif 
     927 
     928    if (with_sdes || with_bye || with_xr) { 
     929        pkt = (pj_uint8_t*) stream->enc->out_pkt; 
     930        pj_memcpy(pkt, sr_rr_pkt, len); 
     931        max_len = stream->enc->out_pkt_size; 
     932    } else { 
     933        pkt = sr_rr_pkt; 
     934        max_len = len; 
     935    } 
     936 
     937    /* Build RTCP SDES packet */ 
     938    if (with_sdes) { 
     939        pjmedia_rtcp_sdes sdes; 
     940        unsigned sdes_len; 
     941 
     942        pj_bzero(&sdes, sizeof(sdes)); 
     943        sdes.cname = stream->cname; 
     944        sdes_len = max_len - len; 
     945        status = pjmedia_rtcp_build_rtcp_sdes(&stream->rtcp, pkt+len, 
     946                                              &sdes_len, &sdes); 
     947        if (status != PJ_SUCCESS) { 
     948            PJ_PERROR(4,(stream->port.info.name.ptr, status, 
     949                                     "Error generating RTCP SDES")); 
     950        } else { 
     951            len += sdes_len; 
     952        } 
     953    } 
     954 
     955    /* Build RTCP XR packet */ 
     956#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
     957    if (with_xr) { 
     958        int i; 
     959        pjmedia_jb_state jb_state; 
     960        void *xr_pkt; 
     961        int xr_len; 
     962 
     963        /* Update RTCP XR with current JB states */ 
     964        pjmedia_jbuf_get_state(stream->jb, &jb_state); 
     965             
     966        i = jb_state.avg_delay; 
     967        status = pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,  
     968                                             PJMEDIA_RTCP_XR_INFO_JB_NOM, i); 
     969        pj_assert(status == PJ_SUCCESS); 
     970 
     971        i = jb_state.max_delay; 
     972        status = pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,  
     973                                             PJMEDIA_RTCP_XR_INFO_JB_MAX, i); 
     974        pj_assert(status == PJ_SUCCESS); 
     975 
     976        pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0, 
     977                                   &xr_pkt, &xr_len); 
     978 
     979        if (xr_len + len <= max_len) { 
     980            pj_memcpy(pkt+len, xr_pkt, xr_len); 
     981            len += xr_len; 
     982 
     983            /* Send the RTCP XR to third-party destination if specified */ 
     984            if (stream->rtcp_xr_dest_len) { 
     985                pjmedia_transport_send_rtcp2(stream->transport,  
     986                                             &stream->rtcp_xr_dest, 
     987                                             stream->rtcp_xr_dest_len,  
     988                                             xr_pkt, xr_len); 
     989            } 
     990 
     991        } else { 
     992            PJ_PERROR(4,(stream->port.info.name.ptr, PJ_ETOOBIG, 
     993                         "Error generating RTCP-XR")); 
     994        } 
     995    } 
     996#endif 
     997 
     998    /* Build RTCP BYE packet */ 
     999    if (with_bye) { 
     1000        unsigned bye_len; 
     1001 
     1002        bye_len = max_len - len; 
     1003        status = pjmedia_rtcp_build_rtcp_bye(&stream->rtcp, pkt+len, 
     1004                                             &bye_len, NULL); 
     1005        if (status != PJ_SUCCESS) { 
     1006            PJ_PERROR(4,(stream->port.info.name.ptr, status, 
     1007                                     "Error generating RTCP BYE")); 
     1008        } else { 
     1009            len += bye_len; 
     1010        } 
     1011    } 
     1012 
     1013    /* Send! */ 
     1014    status = pjmedia_transport_send_rtcp(stream->transport, pkt, len); 
     1015 
     1016    return status; 
     1017} 
     1018 
    9061019/** 
    9071020 * check_tx_rtcp() 
     
    9171030     */ 
    9181031 
    919  
    9201032    if (stream->rtcp_last_tx == 0) { 
    9211033         
     
    9231035 
    9241036    } else if (timestamp - stream->rtcp_last_tx >= stream->rtcp_interval) { 
    925          
    926         void *rtcp_pkt; 
    927         int len; 
     1037        pj_bool_t with_xr = PJ_FALSE; 
    9281038        pj_status_t status; 
    9291039 
    930         pjmedia_rtcp_build_rtcp(&stream->rtcp, &rtcp_pkt, &len); 
    931  
    932         status=pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len); 
     1040#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
     1041        if (stream->rtcp.xr_enabled) { 
     1042            if (stream->rtcp_xr_last_tx == 0) { 
     1043                stream->rtcp_xr_last_tx = timestamp; 
     1044            } else if (timestamp - stream->rtcp_xr_last_tx >=  
     1045                       stream->rtcp_xr_interval) 
     1046            { 
     1047                with_xr = PJ_TRUE; 
     1048 
     1049                /* Update last tx RTCP XR */ 
     1050                stream->rtcp_xr_last_tx = timestamp; 
     1051            } 
     1052        } 
     1053#endif 
     1054 
     1055        status = send_rtcp(stream, !stream->rtcp_sdes_bye_disabled, PJ_FALSE, 
     1056                           with_xr); 
    9331057        if (status != PJ_SUCCESS) { 
    9341058            PJ_PERROR(4,(stream->port.info.name.ptr, status, 
    935                         "Error sending RTCP")); 
     1059                        "Error sending RTCP")); 
    9361060        } 
    9371061 
    9381062        stream->rtcp_last_tx = timestamp; 
    9391063    } 
    940  
    941 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
    942     if (stream->rtcp.xr_enabled) { 
    943  
    944         if (stream->rtcp_xr_last_tx == 0) { 
    945          
    946             stream->rtcp_xr_last_tx = timestamp; 
    947  
    948         } else if (timestamp - stream->rtcp_xr_last_tx >=  
    949                    stream->rtcp_xr_interval) 
    950         { 
    951             int i; 
    952             pjmedia_jb_state jb_state; 
    953             void *rtcp_pkt; 
    954             int len; 
    955  
    956             /* Update RTCP XR with current JB states */ 
    957             pjmedia_jbuf_get_state(stream->jb, &jb_state); 
    958              
    959             i = jb_state.avg_delay; 
    960             pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,  
    961                                         PJMEDIA_RTCP_XR_INFO_JB_NOM, 
    962                                         i); 
    963  
    964             i = jb_state.max_delay; 
    965             pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,  
    966                                         PJMEDIA_RTCP_XR_INFO_JB_MAX, 
    967                                         i); 
    968  
    969             /* Build RTCP XR packet */ 
    970             pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0,  
    971                                        &rtcp_pkt, &len); 
    972  
    973             /* Send the RTCP XR to remote address */ 
    974             pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len); 
    975  
    976             /* Send the RTCP XR to third-party destination if specified */ 
    977             if (stream->rtcp_xr_dest_len) { 
    978                 pjmedia_transport_send_rtcp2(stream->transport,  
    979                                              &stream->rtcp_xr_dest, 
    980                                              stream->rtcp_xr_dest_len,  
    981                                              rtcp_pkt, len); 
    982             } 
    983  
    984             /* Update last tx RTCP XR */ 
    985             stream->rtcp_xr_last_tx = timestamp; 
    986         } 
    987     } 
    988 #endif 
    989 } 
    990  
    991 /* Build RTCP SDES packet */ 
    992 static unsigned create_rtcp_sdes(pjmedia_stream *stream, pj_uint8_t *pkt, 
    993                                  unsigned max_len) 
    994 { 
    995     pjmedia_rtcp_common hdr; 
    996     pj_uint8_t *p = pkt; 
    997  
    998     /* SDES header */ 
    999     hdr.version = 2; 
    1000     hdr.p = 0; 
    1001     hdr.count = 1; 
    1002     hdr.pt = 202; 
    1003     hdr.length = 2 + (4+stream->cname.slen+3)/4 - 1; 
    1004     if (max_len < (hdr.length << 2)) { 
    1005         pj_assert(!"Not enough buffer for SDES packet"); 
    1006         return 0; 
    1007     } 
    1008     hdr.length = pj_htons((pj_uint16_t)hdr.length); 
    1009     hdr.ssrc = stream->enc->rtp.out_hdr.ssrc; 
    1010     pj_memcpy(p, &hdr, sizeof(hdr)); 
    1011     p += sizeof(hdr); 
    1012  
    1013     /* CNAME item */ 
    1014     *p++ = 1; 
    1015     *p++ = (pj_uint8_t)stream->cname.slen; 
    1016     pj_memcpy(p, stream->cname.ptr, stream->cname.slen); 
    1017     p += stream->cname.slen; 
    1018  
    1019     /* END */ 
    1020     *p++ = '\0'; 
    1021     *p++ = '\0'; 
    1022  
    1023     /* Pad to 32bit */ 
    1024     while ((p-pkt) % 4) 
    1025         *p++ = '\0'; 
    1026  
    1027     return (p - pkt); 
    1028 } 
    1029  
    1030 /* Build RTCP BYE packet */ 
    1031 static unsigned create_rtcp_bye(pjmedia_stream *stream, pj_uint8_t *pkt, 
    1032                                 unsigned max_len) 
    1033 { 
    1034     pjmedia_rtcp_common hdr; 
    1035  
    1036     /* BYE header */ 
    1037     hdr.version = 2; 
    1038     hdr.p = 0; 
    1039     hdr.count = 1; 
    1040     hdr.pt = 203; 
    1041     hdr.length = 1; 
    1042     if (max_len < (hdr.length << 2)) { 
    1043         pj_assert(!"Not enough buffer for SDES packet"); 
    1044         return 0; 
    1045     } 
    1046     hdr.length = pj_htons((pj_uint16_t)hdr.length); 
    1047     hdr.ssrc = stream->enc->rtp.out_hdr.ssrc; 
    1048     pj_memcpy(pkt, &hdr, sizeof(hdr)); 
    1049  
    1050     return sizeof(hdr); 
    10511064} 
    10521065 
     
    18321845    /* Send RTCP RR and SDES after we receive some RTP packets */ 
    18331846    if (stream->rtcp.received >= 10 && !stream->initial_rr) { 
    1834         void *sr_rr_pkt; 
    1835         pj_uint8_t *pkt; 
    1836         int len; 
    1837  
    1838         /* Build RR or SR */ 
    1839         pjmedia_rtcp_build_rtcp(&stream->rtcp, &sr_rr_pkt, &len); 
    1840  
    1841         if (!stream->rtcp_sdes_bye_disabled) { 
    1842             pkt = (pj_uint8_t*) stream->enc->out_pkt; 
    1843             pj_memcpy(pkt, sr_rr_pkt, len); 
    1844             pkt += len; 
    1845  
    1846             /* Append SDES */ 
    1847             len = create_rtcp_sdes(stream, (pj_uint8_t*)pkt,  
    1848                                    stream->enc->out_pkt_size - len); 
    1849             if (len > 0) { 
    1850                 pkt += len; 
    1851                 len = ((pj_uint8_t*)pkt) - ((pj_uint8_t*)stream->enc->out_pkt); 
    1852                 status = pjmedia_transport_send_rtcp(stream->transport, 
    1853                                                      stream->enc->out_pkt, 
    1854                                                      len); 
    1855                 if (status != PJ_SUCCESS) { 
    1856                     PJ_PERROR(4,(stream->port.info.name.ptr, status, 
    1857                                  "Error sending RTCP SDES")); 
    1858                 } 
    1859             } 
    1860         } else { 
    1861             status = pjmedia_transport_send_rtcp(stream->transport, 
    1862                                                  sr_rr_pkt, len); 
    1863             if (status != PJ_SUCCESS) { 
    1864                 PJ_PERROR(4,(stream->port.info.name.ptr, status, 
    1865                              "Error sending initial RTCP RR")); 
    1866             } 
    1867         } 
    1868  
    1869         stream->initial_rr = PJ_TRUE; 
     1847        status = send_rtcp(stream, !stream->rtcp_sdes_bye_disabled, 
     1848                           PJ_FALSE, PJ_FALSE); 
     1849        if (status != PJ_SUCCESS) { 
     1850            PJ_PERROR(4,(stream->port.info.name.ptr, status, 
     1851                     "Error sending initial RTCP RR")); 
     1852        } else { 
     1853            stream->initial_rr = PJ_TRUE; 
     1854        } 
    18701855    } 
    18711856} 
     
    24012386    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); 
    24022387 
    2403 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
    2404     /* Send RTCP XR on stream destroy */ 
    2405     if (stream->rtcp.xr_enabled) { 
    2406         int i; 
    2407         pjmedia_jb_state jb_state; 
    2408         void *rtcp_pkt; 
    2409         int len; 
    2410  
    2411         /* Update RTCP XR with current JB states */ 
    2412         pjmedia_jbuf_get_state(stream->jb, &jb_state); 
    2413              
    2414         i = jb_state.avg_delay; 
    2415         pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,  
    2416                                     PJMEDIA_RTCP_XR_INFO_JB_NOM, 
    2417                                     i); 
    2418  
    2419         i = jb_state.max_delay; 
    2420         pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,  
    2421                                     PJMEDIA_RTCP_XR_INFO_JB_MAX, 
    2422                                     i); 
    2423  
    2424         /* Build RTCP XR packet */ 
    2425         pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0,  
    2426                                    &rtcp_pkt, &len); 
    2427  
    2428         /* Send the RTCP XR to remote address */ 
    2429         pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len); 
    2430          
    2431         /* Send the RTCP XR to third-party destination if specified */ 
    2432         if (stream->rtcp_xr_dest_len) { 
    2433             pjmedia_transport_send_rtcp2(stream->transport,  
    2434                                          &stream->rtcp_xr_dest, 
    2435                                          stream->rtcp_xr_dest_len,  
    2436                                          rtcp_pkt, len); 
    2437         } 
    2438     } 
    2439 #endif 
    2440  
    2441     /* Send RTCP BYE */ 
     2388    /* Send RTCP BYE (also SDES & XR) */ 
    24422389    if (!stream->rtcp_sdes_bye_disabled) { 
    2443         pjmedia_stream_send_rtcp_bye(stream); 
     2390        send_rtcp(stream, PJ_TRUE, PJ_TRUE, PJ_TRUE); 
    24442391    } 
    24452392 
     
    27952742pjmedia_stream_send_rtcp_sdes( pjmedia_stream *stream ) 
    27962743{ 
    2797     unsigned len; 
    2798  
    27992744    PJ_ASSERT_RETURN(stream, PJ_EINVAL); 
    28002745 
    2801     len = create_rtcp_sdes(stream, (pj_uint8_t*)stream->enc->out_pkt, 
    2802                            stream->enc->out_pkt_size); 
    2803     if (len != 0) { 
    2804         return pjmedia_transport_send_rtcp(stream->transport,  
    2805                                            stream->enc->out_pkt, len); 
    2806     } 
    2807  
    2808     return PJ_SUCCESS; 
     2746    return send_rtcp(stream, PJ_TRUE, PJ_FALSE, PJ_FALSE); 
    28092747} 
    28102748 
     
    28182756 
    28192757    if (stream->enc && stream->transport) { 
    2820         unsigned len; 
    2821  
    2822         len = create_rtcp_bye(stream, (pj_uint8_t*)stream->enc->out_pkt, 
    2823                               stream->enc->out_pkt_size); 
    2824         if (len != 0) { 
    2825             return pjmedia_transport_send_rtcp(stream->transport,  
    2826                                                stream->enc->out_pkt, len); 
    2827         } 
     2758        return send_rtcp(stream, PJ_TRUE, PJ_TRUE, PJ_FALSE); 
    28282759    } 
    28292760 
Note: See TracChangeset for help on using the changeset viewer.