Files
webrtc/interceptor.go
Joe Turki feeeebf251 Upgrade golangci-lint, more linters
Introduces new linters, upgrade golangci-lint to version (v1.63.4)
2025-01-18 07:16:06 -06:00

217 lines
6.9 KiB
Go

// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT
//go:build !js
// +build !js
package webrtc
import (
"sync/atomic"
"github.com/pion/interceptor"
"github.com/pion/interceptor/pkg/nack"
"github.com/pion/interceptor/pkg/report"
"github.com/pion/interceptor/pkg/rfc8888"
"github.com/pion/interceptor/pkg/twcc"
"github.com/pion/rtp"
"github.com/pion/sdp/v3"
)
// RegisterDefaultInterceptors will register some useful interceptors.
// If you want to customize which interceptors are loaded, you should copy the
// code from this method and remove unwanted interceptors.
func RegisterDefaultInterceptors(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
if err := ConfigureNack(mediaEngine, interceptorRegistry); err != nil {
return err
}
if err := ConfigureRTCPReports(interceptorRegistry); err != nil {
return err
}
if err := ConfigureSimulcastExtensionHeaders(mediaEngine); err != nil {
return err
}
return ConfigureTWCCSender(mediaEngine, interceptorRegistry)
}
// ConfigureRTCPReports will setup everything necessary for generating Sender and Receiver Reports.
func ConfigureRTCPReports(interceptorRegistry *interceptor.Registry) error {
reciver, err := report.NewReceiverInterceptor()
if err != nil {
return err
}
sender, err := report.NewSenderInterceptor()
if err != nil {
return err
}
interceptorRegistry.Add(reciver)
interceptorRegistry.Add(sender)
return nil
}
// ConfigureNack will setup everything necessary for handling generating/responding to nack messages.
func ConfigureNack(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
generator, err := nack.NewGeneratorInterceptor()
if err != nil {
return err
}
responder, err := nack.NewResponderInterceptor()
if err != nil {
return err
}
mediaEngine.RegisterFeedback(RTCPFeedback{Type: "nack"}, RTPCodecTypeVideo)
mediaEngine.RegisterFeedback(RTCPFeedback{Type: "nack", Parameter: "pli"}, RTPCodecTypeVideo)
interceptorRegistry.Add(responder)
interceptorRegistry.Add(generator)
return nil
}
// ConfigureTWCCHeaderExtensionSender will setup everything necessary for adding
// a TWCC header extension to outgoing RTP packets. This will allow the remote peer to generate TWCC reports.
func ConfigureTWCCHeaderExtensionSender(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
if err := mediaEngine.RegisterHeaderExtension(
RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeVideo,
); err != nil {
return err
}
if err := mediaEngine.RegisterHeaderExtension(
RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeAudio,
); err != nil {
return err
}
i, err := twcc.NewHeaderExtensionInterceptor()
if err != nil {
return err
}
interceptorRegistry.Add(i)
return nil
}
// ConfigureTWCCSender will setup everything necessary for generating TWCC reports.
// This must be called after registering codecs with the MediaEngine.
func ConfigureTWCCSender(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
mediaEngine.RegisterFeedback(RTCPFeedback{Type: TypeRTCPFBTransportCC}, RTPCodecTypeVideo)
if err := mediaEngine.RegisterHeaderExtension(
RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeVideo,
); err != nil {
return err
}
mediaEngine.RegisterFeedback(RTCPFeedback{Type: TypeRTCPFBTransportCC}, RTPCodecTypeAudio)
if err := mediaEngine.RegisterHeaderExtension(
RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeAudio,
); err != nil {
return err
}
generator, err := twcc.NewSenderInterceptor()
if err != nil {
return err
}
interceptorRegistry.Add(generator)
return nil
}
// ConfigureCongestionControlFeedback registers congestion control feedback as
// defined in RFC 8888 (https://datatracker.ietf.org/doc/rfc8888/)
func ConfigureCongestionControlFeedback(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
mediaEngine.RegisterFeedback(RTCPFeedback{Type: TypeRTCPFBACK, Parameter: "ccfb"}, RTPCodecTypeVideo)
mediaEngine.RegisterFeedback(RTCPFeedback{Type: TypeRTCPFBACK, Parameter: "ccfb"}, RTPCodecTypeAudio)
generator, err := rfc8888.NewSenderInterceptor()
if err != nil {
return err
}
interceptorRegistry.Add(generator)
return nil
}
// ConfigureSimulcastExtensionHeaders enables the RTP Extension Headers needed for Simulcast.
func ConfigureSimulcastExtensionHeaders(mediaEngine *MediaEngine) error {
if err := mediaEngine.RegisterHeaderExtension(
RTPHeaderExtensionCapability{URI: sdp.SDESMidURI}, RTPCodecTypeVideo,
); err != nil {
return err
}
if err := mediaEngine.RegisterHeaderExtension(
RTPHeaderExtensionCapability{URI: sdp.SDESRTPStreamIDURI}, RTPCodecTypeVideo,
); err != nil {
return err
}
return mediaEngine.RegisterHeaderExtension(
RTPHeaderExtensionCapability{URI: sdp.SDESRepairRTPStreamIDURI}, RTPCodecTypeVideo,
)
}
type interceptorToTrackLocalWriter struct{ interceptor atomic.Value } // interceptor.RTPWriter }
func (i *interceptorToTrackLocalWriter) WriteRTP(header *rtp.Header, payload []byte) (int, error) {
if writer, ok := i.interceptor.Load().(interceptor.RTPWriter); ok && writer != nil {
return writer.Write(header, payload, interceptor.Attributes{})
}
return 0, nil
}
func (i *interceptorToTrackLocalWriter) Write(b []byte) (int, error) {
packet := &rtp.Packet{}
if err := packet.Unmarshal(b); err != nil {
return 0, err
}
return i.WriteRTP(&packet.Header, packet.Payload)
}
//nolint:unparam
func createStreamInfo(
id string,
ssrc, ssrcRTX, ssrcFEC SSRC,
payloadType, payloadTypeRTX, payloadTypeFEC PayloadType,
codec RTPCodecCapability,
webrtcHeaderExtensions []RTPHeaderExtensionParameter,
) *interceptor.StreamInfo {
headerExtensions := make([]interceptor.RTPHeaderExtension, 0, len(webrtcHeaderExtensions))
for _, h := range webrtcHeaderExtensions {
headerExtensions = append(headerExtensions, interceptor.RTPHeaderExtension{ID: h.ID, URI: h.URI})
}
feedbacks := make([]interceptor.RTCPFeedback, 0, len(codec.RTCPFeedback))
for _, f := range codec.RTCPFeedback {
feedbacks = append(feedbacks, interceptor.RTCPFeedback{Type: f.Type, Parameter: f.Parameter})
}
return &interceptor.StreamInfo{
ID: id,
Attributes: interceptor.Attributes{},
SSRC: uint32(ssrc),
SSRCRetransmission: uint32(ssrcRTX),
SSRCForwardErrorCorrection: uint32(ssrcFEC),
PayloadType: uint8(payloadType),
PayloadTypeRetransmission: uint8(payloadTypeRTX),
PayloadTypeForwardErrorCorrection: uint8(payloadTypeFEC),
RTPHeaderExtensions: headerExtensions,
MimeType: codec.MimeType,
ClockRate: codec.ClockRate,
Channels: codec.Channels,
SDPFmtpLine: codec.SDPFmtpLine,
RTCPFeedback: feedbacks,
}
}