4242#include "network.h"
4343#include "srtp.h"
4444#include "tls.h"
45-
4645/**
4746 * Maximum size limit of a Session Description Protocol (SDP),
4847 * be it an offer or answer.
143142#define WHIP_RTCP_PT_START 192
144143#define WHIP_RTCP_PT_END 223
145144
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+
146151/**
147152 * In the case of ICE-LITE, these fields are not used; instead, they are defined
148153 * as constant values.
@@ -303,6 +308,11 @@ typedef struct WHIPContext {
303308 /* The certificate and private key used for DTLS handshake. */
304309 char * cert_file ;
305310 char * key_file ;
311+
312+ /* Consent-freshness state */
313+ int consent_interval ;
314+ int64_t last_consent_tx ;
315+ int consent_failures ;
306316} WHIPContext ;
307317
308318/**
@@ -412,6 +422,12 @@ static av_cold int initialize(AVFormatContext *s)
412422 seed = av_get_random_seed ();
413423 av_lfg_init (& whip -> rnd , seed );
414424
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+
415431 if (whip -> pkt_size < ideal_pkt_size )
416432 av_log (whip , AV_LOG_WARNING , "WHIP: pkt_size=%d(<%d) is too small, may cause packet loss\n" ,
417433 whip -> pkt_size , ideal_pkt_size );
@@ -985,6 +1001,7 @@ static int ice_create_request(AVFormatContext *s, uint8_t *buf, int buf_size, in
9851001 avio_wb16 (pb , STUN_ATTR_USE_CANDIDATE ); /* attribute type use-candidate */
9861002 avio_wb16 (pb , 0 ); /* size of use-candidate */
9871003
1004+
9881005 /* Build and update message integrity */
9891006 avio_wb16 (pb , STUN_ATTR_MESSAGE_INTEGRITY ); /* attribute type message integrity */
9901007 avio_wb16 (pb , 20 ); /* size of message integrity */
@@ -1775,14 +1792,27 @@ static int whip_write_packet(AVFormatContext *s, AVPacket *pkt)
17751792 AVStream * st = s -> streams [pkt -> stream_index ];
17761793 AVFormatContext * rtp_ctx = st -> priv_data ;
17771794
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+ }
17791805
17801806 /**
17811807 * Receive packets from the server such as ICE binding requests, DTLS messages,
17821808 * and RTCP like PLI requests, then respond to them.
17831809 */
17841810 ret = ffurl_read (whip -> udp , whip -> buf , sizeof (whip -> buf ));
17851811 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+ }
17861816 if (is_dtls_packet (whip -> buf , ret )) {
17871817 if ((ret = ffurl_write (whip -> dtls_uc , whip -> buf , ret )) < 0 ) {
17881818 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)
17931823 av_log (whip , AV_LOG_ERROR , "WHIP: Failed to read from UDP socket\n" );
17941824 goto end ;
17951825 }
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+ }
17961832
17971833 if (whip -> h264_annexb_insert_sps_pps && st -> codecpar -> codec_id == AV_CODEC_ID_H264 ) {
17981834 if ((ret = h264_annexb_insert_sps_pps (s , pkt )) < 0 ) {
@@ -1891,7 +1927,8 @@ static const AVOption options[] = {
18911927 { "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 },
18921928 { "authorization" , "The optional Bearer token for WHIP Authorization" , OFFSET (authorization ), AV_OPT_TYPE_STRING , { .str = NULL }, 0 , 0 , DEC },
18931929 { "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 },
18951932 { NULL },
18961933};
18971934
0 commit comments