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