From 94304ec74e4778c1a87ae06ec153536b1a0ddb04 Mon Sep 17 00:00:00 2001 From: filipi87 Date: Thu, 23 Apr 2026 12:18:33 -0300 Subject: [PATCH 1/3] Fixed SmallWebRTC data channel silently stalling on networks with a 1280-byte MTU. --- env.example | 24 ++++++++++++++- .../transports/smallwebrtc/connection.py | 30 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/env.example b/env.example index c59a94f8c..801638919 100644 --- a/env.example +++ b/env.example @@ -214,4 +214,26 @@ WHATSAPP_PHONE_NUMBER_ID=... WHATSAPP_APP_SECRET=... # xAI / Grok -XAI_API_KEY=... \ No newline at end of file +XAI_API_KEY=... + +# SmallWebRTC / aiortc +# +# PIPECAT_SCTP_MAX_CHUNK_SIZE controls the maximum SCTP DATA-chunk payload +# size (bytes) used by aiortc's data channel. The default is 1100. +# +# When to change this: +# Lower it if the data channel silently stalls on your network. This happens +# when aiortc's default (1200) produces UDP datagrams larger than your path +# MTU: each chunk adds ~105 bytes of SCTP + DTLS + UDP + IP headers, so +# 1200 → ~1305-byte datagrams, which exceeds the 1280-byte MTU common on +# IPv6 paths, Tailscale overlays, and many consumer VPNs. The kernel drops +# the packet with EMSGSIZE; aiortc retransmits at the same size and the +# channel stalls indefinitely. A value of 1100 (~1205-byte datagrams) fits +# any path with MTU ≥ 1210. +# Raise it only if you are on a controlled LAN (MTU 1500) and are sending +# large data-channel messages where extra fragmentation matters. Values +# above 1200 are unsafe on most internet paths. +# +# Note: this is a process-global setting (aiortc limitation) — all +# SmallWebRTC connections in the same process share the same value. +#PIPECAT_SCTP_MAX_CHUNK_SIZE=1100 \ No newline at end of file diff --git a/src/pipecat/transports/smallwebrtc/connection.py b/src/pipecat/transports/smallwebrtc/connection.py index efb9a6923..d557b1a35 100644 --- a/src/pipecat/transports/smallwebrtc/connection.py +++ b/src/pipecat/transports/smallwebrtc/connection.py @@ -13,6 +13,7 @@ for real-time communication applications. import asyncio import json +import os import time import uuid from typing import Any, Literal @@ -23,6 +24,7 @@ from pydantic import BaseModel, TypeAdapter from pipecat.utils.base_object import BaseObject try: + import aiortc.rtcsctptransport as _sctp_transport from aiortc import ( RTCConfiguration, RTCIceServer, @@ -36,6 +38,34 @@ except ModuleNotFoundError as e: logger.error("In order to use the SmallWebRTC, you need to `pip install pipecat-ai[webrtc]`.") raise Exception(f"Missing module: {e}") +# Clamp aiortc's SCTP DATA-chunk payload size so the on-wire UDP packet fits +# inside the smallest-MTU path we're likely to see (IPv6 minimum 1280, +# Tailscale overlays default to 1280, some consumer VPNs are lower). +# +# aiortc hardcodes USERDATA_MAX_LENGTH = 1200. After adding SCTP (28) + +# DTLS/GCM (~29) + UDP (8) + IPv6 (40) headers that produces a ~1305-byte +# UDP datagram — over the 1280 MTU. The kernel rejects it with EMSGSIZE, +# SCTP retransmits at the same size, and the data channel silently stalls. +# aiortc has no PMTU discovery (RFC 8831 §6), so there is no auto-recovery. +# +# 1100 brings the worst-case datagram to ~1205 bytes (~75 bytes of slack). +# Throughput cost is negligible: RTVI control frames fragment across one +# extra chunk at most, and audio uses RTP (a separate path). +# +# There is no public API to set this — RTCConfiguration exposes no MTU knob +# and all method references are bare module-global lookups, so patching the +# module attribute before any RTCSctpTransport is instantiated is the only +# option short of forking aiortc. +# +# Remove once aiortc ships DPLPMTUD (RFC 8899) or exposes this as a +# configurable parameter. +_SCTP_MAX_CHUNK_SIZE_DEFAULT = 1100 +_sctp_max_chunk_size = int( + os.environ.get("PIPECAT_SCTP_MAX_CHUNK_SIZE", _SCTP_MAX_CHUNK_SIZE_DEFAULT) +) +_sctp_transport.USERDATA_MAX_LENGTH = _sctp_max_chunk_size +logger.debug(f"[SCTP] USERDATA_MAX_LENGTH set to {_sctp_max_chunk_size}") + SIGNALLING_TYPE = "signalling" AUDIO_TRANSCEIVER_INDEX = 0 VIDEO_TRANSCEIVER_INDEX = 1 From 44756de15a33c09c157478396af4294f32002a89 Mon Sep 17 00:00:00 2001 From: filipi87 Date: Thu, 23 Apr 2026 12:19:56 -0300 Subject: [PATCH 2/3] Adding changelog for the SmallWebRTC fix. --- changelog/4358.fixed.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/4358.fixed.md diff --git a/changelog/4358.fixed.md b/changelog/4358.fixed.md new file mode 100644 index 000000000..719111d8e --- /dev/null +++ b/changelog/4358.fixed.md @@ -0,0 +1 @@ +- Fixed SmallWebRTC data channel silently stalling on networks with a 1280-byte MTU (IPv6, Tailscale overlays, many consumer VPNs). aiortc's default SCTP chunk size of 1200 bytes produces ~1305-byte UDP datagrams after headers, which the kernel rejects with EMSGSIZE; aiortc has no path-MTU discovery so it retransmits forever at the same oversized size. The chunk size is now clamped to 1100 bytes (~1205-byte datagrams, ~75 bytes of slack). Override with `PIPECAT_SCTP_MAX_CHUNK_SIZE` if your path MTU requires a different value. From ce1506792effc66fc4004d8163392da01c84568d Mon Sep 17 00:00:00 2001 From: filipi87 Date: Thu, 23 Apr 2026 17:46:54 -0300 Subject: [PATCH 3/3] Linking to the docs instead of full explanation. --- env.example | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/env.example b/env.example index 801638919..8fd258331 100644 --- a/env.example +++ b/env.example @@ -216,24 +216,8 @@ WHATSAPP_APP_SECRET=... # xAI / Grok XAI_API_KEY=... -# SmallWebRTC / aiortc -# # PIPECAT_SCTP_MAX_CHUNK_SIZE controls the maximum SCTP DATA-chunk payload # size (bytes) used by aiortc's data channel. The default is 1100. -# -# When to change this: -# Lower it if the data channel silently stalls on your network. This happens -# when aiortc's default (1200) produces UDP datagrams larger than your path -# MTU: each chunk adds ~105 bytes of SCTP + DTLS + UDP + IP headers, so -# 1200 → ~1305-byte datagrams, which exceeds the 1280-byte MTU common on -# IPv6 paths, Tailscale overlays, and many consumer VPNs. The kernel drops -# the packet with EMSGSIZE; aiortc retransmits at the same size and the -# channel stalls indefinitely. A value of 1100 (~1205-byte datagrams) fits -# any path with MTU ≥ 1210. -# Raise it only if you are on a controlled LAN (MTU 1500) and are sending -# large data-channel messages where extra fragmentation matters. Values -# above 1200 are unsafe on most internet paths. -# -# Note: this is a process-global setting (aiortc limitation) — all -# SmallWebRTC connections in the same process share the same value. +# All the details here: +# https://docs.pipecat.ai/api-reference/server/services/transport/small-webrtc#pipecat_sctp_max_chunk_size #PIPECAT_SCTP_MAX_CHUNK_SIZE=1100 \ No newline at end of file