Monitor connection quality, candidate pairs, and network metrics with comprehensive statistics APIs
Pion ICE provides detailed statistics for monitoring connection quality, analyzing candidate pair performance, and debugging network issues. Statistics are accessible through thread-safe APIs that return snapshots of current metrics.
The primary statistics interface provides detailed metrics for candidate pairs:
stats.go
type CandidatePairStats struct { // Timestamp is the timestamp associated with this object. Timestamp time.Time // LocalCandidateID is the ID of the local candidate LocalCandidateID string // RemoteCandidateID is the ID of the remote candidate RemoteCandidateID string // State represents the state of the checklist for the local and remote // candidates in a pair. State CandidatePairState // Nominated is true when this valid pair that should be used for media // if it is the highest-priority one amongst those whose nominated flag is set Nominated bool // PacketsSent represents the total number of packets sent on this candidate pair. PacketsSent uint32 // PacketsReceived represents the total number of packets received on this candidate pair. PacketsReceived uint32 // BytesSent represents the total number of payload bytes sent on this candidate pair // not including headers or padding. BytesSent uint64 // BytesReceived represents the total number of payload bytes received on this candidate pair // not including headers or padding. BytesReceived uint64 // LastPacketSentTimestamp represents the timestamp at which the last packet was // sent on this particular candidate pair, excluding STUN packets. LastPacketSentTimestamp time.Time // LastPacketReceivedTimestamp represents the timestamp at which the last packet // was received on this particular candidate pair, excluding STUN packets. LastPacketReceivedTimestamp time.Time // TotalRoundTripTime represents the sum of all round trip time measurements // in seconds since the beginning of the session, based on STUN connectivity // check responses. TotalRoundTripTime float64 // CurrentRoundTripTime represents the latest round trip time measured in seconds, // computed from both STUN connectivity checks, including those that are sent // for consent verification. CurrentRoundTripTime float64 // RequestsReceived represents the total number of connectivity check requests // received (including retransmissions). RequestsReceived uint64 // RequestsSent represents the total number of connectivity check requests // sent (not including retransmissions). RequestsSent uint64 // ResponsesReceived represents the total number of connectivity check responses received. ResponsesReceived uint64 // ResponsesSent represents the total number of connectivity check responses sent. ResponsesSent uint64}
Get information about individual local or remote candidates:
stats.go
type CandidateStats struct { // Timestamp is the timestamp associated with this object. Timestamp time.Time // ID is the candidate ID ID string // NetworkType represents the type of network interface used by the base of a // local candidate. NetworkType NetworkType // IP is the IP address of the candidate IP string // Port is the port number of the candidate. Port int // CandidateType is the "Type" field of the ICECandidate. CandidateType CandidateType // Priority is the "Priority" field of the ICECandidate. Priority uint32 // URL is the URL of the TURN or STUN server indicated in the that translated // this IP address. URL string // RelayProtocol is the protocol used by the endpoint to communicate with the // TURN server. Valid values: UDP, TCP, or TLS. RelayProtocol string // Deleted is true if the candidate has been deleted/freed. Deleted bool}
func checkConnectionActivity(agent *ice.Agent, timeout time.Duration) bool { stats, ok := agent.GetSelectedCandidatePairStats() if !ok { return false } // Check when we last received data lastActivity := stats.LastPacketReceivedTimestamp if lastActivity.IsZero() { lastActivity = stats.LastPacketSentTimestamp } if time.Since(lastActivity) > timeout { fmt.Println("Connection appears idle") return false } return true}// Usageif !checkConnectionActivity(agent, 30*time.Second) { // Connection has been idle for 30+ seconds // Consider reconnecting or alerting}
All statistics methods are thread-safe. They use the agent’s internal event loop to safely access state, so you can call them from any goroutine without additional synchronization.
agent_stats.go
func (a *Agent) GetCandidatePairsStats() []CandidatePairStats { var res []CandidatePairStats err := a.loop.Run(a.loop, func(_ context.Context) { // Safely access agent state within event loop result := make([]CandidatePairStats, 0, len(a.checklist)) for _, cp := range a.checklist { // Collect statistics } res = result }) // ...}