static void process_rr(session_t *sp, rtp_event *rtp_e) { pdb_entry_t *e; uint32_t fract_lost, my_ssrc; uint32_t ssrc = rtp_e->ssrc; rtcp_rr *r = (rtcp_rr *) rtp_e->data; /* Calculate rtt estimate */ my_ssrc = rtp_my_ssrc(sp->rtp_session[0]); if (pdb_item_get(sp->pdb, r->ssrc, &e) == FALSE) { /* Maybe deleted or not heard from yet */ debug_msg("Receiver report on unknown participant (0x%lx)\n", r->ssrc); return; } if (pdb_item_get(sp->pdb, ssrc, &e) && r->ssrc == my_ssrc && r->ssrc != ssrc && /* filter self reports */ r->lsr != 0) { uint32_t ntp_sec, ntp_frac, ntp32; double rtt; ntp64_time(&ntp_sec, &ntp_frac); ntp32 = ntp64_to_ntp32(ntp_sec, ntp_frac); rtt = rtp_rtt_calc(ntp32, r->lsr, r->dlsr); /* * Filter out blatantly wrong rtt values. Some tools might not * implement dlsr and lsr (broken) or forget to do byte-swapping */ if (rtt < 100.0) { e->last_rtt = rtt; debug_msg("rtt %f\n", rtt); } else { debug_msg("Junk rtt (%f secs) ntp32 0x%08x lsr 0x%08x dlsr 0x%08x ?\n", rtt, ntp32, r->lsr, r->dlsr); } if (e->avg_rtt == 0.0) { e->avg_rtt = e->last_rtt; } else { e->avg_rtt += (e->last_rtt - e->avg_rtt) / 2.0; } if (sp->mbus_engine != NULL) { ui_send_rtp_rtt(sp, sp->mbus_ui_addr, ssrc, e->avg_rtt); } } fract_lost = (r->fract_lost * 100) >> 8; /* Update loss stats */ if (sp->mbus_engine != NULL) { ui_send_rtp_packet_loss(sp, sp->mbus_ui_addr, ssrc, r->ssrc, fract_lost); } /* Do we have to log anything? */ if ((r->ssrc == my_ssrc) && (sp->logger != NULL)) { rtpdump_header(sp->logger, "rtt ", rtp_e); fprintf(sp->logger, "%f\n", e->avg_rtt); } }
static void process_delete(session_t *sp, rtp_event *e) { if (log_fp != 0) { struct timeval tv, *dead; int d_sec = -1, d_usec = -1; gettimeofday(&tv, 0); dead = (struct timeval *) e->data; if (dead != 0) { d_sec = (int) dead->tv_sec; d_usec = (int) dead->tv_usec; } fprintf(log_fp, "%d.%06d %d delete %x %d.%06d\n", (int) tv.tv_sec, (int) tv.tv_usec, rtp_get_ssrc_count(sp->rtp_session[0]), e->ssrc, d_sec, d_usec); fflush(log_fp); } if (e->ssrc != rtp_my_ssrc(sp->rtp_session[0]) && sp->mbus_engine != NULL) { struct s_source *s; pdb_entry_t *pdbe; if ((s = source_get_by_ssrc(sp->active_sources, e->ssrc)) != NULL) { source_remove(sp->active_sources, s); } if (pdb_item_get(sp->pdb, e->ssrc, &pdbe)) { pdb_item_destroy(sp->pdb, e->ssrc); /* Will not be in ui if not in pdb */ ui_send_rtp_remove(sp, sp->mbus_ui_addr, e->ssrc); } } }
static void process_sdes(session_t *sp, uint32_t ssrc, rtcp_sdes_item *d) { pdb_entry_t *e; if (pdb_item_get(sp->pdb, ssrc, &e) == FALSE) { debug_msg("process_sdes: unknown source (0x%08x).\n", ssrc); return; } if (sp->mbus_engine == NULL) { /* Nowhere to send updates to, so ignore them. */ return; } switch(d->type) { case RTCP_SDES_END: /* This is the end of the SDES list of a packet. Nothing */ /* for us to deal with. */ break; case RTCP_SDES_CNAME: if (log_fp != 0) { struct timeval tv; gettimeofday(&tv, 0); fprintf(log_fp, "%d.%06d %d cname %x %s\n", (int) tv.tv_sec, (int) tv.tv_usec, (int) rtp_get_ssrc_count(sp->rtp_session[0]), (int) ssrc, rtp_get_sdes(sp->rtp_session[0], ssrc, RTCP_SDES_CNAME)); fflush(log_fp); } ui_send_rtp_cname(sp, sp->mbus_ui_addr, ssrc); break; case RTCP_SDES_NAME: ui_send_rtp_name(sp, sp->mbus_ui_addr, ssrc); break; case RTCP_SDES_EMAIL: ui_send_rtp_email(sp, sp->mbus_ui_addr, ssrc); break; case RTCP_SDES_PHONE: ui_send_rtp_phone(sp, sp->mbus_ui_addr, ssrc); break; case RTCP_SDES_LOC: ui_send_rtp_loc(sp, sp->mbus_ui_addr, ssrc); break; case RTCP_SDES_TOOL: ui_send_rtp_tool(sp, sp->mbus_ui_addr, ssrc); break; case RTCP_SDES_NOTE: ui_send_rtp_note(sp, sp->mbus_ui_addr, ssrc); break; case RTCP_SDES_PRIV: ui_send_rtp_priv(sp, sp->mbus_ui_addr, ssrc); break; default: debug_msg("Ignoring SDES type (0x%02x) from (0x%08x).\n", ssrc); } }
void ui_send_stats(session_t *sp, char *addr, uint32_t ssrc) { /* Send RAT specific statistics to the user interface... */ const rtcp_rr *rr; uint32_t fract_lost, my_ssrc, total_lost; double skew_rate; char *args, *mbes; struct s_source *src; uint32_t buffered, delay; pdb_entry_t *pdbe; session_validate(sp); if (!sp->ui_on) return; if (pdb_item_get(sp->pdb, ssrc, &pdbe) == FALSE) { debug_msg("pdb entry does not exist (0x%08x)\n", ssrc); return; } pdbe->last_ui_update = sp->cur_ts; if (pdbe->enc_fmt) { mbes = mbus_encode_str(pdbe->enc_fmt); args = (char *) xmalloc(strlen(mbes) + 12); sprintf(args, "\"%08x\" %s", pdbe->ssrc, mbes); xfree(mbes); } else { args = (char *) xmalloc(19); sprintf(args, "\"%08x\" unknown", pdbe->ssrc); } mbus_qmsg(sp->mbus_engine, addr, "rtp.source.codec", args, FALSE); xfree(args); src = source_get_by_ssrc(sp->active_sources, pdbe->ssrc); if (src) { buffered = timestamp_to_ms(source_get_audio_buffered(src)); delay = timestamp_to_ms(source_get_playout_delay(src)); skew_rate = source_get_skew_rate(src); } else { buffered = 0; delay = 0; skew_rate = 1.0; } mbus_qmsgf(sp->mbus_engine, addr, FALSE, "tool.rat.audio.buffered", "\"%08lx\" %ld", (unsigned long)pdbe->ssrc, buffered); mbus_qmsgf(sp->mbus_engine, addr, FALSE, "tool.rat.audio.delay", "\"%08lx\" %ld", (unsigned long)pdbe->ssrc, delay); mbus_qmsgf(sp->mbus_engine, addr, FALSE, "tool.rat.audio.skew", "\"%08lx\" %.5f", (unsigned long)pdbe->ssrc, skew_rate); mbus_qmsgf(sp->mbus_engine, addr, FALSE, "tool.rat.spike.events", "\"%08lx\" %ld", (unsigned long)pdbe->ssrc, pdbe->spike_events); mbus_qmsgf(sp->mbus_engine, addr, FALSE, "tool.rat.spike.toged", "\"%08lx\" %ld", (unsigned long)pdbe->ssrc, pdbe->spike_toged); my_ssrc = rtp_my_ssrc(sp->rtp_session[0]); rr = rtp_get_rr(sp->rtp_session[0], my_ssrc, pdbe->ssrc); if (rr != NULL) { fract_lost = (rr->fract_lost * 100) >> 8; total_lost = rr->total_lost; } else {
static void process_rtp_data(session_t *sp, uint32_t ssrc, rtp_packet *p) { struct s_source *s; pdb_entry_t *e; if (sp->filter_loopback && ssrc == rtp_my_ssrc(sp->rtp_session[0])) { /* This packet is from us and we are filtering our own */ /* packets. */ xfree(p); return; } if (pdb_item_get(sp->pdb, ssrc, &e) == FALSE) { debug_msg("Packet discarded: unknown source (0x%08x).\n", ssrc); xfree(p); return; } e->received++; s = source_get_by_ssrc(sp->active_sources, ssrc); if (s == NULL) { s = source_create(sp->active_sources, ssrc, sp->pdb); ui_send_rtp_active(sp, sp->mbus_ui_addr, ssrc); debug_msg("Source created\n"); } /* Calculate the relative playout delay, for this source. Needed for lip-sync. */ /* Discard packet if output is muted... no point wasting time decoding it... */ if ((sp->playing_audio == FALSE) || (e->mute)) { xfree(p); return; } /* Discard packets that contain no data */ if (p->meta.data_len == 0) { printf("Zero length packet\n"); xfree(p); return; } /* Remove any padding */ if (p->fields.p) { p->meta.data_len -= p->meta.data[p->meta.data_len - 1]; p->fields.p = 0; } source_add_packet(s, p); }
timestamp_t playout_calc(session_t *sp, uint32_t ssrc, timestamp_t transit, int new_spurt) /*****************************************************************************/ /* The primary purpose of this function is to calculate the playout point */ /* for new talkspurts (new_spurt). It also maintains the jitter and transit */ /* time estimates from the source to us. The value returned is the local */ /* playout time. */ /*****************************************************************************/ { timestamp_t delta_transit; pdb_entry_t *e; pdb_item_get(sp->pdb, ssrc, &e); assert(e != NULL); delta_transit = ts_abs_diff(transit, e->avg_transit); if (ts_gt(transit, e->avg_transit)) { e->avg_transit = ts_add(e->avg_transit, ts_div(delta_transit,16)); } else { e->avg_transit = ts_sub(e->avg_transit, ts_div(delta_transit,16)); } if (new_spurt == TRUE) { timestamp_t hvar, jvar; /* Host and jitter components */ debug_msg("New talkspurt\n"); hvar = playout_constraints_component(sp, e); jvar = ts_mul(e->jitter, PLAYOUT_JITTER_SCALE); if (ts_gt(hvar, jvar)) { e->playout = hvar; } else { e->playout = jvar; } e->transit = e->avg_transit; } else { /* delta_transit is abs((s[j+1] - d[j+1]) - (s[j] - d[j])) */ delta_transit = ts_abs_diff(transit, e->last_transit); /* Update jitter estimate using */ /* jitter = (7/8)jitter + (1/8) new_jitter */ e->jitter = ts_mul(e->jitter, 7); e->jitter = ts_add(e->jitter, delta_transit); e->jitter = ts_div(e->jitter, 8); } e->last_transit = transit; return e->playout; }
static void process_app(session_t *sp, uint32_t ssrc, rtcp_app *app) { if (strncmp(app->name, "site", 4) == 0) { int site_id_len = 4*(app->length - 2); pdb_entry_t *e; if (pdb_item_get(sp->pdb, ssrc, &e) == FALSE) { debug_msg("process_app: unknown source (0x%08x).\n", ssrc); return; } else { if (e->siteid == NULL) { e->siteid = xmalloc(site_id_len + 1); strncpy(e->siteid, app->data, site_id_len); e->siteid[site_id_len] = '\0'; } ui_send_rtp_app_site(sp, sp->mbus_ui_addr, ssrc, e->siteid); } } }