Игорь Шеко
Lead of Front-end team
Ирина Ламарр
Senior SDK developer
Input devices
(camera, microphone)
Output devices
(screen, speaker)
Sender device
Web browser
Receiver device
Web browser
Network interface controller
Network interface controller
Packets
Packets
Encoder
Decoder
Echo canceller
Noise reduction
Image enhancements
Packetizer
Depacketizer
Jitter buffer
Frames samples
Packets
Raw
signal
Raw
signal
https://www.w3.org/TR/webrtc-stats
https://wpt.fyi/results/webrtc-stats
function calculateBitrate(
bytesNow: number,
bytesBefore: number,
timestampNow: number,
timestampBefore: number
): number {
const deltaBytes = bytesSentNow - bytesSentBefore;
const deltaMs = timestampNow - timestampBefore;
return (deltaBytes / deltaMs) * 8000;
}
Oпределяет размер и качество видео- и аудиофайлов: чем выше битрейт, тем лучше качество и больше размер файла.
Размер файла = битрейт (кбит/с) x продолжительность.
I-frame
P-frame
B-frame
I-frame
P-frame
I-frame
//we can't use user-agent because
// 1. browsers often improve API,
// 2. user-agent is legacy
function detectStrategy(statsSample: RTCStatsReport): StatsStrategy {
//Browsers will check by global usage
// strategy for a chromium-based browsers
if (checkBlink(statsSample, IS_DEBUG)) {
return blinkStatsStrategy;
}
// strategy for a webkit-based browsers
if (checkWebkit(statsSample, IS_DEBUG)) {
return webkitStatsStrategy;
}
// strategy for a firefox-based browsers
if (checkGecko(statsSample, IS_DEBUG)) {
return geckoStatsStrategy;
}
// fallback rfc-like strategy
return baseStatsStrategy;
}
Default interval time | 1000 ms |
> 16ms |
2000 ms |
> 32ms |
3000 ms |
> 48ms |
4000 ms |
// This will only working in the Chrome. For other browsers we can't get battery.
//@ts-ignore because it is deprecated API
try {
const batteryFunction = navigator['getBattery'];
if (batteryFunction) {
const batteryInfo = await batteryFunction();
if (!batteryInfo.charging) {
if (batteryInfo.level && batteryInfo.level <= 0.3)
return LOW_BATTERY_COLLECT_INTERVAL;
return BATTERY_COLLECT_INTERVAL;
}
}
} catch (e){}
не ориентироваться на стандарт
описано много, в реальности работает мало что из этого или написано что-то похожее, но свое
собирать динамически и адаптивно
не все браузеры охотно сообщают, что они там поменяли
возможно придется самостоятельно пересчитывать какие-то метрики, если они вам нужны
не забывать про слабые девайсы и мобильники - слишком частый запрос статистики ведет к плохому UХ
Сбор статистики для решения конкретных инцидентов
Мониторинг инцидентов при обновлениях сервиса
Мониторинг инцидентов при обновлении браузеров
Определение качества работы сети
Помощь в разработке
Красивые графики
Простые флаги и healthcheck
Подсветка типичных проблем и советы по решению
Законно
White label
GW
ClickHouse
GW
ClickHouse
0.8 Gbps
1.1 TB / day
1.1 TB / day
Callstats.io
TestRTC
не расширяется
написаны под конкретные кейсы
писали не мы
Частота сбора: 1 сек
Средний объем конференции: 10 человек
Конференций на инстанс: 300
Хотим хранить: 30 дней
~168 Kbps
~1680 Kbps
~ 165 Mbps
~ 5.06 TB
Уменьшаем json
Меняем формат
Переход к дельтам
Два типа кадров
{
id: 'RTCInboundRTPVideoStream_1635808784',
timestamp: 1628606438021.0002,
type: 'inbound-rtp',
codecId: 'RTCCodec_v4_Inbound_104',
kind: 'video',
mediaType: 'video',
ssrc: 1635808784,
transportId: 'RTCTransport_0_1',
packetsLost: 49,
packetsReceived: 5198,
bytesReceived: 5720775,
estimatedPlayoutTimestamp: 3837595237710,
firCount: 0,
frameHeight: 180,
frameWidth: 320,
framesDecoded: 516,
framesPerSecond: 17,
framesReceived: 518,
headerBytesReceived: 240747,
keyFramesDecoded: 38,
lastPacketReceivedTimestamp: 46062.656,
nackCount: 43,
pliCount: 3,
qpSum: 9966,
totalDecodeTime: 1.038,
totalInterFrameDelay: 60.22499999999982,
totalSquaredInterFrameDelay: 57.38087100000012,
trackId: 'RTCMediaStreamTrack_receiver_11',
},
{
timestamp: 1628606438021.0002,
type: 'inbound-rtp',
mediaType: 'video',
ssrc: 1635808784,
packetsLost: 49,
packetsReceived: 5198,
bytesReceived: 5720775,
estimatedPlayoutTimestamp: 3837595237710,
firCount: 0,
frameHeight: 180,
frameWidth: 320,
framesDecoded: 516,
framesPerSecond: 17,
framesReceived: 518,
headerBytesReceived: 240747,
keyFramesDecoded: 38,
lastPacketReceivedTimestamp: 46062.656,
nackCount: 43,
pliCount: 3,
qpSum: 9966,
totalDecodeTime: 1.038,
totalInterFrameDelay: 60.22499999999982,
totalSquaredInterFrameDelay: 57.38087100000012,
},
[
1628606438021.0002,
"inbound-rtp",
"video",
1635808784,
49,
5198,
5720775,
3837595237710,
0,
180,
320,
516,
17,
518,
240747,
38,
46062.656,
43,
3,
9966,
1.038,
60.22499999999982,
57.38087100000012,
],
{
timestamp: 1628606438021.0002,
type: 'inbound-rtp',
mediaType: 'video',
ssrc: 1635808784,
packetsLost: 49,
packetsReceived: 5198,
bytesReceived: 5720775,
estimatedPlayoutTimestamp: 3837595237710,
firCount: 0,
frameHeight: 180,
frameWidth: 320,
framesDecoded: 516,
framesPerSecond: 17,
framesReceived: 518,
headerBytesReceived: 240747,
keyFramesDecoded: 38,
lastPacketReceivedTimestamp: 46062.656,
nackCount: 43,
pliCount: 3,
qpSum: 9966,
totalDecodeTime: 1.038,
totalInterFrameDelay: 60.22499999999982,
totalSquaredInterFrameDelay: 57.38087100000012,
},
{
type: 'inbound-rtp',
mediaType: 'video',
ssrc: 1635808784,
framesPerSecond: 17,
delta:[
[
timestamp: 1628606438021.0002,
packetsReceived: 5198,
bytesReceived: 5720775,
estimatedPlayoutTimestamp: 3837595237710,
framesDecoded: 516,
framesReceived: 518,
headerBytesReceived: 240747,
lastPacketReceivedTimestamp: 46062.656,
qpSum: 9966,
totalDecodeTime: 1.038,
totalInterFrameDelay: 60.22499999999982,
totalSquaredInterFrameDelay: 57.38087100000012,
keyFramesDecoded: 38,
],[
packetsLost: 49,
nackCount: 43,
pliCount: 3,
frameHeight: 180,
frameWidth: 320,
firCount: 0,
]
],
},
[
'inbound-rtp',
'video',
1635808784,
17,
[
[
1628606438021.0002,
5198,
5720775,
3837595237710,
516,
518,
240747,
46062.656,
9966,
1.038,
60.22499999999982,
57.38087100000012,
38,
],[
49,
43,
3,
180,
320,
0,
]
],
},
[
'inbound-rtp',
'video',
1635808784,
17,
[
[
1021.0001,
5198,
775,
710,
17,
17,
1747,
62.256,
367,
0.316,
1.22499999999982,
2.38087100000012,
0,
],[
1,
2,
0,
0,
0,
0,
]
],
},
[
'inbound-rtp',
'video',
1635808784,
17,
[
[
1021.0001,
5198,
775,
710,
17,
17,
1747,
62.256,
367,
0.316,
1.22499999999982,
2.38087100000012,
],[
1,
2,
]
],
},
[
'inbound-rtp','video',1635808784,17,
[[1021.0001,5198,775,710,17,17,1747,62.256,367,0.316,1.22499999999982,2.38087100000012],[1,2]]
],
{
id: 'RTCInboundRTPVideoStream_1635808784',
timestamp: 1628606438021.0002,
type: 'inbound-rtp',
codecId: 'RTCCodec_v4_Inbound_104',
kind: 'video',
mediaType: 'video',
ssrc: 1635808784,
transportId: 'RTCTransport_0_1',
packetsLost: 49,
packetsReceived: 5198,
bytesReceived: 5720775,
estimatedPlayoutTimestamp: 3837595237710,
firCount: 0,
frameHeight: 180,
frameWidth: 320,
framesDecoded: 516,
framesPerSecond: 17,
framesReceived: 518,
headerBytesReceived: 240747,
keyFramesDecoded: 38,
lastPacketReceivedTimestamp: 46062.656,
nackCount: 43,
pliCount: 3,
qpSum: 9966,
totalDecodeTime: 1.038,
totalInterFrameDelay: 60.22499999999982,
totalSquaredInterFrameDelay: 57.38087100000012,
trackId: 'RTCMediaStreamTrack_receiver_11',
},
Частота сбора: 1 сек
Средний объем конференции: 10 человек
Конференций на инстанс: 100
Хотим хранить: 30 дней
~2 Kbps
~20 Kbps
~1.95 Mbps
~ 0.6 TB
~168 Kbps
~1680 Kbps
~ 165 Mbps
~ 5.06 TB
Data channel
fetch
WebSocket
Beaсon API
GW
ClickHouse
GW
ClickHouse
GW
GW
k8s
Потоковый анализ
Анализ клиента
Анализ сессии
GW
ClickHouse
GW
GW
k8s
SA
SA
SA
SA
GW
ClickHouse
GW
GW
k8s
SA
SA
SA
SA
CA
GW
ClickHouse
GW
GW
k8s
SA
SA
SA
SA
CA
GA