Skip to main content

Overview

Interceptors allow you to intercept and process RTP and RTCP packets as they flow through the WebRTC stack. They enable advanced features like:
  • NACK (Negative Acknowledgment) for packet loss recovery
  • TWCC (Transport Wide Congestion Control) for bandwidth estimation
  • RTCP Sender/Receiver Reports for statistics
  • Custom packet processing and modification
  • FlexFEC forward error correction
Pion provides a default set of interceptors that handle most common use cases. You only need to configure interceptors manually for advanced scenarios.

Default Interceptors

Pion registers these interceptors by default:
1

NACK Generator & Responder

Automatically requests retransmission of lost packets and responds to NACK requests
2

RTCP Reports

Generates Sender and Receiver Reports for connection statistics
3

Stats Interceptor

Collects RTP stream statistics accessible via GetStats()
4

TWCC Sender

Generates Transport-Wide Congestion Control feedback for bandwidth estimation
5

Simulcast Extensions

Enables RTP header extensions needed for simulcast (MID, RID)

Using Default Interceptors

default-interceptors.go
package main

import (
    "github.com/pion/interceptor"
    "github.com/pion/webrtc/v4"
)

func main() {
    // Create MediaEngine and InterceptorRegistry
    m := &webrtc.MediaEngine{}
    if err := m.RegisterDefaultCodecs(); err != nil {
        panic(err)
    }
    
    i := &interceptor.Registry{}
    
    // Register default interceptors
    if err := webrtc.RegisterDefaultInterceptors(m, i); err != nil {
        panic(err)
    }
    
    // Create API with MediaEngine and Interceptors
    api := webrtc.NewAPI(
        webrtc.WithMediaEngine(m),
        webrtc.WithInterceptorRegistry(i),
    )
    
    // Create PeerConnection
    peerConnection, err := api.NewPeerConnection(webrtc.Configuration{})
    if err != nil {
        panic(err)
    }
    defer peerConnection.Close()
}
From interceptor.go:24-29.

Configuring Default Interceptors

You can pass options to configure the default interceptors:
interceptor-options.go
import (
    "github.com/pion/interceptor"
    "github.com/pion/logging"
    "github.com/pion/webrtc/v4"
)

m := &webrtc.MediaEngine{}
m.RegisterDefaultCodecs()

i := &interceptor.Registry{}

// Create a logger factory
loggerFactory := logging.NewDefaultLoggerFactory()

// Register with options
err := webrtc.RegisterDefaultInterceptorsWithOptions(m, i,
    webrtc.WithInterceptorLoggerFactory(loggerFactory),
)
if err != nil {
    panic(err)
}
From interceptor.go:31-75.

NACK Interceptor

NACK (Negative Acknowledgment) enables automatic retransmission of lost RTP packets.

Basic Configuration

nack.go
import (
    "github.com/pion/interceptor"
    "github.com/pion/webrtc/v4"
)

m := &webrtc.MediaEngine{}
m.RegisterDefaultCodecs()

i := &interceptor.Registry{}

// Configure NACK
if err := webrtc.ConfigureNack(m, i); err != nil {
    panic(err)
}
From interceptor.go:142-168.

NACK with Options

nack-options.go
import (
    "github.com/pion/interceptor/pkg/nack"
    "github.com/pion/logging"
)

loggerFactory := logging.NewDefaultLoggerFactory()

genOpts := []nack.GeneratorOption{
    nack.WithGeneratorLoggerFactory(loggerFactory),
}

respOpts := []nack.ResponderOption{
    nack.WithResponderLoggerFactory(loggerFactory),
}

err := webrtc.ConfigureNackWithOptions(m, i, genOpts, respOpts...)
From interceptor.go:147-168.
NACK automatically registers the required RTCP feedback (nack and nack pli) to the MediaEngine.

TWCC (Transport-Wide Congestion Control)

TWCC provides fine-grained bandwidth estimation by tracking individual RTP packets.

Configure TWCC Sender

twcc.go
import (
    "github.com/pion/interceptor"
    "github.com/pion/webrtc/v4"
)

m := &webrtc.MediaEngine{}
m.RegisterDefaultCodecs()

i := &interceptor.Registry{}

// Configure TWCC - generates TWCC feedback reports
if err := webrtc.ConfigureTWCCSender(m, i); err != nil {
    panic(err)
}
This registers:
  • Transport-CC header extension for video and audio
  • TWCC RTCP feedback
  • TWCC sender interceptor
