We are pleased to announce our final and largest release of 2025. This release includes contributions from 69 contributors.
This release also marks a new era for Pion. Going forward, we will publish releases on a regular schedule.
Major new features
RACK
- We are happy to announce that SCTP now includes a RACK implementation, enabled by default. This work is included in pion/sctp#390 and pion/sctp#438, with a reported 71% improvement in maximum throughput and 27% better latency.
ICE Renomination
- Pion now supports ICE renomination It was added in pion/ice#822 and pion/ice#799, and integrated into WebRTC in #3306. It can be enabled via the SettingEngine.
// For advanced use with a custom generator and interval.
se := webrtc.SettingEngine{}
interval := 2 * time.Second
customGen := func() uint32 { return uint32(time.Now().UnixNano()) } // example
if err := se.SetICERenomination(
webrtc.WithRenominationGenerator(customGen),
webrtc.WithRenominationInterval(interval),
); err != nil {
log.Println(err)
}Cryptex
- Pion now supports Cryptex, enabling full encryption of RTP headers and header extensions. This work is included in pion/srtp#324 and pion/sdp#213.
FlexFEC
- FlexFEC has been added, is stable, and is ready for production use. See pion/interceptor#333, #3075, pion/interceptor#330, pion/interceptor#344, and pion/interceptor#383.
ICEAddressRewriteRule
- Pion’s NAT 1:1 API is now deprecated. After years of use, it no longer fits modern deployment models. This change is implemented in pion/ice#834 and #3309.
The new API, SetICEAddressRewriteRules(rules ...ICEAddressRewriteRule) error, rewrites the IP addresses embedded in gathered ICE candidates.
Rule fields (high level):
- External []string: the address or addresses you want to expose
- Matchers: Local, CIDR, or Iface
- Mode: Replace (default) or Append (keep the original and add the rewritten candidate)
- Optional: AsCandidateType (for example, rewrite as srflx)
se := webrtc.SettingEngine{}
_ = se.SetICEAddressRewriteRules(
webrtc.ICEAddressRewriteRule{
Local: "10.0.0.12",
External: []string{"203.0.113.10"},
// Mode omitted, defaults to Replace.
},
)
api := webrtc.NewAPI(webrtc.WithSettingEngine(se))
// pc, _ := api.NewPeerConnection(...)// For more advanced use.
se := webrtc.SettingEngine{}
se.SetICEAddressRewriteRules(
// Allow eth0 (map RFC1918 to public 203.0.113.10)
webrtc.ICEAddressRewriteRule{
Iface: "eth0",
CIDR: "10.0.0.0/8",
External: []string{"203.0.113.10"},
Mode: webrtc.ICEAddressRewriteReplace,
},
// Allow eth1 (map 192.168/16 to public 198.51.100.20)
webrtc.ICEAddressRewriteRule{
Iface: "eth1",
CIDR: "192.168.0.0/16",
External: []string{"198.51.100.20"},
Mode: webrtc.ICEAddressRewriteReplace,
},
// Catch-all: drop any other IPv4 host candidates
webrtc.ICEAddressRewriteRule{
CIDR: "0.0.0.0/0",
Mode: webrtc.ICEAddressRewriteReplace,
External: nil, // drop
},
// Catch-all: drop any other IPv6 host candidates
webrtc.ICEAddressRewriteRule{
CIDR: "::/0",
Mode: webrtc.ICEAddressRewriteReplace,
External: nil, // drop
},
)SVT-AV1
- Adds a new AV1 video encoder to pion/mediadevices backed by SVT-AV1: pion/mediadevices#660.
HEVC reader and writer
-
pkg/media/h265readerparses an H.265/HEVC Annex-B byte stream (start-code delimited) into NAL units you can work with.pkg/media/h265writertakes H.265 RTP payloads (RFC 7798) and writes them back out as an Annex-B bytestream, which is useful for recording and archiving.
New OGG Reader API
-
A series of improvements to oggreader:
- #3301 adds OpusTags support via
ParseOpusTags, enabling access to artist, title, and vendor comments. - #3299 expands
ParseOpusHeadto parse Opus channel mappings for multichannel layouts. - #3300 updates oggreader to handle multi-track Ogg by routing pages by serial and introducing
NewWithOptionsalong with richer page and header APIs. - #3302 validates the full flow by streaming single-track and multi-track Ogg with a playlist and metadata over DataChannel control, while audio remains on the RTP track.
- #3301 adds OpusTags support via
More great features
- Do not discard SEI NALs for H264/H265 — #3313
- Use ping-pong buffer for batch conn — pion/transport#363
- Add CanTrickleICECandidates — #3283
- Add nohost gather policy — #3305
- Make Allocation/Permission lifetime configurable — pion/turn#495
- RFC: Add a configurable sized nonce generator — pion/turn#460
- Add AudioPlayoutStatsProvider interface for getting media-playout stats — #3234
- Expose stats ID for use in interceptor factories — #3249
- Allow IVFWriter Width/Height to be modified — #3219
- Allow IVFWriter Framerate to be modified — #3220
New Examples
- Add ice-proxy example (2) — #3165
- Add Play from disk ogg playlist example — #3302
- Add examples/encrypt-decrypt — pion/srtp#353
- Add simple datachannel example with demo.html — #3252
- Add real-time encoder integration example — pion/bwe-test#99
- Add gocv-to-webrtc — pion/example-webrtc-applications#370
- Create examples/data-channels-detach-create — #3225
Major bug fixes
- Fix a deadlock in TaskLoop — pion/ice#840
- Fix a deadlock with Abort — pion/sctp#441
- Fix nack deadlocks from writers — pion/interceptor#387
- Fix race condition in setSelectedPair — pion/ice#826
- Fix memory leak with nackCountLogs — pion/interceptor#386
- Fix a leak with pop in pending_queue — pion/sctp#401
- Fix PacketsReceived underflow — pion/interceptor#389
- Fix RTP timestamp drift in WriteSample — #3312
- Prevent negative intervals — pion/dtls#760
- Do not block on SCTP accept if the transport is aborted — #3308
- Fix infinite loop when current time equals deadline — pion/transport#359
- Fix zero-delta case in overuse detector — pion/interceptor#369
- Fix off-by-one in TwoByteHeaderExtension.Set — pion/rtp#335
- Fix off-by-one in OneByteHeaderExtension.Set — pion/rtp#334
- Fix unmarshalling extension-only packet — pion/rtp#325
- Fix padding overflow with PacketFactory — pion/interceptor#338
- Fix RTPSender.SetReadDeadline crash — #3224
- fix track.unbind panic — pion/mediadevices#634
- Do not invoke OnBufferedAmountLow after close — #3291
- Emit a disconnected state before failing — pion/ice#846
- Fix error reporting in SendIndication handler — pion/turn#466
- Fix sender/receiver reports in whip-whep example — #3167
- Permissively parse SDPs unless completely invalid — #3297
- Warn on non-zero reliability parameter for reliable channels — pion/datachannel#263
- Assert DONT-FRAGMENT behavior in Server (1) — pion/turn#494
- Assert DONT-FRAGMENT behavior in Server (2) — pion/turn#493
- Add Unknown Attribute Handler — pion/turn#486
Performance improvement
- Optimize slice allocation in UDPMuxDefault — pion/ice#788
- Add MarshalTo for zero-allocation extension marshalling — pion/rtp#344
- Preallocate slice capacity in Registry.Build() — pion/interceptor#353
- use atomic instead of lock in sequencer — pion/rtp#343
- Use atomic.Uint64 for thread-safe byte counters — pion/ice#785
- Change activeTCPConn.close to atomic.Bool — pion/ice#782
- Prefer makezero with a cap — #3230
- Fixes to use the same buffer as input and output (srtp) — pion/srtp#320
- We never allocate more than 32 bytes AES/CTR — pion/srtp#327
@3DRX @5ur3 @aalekseevx @aankur @adeithe @alexhu-oai @amanakin @andjcoll @AnshulMalik @arindamnayak @arjunshajitech @asayyah @astroza @at-wat @atoppi @bajam-genetec @berkant @boks1971 @britblue @cgojin @ChaturvediShilpa @chenosaurus @cmorillas @cnderrauber @copilot @cppcoffee @debugmenot @drshrey @enobufs @FrantaBOT @ghost @Hackerman-ru @hanguyen-nuro @hexbabe @jackielii @jasmoran @jiajieli-dev @JoeTurki @Juliapixel @kevmo314 @kmansoft @lars-sto @lidian-runner @lkang-nuro @mengelbart @mikeyg42 @miya-masa @MrPomidoro @nils-ohlmeier @Olexandr88 @penhauer @philipch07 @pionbot @rg0now @ryanpotat @sean-der @setheck @sirzooro @sundenis @sunofcoder @sxmzou @theodorsm @thesyncim @tmatth @trs00 @valorzard @wrangelvid @xinze-zheng @yannismate @yzhao-nuro