Fix device selection in pre-join screen for Element Call video rooms (#9321)

* Fix device selection in pre-join screen for Element Call video rooms

As per https://github.com/vector-im/element-call/pull/609

* Update unit test

* Lint

* Hold a media stream while we enumerate device so we can do so reliably.

This means we can remove the device fallback labels.

* i18n

* Remove unnecessary useState

* Fix fetching video devices when video muted

* Actually fix preview stream code

* Fix unit test now fallback is no longer a thing

* Test changing devices
This commit is contained in:
David Baker 2022-09-30 17:28:53 +01:00 committed by GitHub
parent eaff7e945c
commit 07a5a1dc6f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 123 additions and 66 deletions

View file

@ -187,6 +187,35 @@ describe("CallLobby", () => {
});
describe("device buttons", () => {
const fakeVideoInput1: MediaDeviceInfo = {
deviceId: "v1",
groupId: "v1",
label: "Webcam",
kind: "videoinput",
toJSON: () => {},
};
const fakeVideoInput2: MediaDeviceInfo = {
deviceId: "v2",
groupId: "v2",
label: "Othercam",
kind: "videoinput",
toJSON: () => {},
};
const fakeAudioInput1: MediaDeviceInfo = {
deviceId: "v1",
groupId: "v1",
label: "Headphones",
kind: "audioinput",
toJSON: () => {},
};
const fakeAudioInput2: MediaDeviceInfo = {
deviceId: "v2",
groupId: "v2",
label: "Tailphones",
kind: "audioinput",
toJSON: () => {},
};
it("hide when no devices are available", async () => {
await renderView();
expect(screen.queryByRole("button", { name: /microphone/ })).toBe(null);
@ -194,13 +223,7 @@ describe("CallLobby", () => {
});
it("show without dropdown when only one device is available", async () => {
mocked(navigator.mediaDevices.enumerateDevices).mockResolvedValue([{
deviceId: "1",
groupId: "1",
label: "Webcam",
kind: "videoinput",
toJSON: () => {},
}]);
mocked(navigator.mediaDevices.enumerateDevices).mockResolvedValue([fakeVideoInput1]);
await renderView();
screen.getByRole("button", { name: /camera/ });
@ -209,27 +232,40 @@ describe("CallLobby", () => {
it("show with dropdown when multiple devices are available", async () => {
mocked(navigator.mediaDevices.enumerateDevices).mockResolvedValue([
{
deviceId: "1",
groupId: "1",
label: "Headphones",
kind: "audioinput",
toJSON: () => {},
},
{
deviceId: "2",
groupId: "1",
label: "", // Should fall back to "Audio input 2"
kind: "audioinput",
toJSON: () => {},
},
fakeAudioInput1, fakeAudioInput2,
]);
await renderView();
screen.getByRole("button", { name: /microphone/ });
fireEvent.click(screen.getByRole("button", { name: "Audio devices" }));
screen.getByRole("menuitem", { name: "Headphones" });
screen.getByRole("menuitem", { name: "Audio input 2" });
screen.getByRole("menuitem", { name: "Tailphones" });
});
it("sets video device when selected", async () => {
mocked(navigator.mediaDevices.enumerateDevices).mockResolvedValue([
fakeVideoInput1, fakeVideoInput2,
]);
await renderView();
screen.getByRole("button", { name: /camera/ });
fireEvent.click(screen.getByRole("button", { name: "Video devices" }));
fireEvent.click(screen.getByRole("menuitem", { name: fakeVideoInput2.label }));
expect(client.getMediaHandler().setVideoInput).toHaveBeenCalledWith(fakeVideoInput2.deviceId);
});
it("sets audio device when selected", async () => {
mocked(navigator.mediaDevices.enumerateDevices).mockResolvedValue([
fakeAudioInput1, fakeAudioInput2,
]);
await renderView();
screen.getByRole("button", { name: /microphone/ });
fireEvent.click(screen.getByRole("button", { name: "Audio devices" }));
fireEvent.click(screen.getByRole("menuitem", { name: fakeAudioInput2.label }));
expect(client.getMediaHandler().setAudioInput).toHaveBeenCalledWith(fakeAudioInput2.deviceId);
});
});
});

View file

@ -616,8 +616,8 @@ describe("ElementCall", () => {
await call.connect();
expect(call.connectionState).toBe(ConnectionState.Connected);
expect(messaging.transport.send).toHaveBeenCalledWith(ElementWidgetActions.JoinCall, {
audioInput: "1",
videoInput: "2",
audioInput: "Headphones",
videoInput: "Built-in webcam",
});
});

View file

@ -34,6 +34,7 @@ import {
} from 'matrix-js-sdk/src/matrix';
import { normalize } from "matrix-js-sdk/src/utils";
import { ReEmitter } from "matrix-js-sdk/src/ReEmitter";
import { MediaHandler } from "matrix-js-sdk/src/webrtc/mediaHandler";
import { MatrixClientPeg as peg } from '../../src/MatrixClientPeg';
import { makeType } from "../../src/utils/TypeUtils";
@ -175,6 +176,11 @@ export function createTestClient(): MatrixClient {
sendToDevice: jest.fn().mockResolvedValue(undefined),
queueToDevice: jest.fn().mockResolvedValue(undefined),
encryptAndSendToDevices: jest.fn().mockResolvedValue(undefined),
getMediaHandler: jest.fn().mockReturnValue({
setVideoInput: jest.fn(),
setAudioInput: jest.fn(),
} as unknown as MediaHandler),
} as unknown as MatrixClient;
client.reEmitter = new ReEmitter(client);