From interceptor.go:195-228.

TWCC with Options

twcc-options.go
import (
    "github.com/pion/interceptor/pkg/twcc"
    "github.com/pion/logging"
)

loggerFactory := logging.NewDefaultLoggerFactory()

opts := []twcc.Option{
    twcc.WithLoggerFactory(loggerFactory),
}

err := webrtc.ConfigureTWCCSenderWithOptions(m, i, opts...)
From interceptor.go:201-228.

TWCC Header Extension Only

If you only want to add TWCC header extensions (to let the remote peer generate reports):
twcc-header.go
// Only add header extension, don't generate reports
if err := webrtc.ConfigureTWCCHeaderExtensionSender(m, i); err != nil {
    panic(err)
}
From interceptor.go:170-193.

RTCP Reports

Generate Sender and Receiver Reports for connection statistics.
rtcp-reports.go
import (
    "github.com/pion/interceptor"
    "github.com/pion/webrtc/v4"
)

m := &webrtc.MediaEngine{}
m.RegisterDefaultCodecs()

i := &interceptor.Registry{}

// Configure RTCP Reports
if err := webrtc.ConfigureRTCPReports(i); err != nil {
    panic(err)
}
From interceptor.go:116-140.

RTCP Reports with Options

rtcp-options.go
import (
    "github.com/pion/interceptor/pkg/report"
    "github.com/pion/logging"
)

loggerFactory := logging.NewDefaultLoggerFactory()

recvOpts := []report.ReceiverOption{
    report.WithReceiverLoggerFactory(loggerFactory),
}

sendOpts := []report.SenderOption{
    report.WithSenderLoggerFactory(loggerFactory),
}

err := webrtc.ConfigureRTCPReportsWithOptions(i, recvOpts, sendOpts...)

Stats Interceptor

Collect detailed RTP stream statistics:
stats.go
import (
    "github.com/pion/interceptor"
    "github.com/pion/webrtc/v4"
)

m := &webrtc.MediaEngine{}
m.RegisterDefaultCodecs()

i := &interceptor.Registry{}

// Configure Stats
if err := webrtc.ConfigureStatsInterceptor(i); err != nil {
    panic(err)
}

api := webrtc.NewAPI(
    webrtc.WithMediaEngine(m),
    webrtc.WithInterceptorRegistry(i),
)

peerConnection, _ := api.NewPeerConnection(webrtc.Configuration{})

// Later, get stats
stats := peerConnection.GetStats()
From interceptor.go:77-95.

Simulcast Extensions

Enable RTP header extensions needed for simulcast:
simulcast.go
import (
    "github.com/pion/interceptor"
    "github.com/pion/webrtc/v4"
)

m := &webrtc.MediaEngine{}
m.RegisterDefaultCodecs()

// Configure simulcast extensions (MID, RID, Repair RID)
if err := webrtc.ConfigureSimulcastExtensionHeaders(m); err != nil {
    panic(err)
}
This registers:
  • sdp.SDESMidURI - Media stream identification
  • sdp.SDESRTPStreamIDURI - RTP stream ID
  • sdp.SDESRepairRTPStreamIDURI - Repair stream ID
From interceptor.go:252-269.

FlexFEC (Forward Error Correction)

FlexFEC adds redundancy to reduce packet loss impact:
flexfec.go
import (
    "github.com/pion/interceptor"
    "github.com/pion/interceptor/pkg/flexfec"
    "github.com/pion/webrtc/v4"
)

m := &webrtc.MediaEngine{}
m.RegisterDefaultCodecs()

i := &interceptor.Registry{}

// Configure FlexFEC with payload type 125
options := []flexfec.FecOption{}
err := webrtc.ConfigureFlexFEC03(
    125, // payload type
    m,
    i,
    options...,
)
if err != nil {
    panic(err)
}
FlexFEC interceptor must be registered before other interceptors that modify RTP packets (like TWCC), so that FEC packets are not modified.
From interceptor.go:271-304.

RFC 8888 Congestion Control Feedback

Register congestion control feedback as defined in RFC 8888:
rfc8888.go
import (
    "github.com/pion/interceptor"
    "github.com/pion/interceptor/pkg/rfc8888"
    "github.com/pion/webrtc/v4"
)

m := &webrtc.MediaEngine{}
m.RegisterDefaultCodecs()

i := &interceptor.Registry{}

