WebRTC with Pion

For a project I’ve been using Pion WebRTC which is a Golang implementation of the WebRTC API.

It is easy to set up and provides great performance.

Some tips when using Pion WebRTC, or WebRTC in general:

  • Use multiple TURN/STUN servers. I’ve been using coturn and Twilio’s WebRTC servers.
  • Use Trickle ICE to speed up the initial connection
  • When using h264, use the h264reader to send NALs

Streaming with Pion WebRTC

Once you’ve done all the peer/ICE handling, you can send video/audio. Below is the piece of code I’ve been using to send a h264 stream through WebRTC:

		h264FrameDuration := time.Millisecond * 33 
		ticker := time.NewTicker(h264FrameDuration)
		for ; true; <-ticker.C {
			nal, h264Err := h264.NextNAL()
			if h264Err == io.EOF {
				fmt.Printf("All video frames parsed and sent")
			if h264Err != nil {

			if h264Err = videoTrack.WriteSample(media.Sample{Data: nal.Data, Duration: time.Second}); h264Err != nil {

Similar for audio, you can send incoming Opus packets like this:

audioTrack, audioTrackErr := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus}, "audio", "pion")

p := make([]byte, 960)

for {
	n, err := audioReader.Read(p)
	if err == io.EOF {
	if audioTrackErr = audioTrack.WriteSample(media.Sample{Data: p[:n], Duration: time.Millisecond * 20}); audioTrackErr != nil {

Signaling and WebRTC

A great way to do signaling is through Websockets. I can highly recommend using Gorilla WebSocket which provides a clean API to handle Websockets with Go.

Upon receiving an ICE candidate through a Websocket message, you can pass the candidate to Pion through a Go channel. The answer can be sent back, by sending a Websocket message back to the sender.