PR #22533 opened by qwerzoid
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22533
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22533.patch

When ffmpeg WHIP client sends sdp offer, it always takes the passive dtls role 
by default.
However, webrtc specs suggest that an initial offer should specify "actpass" 
when generating
sdp offer (RFC 8842 sec 5.2 and RFC  8829 sec 5.2.1).

This patch
[1] sets dtls role to “actpass” by default when generating sdp offer.
[2] The commit also adds a configurable option for the user to specify 
“dtls_passive” role

Signed-off-by: Aditya Banavi <[email protected]>


From 15c62a2aac0fa8186cb3137056effb6db8215dc1 Mon Sep 17 00:00:00 2001
From: Aditya Banavi <[email protected]>
Date: Tue, 17 Mar 2026 18:10:20 +0000
Subject: [PATCH] avformat/whip: set default dtls role to actpass in offer
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When ffmpeg WHIP client sends sdp offer, it always takes the passive dtls role 
by default.
However, webrtc specs suggest that an initial offer should specify "actpass" 
when generating
sdp offer (RFC 8842 sec 5.2 and RFC  8829 sec 5.2.1).

This patch
[1] sets dtls role to “actpass” by default when generating sdp offer.
[2] The commit also adds a configurable option for the user to specify 
“dtls_passive” role

Signed-off-by: Aditya Banavi <[email protected]>
---
 libavformat/tls_gnutls.c | 12 ++++++++++++
 libavformat/whip.c       | 38 +++++++++++++++++++++++++++-----------
 2 files changed, 39 insertions(+), 11 deletions(-)

diff --git a/libavformat/tls_gnutls.c b/libavformat/tls_gnutls.c
index e294aef0c0..a38f7eaa19 100644
--- a/libavformat/tls_gnutls.c
+++ b/libavformat/tls_gnutls.c
@@ -31,6 +31,7 @@
 #include "url.h"
 #include "tls.h"
 #include "libavutil/intreadwrite.h"
+#include "libavutil/mem.h"
 #include "libavutil/opt.h"
 #include "libavutil/thread.h"
 #include "libavutil/random_seed.h"
@@ -538,6 +539,17 @@ static int tls_open(URLContext *h, const char *uri, int 
flags, AVDictionary **op
     if (!s->external_sock) {
         if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0)
             goto fail;
+    } else if (!s->host) {
+        char hostname[256];
+        struct addrinfo hints = { .ai_flags = AI_NUMERICHOST }, *ai;
+        av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), NULL, NULL, 
0, uri);
+        if (hostname[0]) {
+            s->host = av_strdup(hostname);
+            if (!getaddrinfo(hostname, NULL, &hints, &ai)) {
+                s->numerichost = 1;
+                freeaddrinfo(ai);
+            }
+        }
     }
 
     if (s->is_dtls)
diff --git a/libavformat/whip.c b/libavformat/whip.c
index 0d39247a03..f176c925a0 100644
--- a/libavformat/whip.c
+++ b/libavformat/whip.c
@@ -225,6 +225,7 @@ enum WHIPState {
 
 typedef enum WHIPFlags {
     WHIP_DTLS_ACTIVE = (1 << 0),
+    WHIP_DTLS_PASSIVE = (1 << 1),
 } WHIPFlags;
 
 typedef struct RtpHistoryItem {
@@ -310,6 +311,8 @@ typedef struct WHIPContext {
     /* The certificate and private key content used for DTLS handshake */
     char cert_buf[MAX_CERTIFICATE_SIZE];
     char key_buf[MAX_CERTIFICATE_SIZE];
+
+    int is_dtls_active;
     /* The fingerprint of certificate, used in SDP offer. */
     char *dtls_fingerprint;
     /**
@@ -413,7 +416,6 @@ static av_cold int dtls_initialize(AVFormatContext *s)
 {
     int ret = 0;
     WHIPContext *whip = s->priv_data;
-    int is_dtls_active = whip->flags & WHIP_DTLS_ACTIVE;
     AVDictionary *opts = NULL;
     char buf[256];
 
@@ -430,7 +432,7 @@ static av_cold int dtls_initialize(AVFormatContext *s)
         av_dict_set(&opts, "key_pem", whip->key_buf, 0);
     av_dict_set_int(&opts, "external_sock", 1, 0);
     av_dict_set_int(&opts, "use_srtp", 1, 0);
-    av_dict_set_int(&opts, "listen", is_dtls_active ? 0 : 1, 0);
+    av_dict_set_int(&opts, "listen", whip->is_dtls_active ? 0 : 1, 0);
     ret = ffurl_open_whitelist(&whip->dtls_uc, buf, AVIO_FLAG_READ_WRITE, 
&s->interrupt_callback,
         &opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
     av_dict_free(&opts);
@@ -646,7 +648,13 @@ static int generate_sdp_offer(AVFormatContext *s)
     int bundle_index = 0;
     AVBPrint bp;
     WHIPContext *whip = s->priv_data;
-    int is_dtls_active = whip->flags & WHIP_DTLS_ACTIVE;
+    const char *dtls_role = "actpass";
+
+    if (whip->flags & WHIP_DTLS_ACTIVE) {
+        dtls_role = "active";
+    } else if (whip->flags & WHIP_DTLS_PASSIVE) {
+        dtls_role = "passive";
+    }
 
     /* To prevent a crash during cleanup, always initialize it. */
     av_bprint_init(&bp, 1, MAX_SDP_SIZE);
@@ -715,7 +723,7 @@ static int generate_sdp_offer(AVFormatContext *s)
             whip->ice_ufrag_local,
             whip->ice_pwd_local,
             whip->dtls_fingerprint,
-            is_dtls_active ? "active" : "passive",
+            dtls_role,
             whip->audio_payload_type,
             acodec_name,
             whip->audio_par->sample_rate,
@@ -758,7 +766,7 @@ static int generate_sdp_offer(AVFormatContext *s)
             whip->ice_ufrag_local,
             whip->ice_pwd_local,
             whip->dtls_fingerprint,
-            is_dtls_active ? "active" : "passive",
+            dtls_role,
             whip->video_payload_type,
             vcodec_name,
             whip->video_payload_type,
@@ -986,6 +994,15 @@ static int parse_answer(AVFormatContext *s)
                     goto end;
                 }
             }
+            } else if (av_strstart(line, "a=setup:", &ptr)) {
+                if (ptr && av_strcasecmp(ptr, "passive") && av_strcasecmp(ptr, 
"active")) {
+                    av_log(whip, AV_LOG_ERROR, "DTLS setup attribute %s is not 
supported by RTC, choose passive, or active, line %d %s of %s\n",
+                        ptr, i, line, whip->sdp_answer);
+                    ret = AVERROR(EIO);
+                    goto end;
+                }
+                if (!av_strcasecmp(ptr, "passive"))
+                    whip->is_dtls_active = 1;
         }
     }
 
