main.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. //go:build !js
  4. // +build !js
  5. // rtp-to-webrtc demonstrates how to consume a RTP stream video UDP, and then send to a WebRTC client.
  6. package main
  7. import (
  8. "errors"
  9. "fmt"
  10. "io"
  11. "net"
  12. "github.com/pion/webrtc/v3"
  13. "github.com/pion/webrtc/v3/examples/internal/signal"
  14. )
  15. func main() {
  16. peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{
  17. ICEServers: []webrtc.ICEServer{
  18. {
  19. URLs: []string{"stun:stun.l.google.com:19302"},
  20. },
  21. },
  22. })
  23. if err != nil {
  24. panic(err)
  25. }
  26. // Open a UDP Listener for RTP Packets on port 5004
  27. listener, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 5004})
  28. if err != nil {
  29. panic(err)
  30. }
  31. // Increase the UDP receive buffer size
  32. // Default UDP buffer sizes vary on different operating systems
  33. bufferSize := 300000 // 300KB
  34. err = listener.SetReadBuffer(bufferSize)
  35. if err != nil {
  36. panic(err)
  37. }
  38. defer func() {
  39. if err = listener.Close(); err != nil {
  40. panic(err)
  41. }
  42. }()
  43. // Create a video track
  44. videoTrack, err := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8}, "video", "pion")
  45. if err != nil {
  46. panic(err)
  47. }
  48. rtpSender, err := peerConnection.AddTrack(videoTrack)
  49. if err != nil {
  50. panic(err)
  51. }
  52. // Read incoming RTCP packets
  53. // Before these packets are returned they are processed by interceptors. For things
  54. // like NACK this needs to be called.
  55. go func() {
  56. rtcpBuf := make([]byte, 1500)
  57. for {
  58. if _, _, rtcpErr := rtpSender.Read(rtcpBuf); rtcpErr != nil {
  59. return
  60. }
  61. }
  62. }()
  63. // Set the handler for ICE connection state
  64. // This will notify you when the peer has connected/disconnected
  65. peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
  66. fmt.Printf("Connection State has changed %s \n", connectionState.String())
  67. if connectionState == webrtc.ICEConnectionStateFailed {
  68. if closeErr := peerConnection.Close(); closeErr != nil {
  69. panic(closeErr)
  70. }
  71. }
  72. })
  73. // Wait for the offer to be pasted
  74. offer := webrtc.SessionDescription{}
  75. signal.Decode(signal.MustReadStdin(), &offer)
  76. // Set the remote SessionDescription
  77. if err = peerConnection.SetRemoteDescription(offer); err != nil {
  78. panic(err)
  79. }
  80. // Create answer
  81. answer, err := peerConnection.CreateAnswer(nil)
  82. if err != nil {
  83. panic(err)
  84. }
  85. // Create channel that is blocked until ICE Gathering is complete
  86. gatherComplete := webrtc.GatheringCompletePromise(peerConnection)
  87. // Sets the LocalDescription, and starts our UDP listeners
  88. if err = peerConnection.SetLocalDescription(answer); err != nil {
  89. panic(err)
  90. }
  91. // Block until ICE Gathering is complete, disabling trickle ICE
  92. // we do this because we only can exchange one signaling message
  93. // in a production application you should exchange ICE Candidates via OnICECandidate
  94. <-gatherComplete
  95. // Output the answer in base64 so we can paste it in browser
  96. fmt.Println(signal.Encode(*peerConnection.LocalDescription()))
  97. // Read RTP packets forever and send them to the WebRTC Client
  98. inboundRTPPacket := make([]byte, 1600) // UDP MTU
  99. for {
  100. n, _, err := listener.ReadFrom(inboundRTPPacket)
  101. if err != nil {
  102. panic(fmt.Sprintf("error during read: %s", err))
  103. }
  104. if _, err = videoTrack.Write(inboundRTPPacket[:n]); err != nil {
  105. if errors.Is(err, io.ErrClosedPipe) {
  106. // The peerConnection has been closed.
  107. return
  108. }
  109. panic(err)
  110. }
  111. }
  112. }