| @ -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_ */ | |||||