forked from ka9q/ka9q-radio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rtcp.c
127 lines (104 loc) · 3.48 KB
/
rtcp.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Real Time Control Protocol (RTCP) for ka9q-radio - very primitive and not yet complete or tested
// Sep 2018-2023 Phil Karn, KA9Q
#include <sys/types.h>
#include <string.h>
#include <stdint.h>
#include "multicast.h"
// Build a RTCP sender report in network order
// Return pointer to byte after end of written packet
uint8_t *gen_sr(uint8_t *output,int bufsize,struct rtcp_sr const *sr,struct rtcp_rr const *rr,int rc){
int words = 1 + 6 + 6*rc;
if(4*words > bufsize)
return NULL; // Not enough room in buffer
// SR packet header
*output++ = (2 << 6) | rc;
*output++ = 200;
output = put16(output,words-1);
// Sender info
output = put32(output,sr->ssrc);
output = put32(output,sr->ntp_timestamp >> 32);
output = put32(output,sr->ntp_timestamp);
output = put32(output,sr->rtp_timestamp);
output = put32(output,sr->packet_count);
output = put32(output,sr->byte_count);
// Receiver info (if any)
for(int i=0; i < rc; i++){
output = put32(output,rr->ssrc);
*output++ = rr->lost_fract;
output = put24(output,rr->lost_packets);
output = put32(output,rr->highest_seq);
output = put32(output,rr->jitter);
output = put32(output,rr->lsr);
output = put32(output,rr->dlsr);
rr++;
}
return output;
}
// Build a RTCP receiver report in network order
// Return pointer to byte after end of written packet
uint8_t *gen_rr(uint8_t *output,int bufsize,uint32_t ssrc,struct rtcp_rr const *rr,int rc){
int words = 2 + 6*rc;
if(4*words > bufsize)
return NULL; // Not enough room in buffer
// RR packet header
*output++ = (2 << 6) | rc;
*output++ = 201; // Receiver report
output = put16(output,words-1);
output = put32(output,ssrc);
// Receiver info (if any)
for(int i=0; i < rc; i++){
output = put32(output,rr->ssrc);
*output++ = rr->lost_fract;
output = put24(output,rr->lost_packets);
output = put32(output,rr->highest_seq);
output = put32(output,rr->jitter);
output = put32(output,rr->lsr);
output = put32(output,rr->dlsr);
rr++;
}
return output;
}
// Build a RTCP source description packet in network order
// Return pointer to byte after end of written packet
uint8_t *gen_sdes(uint8_t *output,int bufsize,uint32_t ssrc,struct rtcp_sdes const *sdes,int sc){
if(sc < 0 || sc > 31) // Range check on source count
return NULL;
// Calculate size
int bytes = 4 + 4 + 1; // header + ssrc + terminating null
for(int i=0; i < sc; i++){
if(sdes[i].mlen < 0 || sdes[i].mlen > 255)
return NULL;
bytes += 2 + sdes[i].mlen; // type + length + item
}
// Round up to 4 byte boundary
int words = (bytes + 3)/4;
if(4*words > bufsize)
return NULL;
memset(output,0,bufsize); // easist way to guarantee nulls at end
uint8_t *dp = output;
*dp++ = (2 << 6) | 1; // Only one chunk per message at present
*dp++ = 202; // SDES
dp = put16(dp,words-1);
dp = put32(dp,ssrc);
// Put each item
for(int i=0; i<sc; i++){
*dp++ = sdes[i].type;
*dp++ = sdes[i].mlen;
memcpy(dp,sdes[i].message,sdes[i].mlen); // Buffer overrun avoided by size calc?
dp += sdes[i].mlen;
}
return output + words*4;
}
uint8_t *gen_bye(uint8_t *output,int bufsize,uint32_t const *ssrcs,int sc){
if(sc < 0 || sc > 31) // Range check on source count
return NULL;
int words = 1 + sc;
if(4*words > bufsize)
return NULL;
*output++ = (2 << 6) | sc;
*output++ = 203; // BYE
output = put16(output,words-1);
for(int i=0; i<sc; i++)
output = put32(output,ssrcs[i]);
return output;
}