Files
webrtc/examples/gstreamer-receive/main.go
Sean DuBois 1202dbaa06 Migrate SDP generation to Unified Plan
This commit has breaking changes. This API change means we
can no longer support an arbitrary number of receivers. For every track
you want to receive you MUST call PeerConnection.AddTransceiver

We do now support sending an multiple audio/video feeds. You can see
this behavior via gstreamer-receive and gstreamer-send currently.

Resolves #54
2019-04-04 12:55:36 -07:00

121 lines
3.4 KiB
Go

package main
import (
"fmt"
"runtime"
"time"
"github.com/pions/rtcp"
"github.com/pions/webrtc"
gst "github.com/pions/webrtc/examples/internal/gstreamer-sink"
"github.com/pions/webrtc/examples/internal/signal"
)
// gstreamerReceiveMain is launched in a goroutine because the main thread is needed
// for Glib's main loop (Gstreamer uses Glib)
func gstreamerReceiveMain() {
// Everything below is the pion-WebRTC API! Thanks for using it ❤️.
// Prepare the configuration
config := webrtc.Configuration{
ICEServers: []webrtc.ICEServer{
{
URLs: []string{"stun:stun.l.google.com:19302"},
},
},
}
// Create a new RTCPeerConnection
peerConnection, err := webrtc.NewPeerConnection(config)
if err != nil {
panic(err)
}
// Allow us to receive 1 audio track, and 2 video tracks
if _, err = peerConnection.AddTransceiver(webrtc.RTPCodecTypeAudio); err != nil {
panic(err)
} else if _, err = peerConnection.AddTransceiver(webrtc.RTPCodecTypeVideo); err != nil {
panic(err)
} else if _, err = peerConnection.AddTransceiver(webrtc.RTPCodecTypeVideo); err != nil {
panic(err)
}
// Set a handler for when a new remote track starts, this handler creates a gstreamer pipeline
// for the given codec
peerConnection.OnTrack(func(track *webrtc.Track, receiver *webrtc.RTPReceiver) {
// Send a PLI on an interval so that the publisher is pushing a keyframe every rtcpPLIInterval
// This is a temporary fix until we implement incoming RTCP events, then we would push a PLI only when a viewer requests it
go func() {
ticker := time.NewTicker(time.Second * 3)
for range ticker.C {
rtcpSendErr := peerConnection.WriteRTCP(&rtcp.PictureLossIndication{MediaSSRC: track.SSRC()})
if rtcpSendErr != nil {
fmt.Println(rtcpSendErr)
}
}
}()
codec := track.Codec()
fmt.Printf("Track has started, of type %d: %s \n", track.PayloadType(), codec.Name)
pipeline := gst.CreatePipeline(codec.Name)
pipeline.Start()
buf := make([]byte, 1400)
for {
i, readErr := track.Read(buf)
if readErr != nil {
panic(err)
}
pipeline.Push(buf[:i])
}
})
// 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
err = peerConnection.SetRemoteDescription(offer)
if err != nil {
panic(err)
}
// Create an 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)
}
// Output the answer in base64 so we can paste it in browser
fmt.Println(signal.Encode(answer))
// Block forever
select {}
}
func init() {
// This example uses Gstreamer's autovideosink element to display the received video
// This element, along with some others, sometimes require that the process' main thread is used
runtime.LockOSThread()
}
func main() {
// Start a new thread to do the actual work for this application
go gstreamerReceiveMain()
// Use this goroutine (which has been runtime.LockOSThread'd to he the main thread) to run the Glib loop that Gstreamer requires
gst.StartMainLoop()
}