42
42
#include "network.h"
43
43
#include "srtp.h"
44
44
#include "tls.h"
45
-
46
45
/**
47
46
* Maximum size limit of a Session Description Protocol (SDP),
48
47
* be it an offer or answer.
143
142
#define WHIP_RTCP_PT_START 192
144
143
#define WHIP_RTCP_PT_END 223
145
144
145
+ /**
146
+ * Consent-freshness constants
147
+ */
148
+ #define WHIP_CONSENT_DEF_INTERVAL 15000 /* ms – RFC 7675 default */
149
+ #define WHIP_CONSENT_MAX_FAILURES 3
150
+
146
151
/**
147
152
* In the case of ICE-LITE, these fields are not used; instead, they are defined
148
153
* as constant values.
@@ -303,6 +308,11 @@ typedef struct WHIPContext {
303
308
/* The certificate and private key used for DTLS handshake. */
304
309
char * cert_file ;
305
310
char * key_file ;
311
+
312
+ /* Consent-freshness state */
313
+ int consent_interval ;
314
+ int64_t last_consent_tx ;
315
+ int consent_failures ;
306
316
} WHIPContext ;
307
317
308
318
/**
@@ -412,6 +422,12 @@ static av_cold int initialize(AVFormatContext *s)
412
422
seed = av_get_random_seed ();
413
423
av_lfg_init (& whip -> rnd , seed );
414
424
425
+ /* Initialise consent-freshness timers */
426
+ if (whip -> consent_interval <= 0 )
427
+ whip -> consent_interval = WHIP_CONSENT_DEF_INTERVAL ;
428
+ whip -> last_consent_tx = av_gettime ();
429
+ whip -> consent_failures = 0 ;
430
+
415
431
if (whip -> pkt_size < ideal_pkt_size )
416
432
av_log (whip , AV_LOG_WARNING , "WHIP: pkt_size=%d(<%d) is too small, may cause packet loss\n" ,
417
433
whip -> pkt_size , ideal_pkt_size );
@@ -985,6 +1001,7 @@ static int ice_create_request(AVFormatContext *s, uint8_t *buf, int buf_size, in
985
1001
avio_wb16 (pb , STUN_ATTR_USE_CANDIDATE ); /* attribute type use-candidate */
986
1002
avio_wb16 (pb , 0 ); /* size of use-candidate */
987
1003
1004
+
988
1005
/* Build and update message integrity */
989
1006
avio_wb16 (pb , STUN_ATTR_MESSAGE_INTEGRITY ); /* attribute type message integrity */
990
1007
avio_wb16 (pb , 20 ); /* size of message integrity */
@@ -1775,14 +1792,27 @@ static int whip_write_packet(AVFormatContext *s, AVPacket *pkt)
1775
1792
AVStream * st = s -> streams [pkt -> stream_index ];
1776
1793
AVFormatContext * rtp_ctx = st -> priv_data ;
1777
1794
1778
- /* TODO: Send binding request every 1s as WebRTC heartbeat. */
1795
+ /* Periodic consent-freshness STUN Binding Request */
1796
+ int64_t now = av_gettime ();
1797
+ if (now - whip -> last_consent_tx >= (int64_t )whip -> consent_interval * 1000 ) {
1798
+ int req_sz ;
1799
+ if (ice_create_request (s , whip -> buf , sizeof (whip -> buf ), & req_sz ) >= 0 && ffurl_write (whip -> udp , whip -> buf , req_sz ) == req_sz ) {
1800
+ whip -> consent_failures ++ ;
1801
+ whip -> last_consent_tx = now ;
1802
+ av_log (whip , AV_LOG_VERBOSE , "WHIP: consent-freshness request %d sent\n" , whip -> consent_failures );
1803
+ }
1804
+ }
1779
1805
1780
1806
/**
1781
1807
* Receive packets from the server such as ICE binding requests, DTLS messages,
1782
1808
* and RTCP like PLI requests, then respond to them.
1783
1809
*/
1784
1810
ret = ffurl_read (whip -> udp , whip -> buf , sizeof (whip -> buf ));
1785
1811
if (ret > 0 ) {
1812
+ if (ice_is_binding_response (whip -> buf , ret )) {
1813
+ whip -> consent_failures = 0 ;
1814
+ av_log (whip , AV_LOG_VERBOSE , "WHIP: consent-freshness response received, counter reset\n" );
1815
+ }
1786
1816
if (is_dtls_packet (whip -> buf , ret )) {
1787
1817
if ((ret = ffurl_write (whip -> dtls_uc , whip -> buf , ret )) < 0 ) {
1788
1818
av_log (whip , AV_LOG_ERROR , "WHIP: Failed to handle DTLS message\n" );
@@ -1793,6 +1823,12 @@ static int whip_write_packet(AVFormatContext *s, AVPacket *pkt)
1793
1823
av_log (whip , AV_LOG_ERROR , "WHIP: Failed to read from UDP socket\n" );
1794
1824
goto end ;
1795
1825
}
1826
+ /* Check consent freshness consecutive failures */
1827
+ if (whip -> consent_failures >= WHIP_CONSENT_MAX_FAILURES ) {
1828
+ av_log (whip , AV_LOG_ERROR , "WHIP: No consent-freshness response after %d attempts, closing\n" , WHIP_CONSENT_MAX_FAILURES );
1829
+ ret = AVERROR (EHOSTUNREACH );
1830
+ goto end ;
1831
+ }
1796
1832
1797
1833
if (whip -> h264_annexb_insert_sps_pps && st -> codecpar -> codec_id == AV_CODEC_ID_H264 ) {
1798
1834
if ((ret = h264_annexb_insert_sps_pps (s , pkt )) < 0 ) {
@@ -1891,7 +1927,8 @@ static const AVOption options[] = {
1891
1927
{ "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 , DEC },
1892
1928
{ "authorization" , "The optional Bearer token for WHIP Authorization" , OFFSET (authorization ), AV_OPT_TYPE_STRING , { .str = NULL }, 0 , 0 , DEC },
1893
1929
{ "cert_file" , "The optional certificate file path for DTLS" , OFFSET (cert_file ), AV_OPT_TYPE_STRING , { .str = NULL }, 0 , 0 , DEC },
1894
- { "key_file" , "The optional private key file path for DTLS" , OFFSET (key_file ), AV_OPT_TYPE_STRING , { .str = NULL }, 0 , 0 , DEC },
1930
+ { "key_file" , "The optional private key file path for DTLS" , OFFSET (key_file ), AV_OPT_TYPE_STRING , { .str = NULL }, 0 , 0 , DEC },
1931
+ { "consent_interval" , "STUN consent refresh interval in ms (RFC 7675)" , OFFSET (consent_interval ), AV_OPT_TYPE_INT , { .i64 = WHIP_CONSENT_DEF_INTERVAL }, 5000 , 30000 , DEC },
1895
1932
{ NULL },
1896
1933
};
1897
1934
0 commit comments