UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
tfrc.c
Go to the documentation of this file.
1/*
2 * FILE: tfrc.c
3 * AUTHOR: Ladan Gharai <ladan@isi.edu>
4 * MODIFIED: Colin Perkins <csp@isi.edu>
5 *
6 * Copyright (C) 2002 USC Information Sciences Institute
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, is permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 *
22 * This product includes software developed by the University of Southern
23 * California Information Sciences Institute.
24 *
25 * 4. Neither the name of the University nor of the Institute may be used
26 * to endorse or promote products derived from this software without
27 * specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
30 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
31 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
32 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
33 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
34 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
36 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
39 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
40 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 *
42 * $Revision: 1.1 $
43 * $Date: 2007/11/08 09:48:59 $
44 *
45 */
46
47#include "config.h"
48#include "config_unix.h"
49#include "config_win32.h"
50#include "debug.h"
51#include "rtp/rtp.h"
52#include "tv.h"
53#include "tfrc.h"
54
55#define TFRC_MAGIC 0xbaef03b7 /* For debugging */
56
57#define MAX_HISTORY 1000
58#define N 8 /* number of intervals */
59#define MAX_DROPOUT 100
60#define RTP_SEQ_MOD 0x10000
61#define MAX_MISORDER 100
62
63/*
64 * The state of this TFRC connection, stored in a struct that is passed to
65 * all TFRC routines so we can have multiple connections active at once.
66 * See tfrc_init() for initialisation.
67 *
68 */
69struct tfrc {
71 int ooo;
72 int cycles; /* number of times seq number cycles 65535 */
73 uint32_t RTT; /* received from sender in app packet */
74 time_ns_t feedback_timer; /* indicates points in time when p should be computed */
75 double p, p_prev;
76 int s;
80 int gap[20];
81 int jj; /* index for arrival -1<=i<=MAX_HISTORY */
82 int ii; /* index for loss -1<=ii<=10 */
83 double W_tot;
84 double weight[N + 5]; /* Weights for loss event calculation. In the RFC, the numbering is the other way around */
85 uint32_t magic; /* For debugging */
86};
87
88static void validate_tfrc_state(struct tfrc *state)
89{
90 /* Debugging routine. Called each time we enter TFRC code, */
91 /* to ensure that the state information we've been given */
92 /* is valid. */
93 assert(state->magic == TFRC_MAGIC);
94#ifdef DEBUG
95 /* ...do some fancy debugging... */
96#endif
97}
98
99static struct {
100 uint32_t seq;
101 uint32_t ts;
103
104static struct {
105 uint32_t seq;
106 uint32_t ts;
108
109#ifdef NDEF
110static double transfer_rate(double p)
111{
112 double t, t1, t2, t3, t4, rtt, tRTO;
113 if (p == 0) {
114 return 0;
115 }
116
117 /* convert RTT from usec to sec */
118 rtt = ((double)RTT) / 1000000.0;
119 tRTO = 4 * rtt;
120
121 t1 = rtt * sqrt(2 * p / 3);
122 t2 = (1 + 32 * p * p);
123 t3 = 3 * sqrt(3 * p / 8);
124 t4 = t1 + tRTO * t3 * p * t2;
125 t = ((double)s) / t4;
126
127 return (t);
128}
129
130static void compute_transfer_rate(void)
131{
132 double t1;
133 time_ns_t now;
134
135 t1 = transfer_rate(p);
136 now = get_time_in_ns()
137}
138#endif
139
140static int set_zero(int first, int last, uint16_t u)
141{
142 int i, count = 0;;
143
144 assert((first >= 0) && (first < MAX_HISTORY));
145 assert((last >= 0) && (last < MAX_HISTORY));
146
147 if (first == last)
148 return (0);
149 if ((first + 1) % MAX_HISTORY == last)
150 return (1);
151
152 if (first < last) {
153 for (i = first + 1; i < last; i++) {
154 arrival[i].seq = 0;
155 arrival[i].ts = 0;
156 count++;
157 }
158 } else {
159 for (i = first + 1; i < MAX_HISTORY; i++) {
160 arrival[i].seq = 0;
161 arrival[i].ts = 0;
162 count++;
163 }
164 for (i = 0; i < last; i++) {
165 arrival[i].seq = 0;
166 arrival[i].ts = 0;
167 count++;
168 }
169 }
170 assert(count == (u - 1));
171 return (count);
172}
173
174static int arrived(int first, int last)
175{
176 int i, count = 0;
177
178 assert((first >= 0) && (first < MAX_HISTORY));
179 assert((last >= 0) && (last < MAX_HISTORY));
180
181 if (first == last)
182 return (0);
183 if ((first + 1) % MAX_HISTORY == last)
184 return (0);
185
186 if (first < last) {
187 for (i = first; i <= last; i++) {
188 if (arrival[i].seq != 0)
189 count++;
190 }
191 } else {
192 for (i = first; i < MAX_HISTORY; i++) {
193 if (arrival[i].seq != 0)
194 count++;
195 }
196 for (i = 0; i <= last; i++) {
197 if (arrival[i].seq != 0)
198 count++;
199 }
200 }
201 return (count);
202}
203
204static void
205record_loss(struct tfrc *state, uint32_t s1, uint32_t s2, uint32_t ts1,
206 uint32_t ts2)
207{
208 /* Mark all packets between s1 (which arrived at time ts1) and */
209 /* s2 (which arrived at time ts2) as lost. */
210 int i;
211 uint32_t est;
212 uint32_t seq = s1 + 1;
213
214 est = ts1 + (ts2 - ts1) * ((seq - s1) / (s2 - seq));
215
216 state->loss_count++;
217 if (state->ii <= -1) {
218 /* first loss! */
219 state->ii++;
220 loss[state->ii].seq = seq;
221 loss[state->ii].ts = est;
222 return;
223 }
224
225 if (est - loss[state->ii].ts <= state->RTT) { /* not a new event */
226 return;
227 }
228
229 state->interval_count++;
230 if (state->ii > (N + 1)) {
231 printf("how did this happen?\n");
232 }
233
234 if (state->ii >= (N + 1)) { /* shift */
235 for (i = 0; i < (N + 1); i++) {
236 loss[i].seq = loss[i + 1].seq;
237 loss[i].ts = loss[i + 1].ts;
238 }
239 state->ii = N;
240 }
241
242 state->ii++;
243 loss[state->ii].seq = seq;
244 loss[state->ii].ts = est;
245}
246
247static void
248save_arrival(struct tfrc *state, time_ns_t curr_time, uint16_t seq)
249{
250 int kk, inc, last_jj;
251 uint16_t udelta;
252 uint32_t now;
253 uint32_t ext_seq;
254 static uint16_t last_seq;
255 static uint32_t ext_last_ack;
256 static int last_ack_jj = 0;
257
258 curr_time = get_time_in_ns();
259 now = (curr_time - state->start_time) / 1000;
260
261 if (state->jj == -1) {
262 /* first packet arrival */
263 state->jj = 0;
264 last_seq = seq;
265 ext_last_ack = seq;
266 last_ack_jj = 0;
267 arrival[state->jj].seq = seq;
268 arrival[state->jj].ts = now;
269 return;
270 }
271
272 udelta = seq - last_seq;
273
274 state->total_pckts++;
275 if (udelta < MAX_DROPOUT) {
276 /* in order, with permissible gap */
277 if (seq < last_seq) {
278 state->cycles++;
279 }
280 /* record arrival */
281 last_jj = state->jj;
282 state->jj = (state->jj + udelta) % MAX_HISTORY;
283 set_zero(last_jj, state->jj, udelta);
284 ext_seq = seq + state->cycles * RTP_SEQ_MOD;
285 last_seq = seq;
286 arrival[state->jj].seq = ext_seq;
287 arrival[state->jj].ts = now;
288 if (udelta < 10)
289 state->gap[udelta - 1]++;
290
291 if ((ext_seq - ext_last_ack) == 1) {
292 /* We got two consecutive packets, no loss */
293 ext_last_ack = ext_seq;
294 last_ack_jj = state->jj;
295 } else {
296 /* Sequence number jumped, we've missed a packet for some reason */
297 if (arrived(last_ack_jj, state->jj) >= 4) {
298 record_loss(state, ext_last_ack, ext_seq,
299 arrival[last_ack_jj].ts, now);
300 ext_last_ack = ext_seq;
301 last_ack_jj = state->jj;
302 }
303 }
304 } else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) {
305 printf(" -- seq:%u last seq:%u ", seq, arrival[state->jj].seq);
306 abort(); /* FIXME */
307 } else {
308 /* duplicate or reordered packet */
309 ext_seq = seq + state->cycles * RTP_SEQ_MOD;
310 state->ooo++;
311 if (ext_seq > ext_last_ack) {
312 inc = ext_seq - arrival[state->jj].seq;
313
314 kk = (state->jj + inc) % MAX_HISTORY;
315 if (arrival[kk].seq == 0) {
316 arrival[kk].seq = ext_seq;
317 arrival[kk].ts = (arrival[last_ack_jj].ts + now) / 2; /* NOT the best interpolation */
318 }
319 while (arrival[last_ack_jj + 1].seq != 0
320 && last_ack_jj < state->jj) {
321 last_ack_jj = (last_ack_jj + 1) % MAX_HISTORY;
322 }
323 ext_last_ack = arrival[last_ack_jj].seq;
324 }
325 }
326}
327
328static double compute_loss_event(struct tfrc *state)
329{
330 int i;
331 uint32_t t __attribute__((unused));
332 uint32_t temp, I_tot0 = 0, I_tot1 = 0, I_tot = 0;
333 double I_mean, p;
334
335 if (state->ii < N) {
336 return 0;
337 }
338
339 for (i = state->ii - N; i < state->ii; i++) {
340 temp = loss[i + 1].seq - loss[i].seq;
341 I_tot0 = I_tot0 + temp * state->weight[i];
342 if (i >= (state->ii - N + 1)) {
343 I_tot1 = I_tot1 + temp * state->weight[i - 1];
344 }
345 }
346 I_tot1 =
347 I_tot1 + (arrival[state->jj].seq -
348 loss[state->ii].seq) * state->weight[N - 1];
349
350 I_tot = (I_tot1 > I_tot0) ? I_tot1 : I_tot0;
351 I_mean = I_tot / state->W_tot;
352 p = 1 / I_mean;
353
354 t = (get_time_in_ns() - state->start_time) / 1000;
355
356 return p;
357
358}
359
360/*
361 * External API follows...
362 *
363 */
364
365struct tfrc *tfrc_init(time_ns_t curr_time)
366{
367 struct tfrc *state;
368 int i;
369
370 state = (struct tfrc *)malloc(sizeof(struct tfrc));
371 if (state != NULL) {
372 state->magic = TFRC_MAGIC;
373 state->total_pckts = 0;
374 state->ooo = 0;
375 state->cycles = 0;
376 state->RTT = 0;
377 state->feedback_timer = curr_time;
378 state->p = 0.0;
379 state->p_prev = 0.0;
380 state->s = 0;
381 state->start_time = curr_time;
382 state->loss_count = 0;
383 state->interval_count = 0;
384 state->jj = -1;
385 state->ii = -1;
386 state->W_tot = 0;
387 state->weight[0] = 0.2;
388 state->weight[1] = 0.4;
389 state->weight[2] = 0.6;
390 state->weight[3] = 0.8;
391 state->weight[4] = 1.0;
392 state->weight[5] = 1.0;
393 state->weight[6] = 1.0;
394 state->weight[7] = 1.0;
395 state->weight[8] = 1.0;
396
397 for (i = 0; i < 20; i++) {
398 state->gap[i] = 0;
399 }
400
401 for (i = 0; i < N; i++) {
402 state->W_tot = state->W_tot + state->weight[i];
403 }
404 }
405
406 for (i = 0; i < MAX_HISTORY; i++) {
407 arrival[i].seq = 0;
408 arrival[i].ts = 0;
409 loss[i].seq = 0;
410 loss[i].ts = 0;
411 }
412 return state;
413}
414
415void tfrc_done(struct tfrc *state)
416{
417 int i;
418
420
421 if (log_level >= LOG_LEVEL_DEBUG) {
422 for (i = 0; i < 10; i++) {
423 printf("\n%2d %8d", i, state->gap[i]);
424 }
425 printf("\n");
426 printf("\nLost: %8d", state->loss_count);
427 printf("\nIntervals: %8d", state->interval_count);
428 printf("\nTotal: %8d", state->total_pckts);
429 printf("\nooo: %8d -- %7.5f\n\n", state->ooo,
430 (state->ooo * 100) / (double)state->total_pckts);
431 }
432 free(state);
433}
434
435void
436tfrc_recv_data(struct tfrc *state, time_ns_t curr_time, uint16_t seqnum,
437 unsigned length)
438{
439 /* This is called each time an RTP packet is received. Accordingly, */
440 /* it needs to be _very_ fast, otherwise we'll drop packets. */
441
443
444 if (state->RTT > 0) {
445 save_arrival(state, curr_time, seqnum);
446 state->p_prev = state->p;
447#ifdef NDEF
449 if (state->p - state->p_prev > 0.00000000001) {
450 gettimeofday(&(state->feedback_timer), NULL);
451 tv_add(&(state->feedback_timer),
452 (unsigned int)state->RTT);
453 compute_transfer_rate();
454 }
455#endif
456 }
457 state->s = length; /* packet size is needed transfer_rate */
458}
459
460void tfrc_recv_rtt(struct tfrc *state, time_ns_t curr_time, uint32_t rtt)
461{
462 /* Called whenever the receiver gets an RTCP APP packet telling */
463 /* it the RTT to the sender. Not performance critical. */
464 /* Note: RTT is in microseconds. */
465
467
468 if (state->RTT == 0) {
469 state->feedback_timer = curr_time + rtt * NS_IN_SEC;
470 }
471 state->RTT = rtt;
472}
473
475{
476 /* Determine if it is time to send feedback to the sender */
478
479 if ((state->RTT == 0) || state->feedback_timer > curr_time) {
480 /* Not yet time to send feedback to the sender... */
481 return FALSE;
482 }
483 return TRUE;
484}
485
486double tfrc_feedback_txrate(struct tfrc *state, time_ns_t curr_time)
487{
488 /* Calculate the appropriate transmission rate, to be included */
489 /* in a feedback message to the sender. */
490
492
493 assert(tfrc_feedback_is_due(state, curr_time));
494
495 state->feedback_timer = curr_time + state->RTT * NS_IN_SEC;
497 //compute_transfer_rate ();
498 if (state->ii >= N) {
499 abort(); /* FIXME */
500 }
501 return 0.0; /* FIXME */
502}
void ** state
#define TRUE
#define FALSE
int count
Definition hd-rum.c:44
uint32_t RTT
Definition host.cpp:171
#define LOG_LEVEL_DEBUG
Definition kernels.cu:48
volatile int log_level
Definition debug.cpp:65
struct __attribute__((packed))
Definition rtp.h:88
codec_t first
Definition sdl2.c:423
Definition tfrc.c:69
int jj
Definition tfrc.c:81
int s
Definition tfrc.c:76
double weight[N+5]
Definition tfrc.c:84
time_ns_t feedback_timer
Definition tfrc.c:74
double W_tot
Definition tfrc.c:83
uint32_t RTT
Definition tfrc.c:73
int ooo
Definition tfrc.c:71
double p
Definition tfrc.c:75
int cycles
Definition tfrc.c:72
int total_pckts
Definition tfrc.c:70
time_ns_t start_time
Definition tfrc.c:77
int loss_count
Definition tfrc.c:78
uint32_t magic
Definition tfrc.c:85
int gap[20]
Definition tfrc.c:80
int interval_count
Definition tfrc.c:79
double p_prev
Definition tfrc.c:75
int ii
Definition tfrc.c:82
#define N
Definition tfrc.c:58
struct tfrc * tfrc_init(time_ns_t curr_time)
Definition tfrc.c:365
double tfrc_feedback_txrate(struct tfrc *state, time_ns_t curr_time)
Definition tfrc.c:486
static struct @50 arrival[MAX_HISTORY]
uint32_t ts
Definition tfrc.c:101
void tfrc_recv_rtt(struct tfrc *state, time_ns_t curr_time, uint32_t rtt)
Definition tfrc.c:460
#define MAX_DROPOUT
Definition tfrc.c:59
static int set_zero(int first, int last, uint16_t u)
Definition tfrc.c:140
void tfrc_recv_data(struct tfrc *state, time_ns_t curr_time, uint16_t seqnum, unsigned length)
Definition tfrc.c:436
uint32_t seq
Definition tfrc.c:100
static void record_loss(struct tfrc *state, uint32_t s1, uint32_t s2, uint32_t ts1, uint32_t ts2)
Definition tfrc.c:205
#define MAX_HISTORY
Definition tfrc.c:57
static struct @51 loss[MAX_HISTORY]
void tfrc_done(struct tfrc *state)
Definition tfrc.c:415
static int arrived(int first, int last)
Definition tfrc.c:174
#define TFRC_MAGIC
Definition tfrc.c:55
static double compute_loss_event(struct tfrc *state)
Definition tfrc.c:328
#define RTP_SEQ_MOD
Definition tfrc.c:60
int tfrc_feedback_is_due(struct tfrc *state, time_ns_t curr_time)
Definition tfrc.c:474
#define MAX_MISORDER
Definition tfrc.c:61
static void validate_tfrc_state(struct tfrc *state)
Definition tfrc.c:88
static void save_arrival(struct tfrc *state, time_ns_t curr_time, uint16_t seq)
Definition tfrc.c:248
void tv_add(struct timeval *ts, double offset_secs)
Definition tv.c:130
long long time_ns_t
Definition tv.h:81
#define NS_IN_SEC
Definition tv.h:92
static time_ns_t get_time_in_ns()
Definition tv.h:101