interceptor.go 5.0 KB

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