Coverage Report

Created: 2026-09-01 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/janus-gateway/src/rtp.c
Line
Count
Source
1
/*! \file    rtp.c
2
 * \author   Lorenzo Miniero <lorenzo@meetecho.com>
3
 * \copyright GNU General Public License v3
4
 * \brief    RTP processing
5
 * \details  Implementation of the RTP header. Since the server does not
6
 * much more than relaying frames around, the only thing we're interested
7
 * in is the RTP header and how to get its payload, and parsing extensions.
8
 *
9
 * \ingroup protocols
10
 * \ref protocols
11
 */
12
13
#include <string.h>
14
#include "rtp.h"
15
#include "rtpsrtp.h"
16
#include "debug.h"
17
18
/* Local, private, structures for parsing video-layers-allocation extensions */
19
typedef struct janus_rtp_vla_spatial_layer {
20
  uint8_t id;
21
  uint8_t tls;
22
} janus_rtp_vla_spatial_layer;
23
24
typedef struct janus_rtp_vla_rtp_stream {
25
  uint8_t rid;
26
  uint8_t sl_bm;
27
  janus_rtp_vla_spatial_layer sl[4];
28
} janus_rtp_vla_rtp_stream;
29
30
/* Public methods */
31
698
gboolean janus_is_rtp(char *buf, guint len) {
32
698
  if (len < 12)
33
7
    return FALSE;
34
691
  janus_rtp_header *header = (janus_rtp_header *)buf;
35
691
  return ((header->type < 64) || (header->type >= 96));
36
698
}
37
38
615
char *janus_rtp_payload(char *buf, int len, int *plen) {
39
615
  if(!buf || len < 12)
40
0
    return NULL;
41
615
  janus_rtp_header *rtp = (janus_rtp_header *)buf;
42
615
  if (rtp->version != 2) {
43
4
    return NULL;
44
4
  }
45
611
  int hlen = 12;
46
611
  if(rtp->csrccount)  /* Skip CSRC if needed */
47
7
    hlen += rtp->csrccount*4;
48
49
611
  if(rtp->extension) {
50
287
    janus_rtp_header_extension *ext = (janus_rtp_header_extension *)(buf+hlen);
51
287
    int extlen = ntohs(ext->length)*4;
52
287
    hlen += 4;
53
287
    if(len > (hlen + extlen))
54
285
      hlen += extlen;
55
287
  }
56
611
  if (len-hlen <= 0) {
57
7
    return NULL;
58
7
  }
59
604
  if(plen)
60
604
    *plen = len-hlen;
61
604
  return buf+hlen;
62
611
}
63
64
0
int janus_rtp_header_extension_get_id(const char *sdp, const char *extension) {
65
0
  if(!sdp || !extension)
66
0
    return -1;
67
0
  char extmap[100];
68
0
  g_snprintf(extmap, 100, "a=extmap:%%d %s", extension);
69
  /* Look for the extmap */
70
0
  const char *line = strstr(sdp, "m=");
71
0
  while(line) {
72
0
    char *next = strchr(line, '\n');
73
0
    if(next) {
74
0
      *next = '\0';
75
0
      if(strstr(line, "a=extmap") && strstr(line, extension)) {
76
        /* Gotcha! */
77
0
        int id = 0;
78
0
#pragma GCC diagnostic push
79
0
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
80
0
        if(sscanf(line, extmap, &id) == 1) {
81
0
#pragma GCC diagnostic pop
82
0
          *next = '\n';
83
0
          return id;
84
0
        }
85
0
      }
86
0
      *next = '\n';
87
0
    }
88
0
    line = next ? (next+1) : NULL;
89
0
  }
90
0
  return -2;
91
0
}
92
93
0
const char *janus_rtp_header_extension_get_from_id(const char *sdp, int id) {
94
0
  if(!sdp || id < 0)
95
0
    return NULL;
96
  /* Look for the mapping */
97
0
  char extmap[100];
98
0
  g_snprintf(extmap, 100, "a=extmap:%d ", id);
99
0
  const char *line = strstr(sdp, "m=");
100
0
  while(line) {
101
0
    char *next = strchr(line, '\n');
102
0
    if(next) {
103
0
      *next = '\0';
104
0
      if(strstr(line, extmap)) {
105
        /* Gotcha! */
106
0
        char extension[100];
107
0
        if(sscanf(line, "a=extmap:%d %99s", &id, extension) == 2) {
108
0
          *next = '\n';
109
0
          if(strstr(extension, JANUS_RTP_EXTMAP_AUDIO_LEVEL))
110
0
            return JANUS_RTP_EXTMAP_AUDIO_LEVEL;
111
0
          if(strstr(extension, JANUS_RTP_EXTMAP_VIDEO_ORIENTATION))
112
0
            return JANUS_RTP_EXTMAP_VIDEO_ORIENTATION;
113
0
          if(strstr(extension, JANUS_RTP_EXTMAP_PLAYOUT_DELAY))
114
0
            return JANUS_RTP_EXTMAP_PLAYOUT_DELAY;
115
0
          if(strstr(extension, JANUS_RTP_EXTMAP_TOFFSET))
116
0
            return JANUS_RTP_EXTMAP_TOFFSET;
117
0
          if(strstr(extension, JANUS_RTP_EXTMAP_ABS_SEND_TIME))
118
0
            return JANUS_RTP_EXTMAP_ABS_SEND_TIME;
119
0
          if(strstr(extension, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME))
120
0
            return JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME;
121
0
          if(strstr(extension, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC))
122
0
            return JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC;
123
0
          if(strstr(extension, JANUS_RTP_EXTMAP_MID))
124
0
            return JANUS_RTP_EXTMAP_MID;
125
0
          if(strstr(extension, JANUS_RTP_EXTMAP_RID))
126
0
            return JANUS_RTP_EXTMAP_RID;
127
0
          if(strstr(extension, JANUS_RTP_EXTMAP_REPAIRED_RID))
128
0
            return JANUS_RTP_EXTMAP_REPAIRED_RID;
129
0
          if(strstr(extension, JANUS_RTP_EXTMAP_DEPENDENCY_DESC))
130
0
            return JANUS_RTP_EXTMAP_DEPENDENCY_DESC;
131
0
          if(strstr(extension, JANUS_RTP_EXTMAP_VIDEO_LAYERS))
132
0
            return JANUS_RTP_EXTMAP_VIDEO_LAYERS;
133
0
          JANUS_LOG(LOG_ERR, "Unsupported extension '%s'\n", extension);
134
0
          return NULL;
135
0
        }
136
0
      }
137
0
      *next = '\n';
138
0
    }
139
0
    line = next ? (next+1) : NULL;
140
0
  }
141
0
  return NULL;
142
0
}
143
144
/* Static helper to quickly find the extension data */
145
static int janus_rtp_header_extension_find(char *buf, int len, int id,
146
6.28k
    uint8_t *byte, uint32_t *word, char **ref, uint8_t *idlen) {
147
6.28k
  if(idlen == NULL)
148
0
    return -1;
149
6.28k
  *idlen = 0;
150
6.28k
  if(!buf || len < 12)
151
0
    return -2;
152
6.28k
  janus_rtp_header *rtp = (janus_rtp_header *)buf;
153
6.28k
  if(rtp->version != 2) {
154
56
    return -3;
155
56
  }
156
6.23k
  int hlen = 12;
157
6.23k
  if(rtp->csrccount)  /* Skip CSRC if needed */
158
94
    hlen += rtp->csrccount*4;
159
6.23k
  if(rtp->extension && (len > hlen + (int)sizeof(janus_rtp_header_extension))) {
160
2.90k
    janus_rtp_header_extension *ext = (janus_rtp_header_extension *)(buf+hlen);
161
2.90k
    int extlen = ntohs(ext->length)*4;
162
2.90k
    hlen += 4;
163
2.90k
    if(len > (hlen + extlen)) {
164
2.85k
      if(ntohs(ext->type) == 0xBEDE) {
165
        /* 1-Byte extension */
166
1.24k
        const uint8_t padding = 0x00, reserved = 0xF;
167
1.24k
        uint8_t extid = 0;
168
1.24k
        int i = 0;
169
18.7k
        while(i < extlen) {
170
18.4k
          extid = (uint8_t)buf[hlen+i] >> 4;
171
18.4k
          if(extid == reserved) {
172
50
            break;
173
18.3k
          } else if(extid == padding) {
174
11.0k
            i++;
175
11.0k
            continue;
176
11.0k
          }
177
7.29k
          *idlen = ((uint8_t)buf[hlen+i] & 0xF)+1;
178
7.29k
          i++;
179
7.29k
          if(extid == id && ((i+*idlen) <= extlen)) {
180
            /* Found! */
181
870
            if(byte)
182
174
              *byte = (uint8_t)buf[hlen+i];
183
870
            if(word && *idlen >= 4 && (i+4) < extlen) {
184
40
              memcpy(word, buf+hlen+i, sizeof(uint32_t));
185
40
              *word = ntohl(*word);
186
40
            }
187
870
            if(ref)
188
609
              *ref = &buf[hlen+i];
189
870
            return 0;
190
870
          }
191
6.42k
          i += *idlen;
192
6.42k
        }
193
1.61k
      } else if(ntohs(ext->type) == 0x1000) {
194
        /* 2-Byte extension */
195
1.07k
        const uint8_t padding = 0x00;
196
1.07k
        uint8_t extid = 0;
197
1.07k
        int i = 0;
198
9.72k
        while(i < extlen) {
199
9.31k
          if((extlen-i) < 2)
200
60
            break;
201
9.25k
          extid = buf[hlen+i];
202
9.25k
          if(extid == padding) {
203
5.46k
            i += 2;
204
5.46k
            continue;
205
5.46k
          }
206
3.79k
          i++;
207
3.79k
          *idlen = buf[hlen+i];
208
3.79k
          i++;
209
3.79k
          if(extid == id && ((i+*idlen) <= extlen)) {
210
            /* Found! */
211
600
            if(byte)
212
120
              *byte = (uint8_t)buf[hlen+i];
213
600
            if(word && *idlen >= 4 && (i+4) < extlen) {
214
53
              memcpy(word, buf+hlen+i, sizeof(uint32_t));
215
53
              *word = ntohl(*word);
216
53
            }
217
600
            if(ref)
218
420
              *ref = &buf[hlen+i];
219
600
            return 0;
220
600
          }
221
3.19k
          i += *idlen;
222
3.19k
        }
223
1.07k
      }
224
1.38k
      hlen += extlen;
225
1.38k
    }
226
2.90k
  }
227
4.76k
  return -1;
228
6.23k
}
229
230
615
int janus_rtp_header_extension_parse_audio_level(char *buf, int len, int id, gboolean *vad, int *level) {
231
615
  uint8_t byte = 0, idlen = 0;
232
615
  if(janus_rtp_header_extension_find(buf, len, id, &byte, NULL, NULL, &idlen) < 0)
233
468
    return -1;
234
  /* a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level */
235
147
  gboolean v = (byte & 0x80) >> 7;
236
147
  int value = byte & 0x7F;
237
147
  JANUS_LOG(LOG_DBG, "%02x --> v=%d, level=%d\n", byte, v, value);
238
147
  if(vad)
239
0
    *vad = v;
240
147
  if(level)
241
0
    *level = value;
242
147
  return 0;
243
615
}
244
245
int janus_rtp_header_extension_parse_video_orientation(char *buf, int len, int id,
246
615
    gboolean *c, gboolean *f, gboolean *r1, gboolean *r0) {
247
615
  uint8_t byte = 0, idlen = 0;
248
615
  if(janus_rtp_header_extension_find(buf, len, id, &byte, NULL, NULL, &idlen) < 0)
249
468
    return -1;
250
  /* a=extmap:4 urn:3gpp:video-orientation */
251
147
  gboolean cbit = (byte & 0x08) >> 3;
252
147
  gboolean fbit = (byte & 0x04) >> 2;
253
147
  gboolean r1bit = (byte & 0x02) >> 1;
254
147
  gboolean r0bit = byte & 0x01;
255
147
  JANUS_LOG(LOG_DBG, "%02x --> c=%d, f=%d, r1=%d, r0=%d\n", byte, cbit, fbit, r1bit, r0bit);
256
147
  if(c)
257
147
    *c = cbit;
258
147
  if(f)
259
147
    *f = fbit;
260
147
  if(r1)
261
147
    *r1 = r1bit;
262
147
  if(r0)
263
147
    *r0 = r0bit;
264
147
  return 0;
265
615
}
266
267
int janus_rtp_header_extension_parse_playout_delay(char *buf, int len, int id,
268
615
    uint16_t *min_delay, uint16_t *max_delay) {
269
615
  uint32_t bytes = 0;
270
615
  uint8_t idlen = 0;
271
615
  if(janus_rtp_header_extension_find(buf, len, id, NULL, &bytes, NULL, &idlen) < 0)
272
468
    return -1;
273
147
  if(idlen < 3)
274
30
    return -2;
275
  /* a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay */
276
117
  uint16_t min = (bytes & 0x00FFF000) >> 12;
277
117
  uint16_t max = bytes & 0x00000FFF;
278
117
  JANUS_LOG(LOG_DBG, "%"SCNu32"x --> min=%"SCNu16", max=%"SCNu16"\n", bytes, min, max);
279
117
  if(min_delay)
280
0
    *min_delay = min;
281
117
  if(max_delay)
282
0
    *max_delay = max;
283
117
  return 0;
284
147
}
285
286
int janus_rtp_header_extension_parse_mid(char *buf, int len, int id,
287
684
    char *sdes_item, int sdes_len) {
288
684
  char *ext = NULL;
289
684
  uint8_t idlen = 0;
290
684
  if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext, &idlen) < 0)
