Skip to content

Commit

Permalink
Merge pull request #7 from jitsi/feat/add-bitrate-series
Browse files Browse the repository at this point in the history
feat: add bitrate series
  • Loading branch information
andrei-gavrilescu authored Jan 29, 2024
2 parents bf99d46 + f7cc1a1 commit 4513ee9
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 37 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "visualizer-server",
"version": "0.3.5",
"version": "0.3.8",
"description": "Visualize RTC stats data",
"repository": "https://github.com/8x8Cloud/rtc-visualizer",
"author": "8x8",
Expand Down
2 changes: 1 addition & 1 deletion src/client/app/files/formatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const parseData = input => {
lines.forEach(line => {
if (line.length) {
const data = JSON.parse(line)
const time = new Date(data.time || data[data.length - 1])
const time = new Date(data.time || data[3])
delete data.time

switch (data[0]) {
Expand Down
76 changes: 53 additions & 23 deletions src/client/app/raw/legacy.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,18 @@ function createSpecCandidateTable (container, allGroupedStats) {
function createContainers (connid, url) {
let signalingState, iceConnectionState, connectionState, candidates
const container = document.createElement('details')
container.open = true
container.open = false
container.style.margin = '10px'

let innerText = '';
let summary = document.createElement('summary')
summary.innerText = 'Connection:' + connid + ' URL: ' + url
if (connid !== 'null') {
innerText = 'Connection:' + connid// + ' URL: ' + url
} else {
innerText = 'Meeting events';
}

summary.innerText = innerText;

container.appendChild(summary)

if (connid !== 'null') {
Expand Down Expand Up @@ -228,9 +235,34 @@ function createContainers (connid, url) {
return container
}

function convertTotalToRateSeries(timeSeries) {
return timeSeries.reduce(
(accumulator, currentValue) => {

const {prevValue} = accumulator;
accumulator.prevValue = currentValue;

if (!prevValue.length) {
return accumulator;
}

const [timestamp = 0, totalBytesSent = 0] = currentValue;
const [prevTimestamp = 0, prevTotalBytesSent = 0] = prevValue;

const sampleRateSeconds = (timestamp - prevTimestamp) / 1000;
const bitRate = (totalBytesSent - prevTotalBytesSent) * 8;
const bitRatePerSecond = Math.round(bitRate / sampleRateSeconds);

accumulator.bitRate.push([timestamp, bitRatePerSecond]);
return accumulator;
},
{ bitRate: [], prevValue: []},
).bitRate;
}

function processGUM (data) {
const container = document.createElement('details')
container.open = true
container.open = false
container.style.margin = '10px'

const summary = document.createElement('summary')
Expand Down Expand Up @@ -440,23 +472,21 @@ function processConnections (connectionIds, data) {
container.appendChild(chartContainer)

const ignoredSeries = ['type', 'ssrc']
const hiddenSeries = [
'bytesReceived', 'bytesSent',
'headerBytesReceived', 'headerBytesSent',
'packetsReceived', 'packetsSent',
'qpSum', 'estimatedPlayoutTimestamp',
'framesEncoded', 'framesDecoded',
'lastPacketReceivedTimestamp', 'lastPacketSentTimestamp',
'remoteTimestamp',
'audioInputLevel', 'audioOutputLevel',
'totalSamplesDuration',
'totalSamplesReceived', 'jitterBufferEmittedCount',
// legacy
'googDecodingCTN', 'googDecodingCNG', 'googDecodingNormal',
'googDecodingPLCCNG', 'googDecodingCTSG', 'googDecodingMuted',
'googEchoCancellationEchoDelayStdDev',
'googCaptureStartNtpTimeMs'
const visibleSeries = [
'bytesReceivedInBits/S', 'bytesSentInBits/S',
'targetBitrate', 'packetsLost', 'jitter',
'availableOutgoingBitrate', 'roundTripTime'
]
const rateSeriesWhitelist = ['bytesSent', 'bytesReceived'];

// Calculate bitrate per second for time series that contain cumulated values
// over time, time total bytes sent or total bytes received
Object.keys(series[reportname])
.filter(name => rateSeriesWhitelist.includes(name))
.map(name => {
const rateSeries = convertTotalToRateSeries(series[reportname][name]);
series[reportname][`${name}InBits/S`] = rateSeries;
})

const traces = Object.keys(series[reportname])
.filter(name => !ignoredSeries.includes(name))
Expand All @@ -467,11 +497,11 @@ function processConnections (connectionIds, data) {
return {
mode: 'lines+markers',
name: name,
visible: hiddenSeries.includes(name) ? 'legendonly' : true,
visible: visibleSeries.includes(name) ? true: 'legendonly',
x: data.map(d => new Date(d[0])),
y: data.map(d => d[1])
}
})
})

// expand the graph when opening
container.ontoggle = () => container.open && Plotly.react(chartContainer, traces)
Expand Down Expand Up @@ -503,7 +533,7 @@ export const clearStats = () => {

export const showStats = data => {
clearStats()
document.getElementById('userAgent').innerHTML = `<b>User Agent:</b> <span>${data.userAgent}</span>`
// TODO Add user agent support document.getElementById('userAgent').innerHTML = `<b>User Agent:</b> <span>${data.userAgent}</span>`
processGUM(data.getUserMedia)
window.setTimeout(processConnections, 0, Object.keys(data.peerConnections), data)
}
49 changes: 39 additions & 10 deletions src/server/jwt-auth.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,53 @@ function addPEMHeaders (headerlessPEMKey) {
return `-----BEGIN CERTIFICATE-----\n${headerlessPEMKey}\n-----END CERTIFICATE-----`
}

function addRSAPublicKeyPEMHeaders(headerlessPEMKey) {
const nlHeaderlessPEMKey = headerlessPEMKey.replace(/(.{64})/g, '$1\n');

return `-----BEGIN PUBLIC KEY-----\n${nlHeaderlessPEMKey}\n-----END PUBLIC KEY-----`;
}

const { RTCSTATS_JWT_PUBLIC_KEY } = process.env
const formattedKey = addPEMHeaders(RTCSTATS_JWT_PUBLIC_KEY)
const { RTCSTATS_JWT_EGHT_PUBLIC_KEY } = process.env

const formattedKeyJaaS = addPEMHeaders(RTCSTATS_JWT_PUBLIC_KEY)
const formattedKeyEGHT = addRSAPublicKeyPEMHeaders(RTCSTATS_JWT_EGHT_PUBLIC_KEY)


function isValidJaaSToken(authorization) {
try {
const bearerToken = authorization.substring(7)
const decodedToken = jwt.verify(bearerToken, formattedKeyJaaS)

return decodedToken;
} catch (error) {
log.error(`JAAS Bearer authorization failed: ${JSON.stringify(error)}`)
}
}

function isValidEGHTToken(authorization) {
try {
const bearerToken = authorization.substring(7)
const decodedToken = jwt.verify(bearerToken, formattedKeyEGHT)

return decodedToken;
} catch (error) {
log.error(`EGHT Bearer authorization failed: ${JSON.stringify(error)}`)
}
}

export default (req, res, next) => {
const { headers: { authorization = '' } = {} } = req

if (authorization.startsWith('Bearer ')) {
try {
const bearerToken = authorization.substring(7)
const decodedToken = jwt.verify(bearerToken, formattedKey)

const decodedToken = isValidJaaSToken(authorization) || isValidEGHTToken(authorization);

if (decodedToken) {
req.user = decodedToken

next()
} catch (error) {
log.error(`Bearer authorization failed: ${JSON.stringify(error)}`)
res.status(401).json({ error: 'Unauthorized' })
return next()
}

res.status(401).json({ error: 'Unauthorized' })
} else {
log.warn(`Bearer authorization token not present, found: ${authorization}`)

Expand Down

0 comments on commit 4513ee9

Please sign in to comment.