comparison src/twjit_out.c @ 5:1bb26347e253

twjit: split into separate base/in/out modules
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 05 Jul 2024 21:24:56 +0000
parents src/twjit.c@d10ea5dc61b3
children 4f82b9c07ddb
comparison
equal deleted inserted replaced
4:be04d84f5468 5:1bb26347e253
1 /*
2 * Themyscira Wireless jitter buffer implementation:
3 * output to the fixed timing system.
4 */
5
6 #include <stdint.h>
7 #include <stdbool.h>
8 #include <string.h>
9
10 #include <osmocom/core/linuxlist.h>
11 #include <osmocom/core/msgb.h>
12 #include <osmocom/core/utils.h>
13
14 #include <themwi/rtp/twjit.h>
15
16 static bool starting_sb_is_ready(struct twrtp_jibuf_inst *twjit)
17 {
18 struct twrtp_jibuf_sub *sb = &twjit->sb[twjit->write_sb];
19
20 if (sb->depth < sb->conf.bd_start)
21 return false;
22 if (sb->delta_ms < sb->conf.start_min_delta)
23 return false;
24 return true;
25 }
26
27 static bool read_sb_is_empty(struct twrtp_jibuf_inst *twjit)
28 {
29 struct twrtp_jibuf_sub *sb = &twjit->sb[twjit->read_sb];
30
31 return sb->depth == 0;
32 }
33
34 static struct msgb *pull_from_read_sb(struct twrtp_jibuf_inst *twjit)
35 {
36 struct twrtp_jibuf_sub *sb = &twjit->sb[twjit->read_sb];
37 struct msgb *msg;
38
39 OSMO_ASSERT(!llist_empty(&sb->queue));
40 OSMO_ASSERT(sb->depth > 0);
41 msg = llist_entry(sb->queue.next, struct msgb, list);
42 if (msg->cb[0] == sb->head_ts) {
43 llist_del(&msg->list);
44 twjit->stats.delivered_pkt++;
45 twjit->stats.delivered_bytes += msg->len;
46 } else {
47 msg = NULL;
48 twjit->stats.output_gaps++;
49 }
50 sb->head_ts += twjit->ts_quantum;
51 sb->depth--;
52 return msg;
53 }
54
55 static void read_sb_thinning(struct twrtp_jibuf_inst *twjit)
56 {
57 struct twrtp_jibuf_sub *sb = &twjit->sb[twjit->read_sb];
58 struct msgb *msg;
59
60 if (sb->drop_int_count) {
61 sb->drop_int_count--;
62 return;
63 }
64 if (sb->depth <= sb->conf.bd_hiwat)
65 return;
66 twjit->stats.thinning_drops++;
67 msg = pull_from_read_sb(twjit);
68 if (msg)
69 msgb_free(msg);
70 sb->drop_int_count = sb->conf.thinning_int - 2;
71 }
72
73 static void toss_read_queue(struct twrtp_jibuf_inst *twjit)
74 {
75 struct twrtp_jibuf_sub *sb = &twjit->sb[twjit->read_sb];
76
77 msgb_queue_free(&sb->queue);
78 sb->depth = 0;
79 }
80
81 struct msgb *twrtp_jibuf_output(struct twrtp_jibuf_inst *twjit)
82 {
83 switch (twjit->state) {
84 case TWJIT_STATE_EMPTY:
85 return NULL;
86 case TWJIT_STATE_HUNT:
87 if (!starting_sb_is_ready(twjit))
88 return NULL;
89 twjit->state = TWJIT_STATE_FLOWING;
90 twjit->read_sb = twjit->write_sb;
91 return pull_from_read_sb(twjit);
92 case TWJIT_STATE_FLOWING:
93 if (read_sb_is_empty(twjit)) {
94 twjit->state = TWJIT_STATE_EMPTY;
95 twjit->stats.underruns++;
96 return NULL;
97 }
98 read_sb_thinning(twjit);
99 return pull_from_read_sb(twjit);
100 case TWJIT_STATE_HANDOVER:
101 if (starting_sb_is_ready(twjit)) {
102 toss_read_queue(twjit);
103 twjit->state = TWJIT_STATE_FLOWING;
104 twjit->read_sb = twjit->write_sb;
105 return pull_from_read_sb(twjit);
106 }
107 if (read_sb_is_empty(twjit)) {
108 twjit->state = TWJIT_STATE_HUNT;
109 twjit->stats.underruns++;
110 return NULL;
111 }
112 read_sb_thinning(twjit);
113 return pull_from_read_sb(twjit);
114 default:
115 OSMO_ASSERT(0);
116 }
117 }