static bool_t simple_analyzer_process_rtcp(MSQosAnalyzer *objbase, mblk_t *rtcp){ MSSimpleQosAnalyzer *obj=(MSSimpleQosAnalyzer*)objbase; rtpstats_t *cur; const report_block_t *rb=NULL; bool_t got_stats=FALSE; 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)){ 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; } if (ortp_loss_rate_estimator_process_report_block(objbase->lre,&obj->session->rtp,rb)){ cur->lost_percentage=ortp_loss_rate_estimator_get_value(objbase->lre); 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); got_stats=TRUE; } } return got_stats; }
static void event_queue_cb(MediaStream *ms, void *user_pointer) { LossRateEstimatorCtx *ctx = (LossRateEstimatorCtx*)user_pointer; if (ctx->q != NULL) { OrtpEvent *ev = NULL; while ((ev = ortp_ev_queue_get(ctx->q)) != NULL) { OrtpEventType evt = ortp_event_get_type(ev); OrtpEventData *evd = ortp_event_get_data(ev); if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { do { const report_block_t *rb=NULL; if (rtcp_is_SR(evd->packet)){ rb=rtcp_SR_get_report_block(evd->packet,0); }else if (rtcp_is_RR(evd->packet)){ rb=rtcp_RR_get_report_block(evd->packet,0); } if (rb&&ortp_loss_rate_estimator_process_report_block(ctx->estimator,&ms->sessions.rtp_session->rtp,rb)){ float diff = fabs(ortp_loss_rate_estimator_get_value(ctx->estimator) - ctx->loss_rate); CU_ASSERT_IN_RANGE(diff, 0, 10); } } while (rtcp_next_packet(evd->packet)); } ortp_event_destroy(ev); } } }
static void handle_queue_events(stream_manager_t * stream_mgr) { OrtpEvent *ev; while (NULL != (ev=ortp_ev_queue_get(stream_mgr->evq))){ OrtpEventType evt=ortp_event_get_type(ev); OrtpEventData *evd=ortp_event_get_data(ev); if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { const report_block_t *rb=NULL; if (rtcp_is_SR(evd->packet)){ rb=rtcp_SR_get_report_block(evd->packet,0); }else if (rtcp_is_RR(evd->packet)){ rb=rtcp_RR_get_report_block(evd->packet,0); } if (rb){ stream_mgr->rtcp_count++; if (stream_mgr->type==VideoStreamType&&stream_mgr->video_stream->ms.use_rc){ const MSQosAnalyzer *analyzer=ms_bitrate_controller_get_qos_analyzer(stream_mgr->video_stream->ms.rc); if (analyzer->type==Stateful){ const MSStatefulQosAnalyzer *stateful_analyzer=((const MSStatefulQosAnalyzer*)analyzer); stream_mgr->adaptive_stats.network_state=stateful_analyzer->network_state; stream_mgr->adaptive_stats.loss_estim =100*stateful_analyzer->network_loss_rate; stream_mgr->adaptive_stats.congestion_bw_estim =stateful_analyzer->congestion_bandwidth; } } } } ortp_event_destroy(ev); } }
static void rtcp_eventhandler_impl(LinhoneQos *qos, mblk_t *report) { uint32_t ssrc = 0; LinphoneRtcpAnaly *analyze = NULL; MSList *elem; ms_message("linphoneqos begin to handle rtcp report"); if (!qos || !report) { ms_message("linphoneqos report is null"); return; } report_block_t *block = NULL; if (rtcp_is_SR(report)) { ms_message("linphoneqos begin to handle rtcp sr report"); block = rtcp_SR_get_report_block(report, 0); } else if (rtcp_is_RR(report)) { ms_message("linphoneqos begin to handle rtcp rr report"); block = rtcp_RR_get_report_block(report, 0); } else { ms_message("linphoneqos begin to handle rtcp xr report"); return; } if (!block) return; ssrc = report_block_get_ssrc(block); elem = ms_list_find_custom(qos->list, (MSCompareFunc)qos_find_rtcpanly_from_list, &ssrc); if (!elem) { ms_message("linphoneqos create to rtcpanalyze %u", ssrc); analyze = ms_new0(LinphoneRtcpAnaly, 1); linphone_initial_analy(qos, analyze); analyze->ssrc = ssrc; qos->list = ms_list_append(qos->list, analyze); } else { analyze = (LinphoneRtcpAnaly *)elem->data; } if (!analyze) { ms_message("linphoneqos failed to create rtcpanalyze %u", ssrc); return; } analyze->rtcp_eh(analyze, block); // analyze the rtcp report first analyze->net_eh(analyze); // analyze the net qos->adjust_eh(qos, analyze->action, analyze->adjust_level); //adjust the net }
static void parse_rtcp(mblk_t *m){ do{ if (rtcp_is_RR(m)){ ms_message("Receiving RTCP RR"); }else if (rtcp_is_SR(m)){ ms_message("Receiving RTCP SR"); }else if (rtcp_is_SDES(m)){ ms_message("Receiving RTCP SDES"); rtcp_sdes_parse(m,display_items,NULL); }else { ms_message("Receiving unhandled RTCP message"); } }while(rtcp_next_packet(m)); }
static void parse_rtcp(mblk_t *m) { const report_block_t *rb; do { if (rtcp_is_RR(m)) { ms_message("Receiving RTCP RR"); } else if (rtcp_is_SR(m)) { ms_message("Receiving RTCP SR"); rb=rtcp_SR_get_report_block(m,0); if (rb) { ms_message("interarrival jitter=%u", report_block_get_interarrival_jitter(rb)); } } else if (rtcp_is_SDES(m)) { ms_message("Receiving RTCP SDES"); rtcp_sdes_parse(m,display_items,NULL); } else { ms_message("Receiving unhandled RTCP message"); } } while(rtcp_next_packet(m)); }
static void audio_stream_process_rtcp(AudioStream *stream, mblk_t *m){ do{ const report_block_t *rb=NULL; if (rtcp_is_SR(m)){ rb=rtcp_SR_get_report_block(m,0); }else if (rtcp_is_RR(m)){ rb=rtcp_RR_get_report_block(m,0); } if (rb){ unsigned int ij; float rt=rtp_session_get_round_trip_propagation(stream->ms.session); float flost; ij=report_block_get_interarrival_jitter(rb); flost=(float)(100.0*report_block_get_fraction_lost(rb)/256.0); ms_message("audio_stream_iterate(): remote statistics available\n\tremote's interarrival jitter=%u\n" "\tremote's lost packets percentage since last report=%f\n\tround trip time=%f seconds",ij,flost,rt); if (stream->ms.rc) ms_bitrate_controller_process_rtcp(stream->ms.rc,m); if (stream->ms.qi) ms_quality_indicator_update_from_feedback(stream->ms.qi,m); } }while(rtcp_next_packet(m)); }
static void event_queue_cb(MediaStream *ms, void *user_pointer) { video_stream_tester_stats_t *st = (video_stream_tester_stats_t *)user_pointer; OrtpEvent *ev = NULL; if (st->q != NULL) { while ((ev = ortp_ev_queue_get(st->q)) != NULL) { OrtpEventType evt = ortp_event_get_type(ev); OrtpEventData *d = ortp_event_get_data(ev); if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { do { if (rtcp_is_RR(d->packet)) { st->number_of_RR++; } else if (rtcp_is_SR(d->packet)) { st->number_of_SR++; } else if (rtcp_is_SDES(d->packet)) { st->number_of_SDES++; } else if (rtcp_is_PSFB(d->packet)) { switch (rtcp_PSFB_get_type(d->packet)) { case RTCP_PSFB_PLI: st->number_of_PLI++; break; case RTCP_PSFB_SLI: st->number_of_SLI++; break; case RTCP_PSFB_RPSI: st->number_of_RPSI++; break; default: break; } } } while (rtcp_next_packet(d->packet)); } ortp_event_destroy(ev); } } }
static void media_stream_process_rtcp(MediaStream *stream, mblk_t *m, time_t curtime){ stream->last_packet_time=curtime; ms_message("%s stream [%p]: receiving RTCP %s%s",media_stream_type_str(stream),stream,(rtcp_is_SR(m)?"SR":""),(rtcp_is_RR(m)?"RR":"")); do{ if (stream->rc_enable && stream->rc) ms_bitrate_controller_process_rtcp(stream->rc,m); if (stream->qi) ms_quality_indicator_update_from_feedback(stream->qi,m); stream->process_rtcp(stream,m); }while(rtcp_next_packet(m)); }
static bool_t stateful_analyzer_process_rtcp(MSQosAnalyzer *objbase, mblk_t *rtcp){ MSStatefulQosAnalyzer *obj=(MSStatefulQosAnalyzer*)objbase; 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)){ if (ortp_loss_rate_estimator_process_report_block(objbase->lre,&obj->session->rtp,rb)){ int i; float loss_rate = ortp_loss_rate_estimator_get_value(objbase->lre); float up_bw = stateful_qos_analyzer_upload_bandwidth(obj,report_block_get_high_ext_seq(rb)); obj->curindex++; /*flush bandwidth estimation measures for seq number lower than remote report block received*/ for (i=0;i<BW_HISTORY;i++){ if (obj->upload_bandwidth[i].seq_number<report_block_get_high_ext_seq(rb)){ obj->upload_bandwidth[i].seq_number=0; obj->upload_bandwidth[i].up_bandwidth=0.f; } } /* Always skip the first report, since values might be erroneous due to initialization of multiples objects (encoder/decoder/stats computing..) Instead assume loss rate is a good estimation of network capacity */ if (obj->curindex==1) { obj->network_loss_rate=loss_rate; return TRUE; } obj->latest=ms_new0(rtcpstatspoint_t, 1); obj->latest->timestamp=ms_time(0); obj->latest->bandwidth=up_bw; obj->latest->loss_percent=loss_rate; obj->latest->rtt=rtp_session_get_round_trip_propagation(obj->session); obj->rtcpstatspoint=ms_list_insert_sorted(obj->rtcpstatspoint, obj->latest, (MSCompareFunc)sort_by_bandwidth); /*if the measure was 0% loss, reset to 0% every measures below it*/ 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_message("MSStatefulQosAnalyzer[%p]: one more %d: %f %f", obj, obj->curindex-1, obj->latest->bandwidth, obj->latest->loss_percent); if (ms_list_size(obj->rtcpstatspoint) > ESTIM_HISTORY){ int prev_size = ms_list_size(obj->rtcpstatspoint); /*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_message("MSStatefulQosAnalyzer[%p]: reached list maximum capacity " "(count=%d) --> Cleaned list (count=%d)", obj, prev_size, ms_list_size(obj->rtcpstatspoint)); } return TRUE; } } return FALSE; }
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; }