Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add examples/stats #2463

Merged
merged 1 commit into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions examples/stats/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# stats
stats demonstrates how to use the [webrtc-stats](https://www.w3.org/TR/webrtc-stats/) implementation provided by Pion WebRTC.

This API gives you access to the statistical information about a PeerConnection. This can help you understand what is happening
during a session and why.

## Instructions
### Download stats
```
export GO111MODULE=on
go get github.com/pion/webrtc/v3/examples/stats
```

### Open stats example page
[jsfiddle.net](https://jsfiddle.net/s179hacu/) you should see your Webcam, two text-areas and two buttons: `Copy browser SDP to clipboard`, `Start Session`.

### Run stats, with your browsers SessionDescription as stdin
In the jsfiddle the top textarea is your browser's Session Description. Press `Copy browser SDP to clipboard` or copy the base64 string manually.
We will use this value in the next step.

#### Linux/macOS
Run `echo $BROWSER_SDP | stats`
#### Windows
1. Paste the SessionDescription into a file.
1. Run `stats < my_file`

### Input stats' SessionDescription into your browser
Copy the text that `stats` just emitted and copy into second text area

### Hit 'Start Session' in jsfiddle
The `stats` program will now print the InboundRTPStreamStats for each incoming stream. You will see the following in
your console. The exact fields will change as we add more values.

```
Stats for: video/VP8
InboundRTPStreamStats:
PacketsReceived: 1255
PacketsLost: 0
Jitter: 588.9559641717999
LastPacketReceivedTimestamp: 2023-04-26 13:16:16.63591134 -0400 EDT m=+18.317378921
HeaderBytesReceived: 25100
BytesReceived: 1361125
FIRCount: 0
PLICount: 0
NACKCount: 0
```

Congrats, you have used Pion WebRTC! Now start building something cool
141 changes: 141 additions & 0 deletions examples/stats/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
//go:build !js
// +build !js

// stats demonstrates how to use the webrtc-stats implementation provided by Pion WebRTC.
package main

import (
"fmt"
"time"

"github.com/pion/interceptor"
"github.com/pion/interceptor/pkg/stats"
"github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal"
)

// nolint:gocognit
func main() {
// Everything below is the Pion WebRTC API! Thanks for using it ❤️.

// Create a MediaEngine object to configure the supported codec
m := &webrtc.MediaEngine{}

if err := m.RegisterDefaultCodecs(); err != nil {
panic(err)
}

// Create a InterceptorRegistry. This is the user configurable RTP/RTCP Pipeline.
// This provides NACKs, RTCP Reports and other features. If you use `webrtc.NewPeerConnection`
// this is enabled by default. If you are manually managing You MUST create a InterceptorRegistry
// for each PeerConnection.
i := &interceptor.Registry{}

statsInterceptorFactory, err := stats.NewInterceptor()
if err != nil {
panic(err)
}

var statsGetter stats.Getter
statsInterceptorFactory.OnNewPeerConnection(func(_ string, g stats.Getter) {
statsGetter = g
})
i.Add(statsInterceptorFactory)

// Use the default set of Interceptors
if err = webrtc.RegisterDefaultInterceptors(m, i); err != nil {
panic(err)
}

// Create the API object with the MediaEngine
api := webrtc.NewAPI(webrtc.WithMediaEngine(m), webrtc.WithInterceptorRegistry(i))

// Prepare the configuration
config := webrtc.Configuration{
ICEServers: []webrtc.ICEServer{
{
URLs: []string{"stun:stun.l.google.com:19302"},
},
},
}

// Create a new RTCPeerConnection
peerConnection, err := api.NewPeerConnection(config)
if err != nil {
panic(err)
}

// Allow us to receive 1 audio track, and 1 video track
if _, err = peerConnection.AddTransceiverFromKind(webrtc.RTPCodecTypeAudio); err != nil {
panic(err)
} else if _, err = peerConnection.AddTransceiverFromKind(webrtc.RTPCodecTypeVideo); err != nil {
panic(err)
}

// Set a handler for when a new remote track starts. We read the incoming packets, but then
// immediately discard them
peerConnection.OnTrack(func(track *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
fmt.Printf("New incoming track with codec: %s\n", track.Codec().MimeType)

go func() {
for {
stats := statsGetter.Get(uint32(track.SSRC()))

fmt.Printf("Stats for: %s\n", track.Codec().MimeType)
fmt.Println(stats.InboundRTPStreamStats)

time.Sleep(time.Second * 5)
}
}()

rtpBuff := make([]byte, 1500)
for {
_, _, readErr := track.Read(rtpBuff)
if readErr != nil {
panic(readErr)
}
}
})

// 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 answer
answer, err := peerConnection.CreateAnswer(nil)
if err != nil {
panic(err)
}

// Create channel that is blocked until ICE Gathering is complete
gatherComplete := webrtc.GatheringCompletePromise(peerConnection)

// Sets the LocalDescription, and starts our UDP listeners
err = peerConnection.SetLocalDescription(answer)
if err != nil {
panic(err)
}

// Block until ICE Gathering is complete, disabling trickle ICE
// we do this because we only can exchange one signaling message
// in a production application you should exchange ICE Candidates via OnICECandidate
<-gatherComplete

// Output the answer in base64 so we can paste it in browser
fmt.Println(signal.Encode(*peerConnection.LocalDescription()))

// Block forever
select {}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/pion/datachannel v1.5.5
github.com/pion/dtls/v2 v2.2.6
github.com/pion/ice/v2 v2.3.2
github.com/pion/interceptor v0.1.15
github.com/pion/interceptor v0.1.16
github.com/pion/logging v0.2.2
github.com/pion/randutil v0.1.0
github.com/pion/rtcp v1.2.10
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ github.com/pion/dtls/v2 v2.2.6 h1:yXMxKr0Skd+Ub6A8UqXTRLSywskx93ooMRHsQUtd+Z4=
github.com/pion/dtls/v2 v2.2.6/go.mod h1:t8fWJCIquY5rlQZwA2yWxUS1+OCrAdXrhVKXB5oD/wY=
github.com/pion/ice/v2 v2.3.2 h1:vh+fi4RkZ8H5fB4brZ/jm3j4BqFgMmNs+aB3X52Hu7M=
github.com/pion/ice/v2 v2.3.2/go.mod h1:AMIpuJqcpe+UwloocNebmTSWhCZM1TUCo9v7nW50jX0=
github.com/pion/interceptor v0.1.15 h1:vBjnKoSqcNYg2Xq3kz/2m7qp57c0yVH0n/2HJ2rP0hQ=
github.com/pion/interceptor v0.1.15/go.mod h1:SY8kpmfVBvrbUzvj2bsXz7OJt5JvmVNZ+4Kjq7FcwrI=
github.com/pion/interceptor v0.1.16 h1:0GDZrfNO+BmVNWymS31fMlVtPO2IJVBzy2Qq5XCYMIg=
github.com/pion/interceptor v0.1.16/go.mod h1:SY8kpmfVBvrbUzvj2bsXz7OJt5JvmVNZ+4Kjq7FcwrI=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/mdns v0.0.7 h1:P0UB4Sr6xDWEox0kTVxF0LmQihtCbSAdW0H2nEgkA3U=
Expand Down