github.com/pion/webrtc/v3@v3.2.24/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/twcc" 16 "github.com/pion/rtp" 17 "github.com/pion/sdp/v3" 18 ) 19 20 // RegisterDefaultInterceptors will register some useful interceptors. 21 // If you want to customize which interceptors are loaded, you should copy the 22 // code from this method and remove unwanted interceptors. 23 func RegisterDefaultInterceptors(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error { 24 if err := ConfigureNack(mediaEngine, interceptorRegistry); err != nil { 25 return err 26 } 27 28 if err := ConfigureRTCPReports(interceptorRegistry); err != nil { 29 return err 30 } 31 32 return ConfigureTWCCSender(mediaEngine, interceptorRegistry) 33 } 34 35 // ConfigureRTCPReports will setup everything necessary for generating Sender and Receiver Reports 36 func ConfigureRTCPReports(interceptorRegistry *interceptor.Registry) error { 37 reciver, err := report.NewReceiverInterceptor() 38 if err != nil { 39 return err 40 } 41 42 sender, err := report.NewSenderInterceptor() 43 if err != nil { 44 return err 45 } 46 47 interceptorRegistry.Add(reciver) 48 interceptorRegistry.Add(sender) 49 return nil 50 } 51 52 // ConfigureNack will setup everything necessary for handling generating/responding to nack messages. 53 func ConfigureNack(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error { 54 generator, err := nack.NewGeneratorInterceptor() 55 if err != nil { 56 return err 57 } 58 59 responder, err := nack.NewResponderInterceptor() 60 if err != nil { 61 return err 62 } 63 64 mediaEngine.RegisterFeedback(RTCPFeedback{Type: "nack"}, RTPCodecTypeVideo) 65 mediaEngine.RegisterFeedback(RTCPFeedback{Type: "nack", Parameter: "pli"}, RTPCodecTypeVideo) 66 interceptorRegistry.Add(responder) 67 interceptorRegistry.Add(generator) 68 return nil 69 } 70 71 // ConfigureTWCCHeaderExtensionSender will setup everything necessary for adding 72 // a TWCC header extension to outgoing RTP packets. This will allow the remote peer to generate TWCC reports. 73 func ConfigureTWCCHeaderExtensionSender(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error { 74 if err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeVideo); err != nil { 75 return err 76 } 77 78 if err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeAudio); err != nil { 79 return err 80 } 81 82 i, err := twcc.NewHeaderExtensionInterceptor() 83 if err != nil { 84 return err 85 } 86 87 interceptorRegistry.Add(i) 88 return nil 89 } 90 91 // ConfigureTWCCSender will setup everything necessary for generating TWCC reports. 92 func ConfigureTWCCSender(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error { 93 mediaEngine.RegisterFeedback(RTCPFeedback{Type: TypeRTCPFBTransportCC}, RTPCodecTypeVideo) 94 if err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeVideo); err != nil { 95 return err 96 } 97 98 mediaEngine.RegisterFeedback(RTCPFeedback{Type: TypeRTCPFBTransportCC}, RTPCodecTypeAudio) 99 if err := mediaEngine.RegisterHeaderExtension(RTPHeaderExtensionCapability{URI: sdp.TransportCCURI}, RTPCodecTypeAudio); err != nil { 100 return err 101 } 102 103 generator, err := twcc.NewSenderInterceptor() 104 if err != nil { 105 return err 106 } 107 108 interceptorRegistry.Add(generator) 109 return nil 110 } 111 112 type interceptorToTrackLocalWriter struct{ interceptor atomic.Value } // interceptor.RTPWriter } 113 114 func (i *interceptorToTrackLocalWriter) WriteRTP(header *rtp.Header, payload []byte) (int, error) { 115 if writer, ok := i.interceptor.Load().(interceptor.RTPWriter); ok && writer != nil { 116 return writer.Write(header, payload, interceptor.Attributes{}) 117 } 118 119 return 0, nil 120 } 121 122 func (i *interceptorToTrackLocalWriter) Write(b []byte) (int, error) { 123 packet := &rtp.Packet{} 124 if err := packet.Unmarshal(b); err != nil { 125 return 0, err 126 } 127 128 return i.WriteRTP(&packet.Header, packet.Payload) 129 } 130 131 func createStreamInfo(id string, ssrc SSRC, payloadType PayloadType, codec RTPCodecCapability, webrtcHeaderExtensions []RTPHeaderExtensionParameter) *interceptor.StreamInfo { 132 headerExtensions := make([]interceptor.RTPHeaderExtension, 0, len(webrtcHeaderExtensions)) 133 for _, h := range webrtcHeaderExtensions { 134 headerExtensions = append(headerExtensions, interceptor.RTPHeaderExtension{ID: h.ID, URI: h.URI}) 135 } 136 137 feedbacks := make([]interceptor.RTCPFeedback, 0, len(codec.RTCPFeedback)) 138 for _, f := range codec.RTCPFeedback { 139 feedbacks = append(feedbacks, interceptor.RTCPFeedback{Type: f.Type, Parameter: f.Parameter}) 140 } 141 142 return &interceptor.StreamInfo{ 143 ID: id, 144 Attributes: interceptor.Attributes{}, 145 SSRC: uint32(ssrc), 146 PayloadType: uint8(payloadType), 147 RTPHeaderExtensions: headerExtensions, 148 MimeType: codec.MimeType, 149 ClockRate: codec.ClockRate, 150 Channels: codec.Channels, 151 SDPFmtpLine: codec.SDPFmtpLine, 152 RTCPFeedback: feedbacks, 153 } 154 }