package protocol // Quality and problem reports (spec §15.26, 2026-10-03): the wire shape a // client POSTs, client-neutral like the rest of this package. // // A quality report is a fixed schema of numbers and enums about how this // client's connections went over the last window: no names, no addresses, // no device names, no meeting, nothing typed by a person. Every number is // optional (absent means "this client could not measure it"), finite and // non-negative, and has a ceiling the server enforces; every string is an // enum or a version. Counts are what happened during the window (a delta), // not running totals. The server re-encodes what it validated and drops // anything it does not know, so a member a newer client adds is tolerated // and never logged. // QualityVersion is the schema's version, the report's "v". const QualityVersion = 1 // Bounds the server enforces, here so a client can clamp to the same ones. const ( MaxQualityPeers = 4 // remote peers in one report: the mesh holds three, and one spare for a connection on its way out MaxQualitySeconds = 600 // a window, in seconds MaxQualityMillis = 600_000 // any rtt, jitter or buffer delay, in ms MaxQualityCount = 1e9 // any count of packets, frames or samples MaxQualityKbps = 1e6 // any bitrate, in kbit/s MaxQualityPixels = 16384 // a frame's width or height MaxQualityFPS = 240 // frames per second MaxQualityBody = 16 << 10 MaxProblemNote = 1000 // characters of "What went wrong?" MaxProblemBody = 64 << 10 // the whole problem report, diagnostics included ) // QualityReport is one window's summary. type QualityReport struct { V int `json:"v"` Final bool `json:"final,omitempty"` // the report sent at leave or end Seconds *float64 `json:"seconds"` // how long the window was Client ReportClient `json:"client"` Devices *Devices `json:"devices,omitempty"` Events *CallEvents `json:"events,omitempty"` Peers []PeerQuality `json:"peers,omitempty"` } // ReportClient says what is reporting. Enums, and versions as digits and // dots: never a user agent string, a device model or a machine name. type ReportClient struct { App string `json:"app"` // web, mac, iphone, ipad Version string `json:"version,omitempty"` // the app's version, or the server's build for web Browser string `json:"browser,omitempty"` // chrome, safari, firefox, edge, other (web only) BrowserVersion string `json:"browserVersion,omitempty"` // major[.minor] OS string `json:"os,omitempty"` // macos, ios, ipados, windows, linux, android, chromeos, other OSVersion string `json:"osVersion,omitempty"` } // Devices are the kinds of microphone and speaker in use, by transport: // never a device's name, which can be personal ("Paul's AirPods Pro"). type Devices struct { Input string `json:"input,omitempty"` // DeviceKinds Output string `json:"output,omitempty"` // DeviceKinds } // DeviceKinds are the values Devices may carry. var DeviceKinds = []string{"built-in", "bluetooth", "usb", "wired", "airplay", "virtual", "continuity", "other", "none", "unknown"} // CallEvents are the notices this client showed for the whole call during // the window (§15.23), and whether its browser blocked playing sound // (§15.20). type CallEvents struct { Reconnecting *float64 `json:"reconnecting,omitempty"` // times "Reconnecting…" was shown ReconnectingSeconds *float64 `json:"reconnectingSeconds,omitempty"` // for how long AudioBlocked bool `json:"audioBlocked,omitempty"` } // PeerQuality is one remote peer's connection, from this side. type PeerQuality struct { // Peer is the remote peer's id as this client knows it. The server // logs the peer's tag in its place and never the id. Peer PeerID `json:"peer"` Path *Path `json:"path,omitempty"` RTT *float64 `json:"rtt,omitempty"` // the selected candidate pair's, ms Out *Outbound `json:"out,omitempty"` In *Inbound `json:"in,omitempty"` Events *PeerEvents `json:"events,omitempty"` } // Path is the selected candidate pair: what kind of candidate each end // used, and the transport. Never an address or a port. type Path struct { Local string `json:"local,omitempty"` // CandidateKinds Remote string `json:"remote,omitempty"` // CandidateKinds Protocol string `json:"protocol,omitempty"` // udp, tcp, tls, unknown } // CandidateKinds are the values Path.Local and Path.Remote may carry. var CandidateKinds = []string{"host", "srflx", "prflx", "relay", "unknown"} // PathProtocols are the values Path.Protocol may carry. "tls" is a relay // reached over TURN/TLS. var PathProtocols = []string{"udp", "tcp", "tls", "unknown"} // Outbound is what this client sends to the peer. type Outbound struct { Audio *OutStream `json:"audio,omitempty"` Video *OutStream `json:"video,omitempty"` Screen *OutStream `json:"screen,omitempty"` } // OutStream is one outbound stream. Lost, RTT and Jitter are the // receiver's own account (remote-inbound-rtp). type OutStream struct { Kbps *float64 `json:"kbps,omitempty"` Packets *float64 `json:"packets,omitempty"` Lost *float64 `json:"lost,omitempty"` RTT *float64 `json:"rtt,omitempty"` Jitter *float64 `json:"jitter,omitempty"` Limit string `json:"limit,omitempty"` // QualityLimits Width *float64 `json:"width,omitempty"` Height *float64 `json:"height,omitempty"` FPS *float64 `json:"fps,omitempty"` // The screen-share recovery ladder's steps toward this peer during // the window (§15.22): keyframes sent, rebuilds, shares again, and // times it gave up. Keyframes *float64 `json:"keyframes,omitempty"` Rebuilds *float64 `json:"rebuilds,omitempty"` Reshares *float64 `json:"reshares,omitempty"` Failures *float64 `json:"failures,omitempty"` } // QualityLimits are qualityLimitationReason's values. var QualityLimits = []string{"none", "cpu", "bandwidth", "other"} // Inbound is what arrives from the peer. type Inbound struct { Audio *InAudio `json:"audio,omitempty"` Video *InVideo `json:"video,omitempty"` Screen *InVideo `json:"screen,omitempty"` } // InAudio is the peer's audio as it arrives here. type InAudio struct { Kbps *float64 `json:"kbps,omitempty"` Packets *float64 `json:"packets,omitempty"` Lost *float64 `json:"lost,omitempty"` Jitter *float64 `json:"jitter,omitempty"` // ms Samples *float64 `json:"samples,omitempty"` // totalSamplesReceived Concealed *float64 `json:"concealed,omitempty"` // concealedSamples Inserted *float64 `json:"inserted,omitempty"` // insertedSamplesForDeceleration Removed *float64 `json:"removed,omitempty"` // removedSamplesForAcceleration JitterBufferMs *float64 `json:"jitterBufferMs,omitempty"` // mean jitterBufferDelay per emitted sample over the window } // InVideo is the peer's camera or screen as it arrives here. type InVideo struct { Kbps *float64 `json:"kbps,omitempty"` Packets *float64 `json:"packets,omitempty"` Lost *float64 `json:"lost,omitempty"` Jitter *float64 `json:"jitter,omitempty"` Freezes *float64 `json:"freezes,omitempty"` // freezeCount FreezeSeconds *float64 `json:"freezeSeconds,omitempty"` // totalFreezesDuration Decoded *float64 `json:"decoded,omitempty"` Dropped *float64 `json:"dropped,omitempty"` Width *float64 `json:"width,omitempty"` Height *float64 `json:"height,omitempty"` FPS *float64 `json:"fps,omitempty"` Reattaches *float64 `json:"reattaches,omitempty"` // a stalled screen handed to its view again (§15.22) } // PeerEvents are the notices about this peer during the window. type PeerEvents struct { Reconnecting *float64 `json:"reconnecting,omitempty"` // "Reconnecting to …" shown ReconnectingSeconds *float64 `json:"reconnectingSeconds,omitempty"` // for how long CantHearSeconds *float64 `json:"cantHearSeconds,omitempty"` // "… can't hear you yet" (§15.24) NoSound bool `json:"noSound,omitempty"` // this client listed them in noSoundFrom (§15.20) NoSoundFromUs bool `json:"noSoundFromUs,omitempty"` // they listed this client AudioBlocked bool `json:"audioBlocked,omitempty"` // they said their browser blocked sound ScreenStalled bool `json:"screenStalled,omitempty"` // this client reported their screen stalled (§15.21) } // ProblemReport is "Report a problem": what the person typed, and the // text "Copy call diagnostics" would copy, with the people in the call // named by short peer ids rather than their names. type ProblemReport struct { Note string `json:"note"` Diagnostics string `json:"diagnostics"` Client ReportClient `json:"client"` } // ProblemReceipt is the server's answer: the reference to quote. type ProblemReceipt struct { Ref string `json:"ref"` }