FFmpeg
Loading...
Searching...
No Matches
whip.c
Go to the documentation of this file.
1/*
2 * WebRTC-HTTP ingestion protocol (WHIP) muxer
3 * Copyright (c) 2023 The FFmpeg Project
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include "libavcodec/h264.h"
24
26#include "libavutil/avassert.h"
27#include "libavutil/base64.h"
28#include "libavutil/bprint.h"
29#include "libavutil/crc.h"
30#include "libavutil/hmac.h"
32#include "libavutil/lfg.h"
33#include "libavutil/opt.h"
34#include "libavutil/mem.h"
36#include "libavutil/time.h"
37#include "avc.h"
38#include "nal.h"
39#include "avio_internal.h"
40#include "http.h"
41#include "internal.h"
42#include "mux.h"
43#include "network.h"
44#include "rtp.h"
45#include "srtp.h"
46#include "tls.h"
47
48/**
49 * Maximum size limit of a Session Description Protocol (SDP),
50 * be it an offer or answer.
51 */
52#define MAX_SDP_SIZE 8192
53
54/**
55 * The size of the Secure Real-time Transport Protocol (SRTP) master key material
56 * that is exported by Secure Sockets Layer (SSL) after a successful Datagram
57 * Transport Layer Security (DTLS) handshake. This material consists of a key
58 * of 16 bytes and a salt of 14 bytes.
59 */
60#define DTLS_SRTP_KEY_LEN 16
61#define DTLS_SRTP_SALT_LEN 14
62
63/**
64 * The maximum size of the Secure Real-time Transport Protocol (SRTP) HMAC checksum
65 * and padding that is appended to the end of the packet. To calculate the maximum
66 * size of the User Datagram Protocol (UDP) packet that can be sent out, subtract
67 * this size from the `pkt_size`.
68 */
69#define DTLS_SRTP_CHECKSUM_LEN 16
70
71#define WHIP_US_PER_MS 1000
72
73/**
74 * If we try to read from UDP and get EAGAIN, we sleep for 5ms and retry up to 10 times.
75 * This will limit the total duration (in milliseconds, 50ms)
76 */
77#define ICE_DTLS_READ_MAX_RETRY 10
78#define ICE_DTLS_READ_SLEEP_DURATION 5
79
80/* The magic cookie for Session Traversal Utilities for NAT (STUN) messages. */
81#define STUN_MAGIC_COOKIE 0x2112A442
82
83/**
84 * Refer to RFC 8445 5.1.2
85 * priority = (2^24)*(type preference) + (2^8)*(local preference) + (2^0)*(256 - component ID)
86 * host candidate priority is 126 << 24 | 65535 << 8 | 255
87 */
88#define STUN_HOST_CANDIDATE_PRIORITY 126 << 24 | 65535 << 8 | 255
89
90/**
91 * Maximum size of the buffer for sending and receiving UDP packets.
92 * Please note that this size does not limit the size of the UDP packet that can be sent.
93 * To set the limit for packet size, modify the `pkt_size` parameter.
94 * For instance, it is possible to set the UDP buffer to 4096 to send or receive packets,
95 * but please keep in mind that the `pkt_size` option limits the packet size to 1400.
96 */
97#define MAX_UDP_BUFFER_SIZE 4096
98
99/* Referring to Chrome's definition of RTP payload types. */
100#define WHIP_RTP_PAYLOAD_TYPE_H264 106
101#define WHIP_RTP_PAYLOAD_TYPE_OPUS 111
102#define WHIP_RTP_PAYLOAD_TYPE_VIDEO_RTX 105
103
104/**
105 * The STUN message header, which is 20 bytes long, comprises the
106 * STUNMessageType (1B), MessageLength (2B), MagicCookie (4B),
107 * and TransactionID (12B).
108 * See https://datatracker.ietf.org/doc/html/rfc5389#section-6
109 */
110#define ICE_STUN_HEADER_SIZE 20
111
112/**
113 * The RTP header is 12 bytes long, comprising the Version(1B), PT(1B),
114 * SequenceNumber(2B), Timestamp(4B), and SSRC(4B).
115 * See https://www.rfc-editor.org/rfc/rfc3550#section-5.1
116 */
117#define WHIP_RTP_HEADER_SIZE 12
118
119/**
120 * For RTCP, PT is [128, 223] (or without marker [0, 95]). Literally, RTCP starts
121 * from 64 not 0, so PT is [192, 223] (or without marker [64, 95]), see "RTCP Control
122 * Packet Types (PT)" at
123 * https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-4
124 *
125 * For RTP, the PT is [96, 127], or [224, 255] with marker. See "RTP Payload Types (PT)
126 * for standard audio and video encodings" at
127 * https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-1
128 */
129#define WHIP_RTCP_PT_START 192
130#define WHIP_RTCP_PT_END 223
131
132/**
133 * In the case of ICE-LITE, these fields are not used; instead, they are defined
134 * as constant values.
135 */
136#define WHIP_SDP_SESSION_ID "4489045141692799359"
137#define WHIP_SDP_CREATOR_IP "127.0.0.1"
138
139/**
140 * Refer to RFC 7675 5.1,
141 *
142 * To prevent expiry of consent, a STUN binding request can be sent periodically.
143 * Implementations SHOULD set a default interval of 5 seconds(5000ms).
144 *
145 * Consent expires after 30 seconds(30000ms).
146 */
147#define WHIP_ICE_CONSENT_CHECK_INTERVAL 5000
148#define WHIP_ICE_CONSENT_EXPIRED_TIMER 30000
149
150/**
151 * RTP history packet size.
152 * Target is buffering 1000ms of RTP history packets.
153 *
154 * bandwidth_bps = (RTP payload bytes) * (RTP history size) * 8
155 * Assumes average RTP payload is 1184 bytes (MTU - SRTP_CHECKSUM_LEN).
156 */
157#define WHIP_RTP_HISTORY_MIN 64 /* around 0.61 Mbps */
158#define WHIP_RTP_HISTORY_DEFAULT 512 /* around 4.85 Mbps */
159#define WHIP_RTP_HISTORY_MAX 2048 /* around 19.40 Mbps */
160
161/* Calculate the elapsed time from starttime to endtime in milliseconds. */
162#define ELAPSED(starttime, endtime) ((float)(endtime - starttime) / 1000)
163
164/* STUN Attribute, comprehension-required range (0x0000-0x7FFF) */
166 STUN_ATTR_USERNAME = 0x0006, /// shared secret response/bind request
167 STUN_ATTR_PRIORITY = 0x0024, /// must be included in a Binding request
168 STUN_ATTR_USE_CANDIDATE = 0x0025, /// bind request
169 STUN_ATTR_MESSAGE_INTEGRITY = 0x0008, /// bind request/response
170 STUN_ATTR_FINGERPRINT = 0x8028, /// rfc5389
171 STUN_ATTR_ICE_CONTROLLING = 0x802A, /// ICE controlling role
172};
173
176
177 /* The initial state. */
179 /* The muxer has sent the offer to the peer. */
181 /* The muxer has received the answer from the peer. */
183 /**
184 * After parsing the answer received from the peer, the muxer negotiates the abilities
185 * in the offer that it generated.
186 */
188 /* The muxer has connected to the peer via UDP. */
190 /* The muxer has sent the ICE request to the peer. */
192 /* The muxer has received the ICE response from the peer. */
194 /* The muxer has finished the DTLS handshake with the peer. */
196 /* The muxer has finished the SRTP setup. */
198 /* The muxer is ready to send/receive media frames. */
200 /* The muxer is failed. */
202};
203
204typedef enum WHIPFlags {
206} WHIPFlags;
207
208typedef struct RtpHistoryItem {
209 uint16_t seq;
210 int size;
211 uint8_t *buf;
213
214typedef struct WHIPContext {
216
217 uint32_t flags;
218 /* The state of the RTC connection. */
220
221 /* Parameters for the input audio and video codecs. */
224
225 /**
226 * The h264_mp4toannexb Bitstream Filter (BSF) bypasses the AnnexB packet;
227 * therefore, it is essential to insert the SPS and PPS before each IDR frame
228 * in such cases.
229 */
231
232 /* The random number generator. */
234
235 /* The ICE username and pwd fragment generated by the muxer. */
238 /* The SSRC of the audio and video stream, generated by the muxer. */
239 uint32_t audio_ssrc;
240 uint32_t video_ssrc;
242
245
247 /* The PT(Payload Type) of stream, generated by the muxer. */
251 /**
252 * This is the SDP offer generated by the muxer based on the codec parameters,
253 * DTLS, and ICE information.
254 */
256
258 uint64_t ice_tie_breaker; // random 64 bit, for ICE-CONTROLLING
259 /* The ICE username and pwd from remote server. */
262 /**
263 * This represents the ICE candidate protocol, priority, host and port.
264 * Currently, we only support one candidate and choose the first UDP candidate.
265 * However, we plan to support multiple candidates in the future.
266 */
268 char *ice_host;
270
271 /* The SDP answer received from the WebRTC server. */
273 /* The resource URL returned in the Location header of WHIP HTTP response. */
275
276 /* These variables represent timestamps used for calculating and tracking the cost. */
287
288 /* The certificate and private key content used for DTLS handshake */
291 /* The fingerprint of certificate, used in SDP offer. */
293 /* remote DTLS cert fingerprint from SDP answer (sha-256). */
295 /**
296 * This represents the material used to build the SRTP master key. It is
297 * generated by DTLS and has the following layout:
298 * 16B 16B 14B 14B
299 * client_key | server_key | client_salt | server_salt
300 */
302
303 /* TODO: Use AVIOContext instead of URLContext */
305
306 /* The SRTP send context, to encrypt outgoing packets. */
311 /* The SRTP receive context, to decrypt incoming packets. */
313
314 /* The UDP transport is used for delivering ICE, DTLS and SRTP packets. */
316 /* The buffer for UDP transmission. */
318
319 /* The timeout in milliseconds for ICE and DTLS handshake. */
321
322 /* The timeout in microseconds for HTTP operations. */
324 /**
325 * The size of RTP packet, should generally be set to MTU.
326 * Note that pion requires a smaller value, for example, 1200.
327 */
329 int ts_buffer_size;/* Underlying protocol send/receive buffer size */
330 /**
331 * The optional Bearer token for WHIP Authorization.
332 * See https://www.ietf.org/archive/id/draft-ietf-wish-whip-08.html#name-authentication-and-authoriz
333 */
335 /* The certificate and private key used for DTLS handshake. */
337 char* key_file;
338
341 uint8_t *hist_pool;
344
345/**
346 * Get or Generate a self-signed certificate and private key for DTLS,
347 * fingerprint for SDP
348 */
350{
351 int ret = 0;
352 WHIPContext *whip = s->priv_data;
353
354 if (whip->cert_file && whip->key_file) {
355 /* Read the private key and certificate from the file. */
356 if ((ret = ff_ssl_read_key_cert(whip->key_file, whip->cert_file,
357 whip->key_buf, sizeof(whip->key_buf),
358 whip->cert_buf, sizeof(whip->cert_buf),
359 &whip->dtls_fingerprint)) < 0) {
360 av_log(s, AV_LOG_ERROR, "Failed to read DTLS certificate from cert=%s, key=%s\n",
361 whip->cert_file, whip->key_file);
362 return ret;
363 }
364 } else {
365 /* Generate a private key to ctx->dtls_pkey and self-signed certificate. */
366 if ((ret = ff_ssl_gen_key_cert(whip->key_buf, sizeof(whip->key_buf),
367 whip->cert_buf, sizeof(whip->cert_buf),
368 &whip->dtls_fingerprint)) < 0) {
369 av_log(s, AV_LOG_ERROR, "Failed to generate DTLS private key and certificate\n");
370 return ret;
371 }
372 }
373
374 return ret;
375}
376
378{
379 int ret = 0;
380 WHIPContext *whip = s->priv_data;
381 int is_dtls_active = whip->flags & WHIP_DTLS_ACTIVE;
383 char buf[256];
384
385 ff_url_join(buf, sizeof(buf), "dtls", NULL, whip->ice_host, whip->ice_port, NULL);
386 av_dict_set_int(&opts, "mtu", whip->pkt_size, 0);
387 if (whip->cert_file) {
388 av_dict_set(&opts, "cert_file", whip->cert_file, 0);
389 } else
390 av_dict_set(&opts, "cert_pem", whip->cert_buf, 0);
391
392 if (whip->key_file) {
393 av_dict_set(&opts, "key_file", whip->key_file, 0);
394 } else
395 av_dict_set(&opts, "key_pem", whip->key_buf, 0);
396 av_dict_set_int(&opts, "external_sock", 1, 0);
397 av_dict_set_int(&opts, "use_srtp", 1, 0);
398 av_dict_set_int(&opts, "listen", is_dtls_active ? 0 : 1, 0);
399 // Do not verify CA
400 av_dict_set_int(&opts, "verify", 0, 0);
401 ret = ffurl_open_whitelist(&whip->dtls_uc, buf, AVIO_FLAG_READ_WRITE, &s->interrupt_callback,
402 &opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
404 if (ret < 0) {
405 av_log(whip, AV_LOG_ERROR, "Failed to open DTLS url:%s\n", buf);
406 goto end;
407 }
408 /* reuse the udp created by whip */
410end:
411 return ret;
412}
413
414/**
415 * Initialize and check the options for the WebRTC muxer.
416 */
418{
419 int ret, ideal_pkt_size = 532;
420 WHIPContext *whip = s->priv_data;
421 uint32_t seed;
422
424
425 ret = certificate_key_init(s);
426 if (ret < 0) {
427 av_log(whip, AV_LOG_ERROR, "Failed to init certificate and key\n");
428 return ret;
429 }
430
431 /* Initialize the random number generator. */
433 av_lfg_init(&whip->rnd, seed);
434
435 /* 64 bit tie breaker for ICE-CONTROLLING (RFC 8445 16.1) */
436 ret = av_random_bytes((uint8_t *)&whip->ice_tie_breaker, sizeof(whip->ice_tie_breaker));
437 if (ret < 0) {
438 av_log(whip, AV_LOG_ERROR, "Couldn't generate random bytes for ICE tie breaker\n");
439 return ret;
440 }
441
442 whip->audio_first_seq = av_lfg_get(&whip->rnd) & 0x0fff;
443 whip->video_first_seq = whip->audio_first_seq + 1;
444
445 if (whip->pkt_size < ideal_pkt_size)
446 av_log(whip, AV_LOG_WARNING, "pkt_size=%d(<%d) is too small, may cause packet loss\n",
447 whip->pkt_size, ideal_pkt_size);
448
449 whip->hist = av_calloc(whip->hist_sz, sizeof(*whip->hist));
450 if (!whip->hist)
451 return AVERROR(ENOMEM);
452
454 if (!whip->hist_pool)
455 return AVERROR(ENOMEM);
456
457 for (int i = 0; i < whip->hist_sz; i++)
458 whip->hist[i].buf = whip->hist_pool + i * (whip->pkt_size - DTLS_SRTP_CHECKSUM_LEN);
459
460 if (whip->state < WHIP_STATE_INIT)
461 whip->state = WHIP_STATE_INIT;
463 av_log(whip, AV_LOG_VERBOSE, "Init state=%d, handshake_timeout=%dms, pkt_size=%d, seed=%d, elapsed=%.2fms\n",
465
466 return 0;
467}
468
469/**
470 * When duplicating a stream, the demuxer has already set the extradata, profile, and
471 * level of the par. Keep in mind that this function will not be invoked since the
472 * profile and level are set.
473 *
474 * When utilizing an encoder, such as libx264, to encode a stream, the extradata in
475 * par->extradata contains the SPS, which includes profile and level information.
476 * However, the profile and level of par remain unspecified. Therefore, it is necessary
477 * to extract the profile and level data from the extradata and assign it to the par's
478 * profile and level. Keep in mind that AVFMT_GLOBALHEADER must be enabled; otherwise,
479 * the extradata will remain empty.
480 */
482{
483 int ret = 0;
484 const uint8_t *r = par->extradata, *r1, *end = par->extradata + par->extradata_size;
485 H264SPS seq, *const sps = &seq;
486 uint32_t state;
487 WHIPContext *whip = s->priv_data;
488
489 if (par->codec_id != AV_CODEC_ID_H264)
490 return ret;
491
492 if (par->profile != AV_PROFILE_UNKNOWN && par->level != AV_LEVEL_UNKNOWN)
493 return ret;
494
495 if (!par->extradata || par->extradata_size <= 0) {
496 av_log(whip, AV_LOG_ERROR, "Unable to parse profile from empty extradata=%p, size=%d\n",
497 par->extradata, par->extradata_size);
498 return AVERROR(EINVAL);
499 }
500
501 while (1) {
503 if (r >= end)
504 break;
505
506 r1 = ff_nal_find_startcode(r, end);
507 if ((state & 0x1f) == H264_NAL_SPS) {
508 ret = ff_avc_decode_sps(sps, r, r1 - r);
509 if (ret < 0) {
510 av_log(whip, AV_LOG_ERROR, "Failed to decode SPS, state=%x, size=%d\n",
511 state, (int)(r1 - r));
512 return ret;
513 }
514
515 av_log(whip, AV_LOG_VERBOSE, "Parse profile=%d, level=%d from SPS\n",
516 sps->profile_idc, sps->level_idc);
517 par->profile = sps->profile_idc;
518 par->level = sps->level_idc;
519 }
520
521 r = r1;
522 }
523
524 return ret;
525}
526
527/**
528 * Parses video SPS/PPS from the extradata of codecpar and checks the codec.
529 * Currently only supports video(h264) and audio(opus). Note that only baseline
530 * and constrained baseline profiles of h264 are supported.
531 *
532 * If the profile is less than 0, the function considers the profile as baseline.
533 * It may need to parse the profile from SPS/PPS. This situation occurs when ingesting
534 * desktop and transcoding.
535 *
536 * @param s Pointer to the AVFormatContext
537 * @returns Returns 0 if successful or AVERROR_xxx in case of an error.
538 *
539 * TODO: FIXME: There is an issue with the timestamp of OPUS audio, especially when
540 * the input is an MP4 file. The timestamp deviates from the expected value of 960,
541 * causing Chrome to play the audio stream with noise. This problem can be replicated
542 * by transcoding a specific file into MP4 format and publishing it using the WHIP
543 * muxer. However, when directly transcoding and publishing through the WHIP muxer,
544 * the issue is not present, and the audio timestamp remains consistent. The root
545 * cause is still unknown, and this comment has been added to address this issue
546 * in the future. Further research is needed to resolve the problem.
547 */
549{
550 int i, ret = 0;
551 WHIPContext *whip = s->priv_data;
552
553 for (i = 0; i < s->nb_streams; i++) {
554 AVCodecParameters *par = s->streams[i]->codecpar;
555 switch (par->codec_type) {
557 whip->video_par = par;
558
559 if (par->video_delay > 0) {
560 av_log(whip, AV_LOG_ERROR, "Unsupported B frames by RTC\n");
562 }
563
564 if ((ret = parse_profile_level(s, par)) < 0) {
565 av_log(whip, AV_LOG_ERROR, "Failed to parse SPS/PPS from extradata\n");
566 return AVERROR(EINVAL);
567 }
568
569 if (par->profile == AV_PROFILE_UNKNOWN) {
570 av_log(whip, AV_LOG_WARNING, "No profile found in extradata, consider baseline\n");
571 return AVERROR(EINVAL);
572 }
573 if (par->level == AV_LEVEL_UNKNOWN) {
574 av_log(whip, AV_LOG_WARNING, "No level found in extradata, consider 3.1\n");
575 return AVERROR(EINVAL);
576 }
577 break;
579 whip->audio_par = par;
580
581 if (par->ch_layout.nb_channels != 2) {
582 av_log(whip, AV_LOG_ERROR, "Unsupported audio channels %d by RTC, choose stereo\n",
585 }
586
587 if (par->sample_rate != 48000) {
588 av_log(whip, AV_LOG_ERROR, "Unsupported audio sample rate %d by RTC, choose 48000\n", par->sample_rate);
590 }
591 break;
592 default:
593 av_unreachable("already checked via FF_OFMT flags");
594 }
595 }
596
597 return ret;
598}
599
600/**
601 * Generate SDP offer according to the codec parameters, DTLS and ICE information.
602 *
603 * Note that we don't use av_sdp_create to generate SDP offer because it doesn't
604 * support DTLS and ICE information.
605 *
606 * @return 0 if OK, AVERROR_xxx on error
607 */
609{
610 int ret = 0, profile_idc = 0, level, profile_iop = 0;
611 const char *acodec_name = NULL, *vcodec_name = NULL;
612 char bundle[4];
613 int bundle_index = 0;
614 AVBPrint bp;
615 WHIPContext *whip = s->priv_data;
616 int is_dtls_active = whip->flags & WHIP_DTLS_ACTIVE;
617
618 /* To prevent a crash during cleanup, always initialize it. */
620
621 if (whip->sdp_offer) {
622 av_log(whip, AV_LOG_ERROR, "SDP offer is already set\n");
623 ret = AVERROR(EINVAL);
624 goto end;
625 }
626
627 snprintf(whip->ice_ufrag_local, sizeof(whip->ice_ufrag_local), "%08x",
628 av_lfg_get(&whip->rnd));
629 snprintf(whip->ice_pwd_local, sizeof(whip->ice_pwd_local), "%08x%08x%08x%08x",
630 av_lfg_get(&whip->rnd), av_lfg_get(&whip->rnd), av_lfg_get(&whip->rnd),
631 av_lfg_get(&whip->rnd));
632
633 whip->audio_ssrc = av_lfg_get(&whip->rnd);
634 whip->video_ssrc = whip->audio_ssrc + 1;
635 whip->video_rtx_ssrc = whip->video_ssrc + 1;
636
640
641 if (whip->audio_par) {
642 bundle[bundle_index++] = '0';
643 bundle[bundle_index++] = ' ';
644 }
645 if (whip->video_par) {
646 bundle[bundle_index++] = '1';
647 bundle[bundle_index++] = ' ';
648 }
649 bundle[bundle_index - 1] = '\0';
650
651 av_bprintf(&bp, ""
652 "v=0\r\n"
653 "o=FFmpeg %s 2 IN IP4 %s\r\n"
654 "s=FFmpegPublishSession\r\n"
655 "t=0 0\r\n"
656 "a=group:BUNDLE %s\r\n"
657 "a=extmap-allow-mixed\r\n"
658 "a=msid-semantic: WMS\r\n",
661 bundle);
662
663 if (whip->audio_par) {
664 if (whip->audio_par->codec_id == AV_CODEC_ID_OPUS)
665 acodec_name = "opus";
666
667 av_bprintf(&bp, ""
668 "m=audio 9 UDP/TLS/RTP/SAVPF %u\r\n"
669 "c=IN IP4 0.0.0.0\r\n"
670 "a=ice-ufrag:%s\r\n"
671 "a=ice-pwd:%s\r\n"
672 "a=fingerprint:sha-256 %s\r\n"
673 "a=setup:%s\r\n"
674 "a=mid:0\r\n"
675 "a=sendonly\r\n"
676 "a=msid:FFmpeg audio\r\n"
677 "a=rtcp-mux\r\n"
678 "a=rtpmap:%u %s/%d/%d\r\n"
679 "a=ssrc:%u cname:FFmpeg\r\n"
680 "a=ssrc:%u msid:FFmpeg audio\r\n",
681 whip->audio_payload_type,
682 whip->ice_ufrag_local,
683 whip->ice_pwd_local,
684 whip->dtls_fingerprint,
685 is_dtls_active ? "active" : "passive",
686 whip->audio_payload_type,
687 acodec_name,
688 whip->audio_par->sample_rate,
690 whip->audio_ssrc,
691 whip->audio_ssrc);
692 }
693
694 if (whip->video_par) {
695 level = whip->video_par->level;
696 if (whip->video_par->codec_id == AV_CODEC_ID_H264) {
697 vcodec_name = "H264";
698 profile_iop |= whip->video_par->profile & AV_PROFILE_H264_CONSTRAINED ? 1 << 6 : 0;
699 profile_iop |= whip->video_par->profile & AV_PROFILE_H264_INTRA ? 1 << 4 : 0;
700 profile_idc = whip->video_par->profile & 0x00ff;
701 }
702
703 av_bprintf(&bp, ""
704 "m=video 9 UDP/TLS/RTP/SAVPF %u %u\r\n"
705 "c=IN IP4 0.0.0.0\r\n"
706 "a=ice-ufrag:%s\r\n"
707 "a=ice-pwd:%s\r\n"
708 "a=fingerprint:sha-256 %s\r\n"
709 "a=setup:%s\r\n"
710 "a=mid:1\r\n"
711 "a=sendonly\r\n"
712 "a=msid:FFmpeg video\r\n"
713 "a=rtcp-mux\r\n"
714 "a=rtcp-rsize\r\n"
715 "a=rtpmap:%u %s/90000\r\n"
716 "a=fmtp:%u level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=%02x%02x%02x\r\n"
717 "a=rtcp-fb:%u nack\r\n"
718 "a=rtpmap:%u rtx/90000\r\n"
719 "a=fmtp:%u apt=%u\r\n"
720 "a=ssrc-group:FID %u %u\r\n"
721 "a=ssrc:%u cname:FFmpeg\r\n"
722 "a=ssrc:%u msid:FFmpeg video\r\n",
723 whip->video_payload_type,
725 whip->ice_ufrag_local,
726 whip->ice_pwd_local,
727 whip->dtls_fingerprint,
728 is_dtls_active ? "active" : "passive",
729 whip->video_payload_type,
730 vcodec_name,
731 whip->video_payload_type,
733 profile_iop,
734 level,
735 whip->video_payload_type,
738 whip->video_payload_type,
739 whip->video_ssrc,
740 whip->video_rtx_ssrc,
741 whip->video_ssrc,
742 whip->video_ssrc);
743 }
744
745 if (!av_bprint_is_complete(&bp)) {
746 av_log(whip, AV_LOG_ERROR, "Offer exceed max %d, %s\n", MAX_SDP_SIZE, bp.str);
747 ret = AVERROR(EIO);
748 goto end;
749 }
750
751 whip->sdp_offer = av_strdup(bp.str);
752 if (!whip->sdp_offer) {
753 ret = AVERROR(ENOMEM);
754 goto end;
755 }
756
757 if (whip->state < WHIP_STATE_OFFER)
758 whip->state = WHIP_STATE_OFFER;
760 av_log(whip, AV_LOG_VERBOSE, "Generated state=%d, offer: %s\n", whip->state, whip->sdp_offer);
761
762end:
764 return ret;
765}
766
767/**
768 * Exchange SDP offer with WebRTC peer to get the answer.
769 *
770 * @return 0 if OK, AVERROR_xxx on error
771 */
773{
774 int ret;
775 char buf[MAX_URL_SIZE];
776 AVBPrint bp;
777 WHIPContext *whip = s->priv_data;
778 /* The URL context is an HTTP transport layer for the WHIP protocol. */
779 URLContext *whip_uc = NULL;
781 char *hex_data = NULL;
782 const char *proto_name = avio_find_protocol_name(s->url);
783
784 /* To prevent a crash during cleanup, always initialize it. */
786
787 if (!av_strstart(proto_name, "http", NULL)) {
788 av_log(whip, AV_LOG_ERROR, "Protocol %s is not supported by RTC, choose http, url is %s\n",
789 proto_name, s->url);
790 ret = AVERROR(EINVAL);
791 goto end;
792 }
793
794 if (!whip->sdp_offer || !*whip->sdp_offer) {
795 av_log(whip, AV_LOG_ERROR, "No offer to exchange\n");
796 ret = AVERROR(EINVAL);
797 goto end;
798 }
799
800 ret = snprintf(buf, sizeof(buf), "Cache-Control: no-cache\r\nContent-Type: application/sdp\r\n");
801 if (whip->authorization)
802 ret += snprintf(buf + ret, sizeof(buf) - ret, "Authorization: Bearer %s\r\n", whip->authorization);
803 if (ret <= 0 || ret >= sizeof(buf)) {
804 av_log(whip, AV_LOG_ERROR, "Failed to generate headers, size=%d, %s\n", ret, buf);
805 ret = AVERROR(EINVAL);
806 goto end;
807 }
808
809 av_dict_set(&opts, "headers", buf, 0);
810 av_dict_set_int(&opts, "chunked_post", 0, 0);
811
812 if (whip->timeout >= 0)
813 av_dict_set_int(&opts, "timeout", whip->timeout, 0);
814
815 const size_t sdp_offer_len = strlen(whip->sdp_offer);
816 hex_data = av_malloc(2 * sdp_offer_len + 1);
817 if (!hex_data) {
818 ret = AVERROR(ENOMEM);
819 goto end;
820 }
821 ff_data_to_hex(hex_data, whip->sdp_offer, sdp_offer_len, 0);
822 av_dict_set(&opts, "post_data", hex_data, AV_DICT_DONT_STRDUP_VAL);
823
824 ret = ffurl_open_whitelist(&whip_uc, s->url, AVIO_FLAG_READ_WRITE, &s->interrupt_callback,
825 &opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
826 if (ret < 0) {
827 av_log(whip, AV_LOG_ERROR, "Failed to request url=%s, offer: %s\n", s->url, whip->sdp_offer);
828 goto end;
829 }
830
831 if (ff_http_get_new_location(whip_uc)) {
833 if (!proto_name || !av_strstart(proto_name, "http", NULL)) {
834 av_log(whip, AV_LOG_ERROR, "Unsupported resource url %s\n", ff_http_get_new_location(whip_uc));
836 goto end;
837 }
839 if (!whip->whip_resource_url) {
840 ret = AVERROR(ENOMEM);
841 goto end;
842 }
843 }
844
845 while (1) {
846 ret = ffurl_read(whip_uc, buf, sizeof(buf));
847 if (ret == AVERROR_EOF) {
848 /* Reset the error because we read all response as answer util EOF. */
849 ret = 0;
850 break;
851 }
852 if (ret <= 0) {
853 av_log(whip, AV_LOG_ERROR, "Failed to read response from url=%s, offer is %s, answer is %s\n",
854 s->url, whip->sdp_offer, whip->sdp_answer);
855 goto end;
856 }
857
858 av_bprintf(&bp, "%.*s", ret, buf);
859 if (!av_bprint_is_complete(&bp)) {
860 av_log(whip, AV_LOG_ERROR, "Answer exceed max size %d, %.*s, %s\n", MAX_SDP_SIZE, ret, buf, bp.str);
861 ret = AVERROR(EIO);
862 goto end;
863 }
864 }
865
866 if (!av_strstart(bp.str, "v=", NULL)) {
867 av_log(whip, AV_LOG_ERROR, "Invalid answer: %s\n", bp.str);
868 ret = AVERROR(EINVAL);
869 goto end;
870 }
871
872 whip->sdp_answer = av_strdup(bp.str);
873 if (!whip->sdp_answer) {
874 ret = AVERROR(ENOMEM);
875 goto end;
876 }
877
878 if (whip->state < WHIP_STATE_ANSWER)
879 whip->state = WHIP_STATE_ANSWER;
880 av_log(whip, AV_LOG_VERBOSE, "Got state=%d, answer: %s\n", whip->state, whip->sdp_answer);
881
882end:
883 ffurl_closep(&whip_uc);
886 return ret;
887}
888
889/**
890 * Parses the ICE ufrag, pwd, and candidates from the SDP answer.
891 *
892 * This function is used to extract the ICE ufrag, pwd, and candidates from the SDP answer.
893 * It returns an error if any of these fields is NULL. The function only uses the first
894 * candidate if there are multiple candidates. However, support for multiple candidates
895 * will be added in the future.
896 *
897 * @param s Pointer to the AVFormatContext
898 * @returns Returns 0 if successful or AVERROR_xxx if an error occurs.
899 */
901{
902 int ret = 0;
903 AVIOContext *pb;
904 char line[MAX_URL_SIZE];
905 const char *ptr;
906 int i;
907 WHIPContext *whip = s->priv_data;
908
909 if (!whip->sdp_answer || !strlen(whip->sdp_answer)) {
910 av_log(whip, AV_LOG_ERROR, "No answer to parse\n");
911 return AVERROR(EINVAL);
912 }
913
914 pb = avio_alloc_context(whip->sdp_answer, strlen(whip->sdp_answer), 0, NULL, NULL, NULL, NULL);
915 if (!pb)
916 return AVERROR(ENOMEM);
917
918 for (i = 0; !avio_feof(pb); i++) {
919 ff_get_chomp_line(pb, line, sizeof(line));
920 if (av_strstart(line, "a=ice-lite", &ptr))
921 whip->is_peer_ice_lite = 1;
922 if (av_strstart(line, "a=ice-ufrag:", &ptr) && !whip->ice_ufrag_remote) {
923 whip->ice_ufrag_remote = av_strdup(ptr);
924 if (!whip->ice_ufrag_remote) {
925 ret = AVERROR(ENOMEM);
926 goto end;
927 }
928 } else if (av_strstart(line, "a=ice-pwd:", &ptr) && !whip->ice_pwd_remote) {
929 whip->ice_pwd_remote = av_strdup(ptr);
930 if (!whip->ice_pwd_remote) {
931 ret = AVERROR(ENOMEM);
932 goto end;
933 }
934 } else if (av_strstart(line, "a=fingerprint:", &ptr) && !whip->remote_fingerprint) {
935 /* SDP a=fingerprint format is "<algo> <hex:hex:...>". Skip
936 * the algo token, store the hex string for post-handshake compare. */
937 const char *space = strchr(ptr, ' ');
938 if (space) {
940 if (!whip->remote_fingerprint) {
941 ret = AVERROR(ENOMEM);
942 goto end;
943 }
944 }
945 } else if (av_strstart(line, "a=candidate:", &ptr) && !whip->ice_protocol) {
946 if (ptr && av_stristr(ptr, "host")) {
947 /* Refer to RFC 5245 15.1 */
948 char foundation[33], protocol[17], host[129];
949 int component_id, priority, port;
950 ret = sscanf(ptr, "%32s %d %16s %d %128s %d typ host", foundation, &component_id, protocol, &priority, host, &port);
951 if (ret != 6) {
952 av_log(whip, AV_LOG_ERROR, "Failed %d to parse line %d %s from %s\n",
953 ret, i, line, whip->sdp_answer);
954 ret = AVERROR(EIO);
955 goto end;
956 }
957
958 if (av_strcasecmp(protocol, "udp")) {
959 av_log(whip, AV_LOG_ERROR, "Protocol %s is not supported by RTC, choose udp, line %d %s of %s\n",
960 protocol, i, line, whip->sdp_answer);
961 ret = AVERROR(EIO);
962 goto end;
963 }
964
965 whip->ice_protocol = av_strdup(protocol);
966 whip->ice_host = av_strdup(host);
967 whip->ice_port = port;
968 if (!whip->ice_protocol || !whip->ice_host) {
969 ret = AVERROR(ENOMEM);
970 goto end;
971 }
972 }
973 }
974 }
975
976 if (!whip->ice_pwd_remote || !strlen(whip->ice_pwd_remote)) {
977 av_log(whip, AV_LOG_ERROR, "No remote ice pwd parsed from %s\n", whip->sdp_answer);
978 ret = AVERROR(EINVAL);
979 goto end;
980 }
981
982 if (!whip->ice_ufrag_remote || !strlen(whip->ice_ufrag_remote)) {
983 av_log(whip, AV_LOG_ERROR, "No remote ice ufrag parsed from %s\n", whip->sdp_answer);
984 ret = AVERROR(EINVAL);
985 goto end;
986 }
987
988 if (!whip->ice_protocol || !whip->ice_host || !whip->ice_port) {
989 av_log(whip, AV_LOG_ERROR, "No ice candidate parsed from %s\n", whip->sdp_answer);
990 ret = AVERROR(EINVAL);
991 goto end;
992 }
993
994 /* per RFC 8829/8842, SDP answer MUST carry a=fingerprint and that
995 * fingerprint MUST match the DTLS peer certificate. Without it, an
996 * on-path attacker can complete DTLS with an arbitrary self-signed
997 * certificate and the resulting SRTP session is unauthenticated. */
998 if (!whip->remote_fingerprint || !strlen(whip->remote_fingerprint)) {
999 av_log(whip, AV_LOG_ERROR,
1000 "No remote DTLS fingerprint in SDP answer; refusing unauthenticated session\n");
1001 ret = AVERROR(EINVAL);
1002 goto end;
1003 }
1004
1005 if (whip->state < WHIP_STATE_NEGOTIATED)
1008 av_log(whip, AV_LOG_VERBOSE, "SDP state=%d, offer=%zuB, answer=%zuB, ufrag=%s, pwd=%zuB, transport=%s://%s:%d, elapsed=%.2fms\n",
1009 whip->state, strlen(whip->sdp_offer), strlen(whip->sdp_answer), whip->ice_ufrag_remote, strlen(whip->ice_pwd_remote),
1011
1012end:
1013 avio_context_free(&pb);
1014 return ret;
1015}
1016
1017/**
1018 * Creates and marshals an ICE binding request packet.
1019 *
1020 * This function creates and marshals an ICE binding request packet. The function only
1021 * generates the username attribute and does not include goog-network-info,
1022 * use-candidate. However, some of these attributes may be added in the future.
1023 *
1024 * @param s Pointer to the AVFormatContext
1025 * @param buf Pointer to memory buffer to store the request packet
1026 * @param buf_size Size of the memory buffer
1027 * @param request_size Pointer to an integer that receives the size of the request packet
1028 * @return Returns 0 if successful or AVERROR_xxx if an error occurs.
1029 */
1030static int ice_create_request(AVFormatContext *s, uint8_t *buf, int buf_size, int *request_size)
1031{
1032 int ret, size, crc32;
1033 char username[128];
1034 AVIOContext *pb = NULL;
1035 AVHMAC *hmac = NULL;
1036 WHIPContext *whip = s->priv_data;
1037
1038 pb = avio_alloc_context(buf, buf_size, 1, NULL, NULL, NULL, NULL);
1039 if (!pb)
1040 return AVERROR(ENOMEM);
1041
1043 if (!hmac) {
1044 ret = AVERROR(ENOMEM);
1045 goto end;
1046 }
1047
1048 /* Write 20 bytes header */
1049 avio_wb16(pb, 0x0001); /* STUN binding request */
1050 avio_wb16(pb, 0); /* length */
1051 avio_wb32(pb, STUN_MAGIC_COOKIE); /* magic cookie */
1052 avio_wb32(pb, av_lfg_get(&whip->rnd)); /* transaction ID */
1053 avio_wb32(pb, av_lfg_get(&whip->rnd)); /* transaction ID */
1054 avio_wb32(pb, av_lfg_get(&whip->rnd)); /* transaction ID */
1055
1056 /* The username is the concatenation of the two ICE ufrag */
1057 ret = snprintf(username, sizeof(username), "%s:%s", whip->ice_ufrag_remote, whip->ice_ufrag_local);
1058 if (ret <= 0 || ret >= sizeof(username)) {
1059 av_log(whip, AV_LOG_ERROR, "Failed to build username %s:%s, max=%zu, ret=%d\n",
1060 whip->ice_ufrag_remote, whip->ice_ufrag_local, sizeof(username), ret);
1061 ret = AVERROR(EIO);
1062 goto end;
1063 }
1064
1065 /* Write the username attribute */
1066 avio_wb16(pb, STUN_ATTR_USERNAME); /* attribute type username */
1067 avio_wb16(pb, ret); /* size of username */
1068 avio_write(pb, username, ret); /* bytes of username */
1069 ffio_fill(pb, 0, (4 - (ret % 4)) % 4); /* padding */
1070
1071 /* Write the use-candidate attribute */
1072 avio_wb16(pb, STUN_ATTR_USE_CANDIDATE); /* attribute type use-candidate */
1073 avio_wb16(pb, 0); /* size of use-candidate */
1074
1076 avio_wb16(pb, 4);
1078
1080 avio_wb16(pb, 8);
1081 avio_wb64(pb, whip->ice_tie_breaker);
1082
1083 /* Build and update message integrity */
1084 avio_wb16(pb, STUN_ATTR_MESSAGE_INTEGRITY); /* attribute type message integrity */
1085 avio_wb16(pb, 20); /* size of message integrity */
1086 ffio_fill(pb, 0, 20); /* fill with zero to directly write and skip it */
1087 size = avio_tell(pb);
1088 buf[2] = (size - 20) >> 8;
1089 buf[3] = (size - 20) & 0xFF;
1090 av_hmac_init(hmac, whip->ice_pwd_remote, strlen(whip->ice_pwd_remote));
1091 av_hmac_update(hmac, buf, size - 24);
1092 av_hmac_final(hmac, buf + size - 20, 20);
1093
1094 /* Write the fingerprint attribute */
1095 avio_wb16(pb, STUN_ATTR_FINGERPRINT); /* attribute type fingerprint */
1096 avio_wb16(pb, 4); /* size of fingerprint */
1097 ffio_fill(pb, 0, 4); /* fill with zero to directly write and skip it */
1098 size = avio_tell(pb);
1099 buf[2] = (size - 20) >> 8;
1100 buf[3] = (size - 20) & 0xFF;
1101 /* Refer to the av_hash_alloc("CRC32"), av_hash_init and av_hash_final */
1102 crc32 = av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), 0xFFFFFFFF, buf, size - 8) ^ 0xFFFFFFFF;
1103 avio_skip(pb, -4);
1104 avio_wb32(pb, crc32 ^ 0x5354554E); /* xor with "STUN" */
1105
1106 *request_size = size;
1107
1108end:
1109 avio_context_free(&pb);
1110 av_hmac_free(hmac);
1111 return ret;
1112}
1113
1114/**
1115 * Create an ICE binding response.
1116 *
1117 * This function generates an ICE binding response and writes it to the provided
1118 * buffer. The response is signed using the local password for message integrity.
1119 *
1120 * @param s Pointer to the AVFormatContext structure.
1121 * @param tid Pointer to the transaction ID of the binding request. The tid_size should be 12.
1122 * @param tid_size The size of the transaction ID, should be 12.
1123 * @param buf Pointer to the buffer where the response will be written.
1124 * @param buf_size The size of the buffer provided for the response.
1125 * @param response_size Pointer to an integer that will store the size of the generated response.
1126 * @return Returns 0 if successful or AVERROR_xxx if an error occurs.
1127 */
1128static int ice_create_response(AVFormatContext *s, char *tid, int tid_size, uint8_t *buf, int buf_size, int *response_size)
1129{
1130 int ret = 0, size, crc32;
1131 AVIOContext *pb = NULL;
1132 AVHMAC *hmac = NULL;
1133 WHIPContext *whip = s->priv_data;
1134
1135 if (tid_size != 12) {
1136 av_log(whip, AV_LOG_ERROR, "Invalid transaction ID size. Expected 12, got %d\n", tid_size);
1137 return AVERROR(EINVAL);
1138 }
1139
1140 pb = avio_alloc_context(buf, buf_size, 1, NULL, NULL, NULL, NULL);
1141 if (!pb)
1142 return AVERROR(ENOMEM);
1143
1145 if (!hmac) {
1146 ret = AVERROR(ENOMEM);
1147 goto end;
1148 }
1149
1150 /* Write 20 bytes header */
1151 avio_wb16(pb, 0x0101); /* STUN binding response */
1152 avio_wb16(pb, 0); /* length */
1153 avio_wb32(pb, STUN_MAGIC_COOKIE); /* magic cookie */
1154 avio_write(pb, tid, tid_size); /* transaction ID */
1155
1156 /* Build and update message integrity */
1157 avio_wb16(pb, STUN_ATTR_MESSAGE_INTEGRITY); /* attribute type message integrity */
1158 avio_wb16(pb, 20); /* size of message integrity */
1159 ffio_fill(pb, 0, 20); /* fill with zero to directly write and skip it */
1160 size = avio_tell(pb);
1161 buf[2] = (size - 20) >> 8;
1162 buf[3] = (size - 20) & 0xFF;
1163 av_hmac_init(hmac, whip->ice_pwd_local, strlen(whip->ice_pwd_local));
1164 av_hmac_update(hmac, buf, size - 24);
1165 av_hmac_final(hmac, buf + size - 20, 20);
1166
1167 /* Write the fingerprint attribute */
1168 avio_wb16(pb, STUN_ATTR_FINGERPRINT); /* attribute type fingerprint */
1169 avio_wb16(pb, 4); /* size of fingerprint */
1170 ffio_fill(pb, 0, 4); /* fill with zero to directly write and skip it */
1171 size = avio_tell(pb);
1172 buf[2] = (size - 20) >> 8;
1173 buf[3] = (size - 20) & 0xFF;
1174 /* Refer to the av_hash_alloc("CRC32"), av_hash_init and av_hash_final */
1175 crc32 = av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), 0xFFFFFFFF, buf, size - 8) ^ 0xFFFFFFFF;
1176 avio_skip(pb, -4);
1177 avio_wb32(pb, crc32 ^ 0x5354554E); /* xor with "STUN" */
1178
1179 *response_size = size;
1180
1181end:
1182 avio_context_free(&pb);
1183 av_hmac_free(hmac);
1184 return ret;
1185}
1186
1187/**
1188 * A Binding request has class=0b00 (request) and method=0b000000000001 (Binding)
1189 * and is encoded into the first 16 bits as 0x0001.
1190 * See https://datatracker.ietf.org/doc/html/rfc5389#section-6
1191 */
1192static int ice_is_binding_request(uint8_t *b, int size)
1193{
1194 return size >= ICE_STUN_HEADER_SIZE && AV_RB16(&b[0]) == 0x0001;
1195}
1196
1197/**
1198 * A Binding response has class=0b10 (success response) and method=0b000000000001,
1199 * and is encoded into the first 16 bits as 0x0101.
1200 */
1201static int ice_is_binding_response(uint8_t *b, int size)
1202{
1203 return size >= ICE_STUN_HEADER_SIZE && AV_RB16(&b[0]) == 0x0101;
1204}
1205
1206/**
1207 * In RTP packets, the first byte is represented as 0b10xxxxxx, where the initial
1208 * two bits (0b10) indicate the RTP version,
1209 * see https://www.rfc-editor.org/rfc/rfc3550#section-5.1
1210 * The RTCP packet header is similar to RTP,
1211 * see https://www.rfc-editor.org/rfc/rfc3550#section-6.4.1
1212 */
1213static int media_is_rtp_rtcp(const uint8_t *b, int size)
1214{
1215 return size >= WHIP_RTP_HEADER_SIZE && (b[0] & 0xC0) == 0x80;
1216}
1217
1218/* Whether the packet is RTCP. */
1219static int media_is_rtcp(const uint8_t *b, int size)
1220{
1221 return size >= WHIP_RTP_HEADER_SIZE && b[1] >= WHIP_RTCP_PT_START && b[1] <= WHIP_RTCP_PT_END;
1222}
1223
1224/**
1225 * This function handles incoming binding request messages by responding to them.
1226 * If the message is not a binding request, it will be ignored.
1227 */
1228static int ice_handle_binding_request(AVFormatContext *s, char *buf, int buf_size)
1229{
1230 int ret = 0, size;
1231 char tid[12];
1232 WHIPContext *whip = s->priv_data;
1233
1234 /* Ignore if not a binding request. */
1235 if (!ice_is_binding_request(buf, buf_size))
1236 return ret;
1237
1238 if (buf_size < ICE_STUN_HEADER_SIZE) {
1239 av_log(whip, AV_LOG_ERROR, "Invalid STUN message, expected at least %d, got %d\n",
1240 ICE_STUN_HEADER_SIZE, buf_size);
1241 return AVERROR(EINVAL);
1242 }
1243
1244 /* Parse transaction id from binding request in buf. */
1245 memcpy(tid, buf + 8, 12);
1246
1247 /* Build the STUN binding response. */
1248 ret = ice_create_response(s, tid, sizeof(tid), whip->buf, sizeof(whip->buf), &size);
1249 if (ret < 0) {
1250 av_log(whip, AV_LOG_ERROR, "Failed to create STUN binding response, size=%d\n", size);
1251 return ret;
1252 }
1253
1254 ret = ffurl_write(whip->udp, whip->buf, size);
1255 if (ret < 0) {
1256 av_log(whip, AV_LOG_ERROR, "Failed to send STUN binding response, size=%d\n", size);
1257 return ret;
1258 }
1259
1260 return 0;
1261}
1262
1263/**
1264 * To establish a connection with the UDP server, we utilize ICE-LITE in a Client-Server
1265 * mode. In this setup, FFmpeg acts as the UDP client, while the peer functions as the
1266 * UDP server.
1267 */
1269{
1270 int ret = 0;
1271 char url[256];
1273 WHIPContext *whip = s->priv_data;
1274
1275 /* Build UDP URL and create the UDP context as transport. */
1276 ff_url_join(url, sizeof(url), "udp", NULL, whip->ice_host, whip->ice_port, NULL);
1277
1278 av_dict_set_int(&opts, "connect", 1, 0);
1279 av_dict_set_int(&opts, "fifo_size", 0, 0);
1280 /* Pass through the pkt_size and buffer_size to underling protocol */
1281 av_dict_set_int(&opts, "pkt_size", whip->pkt_size, 0);
1282 av_dict_set_int(&opts, "buffer_size", whip->ts_buffer_size, 0);
1283
1284 ret = ffurl_open_whitelist(&whip->udp, url, AVIO_FLAG_WRITE, &s->interrupt_callback,
1285 &opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
1286 if (ret < 0) {
1287 av_log(whip, AV_LOG_ERROR, "Failed to connect udp://%s:%d\n", whip->ice_host, whip->ice_port);
1288 goto end;
1289 }
1290
1291 /* Make the socket non-blocking, set to READ and WRITE mode after connected */
1294
1295 if (whip->state < WHIP_STATE_UDP_CONNECTED)
1298 av_log(whip, AV_LOG_VERBOSE, "UDP state=%d, elapsed=%.2fms, connected to udp://%s:%d\n",
1299 whip->state, ELAPSED(whip->whip_starttime, av_gettime_relative()), whip->ice_host, whip->ice_port);
1300
1301end:
1303 return ret;
1304}
1305
1307{
1308 int ret = 0, size, i;
1309 int64_t starttime = av_gettime_relative(), now;
1310 WHIPContext *whip = s->priv_data;
1311 int is_dtls_active = whip->flags & WHIP_DTLS_ACTIVE;
1312
1313 if (whip->state < WHIP_STATE_UDP_CONNECTED || !whip->udp) {
1314 av_log(whip, AV_LOG_ERROR, "UDP not connected, state=%d, udp=%p\n", whip->state, whip->udp);
1315 return AVERROR(EINVAL);
1316 }
1317
1318 while (1) {
1319 if (whip->state <= WHIP_STATE_ICE_CONNECTING) {
1320 /* Build the STUN binding request. */
1321 ret = ice_create_request(s, whip->buf, sizeof(whip->buf), &size);
1322 if (ret < 0) {
1323 av_log(whip, AV_LOG_ERROR, "Failed to create STUN binding request, size=%d\n", size);
1324 goto end;
1325 }
1326
1327 ret = ffurl_write(whip->udp, whip->buf, size);
1328 if (ret < 0) {
1329 av_log(whip, AV_LOG_ERROR, "Failed to send STUN binding request, size=%d\n", size);
1330 goto end;
1331 }
1332
1333 if (whip->state < WHIP_STATE_ICE_CONNECTING)
1335 }
1336
1337next_packet:
1338 if (whip->state >= WHIP_STATE_DTLS_FINISHED)
1339 /* DTLS handshake is done, exit the loop. */
1340 break;
1341
1342 now = av_gettime_relative();
1343 if (now - starttime >= whip->handshake_timeout * WHIP_US_PER_MS) {
1344 av_log(whip, AV_LOG_ERROR, "DTLS handshake timeout=%dms, cost=%.2fms, elapsed=%.2fms, state=%d\n",
1345 whip->handshake_timeout, ELAPSED(starttime, now), ELAPSED(whip->whip_starttime, now), whip->state);
1346 ret = AVERROR(ETIMEDOUT);
1347 goto end;
1348 }
1349
1350 /* Read the STUN or DTLS messages from peer. */
1351 for (i = 0; i < ICE_DTLS_READ_MAX_RETRY; i++) {
1352 if (whip->state > WHIP_STATE_ICE_CONNECTED)
1353 break;
1354 ret = ffurl_read(whip->udp, whip->buf, sizeof(whip->buf));
1355 if (ret > 0)
1356 break;
1357 if (ret == AVERROR(EAGAIN)) {
1359 continue;
1360 }
1361 if (is_dtls_active)
1362 break;
1363 av_log(whip, AV_LOG_ERROR, "Failed to read message\n");
1364 goto end;
1365 }
1366
1367 /* Handle the ICE binding response. */
1368 if (ice_is_binding_response(whip->buf, ret)) {
1369 if (whip->state < WHIP_STATE_ICE_CONNECTED) {
1370 if (whip->is_peer_ice_lite)
1372 }
1373 goto next_packet;
1374 }
1375
1376 /* When a binding request is received, it is necessary to respond immediately. */
1377 if (ice_is_binding_request(whip->buf, ret)) {
1378 if ((ret = ice_handle_binding_request(s, whip->buf, ret)) < 0)
1379 goto end;
1380 goto next_packet;
1381 }
1382
1383 /* Handle DTLS handshake */
1384 if (ff_is_dtls_packet(whip->buf, ret) || is_dtls_active) {
1386 /* Start consent timer when ICE selected */
1389 av_log(whip, AV_LOG_VERBOSE, "ICE STUN ok, state=%d, url=udp://%s:%d, location=%s, username=%s:%s, res=%dB, elapsed=%.2fms\n",
1390 whip->state, whip->ice_host, whip->ice_port, whip->whip_resource_url ? whip->whip_resource_url : "",
1391 whip->ice_ufrag_remote, whip->ice_ufrag_local, ret, ELAPSED(whip->whip_starttime, whip->whip_ice_time));
1392
1393 ret = dtls_initialize(s);
1394 if (ret < 0)
1395 goto end;
1396 ret = ffurl_handshake(whip->dtls_uc);
1397 if (ret < 0) {
1398 whip->state = WHIP_STATE_FAILED;
1399 av_log(whip, AV_LOG_ERROR, "DTLS session failed\n");
1400 goto end;
1401 }
1402 if (!ret) {
1405 av_log(whip, AV_LOG_VERBOSE, "DTLS handshake is done, elapsed=%.2fms\n",
1406 ELAPSED(whip->whip_starttime, whip->whip_dtls_time));
1407 }
1408 goto next_packet;
1409 }
1410 }
1411
1412end:
1413 return ret;
1414}
1415
1416/**
1417 * Establish the SRTP context using the keying material exported from DTLS.
1418 *
1419 * Create separate SRTP contexts for sending video and audio, as their sequences differ
1420 * and should not share a single context. Generate a single SRTP context for receiving
1421 * RTCP only.
1422 *
1423 * @return 0 if OK, AVERROR_xxx on error
1424 */
1426{
1427 int ret;
1428 char recv_key[DTLS_SRTP_KEY_LEN + DTLS_SRTP_SALT_LEN];
1429 char send_key[DTLS_SRTP_KEY_LEN + DTLS_SRTP_SALT_LEN];
1431 /**
1432 * The profile for OpenSSL's SRTP is SRTP_AES128_CM_SHA1_80, see ssl/d1_srtp.c.
1433 * The profile for FFmpeg's SRTP is SRTP_AES128_CM_HMAC_SHA1_80, see libavformat/srtp.c.
1434 */
1435 const char* suite = "SRTP_AES128_CM_HMAC_SHA1_80";
1436 WHIPContext *whip = s->priv_data;
1437 int is_dtls_active = whip->flags & WHIP_DTLS_ACTIVE;
1438 char *cp = is_dtls_active ? send_key : recv_key;
1439 char *sp = is_dtls_active ? recv_key : send_key;
1440
1442 if (ret < 0)
1443 goto end;
1444 /**
1445 * This represents the material used to build the SRTP master key. It is
1446 * generated by DTLS and has the following layout:
1447 * 16B 16B 14B 14B
1448 * client_key | server_key | client_salt | server_salt
1449 */
1450 char *client_key = whip->dtls_srtp_materials;
1451 char *server_key = whip->dtls_srtp_materials + DTLS_SRTP_KEY_LEN;
1452 char *client_salt = server_key + DTLS_SRTP_KEY_LEN;
1453 char *server_salt = client_salt + DTLS_SRTP_SALT_LEN;
1454
1455 memcpy(cp, client_key, DTLS_SRTP_KEY_LEN);
1456 memcpy(cp + DTLS_SRTP_KEY_LEN, client_salt, DTLS_SRTP_SALT_LEN);
1457
1458 memcpy(sp, server_key, DTLS_SRTP_KEY_LEN);
1459 memcpy(sp + DTLS_SRTP_KEY_LEN, server_salt, DTLS_SRTP_SALT_LEN);
1460
1461 /* Setup SRTP context for outgoing packets */
1462 if (!av_base64_encode(buf, sizeof(buf), send_key, sizeof(send_key))) {
1463 av_log(whip, AV_LOG_ERROR, "Failed to encode send key\n");
1464 ret = AVERROR(EIO);
1465 goto end;
1466 }
1467
1468 ret = ff_srtp_set_crypto(&whip->srtp_audio_send, suite, buf);
1469 if (ret < 0) {
1470 av_log(whip, AV_LOG_ERROR, "Failed to set crypto for audio send\n");
1471 goto end;
1472 }
1473
1474 ret = ff_srtp_set_crypto(&whip->srtp_video_send, suite, buf);
1475 if (ret < 0) {
1476 av_log(whip, AV_LOG_ERROR, "Failed to set crypto for video send\n");
1477 goto end;
1478 }
1479
1480 ret = ff_srtp_set_crypto(&whip->srtp_video_rtx_send, suite, buf);
1481 if (ret < 0) {
1482 av_log(whip, AV_LOG_ERROR, "Failed to set crypto for video rtx send\n");
1483 goto end;
1484 }
1485
1486 ret = ff_srtp_set_crypto(&whip->srtp_rtcp_send, suite, buf);
1487 if (ret < 0) {
1488 av_log(whip, AV_LOG_ERROR, "Failed to set crypto for rtcp send\n");
1489 goto end;
1490 }
1491
1492 /* Setup SRTP context for incoming packets */
1493 if (!av_base64_encode(buf, sizeof(buf), recv_key, sizeof(recv_key))) {
1494 av_log(whip, AV_LOG_ERROR, "Failed to encode recv key\n");
1495 ret = AVERROR(EIO);
1496 goto end;
1497 }
1498
1499 ret = ff_srtp_set_crypto(&whip->srtp_recv, suite, buf);
1500 if (ret < 0) {
1501 av_log(whip, AV_LOG_ERROR, "Failed to set crypto for recv\n");
1502 goto end;
1503 }
1504
1505 if (whip->state < WHIP_STATE_SRTP_FINISHED)
1508 av_log(whip, AV_LOG_VERBOSE, "SRTP setup done, state=%d, suite=%s, key=%zuB, elapsed=%.2fms\n",
1509 whip->state, suite, sizeof(send_key), ELAPSED(whip->whip_starttime, av_gettime_relative()));
1510
1511end:
1512 return ret;
1513}
1514
1515static int rtp_history_store(WHIPContext *whip, const uint8_t *buf, int size)
1516{
1517 uint16_t seq = AV_RB16(buf + 2);
1518 uint32_t pos = ((uint32_t)seq - (uint32_t)whip->video_first_seq) % (uint32_t)whip->hist_sz;
1519 RtpHistoryItem *it = &whip->hist[pos];
1520 if (size > whip->pkt_size - DTLS_SRTP_CHECKSUM_LEN)
1521 return AVERROR_INVALIDDATA;
1522 memcpy(it->buf, buf, size);
1523 it->size = size;
1524 it->seq = seq;
1525
1526 whip->hist_head = ++pos;
1527 return 0;
1528}
1529
1530static const RtpHistoryItem *rtp_history_find(WHIPContext *whip, uint16_t seq)
1531{
1532 uint32_t pos = ((uint32_t)seq - (uint32_t)whip->video_first_seq) % (uint32_t)whip->hist_sz;
1533 const RtpHistoryItem *it = &whip->hist[pos];
1534 return it->seq == seq ? it : NULL;
1535}
1536
1537/**
1538 * Callback triggered by the RTP muxer when it creates and sends out an RTP packet.
1539 *
1540 * This function modifies the video STAP packet, removing the markers, and updating the
1541 * NRI of the first NALU. Additionally, it uses the corresponding SRTP context to encrypt
1542 * the RTP packet, where the video packet is handled by the video SRTP context.
1543 */
1544static int on_rtp_write_packet(void *opaque, const uint8_t *buf, int buf_size)
1545{
1546 int ret, cipher_size, is_rtcp, is_video;
1547 uint8_t payload_type;
1548 AVFormatContext *s = opaque;
1549 WHIPContext *whip = s->priv_data;
1550 SRTPContext *srtp;
1551
1552 /* Ignore if not RTP or RTCP packet. */
1553 if (!media_is_rtp_rtcp(buf, buf_size))
1554 return 0;
1555
1556 /* Only support audio, video and rtcp. */
1557 is_rtcp = media_is_rtcp(buf, buf_size);
1558 payload_type = buf[1] & 0x7f;
1559 is_video = payload_type == whip->video_payload_type;
1560 if (!is_rtcp && payload_type != whip->video_payload_type && payload_type != whip->audio_payload_type)
1561 return 0;
1562
1563 /* Get the corresponding SRTP context. */
1564 srtp = is_rtcp ? &whip->srtp_rtcp_send : (is_video? &whip->srtp_video_send : &whip->srtp_audio_send);
1565
1566 /* Encrypt by SRTP and send out. */
1567 cipher_size = ff_srtp_encrypt(srtp, buf, buf_size, whip->buf, sizeof(whip->buf));
1568 if (cipher_size <= 0 || cipher_size < buf_size) {
1569 av_log(whip, AV_LOG_WARNING, "Failed to encrypt packet=%dB, cipher=%dB\n", buf_size, cipher_size);
1570 return 0;
1571 }
1572
1573 if (is_video) {
1574 ret = rtp_history_store(whip, buf, buf_size);
1575 if (ret < 0)
1576 return ret;
1577 }
1578
1579 ret = ffurl_write(whip->udp, whip->buf, cipher_size);
1580 if (ret < 0) {
1581 av_log(whip, AV_LOG_ERROR, "Failed to write packet=%dB, ret=%d\n", cipher_size, ret);
1582 return ret;
1583 }
1584
1585 return ret;
1586}
1587
1588/**
1589 * Creates dedicated RTP muxers for each stream in the AVFormatContext to build RTP
1590 * packets from the encoded frames.
1591 *
1592 * The corresponding SRTP context is utilized to encrypt each stream's RTP packets. For
1593 * example, a video SRTP context is used for the video stream. Additionally, the
1594 * "on_rtp_write_packet" callback function is set as the write function for each RTP
1595 * muxer to send out encrypted RTP packets.
1596 *
1597 * @return 0 if OK, AVERROR_xxx on error
1598 */
1600{
1601 int ret, i, is_video, buffer_size, max_packet_size;
1602 AVFormatContext *rtp_ctx = NULL;
1604 uint8_t *buffer = NULL;
1605 WHIPContext *whip = s->priv_data;
1606 whip->udp->flags |= AVIO_FLAG_NONBLOCK;
1607
1608
1609 /* The UDP buffer size, may greater than MTU. */
1610 buffer_size = MAX_UDP_BUFFER_SIZE;
1611 /* The RTP payload max size. Reserved some bytes for SRTP checksum and padding. */
1612 max_packet_size = whip->pkt_size - DTLS_SRTP_CHECKSUM_LEN;
1613
1614 for (i = 0; i < s->nb_streams; i++) {
1615 rtp_ctx = avformat_alloc_context();
1616 if (!rtp_ctx) {
1617 ret = AVERROR(ENOMEM);
1618 goto end;
1619 }
1620
1622 rtp_ctx->oformat = &ff_rtp_muxer.p;
1623 if (!avformat_new_stream(rtp_ctx, NULL)) {
1624 ret = AVERROR(ENOMEM);
1625 goto end;
1626 }
1627 /* Pass the interrupt callback on */
1628 rtp_ctx->interrupt_callback = s->interrupt_callback;
1629 /* Copy the max delay setting; the rtp muxer reads this. */
1630 rtp_ctx->max_delay = s->max_delay;
1631 /* Copy other stream parameters. */
1632 rtp_ctx->streams[0]->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio;
1633 rtp_ctx->flags |= s->flags & AVFMT_FLAG_BITEXACT;
1634 rtp_ctx->strict_std_compliance = s->strict_std_compliance;
1635
1636 /* Set the synchronized start time. */
1637 rtp_ctx->start_time_realtime = s->start_time_realtime;
1638
1639 avcodec_parameters_copy(rtp_ctx->streams[0]->codecpar, s->streams[i]->codecpar);
1640 rtp_ctx->streams[0]->time_base = s->streams[i]->time_base;
1641
1642 /**
1643 * For H.264, consistently utilize the annexb format through the Bitstream Filter (BSF);
1644 * therefore, we deactivate the extradata detection for the RTP muxer.
1645 */
1646 if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_H264) {
1647 av_freep(&rtp_ctx->streams[0]->codecpar->extradata);
1648 rtp_ctx->streams[0]->codecpar->extradata_size = 0;
1649 }
1650
1651 buffer = av_malloc(buffer_size);
1652 if (!buffer) {
1653 ret = AVERROR(ENOMEM);
1654 goto end;
1655 }
1656
1657 rtp_ctx->pb = avio_alloc_context(buffer, buffer_size, 1, s, NULL, on_rtp_write_packet, NULL);
1658 if (!rtp_ctx->pb) {
1659 ret = AVERROR(ENOMEM);
1660 goto end;
1661 }
1662 rtp_ctx->pb->max_packet_size = max_packet_size;
1663 rtp_ctx->pb->av_class = &ff_avio_class;
1664
1665 is_video = s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;
1666 av_dict_set_int(&opts, "payload_type", is_video ? whip->video_payload_type : whip->audio_payload_type, 0);
1667 av_dict_set_int(&opts, "ssrc", is_video ? whip->video_ssrc : whip->audio_ssrc, 0);
1668 av_dict_set_int(&opts, "seq", is_video ? whip->video_first_seq : whip->audio_first_seq, 0);
1669
1670 ret = avformat_write_header(rtp_ctx, &opts);
1671 if (ret < 0) {
1672 av_log(whip, AV_LOG_ERROR, "Failed to write rtp header\n");
1673 goto end;
1674 }
1675
1676 ff_format_set_url(rtp_ctx, av_strdup(s->url));
1677 s->streams[i]->time_base = rtp_ctx->streams[0]->time_base;
1678 s->streams[i]->priv_data = rtp_ctx;
1679 rtp_ctx = NULL;
1680 }
1681
1682 if (whip->state < WHIP_STATE_READY)
1683 whip->state = WHIP_STATE_READY;
1684 av_log(whip, AV_LOG_INFO, "Muxer state=%d, buffer_size=%d, max_packet_size=%d, "
1685 "elapsed=%.2fms(init:%.2f,offer:%.2f,answer:%.2f,udp:%.2f,ice:%.2f,dtls:%.2f,srtp:%.2f)\n",
1686 whip->state, buffer_size, max_packet_size, ELAPSED(whip->whip_starttime, av_gettime_relative()),
1691 ELAPSED(whip->whip_udp_time, whip->whip_ice_time),
1692 ELAPSED(whip->whip_ice_time, whip->whip_dtls_time),
1693 ELAPSED(whip->whip_dtls_time, whip->whip_srtp_time));
1694
1695end:
1696 if (rtp_ctx) {
1697 if (!rtp_ctx->pb)
1698 av_freep(&buffer);
1699 avio_context_free(&rtp_ctx->pb);
1700 }
1701 avformat_free_context(rtp_ctx);
1703 return ret;
1704}
1705
1706/**
1707 * RTC is connectionless, for it's based on UDP, so it check whether sesison is
1708 * timeout. In such case, publishers can't republish the stream util the session
1709 * is timeout.
1710 * This function is called to notify the server that the stream is ended, server
1711 * should expire and close the session immediately, so that publishers can republish
1712 * the stream quickly.
1713 */
1715{
1716 int ret;
1717 char buf[MAX_URL_SIZE];
1718 URLContext *whip_uc = NULL;
1720 WHIPContext *whip = s->priv_data;
1721
1722 if (!whip->whip_resource_url)
1723 return 0;
1724
1725 ret = snprintf(buf, sizeof(buf), "Cache-Control: no-cache\r\n");
1726 if (whip->authorization)
1727 ret += snprintf(buf + ret, sizeof(buf) - ret, "Authorization: Bearer %s\r\n", whip->authorization);
1728 if (ret <= 0 || ret >= sizeof(buf)) {
1729 av_log(whip, AV_LOG_ERROR, "Failed to generate headers, size=%d, %s\n", ret, buf);
1730 ret = AVERROR(EINVAL);
1731 goto end;
1732 }
1733
1734 av_dict_set(&opts, "headers", buf, 0);
1735 av_dict_set_int(&opts, "chunked_post", 0, 0);
1736 av_dict_set(&opts, "method", "DELETE", 0);
1737
1738 if (whip->timeout >= 0)
1739 av_dict_set_int(&opts, "timeout", whip->timeout, 0);
1740
1741 ret = ffurl_open_whitelist(&whip_uc, whip->whip_resource_url, AVIO_FLAG_READ_WRITE, &s->interrupt_callback,
1742 &opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
1743 if (ret < 0) {
1744 av_log(whip, AV_LOG_ERROR, "Failed to DELETE url=%s\n", whip->whip_resource_url);
1745 goto end;
1746 }
1747
1748 while (1) {
1749 ret = ffurl_read(whip_uc, buf, sizeof(buf));
1750 if (ret == AVERROR_EOF) {
1751 ret = 0;
1752 break;
1753 }
1754 if (ret < 0) {
1755 av_log(whip, AV_LOG_ERROR, "Failed to read response from DELETE url=%s\n", whip->whip_resource_url);
1756 goto end;
1757 }
1758 }
1759
1760 av_log(whip, AV_LOG_INFO, "Dispose resource %s ok\n", whip->whip_resource_url);
1761
1762end:
1763 ffurl_closep(&whip_uc);
1765 return ret;
1766}
1767
1768/**
1769 * Since the h264_mp4toannexb filter only processes the MP4 ISOM format and bypasses
1770 * the annexb format, it is necessary to manually insert encoder metadata before each
1771 * IDR when dealing with annexb format packets. For instance, in the case of H.264,
1772 * we must insert SPS and PPS before the IDR frame.
1773 */
1775{
1776 int ret = 0;
1777 AVPacket *in = NULL;
1778 AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar;
1779 uint32_t nal_size = 0, out_size = par ? par->extradata_size : 0;
1780 uint8_t unit_type, sps_seen = 0, pps_seen = 0, idr_seen = 0, *out;
1781 const uint8_t *buf, *buf_end, *r1;
1782
1783 if (!par || !par->extradata || par->extradata_size <= 0)
1784 return ret;
1785
1786 /* Discover NALU type from packet. */
1787 buf_end = pkt->data + pkt->size;
1788 for (buf = ff_nal_find_startcode(pkt->data, buf_end); buf < buf_end; buf += nal_size) {
1789 while (!*(buf++));
1790 r1 = ff_nal_find_startcode(buf, buf_end);
1791 if ((nal_size = r1 - buf) > 0) {
1792 unit_type = *buf & 0x1f;
1793 if (unit_type == H264_NAL_SPS) {
1794 sps_seen = 1;
1795 } else if (unit_type == H264_NAL_PPS) {
1796 pps_seen = 1;
1797 } else if (unit_type == H264_NAL_IDR_SLICE) {
1798 idr_seen = 1;
1799 }
1800
1801 out_size += 3 + nal_size;
1802 }
1803 }
1804
1805 if (!idr_seen || (sps_seen && pps_seen))
1806 return ret;
1807
1808 /* See av_bsf_send_packet */
1809 in = av_packet_alloc();
1810 if (!in)
1811 return AVERROR(ENOMEM);
1812
1814 if (ret < 0)
1815 goto fail;
1816
1818
1819 /* Create a new packet with sps/pps inserted. */
1820 ret = av_new_packet(pkt, out_size);
1821 if (ret < 0)
1822 goto fail;
1823
1824 ret = av_packet_copy_props(pkt, in);
1825 if (ret < 0)
1826 goto fail;
1827
1828 memcpy(pkt->data, par->extradata, par->extradata_size);
1829 out = pkt->data + par->extradata_size;
1830 buf_end = in->data + in->size;
1831 for (buf = ff_nal_find_startcode(in->data, buf_end); buf < buf_end; buf += nal_size) {
1832 while (!*(buf++));
1833 r1 = ff_nal_find_startcode(buf, buf_end);
1834 if ((nal_size = r1 - buf) > 0) {
1835 AV_WB24(out, 0x00001);
1836 memcpy(out + 3, buf, nal_size);
1837 out += 3 + nal_size;
1838 }
1839 }
1840
1841fail:
1842 if (ret < 0)
1844 av_packet_free(&in);
1845
1846 return ret;
1847}
1848
1850{
1851 int ret;
1852 WHIPContext *whip = s->priv_data;
1853
1854 if ((ret = initialize(s)) < 0)
1855 goto end;
1856
1857 if ((ret = parse_codec(s)) < 0)
1858 goto end;
1859
1860 if ((ret = generate_sdp_offer(s)) < 0)
1861 goto end;
1862
1863 if ((ret = exchange_sdp(s)) < 0)
1864 goto end;
1865
1866 if ((ret = parse_answer(s)) < 0)
1867 goto end;
1868
1869 if ((ret = udp_connect(s)) < 0)
1870 goto end;
1871
1872 if ((ret = ice_dtls_handshake(s)) < 0)
1873 goto end;
1874
1875 if ((ret = setup_srtp(s)) < 0)
1876 goto end;
1877
1878 if ((ret = create_rtp_muxer(s)) < 0)
1879 goto end;
1880
1881end:
1882 if (ret < 0)
1883 whip->state = WHIP_STATE_FAILED;
1884 return ret;
1885}
1886
1887/**
1888 * See https://datatracker.ietf.org/doc/html/rfc4588#section-4
1889 * Create RTX packet and send it out.
1890 */
1891static void handle_rtx_packet(AVFormatContext *s, uint16_t seq)
1892{
1893 int ret = -1;
1894 WHIPContext *whip = s->priv_data;
1895 uint8_t *ori_buf, rtx_buf[MAX_UDP_BUFFER_SIZE] = { 0 };
1896 int ori_size, rtx_size, cipher_size;
1897 uint16_t ori_seq;
1898 const RtpHistoryItem *it = rtp_history_find(whip, seq);
1899 uint16_t latest_seq = whip->hist[(whip->hist_head - 1 + whip->hist_sz) % whip->hist_sz].seq;
1900
1901 if (!it) {
1902 av_log(whip, AV_LOG_DEBUG,
1903 "RTP history packet seq=%"PRIu16" not found, latest seq=%"PRIu16"\n",
1904 seq, latest_seq);
1905 return;
1906 }
1907 av_log(whip, AV_LOG_DEBUG,
1908 "Found RTP history packet for RTX, seq=%"PRIu16", latest seq=%"PRIu16"\n",
1909 seq, latest_seq);
1910
1911 ori_buf = it->buf;
1912 ori_size = it->size;
1913
1914 /* A valid RTP packet must have at least a RTP header. */
1915 if (ori_size < WHIP_RTP_HEADER_SIZE) {
1916 av_log(whip, AV_LOG_WARNING, "RTX history packet too small, size=%d\n", ori_size);
1917 goto end;
1918 }
1919
1920 /* RTX packet format: header + original seq (2 bytes) + payload */
1921 if (ori_size + 2 > sizeof(rtx_buf)) {
1922 av_log(whip, AV_LOG_WARNING, "RTX packet is too large, size=%d\n", ori_size);
1923 goto end;
1924 }
1925
1926 memcpy(rtx_buf, ori_buf, ori_size);
1927 ori_seq = AV_RB16(rtx_buf + 2);
1928
1929 /* rewrite RTX packet header */
1930 rtx_buf[1] = (rtx_buf[1] & 0x80) | whip->video_rtx_payload_type; /* keep M bit */
1931 AV_WB16(rtx_buf + 2, whip->video_rtx_seq++);
1932 AV_WB32(rtx_buf + 8, whip->video_rtx_ssrc);
1933
1934 /* shift payload 2 bytes to write the original seq number */
1935 memmove(rtx_buf + 12 + 2, rtx_buf + 12, ori_size - 12);
1936 AV_WB16(rtx_buf + 12, ori_seq);
1937
1938 rtx_size = ori_size + 2;
1939 cipher_size = ff_srtp_encrypt(&whip->srtp_video_rtx_send,
1940 rtx_buf, rtx_size,
1941 whip->buf, sizeof(whip->buf));
1942 if (cipher_size <= 0) {
1943 av_log(whip, AV_LOG_WARNING,
1944 "Failed to encrypt RTX packet, size=%d, cipher_size=%d\n",
1945 rtx_size, cipher_size);
1946 goto end;
1947 }
1948 ret = ffurl_write(whip->udp, whip->buf, cipher_size);
1949end:
1950 if (ret < 0)
1951 av_log(whip, AV_LOG_WARNING, "Failed to send RTX packet, skip this one\n");
1952}
1953
1955{
1956 int ret, i = 0;
1957 WHIPContext *whip = s->priv_data;
1958 uint8_t *buf = NULL;
1959 int rtcp_len, srtcp_len, header_len = 12/*RFC 4585 6.1*/;
1960 uint32_t ssrc;
1961
1962 /**
1963 * Refer to RFC 3550 6.4.1
1964 * The length of this RTCP packet in 32 bit words minus one,
1965 * including the header and any padding.
1966 */
1967 rtcp_len = (AV_RB16(&whip->buf[2]) + 1) * 4;
1968 if (rtcp_len <= header_len) {
1969 av_log(whip, AV_LOG_WARNING, "NACK packet is broken, size: %d\n", rtcp_len);
1970 goto error;
1971 }
1972 /* SRTCP index(4 bytes) + HMAC(SRTP_ARS128_CM_SHA1_80) 10bytes */
1973 srtcp_len = rtcp_len + 4 + 10;
1974 if (srtcp_len != size) {
1975 av_log(whip, AV_LOG_WARNING, "NACK packet size not match, srtcp_len:%d, size:%d\n", srtcp_len, size);
1976 goto error;
1977 }
1978 buf = av_memdup(whip->buf, srtcp_len);
1979 if (!buf)
1980 goto error;
1981 if ((ret = ff_srtp_decrypt(&whip->srtp_recv, buf, &srtcp_len)) < 0) {
1982 av_log(whip, AV_LOG_WARNING, "NACK packet decrypt failed: %d\n", ret);
1983 goto error;
1984 }
1985 ssrc = AV_RB32(&buf[8]);
1986 if (ssrc != whip->video_ssrc) {
1987 av_log(whip, AV_LOG_DEBUG,
1988 "NACK packet SSRC: %"PRIu32" not match with video track SSRC: %"PRIu32"\n",
1989 ssrc, whip->video_ssrc);
1990 goto end;
1991 }
1992 while (header_len + i + 4 <= rtcp_len) {
1993 /**
1994 * See https://datatracker.ietf.org/doc/html/rfc4585#section-6.1
1995 * Handle multi NACKs in bundled packet.
1996 */
1997 uint16_t pid = AV_RB16(&buf[12 + i]);
1998 uint16_t blp = AV_RB16(&buf[14 + i]);
1999
2000 handle_rtx_packet(s, pid);
2001 /* retransmit pid + any bit set in blp */
2002 for (int bit = 0; bit < 16; bit++) {
2003 uint16_t seq = pid + bit + 1;
2004 if (!blp)
2005 break;
2006 if (!(blp & (1 << bit)))
2007 continue;
2008
2009 handle_rtx_packet(s, seq);
2010 }
2011 i += 4;
2012 }
2013 goto end;
2014error:
2015 av_log(whip, AV_LOG_WARNING, "Failed to handle NACK and RTX, Skip...\n");
2016end:
2017 av_freep(&buf);
2018}
2019
2021{
2022 int ret;
2023 WHIPContext *whip = s->priv_data;
2024 AVStream *st = s->streams[pkt->stream_index];
2025 AVFormatContext *rtp_ctx = st->priv_data;
2027 /**
2028 * Refer to RFC 7675
2029 * Periodically send Consent Freshness STUN Binding Request
2030 */
2032 int size;
2033 ret = ice_create_request(s, whip->buf, sizeof(whip->buf), &size);
2034 if (ret < 0) {
2035 av_log(whip, AV_LOG_ERROR, "Failed to create STUN binding request, size=%d\n", size);
2036 goto end;
2037 }
2038 ret = ffurl_write(whip->udp, whip->buf, size);
2039 if (ret < 0) {
2040 av_log(whip, AV_LOG_ERROR, "Failed to send STUN binding request, size=%d\n", size);
2041 goto end;
2042 }
2043 whip->whip_last_consent_tx_time = now;
2044 av_log(whip, AV_LOG_DEBUG, "Consent Freshness check sent\n");
2045 }
2046
2047 /**
2048 * Receive packets from the server such as ICE binding requests, DTLS messages,
2049 * and RTCP like PLI requests, then respond to them.
2050 */
2051 ret = ffurl_read(whip->udp, whip->buf, sizeof(whip->buf));
2052 if (ret < 0) {
2053 if (ret == AVERROR(EAGAIN))
2054 goto write_packet;
2055 av_log(whip, AV_LOG_ERROR, "Failed to read from UDP socket\n");
2056 goto end;
2057 }
2058 if (!ret) {
2059 av_log(whip, AV_LOG_ERROR, "Receive EOF from UDP socket\n");
2060 goto end;
2061 }
2062 if (ice_is_binding_response(whip->buf, ret)) {
2064 av_log(whip, AV_LOG_DEBUG, "Consent Freshness check received\n");
2065 }
2066 if (ff_is_dtls_packet(whip->buf, ret)) {
2067 if ((ret = ffurl_write(whip->dtls_uc, whip->buf, ret)) < 0) {
2068 av_log(whip, AV_LOG_ERROR, "Failed to handle DTLS message\n");
2069 goto end;
2070 }
2071 }
2072 if (media_is_rtcp(whip->buf, ret)) {
2073 uint8_t fmt = whip->buf[0] & 0x1f;
2074 uint8_t pt = whip->buf[1];
2075 /**
2076 * Handle RTCP NACK packet
2077 * Refer to RFC 4585 6.2.1
2078 * The Generic NACK message is identified by PT=RTPFB and FMT=1
2079 */
2080 if (pt != RTCP_RTPFB)
2081 goto write_packet;
2082 if (fmt == 1)
2083 handle_nack_rtx(s, ret);
2084 }
2086 now = av_gettime_relative();
2088 av_log(whip, AV_LOG_ERROR,
2089 "Consent Freshness expired after %.2fms (limited %dms), terminate session\n",
2091 ret = AVERROR(ETIMEDOUT);
2092 goto end;
2093 }
2095 if ((ret = h264_annexb_insert_sps_pps(s, pkt)) < 0) {
2096 av_log(whip, AV_LOG_ERROR, "Failed to insert SPS/PPS before IDR\n");
2097 goto end;
2098 }
2099 }
2100
2101 ret = ff_write_chained(rtp_ctx, 0, pkt, s, 0);
2102 if (ret < 0) {
2103 if (ret == AVERROR(EINVAL)) {
2104 av_log(whip, AV_LOG_WARNING, "Ignore failed to write packet=%dB, ret=%d\n", pkt->size, ret);
2105 ret = 0;
2106 } else if (ret == AVERROR(EAGAIN)) {
2107 av_log(whip, AV_LOG_ERROR, "UDP send blocked, please increase the buffer via -ts_buffer_size\n");
2108 } else
2109 av_log(whip, AV_LOG_ERROR, "Failed to write packet, size=%d, ret=%d\n", pkt->size, ret);
2110 goto end;
2111 }
2112
2113end:
2114 if (ret < 0)
2115 whip->state = WHIP_STATE_FAILED;
2116 return ret;
2117}
2118
2120{
2121 int i, ret;
2122 WHIPContext *whip = s->priv_data;
2123
2124 ret = dispose_session(s);
2125 if (ret < 0)
2126 av_log(whip, AV_LOG_WARNING, "Failed to dispose resource, ret=%d\n", ret);
2127
2128 for (i = 0; i < s->nb_streams; i++) {
2129 AVFormatContext* rtp_ctx = s->streams[i]->priv_data;
2130 if (!rtp_ctx)
2131 continue;
2132
2133 av_write_trailer(rtp_ctx);
2134 /**
2135 * Keep in mind that it is necessary to free the buffer of pb since we allocate
2136 * it and pass it to pb using avio_alloc_context, while avio_context_free does
2137 * not perform this action.
2138 */
2139 av_freep(&rtp_ctx->pb->buffer);
2140 avio_context_free(&rtp_ctx->pb);
2141 avformat_free_context(rtp_ctx);
2142 s->streams[i]->priv_data = NULL;
2143 }
2144
2145 av_freep(&whip->hist_pool);
2146 av_freep(&whip->hist);
2147 av_freep(&whip->sdp_offer);
2148 av_freep(&whip->sdp_answer);
2150 av_freep(&whip->ice_ufrag_remote);
2151 av_freep(&whip->ice_pwd_remote);
2152 av_freep(&whip->ice_protocol);
2153 av_freep(&whip->ice_host);
2154 av_freep(&whip->authorization);
2155 av_freep(&whip->cert_file);
2156 av_freep(&whip->key_file);
2161 ff_srtp_free(&whip->srtp_recv);
2162 ffurl_closep(&whip->dtls_uc);
2163 ffurl_closep(&whip->udp);
2164 av_freep(&whip->dtls_fingerprint);
2166}
2167
2169{
2170 int ret = 1, extradata_isom = 0;
2171 uint8_t *b = pkt->data;
2172 WHIPContext *whip = s->priv_data;
2173
2174 if (st->codecpar->codec_id == AV_CODEC_ID_H264) {
2175 extradata_isom = st->codecpar->extradata_size > 0 && st->codecpar->extradata[0] == 1;
2176 if (pkt->size >= 5 && AV_RB32(b) != 0x0000001 && (AV_RB24(b) != 0x000001 || extradata_isom)) {
2177 ret = ff_stream_add_bitstream_filter(st, "h264_mp4toannexb", NULL);
2178 av_log(whip, AV_LOG_VERBOSE, "Enable BSF h264_mp4toannexb, packet=[%x %x %x %x %x ...], extradata_isom=%d\n",
2179 b[0], b[1], b[2], b[3], b[4], extradata_isom);
2180 } else
2182 }
2183
2184 return ret;
2185}
2186
2187#define OFFSET(x) offsetof(WHIPContext, x)
2188#define ENC AV_OPT_FLAG_ENCODING_PARAM
2189static const AVOption options[] = {
2190 { "handshake_timeout", "Timeout in milliseconds for ICE and DTLS handshake.", OFFSET(handshake_timeout), AV_OPT_TYPE_INT, { .i64 = 5000 }, -1, INT_MAX, ENC },
2191 { "timeout", "Set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, ENC },
2192 { "pkt_size", "The maximum size, in bytes, of RTP packets that send out", OFFSET(pkt_size), AV_OPT_TYPE_INT, { .i64 = 1200 }, -1, INT_MAX, ENC },
2193 { "ts_buffer_size", "The buffer size, in bytes, of underlying protocol", OFFSET(ts_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, ENC },
2194 { "whip_flags", "Set flags affecting WHIP connection behavior", OFFSET(flags), AV_OPT_TYPE_FLAGS, { .i64 = 0}, 0, UINT_MAX, ENC, .unit = "flags" },
2195 { "dtls_active", "Set dtls role as active", 0, AV_OPT_TYPE_CONST, { .i64 = WHIP_DTLS_ACTIVE}, 0, UINT_MAX, ENC, .unit = "flags" },
2196 { "rtp_history", "The number of RTP history items to store", OFFSET(hist_sz), AV_OPT_TYPE_INT, { .i64 = WHIP_RTP_HISTORY_DEFAULT }, WHIP_RTP_HISTORY_MIN, WHIP_RTP_HISTORY_MAX, ENC },
2197 { "authorization", "The optional Bearer token for WHIP Authorization", OFFSET(authorization), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, ENC },
2198 { "cert_file", "The optional certificate file path for DTLS", OFFSET(cert_file), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, ENC },
2199 { "key_file", "The optional private key file path for DTLS", OFFSET(key_file), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, ENC },
2200 { NULL },
2201};
2202
2204 .class_name = "WHIP muxer",
2205 .item_name = av_default_item_name,
2206 .option = options,
2207 .version = LIBAVUTIL_VERSION_INT,
2208};
2209
2211 .p.name = "whip",
2212 .p.long_name = NULL_IF_CONFIG_SMALL("WHIP(WebRTC-HTTP ingestion protocol) muxer"),
2213 .p.audio_codec = AV_CODEC_ID_OPUS,
2214 .p.video_codec = AV_CODEC_ID_H264,
2215 .p.subtitle_codec = AV_CODEC_ID_NONE,
2217 .p.priv_class = &whip_muxer_class,
2219 .priv_data_size = sizeof(WHIPContext),
2220 .init = whip_init,
2224};
const FFOutputFormat ff_rtp_muxer
Definition rtpenc.c:721
const FFOutputFormat ff_whip_muxer
Definition whip.c:2210
static FILE * out
static int out_size
static AVDictionary * opts
#define EXTERN
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_unreachable(msg)
Asserts that are used as compiler optimization hints depending upon ASSERT_LEVEL and NBDEBUG.
Definition avassert.h:109
int ff_avc_decode_sps(H264SPS *sps, const uint8_t *buf, int buf_size)
Definition avc.c:196
void ff_format_set_url(AVFormatContext *s, char *url)
Set AVFormatContext url field to the provided pointer.
Definition avformat.c:945
#define AVFMT_FLAG_BITEXACT
When muxing, try to avoid writing any random/volatile data to the output.
Definition avformat.h:1569
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition avformat.h:490
#define AVFMT_EXPERIMENTAL
The muxer/demuxer is experimental and should be used with caution.
Definition avformat.h:497
#define AVFMT_GLOBALHEADER
Format wants global header.
Definition avformat.h:499
int ffurl_handshake(URLContext *c)
Perform one step of the protocol handshake to accept a new client.
Definition avio.c:296
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist, const char *blacklist, URLContext *parent)
Create an URLContext for accessing to the resource indicated by url, and open it.
Definition avio.c:466
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition avio.c:663
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition avio.c:889
const AVClass ff_avio_class
Definition avio.c:104
const char * avio_find_protocol_name(const char *url)
Return the name of the protocol that will handle the passed URL.
Definition avio.c:732
void avio_wb32(AVIOContext *s, unsigned int val)
Definition aviobuf.c:368
void avio_wb16(AVIOContext *s, unsigned int val)
Definition aviobuf.c:446
#define AVIO_FLAG_READ
read-only
Definition avio.h:617
int avio_feof(AVIOContext *s)
Similar to feof() but also returns nonzero on read errors.
Definition aviobuf.c:349
#define AVIO_FLAG_WRITE
write-only
Definition avio.h:618
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition avio.h:494
void avio_wb64(AVIOContext *s, uint64_t val)
Definition aviobuf.c:434
AVIOContext * avio_alloc_context(unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int(*read_packet)(void *opaque, uint8_t *buf, int buf_size), int(*write_packet)(void *opaque, const uint8_t *buf, int buf_size), int64_t(*seek)(void *opaque, int64_t offset, int whence))
Allocate and initialize an AVIOContext for buffered I/O.
Definition aviobuf.c:109
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition aviobuf.c:321
#define AVIO_FLAG_READ_WRITE
read-write pseudo flag
Definition avio.h:619
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition aviobuf.c:206
void avio_context_free(AVIOContext **s)
Free the supplied IO context and everything associated with it.
Definition aviobuf.c:126
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition avio.h:636
void ffio_fill(AVIOContext *s, int b, int64_t count)
Definition aviobuf.c:192
int ff_get_chomp_line(AVIOContext *s, char *buf, int maxlen)
Same as ff_get_line but strip the white-space characters in the text tail.
Definition aviobuf.c:756
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:121
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:68
AVBPrint public header.
#define ENC
Definition caca.c:198
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
static int FUNC sps(CodedBitstreamContext *ctx, RWContext *rw, H264RawSPS *current)
#define bit(string, value)
Definition cbs_mpeg2.c:56
#define s(width, name)
Definition cbs_vp9.c:198
static void deinit(AVFormatContext *s)
Definition chromaprint.c:53
int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src)
Definition codec_par.c:107
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
Public header for CRC hash function implementation.
static unsigned crc32(const uint8_t *data, unsigned size)
#define AV_PROFILE_UNKNOWN
Definition defs.h:65
#define AV_PROFILE_H264_CONSTRAINED
Definition defs.h:121
#define AV_LEVEL_UNKNOWN
Definition defs.h:223
#define AV_PROFILE_H264_INTRA
Definition defs.h:122
static AVPacket * pkt
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
static struct @346255127015250356166251341105367306144006377143 state
static int write_packet(Muxer *mux, OutputStream *ost, AVPacket *pkt)
Definition ffmpeg_mux.c:205
#define fail
Definition test.h:479
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_DURATION
Underlying C type is int64_t.
Definition opt.h:318
@ AV_OPT_TYPE_FLAGS
Underlying C type is unsigned int.
Definition opt.h:254
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
@ AV_CODEC_ID_H264
Definition codec_id.h:77
@ AV_CODEC_ID_NONE
Definition codec_id.h:48
@ AV_CODEC_ID_OPUS
Definition codec_id.h:517
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition packet.c:74
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition packet.c:435
int av_packet_make_refcounted(AVPacket *pkt)
Ensure the data described by a given packet is reference counted.
Definition packet.c:498
void av_packet_move_ref(AVPacket *dst, AVPacket *src)
Move every field in src to dst and reset src.
Definition packet.c:492
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition packet.c:63
int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
Copy only "properties" fields from src to dst.
Definition packet.c:398
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition packet.c:98
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition options.c:165
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition avformat.c:164
av_warn_unused_result int avformat_write_header(AVFormatContext *s, AVDictionary **options)
Allocate the stream private data and write the stream header to an output media file.
Definition mux.c:505
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition mux.c:1276
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition bprint.h:218
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition bprint.c:234
char * av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size)
Encode data to base64 and null-terminate.
Definition base64.c:152
#define AV_BASE64_SIZE(x)
Calculate the output size needed to base64-encode x bytes to a null-terminated string.
Definition base64.h:66
const AVCRC * av_crc_get_table(AVCRCId crc_id)
Get an initialized standard CRC table.
Definition crc.c:389
uint32_t av_crc(const AVCRC *ctx, uint32_t crc, const uint8_t *buffer, size_t length)
Calculate the CRC of a block.
Definition crc.c:421
@ AV_CRC_32_IEEE_LE
Definition crc.h:53
uint32_t av_get_random_seed(void)
Get a seed to use in conjunction with random functions.
int av_random_bytes(uint8_t *buf, size_t len)
Generate cryptographically secure random data, i.e.
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition dict.c:233
#define AV_DICT_DONT_STRDUP_VAL
Take ownership of a value that's been allocated with av_malloc() or another memory allocation functio...
Definition dict.h:79
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition dict.c:86
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)
Convenience wrapper for av_dict_set() that converts the value to a string and stores it.
Definition dict.c:177
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition error.h:64
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
int av_hmac_final(AVHMAC *c, uint8_t *out, unsigned int outlen)
Finish hashing and output the HMAC digest.
Definition hmac.c:181
AVHMAC * av_hmac_alloc(enum AVHMACType type)
Allocate an AVHMAC context.
Definition hmac.c:82
void av_hmac_update(AVHMAC *c, const uint8_t *data, unsigned int len)
Hash data with the HMAC.
Definition hmac.c:176
void av_hmac_free(AVHMAC *c)
Free an AVHMAC context.
Definition hmac.c:147
void av_hmac_init(AVHMAC *c, const uint8_t *key, unsigned int keylen)
Initialize an AVHMAC context with an authentication key.
Definition hmac.c:155
@ AV_HMAC_SHA1
Definition hmac.h:34
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
Definition mem.c:408
@ AVMEDIA_TYPE_AUDIO
Definition avutil.h:201
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
char * av_stristr(const char *s1, const char *s2)
Locate the first case-independent occurrence in the string haystack of the string needle.
Definition avstring.c:58
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition avstring.c:208
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition avstring.c:36
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
H.264 common definitions.
@ H264_NAL_PPS
Definition h264.h:42
@ H264_NAL_SPS
Definition h264.h:41
@ H264_NAL_IDR_SLICE
Definition h264.h:39
int profile_idc
Definition h264_levels.c:53
static uint64_t request_size(URLContext *h)
Definition http.c:1640
const char * ff_http_get_new_location(URLContext *h)
Definition http.c:621
#define r
Definition input.c:42
#define b
Definition input.c:43
#define AV_WB24(p, d)
#define AV_WB32(p, v)
#define AV_RB32(p)
#define AV_WB16(p, v)
#define AV_RB24(x)
#define AV_RB16(p)
av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
Definition lfg.c:32
static unsigned int av_lfg_get(AVLFG *c)
Get the next random unsigned 32-bit number using an ALFG.
Definition lfg.h:53
char * ff_data_to_hex(char *buf, const uint8_t *src, int size, int lowercase)
Write hexadecimal string corresponding to given binary data.
Definition utils.c:473
#define MAX_URL_SIZE
Definition internal.h:30
int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, AVFormatContext *src, int interleave)
Write a packet to another muxer than the one the user originally intended.
Definition mux.c:1375
static int check_bitstream(AVFormatContext *s, FFStream *sti, AVPacket *pkt)
Definition mux.c:1094
int ff_stream_add_bitstream_filter(AVStream *st, const char *name, const char *args)
Add a bitstream filter to a stream.
Definition mux.c:1332
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:97
enum AVColorSpace space
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:370
Memory handling functions.
char * host
Definition mscl.c:249
#define FF_OFMT_FLAG_MAX_ONE_OF_EACH
If this flag is set, it indicates that for each codec type whose corresponding default codec (i....
Definition mux.h:50
#define FF_OFMT_FLAG_ONLY_DEFAULT_CODECS
If this flag is set, then the only permitted audio/video/subtitle codec ids are AVOutputFormat....
Definition mux.h:59
const uint8_t * ff_nal_find_startcode(const uint8_t *p, const uint8_t *end)
Definition nal.c:68
int ff_socket_nonblock(int socket, int enable)
#define av_strdup(s)
Definition ops_static.c:55
#define av_malloc(s)
Definition ops_static.c:52
AVOptions.
int pt
Definition rtp.c:35
@ RTCP_RTPFB
Definition rtp.h:104
unsigned int pos
Definition spdifenc.c:431
int ff_srtp_encrypt(struct SRTPContext *s, const uint8_t *in, int len, uint8_t *out, int outlen)
Definition srtp.c:239
int ff_srtp_set_crypto(struct SRTPContext *s, const char *suite, const char *params)
Definition srtp.c:66
int ff_srtp_decrypt(struct SRTPContext *s, uint8_t *buf, int *lenptr)
Definition srtp.c:127
void ff_srtp_free(struct SRTPContext *s)
Definition srtp.c:32
Accelerated start code search function for start codes common to MPEG-1/2/4 video,...
const uint8_t * avpriv_find_start_code(const uint8_t *p, const uint8_t *end, uint32_t *state)
int nb_channels
Number of channels in this layout.
Describe the class of an AVClass context structure.
Definition log.h:76
This struct describes the properties of an encoded stream.
Definition codec_par.h:49
int extradata_size
Size of the extradata content in bytes.
Definition codec_par.h:75
AVChannelLayout ch_layout
The channel layout and number of channels.
Definition codec_par.h:207
enum AVMediaType codec_type
General type of the encoded data.
Definition codec_par.h:53
int profile
Codec-specific bitstream restrictions that the stream conforms to.
Definition codec_par.h:135
int video_delay
Number of delayed frames.
Definition codec_par.h:200
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition codec_par.h:71
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition codec_par.h:57
int sample_rate
The number of audio samples per second.
Definition codec_par.h:213
Format I/O context.
Definition avformat.h:1400
AVIOContext * pb
I/O context.
Definition avformat.h:1442
int flags
Flags modifying the (de)muxer behaviour.
Definition avformat.h:1552
const struct AVOutputFormat * oformat
The output container format.
Definition avformat.h:1419
int strict_std_compliance
Allow non-standard and experimental extension.
Definition avformat.h:1775
AVIOInterruptCB interrupt_callback
Custom interrupt callbacks for the I/O layer.
Definition avformat.h:1686
int64_t start_time_realtime
Start time of the stream in real world time, in microseconds since the Unix epoch (00:00 1st January ...
Definition avformat.h:1661
AVStream ** streams
A list of all streams in the file.
Definition avformat.h:1468
Definition hmac.c:40
Bytestream IO Context.
Definition avio.h:160
const AVClass * av_class
A class for private options.
Definition avio.h:173
unsigned char * buffer
Start of the buffer.
Definition avio.h:225
int max_packet_size
Definition avio.h:241
Context structure for the Lagged Fibonacci PRNG.
Definition lfg.h:33
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:587
int size
Definition packet.h:611
uint8_t * data
Definition packet.h:610
Stream structure.
Definition avformat.h:768
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition avformat.h:791
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition avformat.h:846
void * priv_data
Definition avformat.h:793
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition avformat.h:807
Definition avc.h:32
uint16_t seq
Definition whip.c:209
uint8_t * buf
Definition whip.c:211
int flags
Definition url.h:40
int64_t whip_last_consent_tx_time
Definition whip.c:285
enum WHIPState state
Definition whip.c:219
int ice_port
Definition whip.c:269
char * authorization
The optional Bearer token for WHIP Authorization.
Definition whip.c:334
SRTPContext srtp_rtcp_send
Definition whip.c:310
AVCodecParameters * audio_par
Definition whip.c:222
char * ice_ufrag_remote
Definition whip.c:260
char * remote_fingerprint
Definition whip.c:294
char key_buf[MAX_CERTIFICATE_SIZE]
Definition whip.c:290
char cert_buf[MAX_CERTIFICATE_SIZE]
Definition whip.c:289
uint16_t audio_first_seq
Definition whip.c:243
char * ice_protocol
This represents the ICE candidate protocol, priority, host and port.
Definition whip.c:267
uint8_t video_payload_type
Definition whip.c:249
char * ice_pwd_remote
Definition whip.c:261
int64_t whip_last_consent_rx_time
Definition whip.c:286
int ts_buffer_size
Definition whip.c:329
uint32_t video_ssrc
Definition whip.c:240
int64_t whip_offer_time
Definition whip.c:279
int64_t timeout
Definition whip.c:323
SRTPContext srtp_recv
Definition whip.c:312
char buf[MAX_UDP_BUFFER_SIZE]
Definition whip.c:317
uint8_t video_rtx_payload_type
Definition whip.c:250
uint32_t audio_ssrc
Definition whip.c:239
AVClass * av_class
Definition whip.c:215
int64_t whip_dtls_time
Definition whip.c:283
char * cert_file
Definition whip.c:336
int hist_head
Definition whip.c:342
int64_t whip_starttime
Definition whip.c:277
uint8_t dtls_srtp_materials[(DTLS_SRTP_KEY_LEN+DTLS_SRTP_SALT_LEN) *2]
This represents the material used to build the SRTP master key.
Definition whip.c:301
int pkt_size
The size of RTP packet, should generally be set to MTU.
Definition whip.c:328
uint16_t video_rtx_seq
Definition whip.c:246
char * key_file
Definition whip.c:337
AVCodecParameters * video_par
Definition whip.c:223
uint64_t ice_tie_breaker
Definition whip.c:258
int64_t whip_answer_time
Definition whip.c:280
SRTPContext srtp_audio_send
Definition whip.c:307
int64_t whip_srtp_time
Definition whip.c:284
char ice_ufrag_local[9]
Definition whip.c:236
SRTPContext srtp_video_send
Definition whip.c:308
char * ice_host
Definition whip.c:268
int64_t whip_udp_time
Definition whip.c:281
RtpHistoryItem * hist
Definition whip.c:340
int64_t whip_ice_time
Definition whip.c:282
uint32_t flags
Definition whip.c:217
int64_t whip_init_time
Definition whip.c:278
int h264_annexb_insert_sps_pps
The h264_mp4toannexb Bitstream Filter (BSF) bypasses the AnnexB packet; therefore,...
Definition whip.c:230
int hist_sz
Definition whip.c:339
SRTPContext srtp_video_rtx_send
Definition whip.c:309
uint8_t * hist_pool
Definition whip.c:341
uint32_t video_rtx_ssrc
Definition whip.c:241
int is_peer_ice_lite
Definition whip.c:257
URLContext * dtls_uc
Definition whip.c:304
char ice_pwd_local[33]
Definition whip.c:237
char * sdp_answer
Definition whip.c:272
AVLFG rnd
Definition whip.c:233
URLContext * udp
Definition whip.c:315
char * dtls_fingerprint
Definition whip.c:292
char * sdp_offer
This is the SDP offer generated by the muxer based on the codec parameters, DTLS, and ICE information...
Definition whip.c:255
char * whip_resource_url
Definition whip.c:274
uint16_t video_first_seq
Definition whip.c:244
int handshake_timeout
Definition whip.c:320
uint8_t audio_payload_type
Definition whip.c:248
uint8_t level
Definition svq3.c:208
#define av_freep(p)
#define av_log(a,...)
static void error(const char *err)
static char buffer[20]
Definition seek.c:32
int av_usleep(unsigned usec)
Sleep for a period of time.
Definition time.c:93
int64_t av_gettime_relative(void)
Get the current time in microseconds since some unspecified starting point.
Definition time.c:57
int ff_is_dtls_packet(const uint8_t *buf, int size)
Whether the packet is a DTLS packet, as defined by RFC 5764 Section 5.1.2.
Definition tls.c:167
int ff_ssl_gen_key_cert(char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
Definition tls_gnutls.c:299
int ff_ssl_read_key_cert(char *key_url, char *cert_url, char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
Definition tls_gnutls.c:115
#define MAX_CERTIFICATE_SIZE
Maximum size limit of a certificate and private key size.
Definition tls.h:34
int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t materials_sz)
Definition tls_gnutls.c:379
int ff_tls_set_external_socket(URLContext *h, URLContext *sock)
Definition tls_gnutls.c:366
int size
int ff_url_join(char *str, int size, const char *proto, const char *authorization, const char *hostname, int port, const char *fmt,...)
Definition url.c:40
static int ffurl_write(URLContext *h, const uint8_t *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition url.h:205
static int ffurl_read(URLContext *h, uint8_t *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf.
Definition url.h:184
static unsigned int seed
Definition videogen.c:78
static int rtp_history_store(WHIPContext *whip, const uint8_t *buf, int size)
Definition whip.c:1515
#define STUN_MAGIC_COOKIE
Definition whip.c:81
static int udp_connect(AVFormatContext *s)
To establish a connection with the UDP server, we utilize ICE-LITE in a Client-Server mode.
Definition whip.c:1268
#define WHIP_ICE_CONSENT_EXPIRED_TIMER
Definition whip.c:148
#define MAX_SDP_SIZE
Maximum size limit of a Session Description Protocol (SDP), be it an offer or answer.
Definition whip.c:52
static int ice_create_response(AVFormatContext *s, char *tid, int tid_size, uint8_t *buf, int buf_size, int *response_size)
Create an ICE binding response.
Definition whip.c:1128
#define WHIP_US_PER_MS
Definition whip.c:71
static int parse_codec(AVFormatContext *s)
Parses video SPS/PPS from the extradata of codecpar and checks the codec.
Definition whip.c:548
WHIPState
Definition whip.c:174
@ WHIP_STATE_READY
Definition whip.c:199
@ WHIP_STATE_INIT
Definition whip.c:178
@ WHIP_STATE_NEGOTIATED
After parsing the answer received from the peer, the muxer negotiates the abilities in the offer that...
Definition whip.c:187
@ WHIP_STATE_ANSWER
Definition whip.c:182
@ WHIP_STATE_ICE_CONNECTING
Definition whip.c:191
@ WHIP_STATE_ICE_CONNECTED
Definition whip.c:193
@ WHIP_STATE_DTLS_FINISHED
Definition whip.c:195
@ WHIP_STATE_OFFER
Definition whip.c:180
@ WHIP_STATE_NONE
Definition whip.c:175
@ WHIP_STATE_SRTP_FINISHED
Definition whip.c:197
@ WHIP_STATE_UDP_CONNECTED
Definition whip.c:189
@ WHIP_STATE_FAILED
Definition whip.c:201
static void handle_nack_rtx(AVFormatContext *s, int size)
Definition whip.c:1954
static const RtpHistoryItem * rtp_history_find(WHIPContext *whip, uint16_t seq)
Definition whip.c:1530
static int ice_dtls_handshake(AVFormatContext *s)
Definition whip.c:1306
#define MAX_UDP_BUFFER_SIZE
Maximum size of the buffer for sending and receiving UDP packets.
Definition whip.c:97
#define DTLS_SRTP_SALT_LEN
Definition whip.c:61
#define ICE_STUN_HEADER_SIZE
The STUN message header, which is 20 bytes long, comprises the STUNMessageType (1B),...
Definition whip.c:110
#define WHIP_RTP_PAYLOAD_TYPE_OPUS
Definition whip.c:101
#define WHIP_RTP_HEADER_SIZE
The RTP header is 12 bytes long, comprising the Version(1B), PT(1B), SequenceNumber(2B),...
Definition whip.c:117
static int exchange_sdp(AVFormatContext *s)
Exchange SDP offer with WebRTC peer to get the answer.
Definition whip.c:772
#define ELAPSED(starttime, endtime)
Definition whip.c:162
static int whip_write_packet(AVFormatContext *s, AVPacket *pkt)
Definition whip.c:2020
static int generate_sdp_offer(AVFormatContext *s)
Generate SDP offer according to the codec parameters, DTLS and ICE information.
Definition whip.c:608
static int media_is_rtp_rtcp(const uint8_t *b, int size)
In RTP packets, the first byte is represented as 0b10xxxxxx, where the initial two bits (0b10) indica...
Definition whip.c:1213
static int on_rtp_write_packet(void *opaque, const uint8_t *buf, int buf_size)
Callback triggered by the RTP muxer when it creates and sends out an RTP packet.
Definition whip.c:1544
static int whip_check_bitstream(AVFormatContext *s, AVStream *st, const AVPacket *pkt)
Definition whip.c:2168
STUNAttr
Definition whip.c:165
@ STUN_ATTR_PRIORITY
shared secret response/bind request
Definition whip.c:167
@ STUN_ATTR_MESSAGE_INTEGRITY
bind request
Definition whip.c:169
@ STUN_ATTR_ICE_CONTROLLING
rfc5389
Definition whip.c:171
@ STUN_ATTR_USE_CANDIDATE
must be included in a Binding request
Definition whip.c:168
@ STUN_ATTR_FINGERPRINT
bind request/response
Definition whip.c:170
@ STUN_ATTR_USERNAME
Definition whip.c:166
#define ICE_DTLS_READ_SLEEP_DURATION
Definition whip.c:78
static int media_is_rtcp(const uint8_t *b, int size)
Definition whip.c:1219
#define WHIP_ICE_CONSENT_CHECK_INTERVAL
Refer to RFC 7675 5.1,.
Definition whip.c:147
static int ice_create_request(AVFormatContext *s, uint8_t *buf, int buf_size, int *request_size)
Creates and marshals an ICE binding request packet.
Definition whip.c:1030
#define WHIP_SDP_CREATOR_IP
Definition whip.c:137
static av_cold int whip_init(AVFormatContext *s)
Definition whip.c:1849
static av_cold int initialize(AVFormatContext *s)
Initialize and check the options for the WebRTC muxer.
Definition whip.c:417
#define WHIP_RTP_PAYLOAD_TYPE_VIDEO_RTX
Definition whip.c:102
WHIPFlags
Definition whip.c:204
@ WHIP_DTLS_ACTIVE
Definition whip.c:205
static int ice_is_binding_request(uint8_t *b, int size)
A Binding request has class=0b00 (request) and method=0b000000000001 (Binding) and is encoded into th...
Definition whip.c:1192
#define WHIP_RTCP_PT_START
For RTCP, PT is [128, 223] (or without marker [0, 95]).
Definition whip.c:129
static int ice_is_binding_response(uint8_t *b, int size)
A Binding response has class=0b10 (success response) and method=0b000000000001, and is encoded into t...
Definition whip.c:1201
#define WHIP_SDP_SESSION_ID
In the case of ICE-LITE, these fields are not used; instead, they are defined as constant values.
Definition whip.c:136
#define WHIP_RTCP_PT_END
Definition whip.c:130
#define STUN_HOST_CANDIDATE_PRIORITY
Refer to RFC 8445 5.1.2 priority = (2^24)*(type preference) + (2^8)*(local preference) + (2^0)*(256 -...
Definition whip.c:88
static int dispose_session(AVFormatContext *s)
RTC is connectionless, for it's based on UDP, so it check whether sesison is timeout.
Definition whip.c:1714
static av_cold int certificate_key_init(AVFormatContext *s)
Get or Generate a self-signed certificate and private key for DTLS, fingerprint for SDP.
Definition whip.c:349
#define WHIP_RTP_HISTORY_MIN
RTP history packet size.
Definition whip.c:157
#define ICE_DTLS_READ_MAX_RETRY
If we try to read from UDP and get EAGAIN, we sleep for 5ms and retry up to 10 times.
Definition whip.c:77
#define WHIP_RTP_PAYLOAD_TYPE_H264
Definition whip.c:100
#define DTLS_SRTP_KEY_LEN
The size of the Secure Real-time Transport Protocol (SRTP) master key material that is exported by Se...
Definition whip.c:60
static av_cold int dtls_initialize(AVFormatContext *s)
Definition whip.c:377
#define WHIP_RTP_HISTORY_DEFAULT
Definition whip.c:158
static int setup_srtp(AVFormatContext *s)
Establish the SRTP context using the keying material exported from DTLS.
Definition whip.c:1425
static int parse_answer(AVFormatContext *s)
Parses the ICE ufrag, pwd, and candidates from the SDP answer.
Definition whip.c:900
static av_cold void whip_deinit(AVFormatContext *s)
Definition whip.c:2119
#define WHIP_RTP_HISTORY_MAX
Definition whip.c:159
static int ice_handle_binding_request(AVFormatContext *s, char *buf, int buf_size)
This function handles incoming binding request messages by responding to them.
Definition whip.c:1228
#define OFFSET(x)
Definition whip.c:2187
static int h264_annexb_insert_sps_pps(AVFormatContext *s, AVPacket *pkt)
Since the h264_mp4toannexb filter only processes the MP4 ISOM format and bypasses the annexb format,...
Definition whip.c:1774
static void handle_rtx_packet(AVFormatContext *s, uint16_t seq)
See https://datatracker.ietf.org/doc/html/rfc4588#section-4 Create RTX packet and send it out.
Definition whip.c:1891
static int parse_profile_level(AVFormatContext *s, AVCodecParameters *par)
When duplicating a stream, the demuxer has already set the extradata, profile, and level of the par.
Definition whip.c:481
static const AVClass whip_muxer_class
Definition whip.c:2203
static int create_rtp_muxer(AVFormatContext *s)
Creates dedicated RTP muxers for each stream in the AVFormatContext to build RTP packets from the enc...
Definition whip.c:1599
#define DTLS_SRTP_CHECKSUM_LEN
The maximum size of the Secure Real-time Transport Protocol (SRTP) HMAC checksum and padding that is ...
Definition whip.c:69