mirror of
https://github.com/pion/webrtc.git
synced 2025-11-03 09:40:59 +08:00
Use offerer PayloadType when generating answer. Before we would use the hardcoded values, this is invalid behavior and would cause browsers to just ignore our video when publishing.
153 lines
3.8 KiB
Go
153 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"time"
|
|
|
|
"github.com/pion/rtcp"
|
|
"github.com/pion/webrtc/v2"
|
|
|
|
"github.com/pion/webrtc/v2/examples/internal/signal"
|
|
)
|
|
|
|
const (
|
|
rtcpPLIInterval = time.Second * 3
|
|
)
|
|
|
|
func main() {
|
|
sdpChan := signal.HTTPSDPServer()
|
|
|
|
// Everything below is the Pion WebRTC API, thanks for using it ❤️.
|
|
offer := webrtc.SessionDescription{}
|
|
signal.Decode(<-sdpChan, &offer)
|
|
fmt.Println("")
|
|
|
|
// Since we are answering use PayloadTypes declared by offerer
|
|
mediaEngine := webrtc.MediaEngine{}
|
|
err := mediaEngine.PopulateFromSDP(offer)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Create the API object with the MediaEngine
|
|
api := webrtc.NewAPI(webrtc.WithMediaEngine(mediaEngine))
|
|
|
|
peerConnectionConfig := webrtc.Configuration{
|
|
ICEServers: []webrtc.ICEServer{
|
|
{
|
|
URLs: []string{"stun:stun.l.google.com:19302"},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Create a new RTCPeerConnection
|
|
peerConnection, err := api.NewPeerConnection(peerConnectionConfig)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Allow us to receive 1 video track
|
|
if _, err = peerConnection.AddTransceiver(webrtc.RTPCodecTypeVideo); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
localTrackChan := make(chan *webrtc.Track)
|
|
// Set a handler for when a new remote track starts, this just distributes all our packets
|
|
// to connected peers
|
|
peerConnection.OnTrack(func(remoteTrack *webrtc.Track, receiver *webrtc.RTPReceiver) {
|
|
// Send a PLI on an interval so that the publisher is pushing a keyframe every rtcpPLIInterval
|
|
// This can be less wasteful by processing incoming RTCP events, then we would emit a NACK/PLI when a viewer requests it
|
|
go func() {
|
|
ticker := time.NewTicker(rtcpPLIInterval)
|
|
for range ticker.C {
|
|
if rtcpSendErr := peerConnection.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: remoteTrack.SSRC()}}); rtcpSendErr != nil {
|
|
fmt.Println(rtcpSendErr)
|
|
}
|
|
}
|
|
}()
|
|
|
|
// Create a local track, all our SFU clients will be fed via this track
|
|
localTrack, newTrackErr := peerConnection.NewTrack(remoteTrack.PayloadType(), remoteTrack.SSRC(), "video", "pion")
|
|
if newTrackErr != nil {
|
|
panic(newTrackErr)
|
|
}
|
|
localTrackChan <- localTrack
|
|
|
|
rtpBuf := make([]byte, 1400)
|
|
for {
|
|
i, readErr := remoteTrack.Read(rtpBuf)
|
|
if readErr != nil {
|
|
panic(readErr)
|
|
}
|
|
|
|
// ErrClosedPipe means we don't have any subscribers, this is ok if no peers have connected yet
|
|
if _, err = localTrack.Write(rtpBuf[:i]); err != nil && err != io.ErrClosedPipe {
|
|
panic(err)
|
|
}
|
|
}
|
|
})
|
|
|
|
// Set the remote SessionDescription
|
|
err = peerConnection.SetRemoteDescription(offer)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Create answer
|
|
answer, err := peerConnection.CreateAnswer(nil)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Sets the LocalDescription, and starts our UDP listeners
|
|
err = peerConnection.SetLocalDescription(answer)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Get the LocalDescription and take it to base64 so we can paste in browser
|
|
fmt.Println(signal.Encode(answer))
|
|
|
|
localTrack := <-localTrackChan
|
|
for {
|
|
fmt.Println("")
|
|
fmt.Println("Curl an base64 SDP to start sendonly peer connection")
|
|
|
|
recvOnlyOffer := webrtc.SessionDescription{}
|
|
signal.Decode(<-sdpChan, &recvOnlyOffer)
|
|
|
|
// Create a new PeerConnection
|
|
peerConnection, err := api.NewPeerConnection(peerConnectionConfig)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
_, err = peerConnection.AddTrack(localTrack)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Set the remote SessionDescription
|
|
err = peerConnection.SetRemoteDescription(recvOnlyOffer)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Create answer
|
|
answer, err := peerConnection.CreateAnswer(nil)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Sets the LocalDescription, and starts our UDP listeners
|
|
err = peerConnection.SetLocalDescription(answer)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Get the LocalDescription and take it to base64 so we can paste in browser
|
|
fmt.Println(signal.Encode(answer))
|
|
}
|
|
}
|