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]
