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  }