mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
WebRTC latency in stats (#20)
* webrtc stats full report. * add ping+pong latency counter. * single console log. * remove report & add latency to webrtc stats. * fix.
This commit is contained in:
parent
69cb72c67f
commit
a22c48c4ca
@ -3,6 +3,8 @@ import { WebRTCStats, CursorPosition, CursorImage } from '../types/webrtc'
|
|||||||
import { Logger } from '../utils/logger'
|
import { Logger } from '../utils/logger'
|
||||||
import { videoSnap } from '../utils/video-snap'
|
import { videoSnap } from '../utils/video-snap'
|
||||||
|
|
||||||
|
const maxUint32 = 2 ** 32 - 1
|
||||||
|
|
||||||
export const OPCODE = {
|
export const OPCODE = {
|
||||||
MOVE: 0x01,
|
MOVE: 0x01,
|
||||||
SCROLL: 0x02,
|
SCROLL: 0x02,
|
||||||
@ -10,6 +12,7 @@ export const OPCODE = {
|
|||||||
KEY_UP: 0x04,
|
KEY_UP: 0x04,
|
||||||
BTN_DOWN: 0x05,
|
BTN_DOWN: 0x05,
|
||||||
BTN_UP: 0x06,
|
BTN_UP: 0x06,
|
||||||
|
PING: 0x07,
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
export interface ICEServer {
|
export interface ICEServer {
|
||||||
@ -44,6 +47,8 @@ export class NekoWebRTC extends EventEmitter<NekoWebRTCEvents> {
|
|||||||
private _connected = false
|
private _connected = false
|
||||||
private _candidates: RTCIceCandidateInit[] = []
|
private _candidates: RTCIceCandidateInit[] = []
|
||||||
private _statsStop?: () => void
|
private _statsStop?: () => void
|
||||||
|
private _requestLatency = 0
|
||||||
|
private _responseLatency = 0
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
constructor(
|
constructor(
|
||||||
@ -340,6 +345,7 @@ export class NekoWebRTC extends EventEmitter<NekoWebRTCEvents> {
|
|||||||
|
|
||||||
public send(event: 'wheel' | 'mousemove', data: { x: number; y: number }): void
|
public send(event: 'wheel' | 'mousemove', data: { x: number; y: number }): void
|
||||||
public send(event: 'mousedown' | 'mouseup' | 'keydown' | 'keyup', data: { key: number }): void
|
public send(event: 'mousedown' | 'mouseup' | 'keydown' | 'keyup', data: { key: number }): void
|
||||||
|
public send(event: 'ping', data: number): void
|
||||||
public send(event: string, data: any): void {
|
public send(event: string, data: any): void {
|
||||||
if (typeof this._channel === 'undefined' || this._channel.readyState !== 'open') {
|
if (typeof this._channel === 'undefined' || this._channel.readyState !== 'open') {
|
||||||
this._log.warn(`attempting to send data, but data-channel is not open`, { event })
|
this._log.warn(`attempting to send data, but data-channel is not open`, { event })
|
||||||
@ -393,6 +399,14 @@ export class NekoWebRTC extends EventEmitter<NekoWebRTCEvents> {
|
|||||||
payload.setUint16(1, 4)
|
payload.setUint16(1, 4)
|
||||||
payload.setUint32(3, data.key)
|
payload.setUint32(3, data.key)
|
||||||
break
|
break
|
||||||
|
case 'ping':
|
||||||
|
buffer = new ArrayBuffer(11)
|
||||||
|
payload = new DataView(buffer)
|
||||||
|
payload.setUint8(0, OPCODE.PING)
|
||||||
|
payload.setUint16(1, 8)
|
||||||
|
payload.setUint32(3, Math.trunc(data / maxUint32))
|
||||||
|
payload.setUint32(7, data % maxUint32)
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
this._log.warn(`unknown data event`, { event })
|
this._log.warn(`unknown data event`, { event })
|
||||||
return
|
return
|
||||||
@ -457,6 +471,18 @@ export class NekoWebRTC extends EventEmitter<NekoWebRTCEvents> {
|
|||||||
}
|
}
|
||||||
reader.readAsDataURL(blob)
|
reader.readAsDataURL(blob)
|
||||||
|
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
const nowTs = Date.now()
|
||||||
|
|
||||||
|
const [clientTs1, clientTs2] = [payload.getUint32(3), payload.getUint32(7)]
|
||||||
|
const clientTs = clientTs1 * maxUint32 + clientTs2
|
||||||
|
const [serverTs1, serverTs2] = [payload.getUint32(11), payload.getUint32(15)]
|
||||||
|
const serverTs = serverTs1 * maxUint32 + serverTs2
|
||||||
|
|
||||||
|
this._requestLatency = serverTs - clientTs
|
||||||
|
this._responseLatency = nowTs - serverTs
|
||||||
|
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
this._log.warn(`unhandled webrtc event`, { event, payload })
|
this._log.warn(`unhandled webrtc event`, { event, payload })
|
||||||
@ -534,6 +560,10 @@ export class NekoWebRTC extends EventEmitter<NekoWebRTCEvents> {
|
|||||||
width: report.frameWidth || NaN,
|
width: report.frameWidth || NaN,
|
||||||
height: report.frameHeight || NaN,
|
height: report.frameHeight || NaN,
|
||||||
muted: this._track?.muted,
|
muted: this._track?.muted,
|
||||||
|
// latency from ping/pong messages
|
||||||
|
latency: this._requestLatency + this._responseLatency,
|
||||||
|
requestLatency: this._requestLatency,
|
||||||
|
responseLatency: this._responseLatency,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,6 +572,8 @@ export class NekoWebRTC extends EventEmitter<NekoWebRTCEvents> {
|
|||||||
framesDecoded = report.framesDecoded
|
framesDecoded = report.framesDecoded
|
||||||
packetsLost = report.packetsLost
|
packetsLost = report.packetsLost
|
||||||
packetsReceived = report.packetsReceived
|
packetsReceived = report.packetsReceived
|
||||||
|
|
||||||
|
this.send('ping', Date.now())
|
||||||
}, ms)
|
}, ms)
|
||||||
|
|
||||||
return function () {
|
return function () {
|
||||||
|
@ -6,6 +6,9 @@ export interface WebRTCStats {
|
|||||||
width: number
|
width: number
|
||||||
height: number
|
height: number
|
||||||
muted?: boolean
|
muted?: boolean
|
||||||
|
latency: number
|
||||||
|
requestLatency: number
|
||||||
|
responseLatency: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CursorPosition {
|
export interface CursorPosition {
|
||||||
|
@ -109,6 +109,20 @@
|
|||||||
<th style="width: 40%">bitrate</th>
|
<th style="width: 40%">bitrate</th>
|
||||||
<td>{{ Math.floor(neko.state.connection.webrtc.stats.bitrate / 1024 / 8) }} KB/s</td>
|
<td>{{ Math.floor(neko.state.connection.webrtc.stats.bitrate / 1024 / 8) }} KB/s</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th style="width: 40%">latency</th>
|
||||||
|
<td
|
||||||
|
:title="
|
||||||
|
'request: ' +
|
||||||
|
neko.state.connection.webrtc.stats.requestLatency +
|
||||||
|
'ms, response: ' +
|
||||||
|
neko.state.connection.webrtc.stats.responseLatency +
|
||||||
|
'ms'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ neko.state.connection.webrtc.stats.latency }}ms
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>loss</th>
|
<th>loss</th>
|
||||||
<td :style="neko.state.connection.webrtc.stats.packetLoss >= 1 ? 'background: red' : ''">
|
<td :style="neko.state.connection.webrtc.stats.packetLoss >= 1 ? 'background: red' : ''">
|
||||||
|
Loading…
Reference in New Issue
Block a user