291
537
    return -1;
292
  /* a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid */
293
147
  if(ext == NULL || idlen < 1)
294
1
    return -2;
295
146
  if(idlen > (sdes_len-1)) {
296
43
    JANUS_LOG(LOG_WARN, "Buffer is too small (%d > %d), MID will be cut\n", idlen, sdes_len);
297
43
    idlen = sdes_len-1;
298
43
  }
299
146
  if(idlen > len-(ext-buf)-1) {
300
0
    return -3;
301
0
  }
302
146
  memcpy(sdes_item, ext, idlen);
303
146
  *(sdes_item+idlen) = '\0';
304
146
  return 0;
305
146
}
306
307
int janus_rtp_header_extension_parse_rid(char *buf, int len, int id,
308
684
    char *sdes_item, int sdes_len) {
309
684
  char *ext = NULL;
310
684
  uint8_t idlen = 0;
311
684
  if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext, &idlen) < 0)
312
537
    return -1;
313
  /* a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id */
314
  /* a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id */
315
147
  if(ext == NULL || idlen < 1)
316
1
    return -2;
317
146
  if(idlen > (sdes_len-1)) {
318
43
    JANUS_LOG(LOG_WARN, "Buffer is too small (%d > %d), RTP stream ID will be cut\n", idlen, sdes_len);
319
43
    idlen = sdes_len-1;
320
43
  }
321
146
  if(idlen > len-(ext-buf)-1) {
322
0
    return -3;
323
0
  }
324
146
  memcpy(sdes_item, ext, idlen);
325
146
  *(sdes_item+idlen) = '\0';
326
146
  return 0;
327
146
}
328
329
int janus_rtp_header_extension_parse_dependency_desc(char *buf, int len, int id,
330
615
    uint8_t *dd_item, int *dd_len) {
331
615
  char *ext = NULL;
332
615
  uint8_t idlen = 0;
333
615
  int buflen = *dd_len;
334
615
  *dd_len = 0;
335
615
  if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext, &idlen) < 0)
336
468
    return -1;
337
  /* a=extmap:10 https://aomediacodec.github.io/av1-rtp-spec/#dependency-descriptor-rtp-header-extension */
338
147
  if(ext == NULL || idlen < 1)
339
1
    return -2;
340
146
  if(idlen > buflen) {
341
0
    JANUS_LOG(LOG_WARN, "Buffer is too small (%d > %d), dependency descriptor will be cut\n", idlen, buflen);
342
0
    idlen = buflen;
343
0
  }
344
146
  if(idlen > len-(ext-buf)-1) {
345
0
    return -3;
346
0
  }
347
146
  memcpy(dd_item, ext, idlen);
348
146
  *dd_len = idlen;
349
146
  return 0;
350
146
}
351
352
615
int janus_rtp_header_extension_parse_abs_send_time(char *buf, int len, int id, uint32_t *abs_ts) {
353
615
  char *ext = NULL;
354
615
  uint8_t idlen = 0;
355
615
  if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext, &idlen) < 0)
356
468
    return -1;
357
  /* a=extmap:4 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time */
358
147
  if(ext == NULL)
359
0
    return -2;
360
147
  if(idlen < 3 || idlen > len-(ext-buf)-1)
361
30
    return -3;
362
117
  uint32_t abs24 = 0;
363
117
  memcpy(&abs24, ext, 3);
364
117
  if(abs_ts)
365
0
    *abs_ts = ntohl(abs24 << 8);
366
117
  return 0;
367
147
}
368
369
0
int janus_rtp_header_extension_set_abs_send_time(char *buf, int len, int id, uint32_t abs_ts) {
370
0
  char *ext = NULL;
371
0
  uint8_t idlen = 0;
372
0
  if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext, &idlen) < 0)
373
0
    return -1;
374
0
  if(ext == NULL)
375
0
    return -2;
376
0
  if(idlen < 3 || idlen > len-(ext-buf)-1)
377
0
    return -3;
378
0
  uint32_t abs24 = htonl(abs_ts) >> 8;
379
0
  memcpy(ext, &abs24, 3);
380
0
  return 0;
381
0
}
382
383
615
int janus_rtp_header_extension_parse_abs_capture_time(char *buf, int len, int id, uint64_t *abs_ts) {
384
615
  char *ext = NULL;
385
615
  uint8_t idlen = 0;
386
615
  if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext, &idlen) < 0)
387
468
    return -1;
388
  /* a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time */
389
147
  if(ext == NULL)
390
0
    return -2;
391
147
  if(idlen < 8 || idlen > len-(ext-buf)-1)
392
75
    return -3;
393
72
  uint64_t abs64 = 0;
394
72
  memcpy(&abs64, ext, 8);
395
72
  if(abs_ts)
396
0
    *abs_ts = ntohll(abs64);
397
72
  return 0;
398
147
}
399
400
0
int janus_rtp_header_extension_set_abs_capture_time(char *buf, int len, int id, uint64_t abs_ts) {
401
0
  char *ext = NULL;
402
0
  uint8_t idlen = 0;
403
0
  if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext, &idlen) < 0)
404
0
    return -1;
405
0
  if(ext == NULL)
406
0
    return -2;
407
0
  if(idlen < 8 || idlen > len-(ext-buf)-1)
408
0
    return -3;
409
0
  uint64_t abs64 = htonll(abs_ts);
410
0
  memcpy(ext, &abs64, 8);
411
0
  return 0;
412
0
}
413
414
615
int janus_rtp_header_extension_parse_transport_wide_cc(char *buf, int len, int id, uint16_t *transSeqNum) {
415
615
  char *ext = NULL;
416
615
  uint8_t idlen = 0;
417
615
  if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext, &idlen) < 0)
418
468
    return -1;
419
  /*  0                   1                   2                   3
420
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
421
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
422
     |  ID   | L=1   |transport-wide sequence number | zero padding  |
423
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
424
  */
425
147
  if(ext == NULL)
426
0
    return -2;
427
147
  if(idlen < 2 || idlen > len-(ext-buf)-1)
428
12
    return -3;
429
135
  memcpy(transSeqNum, ext, sizeof(uint16_t));
430
135
  *transSeqNum = ntohs(*transSeqNum);
431
135
  return 0;
432
147
}
433
434
0
int janus_rtp_header_extension_set_transport_wide_cc(char *buf, int len, int id, uint16_t transSeqNum) {
435
0
  char *ext = NULL;
436
0
  uint8_t idlen = 0;
437
0
  if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext, &idlen) < 0)
438
0
    return -1;
439
0
  if(ext == NULL)
440
0
    return -2;
441
0
  if(idlen < 2 || idlen > len-(ext-buf)-1)
442
0
    return -3;
443
0
  transSeqNum = htons(transSeqNum);
444
0
  memcpy(ext, &transSeqNum, sizeof(uint16_t));
445
0
  return 0;
