Created
January 13, 2021 16:48
-
-
Save Sean-Der/c9c3ba89bb475fc6ccfd9d676da54c1e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// +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