api.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. package webrtc
  2. import (
  3. "net"
  4. "github.com/AlexxIT/go2rtc/pkg/core"
  5. "github.com/pion/interceptor"
  6. "github.com/pion/webrtc/v3"
  7. )
  8. // ReceiveMTU = Ethernet MTU (1500) - IP Header (20) - UDP Header (8)
  9. // https://ffmpeg.org/ffmpeg-all.html#Muxer
  10. const ReceiveMTU = 1472
  11. func NewAPI() (*webrtc.API, error) {
  12. return NewServerAPI("", "", nil)
  13. }
  14. type Filters struct {
  15. Candidates []string `yaml:"candidates"`
  16. Interfaces []string `yaml:"interfaces"`
  17. IPs []string `yaml:"ips"`
  18. Networks []string `yaml:"networks"`
  19. UDPPorts []uint16 `yaml:"udp_ports"`
  20. }
  21. func NewServerAPI(network, address string, filters *Filters) (*webrtc.API, error) {
  22. // for debug logs add to env: `PION_LOG_DEBUG=all`
  23. m := &webrtc.MediaEngine{}
  24. //if err := m.RegisterDefaultCodecs(); err != nil {
  25. // return nil, err
  26. //}
  27. if err := RegisterDefaultCodecs(m); err != nil {
  28. return nil, err
  29. }
  30. i := &interceptor.Registry{}
  31. if err := webrtc.RegisterDefaultInterceptors(m, i); err != nil {
  32. return nil, err
  33. }
  34. s := webrtc.SettingEngine{}
  35. // fix https://github.com/pion/webrtc/pull/2407
  36. s.SetDTLSInsecureSkipHelloVerify(true)
  37. if filters != nil && filters.Interfaces != nil {
  38. s.SetIncludeLoopbackCandidate(true)
  39. s.SetInterfaceFilter(func(name string) bool {
  40. return core.Contains(filters.Interfaces, name)
  41. })
  42. } else {
  43. // disable listen on Hassio docker interfaces
  44. s.SetInterfaceFilter(func(name string) bool {
  45. return name != "hassio" && name != "docker0"
  46. })
  47. }
  48. if filters != nil && filters.IPs != nil {
  49. s.SetIncludeLoopbackCandidate(true)
  50. s.SetIPFilter(func(ip net.IP) bool {
  51. return core.Contains(filters.IPs, ip.String())
  52. })
  53. }
  54. if filters != nil && filters.Networks != nil {
  55. var networkTypes []webrtc.NetworkType
  56. for _, s := range filters.Networks {
  57. if networkType, err := webrtc.NewNetworkType(s); err == nil {
  58. networkTypes = append(networkTypes, networkType)
  59. }
  60. }
  61. s.SetNetworkTypes(networkTypes)
  62. } else {
  63. s.SetNetworkTypes([]webrtc.NetworkType{
  64. webrtc.NetworkTypeUDP4, webrtc.NetworkTypeUDP6,
  65. webrtc.NetworkTypeTCP4, webrtc.NetworkTypeTCP6,
  66. })
  67. }
  68. if filters != nil && len(filters.UDPPorts) == 2 {
  69. _ = s.SetEphemeralUDPPortRange(filters.UDPPorts[0], filters.UDPPorts[1])
  70. }
  71. //if len(hosts) != 0 {
  72. // // support only: host, srflx
  73. // if candidateType, err := webrtc.NewICECandidateType(hosts[0]); err == nil {
  74. // s.SetNAT1To1IPs(hosts[1:], candidateType)
  75. // } else {
  76. // s.SetNAT1To1IPs(hosts, 0) // 0 = host
  77. // }
  78. //}
  79. if address != "" {
  80. if network == "" || network == "tcp" {
  81. if ln, err := net.Listen("tcp", address); err == nil {
  82. tcpMux := webrtc.NewICETCPMux(nil, ln, 8)
  83. s.SetICETCPMux(tcpMux)
  84. }
  85. }
  86. if network == "" || network == "udp" {
  87. if ln, err := net.ListenPacket("udp", address); err == nil {
  88. udpMux := webrtc.NewICEUDPMux(nil, ln)
  89. s.SetICEUDPMux(udpMux)
  90. }
  91. }
  92. }
  93. return webrtc.NewAPI(
  94. webrtc.WithMediaEngine(m),
  95. webrtc.WithInterceptorRegistry(i),
  96. webrtc.WithSettingEngine(s),
  97. ), nil
  98. }
  99. func RegisterDefaultCodecs(m *webrtc.MediaEngine) error {
  100. for _, codec := range []webrtc.RTPCodecParameters{
  101. {
  102. RTPCodecCapability: webrtc.RTPCodecCapability{
  103. MimeType: webrtc.MimeTypeOpus, ClockRate: 48000, Channels: 2, SDPFmtpLine: "minptime=10;useinbandfec=1",
  104. },
  105. PayloadType: 101, //111,
  106. },
  107. {
  108. RTPCodecCapability: webrtc.RTPCodecCapability{
  109. MimeType: webrtc.MimeTypePCMU, ClockRate: 8000,
  110. },
  111. PayloadType: 0,
  112. },
  113. {
  114. RTPCodecCapability: webrtc.RTPCodecCapability{
  115. MimeType: webrtc.MimeTypePCMA, ClockRate: 8000,
  116. },
  117. PayloadType: 8,
  118. },
  119. } {
  120. if err := m.RegisterCodec(codec, webrtc.RTPCodecTypeAudio); err != nil {
  121. return err
  122. }
  123. }
  124. videoRTCPFeedback := []webrtc.RTCPFeedback{
  125. {"goog-remb", ""},
  126. {"ccm", "fir"},
  127. {"nack", ""},
  128. {"nack", "pli"},
  129. }
  130. for _, codec := range []webrtc.RTPCodecParameters{
  131. {
  132. RTPCodecCapability: webrtc.RTPCodecCapability{
  133. MimeType: webrtc.MimeTypeH264,
  134. ClockRate: 90000,
  135. SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f",
  136. RTCPFeedback: videoRTCPFeedback,
  137. },
  138. PayloadType: 96, // Chrome v110 - PayloadType: 102
  139. },
  140. {
  141. RTPCodecCapability: webrtc.RTPCodecCapability{
  142. MimeType: webrtc.MimeTypeH264,
  143. ClockRate: 90000,
  144. SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f",
  145. RTCPFeedback: videoRTCPFeedback,
  146. },
  147. PayloadType: 97, // Chrome v110 - PayloadType: 106
  148. },
  149. {
  150. RTPCodecCapability: webrtc.RTPCodecCapability{
  151. MimeType: webrtc.MimeTypeH264,
  152. ClockRate: 90000,
  153. SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032",
  154. RTCPFeedback: videoRTCPFeedback,
  155. },
  156. PayloadType: 98, // Chrome v110 - PayloadType: 112
  157. },
  158. // macOS Safari 15.1
  159. {
  160. RTPCodecCapability: webrtc.RTPCodecCapability{
  161. MimeType: webrtc.MimeTypeH265,
  162. ClockRate: 90000,
  163. RTCPFeedback: videoRTCPFeedback,
  164. },
  165. PayloadType: 100,
  166. },
  167. } {
  168. if err := m.RegisterCodec(codec, webrtc.RTPCodecTypeVideo); err != nil {
  169. return err
  170. }
  171. }
  172. return nil
  173. }