1package main
2
3import (
4	"fmt"
5	"math/rand"
6	"os"
7	"time"
8
9	"github.com/pion/webrtc/v2"
10	"github.com/pion/webrtc/v2/pkg/media"
11	"github.com/pion/webrtc/v2/pkg/media/ivfreader"
12
13	"github.com/pion/webrtc/v2/examples/internal/signal"
14)
15
16func main() {
17	// Wait for the offer to be pasted
18	offer := webrtc.SessionDescription{}
19	signal.Decode(signal.MustReadStdin(), &offer)
20
21	// We make our own mediaEngine so we can place the sender's codecs in it.  This because we must use the
22	// dynamic media type from the sender in our answer. This is not required if we are the offerer
23	mediaEngine := webrtc.MediaEngine{}
24	err := mediaEngine.PopulateFromSDP(offer)
25	if err != nil {
26		panic(err)
27	}
28
29	// Search for VP8 Payload type. If the offer doesn't support VP8 exit since
30	// since they won't be able to decode anything we send them
31	var payloadType uint8
32	for _, videoCodec := range mediaEngine.GetCodecsByKind(webrtc.RTPCodecTypeVideo) {
33		if videoCodec.Name == "VP8" {
34			payloadType = videoCodec.PayloadType
35			break
36		}
37	}
38	if payloadType == 0 {
39		panic("Remote peer does not support VP8")
40	}
41
42	// Create a new RTCPeerConnection
43	api := webrtc.NewAPI(webrtc.WithMediaEngine(mediaEngine))
44	peerConnection, err := api.NewPeerConnection(webrtc.Configuration{
45		ICEServers: []webrtc.ICEServer{
46			{
47				URLs: []string{"stun:stun.l.google.com:19302"},
48			},
49		},
50	})
51	if err != nil {
52		panic(err)
53	}
54
55	// Create a video track
56	videoTrack, err := peerConnection.NewTrack(payloadType, rand.Uint32(), "video", "pion")
57	if err != nil {
58		panic(err)
59	}
60	if _, err = peerConnection.AddTrack(videoTrack); err != nil {
61		panic(err)
62	}
63
64	go func() {
65		// Open a IVF file and start reading using our IVFReader
66		file, ivfErr := os.Open("output.ivf")
67		if ivfErr != nil {
68			panic(ivfErr)
69		}
70
71		ivf, header, ivfErr := ivfreader.NewWith(file)
72		if ivfErr != nil {
73			panic(ivfErr)
74		}
75
76		// Send our video file frame at a time. Pace our sending so we send it at the same speed it should be played back as.
77		// This isn't required since the video is timestamped, but we will such much higher loss if we send all at once.
78		sleepTime := time.Millisecond * time.Duration((float32(header.TimebaseNumerator)/float32(header.TimebaseDenominator))*1000)
79		for {
80			frame, _, ivfErr := ivf.ParseNextFrame()
81			if ivfErr != nil {
82				panic(ivfErr)
83			}
84
85			time.Sleep(sleepTime)
86			if ivfErr = videoTrack.WriteSample(media.Sample{Data: frame, Samples: 90000}); ivfErr != nil {
87				panic(ivfErr)
88			}
89		}
90	}()
91
92	// Set the handler for ICE connection state
93	// This will notify you when the peer has connected/disconnected
94	peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
95		fmt.Printf("Connection State has changed %s \n", connectionState.String())
96	})
97
98	// Set the remote SessionDescription
99	if err = peerConnection.SetRemoteDescription(offer); err != nil {
100		panic(err)
101	}
102
103	// Create answer
104	answer, err := peerConnection.CreateAnswer(nil)
105	if err != nil {
106		panic(err)
107	}
108
109	// Sets the LocalDescription, and starts our UDP listeners
110	if err = peerConnection.SetLocalDescription(answer); err != nil {
111		panic(err)
112	}
113
114	// Output the answer in base64 so we can paste it in browser
115	fmt.Println(signal.Encode(answer))
116
117	// Block forever
118	select {}
119}
120