// src/services/voiceDiag/checks/wan/wanAppRtpLoss.js // // Per-application audio packet loss — measured on ACTUAL RTP voice // traffic via Prisma DPI. Metric name on the v2.6 monitor/metrics // endpoint is `AppPerfUDPAudioPacketLoss` (unit: percentage), takes // filter.direction="Ingress" AND filter.path_type=[all]. // // See wanAppRtpMos.js for the app-selection contract — the check is // app-agnostic; the tenant picks which voice app to grade via env. // // Grades against the WORST-window loss in the series. A 5-minute // burst of 20% loss makes calls unusable during that window even // if the 24h avg is 2% — always show the operator the worst-case // number so they know a bad experience is real, not aggregated away. // // Skipped when the voice-app env is not configured. import { maybeSkippedByKillSwitch, getAppAudio, evaluateAppAudioMetric, getAppLossWarnPct, getAppLossErrorPct, } from './_helpers.js'; export const WAN_APP_RTP_LOSS_STANDARDS = Object.freeze({ maxWarnPct: 5, maxErrorPct: 15, unit: '%', reference: 'ITU-T G.113 (voice loss tolerance)', gradeAgainst: 'worst-window', }); export const wanAppRtpLossCheck = { id: 'wanAppRtpLoss', label: 'SD-WAN Voice Traffic Packet Loss (worst window)', requires: ['sdwanSite'], scope: null, standards: WAN_APP_RTP_LOSS_STANDARDS, async run(ctx) { const skip = maybeSkippedByKillSwitch(wanAppRtpLossCheck); if (skip) return skip; const audio = getAppAudio(ctx, 'loss'); const warnThresh = getAppLossWarnPct(); const errorThresh = getAppLossErrorPct(); return evaluateAppAudioMetric({ audio, label: 'packet loss', unit: '%', warnThresh, errorThresh, lowIsBad: false, standardLabel: `warn > ${warnThresh}%, error > ${errorThresh}%`, }); }, };