int capt_parse_rtcp(char *packet, int len, char *json_buffer, int buffer_len) { if(packet == NULL || len == 0) return -1; rtcp_header_t *rtcp = (rtcp_header_t *)packet; int ret=0; char *rptr; if(rtcp->version != 2) { LERR("wrong version\n"); return -2; } ret+=snprintf(json_buffer, buffer_len, "{ "); int pno = 0, total = len; LDEBUG("Parsing compound packet (total of %d bytes)\n", total); while(rtcp) { pno++; switch(rtcp->type) { case RTCP_SR: { /* SR, sender report */ LDEBUG("#%d SR (200)\n", pno); rtcp_sr_t *sr = (rtcp_sr_t*)rtcp; ret += snprintf(json_buffer+ret, buffer_len - ret, SENDER_REPORT_JSON, sender_info_get_ntp_timestamp_msw(&sr->si), sender_info_get_ntp_timestamp_lsw(&sr->si), sender_info_get_octet_count(&sr->si), sender_info_get_rtp_timestamp(&sr->si), sender_info_get_packet_count(&sr->si)); if(sr->header.rc > 0) { ret += snprintf(json_buffer+ret, buffer_len - ret, REPORT_BLOCK_JSON, ntohl(sr->ssrc), rtcp->type, report_block_get_ssrc(&sr->rb[0]), report_block_get_high_ext_seq(&sr->rb[0]), report_block_get_fraction_lost(&sr->rb[0]), report_block_get_interarrival_jitter(&sr->rb[0]), report_block_get_cum_packet_loss(&sr->rb[0]), report_block_get_last_SR_time(&sr->rb[0]), report_block_get_last_SR_delay(&sr->rb[0])); } break; } case RTCP_RR: { /* RR, receiver report */ LDEBUG("#%d RR (201)\n", pno); rtcp_rr_t *rr = (rtcp_rr_t*)rtcp; if(rr->header.rc > 0) { ret += snprintf(json_buffer+ret, buffer_len - ret, REPORT_BLOCK_JSON, ntohl(rr->ssrc), rtcp->type, report_block_get_ssrc(&rr->rb[0]), report_block_get_high_ext_seq(&rr->rb[0]), report_block_get_fraction_lost(&rr->rb[0]), report_block_get_interarrival_jitter(&rr->rb[0]), report_block_get_cum_packet_loss(&rr->rb[0]), report_block_get_last_SR_time(&rr->rb[0]), report_block_get_last_SR_delay(&rr->rb[0])); } break; } case RTCP_SDES: { LDEBUG("#%d SDES (202)\n", pno); /* if not needed send sdes */ if(!send_sdes) break; rtcp_sdes_t *sdes = (rtcp_sdes_t*)rtcp; rptr = rtcp+2; int sdes_report_count = 0; char *end=(char*) rptr+(4*(rtcp_header_get_length(&sdes->header)+1)-15); ret += snprintf(json_buffer+ret, buffer_len - ret, SDES_REPORT_BEGIN_JSON, ntohl(sdes->ssrc), sdes_chunk_get_csrc(&sdes->chunk)); while(rptr < end) { if (rptr+2<=end) { uint8_t chunk_type=rptr[0]; uint8_t chunk_len=rptr[1]; if(chunk_len == 0) break; rptr+=2; ret += snprintf(json_buffer+ret, buffer_len - ret, SDES_REPORT_INFO_JSON, chunk_type, chunk_len, rptr); sdes_report_count++; if (rptr+chunk_len<=end) rptr+=chunk_len; else break; } else { break; } } /* cut , off */ ret-=1; ret += snprintf(json_buffer+ret, buffer_len - ret, SDES_REPORT_END_JSON, sdes_report_count); break; } case RTCP_BYE: { LDEBUG("#%d BYE (203)\n", pno); ret = 0; //rtcp_bye_t *bye = (rtcp_bye_t*)rtcp; break; } case RTCP_APP: { LDEBUG("#%d APP (204)\n", pno); ret = 0; //rtcp_app_t *app = (rtcp_app_t*)rtcp; break; } default: break; } int length = ntohs(rtcp->length); if(length == 0) { break; } total -= length*4+4; if(total <= 0) { LDEBUG("End of RTCP packet\n"); break; } rtcp = (rtcp_header_t *)((uint32_t*)rtcp + length + 1); } /* bad parsed message */ if(ret < 10) return 0; ret+=snprintf(json_buffer+ret-1, buffer_len-ret+1, "}"); return ret; }
static bool_t stateful_analyzer_process_rtcp(MSQosAnalyzer *objbase, mblk_t *rtcp){ MSStatefulQosAnalyzer *obj=(MSStatefulQosAnalyzer*)objbase; rtpstats_t *cur; const report_block_t *rb=NULL; if (rtcp_is_SR(rtcp)){ rb=rtcp_SR_get_report_block(rtcp,0); }else if (rtcp_is_RR(rtcp)){ rb=rtcp_RR_get_report_block(rtcp,0); } if (rb && report_block_get_ssrc(rb)==rtp_session_get_send_ssrc(obj->session)){ double up_bw = stateful_qos_analyzer_upload_bandwidth(obj); int total_emitted=stateful_qos_analyzer_get_total_emitted(obj, rb); obj->curindex++; cur=&obj->stats[obj->curindex % STATS_HISTORY]; if (obj->clockrate==0){ PayloadType *pt=rtp_profile_get_payload(rtp_session_get_send_profile(obj->session),rtp_session_get_send_payload_type(obj->session)); if (pt!=NULL) obj->clockrate=pt->clock_rate; else return FALSE; } cur->lost_percentage=100.0*(float)report_block_get_fraction_lost(rb)/256.0; cur->int_jitter=1000.0*(float)report_block_get_interarrival_jitter(rb)/(float)obj->clockrate; cur->rt_prop=rtp_session_get_round_trip_propagation(obj->session); ms_message("MSSimpleQosAnalyzer: lost_percentage=%f, int_jitter=%f ms, rt_prop=%f sec",cur->lost_percentage,cur->int_jitter,cur->rt_prop); if (obj->curindex>2){ double loss_rate = cur->lost_percentage/100.0; int cum_loss=report_block_get_cum_packet_loss(rb); int cum_loss_curr=cum_loss - obj->cum_loss_prev; int uniq_emitted=report_block_get_high_ext_seq(rb) - obj->previous_ext_high_seq_num_rec; if (obj->previous_ext_high_seq_num_rec > 0){ loss_rate=(1. - (uniq_emitted - cum_loss_curr) * 1.f / total_emitted); ms_debug("MSQosStatefulAnalyzer[%p]: RECEIVE estimated loss rate=%f vs 'real'=%f", obj, loss_rate, report_block_get_fraction_lost(rb)/256.); } obj->latest=ms_new0(rtcpstatspoint_t, 1); obj->latest->timestamp=ms_time(0); obj->latest->bandwidth=up_bw; obj->latest->loss_percent=MAX(0,loss_rate); obj->latest->rtt=cur->rt_prop; obj->rtcpstatspoint=ms_list_insert_sorted(obj->rtcpstatspoint, obj->latest, (MSCompareFunc)sort_points); if (obj->latest->loss_percent < 1e-5){ MSList *it=obj->rtcpstatspoint; MSList *latest_pos=ms_list_find(obj->rtcpstatspoint,obj->latest); while (it!=latest_pos->next){ ((rtcpstatspoint_t *)it->data)->loss_percent=0.f; it = it->next; } } ms_debug("MSQosStatefulAnalyzer[%p]: one more %d: %f %f", obj, obj->curindex-2, obj->latest->bandwidth, obj->latest->loss_percent); if (ms_list_size(obj->rtcpstatspoint) > ESTIM_HISTORY){ #ifdef DEBUG int prev_size = ms_list_size(obj->rtcpstatspoint); #endif /*clean everything which occurred 60 sec or more ago*/ time_t clear_time = ms_time(0) - 60; obj->rtcpstatspoint = ms_list_remove_custom(obj->rtcpstatspoint, (MSCompareFunc)earlier_than, &clear_time); ms_debug("MSQosStatefulAnalyzer[%p]: Reached list maximum capacity (count=%d) --> Cleaned list (count=%d)", obj, prev_size, ms_list_size(obj->rtcpstatspoint)); } } obj->cum_loss_prev=report_block_get_cum_packet_loss(rb); obj->previous_ext_high_seq_num_rec=report_block_get_high_ext_seq(rb); } return rb!=NULL; }