github.com/pion/webrtc/v4@v4.0.1/examples/rtcp-processing/main.go (about) 1 // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly> 2 // SPDX-License-Identifier: MIT 3 4 //go:build !js 5 // +build !js 6 7 // rtcp-processing demonstrates the Public API for processing RTCP packets in Pion WebRTC. 8 package main 9 10 import ( 11 "bufio" 12 "encoding/base64" 13 "encoding/json" 14 "errors" 15 "fmt" 16 "io" 17 "os" 18 "strings" 19 20 "github.com/pion/webrtc/v4" 21 ) 22 23 func main() { 24 // Everything below is the Pion WebRTC API! Thanks for using it ❤️. 25 26 // Prepare the configuration 27 config := webrtc.Configuration{ 28 ICEServers: []webrtc.ICEServer{ 29 { 30 URLs: []string{"stun:stun.l.google.com:19302"}, 31 }, 32 }, 33 } 34 35 // Create a new RTCPeerConnection 36 peerConnection, err := webrtc.NewPeerConnection(config) 37 if err != nil { 38 panic(err) 39 } 40 41 // Set a handler for when a new remote track starts 42 peerConnection.OnTrack(func(track *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) { 43 fmt.Printf("Track has started streamId(%s) id(%s) rid(%s) \n", track.StreamID(), track.ID(), track.RID()) 44 45 for { 46 // Read the RTCP packets as they become available for our new remote track 47 rtcpPackets, _, rtcpErr := receiver.ReadRTCP() 48 if rtcpErr != nil { 49 panic(rtcpErr) 50 } 51 52 for _, r := range rtcpPackets { 53 // Print a string description of the packets 54 if stringer, canString := r.(fmt.Stringer); canString { 55 fmt.Printf("Received RTCP Packet: %v", stringer.String()) 56 } 57 } 58 } 59 }) 60 61 // Set the handler for ICE connection state 62 // This will notify you when the peer has connected/disconnected 63 peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { 64 fmt.Printf("Connection State has changed %s \n", connectionState.String()) 65 }) 66 67 // Wait for the offer to be pasted 68 offer := webrtc.SessionDescription{} 69 decode(readUntilNewline(), &offer) 70 71 // Set the remote SessionDescription 72 err = peerConnection.SetRemoteDescription(offer) 73 if err != nil { 74 panic(err) 75 } 76 77 // Create answer 78 answer, err := peerConnection.CreateAnswer(nil) 79 if err != nil { 80 panic(err) 81 } 82 83 // Create channel that is blocked until ICE Gathering is complete 84 gatherComplete := webrtc.GatheringCompletePromise(peerConnection) 85 86 // Sets the LocalDescription, and starts our UDP listeners 87 err = peerConnection.SetLocalDescription(answer) 88 if err != nil { 89 panic(err) 90 } 91 92 // Block until ICE Gathering is complete, disabling trickle ICE 93 // we do this because we only can exchange one signaling message 94 // in a production application you should exchange ICE Candidates via OnICECandidate 95 <-gatherComplete 96 97 // Output the answer in base64 so we can paste it in browser 98 fmt.Println(encode(peerConnection.LocalDescription())) 99 100 // Block forever 101 select {} 102 } 103 104 // Read from stdin until we get a newline 105 func readUntilNewline() (in string) { 106 var err error 107 108 r := bufio.NewReader(os.Stdin) 109 for { 110 in, err = r.ReadString('\n') 111 if err != nil && !errors.Is(err, io.EOF) { 112 panic(err) 113 } 114 115 if in = strings.TrimSpace(in); len(in) > 0 { 116 break 117 } 118 } 119 120 fmt.Println("") 121 return 122 } 123 124 // JSON encode + base64 a SessionDescription 125 func encode(obj *webrtc.SessionDescription) string { 126 b, err := json.Marshal(obj) 127 if err != nil { 128 panic(err) 129 } 130 131 return base64.StdEncoding.EncodeToString(b) 132 } 133 134 // Decode a base64 and unmarshal JSON into a SessionDescription 135 func decode(in string, obj *webrtc.SessionDescription) { 136 b, err := base64.StdEncoding.DecodeString(in) 137 if err != nil { 138 panic(err) 139 } 140 141 if err = json.Unmarshal(b, obj); err != nil { 142 panic(err) 143 } 144 }