options := []rfc8888.Option{}
err := webrtc.ConfigureCongestionControlFeedback(m, i, options...)
if err != nil {
    panic(err)
}
From interceptor.go:230-250.

Custom Interceptor

You can create custom interceptors to process RTP/RTCP packets:
custom-interceptor.go
import (
    "github.com/pion/interceptor"
    "github.com/pion/rtp"
)

// Custom interceptor that logs all RTP packets
type LoggingInterceptor struct {
    interceptor.NoOp
}

func (l *LoggingInterceptor) BindLocalStream(
    info *interceptor.StreamInfo,
    writer interceptor.RTPWriter,
) interceptor.RTPWriter {
    return interceptor.RTPWriterFunc(func(
        header *rtp.Header,
        payload []byte,
        attributes interceptor.Attributes,
    ) (int, error) {
        fmt.Printf("Sending RTP: SSRC=%d PT=%d SN=%d\n",
            header.SSRC, header.PayloadType, header.SequenceNumber)
        return writer.Write(header, payload, attributes)
    })
}

func (l *LoggingInterceptor) BindRemoteStream(
    info *interceptor.StreamInfo,
    reader interceptor.RTPReader,
) interceptor.RTPReader {
    return interceptor.RTPReaderFunc(func(
        b []byte,
        a interceptor.Attributes,
    ) (int, interceptor.Attributes, error) {
        n, attr, err := reader.Read(b, a)
        if err == nil {
            fmt.Printf("Received RTP packet (%d bytes)\n", n)
        }
        return n, attr, err
    })
}

// Register the custom interceptor
i := &interceptor.Registry{}
i.Add(&LoggingInterceptor{})

Complete Example

complete-example.go
package main

import (
    "fmt"
    "github.com/pion/interceptor"
    "github.com/pion/interceptor/pkg/nack"
    "github.com/pion/logging"
    "github.com/pion/webrtc/v4"
)

func main() {
    // Create MediaEngine
    m := &webrtc.MediaEngine{}
    if err := m.RegisterDefaultCodecs(); err != nil {
        panic(err)
    }
    
    // Create InterceptorRegistry
    i := &interceptor.Registry{}
    
    // Create logger factory
    loggerFactory := logging.NewDefaultLoggerFactory()
    
    // Configure NACK with logging
    genOpts := []nack.GeneratorOption{
        nack.WithGeneratorLoggerFactory(loggerFactory),
    }
    respOpts := []nack.ResponderOption{
        nack.WithResponderLoggerFactory(loggerFactory),
    }
    if err := webrtc.ConfigureNackWithOptions(m, i, genOpts, respOpts...); err != nil {
        panic(err)
    }
    
    // Configure RTCP Reports
    if err := webrtc.ConfigureRTCPReports(i); err != nil {
        panic(err)
    }
    
    // Configure simulcast extensions
    if err := webrtc.ConfigureSimulcastExtensionHeaders(m); err != nil {
        panic(err)
    }
    
    // Configure Stats
    if err := webrtc.ConfigureStatsInterceptor(i); err != nil {
        panic(err)
    }
    
    // Configure TWCC
    if err := webrtc.ConfigureTWCCSender(m, i); err != nil {
        panic(err)
    }
    
    // Create API
    api := webrtc.NewAPI(
        webrtc.WithMediaEngine(m),
        webrtc.WithInterceptorRegistry(i),
    )
    
    // Create PeerConnection
    config := webrtc.Configuration{
        ICEServers: []webrtc.ICEServer{
            {URLs: []string{"stun:stun.l.google.com:19302"}},
        },
    }
    
    peerConnection, err := api.NewPeerConnection(config)
    if err != nil {
        panic(err)
    }
    defer peerConnection.Close()
    
    fmt.Println("PeerConnection created with interceptors")
    
    // Later: access stats
    stats := peerConnection.GetStats()
    fmt.Printf("Stats available: %v\n", stats)
}

Interceptor Order

The order of interceptors matters:
  1. FlexFEC - Must be first if used, so FEC packets aren’t modified
  2. NACK Responder - Should be early to handle retransmissions
  3. TWCC - Add sequence numbers to packets
  4. Stats - Collect statistics
  5. RTCP Reports - Generate reports
  6. NACK Generator - Request retransmissions
RegisterDefaultInterceptors handles the correct ordering automatically.

MediaEngine

Configure codecs and capabilities

SettingEngine

Advanced configuration options

Build docs developers (and LLMs) love