Skip to content

Instantly share code, notes, and snippets.

@Sean-Der
Created January 13, 2021 16:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sean-Der/c9c3ba89bb475fc6ccfd9d676da54c1e to your computer and use it in GitHub Desktop.
Save Sean-Der/c9c3ba89bb475fc6ccfd9d676da54c1e to your computer and use it in GitHub Desktop.
// +build !js
package main
import (
"fmt"
"net"
"github.com/pion/rtp"
"github.com/pion/rtp/codecs"
"github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal"
"github.com/pion/webrtc/v3/pkg/media/samplebuilder"
)
func main() {
peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{
ICEServers: []webrtc.ICEServer{
{
URLs: []string{"stun:stun.l.google.com:19302"},
},
},
})
if err != nil {
panic(err)
}
// Open a UDP Listener for RTP Packets on port 5004
listener, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 5004})
if err != nil {
panic(err)
}
defer func() {
if err = listener.Close(); err != nil {
panic(err)
}
}()
fmt.Println("Waiting for RTP Packets, please run GStreamer or ffmpeg now")
// Listen for a single RTP Packet, we need this to determine the SSRC
inboundRTPPacket := make([]byte, 4096) // UDP MTU
n, _, err := listener.ReadFromUDP(inboundRTPPacket)
if err != nil {
panic(err)
}
// Unmarshal the incoming packet
packet := &rtp.Packet{}
if err = packet.Unmarshal(inboundRTPPacket[:n]); err != nil {
panic(err)
}
// Create a video track
videoTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video", "pion")
if err != nil {
panic(err)
}
rtpSender, err := peerConnection.AddTrack(videoTrack)
if err != nil {
panic(err)
}
// Read incoming RTCP packets
// Before these packets are retuned they are processed by interceptors. For things
// like NACK this needs to be called.
go func() {
rtcpBuf := make([]byte, 1500)
for {
if _, _, rtcpErr := rtpSender.Read(rtcpBuf); rtcpErr != nil {
return
}
}
}()
// Set the handler for ICE connection state
// This will notify you when the peer has connected/disconnected
peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
fmt.Printf("Connection State has changed %s \n", connectionState.String())
})
// Wait for the offer to be pasted
offer := webrtc.SessionDescription{}
signal.Decode(signal.MustReadStdin(), &offer)
// Set the remote SessionDescription
if err = peerConnection.SetRemoteDescription(offer); err != nil {
panic(err)
}
// Create answer
answer, err := peerConnection.CreateAnswer(nil)
if err != nil {
panic(err)
}
// Create channel that is blocked until ICE Gathering is complete
gatherComplete := webrtc.GatheringCompletePromise(peerConnection)
// Sets the LocalDescription, and starts our UDP listeners
if err = peerConnection.SetLocalDescription(answer); err != nil {
panic(err)
}
// Block until ICE Gathering is complete, disabling trickle ICE
// we do this because we only can exchange one signaling message
// in a production application you should exchange ICE Candidates via OnICECandidate
<-gatherComplete
// Output the answer in base64 so we can paste it in browser
fmt.Println(signal.Encode(*peerConnection.LocalDescription()))
videoBuilder := samplebuilder.New(10, &codecs.VP8Packet{}, 90000)
// Read RTP packets forever and send them to the WebRTC Client
for {
inboundRTPPacket = make([]byte, 4096) // UDP MTU
packet = &rtp.Packet{}
n, _, err := listener.ReadFrom(inboundRTPPacket)
if err != nil {
panic(fmt.Sprintf("error during read: %s", err))
}
if err = packet.Unmarshal(inboundRTPPacket[:n]); err != nil {
panic(err)
}
videoBuilder.Push(packet)
for {
sample := videoBuilder.Pop()
if sample == nil {
break
}
if writeErr := videoTrack.WriteSample(*sample); writeErr != nil {
panic(writeErr)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment