-
Notifications
You must be signed in to change notification settings - Fork 8
/
rtp.c
197 lines (187 loc) · 5.45 KB
/
rtp.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*! \file rtp.c
* \author Lorenzo Miniero <[email protected]>
* \copyright GNU General Public License v3
* \brief RTP processing
* \details Implementation of the RTP header. Since the gateway does not
* much more than relaying frames around, the only thing we're interested
* in is the RTP header and how to get its payload, and parsing extensions.
*
* \ingroup protocols
* \ref protocols
*/
#include "rtp.h"
#include "debug.h"
char *janus_rtp_payload(char *buf, int len, int *plen) {
if(!buf || len < 12)
return NULL;
rtp_header *rtp = (rtp_header *)buf;
int hlen = 12;
if(rtp->csrccount) /* Skip CSRC if needed */
hlen += rtp->csrccount*4;
if(rtp->extension) {
janus_rtp_header_extension *ext = (janus_rtp_header_extension*)(buf+hlen);
int extlen = ntohs(ext->length)*4;
hlen += 4;
if(len > (hlen + extlen))
hlen += extlen;
}
if(plen)
*plen = len-hlen;
return buf+hlen;
}
int janus_rtp_header_extension_get_id(const char *sdp, const char *extension) {
if(!sdp || !extension)
return -1;
char extmap[100];
g_snprintf(extmap, 100, "a=extmap:%%d %s", extension);
/* Look for the extmap */
const char *line = strstr(sdp, "m=");
while(line) {
char *next = strchr(line, '\n');
if(next) {
*next = '\0';
if(strstr(line, "a=extmap") && strstr(line, extension)) {
/* Gotcha! */
int id = 0;
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
if(sscanf(line, extmap, &id) == 1) {
#pragma GCC diagnostic warning "-Wformat-nonliteral"
*next = '\n';
return id;
}
}
*next = '\n';
}
line = next ? (next+1) : NULL;
}
return -2;
}
const char *janus_rtp_header_extension_get_from_id(const char *sdp, int id) {
if(!sdp || id < 0)
return NULL;
/* Look for the mapping */
char extmap[100];
g_snprintf(extmap, 100, "a=extmap:%d ", id);
const char *line = strstr(sdp, "m=");
while(line) {
char *next = strchr(line, '\n');
if(next) {
*next = '\0';
if(strstr(line, extmap)) {
/* Gotcha! */
char extension[100];
if(sscanf(line, "a=extmap:%d %s", &id, extension) == 2) {
*next = '\n';
if(strstr(extension, JANUS_RTP_EXTMAP_AUDIO_LEVEL))
return JANUS_RTP_EXTMAP_AUDIO_LEVEL;
if(strstr(extension, JANUS_RTP_EXTMAP_VIDEO_ORIENTATION))
return JANUS_RTP_EXTMAP_VIDEO_ORIENTATION;
if(strstr(extension, JANUS_RTP_EXTMAP_PLAYOUT_DELAY))
return JANUS_RTP_EXTMAP_PLAYOUT_DELAY;
if(strstr(extension, JANUS_RTP_EXTMAP_TOFFSET))
return JANUS_RTP_EXTMAP_TOFFSET;
if(strstr(extension, JANUS_RTP_EXTMAP_ABS_SEND_TIME))
return JANUS_RTP_EXTMAP_ABS_SEND_TIME;
if(strstr(extension, JANUS_RTP_EXTMAP_CC_EXTENSIONS))
return JANUS_RTP_EXTMAP_CC_EXTENSIONS;
JANUS_LOG(LOG_ERR, "Unsupported extension '%s'\n", extension);
return NULL;
}
}
*next = '\n';
}
line = next ? (next+1) : NULL;
}
return NULL;
}
/* Static helper to quickly find the extension data */
static int janus_rtp_header_extension_find(char *buf, int len, int id, uint8_t *byte, uint32_t *word) {
if(!buf || len < 12)
return -1;
rtp_header *rtp = (rtp_header *)buf;
int hlen = 12;
if(rtp->csrccount) /* Skip CSRC if needed */
hlen += rtp->csrccount*4;
if(rtp->extension) {
janus_rtp_header_extension *ext = (janus_rtp_header_extension*)(buf+hlen);
int extlen = ntohs(ext->length)*4;
hlen += 4;
if(len > (hlen + extlen)) {
/* 1-Byte extension */
if(ntohs(ext->type) == 0xBEDE) {
const uint8_t padding = 0x00, reserved = 0xF;
uint8_t extid = 0, idlen;
int i = 0;
while(i < extlen) {
extid = buf[hlen+i] >> 4;
if(extid == reserved) {
break;
} else if(extid == padding) {
i++;
continue;
}
idlen = (buf[hlen+i] & 0xF)+1;
if(extid == id) {
/* Found! */
if(byte)
*byte = buf[hlen+i+1];
if(word)
*word = *(uint32_t *)(buf+hlen+i);
return 0;
}
i += 1 + idlen;
}
}
hlen += extlen;
}
}
return -1;
}
int janus_rtp_header_extension_parse_audio_level(char *buf, int len, int id, int *level) {
uint8_t byte = 0;
if(janus_rtp_header_extension_find(buf, len, id, &byte, NULL) < 0)
return -1;
/* a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level */
int v = (byte & 0x80) >> 7;
int value = byte & 0x7F;
JANUS_LOG(LOG_DBG, "%02x --> v=%d, level=%d\n", byte, v, value);
if(level)
*level = value;
return 0;
}
int janus_rtp_header_extension_parse_video_orientation(char *buf, int len, int id,
gboolean *c, gboolean *f, gboolean *r1, gboolean *r0) {
uint8_t byte = 0;
if(janus_rtp_header_extension_find(buf, len, id, &byte, NULL) < 0)
return -1;
/* a=extmap:4 urn:3gpp:video-orientation */
gboolean cbit = (byte & 0x08) >> 3;
gboolean fbit = (byte & 0x04) >> 2;
gboolean r1bit = (byte & 0x02) >> 1;
gboolean r0bit = byte & 0x01;
JANUS_LOG(LOG_DBG, "%02x --> c=%d, f=%d, r1=%d, r0=%d\n", byte, cbit, fbit, r1bit, r0bit);
if(c)
*c = cbit;
if(f)
*f = fbit;
if(r1)
*r1 = r1bit;
if(r0)
*r0 = r0bit;
return 0;
}
int janus_rtp_header_extension_parse_playout_delay(char *buf, int len, int id,
uint16_t *min_delay, uint16_t *max_delay) {
uint32_t bytes = 0;
if(janus_rtp_header_extension_find(buf, len, id, NULL, &bytes) < 0)
return -1;
/* a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay */
uint16_t min = (bytes & 0x00FFF000) >> 12;
uint16_t max = bytes & 0x00000FFF;
JANUS_LOG(LOG_DBG, "%"SCNu32"x --> min=%"SCNu16", max=%"SCNu16"\n", bytes, min, max);
if(min_delay)
*min_delay = min;
if(max_delay)
*max_delay = max;
return 0;
}