From 3cbf7e50b7562b1caf3ed57760395c4ba1ac1ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Jo=20Bj=C3=B6rnerstedt?= Date: Wed, 28 Jan 2026 15:55:06 +0000 Subject: [PATCH 1/3] fix: add frames-total to types --- src/debugger/chronicle.ts | 2 + src/debugger/debugviewcontroller.test.ts | 12 +++--- src/debugger/debugviewcontroller.ts | 51 ++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/debugger/chronicle.ts b/src/debugger/chronicle.ts index 0845c696..7fccacce 100644 --- a/src/debugger/chronicle.ts +++ b/src/debugger/chronicle.ts @@ -46,6 +46,7 @@ type CurrentLatency = CreateMetric<"current-latency", number> type CurrentUrl = CreateMetric<"current-url", string> type Duration = CreateMetric<"duration", number> type FramesDropped = CreateMetric<"frames-dropped", number> +type FramesTotal = CreateMetric<"frames-total", number> type InitialPlaybackTime = CreateMetric<"initial-playback-time", [time: number, timeline: Timeline]> type MediaElementEnded = CreateMetric<"ended", HTMLMediaElement["ended"]> type MediaElementPaused = CreateMetric<"paused", HTMLMediaElement["paused"]> @@ -73,6 +74,7 @@ export type Metric = | CurrentUrl | Duration | FramesDropped + | FramesTotal | InitialPlaybackTime | MediaElementEnded | MediaElementPaused diff --git a/src/debugger/debugviewcontroller.test.ts b/src/debugger/debugviewcontroller.test.ts index 8ff54c7c..6425d4d8 100644 --- a/src/debugger/debugviewcontroller.test.ts +++ b/src/debugger/debugviewcontroller.test.ts @@ -20,7 +20,7 @@ describe("Debug View", () => { controller.showView() chronicle.appendMetric("buffer-length", 0) - chronicle.appendMetric("frames-dropped", 4) + chronicle.appendMetric("auto-resume", 4) chronicle.appendMetric("duration", 30) controller.addEntries(chronicle.retrieve()) @@ -31,7 +31,7 @@ describe("Debug View", () => { expect.objectContaining({ static: [ { id: "buffer-length", key: "buffer length", value: 0 }, - { id: "frames-dropped", key: "frames dropped", value: 4 }, + { id: "auto-resume", key: "auto resume", value: 4 }, { id: "duration", key: "duration", value: 30 }, ], }) @@ -254,22 +254,22 @@ describe("Debug View", () => { const chronicle = new Chronicle() - chronicle.appendMetric("frames-dropped", 0) + chronicle.appendMetric("auto-resume", 0) jest.advanceTimersByTime(500) - chronicle.appendMetric("frames-dropped", 1) + chronicle.appendMetric("auto-resume", 1) jest.advanceTimersByTime(4500) - chronicle.appendMetric("frames-dropped", 4) + chronicle.appendMetric("auto-resume", 4) controller.addEntries(chronicle.retrieve()) jest.advanceTimersToNextTimer() expect(DebugView.render).toHaveBeenCalledWith( - expect.objectContaining({ static: [{ id: "frames-dropped", key: "frames dropped", value: 4 }] }) + expect.objectContaining({ static: [{ id: "auto-resume", key: "auto resume", value: 4 }] }) ) }) diff --git a/src/debugger/debugviewcontroller.ts b/src/debugger/debugviewcontroller.ts index 0287528c..252fb852 100644 --- a/src/debugger/debugviewcontroller.ts +++ b/src/debugger/debugviewcontroller.ts @@ -67,10 +67,22 @@ type MaxBitrate = { data: Record } +type FrameStatKind = Extends + +type FrameStats = { + category: "union" + kind: "frame-stats" + data: { + total?: number + dropped?: number + } +} + type DynamicEntry = TimestampedMessage | TimestampedTrace | Timestamp type StaticEntry = | Exclude> + | Timestamped | Timestamped | Timestamped | Timestamped @@ -107,6 +119,32 @@ class DebugViewController { private dynamicEntries: DynamicEntry[] = [] private latestMetricByKey: Partial> = {} + private isFrameStat(metric: TimestampedMetric): metric is Timestamped> { + const { kind } = metric + return kind === "frames-dropped" || kind === "frames-total" + } + + private mergeFrameStat(entry: Timestamped>): Timestamped { + const prevEntry: FrameStats = + this.latestMetricByKey["frame-stats"] == null + ? { category: "union", kind: "frame-stats", data: {} } + : (this.latestMetricByKey["frame-stats"] as FrameStats) + + const { sessionTime, currentElementTime, kind: metricKind, data: metricData } = entry + + const keyForKind: Record = { + "frames-dropped": "dropped", + "frames-total": "total", + } + + return { + ...prevEntry, + sessionTime, + currentElementTime, + data: { ...prevEntry.data, [keyForKind[metricKind]]: metricData }, + } + } + private isMediaState(metric: TimestampedMetric): metric is Timestamped> { const { kind } = metric const mediaStateMetrics = ["ended", "paused", "playback-rate", "ready-state", "seeking"] @@ -219,6 +257,11 @@ class DebugViewController { switch (category) { case EntryCategory.METRIC: + if (this.isFrameStat(entry)) { + this.cacheStaticEntry(this.mergeFrameStat(entry)) + return + } + if (this.isMediaState(entry)) { this.cacheStaticEntry(this.mergeMediaState(entry)) return @@ -477,6 +520,14 @@ class DebugViewController { return `${bitratePart} kbps` } + if (kind === "frame-stats") { + if (data.total == null) { + return null + } + + return `${(data.dropped ?? (0 / data.total) * 100).toFixed(2)}% (${data.dropped}/${data.total})` + } + return data.join(", ") } From 6207271c8ba5f1e080aa1428a4241605846b7a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Jo=20Bj=C3=B6rnerstedt?= Date: Wed, 28 Jan 2026 17:01:50 +0000 Subject: [PATCH 2/3] chore: rename to frames --- src/debugger/debugviewcontroller.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/debugger/debugviewcontroller.ts b/src/debugger/debugviewcontroller.ts index 252fb852..bcbf0c1f 100644 --- a/src/debugger/debugviewcontroller.ts +++ b/src/debugger/debugviewcontroller.ts @@ -67,11 +67,11 @@ type MaxBitrate = { data: Record } -type FrameStatKind = Extends +type FrameKind = Extends -type FrameStats = { +type Frames = { category: "union" - kind: "frame-stats" + kind: "frames" data: { total?: number dropped?: number @@ -82,7 +82,7 @@ type DynamicEntry = TimestampedMessage | TimestampedTrace | Timestamp type StaticEntry = | Exclude> - | Timestamped + | Timestamped | Timestamped | Timestamped | Timestamped @@ -119,20 +119,20 @@ class DebugViewController { private dynamicEntries: DynamicEntry[] = [] private latestMetricByKey: Partial> = {} - private isFrameStat(metric: TimestampedMetric): metric is Timestamped> { + private isFrameStat(metric: TimestampedMetric): metric is Timestamped> { const { kind } = metric return kind === "frames-dropped" || kind === "frames-total" } - private mergeFrameStat(entry: Timestamped>): Timestamped { - const prevEntry: FrameStats = - this.latestMetricByKey["frame-stats"] == null - ? { category: "union", kind: "frame-stats", data: {} } - : (this.latestMetricByKey["frame-stats"] as FrameStats) + private mergeFrameStat(entry: Timestamped>): Timestamped { + const prevEntry: Frames = + this.latestMetricByKey.frames == null + ? { category: "union", kind: "frames", data: {} } + : (this.latestMetricByKey.frames as Frames) const { sessionTime, currentElementTime, kind: metricKind, data: metricData } = entry - const keyForKind: Record = { + const keyForKind: Record = { "frames-dropped": "dropped", "frames-total": "total", } @@ -520,12 +520,12 @@ class DebugViewController { return `${bitratePart} kbps` } - if (kind === "frame-stats") { + if (kind === "frames") { if (data.total == null) { return null } - return `${(data.dropped ?? (0 / data.total) * 100).toFixed(2)}% (${data.dropped}/${data.total})` + return `${(data.dropped ?? (0 / data.total) * 100).toFixed(2)}% dropped (${data.dropped}/${data.total})` } return data.join(", ") From 88e3d6e5d0b3b2aa22e95595047b7d98eb9e62dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Jo=20Bj=C3=B6rnerstedt?= Date: Thu, 29 Jan 2026 10:59:06 +0000 Subject: [PATCH 3/3] fix: exclude component frame entries from static entries --- src/debugger/debugviewcontroller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debugger/debugviewcontroller.ts b/src/debugger/debugviewcontroller.ts index bcbf0c1f..99078263 100644 --- a/src/debugger/debugviewcontroller.ts +++ b/src/debugger/debugviewcontroller.ts @@ -81,7 +81,7 @@ type Frames = { type DynamicEntry = TimestampedMessage | TimestampedTrace | Timestamp type StaticEntry = - | Exclude> + | Exclude> | Timestamped | Timestamped | Timestamped