Skip to content

Commit 3d8486c

Browse files
committed
feat(metrics): Add V3 background segmentation metrics to media backend via protobuf
- Add video processor pipeline metrics (frame rate, per-processor latency) via protobuf signaling - Add CDN processor performance metrics (segmentation duration, effect render, CPU usage) via observer - Add metric dimensions for processor name, model type, and delegate type - Add numeric initialization metrics (asset loading time, compatibility, processor creation status) - Extend SignalingProtocol.proto with metric type enums 114-128 and dimension types 3-5 - Simplify BackgroundSegmentationInitializationMetrics to numeric-only interface for protobuf compatibility - Remove per-frame reportProcessorError in favor of aggregated CDN errorCount - Rewrite BackgroundSegmentationMetrics.test.ts for new interface - Add new tests to BackgroundSegmentationVideoFrameProcessor.test.ts - Add proper assertions to StatsCollector tests
1 parent 8c4c516 commit 3d8486c

14 files changed

Lines changed: 3552 additions & 1587 deletions

CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- Added CPU pressure state reporting via the [Compute Pressure API](https://developer.mozilla.org/en-US/docs/Web/API/Compute_Pressure_API), sent to the backend as the `CPU_PRESSURE_STATE` client metric where supported.
1313
- Added `BackgroundSegmentationVideoFrameProcessor` with CDN asset loading, request deduplication, and browser compatibility checking (WebGL2, WASM, Workers)
1414
- Added configurable blur strength (low/medium/high) and support for `selfie_general` and `selfie_multiclass` model types
15-
- Added `BackgroundSegmentationMetrics` observer for StatsCollector integration
1615
- Added dynamic filter switching via `setConfig`/`setModelType` without processor recreation
17-
- Added video processor metrics collection (frame rate, per-processor latency) via StatsCollector
16+
- Added video processor pipeline metrics (frame rate, per-processor latency) sent to the media backend via protobuf signaling
17+
- Added CDN processor performance metrics (segmentation duration, effect render time, CPU usage, error count) via `BackgroundSegmentationMetricsObserver`
18+
- Added metric dimensions for processor name, model type, and delegate type
19+
- Added numeric initialization metrics (asset loading time, compatibility status, processor creation status)
1820
- Added event publishing for filter lifecycle (`backgroundFilterStarted`, `backgroundFilterConfigSelected`, `backgroundFilterFailed`)
1921
- Added V3-specific fields to `VideoFXEventAttributes`
2022

demos/browser/package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

protocol/SignalingProtocol.proto

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,22 @@ message SdkMetric {
322322
// Reported via the Compute Pressure API (https://developer.mozilla.org/en-US/docs/Web/API/Compute_Pressure_API).
323323
// Values: 0 = nominal, 1 = fair, 2 = serious, 3 = critical.
324324
CPU_PRESSURE_STATE = 113;
325+
326+
VIDEO_BACKGROUND_SEGMENTATION_DURATION_MS = 114;
327+
VIDEO_BACKGROUND_SEGMENTATION_EFFECT_RENDER_DURATION_MS = 115;
328+
VIDEO_BACKGROUND_SEGMENTATION_FRAMES_PER_SEGMENTATION = 116;
329+
VIDEO_BACKGROUND_SEGMENTATION_CPU_USAGE_PERCENT = 117;
330+
VIDEO_BACKGROUND_SEGMENTATION_INITIALIZATION_DURATION_MS = 118;
331+
VIDEO_BACKGROUND_SEGMENTATION_INITIALIZATION_FAILURE = 119;
332+
VIDEO_BACKGROUND_SEGMENTATION_ERROR_COUNT = 120;
333+
VIDEO_BACKGROUND_SEGMENTATION_FRAMES_SUBMITTED = 121;
334+
VIDEO_BACKGROUND_SEGMENTATION_FRAMES_SEGMENTED = 122;
335+
VIDEO_PIPELINE_FRAME_RATE = 123;
336+
VIDEO_PROCESSOR_LATENCY_MS = 124;
337+
VIDEO_BACKGROUND_SEGMENTATION_ASSET_LOADING_FAILURE = 125;
338+
VIDEO_BACKGROUND_SEGMENTATION_ASSET_LOADING_TIME_MS = 126;
339+
VIDEO_BACKGROUND_SEGMENTATION_COMPATIBILITY_FAILURE = 127;
340+
VIDEO_BACKGROUND_SEGMENTATION_PROCESSOR_CREATION_FAILURE = 128;
325341
}
326342
optional Type type = 1;
327343
optional double value = 2;
@@ -345,6 +361,9 @@ message SdkStreamDimension {
345361
enum Type {
346362
VIDEO_ENCODER_NAME = 1;
347363
VIDEO_DECODER_NAME = 2;
364+
VIDEO_BACKGROUND_SEGMENTATION_MODEL_TYPE = 3;
365+
VIDEO_BACKGROUND_SEGMENTATION_DELEGATE_TYPE = 4;
366+
VIDEO_PROCESSOR_NAME = 5;
348367
}
349368
optional Type type = 1;
350369
optional SdkDimensionValue value = 2;

script/barrelize.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,13 @@ walk('src')
170170

171171
if (typeToImport === 'BackgroundSegmentationMetrics') {
172172
importStrings.push(`import { BackgroundSegmentationMetricsObserver } from '${pathToImport}/BackgroundSegmentationMetrics';`);
173-
importStrings.push(`import { BackgroundSegmentationMetricReport } from '${pathToImport}/BackgroundSegmentationMetrics';`);
173+
importStrings.push(`import { BackgroundSegmentationInitializationMetrics } from '${pathToImport}/BackgroundSegmentationMetrics';`);
174+
importStrings.push(`import { BackgroundSegmentationInitializationStatus } from '${pathToImport}/BackgroundSegmentationMetrics';`);
175+
importStrings.push(`import { BackgroundSegmentationProcessorMetrics } from '${pathToImport}/BackgroundSegmentationMetrics';`);
174176
exportStrings.push(`BackgroundSegmentationMetricsObserver`);
175-
exportStrings.push(`BackgroundSegmentationMetricReport`);
177+
exportStrings.push(`BackgroundSegmentationInitializationMetrics`);
178+
exportStrings.push(`BackgroundSegmentationInitializationStatus`);
179+
exportStrings.push(`BackgroundSegmentationProcessorMetrics`);
176180
}
177181
});
178182

