Reset tracked request value on failure

This commit is contained in:
Johannes Marbach
2026-09-16 16:23:55 +02:00
parent dda549ffd2
commit 11ef319536
2 changed files with 45 additions and 4 deletions
@@ -212,12 +212,13 @@ describe("Publisher device sync", () => {
selected$,
capturedDeviceId,
activeDeviceId,
switchActiveDevice = vi.fn().mockResolvedValue(true),
}: {
selected$: BehaviorSubject<SelectedInput>;
capturedDeviceId?: string;
activeDeviceId: string;
switchActiveDevice?: Mock;
}): { publisher: Publisher; switchActiveDevice: Mock } {
const switchActiveDevice = vi.fn().mockResolvedValue(true);
const livekitRoom = mockLivekitRoom({
localParticipant,
state: LivekitConnectionState.Connected,
@@ -294,6 +295,41 @@ describe("Publisher device sync", () => {
await publisher.destroy();
});
it("retries the same selection after a failed switch", async () => {
const selected$ = new BehaviorSubject<SelectedInput>(selectedInput(""));
const switchActiveDevice = vi
.fn()
.mockRejectedValueOnce(new Error("could not open the device"))
.mockResolvedValue(true);
const { publisher } = createDeviceSyncPublisher({
selected$,
// Pinned to the headset, so moving to the browser default is a switch
capturedDeviceId: "headset",
activeDeviceId: "headset",
switchActiveDevice,
});
expect(switchActiveDevice).toHaveBeenCalledTimes(1);
await flushPromises();
// The failed switch left us on the headset, so selecting the browser
// default again has to try once more rather than count as already done
selected$.next(selectedInput(""));
expect(switchActiveDevice).toHaveBeenCalledTimes(2);
expect(switchActiveDevice).toHaveBeenLastCalledWith(
"audioinput",
"default",
false,
);
await flushPromises();
// This time it worked, so there is nothing left to do
selected$.next(selectedInput(""));
expect(switchActiveDevice).toHaveBeenCalledTimes(2);
await publisher.destroy();
});
it("does not switch when the room already captures from the selected device", async () => {
const selected$ = new BehaviorSubject<SelectedInput>(
selectedInput("headset"),
@@ -392,6 +392,7 @@ export class Publisher {
) {
return;
}
const previousRequestedId = requestedId;
requestedId = device.id;
// For the browser default input, ask for "default" as a non-exact
// constraint: browsers that have no such device ignore it and capture
@@ -399,9 +400,13 @@ export class Publisher {
(browserDefaultInput
? lkRoom.switchActiveDevice(kind, "default", false)
: lkRoom.switchActiveDevice(kind, device.id)
).catch((e: Error) =>
this.logger.error(`Failed to sync ${kind} device with LiveKit`, e),
);
).catch((e: Error) => {
// LiveKit keeps capturing from the previous device, so record that
// again to leave the next selection of this device something to do.
// A selection made while the switch was in flight wins, though.
if (requestedId === device.id) requestedId = previousRequestedId;
this.logger.error(`Failed to sync ${kind} device with LiveKit`, e);
});
});
};