Expand upon playback metrics

This commit is contained in:
Gabe Kangas
2022-03-16 22:49:38 -07:00
parent 1ce2ee398c
commit dd392e34db

View File

@@ -28,9 +28,23 @@ function DescriptionBox({ title, description }: DescriptionBoxProps) {
export default function StreamHealth() { export default function StreamHealth() {
const [errors, setErrors] = useState<TimedValue[]>([]); const [errors, setErrors] = useState<TimedValue[]>([]);
const [qualityVariantChanges, setQualityVariantChanges] = useState<TimedValue[]>([]); const [qualityVariantChanges, setQualityVariantChanges] = useState<TimedValue[]>([]);
const [latency, setLatency] = useState<TimedValue[]>([]);
const [segmentDownloadDurations, setSegmentDownloadDurations] = useState<TimedValue[]>([]); const [lowestLatency, setLowestLatency] = useState<TimedValue[]>();
const [highestLatency, setHighestLatency] = useState<TimedValue[]>();
const [medianLatency, setMedianLatency] = useState<TimedValue[]>([]);
const [medianSegmentDownloadDurations, setMedianSegmentDownloadDurations] = useState<
TimedValue[]
>([]);
const [maximumSegmentDownloadDurations, setMaximumSegmentDownloadDurations] = useState<
TimedValue[]
>([]);
const [minimumSegmentDownloadDurations, setMinimumSegmentDownloadDurations] = useState<
TimedValue[]
>([]);
const [minimumPlayerBitrate, setMinimumPlayerBitrate] = useState<TimedValue[]>([]); const [minimumPlayerBitrate, setMinimumPlayerBitrate] = useState<TimedValue[]>([]);
const [medianPlayerBitrate, setMedianPlayerBitrate] = useState<TimedValue[]>([]);
const [maximumPlayerBitrate, setMaximumPlayerBitrate] = useState<TimedValue[]>([]);
const [availableBitrates, setAvailableBitrates] = useState<Number[]>([]); const [availableBitrates, setAvailableBitrates] = useState<Number[]>([]);
const [segmentLength, setSegmentLength] = useState(0); const [segmentLength, setSegmentLength] = useState(0);
@@ -39,9 +53,19 @@ export default function StreamHealth() {
const result = await fetchData(API_STREAM_HEALTH_METRICS); const result = await fetchData(API_STREAM_HEALTH_METRICS);
setErrors(result.errors); setErrors(result.errors);
setQualityVariantChanges(result.qualityVariantChanges); setQualityVariantChanges(result.qualityVariantChanges);
setLatency(result.latency);
setSegmentDownloadDurations(result.segmentDownloadDuration); setHighestLatency(result.highestLatency);
setLowestLatency(result.lowestLatency);
setMedianLatency(result.medianLatency);
setMedianSegmentDownloadDurations(result.medianSegmentDownloadDuration);
setMaximumSegmentDownloadDurations(result.maximumSegmentDownloadDuration);
setMinimumSegmentDownloadDurations(result.minimumSegmentDownloadDuration);
setMinimumPlayerBitrate(result.minPlayerBitrate); setMinimumPlayerBitrate(result.minPlayerBitrate);
setMedianPlayerBitrate(result.medianPlayerBitrate);
setMaximumPlayerBitrate(result.maxPlayerBitrate);
setAvailableBitrates(result.availableBitrates); setAvailableBitrates(result.availableBitrates);
setSegmentLength(result.segmentLength - 0.3); setSegmentLength(result.segmentLength - 0.3);
} catch (error) { } catch (error) {
@@ -74,11 +98,11 @@ export default function StreamHealth() {
return noData; return noData;
} }
if (!latency?.length) { if (!medianLatency?.length) {
return noData; return noData;
} }
if (!segmentDownloadDurations?.length) { if (!medianSegmentDownloadDurations?.length) {
return noData; return noData;
} }
@@ -99,24 +123,48 @@ export default function StreamHealth() {
const latencyChart = [ const latencyChart = [
{ {
name: 'Average stream latency', name: 'Median stream latency',
color: '#00FFFF',
options: { radius: 2 },
data: medianLatency,
},
{
name: 'Lowest stream latency',
color: '#02FD0D',
options: { radius: 2 },
data: lowestLatency,
},
{
name: 'Highest stream latency',
color: '#B63FFF', color: '#B63FFF',
options: { radius: 2 }, options: { radius: 2 },
data: latency, data: highestLatency,
}, },
]; ];
const segmentDownloadDurationChart = [ const segmentDownloadDurationChart = [
{ {
name: 'Average download duration', name: 'Median download duration',
color: '#00FFFF',
options: { radius: 2 },
data: medianSegmentDownloadDurations,
},
{
name: 'Max download duration',
color: '#B63FFF', color: '#B63FFF',
options: { radius: 2 }, options: { radius: 2 },
data: segmentDownloadDurations, data: maximumSegmentDownloadDurations,
},
{
name: 'Min download duration',
color: '#02FD0D',
options: { radius: 2 },
data: minimumSegmentDownloadDurations,
}, },
{ {
name: `Approximate limit`, name: `Approximate limit`,
color: '#003FFF', color: '#003FFF',
data: segmentDownloadDurations.map(item => ({ data: medianSegmentDownloadDurations.map(item => ({
time: item.time, time: item.time,
value: segmentLength, value: segmentLength,
})), })),
@@ -131,6 +179,18 @@ export default function StreamHealth() {
data: minimumPlayerBitrate, data: minimumPlayerBitrate,
options: { radius: 2 }, options: { radius: 2 },
}, },
{
name: 'Median viewer bitrate',
color: '#00FFFF',
data: medianPlayerBitrate,
options: { radius: 2 },
},
{
name: 'Maximum viewer bitrate',
color: '#02FD0D',
data: maximumPlayerBitrate,
options: { radius: 2 },
},
]; ];
availableBitrates.forEach(bitrate => { availableBitrates.forEach(bitrate => {
@@ -147,9 +207,13 @@ export default function StreamHealth() {
const currentSpeed = bitrateChart[0]?.data[bitrateChart[0].data.length - 1]?.value; const currentSpeed = bitrateChart[0]?.data[bitrateChart[0].data.length - 1]?.value;
const currentDownloadSeconds = const currentDownloadSeconds =
segmentDownloadDurations[segmentDownloadDurations.length - 1]?.value; medianSegmentDownloadDurations[medianSegmentDownloadDurations.length - 1]?.value;
const lowestVariant = availableBitrates[0]; // TODO: get lowest bitrate from available bitrates const lowestVariant = availableBitrates[0]; // TODO: get lowest bitrate from available bitrates
const latencyStat = latencyChart[0]?.data[latencyChart[0].data.length - 1]?.value || 0;
const latencyMedian = medianLatency[medianLatency.length - 1]?.value || 0;
const latencyMax = highestLatency[highestLatency.length - 1]?.value || 0;
const latencyMin = lowestLatency[lowestLatency.length - 1]?.value || 0;
const latencyStat = (Number(latencyMax) + Number(latencyMin) + Number(latencyMedian)) / 3;
let recentErrorCount = 0; let recentErrorCount = 0;
const errorValueCount = errorChart[0]?.data.length || 0; const errorValueCount = errorChart[0]?.data.length || 0;
@@ -202,7 +266,7 @@ export default function StreamHealth() {
<Card type="inner"> <Card type="inner">
<div style={statStyle}> <div style={statStyle}>
<Statistic <Statistic
title="Slowest Viewer Speed" title="Viewer Playback Speed"
value={`${currentSpeed}`} value={`${currentSpeed}`}
prefix={<WifiOutlined style={{ marginRight: '5px' }} />} prefix={<WifiOutlined style={{ marginRight: '5px' }} />}
precision={0} precision={0}
@@ -215,7 +279,7 @@ export default function StreamHealth() {
<Card type="inner"> <Card type="inner">
<div style={statStyle}> <div style={statStyle}>
<Statistic <Statistic
title="Average Latency" title="Viewer Latency"
value={`${latencyStat}`} value={`${latencyStat}`}
prefix={<ClockCircleOutlined style={{ marginRight: '5px' }} />} prefix={<ClockCircleOutlined style={{ marginRight: '5px' }} />}
precision={0} precision={0}
@@ -275,10 +339,10 @@ export default function StreamHealth() {
description={ description={
<> <>
<Typography.Paragraph> <Typography.Paragraph>
The slowest bitrate of any of your viewers. Once somebody's bitrate drops below The playback bitrate of your viewers. Once somebody's bitrate drops below the
the lowest video variant bitrate they will experience buffering. If you see lowest video variant bitrate they will experience buffering. If you see viewers
viewers with slow connections trying to play your video you should consider with slow connections trying to play your video you should consider offering an
offering an additional, lower quality. additional, lower quality.
</Typography.Paragraph> </Typography.Paragraph>
<Typography.Paragraph> <Typography.Paragraph>
In short, once the pink line gets near the lowest blue line, your stream is likely In short, once the pink line gets near the lowest blue line, your stream is likely
@@ -324,8 +388,8 @@ export default function StreamHealth() {
</Card> </Card>
<Card> <Card>
<DescriptionBox <DescriptionBox
title="Average Latency" title="Viewer Latency"
description="An approximate, averaged, seconds across all your viewers that they are behind your live video. The more people buffer the further behind they will be. High latency itself is not a problem, but some people care about this more than others." description="An approximate number of seconds that your viewers are behind your live video. The more people buffer the further behind they will be. High latency itself is not a problem, but some people care about this more than others."
/> />
<Chart title="Seconds" dataCollections={latencyChart} color="#FF7700" unit="s" /> <Chart title="Seconds" dataCollections={latencyChart} color="#FF7700" unit="s" />
</Card> </Card>