github.com/pion/webrtc/v4@v4.0.1/interceptor.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
     2  // SPDX-License-Identifier: MIT
     3  
     4  //go:build !js
     5  // +build !js
     6  
     7  package webrtc
     8  
     9  import (
    10  	"sync/atomic"
    11  
    12  	"github.com/pion/interceptor"
    13  	"github.com/pion/interceptor/pkg/nack"
    14  	"github.com/pion/interceptor/pkg/report"
    15  	"github.com/pion/interceptor/pkg/rfc8888"
    16  	"github.com/pion/interceptor/pkg/twcc"
    17  	"github.com/pion/rtp"
    18  	"github.com/pion/sdp/v3"
    19  )
    20  
    21  // RegisterDefaultInterceptors will register some useful interceptors.
    22  // If you want to customize which interceptors are loaded, you should copy the
    23  // code from this method and remove unwanted interceptors.
    24  func RegisterDefaultInterceptors(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
    25  	if err := ConfigureNack(mediaEngine, interceptorRegistry); err != nil {
    26  		return err
    27  	}
    28  
    29  	if err := ConfigureRTCPReports(interceptorRegistry); err != nil {
    30  		return err
    31  	}
    32  
    33  	if err := ConfigureSimulcastExtensionHeaders(mediaEngine); err != nil {
    34  		return err
    35  	}
    36  
    37  	return ConfigureTWCCSender(mediaEngine, interceptorRegistry)
    38  }
    39  
    40  // ConfigureRTCPReports will setup everything necessary for generating Sender and Receiver Reports
    41  func ConfigureRTCPReports(interceptorRegistry *interceptor.Registry) error {
    42  	reciver, err := report.NewReceiverInterceptor()
    43  	if err != nil {
    44  		return err
    45  	}
    46  
    47  	sender, err := report.NewSenderInterceptor()
    48  	if err != nil {
    49  		return err
    50  	}
    51  
    52  	interceptorRegistry.Add(reciver)
    53  	interceptorRegistry.Add(sender)
    54  	return nil
    55  }
    56  
    57  // ConfigureNack will setup everything necessary for handling generating/responding to nack messages.
    58  func ConfigureNack(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
    59  	generator, err := nack.NewGeneratorInterceptor()
    60  	if err != nil {
    61  		return err
    62  	}
    63  
    64  	responder, err := nack.NewResponderInterceptor()
    65  	if err != nil {
    66  		return err
    67  	}
    68  
    69  	mediaEngine.RegisterFeedback(RTCPFeedback{Type: "nack"}, RTPCodecTypeVideo)
    70  	mediaEngine.RegisterFeedback(RTCPFeedback{Type: "nack", Parameter: "pli"}, RTPCodecTypeVideo)
    71  	interceptorRegistry.Add(responder)
    72  	interceptorRegistry.Add(generator)
    73  	return nil
    74  }
    75  
    76  // ConfigureTWCCHeaderExtensionSender will setup everything necessary for adding
    77  // a TWCC header extension to outgoing RTP packets. This will allow the remote peer to generate TWCC reports.
    78  func ConfigureTWCCHeaderExtensionSender(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
    79  	if err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeVideo); err != nil {
    80  		return err
    81  	}
    82  
    83  	if err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeAudio); err != nil {
    84  		return err
    85  	}
    86  
    87  	i, err := twcc.NewHeaderExtensionInterceptor()
    88  	if err != nil {
    89  		return err
    90  	}
    91  
    92  	interceptorRegistry.Add(i)
    93  	return nil
    94  }
    95  
    96  // ConfigureTWCCSender will setup everything necessary for generating TWCC reports.
    97  func ConfigureTWCCSender(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
    98  	mediaEngine.RegisterFeedback(RTCPFeedback{Type: TypeRTCPFBTransportCC}, RTPCodecTypeVideo)
    99  	if err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeVideo); err != nil {
   100  		return err
   101  	}
   102  
   103  	mediaEngine.RegisterFeedback(RTCPFeedback{Type: TypeRTCPFBTransportCC}, RTPCodecTypeAudio)
   104  	if err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeAudio); err != nil {
   105  		return err
   106  	}
   107  
   108  	generator, err := twcc.NewSenderInterceptor()
   109  	if err != nil {
   110  		return err
   111  	}
   112  
   113  	interceptorRegistry.Add(generator)
   114  	return nil
   115  }
   116  
   117  // ConfigureCongestionControlFeedback registers congestion control feedback as
   118  // defined in RFC 8888 (https://datatracker.ietf.org/doc/rfc8888/)
   119  func ConfigureCongestionControlFeedback(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
   120  	mediaEngine.RegisterFeedback(RTCPFeedback{Type: TypeRTCPFBACK, Parameter: "ccfb"}, RTPCodecTypeVideo)
   121  	mediaEngine.RegisterFeedback(RTCPFeedback{Type: TypeRTCPFBACK, Parameter: "ccfb"}, RTPCodecTypeAudio)
   122  	generator, err := rfc8888.NewSenderInterceptor()
   123  	if err != nil {
   124  		return err
   125  	}
   126  	interceptorRegistry.Add(generator)
   127  	return nil
   128  }
   129  
   130  // ConfigureSimulcastExtensionHeaders enables the RTP Extension Headers needed for Simulcast
   131  func ConfigureSimulcastExtensionHeaders(mediaEngine *MediaEngine) error {
   132  	if err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.SDESMidURI}, RTPCodecTypeVideo); err != nil {
   133  		return err
   134  	}
   135  
   136  	if err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.SDESRTPStreamIDURI}, RTPCodecTypeVideo); err != nil {
   137  		return err
   138  	}
   139  
   140  	return mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdesRepairRTPStreamIDURI}, RTPCodecTypeVideo)
   141  }
   142  
   143  type interceptorToTrackLocalWriter struct{ interceptor atomic.Value } // interceptor.RTPWriter }
   144  
   145  func (i *interceptorToTrackLocalWriter) WriteRTP(header *rtp.Header, payload []byte) (int, error) {
   146  	if writer, ok := i.interceptor.Load().(interceptor.RTPWriter); ok && writer != nil {
   147  		return writer.Write(header, payload, interceptor.Attributes{})
   148  	}
   149  
   150  	return 0, nil
   151  }
   152  
   153  func (i *interceptorToTrackLocalWriter) Write(b []byte) (int, error) {
   154  	packet := &rtp.Packet{}
   155  	if err := packet.Unmarshal(b); err != nil {
   156  		return 0, err
   157  	}
   158  
   159  	return i.WriteRTP(&packet.Header, packet.Payload)
   160  }
   161  
   162  // nolint: unparam
   163  func createStreamInfo(id string, ssrc, ssrcRTX, ssrcFEC SSRC, payloadType, payloadTypeRTX, payloadTypeFEC PayloadType, codec RTPCodecCapability, webrtcHeaderExtensions []RTPHeaderExtensionParameter) *interceptor.StreamInfo {
   164  	headerExtensions := make([]interceptor.RTPHeaderExtension, 0, len(webrtcHeaderExtensions))
   165  	for _, h := range webrtcHeaderExtensions {
   166  		headerExtensions = append(headerExtensions, interceptor.RTPHeaderExtension{ID: h.ID, URI: h.URI})
   167  	}
   168  
   169  	feedbacks := make([]interceptor.RTCPFeedback, 0, len(codec.RTCPFeedback))
   170  	for _, f := range codec.RTCPFeedback {
   171  		feedbacks = append(feedbacks, interceptor.RTCPFeedback{Type: f.Type, Parameter: f.Parameter})
   172  	}
   173  
   174  	return &interceptor.StreamInfo{
   175  		ID:                                id,
   176  		Attributes:                        interceptor.Attributes{},
   177  		SSRC:                              uint32(ssrc),
   178  		SSRCRetransmission:                uint32(ssrcRTX),
   179  		SSRCForwardErrorCorrection:        uint32(ssrcFEC),
   180  		PayloadType:                       uint8(payloadType),
   181  		PayloadTypeRetransmission:         uint8(payloadTypeRTX),
   182  		PayloadTypeForwardErrorCorrection: uint8(payloadTypeFEC),
   183  		RTPHeaderExtensions:               headerExtensions,
   184  		MimeType:                          codec.MimeType,
   185  		ClockRate:                         codec.ClockRate,
   186  		Channels:                          codec.Channels,
   187  		SDPFmtpLine:                       codec.SDPFmtpLine,
   188  		RTCPFeedback:                      feedbacks,
   189  	}
   190  }