/** * @file source.c Real-time Transport Control Protocol source * * Copyright (C) 2010 Creytiv.com */ #include #include #include #include #include #include #include #include #include #include "rtcp.h" enum { RTP_SEQ_MOD = 1<<16, }; void source_init_seq(struct rtp_source *s, uint16_t seq) { if (!s) return; s->base_seq = seq; s->max_seq = seq; s->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */ s->cycles = 0; s->received = 0; s->received_prior = 0; s->expected_prior = 0; /* other initialization */ } /** * See RFC 3550 - A.1 RTP Data Header Validity Checks */ int source_update_seq(struct rtp_source *s, uint16_t seq) { uint16_t udelta = seq - s->max_seq; const int MAX_DROPOUT = 3000; const int MAX_MISORDER = 100; const int MIN_SEQUENTIAL = 2; /* * Source is not valid until MIN_SEQUENTIAL packets with * sequential sequence numbers have been received. */ if (s->probation) { /* packet is in sequence */ if (seq == s->max_seq + 1) { s->probation--; s->max_seq = seq; if (s->probation == 0) { source_init_seq(s, seq); s->received++; return 1; } } else { s->probation = MIN_SEQUENTIAL - 1; s->max_seq = seq; } return 0; } else if (udelta < MAX_DROPOUT) { /* in order, with permissible gap */ if (seq < s->max_seq) { /* * Sequence number wrapped - count another 64K cycle. */ s->cycles += RTP_SEQ_MOD; } s->max_seq = seq; } else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) { /* the sequence number made a very large jump */ if (seq == s->bad_seq) { /* * Two sequential packets -- assume that the other side * restarted without telling us so just re-sync * (i.e., pretend this was the first packet). */ source_init_seq(s, seq); } else { s->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1); return 0; } } else { /* duplicate or reordered packet */ } s->received++; return 1; } /* RFC 3550 A.8 * * The inputs are: * * rtp_ts: the timestamp from the incoming RTP packet * arrival: the current time in the same units. */ void source_calc_jitter(struct rtp_source *s, uint32_t rtp_ts, uint32_t arrival) { const int transit = arrival - rtp_ts; int d = transit - s->transit; if (!s->transit) { s->transit = transit; return; } s->transit = transit; if (d < 0) d = -d; s->jitter += d - ((s->jitter + 8) >> 4); } /* A.3 */ int source_calc_lost(const struct rtp_source *s) { int extended_max = s->cycles + s->max_seq; int expected = extended_max - s->base_seq + 1; int lost; lost = expected - s->received; /* Clamp at 24 bits */ if (lost > 0x7fffff) lost = 0x7fffff; else if (lost < -0x7fffff) lost = -0x7fffff; return lost; } /* A.3 */ uint8_t source_calc_fraction_lost(struct rtp_source *s) { int extended_max = s->cycles + s->max_seq; int expected = extended_max - s->base_seq + 1; int expected_interval = expected - s->expected_prior; int received_interval; int lost_interval; uint8_t fraction; s->expected_prior = expected; received_interval = s->received - s->received_prior; s->received_prior = s->received; lost_interval = expected_interval - received_interval; if (expected_interval == 0 || lost_interval <= 0) fraction = 0; else fraction = (lost_interval << 8) / expected_interval; return fraction; }