446
0
}
447
448
int janus_rtp_header_extension_parse_video_layers_allocation(char *buf, int len, int id,
449
615
    int8_t *spatial_layers, int8_t *temporal_layers) {
450
615
  char *ext = NULL;
451
615
  uint8_t idlen = 0;
452
615
  if(janus_rtp_header_extension_find(buf, len, id, NULL, NULL, &ext, &idlen) < 0)
453
468
    return -1;
454
  /* a=extmap:9 http://www.webrtc.org/experiments/rtp-hdrext/video-layers-allocation00 */
455
147
  if(ext == NULL || idlen < 2)
456
12
    return -2;
457
  /* Parse the extension to reconstruct the layers topology */
458
135
  janus_rtp_vla_rtp_stream streams[4] = { 0 };
459
  /* First byte */
460
135
  uint8_t offset = 0;
461
135
  uint8_t ns = (ext[offset] & 0x30) >> 4;
462
135
  uint8_t sl_bm = ext[offset] & 0x0F;
463
135
  offset++;
464
  /* Spatial layer bitmasks (up to two bytes) */
465
135
  uint8_t i = 0;
466
503
  for(i=0; i<=ns; i++) {
467
373
    if(sl_bm > 0) {
468
      /* Copy the shared value */
469
240
      streams[i].sl_bm = sl_bm;
470
240
    } else {
471
133
      if(i == 2) {
472
30
        offset++;
473
30
        if(offset == idlen)
474
5
          return -3;
475
30
      }
476
128
      if(i % 2 == 0) {
477
78
        streams[i].sl_bm = (ext[offset] & 0xF0) >> 4;
478
78
      } else {
479
50
        streams[i].sl_bm = ext[offset] & 0x0F;
480
50
      }
481
128
    }
482
373
  }
483
130
  if(sl_bm == 0)
484
48
    offset++;
485
130
  if(offset == idlen)
486
5
    return -3;
487
  /* Temporal layers (one byte) */
488
125
  uint8_t j = 0, boff = 8, sl = 0, tl = 0;
489
448
  for(i=0; i<=ns; i++) {
490
339
    sl = 0;
491
1.66k
    for(j=0; j<4; j++) {
492
1.34k
      if((streams[i].sl_bm & (1 << j)) == 0)
493
550
        continue;
494
792
      sl++;
495
792
      boff -= 2;
496
792
      streams[i].sl[j].id = j;
497
792
      streams[i].sl[j].tls = (ext[offset] >> boff) & 0x03;
498
792
      tl = streams[i].sl[j].tls + 1;
499
792
      if(temporal_layers && tl > *temporal_layers)
500
0
        *temporal_layers = tl;
501
792
      if(boff == 0) {
502
176
        boff = 8;
503
176
        offset++;
504
176
        if(offset == idlen)
505
16
          return -3;
506
176
      }
507
792
    }
508
323
    if(spatial_layers && sl > *spatial_layers)
509
0
      *spatial_layers = sl;
510
323
  }
511
  /* Done, we don't care about bitrates and resolutions for now */
512
109
  return 0;
513
125
}
514
515
0
int janus_rtp_header_extension_replace_id(char *buf, int len, int id, int new_id) {
516
0
  if(!buf || len < 12)
517
0
    return -1;
518
0
  janus_rtp_header *rtp = (janus_rtp_header *)buf;
519
0
  if (rtp->version != 2) {
520
0
    return -2;
521
0
  }
522
0
  int hlen = 12;
523
0
  if(rtp->csrccount) /* Skip CSRC if needed */
524
0
    hlen += rtp->csrccount*4;
525
0
  if(rtp->extension) {
526
0
    janus_rtp_header_extension *ext = (janus_rtp_header_extension *)(buf+hlen);
527
0
    int extlen = ntohs(ext->length)*4;
528
0
    hlen += 4;
529
0
    if(len > (hlen + extlen)) {
530
0
      if(ntohs(ext->type) == 0xBEDE) {
531
        /* 1-Byte extension */
532
0
        const uint8_t padding = 0x00, reserved = 0xF;
533
0
        uint8_t extid = 0, idlen = 0;
534
0
        int i = 0;
535
0
        while(i < extlen) {
536
0
          extid = buf[hlen+i] >> 4;
537
0
          if(extid == reserved) {
538
0
            break;
539
0
          } else if(extid == padding) {
540
0
            i++;
541
0
            continue;
542
0
          }
543
0
          idlen = (buf[hlen+i] & 0xF)+1;
544
0
          if(extid == id) {
545
            /* Found! */
546
0
            buf[hlen+i] = (new_id << 4) + (idlen - 1);
547
0
            return 0;
548
0
          }
549
0
          i += 1 + idlen;
550
0
        }
551
0
      } if(ntohs(ext->type) == 0x1000) {
552
        /* 2-Byte extension */
553
0
        const uint8_t padding = 0x00;
554
0
        uint8_t extid = 0, idlen = 0;
555
0
        int i = 0;
556
0
        while(i < extlen) {
557
0
          if((extlen-i) < 2)
558
0
            break;
559
0
          extid = buf[hlen+i];
560
0
          if(extid == padding) {
561
0
            i += 2;
562
0
            continue;
563
0
          }
564
0
          if(extid == id) {
565
            /* Found! */
566
0
            buf[hlen+i] = new_id;
567
0
            return 0;
568
0
          }
569
0
          i++;
570
0
          idlen = buf[hlen+i];
571
0
          i += 1 + idlen;
572
0
        }
573
0
      }
574
0
      hlen += extlen;
575
0
    }
576
0
  }
577
0
  return -3;
578
0
}
579
580
0
int janus_rtp_extension_id(const char *type) {
581
0
  if(type == NULL)
582
0
    return 0;
583
0
  if(!strcasecmp(type, JANUS_RTP_EXTMAP_AUDIO_LEVEL))
584
0
    return 1;
585
0
  else if(!strcasecmp(type, JANUS_RTP_EXTMAP_TOFFSET))
586
0
    return 14;
587
0
  else if(!strcasecmp(type, JANUS_RTP_EXTMAP_ABS_SEND_TIME))
588
0
    return 2;
589
0
  else if(!strcasecmp(type, JANUS_RTP_EXTMAP_ABS_CAPTURE_TIME))
590
0
    return 7;
591
0
  else if(!strcasecmp(type, JANUS_RTP_EXTMAP_VIDEO_ORIENTATION))
592
0
    return 13;
593
0
  else if(!strcasecmp(type, JANUS_RTP_EXTMAP_TRANSPORT_WIDE_CC))
594
0
    return 3;
595
0
  else if(!strcasecmp(type, JANUS_RTP_EXTMAP_PLAYOUT_DELAY))
596
0
    return 12;
597
0
  else if(!strcasecmp(type, JANUS_RTP_EXTMAP_MID))
598
0
    return 4;
599
0
  else if(!strcasecmp(type, JANUS_RTP_EXTMAP_RID))
600
0
    return 5;
601
0
  else if(!strcasecmp(type, JANUS_RTP_EXTMAP_REPAIRED_RID))
602
0
    return 6;
603
0
  return 0;
604
0
}
605
606
/* RTP context related methods */
607
0
void janus_rtp_switching_context_reset(janus_rtp_switching_context *context) {
608
0
  if(context == NULL)
609
0
    return;
610
  /* Reset the context values */
611
0
  memset(context, 0, sizeof(*context));
612
0
}
613
614
0
int janus_rtp_skew_compensate_audio(janus_rtp_header *header, janus_rtp_switching_context *context, gint64 now) {
615
  /* Reset values if a new ssrc has been detected */
616
0
  if(context->new_ssrc) {
617
0
    JANUS_LOG(LOG_VERB, "audio skew SSRC=%"SCNu32" resetting status\n", context->last_ssrc);
618
0
    context->reference_time = now;
619
0
    context->start_time = 0;
620
0
    context->evaluating_start_time = 0;
621
0
    context->start_ts = 0;
622
0
    context->active_delay = 0;
623
0
    context->prev_delay = 0;
624
0
    context->seq_offset = 0;
625
0
    context->ts_offset = 0;
626
0
    context->target_ts = 0;
627
0
    context->new_ssrc = FALSE;
628
0
  }
629
630
  /* N  : a N sequence number jump has been performed */
631
  /* 0    : any new skew compensation has been applied */
632
  /* -N   : a N packet drop must be performed */
633
0
  int exit_status = 0;
634
635
  /* Do not execute skew analysis in the first seconds */
636
0
  if(now-context->reference_time < SKEW_DETECTION_WAIT_TIME_SECS/2 * G_USEC_PER_SEC) {
637
0
    return 0;
638
0
  } else if(!context->start_time) {
639
0
    JANUS_LOG(LOG_VERB, "audio skew SSRC=%"SCNu32" evaluation phase start\n", context->last_ssrc);
640
0
    context->start_time = now;
641
0
    context->evaluating_start_time = now;
642
0
    context->start_ts = context->last_ts;
643
0
  }
644
645
  /* Skew analysis */
646
  /* Are we waiting for a target timestamp? (a negative skew has been evaluated in a previous iteration) */
647
0
  if(context->target_ts > 0 && (gint32)(context->target_ts - context->last_ts) > 0) {
648
0
    context->seq_offset--;
649
0
    exit_status = -1;
650
0
  } else {
651
0
    context->target_ts = 0;
652
    /* Do not execute analysis for out of order packets or multi-packets frame */
653
0
    if(context->last_seq == context->prev_seq + 1 && context->last_ts != context->prev_ts) {
654
      /* Set the sample rate according to the header */
655
0
      guint32 akhz = 48; /* 48khz for Opus */
656
0
      if(header->type == 0 || header->type == 8 || header->type == 9)
657
0
        akhz = 8;
658
      /* Evaluate the local RTP timestamp according to the local clock */
659
0
      guint32 expected_ts = ((now - context->start_time)*akhz)/1000 + context->start_ts;
660
      /* Evaluate current delay */
661
0
      gint32 delay_now = context->last_ts - expected_ts;
662
      /* Exponentially weighted moving average estimation */
663
0
      gint32 delay_estimate = (63*context->prev_delay + delay_now)/64;
664
      /* Save previous delay for the next iteration*/
665
0
      context->prev_delay = delay_estimate;
666
      /* Evaluate the distance between active delay and current delay estimate */
667
0
      gint32 offset = context->active_delay - delay_estimate;
668
0
      JANUS_LOG(LOG_HUGE, "audio skew status SSRC=%"SCNu32" RECVD_TS=%"SCNu32" EXPTD_TS=%"SCNu32" OFFSET=%"SCNi32" TS_OFFSET=%"SCNi32" SEQ_OFFSET=%"SCNi16"\n", context->last_ssrc, context->last_ts, expected_ts, offset, context->ts_offset, context->seq_offset);
669
0
      gint32 skew_th = RTP_AUDIO_SKEW_TH_MS*akhz;
670
      /* Evaluation phase */
671
0
      if(context->evaluating_start_time > 0) {
672
        /* Check if the offset has surpassed half the threshold during the evaluating phase */
673
0
        if(now-context->evaluating_start_time <= SKEW_DETECTION_WAIT_TIME_SECS/2 * G_USEC_PER_SEC) {
674
0
          if(abs(offset) <= skew_th/2) {
675
0
            JANUS_LOG(LOG_HUGE, "audio skew SSRC=%"SCNu32" evaluation phase continue\n", context->last_ssrc);
676
0
          } else {
677
0
            JANUS_LOG(LOG_VERB, "audio skew SSRC=%"SCNu32" evaluation phase reset\n", context->last_ssrc);
678
0
            context->start_time = now;
679
0
            context->evaluating_start_time = now;
680
0
            context->start_ts = context->last_ts;
681
0
          }
682
0
        } else {
683
0
          JANUS_LOG(LOG_VERB, "audio skew SSRC=%"SCNu32" evaluation phase stop\n", context->last_ssrc);
684
0
          context->evaluating_start_time = 0;
685
0
        }
686
0
        return 0;
687
0
      }
688
      /* Check if the offset has surpassed the threshold */
689
0
      if(offset >= skew_th) {
690
        /* The source is slowing down */
691
        /* Update active delay */
692
0
        context->active_delay = delay_estimate;
693
        /* Adjust ts offset */
694
0
        context->ts_offset += skew_th;
695
        /* Calculate last ts increase */
696
0
        guint32 ts_incr = context->last_ts-context->prev_ts;
697
        /* Evaluate sequence number jump */
698
0
        guint16 jump = (skew_th+ts_incr-1)/ts_incr;
699
        /* Adjust seq num offset */
700
0
        context->seq_offset += jump;
701
0
        exit_status = jump;
702
0
      } else if(offset <= -skew_th) {
703
        /* The source is speeding up*/
704
        /* Update active delay */
705
0
        context->active_delay = delay_estimate;
706
        /* Adjust ts offset */
707
0
        context->ts_offset -= skew_th;
708
        /* Set target ts */
709
0
        context->target_ts = context->last_ts + skew_th;
710
0
        if (context->target_ts == 0)
711
0
          context->target_ts = 1;
712
        /* Adjust seq num offset */
713
0
        context->seq_offset--;
714
0
        exit_status = -1;
715
0
      }
716
0
    }
717
0
  }
718
719
  /* Skew compensation */
720
  /* Fix header timestamp considering the active offset */
721
0
  guint32 fixed_rtp_ts = context->last_ts + context->ts_offset;
722
0
  header->timestamp = htonl(fixed_rtp_ts);
723
  /* Fix header sequence number considering the total offset */
724
0
  guint16 fixed_rtp_seq = context->last_seq + context->seq_offset;
725
0
  header->seq_number = htons(fixed_rtp_seq);
726
727
0
  return exit_status;
728
0
}
729
730
0
int janus_rtp_skew_compensate_video(janus_rtp_header *header, janus_rtp_switching_context *context, gint64 now) {
731
  /* Reset values if a new ssrc has been detected */
732
0
  if(context->new_ssrc) {
733
0
    JANUS_LOG(LOG_VERB, "video skew SSRC=%"SCNu32" resetting status\n", context->last_ssrc);
734
0
    context->reference_time = now;
735
0
    context->start_time = 0;
736
0
    context->evaluating_start_time = 0;
737
0
    context->start_ts = 0;
738
0
    context->active_delay = 0;
739
0
    context->prev_delay = 0;
740
0
    context->seq_offset = 0;
741
0
    context->ts_offset = 0;
742
0
    context->target_ts = 0;
743
0
    context->new_ssrc = FALSE;
744
0
  }
745
746
  /* N  : a N sequence numbers jump has been performed */
747
  /* 0    : any new skew compensation has been applied */
748
  /* -N   : a N packets drop must be performed */
749
0
  int exit_status = 0;
750
751
  /* Do not execute skew analysis in the first seconds */
752
0
  if(now-context->reference_time < SKEW_DETECTION_WAIT_TIME_SECS/2 *G_USEC_PER_SEC) {
753
0
    return 0;
754
0
  } else if(!context->start_time) {
755
0
    JANUS_LOG(LOG_VERB, "video skew SSRC=%"SCNu32" evaluation phase start\n", context->last_ssrc);
756
0
    context->start_time = now;
757
0
    context->evaluating_start_time = now;
758
0
    context->start_ts = context->last_ts;
759
0
  }
760
761
  /* Skew analysis */
762
  /* Are we waiting for a target timestamp? (a negative skew has been evaluated in a previous iteration) */
763
0
  if(context->target_ts > 0 && (gint32)(context->target_ts - context->last_ts) > 0) {
764
0
    context->seq_offset--;
765
0
    exit_status = -1;
766
0
  } else {
767
0
    context->target_ts = 0;
768
    /* Do not execute analysis for out of order packets or multi-packets frame */
769
0
    if(context->last_seq == context->prev_seq + 1 && context->last_ts != context->prev_ts) {
770
      /* Set the sample rate */
771
0
      guint32 vkhz = 90; /* 90khz */
772
      /* Evaluate the local RTP timestamp according to the local clock */
773
0
      guint32 expected_ts = ((now - context->start_time)*vkhz)/1000 + context->start_ts;
774
      /* Evaluate current delay */
775
0
      gint32 delay_now = context->last_ts - expected_ts;
776
      /* Exponentially weighted moving average estimation */
777
0
      gint32 delay_estimate = (63*context->prev_delay + delay_now)/64;
778
      /* Save previous delay for the next iteration*/
779
0
      context->prev_delay = delay_estimate;
780
      /* Evaluate the distance between active delay and current delay estimate */
781
0
      gint32 offset = context->active_delay - delay_estimate;
782
0
      JANUS_LOG(LOG_HUGE, "video skew status SSRC=%"SCNu32" RECVD_TS=%"SCNu32" EXPTD_TS=%"SCNu32" OFFSET=%"SCNi32" TS_OFFSET=%"SCNi32" SEQ_OFFSET=%"SCNi16"\n", context->last_ssrc, context->last_ts, expected_ts, offset, context->ts_offset, context->seq_offset);
783
0
      gint32 skew_th = RTP_VIDEO_SKEW_TH_MS*vkhz;
784
      /* Evaluation phase */
785
0
      if(context->evaluating_start_time > 0) {
786
        /* Check if the offset has surpassed half the threshold during the evaluating phase */
787
0
        if(now-context->evaluating_start_time <= SKEW_DETECTION_WAIT_TIME_SECS/2 * G_USEC_PER_SEC) {
788
0
          if(abs(offset) <= skew_th/2) {
789
0
            JANUS_LOG(LOG_HUGE, "video skew SSRC=%"SCNu32" evaluation phase continue\n", context->last_ssrc);
790
0
          } else {
791
0
            JANUS_LOG(LOG_VERB, "video skew SSRC=%"SCNu32" evaluation phase reset\n", context->last_ssrc);
792
0
            context->start_time = now;
793
0
            context->evaluating_start_time = now;
794
0
            context->start_ts = context->last_ts;
795
0
          }
796
0
        } else {
797
0
          JANUS_LOG(LOG_VERB, "video skew SSRC=%"SCNu32" evaluation phase stop\n", context->last_ssrc);
798
0
          context->evaluating_start_time = 0;
799
0
        }
800
0
        return 0;
801
0
      }
802
      /* Check if the offset has surpassed the threshold */
803
0
      if(offset >= skew_th) {
804
        /* The source is slowing down */
805
        /* Update active delay */
806
0
        context->active_delay = delay_estimate;
807
        /* Adjust ts offset */
808
0
        context->ts_offset += skew_th;
809
        /* Calculate last ts increase */
810
0
        guint32 ts_incr = context->last_ts-context->prev_ts;
811
        /* Evaluate sequence number jump */
812
0
        guint16 jump = (skew_th+ts_incr-1)/ts_incr;
813
        /* Adjust seq num offset */
814
0
        context->seq_offset += jump;
815
0
        exit_status = jump;
816
0
      } else if(offset <= -skew_th) {
817
        /* The source is speeding up*/
818
        /* Update active delay */
819
0
        context->active_delay = delay_estimate;
820
        /* Adjust ts offset */
821
0
        context->ts_offset -= skew_th;
822
        /* Set target ts */
823
0
        context->target_ts = context->last_ts + skew_th;
824
0
        if(context->target_ts == 0)
825
0
          context->target_ts = 1;
826
        /* Adjust seq num offset */
827
0
        context->seq_offset--;
828
0
        exit_status = -1;
829
0
      }
830
0
    }
831
0
  }
832
833
  /* Skew compensation */
834
  /* Fix header timestamp considering the active offset */
835
0
  guint32 fixed_rtp_ts = context->last_ts + context->ts_offset;
836
0
  header->timestamp = htonl(fixed_rtp_ts);
837
  /* Fix header sequence number considering the total offset */
838
0
  guint16 fixed_rtp_seq = context->last_seq + context->seq_offset;
839
0
  header->seq_number = htons(fixed_rtp_seq);
840
841
0
  return exit_status;
842
0
}
843
844
0
void janus_rtp_header_update(janus_rtp_header *header, janus_rtp_switching_context *context, gboolean video, int step) {
845
0
  if(header == NULL || context == NULL)
846
0
    return;
847
  /* Note: while the step property is still there for compatibility reasons, to
848
   * keep the signature as it was before, it's ignored: whenever there's a switch
849
   * to take into account, we compute how much time passed between the last RTP
850
   * packet with the old SSRC and this new one, and prepare a timestamp accordingly */
851
0
  uint32_t ssrc = ntohl(header->ssrc);
852
0
  uint32_t timestamp = ntohl(header->timestamp);
853
0
  uint16_t seq = ntohs(header->seq_number);
854
0
  if(ssrc != context->last_ssrc) {
855
    /* Audio SSRC changed: update both sequence number and timestamp */
856
0
    JANUS_LOG(LOG_VERB, "SSRC changed, %"SCNu32" --> %"SCNu32"\n",
857
0
      context->last_ssrc, ssrc);
858
0
    context->last_ssrc = ssrc;
859
0
    context->ts_reset = TRUE;
860
0
    context->seq_reset = TRUE;
861
    /* Reset skew compensation data */
862
0
    context->new_ssrc = TRUE;
863
0
  }
864
0
  if(context->ts_reset) {
865
    /* RTP timestamp was paused for a while */
866
0
    JANUS_LOG(LOG_HUGE, "RTP timestamp reset requested\n");
867
0
    context->ts_reset = FALSE;
868
0
    context->base_ts_prev = context->last_ts;
869
0
    context->base_ts = timestamp;
870
    /* How much time since the last audio RTP packet? We compute an offset accordingly */
871
0
    if(context->last_time > 0) {
872
0
      gint64 time_diff = janus_get_monotonic_time() - context->last_time;
873
      /* We're assuming 90khz for video and 48khz for audio, here */
874
0
      int khz = video ? 90 : 48;
875
0
      if(!video && (header->type == 0 || header->type == 8 || header->type == 9))
876
0
        khz = 8; /* We're assuming 48khz here (Opus), unless it's G.711/G.722 (8khz) */
877
0
      time_diff = (time_diff*khz)/1000;
878
0
      if(time_diff == 0)
879
0
        time_diff = 1;
880
0
      context->base_ts_prev += (guint32)time_diff;
881
0
      context->prev_ts += (guint32)time_diff;
882
0
      context->last_ts += (guint32)time_diff;
883
0
      JANUS_LOG(LOG_VERB, "Computed offset for RTP timestamp: %"SCNu32"\n", (guint32)time_diff);
884
0
    }
885
0
  }
886
0
  if(context->seq_reset) {
887
    /* Audio sequence number was paused for a while: just update that */
888
0
    context->seq_reset = FALSE;
889
0
    context->base_seq_prev = context->last_seq;
890
0
    context->base_seq = seq;
891
0
  }
892
  /* Compute a coherent timestamp and sequence number */
893
0
  context->prev_ts = context->last_ts;
894
0
  context->last_ts = (timestamp-context->base_ts) + context->base_ts_prev;
895
0
  context->prev_seq = context->last_seq;
896
0
  context->last_seq = (seq-context->base_seq)+context->base_seq_prev+1;
897
  /* Update the timestamp and sequence number in the RTP packet */
898
0
  header->timestamp = htonl(context->last_ts);
899
0
  header->seq_number = htons(context->last_seq);
900
  /* Take note of when we last handled this RTP packet */
901
0
  context->last_time = janus_get_monotonic_time();
902
0
}
903
904
905
/* SRTP stuff: we may need our own randomizer */
906
#ifdef HAVE_SRTP_2
907
0
int srtp_crypto_get_random(uint8_t *key, int len) {
908
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
909
  /* libsrtp 2.0 doesn't have crypto_get_random, we use OpenSSL's RAND_* to replace it:
910
   *    https://wiki.openssl.org/index.php/Random_Numbers */
911
  int rc = RAND_bytes(key, len);
912
  if(rc != 1) {
913
    /* Error generating */
914
    return -1;
915
  }
916
#endif
917
0
  return 0;
918
0
}
919
#endif
920
/* SRTP error codes as a string array */
921
static const char *janus_srtp_error[] =
922
{
923
#ifdef HAVE_SRTP_2
924
  "srtp_err_status_ok",
925
  "srtp_err_status_fail",
926
  "srtp_err_status_bad_param",
927
  "srtp_err_status_alloc_fail",
928
  "srtp_err_status_dealloc_fail",
929
  "srtp_err_status_init_fail",
930
  "srtp_err_status_terminus",
931
  "srtp_err_status_auth_fail",
932
  "srtp_err_status_cipher_fail",
933
  "srtp_err_status_replay_fail",
934
  "srtp_err_status_replay_old",
935
  "srtp_err_status_algo_fail",
936
  "srtp_err_status_no_such_op",
937
  "srtp_err_status_no_ctx",
938
  "srtp_err_status_cant_check",
939
  "srtp_err_status_key_expired",
940
  "srtp_err_status_socket_err",
941
  "srtp_err_status_signal_err",
942
  "srtp_err_status_nonce_bad",
943
  "srtp_err_status_read_fail",
944
  "srtp_err_status_write_fail",
945
  "srtp_err_status_parse_err",
946
  "srtp_err_status_encode_err",
947
  "srtp_err_status_semaphore_err",
948
  "srtp_err_status_pfkey_err",
949
#else
950
  "err_status_ok",
951
  "err_status_fail",
952
  "err_status_bad_param",
953
  "err_status_alloc_fail",
954
  "err_status_dealloc_fail",
955
  "err_status_init_fail",
956
  "err_status_terminus",
957
  "err_status_auth_fail",
958
  "err_status_cipher_fail",
959
  "err_status_replay_fail",
960
  "err_status_replay_old",
961
  "err_status_algo_fail",
962
  "err_status_no_such_op",
963
  "err_status_no_ctx",
964
  "err_status_cant_check",
965
  "err_status_key_expired",
966
  "err_status_socket_err",
967
  "err_status_signal_err",
968
  "err_status_nonce_bad",
969
  "err_status_read_fail",
970
  "err_status_write_fail",
971
  "err_status_parse_err",
972
  "err_status_encode_err",
973
  "err_status_semaphore_err",
974
  "err_status_pfkey_err",
975
#endif
976
};
977
0
const char *janus_srtp_error_str(int error) {
978
0
  if(error < 0 || error > 24)
979
0
    return NULL;
980
0
  return janus_srtp_error[error];
981
0
}
982
983
/* Payload types we'll offer internally */
984
0
#define OPUS_PT   111
985
0
#define MULTIOPUS_PT  OPUS_PT
986
0
#define OPUSRED_PT  120
987
0
#define ISAC32_PT 104
988
0
#define ISAC16_PT 103
989
0
#define PCMU_PT   0
990
0
#define PCMA_PT   8
991
0
#define G722_PT   9
992
0
#define L16_48_PT 105
993
0
#define L16_PT    106
994
0
#define VP8_PT    96
995
0
#define VP9_PT    101
996
0
#define H264_PT   107
997
0
#define AV1_PT    98
998
0
#define H265_PT   100
999
0
const char *janus_audiocodec_name(janus_audiocodec acodec) {
1000
0
  switch(acodec) {
1001
0
    case JANUS_AUDIOCODEC_NONE:
1002
0
      return "none";
1003
0
    case JANUS_AUDIOCODEC_OPUS:
1004
0
      return "opus";
1005
0
    case JANUS_AUDIOCODEC_MULTIOPUS:
1006
0
      return "multiopus";
1007
0
    case JANUS_AUDIOCODEC_OPUSRED:
1008
0
      return "red";
1009
0
    case JANUS_AUDIOCODEC_PCMU:
1010
0
      return "pcmu";
1011
0
    case JANUS_AUDIOCODEC_PCMA:
1012
0
      return "pcma";
1013
0
    case JANUS_AUDIOCODEC_G722:
1014
0
      return "g722";
1015
0
    case JANUS_AUDIOCODEC_ISAC_32K:
1016
0
      return "isac32";
1017
0
    case JANUS_AUDIOCODEC_ISAC_16K:
1018
0
      return "isac16";
1019
0
    case JANUS_AUDIOCODEC_L16_48K:
1020
0
      return "l16-48";
1021
0
    case JANUS_AUDIOCODEC_L16_16K:
1022
0
      return "l16";
1023
0
    default:
1024
      /* Shouldn't happen */
1025
0
      return "opus";
1026
0
  }
1027
0
}
1028
0
janus_audiocodec janus_audiocodec_from_name(const char *name) {
1029
0
  if(name == NULL)
1030
0
    return JANUS_AUDIOCODEC_NONE;
1031
0
  else if(!strcasecmp(name, "opus"))
1032
0
    return JANUS_AUDIOCODEC_OPUS;
1033
0
  else if(!strcasecmp(name, "multiopus"))
1034
0
    return JANUS_AUDIOCODEC_MULTIOPUS;
1035
0
  else if(!strcasecmp(name, "red"))
1036
0
    return JANUS_AUDIOCODEC_OPUSRED;
1037
0
  else if(!strcasecmp(name, "isac32"))
1038
0
    return JANUS_AUDIOCODEC_ISAC_32K;
1039
0
  else if(!strcasecmp(name, "isac16"))
1040
0
    return JANUS_AUDIOCODEC_ISAC_16K;
1041
0
  else if(!strcasecmp(name, "pcmu"))
1042
0
    return JANUS_AUDIOCODEC_PCMU;
1043
0
  else if(!strcasecmp(name, "pcma"))
1044
0
    return JANUS_AUDIOCODEC_PCMA;
1045
0
  else if(!strcasecmp(name, "g722"))
1046
0
    return JANUS_AUDIOCODEC_G722;
1047
0
  else if(!strcasecmp(name, "l16-48"))
1048
0
    return JANUS_AUDIOCODEC_L16_48K;
1049
0
  else if(!strcasecmp(name, "l16"))
1050
0
    return JANUS_AUDIOCODEC_L16_16K;
1051
0
  JANUS_LOG(LOG_WARN, "Unsupported audio codec '%s'\n", name);
1052
0
  return JANUS_AUDIOCODEC_NONE;
1053
0
}
1054
0
int janus_audiocodec_pt(janus_audiocodec acodec) {
1055
0
  switch(acodec) {
1056
0
    case JANUS_AUDIOCODEC_NONE:
1057
0
      return -1;
1058
0
    case JANUS_AUDIOCODEC_OPUS:
1059
0
      return OPUS_PT;
1060
0
    case JANUS_AUDIOCODEC_MULTIOPUS:
1061
0
      return MULTIOPUS_PT;
1062
0
    case JANUS_AUDIOCODEC_OPUSRED:
1063
0
      return OPUSRED_PT;
1064
0
    case JANUS_AUDIOCODEC_ISAC_32K:
1065
0
      return ISAC32_PT;
1066
0
    case JANUS_AUDIOCODEC_ISAC_16K:
1067
0
      return ISAC16_PT;
1068
0
    case JANUS_AUDIOCODEC_PCMU:
1069
0
      return PCMU_PT;
1070
0
    case JANUS_AUDIOCODEC_PCMA:
1071
0
      return PCMA_PT;
1072
0
    case JANUS_AUDIOCODEC_G722:
1073
0
      return G722_PT;
1074
0
    case JANUS_AUDIOCODEC_L16_48K:
1075
0
      return L16_48_PT;
1076
0
    case JANUS_AUDIOCODEC_L16_16K:
1077
0
      return L16_PT;
1078
0
    default:
1079
      /* Shouldn't happen */
1080
0
      return OPUS_PT;
1081
0
  }
1082
0
}
1083
1084
0
const char *janus_videocodec_name(janus_videocodec vcodec) {
1085
0
  switch(vcodec) {
1086
0
    case JANUS_VIDEOCODEC_NONE:
1087
0
      return "none";
1088
0
    case JANUS_VIDEOCODEC_VP8:
1089
0
      return "vp8";
1090
0
    case JANUS_VIDEOCODEC_VP9:
1091
0
      return "vp9";
1092
0
    case JANUS_VIDEOCODEC_H264:
1093
0
      return "h264";
1094
0
    case JANUS_VIDEOCODEC_AV1:
1095
0
      return "av1";
1096
0
    case JANUS_VIDEOCODEC_H265:
1097
0
      return "h265";
1098
0
    default:
1099
      /* Shouldn't happen */
1100
0
      return "vp8";
1101
0
  }
1102
0
}
1103
0
janus_videocodec janus_videocodec_from_name(const char *name) {
1104
0
  if(name == NULL)
1105
0
    return JANUS_VIDEOCODEC_NONE;
1106
0
  else if(!strcasecmp(name, "vp8"))
1107
0
    return JANUS_VIDEOCODEC_VP8;
1108
0
  else if(!strcasecmp(name, "vp9"))
1109
0
    return JANUS_VIDEOCODEC_VP9;
1110
0
  else if(!strcasecmp(name, "h264"))
1111
0
    return JANUS_VIDEOCODEC_H264;
1112
0
  else if(!strcasecmp(name, "av1"))
1113
0
    return JANUS_VIDEOCODEC_AV1;
1114
0
  else if(!strcasecmp(name, "h265"))
1115
0
    return JANUS_VIDEOCODEC_H265;
1116
0
  JANUS_LOG(LOG_WARN, "Unsupported video codec '%s'\n", name);
1117
0
  return JANUS_VIDEOCODEC_NONE;
1118
0
}
1119
0
int janus_videocodec_pt(janus_videocodec vcodec) {
1120
0
  switch(vcodec) {
1121
0
    case JANUS_VIDEOCODEC_NONE:
1122
0
      return -1;
1123
0
    case JANUS_VIDEOCODEC_VP8:
1124
0
      return VP8_PT;
1125
0
    case JANUS_VIDEOCODEC_VP9:
1126
0
      return VP9_PT;
1127
0
    case JANUS_VIDEOCODEC_H264:
1128
0
      return H264_PT;
1129
0
    case JANUS_VIDEOCODEC_AV1:
1130
0
      return AV1_PT;
1131
0
    case JANUS_VIDEOCODEC_H265:
1132
0
      return H265_PT;
1133
0
    default:
1134
      /* Shouldn't happen */
1135
0
      return VP8_PT;
1136
0
  }
1137
0
}
1138
1139
0
void janus_rtp_simulcasting_context_reset(janus_rtp_simulcasting_context *context) {
1140
0
  if(context == NULL)
1141
0
    return;
1142
  /* Reset the context values */
1143
0
  janus_av1_svc_context_reset(&context->av1_context[0]);
1144
0
  janus_av1_svc_context_reset(&context->av1_context[1]);
1145
0
  janus_av1_svc_context_reset(&context->av1_context[2]);
1146
0
  memset(context, 0, sizeof(*context));
1147
0
  context->rid_ext_id = -1;
1148
0
  context->substream = -1;
1149
0
  context->substream_target_temp = -1;
1150
0
  context->templayer = -1;
1151
0
}
1152
1153
0
void janus_rtp_simulcasting_prepare(json_t *simulcast, int *rid_ext_id, uint32_t *ssrcs, char **rids) {
1154
0
  if(simulcast == NULL)
1155
0
    return;
1156
0
  json_t *r = json_object_get(simulcast, "rids");
1157
0
  json_t *s = json_object_get(simulcast, "ssrcs");
1158
0
  if(r && json_array_size(r) > 0) {
1159
0
    JANUS_LOG(LOG_VERB, "  -- Simulcasting is rid based\n");
1160
0
    size_t i = 0;
1161
0
    int count = json_array_size(r);
1162
0
    for(i=count; i > 0; i--) {
1163
0
      json_t *rid = json_array_get(r, i-1);
1164
0
      if(rid && json_is_string(rid) && rids)
1165
0
        rids[count-i] = g_strdup(json_string_value(rid));
1166
0
    }
1167
0
    json_t *rid_ext = json_object_get(simulcast, "rid-ext");
1168
0
    if(rid_ext_id != NULL)
1169
0
      *rid_ext_id = json_integer_value(rid_ext);
1170
0
  } else if(s && json_array_size(s) > 0) {
1171
0
    JANUS_LOG(LOG_VERB, "  -- Simulcasting is SSRC based\n");
1172
0
    size_t i = 0;
1173
0
    for(i=0; i<json_array_size(s); i++) {
1174
0
      if(i == 3)
1175
0
        break;
1176
0
      json_t *ssrc = json_array_get(s, i);
1177
0
      if(ssrc && json_is_integer(ssrc) && ssrcs)
1178
0
        ssrcs[i] = json_integer_value(ssrc);
1179
0
    }
1180
0
  }
1181
0
}
1182
1183
0
void janus_rtp_simulcasting_cleanup(int *rid_ext_id, uint32_t *ssrcs, char **rids, janus_mutex *rid_mutex) {
1184
0
  if(rid_mutex != NULL)
1185
0
    janus_mutex_lock(rid_mutex);
1186
0
  if(rid_ext_id)
1187
0
    *rid_ext_id = -1;
1188
0
  if(ssrcs || rids) {
1189
0
    int i = 0;
1190
0
    for(i=0; i<3; i++) {
1191
0
      if(ssrcs)
1192
0
        *(ssrcs+i) = 0;
1193
0
      if(rids) {
1194
0
        g_free(rids[i]);
1195
0
        rids[i] = NULL;
1196
0
      }
1197
0
    }
1198
0
  }
1199
0
  if(rid_mutex != NULL)
1200
0
    janus_mutex_unlock(rid_mutex);
1201
0
}
1202
1203
gboolean janus_rtp_simulcasting_context_process_rtp(janus_rtp_simulcasting_context *context,
1204
    char *buf, int len, uint8_t *dd_content, int dd_len, uint32_t *ssrcs, char **rids,
1205
0
    janus_videocodec vcodec, janus_rtp_switching_context *sc, janus_mutex *rid_mutex) {
1206
0
  if(!context || !buf || len < 1)
1207
0
    return FALSE;
1208
0
  janus_rtp_header *header = (janus_rtp_header *)buf;
1209
0
  uint32_t ssrc = ntohl(header->ssrc);
1210
0
  int substream = -1;
1211
0
  if(ssrc == *(ssrcs)) {
1212
0
    substream = 0;
1213
0
  } else if(ssrc == *(ssrcs+1)) {
1214
0
    substream = 1;
1215
0
  } else if(ssrc == *(ssrcs+2)) {
1216
0
    substream = 2;
1217
0
  } else {
1218
    /* We don't recognize this SSRC, check if rid can help us */
1219
0
    if(context->rid_ext_id < 1 || rids == NULL)
1220
0
      return FALSE;
1221
0
    char sdes_item[16];
1222
0
    if(janus_rtp_header_extension_parse_rid(buf, len, context->rid_ext_id, sdes_item, sizeof(sdes_item)) != 0)
1223
0
      return FALSE;
1224
0
    if(rid_mutex != NULL)
1225
0
      janus_mutex_lock(rid_mutex);
1226
0
    if(rids[0] != NULL && !strcmp(rids[0], sdes_item)) {
1227
0
      JANUS_LOG(LOG_VERB, "Simulcasting: rid=%s --> ssrc=%"SCNu32"\n", sdes_item, ssrc);
1228
0
      *(ssrcs) = ssrc;
1229
0
      substream = 0;
1230
0
    } else if(rids[1] != NULL && !strcmp(rids[1], sdes_item)) {
1231
0
      JANUS_LOG(LOG_VERB, "Simulcasting: rid=%s --> ssrc=%"SCNu32"\n", sdes_item, ssrc);
1232
0
      *(ssrcs+1) = ssrc;
1233
0
      substream = 1;
1234
0
    } else if(rids[2] != NULL && !strcmp(rids[2], sdes_item)) {
1235
0
      JANUS_LOG(LOG_VERB, "Simulcasting: rid=%s --> ssrc=%"SCNu32"\n", sdes_item, ssrc);
1236
0
      *(ssrcs+2) = ssrc;
1237
0
      substream = 2;
1238
0
    }
1239
0
    if(rid_mutex != NULL)
1240
0
      janus_mutex_unlock(rid_mutex);
1241
0
    if(substream == -1) {
1242
0
      JANUS_LOG(LOG_WARN, "Simulcasting: unknown rid '%s'...\n", sdes_item);
1243
0
      return FALSE;
1244
0
    }
1245
0
  }
1246
  /* Reset the flags */
1247
0
  context->changed_substream = FALSE;
1248
0
  context->changed_temporal = FALSE;
1249
0
  context->need_pli = FALSE;
1250
0
  gint64 now = janus_get_monotonic_time();
1251
  /* Access the packet payload */
1252
0
  int plen = 0;
1253
0
  char *payload = janus_rtp_payload(buf, len, &plen);
1254
0
  if(payload == NULL)
1255
0
    return FALSE;
1256
  /* Check what's our target */
1257
0
  if(context->substream_target_temp != -1 && (substream > context->substream_target_temp ||
1258
0
      context->substream_target <= context->substream_target_temp)) {
1259
    /* We either just received media on a substream that is higher than
1260
     * the target we dropped to (which means the one we want is now flowing
1261
     * again) or we've been requested a lower substream target instead */
1262
0
    context->substream_target_temp = -1;
1263
0
  }
1264
0
  int target = (context->substream_target_temp == -1) ? context->substream_target : context->substream_target_temp;
1265
  /* Check what we need to do with the packet */
1266
0
  if(context->substream == -1) {
1267
0
    if((vcodec == JANUS_VIDEOCODEC_VP8 && janus_vp8_is_keyframe(payload, plen)) ||
1268
0
        (vcodec == JANUS_VIDEOCODEC_VP9 && janus_vp9_is_keyframe(payload, plen)) ||
1269
0
        (vcodec == JANUS_VIDEOCODEC_H264 && janus_h264_is_keyframe(payload, plen)) ||
1270
0
        (vcodec == JANUS_VIDEOCODEC_AV1 && janus_av1_is_keyframe(payload, plen)) ||
1271
0
        (vcodec == JANUS_VIDEOCODEC_H265 && janus_h265_is_keyframe(payload, plen))) {
1272
0
      context->substream = substream;
1273
      /* Notify the caller that the substream changed */
1274
0
      context->changed_substream = TRUE;
1275
0
      context->last_relayed = now;
1276
0
    } else {
1277
      /* Don't relay anything until we get a keyframe */
1278
0
      return FALSE;
1279
0
    }
1280
0
  } else if(context->substream != target) {
1281
    /* We're not on the substream we'd like: let's wait for a keyframe on the target */
1282
0
    if(((context->substream < target && substream > context->substream) ||
1283
0
        (context->substream > target && substream < context->substream)) &&
1284
0
          ((vcodec == JANUS_VIDEOCODEC_VP8 && janus_vp8_is_keyframe(payload, plen)) ||
1285
0
          (vcodec == JANUS_VIDEOCODEC_VP9 && janus_vp9_is_keyframe(payload, plen)) ||
1286
0
          (vcodec == JANUS_VIDEOCODEC_H264 && janus_h264_is_keyframe(payload, plen)) ||
1287
0
          (vcodec == JANUS_VIDEOCODEC_AV1 && janus_av1_is_keyframe(payload, plen)) ||
1288
0
          (vcodec == JANUS_VIDEOCODEC_H265 && janus_h265_is_keyframe(payload, plen)))) {
1289
0
      JANUS_LOG(LOG_VERB, "Received keyframe on #%d (SSRC %"SCNu32"), switching (was #%d/%"SCNu32")\n",
1290
0
        substream, ssrc, context->substream, *(ssrcs + context->substream));
1291
0
      context->substream = substream;
1292
      /* Notify the caller that the substream changed */
1293
0
      context->changed_substream = TRUE;
1294
0
      context->last_relayed = now;
1295
0
    }
1296
0
  }
1297
  /* If we haven't received our desired substream yet, let's drop temporarily */
1298
0
  if(context->last_relayed == 0) {
1299
    /* Let's start slow */
1300
0
    context->last_relayed = now;
1301
0
  } else if(context->substream > 0) {
1302
    /* Check if too much time went by with no packet relayed */
1303
0
    gint64 delay_us = (now - context->last_relayed);
1304
0
    if(delay_us > (context->drop_trigger ? context->drop_trigger : 250000)) {
1305
0
      context->last_relayed = now;
1306
0
      if(context->substream != substream && context->substream_target_temp != 0) {
1307
0
        if(context->substream_target > substream) {
1308
0
          int prev_target = context->substream_target_temp;
1309
0
          if(context->substream_target_temp == -1)
1310
0
            context->substream_target_temp = context->substream_target - 1;
1311
0
          else
1312
0
            context->substream_target_temp--;
1313
0
          if(context->substream_target_temp < 0)
1314
0
            context->substream_target_temp = 0;
1315
0
          if(context->substream_target_temp != prev_target) {
1316
0
            JANUS_LOG(LOG_WARN, "No packet received on substream %d for %"SCNi64"ms, falling back to %d\n",
1317
0
              context->substream, (delay_us / 1000), context->substream_target_temp);
1318
            /* Notify the caller that we (still) need a PLI */
1319
0
            context->need_pli = TRUE;
1320
0
          }
1321
0
        }
1322
0
      }
1323
0
    }
1324
0
  }
1325
  /* Do we need to drop this? */
1326
0
  if(context->substream < 0)
1327
0
    return FALSE;
1328
0
  if(substream != context->substream) {
1329
0
    JANUS_LOG(LOG_HUGE, "Dropping packet (it's from SSRC %"SCNu32", but we're only relaying SSRC %"SCNu32" now\n",
1330
0
      ssrc, *(ssrcs + context->substream));
1331
0
    return FALSE;
1332
0
  }
1333
0
  context->last_relayed = janus_get_monotonic_time();
1334
  /* Temporal layers are only easily available for some codecs */
1335
0
  if(vcodec == JANUS_VIDEOCODEC_VP8) {
1336
    /* Check if there's any temporal scalability to take into account */
1337
0
    gboolean m = FALSE;
1338
0
    uint16_t picid = 0;
1339
0
    uint8_t tlzi = 0;
1340
0
    uint8_t tid = 0;
1341
0
    uint8_t ybit = 0;
1342
0
    uint8_t keyidx = 0;
1343
0
    if(janus_vp8_parse_descriptor(payload, plen, &m, &picid, &tlzi, &tid, &ybit, &keyidx) == 0) {
1344
      //~ JANUS_LOG(LOG_WARN, "%"SCNu16", %u, %u, %u, %u\n", picid, tlzi, tid, ybit, keyidx);
1345
0
      if(context->templayer != context->templayer_target && tid == context->templayer_target) {
1346
        /* FIXME We should be smarter in deciding when to switch */
1347
0
        context->templayer = context->templayer_target;
1348
        /* Notify the caller that the temporal layer changed */
1349
0
        context->changed_temporal = TRUE;
1350
0
      }
1351
0
      if(context->templayer != -1 && tid > context->templayer) {
1352
0
        JANUS_LOG(LOG_HUGE, "Dropping packet (it's temporal layer %d, but we're capping at %d)\n",
1353
0
          tid, context->templayer);
1354
        /* We increase the base sequence number, or there will be gaps when delivering later */
1355
0
        if(sc)
1356
0
          sc->base_seq++;
1357
0
        return FALSE;
1358
0
      }
1359
0
    }
1360
0
  } else if(vcodec == JANUS_VIDEOCODEC_VP9) {
1361
    /* We use the VP9 SVC parser to extract info on temporal layers */
1362
0
    gboolean found = FALSE;
1363
0
    janus_vp9_svc_info svc_info = { 0 };
1364
0
    if(janus_vp9_parse_svc(payload, plen, &found, &svc_info) == 0 && found) {
1365
0
      int temporal_layer = context->templayer;
1366
0
      if(context->templayer_target > context->templayer) {
1367
        /* We need to upscale */
1368
0
        if(svc_info.ubit && svc_info.bbit &&
1369
0
            svc_info.temporal_layer > context->templayer &&
1370
0
            svc_info.temporal_layer <= context->templayer_target) {
1371
0
          context->templayer = svc_info.temporal_layer;
1372
0
          temporal_layer = context->templayer;
1373
0
          context->changed_temporal = TRUE;
1374
0
        }
1375
0
      } else if(context->templayer_target < context->templayer) {
1376
        /* We need to downscale */
1377
0
        if(svc_info.ebit && svc_info.temporal_layer == context->templayer_target) {
1378
0
          context->templayer = context->templayer_target;
1379
0
          context->changed_temporal = TRUE;
1380
0
        }
1381
0
      }
1382
0
      if(temporal_layer < svc_info.temporal_layer) {
1383
0
        JANUS_LOG(LOG_HUGE, "Dropping packet (it's temporal layer %d, but we're capping at %d)\n",
1384
0
          svc_info.temporal_layer, context->templayer);
1385
        /* We increase the base sequence number, or there will be gaps when delivering later */
1386
0
        if(sc)
1387
0
          sc->base_seq++;
1388
0
        return FALSE;
1389
0
      }
1390
0
    }
1391
0
  } else if(vcodec == JANUS_VIDEOCODEC_AV1 && dd_content != NULL && dd_len > 0) {
1392
    /* Use the Dependency Descriptor to check temporal layers */
1393
0
    janus_av1_svc_context *av1ctx = NULL;
1394
0
    if(context->substream >= 0 && context->substream <= 2)
1395
0
      av1ctx = &context->av1_context[context->substream];
1396
0
    if(av1ctx != NULL) {
1397
0
      uint8_t template = 0;
1398
0
      if(janus_av1_svc_context_process_dd(av1ctx, dd_content, dd_len, &template, NULL)) {
1399
0
        janus_av1_svc_template *t = g_hash_table_lookup(av1ctx->templates, GUINT_TO_POINTER(template));
1400
0
        if(t) {
1401
0
          int temporal_layer = context->templayer;
1402
0
          if(context->templayer_target > context->templayer) {
1403
            /* We need to upscale */
1404
0
            if(t->temporal > context->templayer && t->temporal <= context->templayer_target) {
1405
0
              context->templayer = t->temporal;
1406
0
              temporal_layer = context->templayer;
1407
0
              context->changed_temporal = TRUE;
1408
0
            }
1409
0
          } else if(context->templayer_target < context->templayer) {
1410
            /* We need to downscale */
1411
0
            if(t->temporal == context->templayer_target) {
1412
0
              context->templayer = context->templayer_target;
1413
0
              context->changed_temporal = TRUE;
1414
0
            }
1415
0
          }
1416
0
          if(temporal_layer < t->temporal) {
1417
0
            JANUS_LOG(LOG_HUGE, "Dropping packet (it's temporal layer %d, but we're capping at %d)\n",
1418
0
              t->temporal, context->templayer);
1419
            /* We increase the base sequence number, or there will be gaps when delivering later */
1420
0
            if(sc)
1421
0
              sc->base_seq++;
1422
0
            return FALSE;
1423
0
          }
1424
0
        }
1425
0
      }
1426
0
    }
1427
0
  }
1428
  /* If we got here, the packet can be relayed */
1429
0
  return TRUE;
1430
0
}
1431
1432
/* VP9 SVC */
1433
0
void janus_rtp_svc_context_reset(janus_rtp_svc_context *context) {
1434
0
  if(context == NULL)
1435
0
    return;
1436
  /* Reset the context values */
1437
0
  janus_av1_svc_context_reset(&context->dd_context);
1438
0
  memset(context, 0, sizeof(*context));
1439
0
  context->spatial = -1;
1440
0
  context->temporal = -1;
1441
0
}
1442
1443
gboolean janus_rtp_svc_context_process_rtp(janus_rtp_svc_context *context,
1444
    char *buf, int len, uint8_t *dd_content, int dd_len,
1445
0
    janus_videocodec vcodec, janus_vp9_svc_info *info, janus_rtp_switching_context *sc) {
1446
0
  if(!context || !buf || len < 1 || (vcodec != JANUS_VIDEOCODEC_VP9 && vcodec != JANUS_VIDEOCODEC_AV1))
1447
0
    return FALSE;
1448
0
  janus_rtp_header *header = (janus_rtp_header *)buf;
1449
  /* Reset the flags */
1450
0
  context->changed_spatial = FALSE;
1451
0
  context->changed_temporal = FALSE;
1452
0
  context->need_pli = FALSE;
1453
0
  gint64 now = janus_get_monotonic_time();
1454
  /* Access the packet payload */
1455
0
  int plen = 0;
1456
0
  char *payload = janus_rtp_payload(buf, len, &plen);
1457
0
  if(payload == NULL)
1458
0
    return FALSE;
1459
  /* Check if we should use the Dependency Descriptor */
1460
0
  if(vcodec == JANUS_VIDEOCODEC_AV1) {
1461
    /* We do, make sure the data is there */
1462
0
    if(dd_content == NULL || dd_len < 1) {
1463
      /* No Dependency Descriptor, relay as it is */
1464
0
      return TRUE;
1465
0
    }
1466
0
    uint8_t template = 0, ebit = 0;
1467
0
    if(!janus_av1_svc_context_process_dd(&context->dd_context, dd_content, dd_len, &template, &ebit)) {
1468
      /* We couldn't parse the Dependency Descriptor, relay as it is */
1469
0
      return TRUE;
1470
0
    }
1471
0
    janus_av1_svc_template *t = g_hash_table_lookup(context->dd_context.templates, GUINT_TO_POINTER(template));
1472
0
    if(t == NULL) {
1473
      /* We couldn't find the template, relay as it is */
1474
0
      return TRUE;
1475
0
    }
1476
    /* Now let's check if we should let the packet through or not */
1477
0
    gboolean keyframe = janus_av1_is_keyframe((const char *)payload, plen);
1478
0
    gboolean override_mark_bit = FALSE, has_marker_bit = header->markerbit;
1479
0
    int spatial_layer = context->spatial;
1480
0
    if(t->spatial >= 0 && t->spatial <= 2)
1481
0
      context->last_spatial_layer[t->spatial] = now;
1482
0
    if(context->spatial_target > context->spatial) {
1483
0
      JANUS_LOG(LOG_HUGE, "We need to upscale spatially: (%d < %d)\n",
1484
0
        context->spatial, context->spatial_target);
1485
      /* We need to upscale: wait for a keyframe */
1486
0
      if(keyframe) {
1487
0
        int new_spatial_layer = context->spatial_target;
1488
0
        while(new_spatial_layer > context->spatial && new_spatial_layer > 0) {
1489
0
          if(now - context->last_spatial_layer[new_spatial_layer] >= (context->drop_trigger ? context->drop_trigger : 250000)) {
1490
            /* We haven't received packets from this layer for a while, try a lower layer */
1491
0
            JANUS_LOG(LOG_HUGE, "Haven't received packets from layer %d for a while, trying %d instead...\n",
1492
0
              new_spatial_layer, new_spatial_layer-1);
1493
0
            new_spatial_layer--;
1494
0
          } else {
1495
0
            break;
1496
0
          }
1497
0
        }
1498
0
        if(new_spatial_layer > context->spatial) {
1499
0
          JANUS_LOG(LOG_HUGE, "  -- Upscaling spatial layer: %d --> %d (need %d)\n",
1500
0
            context->spatial, new_spatial_layer, context->spatial_target);
1501
0
          context->spatial = new_spatial_layer;
1502
0
          spatial_layer = context->spatial;
1503
0
          context->changed_spatial = TRUE;
1504
0
        }
1505
0
      }
1506
0
    } else if(context->spatial_target < context->spatial) {
1507
      /* We need to scale: wait for a keyframe */
1508
0
      JANUS_LOG(LOG_HUGE, "We need to downscale spatially: (%d > %d)\n",
1509
0
        context->spatial, context->spatial_target);
1510
      /* Check the E bit to see if this is an end-of-frame */
1511
0
      if(ebit) {
1512
0
        JANUS_LOG(LOG_HUGE, "  -- Downscaling spatial layer: %d --> %d\n",
1513
0
          context->spatial, context->spatial_target);
1514
0
        context->spatial = context->spatial_target;
1515
0
        context->changed_spatial = TRUE;
1516
0
      }
1517
0
    }
1518
0
    if(spatial_layer < t->spatial) {
1519
      /* Drop the packet: update the context to make sure sequence number is increased normally later */
1520
0
      JANUS_LOG(LOG_HUGE, "Dropping packet (spatial layer %d < %d)\n", spatial_layer, t->spatial);
1521
0
      if(sc)
1522
0
        sc->base_seq++;
1523
0
      return FALSE;
1524
0
    } else if(ebit && spatial_layer == t->spatial) {
1525
      /* If we stop at layer 0, we need a marker bit now, as the one from layer 1 will not be received */
1526
0
      override_mark_bit = TRUE;
1527
0
    }
1528
0
    int temporal = context->temporal;
1529
0
    if(context->temporal_target > context->temporal) {
1530
      /* We need to upscale */
1531
0
      if(t->temporal > context->temporal && t->temporal <= context->temporal_target) {
1532
0
        context->temporal = t->temporal;
1533
0
        temporal = context->temporal;
1534
0
        context->changed_temporal = TRUE;
1535
0
      }
1536
0
    } else if(context->temporal_target < context->temporal) {
1537
      /* We need to downscale */
1538
0
      if(t->temporal == context->temporal_target) {
1539
0
        context->temporal = context->temporal_target;
1540
0
        context->changed_temporal = TRUE;
1541
0
      }
1542
0
    }
1543
0
    if(temporal < t->temporal) {
1544
0
      JANUS_LOG(LOG_HUGE, "Dropping packet (it's temporal layer %d, but we're capping at %d)\n",
1545
0
        t->temporal, context->temporal);
1546
      /* We increase the base sequence number, or there will be gaps when delivering later */
1547
0
      if(sc)
1548
0
        sc->base_seq++;
1549
0
      return FALSE;
1550
0
    }
1551
    /* If we got here, we can send the frame: this doesn't necessarily mean it's
1552
     * one of the layers the user wants, as there may be dependencies involved */
1553
0
    JANUS_LOG(LOG_HUGE, "Sending packet (spatial=%d, temporal=%d)\n",
1554
0
      t->spatial, t->temporal);
1555
0
    if(override_mark_bit && !has_marker_bit)
1556
0
      header->markerbit = 1;
1557
0
    return TRUE;
1558
0
  }
1559
  /* If we got here, it's VP9, for which we parse the payload manually:
1560
   * if we don't have any info parsed from the VP9 payload header, get it now */
1561
0
  janus_vp9_svc_info svc_info = { 0 };
1562
0
  if(!info) {
1563
0
    gboolean found = FALSE;
1564
0
    if(janus_vp9_parse_svc(payload, plen, &found, &svc_info) < 0) {
1565
      /* Error parsing, relay as it is */
1566
0
      return TRUE;
1567
0
    }
1568
0
    if(!found) {
1569
      /* No SVC info, maybe a generic VP9 payload? Relay as it is */
1570
0
      return TRUE;
1571
0
    }
1572
0
  } else {
1573
0
    svc_info = *info;
1574
0
  }
1575
  /* Note: Following code inspired by the excellent job done by Sergio Garcia Murillo here:
1576
   * https://github.com/medooze/media-server/blob/master/src/vp9/VP9LayerSelector.cpp */
1577
0
  gboolean keyframe = janus_vp9_is_keyframe((const char *)payload, plen);
1578
0
  gboolean override_mark_bit = FALSE, has_marker_bit = header->markerbit;
1579
0
  int spatial_layer = context->spatial;
1580
0
  if(svc_info.spatial_layer >= 0 && svc_info.spatial_layer <= 2)
1581
0
    context->last_spatial_layer[svc_info.spatial_layer] = now;
1582
0
  if(context->spatial_target > context->spatial) {
1583
0
    JANUS_LOG(LOG_HUGE, "We need to upscale spatially: (%d < %d)\n",
1584
0
      context->spatial, context->spatial_target);
1585
    /* We need to upscale: wait for a keyframe */
1586
0
    if(keyframe) {
1587
0
      int new_spatial_layer = context->spatial_target;
1588
0
      while(new_spatial_layer > context->spatial && new_spatial_layer > 0) {
1589
0
        if(now - context->last_spatial_layer[new_spatial_layer] >= (context->drop_trigger ? context->drop_trigger : 250000)) {
1590
          /* We haven't received packets from this layer for a while, try a lower layer */
1591
0
          JANUS_LOG(LOG_HUGE, "Haven't received packets from layer %d for a while, trying %d instead...\n",
1592
0
            new_spatial_layer, new_spatial_layer-1);
1593
0
          new_spatial_layer--;
1594
0
        } else {
1595
0
          break;
1596
0
        }
1597
0
      }
1598
0
      if(new_spatial_layer > context->spatial) {
1599
0
        JANUS_LOG(LOG_HUGE, "  -- Upscaling spatial layer: %d --> %d (need %d)\n",
1600
0
          context->spatial, new_spatial_layer, context->spatial_target);
1601
0
        context->spatial = new_spatial_layer;
1602
0
        spatial_layer = context->spatial;
1603
0
        context->changed_spatial = TRUE;
1604
0
      }
1605
0
    }
1606
0
  } else if(context->spatial_target < context->spatial) {
1607
    /* We need to downscale */
1608
0
    JANUS_LOG(LOG_HUGE, "We need to downscale spatially: (%d > %d)\n",
1609
0
      context->spatial, context->spatial_target);
1610
0
    gboolean downscaled = FALSE;
1611
0
    if(!svc_info.fbit && keyframe) {
1612
      /* Non-flexible mode: wait for a keyframe */
1613
0
      downscaled = TRUE;
1614
0
    } else if(svc_info.fbit && svc_info.ebit) {
1615
      /* Flexible mode: check the E bit */
1616
0
      downscaled = TRUE;
1617
0
    }
1618
0
    if(downscaled) {
1619
0
      JANUS_LOG(LOG_HUGE, "  -- Downscaling spatial layer: %d --> %d\n",
1620
0
        context->spatial, context->spatial_target);
1621
0
      context->spatial = context->spatial_target;
1622
0
      context->changed_spatial = TRUE;
1623
0
    }
1624
0
  }
1625
0
  if(spatial_layer < svc_info.spatial_layer) {
1626
    /* Drop the packet: update the context to make sure sequence number is increased normally later */
1627
0
    JANUS_LOG(LOG_HUGE, "Dropping packet (spatial layer %d < %d)\n", spatial_layer, svc_info.spatial_layer);
1628
0
    if(sc)
1629
0
      sc->base_seq++;
1630
0
    return FALSE;
1631
0
  } else if(svc_info.ebit && spatial_layer == svc_info.spatial_layer) {
1632
    /* If we stop at layer 0, we need a marker bit now, as the one from layer 1 will not be received */
1633
0
    override_mark_bit = TRUE;
1634
0
  }
1635
0
  int temporal_layer = context->temporal;
1636
0
  if(context->temporal_target > context->temporal) {
1637
    /* We need to upscale */
1638
0
    JANUS_LOG(LOG_HUGE, "We need to upscale temporally: (%d < %d)\n",
1639
0
      context->temporal, context->temporal_target);
1640
0
    if(svc_info.ubit && svc_info.bbit &&
1641
0
        svc_info.temporal_layer > context->temporal &&
1642
0
        svc_info.temporal_layer <= context->temporal_target) {
1643
0
      JANUS_LOG(LOG_HUGE, "  -- Upscaling temporal layer: %d --> %d (want %d)\n",
1644
0
        context->temporal, svc_info.temporal_layer, context->temporal_target);
1645
0
      context->temporal = svc_info.temporal_layer;
1646
0
      temporal_layer = context->temporal;
1647
0
      context->changed_temporal = TRUE;
1648
0
    }
1649
0
  } else if(context->temporal_target < context->temporal) {
1650
    /* We need to downscale */
1651
0
    JANUS_LOG(LOG_HUGE, "We need to downscale temporally: (%d > %d)\n",
1652
0
      context->temporal, context->temporal_target);
1653
0
    if(svc_info.ebit && svc_info.temporal_layer == context->temporal_target) {
1654
0
      JANUS_LOG(LOG_HUGE, "  -- Downscaling temporal layer: %d --> %d\n",
1655
0
        context->temporal, context->temporal_target);
1656
0
      context->temporal = context->temporal_target;
1657
0
      context->changed_temporal = TRUE;
1658
0
    }
1659
0
  }
1660
0
  if(temporal_layer < svc_info.temporal_layer) {
1661
    /* Drop the packet: update the context to make sure sequence number is increased normally later */
1662
0
    JANUS_LOG(LOG_HUGE, "Dropping packet (temporal layer %d < %d)\n", temporal_layer, svc_info.temporal_layer);
1663
0
    if(sc)
1664
0
      sc->base_seq++;
1665
0
    return FALSE;
1666
0
  }
1667
  /* If we got here, we can send the frame: this doesn't necessarily mean it's
1668
   * one of the layers the user wants, as there may be dependencies involved */
1669
0
  JANUS_LOG(LOG_HUGE, "Sending packet (spatial=%d, temporal=%d)\n",
1670
0
    svc_info.spatial_layer, svc_info.temporal_layer);
1671
0
  if(override_mark_bit && !has_marker_bit)
1672
0
    header->markerbit = 1;
1673
  /* If we got here, the packet can be relayed */
1674
0
  return TRUE;
1675
0
}
1676
1677
/* AV1 SVC (still WIP) */
1678
0
void janus_av1_svc_context_reset(janus_av1_svc_context *context) {
1679
0
  if(context == NULL)
1680
0
    return;
1681
  /* Reset the context values */
1682
0
  if(context->templates != NULL)
1683
0
    g_hash_table_destroy(context->templates);
1684
0
  memset(context, 0, sizeof(*context));
1685
0
}
1686
1687
gboolean janus_av1_svc_context_process_dd(janus_av1_svc_context *context,
1688
0
    uint8_t *dd, int dd_len, uint8_t *template_id, uint8_t *ebit) {
1689
0
  if(!context || !dd || dd_len < 3)
1690
0
    return FALSE;
1691
1692
  /* First of all, let's parse the Dependency Descriptor */
1693
0
  size_t blen = dd_len*8;
1694
0
  uint32_t offset = 0;
1695
  /* mandatory_descriptor_fields() */
1696
0
  uint8_t start = janus_bitstream_getbit(dd, offset++);
1697
0
  uint8_t end = janus_bitstream_getbit(dd, offset++);
1698
0
  if(ebit)
1699
0
    *ebit = end;
1700
0
  uint8_t template = janus_bitstream_getbits(dd, 6, &offset);
1701
0
  uint16_t frame = janus_bitstream_getbits(dd, 16, &offset);
1702
0
  JANUS_LOG(LOG_HUGE, "  -- s=%u, e=%u, t=%u, f=%u\n",
1703
0
    start, end, template, frame);
1704
0
  if(blen > 24) {
1705
    /* extended_descriptor_fields() */
1706
0
    uint8_t tdeps = janus_bitstream_getbit(dd, offset++);
1707
0
    (void)janus_bitstream_getbit(dd, offset++);
1708
0
    (void)janus_bitstream_getbit(dd, offset++);
1709
0
    (void)janus_bitstream_getbit(dd, offset++);
1710
0
    (void)janus_bitstream_getbit(dd, offset++);
1711
    /* template_dependency_structure() */
1712
0
    if(tdeps) {
1713
0
      uint8_t tioff = janus_bitstream_getbits(dd, 6, &offset);
1714
0
      (void)janus_bitstream_getbits(dd, 5, &offset);
1715
      /* template_layers() */
1716
0
      uint32_t nlidc = 0;
1717
0
      uint8_t tcnt = 0;
1718
0
      int spatial_layers = 0;
1719
0
      int temporal_layers = 0;
1720
0
      do {
1721
0
        nlidc = janus_bitstream_getbits(dd, 2, &offset);
1722
0
        if(context->templates == NULL)
1723
0
          context->templates = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)g_free);
1724
0
        janus_av1_svc_template *t = g_hash_table_lookup(context->templates,
1725
0
          GUINT_TO_POINTER(tcnt));
1726
0
        if(t == NULL) {
1727
0
          t = g_malloc0(sizeof(janus_av1_svc_template));
1728
0
          t->id = tcnt;
1729
0
          g_hash_table_insert(context->templates, GUINT_TO_POINTER(t->id), t);
1730
0
          context->updated = TRUE;
1731
0
        }
1732
0
        t->spatial = spatial_layers;
1733
0
        t->temporal = temporal_layers;
1734
0
        JANUS_LOG(LOG_HUGE, "  -- -- -- [%u] spatial=%u, temporal=%u\n",
1735
0
          tcnt, t->spatial, t->temporal);
1736
0
        if(nlidc == 1) {
1737
0
          temporal_layers++;
1738
0
        } else if(nlidc == 2) {
1739
0
          temporal_layers = 0;
1740
0
          spatial_layers++;
1741
0
        }
1742
0
        tcnt++;
1743
0
      } while(nlidc != 3);
1744
      /* Check if anything changed since the latest update */
1745
0
      if(context->tcnt != tcnt || context->tioff != tioff ||
1746
0
          context->spatial_layers != spatial_layers ||
1747
0
          context->temporal_layers != temporal_layers)
1748
0
        context->updated = TRUE;
1749
0
      context->tcnt = tcnt;
1750
0
      context->tioff = tioff;
1751
0
      context->spatial_layers = spatial_layers;
1752
0
      context->temporal_layers = temporal_layers;
1753
      /* FIXME We currently don't care about the other fields */
1754
0
    }
1755
0
  }
1756
  /* frame_dependency_definition() */
1757
0
  uint8_t tindex = (template + 64 - context->tioff) % 64;
1758
0
  janus_av1_svc_template *t = context->templates ? g_hash_table_lookup(context->templates,
1759
0
    GUINT_TO_POINTER(tindex)) : NULL;
1760
0
  if(t == NULL) {
1761
0
    JANUS_LOG(LOG_WARN, "Invalid template ID '%u' (count is %u), ignoring packet...\n",
1762
0
      tindex, context->tcnt);
1763
0
    return FALSE;
1764
0
  }
1765
0
  JANUS_LOG(LOG_HUGE, "  -- spatial=%u, temporal=%u (tindex %u)\n",
1766
0
    t->spatial, t->temporal, t->id);
1767
  /* FIXME We currently don't care about the other fields */
1768
1769
  /* If we got here, the packet is fine */
1770
0
  if(template_id != NULL)
1771
0
    *template_id = tindex;
1772
0
  return TRUE;
1773
0
}