// SPDX-FileCopyrightText: 2023 The Pion community // 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/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 } 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. 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 } // 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: 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) } func createStreamInfo(id string, ssrc SSRC, payloadType 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), PayloadType: uint8(payloadType), RTPHeaderExtensions: headerExtensions, MimeType: codec.MimeType, ClockRate: codec.ClockRate, Channels: codec.Channels, SDPFmtpLine: codec.SDPFmtpLine, RTCPFeedback: feedbacks, } }