src/backgroundsegmentation/BackgroundSegmentationMetrics.ts

Lines changed: 75 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,64 @@
33

44
import Logger from '../logger/Logger';
55

6+
export enum BackgroundSegmentationInitializationStatus {
7+
SUCCESS = 0,
8+
FAILURE = 1,
9+
}
10+
611
/**
7-
* [[BackgroundSegmentationMetricReport]] will contain metrics reported
8-
* by the [[BackgroundSegmentationVideoFrameProcessor]]
12+
* [[BackgroundSegmentationInitializationMetrics]] contains metrics reported
13+
* once per processor creation by [[BackgroundSegmentationVideoFrameProcessor]].
914
*/
10-
export class BackgroundSegmentationMetricReport {
11-
metricName: string = '';
12-
timestamp: number = 0;
13-
assetType?: string;
14-
loadTimeMs?: number;
15-
success?: number;
16-
error?: string;
17-
errorType?: string;
18-
errorMessage?: string;
19-
modelType?: string;
20-
isCompatible?: boolean;
21-
missingFeatures?: string;
15+
export interface BackgroundSegmentationInitializationMetrics {
16+
assetLoadingStatus: BackgroundSegmentationInitializationStatus;
17+
assetLoadingTimeMs: number;
18+
compatibilityStatus: BackgroundSegmentationInitializationStatus;
19+
processorCreationStatus: BackgroundSegmentationInitializationStatus;
20+
}
21+
22+
export interface BackgroundSegmentationProcessorMetrics {
23+
segmentationDurationMs: number;
24+
effectRenderDurationMs: number;
25+
framesPerSegmentation: number;
26+
framesSubmitted: number;
27+
framesSegmented: number;
28+
estimatedCPUUsagePercentage: number;
29+
modelType: string;
30+
delegateType: string;
31+
initializationDurationMs?: number;
32+
initializationFailure?: number;
33+
errorCount: number;
2234
}
2335

2436
/**
2537
* Observer interface for receiving background segmentation metrics
2638
*/
2739
export interface BackgroundSegmentationMetricsObserver {
28-
backgroundSegmentationMetricsDidReceive(metricReport: BackgroundSegmentationMetricReport): void;
40+
backgroundSegmentationInitializationMetricsDidReceive(
41+
metricReport: BackgroundSegmentationInitializationMetrics
42+
): void;
43+
backgroundSegmentationProcessorMetricsDidReceive(
44+
report: BackgroundSegmentationProcessorMetrics
45+
): void;
2946
}
3047

3148
/**
32-
* Metrics collection for background segmentation processing
49+
* Metrics collection for background segmentation processing.
50+
* Collects one-time processor creation metrics and periodic CDN performance metrics.
3351
*/
3452
export default class BackgroundSegmentationMetrics {
3553
private static readonly MAX_BUFFERED_METRICS = 100;
3654
private metricsCollector: BackgroundSegmentationMetricsObserver | undefined;
37-
private bufferedMetrics: BackgroundSegmentationMetricReport[] = [];
55+
private bufferedMetrics: BackgroundSegmentationInitializationMetrics[] = [];
56+
57+
private _assetLoadingStatus: BackgroundSegmentationInitializationStatus =
58+
BackgroundSegmentationInitializationStatus.SUCCESS;
59+
private _assetLoadingTimeMs: number = 0;
60+
private _compatibilityStatus: BackgroundSegmentationInitializationStatus =
61+
BackgroundSegmentationInitializationStatus.SUCCESS;
62+
private _processorCreationStatus: BackgroundSegmentationInitializationStatus =
63+
BackgroundSegmentationInitializationStatus.SUCCESS;
3864

3965
constructor(
4066
private logger: Logger,
@@ -65,58 +91,48 @@ export default class BackgroundSegmentationMetrics {
6591
});
6692
}
6793

68-
reportAssetLoadingResult(assetType: string, error?: string, loadTimeMs?: number): void {
69-
try {
70-
const metricReport = new BackgroundSegmentationMetricReport();
71-
metricReport.metricName = 'BackgroundSegmentationAssetLoadingResult';
72-
metricReport.assetType = assetType;
73-
metricReport.success = error ? 0 : 1;
74-
metricReport.error = error;
75-
metricReport.loadTimeMs = loadTimeMs;
76-
metricReport.timestamp = Date.now();
77-
78-
this.emitMetricReport(metricReport);
79-
} catch (err) {
80-
this.logger.warn(
81-
`[BackgroundSegmentationMetrics] Failed to report asset loading status: ${err}`
82-
);
83-
}
94+
reportCompatibilityCheck(isCompatible: boolean): void {
95+
this._compatibilityStatus = isCompatible
96+
? BackgroundSegmentationInitializationStatus.SUCCESS
97+
: BackgroundSegmentationInitializationStatus.FAILURE;
8498
}
8599

86-
reportProcessorError(errorType: string, errorMessage: string, modelType: string): void {
87-
try {
88-
const metricReport = new BackgroundSegmentationMetricReport();
89-
metricReport.metricName = 'BackgroundSegmentationProcessorError';
90-
metricReport.errorType = errorType;
91-
metricReport.errorMessage = errorMessage;
92-
metricReport.modelType = modelType;
93-
metricReport.timestamp = Date.now();
94-
95-
this.emitMetricReport(metricReport);
96-
} catch (error) {
97-
this.logger.warn(
98-
`[BackgroundSegmentationMetrics] Failed to report processor error: ${error}`
99-
);
100-
}
100+
reportAssetLoadingResult(error?: string, loadTimeMs?: number): void {
101+
this._assetLoadingStatus = error
102+
? BackgroundSegmentationInitializationStatus.FAILURE
103+
: BackgroundSegmentationInitializationStatus.SUCCESS;
104+
this._assetLoadingTimeMs = loadTimeMs ?? 0;
101105
}
102106

103-
reportCompatibilityCheck(isCompatible: boolean, missingFeatures: string[]): void {
104-
try {
105-
const metricReport = new BackgroundSegmentationMetricReport();
106-
metricReport.metricName = 'BackgroundSegmentationCompatibilityCheck';
107-
metricReport.isCompatible = isCompatible;
108-
metricReport.missingFeatures = missingFeatures.join(',');
109-
metricReport.timestamp = Date.now();
107+
reportProcessorError(): void {
108+
this._processorCreationStatus = BackgroundSegmentationInitializationStatus.FAILURE;
109+
}
110+
111+
emitInitializationMetrics(): void {
112+
const report: BackgroundSegmentationInitializationMetrics = {
113+
assetLoadingStatus: this._assetLoadingStatus,
114+
assetLoadingTimeMs: this._assetLoadingTimeMs,
115+
compatibilityStatus: this._compatibilityStatus,
116+
processorCreationStatus: this._processorCreationStatus,
117+
};
110118

111-
this.emitMetricReport(metricReport);
119+
this.emitMetricReport(report);
120+
}
121+
122+
reportPerformance(report: BackgroundSegmentationProcessorMetrics): void {
123+
if (!this.metricsCollector) {
124+
return;
125+
}
126+
try {
127+
this.metricsCollector.backgroundSegmentationProcessorMetricsDidReceive(report);
112128
} catch (error) {
113129
this.logger.warn(
114-
`[BackgroundSegmentationMetrics] Failed to report compatibility check: ${error}`
130+
`[BackgroundSegmentationMetrics] Failed to send performance report to collector: ${error}`
115131
);
116132
}
117133
}
118134

119-
private emitMetricReport(metricReport: BackgroundSegmentationMetricReport): void {
135+
private emitMetricReport(metricReport: BackgroundSegmentationInitializationMetrics): void {
120136
if (!this.metricsCollector) {
121137
if (this.bufferedMetrics.length >= BackgroundSegmentationMetrics.MAX_BUFFERED_METRICS) {
122138
this.bufferedMetrics.shift();
@@ -126,7 +142,7 @@ export default class BackgroundSegmentationMetrics {
126142
}
127143

128144
try {
129-
this.metricsCollector.backgroundSegmentationMetricsDidReceive(metricReport);
145+
this.metricsCollector.backgroundSegmentationInitializationMetricsDidReceive(metricReport);
130146
} catch (error) {
131147
this.logger.warn(
132148
`[BackgroundSegmentationMetrics] Failed to send metric report to collector: ${error}`

0 commit comments

Comments
 (0)