| @ -0,0 +1,160 @@ | |||
| /* | |||
| * rtcp_xr.c | |||
| * | |||
| * Created on: Mar 29, 2015 | |||
| * Author: fmetz | |||
| */ | |||
| #include <stdio.h> | |||
| #include <arpa/inet.h> | |||
| #include "rtcp_xr.h" | |||
| /* RTCP XR payload type */ | |||
| #define RTCP_XR 207 | |||
| /* RTCP XR block types */ | |||
| #define BT_LOSS_RLE 1 | |||
| #define BT_DUP_RLE 2 | |||
| #define BT_RCPT_TIMES 3 | |||
| #define BT_RR_TIME 4 | |||
| #define BT_DLRR 5 | |||
| #define BT_STATS 6 | |||
| #define BT_VOIP_METRICS 7 | |||
| void print_rtcp_xr_common(char* cdrbufcur,pjmedia_rtcp_xr_pkt *rtcp_xr) { | |||
| cdrbufcur += sprintf(cdrbufcur,"version=%u, padding=%u, count=%u, payloadtype=%u, length=%u, ssrc=%u, ", | |||
| ntohl(rtcp_xr->common.version), | |||
| ntohl(rtcp_xr->common.p), | |||
| ntohl(rtcp_xr->common.count), | |||
| ntohl(rtcp_xr->common.pt), | |||
| ntohl(rtcp_xr->common.length), | |||
| ntohl(rtcp_xr->common.ssrc)); | |||
| } | |||
| void print_rtcp_xr_rb_header(char* cdrbufcur,pjmedia_rtcp_xr_rb_header *rb_header) { | |||
| cdrbufcur += sprintf(cdrbufcur,"rb_header_blocktype=%u, rb_header_blockspecdata=%u, rb_header_blocklength=%u, ", | |||
| ntohl(rb_header->bt), | |||
| ntohl(rb_header->specific), | |||
| ntohl(rb_header->length)); | |||
| } | |||
| void print_rtcp_xr_rb_rr_time(char* cdrbufcur,pjmedia_rtcp_xr_rb_rr_time *rb_rr_time) { | |||
| print_rtcp_xr_rb_header(cdrbufcur,&rb_rr_time->header); | |||
| cdrbufcur += sprintf(cdrbufcur,"rb_rr_time_ntp_sec=%u, rb_rr_time_ntp_frac=%u, ", | |||
| ntohl(rb_rr_time->ntp_sec), | |||
| ntohl(rb_rr_time->ntp_frac)); | |||
| } | |||
| void print_rtcp_xr_rb_dlrr(char* cdrbufcur,pjmedia_rtcp_xr_rb_dlrr *rb_dlrr) { | |||
| print_rtcp_xr_rb_header(cdrbufcur,&rb_dlrr->header); | |||
| cdrbufcur += sprintf(cdrbufcur,"rb_dlrr_ssrc=%u, rb_dlrr_lrr=%u, rb_dlrr_dlrr=%u, ", | |||
| ntohl(rb_dlrr->item.ssrc), | |||
| ntohl(rb_dlrr->item.lrr), | |||
| ntohl(rb_dlrr->item.dlrr)); | |||
| } | |||
| void print_rtcp_xr_rb_stats(char* cdrbufcur,pjmedia_rtcp_xr_rb_stats *rb_stats) { | |||
| print_rtcp_xr_rb_header(cdrbufcur,&rb_stats->header); | |||
| cdrbufcur += sprintf(cdrbufcur,"rb_stats_ssrc=%u, rb_stats_begin_seq=%u, rb_stats_end_seq=%u, rb_stats_lost_packets=%u, rb_stats_duplicate_packets=%u," | |||
| "rb_stats_jitter_min=%u, rb_stats_jitter_max=%u, rb_stats_jitter_mean=%u, rb_stats_jitter_deviation=%u," | |||
| "rb_stats_toh_min=%u, rb_stats_toh_max=%u, rb_stats_toh_mean=%u, rb_stats_toh_deviation=%u, ", | |||
| ntohl(rb_stats->ssrc), | |||
| ntohl(rb_stats->begin_seq), | |||
| ntohl(rb_stats->end_seq), | |||
| ntohl(rb_stats->lost), | |||
| ntohl(rb_stats->dup), | |||
| ntohl(rb_stats->jitter_min), | |||
| ntohl(rb_stats->jitter_max), | |||
| ntohl(rb_stats->jitter_mean), | |||
| ntohl(rb_stats->jitter_dev), | |||
| ntohl(rb_stats->toh_min), | |||
| ntohl(rb_stats->toh_max), | |||
| ntohl(rb_stats->toh_mean), | |||
| ntohl(rb_stats->toh_dev)); | |||
| } | |||
| void print_rtcp_xr_rb_voip_mtc(char* cdrbufcur,pjmedia_rtcp_xr_rb_voip_mtc *rb_voip_mtc) { | |||
| print_rtcp_xr_rb_header(cdrbufcur,&rb_voip_mtc->header); | |||
| cdrbufcur += sprintf(cdrbufcur,"rb_voip_mtc_ssrc=%u, rb_voip_mtc_loss_rate=%u, rb_voip_mtc_discard_rate=%u, rb_voip_mtc_burst_den=%u, " | |||
| "rb_voip_mtc_gap_den=%u, rb_voip_mtc_burst_dur=%u, rb_voip_mtc_gap_dur=%u, rb_voip_mtc_rnd_trip_delay=%u, " | |||
| "rb_voip_mtc_end_sys_delay=%u, rb_voip_mtc_signal_lvl=%u, rb_voip_mtc_noise_lvl=%u, rb_voip_mtc_rerl=%u, " | |||
| "rb_voip_mtc_gmin=%u, rb_voip_mtc_r_factor=%u, rb_voip_mtc_ext_r_factor=%u, rb_voip_mtc_mos_lq=%u, " | |||
| "rb_voip_mtc_mos_cq=%u, rb_voip_mtc_rx_config=%u, rb_voip_mtc_jb_nom=%u, rb_voip_mtc_jb_max=%u, " | |||
| "rb_voip_mtc_jb_abs_max=%u, ", | |||
| ntohl(rb_voip_mtc->ssrc), | |||
| ntohl(rb_voip_mtc->loss_rate), | |||
| ntohl(rb_voip_mtc->discard_rate), | |||
| ntohl(rb_voip_mtc->burst_den), | |||
| ntohl(rb_voip_mtc->gap_den), | |||
| ntohl(rb_voip_mtc->burst_dur), | |||
| ntohl(rb_voip_mtc->gap_dur), | |||
| ntohl(rb_voip_mtc->rnd_trip_delay), | |||
| ntohl(rb_voip_mtc->end_sys_delay), | |||
| ntohl(rb_voip_mtc->signal_lvl), | |||
| ntohl(rb_voip_mtc->noise_lvl), | |||
| ntohl(rb_voip_mtc->rerl), | |||
| ntohl(rb_voip_mtc->gmin), | |||
| ntohl(rb_voip_mtc->r_factor), | |||
| ntohl(rb_voip_mtc->ext_r_factor), | |||
| ntohl(rb_voip_mtc->mos_lq), | |||
| ntohl(rb_voip_mtc->mos_cq), | |||
| ntohl(rb_voip_mtc->rx_config), | |||
| ntohl(rb_voip_mtc->jb_nom), | |||
| ntohl(rb_voip_mtc->jb_max), | |||
| ntohl(rb_voip_mtc->jb_abs_max)); | |||
| } | |||
| void pjmedia_rtcp_xr_rx_rtcp_xr(char* cdrbufcur, const void *pkt, size_t size) { | |||
| const pjmedia_rtcp_xr_pkt *rtcp_xr = (pjmedia_rtcp_xr_pkt*) pkt; | |||
| const pjmedia_rtcp_xr_rb_rr_time *rb_rr_time = NULL; | |||
| const pjmedia_rtcp_xr_rb_dlrr *rb_dlrr = NULL; | |||
| const pjmedia_rtcp_xr_rb_stats *rb_stats = NULL; | |||
| const pjmedia_rtcp_xr_rb_voip_mtc *rb_voip_mtc = NULL; | |||
| const pjmedia_rtcp_xr_rb_header *rb_hdr = (pjmedia_rtcp_xr_rb_header*) | |||
| rtcp_xr->buf; | |||
| unsigned pkt_len, rb_len; | |||
| if (rtcp_xr->common.pt != RTCP_XR) | |||
| return; | |||
| print_rtcp_xr_common(cdrbufcur,rtcp_xr); | |||
| pkt_len = ntohs((u_int16_t)rtcp_xr->common.length); | |||
| if ((pkt_len + 1) > (size / 4)) | |||
| return; | |||
| /* Parse report rpt_types */ | |||
| while ((int32_t*)rb_hdr < (int32_t*)pkt + pkt_len) | |||
| { | |||
| rb_len = ntohs((u_int16_t)rb_hdr->length); | |||
| /* Just skip any block with length == 0 (no report content) */ | |||
| if (rb_len) { | |||
| switch (rb_hdr->bt) { | |||
| case BT_RR_TIME: | |||
| rb_rr_time = (pjmedia_rtcp_xr_rb_rr_time*) rb_hdr; | |||
| print_rtcp_xr_rb_rr_time(cdrbufcur,rb_rr_time); | |||
| break; | |||
| case BT_DLRR: | |||
| rb_dlrr = (pjmedia_rtcp_xr_rb_dlrr*) rb_hdr; | |||
| print_rtcp_xr_rb_dlrr(cdrbufcur,rb_dlrr); | |||
| break; | |||
| case BT_STATS: | |||
| rb_stats = (pjmedia_rtcp_xr_rb_stats*) rb_hdr; | |||
| print_rtcp_xr_rb_stats(cdrbufcur,rb_stats); | |||
| break; | |||
| case BT_VOIP_METRICS: | |||
| rb_voip_mtc = (pjmedia_rtcp_xr_rb_voip_mtc*) rb_hdr; | |||
| print_rtcp_xr_rb_voip_mtc(cdrbufcur,rb_voip_mtc); | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| rb_hdr = (pjmedia_rtcp_xr_rb_header*) | |||
| ((int32_t*)rb_hdr + rb_len + 1); | |||
| } | |||
| } | |||
| @ -0,0 +1,229 @@ | |||
| /* | |||
| * rtcp_xr.h | |||
| * | |||
| * Created on: Mar 29, 2015 | |||
| * Author: fmetz | |||
| */ | |||
| #ifndef RTCP_XR_H_ | |||
| #define RTCP_XR_H_ | |||
| #include <stdint.h> | |||
| #include <sys/types.h> | |||
| /** | |||
| * @defgroup PJMED_RTCP_XR RTCP Extended Report (XR) - RFC 3611 | |||
| * @ingroup PJMEDIA_SESSION | |||
| * @brief RTCP XR extension to RTCP session | |||
| * @{ | |||
| * | |||
| * PJMEDIA implements subsets of RTCP XR specification (RFC 3611) to monitor | |||
| * the quality of the real-time media (audio/video) transmission. | |||
| */ | |||
| /** | |||
| * Enumeration of report types of RTCP XR. Useful for user to enable varying | |||
| * combinations of RTCP XR report blocks. | |||
| */ | |||
| typedef enum { | |||
| PJMEDIA_RTCP_XR_LOSS_RLE = (1 << 0), | |||
| PJMEDIA_RTCP_XR_DUP_RLE = (1 << 1), | |||
| PJMEDIA_RTCP_XR_RCPT_TIMES = (1 << 2), | |||
| PJMEDIA_RTCP_XR_RR_TIME = (1 << 3), | |||
| PJMEDIA_RTCP_XR_DLRR = (1 << 4), | |||
| PJMEDIA_RTCP_XR_STATS = (1 << 5), | |||
| PJMEDIA_RTCP_XR_VOIP_METRICS = (1 << 6) | |||
| } pjmedia_rtcp_xr_type; | |||
| /** | |||
| * Enumeration of info need to be updated manually to RTCP XR. Most info | |||
| * could be updated automatically each time RTP received. | |||
| */ | |||
| typedef enum { | |||
| PJMEDIA_RTCP_XR_INFO_SIGNAL_LVL = 1, | |||
| PJMEDIA_RTCP_XR_INFO_NOISE_LVL = 2, | |||
| PJMEDIA_RTCP_XR_INFO_RERL = 3, | |||
| PJMEDIA_RTCP_XR_INFO_R_FACTOR = 4, | |||
| PJMEDIA_RTCP_XR_INFO_MOS_LQ = 5, | |||
| PJMEDIA_RTCP_XR_INFO_MOS_CQ = 6, | |||
| PJMEDIA_RTCP_XR_INFO_CONF_PLC = 7, | |||
| PJMEDIA_RTCP_XR_INFO_CONF_JBA = 8, | |||
| PJMEDIA_RTCP_XR_INFO_CONF_JBR = 9, | |||
| PJMEDIA_RTCP_XR_INFO_JB_NOM = 10, | |||
| PJMEDIA_RTCP_XR_INFO_JB_MAX = 11, | |||
| PJMEDIA_RTCP_XR_INFO_JB_ABS_MAX = 12 | |||
| } pjmedia_rtcp_xr_info; | |||
| /** | |||
| * Enumeration of PLC types definitions for RTCP XR report. | |||
| */ | |||
| typedef enum { | |||
| PJMEDIA_RTCP_XR_PLC_UNK = 0, | |||
| PJMEDIA_RTCP_XR_PLC_DIS = 1, | |||
| PJMEDIA_RTCP_XR_PLC_ENH = 2, | |||
| PJMEDIA_RTCP_XR_PLC_STD = 3 | |||
| } pjmedia_rtcp_xr_plc_type; | |||
| /** | |||
| * Enumeration of jitter buffer types definitions for RTCP XR report. | |||
| */ | |||
| typedef enum { | |||
| PJMEDIA_RTCP_XR_JB_UNKNOWN = 0, | |||
| PJMEDIA_RTCP_XR_JB_FIXED = 2, | |||
| PJMEDIA_RTCP_XR_JB_ADAPTIVE = 3 | |||
| } pjmedia_rtcp_xr_jb_type; | |||
| #pragma pack(1) | |||
| /** | |||
| * This type declares RTCP XR Report Header. | |||
| */ | |||
| typedef struct pjmedia_rtcp_xr_rb_header | |||
| { | |||
| u_int8_t bt; /**< Block type. */ | |||
| u_int8_t specific; /**< Block specific data. */ | |||
| u_int16_t length; /**< Block length. */ | |||
| } pjmedia_rtcp_xr_rb_header; | |||
| /** | |||
| * This type declares RTCP XR Receiver Reference Time Report Block. | |||
| */ | |||
| typedef struct pjmedia_rtcp_xr_rb_rr_time | |||
| { | |||
| pjmedia_rtcp_xr_rb_header header; /**< Block header. */ | |||
| u_int32_t ntp_sec; /**< NTP time, seconds part. */ | |||
| u_int32_t ntp_frac; /**< NTP time, fractions part. */ | |||
| } pjmedia_rtcp_xr_rb_rr_time; | |||
| /** | |||
| * This type declares RTCP XR DLRR Report Sub-block | |||
| */ | |||
| typedef struct pjmedia_rtcp_xr_rb_dlrr_item | |||
| { | |||
| u_int32_t ssrc; /**< receiver SSRC */ | |||
| u_int32_t lrr; /**< last receiver report */ | |||
| u_int32_t dlrr; /**< delay since last receiver | |||
| report */ | |||
| } pjmedia_rtcp_xr_rb_dlrr_item; | |||
| /** | |||
| * This type declares RTCP XR DLRR Report Block | |||
| */ | |||
| typedef struct pjmedia_rtcp_xr_rb_dlrr | |||
| { | |||
| pjmedia_rtcp_xr_rb_header header; /**< Block header. */ | |||
| pjmedia_rtcp_xr_rb_dlrr_item item; /**< Block contents, | |||
| variable length list */ | |||
| } pjmedia_rtcp_xr_rb_dlrr; | |||
| /** | |||
| * This type declares RTCP XR Statistics Summary Report Block | |||
| */ | |||
| typedef struct pjmedia_rtcp_xr_rb_stats | |||
| { | |||
| pjmedia_rtcp_xr_rb_header header; /**< Block header. */ | |||
| u_int32_t ssrc; /**< Receiver SSRC */ | |||
| u_int16_t begin_seq; /**< Begin RTP sequence reported */ | |||
| u_int16_t end_seq; /**< End RTP sequence reported */ | |||
| u_int32_t lost; /**< Number of packet lost in this | |||
| interval */ | |||
| u_int32_t dup; /**< Number of duplicated packet in | |||
| this interval */ | |||
| u_int32_t jitter_min; /**< Minimum jitter in this interval */ | |||
| u_int32_t jitter_max; /**< Maximum jitter in this interval */ | |||
| u_int32_t jitter_mean; /**< Average jitter in this interval */ | |||
| u_int32_t jitter_dev; /**< Jitter deviation in this | |||
| interval */ | |||
| u_int32_t toh_min:8; /**< Minimum ToH in this interval */ | |||
| u_int32_t toh_max:8; /**< Maximum ToH in this interval */ | |||
| u_int32_t toh_mean:8; /**< Average ToH in this interval */ | |||
| u_int32_t toh_dev:8; /**< ToH deviation in this interval */ | |||
| } pjmedia_rtcp_xr_rb_stats; | |||
| /** | |||
| * This type declares RTCP XR VoIP Metrics Report Block | |||
| */ | |||
| typedef struct pjmedia_rtcp_xr_rb_voip_mtc | |||
| { | |||
| pjmedia_rtcp_xr_rb_header header; /**< Block header. */ | |||
| u_int32_t ssrc; /**< Receiver SSRC */ | |||
| u_int8_t loss_rate; /**< Packet loss rate */ | |||
| u_int8_t discard_rate; /**< Packet discarded rate */ | |||
| u_int8_t burst_den; /**< Burst density */ | |||
| u_int8_t gap_den; /**< Gap density */ | |||
| u_int16_t burst_dur; /**< Burst duration */ | |||
| u_int16_t gap_dur; /**< Gap duration */ | |||
| u_int16_t rnd_trip_delay;/**< Round trip delay */ | |||
| u_int16_t end_sys_delay; /**< End system delay */ | |||
| u_int8_t signal_lvl; /**< Signal level */ | |||
| u_int8_t noise_lvl; /**< Noise level */ | |||
| u_int8_t rerl; /**< Residual Echo Return Loss */ | |||
| u_int8_t gmin; /**< The gap threshold */ | |||
| u_int8_t r_factor; /**< Voice quality metric carried | |||
| over this RTP session */ | |||
| u_int8_t ext_r_factor; /**< Voice quality metric carried | |||
| outside of this RTP session*/ | |||
| u_int8_t mos_lq; /**< Mean Opinion Score for | |||
| Listening Quality */ | |||
| u_int8_t mos_cq; /**< Mean Opinion Score for | |||
| Conversation Quality */ | |||
| u_int8_t rx_config; /**< Receiver configuration */ | |||
| u_int8_t reserved2; /**< Not used */ | |||
| u_int16_t jb_nom; /**< Current delay by jitter | |||
| buffer */ | |||
| u_int16_t jb_max; /**< Maximum delay by jitter | |||
| buffer */ | |||
| u_int16_t jb_abs_max; /**< Maximum possible delay by | |||
| jitter buffer */ | |||
| } pjmedia_rtcp_xr_rb_voip_mtc; | |||
| /** | |||
| * Constant of RTCP-XR content size. | |||
| */ | |||
| #define PJMEDIA_RTCP_XR_BUF_SIZE \ | |||
| sizeof(pjmedia_rtcp_xr_rb_rr_time) + \ | |||
| sizeof(pjmedia_rtcp_xr_rb_dlrr) + \ | |||
| sizeof(pjmedia_rtcp_xr_rb_stats) + \ | |||
| sizeof(pjmedia_rtcp_xr_rb_voip_mtc) | |||
| /** | |||
| * This structure declares RTCP XR (Extended Report) packet. | |||
| */ | |||
| typedef struct pjmedia_rtcp_xr_pkt | |||
| { | |||
| struct { | |||
| #if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0 | |||
| unsigned version:2; /**< packet type */ | |||
| unsigned p:1; /**< padding flag */ | |||
| unsigned count:5; /**< varies by payload type */ | |||
| unsigned pt:8; /**< payload type */ | |||
| #else | |||
| unsigned count:5; /**< varies by payload type */ | |||
| unsigned p:1; /**< padding flag */ | |||
| unsigned version:2; /**< packet type */ | |||
| unsigned pt:8; /**< payload type */ | |||
| #endif | |||
| unsigned length:16; /**< packet length */ | |||
| u_int32_t ssrc; /**< SSRC identification */ | |||
| } common; | |||
| int8_t buf[PJMEDIA_RTCP_XR_BUF_SIZE]; | |||
| /**< Content buffer */ | |||
| } pjmedia_rtcp_xr_pkt; | |||
| /** | |||
| * This function is called internally by RTCP session when it receives | |||
| * incoming RTCP XR packets. | |||
| * | |||
| * @param rtcp_pkt The received RTCP XR packet. | |||
| * @param size Size of the incoming packet. | |||
| */ | |||
| void pjmedia_rtcp_xr_rx_rtcp_xr( char* cdrbufcur, const void *rtcp_pkt, size_t size); | |||
| #endif /* RTCP_XR_H_ */ | |||