Browse Source

TT#12800 consider RTCP XR reports for MOS calculations and stats

Change-Id: I18f6ff92bab432caf446c59395ab253a305378f4
changes/17/12817/7
Richard Fuchs 9 years ago
parent
commit
23bc99ed81
3 changed files with 210 additions and 59 deletions
  1. +45
    -8
      daemon/rtcp.c
  2. +132
    -45
      daemon/ssrc.c
  3. +33
    -6
      daemon/ssrc.h

+ 45
- 8
daemon/rtcp.c View File

@ -136,8 +136,8 @@ struct xr_packet {
struct xr_rb_rr_time { struct xr_rb_rr_time {
struct xr_report_block header; struct xr_report_block header;
u_int32_t ntp_sec; /**< NTP time, seconds part. */
u_int32_t ntp_frac; /**< NTP time, fractions part. */
u_int32_t ntp_msw; /**< NTP time, seconds part. */
u_int32_t ntp_lsw; /**< NTP time, fractions part. */
} __attribute__ ((packed)); } __attribute__ ((packed));
struct xr_rb_dlrr_item { struct xr_rb_dlrr_item {
@ -235,6 +235,8 @@ struct rtcp_process_ctx {
struct ssrc_receiver_report rr; struct ssrc_receiver_report rr;
struct ssrc_sender_report sr; struct ssrc_sender_report sr;
struct ssrc_xr_voip_metrics xr_vm; struct ssrc_xr_voip_metrics xr_vm;
struct ssrc_xr_rr_time xr_rr;
struct ssrc_xr_dlrr xr_dlrr;
} scratch; } scratch;
u_int32_t scratch_common_ssrc; u_int32_t scratch_common_ssrc;
@ -285,11 +287,16 @@ static void dummy_handler();
static void scratch_common(struct rtcp_process_ctx *, const struct rtcp_packet *); static void scratch_common(struct rtcp_process_ctx *, const struct rtcp_packet *);
static void scratch_sr(struct rtcp_process_ctx *, const struct sender_report_packet *); static void scratch_sr(struct rtcp_process_ctx *, const struct sender_report_packet *);
static void scratch_rr(struct rtcp_process_ctx *, const struct report_block *); static void scratch_rr(struct rtcp_process_ctx *, const struct report_block *);
static void scratch_xr_rr_time(struct rtcp_process_ctx *, const struct xr_rb_rr_time *);
static void scratch_xr_dlrr(struct rtcp_process_ctx *, const struct xr_rb_dlrr *);
static void scratch_xr_voip_metrics(struct rtcp_process_ctx *, const struct xr_rb_voip_metrics *); static void scratch_xr_voip_metrics(struct rtcp_process_ctx *, const struct xr_rb_voip_metrics *);
// MOS calculation / stats // MOS calculation / stats
static void mos_sr(struct rtcp_process_ctx *, const struct sender_report_packet *); static void mos_sr(struct rtcp_process_ctx *, const struct sender_report_packet *);
static void mos_rr(struct rtcp_process_ctx *, const struct report_block *); static void mos_rr(struct rtcp_process_ctx *, const struct report_block *);
static void mos_xr_rr_time(struct rtcp_process_ctx *, const struct xr_rb_rr_time *);
static void mos_xr_dlrr(struct rtcp_process_ctx *, const struct xr_rb_dlrr *);
static void mos_xr_voip_metrics(struct rtcp_process_ctx *, const struct xr_rb_voip_metrics *);
// homer functions // homer functions
static void homer_init(struct rtcp_process_ctx *); static void homer_init(struct rtcp_process_ctx *);
@ -326,11 +333,16 @@ static struct rtcp_handler scratch_handlers = {
.common = scratch_common, .common = scratch_common,
.rr = scratch_rr, .rr = scratch_rr,
.sr = scratch_sr, .sr = scratch_sr,
.xr_rr_time = scratch_xr_rr_time,
.xr_dlrr = scratch_xr_dlrr,
.xr_voip_metrics = scratch_xr_voip_metrics, .xr_voip_metrics = scratch_xr_voip_metrics,
}; };
static struct rtcp_handler mos_handlers = { static struct rtcp_handler mos_handlers = {
.rr = mos_rr, .rr = mos_rr,
.sr = mos_sr, .sr = mos_sr,
.xr_rr_time = mos_xr_rr_time,
.xr_dlrr = mos_xr_dlrr,
.xr_voip_metrics = mos_xr_voip_metrics,
}; };
static struct rtcp_handler log_handlers = { static struct rtcp_handler log_handlers = {
.init = logging_init, .init = logging_init,
@ -556,6 +568,7 @@ static void xr_rr_time(struct xr_rb_rr_time *rb, struct rtcp_process_ctx *log_ct
CAH(xr_rr_time, rb); CAH(xr_rr_time, rb);
} }
static void xr_dlrr(struct xr_rb_dlrr *rb, struct rtcp_process_ctx *log_ctx) { static void xr_dlrr(struct xr_rb_dlrr *rb, struct rtcp_process_ctx *log_ctx) {
// XXX support multiple report blocks
CAH(xr_rb, &rb->header); CAH(xr_rb, &rb->header);
CAH(xr_dlrr, rb); CAH(xr_dlrr, rb);
} }
@ -918,10 +931,25 @@ static void scratch_sr(struct rtcp_process_ctx *ctx, const struct sender_report_
.timestamp = ntohl(sr->timestamp), .timestamp = ntohl(sr->timestamp),
.packet_count = ntohl(sr->packet_count), .packet_count = ntohl(sr->packet_count),
}; };
ctx->scratch.sr.ntp_ts = ntp_ts_to_double(ctx->scratch.sr.ntp_msw, ctx->scratch.sr.ntp_lsw);
}
static void scratch_xr_rr_time(struct rtcp_process_ctx *ctx, const struct xr_rb_rr_time *rr) {
ctx->scratch.xr_rr = (struct ssrc_xr_rr_time) {
.ssrc = ctx->scratch_common_ssrc,
.ntp_msw = ntohl(rr->ntp_msw),
.ntp_lsw = ntohl(rr->ntp_lsw),
};
}
static void scratch_xr_dlrr(struct rtcp_process_ctx *ctx, const struct xr_rb_dlrr *dlrr) {
ctx->scratch.xr_dlrr = (struct ssrc_xr_dlrr) {
.from = ctx->scratch_common_ssrc,
.ssrc = htonl(dlrr->item.ssrc),
.lrr = ntohl(dlrr->item.lrr),
.dlrr = ntohl(dlrr->item.dlrr),
};
} }
static void scratch_xr_voip_metrics(struct rtcp_process_ctx *ctx, const struct xr_rb_voip_metrics *vm) { static void scratch_xr_voip_metrics(struct rtcp_process_ctx *ctx, const struct xr_rb_voip_metrics *vm) {
ctx->scratch.xr_vm = (struct ssrc_xr_voip_metrics) { ctx->scratch.xr_vm = (struct ssrc_xr_voip_metrics) {
.from = ctx->scratch_common_ssrc,
.ssrc = ntohl(vm->ssrc), .ssrc = ntohl(vm->ssrc),
.loss_rate = vm->loss_rate, .loss_rate = vm->loss_rate,
.discard_rate = vm->discard_rate, .discard_rate = vm->discard_rate,
@ -1099,14 +1127,14 @@ static void logging_xr_rb(struct rtcp_process_ctx *ctx, const struct xr_report_b
} }
static void logging_xr_rr_time(struct rtcp_process_ctx *ctx, const struct xr_rb_rr_time *rb_rr_time) { static void logging_xr_rr_time(struct rtcp_process_ctx *ctx, const struct xr_rb_rr_time *rb_rr_time) {
g_string_append_printf(ctx->log, "rb_rr_time_ntp_sec=%u, rb_rr_time_ntp_frac=%u, ", g_string_append_printf(ctx->log, "rb_rr_time_ntp_sec=%u, rb_rr_time_ntp_frac=%u, ",
ntohl(rb_rr_time->ntp_sec),
ntohl(rb_rr_time->ntp_frac));
ntohl(ctx->scratch.xr_rr.ntp_msw),
ntohl(ctx->scratch.xr_rr.ntp_lsw));
} }
static void logging_xr_dlrr(struct rtcp_process_ctx *ctx, const struct xr_rb_dlrr *rb_dlrr) { static void logging_xr_dlrr(struct rtcp_process_ctx *ctx, const struct xr_rb_dlrr *rb_dlrr) {
g_string_append_printf(ctx->log, "rb_dlrr_ssrc=%u, rb_dlrr_lrr=%u, rb_dlrr_dlrr=%u, ", g_string_append_printf(ctx->log, "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));
ntohl(ctx->scratch.xr_dlrr.ssrc),
ntohl(ctx->scratch.xr_dlrr.lrr),
ntohl(ctx->scratch.xr_dlrr.dlrr));
} }
static void logging_xr_stats(struct rtcp_process_ctx *ctx, const struct xr_rb_stats *rb_stats) { static void logging_xr_stats(struct rtcp_process_ctx *ctx, const struct xr_rb_stats *rb_stats) {
g_string_append_printf(ctx->log, "rb_stats_ssrc=%u, rb_stats_begin_seq=%u, rb_stats_end_seq=%u, rb_stats_lost_packets=%u, rb_stats_duplicate_packets=%u," g_string_append_printf(ctx->log, "rb_stats_ssrc=%u, rb_stats_begin_seq=%u, rb_stats_end_seq=%u, rb_stats_lost_packets=%u, rb_stats_duplicate_packets=%u,"
@ -1180,6 +1208,15 @@ static void mos_sr(struct rtcp_process_ctx *ctx, const struct sender_report_pack
static void mos_rr(struct rtcp_process_ctx *ctx, const struct report_block *rr) { static void mos_rr(struct rtcp_process_ctx *ctx, const struct report_block *rr) {
ssrc_receiver_report(ctx->media, &ctx->scratch.rr, ctx->received); ssrc_receiver_report(ctx->media, &ctx->scratch.rr, ctx->received);
} }
static void mos_xr_rr_time(struct rtcp_process_ctx *ctx, const struct xr_rb_rr_time *rr) {
ssrc_receiver_rr_time(ctx->media, &ctx->scratch.xr_rr, ctx->received);
}
static void mos_xr_dlrr(struct rtcp_process_ctx *ctx, const struct xr_rb_dlrr *dlrr) {
ssrc_receiver_dlrr(ctx->media, &ctx->scratch.xr_dlrr, ctx->received);
}
static void mos_xr_voip_metrics(struct rtcp_process_ctx *ctx, const struct xr_rb_voip_metrics *rb_voip_mtc) {
ssrc_voip_metrics(ctx->media, &ctx->scratch.xr_vm, ctx->received);
}


+ 132
- 45
daemon/ssrc.c View File

@ -25,11 +25,15 @@ static void add_ssrc_entry(struct ssrc_entry *ent, struct ssrc_hash *ht) {
static void free_sender_report(struct ssrc_sender_report_item *i) { static void free_sender_report(struct ssrc_sender_report_item *i) {
g_slice_free1(sizeof(*i), i); g_slice_free1(sizeof(*i), i);
} }
static void free_rr_time(struct ssrc_rr_time_item *i) {
g_slice_free1(sizeof(*i), i);
}
static void free_stats_block(struct ssrc_stats_block *ssb) { static void free_stats_block(struct ssrc_stats_block *ssb) {
g_slice_free1(sizeof(*ssb), ssb); g_slice_free1(sizeof(*ssb), ssb);
} }
static void free_ssrc_entry(struct ssrc_entry *e) { static void free_ssrc_entry(struct ssrc_entry *e) {
g_queue_clear_full(&e->sender_reports, (GDestroyNotify) free_sender_report); g_queue_clear_full(&e->sender_reports, (GDestroyNotify) free_sender_report);
g_queue_clear_full(&e->rr_time_reports, (GDestroyNotify) free_rr_time);
g_queue_clear_full(&e->stats_blocks, (GDestroyNotify) free_stats_block); g_queue_clear_full(&e->stats_blocks, (GDestroyNotify) free_stats_block);
g_slice_free1(sizeof(*e), e); g_slice_free1(sizeof(*e), e);
} }
@ -44,6 +48,8 @@ static void mos_calc(struct ssrc_stats_block *ssb) {
else else
r = 93.2 - (eff_rtt - 120) / 40.0; r = 93.2 - (eff_rtt - 120) / 40.0;
r = r - (ssb->packetloss * 2.5); r = r - (ssb->packetloss * 2.5);
if (r < 0)
r = 0;
double mos = 1.0 + (0.035) * r + (.000007) * r * (r-60) * (100-r); double mos = 1.0 + (0.035) * r + (.000007) * r * (r-60) * (100-r);
int64_t intmos = mos * 10.0; int64_t intmos = mos * 10.0;
if (intmos < 0) if (intmos < 0)
@ -117,88 +123,124 @@ struct ssrc_ctx *get_ssrc_ctx(u_int32_t ssrc, struct ssrc_hash *ht, enum ssrc_di
void ssrc_sender_report(struct call_media *m, const struct ssrc_sender_report *sr,
const struct timeval *tv)
static void *__do_time_report_item(struct call_media *m, size_t struct_size, size_t reports_queue_offset,
const struct timeval *tv, u_int32_t ssrc, u_int32_t ntp_msw, u_int32_t ntp_lsw,
GDestroyNotify free_func, struct ssrc_entry **e_p)
{ {
struct call *c = m->call; struct call *c = m->call;
struct ssrc_entry *e; struct ssrc_entry *e;
struct ssrc_sender_report_item *seri;
seri = g_slice_alloc(sizeof(*seri));
seri->received = *tv;
seri->report = *sr;
seri->ntp_middle_bits = sr->ntp_msw << 16 | sr->ntp_lsw >> 16;
struct ssrc_time_item *sti;
ilog(LOG_DEBUG, "SR from %u: RTP TS %u PC %u OC %u NTP TS %u/%u=%f",
sr->ssrc, sr->timestamp, sr->packet_count, sr->octet_count,
sr->ntp_msw, sr->ntp_lsw, sr->ntp_ts);
sti = g_slice_alloc0(struct_size);
sti->received = *tv;
sti->ntp_middle_bits = ntp_msw << 16 | ntp_lsw >> 16;
sti->ntp_ts = ntp_ts_to_double(ntp_msw, ntp_lsw);
e = get_ssrc(sr->ssrc, c->ssrc_hash);
e = get_ssrc(ssrc, c->ssrc_hash);
if (G_UNLIKELY(!e)) { if (G_UNLIKELY(!e)) {
free_sender_report(seri);
return;
free_func(sti);
return NULL;
} }
mutex_lock(&e->lock); mutex_lock(&e->lock);
g_queue_push_tail(&e->sender_reports, seri);
while (e->sender_reports.length > 10)
free_sender_report(g_queue_pop_head(&e->sender_reports));
GQueue *q = (((void *) e) + reports_queue_offset);
mutex_unlock(&e->lock);
g_queue_push_tail(q, sti);
while (q->length > 10)
free_func(g_queue_pop_head(q));
*e_p = e;
return sti;
} }
void ssrc_receiver_report(struct call_media *m, const struct ssrc_receiver_report *rr,
const struct timeval *tv)
{
struct call *c = m->call;
ilog(LOG_DEBUG, "RR from %u about %u: FL %u TL %u HSR %u J %u LSR %u DLSR %u",
rr->from, rr->ssrc, rr->fraction_lost, rr->packets_lost,
rr->high_seq_received, rr->jitter, rr->lsr, rr->dlsr);
static long long __calc_rtt(struct call *c, u_int32_t ssrc, u_int32_t ntp_middle_bits,
u_int32_t delay, size_t reports_queue_offset, const struct timeval *tv, int *pt_p)
{
if (pt_p)
*pt_p = -1;
if (!rr->lsr || !rr->dlsr)
return; // no delay to be known
if (!ntp_middle_bits || !delay)
return 0;
struct ssrc_entry *e = get_ssrc(rr->ssrc, c->ssrc_hash);
struct ssrc_entry *e = get_ssrc(ssrc, c->ssrc_hash);
if (G_UNLIKELY(!e)) if (G_UNLIKELY(!e))
return;
return 0;
if (pt_p)
*pt_p = e->payload_type;
struct ssrc_sender_report_item *seri;
struct ssrc_time_item *sti;
GQueue *q = (((void *) e) + reports_queue_offset);
mutex_lock(&e->lock); mutex_lock(&e->lock);
// go through the list backwards until we find the SR referenced // go through the list backwards until we find the SR referenced
for (GList *l = e->sender_reports.tail; l; l = l->prev) {
seri = l->data;
if (seri->ntp_middle_bits != rr->lsr)
for (GList *l = q->tail; l; l = l->prev) {
sti = l->data;
if (sti->ntp_middle_bits != ntp_middle_bits)
continue; continue;
goto found; goto found;
} }
// not found // not found
goto out_ul_e;
mutex_unlock(&e->lock);
return 0;
found:
// `e` remains locked for access to `seri`
ilog(LOG_DEBUG, "RR from %u reports delay %u from %u", rr->from, rr->dlsr, rr->ssrc);
long long rtt = timeval_diff(tv, &seri->received);
found:;
// `e` remains locked for access to `sti`
long long rtt = timeval_diff(tv, &sti->received);
mutex_unlock(&e->lock); mutex_unlock(&e->lock);
rtt -= (long long) rr->dlsr * 1000000LL / 65536LL;
ilog(LOG_DEBUG, "Calculated round-trip time for %u is %lli us", rr->ssrc, rtt);
rtt -= (long long) delay * 1000000LL / 65536LL;
ilog(LOG_DEBUG, "Calculated round-trip time for %u is %lli us", ssrc, rtt);
if (rtt <= 0 || rtt > 10000000) { if (rtt <= 0 || rtt > 10000000) {
ilog(LOG_DEBUG, "Invalid RTT - discarding"); ilog(LOG_DEBUG, "Invalid RTT - discarding");
goto out_nl;
return 0;
} }
e->last_rtt = rtt; e->last_rtt = rtt;
return rtt;
}
void ssrc_sender_report(struct call_media *m, const struct ssrc_sender_report *sr,
const struct timeval *tv)
{
struct ssrc_entry *e;
struct ssrc_sender_report_item *seri = __do_time_report_item(m, sizeof(*seri),
G_STRUCT_OFFSET(struct ssrc_entry, sender_reports), tv, sr->ssrc,
sr->ntp_msw, sr->ntp_lsw, (GDestroyNotify) free_sender_report, &e);
if (!seri)
return;
seri->report = *sr;
ilog(LOG_DEBUG, "SR from %u: RTP TS %u PC %u OC %u NTP TS %u/%u=%f",
sr->ssrc, sr->timestamp, sr->packet_count, sr->octet_count,
sr->ntp_msw, sr->ntp_lsw, seri->time_item.ntp_ts);
mutex_unlock(&e->lock);
}
void ssrc_receiver_report(struct call_media *m, const struct ssrc_receiver_report *rr,
const struct timeval *tv)
{
struct call *c = m->call;
ilog(LOG_DEBUG, "RR from %u about %u: FL %u TL %u HSR %u J %u LSR %u DLSR %u",
rr->from, rr->ssrc, rr->fraction_lost, rr->packets_lost,
rr->high_seq_received, rr->jitter, rr->lsr, rr->dlsr);
int pt;
long long rtt = __calc_rtt(c, rr->ssrc, rr->lsr, rr->dlsr,
G_STRUCT_OFFSET(struct ssrc_entry, sender_reports), tv, &pt);
struct ssrc_entry *other_e = get_ssrc(rr->from, c->ssrc_hash); struct ssrc_entry *other_e = get_ssrc(rr->from, c->ssrc_hash);
if (G_UNLIKELY(!other_e)) if (G_UNLIKELY(!other_e))
goto out_nl; goto out_nl;
// determine the clock rate for jitter values // determine the clock rate for jitter values
int pt = e->payload_type;
if (pt < 0) { if (pt < 0) {
pt = other_e->payload_type; pt = other_e->payload_type;
if (pt < 0) { if (pt < 0) {
@ -255,12 +297,57 @@ found:
goto out_ul_oe; goto out_ul_oe;
out_ul_e:
mutex_unlock(&e->lock);
goto out_nl;
out_ul_oe: out_ul_oe:
mutex_unlock(&other_e->lock); mutex_unlock(&other_e->lock);
goto out_nl; goto out_nl;
out_nl: out_nl:
; ;
} }
void ssrc_receiver_rr_time(struct call_media *m, const struct ssrc_xr_rr_time *rr,
const struct timeval *tv)
{
struct ssrc_entry *e;
struct ssrc_rr_time_item *srti = __do_time_report_item(m, sizeof(*srti),
G_STRUCT_OFFSET(struct ssrc_entry, rr_time_reports), tv, rr->ssrc,
rr->ntp_msw, rr->ntp_lsw, (GDestroyNotify) free_rr_time, &e);
if (!srti)
return;
ilog(LOG_DEBUG, "XR RR TIME from %u: NTP TS %u/%u=%f",
rr->ssrc,
rr->ntp_msw, rr->ntp_lsw, srti->time_item.ntp_ts);
mutex_unlock(&e->lock);
}
void ssrc_receiver_dlrr(struct call_media *m, const struct ssrc_xr_dlrr *dlrr,
const struct timeval *tv)
{
ilog(LOG_DEBUG, "XR DLRR from %u about %u: LRR %u DLRR %u",
dlrr->from, dlrr->ssrc,
dlrr->lrr, dlrr->dlrr);
__calc_rtt(m->call, dlrr->ssrc, dlrr->lrr, dlrr->dlrr,
G_STRUCT_OFFSET(struct ssrc_entry, rr_time_reports), tv, NULL);
}
void ssrc_voip_metrics(struct call_media *m, const struct ssrc_xr_voip_metrics *vm,
const struct timeval *tv)
{
ilog(LOG_DEBUG, "XR VM from %u about %u: LR %u DR %u BD %u GD %u BDu %u GDu %u RTD %u "
"ESD %u SL %u NL %u RERL %u GMin %u R %u eR %u MOSL %u MOSC %u RX %u "
"JBn %u JBm %u JBam %u",
vm->from, vm->ssrc,
vm->loss_rate, vm->discard_rate, vm->burst_den, vm->gap_den,
vm->burst_dur, vm->gap_dur, vm->rnd_trip_delay, vm->end_sys_delay,
vm->signal_lvl, vm->noise_lvl, vm->rerl, vm->gmin, vm->r_factor,
vm->ext_r_factor, vm->mos_lq, vm->mos_cq, vm->rx_config, vm->jb_nom,
vm->jb_max, vm->jb_abs_max);
struct call *c = m->call;
struct ssrc_entry *e = get_ssrc(vm->ssrc, c->ssrc_hash);
if (!e)
return;
e->last_rtt = vm->rnd_trip_delay;
}

+ 33
- 6
daemon/ssrc.h View File

@ -45,6 +45,7 @@ struct ssrc_entry {
struct ssrc_ctx input_ctx, struct ssrc_ctx input_ctx,
output_ctx; output_ctx;
GQueue sender_reports; // as received via RTCP GQueue sender_reports; // as received via RTCP
GQueue rr_time_reports; // as received via RTCP
GQueue stats_blocks; // calculated GQueue stats_blocks; // calculated
struct ssrc_stats_block *lowest_mos, struct ssrc_stats_block *lowest_mos,
*highest_mos, *highest_mos,
@ -57,6 +58,11 @@ enum ssrc_dir { // these values must not be used externally
SSRC_DIR_OUTPUT = G_STRUCT_OFFSET(struct ssrc_entry, output_ctx), SSRC_DIR_OUTPUT = G_STRUCT_OFFSET(struct ssrc_entry, output_ctx),
}; };
struct ssrc_time_item {
struct timeval received;
u_int32_t ntp_middle_bits; // to match up with lsr/dlrr
double ntp_ts; // XXX convert to int?
};
struct ssrc_sender_report { struct ssrc_sender_report {
u_int32_t ssrc; u_int32_t ssrc;
u_int32_t ntp_msw; u_int32_t ntp_msw;
@ -64,11 +70,9 @@ struct ssrc_sender_report {
u_int32_t timestamp; u_int32_t timestamp;
u_int32_t packet_count; u_int32_t packet_count;
u_int32_t octet_count; u_int32_t octet_count;
double ntp_ts;
}; };
struct ssrc_sender_report_item { struct ssrc_sender_report_item {
struct timeval received;
u_int32_t ntp_middle_bits; // to match up with rr->lsr
struct ssrc_time_item time_item; // must be first;
struct ssrc_sender_report report; struct ssrc_sender_report report;
}; };
@ -82,12 +86,29 @@ struct ssrc_receiver_report {
u_int32_t lsr; u_int32_t lsr;
u_int32_t dlsr; u_int32_t dlsr;
}; };
struct ssrc_receiver_report_item {
struct timeval received;
struct ssrc_receiver_report report;
//struct ssrc_receiver_report_item {
// struct timeval received;
// struct ssrc_receiver_report report;
//};
struct ssrc_xr_rr_time {
u_int32_t ssrc;
u_int32_t ntp_msw;
u_int32_t ntp_lsw;
};
struct ssrc_rr_time_item {
struct ssrc_time_item time_item; // must be first;
};
struct ssrc_xr_dlrr {
u_int32_t from;
u_int32_t ssrc;
u_int32_t lrr;
u_int32_t dlrr;
}; };
struct ssrc_xr_voip_metrics { struct ssrc_xr_voip_metrics {
u_int32_t from;
u_int32_t ssrc; u_int32_t ssrc;
u_int8_t loss_rate; u_int8_t loss_rate;
u_int8_t discard_rate; u_int8_t discard_rate;
@ -126,6 +147,12 @@ struct ssrc_ctx *get_ssrc_ctx(u_int32_t, struct ssrc_hash *, enum ssrc_dir); //
void ssrc_sender_report(struct call_media *, const struct ssrc_sender_report *, const struct timeval *); void ssrc_sender_report(struct call_media *, const struct ssrc_sender_report *, const struct timeval *);
void ssrc_receiver_report(struct call_media *, const struct ssrc_receiver_report *, void ssrc_receiver_report(struct call_media *, const struct ssrc_receiver_report *,
const struct timeval *); const struct timeval *);
void ssrc_receiver_rr_time(struct call_media *m, const struct ssrc_xr_rr_time *rr,
const struct timeval *);
void ssrc_receiver_dlrr(struct call_media *m, const struct ssrc_xr_dlrr *dlrr,
const struct timeval *);
void ssrc_voip_metrics(struct call_media *m, const struct ssrc_xr_voip_metrics *vm,
const struct timeval *);


Loading…
Cancel
Save