Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/catch-initial-background-load.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@livekit/track-processors': patch
---

Log a failing background image passed to the processor's constructor, instead of raising an unhandled promise rejection
2 changes: 1 addition & 1 deletion e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Seventeen cases across eleven concerns.
| `capability.spec.ts` | A1, A1b, A3, A4 | Support predicates; both pipelines selected and working |
| `lifecycle.spec.ts` | B1, B2 | Attach produces blurred frames; detach restores them |
| `modes.spec.ts` | C1, C1b, C3 | Switching lands correctly, publishes no intermediate frame, and `disabled` is true passthrough |
| `background.spec.ts` | D1, D5 | Image composited behind the subject; fetched once |
| `background.spec.ts` | D1, D5, D6 | Image composited behind the subject; fetched once; a failing image at construction is logged |
| `geometry.spec.ts` | E1 | Output dimensions follow the source at three resolutions |
| `performance.spec.ts` | G1 | `onFrameProcessed` timings are coherent at a usable frame rate |

Expand Down
24 changes: 24 additions & 0 deletions e2e/specs/background.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,28 @@ test.describe('virtual background', () => {
// this asserts only about repeated switches within a single processor session.
expect(requests, `bg-solid.png was fetched ${requests} times`).toBe(1);
});

test('D6: an image that fails to load at construction is logged, not thrown', async ({ app }) => {
const { page } = app;

let requests = 0;
await page.route('**/missing-bg.png', (route) => {
requests += 1;
return route.fulfill({ status: 404 });
});

// `mode` and `bg` are read when the harness constructs the processor, so the failing image
// goes through the constructor rather than switchTo().
await app.goto({ mode: 'virtual-background', bg: '/missing-bg.png', backdrop: 'flat' });
await startCamera(page);
await attachProcessor(page);

// The failure must actually have happened, or a clean page would be trivially true.
expect(requests, 'missing-bg.png was never requested').toBeGreaterThan(0);

// Regression guard for #141. A rejection from the constructor reaches the page as an
// uncaught error with no message.
expect(app.pageErrors, 'uncaught page errors').toEqual([]);
expect(await page.evaluate(() => window.harness.lastError()), 'harness logged an error').toBeNull();
});
});
4 changes: 3 additions & 1 deletion src/transformers/BackgroundTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ export default class BackgroundProcessor extends VideoTransformer<BackgroundOpti
constructor(opts: BackgroundOptions) {
super();
this.options = opts;
this.update(opts);
this.update(opts).catch((err) =>
this.log.error('Error while applying initial processor options: ', err),
);
}

async init({ outputCanvas, inputElement: inputVideo }: VideoTransformerInitOptions) {
Expand Down
Loading