@@ -1313,7 +1330,6 @@ static int ice_dtls_handshake(AVFormatContext *s)
     int ret = 0, size, i;
     int64_t starttime = av_gettime_relative(), now;
     WHIPContext *whip = s->priv_data;
-    int is_dtls_active = whip->flags & WHIP_DTLS_ACTIVE;
 
     if (whip->state < WHIP_STATE_UDP_CONNECTED || !whip->udp) {
         av_log(whip, AV_LOG_ERROR, "UDP not connected, state=%d, udp=%p\n", 
whip->state, whip->udp);
@@ -1363,7 +1379,7 @@ next_packet:
                 av_usleep(ICE_DTLS_READ_SLEEP_DURATION * WHIP_US_PER_MS);
                 continue;
             }
-            if (is_dtls_active)
+            if (whip->is_dtls_active)
                 break;
             av_log(whip, AV_LOG_ERROR, "Failed to read message\n");
             goto end;
@@ -1386,7 +1402,7 @@ next_packet:
         }
 
         /* Handle DTLS handshake */
-        if (is_dtls_packet(whip->buf, ret) || is_dtls_active) {
+        if (is_dtls_packet(whip->buf, ret) || whip->is_dtls_active) {
             whip->whip_ice_time = av_gettime_relative();
             /* Start consent timer when ICE selected */
             whip->whip_last_consent_tx_time = whip->whip_last_consent_rx_time 
= whip->whip_ice_time;
@@ -1439,9 +1455,8 @@ static int setup_srtp(AVFormatContext *s)
      */
     const char* suite = "SRTP_AES128_CM_HMAC_SHA1_80";
     WHIPContext *whip = s->priv_data;
-    int is_dtls_active = whip->flags & WHIP_DTLS_ACTIVE;
-    char *cp = is_dtls_active ? send_key : recv_key;
-    char *sp = is_dtls_active ? recv_key : send_key;
+    char *cp = whip->is_dtls_active ? send_key : recv_key;
+    char *sp = whip->is_dtls_active ? recv_key : send_key;
 
     ret = ff_dtls_export_materials(whip->dtls_uc, whip->dtls_srtp_materials, 
sizeof(whip->dtls_srtp_materials));
     if (ret < 0)
@@ -2191,6 +2206,7 @@ static const AVOption options[] = {
     { "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 },
     { "whip_flags",         "Set flags affecting WHIP connection behavior",    
         OFFSET(flags),              AV_OPT_TYPE_FLAGS,  { .i64 = 0},         
0, UINT_MAX, ENC, .unit = "flags" },
     { "dtls_active",        "Set dtls role as active",                         
         0,                          AV_OPT_TYPE_CONST,  { .i64 = 
WHIP_DTLS_ACTIVE}, 0, UINT_MAX, ENC, .unit = "flags" },
+    { "dtls_passive",       "Set dtls role as passive",                        
         0,                          AV_OPT_TYPE_CONST,  { .i64 = 
WHIP_DTLS_PASSIVE}, 0, UINT_MAX, ENC, .unit = "flags" },
     { "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 },
     { "authorization",      "The optional Bearer token for WHIP 
Authorization",         OFFSET(authorization),      AV_OPT_TYPE_STRING, { .str 
= NULL },     0,       0, ENC },
     { "cert_file",          "The optional certificate file path for DTLS",     
         OFFSET(cert_file),          AV_OPT_TYPE_STRING, { .str = NULL },     
0,       0, ENC },
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to